[
  {
    "path": ".codecov.yml",
    "content": "# Codecov configuration file\n\ncomment: false\n\ncoverage:\n    range: 0..100  # sets the range for the color bar in the dashboard\n    round: down\n    precision: 2\n    status:\n        project:\n            default:\n                # allow coverage to drop by this amount and still post success\n                threshold: 10\n        patch:\n            default:\n                threshold: 10\n\nignore:\n    - \"setup.py\"\n    - \"tests/\"\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Report a bug to help us improve\ntitle: 'Bug report'\nlabels: \"Type: Bug\"\n---\n\n<!--\nIMPORTANT NOTES\n\nThank you for taking the time to report a bug. If you aren't certain whether an issue\nis a bug, please first open a Discussion. Before submitting, please reread your\ndescription to ensure that other readers can reasonably understand the issue\nyou're facing and the impact on your workflow or results.\n\nThis form is written in GitHub's Markdown format. For a reference on this type\nof syntax, see GitHub's documentation:\nhttps://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax\n\nThis template contains guidance for your submission within the < ! - -, - - > blocks.\nThese are comments in HTML syntax and will not appear in the submission.\nBe sure to use the \"Preview\" feature on GitHub to ensure your submission is formatted as intended.\n\nWhen including code snippets, please paste the text itself and wrap the code block with\nticks (see the other character on the tilde ~ key in a US keyboard) to format it as code.\nFor example, Python code should be wrapped in ticks like this:\n```python\ndef a_func():\n    return 1\n\na = 1\nb = a_func()\nprint(a + b)\n```\nThis is preferred over screen shots since it is searchable and others can copy/paste\nthe text to run it.\n-->\n\n# Add meaningful title here\n<!--\nA clear and concise description of the bug including what happened\nand what you expected to happen.\n-->\n\n## How to reproduce\n<!--\nDescribe how another person with no context can recreate this issue.\nIt is typically very helpful to reduce the problem as much as possible\nand share a minimum working example. See the note above on including\ncode as text rather than screenshots.\n-->\n\n## Relevant output\n<!--\nInclude any output, plots, or other means of communication here to add context to the problem.\n -->\n\n## Floris version\n<!--\nShare your floris version and how you installed it. You can print the floris version from\na Python REPL or script with these commands:\n```python\nimport floris\nprint(floris.__version__)\n```\n -->\n\n## System Information\n<!-- Add your information here. -->\n - OS: <e.g. Ubuntu 20.04 or macOS 10.12>\n - Python version: <Result of `python --version`>\n - Library versions\n   - Results of `pip freeze`, for example\n   - matplotlib\n   - numpy\n   - numexpr\n   - scipy\n   - pandas\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Usage question\n    url: https://github.com/NatLabRockies/floris/discussions\n    about: Have any questions about using FLORIS? Post in Discussions to engage with the NLR team and FLORIS community.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: 'Feature request'\nlabels: 'Type: Enhancement'\n---\n\n<!--\nIMPORTANT NOTES\n\nThank you for taking the time to suggest a feature. Before submitting,\nplease reread your description to ensure that other readers can reasonably\nunderstand the motivation and proposed solution.\n\nThis form is written in GitHub's Markdown format. For a reference on this type\nof syntax, see GitHub's documentation:\nhttps://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax\n\nThis template contains guidance for your submission within the < ! - -, - - > blocks.\nThese are comments in HTML syntax and will not appear in the submission.\nBe sure to use the \"Preview\" feature on GitHub to ensure your submission is formatted as intended.\n\nWhen including code snippets, please paste the text itself and wrap the code block with\nticks (see the other character on the tilde ~ key in a US keyboard) to format it as code.\nFor example, Python code should be wrapped in ticks like this:\n```python\ndef a_func():\n    return 1\n\na = 1\nb = a_func()\nprint(a + b)\n```\nThis is preferred over screen shots since it is searchable and others can copy/paste\nthe text to run it.\n-->\n\n# Add meaningful title here\n<!--\nHigh level description of the feature request including motivation and background.\n-->\n\n## Proposed solution\n<!--\nHere's an opportunity to prototype a feature. Please include pseudocode, images, or\nany other visual aids to communicate the idea.\n-->\n\n## Alternatives considered\n<!--\nDescribe workarounds or alternatives even if hacky or incomplete.\n-->\n\n## Additional context\n<!--\nOptional. Provide anything else that helps to communicate the idea here.\n-->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "\n<!--\nIMPORTANT NOTES\n\nIs this pull request ready to be merged?\n- Do the existing tests pass and new tests added for new code?\n- Is all development in a state where you are proud to share it with others and\n  willing to ask other people to take the time to review it?\n- Is it documented in such a way that a review can reasonably understand what you've\n  done and why you've done it? Can other users understand how to use your changes?\nIf not but opening the pull request will facilitate development, make it a \"draft\" pull request\n\nThis form is written in GitHub's Markdown format. For a reference on this type\nof syntax, see GitHub's documentation:\nhttps://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax\n\nThis template contains guidance for your submission within the < ! - -, - - > blocks.\nThese are comments in HTML syntax and will not appear in the submission.\nBe sure to use the \"Preview\" feature on GitHub to ensure your submission is formatted as intended.\n\nWhen including code snippets, please paste the text itself and wrap the code block with\nticks (see the other character on the tilde ~ key in a US keyboard) to format it as code.\nFor example, Python code should be wrapped in ticks like this:\n```python\ndef a_func():\n    return 1\n\na = 1\nb = a_func()\nprint(a + b)\n```\nThis is preferred over screen shots since it is searchable and others can copy/paste\nthe text to run it.\n-->\n\n\n# Add meaningful title here\n<!--\nBe sure to title your pull request so that readers can scan through the list of PR's and understand\nwhat this one involves. It should be a few well selected words to get the point across. If you have\na hard time choosing a brief title, consider splitting the pull request into multiple pull requests.\nKeep in mind that the title will be automatically included in the release notes.\n-->\nDescribe your feature here.\n\n## Related issue\n<!--\nIf one exists, link to a related GitHub Issue.\n-->\n\n## Impacted areas of the software\n<!--\nList any modules or other areas which should be impacted by this pull request. This helps to determine the verification tests.\n-->\n\n## Additional supporting information\n<!--\nAdd any other context about the problem here.\n-->\n\n## Test results, if applicable\n<!--\nAdd the results from unit tests and regression tests here along with justification for any failing test cases.\n-->\n\n<!--\n__ For NLR use __\nRelease checklist:\n- Update the version in\n    - [ ] README.md (appears twice in README.md)\n    - [ ] pyproject.toml\n- [ ] Verify docs builds correctly\n- [ ] Create a tag in the NREL/FLORIS repository\n-->\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: \"pip\"\n  directory: \"/\" # Location of package manifests\n  target-branch: \"develop\"\n  schedule:\n    interval: \"monthly\"\n  labels:\n    - \"package\"\n  ignore:\n    - dependency-name: \"*\"\n      update-types: [\"version-update:semver-minor\", \"version-update:semver-patch\"]\n"
  },
  {
    "path": ".github/workflows/check-working-examples.yaml",
    "content": "name: Check Examples APIs\n\non: [push, pull_request]\n\njobs:\n\n  examples-check:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        python-version: [\"3.10\", \"3.14\"]\n        os: [ubuntu-latest]\n      fail-fast: False\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v4\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Install project\n      run: |\n        python -m pip install --upgrade pip\n        pip install .\n        pip install nbconvert  # For converting Jupyter notebook to python script in the next step\n\n    - name: Run examples (ubuntu, macos)\n      # Run all examples and test that they finish successfully. Do not evaluate the results.\n      # Copy the examples to a new directory outside of the repo to ensure that there is no\n      # reliance on the repo directory structure.\n      run: |\n        mkdir -p temp1/temp2/temp3\n        cp -rL examples temp1/temp2/temp3/.\n        cd temp1/temp2/temp3/examples/\n\n        error_found=0  # 0 is false\n        error_results=\"Error in example:\"\n\n        # Now run the examples in root and  subdirectories\n        echo \"Running examples\"\n        for d in . $(find . -type d -name \"*examples*\"); do\n          cd $d\n          echo \"========================= Example directory- $d\"\n          for i in *.py; do\n            echo \"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Running example- $i\"\n\n            # If \"convert_examples\" is in i, skip this script\n            if [[ $i == *\"convert_examples\"* ]]; then\n              continue\n            fi\n\n            if ! python $i; then\n              error_results=\"${error_results}\"$'\\n'\" - ${i}\"\n              error_found=1\n            fi\n          done\n          if [ \"$d\" != \".\" ]; then\n            cd ..\n          fi\n\n        done\n\n        if [[ $error_found ]]; then\n          echo \"${error_results}\"\n        fi\n\n        exit $error_found\n"
  },
  {
    "path": ".github/workflows/continuous-integration-workflow.yaml",
    "content": "name: Automated tests & code coverage\n\non: [push, pull_request]\n\njobs:\n\n  code-qa-validation:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        python-version: [\"3.10\", \"3.11\", \"3.12\", \"3.13\", \"3.14\"]\n        os: [ubuntu-latest, macos-latest, windows-latest]\n      fail-fast: False\n    env:\n      CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v4\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Install project\n      run: |\n        python -m pip install --upgrade pip\n        pip install \".[develop]\"\n    - uses: pre-commit/action@v3.0.0\n    - name: Run tests (ubuntu, macos)\n      if: matrix.os != 'windows-latest' && (success() || failure())  # Run this step even if the linting step fails\n      run: |\n        mkdir -p temp1/temp2/temp3\n        cp -rL tests temp1/temp2/temp3/.\n        cd temp1/temp2/temp3/\n\n        # -rA displays the captured output for all tests after they're run\n        # See the docs: https://doc.pytest.org/en/latest/reference/reference.html#command-line-flags\n        pytest -rA tests/ --ignore tests/timing.py --ignore tests/profiling.py\n    - name: Run tests (windows)\n      if: matrix.os == 'windows-latest' && (success() || failure())  # Run this step even if the linting step fails\n      run: |\n        mkdir -p temp1/temp2/temp3\n        cp -r tests temp1/temp2/temp3/.\n        cd temp1/temp2/temp3/\n\n        # -rA displays the captured output for all tests after they're run\n        # See the docs: https://doc.pytest.org/en/latest/reference/reference.html#command-line-flags\n        pytest -rA tests/ --ignore tests/timing.py --ignore tests/profiling.py\n    - name: Generate coverage report\n      # Run these tests on unit tests only so that we avoid inflating our code\n      # coverage through the regression tests\n      if: matrix.os == 'ubuntu-latest'\n      run: |\n        pip install pytest\n        pip install pytest-cov\n        pytest --cov=./ --cov-report=xml tests/ --ignore tests/reg_tests --ignore tests/timing.py --ignore tests/profiling.py\n    - name: Upload coverage to Codecov\n      if: ${{ matrix.os == 'ubuntu-latest' && env.CODECOV_TOKEN }}  # Don't attempt to upload if the codecov token is not configured\n      uses: codecov/codecov-action@v3\n      with:\n        token: ${{ env.CODECOV_TOKEN }}\n        files: ./coverage.xml\n        fail_ci_if_error: true\n"
  },
  {
    "path": ".github/workflows/deploy-pages.yaml",
    "content": "name: deploy-pages\n\non:\n  push:\n    branches:\n    - develop\n\n\n  workflow_dispatch:  # Allows manual triggering of the workflow\n\n# This job installs dependencies, builds the book, and pushes it to `gh-pages`\njobs:\n  deploy-book:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v2\n\n    # Install dependencies\n    - name: Set up Python\n      uses: actions/setup-python@v4\n      with:\n        python-version: \"3\"\n\n    - name: Install dependencies\n      run: |\n        pip install -e \".[docs, develop]\"\n\n    # Make a copy of the examples folder within the docs folder\n    - name: Copy examples to docs\n      working-directory: ${{runner.workspace}}/floris/\n      run: |\n        rsync -av examples/ docs/examples\n        ls docs/examples\n\n    # Run the script examples/_convert_examples_to_notebooks.py\n    - name: Convert examples to notebooks\n      working-directory: ${{runner.workspace}}/floris/docs/examples/\n      run: |\n        pwd\n        ls\n        python _convert_examples_to_notebooks.py\n\n    # Build the book\n    - name: Build the book\n      working-directory: ${{runner.workspace}}/floris/docs/\n      run: |\n        jupyter-book build .\n\n    # Push the book's HTML to github-pages\n    - name: GitHub Pages action\n      uses: peaceiris/actions-gh-pages@v4.0.0\n      with:\n        github_token: ${{ secrets.GITHUB_TOKEN }}\n        publish_dir: ./docs/_build/html\n\n    # Stash changes before benchmark action\n    - name: Stash changes\n      working-directory: ${{runner.workspace}}/floris/\n      run: |\n        git stash\n\n    - name: Run benchmark\n      working-directory: ${{runner.workspace}}/floris/\n      run: |\n        ls -lah\n        cd benchmarks\n        pytest bench.py --benchmark-json output.json\n\n    # Store benchmark result and create the benchmark pages\n    # Update the index.html and data.js files in the\n    # dev/bench folder of the benches branch\n    # dev/bench is the default folder for pytest-benchmark\n    - name: Store benchmark result\n      uses: benchmark-action/github-action-benchmark@v1\n      with:\n        name: Python Benchmark with pytest-benchmark\n        tool: 'pytest'\n        output-file-path: benchmarks/output.json\n        github-token: ${{ secrets.GITHUB_TOKEN }}\n        auto-push: true\n        gh-pages-branch: benches\n\n    # Add bench mark files to the gh-pages branch\n    - name: Add benchmark files to gh-pages\n      working-directory: ${{runner.workspace}}/floris/\n      run: |\n        ls -lah\n        git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n        git config --global user.name \"github-actions[bot]\"\n        git fetch origin benches\n        git checkout benches\n        rsync -av dev/bench /tmp/bench\n        git fetch origin gh-pages\n        git checkout gh-pages\n        mkdir -p dev\n        rsync -av /tmp/bench/ dev/\n        ls -lah dev/bench\n        git add dev\n        git commit -m \"Add bench folder to gh-pages\"\n        git push origin gh-pages\n"
  },
  {
    "path": ".github/workflows/python-publish.yml",
    "content": "# This workflows will upload a Python Package using Twine when a release is created\n# Published via GitHub Actions as a PyPI Trusted Publisher.\n# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries\n# and: https://docs.pypi.org/trusted-publishers/\n\nname: Upload Python Package\n\non:\n  release:\n    types: [published]\n\njobs:\n  deploy:\n    environment: release-pypi\n    if: github.repository_owner == 'NatLabRockies'\n    runs-on: ubuntu-latest\n    permissions:\n      id-token: write\n    steps:\n      - uses: actions/checkout@v6\n      - name: Set up Python\n        uses: actions/setup-python@v6\n        with:\n          python-version: '3.x'\n      - name: Install dependencies and build package\n        run: |\n          python -m pip install --upgrade pip\n          pip install build twine\n          python -m build\n          twine check --strict dist/*\n      - name: Publish package to PyPI\n        uses: pypa/gh-action-pypi-publish@release/v1\n        with:\n          verbose: True\n"
  },
  {
    "path": ".github/workflows/quality-metrics-workflow.yaml",
    "content": "name: Code Quality Check\n\non: [push, pull_request]\n\njobs:\n\n  code-qa-validation:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        python-version: [\"3.13\"]\n        os: [ubuntu-latest]\n      fail-fast: False\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v4\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Install project\n      run: |\n        python -m pip install --upgrade pip\n        pip install \".[develop]\"\n    - name: Run the code quality script\n      run: |\n        cd profiling\n        python quality_metrics.py\n"
  },
  {
    "path": ".gitignore",
    "content": "\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_cache\n\n# pip meta data\npip-wheel-metadata\n\n# macOS files\n.DS_Store\n\n# IDE settings and files\n.idea\n.vscode\n\n# Documentation notebooks\n!docs/*.ipynb\n\n# The examples folder within docs\ndocs/examples\n\n# Documentation output\n_site/\n.jekyll-cache/\n_build\n_autosummary/\n\n# Output from examples\nexamples/cp_ct_cq_lut.p\nexamples/hist.hist\nexamples/SLSQP.out\n\n# Log files\n*.log\n\n# Temp files in convert test\ntests/v3_to_v4_convert_test/convert_turbine_v3_to_v4.py\ntests/v3_to_v4_convert_test/convert_floris_input_v3_to_v4.py\ntests/v3_to_v4_convert_test/gch_v4.yaml\ntests/v3_to_v4_convert_test/nrel_5MW_v3_v4.yaml\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "\nrepos:\n\n- repo: https://github.com/pre-commit/pre-commit-hooks\n  rev: v4.4.0\n  hooks:\n  - id: trailing-whitespace\n  - id: end-of-file-fixer\n  - id: check-executables-have-shebangs\n  - id: check-yaml\n    args: [--unsafe]\n  - id: check-merge-conflict\n  - id: check-symlinks\n  - id: mixed-line-ending\n\n- repo: https://github.com/charliermarsh/ruff-pre-commit\n  rev: v0.9.6\n  hooks:\n  - id: ruff\n\n- repo: https://github.com/timothycrosley/isort\n  rev: 5.12.0\n  hooks:\n  - id: isort\n    name: isort\n    stages: [commit]\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to FLORIS\n\nFLORIS is a community model, and we are excited for community contributions!\nThere are a variety of ways in which you can contribute beyond writing code.\nThis document provides a high-level overview of how you can get involved.\n\n\n## Asking Questions\n\nHave a question? Rather than opening an issue directly, please ask questions\nor post comments in [Q&A Discussions](https://github.com/NatLabRockies/floris/discussions/categories/q-a).\nThe NLR team or other members of the community will assist. Your well-worded\nquestion will serve as a resource to others searching for help.\n\n\n## Providing Feedback\n\nYour comments and feedback are very welcome. Please post to\n[General Discussions](https://github.com/NatLabRockies/floris/discussions/categories/general)\nwith lots of information and detail. It is beneficial to consider\nhow someone else will understand your comments in order to make\nthem most effective.\n\n\n## Reporting Issues\n\nHave you identified a reproducible problem in FLORIS?\nHave a feature request? We want to hear about it! Here's how you can make\nreporting your issue as effective as possible.\n\n### Look For an Existing Issue\n\nBefore you create a new issue, please do a search in\n[open issues](https://github.com/microsoft/vscode/issues) to see if\nthe issue or feature request has already been filed.\n\nIf you find your issue already exists, make relevant comments and add your\n[reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments).\nUse a reaction in place of a \"+1\" comment:\n\n- 👍 - upvote\n- 👎 - downvote\n\nIf you cannot find an existing issue that describes your bug or feature,\ncreate a new issue using the guidelines below.\n\n### Writing Good Bug Reports and Feature Requests\n\nFile a single issue per problem and feature request. Do not enumerate\nmultiple bugs or feature requests in the same issue.\n\nDo not add your issue as a comment to an existing issue unless it's for the\nidentical input. Many issues look similar, but have different causes.\n\nThe more information you can provide, the more likely someone will\nbe successful at reproducing the issue and finding a fix.\n\nPlease follow the issue template guidelines to include relevant information\nthat will help in diagnosing the problem.\n\n### Final Checklist\n\nPlease remember to do the following:\n\n- [ ] Search the issue repository to ensure your report is a new issue\n\n- [ ] Recreate the issue with a minimally descriptive example\n\n- [ ] Simplify your code around the issue to better isolate the problem\n\n\n## Contributing Fixes\n\nIf you are interested in writing code to fix an issue or\nsubmit a new feature, let us know in\n[Ideas Discussions](https://github.com/NatLabRockies/floris/discussions/categories/ideas)!\n\nWe rely heavily on git and GitHub, so be sure to review the\ncontributing guidelines in the\n[online documentation](https://natlabrockies.github.io/floris/dev_guide.html).\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2025, Alliance for Energy Innovation LLC, All rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted\nprovided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions\nand the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice, this list of\nconditions and the following disclaimer in the documentation and/or other materials provided\nwith the distribution.\n\n* Neither the name of the copyright holder nor the names of its contributors may be used to\nendorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\nOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# FLORIS Wake Modeling and Wind Farm Controls Software\n\nFLORIS is a controls-focused wind farm simulation software incorporating\nsteady-state engineering wake models into a performance-focused Python\nframework. It has been in active development at NLR since 2013 and the latest\nrelease is [FLORIS v.4.6.4](https://github.com/NatLabRockies/floris/releases/latest).\nOnline documentation is available at https://natlabrockies.github.io/floris.\n\nThe software is in active development and engagement with the development team\nis highly encouraged. If you are interested in using FLORIS to conduct studies\nof a wind farm or extending FLORIS to include your own wake model, please join\nthe conversation in [GitHub Discussions](https://github.com/NatLabRockies/floris/discussions/)!\n\n## WETO software\n\nFLORIS is primarily developed with the support from the U.S. Department of Energy and\nis part of the [WETO Software Stack](https://natlabrockies.github.io/WETOStack).\nFor more information and other integrated modeling software, see:\n\n- [Portfolio Overview](https://natlabrockies.github.io/WETOStack/portfolio_analysis/overview.html)\n- [Entry Guide](https://natlabrockies.github.io/WETOStack/_static/entry_guide/index.html)\n- [Wind Farm Controls Workshop](https://www.youtube.com/watch?v=f-w6whxIBrA&list=PL6ksUtsZI1dwRXeWFCmJT6cEN1xijsHJz)\n\n## Installation\n\n**If upgrading from a previous version, it is recommended to install FLORIS v4 into a new virtual environment**.\nIf you intend to use [pyOptSparse](https://mdolab-pyoptsparse.readthedocs-hosted.com/en/latest/) with FLORIS,\nit is recommended to install that package first before installing FLORIS.\n\nFLORIS can be installed by downloading the source code or via the PyPI\npackage manager with `pip`.\n\nThe simplest method is with `pip` by using this command:\n\n```bash\npip install floris\n```\n\nDevelopers and anyone who intends to inspect the source code\ncan install FLORIS by downloading the git repository\nfrom GitHub with ``git`` and use ``pip`` to locally install it.\nIt is highly recommended to use a Python virtual environment manager\nsuch as [conda](https://docs.conda.io/en/latest/miniconda.html)\nin order to maintain a clean and sandboxed environment. The following\ncommands in a terminal or shell will download and install FLORIS.\n\n```bash\n    # Download the source code from the `main` branch\n    git clone -b main https://github.com/NatLabRockies/floris.git\n\n    # If using conda, be sure to activate your environment prior to installing\n    # conda activate <env name>\n\n    # If using pyOptSpare, install it first\n    conda install -c conda-forge pyoptsparse\n\n    # Install FLORIS\n    pip install -e floris\n```\n\nWith both methods, the installation can be verified by opening a Python interpreter\nand importing FLORIS:\n\n```python\n>>> import floris\n>>> help(floris)\n\nHelp on package floris:\n\nNAME\n    floris\n\nPACKAGE CONTENTS\n    convert_floris_input_v3_to_v4\n    convert_turbine_v3_to_v4\n    core (package)\n    cut_plane\n    floris_model\n    flow_visualization\n    layout_visualization\n    logging_manager\n    optimization (package)\n    parallel_floris_model\n    turbine_library (package)\n    type_dec\n    uncertain_floris_model\n    utilities\n    version\n    wind_data\n\nVERSION\n    4.6.4\n\nFILE\n    ~/floris/floris/__init__.py\n```\n\nIt is important to regularly check for new updates and releases as new\nfeatures, improvements, and bug fixes will be issued on an ongoing basis.\n\n## Quick Start\n\nFLORIS is a Python package run on the command line typically by providing\nan input file with an initial configuration. It can be installed with\n```pip install floris``` (see [installation](https://natlabrockies.github.io/floris/installation.html)).\nThe typical entry point is\n[FlorisModel](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html)\nwhich accepts the path to the input file as an argument. From there,\nchanges can be made to the initial configuration through the\n[FlorisModel.set](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.set)\nroutine, and the simulation is executed with\n[FlorisModel.run](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.run).\n\n```python\nfrom floris import FlorisModel\nfmodel = FlorisModel(\"path/to/input.yaml\")\nfmodel.set(\n    wind_directions=[i for i in range(10)],\n    wind_speeds=[8.0]*10,\n    turbulence_intensities=[0.06]*10\n)\nfmodel.run()\n```\n\nFinally, results can be analyzed via post-processing functions available within\n[FlorisModel](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel)\nsuch as\n- [FlorisModel.get_turbine_layout](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.get_turbine_layout)\n- [FlorisModel.get_turbine_powers](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.get_turbine_powers)\n- [FlorisModel.get_farm_AEP](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.get_farm_AEP)\n\nand 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).\nA collection of examples describing the creation of simulations as well as\nanalysis and post processing are included in the\n[repository](https://github.com/NatLabRockies/floris/tree/main/examples). Examples are also listed\nin the [online documentation](https://natlabrockies.github.io/floris/examples/001_opening_floris_computing_power.html).\n\n## Engaging on GitHub\n\nFLORIS leverages the following GitHub features to coordinate support and development efforts:\n\n- [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\n- [Issues](https://github.com/NatLabRockies/floris/issues): Report potential bugs and well-developed feature requests\n- [Projects](https://github.com/orgs/NREL/projects/96): Include current and future work on a timeline and assign a person to \"own\" it\n\nGenerally, the first entry point for the community will be within one of the\ncategories in Discussions.\n[Ideas](https://github.com/NatLabRockies/floris/discussions/categories/ideas) is a great spot to develop the\ndetails for a feature request. [Q&A](https://github.com/NatLabRockies/floris/discussions/categories/q-a)\nis where to get usage support.\n[Show and tell](https://github.com/NatLabRockies/floris/discussions/categories/show-and-tell) is a free-form\nspace to show off the things you are doing with FLORIS.\n\n\n# License\n\nBSD 3-Clause License\n\nCopyright (c) 2025, Alliance for Energy Innovation LLC, All rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted\nprovided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions\nand the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice, this list of\nconditions and the following disclaimer in the documentation and/or other materials provided\nwith the distribution.\n\n* Neither the name of the copyright holder nor the names of its contributors may be used to\nendorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\nOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "benchmarks/bench.py",
    "content": "from pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n)\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT\nfrom floris.heterogeneous_map import HeterogeneousMap\n\n\nN_Conditions = 100\n\n# These tests are run automatically by pytest-benchmark.  The benchmark\n# object is passed to the test function.\n\ndef test_timing_small_farm_set(benchmark):\n    \"\"\"Timing test for setting up a small farm\"\"\"\n    fmodel = FlorisModel(configuration=\"defaults\")\n    wind_directions = np.linspace(0, 360, N_Conditions)\n    wind_speeds = np.ones(N_Conditions) * 8\n    turbulence_intensities = np.ones(N_Conditions) * 0.06\n\n    benchmark(\n        fmodel.set,\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=np.linspace(0, 1000, 3),\n        layout_y=np.linspace(0, 1000, 3),\n    )\n\n\ndef test_timing_small_farm_run(benchmark):\n    \"\"\"Timing test for running a small farm\"\"\"\n    fmodel = FlorisModel(configuration=\"defaults\")\n    wind_directions = np.linspace(0, 360, N_Conditions)\n    wind_speeds = np.ones(N_Conditions) * 8\n    turbulence_intensities = np.ones(N_Conditions) * 0.06\n\n    fmodel.set(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=np.linspace(0, 1000, 3),\n        layout_y=np.linspace(0, 1000, 3),\n    )\n\n    benchmark(fmodel.run)\n\n\ndef test_timing_large_farm_set(benchmark):\n    \"\"\"Timing test for setting up a large farm\"\"\"\n    fmodel = FlorisModel(configuration=\"defaults\")\n    wind_directions = np.linspace(0, 360, N_Conditions)\n    wind_speeds = np.ones(N_Conditions) * 8\n    turbulence_intensities = np.ones(N_Conditions) * 0.06\n\n    benchmark(\n        fmodel.set,\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=np.linspace(0, 10000, 100),\n        layout_y=np.linspace(0, 10000, 100),\n    )\n\n\ndef test_timing_large_farm_run(benchmark):\n    \"\"\"Timing test for running a large farm\"\"\"\n    fmodel = FlorisModel(configuration=\"defaults\")\n    wind_directions = np.linspace(0, 360, N_Conditions)\n    wind_speeds = np.ones(N_Conditions) * 8\n    turbulence_intensities = np.ones(N_Conditions) * 0.06\n\n    fmodel.set(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=np.linspace(0, 10000, 100),\n        layout_y=np.linspace(0, 10000, 100),\n    )\n\n    benchmark(fmodel.run)\n\n\ndef test_timing_het_set(benchmark):\n    \"\"\"Timing test for setting up a farm with a heterogeneous map\"\"\"\n\n    # The side of the flow which is accelerated reverses for east versus west\n    het_map = HeterogeneousMap(\n        x=np.array([0.0, 0.0, 500.0, 500.0]),\n        y=np.array([0.0, 500.0, 0.0, 500.0]),\n        speed_multipliers=np.array(\n            [\n                [1.0, 2.0, 1.0, 2.0],  # Top accelerated\n                [2.0, 1.0, 2.0, 1.0],  # Bottom accelerated\n            ]\n        ),\n        wind_directions=np.array([270.0, 90.0]),\n        wind_speeds=np.array([8.0, 8.0]),\n    )\n\n    # Get the FLORIS model\n    fmodel = FlorisModel(configuration=\"defaults\")\n\n    time_series = TimeSeries(\n        wind_directions=np.linspace(0, 360, N_Conditions),\n        wind_speeds=8.0,\n        turbulence_intensities=0.06,\n        heterogeneous_map=het_map,\n    )\n\n    # Set the model to a turbines perpendicular to\n    # east/west flow with 0 turbine closer to bottom and\n    # turbine 1 closer to top\n    benchmark(\n        fmodel.set,\n        wind_data=time_series,\n        layout_x=[250.0, 250.0],\n        layout_y=[100.0, 400.0],\n    )\n\n\ndef test_timing_het_run(benchmark):\n    \"\"\"Timing test for running a farm with a heterogeneous map\"\"\"\n\n    # The side of the flow which is accelerated reverses for east versus west\n    het_map = HeterogeneousMap(\n        x=np.array([0.0, 0.0, 500.0, 500.0]),\n        y=np.array([0.0, 500.0, 0.0, 500.0]),\n        speed_multipliers=np.array(\n            [\n                [1.0, 2.0, 1.0, 2.0],  # Top accelerated\n                [2.0, 1.0, 2.0, 1.0],  # Bottom accelerated\n            ]\n        ),\n        wind_directions=np.array([270.0, 90.0]),\n        wind_speeds=np.array([8.0, 8.0]),\n    )\n\n    # Get the FLORIS model\n    fmodel = FlorisModel(configuration=\"defaults\")\n\n    time_series = TimeSeries(\n        wind_directions=np.linspace(0, 360, N_Conditions),\n        wind_speeds=8.0,\n        turbulence_intensities=0.06,\n        heterogeneous_map=het_map,\n    )\n\n    # Set the model to a turbines perpendicular to\n    # east/west flow with 0 turbine closer to bottom and\n    # turbine 1 closer to top\n    fmodel.set(\n        wind_data=time_series,\n        layout_x=[250.0, 250.0],\n        layout_y=[100.0, 400.0],\n    )\n\n    benchmark(fmodel.run)\n"
  },
  {
    "path": "docs/.nojekyll",
    "content": ""
  },
  {
    "path": "docs/_config.yml",
    "content": "# Book settings\n# Learn more at https://jupyterbook.org/customize/config.html\n\ntitle: FLORIS\nauthor: National Laboratory of the Rockies\nlogo: docs_image.png\ncopyright: '2025'\nonly_build_toc_files: false\n\n# Force re-execution of notebooks on each build.\n# See https://jupyterbook.org/content/execute.html\nexecute:\n  execute_notebooks: auto\n  timeout: 420 # Give each notebook cell 7 minutes to execute\n\n# Define the name of the latex output file for PDF builds\nlatex:\n  latex_documents:\n    targetname: book.tex\n\n# Add a bibtex file so that we can create citations\nbibtex_bibfiles:\n  - references.bib\n\n# Information about where the book exists on the web\nrepository:\n  url: https://github.com/NatLabRockies/floris\n  path_to_book: docs\n  branch: main\n\n# Add GitHub buttons to your book\n# See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository\nhtml:\n  use_issues_button: true\n  use_repository_button: true\n  use_edit_page_button: true\n  analytics:\n    google_analytics_id: G-JV2SK7CNPR\n\n\n# Sphinx for API doc generation\nsphinx:\n  extra_extensions:\n  - 'sphinx.ext.autodoc'\n  - 'sphinx.ext.autosummary'\n  - 'sphinx.ext.viewcode'\n  - 'sphinx_autodoc_typehints'\n  - 'sphinxcontrib.autoyaml'\n  - 'sphinxcontrib.mermaid'\n  config:\n    language: 'python'\n    nb_execution_show_tb: true          # Shows the stack trace in stdout; its suppressed otherwise.\n    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\n    suppress_warnings:\n    - etoc.toctree                      # autodoc output contains toctrees, so suppress this warning. See https://github.com/executablebooks/sphinx-external-toc/issues/36\n    autoyaml_level: 3\n    autosummary_generate: true\n\n    # Autodoc config reference\n    # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#configuration\n    autodoc_default_options:\n      members: true\n      member-order: bysource\n      undoc-members: true\n      private-members: false\n      # special-members: true\n      # inherited-members\n      # show-inheritance\n      # ignore-module-all\n      # imported-members: true\n      # exclude-members\n      # class-doc-from\n      # no-value\n    autodoc_typehints: both\n    mermaid_version: \"10.8\"\n"
  },
  {
    "path": "docs/_toc.yml",
    "content": "# Table of contents\n# Learn more at https://jupyterbook.org/customize/toc.html\n\nformat: jb-book\nroot: index\nparts:\n  - caption: Getting Started\n    chapters:\n    - file: installation\n    - file: v3_to_v4\n\n  - caption: User Reference\n    chapters:\n    - file: intro_concepts\n    - file: wind_data_user\n    - file: floris_models\n    - file: input_reference_main\n    - file: turbine_models\n      sections:\n      - file: input_reference_turbine\n      - file: operation_models_user\n      - file: floating_wind_turbine\n      - file: multidimensional_wind_turbine\n      - file: turbine_library\n    - file: advanced_concepts\n    - file: heterogeneous_map\n    - file: layout_optimization\n    - file: examples\n\n  - caption: Theory and Background\n    chapters:\n    - file: wake_models\n      sections:\n      - file: empirical_gauss_model\n    - file: bibliography\n\n  - caption: Developer Reference\n    chapters:\n    - file: dev_guide\n    - file: architecture\n    - file: code_quality\n    - file: api_docs\n"
  },
  {
    "path": "docs/advanced_concepts.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"(concepts_advanced)=\\n\",\n    \"\\n\",\n    \"# Advanced Concepts\\n\",\n    \"\\n\",\n    \"More information regarding the numerical and computational formulation in FLORIS\\n\",\n    \"are detailed here. See [Introductory Concepts](intro_concepts) for a guide on the basics.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Create a basic FLORIS model for use later\\n\",\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"from floris import FlorisModel\\n\",\n    \"fmodel = FlorisModel(\\\"gch.yaml\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Data structures\\n\",\n    \"\\n\",\n    \"FLORIS adopts a structures of arrays data modeling paradigm (SoA, relative to array of structures {AoS})\\n\",\n    \"for nearly all of the data in the `floris.core` package.\\n\",\n    \"This data model enables vectorization (SIMD operations) through Numpy array broadcasting\\n\",\n    \"for many operations.\\n\",\n    \"In general, there are two types of array shapes:\\n\",\n    \"- Field quantities have points throughout the computational domain but in context-specific locations\\n\",\n    \"    and have the shape `(n findex, n turbines, n grid, n grid)`.\\n\",\n    \"- Scalar quantities have a single value for each turbine and typically have the shape\\n\",\n    \"    `(n findex, n turbines, 1, 1)`. For scalar quanities, the arrays\\n\",\n    \"    may be created with the shape `(n findex, n turbines)` and\\n\",\n    \"    then expanded to the 4-dimensional shape prior to running the wake calculation.\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Grids\\n\",\n    \"\\n\",\n    \"FLORIS includes a number of grid-types that create sampling points within the computational\\n\",\n    \"domain for different contexts. In the typical use case, AEP or some other metric of wind\\n\",\n    \"farm energy yield is the end result. Since the mathematical models in FLORIS are all\\n\",\n    \"analytical, we only need to create points on the turbines themselves in order to calculate\\n\",\n    \"the incoming wind speeds given all of the upstream conditions. In this case, we use\\n\",\n    \"the {py:meth}`floris.core.grid.TurbineGrid` or {py:meth}`floris.core.grid.TurbineCubatureGrid`.\\n\",\n    \"Each of these grid-types put points only on the turbine swept area, so all other\\n\",\n    \"field-quantities in FLORIS have the same shape.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Plot the grid point locations for TurbineGrid and TurbineCubatureGrid\\n\",\n    \"\\n\",\n    \"fmodel.set(layout_x=[0.0], layout_y=[0.0])\\n\",\n    \"rotor_radius = fmodel.core.farm.rotor_diameters[0] / 2.0\\n\",\n    \"hub_height = fmodel.core.farm.hub_heights[0]\\n\",\n    \"theta = np.linspace(0, 2*np.pi, 100)\\n\",\n    \"circlex = rotor_radius * np.cos(theta)\\n\",\n    \"circley = rotor_radius * np.sin(theta) + hub_height\\n\",\n    \"\\n\",\n    \"# TurbineGrid is the default\\n\",\n    \"fig, ax = plt.subplots()\\n\",\n    \"ax.scatter(0, hub_height, marker=\\\"+\\\", color=\\\"r\\\")\\n\",\n    \"ax.scatter(fmodel.core.grid.y_sorted[0,0], fmodel.core.grid.z_sorted[0,0], marker=\\\"+\\\", color=\\\"r\\\")\\n\",\n    \"ax.plot(circlex, circley)\\n\",\n    \"ax.set_aspect('equal', 'box')\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## FLORIS as a library\\n\",\n    \"\\n\",\n    \"FLORIS is commonly used as a library in other software packages.\\n\",\n    \"In cases where the calling-code will create inputs for FLORIS rather than require them from the\\n\",\n    \"user, it can be helpful to initialize the FLORIS model with default inputs and then\\n\",\n    \"change them in code.\\n\",\n    \"In this case, the following workflow is recommended.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import floris\\n\",\n    \"\\n\",\n    \"# Initialize FLORIS with defaults\\n\",\n    \"fmodel = floris.FlorisModel(\\\"defaults\\\")\\n\",\n    \"\\n\",\n    \"# Within the calling-code's setup step, update FLORIS as needed\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_directions=[i for i in range(10)],\\n\",\n    \"    wind_speeds=[5 + i for i in range(10)],\\n\",\n    \"    turbulence_intensities=[i for i in range(10)],\\n\",\n    \"    # turbine_library_path=\\\"path/to/turbine_library\\\",   # Shown here for reference\\n\",\n    \"    # turbine_type=[\\\"my_turbine\\\"]\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Within the calling code's computation, run FLORIS\\n\",\n    \"fmodel.run()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Alternatively, the calling-code can import the FLORIS default inputs as a Python dictionary\\n\",\n    \"and modify them directly before initializing the FLORIS model.\\n\",\n    \"This is especially helpful when the calling-code will modify a parameter that isn't\\n\",\n    \"supported by the `FlorisModel.set(...)` command.\\n\",\n    \"In particular, the wake model parameters are not directly accessible, so these can be updated\\n\",\n    \"externally, as shown below.\\n\",\n    \"Note that the `FlorisModel.get_defaults()` function returns a deep copy of the default inputs,\\n\",\n    \"so these can be modified directly without side effects.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"solver\\n\",\n      \"    type\\n\",\n      \"        turbine_grid\\n\",\n      \"    turbine_grid_points\\n\",\n      \"        3\\n\",\n      \"wake\\n\",\n      \"    model_strings\\n\",\n      \"        combination_model\\n\",\n      \"            sosfs\\n\",\n      \"        deflection_model\\n\",\n      \"            gauss\\n\",\n      \"        turbulence_model\\n\",\n      \"            crespo_hernandez\\n\",\n      \"        velocity_model\\n\",\n      \"            jensen\\n\",\n      \"farm\\n\",\n      \"    layout_x\\n\",\n      \"        [0.0]\\n\",\n      \"    layout_y\\n\",\n      \"        [0.0]\\n\",\n      \"    turbine_type\\n\",\n      \"        ['nrel_5MW']\\n\",\n      \"    turbine_library_path\\n\",\n      \"        /Users/rmudafor/Development/floris/floris/turbine_library\\n\",\n      \"flow_field\\n\",\n      \"    wind_speeds\\n\",\n      \"        [5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0]\\n\",\n      \"    wind_directions\\n\",\n      \"        [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]\\n\",\n      \"    wind_veer\\n\",\n      \"        0.0\\n\",\n      \"    wind_shear\\n\",\n      \"        0.12\\n\",\n      \"    air_density\\n\",\n      \"        1.225\\n\",\n      \"    turbulence_intensities\\n\",\n      \"        [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]\\n\",\n      \"    reference_wind_height\\n\",\n      \"        90.0\\n\",\n      \"name\\n\",\n      \"    GCH\\n\",\n      \"description\\n\",\n      \"    Default initialization: Gauss-Curl hybrid model (GCH)\\n\",\n      \"floris_version\\n\",\n      \"    v4\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"import floris\\n\",\n    \"\\n\",\n    \"# Retrieve the default parameters\\n\",\n    \"fdefaults = floris.FlorisModel.get_defaults()\\n\",\n    \"\\n\",\n    \"# Update wake model parameters\\n\",\n    \"fdefaults[\\\"wake\\\"][\\\"model_strings\\\"][\\\"velocity_model\\\"] = \\\"jensen\\\"\\n\",\n    \"fdefaults[\\\"wake\\\"][\\\"wake_velocity_parameters\\\"][\\\"jensen\\\"][\\\"we\\\"] = 0.05\\n\",\n    \"\\n\",\n    \"# Initialize FLORIS with modified parameters\\n\",\n    \"fmodel = floris.FlorisModel(configuration=fdefaults)\\n\",\n    \"\\n\",\n    \"# Within the calling-code's setup step, update FLORIS as needed\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_directions=[i for i in range(10)],\\n\",\n    \"    wind_speeds=[5 + i for i in range(10)],\\n\",\n    \"    turbulence_intensities=[i for i in range(10)],\\n\",\n    \"    # turbine_library_path=\\\"path/to/turbine_library\\\",   # Shown here for reference\\n\",\n    \"    # turbine_type=[\\\"my_turbine\\\"]\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Verify settings are correct\\n\",\n    \"fmodel.show_config()  # Shows truncated set of inputs; show all with fmodel.show_config(full=True)\\n\",\n    \"\\n\",\n    \"# Within the calling code's computation, run FLORIS\\n\",\n    \"fmodel.run()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"floris\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.12.1\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"
  },
  {
    "path": "docs/api_docs.md",
    "content": "# API Documentation\n\nFLORIS is primarily divided into the {py:mod}`floris` package, which contains the user-level API,\nand {py:mod}`floris.core` is the core code that models the wind turbines and wind farms.\nAdditionally, the {py:mod}`turbine_library` package contains turbine models that ship with FLORIS;\nand the {py:mod}`optimization` package contains high-level optimization routines that accept and\nwork on instantiated `FlorisModel` objects.\n\n```{eval-rst}\n.. autosummary::\n   :toctree: _autosummary\n   :recursive:\n\n   floris.flow_visualization\n   floris.floris_model\n   floris.wind_data\n   floris.uncertain_floris_model\n   floris.turbine_library\n   floris.parallel_floris_model\n   floris.optimization\n   floris.layout_visualization\n   floris.cut_plane\n   floris.core\n   floris.convert_turbine_v3_to_v4\n   floris.convert_floris_input_v3_to_v4\n   floris.utilities\n   floris.type_dec\n   floris.logging_manager\n```\n"
  },
  {
    "path": "docs/architecture.md",
    "content": "\n# Architecture and Design\n\nAt the outset of the design of the FLORIS software, a few fundamental ideas were identified\nthat should continue to guide future design decisions. These characteristics should never\nbe violated, and ongoing work should strive to meet these ideas and expand on them as much\nas possible.\n\n- Modularity in wake model formulation:\n    - New mathematical formulation should be straightforward to incorporate by non-expert\n        software developers.\n    - Solver and grid data structures for one wake model should not conflict with the data\n        structures for other wake models.\n- Any new feature or work should not affect an existing feature:\n    - Low level code should be reused as much as possible, but high level code should rarely\n        be repurposed.\n    - It is expected that a new feature will include a new user entry point\n        at the highest level.\n    - Avoid flags and if-statements that allow using one high-level routine for multiple unrelated\n        tasks.\n    - When in doubt, create a new pipeline from the user-level API to the low level implementation\n        and refactor to consolidate, if necessary, afterwards.\n- Management of abstraction:\n    - Low level code is opaque but well tested and exercised; it should be very computationally\n        efficient with low algorithmic complexity.\n    - High level code should be expressive and clear even if it results in verbose or less\n        efficient code.\n\nThe FLORIS software consists of two primary high-level packages and a few other low level\npackages. The internal structure and hierarchy is described below.\n\n```{mermaid}\nclassDiagram\n\n    class core[\"floris.core\"] {\n        +Core\n    }\n\n    class floris[\"floris\"] {\n        +FlorisModel\n    }\n\n    class logging_manager\n    class type_dec\n    class utilities\n\n    tools <-- logging_manager\n    simulation <-- logging_manager\n    simulation <-- type_dec\n    simulation <-- utilities\n    tools <-- simulation\n```\n\n## floris\n\nThis is the user interface. Most operations at the user level will happen through `floris`.\nThis package contains a wide variety of functionality including but not limited to:\n\n- Initializing and driving a simulation with `floris_model`\n- Wake field visualization through `flow_visualization`\n- Yaw and layout optimization in `optimization`\n- Wind data handling in `wind_data`\n\n## floris.core\n\nThis is the core simulation package. This should primarily be used within `floris.core` and\n`floris`, and user scripts generally won't interact directly with this package.\n\n```{mermaid}\nclassDiagram\n\n    class Core\n\n    class Farm\n\n    class FlowField {\n        u: NDArrayFloat\n        v: NDArrayFloat\n        w: NDArrayFloat\n    }\n\n    class Grid {\n        <<interface>>\n        x: NDArrayFloat\n        y: NDArrayFloat\n        z: NDArrayFloat\n    }\n    class TurbineGrid\n    class TurbineCubatureGrid\n    class FlowFieldPlanarGrid\n    class PointsGrid\n\n    class WakeModelManager {\n        <<interface>>\n    }\n    class WakeCombination {\n        parameters: dict\n        function()\n    }\n    class WakeDeflection {\n        parameters: dict\n        function()\n    }\n    class WakeTurbulence {\n        parameters: dict\n        function()\n    }\n    class WakeVelocity {\n        parameters: dict\n        function()\n    }\n\n    class Solver {\n        <<interface>>\n        parameters: dict\n    }\n\n    Core *-- Farm\n    Core *-- FlowField\n    Core *-- Grid\n    Core *-- WakeModelManager\n    Core --> Solver\n    WakeModelManager *-- WakeCombination\n    WakeModelManager *-- WakeDeflection\n    WakeModelManager *-- WakeTurbulence\n    WakeModelManager *-- WakeVelocity\n\n    Grid <|-- TurbineGrid\n    Grid <|-- TurbineCubatureGrid\n    Grid <|-- FlowFieldPlanarGrid\n    Grid <|-- PointsGrid\n\n    Solver --> Farm\n    Solver --> FlowField\n    Solver --> Grid\n    Solver --> WakeModelManager\n```\n"
  },
  {
    "path": "docs/bibliography.md",
    "content": "\n# Bibliography\n\n```{bibliography}\n:style: unsrt\n```\n"
  },
  {
    "path": "docs/code_quality.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Code Quality\\n\",\n    \"\\n\",\n    \"This page contains information on various code quality metrics\\n\",\n    \"that are collected during the development cycle. Some of these\\n\",\n    \"are autogenerated while others rely on manual scripts and updating\\n\",\n    \"the documentation, so these will be updating as needed and when\\n\",\n    \"appropriate. All plots show the corresponding commit hash\\n\",\n    \"when hovering over a point with the mouse pointer.\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Live Code Quality Metrics\\n\",\n    \"\\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\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Performance History\\n\",\n    \"\\n\",\n    \"The plot below shows the runtime performance over a series of commits for a\\n\",\n    \"3-turbine test case with 1,440 atmospheric conditions.\\n\",\n    \"This data is collected on [NLR's Kestrel supercomputer](https://nrel.github.io/HPC/Documentation/Systems/Kestrel/).\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {\n    \"tags\": [\n     \"hide-cell\"\n    ]\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stderr\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"/var/folders/yp/vdv3q8mn4xj1_m277lk54s75tvdqcf/T/ipykernel_74430/1348870237.py:3: DeprecationWarning: \\n\",\n      \"Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0),\\n\",\n      \"(to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries)\\n\",\n      \"but was not found to be installed on your system.\\n\",\n      \"If this would cause problems for you,\\n\",\n      \"please provide us feedback at https://github.com/pandas-dev/pandas/issues/54466\\n\",\n      \"        \\n\",\n      \"  import pandas as pd\\n\"\n     ]\n    },\n    {\n     \"data\": {\n      \"text/html\": [\n       \"    <style>\\n\",\n       \"        .bk-notebook-logo {\\n\",\n       \"            display: block;\\n\",\n       \"            width: 20px;\\n\",\n       \"            height: 20px;\\n\",\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       \"        }\\n\",\n       \"    </style>\\n\",\n       \"    <div>\\n\",\n       \"        <a href=\\\"https://bokeh.org\\\" target=\\\"_blank\\\" class=\\\"bk-notebook-logo\\\"></a>\\n\",\n       \"        <span id=\\\"a67e122f-6aa9-4ff8-97f7-6378dc8e5a11\\\">Loading BokehJS ...</span>\\n\",\n       \"    </div>\\n\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    },\n    {\n     \"data\": {\n      \"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));\",\n      \"application/vnd.bokehjs_load.v0+json\": \"\"\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"from bokeh.plotting import figure, show, output_notebook\\n\",\n    \"from bokeh.models import ColumnDataSource, HoverTool, Range1d\\n\",\n    \"import pandas as pd\\n\",\n    \"from datetime import datetime\\n\",\n    \"\\n\",\n    \"output_notebook()\\n\",\n    \"\\n\",\n    \"COLORS = ['blue', 'green', 'red', 'cyan', 'magenta', 'y', 'k']\\n\",\n    \"\\n\",\n    \"columns = [\\\"commit_hash\\\", \\\"commit_hash_8char\\\", \\\"date\\\", \\\"jensen\\\", \\\"gauss\\\", \\\"gch\\\", \\\"cc\\\", \\\"emgauss\\\", \\\"tooltip_label\\\"]\\n\",\n    \"data = [\\n\",\n    \"    (\\\"df25a9cfacd3d652361d2bd37f568af00acb2631\\\", \\\"df25a9cf\\\", datetime(2021, 12, 29), 1.2691, 1.2584, 1.6432,   None,   None, \\\"df25a9cf\\\"),\\n\",\n    \"    (\\\"b797390a43298a815f3ff57955cfdc71ecf3e866\\\", \\\"b797390a\\\", datetime(2022,  1,  3), 0.6867, 1.2354, 1.8026,   None,   None, \\\"b797390a\\\"),\\n\",\n    \"    (\\\"01a02d5f91b2f4a863eebe88a618974b0749d1c4\\\", \\\"01a02d5f\\\", datetime(2022,  1,  4), 0.2329, 0.5661, 0.9869,   None,   None, \\\"01a02d5f\\\"),\\n\",\n    \"    (\\\"dd847210082035d43b0273ae63a76a53cb8d2e12\\\", \\\"dd847210\\\", datetime(2022,  1,  6), 0.2290, 0.5815, 0.9822,   None,   None, \\\"dd847210\\\"),\\n\",\n    \"    (\\\"33779269e98cc882a5f066c462d8ec1eadf37a1a\\\", \\\"33779269\\\", datetime(2022,  1, 10), 0.2300, 0.5845, 1.0114,   None,   None, \\\"33779269\\\"),\\n\",\n    \"    (\\\"12890e029a7155b074b9b325d320d1798338e287\\\", \\\"12890e02\\\", datetime(2022,  1, 11), 0.2296, 0.5660, 1.0114,   None,   None, \\\"12890e02\\\"),\\n\",\n    \"    (\\\"66dafc08bd620d96deda7d526b0e4bfc3b086650\\\", \\\"66dafc08\\\", datetime(2022,  1, 12), 0.2342, 0.5937, 1.0284,   None,   None, \\\"66dafc08\\\"),\\n\",\n    \"    (\\\"a325819b3b03b84bd76ad455e3f9b4600744ba14\\\", \\\"a325819b\\\", datetime(2022,  1, 13), 0.2349, 0.5711, 1.0072,   None,   None, \\\"a325819b\\\"),\\n\",\n    \"    (\\\"8a2c1a610295c007f0222ce737723c341189811d\\\", \\\"8a2c1a61\\\", datetime(2022,  1, 14), 0.2338, 0.5837, 1.0242,   None,   None, \\\"8a2c1a61\\\"),\\n\",\n    \"    (\\\"c6bc79b0cfbc8ce5d6da0d33b68028157d2e93c0\\\", \\\"c6bc79b0\\\", datetime(2022,  1, 14), 0.2374, 0.5653, 0.9781,   None,   None, \\\"c6bc79b0\\\"),\\n\",\n    \"    (\\\"03e1f461c152e4f221fe92c834f2787680cf5772\\\", \\\"03e1f461\\\", datetime(2022,  1, 18), 0.2423, 0.5820, 1.0411, 1.2251,   None, \\\"PR #56\\\"),\\n\",\n    \"    (\\\"9e96d6c412b64fe76a57e7de8af3b00c21d18348\\\", \\\"9e96d6c4\\\", datetime(2022,  1, 19), 0.2507, 0.5674, 1.0053, 1.1828,   None, \\\"v3.0rc1\\\"),\\n\",\n    \"    (\\\"2a98428f9c6fb9bb4302ae09809441bf3e7162b0\\\", \\\"2a98428f\\\", datetime(2022,  2, 15), 0.1662, 0.5699, 1.0081, 1.1906,   None, \\\"PR #317\\\"),\\n\",\n    \"    (\\\"9b4e85cf1b41ba7001aaba1a830b93e176f3dd43\\\", \\\"9b4e85cf\\\", datetime(2022,  3,  1), 0.1710, 0.6143, 1.0626, 1.2013,   None, \\\"v3.0\\\"),\\n\",\n    \"    (\\\"d18f4d263ecabf502242592f9d60815a07c7b89c\\\", \\\"d18f4d26\\\", datetime(2022,  3,  4), 0.1766, 0.6020, 1.0612, 1.2088,   None, \\\"v3.0.1\\\"),\\n\",\n    \"    (\\\"a23241bb9e45078e36a4662d48c9d3fe0c3316e4\\\", \\\"a23241bb\\\", datetime(2022,  4,  6), 0.1764, 0.6044, 1.0656, 1.2067,   None, \\\"v3.1\\\"),\\n\",\n    \"    (\\\"c2006b0011a5df036c306c15e75763ec492dafda\\\", \\\"c2006b00\\\", datetime(2022,  6, 22), 0.1801, 0.6082, 1.0603, 1.2025,   None, \\\"v3.1.1\\\"),\\n\",\n    \"    (\\\"0c2adf3e702b6427da946a6ba9dbedbea22738be\\\", \\\"0c2adf3e\\\", datetime(2022,  9, 16), 0.1753, 0.6202, 1.0486, 1.1962,   None, \\\"v3.2\\\"),\\n\",\n    \"    (\\\"39c466000b1874e06a6f58da9c30bb877fc8d4d2\\\", \\\"39c46600\\\", datetime(2022, 11, 20), 0.1738, 0.6140, 1.0498, 1.1783,   None, \\\"v3.2.1\\\"),\\n\",\n    \"    (\\\"8436fd78b002e5792f5d0dd1409332d171036d49\\\", \\\"8436fd78\\\", datetime(2023,  2,  8), 0.1980, 0.6334, 1.0631, 1.2009,   None, \\\"v3.2.2\\\"),\\n\",\n    \"    (\\\"07a45b66c5facfea06c40bd82e34040c97560640\\\", \\\"07a45b66\\\", datetime(2023,  2,  8), 0.1831, 0.6070, 1.0233, 1.1991,   None, \\\"07a45b66\\\"),\\n\",\n    \"    (\\\"1d84538c334a502c6ad7df48b8cc2309d6a6436d\\\", \\\"1d84538c\\\", datetime(2023,  2, 22), 0.1771, 0.6226, 1.0541, 1.2044,   None, \\\"1d84538c\\\"),\\n\",\n    \"    (\\\"4d528a3d6456621a382d409b5145a877b5414b88\\\", \\\"4d528a3d\\\", datetime(2023,  2, 23), 0.1768, 0.6026, 1.0366, 1.1958,   None, \\\"4d528a3d\\\"),\\n\",\n    \"    (\\\"8c637b36b66069b216cb94ae87d4c0a91e9b211e\\\", \\\"8c637b36\\\", datetime(2023,  2, 27), 0.2052, 0.6264, 1.0655, 1.2137,   None, \\\"8c637b36\\\"),\\n\",\n    \"    (\\\"4d23fa6dd78d0497deb4fd62783f0b3ee4204579\\\", \\\"4d23fa6d\\\", datetime(2023,  2, 27), 0.1996, 0.6083, 1.0465, 1.2184,   None, \\\"4d23fa6d\\\"),\\n\",\n    \"    (\\\"015f6874c320efee2c0d1ae76eea4a5b043d69d6\\\", \\\"015f6874\\\", datetime(2023,  3,  1), 0.2204, 0.6383, 1.0633, 1.2093,   None, \\\"015f6874\\\"),\\n\",\n    \"    (\\\"26f06d449da208ce64724b1463b07ad20746cbdc\\\", \\\"26f06d44\\\", datetime(2023,  3,  6), 0.1848, 0.6186, 1.0410, 1.2076,   None, \\\"26f06d44\\\"),\\n\",\n    \"    (\\\"6b9d6bb8bec6e3ea548f5858e2a8ea5986264fc8\\\", \\\"6b9d6bb8\\\", datetime(2023,  3,  6), 0.1946, 0.6247, 1.0742, 1.2250,   None, \\\"6b9d6bb8\\\"),\\n\",\n    \"    (\\\"b796bd0fd92ba6b91d590f6cb60bb7ab3bca9932\\\", \\\"b796bd0f\\\", datetime(2023,  3,  6), 0.2027, 0.6333, 1.0612, 1.2038,   None, \\\"b796bd0f\\\"),\\n\",\n    \"    (\\\"780aef7c7b4b9cafea3e323d536a34a4af5818b4\\\", \\\"780aef7c\\\", datetime(2023,  3,  7), 0.1922, 0.6292, 1.0494, 1.2125,   None, \\\"780aef7c\\\"),\\n\",\n    \"    (\\\"9f93ad9bf85e4a0e6baf5b62ea4b3ef143729861\\\", \\\"9f93ad9b\\\", datetime(2023,  3,  7), 0.2007, 0.6342, 1.0611, 1.2059,   None, \\\"9f93ad9b\\\"),\\n\",\n    \"    (\\\"16628a0ba45a675df762245694e0a7666a3478f8\\\", \\\"16628a0b\\\", datetime(2023,  3,  7), 0.2110, 0.6405, 1.0799, 1.2101,   None, \\\"v3.3\\\"),\\n\",\n    \"    (\\\"01684c8559604344bd09791268131819a09770a8\\\", \\\"01684c85\\\", datetime(2023,  3, 17), 0.2067, 0.6334, 1.0691, 1.1924,   None, \\\"01684c85\\\"),\\n\",\n    \"    (\\\"e9231fb893c765b723fa4c1e087a58761b6aa471\\\", \\\"e9231fb8\\\", datetime(2023,  3, 20), 0.2082, 0.6357, 1.0728, 1.2212,   None, \\\"e9231fb8\\\"),\\n\",\n    \"    (\\\"219889e243ffc69c71b6f7747f5af751d5694de1\\\", \\\"219889e2\\\", datetime(2023,  3, 23), 0.1912, 0.6182, 1.0651, 1.2033,   None, \\\"219889e2\\\"),\\n\",\n    \"    (\\\"6124d2a82a7a823722210bc2e8516d355ba19eb3\\\", \\\"6124d2a8\\\", datetime(2023,  4,  5), 0.2064, 0.6419, 1.0711, 1.1933,   None, \\\"6124d2a8\\\"),\\n\",\n    \"    (\\\"f6e4287f712cc866893e71b1ea7a7546e4567bf9\\\", \\\"f6e4287f\\\", datetime(2023,  4, 25), 0.1944, 0.6103, 1.0460, 1.2236,   None, \\\"f6e4287f\\\"),\\n\",\n    \"    (\\\"f2797fef396f2f19b02abb1f9555b678dac614f1\\\", \\\"f2797fef\\\", datetime(2023,  4, 25), 0.1997, 0.6357, 1.0648, 1.2128,   None, \\\"f2797fef\\\"),\\n\",\n    \"    (\\\"b4e538f530048fec58eaca5170be82c67dbdcceb\\\", \\\"b4e538f5\\\", datetime(2023,  4, 25), 0.2103, 0.6415, 1.0679, 1.2248,   None, \\\"b4e538f5\\\"),\\n\",\n    \"    (\\\"68820b715ed6b2c981aa11d29c0102e879280d79\\\", \\\"68820b71\\\", datetime(2023,  4, 25), 0.2076, 0.6354, 1.0625, 1.2018,   None, \\\"68820b71\\\"),\\n\",\n    \"    (\\\"03deffeda91fa8d8ab188d57b9fa302a7be008e0\\\", \\\"03deffed\\\", datetime(2023,  4, 25), 0.2138, 0.6453, 1.0738, 1.2148,   None, \\\"03deffed\\\"),\\n\",\n    \"    (\\\"0d2bfecc271d561f67050659684b4797af8ee740\\\", \\\"0d2bfecc\\\", datetime(2023,  4, 25), 0.2117, 0.6464, 1.0855, 1.2213,   None, \\\"0d2bfecc\\\"),\\n\",\n    \"    (\\\"1d03a465593f56c99a64a576d185d4ed17b659f2\\\", \\\"1d03a465\\\", datetime(2023,  4, 25), 0.2060, 0.6376, 1.0722, 1.2129,   None, \\\"1d03a465\\\"),\\n\",\n    \"    (\\\"78a953b7ef9a36b62e5b446c80ed68abfddbfb74\\\", \\\"78a953b7\\\", datetime(2023,  5,  4), 0.2170, 0.6323, 1.0673, 1.2116,   None, \\\"78a953b7\\\"),\\n\",\n    \"    (\\\"6c4f70ffbf3d4d2922d41d0032ae1b93d8a23c99\\\", \\\"6c4f70ff\\\", datetime(2023,  5,  4), 0.2123, 0.6407, 1.0688, 1.2183,   None, \\\"6c4f70ff\\\"),\\n\",\n    \"    (\\\"ab03282623d0262b20b8c132efcdcace2dace766\\\", \\\"ab032826\\\", datetime(2023,  5,  6), 0.1846, 0.6147, 1.0605, 1.2106,   None, \\\"ab032826\\\"),\\n\",\n    \"    (\\\"d2f7a45af27a6b40027d6f6a0f4f0be0c6dee5d9\\\", \\\"d2f7a45a\\\", datetime(2023,  5,  6), 0.1924, 0.6259, 1.0525, 1.1896,   None, \\\"d2f7a45a\\\"),\\n\",\n    \"    (\\\"98b23f3d517481b127f190f5f8b7ebfae7f8b6b2\\\", \\\"98b23f3d\\\", datetime(2023,  5,  6), 0.1940, 0.6177, 1.0524, 1.1916,   None, \\\"98b23f3d\\\"),\\n\",\n    \"    (\\\"452425de723cc1640d999022389672caf9bffbd0\\\", \\\"452425de\\\", datetime(2023,  5,  6), 0.2075, 0.6297, 1.0647, 1.2017,   None, \\\"452425de\\\"),\\n\",\n    \"    (\\\"85dadb1a566c9fa8dc84cb9837b98bd5d23b8d58\\\", \\\"85dadb1a\\\", datetime(2023,  5,  7), 0.1853, 0.6164, 1.0244, 1.1917,   None, \\\"85dadb1a\\\"),\\n\",\n    \"    (\\\"432ee7f96c1f6cccd05a0034c86c720cdb63a3e6\\\", \\\"432ee7f9\\\", datetime(2023,  5, 10), 0.1813, 0.6003, 1.0310, 1.1856,   None, \\\"432ee7f9\\\"),\\n\",\n    \"    (\\\"ebd70ecaef14c0e239337eb6e36506303378a31a\\\", \\\"ebd70eca\\\", datetime(2023,  5, 10), 0.1814, 0.6012, 1.0402, 1.2075, 0.3262, \\\"ebd70eca\\\"),\\n\",\n    \"    (\\\"77fa7155d55bdf3fd43e29f58fe57feffcb107cf\\\", \\\"77fa7155\\\", datetime(2023,  5, 11), 0.1763, 0.6095, 1.0507, 1.2181, 0.3431, \\\"77fa7155\\\"),\\n\",\n    \"    (\\\"d5d4b1346bd6acba9ba41b4bf546640de162a9d6\\\", \\\"d5d4b134\\\", datetime(2023,  5, 12), 0.1921, 0.6277, 1.0608, 1.2104, 0.3342, \\\"d5d4b134\\\"),\\n\",\n    \"    (\\\"d5d4b1346bd6acba9ba41b4bf546640de162a9d6\\\", \\\"d5d4b134\\\", datetime(2023,  5, 16), 0.1783, 0.6172, 1.0474, 1.1958, 0.3263, \\\"d5d4b134\\\"),\\n\",\n    \"    (\\\"7c879f1ce18b52d9b0a8eecf877d03e66afc975b\\\", \\\"7c879f1c\\\", datetime(2023,  5, 16), 0.1754, 0.5924, 1.0241, 1.1966, 0.3096, \\\"7c879f1c\\\"),\\n\",\n    \"    (\\\"2aa9f2a55686f2ee5dc407e8e0223eb25176d906\\\", \\\"2aa9f2a5\\\", datetime(2023,  5, 16), 0.1843, 0.6066, 1.0405, 1.1988, 0.3263, \\\"2aa9f2a5\\\"),\\n\",\n    \"    (\\\"5e5bb7f4e653621e7a81ff4bcaa27dbc1f759de7\\\", \\\"5e5bb7f4\\\", datetime(2023,  5, 16), 0.1911, 0.6197, 1.0425, 1.1792, 0.3426, \\\"v3.4\\\"),\\n\",\n    \"    (\\\"d91953a499dfb88b457a1e7a07903debbda4058b\\\", \\\"d91953a4\\\", datetime(2023,  6,  1), 0.1839, 0.6171, 1.0521, 1.1919, 0.3269, \\\"d91953a4\\\"),\\n\",\n    \"    (\\\"76742879c81c9baced49b9fc60abbf1d2eba65ff\\\", \\\"76742879\\\", datetime(2023,  7,  3), 0.1818, 0.6128, 1.0514, 1.1965, 0.3338, \\\"76742879\\\"),\\n\",\n    \"    (\\\"9c73a41eaca95bb718ac79980a1799dfa1c48cf3\\\", \\\"9c73a41e\\\", datetime(2023,  7,  6), 0.1795, 0.6011, 1.0335, 1.2146, 0.3142, \\\"9c73a41e\\\"),\\n\",\n    \"    (\\\"67104dd714de939be136646af68edd9643ddfcd3\\\", \\\"67104dd7\\\", datetime(2023,  7,  6), 0.1869, 0.5838, 0.7982, 0.9479, 0.3153, \\\"67104dd7\\\"),\\n\",\n    \"    (\\\"e6906feebdee6bdd2103f0bd390679e6a1b0052d\\\", \\\"e6906fee\\\", datetime(2023,  7,  7), 0.1751, 0.5780, 0.7820, 0.9452, 0.3136, \\\"e6906fee\\\"),\\n\",\n    \"    (\\\"8908ab47eaa8a3d7e7c9126484b524f751e41f55\\\", \\\"8908ab47\\\", datetime(2023,  7, 10), 0.1739, 0.5472, 0.7007, 0.8955, 0.3012, \\\"8908ab47\\\"),\\n\",\n    \"    (\\\"063d8b58464f95520c9887ac4f575e6c1f6880d8\\\", \\\"063d8b58\\\", datetime(2023,  7, 11), 0.1758, 0.5891, 0.7337, 0.8818, 0.3062, \\\"063d8b58\\\"),\\n\",\n    \"    (\\\"59e53a66aef134a3c9e912f9468ca667b599d4e5\\\", \\\"59e53a66\\\", datetime(2023,  7, 27), 0.1918, 0.6174, 1.0461, 1.1964, 0.3380, \\\"59e53a66\\\"),\\n\",\n    \"    (\\\"cd14608474be8561c188d2aa7a772b8ac753fb70\\\", \\\"cd146084\\\", datetime(2023,  8,  3), 0.1799, 0.5783, 0.7979, 0.9539, 0.3214, \\\"cd146084\\\"),\\n\",\n    \"    (\\\"db958c4b779ffc825689e052958020864cbcde63\\\", \\\"db958c4b\\\", datetime(2023,  8, 15), 0.1683, 0.5486, 0.7048, 0.8803, 0.2955, \\\"db958c4b\\\"),\\n\",\n    \"    (\\\"8ece0f5f7d3bfd66f4f83198debf5627344af534\\\", \\\"8ece0f5f\\\", datetime(2023,  8, 15), 0.1697, 0.5529, 0.7032, 0.8925, 0.2899, \\\"8ece0f5f\\\"),\\n\",\n    \"    (\\\"77ea50d9bd5d01f7110dbebf1ba689a25eee9d96\\\", \\\"77ea50d9\\\", datetime(2023,  9, 11), 0.1858, 0.5741, 0.7973, 0.9559, 0.3191, \\\"77ea50d9\\\"),\\n\",\n    \"    (\\\"05b900c228d427bfa8e531527b546cdeb822cfc9\\\", \\\"05b900c2\\\", datetime(2023, 10,  4), 0.1842, 0.5622, 0.7196, 0.8759, 0.2821, \\\"05b900c2\\\"),\\n\",\n    \"    (\\\"2dccbbd0ca67a274a2aeb9996f262014b3137fc0\\\", \\\"2dccbbd0\\\", datetime(2023, 10, 20), 0.1708, 0.5382, 0.6906, 0.8738, 0.2908, \\\"2dccbbd0\\\"),\\n\",\n    \"    (\\\"e9c90aa521917e587dd9497d529822f359eec3e2\\\", \\\"e9c90aa5\\\", datetime(2023, 10, 26), 0.1778, 0.5911, 0.7423, 0.8710, 0.2858, \\\"e9c90aa5\\\"),\\n\",\n    \"    (\\\"6c3ddb48b59d286899a8efd5989d741f86c4ade3\\\", \\\"6c3ddb48\\\", datetime(2023, 10, 26), 0.1700, 0.5585, 0.6991, 0.8823, 0.2887, \\\"6c3ddb48\\\"),\\n\",\n    \"    (\\\"31fe1b69ff863f0a610aec5b22424382ec3cc933\\\", \\\"31fe1b69\\\", datetime(2023, 10, 26), 0.1661, 0.5548, 0.7630, 0.9317, 0.2969, \\\"v3.5\\\"),\\n\",\n    \"    (\\\"a4768d08e172e009efb7ccafb8dc37a90753df7f\\\", \\\"a4768d08\\\", datetime(2023, 11,  8), 0.1725, 0.5768, 0.7635, 0.8827, 0.2990, \\\"a4768d08\\\"),\\n\",\n    \"    (\\\"1a2e86847d7942d9ecac20d91d2f4cd73685b230\\\", \\\"1a2e8684\\\", datetime(2023, 11, 15), 0.1764, 0.5933, 0.7970, 0.8984, 0.2972, \\\"1a2e8684\\\"),\\n\",\n    \"    (\\\"bc4fd2812636baba036d6f5648c6e77bcfb263e4\\\", \\\"bc4fd281\\\", datetime(2023, 11, 15), 0.1728, 0.5468, 0.7200, 0.8730, 0.2886, \\\"bc4fd281\\\"),\\n\",\n    \"    (\\\"34a7e0cd84226520f5a39cf3345699f012aad505\\\", \\\"34a7e0cd\\\", datetime(2023, 11, 28), 0.1697, 0.5541, 0.7179, 0.8844, 0.2929, \\\"34a7e0cd\\\"),\\n\",\n    \"    (\\\"e1dd6b73ae1d9552e0fe9679c0d35199c113d647\\\", \\\"e1dd6b73\\\", datetime(2023, 11, 30), 0.1715, 0.5709, 0.7846, 0.9334, 0.2871, \\\"e1dd6b73\\\"),\\n\",\n    \"    (\\\"599f2266ad55f73f4afaf80d4d1e32523a256d3b\\\", \\\"599f2266\\\", datetime(2023, 12,  1), 0.1892, 0.5930, 0.7877, 0.9125, 0.2928, \\\"599f2266\\\"),\\n\",\n    \"    (\\\"52b8a5f595f565b149a227b26bea7786d742f15c\\\", \\\"52b8a5f5\\\", datetime(2023, 12,  6), 0.1747, 0.5856, 0.7290, 0.8946, 0.2960, \\\"52b8a5f5\\\"),\\n\",\n    \"    (\\\"6f2256dab34c9d9548bd6d4d81594605d75434bd\\\", \\\"6f2256da\\\", datetime(2023, 12,  6), 0.1799, 0.5777, 0.7798, 0.9518, 0.3016, \\\"6f2256da\\\"),\\n\",\n    \"    (\\\"b6de318f12c93872daec8762edecb66d311504b5\\\", \\\"b6de318f\\\", datetime(2023, 12,  6), 0.1820, 0.5993, 0.8048, 0.9650, 0.3211, \\\"b6de318f\\\"),\\n\",\n    \"    (\\\"94357caf7092f6bfb6d8b51b9daf1ae9b47f26dc\\\", \\\"94357caf\\\", datetime(2023, 12,  7), 0.1731, 0.5623, 0.7093, 0.8866, 0.2924, \\\"94357caf\\\"),\\n\",\n    \"    (\\\"64ae6789f1860734ab4d6d34cd7c4313a85274fc\\\", \\\"64ae6789\\\", datetime(2023, 12,  8), 0.1701, 0.5625, 0.7113, 0.8901, 0.2897, \\\"64ae6789\\\"),\\n\",\n    \"    (\\\"da61128340ac0e520b4583eb759bf771512332f6\\\", \\\"da611283\\\", datetime(2023, 12, 13), 0.1713, 0.5603, 0.6923, 0.8770, 0.2882, \\\"da611283\\\"),\\n\",\n    \"    (\\\"bbcb8c33f4f35036c8156c57cea60fea5c5e17af\\\", \\\"bbcb8c33\\\", datetime(2023, 12, 13), 0.1748, 0.5769, 0.6966, 0.8766, 0.2840, \\\"bbcb8c33\\\"),\\n\",\n    \"    (\\\"ebdf9a146359606dc5e13363beee6dd82ad1c247\\\", \\\"ebdf9a14\\\", datetime(2023, 12, 13), 0.1782, 0.5622, 0.7108, 0.8755, 0.2895, \\\"ebdf9a14\\\"),\\n\",\n    \"    (\\\"b88dc7bb15370da91956ca24db3875245dc073d2\\\", \\\"b88dc7bb\\\", datetime(2024,  1,  4), 0.1836, 0.5699, 0.7204, 0.8891, 0.2957, \\\"b88dc7bb\\\"),\\n\",\n    \"    (\\\"a88a15432ef01f7600e3ccd7b9d2b4ba89a01df0\\\", \\\"a88a1543\\\", datetime(2024,  2,  7), 0.1922, 0.5925, 0.7759, 0.8914, 0.2937, \\\"a88a1543\\\"),\\n\",\n    \"    (\\\"c7f8f36178f35ccd8e08e0ce10a77fc487f78a14\\\", \\\"c7f8f361\\\", datetime(2024,  2, 20), 0.1801, 0.5775, 0.7097, 0.8755, 0.2907, \\\"c7f8f361\\\"),\\n\",\n    \"    (\\\"4b331398bc4a08edcd32539157cff2866f481875\\\", \\\"4b331398\\\", datetime(2024,  3, 19), 0.1810, 0.5678, 0.7276, 0.8805, 0.2958, \\\"4b331398\\\"),\\n\",\n    \"    (\\\"faba9890d5d07d9d8720464547602df1ff73124b\\\", \\\"faba9890\\\", datetime(2024,  3, 26), 0.1839, 0.5771, 0.7172, 0.8974, 0.2981, \\\"faba9890\\\"),\\n\",\n    \"    (\\\"3fba47f290480d1795f2d9f813179bc61844778b\\\", \\\"3fba47f2\\\", datetime(2024,  4,  5), 0.1963, 0.5967, 0.8054, 0.9267, 0.2930, \\\"3fba47f2\\\"),\\n\",\n    \"    (\\\"abc785646aff61557c7ed4c8850ea1117c65e8ea\\\", \\\"abc78564\\\", datetime(2024,  4,  5), 0.1878, 0.5878, 0.7231, 0.8906, 0.2978, \\\"abc78564\\\"),\\n\",\n    \"]\\n\",\n    \"\\n\",\n    \"df = pd.DataFrame(data=data, columns=columns)\\n\",\n    \"data_source = ColumnDataSource(df)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {\n    \"tags\": [\n     \"hide-input\"\n    ]\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/html\": [\n       \"\\n\",\n       \"  <div id=\\\"c5f00d44-6823-4878-a9b4-0b348e9bde1f\\\" data-root-id=\\\"p1005\\\" style=\\\"display: contents;\\\"></div>\\n\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    },\n    {\n     \"data\": {\n      \"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);\",\n      \"application/vnd.bokehjs_exec.v0+json\": \"\"\n     },\n     \"metadata\": {\n      \"application/vnd.bokehjs_exec.v0+json\": {\n       \"id\": \"p1005\"\n      }\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"## Run-time performance\\n\",\n    \"\\n\",\n    \"hover_tool = HoverTool(\\n\",\n    \"    tooltips=[\\n\",\n    \"        # (\\\"index\\\", \\\"$index\\\"),\\n\",\n    \"        (\\\"git ref\\\", \\\"@tooltip_label\\\"),\\n\",\n    \"        # (\\\"date\\\", \\\"@date\\\"),\\n\",\n    \"    ],\\n\",\n    \"    # formatters={\\n\",\n    \"    #     '@date': 'datetime',\\n\",\n    \"    # },\\n\",\n    \")\\n\",\n    \"p = figure(\\n\",\n    \"    title=\\\"5x5 Wind Farm Timing Test\\\",\\n\",\n    \"    x_axis_type=\\\"datetime\\\",\\n\",\n    \"    tooltips=hover_tool.tooltips,\\n\",\n    \"    width=600,\\n\",\n    \"    height=450\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"p.line(\\\"date\\\", \\\"jensen\\\", source=data_source, color=COLORS[0], legend_label=\\\"jensen\\\")\\n\",\n    \"p.scatter(\\\"date\\\", \\\"jensen\\\", source=data_source, line_color=COLORS[0], fill_color=COLORS[0], size=6, legend_label=\\\"jensen\\\")\\n\",\n    \"p.line(\\\"date\\\", \\\"gauss\\\", source=data_source, color=COLORS[1], legend_label=\\\"gauss\\\")\\n\",\n    \"p.scatter(\\\"date\\\", \\\"gauss\\\", source=data_source, line_color=COLORS[1], fill_color=COLORS[1], size=6, legend_label=\\\"gauss\\\")\\n\",\n    \"p.line(\\\"date\\\", \\\"gch\\\", source=data_source, color=COLORS[2], legend_label=\\\"gch\\\")\\n\",\n    \"p.scatter(\\\"date\\\", \\\"gch\\\", source=data_source, line_color=COLORS[2], fill_color=COLORS[2], size=6, legend_label=\\\"gch\\\")\\n\",\n    \"p.line(\\\"date\\\", \\\"cc\\\", source=data_source, color=COLORS[3], legend_label=\\\"cc\\\")\\n\",\n    \"p.scatter(\\\"date\\\", \\\"cc\\\", source=data_source, line_color=COLORS[3], fill_color=COLORS[3], size=6, legend_label=\\\"cc\\\")\\n\",\n    \"p.line(\\\"date\\\", \\\"emgauss\\\", source=data_source, color=COLORS[4], legend_label=\\\"cc\\\")\\n\",\n    \"p.scatter(\\\"date\\\", \\\"emgauss\\\", source=data_source, line_color=COLORS[4], fill_color=COLORS[4], size=6, legend_label=\\\"empirical gauss\\\")\\n\",\n    \"\\n\",\n    \"p.xaxis.axis_label = \\\"Commit date\\\"\\n\",\n    \"p.yaxis.axis_label = \\\"Time to solution (s)\\\"\\n\",\n    \"\\n\",\n    \"p.legend.location = \\\"bottom_left\\\"\\n\",\n    \"p.legend.click_policy=\\\"mute\\\"\\n\",\n    \"p.legend.border_line_width = 1\\n\",\n    \"p.legend.border_line_color = \\\"black\\\"\\n\",\n    \"p.legend.border_line_alpha = 0.5\\n\",\n    \"\\n\",\n    \"show(p)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"floris\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.13.2\"\n  },\n  \"orig_nbformat\": 4\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"
  },
  {
    "path": "docs/dev_guide.md",
    "content": "# Developer's Guide\n\nFLORIS is maintained by NLR.\nWe are excited about community contribution, and this page outlines\nprocesses and procedures to follow when contributing to the\nsource code. For technical questions regarding FLORIS usage, please\npost your questions to [GitHub Discussions](https://github.com/NatLabRockies/floris/discussions).\n\n## Getting Started\n\nThere are a few steps that nearly all contributors will need to go through to get started with\nmaking contributions to FLORIS. Each of these steps will be addressed in a later section of the\ndeveloper's guide, so please read on to learn more about each of these steps.\n\n1. Create a fork of FLORIS on GitHub\n2. Clone the repository\n\n    ```bash\n    git clone -b develop https://github.com/<your-GitHub-username>/floris.git\n    ```\n\n3. Move into the FLORIS source code directory\n\n    ```bash\n    cd floris/\n    ```\n\n4. Install FLORIS in editable mode with the appropriate developer tools\n\n   - ``\".[develop]\"`` is for the linting and code checking tools\n   - ``\".[docs]\"`` is for the documentation building tools. Ideally, developers should also be\n     contributing to the documentation, and therefore checking that the documentation builds locally.\n\n    ```bash\n    pip install -e \".[develop, docs]\"\n    ```\n5. Turn on the linting and code checking tools\n   ```bash\n   pre-commit install\n   ```\n\n## Git and GitHub Workflows\n\nThe majority of the collaboration and development for FLORIS takes place in\nthe [GitHub repository](http://github.com/NatLabRockies/floris). There,\n[issues](http://github.com/NatLabRockies/floris/issues) and\n[pull requests](http://github.com/NatLabRockies/floris/pulls) are managed,\nquestions and ideas are [discussed](https://github.com/NatLabRockies/floris/discussions),\nand [new versions](http://github.com/NatLabRockies/floris/releases)\nare released. It is the best mechanism for engaging with the NLR team\nand other developers throughout the FLORIS community.\n\nFLORIS development should follow \"Git Flow\" when interacting with the GitHub\nrepository. Git Flow is a git workflow outlining safe methods of pushing and\npulling commits to a shared repository. Maintaining this workflow is critical\nto prevent remote changes from blocking your local development. The Git Flow\nprocess is detailed nicely [here](http://nvie.com/posts/a-successful-git-branching-model).\n\n### Syncing a local repository with NREL/FLORIS\nThe \"main\" FLORIS repository is continuously updated along with ongoing\nresearch at NLR. From time to time, developers of FLORIS using their own\n\"local\" repositories (versions of the software that exist on a local computer)\nmay want to sync with NREL/FLORIS. To do this, use the following git commands:\n\n```bash\n# Move into the FLORIS source code directory;\n# this may be named differently on your computer.\ncd floris/\n\n# Find the remote name that corresponds to\n# NREL/FLORIS; usually \"origin\" or \"upstream\".\ngit remote -v\n\n# Fetch the changes on all remotes.\ngit fetch --all\n\n# Decide which branch to sync with\n# NREL/FLORIS. Generally, this will be \"main\".\ngit checkout main\ngit pull origin main\n\n# Update any local working branches with the\n# latest from NREL/FLORIS.\ngit checkout feature/working_branch\ngit merge main\n```\n\nNote that the example above is a general case and may need to be modified\nto fit a specific use case or purpose. If significant development has\nhappened locally, then [merge conflicts](https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts)\nare likely and should be resolved as early as possible.\n\n\n## Code quality tools\n\nFLORIS is configured to use tools to automatically check and enforce\naspects of code quality. In general, these should be adopted by all\ndevelopers and incorporated into the development workflow. Most\ntools are configured in [pyproject.toml](https://github.com/NatLabRockies/floris/blob/main/pyproject.toml),\nbut some may have a dedicated configuration file.\n\n### isort\n\nImport lines can easily get out of hand and cause unnecessary distraction\nin source code files. [isort](https://pycqa.github.io/isort/index.html)\nis used to automatically manage imports in the source code. It can be run\ndirectly with the following command:\n\n```bash\nisort <path to file>\nisort dir/*\n```\n\nThis tool was initially configured in [PR#535](https://github.com/NatLabRockies/floris/pull/535),\nand additional information on specific decisions can be found there.\n\n### Ruff\n\n[Ruff](https://github.com/charliermarsh/ruff) is a general linter and limited auto-formatter.\nIt is configured in `pyproject.toml` through various `[tool.ruff.*]` blocks. It is a command line\ntool and integrations into popular IDE's are available. A typical command to run Ruff for all of\nFLORIS is the following:\n\n```bash\nruff . --fix\n```\n\nThis sets the configuration from `pyproject.toml`, applies the selected rules to Python files,\nand fixes errors in-place where possible.\n\nRuff was initially configured in [PR#562](https://github.com/NatLabRockies/floris/pull/562), and discussed\nin more detail in [D#561](https://github.com/NatLabRockies/floris/discussions/561). See the Ruff\ndocumentation for a list of [supported rules](https://github.com/charliermarsh/ruff#supported-rules)\nand [available options for various rules](https://github.com/charliermarsh/ruff#reference).\n\n### Pre-commit\n\n[Pre-commit](https://pre-commit.com) is a utility to execute a series of git-hooks to catch\nand fix formatting errors. It integrates easily with other tools, in our case isort and Ruff.\nPre-commit is tightly integrated into git and is mostly not used directly by users.\n\nOnce installed, the precommit hooks must be installed into each development environment with\nthe following command from the `floris/` directory:\n\n```bash\npre-commit install\n```\n\nThen, each commit creation with `git` will run the installed hooks and display where\nchecks have failed. Pre-commit will typically modify the files directly to fix the issues. However,\neach file fixed by Pre-commit must be added to the git-commit again to capture the changes. A\ntypical workflow is given below.\n\n```bash\ngit add floris/simulation/turbine.py\ngit commit -m \"Update so and so\"\n> [WARNING] Unstaged files detected.\n> [INFO] Stashing unstaged files to /Users/rafmudaf/.cache/pre-commit/patch1675722485-25489.\n> isort....................................................................Failed\n> - hook id: isort\n> - files were modified by this hook\n>\n> Fixing /Users/rafmudaf/Development/floris/floris/simulation/turbine.py\n\n# Check that the error is fixed or fixed it manually\ngit status\n\n# Stage the new changes and commit\ngit add floris/simulation/turbine.py\ngit commit -m \"Update so and so\"\n```\n\n## Testing\n\nIn order to maintain a level of confidence in the software, FLORIS is expected\nto maintain a reasonable level of test coverage. To that end, unit\ntests for a the low-level code in the `floris.core` package are included.\n\nThe full testing suite can by executed by running the command ``pytest`` from\nthe highest directory in the repository. A testing-only class is included\nto provide consistent and convenient inputs to modules at\n`floris/tests/conftest.py`.\n\nUnit tests are integrated into FLORIS with [pytest](https://docs.pytest.org/en/latest/),\nand they can be executed with the following command:\n\n```bash\ncd floris/\npytest tests/*_unit_test.py\n```\n\nRegression tests are also included through [pytest](https://docs.pytest.org/en/latest/).\nFunctionally, the only difference is that the regression tests take more\ntime to execute and exercise a large portion of the software. These can be\nexecuted with the following command:\n\n```bash\ncd floris/\npytest tests/*_regression_test.py\n```\n\n### Continuous Integration\n\nContinuous integration is configured with [GitHub Actions](https://github.com/NatLabRockies/floris/actions)\nand executes all of the existing tests for every push-event. The configuration file\nis located at `floris/.github/workflows/continuous-integration-workflow.yaml`.\n\n## Documentation\n\nThe online documentation is built with Jupyter Book which uses Sphinx\nas a framework. It is automatically built and hosted by GitHub, but it\ncan also be compiled locally. Additional dependencies are required\nfor the documentation, and they are listed in the `project.optional-dependencies` of `pyproject.toml`.\nThe commands to build the docs are given below. After successfully\ncompiling, a file should be located at ``docs/_build/html/index.html``.\nThis file can be opened in any browser.\n\n```bash\npip install -e \".[docs]\"\njupyter-book build docs/\n\n# Lots of output to the terminal here...\n\nopen docs/_build/html/index.html\n```\n\n## Release guide\n\nFollow the process outlined here to \"release\" FLORIS.\nAfter completing these steps, a few additional automated processes\nare launched to deploy FLORIS to PyPI and conda-forge.\nBe sure to complete each step in the sequence as described.\n\n1. Merge the `develop` branch into `main` with a pull request.\n    Create a pull request titled `FLORIS vN.M` with version number filled in\n    as appropriate.\n    The body of the pull request should a brief summary of the changes\n    as well as a listing of the major changes and their associated pull requests.\n    Since creating the pull request does not mean it is merged, it is\n    reasonable to create the pull request, and edit the body of the pull\n    request later.\n    The pull request template has a checklist at the bottom that should be\n    uncommented for this PR.\n\n2. Update the version number and commit to the `develop`` branch\n    with a commit message such as \"Update version to vN.M\".\n    The version number must be updated in the following two files:\n    - [floris/README.md](https://github.com/NatLabRockies/floris/blob/main/README.md)\n    - [pyproject.toml](https://github.com/NatLabRockies/floris/blob/main/pyproject.toml)\n    Note that a `.0` version number is left off meaning that valid versions\n    are `v3`, `v3.1`, `v3.1.1`, etc.\n\n3. Verify that the documentation is building correctly.\n    The docs build for every commit to `develop`, so there should be no\n    surprises in this regard prior to a release. However, it's a good\n    opportunity to ensure that the documentation is up to date and there\n    are no obvious issues.\n    Check this by opening the documentation website at https://natlabrockies.github.io/floris\n    and scrolling through the pages.\n    Also, verify that the automated build process has successfully completed\n    for the commits to `develop` in [GitHub Actions](https://github.com/NatLabRockies/floris/actions/workflows/deploy-pages.yaml).\n\n4. The changes since the prior commit can be gotten from GitHub by going through the\n    process to create a release, but stopping short of actually publishing it.\n    In this form, GitHub provides the option to autogenerate release notes.\n    Be sure to choose the correct starting tag, and then hit \"Generate release notes\".\n    Then, copy the generated text into the pull request body, and format it\n    as appropriate. A good reference is typically the previous release.\n\n5. Merge the pull request into `main`. Select \"Create a merge commit\" from the merge\n    dropdown, and hit \"Merge pull request\".\n\n6. Create a [new release](https://github.com/NatLabRockies/floris/releases/new) on GitHub\n    with the title \"vN.M\". Choose to create a new tag on publish with the same\n    name. Also, autogenerate the release notes again. If you autogenerated the release\n    notes in step 4, make sure to start this step from a new browser window.\n    Be sure that the \"Set as latest release\" radio button is enabled.\n\n7. Double check everything.\n\n8. Hit \"Publish release\".\n\n9. Go to GitHub Actions and watch the [Upload Python Package](https://github.com/NatLabRockies/floris/actions/workflows/python-publish.yml)\n    job complete. Upon success, FLORIS will be uploaded to PyPI for installation with pip.\n    If it fails, the latest release will not be distributed.\n\n10. Merge the main branch into develop to align all branches on all remotes.\n\n11. That's it, well done!\n\n## Deploying to pip\n\nGenerally, only NLR developers will have appropriate permissions to deploy\nFLORIS updates. When the time comes, here is a great reference on doing it\nis available [here](https://medium.freecodecamp.org/how-to-publish-a-pyton-package-on-pypi-a89e9522ce24).\n\n## Extending the models\n\nThe FLORIS architecture is designed to support adding new wake models relatively easily.\nEach of the following components have a general API that support plugging in to the rest of the\nFLORIS framework:\n- Velocity deficit\n- Wake deflection\n- Added turbulence due to the turbine wake\n- Wake combination\n- Solver algorithm\n- Grid-points\n\nInitially, it's recommended to copy an existing model as a starting point, and the\n[Jensen](https://github.com/NatLabRockies/floris/blob/main/floris/simulation/wake_velocity/jensen.py) and\n[Jimenez](https://github.com/NatLabRockies/floris/blob/main/floris/simulation/wake_deflection/jimenez.py)\nmodels are good choices due to their simplicity.\nNew models must be registered in\n[Wake.model_map](https://github.com/NatLabRockies/floris/blob/main/floris/simulation/wake.py#L45)\nso that they can be enabled via the input dictionary.\n\n```{mermaid}\nclassDiagram\n\n    class Floris\n\n    class Farm\n\n    class FlowField {\n        u: NDArrayFloat\n        v: NDArrayFloat\n        w: NDArrayFloat\n    }\n\n    class Grid {\n        <<interface>>\n        x: NDArrayFloat\n        y: NDArrayFloat\n        z: NDArrayFloat\n    }\n\n    class WakeModelManager {\n        <<interface>>\n        combination_model: BaseModel\n        deflection_model: BaseModel\n        velocity_model: BaseModel\n        turbulence_model: BaseModel\n    }\n\n    class Solver {\n        <<interface>>\n        parameters: dict\n    }\n\n    class BaseModel {\n        prepare_function() dict\n        function() None\n    }\n\n    Floris *-- Farm\n    Floris *-- FlowField\n    Floris *-- Grid\n    Floris *-- WakeModelManager\n    Floris --> Solver\n\n    Solver --> Farm\n    Solver --> FlowField\n    Solver --> Grid\n    Solver --> WakeModelManager\n\n    WakeModelManager -- BaseModel\n\n    style Grid stroke:#FF496B, stroke-width:2px\n    style WakeModelManager stroke:#FF496B, stroke-width:2px\n    style Solver stroke:#FF496B, stroke-width:2px\n```\n\nAll of the models have a `prepare_function` and a `function` method.\nThe `prepare_function` allows the model classes to extract any information from the `Grid` and\n`FlowField` data structures, and this is generally used for sizing the data arrays.\nThe `prepare_function` should return a dictionary that will ultimately be passed to the\n`function`.\nThe `function` method is where the actual calculation is performed.\nThe API is dependent on the type of model, but generally it requires some indicationg of\nthe location of the current turbine in the solve step and some other information about the\natmospheric conditions and operation of the turbine.\nNote the `*` in the function signature, which is a Python feature that allows\nany number of arguments to be passed to the function after the `*` as keyword arguments.\nTypically, these arguments are the ones returned from the `prepare_function`.\n\n```python\ndef prepare_function(self, grid: Grid, flow_field: FlowField) -> Dict[str, Any]\n\ndef function(\n    self,\n    x_i: np.ndarray,\n    y_i: np.ndarray,\n    z_i: np.ndarray,\n    axial_induction_i: np.ndarray,\n    deflection_field_i: np.ndarray,\n    yaw_angle_i: np.ndarray,\n    turbulence_intensity_i: np.ndarray,\n    ct_i: np.ndarray,\n    hub_height_i: np.ndarray,\n    rotor_diameter_i: np.ndarray,\n    *,\n    variables_from_prepare_function: dict\n) -> None:\n```\n\nSome models require a special grid and/or solver, and that mapping happens in\n[floris.core.core.Core](https://github.com/NatLabRockies/floris/blob/main/floris/core/core.py).\nGenerally, a specific kind of solver requires one or a number of specific grid-types.\nFor example, `full_flow_sequential_solver` requires either `FlowFieldGrid` or\n`FlowFieldPlanarGrid`.\nSo, it is often the case that adding a new solver will require adding a new grid type, as well.\n"
  },
  {
    "path": "docs/empirical_gauss_model.md",
    "content": "\n(empirical_gauss_model)=\n# Empirical Gaussian model\n\nFLORIS's \"empirical\" model has the same Gaussian wake shape as other popular\nFLORIS models. However, the models that describe the wake width and deflection\nhave been reorganized to provide simpler tuning and data fitting.\n\n## Wake shape\n\nThe velocity deficit at a point $(x, y, z)$ in the wake follows a Gaussian\ncurve, i.e.,\n\n$$ \\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}} $$\n\nwhere the $(x, y, z)$ origin is at the turbine location (at ground level).\nThe terms $C$, $\\sigma_y$, $\\sigma_z$, $\\delta_y$, and $\\delta_z$ all depend\non the downstream location $x$.\n\n$C$ is the scaling factor for the Gaussian curve, defined as\n\n$$C = \\frac{1}{8\\sigma_{0_D}^2}\\left(1 - \\sqrt{1 - \\frac{\\sigma_{y0} \\sigma_{z0} C_T}{\\sigma_y \\sigma_z}}\\right)$$\n\nHere, $C_T$ is the turbine thrust coefficient, which includes any reduction\nin thrust due to yaw or tilt of the turbine rotor. $\\sigma_{y0}$ and\n$\\sigma_{z0}$ define the wake width at the turbine location $x=0$, which are\nbased on the user-specified rotor-diameter normalized initial width\n$\\sigma_{0_D}$. Note that\nthis contrasts with FLORIS's\nother Gaussian models, where $\\sigma_{y0}$ and $\\sigma_{z0}$ are defined at\nthe end of the near wake/beginning of the far wake, at some $x_0 > 0$. The\nnormalization term $8\\sigma_{0_D}^2$ provides consistency with actuator\ndisc theory.\n\n## Wake expansion\nThe wake lateral and vertical widths, $\\sigma_y$ and $\\sigma_z$, respectively,\nare a function of downstream distance $x$. The expansion of the wake is\ndescribed by a user-tunable, piecewise linear function. This is simplest to\nexpress as an integral of a piecewise constant wake expansion rate $k$, i.e.,\n\n$$ \\sigma_{y}(x) = \\int_{0}^x \\sum_{i=0}^n k_i \\mathbf{1}_{[b_{i}, b_{i+1})} (x') dx' + \\sigma_{y0} $$\n\nHere, $\\mathbf{1}_{[a, b)}(x)$ is the indicator function, which takes value\n1 when $a \\leq x < b$, and 0 otherwise.\nThe above function ensures that expansion rate $k_i$ applies only between\nbreakpoints $b_{i-1}$ and $b_i$, allowing $n+1$ varying rates of linear\nexpansion at different downstream ranges, determined by the $b_i$. Note that\n$b_0 = 0$ and $b_{n+1} = \\infty$ by design.\n\nA slight modification is made to the above so that the wake width varies\nsmoothly. As stated above, the wake expansion rate contains jump\ndiscontinuities that create \"sharp\" changes in the wake width. To avoid this,\nthe indicator function $\\mathbf{1}_{[a, b)}(x)$ is replaced with a pair of\n\"smoothstep\" functions that vary smoothly with width parameter $d$. In the\nlimit as $d\\rightarrow 0$, the approximation becomes exact.\n\nWhile the form of this wake expansion model seems complex, it is very simple\nto tune to fit data: the user provides the $n+1$ expansion rates\n$k_i, i=0,\\dots,n+1$\n(defined as a list in the `wake_expansion_rates` field of the input yaml)\nand\nthe $n$ 'break points' $b_i, i=1,\\dots,n$ where those expansion rates should go\ninto effect (specified in terms of rotor diameters downstream as a list in the\n`breakpoints_D` field of the input yaml.\n\nAs well as these, the initial width $\\sigma_{0_D}$ should be\nprovided by setting `sigma_0_D` and the\nlogistic function width $d$ as `smoothing_length_D` (both specified in\nterms of rotor diameters).\n\nWe expect that the default values for $\\sigma_{0_D}$ and $d$ should be\nsatisfactory for most users. Further, we anticipate that most users will not\nneed more than $n+1=3$ expansion rates (along with $n=2$ break points) to\ndescribe the wake expansion.\n\n## Wake deflection\n\nThe deflection of the wake centerline $\\delta_y$ and $\\delta_z$ due to\nyawing and tilting, respectively, follow a simple model\n\n$$ \\delta = k_\\text{def} C_T \\alpha \\operatorname{ln}\\left(\\frac{x/D - c}{x/D + c} + 2\\right)$$\n\nHere, $k_\\text{def}$ is a user-tunable deflection gain and $\\alpha$ is the\nmisalignment. When computing the lateral wake deflection $\\delta_y$ due to\nyaw misalignment, $\\alpha$ should be the yaw misalignment _specified in\nradians, clockwise positive from the wind direction_. When\ncomputing the vertical wake deflection $\\delta_z$ due to rotor tilt,\n$\\alpha$ should be the tilt angle _specified in radians, clockwise positive\nwhen the rotor is tilted back_.\n\nFinally, $c$ in the above deflection model is a 'deflection rate'. This\nspecifies how quickly the wake will reach it's maximum deflection\n$k_\\text{def} C_T \\alpha \\operatorname{ln}(3)$ for a given\nyaw/tilt angle.\n\nUser-tunable parameters of the model are as follows:\n- A separately tunable deflection gain $k_\\text{def}$ for each of\nlateral deflections (due to yaw misalignments) and vertical deflections\n(due to nonzero tilt), specified using `horizontal_deflection_gain_D` and\n`vertical_deflection_gain_D` (specified in terms of rotor diameters)\n- The deflection rate $c$, specified using `deflection_rate`.\n\nWe anticipate that most users will be able to use the default value for $c$,\nand set `vertical_deflection_gain_D` to the same value as\n`horizontal_deflection_gain_D` (which can also be achieved by providing\n`vertical_deflection_gain_D = -1`).\n\n## Wake-induced mixing\n\nFinally, turbines contribute to mixing in the flow. In other models, this\nextra mixing is accounted for by adding to the turbulence intensity value. In\nthe empirical model, explicit dependencies on turbulence intensity are removed\ncompletely to aid in tuning. Instead, a non-physical \"wake-induced mixing\nfactor\" is specified for turbine $j$ as\n\n$$ \\text{WIM}_j = \\sqrt{\\sum_{i \\neq j}\n\\left(\\frac{A_{ij} a_i} {\\bar{d}_{ij}^2}\\right)^2} $$\n\nwhere $A_{ij}$ is the area of overlap of the wake of turbine $i$\nonto turbine $j$; $a_i$ is the axial induction factor of the\nturbine $i$;\nand $\\bar{d}_{ij} = (x_j - x_i)/D_i$ is the downstream distance of turbine $j$ from\nthe 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$).\n\nWake-induced mixing can affect both the velocity deficit and wake deflection.\nTo account for wake-induced mixing, the wake width of turbine $j$ is adjusted\nto\n\n$$ \\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} $$\n\nwhere $w_v$ is the velocity deficit wake-induced mixing gain, which the\nuser can vary by setting `wim_gain_velocity` to represent different levels of\nmixing caused by the turbines.\n\nThe wake deflection model is similarly adjusted to\n\n$$ \\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)$$\n\nwhere $w_d$ is the wake-induced mixing gain for deflection, provided by the\nuser by setting `wim_gain_deflection`.\n\n```{note}\nThe documentation previously had an erroneous form for the wake-induced mixing\nterm,\n\n$$ \\text{WIM}_j = \\sum_{i \\in T^{\\text{up}}(j)} \\frac{A_{ij} a_i} {(x_j - x_i)/D_i} \\:.$$\n\nThis 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.\n```\n\n## Yaw added mixing\n\nYaw misalignment can also add turbulence to the wake. In the empirical Gaussian\nmodel, this effect, referred to as \"yaw-added wake recovery\" in other models,\nis activated by setting\n`enable_yaw_added_recovery` to `true`. Yaw-added mixing is represented\nby updating the wake-induced mixing term as follows:\n\n$$ \\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}$$\n\nNote that the second term means that, unlike when `enable_yaw_added_recovery`\nis `false`, a turbine may affect the recovery of its own wake by yawing.\n\n## Mirror wakes\n\nMirror wakes are also enabled by default in the empirical model to model the\nground effect. Essentially, turbines are placed below the ground so that\nthe vertical expansion of their (mirror) wakes appears in the above-ground\nflow some distance downstream, to model the reflection of the true turbine\nwakes as they bounce off of the ground/sea surface.\n\n## Added mixing by active wake control\n\nAs the name suggests, active wake control (AWC) aims to enhance mixing to the\nwake of the controlled turbine. This effect is activated by setting\n`enable_active_wake_mixing` to `true`, and `awc_modes` to `\"helix\"` (other AWC\nstrategies are yet to be implemented). The wake can then be controlled by\nsetting the amplitude of the AWC excitation using `awc_amplitudes` (see the\n[AWC operation model](operation_models_user.ipynb#awc-model)).\nThe effect of AWC is represented by updating the\nwake-induced mixing term as follows:\n\n$$ \\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}$$\n\nwhere $\\beta_{j}$ is the AWC amplitude of turbine $j$, and the exponent $p_\\text{AWC}$ and\ndenominator $d_\\text{AWC}$ are tuning parameters that can be set in the `emgauss.yaml` file with\nthe fields `awc_wake_exp` and `awc_wake_denominator`, respectively.\nNote that, in contrast to the yaw added mixing case, a turbine currently affects _only_ its own\nwake by applying AWC.\n"
  },
  {
    "path": "docs/floating_wind_turbine.md",
    "content": "\n# Floating Wind Turbine Modeling\n\nThe FLORIS wind turbine description includes a definition of the performance curves\n(`power` and `thrust_coefficient`) as a function of wind speed, and this lookup table is used\ndirectly in the calculation of power production for a steady-state atmospheric condition\n(wind speed and wind direction). The power curve definition typically assumes a\nfixed-bottom wind turbine with a fixed shaft tilt. However, floating\nwind turbines have an additional rotational degrees of freedom in the platform pitch, which\nadds a tilt angle to the rotor. As the turbine tilts, its performance is affected\nbecause the turbine is no longer operating on its defined performance curve.\n\nFLORIS allows the user to correct for the tilt angle of the turbine as a function of wind speed.\nThis 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`.\n\nThe tilt angle is then used directly in the selected wake models to compute wake effects of tilted turbines.\n"
  },
  {
    "path": "docs/floris_models.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"(floris_models)=\\n\",\n    \"\\n\",\n    \"# FLORIS Models\\n\",\n    \"\\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\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Parallelized FLORIS Model\\n\",\n    \"\\n\",\n    \"The `ParFlorisModel` class is a subclass of `FlorisModel` that parallelizes the FLORIS calculations. This class is designed to \\n\",\n    \"have an interface that is the same as `FlorisModel`, but the calculations are parallelized. \"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Instantiation\\n\",\n    \"\\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\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from floris import FlorisModel, ParFlorisModel, TimeSeries\\n\",\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"\\n\",\n    \"fmodel = FlorisModel(\\\"gch.yaml\\\")\\n\",\n    \"\\n\",\n    \"# Instantiation using yaml input file\\n\",\n    \"pfmodel = ParFlorisModel(\\\"gch.yaml\\\")\\n\",\n    \"\\n\",\n    \"# Instantiation using fmodel\\n\",\n    \"pfmodel = ParFlorisModel(fmodel)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Parameters\\n\",\n    \"\\n\",\n    \"The `ParFlorisModel` class has additional parameters the define the parallelization. These parameters are:\\n\",\n    \"\\n\",\n    \"**interface**: The parallelization interface to use. Options are `\\\"multiprocessing\\\"`,\\n\",\n    \"    `\\\"pathos\\\"`, and `\\\"concurrent\\\"`, with possible future support for `\\\"mpi4py\\\"`\\n\",\n    \"\\n\",\n    \"**max_workers**: The maximum number of workers to use. Defaults to -1, which then\\n\",\n    \"    takes the number of CPUs available.\\n\",\n    \"\\n\",\n    \"**n_wind_condition_splits**: The number of wind conditions to split the simulation over.\\n\",\n    \"    Defaults to the same as max_workers.\\n\",\n    \"\\n\",\n    \"**return_turbine_powers_only**: Whether to return only the turbine powers.\\n\",\n    \"\\n\",\n    \"**print_timings** (bool): Print the computation time to the console. Defaults to False.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Alternative parameters\\n\",\n    \"pfmodel = ParFlorisModel(fmodel, max_workers=2)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Usage\\n\",\n    \"\\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    \"\\n\",\n    \"```python\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Set to a two turbine layout\\n\",\n    \"layout_x = [0, 500]\\n\",\n    \"layout_y = [0, 0]\\n\",\n    \"fmodel.set(layout_x=layout_x, layout_y=layout_y)\\n\",\n    \"pfmodel.set(layout_x=layout_x, layout_y=layout_y)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"wind_directions = np.arange(240, 300, 0.5)\\n\",\n    \"time_series = TimeSeries(\\n\",\n    \"    wind_directions=wind_directions, wind_speeds=8.0, turbulence_intensities=0.06\\n\",\n    \")\\n\",\n    \"fmodel.set(wind_data=time_series)\\n\",\n    \"pfmodel.set(wind_data=time_series)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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9qVkPrON9stcruAQms2b1Wn6OgCVjGVbUC8Fb9WqFTVr1rRTZEIULauSm19++YVnn30WDw+PPPfJa3ZhIYTtaF232hcVZCU34eHhpKen2yMsUcJoia55+4x0SYmyoFADivv3709MTEyO8h07djBw4MBcjhBC2FLHjh2pWLEid4AoY1kboDqQlJQks3YLFEXJd7yNrCclHFmhkpv77ruP/v37WyzUFxERweDBg/nggw9sFpwQInfOzs6mwfu5LcWgrQAtyq4jR45w/fp1ygNdjWXngIuol9Saz0wshKMpVHIzf/586tSpw9ChQ0lLS2Pr1q0MGTKEDz/8kFdeecXWMQohcqH98jZPYwYY77NPty/KHu0z0JusQefaZyUwMBBPT097hCVEsShUclOuXDmWL1+Oi4sLffr04YEHHmD69Om8/PLLto5PCJEHrQt4J6C1oQ4AdMD+/fu5ceOGnSITJYGW3LQzLzPey/AB4egKnNwcPnzY4qZNonflyhWefPJJevbsadomhCh6DRo0oFGjRuhRF9AEdb2pAONjuWqq7EpMTGT79u0AfAzUBsahDkAHSW6E4yvwPDft2rVDp9NZzH6qPf/hhx/4v//7PxRFQafTkZmZWSTBCiEsDRw4kG+++YYQYDhwBPAxbtuwYQNPPvmkvUITdrR161aLFZSvAouMj319fWnbtq1d4hKiuBQ4ublw4UJRxiGEKAQtufkFWIv6JaYJCQnBYDBYzPItyob8xlwNGDBAPhPC4RU4ualbt25RxiGEKISgoCBcXV2JS08nLtu2W7dusX//fjp27GiX2IT95JfcSJeUKAsKnL5bMzlfcnIyx44dK1RAQoiCq1ChAj169Mhze0hISDFGI0qCs2fPcv78eVxR50D6HNAu+tbpdDK/jSgTCpzcjBo1igEDBrBixQqSkpJy3ef48eO88847NGzYkH379tksSCFE3nL7JV7ReC+XhJc92r95N9RlF14BnjJu69ChA9WqVbNTZEIUnwInN8ePH2fIkCFMmTIFHx8fWrZsSb9+/Rg6dCjdu3enatWqtG/fngsXLrBx40ZGjx5dlHELIYzMk5vpwAngkPF5ZGQksbGxdohK2IuW3JinvFr7nXRJibKiwMmNi4sLEydO5NSpU0RGRvLMM8/QqlUratWqRVBQED/88APXrl3jl19+oXXr1kUZsxDCTMuW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Tz3F1q1bAXX8xogRI3B1dWX37t18//33vPXWWxbn0Ov1DBgwAC8vL7Zt28aOHTvw9PRk4MCBpKenW11PouDee+892rVrxw2gP3DTWN4TWI66RMOCBQvo1asX586dy/M8qampvPnmmzzwwAOmlp5EwGDc/gKwCvUHwuLFi3FzcyuaNySEKB73tP54KZTfkukpKSnK8ePHlZSUlJwHzp6tKLVq5Xsz1KqlpA8cqGRmZloeO3ToXY9VatVSX6OQxowZowwbNkxRFEUxGAxKaGio4ubmprz++us59l2xYoVSpUoV0/NFixYpgHLw4EGL/T744AOlXLlySoUKFUy3Tp065fqaiYmJiouLi7J06VLT9vT0dMXPz0+ZOXOmoiiKsnXrVgVQVq9erSiKomRmZip37txR3n//faVt27aKoijK7du3FUAJCwvL9X0uWrRIqVixoqIoitKuXTvlxx9/VAwGg9KwYUPlzz//VL744gulbt26pv27du2qPPPMMxbneOSRR5TBgwcriqIoISEhirOzs3L16lXT9vXr1yuAsmrVKkVRFOWnn35SmjZtqhgMBtM+aWlpioeHhxISEpKjLnKT72erANLT05XVq1cr6enphTq+NLt27ZpSv359BVDagxIPigKKHpRuoGC8lS9fXvnmm2+U+Ph4U32lpKQoERERSsuWLU37md9GgPK28XG5cuWUlStX2vvt2kVZ/nwVhtSXdWxVX/l9f2cnM1MVVHw8XL2a7y46QOfnl3PDv//e9VjTa9yDv/76C09PT/R6PQaDgSeeeIKpU6eyadMmpk+fzsmTJ4mPjycjI4PU1FSSk5MpX748AK6urrRp0ybHOZs2bWqxInNev2jPnTuHXq+nW7dupjIXFxc6d+7MiRMnLPbt2LFjnu+hcuXKjB07lgEDBtCvXz+Cg4N59NFHqVmzZo59x40bx6JFi6hTpw5JSUkMHjyYb775xmKfEydO8Oyzz1qUdevWjTlz5pi2+/v742f27xYYGGix/6FDhzh79myOS4JTU1PzbS0QtlGzZk1CQkLo1q0b+//9lweB34EngR1m+yUnJ/PSSy8xceJE2rRpg6IojBo1yjTpX3XgDuqVUJqVZo+///57HnzwwSJ+N0KI4iDJTUF5e0OtWvnuogBKbgNjq1W767Gm17gHvXv3Zu7cubi6uuLn54ezszMXL17k/vvv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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"fmodel.run()\\n\",\n    \"pfmodel.run()\\n\",\n    \"\\n\",\n    \"farm_power = fmodel.get_farm_power()\\n\",\n    \"pfarm_power = pfmodel.get_farm_power()\\n\",\n    \"\\n\",\n    \"# Show the results are the same\\n\",\n    \"fig, ax = plt.subplots()\\n\",\n    \"ax.plot(wind_directions, farm_power, label=\\\"FlorisModel\\\", color='k', lw=5)\\n\",\n    \"ax.plot(wind_directions, pfarm_power, label=\\\"ParFlorisModel\\\", color='r', ls='--', lw=2)\\n\",\n    \"ax.set_xlabel(\\\"Wind Direction (deg)\\\")\\n\",\n    \"ax.set_ylabel(\\\"Farm Power (kW)\\\")\\n\",\n    \"ax.legend()\\n\",\n    \"ax.grid()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## UncertainFlorisModel\\n\",\n    \"\\n\",\n    \"The `UncertainFlorisModel` class is a composition of `FlorisModel` that adds uncertainty to the input conditions.  Its interface is meant to made similar to `FlorisModel`, but with the addition of uncertainty in wind direction.\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Instantiation\\n\",\n    \"\\n\",\n    \"The `UncertainFlorisModel` 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.  Alternatively a `ParFlorisModel` object can be passed to the constructor which ensures the underlying calculations are parallelized according to the `ParFlorisModel` parameters.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from floris import UncertainFlorisModel\\n\",\n    \"\\n\",\n    \"# Instantiation options\\n\",\n    \"ufmodel = UncertainFlorisModel(\\\"gch.yaml\\\") # Using input yaml\\n\",\n    \"ufmodel = UncertainFlorisModel(fmodel) # Using a FlorisModel object\\n\",\n    \"ufmodel = UncertainFlorisModel(pfmodel) # Using a ParFlorisModel object\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Parameters\\n\",\n    \"\\n\",\n    \"To include uncertainty into the wind direction, the `UncertainFlorisModel` class, for each findex run, the result for a wind direction is provided by performing a Gaussian blend over results from multiple wind directions nearby wind directions.  To reduce the total number of calculations required, a resolution of wind direction, wind speed, turbulence intensity and control inputs are specified and repeated calculations are only calculated once.  See the class API for complete details but some key parameters are:\\n\",\n    \"\\n\",\n    \"**wd_resolution, ws_resolution, ti_resolution, yaw_resolution, and power_setpoint_resolution**: Define the granularity of calculations for wind direction, wind speed, turbulence intensity, yaw angle, and power setpoints, respectively.\\n\",\n    \"\\n\",\n    \"**wd_std**: The standard deviation of wind direction, used in the Gaussian blending.\\n\",\n    \"\\n\",\n    \"**wd_sample_points**: Specific wind direction points to sample for expanded conditions.\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Define the uncertainty to have a wd_std of 5 degrees and blend over 10 degrees\\n\",\n    \"ufmodel = UncertainFlorisModel(fmodel, wd_std=5, wd_sample_points=[-5, -4, -3, -2, -1, 0, 1, 2,3, 4, 5], wd_resolution=0.5)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Usage\\n\",\n    \"\\n\",\n    \"Usage of `UncertainFlorisModel` is similar to `FlorisModel` however the results will now include the effects of Gaussian blending\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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atfUhg2A2jW1N1Xxli1bmDx5sr2jEjnQmTNnCAsLMzpm2CWlLVQIp7Zt7R6XENZmUctN/fr1CQ8PZ+/evezbt48DBw6YnCtBCGFFQUFoUyZT603aX9rDhw/z8OFDu4clcp5ndUnJU1Iit7AouTl8+DAPHjzg888/x8PDg88//5ySJUtSp04dxowZw+rVq7l7966tYhUibypQwKhrqnmqYq1Wy/bt2+0elsh5TCU3Lxhsa194IU25EDmRxQOKvby86NKlC7NmzSIkJESf7Li6ujJixAhKlSpliziFyNM0vXvrt019/Pz111/2C0bkSNHR0ezfv9/omCtPu6SeeHigBATYOywhbMKiMTeGtFotR48eZffu3ezatYsDBw4QExND+fLlrRmfEAKge3e0zs44JSfzAvBOquLt27ejKAoajcYR0YkcYPfu3WlWkm8HFEzZvtu0KSVlLSmRS1jUcnPkyBE+//xzunbtio+PD82bN2f+/Pn4+vry9ddfc/XqVa5du2arWIXIuwoVIqlVKwAqAH6pim/evMmlS5fsHZXIQUx1XfY22A5rnrrDU4icy6KWm+eee44SJUrQtm1b5s6dS9u2balcubKtYhNCGHB+8UXYvRtQu6ZOpioPDg6mevXq9g5L5BDBwcFG+05Az5TtxHz5uOeXOmUWIueyqOXm/Pnz3L59m19//ZVXX33VZGKjKIrVghNCPKV9/nl088r2NlEug4qFObdv3+bcuXNGx1oCxVK2E9u3JzllskghcgOLkhvdX4VffPGFyfLk5GT69++f9aiEEGkVL85/FSoAUBOokap4165dJCUl2TsqkQOYSnwNB6bne/ll+wUjhB1kavmFL774gkWLFhkdS05O5uWXXyY0NNQacQkhTHho8DRL6qemoqKiOHr0qF3jETlD6i4pDU/fP0lOTihdu9o9JiFsKVPJzaZNm5gwYQJr1qwBICkpiRdffJG///6bXbt2WTVAIcRTd1q00G+beiQ89YeYEIqipGm5aQyUTdmOaNgQChZMc50QOVmmkpsmTZqwdu1ahg0bxsaNG+nduzcXL15k165dshyDEDYU5+tLeJkyADQCUk+8IMmNSO3vv/8mPDzc6JhhYuw9ZIhd4xHCHjK9Kni7du346aef6N27N9euXWPPnj0UL17cmrEJIUxQevbUb/dKVXb48GEeP35s13hE9mYq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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"ufmodel.set(wind_data=time_series, layout_x=layout_x, layout_y=layout_y)\\n\",\n    \"ufmodel.run()\\n\",\n    \"\\n\",\n    \"# Get the power of the downstream turbine\\n\",\n    \"f_power = fmodel.get_turbine_powers()[:,1]\\n\",\n    \"uf_power = ufmodel.get_turbine_powers()[:,1]\\n\",\n    \"\\n\",\n    \"# Plot the two powers\\n\",\n    \"fig, ax = plt.subplots()\\n\",\n    \"ax.plot(wind_directions, f_power, label=\\\"FlorisModel\\\", color='k', lw=5)\\n\",\n    \"ax.plot(wind_directions, uf_power, label=\\\"UncertainFlorisModel\\\", color='r', lw=2)\\n\",\n    \"ax.set_xlabel(\\\"Wind Direction (deg)\\\")\\n\",\n    \"ax.set_ylabel(\\\"Turbine Power (kW)\\\")\\n\",\n    \"ax.legend()\\n\",\n    \"ax.grid()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## ApproxFlorisModel\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"   The ApproxFlorisModel overloads the UncertainFlorisModel with the special case that the `wd_sample_points = [0]`.  This is a special case where no uncertainty is added but the resolution of the values wind direction, wind speed etc are still reduced  by the specified resolution.  This allows for cases to be reused and a faster approximate result computed\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Instantiation\\n\",\n    \"\\n\",\n    \"`ApproxFlorisModel` can be instantiated in the same way as the `UncertainFlorisModel` class\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 9,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from floris import ApproxFlorisModel\\n\",\n    \"\\n\",\n    \"# Instantiation options\\n\",\n    \"amodel = ApproxFlorisModel(\\\"gch.yaml\\\") # Using input yaml\\n\",\n    \"amodel = ApproxFlorisModel(fmodel) # Using a FlorisModel object\\n\",\n    \"amodel = ApproxFlorisModel(pfmodel) # Using a ParFlorisModel object\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Usage\\n\",\n    \"\\n\",\n    \"`ApproxFlorisModel` is used in the same way as `UncertainFlorisModel` but with the special case that the `wd_sample_points = [0]`. This means that while the resolution of the values `wind_direction`, `wind_speeds` etc are still reduced by the specified resolution, no uncertainty is added. It is intended for quickly processing large sets of inflow conditions (e.g., when reproducing SCADA records), when approximate solutions are sufficient.\\n\",\n    \"\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 10,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Instantiate with a wind speed resolution of 0.5 m/s and a wind direction resolution of 1 degree\\n\",\n    \"amodel = ApproxFlorisModel(fmodel, ws_resolution=0.5, wd_resolution=1.0) \"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 11,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"amodel has an n_findex of 40,  however, the number of unique cases to run at this resolution is 9.\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# Show approximation for a time series including smaller increments of wind speed\\n\",\n    \"wind_speeds = np.arange(6, 10, 0.1)\\n\",\n    \"time_series = TimeSeries(\\n\",\n    \"    wind_directions = 270.0,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=0.06\\n\",\n    \")\\n\",\n    \"amodel.set(wind_data=time_series)\\n\",\n    \"\\n\",\n    \"print(f\\\"amodel has an n_findex of {amodel.n_findex}, \\\",\\n\",\n    \"      f\\\"however, the number of unique cases to run at this resolution is {amodel.n_unique}.\\\")\\n\",\n    \"\\n\",\n    \"amodel.run()\\n\",\n    \"farm_power = amodel.get_farm_power()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 12,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Show the farm power over wind speeds\\n\",\n    \"fig, ax = plt.subplots()\\n\",\n    \"ax.plot(wind_speeds, farm_power, label=\\\"ApproxFlorisModel\\\", color='k', lw=2)\\n\",\n    \"ax.legend()\\n\",\n    \"ax.set_xlabel(\\\"Wind Speed (m/s)\\\")\\n\",\n    \"ax.set_ylabel(\\\"Farm Power (kW)\\\")\\n\",\n    \"ax.grid()\\n\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"floris\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.10.6\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"
  },
  {
    "path": "docs/heterogeneous_map.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"(heterogeneous_map)=\\n\",\n    \"\\n\",\n    \"# Heterogeneous Map\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"FLORIS provides a HeterogeneousMap object to enable a heterogeneity in the background wind speed. This notebook demonstrates how to use the HeterogeneousMap object in FLORIS.\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Note that more detailed examples are provided within the examples_heterogeneous folder\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import matplotlib.pyplot as plt\\n\",\n    \"import numpy as np\\n\",\n    \"\\n\",\n    \"from floris import (\\n\",\n    \"    FlorisModel,\\n\",\n    \"    HeterogeneousMap,\\n\",\n    \"    TimeSeries,\\n\",\n    \")\\n\",\n    \"from floris.flow_visualization import visualize_heterogeneous_cut_plane, visualize_cut_plane\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Initialization\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"The HeterogeneousMap defines the heterogeneity in the background wind speed. For a set of x,y coordinates, a speed up (or low down), relative to the inflow wind speed, can be defined. This can vary according to the inflow wind speed and wind direction.  For wind directions and wind speeds not directly defined with the HeterogeneousMap, the nearest defined value is used.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Define a map in which there is ab observed speed up for wind from the east (90 degrees)\\n\",\n    \"# but not from the west (270 degrees)\\n\",\n    \"heterogeneous_map = HeterogeneousMap(\\n\",\n    \"    x=np.array([0.0, 0.0, 250.0, 500.0, 500.0]),\\n\",\n    \"    y=np.array([0.0, 500.0, 250.0, 0.0, 500.0]),\\n\",\n    \"    speed_multipliers=np.array(\\n\",\n    \"        [\\n\",\n    \"            [1.0, 1.0, 1.0, 1.0, 1.0],\\n\",\n    \"            [1.0, 1.0, 1.0, 1.0, 1.0],\\n\",\n    \"            [1.5, 1.0, 1.25, 1.5, 1.0],\\n\",\n    \"            [1.0, 1.5, 1.25, 1.0, 1.5],\\n\",\n    \"        ]\\n\",\n    \"    ),\\n\",\n    \"    wind_directions=np.array([270.0, 270.0, 90.0, 90.0]),\\n\",\n    \"    wind_speeds=np.array([5.0, 10.0, 5.0, 10.0]),\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Can print basic information about the map\\n\",\n    \"print(heterogeneous_map)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Interpolation\\n\",\n    \"\\n\",\n    \"By default the HeterogeneousMap uses linear interpolation to determine the speed up for a given wind speed and wind direction using `scipy.interpolate.LinearNDInterpolator`. This can be changed to nearest neighbor interpolation by setting the `interp_method` argument to `'nearest'`, which uses `scipy.interpolate.NearestNDInterpolator`. The default behavior is recovered by setting `interp_method` to `'linear'`.\\n\",\n    \"\\n\",\n    \"When `interp_method` is `'linear'`, any location outside of the convex hull of points defined by `x`, `y` and `z` are given a speed multiplier of 1.0 (that is, the freestream wind speed is applied) and an \\\"out of bounds\\\" warning is raised. When `interp_method` is `'nearest'`, points \\\"outside\\\" of the specified region still get assigned the speed multiplier of the nearest specified point, and \\\"out of bounds\\\" warning is raised.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"heterogeneous_map_nearest = HeterogeneousMap(\\n\",\n    \"    x=np.array([0.0, 0.0, 250.0, 500.0, 500.0]),\\n\",\n    \"    y=np.array([0.0, 500.0, 250.0, 0.0, 500.0]),\\n\",\n    \"    speed_multipliers=np.array(\\n\",\n    \"        [\\n\",\n    \"            [1.0, 1.0, 1.0, 1.0, 1.0],\\n\",\n    \"            [1.0, 1.0, 1.0, 1.0, 1.0],\\n\",\n    \"            [1.5, 1.0, 1.25, 1.5, 1.0],\\n\",\n    \"            [1.0, 1.5, 1.25, 1.0, 1.5],\\n\",\n    \"        ]\\n\",\n    \"    ),\\n\",\n    \"    wind_directions=np.array([270.0, 270.0, 90.0, 90.0]),\\n\",\n    \"    wind_speeds=np.array([5.0, 10.0, 5.0, 10.0]),\\n\",\n    \"    interp_method=\\\"nearest\\\"\\n\",\n    \")\\n\",\n    \"print(heterogeneous_map_nearest)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Visualization\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"HeterogeneousMap includes methods to visualize the speed up for a given wind speed and wind direction. Note that in FLORIS, heterogeneity in the ambient flow only exists for points within the convex hull surrounding the defined points.  This boundary is illustrated in the flow.  All points outside the boundary are assume to be 1.0 * the inflow wind speed.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Use the HeterogeneousMap object to plot the speedup map for 3 wd/ws combinations\\n\",\n    \"fig, axarr = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(15, 5))\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"ax = axarr[0]\\n\",\n    \"heterogeneous_map.plot_single_speed_multiplier(\\n\",\n    \"    wind_direction=60.0, wind_speed=8.5, ax=ax, vmin=1.0, vmax=1.2\\n\",\n    \")\\n\",\n    \"ax.set_title(\\\"Wind Direction = 60.0\\\\nWind Speed = 8.5\\\")\\n\",\n    \"ax.legend()\\n\",\n    \"\\n\",\n    \"ax = axarr[1]\\n\",\n    \"heterogeneous_map.plot_single_speed_multiplier(\\n\",\n    \"    wind_direction=130.0, wind_speed=4.0, ax=ax, vmin=1.0, vmax=1.2\\n\",\n    \")\\n\",\n    \"ax.set_title(\\\"Wind Direction = 130.0\\\\nWind Speed = 4.0\\\")\\n\",\n    \"\\n\",\n    \"ax = axarr[2]\\n\",\n    \"heterogeneous_map.plot_single_speed_multiplier(\\n\",\n    \"    wind_direction=280.0, wind_speed=16.0, ax=ax, vmin=1.0, vmax=1.2\\n\",\n    \")\\n\",\n    \"ax.set_title(\\\"Wind Direction = 280.0\\\\nWind Speed = 16.0\\\")\\n\",\n    \"fig.suptitle(\\\"Heterogeneous speedup map for several directions and wind speeds\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Applying heterogeneity to a FlorisModel\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Applying the HeterogeneousMap to a FlorisModel is done by passing the HeterogeneousMap to a WindData object which is used to set the FlorisModel.  The WindData object constructs the appropriate speed up map for each wind direction and wind speed condition.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Initialize FlorisModel\\n\",\n    \"fmodel = FlorisModel(\\\"gch.yaml\\\")\\n\",\n    \"\\n\",\n    \"# Change the layout to a 2 turbine layout within the heterogeneous domain\\n\",\n    \"fmodel.set(layout_x=[200, 200.0], layout_y=[50, 450.0])\\n\",\n    \"\\n\",\n    \"# Define a TimeSeries object with 3 wind directions and wind speeds\\n\",\n    \"# and turbulence intensity and using the above HeterogeneousMap object\\n\",\n    \"time_series = TimeSeries(\\n\",\n    \"    wind_directions=np.array([275.0, 95.0, 75.0]),\\n\",\n    \"    wind_speeds=np.array([7.0, 6.2, 8.0]),\\n\",\n    \"    turbulence_intensities=0.06,\\n\",\n    \"    heterogeneous_map=heterogeneous_map,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Apply the time series to the FlorisModel\\n\",\n    \"fmodel.set(wind_data=time_series)\\n\",\n    \"\\n\",\n    \"# Run the FLORIS simulation\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"# Visualize each of the findices\\n\",\n    \"fig, axarr = plt.subplots(3, 1, sharex=True, sharey=True, figsize=(10, 10))\\n\",\n    \"\\n\",\n    \"for findex in range(3):\\n\",\n    \"    ax = axarr[findex]\\n\",\n    \"\\n\",\n    \"    horizontal_plane = fmodel.calculate_horizontal_plane(\\n\",\n    \"        x_resolution=200, y_resolution=100, height=90.0, findex_for_viz=findex\\n\",\n    \"    )\\n\",\n    \"\\n\",\n    \"    visualize_heterogeneous_cut_plane(\\n\",\n    \"        cut_plane=horizontal_plane,\\n\",\n    \"        fmodel=fmodel,\\n\",\n    \"        ax=ax,\\n\",\n    \"        title=(\\n\",\n    \"            f\\\"Wind Direction = {time_series.wind_directions[findex]}\\\\n\\\"\\n\",\n    \"            f\\\"Wind Speed = {time_series.wind_speeds[findex]}\\\"\\n\",\n    \"        ),\\n\",\n    \"    )\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Definining a 3D HeterogeneousMap\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Including a z-dimension in the HetereogeneousMap allows for a 3D heterogeneity.   This uses the underlying support in FlorisMode for 3D heterogeneous_inflow_config_by_wd.\\n\",\n    \"\\n\",\n    \"Note that when using the 3D version, wind_sheer must be set to 0.0 to avoid an error.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Define a 3D heterogeneous map with two z-levels\\n\",\n    \"\\n\",\n    \"heterogeneous_map = HeterogeneousMap(\\n\",\n    \"    x=np.array(\\n\",\n    \"        [\\n\",\n    \"            -1000.0,\\n\",\n    \"            -1000.0,\\n\",\n    \"            1000.0,\\n\",\n    \"            1000.0,\\n\",\n    \"            -1000.0,\\n\",\n    \"            -1000.0,\\n\",\n    \"            1000.0,\\n\",\n    \"            1000.0,\\n\",\n    \"            -1000.0,\\n\",\n    \"            -1000.0,\\n\",\n    \"            1000.0,\\n\",\n    \"            1000.0,\\n\",\n    \"        ]\\n\",\n    \"    ),\\n\",\n    \"    y=np.array(\\n\",\n    \"        [-500.0, 500.0, -500.0, 500.0, -500.0, 500.0, -500.0, 500.0, -500.00, 500.0, -500.0, 500.0]\\n\",\n    \"    ),\\n\",\n    \"    z=np.array(\\n\",\n    \"        [100.0, 100.0, 100.0, 100.0, 200.0, 200.0, 200.0, 200.0, 500.0, 500.0, 500.0, 500.0]\\n\",\n    \"    ),\\n\",\n    \"    speed_multipliers=np.array(\\n\",\n    \"        [\\n\",\n    \"            [1.0, 1.0, 1.0, 1.0, 1.1, 1.1, 1.1, 1.1, 1.5, 1.5, 1.5, 1.5],\\n\",\n    \"            [1.0, 1.0, 1.0, 1.0, 1.1, 1.1, 1.1, 1.1, 1.5, 1.5, 1.5, 1.5],\\n\",\n    \"            [1.0, 1.2, 1.2, 1.0, 1.3, 1.1, 1.1, 1.3, 1.5, 1.5, 1.5, 1.5],\\n\",\n    \"            [1.0, 1.0, 1.0, 1.0, 1.1, 1.1, 1.1, 1.1, 1.5, 1.5, 1.5, 1.5],\\n\",\n    \"        ]\\n\",\n    \"    ),\\n\",\n    \"    wind_directions=np.array([270.0, 270.0, 90.0, 90.0]),\\n\",\n    \"    wind_speeds=np.array([5.0, 10.0, 5.0, 10.0]),\\n\",\n    \")\\n\",\n    \"print(heterogeneous_map)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"When visualizing the 3D heterogeneity, the z-height to plot must be specified (nearest defined is used)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"heterogeneous_map.plot_single_speed_multiplier(wind_direction=90.0, wind_speed=5.0, z=100.0)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"heterogeneous_map.plot_single_speed_multiplier(wind_direction=90.0, wind_speed=5.0, z=200.0)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"## Apply the 3D heterogeneous map to the FlorisModel\\n\",\n    \"time_series = TimeSeries(\\n\",\n    \"    wind_directions=np.array([275.0, 95.0, 75.0]),\\n\",\n    \"    wind_speeds=np.array([7.0, 6.2, 8.0]),\\n\",\n    \"    turbulence_intensities=0.06,\\n\",\n    \"    heterogeneous_map=heterogeneous_map,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Apply the time series to the FlorisModel, make sure to set wind_shear to 0.0\\n\",\n    \"fmodel.set(wind_data=time_series, wind_shear=0.0)\\n\",\n    \"\\n\",\n    \"# Run the FLORIS simulation\\n\",\n    \"fmodel.run()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Show a horizontal and y plane slice (note that heterogeneity is only defined within the hull of points)\\n\",\n    \"\\n\",\n    \"# Visualize each of the findices\\n\",\n    \"fig, axarr = plt.subplots(2, 1, sharex=True, sharey=False, figsize=(5, 7))\\n\",\n    \"findex = 0\\n\",\n    \"\\n\",\n    \"ax = axarr[0]\\n\",\n    \"horizontal_plane = fmodel.calculate_horizontal_plane(\\n\",\n    \"    x_resolution=200, y_resolution=100, height=90.0, findex_for_viz=findex\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"visualize_heterogeneous_cut_plane(\\n\",\n    \"    cut_plane=horizontal_plane,\\n\",\n    \"    fmodel=fmodel,\\n\",\n    \"    ax=ax,\\n\",\n    \"    title=(\\n\",\n    \"        f\\\"Wind Direction = {time_series.wind_directions[findex]}\\\\n\\\"\\n\",\n    \"        f\\\"Wind Speed = {time_series.wind_speeds[findex]}\\\"\\n\",\n    \"    ),\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"ax = axarr[1]\\n\",\n    \"y_plane = fmodel.calculate_y_plane(\\n\",\n    \"    x_resolution=200,\\n\",\n    \"    z_resolution=100,\\n\",\n    \"    findex_for_viz=findex,\\n\",\n    \"    crossstream_dist=400.0,  # x_bounds=[-200,500]\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"visualize_cut_plane(\\n\",\n    \"    cut_plane=y_plane,\\n\",\n    \"    ax=ax,\\n\",\n    \"    title=(\\n\",\n    \"        f\\\"Wind Direction = {time_series.wind_directions[findex]}\\\\n\\\"\\n\",\n    \"        f\\\"Wind Speed = {time_series.wind_speeds[findex]}\\\"\\n\",\n    \"    ),\\n\",\n    \")\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"floris\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.13.2\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"
  },
  {
    "path": "docs/index.md",
    "content": "# FLORIS Wake Modeling & Wind Farm Controls\n\nFLORIS is a controls-focused wind farm simulation software incorporating\nsteady-state engineering wake models into a performance-focused Python\nframework.\nThe software is in active development and engagement with the development team\nis highly encouraged. If you are interested in using FLORIS to conduct studies\nof a wind farm or extending FLORIS to include your own wake model, please join\nthe conversation in [GitHub Discussions](https://github.com/NatLabRockies/floris/discussions/)!\n\n```{note}\nFLORIS support for python version 3.8 and 3.9 was recently ended as they reached [end-of-life](https://devguide.python.org/versions/).\nFLORIS v4.3 also made the move to requiring `numpy` version 2. See the [numpy documentation for details](https://numpy.org/doc/stable/numpy_2_0_migration_guide.html).\n```\n\n## WETO software\n\nFLORIS is primarily developed with the support from the U.S. Department of Energy and\nis part of the  [WETO Software Stack](https://natlabrockies.github.io/WETOStack).\nFor more information and other integrated modeling software, see:\n\n- [Portfolio Overview](https://natlabrockies.github.io/WETOStack/portfolio_analysis/overview.html)\n- [Entry Guide](https://natlabrockies.github.io/WETOStack/_static/entry_guide/index.html)\n- [Wind Farm Controls Workshop](https://www.youtube.com/watch?v=f-w6whxIBrA&list=PL6ksUtsZI1dwRXeWFCmJT6cEN1xijsHJz)\n\n## Quick Start\n\nFLORIS is a Python package run on the command line typically by providing\nan input file with an initial configuration. It can be installed with\n```pip install floris``` (see {ref}`installation`). The typical entry point is\n{py:class}`.FlorisModel` which accepts the path to the\ninput file as an argument. From there, changes can be made to the initial\nconfiguration through the {py:meth}`.FlorisModel.set`\nroutine, and the simulation is executed with\n{py:meth}`.FlorisModel.run`.\n\n```python\nfrom floris import FlorisModel\nfmodel = FlorisModel(\"path/to/input.yaml\")\nfmodel.set(\n    wind_directions=[i for i in range(10)],\n    wind_speeds=[8.0]*10,\n    turbulence_intensities=[0.06]*10\n)\nfmodel.run()\n```\n\nFinally, results can be analyzed via post-processing functions available within\n{py:class}`.FlorisModel` such as\n{py:meth}`.FlorisModel.get_turbine_layout`,\n{py:meth}`.FlorisModel.get_turbine_powers` and\n{py:meth}`.FlorisModel.get_farm_AEP`, and\na visualization package is available in {py:mod}`floris.flow_visualization`.\nA collection of examples are included in the [repository](https://github.com/NatLabRockies/floris/tree/main/examples)\nand described in detail in {ref}`examples`.\n\n## Engaging on GitHub\n\nFLORIS leverages the following GitHub features to coordinate support and development efforts:\n\n- [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\n- [Issues](https://github.com/NatLabRockies/floris/issues): Report potential bugs and well-developed feature requests\n- [Projects](https://github.com/orgs/NREL/projects/18/): Include current and future work on a timeline and assign a person to \"own\" it\n\nGenerally, the first entry point for the community will be within one of the\ncategories in Discussions.\n[Ideas](https://github.com/NatLabRockies/floris/discussions/categories/ideas) is a great spot to develop the\ndetails for a feature request. [Q&A](https://github.com/NatLabRockies/floris/discussions/categories/q-a)\nis where to get usage support.\n[Show and tell](https://github.com/NatLabRockies/floris/discussions/categories/show-and-tell) is a free-form\nspace to show off the things you are doing with FLORIS.\n"
  },
  {
    "path": "docs/input_reference_main.md",
    "content": "# Main Input File Reference\n\nIn addition to calling the `set()` method on {py:class}`FlorisModel`, users can configure FLORIS\nwith an input file. The file must be YAML format with either \"yaml\" or \"yml\" extension.\nThe below definitions guide a user to the top, mid, and lower level parameterizations. A few\nreference input files are available in the\n[floris/examples](https://github.com/NatLabRockies/floris/tree/main/examples/inputs) folder.\n\n```{eval-rst}\n.. autoyaml:: docs/gch.yaml\n```\n"
  },
  {
    "path": "docs/input_reference_turbine.md",
    "content": "# Turbine Input File Reference\n\nThe turbine input file is an optional input used to define a custom turbine type.\nThe file must be YAML format with either \"yaml\" or \"yml\" extension. See\nfor more information on inspecting and creating the turbine definition.\n\n```{eval-rst}\n.. autoyaml:: docs/nrel_5MW.yaml\n```\n"
  },
  {
    "path": "docs/installation.md",
    "content": "(installation)=\n# Installation\n\nFLORIS can be installed by downloading the source code or via the PyPI package manager with `pip`.\nThe following sections detail how download and install FLORIS for each use case.\n\n(requirements)=\n## Requirements\n\nFLORIS is a python package. FLORIS is intended to work with all [active versions of python](https://devguide.python.org/versions/). Support will drop for python versions once they reach end-of-life.\nIt is highly recommended that users\nwork within a virtual environment for both working with and working on FLORIS, to maintain a clean\nand sandboxed environment. The simplest way to get started with virtual environments is through\n[conda](https://docs.conda.io/en/latest/miniconda.html).\n\n```{note}\nFLORIS support for python version 3.8 and 3.9 was recently ended as they reached [end-of-life](https://devguide.python.org/versions/).\nFLORIS v4.3 also made the move to requiring `numpy` version 2. See the [numpy documentation for details](https://numpy.org/doc/stable/numpy_2_0_migration_guide.html).\n```\n\n```{warning}\nSupport for python version 3.9 will end in the latter half of 2025 as it reaches [end-of-life](https://devguide.python.org/versions/).\n```\n\nInstalling into a Python environment that contains a previous version of FLORIS may cause conflicts.\nIf you intend to use [pyOptSparse](https://mdolab-pyoptsparse.readthedocs-hosted.com/en/latest/)\nwith FLORIS, it is recommended to install that package first before installing FLORIS.\n\n\n```{note}\nIf upgrading, it is highly recommended to install FLORIS v4 into a new virtual environment.\n```\n\n(pip)=\n## Pip\n\nThe simplest method is with `pip` by using this command:\n\n```bash\npip install floris\n```\n\n(source)=\n## Source Code Installation\n\nDevelopers and anyone who intends to inspect the source code or wants to run examples can install FLORIS by downloading the\ngit repository from GitHub with ``git`` and use ``pip`` to locally install it. The following commands in a terminal or shell will download and install FLORIS.\n\n```bash\n# Download the source code from the `main` branch\ngit clone -b main https://github.com/NatLabRockies/floris.git\n\n# If using conda, be sure to activate your environment prior to installing\n# conda activate <env name>\n\n# If using pyOptSpare, install it first\nconda install -c conda-forge pyoptsparse\n\n# Install FLORIS\npip install -e floris\n```\n\nWith both methods, the installation can be verified by opening a Python interpreter\nand importing FLORIS:\n\n```python\n>>> import floris\n>>> help(floris)\n\nHelp on package floris:\n\nNAME\n    floris\n\nPACKAGE CONTENTS\n    convert_floris_input_v3_to_v4\n    convert_turbine_v3_to_v4\n    core (package)\n    cut_plane\n    floris_model\n    flow_visualization\n    layout_visualization\n    logging_manager\n    optimization (package)\n    parallel_floris_model\n    turbine_library (package)\n    type_dec\n    uncertain_floris_model\n    utilities\n    version\n    wind_data\n\nVERSION\n    4.6.4\n\nFILE\n    ~/floris/floris/__init__.py\n```\n\n(developers)=\n## Developer Installation\n\nFor users that will also be contributing to the FLORIS code repository, the process is similar to\nthe source code installation, but with a few extra considerations. The steps are laid out in our\n[developer's guide](dev_guide.md).\n\n(updating)=\n## Updating FLORIS\n\nIt is important to regularly check for new updates and releases as new features, improvements, and\nbug fixes will be issued on an ongoing basis, and will require manually updating the software.\n\n(pip-update)=\n### Pip\n\n```bash\npip install --upgrade floris\n\n# Alternatively, users can specify a particular version, for example:\n# pip install --upgrade floris==3.2.1\n```\n\n(source-update)=\n### From Source\n```bash\n\n# If you're not already on the main branch, save your changes and move there\ngit checkout main\n\n# Pull down the changes from GitHub\ngit pull main\n```\n"
  },
  {
    "path": "docs/intro_concepts.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"86e53920\",\n   \"metadata\": {},\n   \"source\": [\n    \"(intro_concepts)=\\n\",\n    \"# Introductory Concepts\\n\",\n    \"\\n\",\n    \"FLORIS is a Python-based software library for calculating wind farm performance considering\\n\",\n    \"the effect of turbine-turbine interactions through their wakes.\\n\",\n    \"There are two primary packages to understand when using FLORIS:\\n\",\n    \"- `floris.core`: This package contains the core functionality for calculating the wind farm wake\\n\",\n    \"    and turbine-turbine interactions. This package is the computational engine of FLORIS.\\n\",\n    \"    All of the mathematical models and algorithms are implemented here.\\n\",\n    \"- `floris`: This is the top-level package that provides most of the functionality that the\\n\",\n    \"    majority of users will need. The main entry point is `FlorisModel` which is a high-level\\n\",\n    \"    interface to the computational engine.\\n\",\n    \"\\n\",\n    \"<!-- TODO add chart  -->\\n\",\n    \"\\n\",\n    \"Users of FLORIS will develop a Python script with the following sequence of steps:\\n\",\n    \"\\n\",\n    \"1. Load inputs and preprocess data\\n\",\n    \"2. Run the wind farm wake calculation\\n\",\n    \"3. Extract data and postprocess results\\n\",\n    \"\\n\",\n    \"Generally, users will only interact with `floris` and most often through the `FlorisModel` class.\\n\",\n    \"Additionally, `floris` contains functionality for comparing results, creating visualizations,\\n\",\n    \"and developing optimization cases. \\n\",\n    \"\\n\",\n    \"This notebook steps through the basic ideas and operations of FLORIS while showing\\n\",\n    \"realistic uses and expected behavior.\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"699c51dd\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Initialize Floris\\n\",\n    \"\\n\",\n    \"The `FlorisModel` class provides functionality to build a wind farm representation and drive\\n\",\n    \"the simulation. This object is created (instantiated) by passing the path to a FLORIS input\\n\",\n    \"file as the only argument. After this object is created, it can immediately be used to\\n\",\n    \"inspect the data.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"id\": \"602f311c\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"     x       y\\n\",\n      \"   0.0,    0.0\\n\",\n      \" 630.0,    0.0\\n\",\n      \"1260.0,    0.0\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"\\n\",\n    \"from floris import FlorisModel\\n\",\n    \"\\n\",\n    \"fmodel = FlorisModel(\\\"gch.yaml\\\")\\n\",\n    \"x, y = fmodel.get_turbine_layout()\\n\",\n    \"\\n\",\n    \"print(\\\"     x       y\\\")\\n\",\n    \"for _x, _y in zip(x, y):\\n\",\n    \"    print(f\\\"{_x:6.1f}, {_y:6.1f}\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"e1eaeb53\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Build the model\\n\",\n    \"\\n\",\n    \"At this point, FLORIS has been initialized with the data defined in the input file.\\n\",\n    \"However, it is often simplest to define a basic configuration in the input file as\\n\",\n    \"a starting point and then make modifications in the Python script. This allows for\\n\",\n    \"generating data algorithmically or loading data from a data file. Modifications to\\n\",\n    \"the wind farm representation are handled through the `FlorisModel.set()`\\n\",\n    \"function with keyword arguments. Another way to think of this function is that it\\n\",\n    \"changes the value of inputs specified in the input file.\\n\",\n    \"\\n\",\n    \"Let's change the location of turbines in the wind farm. The code below changes the\\n\",\n    \"initial 3x1 layout to a 2x2 rectangular layout.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"id\": \"d040b810\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"     x       y\\n\",\n      \"   0.0,    0.0\\n\",\n      \"   0.0,  400.0\\n\",\n      \" 800.0,    0.0\\n\",\n      \" 800.0,  400.0\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"x_2x2 = [0, 0, 800, 800]\\n\",\n    \"y_2x2 = [0, 400, 0, 400]\\n\",\n    \"fmodel.set(layout_x=x_2x2, layout_y=y_2x2)\\n\",\n    \"\\n\",\n    \"x, y = fmodel.get_turbine_layout()\\n\",\n    \"\\n\",\n    \"print(\\\"     x       y\\\")\\n\",\n    \"for _x, _y in zip(x, y):\\n\",\n    \"    print(f\\\"{_x:6.1f}, {_y:6.1f}\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"63f45e11\",\n   \"metadata\": {},\n   \"source\": [\n    \"Additionally, we can change the wind speeds, wind directions, and turbulence intensity.\\n\",\n    \"The set of wind conditions is given as arrays of wind speeds, wind directions, and turbulence\\n\",\n    \"intensity combinations that describe the atmospheric conditions to compute.\\n\",\n    \"This requires that all arrays be the same length.\\n\",\n    \"\\n\",\n    \"Notice that we can give `FlorisModel.set()` multiple keyword arguments at once.\\n\",\n    \"There is no expected output from the `FlorisModel.set()` function.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"id\": \"6f9d834a\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"fmodel.set(wind_directions=[270.0], wind_speeds=[8.0], turbulence_intensities=[0.1])\\n\",\n    \"\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_directions=[270.0, 280.0],\\n\",\n    \"    wind_speeds=[8.0, 8.0],\\n\",\n    \"    turbulence_intensities=[0.1, 0.1],\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_directions=[270.0, 280.0, 270.0, 280.0],\\n\",\n    \"    wind_speeds=[8.0, 8.0, 9.0, 9.0],\\n\",\n    \"    turbulence_intensities=[0.1, 0.1, 0.1, 0.1],\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"da4f3309\",\n   \"metadata\": {},\n   \"source\": [\n    \"`FlorisModel.set()` creates all of the basic data structures required\\n\",\n    \"for the simulation but it does not do any aerodynamic calculations. The low level\\n\",\n    \"data structures have a complex shape that enables faster computations. Specifically,\\n\",\n    \"most data is structured as a 4-dimensional Numpy array with the following dimensions:\\n\",\n    \"\\n\",\n    \"```python\\n\",\n    \"np.array(\\n\",\n    \"    (\\n\",\n    \"        findex,\\n\",\n    \"        turbines,\\n\",\n    \"        grid-1,\\n\",\n    \"        grid-2\\n\",\n    \"    )\\n\",\n    \")\\n\",\n    \"```\\n\",\n    \"\\n\",\n    \"The `findex` dimension contains the index to a particular calculation in the overall data\\n\",\n    \"domain. This typically represents a unique combination of wind direction and wind speed\\n\",\n    \"making up a wind condition, but it can also be used to represent any other varying quantity.\\n\",\n    \"\\n\",\n    \"For example, we can see the shape of the data structure for the grid point x-coordinates\\n\",\n    \"for the all turbines and get the x-coordinates of grid points for the third turbine in\\n\",\n    \"the first wind condition. We can also plot all the grid points in\\n\",\n    \"space to get an idea of the overall form of our grid.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"id\": \"01ea3a98\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Dimensions of grid x-components\\n\",\n      \"(4, 4, 3, 3)\\n\",\n      \"\\n\",\n      \"3rd turbine x-components for first wind condition (at findex=0)\\n\",\n      \"[[800. 800. 800.]\\n\",\n      \" [800. 800. 800.]\\n\",\n      \" [800. 800. 800.]]\\n\"\n     ]\n    },\n    {\n     \"data\": {\n      \"image/png\": \"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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"print(\\\"Dimensions of grid x-components\\\")\\n\",\n    \"print(np.shape(fmodel.core.grid.x_sorted))\\n\",\n    \"\\n\",\n    \"print()\\n\",\n    \"print(\\\"3rd turbine x-components for first wind condition (at findex=0)\\\")\\n\",\n    \"print(fmodel.core.grid.x_sorted[0, 2, :, :])\\n\",\n    \"\\n\",\n    \"x = fmodel.core.grid.x_sorted[0, :, :, :]\\n\",\n    \"y = fmodel.core.grid.y_sorted[0, :, :, :]\\n\",\n    \"z = fmodel.core.grid.z_sorted[0, :, :, :]\\n\",\n    \"\\n\",\n    \"fig = plt.figure()\\n\",\n    \"ax = fig.add_subplot(111, projection=\\\"3d\\\")\\n\",\n    \"ax.scatter(x, y, z, marker=\\\".\\\")\\n\",\n    \"ax.set_zlim([0, 150])\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"ebfdc746\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Run the Floris wake calculation\\n\",\n    \"\\n\",\n    \"Running the wake calculation is a one-liner. This will calculate the velocities\\n\",\n    \"at each turbine given the wake of other turbines for every wind speed and wind\\n\",\n    \"direction combination. Since we have not explicitly specified yaw control settings\\n\",\n    \"when creating the `FlorisModel` settings, all turbines are aligned with the inflow.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"id\": \"e3bf1698\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"fmodel.run()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"e11352e8\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Get turbine power\\n\",\n    \"\\n\",\n    \"At this point, the simulation has completed and we can use `FlorisModel` to\\n\",\n    \"extract useful information such as the power produced at each turbine. Remember that\\n\",\n    \"we have configured the simulation with four wind conditions and four turbines.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"id\": \"cc05bfe7\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Dimensions of `powers`\\n\",\n      \"(4, 4)\\n\",\n      \"\\n\",\n      \"Turbine powers for 8 m/s\\n\",\n      \"Wind condition 0\\n\",\n      \"  Turbine 0 - 1,753.95 kW\\n\",\n      \"  Turbine 1 - 1,753.95 kW\\n\",\n      \"  Turbine 2 -  904.68 kW\\n\",\n      \"  Turbine 3 -  904.85 kW\\n\",\n      \"\\n\",\n      \"Wind condition 1\\n\",\n      \"  Turbine 0 - 1,753.95 kW\\n\",\n      \"  Turbine 1 - 1,753.95 kW\\n\",\n      \"  Turbine 2 - 1,644.86 kW\\n\",\n      \"  Turbine 3 - 1,643.39 kW\\n\",\n      \"\\n\",\n      \"Turbine powers for all turbines at all wind conditions\\n\",\n      \"[[1753.95445918 1753.95445918  904.68478734  904.84672946]\\n\",\n      \" [1753.95445918 1753.95445918 1644.85720431 1643.39012544]\\n\",\n      \" [2496.42786184 2496.42786184 1276.4580679  1276.67310219]\\n\",\n      \" [2496.42786184 2496.42786184 2354.40522998 2352.47398836]]\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"powers = fmodel.get_turbine_powers() / 1000.0  # calculated in Watts, so convert to kW\\n\",\n    \"\\n\",\n    \"print(\\\"Dimensions of `powers`\\\")\\n\",\n    \"print( np.shape(powers) )\\n\",\n    \"\\n\",\n    \"N_TURBINES = fmodel.core.farm.n_turbines\\n\",\n    \"\\n\",\n    \"print()\\n\",\n    \"print(\\\"Turbine powers for 8 m/s\\\")\\n\",\n    \"for i in range(2):\\n\",\n    \"    print(f\\\"Wind condition {i}\\\")\\n\",\n    \"    for j in range(N_TURBINES):\\n\",\n    \"        print(f\\\"  Turbine {j} - {powers[i, j]:7,.2f} kW\\\")\\n\",\n    \"    print()\\n\",\n    \"\\n\",\n    \"print(\\\"Turbine powers for all turbines at all wind conditions\\\")\\n\",\n    \"print(powers)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"8ab273db\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Applying yaw angles\\n\",\n    \"\\n\",\n    \"Yaw angles are another configuration option through `FlorisModel.set`.\\n\",\n    \"In order to fit into the vectorized framework, the yaw settings must be represented as\\n\",\n    \"a `Numpy.array` with  dimensions equal to:\\n\",\n    \"- 0: findex\\n\",\n    \"- 1: number of turbines\\n\",\n    \"\\n\",\n    \"It is typically easiest to start with an array of 0's and modify individual\\n\",\n    \"turbine yaw settings, as shown below.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"id\": \"be78e20d\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Yaw angle array initialized with 0's\\n\",\n      \"[[0. 0. 0. 0.]\\n\",\n      \" [0. 0. 0. 0.]\\n\",\n      \" [0. 0. 0. 0.]\\n\",\n      \" [0. 0. 0. 0.]]\\n\",\n      \"First turbine yawed 25 degrees for every atmospheric condition\\n\",\n      \"[[25.  0.  0.  0.]\\n\",\n      \" [25.  0.  0.  0.]\\n\",\n      \" [25.  0.  0.  0.]\\n\",\n      \" [25.  0.  0.  0.]]\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# Recall that the previous `fmodel.set()` command set up four atmospheric conditions\\n\",\n    \"# and there are 4 turbines in the farm.  So, the yaw angles array must be 4x4.\\n\",\n    \"yaw_angles = np.zeros((4, 4))\\n\",\n    \"print(\\\"Yaw angle array initialized with 0's\\\")\\n\",\n    \"print(yaw_angles)\\n\",\n    \"\\n\",\n    \"print(\\\"First turbine yawed 25 degrees for every atmospheric condition\\\")\\n\",\n    \"yaw_angles[:, 0] = 25\\n\",\n    \"print(yaw_angles)\\n\",\n    \"\\n\",\n    \"fmodel.set(yaw_angles=yaw_angles)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"1ef54dc5\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Start to finish\\n\",\n    \"\\n\",\n    \"Let's put it all together. The code below outlines these steps:\\n\",\n    \"1. Load an input file\\n\",\n    \"2. Modify the inputs with a more complex wind turbine layout and additional atmospheric conditions\\n\",\n    \"3. Calculate the velocities at each turbine for all atmospheric conditions\\n\",\n    \"4. Get the total farm power\\n\",\n    \"5. Develop the yaw control settings\\n\",\n    \"6. Calculate the velocities at each turbine for all atmospheric conditions with the new yaw settings\\n\",\n    \"7. Get the total farm power\\n\",\n    \"8. Compare farm power with and without wake steering\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"id\": \"205738aa\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Power % difference with yaw\\n\",\n      \"    270 degrees: 0.16%\\n\",\n      \"    280 degrees: 0.17%\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# 1. Load an input file\\n\",\n    \"fmodel = FlorisModel(\\\"gch.yaml\\\")\\n\",\n    \"\\n\",\n    \"# 2. Modify the inputs with a more complex wind turbine layout\\n\",\n    \"D = 126.0  # Design the layout based on turbine diameter\\n\",\n    \"x = [0, 0,  6 * D, 6 * D]\\n\",\n    \"y = [0, 3 * D, 0, 3 * D]\\n\",\n    \"wind_directions = [270.0, 280.0]\\n\",\n    \"wind_speeds = [8.0, 8.0]\\n\",\n    \"turbulence_intensities = [0.1, 0.1]\\n\",\n    \"\\n\",\n    \"# Pass the new data to FlorisInterface\\n\",\n    \"fmodel.set(\\n\",\n    \"    layout_x=x,\\n\",\n    \"    layout_y=y,\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# 3. Calculate the velocities at each turbine for all atmospheric conditions\\n\",\n    \"# All turbines have 0 degrees yaw\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"# 4. Get the total farm power\\n\",\n    \"turbine_powers = fmodel.get_turbine_powers() / 1000.0  # Given in W, so convert to kW\\n\",\n    \"farm_power_baseline = np.sum(turbine_powers, 1)  # Sum over the second dimension\\n\",\n    \"\\n\",\n    \"# 5. Develop the yaw control settings\\n\",\n    \"yaw_angles = np.zeros( (2, 4) )    # Construct the yaw array with dimensions for two wind directions, one wind speed, and four turbines\\n\",\n    \"yaw_angles[0, 0] = 25           # At 270 degrees, yaw the first turbine 25 degrees\\n\",\n    \"yaw_angles[0, 1] = 15           # At 270 degrees, yaw the second turbine 15 degrees\\n\",\n    \"yaw_angles[1, 0] = 10           # At 280 degrees, yaw the first turbine 10 degrees\\n\",\n    \"yaw_angles[1, 1] = 0            # At 280 degrees, yaw the second turbine 0 degrees\\n\",\n    \"fmodel.set(yaw_angles=yaw_angles)\\n\",\n    \"\\n\",\n    \"# 6. Calculate the velocities at each turbine for all atmospheric conditions with the new yaw settings\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"# 7. Get the total farm power\\n\",\n    \"turbine_powers = fmodel.get_turbine_powers() / 1000.0\\n\",\n    \"farm_power_yaw = np.sum(turbine_powers, 1)\\n\",\n    \"\\n\",\n    \"# 8. Compare farm power with and without wake steering\\n\",\n    \"difference = 100 * (farm_power_yaw - farm_power_baseline) / farm_power_baseline\\n\",\n    \"print(\\\"Power % difference with yaw\\\")\\n\",\n    \"print(f\\\"    270 degrees: {difference[0]:4.2f}%\\\")\\n\",\n    \"print(f\\\"    280 degrees: {difference[1]:4.2f}%\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"99b7465c\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Visualization\\n\",\n    \"\\n\",\n    \"While comparing turbine and farm powers is meaningful, a picture is worth at least\\n\",\n    \"1000 Watts, and `FlorisModel` provides powerful routines for visualization.\\n\",\n    \"\\n\",\n    \"The visualization functions require that the user select a single atmospheric condition\\n\",\n    \"to plot. The internal data structures still have the same shape but the wind speed and\\n\",\n    \"wind direction dimensions have a size of 1. This means that the yaw angle array used\\n\",\n    \"for plotting must have the same shape as above but a single atmospheric condition must\\n\",\n    \"be selected.\\n\",\n    \"\\n\",\n    \"Let's create a horizontal slice of each atmospheric condition from above with and without\\n\",\n    \"yaw settings included.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 9,\n   \"id\": \"8bb179ff\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAABNwAAAKqCAYAAADhZ0P2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd7wcV33//9e07Xdv173qzbLlinHBNsZUgxMbCL3E4WeTBALY+dJCgCSATTOQEJptCCHfwDcYHBJ6MWCMAeMqWa5qlm1Zxeq6ddvslPP748zM7t6ieq+kK3+ej8c+dndmtlxpd+fMez7nHEMppRBCCCGEEEIIIYQQQkwJ82i/ASGEEEIIIYQQQgghjicSuAkhhBBCCCGEEEIIMYUkcBNCCCGEEEIIIYQQYgpJ4CaEEEIIIYQQQgghxBSSwE0IIYQQQgghhBBCiCkkgZsQQgghhBBCCCGEEFNIAjchhBBCCCGEEEIIIaaQBG5CCCGEEEIIIYQQQkwhCdyEEEIIIYQQQgghhJhCErgJIcQkDMPgmmuuSe5/85vfxDAMnnrqqaP2ng7ElVdeyaJFi4722xBCCCGEEIdB2nRCzGwSuAkhDtiKFSu4+uqrOfXUU8nn8yxYsIA3vOENPPbYY+O2NQxj0stLX/rSlm3DMORzn/scixcvJpPJcMYZZ/Dd7353Wv+WG2+8EcMwOO+886b1dYQQQgghZqqZ3Pb70z/9Uzo7O9m5c+e4dcPDw8yePZvzzjuPMAyn9HWFECJmH+03IISYOT772c9y55138vrXv54zzjiDHTt2cP3113PWWWdxzz33cNpppyXb/td//de4x69cuZIvfelLvOxlL2tZ/o//+I985jOf4W1vexvnnnsuP/7xj/nzP/9zDMPgTW9607T8LTfddBOLFi3ivvvu4/HHH+eEE07Y72Pe8pa38KY3vYl0Oj0t70kIIYQQ4lgyk9t+N954I6eddhrvfe97+c53vtOy7h/+4R/Ys2cPv/zlLzFNqUERQkwTJYQQB+jOO+9Uruu2LHvsscdUOp1Wl19++X4f/1d/9VfKMAy1ZcuWZNnWrVuV4zjqqquuSpaFYaguuugiNW/ePOX7/tT9AZEnn3xSAeoHP/iB6u3tVddcc82E2wHqYx/72JS//nS74oor1MKFC4/22xBCCCHEDDfT236f/exnFaB+9atfJcvuu+8+ZZqm+vu///spe53pIm06IWY2ifOFEAfsuc99LqlUqmXZsmXLOPXUU1m7du0+H+u6Lt///vd5wQtewLx585LlP/7xj/E8j3e9613JMsMweOc738nWrVu5++67p/aPQFe3dXZ2ctlll/G6172Om2666YAeN9EYbmEYcs011zBnzhxyuRwvetGLWLNmDYsWLeLKK68c99g777yT973vffT29pLP53n1q1/N7t27x73WLbfcwkUXXUQ+n6etrY3LLruM1atXj9vuRz/6EaeddhqZTIbTTjuNH/7whwf97yGEEEIIMZGZ3vZ73/vexxlnnMG73vUuarUaQRDwjne8g4ULF/Kxj32Mhx9+mCuvvJIlS5aQyWTo7+/nL//yL9m7d2/yHA8//DCGYfCTn/wkWXb//fdjGAZnnXVWy+v96Z/+6bjhSqRNJ8QzlwRuQojDopRi586d9PT07HO7X/ziFwwNDXH55Ze3LH/ggQfI5/OcfPLJLcuf85znJOun2k033cRrXvMaUqkUb37zm9mwYQMrVqw4pOf68Ic/zLXXXss555zDP//zP7Ns2TIuueQSyuXyhNv/7d/+LQ899BAf+9jHeOc738lPf/pTrr766pZt/uu//ovLLruMQqHAZz/7WT7ykY+wZs0anve857WEfb/+9a957Wtfi2EYXHfddbzqVa/irW99KytXrjykv0UIIYQQYn9mUtvPtm2+/vWvs3HjRj7xiU9w/fXXs2rVKr761a+Sy+W49dZbefLJJ3nrW9/KV77yFd70pjdx8803c+mll6KUAuC0006jo6ODP/zhD8nz3nHHHZimyUMPPcTIyAigT8LeddddPP/5z0+2kzadEM9wR7nCTggxw/3Xf/2XAtR//Md/7HO71772tSqdTqvBwcGW5ZdddplasmTJuO3L5bIC1Ic+9KGpfLtq5cqVClC33nqrUkp3YZg3b55697vfPW5bxnQp/c///E8FqI0bNyqllNqxY4eybVu96lWvanncNddcowB1xRVXjHvsxRdfrMIwTJa/973vVZZlqaGhIaWUUqOjo6qjo0O97W1va3nOHTt2qPb29pblZ555ppo9e3byWKWU+vWvf60A6X4ghBBCiGkx09p+Sil19dVXK8dxVKFQUG9+85uT5ZVKZdy23/3udxWg/vCHP7S85+c85znJ/de85jXqNa95jbIsS91yyy1KKaVWrVqlAPXjH/9YKSVtOiGEdCkVQhyGdevWcdVVV3HBBRdwxRVXTLrdyMgIP//5z7n00kvp6OhoWVetViechCCTySTrp9JNN91EX18fL3rRiwDdheGNb3wjN998M0EQHNRz3Xbbbfi+39IlAnQV22Te/va3YxhGcv+iiy4iCAI2bdoEwK233srQ0BBvfvOb2bNnT3KxLIvzzjuP22+/HYDt27fz4IMPcsUVV9De3p4830tf+lJOOeWUg/o7hBBCCCEOxExs+wF86lOforu7G9M0+cIXvpAsz2azye1arcaePXs4//zzAVi1alWy7qKLLmLVqlVJD4Y//vGPXHrppZx55pnccccdgK56MwyD5z3veYC06YQQMkupEOIQ7dixg8suu4z29nb+93//F8uyJt32+9//PrVabVyXAtANHdd1xy2v1WrJ+slUq1WGh4dblvX390+6fRAE3HzzzbzoRS9i48aNyfLzzjuPz3/+89x2223jZtHalzgkGzvDaVdXF52dnRM+ZsGCBS334+0GBwcB2LBhAwAvfvGLJ3x8sVhsee1ly5aN2+akk05qaSQKIYQQQhyumdj2ixWLRU466ST27NlDX19fsnxgYIBrr72Wm2++mV27drU8pvl1LrroInzf5+6772b+/Pns2rWLiy66iNWrV7cEbqeccgpdXV2AtOmEEBK4CSEOwfDwMH/6p3/K0NAQd9xxB3PmzNnn9jfddBPt7e28/OUvH7du9uzZ3H777SilWiq/tm/fDrDP5/7v//5v3vrWt7YsU9F4GxP57W9/y/bt27n55pu5+eabJ3yfBxO4HYrJGqfx+w7DENBjfkzUgLRt+dkWQgghxJE1U9t++/OGN7yBu+66iw984AOceeaZFAoFwjDkT/7kT5I2GcA555xDJpPhD3/4AwsWLGDWrFmceOKJXHTRRdx44424rssdd9zBq1/96uQx0qYTQsi3XAhxUGq1Gq94xSt47LHH+M1vfrPfUvft27dz++23c+WVV07YfeDMM8/kG9/4BmvXrm15rnvvvTdZP5lLLrmEW2+99YDf+0033cSsWbO44YYbxq37wQ9+wA9/+EO+9rWv7fPMarOFCxcC8Pjjj7N48eJk+d69e5OKtYO1dOlSAGbNmsXFF1+839eOz542W79+/SG9thBCCCHEWDO57bcvg4OD3HbbbVx77bV8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b32Lb37zm3z0ox+dzrcuhBBCCCH2Qdp5QgghhBCTM5RS6ki92O7du5k1axa///3vef7zn8/w8DC9vb185zvf4XWvex0A69at4+STT+buu+/m/PPP55ZbbuHlL38527Zto6+vD4Cvfe1rfPCDH2T37t2kUqn9vu7IyAjt7e18z1pKzrCm9W8UQgghxPGhogLeEDzB8PAwxWLxaL+dY56084QQQggxUxyJdt4RHcNteHgYgK6uLgDuv/9+PM/j4osvTrZZvnw5CxYs4O677wbg7rvv5vTTT08aYQCXXHIJIyMjrF69+gi+eyGEEEIIMRlp5wkhhBBCNNhH6oXCMOQ973kPF154IaeddhoAO3bsIJVK0dHR0bJtX18fO3bsSLZpboTF6+N1E3FdF9d1k/sjIyNT9WcIIYQQQogxpJ0nhBBCCNHqiFW4XXXVVTz66KPcfPPN0/5a1113He3t7cll/vz50/6aQgghhBDPVNLOE0IIIYRodUQCt6uvvpqf/exn3H777cybNy9Z3t/fT71eZ2hoqGX7nTt30t/fn2wzdjar+H68zVgf/vCHGR4eTi5btmyZwr9GCCGEEELEpJ0nhBBCCDHetAZuSimuvvpqfvjDH/Lb3/6WxYsXt6w/++yzcRyH2267LVm2fv16Nm/ezAUXXADABRdcwCOPPMKuXbuSbW699VaKxSKnnHLKhK+bTqcpFostl/+fvfuOj+yq7///un2aelltb173buy16cWxIU6IScEBvmAnBBJikxCT0AN2GmBDAhjbwLdAyC/UACYhNGOwHWDd1rtu27z2eru2qk677fz+OPdOkbTV0q4kf56Phx4zc+dqNNLMaM687+d8jhBCCCGEmDwyzhNCCCGEOLQp7eF2/fXX87WvfY3vf//7tLS01HpxtLW1kc1maWtr4+1vfzs33ngjnZ2dtLa28u53v5vLLruMSy+9FIArrriCM888k7e+9a3ccsst9Pf385GPfITrr78ez/Om8u4LIYQQQohDkHGeEEIIIcShGUopNWU3bhgTbv/yl7/MddddB0ClUuG9730vX//616lWq1x55ZXccccdTdMItm7dyrve9S7uvfde8vk81157LZ/4xCew7aPLC2W5eCGEEEIcqxOxXPxMJuM8IYQQQsxUJ2KcN6WB23QhAzEhhBBCHCsJ3GYGGecJIYQQ4lidiHHeCVul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9/Anf/In/OQnPzmhv694YZBx3swi47yZTcZ6s4uM82aXGTfOU2JWuOSSS9T1119fuxxFkZo3b576+Mc/fhLvlZjIxz72MXXeeedNeN3g4KByHEd9+9vfrm1bv369AtSqVauUUkr98Ic/VKZpqv7+/to+d955p2ptbVXVanVK77toBqjvfe97tctxHKu+vj5166231rYNDg4qz/PU17/+daWUUuvWrVOAevjhh2v7/OhHP1KGYaidO3cqpZS64447VEdHR9Pj+f73v1+ddtppU/wbibGPqVJKXXvttep3fud3Dvk98phOb3v37lWAuu+++5RSk/d/9n3ve58666yzmn7WNddco6688sqp/pXEC5CM82YOGefNLjLWm11knDf7TPdxnlS4zQK+77N69Wouv/zy2jbTNLn88stZtWrVSbxn4lCefvpp5s2bx7Jly3jLW97Ctm3bAFi9ejVBEDQ9lqeffjqLFi2qPZarVq3inHPOYc6cObV9rrzySoaHh3nqqadO7C8immzZsoX+/v6mx6+trY2VK1c2PX7t7e286EUvqu1z+eWXY5omDz74YG2fl7/85biuW9vnyiuvZOPGjQwMDJyg30Y0uvfee+nt7eW0007jXe96FwcOHKhdJ4/p9DY0NARAZ2cnMHn/Z1etWtV0G+k+8r4rJpuM82YeGefNXjLWm51knDdzTfdxngRus8D+/fuJoqjpCQMwZ84c+vv7T9K9EoeycuVKvvKVr/DjH/+YO++8ky1btvCyl72MkZER+vv7cV2X9vb2pu9pfCz7+/snfKzT68TJk/79D/da7O/vp7e3t+l627bp7OyUx3iaeu1rX8tXv/pV7rnnHj75yU9y33338brXvY4oigB5TKezOI55z3vew0te8hLOPvtsgEn7P3uofYaHhymXy1Px64gXKBnnzSwyzpvdZKw3+8g4b+aaCeM8+5h+IyHE8/a6172udv7cc89l5cqVLF68mG9961tks9mTeM+EEBP5wz/8w9r5c845h3PPPZfly5dz77338prXvOYk3jNxJNdffz1PPvlkU/8kIYSYSjLOE2JmkXHezDUTxnlS4TYLdHd3Y1nWuJU39uzZQ19f30m6V+Jotbe3c+qpp7J582b6+vrwfZ/BwcGmfRofy76+vgkf6/Q6cfKkf//DvRb7+vrGNbkOw5CDBw/KYzxDLFu2jO7ubjZv3gzIYzpd3XDDDfzgBz/gF7/4BQsWLKhtn6z/s4fap7W1VT5Ui0kl47yZTcZ5s4uM9WY/GefNDDNlnCeB2yzgui4XXXQR99xzT21bHMfcc889XHbZZSfxnomjMTo6yjPPPMPcuXO56KKLcByn6bHcuHEj27Ztqz2Wl112GU888UTTP/67776b1tZWzjzzzBN+/0Xd0qVL6evra3r8hoeHefDBB5sev8HBQVavXl3b5+c//zlxHLNy5craPvfffz9BENT2ufvuuznttNPo6Og4Qb+NOJQdO3Zw4MAB5s6dC8hjOt0opbjhhhv43ve+x89//nOWLl3adP1k/Z+97LLLmm4j3Ufed8Vkk3HezCbjvNlFxnqzn4zzprcZN847joUgxDT0jW98Q3mep77yla+odevWqXe+852qvb29aeUNMT28973vVffee6/asmWL+tWvfqUuv/xy1d3drfbu3auUUurP/uzP1KJFi9TPf/5z9cgjj6jLLrtMXXbZZbXvD8NQnX322eqKK65Qa9euVT/+8Y9VT0+P+uAHP3iyfqUXlJGREbVmzRq1Zs0aBah//ud/VmvWrFFbt25VSin1iU98QrW3t6vvf//76vHHH1e/8zu/o5YuXarK5XLtNl772teqCy64QD344IPql7/8pVqxYoV605veVLt+cHBQzZkzR731rW9VTz75pPrGN76hcrmc+uIXv3jCf98XgsM9piMjI+qv//qv1apVq9SWLVvUz372M3XhhReqFStWqEqlUrsNeUynj3e9612qra1N3XvvvWr37t21r1KpVNtnMv7PPvvssyqXy6m/+Zu/UevXr1e33367sixL/fjHPz6hv694YZBx3swh47yZT8Z6s4uM82aXmTbOk8BtFrntttvUokWLlOu66pJLLlEPPPDAyb5LYgLXXHONmjt3rnJdV82fP19dc801avPmzbXry+Wy+vM//3PV0dGhcrmcesMb3qB2797ddBvPPfecet3rXqey2azq7u5W733ve1UQBCf6V3lB+sUvfqGAcV/XXnutUkovF/+3f/u3as6cOcrzPPWa17xGbdy4sek2Dhw4oN70pjepQqGgWltb1R/90R+pkZGRpn0ee+wx9dKXvlR5nqfmz5+vPvGJT5yoX/EF53CPaalUUldccYXq6elRjuOoxYsXq3e84x3jPuTKYzp9TPRYAurLX/5ybZ/J+j/7i1/8Qp1//vnKdV21bNmypp8hxGSTcd7MIOO8mU/GerOLjPNml5k2zjOSOy2EEEIIIYQQQgghhJgE0sNNCCGEEEIIIYQQQohJJIGbEEIIIYQQQgghhBCTSAI3IYQQQgghhBBCCCEmkQRuQgghhBBCCCGEEEJMIgnchBBCCCGEEEIIIYSYRBK4CSGEEEIIIYQQQggxiSRwE0IIIYQQQgghhBBiEkngJoQQQgghhBBCCCHEJJLATQghhBBCCCGEEEKISSSBmxBCCCGEEEIIIYQQk0gCNyGEEEIIIYQQQgghJpEEbkIIIYQQQgghhBBCTCIJ3IQQ4hAMw+Cmm26qXf7KV76CYRg899xzJ+0+HY3rrruOJUuWnOy7IYQQQgghngcZ0wkxs0ngJoQ4ag8//DA33HADZ511Fvl8nkWLFvHGN76RTZs2Tbj/t771LS699FLa29vp6uriFa94Bf/93/89br84jrnllltYunQpmUyGc889l69//etT+rvccccdGIbBypUrp/TnCCGEEELMVDN57Pe6172Ojo4O9uzZM+66oaEh5s6dy8qVK4njeFJ/rhBCpCRwE0IctU9+8pN85zvf4TWveQ2f/exneec738n999/PhRdeyJNPPtm072233cY111xDd3c3n/jEJ/jbv/1bhoaG+K3f+i2++93vNu374Q9/mPe///38xm/8BrfddhuLFi3izW9+M9/4xjem7Hf593//d5YsWcJDDz3E5s2bj+p73vrWt1Iul1m8ePGU3S8hhBBCiOliJo/97rjjDnzf56/+6q/GXfehD32I/fv386UvfQnTlI/EQogpooQQ4ij96le/UtVqtWnbpk2blOd56i1veUvT9hUrVqiLL75YxXFc2zY0NKQKhYJ6/etfX9u2Y8cO5TiOuv7662vb4jhWL3vZy9SCBQtUGIaT/ns8++yzClDf/e53VU9Pj7rpppsm3A9QH/vYxyb950+1a6+9Vi1evPhk3w0hhBBCzHAzfez3yU9+UgHqJz/5SW3bQw89pEzTVO973/sm7edMFRnTCTGzSZwvhDhqL37xi3Fdt2nbihUrOOuss1i/fn3T9uHhYXp7ezEMo7attbWVQqFANputbfv+979PEAT8+Z//eW2bYRi8613vYseOHaxatWrSf49///d/p6Ojg6uuuorf//3f59///d+P6vsm6uEWxzE33XQT8+bNI5fL8apXvYp169axZMkSrrvuunHf+6tf/Yobb7yRnp4e8vn8/8/efcfJWZf7/3/dc08vu7O9pAMhhZZA6MWGoKAexV5Rz9EjRxCB0/ye3znqQcGGoPjFcor6PaJ4VOyiIi2hI0hLIKGEkLZJNrs7fe65574/vz/uMjNbkk2yPdfz8dhHktnNzmz2hvu91/X5XB/e8pa3sGfPnhHPddttt3H22WeTSCRIpVJceOGFrF+/fsTH/eIXv+DYY48lGo1y7LHH8vOf//yA/z2EEEIIIUYz27PflVdeyfHHH8/f/d3fUS6XsSyLj33sYyxatIhPf/rTPPnkk3zwgx/kiCOOIBqN0t3dzYc//GH27t3rf44nn3wSTdP41a9+5T/26KOPomkaJ554YsPzvf71rx8xrkQynRCHLym4CSEOiVKKXbt20d7e3vD4K1/5Sn7/+99z44038tJLL/Hss8/y8Y9/nEwmw+WXX+5/3F/+8hcSiQQrVqxo+PunnHKK//6JdvPNN3PRRRcRDod597vfzXPPPccjjzxyUJ/rU5/6FJ/97GdZs2YNX/7yl1m6dCnnn38+hUJh1I+/7LLLeOKJJ/j0pz/NJZdcwq9//WsuvfTSho/5n//5Hy688EKSySRf/OIX+dd//Vc2bNjAWWed1VDs++Mf/8hb3/pWNE3j2muv5c1vfjMf+tCH+POf/3xQX4sQQgghxP7MpuwXDAb5zne+w+bNm7n66qv5xje+wWOPPcY3v/lN4vE4t99+Oy+++CIf+tCHuPHGG3nXu97FLbfcwgUXXIBSCoBjjz2WdDrN2rVr/c+7bt06AoEATzzxBNlsFnCasPfffz/nnHOO/3GS6YQ4zE3zCjshxCz3P//zPwpQ//Vf/9Xw+K5du9RrXvMaBfhv7e3t6v7772/4uAsvvFAdccQRIz5voVBQgPrnf/7nCX29f/7znxWgbr/9dqWUs4Vh/vz56vLLLx/xsQzbUvrd735XAWrz5s1KKaX6+vpUMBhUb37zmxv+3mc+8xkFqIsvvnjE3z333HMbtlpcccUVStd1NTQ0pJRSKpfLqXQ6rT7ykY80fM6+vj7V3Nzc8PiqVatUT0+P/3eVUuqPf/yjAmT7gRBCCCEmxWzLfkopdemll6pQKKSSyaR697vf7T9eLBZHfOyPfvQjBai1a9c2vOZTTjnF//NFF12kLrroIqXrurrtttuUUko99thjClC//OUvlVKS6YQQsqVUCHEIvM7l6aefzsUXX9zwvng8zrJly7j44ov5yU9+wn//93/T09PDRRdd1HBIQalUIhKJjPjc0WjUf/9Euvnmm+nq6uJVr3oV4GxheOc738ktt9yCZVkH9LnuuOMOqtVqw5YIcFaxjeWjH/1ow1aLs88+G8uy2LJlCwC33347Q0NDvPvd76a/v99/03WdU089lbvuuguAnTt38vjjj3PxxRfT3Nzsf77Xvva1rFy58oC+DiGEEEKI8ZiN2Q/g85//PG1tbQQCAa6//nr/8fqtruVymf7+fk477TQAHnvsMf99Z599No899pi/g+Hee+/lggsuYNWqVaxbtw5wVr1pmsZZZ50FSKYTQkBwul+AEGJ26uvr48ILL6S5uZmf/vSn6Lre8P63v/3tBINBfv3rX/uP/dVf/RVLly7lX/7lX/jxj38MOEHHMIwRn79cLvvvH0upVCKTyTQ81t3dPebHW5bFLbfcwqte9So2b97sP37qqady3XXXcccdd3Deeeft46tu5BXJjjrqqIbHW1tbaWlpGfXvLFy4sOHP3scNDg4C8NxzzwHw6le/etS/39TU1PDcS5cuHfExy5YtawiJQgghhBCHajZmP09TUxPLli2jv7+frq4u//GBgQE++9nPcsstt7B79+6Gv1P/PGeffTbVapUHHniABQsWsHv3bs4++2zWr1/fUHBbuXIlra2tgGQ6IYQU3IQQByGTyfD617+eoaEh1q1bR29vb8P7X3zxRX7/+9/zne98p+Hx1tZWzjrrLO677z7/sZ6eHu666y6UUg0rv3bu3Akw4nPX+/GPf8yHPvShhseUO29jNHfeeSc7d+7klltuGfXY+ZtvvvmACm4HY3g49Xiv27ZtwJn5MVqADAblf9tCCCGEmFqzNfvtzzve8Q7uv/9+/uEf/oFVq1aRTCaxbZvXve51fiYDWLNmDdFolLVr17Jw4UI6Ozs5+uijOfvss7npppswDIN169bxlre8xf87kumEEPJfuRDigJTLZd74xjeyadMm/vSnP4261H3Xrl0Ao27RNE2TarXq/3nVqlX853/+J88880zD53rooYf894/l/PPP5/bbbx/3a7/55pvp7Ozk//7f/zvifbfeeis///nP+da3vrXPzmq9RYsWAfD888+zZMkS//G9e/f6K9YO1JFHHglAZ2cn55577n6f2+ue1tu4ceNBPbcQQgghxHCzOfvty+DgIHfccQef/exn+bd/+zf/8dGyVTgc5pRTTmHdunUsXLiQs88+G3BWvhmGwc0338yuXbsaDkyQTCeEkBluQohxsyyLd77znTzwwAP85Cc/4fTTTx/144466igCgQA//vGPG7qO27ZtY926daxevdp/7K/+6q8IhULcdNNN/mNKKb71rW8xb948zjjjjDFfT09PD+eee27D21hKpRK33norb3jDG3jb29424u3SSy8ll8s1HPm+P695zWsIBoN885vfbHj8G9/4xrg/x3Dnn38+TU1NXHPNNZimOeL9e/bsAZyvfdWqVXz/+99v2PJw++23s2HDhoN+fiGEEEIIz2zOfvvj7ToYvkLuhhtuGPXjzz77bB566CHuuusuv+DW3t7OihUr+OIXv+h/jEcynRBCVrgJIcbtqquu4le/+hVvfOMbGRgY4Ac/+EHD+9/3vvcB0NHRwYc//GH+8z//k9e85jVcdNFF5HI5brrpJkqlEp/61Kf8vzN//nw++clP8uUvfxnTNDn55JP5xS9+wbp167j55pvH3IJ5oH71q1+Ry+V405veNOr7TzvtNDo6Orj55pt55zvfOa7P2dXVxeWXX851113Hm970Jl73utfxxBNPcNttt9He3t6wTWK8mpqa+OY3v8n73/9+TjzxRN71rnfR0dHByy+/zG9/+1vOPPNMv6B37bXXcuGFF3LWWWfx4Q9/mIGBAW688UaOOeYY8vn8AT+3EEIIIUS92Zz99qepqYlzzjmHL33pS5imybx58/jjH//YMOe33tlnn83nP/95tm7d2lBYO+ecc/j2t7/N4sWLmT9/fsPnl0wnxGFuuo5HFULMPq94xSsajnof/lbPNE114403qlWrVqlkMqmSyaR61atepe68884Rn9eyLHXNNdeoRYsWqXA4rI455hj1gx/8YEJf+xvf+EYVjUZVoVAY82M++MEPqlAopPr7+5VSSgHq05/+tP/+7373uwpQmzdv9h+rVqvqX//1X1V3d7eKxWLq1a9+tXrmmWdUW1ub+tjHPjbi7z7yyCMNz3nXXXcpQN11110jHj///PNVc3Ozikaj6sgjj1Qf/OAH1Z///OeGj/vZz36mVqxYoSKRiFq5cqW69dZb1cUX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0oLkc5/7HJqmTbisXbu2fXuz2eTDH/4w3d3dpNNpfu3Xfo29e/dOeI7t27dz7bXXkkwm6evr44/+6I9wXfdEv5V5yQMPPMCv/MqvMDg4iKZp3HXXXRNuV0rxmc98hiVLlpBIJLjqqqt48cUXJ9xndHSU97znPWSzWfL5PB/4wAeoVqsT7vPss89yxRVXEI/HWb58ObfeeutMv7V5yeE+j/e///0H/b286U1vmnAf+Tymj5tvvpmLLrqITCZDX18fb3vb29i8efOE+0zX/6j77ruP888/n1gsxurVq/nmN785029PEBY1ovNODKLzZhfReXMP0XpzB9F5x44YbsJx8e1vf5sbbriBz372szz11FOce+65XHPNNezbt2+2D21BcuaZZ7Jnz5725aGHHmrfdv311/Of//mffOc73+H+++9n9+7dvP3tb2/f7nke1157LbZt8/DDD/MP//APfPOb3+Qzn/nMbLyVeUetVuPcc8/lq1/96qS333rrrXz5y1/m61//Oo899hipVIprrrmGZrPZvs973vMeNmzYwN133833v/99HnjgAX7/93+/fXu5XObqq69m5cqVPPnkk9x222187nOf4xvf+MaMv7/5xuE+D4A3velNE/5evvWtb024XT6P6eP+++/nwx/+MI8++ih33303juNw9dVXU6vV2veZjv9Rr7zyCtdeey2ve93rePrpp7nuuuv4vd/7PX70ox+d0PcrCIsF0XknFtF5s4fovLmHaL25g+i840AJwnFw8cUXqw9/+MPt7z3PU4ODg+rmm2+exaNamHz2s59V55577qS3FYtFZZqm+s53vtP+2caNGxWgHnnkEaWUUj/4wQ+UrutqaGiofZ+vfe1rKpvNKsuyZvTYFxqA+vd///f2977vq4GBAXXbbbe1f1YsFlUsFlPf+ta3lFJKPf/88wpQTzzxRPs+P/zhD5WmaWrXrl1KKaX+5m/+RhUKhQmfx4033qjWrFkzw+9ofnPg56GUUu973/vUW9/61ikfI5/HzLJv3z4FqPvvv18pNX3/oz75yU+qM888c8JrvfOd71TXXHPNTL8lQViUiM47cYjOmzuIzpt7iNabW4jOO3Ikw004Zmzb5sknn+Sqq65q/0zXda666ioeeeSRWTyyhcuLL77I4OAgJ598Mu95z3vYvn07AE8++SSO40z4LNauXcuKFSva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\",\n      \"text/plain\": [\n       \"<Figure size 1500x800 with 4 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"from floris.flow_visualization import visualize_cut_plane\\n\",\n    \"from floris.layout_visualization import plot_turbine_labels\\n\",\n    \"\\n\",\n    \"fig, axarr = plt.subplots(2, 2, figsize=(15,8))\\n\",\n    \"\\n\",\n    \"# Plot the first wind condition\\n\",\n    \"wd = wind_directions[0]\\n\",\n    \"ws = wind_speeds[0]\\n\",\n    \"ti = turbulence_intensities[0]\\n\",\n    \"\\n\",\n    \"fmodel.reset_operation()\\n\",\n    \"fmodel.set(wind_speeds=[ws], wind_directions=[wd], turbulence_intensities=[ti])\\n\",\n    \"horizontal_plane = fmodel.calculate_horizontal_plane(height=90.0)\\n\",\n    \"visualize_cut_plane(horizontal_plane, ax=axarr[0,0], title=\\\"270 - Aligned\\\")\\n\",\n    \"plot_turbine_labels(fmodel, axarr[0,0])\\n\",\n    \"\\n\",\n    \"fmodel.set(yaw_angles=yaw_angles[0:1])\\n\",\n    \"horizontal_plane = fmodel.calculate_horizontal_plane(height=90.0)\\n\",\n    \"visualize_cut_plane(horizontal_plane, ax=axarr[0,1], title=\\\"270 - Yawed\\\")\\n\",\n    \"plot_turbine_labels(fmodel, axarr[0,1])\\n\",\n    \"\\n\",\n    \"# Plot the second wind condition\\n\",\n    \"wd = wind_directions[1]\\n\",\n    \"ws = wind_speeds[1]\\n\",\n    \"ti = turbulence_intensities[1]\\n\",\n    \"\\n\",\n    \"fmodel.reset_operation()\\n\",\n    \"fmodel.set(wind_speeds=[ws], wind_directions=[wd], turbulence_intensities=[ti])\\n\",\n    \"horizontal_plane = fmodel.calculate_horizontal_plane(height=90.0)\\n\",\n    \"visualize_cut_plane(horizontal_plane, ax=axarr[1,0], title=\\\"280 - Aligned\\\")\\n\",\n    \"plot_turbine_labels(fmodel, axarr[1,0])\\n\",\n    \"\\n\",\n    \"fmodel.set(yaw_angles=yaw_angles[1:2])\\n\",\n    \"horizontal_plane = fmodel.calculate_horizontal_plane(height=90.0)\\n\",\n    \"visualize_cut_plane(horizontal_plane, ax=axarr[1,1], title=\\\"280 - Yawed\\\")\\n\",\n    \"plot_turbine_labels(fmodel, axarr[1,1])\\n\",\n    \"\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"d84cf194\",\n   \"metadata\": {},\n   \"source\": [\n    \"We can also plot the streamwise inflow velocities on the turbine rotor\\n\",\n    \"grid points located on the rotor plane. The `plot_rotor_values` function\\n\",\n    \"simply plots any data given as the first argument, so in this case\\n\",\n    \"`fi.floris.flow_field.u` contains the yawed calculation from above.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 10,\n   \"id\": \"4eaa8343\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Set the FlorisModel as it was before visualizing the cut planes\\n\",\n    \"fmodel.reset_operation()\\n\",\n    \"fmodel.set(\\n\",\n    \"    layout_x=x,\\n\",\n    \"    layout_y=y,\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities,\\n\",\n    \")\\n\",\n    \"fmodel.run()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 11,\n   \"id\": \"3e517614\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAAgoAAAFyCAYAAACUWPJkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAuPUlEQVR4nO3de1xVZaL/8e8G5ZqQJQooIl6mjLTStAE1cjJJyW4TVsdG7KKVlaOlTZ5+peWkWWPq6aJZhqZmx7SLjZZpI1MqlZ6pSS2lRgUysHolYMhF935+fzjsaQtLWO4t2w2f9+u1Xuew9nqe9ez9yPDtuaztMMYYAQAA1CHI3w0AAACnL4ICAACwRFAAAACWCAoAAMASQQEAAFgiKAAAAEsEBQAAYImgAAAALBEUAACAJYICmp2cnBw5HA7l5OScNnVOnTpVDofD41ynTp00atQo7xvnQ6djmwCcWgQFBJQVK1bI4XDorbfeqvXaBRdcIIfDoY0bN9Z6rWPHjkpNTW2MJga8LVu2aOrUqSopKfF3U9y2bt2qe++9V8nJyYqMjFTHjh01fPhw5eXl1brW4XBYHldccYXHtS6XS0899ZSSkpIUFhamnj17avny5Y31toCA0MLfDQDs6N+/vyRp06ZNuu6669zny8rKtGPHDrVo0UKbN2/WwIED3a8VFhaqsLBQN910kyTp0ksvVUVFhUJCQhq38Tbt3r1bQUGNn+W3bNmixx57TKNGjdKZZ555WrRp5syZ2rx5szIzM9WzZ08VFxfrueeeU69evfTJJ5/o/PPPd1+7ZMmSWuW3bdumuXPnavDgwR7nH374YT355JMaPXq0+vTpo3feeUf/9V//JYfD4f73AjR3BAUElPj4eCUlJWnTpk0e53Nzc2WMUWZmZq3Xan6uCRlBQUEKCwtrnAZ7ITQ0tN5rysvLFRkZ2QitOaYhbToV7r//fr322mse4e7GG29Ujx499OSTT2rp0qXu87fcckut8jVTQzfffLP73P79+zVr1izdc889eu655yRJd9xxh9LS0jRp0iRlZmYqODj4FL4rIDAw9YCA079/f33++eeqqKhwn9u8ebOSk5M1ZMgQffLJJ3K5XB6vORwO9evXT1Ld6wkuu+wynX/++frqq680cOBARUREqH379nrqqadq3f+7777Ttddeq8jISLVt21YTJkxQVVVVg9u/adMm9enTR2FhYerSpYtefPHFOq87fj3AokWL5HA49Pe//11jx45V27Zt1aFDB/fr7733ngYMGKDIyEi1atVKGRkZ2rlzZ616d+3apeHDhysmJkbh4eE655xz9PDDD0s6tlZi0qRJkqSkpCT3kP2+ffvqbJMk7dmzR5mZmTrrrLMUERGh3/72t1qzZo3HNTWf+YoVK/TEE0+oQ4cOCgsL0+WXX65vv/223s8sNTW11ghQt27dlJycrK+//vqEZauqqrRq1SqlpaV5fF7vvPOOjhw5orFjx7rPORwO3X333fruu++Um5tbb7uA5oARBQSc/v37a8mSJfr000912WWXSToWBlJTU5WamqrS0lLt2LFDPXv2dL927rnn6uyzzz5hvQcPHtSVV16p66+/XsOHD9fKlSv1pz/9ST169NCQIUMkSRUVFbr88stVUFCgcePGKT4+XkuWLNHf/va3BrV9+/btGjx4sGJiYjR16lQdPXpUU6ZMUbt27Rr8/seOHauYmBg9+uijKi8vl3RsuD0rK0vp6emaOXOmDh8+rHnz5rlDVadOnSRJX375pQYMGKCWLVtqzJgx6tSpk/71r3/p3Xff1RNPPKHrr79eeXl5Wr58uWbPnq02bdpIkmJiYupsy4EDB5SamqrDhw9r3LhxOvvss7V48WJdffXVWrlypcf0kCQ9+eSTCgoK0sSJE1VaWqqnnnpKI0aM0Kefftrg91/DGKMDBw4oOTn5hNetXbtWJSUlGjFihMf5zz//XJGRkerevbvH+b59+7pfrxmFApo1AwSYnTt3Gklm2rRpxhhjjhw5YiIjI83ixYuNMca0a9fOPP/888YYY8rKykxwcLAZPXq0u/zGjRuNJLNx40b3ubS0NCPJvPrqq+5zVVVVJjY21vz+9793n5szZ46RZFasWOE+V15ebrp27Vqrzrpce+21JiwszOTn57vPffXVVyY4ONgc/+uYmJhosrKy3D9nZ2cbSaZ///7m6NGj7vOHDh0yZ555psd7NMaY4uJiEx0d7XH+0ksvNa1atfK4vzHGuFwu9///9NNPG0lm7969tdp/fJvGjx9vJJmPP/7Yoz1JSUmmU6dOxul0GmP+85l3797dVFVVua+dO3eukWS2b99e18d1QkuWLDGSzMKFC0943e9//3sTGhpqDh486HE+IyPDdO7cudb15eXlRpJ56KGHbLcJaIqYekDA6d69u84++2z32oN//vOfKi8vd+9qSE1N1ebNmyUdW7vgdDob9F+GZ5xxhsf8dkhIiPr27as9e/a4z61du1ZxcXG64YYb3OciIiI0ZsyYeut3Op1at26drr32WnXs2NHj/aSnp9dbvsbo0aM95s7Xr1+vkpIS3Xzzzfrpp5/cR3BwsC655BL3LpAff/xRH330kW677TaP+0uqtTWzodauXau+fft6fL5nnHGGxowZo3379umrr77yuP7WW2/1mEIYMGCAJHl8xg2xa9cu3XPPPUpJSVFWVpbldWVlZVqzZo2GDh1aa2FmRUVFnWsuatav/HpqC2jOCAoIOA6HQ6mpqe61CJs3b1bbtm3VtWtXSZ5Boeb/NiQodOjQodYfzNatW+vgwYPun/Pz89W1a9da151zzjn11v/jjz+qoqJC3bp1q/VaQ8rXSEpK8vj5m2++kST97ne/U0xMjMfxwQcf6IcffpD0nz/Gv94h4K38/Pw6214znJ+fn+9x/viA0rp1a0ny+IzrU1xcrIyMDEVHR2vlypUnXHC4atUqVVZW1pp2kKTw8PA615ZUVla6XwfAGgUEqP79++vdd9/V9u3b3esTaqSmpmrSpEnav3+/Nm3apPj4eHXu3LneOq3+4BhjfNZuXzj+D1jNws0lS5YoNja21vUtWpw+v+befsalpaUaMmSISkpK9PHHHys+Pv6E1y9btkzR0dG66qqrar0WFxenjRs3yhjjEfyKiookqd66gebi9PlfEMCGXz9PYfPmzRo/frz7td69eys0NFQ5OTn69NNPNXToUJ/dNzExUTt27Kj1x2X37t31lq3ZZVAzAvBrDSlvpUuXLpKktm3batCgQZbX1YSlHTt2nLA+O9MQiYmJdbZ9165d7td9pbKyUsOGDVNeXp42bNig884774TXFxUVaePGjRo1alSdUwwXXnihXn75ZX399dceddUsrLzwwgt91nYgkDH1gIB08cUXKywsTMuWLdP+/fs9RhRCQ0PVq1cvPf/88yovL/fpyvWhQ4fq+++/18qVK93nDh8+rAULFtRbNjg4WOnp6Xr77bdVUFDgPv/1119r3bp1J92m9PR0RUVFafr06Tpy5Eit13/88UdJx4LKpZdeqldeecXj/pLnf9HXPJehIU9mHDp0qD777DOPrYTl5eVasGCBOnXqVO8f84ZyOp268cYblZubqzfeeEMpKSn1lnn99dflcrnqnHaQpGuuuUYtW7bUCy+84D5njNH8+fPVvn17nuQJ/BsjCghIISEh6tOnjz7++GOFhoaqd+/eHq+npqZq1qxZkhq2PqGhRo8ereeee04jR47U//3f/ykuLk5LlixRREREg8o/9thjev/99zVgwACNHTtWR48e1bPPPqvk5GR9+eWXJ9WmqKgozZs3T3/4wx/Uq1cv3XTTTYqJiVFBQYHWrFmjfv36uR8o9D//8z/q37+/evXqpTFjxigpKUn79u3TmjVr9MUXX0iS+7N8+OGHddNNN6lly5YaNmxYnQ92euihh7R8+XINGTJE48aN01lnnaXFixdr7969WrVqlc+e4vjAAw9o9erVGjZsmH7++WePByxJdT9kadmyZYqPj3dvoT1ehw4dNH78eD399NM6cuSI+vTpo7ffflsff/yxli1bxsOWgBr+3HIBeGPy5MlGkklNTa312ptvvmkkmVatWnlsJTTGentkcnJyrXqysrJMYmKix7n8/Hxz9dVXm4iICNOmTRvzxz/+0bz//vsN2h5pjDF///vfTe/evU1ISIjp3LmzmT9/vpkyZUqDt0du3bq1zno3btxo0tPTTXR0tAkLCzNdunQxo0aNMtu2bfO4bseOHea6664zZ555pgkLCzPnnHOOeeSRRzyumTZtmmnfvr0JCgry2Cp5fJuMMeZf//qXueGGG9z19e3b1/z1r3+t1TZJ5o033vA4v3fvXiPJZGdnn/Azq9m+anUcb9euXUaSuf/++09Yr9PpNNOnTzeJiYkmJCTEJCcnm6VLl56wDNDcOIw5zVZqAQCA0wZrFAAAgCWCAgAAsERQAAAAlggKAADAEkEBAABYIigAAABLBAUAAGCJoAAAACwRFAAAgCWCAgAAsERQAAAAlggKAADAEkEBAABYIigAAABLBAUAAGCJoAAAACwRFAAAgCWCAgAAsERQAAAAlggKAADAEkEBAABYIigAAABLBAUAAGCJoAAAACwRFAAAgCWCAgAAsERQAAAAlggKAADAEkEBAABYIigAAABLBAUAAGCJoAAAACwRFAAAgCWCAgAAsERQAAAAlggKAADAEkEBAABYIigAAABLBAUAAGCJoAAAACwRFAAAgCWCAgAAsERQAAAAlggKAADAEkEBAABYIigAAABLBAUAAGCJ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G379wCRv6ggUBAUAAGwwLiPj5V96b8s3JoICAAA2+OM5Cv5EUAAAwAZ/PJnRnwgKAADYwGJGAABgybi8397I9kgAAJoolzFyeTki4G35xkRQAADABqYeAACAJRYzAgAAS2yPBAAAlozxwQOXAigpEBQAALDB5XTJ6fRu24LLy/KNiaAAAIANPMIZAABY4kuhAACAJUYUAACAJZ6jAAAALLlc3j8HwRU4axkJCgAA2MGIAgAAsMQaBQAAYImgAAAALLnkg2+PFEEBAIAmiREFAABgicWMAADAkvHB10wzogAAQBPF1AMAALDE1AMAALDkPOpUULDT6zoCBUEBAAAbGFEAAACWWKMAAAAsERQAAIAll1xyGe++/tGlwPn6SIICAAA2GJf3IwJe5oxGRVAAAMAGph4AAIAldj0AAABLLpdLLpeXaxS8LN+YgvzdAAAAAknN1IO3h1379+/XLbfcorPPPlvh4eHq0aOHtm3bdsIyOTk56tWrl0JDQ9W1a1ctWrTI9n0JCgAA2GCMyyeHHQcPHlS/fv3UsmVLvffee/rqq680a9YstW7d2rLM3r17lZGRoYEDB+qLL77Q+PHjdccdd2jdunW27s3UAwAANvhjMePMmTOVkJCg7Oxs97mkpKQTlpk/f76SkpI0a9YsSVL37t21adMmzZ49W+np6Q2+NyMKAADY4Ytph38HhbKyMo+jqqqqzluuXr1aF198sTIzM9W2bVtddNFFeumll07YzNzcXA0aNMjjXHp6unJzc229XYICAAA2uIzLJ4ckJSQkKDo62n3MmDGjznvu2bNH8+bNU7du3bRu3TrdfffdGjdunBYvXmzZzuLiYrVr187jXLt27VRWVqaKiooGv1+mHgAAsMGXUw+FhYWKiopynw8NDa3zepfLpYsvvljTp0+XJF100UXasWOH5s+fr6ysLK/aUh+CAgAANricTrm8/Jpol/NY+aioKI+gYCUuLk7nnXeex7nu3btr1apVlmViY2N14MABj3MHDhxQVFSUwsPDG9xWggIAADaczK6Fuuqwo1+/ftq9e7fHuby8PCUmJlqWSUlJ0dq1az3OrV+/XikpKbbuzRoFAABscLkkl8t4edi754QJE/TJJ59o+vTp+vbbb/Xaa69pwYIFuueee9zXTJ48WSNHjnT/fNddd2nPnj168MEHtWvXLr3wwgtasWKFJkyYYOveBAUAAGwwLpdPDjv69Omjt956S8uXL9f555+vadOmac6cORoxYoT7mqKiIhUUFLh/TkpK0po1a7R+/XpdcMEFmjVrll5++WVbWyMlyWEC6YHTAAD4SVlZmaKjo5V61Qdq0TLSq7qOHinXlr8OVmlpaYPWKPgTaxQAALDBH2sU/ImgAACADXzNNAAAsHS0+pDtNQbHcx4t91FrTj2CAgAADRASEqLY2Fht+3C4T+qLjY1VSEiIT+o6lVjMCABAA1VWVqq6utondYWEhCgsLMwndZ1KBAUAAGCJ5ygAAABLBAUAAGCJoAAAACwRFAAAgCWCAgAAsERQAAAAlggKAADA0v8HFGft/M49IjUAAAAASUVORK5CYII=\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 5 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"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P2rZsmWefSdOnCj0F2xRgoOD1bNnT61YsUJZWVme/Xv27NGaNWtK3KaePXsqIiJCkyZN0pkzZwq9//PPP0s6F1Q6d+6sefPmeZ1f8v6LPjw8XJKKdWfG3r17a9u2bV6XEubl5WnOnDmKi4sr8pd5SbhcLt1xxx3asmWLli5dqg4dOhR5XNOmTRUUFKR33nnH6zP98MMP2rBhg6699lrPvltuuUWVK1fWyy+/7NlnjNErr7yi+vXrcydP4D8YUUCZFBISorZt22rDhg0KDQ1VmzZtvN5PTEzUCy+8IKl46xOK68EHH9RLL72kAQMG6F//+pfq1aunBQsWqGrVqsUqP378eH300Ufq1KmThgwZorNnz2rWrFlKSEjwWgvhREREhGbPnq17771X1113ne68805FRUUpKytLq1at0vXXX+9Zs/E///M/6tixo6677joNGjRIjRs31oEDB7Rq1Sp98cUXkuT5LkePHq0777xTlStXVnJysidA/NbIkSO1ePFi9erVS4888ohq1aql+fPna//+/Xr33XcVFOSfv0X+9re/6f3331dycrJ+/fVXLVy40Ov9gkWoUVFRSk1N1euvv66uXbvq9ttv17Fjx/Tyyy/r5MmTGjVqlKdMgwYNNGzYMD333HM6c+aM2rZtqxUrVmjDhg166623bKdJgAongFdcAD4ZNWqUkWQSExMLvbd8+XIjyVSvXr3QHfbsLo9MSEgoVE9KSopp1KiR177MzExz8803m6pVq5ratWubRx991Hz00UfFvjPjP//5T9OmTRsTEhJimjRpYl555ZUi78xod3nk9u3bi6x37dq1pmfPniYyMtKEhYWZ+Ph4M3DgQPPZZ595Hbdr1y5z2223mRo1apiwsDDTvHlzM2bMGK9jJkyYYOrXr2+CgoK8LpU8v03GGPP999+bPn36eOpr166d+eCDDwq1TZJZunSp1/79+/cbSSYtLe2C31nB5at222+dOXPGzJo1y1xzzTWmWrVqplq1aubGG280n3zySaF6XS6XmTRpkmnUqJEJCQkxCQkJZuHChRdsC1DRWMZcZiu1AADAZYM1CgAAwBZBAQAA2CIoAAAAWwQFAABgi6AAAABsERQAAIAtggIAALBFUAAAALYICgAAwBZBAQAA2CIoAAAAWwQFAABgi6AAAABsERQAAIAtggIAALBFUAAAALYICgAA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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 5 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"from floris.flow_visualization import plot_rotor_values\\n\",\n    \"\\n\",\n    \"fig, _, _ , _ = plot_rotor_values(fmodel.core.flow_field.u, findex=0, n_rows=1, n_cols=4, return_fig_objects=True)\\n\",\n    \"fig.suptitle(\\\"Wind direction 270\\\")\\n\",\n    \"\\n\",\n    \"fig, _, _ , _ = plot_rotor_values(fmodel.core.flow_field.u, findex=1, n_rows=1, n_cols=4, return_fig_objects=True)\\n\",\n    \"fig.suptitle(\\\"Wind direction 280\\\")\\n\",\n    \"\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"4dc966e1\",\n   \"metadata\": {},\n   \"source\": [\n    \"## On grid points\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"e8241714\",\n   \"metadata\": {},\n   \"source\": [\n    \"In FLORIS, grid points are the points in space where the wind conditions are calculated.\\n\",\n    \"In a typical simulation, these are all located on a regular grid on each turbine rotor.\\n\",\n    \"\\n\",\n    \"The parameter `turbine_grid_points` specifies the number of rows and columns which define the turbine grid.\\n\",\n    \"In the example inputs, this value is 3 meaning there are 3 x 3 = 9 total grid points for each turbine.\\n\",\n    \"Wake steering codes currently require greater values greater than 1 in order to compute gradients.\\n\",\n    \"However, a single grid point (1 x 1) may be suitable for non wind farm control applications,\\n\",\n    \"but retuning of some parameters might be required.\\n\",\n    \"\\n\",\n    \"We can visualize the locations of the grid points in the current example using `matplotlib.pyplot`.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 12,\n   \"id\": \"774acfea\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"shape of xs: (2, 4, 3, 3)\\n\",\n      \"  2 wd x 2 ws x 4 turbines x 3 x 3 grid points\\n\"\n     ]\n    },\n    {\n     \"data\": {\n      \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAAZsAAAGQCAYAAAB4X807AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAADViklEQVR4nOz9d3gkZ50tjp/OQaFbOUsjaZRGM6NRmNFoxhgDxgYMmLAsZrnsLL6EaxxIX2DZa8Brks1ydwfMYgM/roELXnaXYEywvcYBp/EESa2cc+4sqXOo+v2hfcvVpQ7V3dXq7nGd5+HZtaR5u7q6+j3vJ50joWmahggRIkSIEJFCSNN9ASJEiBAh4uqHSDYiRIgQISLlEMlGhAgRIkSkHCLZiBAhQoSIlEMkGxEiRIgQkXKIZCNChAgRIlIOkWxEiBAhQkTKIZKNCBEiRIhIOUSyESFChAgRKYdINiJEiBAhIuUQyUaECBEiRKQcItmIECFChIiUQyQbESJEiBCRcohkI0KECBEiUg6RbESIECFCRMohko0IESJEiEg5RLIRIUKECBEph0g2IkSIECEi5RDJRoQIESJEpBwi2YgQIUKEiJRDJBsRIkSIEJFyiGQjQoQIESJSDpFsRIgQIUJEyiGSjQgRIkSISDlEshEhQoQIESmHSDYiRIgQISLlEMlGhAgRIkSkHCLZiBAhQoSIlEMkGxEiRIgQkXKIZCNChAgRIlIOkWxEiBAhQkTKIZKNCBEiRIhIOUSyESFChAgRKYdINiJEiBAhIuUQyUaECBEiRKQcItmIECFChIiUQyQbEQcOmqYRDAZB03S6L0WECBEHBHm6L0DEawsURSEQCMDlckEqlUIul0Mul0Mmk0EqlUIikaT7EkWIEJECSGjxeCniAEDTNCiKgt/vB0VR8Hq9Ib+TSqUi+YgQcRVDJBsRKQdN0wgEAhgbG0NhYSFKSkrg8/kglUqZ3xMyIpBIJJBKpVAoFJDJZJDL5ZBIJCL5iBCRpRDTaCJSChLNBINBOBwO5ObmAkAIaRAS4ZJPMBhEIBBgfk9Ih0Q+IvmIEJE9EMlGRErAJguKopiUGAmkyf8NRxaRyCcQCMDv94eQD4l8SNpNhAgRmQmRbEQIDpqmmWgGAEM0iUYhkchnZ2cHw8PDOH36tEg+IkRkOESyESEoKIqCz+cLiWYI2JFNMmBHNoFAADKZLCTyAbCv2UAkHxEi0guRbEQIApI28/v9THcZN5IRimzY65H/Gy7y8fv98Pl8zO9F8hEhIn0QyUZE0oiUNuNCaLIhrx3udbjkQxoVSOTDJR/S7SZChIjUQCQbEUmBRDPh0mbhQNO0YJs633VIyo19DYR8wkU+7G43ESJECAORbEQkBFIjCQQCACJHM2wcVGQTC3zIRyqV7ms4EMlHhIjEIZKNiLjBVgIAwLv2wSabTNq4+ZIPt+aTSe9BhIhMh0g2IniDKzkTr5wMIRuapuFyuaBWq0M2+XhBXlvI1BxZl1wXIUfSZef1ekXyESEiAYhkI4IX+DYBRINEIkEwGITBYIDRaIRMJkNBQQH0ej0KCgqQm5ubcRs2uR6RfESISA4i2YiICbbkTDLimD6fD5ubmygoKMDZs2fh9Xpht9ths9mwsLAAqVTKEE9BQQG0Wm3U10rHZh6OfMj/vF4vfD4fgPBzPiL5iHgtQyQbERFB0zR8Ph9WV1dRVlaWcHswTdNYWFiAyWRCQUEBOjs74ff7oVQqkZ+fj9raWlAUhd3dXdhsNphMJszOzkIulzPEU1BQAI1GE3H9dG3kbGUEMlzKJh8S+VAUBZlMBq1WKypai3hNQiQbEWHBHoocHR1FaWlpQpuj1+vFyMgInE4nysrKoFarw64jlUqh0+mg0+lw6NAhBINB7OzswGazYWNjA1NTU1CpVCHkk4mbdSTyWV9fh81mw5EjR0IUrUU7BRGvFYhkI2IfuLMzicJisWB4eBgFBQU4c+YMZmdnebcqk3pOQUEBc00k5ba6uorx8XEm0jEajSgsLIRSqUz4WlMFQj7sWR5CQB6Ph/kbrqK1SD4irjaIZCOCAXt2hkjOcFWa+YCiKMzNzWFxcREtLS2oqalhNlu2Z008kMlkKCoqQlFREQAgEAjAbDZjfHwcS0tLGB8fR05ODkNQer0eCoUioddKFdikA4RGPhRFMeQjGsmJuBohko0IAK/aNUfqNuNLNh6PB0NDQ/D5fDh9+jTy8vKY3wk51CmXyxni6e7uBkVRTOQzNzcHl8uFvLw8hnx0Oh3k8vQ97pHedzTy8Xq98Hg8IvmIuCogks1rHOzZGVJoD2dsxiciMRqNGBkZQWlpKbq7u/dt7qlQECBQKpUoLS1FaWkpgL1akc1mg81mw9TUFLxeL/Lz8xnyyc/PT2rGJxHwIQfu/WcbyQWDwZBWa9HFVEQ2QSSb1zC4szORNqxYJEFRFKanp7GysoL29nZUVlaG/Tuh7Qaiba4qlQrl5eUoLy8HALjdboZ81tfXEQgEoNPpGPLJy8vLSBVo0cVUxNUCkWxeo4hndiYaMbhcLgwNDYGiKJw5cwY5OTkJrZMM+Kyp0Wig0WhQWVnJKBjYbDbY7XasrKyAoijo9XpmzicvL0/QzVqo9y26mIrIVohk8xpDJLvmaIhEEpubmxgdHUVlZSVaWlpipqVS5WeTyL/LyclBTk4OqqurQdM0nE4nE/ksLi5CIpGEDJjm5OQkTT6piDRE8hGRLRDJ5jWERCVnpFJpSM0mGAxicnISGxsbOHr0KJOq4nsNQkOIdFxubi5yc3NRU1MDiqLgcDhgs9lgsVgwNzcX0opNBkzjIY9U1aq4iEU+gOhiKiI9EMnmNYJods2xwI5IHA4HDAYDZDIZzpw5A61Wy3sddit1JkMqlSI/Px/5+fmoq6sDRVHMgOnW1hamp6ehVCpDyEetVqf7ssNCdDEVkSkQyeYqBx+75lggZLO2tobx8XHU1taiqakpoQ0pE9Jo8YJotun1etTX1yMYDGJ7exs2mw1ra2uYnJyEWq0OSbupVKq0XW808HUxlUgkUCqVDAllwrWLyG6IZHMVI9bsTDyYnZ3F7u4uTpw4gZKSkoTWSGeDgJCQyWQoLCxEYWEhgL0BU0I+KysrGB8fh1arDYl8MjWii+TlMzAwgIqKCpSVlYkupiIEgUg2VyFizc7Eg52dHXi9XigUCpw5cyapdFGmNAgIDTJgSoZM/X5/iJr16OgoEyWYzWbo9fq0DphGA5t8CLGILqYihEBmPvEiEgYpBo+OjqKmpiZhjxiaprG8vIzp6WkoFAo0NTUlXZdI1YaUaVGDQqFASUkJEwH6fD5MTU3B6XRiZmYGHo9nn7rBQQ+YxgI75Sq6mIoQAiLZXEVgz86YTCaUl5cn9KX3+/0YHR2F3W5Hd3c3JiYmBLm+qzWyiQWlUomcnBzI5XK0tbXB4/EwbdYTExPw+XzMgKler4dOp0t7gT6SbYPoYioiUYhkcxUg3OwMt12ZL+x2OwwGA/Ly8nD27FkolUrBSIK7jlA+NJkW2cSCWq1GRUUFKioqQNN0iLrB2tpaRqgb8PlswhnJASL5iAgPkWyyHJFmZ+IlCGJwNjc3h8OHD+PQoUPMhpCMWnO413G73ZicnIRCoUBRUVFSNYxs2rQiRQparRZarRZVVVUh6gY2mw3Ly8ugaTqk0+0g7LMpikqoaxEITz6ii6kIkWyyGNFmZ+KJbNgGZydPnoRerw/5vVDzMVKpFF6vFy+//DJKSkpA0zRmZ2fhdruTqmFkQ2TD9xrDqRuQAVPScCCRSEI63WLZZyd6vUIpJhBCieRiyhUVFRWtr06IZJOF4DM7wzey4RqchfOAESKNRlEU1tfX4XQ6cfz4cRQXFzMkya5hjI+Ph6SRCgsLBdcpSxcSeQ8SiQR5eXnIy8vjbZ8dyQ01HqTCajuSnQLXSE50Mb06IZJNloGv5EysyIZEFVyDs3BIlmzcbjcMBgO8Xi9yc3NRUVHBDBAC+2sY3DQSACaNVFhYGHKSf61tQlz7bIqimBkfYp8thLoBOcSkEnzJR3QxvTogkk0WgWvXHO0LF41sohmcxbtWLBCPm7KyMtTV1WFxcTHq34dLI5GTvNlsxtzcXMhJnmxOmY5UXaNUKt1nn81WN5iYmIBGowkhHz722amIbGIhEvmwXUxF8sleiGSTBWDbNQP8lAAiFfVNJhOGh4cjGpxFWivezZKiKMzMzGB5eZnxuNna2oprDfLaXJ0y9kmepmkYDAYUFRWhsLAQer2e12aaDhzEhhhO3YAMmC4tLWFsbIyXfXY6yIaLaOQjuphmH0SyyXCQ2RlCHHzVALhFfb4GZ+EQL9l4PB4YDAYEAgH09fUhNzc3ZJ1kNgLuSf65555DXV0d3G43FhcX4XA4kJuby6Tc0m0HnW7I5XIUFxejuLgYwN6AKR/77ES60VIN7rPPNpJzuVyYnp7G8ePHRfLJULx2v4UZDvakdiJKzezUVzwGZ+EQD9mQyKmsrAxtbW0hXWXsdYT68hORzOrqagB7m2kkO+jCwkLk5+enZWAyU1J9fO2zidK1Wq3OOHUDAraoqNfrxc7ODiQSiehimqEQySYDkajvDBtkY4/X4Cwc+NRsKIrC7OwslpaWcOTIEVRVVYX9u1RvukqlEmVlZSgrKwMQagc9MjICiqKg0+lQWFh4YDMrBJm4wUWyz97e3sbs7CympqYYsi4oKEgbWccCicRIWg2IbiQnks/BQySbDEM8ds3RIJFIsLm5CZfLFbfBWbi1opEEaTjw+/0haTMuUuVnE21Nrh0025FzYWGBiYwI+cRrina1QaPRQK1WY3JyEidPngRFUcz9Wl1dZciarW6QCfeLRP9shLNTEF1M0weRbDIEidg1R4LD4YDJZIJUKo3b4CwcopGN2WzG8PAwiouLeTUcCE028dwjiWS/IyfpdOOaohHyCedLkwgyoeDOF+QzkkqlUKvVIeoGbLJeWloCAMHtsxNBOLLhIhb5AKKLaSohkk0GgKZp7OzsYG1tDfX19UkRDTE402q1KCoqSppogPCdbew5nba2NqZmEmsdoWs25FoSAXdmhd02zPWlIZ1u4Tq3+CLbyCbcoDCbrNlt6ULZZycKiqLiThFHIh+iaA2I5CMkRLJJM8jsjMvlwtLSEhobGxNaJxAIYHx8HGazGSdOnIDFYhEsiuBGNh6PB8PDw/B6vbzmdMKtI+S1CQV223BjY2OILw23c4t0umVq8TwZsDsfoyFcWzrbPntmZgYKhSIk8tFoNCm7ZiHkdbjkE87FVCSfxCCSTZrAnp2haZppN00EOzs7MBgMUKvVjMGZ1WoVTDyTXWuxWCwYGhpCUVERurq64morTtUJN1VNB1xfGtK5ZbVa91kDEFmdSBtPpnSj8UGi0Wc0+2yibqBSqUIiH6HSlHzSaPGC1HMI+JCPaKEdGSLZpAHh7JoTmdKnaRorKyuYmppCfX09GhsbmQddKpWGSMIkA9JOOjs7i4WFBbS2tqK6ujrhDrlsBbtzi20NYLVameI5u9mAW7/Ilk1IqFRnIvbZiaYpU0E2XEQjH9HFNDZEsjlARLNrJmTDt5DMNTgjX2iCZCRmuAgGgzAajZDJZOjt7UV+fn5C66SCbNL1RZZI9lsDEHVmq9WK+fl5ZgC1sLAQgUAga4ZLU1FXA/jZZ5OBXKJuwPeeHQTZcMGXfEQ7hT1kx9N/FYA7O8Pt7WfniWM9jOEMzriIJFcTLywWC9bW1qBUKnHmzJmkNsxURTaZEC2FU2cm9YuNjQ1sb29DLpfD5/MxkU+myupwD0KpQjj7bNLpFq99djrIhgs2+YhGcvshks0BgM/sDPmiRPvS0DSNxcVFzM7O7jM4C7deMpswTdOYn5/H/Pw8CgsLmS9IsrhaIptY4NYvxsfHQVEUFApFiEYZIZ5kDOSERrratLkDueHss9kDpmz77EwgGzbYmm5AZPIJBAKQyWTIycm56sknM57uqxTxzM6QhzJSNOLz+TA8PBzR4IyLZNJo5LVcLhd6e3thNpuxu7ub0FpsXM2RTSyQtFtDQwOAvRRSuFM8IR/2RnrQyBRdtHD22STttr6+HuJ75Ha7M+KaIyES+SwsLCAQCKCpqQnA1e1iKpJNihCv5Az7hMYFH4MzLhLd2K1WK4aGhqDX69HX1weFQiFYGzW5JpqmsbW1Bb/fj6KiooT8VthrZiMUCkWIRhk5xVut1pCNlJDPQU7qZ+IAKrtGRtQg2L5H5BkNBAIHap+dKMh10TTNNBOwXUzZcz4KhQKjo6OoqalBRUVFOi87KYhkkwJEs2uOBJIjZ5NNPAZnXMQb2dA0jYWFBczNzaG5uRm1tbXMawkVkZB1hoeHYbFYoFarMT09DbVazWyqiXQkZUNkA0QnxkgGclarNWRSn9ynVFhBE2Qi2XAhkYT6Hk1PTzNptoO0z04WwWCQaZdmRz9cI7m77roLn/jEJ/C3f/u3ab7ixCGSjYDgY9ccDWyCiNfgjIt4GgR8Ph9GRkbgcDhw6tQp6HS6iNeVDNxuN4C999bb2wuZTAaKomC322G1WpmOJLZKc6x0UqZtHpEQDyFyN1IyqW+1WvdZQRPySSY6DHet2XJfCWiahlqtRm1tbVT7bO6AabrfZzAYDNv0wCUfl8sVUXMwWyCSjUAINzuTyFAcRVEJGZyFW4vPBmez2TA0NASdThcxRSdEZLOxsYHR0VEAQE9PD4C9ugXXb8Xr9cJqtcJms2FsbAyBQCDkRB8uNZItkU2iYE/qE1mdnZ0dWK1WrK2tYXJyMunokI1sJBvSfEEQzT6bq4OXjH12sohENmwQTTqRbF7jiDY7Ey8kEgkWFhZgNBqjyvTzQaxohN3Z1tTUhLq6uojXnQzZUBSFqakprK2t4ciRIxgZGYm6nkql2pdOslqtTOTDnl0hBmrZAqE2cLb+GPCqGyc7OszNzQ3pdItHVodE5dmEWN1oseyzCWHHa5+dLPiQDQCRbF7r4No1J0M0LpcLfr8f29vbUWX6+SLahk7SZru7u7w62wBg1uqHeXQLJXkqnKjOh1wWezNyu90wGAygaTpkRocvcbHTSUSlmT27MjU1BQBYXV1FMBhM+kSfSqQy+grnxkmiQ7YhGiGfWJ40mdKNFg/ibX0Wyj47WYhkIyImiA86iWaSOQkSgzOZTIbW1lZBHqpIkQ0ZCM3Pz8eZM2d4nd4WbH5cWPej2G+DRCoBTVM4eagw6r8J59hJOmwSFePkzq4EAgFcvHiRiQhHR0eZ9mE+9Z6rFUqlcp8hGiEftqxOpK6tbE2jJfNZJ2qfLcR1802jxeuwm2kQySZOkCYAp9OJ5557Dm9+85sTfsiDwSAmJyexsbGBo0ePYm5uTrDr5JINTdNYWlrCzMxMzIFQLuyeIHxBGodLczFvdmJzxxvxb9kddNxUYDwqCXwgl8uhUChQWVmJ4uLiiPUeknZLdytsul5bo9GgqqoqxJOG3Cd2apL877UQ2cQCH/tsvuoG0UAGvaPB5XKBpum4m4QyDSLZxAH27Ay7Tz4ROBwODA0NhRicLSwsCKZnxk6j+f1+jIyMYGdnBz09PXHXOkpyFVDLgKmtXSjlUlTpw8vE+3w+DA0Nwe12R+2gE/rkTN5npHqPzWbD4uLivnpPquTuo11jusH2pGF3bVmtVqZwLpfLQdN7luJCKjOnEqlWEAhnn00in4mJCfj9/oTss/mk0ZxOJwCIabTXCrizMyR/S/rk4wExOKutrUVTUxPzUAopnknW2t7ehsFgQG5uLq+0mS9AweTwIlclh06z9x4bijQ4XSFFZWMJCrRKtFfsJxGSniNdbeHuSSpOy9GaGrj1HrKpknqPkB1cyVxrOsHu2iK2AIuLi9jY2GCUmQ+idpEsDlquhtiNs9UN2PbZwWAwJFUZaSiXL9nI5fKsIP1oEMkmBmLNzsRDDlyDMyJASCAk2RDdpUuXLqGxsRH19fUxNzunN4DfGjYwb3YiTyXH24+Xo6k0F1KpFFU5EryuqXjfv6FpGsvLy5ienubV1QakR8eKu6myC8Lcek8yaZFIyJTIJhaITpdWq0VXVxejzGy1WjE3Nwe32y1I+khopFMbLZwCOB/7bHLdfMhGq9Vmff1RJJsoiCY5Q5oCyO9iYWdnB0NDQ1CpVIzBGRdCkY3f78fU1BRomo4rbTZrcmJicxfVeg3Wt914Zd6KptLciJ1tgUAAo6OjsNlsvF4nk8zTws33kIn98fHxELmYTKj3HCTYNZtwBnIkNclOH7FlddKxKWaSECc7VRnOPpvYT5Dhaa/XC5VKFfH5cjgcWZ9CA0SyiQgSzUSTnCET8NEQzeCMCyHIZnt7myE1AHHVZ6QSCSQAvIEgKIqGTBpZrmZ3dzfEHZRPiJ9snSvamsmCa4yWinpPtpBVtJoaty7G7nRbXl4GTdMhzQZcA7lUIZPIhgv2UC6xz97d3YXJZAIADAwMQKFQhNw39vOVbCfa888/j3/6p39Cf38/NjY28Nvf/hbvete7wv7t//pf/ws/+MEP8C//8i/41Kc+xfzcarXizjvvxO9//3tIpVK8973vxXe+8524SFAkGw64szPRlABikUMsg7N414t13YTUGhoaUFlZib/85S9xFeNbynLRXavHtNGB6gINkzbjSt+sr69jbGwMhw4dwuHDh+PaTAhxpaJBQCjwrfewySdWHSNb0mgA/wYOdvqIyOo4HA5YrVZYLBbMzc0xsjrhNlEhkclkwwWJapRKJVZWVvC6172OiXzY9tl6vR4vv/wylEplUrpuTqcTHR0duPXWW/Ge97wn4t/99re/xSuvvILKysp9v/vgBz+IjY0NPPXUU/D7/fjwhz+Mj33sY3jkkUd4X4dINiwQJQCyscYa0pTJZBHTaHa7HUNDQ8jNzY1ocMZFPGk5NtjpLEJqZKYlUk54esuBsfUd5KnlON1QiFyVHEq5FDd3VGDXG4BGIYNS/mrjAqldTU5OYnNzM2zNiS8yMbKJhnTXew4aiR4G2AZy5ARPpvTZmyi7KUOoKf1sIhsC0vbMJmTgVfvs+fl5/OAHP8DMzAxycnLwiU98Am984xtx3XXXMelfPnjrW9+Kt771rVH/Zm1tDXfeeSeefPJJ3HTTTSG/m5iYwBNPPIHLly8zUlMPPPAA3va2t+Hb3/52WHIKB5FsECo5E49Sc7hIJB6DMz7rxcLOzg4MBgM0Gk1IOottWcDd+NbtHvxn/xps7r2mB5vLj/d1V/33v5MwXWgEJLIhA5RnzpxJ+ISarKlbOBx01BCt3kPqGNx6D3B1pNHiAVciJtyUfqI20OGuORvJJtyhhG2fffnyZTzwwAP41a9+BaVSiXvvvRfvf//7YTAYcOzYMUGug6IofOhDH8LnPvc5tLe37/v9hQsXoNfrGaIBgOuvvx5SqRQXL17Eu9/9bl6v85onm3h9Z9jgRiLxGpyFW48v2dA0jdXVVUxOToatBUWrj5gdXthcfjSX5WBzx4slqyvqa9lsNmZAsrW1NekvdTZOqEdDuHoPIR9S7yENJUVFRQc635MIUrVxh5vS5xrIRXLijHW92RrZ8ImAg8Eg6uvrcf78eQB76hyxUvLx4P7774dcLsddd90V9vebm5vMcCuBXC5HYWEhNjc3eb/Oa5ps+Ng1RwO7QYAYnOn1et4GZ1zwTaMFAgGMjY3BYrGgq6sLRUVFYdcCwrdml+vUKM1XYnLTAalUghPVun1/A+x9iWdmZrC0tASJRIIjR47E+Y72Q2iSSZX7Z6Lg2gOQes/4+Dh2d3fxyiuvMKkkvvWeg8ZBKQhwbaDZsyrEQI7PrAp5xq9WsuE2CCSavg6H/v5+fOc738HAwEDKP/PXJNnEY9ccDVKpFIFAADMzMwkZnIVbj9RaIoF0galUKpw9ezZiF1g4MzaC0jwVPtBTjWmjE1qlDF01+8nG6/ViaGgIXq8XJ06cwMDAQELvKdx1sWtiVztIvUer1aK4uBhlZWVh6z1s/55013vSFXmSQUnixBluViWcGdprgWxS1fr8wgsvwGg0ora2NuS6PvvZz+L8+fNYXFxEeXk5jEZjyL8LBAKwWq2MogIfvObIJpm0WTgsLi5CIpEkZHDGRbQ0Gk3TWFtbw8TEBO8usGin/ppCLWoKtWF/Z7PZYDAYUFBQwAz2CRU9kGsmhePCwsKkTKyyhbDI/Yun3nPQdtDsa033feXOqlAUxXS6ETM00i5MvnfZRjZ8U38OhyOuhoB48KEPfQjXX399yM9uvPFGfOhDH8KHP/xhAEBfXx/sdjv6+/vR3d0NAHjmmWdAURR6e3t5v9Zrimz4zM7whclkgtVqRV5eHk6dOiWIAmwksmErD3R2dvJ+8BKxhibNDWxraNIGLtQmtLGxgeXlZeTl5WFmZibptFImpdGiIdy9i1XvkUgkzH0hxJxqZALZcCGVSvcZyLE73QDg0qVLIZFPpqUnueAb2STr0ulwODA7O8v898LCAgwGAwoLC1FbW7svDa9QKFBeXo6WlhYAQFtbG97ylrfgox/9KB566CH4/X7ccccduOWWW3h3ogGvEbIhPt7EGTIZoqEoCtPT01hZWYFer0dRUZEgRAOEJweSNlMqlRGVByIhHmtoMhO0vb29r7mB3WyQzCZE5pfW1tbQ09MDrVYLmqbD2kKz24hfK7bQkeo9bJHMg6j3ZCLZcMH2oykvL2dkmcKlJxMxkDsIJFqziRdXrlzBG97wBua/P/OZzwAAzp07h5/85Ce81vjFL36BO+64A29605uYoc7vfve7cV3HVU82xK55ZmYGfr8f7e3tSRmcDQ0NgaIo9PX1YWlpSTAtM2A/2RDBzrq6Ohw+fDjuNAHfNmPSPq3VasOKdbKbDRJNVTidTgwODoKmabS3t0Ov18Pn80EmkzFtnsCrcijE8ph4r5CNJdxwW7ZENvEi3HzP9vZ2CDGnot6TbW3ENE1DJpPtk9XhWgLodLq4VZlTiYOq2Vx33XVxfUcWFxf3/aywsDCuAc5wuGrJhmvXLJPJ4PV6EyYaYnBWWVmJlpYWyGSyhIcwI4GQTTAYxPj4OIxGY1LDk3zSaKurq5iYmIgqpZOszIzRaMTw8DCqq6sRDAajnsa5cigOhwM2mw1msxlzc3NQKBQhJ/tMP4Gzkey1sucvgNANlV3vIeSTaL0nGyIbNsIdgrjpSa4qcywDuYNAJjQIHCSuSrLhNgFIJBJeOmbhwDU4Y3dfyGQy+P1+wa5bKpXC7/fjwoULUCgUOHv2bFxpMy6iNQgEg0FMTExga2srZh0oUbJht04fPXoUFRUVMBqNcdlCk4n02tpaJk9vtVqZoUCZTAaapqHRaKDX69N+Wo2EVERf0eo9pF2dEE889Z5sM0+LZUAWTpWZHGIiGcgl07QSz3Xz0RR0uVxZ79IJXIVkE2l2Jpq0TCSEMzhjQ+jIxm63w+FwoL6+PsTnJlFEimxcLhcGBwchk8l4ERrbGoAviJGax+NBX19fyBR9ohsv1zfe5/PBYDAwDRRkLoP8zUGJQGYC4qn3xJKKuRoim2jgHmIoisLOzg5sNlvIvWKTTyq8ZPhcN2kBz3aXTuAqIptYszPxkk0kgzM2Eo2WuCBRxsbGBlQqFdMFkizCkc3W1hZGRkZQVVWFlpYWXl/SeCOb7e1tDA4OQqfToa+vL6SBQshNTKlUMgZoVVVVzFyG1WrF/Pw8M+VMNth0m08d5AYezhSNNGKQqDBSvSfbyCbZGpNUKoVer4derw+5VzabLayBXEFBgSBNQWIaLQvBZ3aGL9mQU7LJZIpZLxEisnE6nTAYDJDJZGhvb8fMzExS67HBjiLYXXTHjh2LaxiLDIjyIZuVlRVMTk5G1IVLxcQ/2Ry5cxkk5UY2jNzcXIZ4Dro7Kd1NDNxGDJ/Pt8+XhtR7fD5fVqVthJaq4d4rv9/PpNyENJA7qNbnTEHWkw3XrjnSiYwP2bANzvikl5KNbDY2NjA6Ooqamho0Nzdje3s7Jd1tHo8HQ0ND8Pv9ISmteBCLJEh0ZjQaI0ro8FknkesKB3YOvrGxkdHhslqtmJycDCuWmU2n+WShVCr3FdAJ+djtdmxvb2N3dzfEvydT70+smk2yUCgUKC0tZfTBPB4PQz5so714GzP4kA1FUUm3PmcKspZsYtk1cxGNbOIxOGMjUf8ZtlR/R0cH8xALaQtN1tvZ2cHk5CSKi4vR3d2dcPgfbWbH5XLBYDAwitDRSDpVkU0ssHW4IollEuIpLCxMScotUzdrri/N0NAQtFotFArFvhoGIR+hrAGEgNCt2maHD74ghfJ8FaRhPjO1Wh3SMUmeJWIgB7xqAR2pXR/gRzZOpxMAxJpNukBmZ+KRnIkUhcRrcMZdM940mtPpxNDQECQSCfr6+kKaDoQkG/Zp9ciRI6iurk5qs4s0s2MymTA8PIyKigreitDp9rMJV0zf2dlhZnsmJiaYHD3ZXJNNuaU7jRYvSOcWmdbn1nvSmZLkQsg02ktzVjw6vAV/kEJPrR639FRCLo38jHGfJa4FdDQDuXjIRoxsDhjc2ZlY5mZsENFMNhIxOOOuGQ85kFmdSMV5ocjG7/djeHgYHo8HdXV1qKmpSXpNbkRC0zTm5+cxPz+PI0eOoKqqKqF1MgHsAnFDQwOTo7darZienmYGAknUk+j8SqZGNlxwW5+j1XvYKclk53uSuV4hyMYXoPCnMSM8/iByVXK8smDDqUN6NJfy3+glkv0W0FwDOeLyyjZqjASXywWFQpH25hYhkDVkw7VrjodogFcjG7LRJWpwxgbfBgGKojA5OYn19XUcO3aMkVQPtx5N00l1A21vb8NgMCA3NxdFRUWCPaRskiBk5nA40Nvbi/z8/ITWEQpCr8fN0bNTbiRNwu5yy3R/mngR6/mLVu8h94cdFaa63iN0zYamAeq/n6lkrzqagVwwGGQOu5EM5BwOx1XTwp8VZMOenSEmVPGCDP95vV6Mjo4mbHDGXZPPycRgMABA2Fkd7npAZCvnaGDXnRobG1FfX4/h4WFB1ZrJ7Mbg4CBycnIS8u05qAYBIcEeCGTPr5CTqkajCdlcw9XFMi2ai4Z4Djvceg9JI3Hne1JZ7xGqZqOUS/GOY2X47dAm/EEKZxsL0FAc+fuaCIjqd1FREVZWVtDT08OoG5AomhjIra6uIhgMJpVCe/755/FP//RP6O/vx8bGBn7729/iXe96F4C9Q+Pdd9+NP/3pT5ifn4dOp8P111+P++67L0Rg02q14s4778Tvf/97RhftO9/5TtyNRhlNNkL5zgCvbuTE4jRRgzM2YqW9yExLZWUlr3pGNCvnaGCrQrM7wYSsAUmlUphMJiwvL8fVRMFFKsjhIDfycHplJOohbbFESJSklMjnmi2n02Q2b3YaiV3v4VpBC1nvSTSNtu32Y2BlBzKpBD21OmiVMpyuL0BbeS68AQolucqUfWbke6lWq5Gfn7/PQG5rawvnzp2Dw+FAXl4evv3tb+P6669HR0dHXO/V6XSio6MDt956K97znveE/M7lcmFgYABf+tKX0NHRAZvNhk9+8pN45zvfiStXrjB/98EPfhAbGxt46qmn4Pf78eEPfxgf+9jH4tZKy1iyEdJ3hqZpLCwsAABqa2vR0NAgyEMUqUGAoihMTU1hbW1tn8RNNERz14wEh8MBg8EAhUKxrxNMqCiCtJcvLy+HdM8lgmyMbKJBLpeHCECSzYLM9wBgZle8Xm86L5U3hBzqDFfvYbeg+3y+pOthiZCN2x/E959fwuSWAxIJMLqux/96XR2kEgl0mtRbE5B9g0u0bAO5ubk5PPjgg3jooYfwwgsv4Ktf/SoUCgWeeOIJnDx5ktfrvPWtb8Vb3/rWsL/T6XR46qmnQn72ve99D6dOncLy8jJqa2sxMTGBJ554ApcvX0ZPTw8A4IEHHsDb3vY2fPvb385+iwG+szN84PF4MDw8zIhwlpeXC/ZFIpED+8vJVYaOJwSOVxZmc3MTIyMjEVUOhIhsPB4PDAYDzC4KuzmVsCx50UU70FyW2JBZNtRskgHXbZKklKxWK2ZmZrC8vJzRltBAahUEuC3okeo9bP+eWNdCUVTcLf1rdg8WLC5U69Xw+ilMbDpgc/lRlHMwLd3sQ3QkkCi6trYWjz32GAKBAK5cuYK2traUXdf29jYkEglTXiCZIEI0AHD99ddDKpXi4sWLePe738177YwiG5I2m5ubA0VRqK+vT9rgbHh4GCUlJejq6sJf/vIXQbXMuDUWo9GIkZERlJeXo7W1Ne70AGl6iEUQ7Mjp+PHjERsO4vGzCQeLxYKhoSEUFBVj1umBVBKEXx7Ai7NmlOQpUaCN/4uZid1oqQI7pWQ0GlFXVweZTMZYBBDJGEI+mSB7DxycEGe0eo/RaGSM9WLVexKJbPQaBfJUcqxte0BRQG2hBrmqg9sOyZ4R6z6zBzrlcjlOnz6dsmvyeDz4whe+gA984ANM08/m5ua+TAaRgdrc3Ixr/YwhG3bazOv1wu/3J2VwRk6R7LbcVFgCAGD8clZWVhh140QRq+mARBrBYDBmw0Gi75ft2Nna2orC0go8OvYSipQyFOUoYXZ64QskRmKEbOx2O2NAl8wQZbrTaPFAJpPts4QmUc/IyAgoigrZWCMNA6Ya6dJGS7TekwjZFOcqce50Nf5rwgSFbK8xQCU/OKLn20F3UOoBfr8ff/3Xfw2apvHggw+m5DUygmy4ds0KhQIejyehtbhpLHbHhFDCmQTkYenv7wdN0zhz5kzSD0a01JfZbMbQ0BDKysrQ1tYWM3IilgXxIBAIYGRkZJ9jZ02eDGZfEJs7HrSU5qIwwXQDTdPM/EpZWRkzREk2kURMwLIhUgp3jeG8e6xWK0wmE2ZnZ/d59xzU1H6mCHFGq/ewDdF8Ph9UKlXE66ZpGs/NWDGwbEdpvgo3Hy9HvlqO41X5OF7Fv21fSGSSCCchmqWlJTzzzDMhowzl5eUwGo0hfx8IBGC1WuPSVwTSTDbc2RlSn0lkMh8Ib3DGRqLrRoLFYgGw1xp77NgxQaaow5ENTdOYm5vDwsIC2traUF1dnfBa0eBwODA4OAgHpURdUwfkmlcf8vYSOZR6HYpLSlGhU0Mhi/8UGAwGsbu7C5/Ph+7ubmZ+gDy8VquVEYVk+7BEO+FnwqbIF9GulS17X1dXF/ZUz065xbLLTgaZ6tQZrt5js9kwPz+PtbU1bGxshK33DK3t4ueXVuEPUvAv0/AFKPzPM7VpfS8HZQkdC4RoZmZm8Oyzz+7TNOzr64Pdbkd/fz+6u7sBAM888wwoikJvb29cr5U2siGzM2QzZA9pymSyfdP+0RDN4IwNociGnaaTSCRobGwUTK6DSxA+nw/Dw8NwuVwpHaAkzQbenDLM+bQYGjWhtsCBdx6vQK5aDplUirJcOaqLEps7cLvdjPdMbW0t06EF7A1RsjcRp9MJq9XKyH2QE35RUVHYono2RDbxIpxdNjnVj42NIRAIhGysQg7+ZUpkEw3ses/W1hYqKiqQk5PDRIYzMzNQKpUoLCzElF0OpzeAptIcrG17sWx1p/vy4yKbSDVZPnA4HJidnWX+e2FhAQaDAYWFhaioqMBf/dVfYWBgAH/4wx8QDAaZOkxhYSGUSiXa2trwlre8BR/96Efx0EMPwe/344477sAtt9wSVycakCayYddnwnWbyeVy3qQQy+CMDSHIhqugfOnSpZQoNQN7cjoGg4HxhYm3c4lPZEOIc2VlBcePH8efF32AxIeG4hzMm51YtbvRWp4XURuND6xWKwwGA0pLS6HVaqN2DrGtAtjunBaLZV9RPZKydCYiWULkunISQg7n3UM2imSuNdPJhg1SbOfWe4jFhMptBjweDC26oFLI0Xgoh/dmnyocVBrtypUreMMb3sD892c+8xkAwLlz53DPPffgscceAwCcOHEi5N89++yzuO666wAAv/jFL3DHHXfgTW96EzPU+d3vfjfua0kL2RAVgEgPNV9S4GNwlsi6kUC620pLS3HkyBHIZLKUKDUHg0EsLS1heno6KTmdWJGN1+vF0NAQfD4f06adt7WBJasLxl0vlDIp1AoZr7XCgaZpLC0tYWZmBq2traipqcHIyEhc63DdOUlR3WKxYG1tDYFAAGq1mjFRy2TpGKE2cC4hUxS1z+wrmRpYttlCh2sQYD83hw8fRlOLHf3zRsgCLtRiC88/v8LM9xQUFIQM3x7UNfP1skkmjXbddddF/b7x+S4WFhbGPcAZDmlLo0XTNouVRovH4IyNRLuzKIrC7OwslpaW9olOCl0HkkgkWFxchNvtRk9PD6OplAiiEaHdbsfg4CAKCgrQ1dXFRBvXNBYhSNHYdvlxpE6P2gINc13xkEQwGMTY2BgsFkvI+0i29ZlbVB8bG4PX62WkUTQaDbPJcHWmrlaw7RG43j1sYzS+3j3ZGNnEIor2Kj3aq/QAEFLvYevdsS3FD0LPjQ/ZOByOq8I4DciQbjQuom3gu7u7MBgMvA3O+K4bCSRtRk7/3A9eyMjG4XBgd3cXGo0GZ86cSVpEM1KzwcrKCkYnpuDMqYQlqAe17sCJah2kUgkKc5R494nKfRtOPDM7RA9OKpWir68vJaoGZC1iDX348OEQ6ZiZmRl4PB7odDoUFRWl3SDtIOtK4bx7SMqNj3fP1Ug2bLDrPVVVVSHzPdxOQFITE7oTkG/rs8vluiq8bIA0RzaREK5mk6jBGRvxtj6bzWYMDw9HNR4TanZnfX0dY2NjUKlUqKurE0Stmbuxs6MNlB7G2JoHKocTMyYHtEoZWsvzQv5ttLUigbRnR/K3IesIuZmR6+JKx0TbZIuKig7cACxdsyvEb4Vtl22z2UK8e9jR4NVONlyEm+8JZylOiEcIPbd4ajbR6tDZhIyNbCiKYh6iZAzOuOvyIQaapjE7O4vFxUW0tbWhqqoqasovmciG2A9sbGygo6MDq6urgopnkrVcLhcGBwchl8vR19eHxyesUMp8OFSkxfTWLrbd0edxYjUIsAdBY7Vnk3WE2NCircGeTicGaRaLBaurq/tme/R6fUpz9pnSMceWvOd695DZFWDv8FNSUnLg3jSJQEjzNGB/nZCkJW02W8h8D9u/J97XDwaDMRt+SCOIGNmkEITxg8EgdnZ2MDQ0hJycnIQMzrjrknbbSCBFc6/Xi9OnT8f8oJOp2ZB2YJqmGdfO9fV1wTYmQhBGoxHDw8Mhpm0NJTmY2nJgasuBAq0Slbro6chokU0gEGAOA6dOnYJOp0tonUTBZz22QRq7rmGxWBgfeb6zPVcT2N49ZHO7dOkSdnd3sbq6ypATuS/xpK0PCkKTDRfstCQARs+NLbZK6j18lR+CwSCve3kQQ50HhYwmm8XFRSwuLibVkcVdNxoxEC2woqKikKJ5NCRasyGdbeXl5Whra2O+LEJ3t7ndbgwNDaG9vT2kL/54VT40Chm23X6U69SoKYjexRWpZkNkyhUKBfr6+mKm/5LVawu3XiLkxa1rhJvtIbUeoQQzM528JBIJswG2t7dDJpOF9e7JpAYM4t57kJ1kGo0GVVVVIfUem80WV73noLrRMgkZWbMhnWirq6tJG5yxEYls2BP6ra2tqK6u5r0xxFuzoWkaMzMzWFpa2kcAZD0hNmOfz4fZ2VkEAgGcOXNmX4QmkUjiUm4Ol0YjhEkUG/h84TNxww0322O328MKZhYVFSWUNsmUNFossFOc0bx7SAMG27snPz//wD9fcr3pUjzg2kCHq/ewa2I6nY6pSccim2AwCLfbLUY2qYLVasXQ0BAkEgmOHz8uGNEA4cnG6/VieHgYbrc77gl9siZfciCv5fF4IqbohCAbYg2tUqmgVCoFyfmyIwiapjE/P4/5+fmwhMl3HSGQirQcd3rf4/EwaZPV1VUAr9oeFxUV8U4tZSLRchGtnhbOu4ebTmKn3A5i5ol8VzJFXidcvYccXNj1HrfbDY/HEzUqczgcACDWbIQGO7poaWnB3Nyc4F9OLtkQYisoKEBnZ2dCKQG+5GCz2WAwGGK+VrLdbaT43djYiIKCAsaSOlmQTZ0Ide7s7CREztloMaBWq1FZWRniUWOxWLC5ublvtqegoCCtk+nJIp7mjXDpJLYdNBm0JSm3VHj3ZBrZcKFUKpmaGPAqQc/NzWFlZQUrKysRlb5dLhcAJBzZRLOEBvY+66985Sv40Y9+BLvdjrNnz+LBBx9EU1MT8zdCWUIDGZJGYxuckQ1seXlZ0GFJ4NWNnH0yb2lpQU1NTVJ209Gukz1F39zcjNra2qivJZVK49KFI6AoCuPj49ja2kJnZyeKi4uxs7MjWH1EIpHA6/XiwoULUKvV6OvrS6hZI9vN09hpE25qiXjIs4cDyWxPthBsop2C3PbhQCDAnOiJXXYqvHvY2orZAELQy8vLaG5uhlKp3DffU1BQgKmpKZSUlEClUiVcF4tmCQ0A3/rWt/Dd734XP/3pT1FfX48vfelLuPHGGzE+Ps5E60JZQgMZENlwDc7IjY1XjJMPCDH09/fD6XTG7Jzig2gy/pHk+mOtFy9BkK42ADhz5gyTvhByk3O73dja2sKhQ4fQ3Nyc8Jf7areF5s72kLRKMBgU/HlOBciMTbL3VS6Xh3j3sFORa2trId49yUzsC+Hmmw4Eg0HI5fJ9St+k3vPP//zPGBkZgVarxWc/+1m8+c1vxrXXXhtXRBHNEpqmaZw/fx533303br75ZgDAz372M5SVleHRRx/FLbfcIqglNJBm1eepqal9BmcE8Yhx8oXT6YTb7UZ+fj7OnDkjSFgfKe21u7uLwcFBRg2AbxQQL9mQIUpuV1sia4UDmTna2tqCXq9HS0tLUuuRNYVEJkUN3NkesnlQFIWhoSFmtqeoqCilNgGJIlW6aNxUJNu7h+3IGUnZO9r1Zto95INw3Wjses8LL7yAP/7xj/j0pz8Nl8uFu+66C0tLS/j973+Pt7zlLUm//sLCAjY3N3H99dczP9PpdOjt7cWFCxdwyy23CGoJDaSRbAKBAHZ3d8NKwADCao7RNI2FhQXMzs5CKpXixIkTgn2hwjUIEIHQRJQO+Kors1OBkYYok20z9vv9GB4ehtPpRE1NjSAnc26jQbKfQyafaNkDlOvr6zhy5Aj8fj9jExAMBpmUW1FRUcr1uPjgINQDInn3kO6/0dFR3t492Uo2fLrR5HI59Ho9fvCDHwDYIwihlM6JlQDXvqCsrIz5nZCW0EAayUalUoUwJhdCpdF8Ph9GRkbgcDjQ0dEBg8Eg6JeJHdkEg0FMTExga2srLoHQSOtFgt/vx8jICHZ3d6OmAsmXMJENxOFwYGBgAFqtFn19fVhZWcHOzk5ca4QDIZuVlRVMTk4iJyeHmWdJNI+fSZFNNCiVShQVFe2zCTCbzZibm2P8V4Sc7YkX6ZCqCefdQ1JuXFLmDtxmI9lQFAWapmOSDdc4rb6+PtWXllKktWYTLX8vRGRjs9kwNDTEpM3IhyzkA0oiGyI+KZFIQuom8SJW6ouk5wgJREvPkffId4CMgBipHTp0CIcPHw6xhBACOzs7sFqtOHr0KHPSJ9YDJJWSqdPqiYJ77/jM9qRjhiUTdNG4yt7hBm5JvUcqlWYd2ZB9LdZ1p1LxmRhMEuM5AnJQJn8jlCU0kAENApGQTM2GrdPV1NSEuro6xn4Y4K+4ygdSqRQejwcvv/xyiBxMMutFIhsi1skmgVhrAfxP/mTgdHl5GcePHw8JsYUo7Hu9XiwvL8Pv9+PMmTOQy+WgaZrZVEhLMZlW12q1TIopknZZujdGoRBttofMsLCVmlNFxJlANmxEMtMj1gAOhwNSqRSzs7MJefekA2Rfi3WdqVQPqK+vR3l5OZ5++mmGXHZ2dnDx4kXcdtttAIS1hAYymGxkMhkjChgPSIppZ2dnXwcY2az4iODxAUVR2NzchMvlQkdHR8gJIVGEIxvSTLG2toaOjo59edRIYKcaYoHYT7vdbpw+fXrfiSpZstne3sbg4CCUSiVycnKg0WhCuvi4LcVEINJisTCeLOyoh62Emy1ptHg2cW5BnUSDXNkYQsRCbbA0TWd0pMAdmlxfX8fS0hL8fj/znLBTbvHaZQspEhsJkRyKueCm0eJFNEvo2tpafOpTn8LXvvY1NDU1Ma3PlZWVzCyOkJbQQIan0eKt2RAb5by8vLAdYOQDFmL2hPjcuN1uaDQaQYgG2E82Ho8HBoMBwWAwpu11uLWA2GSzu7uLgYEB5OXloa+vL2xffzL3jURkjY2NkMvl+0LzcAgnEMntXioqKkIwGBRUay1VSIYQJRJJiGyM3++H3W6HxWJhptLDzfYkgmxz6ZRKpVCpVGhra9vn3bOwsACZTBbSYh1Nu29sYxf/NW4CDeD61mIcr4pvYJkv+Ka1k02jRbOE/slPfoLPf/7zcDqd+NjHPga73Y5rrrkGTzzxREjULJQlNJDBkU08aTT24GQs0U4hakFWqxUGgwFFRUVobGzE6OhoUuuxwSYbonBQVFTECCPGAz6RzcbGBkZHR2N2ziVqCz01NYXV1VWmYWJ1dTXudcKlUsggpcVigd/vx+DgIHPSj/c0m21QKBTMbA9xnST3gj3bQ/4Xz/BtpqXRYoFdf43k3UNkhsJ595DvlMMbwO+GtmBx+SAF8LvhLdQVaqDTCN+kEY+XTSotoSUSCe69917ce++9Ef9GKEtoIIPJhm9kQ7xutre3edkoJ0M2pIV6bm6OUR4QckofeLUbbXFxETMzM0krHEQq7FMUhenpaayurvJKzcXbIODz+TA0NASPx4O+vr6QL02yaS+ZTMYMDKrValitVhQXF4cMUpJ0W2FhYVq6usIhFZs423WSO9tDhCD5thED2U02XLBbzxsbG8N69+j1ehQUFIBW58PlC6BIq4BUKsGOOwCXL5hWsnG5XAmlqzIVaU+jRQIfUiCCk7m5ubwHJxMlG3YtiN1u7AnQsLuDgn1JaZqG3+/HwsKCIIrX4WpAPp8PBoOBsbrmc3qKJ7IhHXM5OTn70nKpkG6Ry+Worq5mNlvS1bW4uMhstqT4ni4zsIOqK3E3WJ/PF7aNmJAxd7bnaiIbLripWbaQqGVxCWqXBAsWJRRKJU7VF6IkL3m33HDg26CUbGSTacjoyCYSKdA0jeXlZUxPT6OxsRH19fW8vyCJkE0kUnt+xoz/89QMbDvAjHwGn73+MOSyxIurDocDo6OjoGkaZ86cSYk1NCnU63Q63p49ZB0+EdzW1haGh4cjdsylWvWZbf18+PBheL1eWCyWfV1dZLMV4h7Hc60HDaVSifLy8pDZHovFElL7IvejoKDgqiYbNmgAOwEZcgrLmEPKUZsdgwtGbG9vQ+dewJVLmynx7oknjXa12AsAGUw2kWo2fr8fY2NjsNlsCVlEx6OqTNM0VldXMTk5iYaGBjQ0NLDqIDQeeHYeNtdeR9WTY0Zc21SMvobELKu3trYwMjKCsrIyrK+vC7YJsiMbomwQL0EDexvluiOIC/NW6DVyNJXmhhAr20r72LFjEfvwD1qUUqVSMV1dFEUx7dVra2uMNTQhnkyUjxES7NoXe3KfzK+QZhfSXpwOf5p4kUhDQ4Ci8auBDQysbEMpl+Kdx8pw6pAeJUWFuKFo7/tLmjDY3j3ECjrZCJkv2aRyziYdyOg0Grdms7OzA4PBAK1Wm7BFNN/IJhgMYmxsDGazGV1dXftkIoI0DV+A2ttwqb3/9gbir91QFMXMthw7dgz5+flYW1sT7IRJ5osmJiawvr7OKELHi02HH2PmIHbzdkFRAEUD7ZV73TqBQADDw8PY3d2NaaXNfU9CvE++5MU2A2toaAibYmK3Vwvpx5KJ7dnhZnvm5+cZx1rgYGZ7kkG8A8sAsGhx4eKiDXlqORzeIB4fM6KzJh8K1uGJ3YQBCOvdE49Lp0g2BwB2ZEPkTaampvZFGPGCj9mZ0+nE4OAgFAoFzpw5E/ZLppBJccvJajz88hJ2A0B3TR5O1unjuhZSO/F6vYxGnMfjASBc7lwikWBqagrA3pBWPK3TbDh9FLxBGnWFWqzY3LC5fHs//+97pVKpeNkOZJLqMzfF5HA4YLFYGD8WoWdZMj1KUKvV0Ov18Hq9OHHixL7ZHjJky+3kSieSVQOhAYDHx8L17iH3hngasb17CgoKoqbcDqobLdOQsWQjk8lA0zR8Ph/Gx8cTTpuFWzdaZLO5uYnR0VFUV1ejubn5v9NQNEwOH/LVcmiUrz4kHzhZje5aHf78l5fwgbccRo6K/+0kM0F6vT6kdsKejUk2pWO32+HxeKDX69Hd3Z1UzrlQq4BGBsybnVBIJSjLVzOK0/HaQmei6jNbHJL4sbA7l3w+X4hoJluf62oC22KAO9vDvR86nY6JAtPVbk5RVNzPdX2RFn0NBehf2kaOUoa3HikNiWpigXtvwnn35Ofnh6Tc2N8NPmRD6mtXi0snkOFpNAC4cOECtFqtYAXzSGTDntI/evQoU3Nw+4L4yh8m0b9sR55Khrvf1ooeVgTTXJaHRb0UShm/Lxo7Sgs3E8R3EDMWyFyBUqnEoUOH4v5Cun1ByKQSKOV711OWr0Z7IdBSXwitUgZqZwuDc3Nh7SGiIZMim2hg+9SwhwUtFgvm5+ehUCiYFFSskyyQmWm0cIgUUYfr5CKNF/Pz84wacCKzPcmAT83G5vJjyepGoVaB2kINZFIJ/qqzAq8/XASVXAq9Nrn25ni9ewKBAK/vYyrlatKBjIxsaJrG+vo6AKC0tBStra2CWgJwyYY9pc9tBf7zpAkvzVmQo5TBuOvF956bw0/OdcdcMxyCwSDGx8dhMpkiRmnJkg1FUZiYmMDm5ia6urowPT0d10ZH0zQGlrcxubkLlUKK0/WFqC7Ya48tUAGtZTkYHR2F1WpN2HwuWzZeAu6wIFs0k32SJeQTaYI/GyIhPulb9mwPe3jSYrFgeXk57tmeZBCr/mHc9eKhF5ewYvVAp5Hjlp5K9NTqIZVIUJafmk7EcDbiVqsVRqMRMzMzkEql0Gq1MBqNUdW9xW60FCMQCGB8fBxmsxlSqTSpgcZw4BKD2WxmnEKPHDmy78H1BSmABpRyKaQ+Cbz+/STAx6TM5XJhcHAQMpksYh2IrJWoNAwhTYqiGOXpeA3UjLteGFa3oVFKYXX6cGnRhkqdmrmmixcvQiqVJhxpprr1+SDALqw3NTWFFI+XlpYglUpDhkoP6pQvBBLRRmPP9gCI2HjBtggQCrHSzSPru1i2utFYnIMlqxsX5u3oqdUL9vqxwLXLDgaDjKsu8e4hKTc2Mfv9fni9XsHIJhgM4p577sHPf/5zbG5uorKyEn/3d3+Hu+++m9lfaZrGV77yFfzoRz+C3W7H2bNn8eCDD6KpqUmQa8gostnd3YXBYIBKpcLZs2fx0ksvCe7WKZPJ4PP5eJmPAcAbmovxO8MGFiwuaJQyfOh0zb6/idVOTayvKyoq0NraGvPLnIjDps1mYyR02NI28W7GQQoIUhTUcjm8MikCFA0ae5+N3+9HWVkZjhw5kvBJNR3kkGqwi8eRJviBvXuoVCozur1aCG20cI0X4XTt+BTTk71erVIGmVQKi9MHf5BCnjq9TQ0ymQwymQwlJSWoqqoK8e4ZHR0FRVF47LHHGHsJocjm/vvvx4MPPoif/vSnaG9vx5UrV/DhD38YOp0Od911FwDgW9/6Fr773e/ipz/9KSPMeeONN2J8fFyQTsSMqdmQGgN7GFAoAzU2ZDIZ/H4/+vv74XK50Nvbi/z8vRZeX4CC2x8qUVGYo8T3P9CBic1dFOcqUV+8P4caqcONpmnMzc1hYWEB7e3tvKUn4iEbdg2oubkZtbW1+2pA8RBXaZ4SLWV5mDU5oZRLcaJah7XVPaMziUSC9vb2pDYjQjZCRquZRF7hJviJcvXExAQAZLRnj9CfTThXTtJowE5BksaLeOdXYkU23TU6LFpcGF7bxfGqfLz1CD/F9FSC3SDA9e5xOBy4ePEi/vSnP8Fut+P48eO44YYb8OY3vxk33HBDwg1SL7/8Mm6++WbcdNNNAIBDhw7h3/7t33Dp0iUAe5/7+fPncffdd+Pmm28GAPzsZz9DWVkZHn30Udxyyy1Jv++0RzbstBl3BiQZT5tI8Hq9MJvNKC4uRl9fH5MvfWHWgm88PgW3n8INbSX4wo3NkEn3HvpctRwnD0XWXAsX2bAtlWPNnoRbjw9B8KkBRUvJBYIU1uwe0ACq9GooZFLIZVJcc7gIRyryIJMC6wszWDUacfToUYyOjgpm40xRFJNyKi4uTnimJdPrIEqlEmVlZZiYmMCpU6cY8onHs+cgkWoFAbauHRB+fiWe2Z5YNRulXIoP9FThfV00ZJLMeF4iXTMh5s9//vO4+eab8brXvQ4//vGP8ec//xn3338/aJrGBz7wgYRe88yZM/jhD3+I6elpNDc3Y2hoCC+++CL++Z//GcBeSm9zcxPXX3898290Oh16e3tx4cKF7Ccbj8eDV155JeI8ixAKzQQkAlhaWoJGo0FnZ2eIGsC3npyG1emHWiHFH0Y28bqmYrzuMD+/b25ks7Ozg8HBQeTm5oYQGl/wIRu3283kfmPVgMILcdJ4YdaC4bUdSLA3oPmG5mJIpRLIpBLkK4HBwUFQFIW+vj7QNC1YizFFUbh8+TL8fj/kcjlmZ2eTmmnJpMgmGqRSacKePQeFg5ar4aYgicLD+vo6r9keviMCcmn6SYaAjzYaUQ8gEQ2Q3HP+93//99jZ2UFrayuzr37961/HBz/4QQB7Ix8AQgwTyX+T3yWLtJKNWq1GXV0dqqqqwt58odJogUAAY2NjsFqtaGhogMViCflCUTQNt5+CXCaBWiGFx0/B5eP/uuEkYZIZPo1FNsTioLS0NGb9JNJaO54AZk1OFOUoIZVIMGt0oLNGh8IcJba3tzEwMIDCwkIcPXoUMpkMbrebIZxkNiOXywWfz4fCwkJ0dHQA2NswyKY7OTkZ16abCSfVRMHXs4cQsFDaXNGQTm00rsIDe7aHPBfc2Z5s898B+M3ZhBvoTOZ9/sd//Ad+8Ytf4JFHHkF7ezsMBgM+9alPobKyEufOnUt43XiQ9ppNbW1tRMYWIo3mcDiYCfczZ85ge3t7n3mXXCbFB05W4ycXlrHtDqClLBdnGvhFNcCrdaCxsTFsbm4mLAlDEIkg2L49ra2tqKnZ36zARaSCvEouhUYhg9Xp2xtS08ihkksZsuTOALE7VhJ96Le2tjA6OgqpVIqOjg4EAgEEg8F9My3cTVetVodsutwvaqZHNnyuL5pnD9HmYg+VpmqIMpOcOrlkzDZGI7M9pA09Ly8va7r+4iEboT7jz33uc/j7v/97Jh127NgxLC0t4Zvf/CbOnTvHzBVubW2FGEFubW0xttHJIu01m2hINo1GjMHq6upw+PBhSKXSiGveeqYWJw/pse0OoKtGF5caACEBpVKZlCQMQTiyIVptFouFl29PtLUAQKOU4dqmIlxatIGige5aHVYWZkOMzrjrAIlt7OxGiebmZszOzjJT6lxwN10yyR8p6skmxLNxcGsb7I02lZ49mUQ2bIQzRrPb7RgeHobRaMTS0tKBzfYki0Qjm2Tgcrn23Q92+r++vh7l5eV4+umnGXLZ2dnBxYsXcdtttwlyDRlPNomk0SiKwuTkJNbX1/cZg0UiG4lEguNV8Q8oWiwWWCwW5Obmore3VxC9KC5BuFwuGAwGSKVS9PX1xdXBFC0lV1uoRW2hljE6Ixpt4R5ydmQTD4LBIEZGRmC323H69GkAwMzMDO9/H26Sny2RTzZZi8WSMXpdqQDXIC1Vnj3ZYjFArCSkUimOHj0KpVK5r4U4VbM9yYCiKNA0HfM5FVrx+R3veAe+/vWvo7a2Fu3t7RgcHMQ///M/49ZbbwWw9/3+1Kc+ha997WtoampiWp8rKyvxrne9S5BrSDvZRJu7SCSyIYVz4gnDfciEajpgu3YS6XGhNjo2QRD9Mb4zOlzEGhDd3d3FwMAA8vLycPr06Yh1AT4W01y43e6QQValUgmHw8F83onYQ5PTLYl6FhcXsbGxERL1sPXLMgFCp/lS6dmTbTUQ0iAQroXYYrEwU/tCzvYke70AYu4VLpdL0Of3gQcewJe+9CV84hOfgNFoRGVlJT7+8Y/jy1/+MvM3n//85+F0OvGxj30Mdrsd11xzDZ544gnB2vPTTjbRIJfL4Xa7ef89GZ4sLy9nui64iMfPJhICgQBGRkawvb2NU6dOYX19XdAWbXKNCwsLmJ2djTp0ynetcNjc3MTIyEhEozPuOgD/jdNms2FwcHBfE4OQQ51yuRz5+fmw2+3o7u5moh6z2YzZ2dmYtZ6DRqo2cSE9e7IlsgH2rjVcN1o4UdVI8kKFhYUH6t5KvouxDo1CS9Xk5eXh/PnzOH/+fMS/kUgkuPfee3HvvfcK9rpsZDTZ8E2jsY27YglDEjXpRFWVHQ4HBgYGoNFomNP61tYW/H5/3GtFgkQiwerqKvx+f8L6YwRE+oIN9v06fvz4vnbHSNdE/m0skAHdcEOmqSpqh4t6wqk2E/LJlKhHaCTr2ZNtZAPEjhK4Qpns2Z7l5eU93T9WRJxK99ZgMAiJRHLgZJMJyHiyiRUxkHqD2+3mNTxJHsxEyIbdcNDU1MR8KYWIlghIIVihUKCvry/pB58bScRjdMZdB4hONkQ5e319PazhXLjrSRaRNsZItZ50RD3p7JaL17MnUxsEwoGkpOIlx2izPZOTk8jJyUmZb89r1aUTyACyifagxGp9Jnpger0eZ86c4ZWHJR80abnlA7b9ALfhgKyZrCUA8GoaUKVSoby8XJATFrv+43Q6MTAwALVazcvojItoROH3+0NIP1InTaKNBskgXNRD7JAPMupJd8TAx7OHPMvZ4NlDnutkyDHSbA+7+5G0nAvh28OXbFwuV9jDWjYj7WQTDZEiG/a8SVNTE+rq6ng/AERVmW8k4vV6YTAY4Pf7I3ZqJSKcyQZbFLS9vR02m00Q8gJebRAwmUwYGhoKMYWLF5HeJyExrVaLvr6+qCQuNNkkEimx0yrRoh5STE53rSdVCBf9jY6OwuVy4fLly3F79hw0hCAbLmLN9igUihA5nXhbzuNx6RQjmwNEuJoNKc7b7fa45k246/IhGxI5FRYWRnW6TKbDjbyfnZ0dRhR0e3tbULJxOBwwGAxxiYFGWou7sRMSq6mpQXNzMy8vFCBzagPRop7p6el9UY9Go4n7ujN96BR49T6oVCqUlJSgvLw8Ic+egwTpnEvVdYTzMSKK3ktLSxgbG2NazgsLC5Gfnx+T+GJpuRFcbS6dQAaQTTxptN3dXQwODkKj0eDs2bMJTwzHIgeaprG8vMyI1nGL3FwkGtkQdQNuWkuoGlAwGMTGxgbcbjd6e3uTajQAQsmGHV0mQmJCbsBCrhUr6mFLyMQb9aR7c+YDcgjIBs8eIazT44FMJmPeL4AQe4CRkZGQ2R5yMOGCjy4acPW5dAIZQDbRwCYFIqPCp003nnW5YOuo8Y2cEiEHo9GI4eHhsBFBuA6yeEFmXAKBAJOTThaEbCiKwtjYGMxmM06ePAm9Xh/XGoBwkU0qN3Bu1EMkZMJFPWRwMBsIJRoifS58PHviOeELgYMmGy5izfao1WqGnEgaUmwQyFCQNNro6Cij0cOVUUkE0WoPg4ODjAo13wJ9PA0C7Lbjo0ePhugQxbo+viBCnWVlZdDpdFhbW0t4LTYkEgm8Xi8mJiYYNeh4B77YZCPURnFQaSq2hAw7n2+xWDA3NwelUhk26smGNBoBn0NAJM8ecsKnafpAPHvSTTZsRJvtmZ2dhcfjYWaciIpAtPsstFxNJiDtZBPthpPT/c7ODmNzLATCRTZbW1sYGRlJqIDOlxz4etwkmkZjG6m1tLSgtrYWm5ubgtV/AGB0dBRFRUWMGnS8EPrkn65IIlw+P1LUQ06o2RD1JHIIUCqVISd80kqcas8eIckmSNHY3PFCJpWgPD/5LtBIsz0rKytwu9148cUXQxoN2AdbIkYr1mwOCCTNBABdXV2Cno7YZEPTNGZmZrC0tBQx0ohnvUggw6CkYytaF0sikQ1FURgfH4fRaAxJ/wk117K5uQmv14vq6uqk3DrT0fp8EOBGPW63m9HNm52dBQBMT08nVOs5SCST3lywuPDDF5fhDVD40KkqdHen1rNHKLIJUjSeGDfCsLoDmVSCs42FeF2jsCKvJA3pdrsRCARQXl4Oq9XKqDyQ2R6fz4e6ujrB5WrW1tbwhS98AY8//jhcLhcOHz6Mhx9+GD09PQD2PvevfOUr+NGPfgS73Y6zZ8/iwQcfRFNTk2DXkHFkQ1EUZmZmsLy8jPb2dgwPDwt6MgdeJQcyEOrxeNDX15dwjjQWOcQjC8NnPS48Hg8MBgOT2mJHgEK0ZZO0n0qlQllZWdK20GTd3d1dRjo/mU0j04hLIpEwwpk1NTVwOp24ePEiADBRD/FlybR5lkS10XwBCp/45SiMu17QNHBpyY5ffaQb5fmqlHn2CEU2W7teGFZ3kKeSwxOgcHnRjq7q/LiU3/mCoijI5XLo9Xro9Xpmtoc0Gvzv//2/majn17/+NbRaLdra2pJ6Pmw2G86ePYs3vOENePzxx1FSUoKZmZmQevS3vvUtfPe738VPf/pTRoTzxhtvxPj4+NWjjca+iV6vN0R9ODc3l5HYEBIymQwOhwMvv/wydDpdzNmQWIiU9iJR0/LyMm9ZGLIeX4Kw2+0YHBxEUVER2tvb952YkyEbdlv26dOnMTQ0lPTGTj7vzc1NTE9PM5sFSbMUFRXF1dmUKZt0NJDPpKWlZV/UMz8/H7HWkw4kGtls7Xphdvggk0oglUjg9gUxZ3KGpKSE9uwRimxkEgnkUgnc/iB8QRoqtRzSFDl7hhsmVygUKCsrQ1lZGX7zm9/gypUreN/73oeLFy/iO9/5DoqKinDfffcxrprx4v7770dNTQ0efvhh5mf19fXM/0/TNM6fP4+7774bN998MwDgZz/7GcrKyvDoo48KYgkNZADZEFitVgwNDaGwsBBdXV3MByKEgRoXHo8HW1tbaG5uDjEISxSkQYD9RfX5fBgeHmYm6uOJmvgSRCSjMzYSTaO53W4MDAwwsjlKpTKixXQ8IP9+ZmYGHR0dyMvLg9PphMViYTTV2PMcfEQSMy2y4YJ9fdyoJ9KGm66oJ1GyKctToTRPic0dLwKgkauUo6k0eoE7Wc8eocimLF+F1x0uxCsLdmiUErypuRgaRWoIP1Y3mlQqxeHDh2Gz2fDoo49CqVTixRdfZMzNEsFjjz2GG2+8Ee973/vwl7/8BVVVVfjEJz6Bj370owCAhYUFbG5u4vrrr2f+jU6nQ29vLy5cuHD1kA2R6p+dnUVLSwtqampCHnahLAGAvQ96YmICOzs7KCsrC2H3ZODwUTC5AV8gAJVCESLbn0jUFIts2BpksVxBE4lsiGJzWVkZ2traBFNsJpESAHR0dECv18Pn8yE3Nxd5eXmMcCQ59a+srEAikTAbb7gNJxsiGyDydYbbcNMZ9SRKNkq5FA/ecgw/fnkF3iCFD/ZUojQvvkJ7vJ49CYvpegNYsrihVkjRULxH5mcaCnGiWgepBFCniGgAfgoCDocDwN79kMvlISSQCObn5/Hggw/iM5/5DP7hH/4Bly9fxl133QWlUolz585hc3MTAPZlXsrKypjfCYG0k43H48Ha2lpEdeNEDdS4IAZkEokElZWVgnWxvLJgxXeensWWRYaJP0zhI90FmJsaR319PRobGxP64kYjCK7RWawiYiw/Gy5WVlYwOTnJdLMlsxYbHo8HAwMDkMlkkEgkUKlUzMbGPkxIpVKUlZWhoqKCmeewWCzMhpOfn4/i4mImzQJkfmQTD7hRD1EzOKioh083Gk3TeGrSjGWrG9c0FqK1fC9qry3U4B/f3izIdfDx7FGr1Uw7Pt8xBac3gEcur2HO7IJKLsX1LcW4tmlPg0yrTH36Mh6XTiG79np6evCNb3wDANDZ2YnR0VE89NBDOHfunCCvwQdpJxutVouzZ89GVe9NNrIhApfEgGxubg5erzepNQn+3ysrsLr8UElpXJg1oci7iQ+9cb9YZzyIRDYkYsrPz0dnZyeviIlv6iuVis2krlRSUoK2tjY888wzMJvNqKiogFKpZAZFSSqSHC4kEgny8/Oh0+lw+PBheDwe5tS/sLAAhUKBvLw8BINBBAKBjNPuIkiUDNlT/EDkqEdIQzA+kc1DLy7jBy8uQwLgBy8u4//+j+M4VpWf9GtHQzjPnrm5OTgcDrz00ku8PXuWbR7Mm12oL9LA5PDh0tI2rjlcCOkB+tnwiWySFfxko6KiAkeOHAn5WVtbG379618DAJOi29raCunGJbONQiEjvp3RNsRkIhu2wCXb50bI1BxN0wANQLL3IDW1NCdFNEB4siEdbfFGTHzSaHyjpURqNsSWoampCbW1taAoCvX19djY2MDs7Cx0Oh2TRsrNzQVN0wgGgwwBsT8nuVyOiooKVFVVMaf+jY0NBINBvPDCC9Dr9UzUk2l+NUJsHJGiHjI0KETUw6cb7XfDW3vWxlIJAhSN/5o0p5xs2CBKzXq9HhqNBo2Njbw9ezQKKdQKGbZ2fXB6g6jIVx8Y0QD8tNGEbns+e/YspqamQn42PT2Nuro6AHvNAuXl5Xj66acZctnZ2cHFixdx2223CXYdGUE20ZAoMZABSofDwQhcJrtmOLzraCH+5SkzPEEJTtYX441HEhe6JGATRCJGZ2zEikbI/E9ubm5UW2g+a7FBrntpaQkdHR0oKSlBMBgERVE4dOgQ6uvr4fF4YDabYTabsbCwEDIIV1hYCLlczpAPiXzYSr/Ea8Rut6OrqytkriWTXDpTkeaLFPWw1YkTUWzmE9lU5quwteNF8L/fVoUAQ5CJgNRs4vHsqdHrcUNbCS4t2lGjV+Mt7ckdDOMFH200oSObT3/60zhz5gy+8Y1v4K//+q9x6dIl/PCHP8QPf/hDAHvf60996lP42te+hqamJqb1ubKyEu9617sEuQYgC8gmkTQaEezMycnBmTNn9hWVEyUbu8sPhUzC9N+vra1BsjWFr72lDhPzy3jL2TrkCtCbT8gmEAhgaGgopuJArLVomg67iRDF5tra2hAzuEjgSzbBYDDENjs3N5eJTonFA7CXc6+urmYKwjabDWazGTMzM3C73SgoKEBJSQlTnyGRDkm3kXtE0zRUKhWqqqpCOrzMZjPjSVJQUMCQmFBKFJkEvlFPLE8WPmRzz03N+MKjk1iyufGmliK8ryv+QWghwMcSetniwNiyCXabEybTq/40724sQHFxEbTagyVKvjUbIXXRTp48id/+9rf44he/iHvvvRf19fU4f/58SCv15z//eTidTnzsYx+D3W7HNddcgyeeeELQYfqMIJtom1i8xLC+vo6xsbGo6aZ416RpGg89v4Anx41QyKT4X9ceQiVtCekG2zWtQyZQNE7mdi5cuMAoQsfrm8FeCwgN32maxuLiImZnZ+NSbOaTkvN4PBgcHIRUKmUiJXKvo8nBExXhoqIitLS0wOVyMVEPOZ2SqIcMozkcDkxPT6OwsHBfkwEpLkskEqa1mpx0tVot81rR8vtC4iC75sJFPUTDLVbUwyUbly+IBbML1QVq6DR7z2BtoQb/dmvngb2fSKBpOurGvWJz42eXNmB2+qBRyHHz8SM4Uapk7gWp+x2kZ088NRsh8fa3vx1vf/vbI/5eIpHg3nvvxb333ivo67KREWQTDXxrNhRFYXJyEhsbGzEFO+Mlm5G1HTw2vAm5TAqHy4d/fnwUn+tRhtQ3hLSGttlsAICSkhK0tLQINrEP7D3sY2NjsFgsETsAo60VLbLZ3t7GwMAAM2BKog8gfoMrrVaL2tpaxmPGarXCbDZjbGwMgUAAubm52N3dRWVlJVpbW0PSbdwmA41Gg5qaGtTV1THyKWazGaOjo6AoKmSgNBX+8+nulmO3FLOjHuJTw4562GSzZHXjb39qgNXlh0YhxQ//5jhOVB9cbSYWgsFg1AHgBbMLZqcPzSU5WLK6Mb6xi9P1tSF6dgfp2UO+D3xqNlebCCeQBWQjl8tjdo5x5VpiFdfiJQZvgEKQoqGRUdj1eiBXytDZ3QOt9tUQUwhraDJzNDc3BwC8UluxwI5sSNQBIGHF5kgbJ2lgaGxsxKFDh5j6CjttlijkcnmI5Mn8/DwWFhagVquxtrYGu92OkpISFBcXQ6fThXS3cZsMpFIpiouLmbW4/vPsWY78/PysmePhi1hRD7A3l1FaWor/3ysWbLv3xHC9AQoPPLeAH/+PjrRdOxex5mzyNQooZFKs2D3wBCgU54YS00F79pDn8KDTaJmCjCebWFGIxWLB0NAQSkpKcOTIEV6F4HiJ4XhVPlqLFRhc2YZGpcIHTtdBpw3dqJONbEidw263o7u7G5cuXeLt6hcNZLO02+0YGxuLKGvDdy0u2bA7/riNAEIQDfe1Zmdnsbq6iq6uLhQWFsLv9zPmZgaDAQBQVFTEdKXFaq3OyclBbm4u6uvrQwZKV1dXIZFIQqKeRFOZ5LUyEeyox+/344UXXoBMJsPc3Bw2Nj2g6b3NnKYBKsPGmWKRzfGqPNhdJRjbcKBCp8IbWyIPPwOp9+whe45INmlEtC9ipDQau+4QTnkgGvg4dZK1KIrC7PQk3la6g/d0tKC8uAAtZfsfhGQiGyINI5fLQ+ozQgiQkvdhMBjQ1NSUlDwPd6gzGAxidHQUNpsNvb29yM3NTRnRkNfa3d3FqVOnmDSDQqEI6UTa3t6G2WxmbHvJEGhxcTHy8vJiRj3sgdKdnR1YLBYsLy/vk9GJJ8WS7jQaX5D309jYuDfDVG3FR/5tHA4fBbmUxrWFu5icnDyw+kYsxBpAlUokuK65GNc1RyeZsP82BZ49wWCQl421SDZpQjhiILIn29vbcTtFRloTAIy7Xtz/5DTmTE6cOlSA266pxtTYnt3r6685G7WLKdHIxmKxwGAwoLy8nJGGIZuTEGm5mZkZAHtDXDU1NUmtx742r9eLgYEBSCQSnD59GgqFgnn/QhON1+uFwWCAVCrFqVOnIqYzJBIJo6bLHgI1m81YXFyM2lpNOvbYUU9eXh7y8/PR2NjITLBbLBYsLS0xKRjSsJDujVcIkM+WfHbt1YV48s7TmDU5Ua1TQuZ3hdQ32MrVQrbq8gVfi2UhIIRnD7lePmQT74hDNiDjvyHc1meHw4HBwUGoVCqcOXMmoTxqOOFMAPjxS0u4tGiDVinD46ObCFhX8a5jJbzSTvFGNjRNY3l5GdPT02htbQ0hAnL6SYZsAoEAM2dETmnJgqTRdnZ2MDAwgIKCArS3twN4lRiF/vKTz1uv16O9vT2u9dVqdUhaxG63w2QyYXZ2Fi6Xi2mHLi4uhlarjTpQKpPJUF5ezkywRyqyRxqozNQ0GhtcsgGAfLUcXTWkiUQTUt/gqjkUFhYeKPmmy6mTKFvk5+ejvp6/Zw9fS+ir0aUTyBCyiZVGI196UoQmcyGJPmjkA+fKfZsdXkgggVZGwebzQZlXjGPHjvHaKOIRvIxkdJboely4XC4MDAxApVLh9OnTeOGFFwRLyTkcDly8eBENDQ2or68XtBGAC7PZzHzeDQ0NSa3PbocGENJaPTs7C5VKFdJaHWuglEywczfecOKZ2ZJGC0c2kaDRaJgZqWAwyGjYHWTUI6S1eDJQKBS8PHuIcnosiGm0NEEmk8Hv92NychKrq6sJTdGHWxPYTzZvbi3BwIIZa/YgSvO1eOdJ/rIwfNup2Z1zZ86ciZjrTbQGRNJyRAdOKpUmbaAGgIlo7HY7Ojo6UFZWFnZQUyisrKxgenoaR44cScg9NRbYrdXBYJBprZ6YmIDP50NhYSHT4aZWq8MOlAJ7G7NSqURlZSWz8XLtoUkty+12Z/RAaTxkw4ZMJmOIPFrUQ076QkU96YpsoiGaZ8/a2hp8Ph8GBwejevaIrc9pAkVR8Pv9MJvN6OvrE+RDIGkqNjm43W7odhfwkaMKaEsP40RdIeqL+b8Wnw09ltFZvOtxsby8jKmpqbBpuWRO1xRFYXR0FDs7O8wJjqSbUtFxNj09jY2NDXR3d8ddj0sEMpkMJSUlKCkpYU6mJpMJGxsbmJycRE5ODhP1kLkkdtQTaaC0ubkZLpcLa2tr2N3dxSuvvAKNRhMio5NJmyXRRUv284wU9czPz2NsbEywqOcgazaJgm0hkZ+fj+XlZZSUlIT17CkoKIBSqUxZZHPffffhi1/8Ij75yU/i/PnzAPYOv5/97Gfxy1/+El6vFzfeeCO+//3vp6RmlBFkE+lhs9lsTDtrb29vUq2n3Ndjb+ZWqxUGgwGlpaX4QO+RhB7gWA0CxBisqakJdXV1Mb9g8ablyEBrd3c3kypKZC0uvF4vBgcHQdM0I4CZqkaAQCCA0dFROJ1OnDp1Ki1imuyTKcnHkyYD4lRKGgMiRT3sJgO1Wo3S0lIYjUacPn2amWkZHx9HMBhM+UBpPEjUyyYaIkU9Vqs16agnEyObaKAoCgqFIkSiie3Zc/fdd2NkZAQKhQJra2u8azx8cPnyZfzgBz/A8ePHQ37+6U9/Gn/84x/xn//5n9DpdLjjjjvwnve8By+99JIgr8tGRpANFzRNY2VlBVNTU2hoaMDMzExKvgSBQACLi4uYmZnZFw0kuh4X8RidscGXIHw+HwwGA/x+f8SB1kTJZnd3F/39/dDr9Th69CgWFhZgNBqxuLiIkpISQU9fJL0ol8tx6tQpwQ4WyYLbWr2zswOz2czMXvBprfb5fMx67IFSIhhJOppycnJCBkoPeiNNBdlwwY562I0W7KiHkE+s9vJMqdnwBZc8uJ495eXleOyxx/D9738fX/rSl/DVr34VN9xwA/7u7/4ON954Y8Kv63A48MEPfhA/+tGP8LWvfY35+fb2Nn784x/jkUcewRvf+EYAwMMPP4y2tja88sorOH36dOJvNgwyjmzYciokjTIzMxPWuzsZSKVSzMzMwOFwRCzSx7seN7IhRODz+XgpG3DXi0UQbH8btpU2F4mk0YxGI4aGhlBfX4+GhgYmslEqlYxKs1KpRHFxMUpKSpJykdzZ2YHBYEBRUVGIM2imQSKRQKfTQafThbRDm0wmZuKcEE9RURHkcjl2dnYwPT2NsrKyfVGPVqtFTk4ODh06xERQFouFmeNgO5QmO73OBwdBNmywN1v2BD+3vTxS1JNtkU2sSKWurg533HEH7r//fjzzzDMIBAJ44oknYDKZknrd22+/HTfddBOuv/76ELLp7++H3+8PcQJtbW1FbW0tLly4cHWSDXnAXS4XBgcHIZPJGDmVcG6OycLlcsHn84W8TrLgFvR3dnYwODgYkwgiIRbZGI1GDA8Po66uDocPH466ScQT2bCHZY8ePYry8nImRaRUKkNy8URjjBTVueklPjAajRgdHUVDQwOv9GImgWvoZbfbYTabMTc3h5GREeTk5MDpdKK2thaHDx8GgIit1VKpFKWlpSERFLHGnpiY2GeJnKrurnTef+4EP4l6FhYWwkY9VxvZAGBqhqTTsa+vL6nX/OUvf4mBgQFcvnx53+82NzehVCr31UWFtoMmyAiyAV7dPKuqqtDS0hLiey+k/wzJvcvlcjQ2Ngomoc3e0BM1Oou0Hhts/bRjx44xLnvRwHdmh6IojI2NwWw249SpU4wLZrjWZnbhs6WlZV9RPTc3l4l6wmmMkTmjubk5tLe3Z/0QG7cxgBB2Tk4OVlZWYDQaI7ZWhxsozc3NRV5eHhoaGkIGSpeXl5k6CHs4VQhkUlqK26oeLuqhaRpWqxWlpaUZk3aNBj5k4/F4EAwGE7IT4WJlZQWf/OQn8dRTTwlqFZAoMoJsnE4nhoeHceTIkbBy93K5PGG3TgL2ib2trQ3r6+uCzj9IpVIEAgFMT09jeXkZHR3CW0Oz5WHiUWzm47BJWjKDwSBOnz4NlUrFuxGAW1Qn0h4mkwkDAwP70ktSqRRTU1MwGo3o7u6OS3k600Ges8XFRXR2dqKoqChiazW5JxqNhol0+AyUku4u9olfiO4uPi6d6QI36rFarRgeHmZa5FOp1iwUgsFgzCYQl8sFAIJ03fb398NoNKKrqyvkGp5//nl873vfw5NPPgmfzwe73R4S3WxtbfE6xMaLjCCb3NxcXHvttRHz0slGNqTLyW63M5v01taWoKk5YK+G4vV6cfr06aSL51yyIYrNEokEfX19cXUuxUqjORwO9Pf3Iz8/H8eOHQOAEKKJF2xpD7I5mkwmJr0kl8shkUhw7Nixq45oJicnmWFdcjoN11ptNpuxtbXFSJ0QkzjypY82UJqfnw+dTofDhw+HnWkhpB5vHS3daTS+IEO1wJ4xmM/ni1jrKSgoyJioh0/az+FwMPW8ZPGmN70JIyMjIT/78Ic/jNbWVnzhC19ATU0NFAoFnn76abz3ve8FAExNTWF5eTnp9F04ZATZAIhaAOXraRMOZJpeqVSGbNJC+s84HA7MzMyApumkjM7YYBMEmc8pLi6OW7IFiN4gQNw66+rq0NjYyGxyQrU1swUNa2pqMDAwAGCv3jEwMACtVsuc8DNt7iQeENVul8uFU6dORRzeZEeBpDGARD0jI3s6fGzV6ngHSkmdY2ZmBl6vd5+MTjRkC9kAofJI4Wo9pLWaiLFmQtQTj0unENeYl5eHo0ePhvyMdDySn//P//k/8ZnPfIZRsr7zzjvR19cneHMAkEFkI6RbJ4HJZMLw8DAqKytD6kBkTSEkXMhmXVxcjJ2dHcFOUYRsiPMo3/mcaGuxQdM0lpaWMDMzg/b2dlRUVKRMsRnYa7Mks0zksyCmaCaTKWSjJaf8g+jAEgKk61AikeDkyZNxPQMKhQJlZWVMtxq3tTovLy9kKJDUdyINlBJNLpqmmaiHSPKo1WqGyMIRe7aRTbgBVG47MRFjZUc9bA23g4x6+JLNQYqa/su//AukUine+973hgx1pgIZQzbRwBXjjAW2x0ok2+NkU3Pc11Cr1RgeHk54PS4kEglMJhMcDkdM51E+a7HJhq3NdvLkSeTn56eUaLa2tjA2NobDhw+HWEFwTdHIRkvsAXQ6HdNkkA5VYT4g9hC5ubk4evRoUkN43NZqn8/H6LctLy8zZl4lJSWMrH20gVKVSoWqqirU1NQgEAiEiEUGAgGGmEgElW1kwycK5oqxcutdBxn18CWbVA4zP/fccyH/rVar8a//+q/413/915S9JkFWkE08xEDsB3Z2dtDb24v8/PA2tsmQDbsGRF5je3tbkEiJrG+xWJhivRD1HxI1sodAT58+DbVanTJFAFIsX1hYwLFjx6ISJnej9Xg8zEZLxC2FmOkREqS9vaysLGn77nAgKTJ2YwC5HyMjI9Dr9UzUk5OTE9OrhxAVu260ubmJ6elpaLVaplEhG1qKE7lGdko3WtRD5nqEjnr4kI3D4cjYg1WyyBiyiZVG41OzIXL0arUafX19MetAseymw4HMAsnl8hCLA6FqQE6nk6lrlJWVCTKlT9JoDoeDOYV3dnaGzC8JoYnFBkVRmJiYgMViQU9PT0TSjwS1Wi34TI+QMJvNGB4ePrD5IPZGSQYgCRnPzc0xZMz16onkUKrRaFBbWxtSN1pdXYXb7caLL74YIqOTielMIQgxUtSzuLjIqEMIGfXEU7O5GpExZBMNfNJoZE6npqYGzc3NMR+MRCKbcIrK7PWSjWzI+pWVlUxNQwhIpVI4nU688sorzIBhKq0B/H4/hoaGEAgEcOrUqaTJINmZHqGxvr6OiYmJlClS84FGo0FNTQ1qampCyHhqagperxcFBQWManWs1mqpVIqSkhLm+W1qaoLFYsHa2lrIQCmR5Il0f1dsbqxve9BalgudJrW1EKGjr0hRj9VqFSzqoajYNu+pTqOlE1lBNsRmIByIL/3i4iKOHj3K+8sfTyQSzeiMvR4p3sa72bHXb2trQ3V1NWZnZxOKvMLB4XDAZrPh6NGjqKysTGl9hkR+OTk56OzsFDzdFe9Mj5ASR9wZGq7gabrAJmOapuFyuWAymWA0GpnWanbHH/BqazU7+vH7/ZBIJMjJydl3f8lBSCKRhEjIkE33mSkzvvrELLz+IMrzVfjX9x9FhS51EWeqU318oh5CPnwVHfioVIuRzQEgloGa2+3e93O/34/h4WE4nU6cPn06rqlbvpFNMBjE+Pg4zGZzVA018hDFq+FG0k1bW1sh6wvhQUPUoO12O0pLS1PecWaz2TA0NISKigpe0aUQ4M70cCVj2Cf8ZE6MZIbGZDKFzNBkGghZEM01Uv9jt1azB0pVKhUoisLOzg6Wl5cZeSKylkwmQ1lZGXN/iYzO0tJSSKrp/75sgdsXRK5KhvVtL/44asRHztam7H0eZF0pXNRD5nrYig7Roh5C7mIaLcMRjhhI/UGr1SY028In7UUGKQHE1FAjD1E8BEGm9gOBAPr6+kJmM/hM/UeD3++HwWCA1+tFVVUV87CTtYUmgo2NDYyPj6O5uTkp9exkEM5Lxmw2w2QyMUXwRGZ62DM0J0+ezGgDNC7kcnlIa/Xu7i7MZjOTIiOyOFtbW6ipqUFDQwMARGytJnbIpImDRD1elwOBoAReHwXQEshSfM5IZxODWq3e17jBjnrC6diRfYFPg4BINmkEt2ZDtMcOHToUU4QyEmJFNvEYndlcPvzbpVVcnJPCWbyJd3fVQCqNfk1EsVmn06G7u3tfNJRMZEOaDLRaLXp7e7G4uIiNjQ2sr6+jpKREUN8U0gK+vLyMEydOoKioSLC1kwXbjTPcCZ/PTE8yMzSZBolEwpBFQ0MDfD4flpaWsLS0BIlEgrW1NXi93qgDpewmA4VCgYqKClRVVeF/F9jxxd9NYsftR20ujVLnHAYHLSEDpUI3oGRCx1ysqId0ARLFg1hk43K5ripVDTaygmxINxpN05iZmcHy8nLS9tDRyCZeo7NHLq3iv8aN8Lgk+Lcr66gqysXp+sj5/K2tLQwPD0cV6ky0u43k1quqqtDc3AyKolBRUQGaprG2tobJyUnk5+cz8inJOiWOj4/Dbrfj5MmTGX0i457w+cz0kPqTEDM0mQi73Y7l5WUcOXIE5eXlTGv1wsICRkdHmXtSXFyM3NzcqAOlRyty8auPdmPbE0RZngpez6syOuzWdSLJk+y9zBSy4SJS1LOysgIAzAE2Uq3H5XKhqqoqHZeecmQM2cSq2QQCAfT398PtdgsyexKObNiOl11dXbxP6Ss2N9QKGXLUEuwGKBh3wxf22YOgsRSbE4lsVlZWMDk5iba2NsZVk6IoqNVqNDY2Mh4sJLU0Pz8PlUoVMr/C9wvs8/kY58pTp06l3WUyHvCZ6dHpdLBYLCgvL0dra+tVN/ewtraGqakpHDt2jBGMZbdWh7snRUVFKCgsxo/6bXhmyoyaAg3uedthVOtVoGkaCgmNYo0UVDAQMlBKuuUsFgsmJyfh9/tDBkoTSUtmKtmwwY56KioqcPnyZVRWVu6Leki9R6FQMHM2QuCb3/wmfvOb32BychIajQZnzpzB/fffj5aWFuZvXnO20LHg8/ngcrmQk5ODvr4+QTqMuGTDx/EyEk4dKsCcyQmzG6gqlqO9Yv9MCcn7swdBoyFeW2jiBtrd3Y2CgoKIjQBkEyBkRORixsbGEAwGQ+ZXIqWWnE4n49UTK8WYDeDO9CwtLWF+fh4ymQzr6+tMaildMz1CY2lpCXNzczhx4kTEjjruPbHb7TCZTPjp85P4zXQAUokEo24/vvHkLH78t10hw6Thaj2kKaG5uRlOpxMWiwVGoxEzMzPQarUM8eh0Ol4kkg1kwwZpDuBGPVarFcvLy3jooYfwxBNPoKCgABaLRZD395e//AW33347Tp48iUAggH/4h3/ADTfcgPHxcYbQDtIWWkILqbOfBILBYNi5ko2NDYyMjEAikeD6668X7ITpcDjw8ssv44YbbsDOzg5TPzl27FjcZBakaFyYt+LFK8N4U1cTTjZXh/ze4/FgYGAAMpkMJ06c4BUFGI1GTE9P45prron6d2SmxePxoLOzk5mpIC3YfO8XKR6bTCZGJken0zHpNpJzt1gszDxTol49mQz2DE15eTkz02M2m7G9vY3c3Fymu+0gZnqEBE3TmJubw+rqKjo7OxOqDTz4/CJ+9NISNDLA5adQoKTx1TOqEK8e8lpsrx6yzUgkEuYAxNbHIym3YDAYMlAa6buysLAAj8eDtra2xG/IAcJms2FiYgJnzpwJ+/uVlRU8+uij+MlPfoLV1VXk5eXhxhtvxPvf/37cdNNNglyDyWRCaWkp/vKXv+Daa6/F9vY2SkpK8Mgjj+Cv/uqvAIDJjFy1Tp3A/jQaRVGYnp7G6uoqWltbMTk5KegXWy6XhwhdNjQ0oKGhIeprrNndeGrCBAmAG46UMnMEMqkE1xwuAjYVOFQQ+uWw2WwYHBxEaWkpjhw5wvu0wieycblc6O/vh0ajwalTp0KitXgVAdjFY3ZqiVgDqFQqaDQa2Gw2Jk13NYGY0i0tLYXM0ESa6SFpkFTN9AgNbut2omnoNzQX45HLq3D5gpDLZLjldA2amnJgNpsxNjaGQCAQUbU60kBpcXExo4/ncDhgNpuxvr6Oqakp5OTkMGuxyT1bI5tIqKmpwZ133olf/vKXePjhh1FRUYHHH38cIyMjgpHN9vY2ADDP9mvSFpoLUg/wer3o6+uDTCbD+Pi4oEKBZJ3x8XFeRmdObwD3PTGDWZMDADCwbMd9726HRvnqA8QliLW1NaYduLa2Nq5rj0U2VqsVg4ODqKysRHNzc4j0vBBfQnYaJRAIYGxsDCaTCTKZDNPT07BarUwnVzZ3aAGv1urILFWkGZqDmukRGhRFYXR0FLu7u0m3breW5+Lhv+3EhXkbqvRqvKG5CBKJJIQsTCZTSGs1IWSdTrevyYDr1aPValFXV8eQO4l6hoaGAICJePx+f1alb+OxhC4oKMC1116La6+9VrDXpygKn/rUp3D27FnGXuA1awtNsL29jcHBQeh0OnR2dkIulzPqAfEOTEYCGQYFwNQ4YmFzx4v1bTcqdCqABta2Pdja9eJQ0aubCukgo2kaU1NTWFtbQ2dnJ4qLi+O+xmhkQ7rlWltbmZx6vGkzvggGgxgbG8Pu7i5Ty9rZ2YHJZGK6lvR6fUi6LZsQDAYxPDwMt9sd10bMd6anpKSEdx0iFQgGgxgaGoLP58PJkyfj0jlbs3vwG8MGFDIJ3t9diQLt3r89XJKDwyX7i9gSiQR5eXmMnTWJBM1mMwwGAwDs07SL5tUjk8lQWlqK8vLykA7C5eVlOBwOqFQqyOVyplsuk1OafMgGeNViQGjcfvvtGB0dxYsvvij42nyRMWRD+vzHx8fR2NiI+vp65uEhH1IgEEiabNjDoAB4F3zL8lQozVNh0bJn29pQnIOS3NAvLpHVYXfNJfrgRPKgISTW1dWFwsLClBKN1+uFwWCAVCrFqVOnmI2KdHIRp0iyyZJiLznd6/X6jN4AhJyhiTTTMzw8nDafHr/fj8HBQUilUvT09MT13dnx+PHhnw3C5PABAJ6ZNOMXt3ZBIeNPmuxIkKZpprWa227Op7VaKpUyRNbY2IjR0VFGXJZM8bNldDItpclHFw1IjYLAHXfcgT/84Q94/vnnUV39aj25vLz8tWcLDezJtU9OToaNBKRSqSCqykSss7a2Fk1NTfjzn//Me81ctRyfv6EJfxzdggTATcfKkaMKvX0URWFubg75+fk4ffp0UpsXl2wCgQCGhobgcrnQ29sLrVabUumZ3d1dGAwGFBQURK01sQUhySZLDOUAMKf7TKtpkBmavLw8wTvqws30mEymA/Xp8Xq9GBgYgFqtxvHjx+N+f+MbDhgdPiike2rss2Yn1uyekEg+HkgkEuj1euj1emb4kbRWLywsMBEKUa1WKpVRB0oBID8/H4cOHQqZZ5mfnw+5x6kYKE0E8aTRhCIbmqZx55134re//S2ee+451NfXh/y+u7v7tWkLnZ+fj9e//vURN6Rk/GfY8y1ssc5Iay5aXJjc3EWVXoNjVa+2KNcX5+CO6xrCvobZbGZOCN3d3Uk/3IRsiOPiwMAAVCoVent7Q647FURDpuxJ7pzv+txNdnt7m2kwYNc0SkpK0ir5QnxoysvLU67hxp7p4W6yZH6FRIJC+fQQK3S9Xh9XUwobVXo1lDIJvIG9A0++Wr4vkk8G7JogRVGMavXMzAzcbjfzrBQVFSEnJyekvuP1erG7u4v8/Hz4fD5IpVLodDpmip84lLIHSknUky4vJD4inG63GzRNC6a7d/vtt+ORRx7B7373O+Tl5TF1GJ1OB41GA51O99q1hY528uXracMFMVPb3t7eN98SjmwmN3dx7x+nYHZ4kauW4/bXN+BNrZFNv9j2yuQ0JcTmRR5Mq9WKoaEhlJeXo6WlRfBGAC5WVlYwPT2dtHw++yTb1NS0r6aRk5PDbLI6ne7ATp4ktdXY2Ii6uroDeU02wvn0mEwmwXx6HA4H+vv7kzZ0qynQ4OvvbMNDLyxCKZPis9c37ovkhQIZbiwqKmIsJEgacnp6GhqNJsQkbnR0FLm5uYwDLzfqIaZz7Bkhi8WC6elp+Hw+xnQu0YHSRMBXhBOAYDWbBx98EABw3XXXhfz84Ycfxt/93d8BOFhb6IyZswEQVVL/xRdfREtLS1z2yOSEp1QqceLEiX258nBr/vTCMn5+aQX1RVos29w4WVeAr74zfC8/sVc2mUzo7OzE2toaFAoFmpubeV9jJPh8PjzzzDOQSqVoaWlBbW1tStNmNE1jenoaGxsbOHHixL4OFSHh9/uZdJvZbGbaX4ndcarSbUSup729PSU56WTAbvtNdKaH6PnV1tbGbOPPFpA5HHJQ8fl8UKlUqK+vR0lJCdNkwP4fe0sjKXgibOtyuZiox263Q6PRMEQXjzhrvJicnIRCoUBjY2PEv5mfn0d3dze8Xm9WddrxRcZENkBst8540mjRjM4IwtWB9FoFZBIJTA4fghSN4pzwqQOv14vBwUFQFMUoQm9sbAji1knSfgAYDbhUEg2J/txuN06dOpXyjjKFQoHy8nKUl5eHtBDPzMzA4/GEpNuEmNiPNEOTSWB3ckWb6YlEyKQ9+PDhw6itTZ20/0FDLpejtLQU+fn5sFqtTCS8ubkZModDuv7YTQbk/2dHPSSyJI0cREZnYmICgUAgREZHSLWIYDAYcz3SiZZN80PxIKPIJhr4ptHYaS1iRBZtTW7H11uOlGLR4sKVJRs6qvLxwd79/54oDuj1ehw7dow5hQjhrhkIBDA8PAyHY2+eJz8/P6VE4/F4YDAYoFAo0qJqzG0hJhP7ZDNJdmKf7wxNpiHSTM/s7CxcLleIJ83u7i5GR0fT6hyaSrjdbvT396OwsBBtbW2QSCRoaGhgIuRwrdVEfSDWQCnpEiSRpcViwebmJpPqJcSTn5+fFAnwdelMRdtzpiCryCZW1EBmQiwWC06ePBkzFRRuTZVChk++MXKoS+wNwikOyGQy+Hy+2G8mAkgjgEKhQG9vL5577jl4vV4oFIqUEA0plJeUlESM/g4abOMvv9/PpE/I6Z5EPIWFhTG/vOwZGiHsqdOFaDM9U1NTAIDS0lImpZQJn6NQICoZJSUl+2pQ7Ag5XGt1fn4+Q8h5eXm8BkrZzx4ZKB0ZGQFN0yEyOvG2r/Ot2Yhkc0CIlkbjetpwEY/RGUE8qTmiK7WwsBDR3iCZ9my73Y6BgQGUlpaira0NNE1Dr9fj0qVL0Ov1KC0tFbSLy2g0YnR0FA0NDbxsFNIB4pdCTvekY2lqagperxeFhYUM+XA1tMgMjVQqzXofGi7ITE8wGMT29jYOHToEt9vNzPSQDba4uDir37fT6cSVK1dQUVGBpqamqM9ouNZqEvUsLi4y1tnkoBKutZo9UEoONlzTOTJQTRxK+dpC87WETlUrfCYgo8gmGqIRg81mg8FgQHFxMY4cOcK7uMaXbEhNY2dnJ6r9NB/3z3Ag+mxNTU2ora1lHvzu7m54PB5GHJPdxVVSUpJQWommaSwvL2Nubg7t7e0pkRJPBdgdS+x02/r6OiYnJ5GXl8fcF6lUyqhSHz169Ko66QNgfJ02NjbQ09PDdFima6YnFSDmglVVVQkJvqrVakbdnKQhyeAxaa0mhKzVamMOlObm5oaYzpEmg5WVFUgkkpCB0nAEzyeyuZpdOoEsI5tw9RDi4ZKI/hgfsiGpLblcjr6+vqjhc7yRDU3TmJ2dxdLSEk6cOIHi4uJ99RmNRsNMppMctdFoZFSkiYghn/kBUr8wmUzo7u7OWkdAiUSyTyCTpJUWFhZAURRyc3OZyfWrCTRNY3x8HFarFT09PSFpl0gzPcS7KBUzPakAqYmSrrpkwU5DtrS0MGlIUgMjnk7kvsQaKJXJZCgrK2Mibq4ttE6nY8iHEDwfsiE2KlcrMopsohGFXC4PaY1O1OiMjVjkQBSby8rK0NbWFvOEHE9kw42W+CgCcLu42DMafr+fKXaG86IhenA+nw+nTp1K61Cl0CBzFQqFAmazGVVVVZBKpYxRFykal5SUHJhUTCpAURRGRkbgdDpx8uTJmKniVM/0pALb29sYGBhAfX09Dh06lJLXYEsLEU8ns9nM3BeSnmXrt0Xz6mEPlJL0ncViwcLCAhQKBSMcGgtCGqdlIjKKbKKBHdn4fD4MDg4iEAjEbXTGXTNSQZ/kZsmMCx/wNTxj+9sQWZt4FQG4g3AOhwNGoxHLy8sYHx8PEceUSCQYHByEWq3GyZMnM0o2RiiEm6Eh98VkMoXk2oWwxD5oELmiQCCAnp6euEmTRMHFxcX7pPwnJyczwqeHpMMbGxsPrH1bJpMxzwORizGZTNjY2MDk5CTTWk1argEwae5wUQ+pMxJzQtK0QD4/9kApd99KhS5aJiFrdh2S8mK3HXd3dye1cYaLRNiul/FGTHzScuTkRupLJE8MxO9BQ8Ce0SBeNKTOMzMzAwBMyilTUyeJgswkLS8v75uh4aoQC2WJfdAgzQ4ymSzpZx5IfqYnFbBarTAYDGhubo46rpBKcNOz7NZqYoHOjgb5tFbr9XoUFBRgbW0NHR0djDrC7Ows1Go1406am5sLl8uVcrL513/9V/zTP/0TNjc30dHRgQceeACnTp1K6WsSZBTZxEqjuVwuXLx4kZfRGR9wycHv98NgMDA+OvFGTLEim42NDYyOjuLw4cOoq6tjHlCh25rVajVqamqgUChgs9mYjhrSnRVP+3Amgz1Dc/LkyZhfVCEssQ8aJArOycnB0aNHU/J5RZrpIcV09kxPKgZ+iYRQa2srI0GTCeC2VhOLg5WVFYyPjzMdaSUlJftaq9nRD4mANBoN9Ho9ampqmLSmxWLBr3/9a3zlK19Bc3MzysvLsby8nJLI7t///d/xmc98Bg899BB6e3tx/vx53HjjjZiamorp5yUEMkquJpI1NE3TGBwchNFoRFdXl2A3ZmVlBVtbW+jp6WGsB3JyctDR0ZHQaY6kAd7whjfsu37SNt3R0YGSkpKUS88sLi5iYWEBx44dY+R42F05RqMRPp+POcFm0gbLB2SGhthhJ1Nz4GuJfdAgMyZkmDEdkRd7psdms4VYSAjh00Na8IkNd7aARMlmsxlWqzWsaytFUQgEApibm2OactiW2OT/UhSF/v5+fPWrX8XCwgJWV1fR1taG97///bj77rsFu+be3l6cPHkS3/ve9wDs7QfEIfTv//7vBXudSMh4svH7/RgaGsLu7i6kUile//rXC/Z66+vrWFlZQUNDA4aGhlBTU5OUCvDOzg4uX76MN73pTczPgsEgRkZGYLfb0d3dHaJgmwqiIXptVqsVnZ2dEdu02a6KJpMJu7u7IRtsJhcqSc1OJpOho6ND8FkSdheX1WqFSqVi7ksq9bPYIK2/fGZMDgpsnx6TyQSappOa6dna2sLo6CiOHTt2ICfrVIEdDZrNZrhcLqY243Q6YTab0d3dDY1GE9LhRkD2gf/xP/4HrrvuOnzkIx/BU089BaPRiNtvv12Qa/T5fNBqtfjVr36Fd73rXczPz507B7vdjt/97neCvE40ZHQajR1tHD16FGNjY4K+nlQqhcvlgsFgQHt7e9IhPLe7jQyaSiQSnD59GkqlMqXWAISYA4EAent79w06ssGtZ7DrPLOzs8wJlmhOZcJmB7wqrprKGRpuFxepZ4yMjBzI0CQR1Dx06BAOHTqUMfeej08PiXpiNV9sbGxgYmICx48fj0tcNxPBVXgghoJLS0twu91QqVRYXV2N2lpN1E/a2tqg1+vxvve9T9BrNJvNCAaD++bqysrKMDk5KehrRUJGkQ0bXKOz3d1dQUQuCSiKwsrKCnw+H06fPi3IzAlpOCBpmf7+fhQVFaG9vV2QRoBocDqdMBgMyMnJQWdnZ9y5fVLn4ZqgESdLtglauuo8xDK8oqIi5T40BMSauLS0NGSDXVxcxNjYmOCW2KR+kc5COR9Em+mZm5uLOtOztraGqakpdHR0JDSykOnQaDTw+XwIBoPo7e1lUm7s1mpyX3Jzc0FRFP7xH/8RVqsVZ8+eTfflpwwZRzbs+saxY8eYPG6ifjbhQBSb/X4/lEqlYMON5JS9ubmJ0dFRNDY2Mk6CFEUxOVqhYbPZMDQ0hMrKSkFSLuwTLLvOMz09Da/XyxRFD3JuhUQW6fKhAfZvsG63m7FJEMISe2NjA+Pj4xlpgRAL3GiQPbvi9/uZ2RWfz4eFhQWcOHEiI9W3hcD8/DxWVlbQ09PDNK2wW6vNZjO2trbw1a9+FS+++CIOHz6My5cv47nnnkNnZ2dKrqm4uBgymQxbW1shP0+VBXQ4ZFTNxufzYWBgADs7O+js7AwxOvN4PHjuuedwww03JLVhk9NxQUEBampqYDAY8MY3vlGIy4ff78fTTz8NmUyG48ePo7S0NKWNAMBe3YnMA6X6JMyeQzCZTNjZ2UF+fj6j25aqOk8m+9AQsKNBs9kMID5L7JWVFczMzOD48eP7bNGzAYsWFwyr26jSqdFT9yrRsmd6VldX4fF4oNVqUV5entaZnlSBWFl0d3fHVBg3m82455578NRTT8HtdsPv9+OGG27ARz7yEdx4442CX1tvby9OnTqFBx54AMBedqe2thZ33HHHgTQIZFRk43a7GX8Y7omZfFn5CNpFAmk9bmxsRH19PZxOp2CpuWAwiPHxcQBAZ2cnioqKUt5xNjc3h5WVFZw4ceJA0hHcOQSv18sQz9zcHNRqdUghPdn3HG2GJtOQqCU222unq6srpaZ1qcKM0YHP/GoMNpcfKrkUn3h9Pd7buWd1QGqDZLCxs7OTkRdK10xPqrC4uMibaGiaxiOPPIJHH30UTz75JLq7uzEwMIA//elPsFqtKbm+z3zmMzh37hx6enpw6tQpnD9/Hk6nEx/+8IdT8npcZNQnm5+fj+7u7rC/IznfYDAYd1GWrUHW0dHBdL6QORuappPaGL1eLwYGBpj/VqvVTMovFURDionb29u85ktSBZVKxaROiKOi0WjE0NAQADCbayJ1nnhnaDIJ8Vhib25uMu332eK1w8Xzs1bYXH6U5ilhdvjw+NgWQzbkwEDSSuQ9VlZWRp3pEVLh/CCwvLyMhYUF3kTzgx/8APfddx8ef/xxnDx5EgDQ09ODnp6elF3j+9//fphMJnz5y1/G5uYmTpw4gSeeeOLAxHgzimyigdQ74q3bsDXIent7Qx4EsgHyMTaKBKJoUFBQgPb2djz77LNwOBxQqVQpaQQg0+TAXlicKbMxxFGRFNLZKrsjIyNR7QC4YM/QZLMPDQFbi4ttiX3lyhXQNI3S0lK43W5oNJqsPNkX5SgglUiw7Q4gSAOleXufLznkra+vh9QvCMIZ57FJWeiZnlRhZWUFc3Nz6OrqCkn9hwNN03j44Ydxzz334A9/+AP6+voO6Cr3cMcdd+COO+440NckyKgnO9bGHMvThgvSJqtUKsOm5tjRUiJkQ07xDQ0NqK+vB0VRKC0txfDwMNRqNVPLEKp12OFwwGAwID8/H+3t7Rk7/S+RSFBQUICCggI0NTXtswOIpk/GnqHp6enJaj+WcFAoFCgpKcHm5ia0Wi0aGhqws7OTMkvsg8DbjpZh2ujECzMWHKnIw+2vrwdN05ienmaiNj71PGKcV1dXFzLTQ6RiMtGnZ2VlBbOzs+jq6orZaETTNP7f//t/+OIXv4jHHnsM11577QFdZWYgoxoEgL3NJtIl/eUvf8GxY8d45e6tVivTJhvJhZKmaTz55JN4/etfH1fITvLsc3NzOHbsGMrKykLqM+zZDJPJxEjElJaWorCwMKETmsViwfDwMGpqahLy98gUkDZQo9EYMjBZWloKpVJ5VfvQAHuRtsFgAEVR6OzsDNk02c0X29vbGSGOGQ5BigYNGvIInw9N00wKtLu7O+mWcHbLudlsDlF44DPTkyqsrq5ienqaV62Npmn8+7//O+666y78+te/TkkDQKYjq8jmxRdfRHNzc8xpY+Jxw0ex+amnnkJfXx/vmgBFURgdHYXFYmHC5miNAGwrAKPRiEAgwHjQFBUV8Tqhra6uYmpqCm1tbRmlHZUs2KRM7k1OTg4aGxt5dXBlG0i3pVKpREdHR9TIlG2JbbFYMkbT7rHhTXz/+UXQNI2Pv+4Q3nOiIuT3xG/HZrMxU/NCI5zCw0ELqpJZoc7OThQUFMT8+9/85jf4+Mc/jv/4j//ATTfdlPLry0RkFdlcuHABhw4dQkVFRdjfsz1u+HYvPf300+jp6eE1a0M2C3IqJaqvfDvOyLCn0WiEyWSC0+kMqWVw0ybEkXF9fR0dHR28HupshMlkwvDwMKqrqyGVSmE0GuHxePb5imQziKBmbm5u3FEb2xLbZDLFtMROFYy7Xtzy4354/HupbLVChp9/uAuVOjVznePj49je3kZ3d/eBfGbsmR6z2Rwy00OUmYUGSQfznRX6/e9/j1tvvRW/+MUvQqRiXmvIqqNjtJoNKZz7fL64FJv5Gp4RrSqdToejR48y7nsA/44ziUSC/Px85Ofn4/Dhw3C5XDAajdjc3MTU1BRTyygtLYVarcbo6CgcDgdOnjyZ0VplyYBEbUePHmW6Yth1HuIrQmyfS0tLs8qHBthLjw0MDKCoqAhtbW1xX3s8lti5ubkpuzc7ngACFA2NQgaJBPAFaOy4A6jUvRrxO51O9PT0HBgBcv1oyEzP2toaJiYmkJeXx0Q9eXl5Sd8b8jzyJZrHH38ct956K37yk5+8pokGyECykUgkESObSCoCREMtNzcXXV1dcaVf+HjQEOmcQ4cOoaGhgYlmACQVsmu1Wkb/yufzMemkubk5xojpyJEjKZF1TzdizdCQYjH73hDb53QIYyYK0q1YVVWFw4cPJ73ZRbPEXlxchEKhCEkpCZluqy/SoqdWh1cW7ABonKzT43CpFhRFMd2D3d3daeuQDOfTQyIeIWZ6Njc3MTExgY6ODt5Zk3PnzuGHP/wh/uqv/irRt3XVIOPSaH6/P2KkMTw8zOT0CbgaavF+mV9++WU0NjaG7TUnUv2zs7M4evQoysvLU64IQCIorVYLtVoNs9ksSINBJoGiKExMTDDK1PHM0LB9aEwmEyiKCpnnyaQ6j9VqxdDQUEotjtmgKIpJKZlMppRYYnsDQbw0ZwMNGtc0FkIuAYaGhuD3+9HV1ZUxXWJcsGWXzGZz3DM9W1tbGBsb463w8Pzzz+N973sfHnjgAZw7dy6rIvFUIavIZmxsDAqFAs3NzSEdYUePHo1Yx4mFixcvoqamZl/hneSfTSYT0wjAtn9NxcND9L8OHTqE+vp6SCQSQRoMMgmBQADDw8Pwer2C+NCQSX2TyQSXyxW1BnaQID4tLS0tqKqqOvDXD2chEY8ldpCi8aexLazZPTjbUIhjVfvnR4LBYEhnXSYRfSyQmR6z2RzTp8doNGJkZIS3QvVLL72E9773vfj2t7+Nj370oyLR/DcyjmwCgUDEtNbk5CQoikJLSwvGxsaYjrBkhDSvXLmCsrIy1NTUMD8jsx7BYDChRoBEsLy8jNnZ2agmUvE2GGQaUu1DE651mMw6pbKWwQXRq2PXodINtiW2xWJhVJkjdXB9/y8L+NnFVVD0Xo3me+8/FkI4gUCAsc84ceJEVhENF36/n4mWzWZzyEwPAIyPj/P23Ll06RJuvvlmfP3rX8ftt98uEg0LWUU2MzMzcDqdcLvdAJD0yRgAI8pJ0hwOhwP9/f0hsx4k0kpFRENRFKanpxn5iHi0sUiDAdlc2Q0GmdZQQAZsdTod2tvbU54KZNcyLBYLM0yZ6vZYcmjIZPl8diqS+JxwLbHf84PLWN/2IE8lw7YngP95phYff90hAHub8+DgIORyecwW7mwDe6Znc3MTbrcbOTk5qKysjDnTMzAwgHe84x340pe+hE9/+tMi0XCQVccRv98Po9GI8vJywSbo2YZnJpMJQ0NDqK2txeHDhwVrBIgEIqXjdrvR29sb90wCu8GAPSw5Pz+fEgWDREGUtoWyQOADpVKJyspKVFZWhmyuo6OjjAEaqfMIEWGxNcC6u7sFs61IBbgdXMQSe3l5GePj43sDk2oKKzYKu969Q1aVfu/ZJO3/KpUKx48fv6qIBnjVRsLv92N5eRmtra2QSCSMqGqkmZ7h4WG8853vxBe+8AWRaCIg4yKbcNbQwF5qYmRkBFqtFtdcc41gH+bo6CiUSiVUKhWmp6fR3t6OiooKxkkvVWkz4uKpVCpx/PhxQVNKbLl7omBAiOegGwxIHerw4cMxB2wPAuyTK0lFRlJkjmfNqakpGI1GdHV1ZZVoKBdkYHJqeQv/d3AbZq8EZ+tycdvrG5CXm4PBwUFotVocO3Ys6xtVIsFisWBoaGhfSps70zMyMoLf//736O3txY9//GPcdddd+PKXvywSTQRkPNmQwcbl5WVUV1dje3sbvb29gr0emXb2er1M/SfVHWfb29swGAwoKSmJKKUjFLgNBiRlUlpaiuLi4pTm2omcR3t7e8bULrhwuVwM8djtdkYihu9cBkVRjAJ3qibm0wWu7JLf74darUZjYyNKSkqyrjmFD6xWKwwGA9ra2qI2HZEDxve//3088cQTWF9fR3d3N97+9rfjHe94B7q6ug7wqrMDGU02gUAAQ0NDcDqd6OrqgtPpxNzcHM6cOSPIa/l8Prz88ssIBoM4c+bMgTQCkC6lhoYG1NXVHegpKFKDAYl6hBrE43rtZIvyAVsixmw2x6zzEHVq0ll3UIOMBw2Px4PLly8z8z1msxlOp1NwS+x0w2azYXBwEK2trbxkoWZnZ/GWt7wFf/M3f4PPfe5zePLJJ/GHP/wBHo8Hjz322AFccXYh48iGoij4/X6moKxSqXDixAkoFArGZvZ1r3td0q9DBkHJINjx48eZ2k0qGgFomsbS0hLm5+dx9OhRXp0tqUYqGgySmaHJJJCZFXKqJxEhaY8FwFg9kOfzaoTb7caVK1f2qR+wLbGtVmvSltjpht1ux8DAAO9W9YWFBbz1rW/Fu971Lpw/f17w7MQ999yDf/zHfwz5WUtLCyYnJwHsHQA++9nP4pe//CW8Xi9uvPFGfP/73w/JICwvL+O2227Ds88+i9zcXJw7dw7f/OY309Y5mJENAhaLBQaDAZWVlWhpaWE+yEgKAvHCbDbDYDCgpqYGCoUCdrs9RHpGaBDNNpPJhJ6enpieFweFaA0GGo2GIR6+isPsGZqTJ09mfCt2NJBp8+LiYrS2tjIR4eLiIsbGxiCVSqFWqwWvt2USnE4n+vv7UVZWhubm5pBnQKPRMB497BohMc6LxxI73bDb7RgcHERzczMvolleXsZNN92Et73tbSkhGoL29nb8+c9/Zv6bfR8//elP449//CP+8z//EzqdDnfccQfe85734KWXXgKwF3XfdNNNKC8vx8svv4yNjQ387d/+LRQKBb7xjW+k5HpjIeMiG6PRiEuXLqG1tTVk9gXYm66/ePEirr/++oTXX15extTUFI4cOYLKykpsbm5iZGQERUVFKCsrE9wrw+/3Y3h4GD6fT5BW7YNAIg0GXq8Xg4ODUCgUV/UGTE76CoUCcrkcdrudcd4sLS0VRH8rE0BGACorK+OS2Qk3aJtsA0Yqsb29jYGBARw+fHjffhMOGxsbuPHGG/H6178eP/zhD1PWjXfPPffg0UcfZaJnNra3t1FSUoJHHnmEkcGZnJxEW1sbLly4gNOnT+Pxxx/H29/+dqyvrzPRzkMPPYQvfOELMJlMaZEUyrgjR2FhIU6dOhW2dTQZG2e2InRPTw/0ej2CwSDzeiaTCUtLSxgbGxOsjuF2uzE4OAiNRoOTJ09m/AmPQC6Xo6ysDGVlZSENBuPj42EbDJxOJwYHBw9shiZdIKnX0tJStLS0QCKRhNR5+vv7Q9qKs1VaaHd3F/39/aipqUFDQ0Nc37V4LLHT3ZJPdOsaGxt5Ec3m5ibe9ra3oa+vL6VEQzAzM4PKykqo1Wr09fXhm9/8Jmpra9Hf3w+/3x9y6G5tbUVtbS1DNhcuXGC8tghuvPFG3HbbbRgbG0NnZ2dKrz0cMm73k8lkEWcUZDIZaJqOm2z8fj8MBgO8Xi/6+vqgVquZjjOZTMaI9zU0NMDtdsNoNDLqrjqdjrE7judUZrfbYTAYUF5ezmxM2Qi24nBLSwuTTlpYWMDo6Cjy8/Oxu7uLyspKZibhagSZFaqurg4xr1MoFKioqGDa5QkxT0xMMNpkhJizIdojG3BdXR3q6+uTXi+SJfbg4GDSwpjJYGdnB/39/WhoaODVkm8ymfCOd7wDJ06cwMMPP5xyount7cVPfvITtLS0YGNjA//4j/+I173udRgdHcXm5iaUSuW+AfCysjJsbm4C2CNGbgco+W/yNweNjCObaCAfcCAQ4B0GEnl3rVaL3t7eEJXncB1nGo0GdXV1qKurg9frZVqGZ2ZmmLbYsrKyqJPEm5ubGBsbQ1NTU0bMlggFrkXC6uoqJicnoVarsba2ht3d3YxVMEgGZO4i1qxQOGJmR8yZ3r1FahekU1JoKBQKlJeXo7y8nBHGNJvNB26JTcRu6+vreb1Pi8WCd7zjHWhubsbPf/7zAyHFt771rcz/f/z4cfT29qKurg7/8R//kXGpSL7ISrKJZQlAQBoNqqqq0NzczAxqAvw6zlQqFaqrq1FdXc2kS0iRWKVSoaysLGRCn4iDLi0t8Rbty1aQGRoSqhNiNplMCTcYZCJIqzrfdlgCNjE3NjYy3VsmkwkzMzNMOqmkpCQj7o/NZoPBYOBdu0gWUqkUhYWFKCwsDPHoId5OqbLEJrWouro6XkrcdrsdN998M2pra/Hv//7vaYtO9Xo9mpubMTs7ize/+c3w+Xyw2+0h0c3W1hYzhFpeXo5Lly6FrLG1tcX8Lh3IOLKJ9lBJJBJe/jPAq9bQbW1tqKqqSnpQk50uIcNuRqOREZYsLi6G2+1mzKPy8vLifo1sAHuGhm2JyyZm0mBgNBoxMDCQVgWDZECsf4VoVWd3b7HTSeT+pNPymURuzc3NqK6uPtDXJmD7F7HrYMSHRoj7Q4imtraWV4pwZ2cH7373u1FSUoJf/epXafPpAfaufW5uDh/60IfQ3d0NhUKBp59+Gu9973sBAFNTU1heXkZfXx8AoK+vD1//+tdhNBqZZ/epp55Cfn4+jhw5kpb3kHHdaEB0a+hnn30WnZ2dEQUraZrG5OQk1tfXmc0wlYoAFEXBZDJhcnISfr+fKRATC4CrSTsqkRmadCoYJIPFxUUsLCzwNspKFOz7w/agIaf6VG9wZrMZw8PDcUduBwWhLLGdTieuXLnC1NxiweFw4N3vfjdUKhX++Mc/Hnjq6v/7//4/vOMd70BdXR3W19fxla98BQaDAePj4ygpKcFtt92GP/3pT/jJT36C/Px83HnnnQD2/LmAvezPiRMnUFlZiW9961vY3NzEhz70IXzkIx8RW5/ZiEY2zz//PNrb28Mq6gYCARgMBrjdbsYDPdWKAKQTKy8vD+3t7XA4HDAajTAajfB6vYz3TLYUiCNBCB8ati6Z0Whk/GeEVjBIBiRyW11dZXyMDvK1iQeN0WiEw+HYE8X878OL0HUekiKMZmuRSaBpOsRGYmdnh5clNiGaqqqqkOaOSHC5XEzE8Mc//jEtg8m33HILnn/+eVgsFpSUlOCaa67B17/+dYYoyVDnv/3bv4UMdbI/x6WlJdx222147rnnkJOTg3PnzuG+++5L2wEv68jmpZdeQlNT0760BlEcIIN2crk8pYoAwKtOjNXV1ftmEcjGQYgnVdIwBwH2DE1HR4dgDyvXfybdFgk0TWNiYoLxSUp3k4PH42HuD3tKXwgl762tLYyOjvL2aclEhLOR4Fpiu1wuXLlyBRUVFbzmhdxuN97//vfD5XLhiSeeyJgB7KsBGUk20dw6X3nlFdTW1oaE/FarlZGwb25uBoCUetAArxpktbS08Mpzc6VhEm2pPmgc1AwNu8HAarUeeIMBRVEYHR3F7u4uurq6Mu4zCTdom2gdY2NjAxMTEzh27NhV08QSzhJbr9dje3sb5eXlvNryvV4v/uZv/gYWiwX/9V//FZe3lIjYyDqy4Tprrq6uMpt+TU0NU5+RSCQp2RjZBfLjx48nZJDFbqm2Wq2MoyQ50ae7M4mAzApVVVXFNUWeLNgNBmazOeUNBsFgEENDQ/D5fOjq6kprIZgPSNswIR6v18vUeUpKSqJeP2l6yGRzt2RB0zTMZjNGR0chlUrh9/tjWmL7fD586EMfwurqKp5++umU1uleq8g6siHOmnV1dZiamsLa2hpOnDiBwsLClFsDBINBjI2NYWdnBydOnBAkl8tuqTabzYzpWbpbhkk+P90+NOEaDEiqRIgGA+I6KZVKs9LemNQxSNS8u7vL1HnIxkqwsrKCmZmZkC7CqxEejwdXrlxBcXExWlpa9qXbiCW2XC5HdXU1ZDIZbr31VkxPT+OZZ565aqK9TEPWkc3w8DDUajV2d3fhdDrR3d0NrVabcqLxer2MyOCJEydScvplt1SbTCbIZDKGePR6/YG1DGeqD43QDQZerxcDAwPQaDQ4duzYVdE5SMzPSNSs0WhQWlqKYDCI9fV1dHV1XdXpIUI0RUVFYVNnbNfW++67D3/605/Q2NgIq9WKP//5z2hra0vTlV/9yEiyCQQCEWdphoeHYTKZkJ+fzxSrKYpiJGxSQTQOhyOkbnEQmxI50ZMGA5qmmdNqqlqqs82HJlyDASGeWMV90lCi1+tx5MiRrJn9iQckHbmwsIDd3V3I5XLm/lxtbfnA3uHhypUrKCgoCLFDiAS/34+Pf/zj6O/vh1arxdjYGPr6+nD77bfjlltuOaCrfu0gq8jGZrPh8uXL0Gq1zPBSqhsBLBYLhoeHUVtbG7cooVAgSrqEeHw+n+CaW9nuQ8NuMLBYLEznVrh0JJErKS8v3yedfzWBpmnMz89jZWUFXV1dCAaDTNRM5lXIM5RN3ZHh4PV60d/fD51OhyNHjvByWP3kJz+J5557Ds8++yxqa2uxtraGP/zhDygpKcF73vOeA7ry1w6yhmzW1tYwPj6OgoICKJVKHDlyhGmPTtWpdHV1lbEjiGYRe5CI1lJdWlqaUHpPiBmaTAK3wYA9aCuRSDA0NMQITV7NRDM7O8vYFbMPD+HmVWIV0DMZPp8PV65cQX5+Ptrb23kRzec+9zn86U9/wnPPPSeI4Ggs3HffffjiF7+IT37ykzh//jyA7DRASwYZecXceZWZmRksLy+js7MTu7u7MJvNKa3PkNckOe5MSicRZ9G8vDw0NjYyLdXr6+sJqVSzZ2iyyQYhGiJZJIyMjDCdSaTOdzW8Xy5omsb09DS2trbQ09OzL6UokUgYi+f6+vp9unZqtZohnkx33fT5fOjv72eGqvkQzT/8wz/g97//PZ599tkDIZrLly/jBz/4AY4fPx7y82w0QEsGGRnZBINBBAIB5sTtcDiYITsirskunhcUFAj2hQgGgxgZGYHT6URnZ2dGqvNGAhkCNBqNsNlsMVuqiSJ2QUHBVVu3INja2sLIyAgaGhpAUVTGKhgkCyLXZDab0dPTE/e8EGlSIeQDgFHByLQ6DyGanJwcHD16NObzS9M07rnnHvz85z/Hs88+i9bW1pRfI9m7vv/97+NrX/saTpw4gfPnz2etAVoyyFiyIXl1MrWuUCgY6RlgbwZka2sLJpMJNE0zm2oycxgejwcGgwFyuZx5zWyF3+9niMdisexrqd7e3k7LDE06wFaoZre1JtNgkImgaRrj4+Ow2Wzo7u5OejCVpumQeR6Px5OQLlkq4Pf70d/fz3QS8iGab37zm/jhD3+IZ555BkePHj2Q6zx37hwKCwvxL//yL7juuusYsnnmmWfwpje9CTabLaQ7sK6uDp/61Kfw6U9/Gl/+8pfx2GOPhbh1LiwsoKGhAQMDA2kxQEsGGZlD2N7exsWLF1FaWsq0InI9aIhvCE3TTNcWcZJMRAhzd3cXg4ODKCoqQltbW9af8hUKBSorK1FZWYlgMMjMGQwMDEAikSAQCOwzArsasbCwgMXFxbCzJWylYXYqaXZ2NmqDQSaCoiiMjY1hd3cXPT09gtTdJBIJCgoKUFBQEGIDQFK26arz+P1+RpqKL9H8n//zf/Dggw8eKNH88pe/xMDAAC5fvrzvd9lqgJYMMpJsZDIZY9VK2pqB8I0AEomE8cVoaWlhuramp6fh8/lQXFyMsrIyFBcXRyQeks+vr6/HoUOHMn5jiRcymYypYSwvL2NmZgaFhYXY2trC5uYms6mmQ94+VSB1N2IDHsvyIZpFArvBoKCgIOMOIhRFYWRkBC6XCz09PSlLr7DJ2efzhdR5VCpVSJ0nVfeIEI1SqcTx48d5Ec13v/tdnD9/Hv/1X/+Fjo6OlFwXFysrK/jkJz+Jp556KusbboRCRpJNXl4eVCpV3IOaXP9zYmE8NzeH0dFRFBUVMcSjUChA0zRWVlYwOzubcQOMQoOtZtzd3Q29Xh/SUj01NcWQc6bL/8cCu407XIE8FsI1GBiNRoyNjQmuYJAsKIrC0NAQvF4vuru7DyyPr1QqUVVVxXhFkTrPyMgIaJpm7lFRUZFg9ygQCIQIwvIhmoceegj3338/nnjiCfT09AhyHXzQ398Po9GIrq4u5mfBYBDPP/88vve97+HJJ5/MSgO0ZJCRNZuRkRHk5uYyaTAhIg3SLry1tcW0C1MUBYfDgRMnTlzVU9UURTG5/EhqxuFaqoneVqIt1ekAOeU7nU50dXUJeqrMNIsEoukWCATw/2/vzKOauvY9/k2YRCHMoxVEARFEmQpF61iUUYK1tnptRWrb1VaverVa2lfxvtt61dpnrb0qta+Kq9bWARxA1DogjnVIABkEqSBIkTDJPCbZ7w/XOY8AaoSMsD9rsVabHJJ9Ijnfs/f+/b5fb29vjdhjZG5gmFkP8xn1N+6ZERrGVuh5M3BCCPbs2YP/+q//wsmTJzF58uQ+vW9faWxsRElJicxjMTExcHNzw6effooRI0bAysoKv/76q0wAmpubW48CgUePHrHO3Lt378aaNWtQWVmpdQUtGik2f//73xEfH4/AwEDw+XxERkbC3t5eYctbDQ0NyM7ORltbGwghMDMzYzfPte0f8HkwFX0dHR3w9vaW+/yYkurKyko0NDTAxMSEjcHWNEdkBrFYLHPxVbZAMnsYzGekygIDiUSCjIwMEELg7e2t9hnW0+hehCFP/kx3JBIJm2gqr9D8/PPPWLNmDZKTkzFt2jQFnU3/6FogAEArA9D6g0aKDbO8lZiYiKNHj+L69evw8/MDn89n88D7Kjytra3IzMyEgYEBPD092a5qkUikVdb/8qCoHJpnlVRritNAR0cHMjIy2EpCVV98X8TBoL+86F2+ptDVELO6ulqufR5GVAHA29tbLqE5ePAgli9fjqSkJMyaNUsp59IXuouNNgag9QeNFJuuEEJQXl6Oo0ePIikpCZcvX8aECRMQFRUFPp//QhYyTLmvtbU1xowZ0+OPu729nb2bf/z4MYyNjWFtbQ0bGxut6rcBlNdD87ySanUUV7S1tUEoFGLYsGFyVScpm2c5GPS3wIDZIGduILRFaLrT1RCzqqoKUqm0x16YRCJBZmYmpFKp3LO3xMREfPjhhzh06BDCw8NVcCYUedF4sekKIQRVVVU4duwYEhMTkZaWhrFjx7LCM2bMmKde7EQiEXJzczF69Gi5ZkZMtQ1zUR02bBgrPJpu56GqHBqmpJq5qOrq6rIXVVW5VDOiam5urpEl610LDKqqqvpVYNDR0QGhUAgDAwO5Nsi1BWYvjPmMWlpaYGZmhvb2dnC5XPj5+cn1OZ04cQJLlizBL7/8gqioKOUPnPJCaJXYdIXprzl+/DgSExNx7tw5jB49GpGRkZgzZw57Ny+VSnHlyhWIxWKMGzeuTxG4vWXO2NjYwNraGsbGxholPEwOjYuLCxswpwqYpETmgsG4VCuzpJpp/LWzs4OLi4tG/Tv0Rm8FBl1Dz561n8bEIQwdOlQjZm/KpKmpCXfu3EFbWxukUimMjIzYv6Wn7fOkpqYiOjoaCQkJmDdvnhpGTXkeWis23amvr0dycjKSkpJw+vRpvPTSS4iIiEBeXh7y8vJw7do1haTvMXfzIpEI1dXV0NfXZ5eR+psL31+YcKy+iqqiYDrPmSXJzs5OhZdUP378GJmZmRg5cqRK/K2UgbwFBswyIeP/NZCFRiqVsqawPj4+bOomsxemp6fHJrbyeDwMGTIE586dw4IFC/Djjz9iwYIFGn/TMVgZMGLTlcbGRhw6dAiff/45Ojo6YG9vj6CgIMyZMwd+fn4K+7Iy686MbY6y/NqeB+Pwy6SWalIZN1NSzXxGTEk1c1HtS8UY08/h6uqKl156SQmjVj29FRgw+2AFBQUwNzeXyzpfm2HK1ltbW+Hr69ujlFsikbBLkufPn8eXX34JHx8fCIVCfP311/joo48G9Oej7QxIsbl//z4iIiLg4uKC//3f/8XVq1eRmJiIlJQUGBsbIzIyElFRUXjllVcUtrzDrM2LRCJUVlYCALvHo8yuc3l6aDSJ7nfzpqamrPDIU/336NEj3L17d0A34TIFBuXl5WyBgZ2dncY6GCiC5wlNdyQSCfbs2YMff/yRnUVPnToVkZGR+Oijj7SyWmugMyDF5ty5czh16hS+/vprGTFpa2vD2bNnkZSUhBMnTkBfXx+zZ89GVFQUJk2apLCmuK5+bZWVlaxfm42NjUL3L5i+ks7OzhfqodEUupdUM9V/jEt1d5hlwgkTJsDCwkINI1Ydzc3NEAgE7NIjM+thCgwY77+BcFGVSqXIyclhY97lme3euHEDUVFR2LBhA5YuXYoHDx7gxIkTuHXrFn7++Wc6w9FABqTYyENnZyfS0tJw5MgRHD9+HFKpFOHh4ZgzZw6mTp2qsIbArpYwIpGI3b94nl/b82B6aBiPKG2/6DA9GEz1n6GhITvjMTY2xoMHD1BSUgJvb2+NWiZUBk1NTRAIBLC3t5epJuxPgYGmQghBTk4OayAqz/dOIBAgMjIScXFxWLlypdKEZdeuXdi1axcePHgAAPDw8EBcXBxCQ0MBDL7ws/4yaMWmK2KxGJcvX8bhw4dx/PhxtLS0IDw8HHw+H6+99prCLE8IIaxfm0gkQltbm8zGubwzq4GeQ9O1T4XJVCGEwM3NTaFOEppIY2MjBAIBRowY8dweMnU6GCgCQghyc3PR0NAAX19fucQyKysL4eHh+PTTT7F27Vql/i0kJydDR0cHLi4uIIRg37592LJlCzIyMuDh4YGPPvoIJ0+eREJCAht+xuVyZcLPvLy8YGtriy1btrDhZ++//75WOgD0Fyo23ZBIJLh27RrrXlBXV4eQkBBERUVh5syZCmvuZKJ5mT0eeTfOmR6awRAPwNjm19bWwszMDI8fP5YpqbawsBhQQltfXw+hUNinCrunFRhYWVlpZEQCk71TV1cHPz8/uYQmNzcXoaGhWL58OdatW6eWczI3N8eWLVvwxhtvDLrws/5CxeYZSKVS3Lx5kxWeiooKzJo1C1FRUQgODn6ubf2L0NLSwgpPY2Njr35t6uqhUQdMYmprayt8fHxgYGCgkpJqdVFXV4eMjAyMGjUKjo6O/XotZToYKAJCiIwrtzwrB/n5+QgNDcV7772Hr776SuVCI5FIcPjwYURHRyMjIwMVFRWDLvysv1CxkROpVIqMjAwkJiYiKSkJJSUlCAoKQlRUFMLCwhR699ja2speUBm/Nn19fVRXV8PT01OtPTSqQCwWy9iU9La82HVJsrKyEq2trTIOzNp011hbW4vMzEyl3EQ8zcFAXQUGTGx1TU2N3EJTWFiI0NBQLFy4EJs3b1apWGZnZyMwMBBtbW0wMjLCgQMHEBYWhgMHDiAmJgbt7e0yx/v7+2P69OnYvHkzPvjgA5SUlODMmTPs8y0tLRg2bBhSU1PZvZ/BgvbeCqoYLpcLX19f+Pr6YsOGDcjJycGRI0ewbds2fPzxx5gxYwb4fD7Cw8Nhbm7eL+ExNDSEo6MjHB0d0dbWhtzcXHbvori4GC0tLbC2ttY6vzZ5YCxZ9PX1n2m8yOFwwOPxwOPx4OzsjObmZlRWVqKsrAx3795lS6qtra01OryqpqYGWVlZGDNmDIYPH67w1+dyuWyqrZubG2sLc//+fWRnZ6u0wIAQgoKCAlRXV8stNMXFxYiIiMAbb7yhcqEBgDFjxiAzMxP19fU4cuQIoqOjkZ6ertIxDBTozKafMF8gZsaTnZ2NyZMnIyoqCrNnz4aVlVWfhad7D42enl4PvzbGNkdT3Jf7Q1tbGwQCAYyNjTFu3Lg+X1ja2trYGU9dXd1zS6rVBdOcOnbsWNjZ2an8/VVZYEAIwb1791BZWQk/Pz+5eqpKS0sREhKCkJAQ7Ny5U+3LfwAQFBSE0aNH46233qLLaC8IFRsFQghBUVERjhw5gqNHj0IgECAwMBBRUVGIjIyEnZ2d3MLzvB4axq9NJBLJlAprol+bPDAVdhYWFhg7dqzCxt/VULW2tlZjPqfKykpkZ2dj3LhxGtGcyhQYMJ+TIgsMmIjuiooK+Pn5yTUjLy8vR3BwMKZNm4bdu3drjLv1jBkz4ODggO+++27QhZ/1Fyo2SoIQgtLSUiQlJSEpKQnXr1+Hv78/m8kzYsSIp36B29rakJmZKXcPDbMhrIl+bfLQ0NAAoVCo9Aq77p+Tnp4e+zmZmpqq7HOqqKhAXl6e2j3snoZYLJbJnelPgQFjpfTo0SP4+vrKNWOqqKhAaGgoAgICsHfvXrUJzWeffYbQ0FA4ODigsbERBw4cwObNm3HmzBnMnDlz0IWf9RcqNiqgayZPYmIirly5Ai8vLzYawcnJib3QlZeX4/79+33uoWHy4JkNYXX5tclLbW0tsrKyFFKF9SJIpVLU1NSwd/MA2Dt5ZZZUl5eXIz8/H+PHj4elpaVS3kOR9LfAgPHs8/Pzk0toqqqqEBYWBk9PT+zfv1+tFYZLlizB+fPn8ejRI5iYmGD8+PH49NNPMXPmTACDL/ysv1CxUTGEEFRWVrKZPBcvXoS7uzv4fD7s7e2xdu1a7NmzByEhIf0Whq62/5WVleBwOKxtjiaUwDKl3MraHJeXp5VU29jYKLRiq6ysDPfu3dNau53ecmeeVWBw//59lJWVwdfXV649xZqaGoSHh8PZ2RkHDx5UmH0URTOgYqNGCCGora3F8ePHsWPHDmRlZcHf3x/Tpk3DnDlzFBoG1ptfGzPjUUdzJHOHr2lLScoqqX748CH+/PNPeHl5wczMTMGjVg/dCwxMTExY4RGJRCgtLYWfn59cQlNXV4eIiAgMHz4ciYmJWlW6TpEPKjYawH/+8x/ExsZi9+7dkEgkSEpKwpkzZ/DSSy+Bz+djzpw5GD9+vEKFp7tfG7Mm3x+/NnkpLS3Fn3/+qRV3+ExJNdNs25eS6pKSEhQVFQ1oX7euBQY1NTUAgOHDh2P48OHPLTBoaGhAZGQkzM3NcezYMY0uVaf0HSo2aqampgaTJ0/GTz/9hMDAQPbxxsZGnDx5EklJSTh16hQsLS3B5/MRFRWl0EyeZ/m1WVlZKXRtmRDCLq14e3vDxMREYa+tCvpSUl1cXIySkhL4+PiAx+OpeMSq58GDByguLoaTkxMaGxvZAgPm76n78m1TUxPmzJmDIUOGICUlRa6SaIp2QsVGA5BIJM+cTbS0tOD06dNITEzEyZMnwePxEBkZCT6fr9BMnr76tcn72gUFBaisrISPj4/W9wU9r6QakN2zUKS1kaZSWlqK+/fvw9fXlxXWrgUGlZWVkEqlaGxsRE1NDUJCQvDuu+8CAE6ePKn1fxOUZ0PFRstobW2VyeQZMmSITCaPImci3ZeQevNrkwfGULOhoQE+Pj4D7u6VKRVmvMj09PSgr6+PlpYW+Pn5DQqhYfakfHx8njpjZQoMkpKS8PXXX+PRo0cYNmwY/vWvf+HNN9/UiH4jivKgYqPFdHR0yGTyAGAzeaZMmaLQTdbe/NoY94JnrbFLJBI2U14bA95eFLFYjOzsbNTW1oLL5YLL5bL7Yebm5mqvAFQGjNDIuyfV3t6OBQsWoKamBhEREThz5gxu3ryJsLAwnDhxQvkDpqgFKjYDBLFYjEuXLrGZPG1tbQgPD0dUVBSmT5+u0E3X9vZ2VniYhE1GeLp2h3d2drJWHV5eXgO+lJVxM2ZMJg0MDNiS6qqqKojF4gGXssmUc/v4+MglNB0dHXjnnXdQVlaG8+fPw9zcHMCTuO/8/HxMnz5dIePauHEjkpKSkJ+fD0NDQ0ycOBGbN2/GmDFj2GNo+JlqoWIzAJFIJLh69SobjVBfX4/Q0FBERUUhKChIoQaezN6FSCRCbW0tjIyM2AbSgoICGBgYYPz48RpjN6IsmCAwJp+lu7h3T9lsbW1l98MsLS21stT3r7/+QkFBAby9veUq5+7s7ERMTAwKCwuRlpam1KbWkJAQzJ8/Hy+//DLEYjE+//xz5OTkIC8vjy3moOFnqoWKzQBHKpXixo0brPCIRCIEBweDz+cjJCREoZuyjF9beXk5amtroaOjgxEjRsDW1hZGRkYa516gKKRSKXJyctDU1CR34mRTUxMrPF33w6ysrLSi9Jfpk/Ly8mJnJ89CLBbjgw8+wJ07d5CWlqby/ZmqqipYW1sjPT0dU6ZMQX19PQ0/UzFat4C8Y8cOjBw5EkOGDEFAQABu3ryp7iFpNFwuF4GBgfjmm29QWFiI9PR0uLq6YsOGDRg5ciTmz5+PX3/9FfX19ejvfYeenh6MjY3R3NyM4cOHw93dHa2trbh16xauXr2Ke/fuKeR9NAmpVIrs7Gw0NzfLnTgJAEZGRnByckJAQAAmTZrENkJeuXIFN2/eRHFxMZqbm5U8+r7BLHlNmDBBLqGRSCRYunQphEIhzp07p5ZCgPr6egBgxysQCNDZ2YmgoCD2GDc3Nzg4OOD69esAgOvXr8PT01NmvMHBwWhoaEBubq4KRz8w0KqFx4MHD2LVqlWIj49HQEAAtm3bhuDgYBQUFGhUF7qm0jWT59///jdycnJw+PBhfPvtt1i6dClmzJiByMhIRERE9MlHrb6+HhkZGRgxYgRGjRoFDocDW1tbGb82oVDI9l3Y2Nio1ABT0XQtfvD19e3zna6hoSEcHBzg4OAgU1J9//591n1Z3S7VDBUVFbh7967cDblSqRQrVqzAtWvXkJaWBnt7exWMsucYVq5ciUmTJmHcuHEAnpyHvr5+j30mGxsbVFRUsMd0F0bm/5ljKPKjVWKzdetWvP/++4iJiQHwZEp78uRJ7NmzB7GxsWoenXbB4XDg6ekJT09P/Pd//zfy8/Nx5MgR7N69G8uXL8eUKVPYTB5LS8vnXuSYEDBnZ2c4ODjIPNfVDLSrX1tWVpbG+bXJi0QiQVZWFsRiMXx9fRVW/KCvr8923nctqb59+7baXKoZRCIRcnNzX0hoPvnkE1y4cAFpaWk9/i5UxdKlS5GTk4MrV66o5f0pT9CObzaebEQLBAKZaS+Xy0VQUBA77aX0DQ6Hg7Fjx2LdunUQCATIy8tDUFAQfv75Zzg7OyMsLAw//PADHj161OsSmEgkQmZmJrsM8Sy4XC4sLS3h7u6OKVOmwNPTE1wuFzk5Obh06RKbSiqVSpV1uv1GLBYjIyMDEomEDbVTBrq6urC1tcX48eMxdepUuLm5sTlHly5dQl5eHqqrq1XyWTGmqfK6VUulUnz++edISUnBuXPn4OTkpPQx9sayZcuQkpKCtLQ0vPTSS+zjtra26OjoQF1dnczxIpGIdW22tbWFSCTq8TzzHOXF0Bqxqa6uhkQi6XVaS6e0ioPD4cDZ2RmxsbH4448/UFhYCD6fj8TERIwZMwazZs3Cf/7zHzx8+BCEEGzfvh2//fYbxo8f/8JLJFwuF+bm5nBzc8OUKVPg5eUFXV1d5Ofn4+LFi8jOzoZIJIJEIlHS2b44nZ2dEAqF4HA48PHxUVkJLJMp4+HhISPSeXl5SE9PV+pnxSSKenp6wsrK6rnHS6VS/POf/8Thw4dx/vx5ODs7K3xMz4MQgmXLluHo0aO4cOFCD7FjZqPnz59nHysoKEBpaSlrGxUYGIjs7Gw2ggIAzp49Cx6PB3d3d9WcyABCa6rRysvLMXz4cFy7dk3GQ2zt2rVIT0/HjRs31Di6gQ+TyZOUlITExERcvXoVbm5uKCoqwtatW/H2228rbFmH8WtjbHOU6df2IjBCo6enhwkTJmhEOXdX23/ms+pqMdTfWVdVVRXu3Lkjd6IoIQT//ve/8eOPPyItLQ0eHh79ev++8vHHH+PAgQM4fvy4TG+NiYkJ62BBw89Ui9aITUdHB4YOHYojR44gKiqKfTw6Ohp1dXVsBz1F+TCbvgkJCfDz88PVq1fh4eHBGoW6uLgoVHi6+rW1tLTA3NwcNjY2CrmYyktHRweEQiGGDBmiUAduRdPU1MQKT1NTU79Kqqurq3Hnzh14eHjILTTffPMNtm/fjgsXLmDChAl9PY1+87S/v71792Lx4sUAaPiZqtEasQGAgIAA+Pv74/vvvwfw5KLn4OCAZcuW0QIBFbJy5UokJSXh7NmzcHV1RW1tLRsGd/78ebi6uiIyMpLN5FHkRnZvfm2M8CjLCqe9vR0CgQBGRkYYN26cxgpNd7pbDPF4PLbA4HmNvUzBx9ixY2FnZ/fc92KWVLds2YLff/8dfn5+ijoNygBBq8Tm4MGDiI6Oxg8//AB/f39s27YNhw4dQn5+PjXxUyGMoIwYMULmcSYn58SJE2wmj4ODA5vJw+wzKArmYioSidjwLnn82l6EtrY2CAQCmJiY9CmmW1Po6Ohghae2thbDhg1jhad7w21tbS0yMzNfSGji4+Px5Zdf4vTp03jllVeUeSoULUWrxAZ4EjS2ZcsWVFRUwMvLC9u3b0dAQIC6h0XphYaGBplMHmtra3apzdfXV6EX7ra2NtY2p66u7oXu4p9Ga2srBAIBzMzM4O7urvYeF0XBOD1UVVWhuroa+vr6MqXpTGWhPAUfhBD89NNP+OKLL5CamopXX31VBWdA0Ua0Tmwo2klzc7NMJo+pqSmbyRMQEKDQzfbud/GMXxtzFy8PLS0tEAgEsLS0hJub24ARmu5IJBK274mpZjMzM4OTk9Nz+54IIfj555+xZs0aJCcnY9q0aaobOEXroGJDUTlMJk9iYiKSk5PZTJ45c+Zg4sSJCt187ezslIkrZkLObGxsnurX1tzcDIFAABsbG7i6ug5YoelKXV0dhEIhhg8fDkIIKisrIZFIYGVlBSsrqx5x4YQQ/Pbbb1ixYgWOHj2KmTNnqnH0FG2Aig1FrXR0dODChQtsJg+Hw0FERASbyaPIarPuIWf6+vrsHg+PxwOHw0FTUxMEAgHs7e3h7Ow8KISmvr4eQqEQzs7O7D5cbyXV5ubmEAqFiIyMRHp6Oj7++GMcOnQIYWFhaj4DijZAxYaiMYjFYqSnp7OZPB0dHTKZPIqsNuvq11ZVVQVdXV2YmpqiqqoKDg4OGD169KAQmoaGBggEAowePfqp7g9M+XlhYSFiYmJQVFSEoUOH4m9/+xvWr18vVxEBhULFhqKRSCQSXLlyhY1GaGxslMnkUWS0tFQqxcOHD1FYWAgOhwNdXV12j0eb/NpeFEZoRo0aBUdHR7l+JzU1FStWrMDMmTNRVFSEa9euwd/fHz/88AM8PT2VPGKKNjMwv0VKZuPGjXj55ZdhbGwMa2trREVFoaCgQOaYtrY2LF26FBYWFjAyMsLcuXN7+CyVlpYiPDycdfZds2YNxGKxKk9FY9HR0cHUqVOxfft2lJSUIDU1Ffb29vjss88wcuRILFq0CImJiWhqaur3ezU0NKCoqAiurq6YPn06e9HUJr+2F6WxsRFCoRBOTk5yC825c+ewePFifPPNN0hISMClS5fw119/ISYmRuGzm0uXLmH27Nmwt7cHh8PBsWPHZJ4nhCAuLg52dnYwNDREUFAQCgsLZY6pra3FwoULwePxYGpqiiVLlijk74XSN+jMpg/QFED1IZVKIRQKceTIESQlJaGsrAwzZ84En89HaGgou/ciL0xPiYuLy1P7hhj3gq6xzt03zLWJpqYm3L59G46OjnIbZKanp2PevHnYsWMHFi1apPQlxlOnTuHq1avw9fXF66+/jqNHj8o4h2zevBkbN27Evn374OTkhHXr1iE7Oxt5eXlsj1VoaCgePXqEH374gU0Jffnll3HgwAGljp3SO1RsFABNAVQPTHAZIzz379/HjBkzwOfzER4e/txMHqZLfsyYMRg+fPgz36u3DXNN8Gt7URihcXBwwKhRo+T6nStXrmDu3LnYunUr3nvvPZXvZXE4HBmxIYTA3t4eq1evxieffALgSZGDjY0NEhISMH/+fNy9exfu7u64desW62Zw+vRphIWFoaysTC25OoMduoymAGgKoHrgcrmYMGECvvzyS+Tk5EAoFOKVV15BfHw8Ro0ahaioKOzduxdVVVU9ohGYPJ2xY8c+V2iAJxc8ExMTuLi4YOLEifD394eRkREePHiA9PR0ZGRkoLy8HJ2dnco63X7DlHQz4XbycOPGDcybNw8bN25Ui9D0RnFxMSoqKmS+XyYmJggICJD5fpmamsrY5gQFBYHL5VLTXjVBxaaf0BRAzYDD4cDd3R1xcXEQCoXIzc3FjBkzsG/fPjg7OyM8PBy7d+9GRUUF9u3bh0WLFsHd3b1Pew0cDgfGxsYYPXo0AgMD8corr8DU1BSlpaVIT0+HUChEWVkZOjo6lHCmfaO5uRm3b9/G8OHD5RYagUCA119/Hf/85z+xdOlSjRAa4P+/H8+KG6moqOiR3qurqwtzc3P6/VIT2jH312BoCqDmweFw4OLigs8++wyxsbEoKSlBYmIiDh8+jDVr1oDL5eLdd9+FWCwGIaTfF9Fhw4bByckJTk5OrF9beXk58vPzYWpqyla2Kcqv7UVh3BDs7e3lLunOyspCZGQkYmNjsXLlSo0RGor2QsWmHzApgJcuXXpqCmDX2U33FMCbN2/KvB5NAVQ8HA4HI0eOxOrVq2FhYYHMzEwsWrQIeXl58PDwgI+PD/h8Pvh8PkaOHNnvi6qhoSEcHR3h6Ogo49d279491q/NxsZGoaXbz4Lxd7OxsZG7STU3NxezZ8/GqlWrsHbtWo0TGub7IRKJZGamIpEIXl5e7DFdQ8+AJ31ctbW19PulJugyWh+gKYDax5kzZ/D3v/8dycnJ2LVrFy5evIiHDx9i8eLFuHDhAry8vDB58mRs2bIF9+7d6zX++kUZMmQIRowYAT8/P0yZMgX29vaora3F1atX8ccff6CoqAjNzc0KOLveaW1txe3bt2FlZSW37U5+fj4iIiLw4Ycf4osvvtA4oQEAJycn2Nrayny/GhoacOPGDZnvV11dHQQCAXvMhQsXIJVKqXGvmqDVaH2ApgBqH+3t7bh79y5759sVQghqampw/PhxHDlyBBcuXICrqyvrUK3oTJ6++LW9KG1tbbh9+zYsLCzkNhItLCxEaGgo3n77bWzatEmtzaxNTU34888/AQDe3t7YunUrpk+fDnNzczg4OGDz5s3YtGmTTOnznTt3epQ+i0QixMfHs6XPfn5+tPRZTVCx6QM0BXDgQghBXV0dm8nz+++/w9HRkc3kUXR4mjx+bS8KIzTm5uZyC2VxcTFCQkLw+uuv49tvv1W7a8LFixcxffr0Ho9HR0cjISEBhBCsX78eu3fvRl1dHV599VXs3LkTrq6u7LG1tbVYtmwZkpOTweVyMXfuXGzfvl1u52+KYqFiQ6E8g4aGBqSkpCApKQmnT5+GjY0NO+Px8fFR6EW5N782prjA1NRULtFob2/H7du3YWpqKncGT2lpKYKDgxEWFoYdO3aoXWgoAxMqNhSKnDQ3N+PUqVNsJo+ZmRkiIyMRFRUFf39/hToKSKVS1NbWQiQSoaqqChwO57l+bUx8NZMqKo/QlJeXIzg4GNOnT8fu3bup0FCUBhUbCqUPtLa24vfff0diYiJSUlJgaGiI2bNnIyoqSuGZPFKpFHV1daxtDiEEVlZWsLa2hoWFBbhcLjo6OnD79m3weDx4eHjIJTQVFRUIDQ1FQEAA9u7dq7X2OxTtgIoNhdJPOjo6cO7cOSQmJuL48ePQ0dFhM3kmT56s0Eye3vzazM3N0dDQABMTE3h6esolNJWVlQgLC8P48eOxf/9+uk9IUTpUbCgUBdLZ2Yn09HQcOXIEx44dQ2dnJyIiIsDn8xWeycNU0eXk5EAqlYIQAktLS9jY2MDS0vKpAlJTU4Pw8HC4uLjgt99+U6gYUihPgy7QDkI2bdoEDoeDlStXso/RSATFoKenh6CgIMTHx+Ovv/5CYmIieDweli9fDicnJ7z33ntISUlBa2trv99LLBbjzz//hJmZGaZOncr6tRUVFSE9PR2ZmZk9/NoeP34MPp8PR0dH/Prrr1RoKCqDzmwGGbdu3cKbb74JHo+H6dOnY9u2bQBoJIKykUgk+OOPP9gwuOrqaoSEhIDP5yM4OJiNppCXzs5OCIVCGBgYYPz48T029pubm1FZWQmRSITCwkL89NNPCAkJwalTp2BhYYFjx46pzT6HMkghlEFDY2MjcXFxIWfPniVTp04lK1asIIQQUldXR/T09Mjhw4fZY+/evUsAkOvXrxNCCElNTSVcLpdUVFSwx+zatYvweDzS3t6u0vPQdiQSCbl58yZZu3YtcXFxIUOHDiV8Pp/s2bOHPHr0iDQ3Nz/zp66ujly4cIFcuXKFNDY2Pvf4goIC8o9//IM4OTkRDodDpkyZQr7//ntSVlam7o+CMoigy2iDiKVLlyI8PFzGmh2gkQiqhsvl4uWXX8bmzZuRn5+Pq1evYty4cdiyZQtGjhyJefPmYf/+/Xj8+HEP2xyxWIyMjAzo6elhwoQJcpUqm5mZ4fbt2xgxYgTy8/Mxb948JCYmYuTIkbh//76yTvOZ7NixAyNHjsSQIUMQEBDQwyeQMvCgYjNI+O233yAUCrFx48Yez9FIBPXB5XLh5eWFr776Crm5uRAIBPD398fOnTvh5OSEOXPmICEhAdXV1Xj8+DHefPNNPH78WG6haW1txfz58yGRSJCcnAxXV1csW7YMaWlpKC8vlztuQJEcPHgQq1atwvr16yEUCjFhwgQEBwf3MM6kDCyo2AwCHj58iBUrVuCXX36h6/QaDIfDgYeHB9avX4+MjAzk5ORg2rRp2Lt3L0aNGoWJEyeirKwMLi4ucglNe3s7Fi5ciMbGRpw8eRI8Hk/meSsrK7UYbW7duhXvv/8+YmJi4O7ujvj4eAwdOhR79uxR+VgoqoOKzSBAIBCgsrISPj4+0NXVha6uLtLT07F9+3bo6urCxsaGjUToSvdIhO7VaTQSQXlwOBy4urri888/x8WLF+Hv7w89PT2YmprCy8sLISEh2LFjB8rKynp1qO7o6MCiRYtQWVmJ06dP95i1qouOjg4IBAKZJVsul4ugoCB2yZYyMKFiMwh47bXXkJ2djczMTPbHz88PCxcuZP+bRiJoJmKxGHPmzIGuri4yMzNx+fJlFBcX44033kBKSgo8PDzw2muv4bvvvsODBw9ACEFnZyfeffddlJSU4Pfff2fjyjWB6upqSCSSZ6ZsUgYmtG14EGBsbMxGVjMMGzYMFhYW7ONLlizBqlWrYG5uzkYiMJHHADBr1iy4u7vjnXfeYSMRvvjiCyxdulShjYoUWXR1dfG3v/0Nc+fOZd2KR4wYgRUrVmD58uWoqKjA0aNHkZiYiLi4OIwbNw4SiQQdHR1IT0+HpaWlms+AQnkCndlQAADffvstIiIiMHfuXEyZMgW2trZISkpin9fR0UFKSgp0dHQQGBiIt99+G4sWLcK//vUvNY56cLB48WIYGxv3eJzD4cDOzg4ff/wxzp07h/LycsTExKCmpgapqak9Zg+agKWlJXR0dHpdkqXLsQMb2tRJoVBUSkBAAPz9/fH9998DeGI06uDggGXLliE2NlbNo6MoC7qMRqFQVMqqVasQHR0NPz8/+Pv7Y9u2bWhubkZMTIy6h0ZRIlRsKBSKSnnrrbdQVVWFuLg4VFRUwMvLiw2mowxc6DIahUKhUJQOLRCgUCgUitKhYkPRaP766y+8/fbbsLCwgKGhITw9PXH79m32eUII4uLiYGdnB0NDQwQFBaGwsFDmNWpra7Fw4ULweDyYmppiyZIlaGpqUvWpUCiDGio2FI3l8ePHmDRpEvT09HDq1Cnk5eXhf/7nf2BmZsYe8/XXX2P79u2Ij4/HjRs3MGzYMAQHB6OtrY09ZuHChcjNzcXZs2eRkpKCS5cu4YMPPlDHKVEogxa6Z0PRWGJjY3H16lVcvny51+cJIbC3t8fq1avxySefAADq6+thY2ODhIQEzJ8/H3fv3oW7uztu3boFPz8/AMDp06cRFhaGsrIy2Nvbq+x8KJTBDJ3ZUDSWEydOwM/PD/PmzYO1tTW8vb3x448/ss8XFxejoqJCxmfLxMQEAQEBMtEIpqamrNAAQFBQELhcLm7cuKG6k6FQBjlUbCgaS1FREXbt2gUXFxecOXMGH330EZYvX459+/YB+P9og2f5bFVUVMDa2lrmeV1dXZibm1MvLgpFhdA+G4rGIpVK4efnx8ZOe3t7IycnB/Hx8YiOjlbz6CgUyotAZzYUjcXOzq6Ho/TYsWNRWloK4P+jDZ7ls2Vra9sjlEssFqO2tpZ6cVEoKoSKDUVjmTRpEgoKCmQeu3fvHhwdHQEATk5OsLW1lYlGaGhowI0bN2SiEerq6iAQCNhjLly4AKlUioCAABWchfayYcMGTJw4EUOHDn1qHk5paSnCw8MxdOhQWFtbY82aNRCLxTLHXLx4ET4+PjAwMICzszMSEhKUP3iK5kEoFA3l5s2bRFdXl2zYsIEUFhaSX375hQwdOpTs37+fPWbTpk3E1NSUHD9+nNy5c4fw+Xzi5OREWltb2WNCQkKIt7c3uXHjBrly5QpxcXEhCxYsUMcpaRVxcXFk69atZNWqVcTExKTH82KxmIwbN44EBQWRjIwMkpqaSiwtLclnn33GHlNUVESGDh1KVq1aRfLy8sj3339PdHR0yOnTp1V4JhRNgIoNRaNJTk4m48aNIwYGBsTNzY3s3r1b5nmpVErWrVtHbGxsiIGBAXnttddIQUGBzDE1NTVkwYIFxMjIiPB4PBITE0MaGxtVeRpazd69e3sVm9TUVMLlcklFRQX72K5duwiPxyPt7e2EEELWrl1LPDw8ZH7vrbfeIsHBwUodM0XzoH02FArlmSQkJGDlypU9YsPj4uJw4sQJZGZmso8VFxdj1KhREAqF8Pb2xpQpU+Dj44Nt27axx+zduxcrV65EfX29ak6AohHQPRsKhdInKioqei07Z5571jENDQ1obW1VzUApGgEVGwplEBEbGwsOh/PMn/z8fHUPkzIAoX02FMogYvXq1Vi8ePEzjxk1apRcr2Vra4ubN2/KPMaUoXctPe+tNJ3H48HQ0FDOUVMGAlRsKJRBhJWVFaysrBTyWoGBgdiwYQMqKytZl4azZ8+Cx+Ox/VGBgYFITU2V+b2zZ8+ypemUwQNdRqNQFIxEIsG6devg5OQEQ0NDjB49Gl9++SW61uIQLYhGKC0tRWZmJkpLSyGRSJCZmYnMzEx2DLNmzYK7uzveeecdZGVl4cyZM/jiiy+wdOlSGBgYAAA+/PBDFBUVYe3atcjPz8fOnTtx6NAh/OMf/1DZeVA0BPUWw1EoA48NGzYQCwsLkpKSQoqLi8nhw4eJkZER+e6779hjNm3aRExMTMixY8dIVlYWiYyM7LU/aMKECeSPP/4gly9fJs7OzirtD4qOjiYAevykpaWxxzx48ICEhoYSQ0NDYmlpSVavXk06OztlXictLY14eXkRfX19MmrUKLJ3716VnQNFc6ClzxSKgomIiICNjQ1++ukn9rG5c+fC0NAQ+/fvp9EIlEEJXUajUBTMxIkTcf78edy7dw8AkJWVhStXriA0NBQAjUagDE5ogQCFomBiY2PR0NAANzc36OjoQCKRYMOGDVi4cCEAGo1AGZxQsaFQFMyhQ4fwyy+/4MCBA/Dw8EBmZiZWrlwJe3t7Go1AGbRQsaFQFMyaNWsQGxuL+fPnAwA8PT1RUlKCjRs3Ijo6WiYawc7Ojv09kUgELy8vADQagTLwoHs2FIqCaWlpAZcr+9XS0dGBVCoFQKMRKIMTOrOhUBTM7NmzsWHDBjg4OMDDwwMZGRnYunUr3n33XQAAh8PBypUr8dVXX8HFxQVOTk5Yt24d7O3tERUVBeBJSFxISAjef/99xMfHo7OzE8uWLcP8+fNpJRpFK6GlzxSKgmlsbMS6detw9OhRVFZWwt7eHgsWLEBcXBz09fUBPGnqXL9+PXbv3o26ujq8+uqr2LlzJ1xdXdnXqa2txbJly5CcnAwul4u5c+di+/btMDIyUtepUSh9hooNhUKhUJQO3bOhUCgUitKhYkOhUCgUpUPFhkKhUChKh4oNhUKhUJQOFRsKhUKhKB0qNhQKhUJROlRsKBQKhaJ0qNhQKBQKRelQsaFQKBSK0qFiQ6FQKBSlQ8WGQqFQKEqHig2FQqFQlM7/ARYawGiJiE+WAAAAAElFTkSuQmCC\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Get the grid points\\n\",\n    \"xs = fmodel.core.grid.x_sorted\\n\",\n    \"ys = fmodel.core.grid.y_sorted\\n\",\n    \"zs = fmodel.core.grid.z_sorted\\n\",\n    \"\\n\",\n    \"# Consider the shape\\n\",\n    \"print(f\\\"shape of xs: {xs.shape}\\\")\\n\",\n    \"print(\\\"  2 wd x 2 ws x 4 turbines x 3 x 3 grid points\\\")\\n\",\n    \"\\n\",\n    \"# Lets plot just one wd/ws conditions\\n\",\n    \"xs = xs[1, :, :, :]\\n\",\n    \"ys = ys[1, :, :, :]\\n\",\n    \"zs = zs[1, :, :, :]\\n\",\n    \"\\n\",\n    \"fig = plt.figure()\\n\",\n    \"ax = fig.add_subplot(111, projection=\\\"3d\\\")\\n\",\n    \"ax.scatter(xs, ys, zs, marker=\\\".\\\")\\n\",\n    \"ax.set_zlim([0, 150])\\n\",\n    \"\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"e91f7a84\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Basic use case: calculating AEP\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"34bc7865\",\n   \"metadata\": {},\n   \"source\": [\n    \"FLORIS leverages vectorized operations on the CPU to reduce the computation\\n\",\n    \"time for bulk calculations, and this is especially meaningful for calculating\\n\",\n    \"annual energy production (AEP) on a wind rose.\\n\",\n    \"Here, we demonstrate a simple AEP calculation for a 25-turbine farm\\n\",\n    \"using several different modeling options. We make the assumption\\n\",\n    \"that every wind speed and direction is equally likely. We also\\n\",\n    \"report the time required for the computation using the Python\\n\",\n    \"`time.perf_counter()` function.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 13,\n   \"id\": \"ee1918d6\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Calculating AEP for 1440 wind direction and speed combinations...\\n\",\n      \"Number of turbines = 25\\n\",\n      \"Model    AEP (GWh)  Compute Time (s)\\n\",\n      \"Jensen   661.838    0.438 \\n\",\n      \"GCH      683.869    1.489 \\n\",\n      \"CC       661.315    3.243 \\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"import time\\n\",\n    \"from typing import Tuple\\n\",\n    \"\\n\",\n    \"# Using Numpy.meshgrid, we can combine 1D arrays of wind speeds and wind directions to produce\\n\",\n    \"# combinations of both. Though the input arrays are not the same size, the resulting arrays\\n\",\n    \"# will be the same size.\\n\",\n    \"wind_directions, wind_speeds = np.meshgrid(\\n\",\n    \"    np.arange(0.0, 360.0, 5),   # wind directions 0 to 360 degrees (exclusive) in 5 degree increments\\n\",\n    \"    np.arange(8.0, 12.0, 0.2),  # wind speeds from 8 to 12 m/s in 0.2 m/s increments\\n\",\n    \"    indexing=\\\"ij\\\"\\n\",\n    \")\\n\",\n    \"# meshgrid returns arrays with shape (len(wind_speeds), len(wind_directions)), so we \\\"flatten\\\" them\\n\",\n    \"wind_directions = wind_directions.flatten()\\n\",\n    \"wind_speeds = wind_speeds.flatten()\\n\",\n    \"turbulence_intensities = 0.1 * np.ones_like(wind_speeds)\\n\",\n    \"\\n\",\n    \"n_findex = len(wind_directions)\\n\",\n    \"print(f\\\"Calculating AEP for {n_findex} wind direction and speed combinations...\\\")\\n\",\n    \"\\n\",\n    \"# Set up a square 25 turbine layout\\n\",\n    \"N = 5  # Number of turbines per row and per column\\n\",\n    \"D = 126.0\\n\",\n    \"\\n\",\n    \"# Create the turbine locations using the same method as above\\n\",\n    \"x, y = np.meshgrid(\\n\",\n    \"    7.0 * D * np.arange(0, N, 1),\\n\",\n    \"    7.0 * D * np.arange(0, N, 1),\\n\",\n    \")\\n\",\n    \"x = x.flatten()\\n\",\n    \"y = y.flatten()\\n\",\n    \"print(f\\\"Number of turbines = {len(x)}\\\")\\n\",\n    \"\\n\",\n    \"# Define several models\\n\",\n    \"fmodel_jensen = FlorisModel(\\\"jensen.yaml\\\")\\n\",\n    \"fmodel_gch = FlorisModel(\\\"gch.yaml\\\")\\n\",\n    \"fmodel_cc = FlorisModel(\\\"cc.yaml\\\")\\n\",\n    \"\\n\",\n    \"# Assign the layouts, wind speeds and directions\\n\",\n    \"fmodel_jensen.set(\\n\",\n    \"    layout_x=x,\\n\",\n    \"    layout_y=y,\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities\\n\",\n    \")\\n\",\n    \"fmodel_gch.set(\\n\",\n    \"    layout_x=x,\\n\",\n    \"    layout_y=y,\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities,\\n\",\n    \")\\n\",\n    \"fmodel_cc.set(\\n\",\n    \"    layout_x=x,\\n\",\n    \"    layout_y=y,\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"def time_model_calculation(model_fmodel: FlorisModel) -> Tuple[float, float]:\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    This function performs the wake calculation for a given\\n\",\n    \"    FlorisModel object and computes the AEP while\\n\",\n    \"    tracking the amount of wall-time required for both steps.\\n\",\n    \"\\n\",\n    \"    Args:\\n\",\n    \"        model_fmodel (FlorisModel): _description_\\n\",\n    \"        float (_type_): _description_\\n\",\n    \"\\n\",\n    \"    Returns:\\n\",\n    \"        tuple(float, float):\\n\",\n    \"            0: AEP\\n\",\n    \"            1: Wall-time for the computation\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    start = time.perf_counter()\\n\",\n    \"    model_fmodel.run()\\n\",\n    \"    aep = model_fmodel.get_farm_power().sum() / n_findex  / 1E9 * 365 * 24\\n\",\n    \"    end = time.perf_counter()\\n\",\n    \"    return aep, end - start\\n\",\n    \"\\n\",\n    \"jensen_aep, jensen_compute_time = time_model_calculation(fmodel_jensen)\\n\",\n    \"gch_aep, gch_compute_time = time_model_calculation(fmodel_gch)\\n\",\n    \"cc_aep, cc_compute_time = time_model_calculation(fmodel_cc)\\n\",\n    \"\\n\",\n    \"print('Model    AEP (GWh)  Compute Time (s)')\\n\",\n    \"print('{:8s} {:<10.3f} {:<6.3f}'.format(\\\"Jensen\\\", jensen_aep, jensen_compute_time))\\n\",\n    \"print('{:8s} {:<10.3f} {:<6.3f}'.format(\\\"GCH\\\", gch_aep, gch_compute_time))\\n\",\n    \"print('{:8s} {:<10.3f} {:<6.3f}'.format(\\\"CC\\\", cc_aep, cc_compute_time))\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"c006ae1e\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Basic use case: wake steering design\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"f5777dae\",\n   \"metadata\": {},\n   \"source\": [\n    \"FLORIS includes a set of optimization routines for the design of wake steering controllers.\\n\",\n    \"`SerialRefine` is a new method for quickly identifying optimum yaw angles.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 14,\n   \"id\": \"32a93c6d\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Demonstrate on 7-turbine single row farm\\n\",\n    \"x = np.linspace(0, 6*7*D, 7)\\n\",\n    \"y = np.zeros_like(x)\\n\",\n    \"wind_directions = np.arange(0.0, 360.0, 2.0)\\n\",\n    \"wind_speeds = 8.0 * np.ones_like(wind_directions)\\n\",\n    \"turbulence_intensities = 0.1 * np.ones_like(wind_directions)\\n\",\n    \"fmodel_gch.set(\\n\",\n    \"    layout_x=x,\\n\",\n    \"    layout_y=y,\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities,\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 15,\n   \"id\": \"7d773cdc\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\\n\",\n    \"\\n\",\n    \"# Define the SerialRefine optimization\\n\",\n    \"yaw_opt = YawOptimizationSR(\\n\",\n    \"    fmodel=fmodel_gch,\\n\",\n    \"    minimum_yaw_angle=0.0,  # Allowable yaw angles lower bound\\n\",\n    \"    maximum_yaw_angle=25.0,  # Allowable yaw angles upper bound\\n\",\n    \"    Ny_passes=[5, 4],\\n\",\n    \"    exclude_downstream_turbines=True,\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 16,\n   \"id\": \"1ccb9ab7\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"[Serial Refine] Processing pass=0, turbine_depth=0 (0.0%)\\n\",\n      \"[Serial Refine] Processing pass=0, turbine_depth=1 (7.1%)\\n\",\n      \"[Serial Refine] Processing pass=0, turbine_depth=2 (14.3%)\\n\",\n      \"[Serial Refine] Processing pass=0, turbine_depth=3 (21.4%)\\n\",\n      \"[Serial Refine] Processing pass=0, turbine_depth=4 (28.6%)\\n\",\n      \"[Serial Refine] Processing pass=0, turbine_depth=5 (35.7%)\\n\",\n      \"[Serial Refine] Processing pass=0, turbine_depth=6 (42.9%)\\n\",\n      \"[Serial Refine] Processing pass=1, turbine_depth=0 (50.0%)\\n\",\n      \"[Serial Refine] Processing pass=1, turbine_depth=1 (57.1%)\\n\",\n      \"[Serial Refine] Processing pass=1, turbine_depth=2 (64.3%)\\n\",\n      \"[Serial Refine] Processing pass=1, turbine_depth=3 (71.4%)\\n\",\n      \"[Serial Refine] Processing pass=1, turbine_depth=4 (78.6%)\\n\",\n      \"[Serial Refine] Processing pass=1, turbine_depth=5 (85.7%)\\n\",\n      \"[Serial Refine] Processing pass=1, turbine_depth=6 (92.9%)\\n\",\n      \"Optimization wall time: 3.771 s\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"start = time.perf_counter()\\n\",\n    \"\\n\",\n    \"## Calculate the optimum yaw angles for 25 turbines and 72 wind directions\\n\",\n    \"df_opt = yaw_opt.optimize()\\n\",\n    \"\\n\",\n    \"end = time.perf_counter()\\n\",\n    \"\\n\",\n    \"walltime = end - start\\n\",\n    \"print(f\\\"Optimization wall time: {walltime:.3f} s\\\")\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"fb2e01e8\",\n   \"metadata\": {},\n   \"source\": [\n    \"In the results, T0 is the upstream turbine when wind direction is 270, while T6 is upstream at 90 deg\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 17,\n   \"id\": \"686548be\",\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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dAHZnj17snfvXjZt2uS3RZL4p8OHD7v+/7333mP69Ons27fPdSwyMtL1/7fffjubN29mx44ddRKbW0VScXExzz33HIsWLeKXX36hc+fOJCQkEBYWxg8//MCHH37IxIkTSU5OZvr06W53nZs0aRJLly7lo48+IioqyrXPKCYmhrCwMGJiYhg/fjwpKSk0btyY6Oho7rnnHnr37q3OdiIiItKgOJs2BAQEVFpC1LNnT/7xj3+wefNmX4UmUiMVV4bFxMRgsViqXC22YMECAI4dO2auIqlNmzb07t2bxYsXV7sm9MCBAyxdupQxY8bw2GOPMXHixAuOu2jRIgD69etX6fiSJUu47bbbAJg3bx4BAQGMGjWq0sVkRURERBqSiu2/Ky5T6tmzJwBbtmzBbreb/jo2UjecF1b1BrvdTmFhIYGBgW79foWHh9eLvUvn41aRlJaWRvv27c97n5YtWzJ16lQefPBBsrOz3Tq5s53g+YSGhrJw4UIWLlzo1pgiIiIi/si53K7iEiSAK664gtDQUE6dOsV3331Hu3btfBGemExRUdE5vyt1paCgoNKS0PrIrY8aLlQgVWS1Wrn00ktrHJCIiIiInKviTFJFVquVbt26AWjJnYiXeNzdrrp1gBaLhdDQUFq0aFFldzkRERERqTlnkVTVJ/Q9e/bkyy+/ZPPmzdx66611HZqYUHh4uOt3prbsdjt5eXlER0e7vdyuvvO4SOrcufN51xharVZGjx7N3//+d6/3aBcRERFpqKqbSYKz+5I0kyROFovFa0ve7HY75eXlRERENJg9bx7/K5cvX07r1q155ZVXyMzMJDMzk1deeYW2bduydOlSXnvtNT7//HOmTZtmRLwiIiIiDZI7RdKOHTtc11IS8Rc//PADmZmZ5ObmUlxc7KpBysrKDDunxzNJTz75JM8//zyDBg1yHbviiitITEzkL3/5C1u2bCEiIoIpU6bw7LPPejVYERERkYaqusYNAElJScTHx5Obm8vXX3/N7373u7oOT8QwEyZMYN26da7vu3TpAkBWVhaXXHKJIef0eCZp586dtGzZ8pzjLVu2ZOfOncCZJXkVLw4lIiIiIrVzvpkki8WiJXdSr912222cPHmyytvWrl2Lw+E458uoAglqUCS1a9eOOXPmVJrestlszJkzx9Vy8qeffiIuLs57UYqIiIg0cOdr3ADalyTiTR4vt1u4cCHDhg0jMTGRjh07Amdml8rLy1mxYgUA+/fv5+677/ZupCIiIiIN2PlmkkBFkog3eVwk9enTh6ysLN5++22+++47AG688UbGjh1LVFQUADfffLN3oxQRERFp4C5UJHXr1g2LxcKBAwfIzc0lPj6+LsMT8SseF0kAUVFR3Hnnnd6ORURERESqcb7GDQDR0dFcdtll7N69m82bNzN8+PC6DE/Er9So0fk///lPrrrqKhISEjhw4AAA8+bN46OPPvJqcCIiIiJyxoVmkkBL7kS8xeMiadGiRaSkpDB48GBOnDhBeXk5AI0aNWL+/Pnejk9EREREcK9I6tWrF6AiqSFzOBy+DsHn7HZ7rcfweLndCy+8wOLFixkxYgRz5sxxHe/WrRsPPvhgrQMSERERkXNdqLsdnJ1J2rp1K+Xl5QQGBtZJbOJ7VqsVi8XCsWPHaNq0KRaLxWtj2+12ysrKKCkpISCgRgvR6oTD4aCsrIxjx44REBBAcHBwjcfyuEjKyspyXcCpopCQENdaWRERERHxLndmkjp06EBERAT5+fns3buXDh061FV44mOBgYEkJiZy8OBBfvzxR6+O7XA4KC4uJiwszKvFl1HCw8Np0aJFrQo6j4ukVq1akZmZec4FZVetWkX79u1rHIiIiIiIVO9CjRvgzB/K3bp1Y926dWzevFlFUgMTGRlJ69atsdlsXh3XZrOxfv16+vbti9Vq9erY3hYYGEhQUFCtizmPi6SUlBQmTZpESUkJDoeDLVu28M477zB79mxeffXVWgUjIiIiIlVzZyYJziy5cxZJt99+e12EJiYSGBjo9WWWgYGBnD59mtDQUNMXSd7icZE0YcIEwsLCmDZtGkVFRYwdO5aEhASef/55xowZY0SMIiIiIg2eJ0USqHmDSG3U6DpJN910EzfddBNFRUUUFBTQrFkzb8clIiIiIv+nrKzMtYTqfI0b4GyRtHPnTgoLCy94fxE5V412Mx0/fpxt27bx7bffqmuKiIiIiMGcs0hw4SLp4osv5uKLL8Zut5ORkWF0aCJ+yaMiaffu3fTt25e4uDh69uxJjx49aNasGf3792ffvn1GxSgiIiLSoDmbNgQHB7vV1lhL7kRqx+0iKTc3l2uuuYZjx44xd+5cVq5cySeffMIzzzzD4cOHufrqqzl69KiRsYqIiIg0SO7uR3JSkSRSO24XSfPmzaNly5Zs376d++67j0GDBnHttdeSkpLC119/TVJSEvPmzTMyVhExmVdffZVbb72V/Px8X4ciIuLXalokbdq0ybCYRPyZ20VSeno6jzzyCKGhoefcFhYWxkMPPcRnn33m1eBExLyKi4u57777ePPNN/nzn//s63BERPyas0hytwlD165dCQgI4KeffuKnn34yMjQRv+R2kbR//36uvPLKam/v1q0b+/fv90pQImJ+n332GUVFRQC89NJLfPnllz6OSETEf3k6kxQZGckVV1wBaMmdSE24XSTl5+cTHR1d7e1RUVGVOq+IiH9btmwZcPYNe8KECZSUlPgyJBERv+VpkQTalyRSGx51t8vPzycvL6/aL4fDYVScImIiZWVl/Pvf/wbgnXfeoXnz5uzbt4+//vWvPo5MRMQ/ObvbqUgSqRtuF0kOh4M2bdrQqFGjKr/atm1rZJwiYiKff/45p06dIj4+niFDhrBw4UIAnn76ab755hsfRyci4n9qM5O0bds2ysvLDYlLxF8FuXvHNWvWGBmHiNQjzqV2I0aMICAggBtuuIFRo0axbNkyxo8fz6ZNmwgKcvvlRURELqAmRVK7du2IiooiPz+f3bt307FjR6PCE/E7bs8kXXPNNW59eWL9+vUMHTqUhIQELBYLH374YaXbHQ4H06dPp3nz5oSFhTFgwAC+//57j84hIt5VXl7ueq6OGjXKdfzFF18kNjaWjIwM5s+f75vgRET8lKfd7QACAwPp06cPAM8995whcYn4K7eKJOc6WHe5e//CwkI6derkWqrza08//TQLFizg5ZdfZvPmzURERDBo0CBtDhfxoS+++ILjx4/TuHHjSh+MxMfHu96Ep0+fzg8//OCrEEVE/E5NZpIAnnjiCSwWC2+++aYu1SLiAbeKpN/+9rfMmTOHw4cPV3sfh8NBeno6gwcPZsGCBW6dfPDgwcyaNYsbbrihyvHmz5/PtGnTGD58OB07duTNN9/k0KFD58w4iUjdcS61GzZsGFartdJt48aN43/+538oLi7mjjvuUDMXEREvqUnjBjizL+m+++4D4I477lAnYhE3ubVpYO3atTz66KM8/vjjdOrUiW7dupGQkEBoaCgnTpxgz549bNy4kaCgIKZOncqf/vSnWgeWlZVFbm4uAwYMcB2LiYmhZ8+ebNy4kTFjxlT5uNLS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s3jx4mqnOw8cOMDSpUsZM2YMjz32GBMnTrzguIsWLQKgX79+lY4vWbKE2267DYB58+YREBDAqFGjKl1MVkRERKShWbBgAY8//jjLly/n448/rhdLn0SqU3H7TExMDBaL5ZwtNbfffnul73/zm9+wceNGUlNTfV8kpaWl0b59+/Pep2XLlkydOpUHH3yQ7Oxst07u7JRxPqGhoSxcuJCFCxe6NaaIiIiIvzp48CAAK1as4L333mPMmDE+jkjMynlhVW+w2+0UFhYSGBjo1nK78PBwQwv4U6dOuS4ZZBS3iqQLFUgVWa1WLr300hoHJCIiIiJVq7jp/N5772XgwIFcdNFFPoxIzKqoqIjIyEifnLugoICIiAhDxt6wYQPvvfcen3zyiSHjO3nc3W7Hjh1VHrdYLISGhtKiRYsqGyeIiIiISO04i6SAgACOHTvGAw88wJtvvunjqETqxq5duxg+fDgzZswgOTnZ0HN5XCR17tz5vNNnVquV0aNH8/e//93r7QdFREREGjJnkfTggw/yzDPP8M9//pOxY8dy7bXX+jgyMZvw8HAKCgq8MpbdbicvL4/o6Gi3l9t52549e/if//kf7rjjDqZNm+b18X/N4yJp+fLlPPLIIzz00EP06NEDgC1btvDcc88xY8YMTp8+zZ///GemTZvGs88+6/WARURERBoqZ5E0cOBAysrKmD9/Pn/605/YtWuXut1JJRaLxWtL3ux2O+Xl5URERHi9vbg7du/eTf/+/bn11lt58skn6+ScHhdJTz75JM8//zyDBg1yHbviiitITEzkL3/5C1u2bCEiIoIpU6aoSBIRERHxovz8fACioqKYNWsWH374IT/++COPPfYYCxYs8HF0It63a9cu+vfvz6BBg0hJSXFdMigwMJCmTZsadl6PS8GdO3fSsmXLc463bNmSnTt3AmeW5FXsey4iIiIiteecSYqOjiYiIoLFixcD8OKLL7Jx40ZfhiZiiA8++IBjx47x1ltv0bx5c9dX9+7dDT2vx0VSu3btmDNnDmVlZa5jNpuNOXPm0K5dOwB++ukn4uLivBeliIiISAPncDgqFUkAAwYM4LbbbsPhcDB+/HhKS0t9GaJIjd12222cPHnynOOPP/44DofjnK8ff/zR0Hg8LpIWLlzIihUrSExMZMCAAQwYMIDExERWrFjhujjs/v37ufvuu70e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i/NupCLic6dOnQJgzJgxdOjQgcsuu4xly5bxySefUFJSon2IIiIGc74O//73v+e2226jtLSUF198kUOHDrFlyxZ69erl4whFaua2225zXSe1ot///vds2LChzuPxeCZp4cKFrFixgsTERAYMGMCAAQNITExkxYoVrovD7t+/n7vvvtvrwYqI7zgcDk6ePAmcueAbQPfu3UlMTKSwsJC0tDQfRici0jD8+nU4JCSE66+/HoBly5b5KiwRv+NxkdSnTx+ysrKYOXMmHTt2pGPHjsycOZOsrCzXpxc333wzDz30kNeDFRHfKSoqcjVscL45WywWRo4cCejNWUSkLjhnkpyvw0Cl12GHw+GTuET8jcfL7eBMF5U777zT27GIiIk535gDAgIqXcF71KhRLFiwgI8//hibzYbVavVViCIifq+qImnw4MGEhYWRlZXFN998Q+fOnX0UnYj/qFGj83/+859cddVVJCQkcODAAeDMBZ4++ugjrwYnIubhfGOOjo6udK203/3udzRr1oyTJ0+yZs0aX4UnItIgVFUkRUREcO211wKa1RfxFo+LpEWLFpGSksLgwYM5ceKEa/lNo0aNmD9/vrfjExGTqOqNGSAwMJARI0YA6nInImIkh8NR7Wuxlj6Lk5Zceudn4HGR9MILL7B48WIee+wxgoLOrtbr1q2bqwW4iPif6t6YAVcr8OXLl1e60KyIiHhPSUkJNpsNOPe1+Prrr8dqtfLtt9/y7bff+iI88bHAwEAAysrKfByJ7xUVFQHUaguAx3uSsrKy6NKlyznHQ0JCKCwsrHEgImJu5yuS+vXrR2xsLEePHuWrr76ib9++dR2eiIjfc74OWyyWSntDAWJjYxkwYACffvopqampPPbYY74IUXwoKCiI8PBwjh07htVqJSCgRrtqqmS32ykrK6OkpMSr43qbw+GgqKiIo0ePEhsb6yoca8LjIqlVq1ZkZmaec0HZVatW0b59+xoHIiLmdr4iKTg4mGHDhvHmm2+SmpqqIklExAAV94ZW9YfqyJEj+fTTT1m2bJmKpAbIYrHQvHlzsrKyXD0DvMXhcFBcXExYWFilfclmFRsbS3x8fK3G8LhISklJYdKkSZSUlOBwONiyZQvvvPMOs2fP5tVXX61VMCJiXucrkuDMkjtnkTRv3rx68SIqIlKfXOh1ePjw4fzpT39i+/btZGVl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ojpYJBEREREREdXBIomIiIiIiKgOFklERERERER1sEgiIiIiIiKqg0USERERERFRHSySiIiIiIiI6mCRREREREREVAeLJCIiIiIiojpszB2A1DQaDTIzM+Hi4gKFQmHucIiIiIiIyEwEQUBxcTF8fX1hZdVwf5HFF0mZmZnw8/MzdxhERERERCQTN27cQPv27Rvcb/FFkouLC4DaN8LV1dWssajVauzevRvh4eFQKpVmjaW1Yy7kgXmQB+ZBPpgLeWAe5IO5kAdLykNRURH8/Px0NUJDLL5I0g6xc3V1lUWR5OjoCFdX1xb/DdbSMRfywDzIA/MgH8yFPDAP8sFcyIMl5qGxaThcuIGIiIiIiKgOFklERERERER1sEgiIiIiIiKqw+LnJBERERERtRYajQZVVVWitqlWq2FjY4OKigrU1NSI2rbYlEolrK2tm92OWYukZcuWITY2FpcuXYKDgwOGDBmC9957D926ddMdU1FRgblz5+K7775DZWUlIiIi8Omnn8Lb29uMkRMRERERyUtVVRXS09Oh0WhEbVcQBKhUKty4caNF3HfU3d0dKpWqWbGatUg6cOAAZs2ahYEDB6K6uhoLFy5EeHg4Lly4ACcnJwDAa6+9hh07duCHH36Am5sbZs+ejQkTJuDIkSPmDJ2IiIiISDYEQUBWVhasra3h5+d3zxulGkuj0aCkpATOzs6itis2QRBQVlaG3NxcAICPj0+T2zJrkRQXF6f3eNOmTfDy8kJycjJCQ0NRWFiIL774Aps3b8bIkSMBAF999RV69OiBY8eOYdCgQeYIm6jV2rRpE/773//i888/h6+vr7nDISIiov9TXV2NsrIy+Pr6wtHRUdS2tUP47O3tZV0kAYCDgwMAIDc3F15eXk0eeierOUmFhYUAgDZt2gAAkpOToVarERYWpjume/fu6NChAxITE+stkiorK1FZWal7XFRUBKB2LKVarZYy/EZpz2/uOIi5aKpVq1bhzJkzeOGFF7B169Zmd7kzD/LAPMgHcyEPzIN8MBeGq6yshCAIsLGxkWS4nfZfsduWgr29PQRBQHl5Oezs7PT2Gfq9pBC0r9rMNBoNxo0bh4KCAhw+fBgAsHnzZkybNk2v6AGA4OBgjBgxAu+9995d7bz11lt4++2379q+efNm0atqotZm5syZyM7OBgC8/vrrePDBB80cEREREQGAjY0NVCoV/Pz8YGtra+5wzKqqqgo3btxAdnY2qqur9faVlZVhypQpKCwshKura4NtyKYnadasWTh37pyuQGqqmJgYREdH6x4XFRXBz88P4eHh93wjTEGtViM+Ph6jRo2ymLsVt1TMRdPU/fTo66+/xty5c9G2bdsmt8c8yAPzIB/MhTwwD/LBXBiuoqICN27cgLOzM+zt7UVtWxAEFBcXw8XFpUUs3FBRUQEHBweEhobe9V5oR5k1RhZF0uzZs7F9+3YcPHgQ7du3121XqVSoqqpCQUEB3N3dddtzcnKgUqnqbcvOzu6ubjWgdjlAuVxccoqltWMujFNcXAwA8Pb2Rk5ODhYsWICvv/662e0yD/LAPMgHcyEPzIN8MBeNq6mpgUKhgJWVlejzhrQfkmrblzsrKysoFIp6v28M/T4y6lVqNBrs27cP77zzDqZPn44nnngCL7/8Mr766ivcuHHDmKYA1Fals2fPxrZt27B37174+/vr7e/fvz+USiUSEhJ029LS0pCRkYHBgwcbfT4iarqamhqUl5cDAD7//HMoFAp88803+O2338wcGREREbVECoXinl9vvfWW7thNmzahT58+sLe3h5eXF2bNmiVpbAYVSeXl5Vi6dCn8/PwwZswY7Nq1CwUFBbC2tsaVK1ewZMkS+Pv7Y8yYMTh27JjBJ581axb+93//F5s3b4aLiwuys7ORnZ2t+0PMzc0N06dPR3R0NPbt24fk5GRMmzYNgwcP5sp2RCZWUlKi+/+oUaPw8ssvAwBeeOEFvX1EREREhsjKytJ9rVq1Cq6urnrbXn/9dQDAihUr8MYbb+Cf//wnzp8/jz179iAiIkLS2AwabhcQEIDBgwdj48aNDY4JvX79OjZv3ozJkyfjjTfewIwZMxptd926dQCA4cOH623/6quv8MwzzwAAVq5cCSsrK0ycOFHvZrJEZFraoXZKpRJ2dnZYunQpfvrpJ1y/fh2LFi3CqlWrzBsgERER6WjvGSQGjUaD0tJSWFtbGzTcztHR0aC5S3Wnz7i5uUGhUNw1pSY/Px+LFi3Cr7/+iocffli3vU+fPka8AuMZVCTt3r0bPXr0uOcxHTt2RExMDF5//XVkZGQYdHJDFtazt7fH2rVrsXbtWoPaJCJpaHuLnJ2ddf9u2LABERERWL16NSZNmsRhsERERDJRVlam+51taiUlJXBychKlrfj4eGg0Gvz555/o0aMHiouLMWTIEHz00Ufw8/MT5Rz1MWi4XWMFUl1KpRKdO3duckBEJE/aniQXFxfdtvDwcEydOhWCIOC55567a7l+IiIioua4du0aNBoN/v3vf2PVqlX48ccfcefOHYwaNQpVVVWSndfo1e1SU1Pr3a5QKGBvb48OHTrUu7ocEbVs9RVJQO044V27duHChQtYtmyZ3iRLIiIiMg9HR0fR5gxrNBoUFRXB1dXV4OF2YtFoNFCr1Vi9ejXCw8MBAFu2bIFKpcK+ffskm5tkdJHUt2/fe44xVCqVmDRpEj777DPR12gnIvPRFkl/77pv06YN1qxZg0mTJuHf//43/ud//ge9evUyR4hERET0fxQKhWhD3jQaDWpqauDk5GTyJcB9fHwAAD179tRta9euHTw9PQ2e4tMURr/Kbdu2oWvXrtiwYQNSUlKQkpKCDRs2oFu3bti8eTO++OIL7N27F4sWLZIiXiIyE+2nUX/vSQKAxx57DFFRUVCr1Zg+fbreTWeJiIiImmro0KEAam8DpHXnzh3k5eWhY8eOkp3X6J6kd999Fx9//LFe11bv3r3Rvn17vPnmmzh+/DicnJwwd+5cfPjhh6IGS0Tm09BwO6D206pPP/0UCQkJOH78OE6ePIng4GBTh0hEREQWJiAgAFFRUXjllVewYcMGuLq6IiYmBt27d8eIESMkO6/RPUlnz56tt2rr2LEjzp49C6B2SF5WVlbzoyMi2bhXkQQAvr6+CA0NBQCj7pdGREREdC/ffPMNQkJC8Mgjj2DYsGFQKpWIi4ur97ZEYjG6SOrevTuWL1+ut5qEWq3G8uXL0b17dwDAn3/+CW9vb/GiJCKz+/sS4PUJCQkBACQlJZkkJiIiIrIMzzzzDAoKCurd5+rqii+++AL5+fm4ffs2YmNjJV3+G2jCcLu1a9di3LhxaN++ve4mTmfPnkVNTQ22b98OoHapvpdeekncSInIrBrrSQKAQYMGAWCRRERERC2b0UXSkCFDkJ6ejm+//Ra///47gNpJ21OmTNH98fTUU0+JGyURmZ0hRZJ2HtLVq1eRl5cHT09Pk8RGREREJCajiySg9o+kmTNnih0LEclYQ0uA1+Xu7o5u3bohLS0Nx48fx5gxY0wVHhEREZFomrTQ+X/+8x88+OCD8PX1xfXr1wEAK1euxM8//yxqcEQkH/daArwuzksiIiKils7oImndunWIjo5GZGQk8vPzUVNTAwDw8PDAqlWrxI6PiGTCkOF2AIskIiIicxIEwdwhmJ0Y74HRRdKaNWuwceNGvPHGG7Cx+Wu03oABA3RLgBOR5TG2SDp+/DhvKktERGQi1tbWAKC3AnVrVVZWBgDNWiLc6DlJ6enpCAoKumu7nZ0dSktLmxwIEcmbIUuAA0CfPn1gb2+P/Px8XL58Gd26dTNFeERERK2ajY0NHB0dcevWLSiVSlhZNWlWTb00Gg2qqqpQUVEhartiEwQBZWVlyM3Nhbu7u65wbAqjiyR/f3+kpKTcdUPZuLg49OjRo8mBEJG8GdqTpFQq0a9fPxw9ehRJSUkskoiIiExAoVDAx8cH6enpujUDxCIIAsrLy+Hg4ACFQiFq21Jwd3eHSqVqVhtGF0nR0dGYNWsWKioqIAgCjh8/ji1btmDZsmX4/PPPmxUMEcmXoUUSUDvkTlskPf3001KHRkRERABsbW3RtWtX0YfcqdVqHDx4EKGhoc0awmYKSqWyWT1IWkYXSc899xwcHBywaNEilJWVYcqUKfD19cXHH3+MyZMnNzsgIpIfjUajG07b2HA7gIs3EBERmYuVlRXs7e1FbdPa2hrV1dWwt7eXfZEklibdJ+nJJ5/Ek08+ibKyMpSUlMDLy0vsuIhIRurONzS0JwkAzpw5o+ueJyIiImopmjTzKi8vDydPnsTFixdF6c4iInnTDrWztrY26NOpjh07wsvLC9XV1Th9+rTU4RERERGJyqgi6fz58wgNDYW3tzdCQkIQHBwMLy8vjBw5EmlpaVLFSERmpi2SnJ2dDZqwqVAoOOSOiIiIWiyDi6Ts7GwMGzYMt27dwooVK7Bz507s2LEDH3zwAbKysvDQQw8hNzdXyliJyEy0y38bMtROi0USERERtVQGz0lauXIlOnbsiCNHjugNtxk9ejRefPFFPPjgg1i5ciWWLVsmSaBEZD7GrGynxSKJiIiIWiqDe5Li4+OxYMGCeucjODg4YN68efjtt99EDY6I5KEpRdLAgQOhUCjwxx9/4ObNm1KFRkRERCQ6g4uka9euoV+/fg3uHzBgAK5duyZKUEQkL3XnJBnKzc0NgwYNAgD89NNPUoRFREREJAmDi6Ti4mK4uro2uN/FxUU3b4GILEtT5iQBwMSJEwEAsbGxosdEREREJBWjVrcrLi5GUVFRg1+CIEgVJxGZUVOG2wHAhAkTAAAHDhzArVu3RI+LiIiISAoGF0mCICAgIAAeHh71fnXr1k3KOInIjJoy3A4A/P39ERQUBI1Gg19++UWK0IiIiIhEZ/Dqdvv27ZMyDiKSsaYOtwNqh9ydPn0aW7duxfTp08UOjYiIiEh0BhdJw4YNE/3kBw8exAcffIDk5GRkZWVh27ZtGD9+vG6/IAhYsmQJNm7ciIKCAgwdOhTr1q1D165dRY+FiBrW1OF2QO2Qu0WLFmHPnj0oKCiAu7u7yNERERERicug4XalpaVGNWro8aWlpQgMDMTatWvr3f/+++9j9erVWL9+PZKSkuDk5ISIiAhUVFQYFQ8RNU9ziqQePXqgR48eUKvV2LFjh9ihEREREYnOoCKpS5cuWL58ObKysho8RhAExMfHIzIyEqtXrzbo5JGRkVi6dCkeffTRettbtWoVFi1ahKioKPTp0wfffPMNMjMzuZwwkYk1dU6SlnYBh61bt4oWExEREZFUDBput3//fixcuBBvvfUWAgMDMWDAAPj6+sLe3h75+fm4cOECEhMTYWNjg5iYGLzwwgvNDiw9PR3Z2dkICwvTbXNzc0NISAgSExMxefLkep9XWVmJyspK3eOioiIAgFqthlqtbnZczaE9v7njIObCWNoiycHBoUnv2bhx4/Duu+8iLi4OBQUFcHJyAsA8yAXzIB/MhTwwD/LBXMiDJeXB0NdgUJHUrVs3bN26FRkZGfjhhx9w6NAhHD16FOXl5fD09ERQUBA2btyIyMhIWFtbNytwrezsbACAt7e33nZvb2/dvvosW7YMb7/99l3bd+/eDUdHR1Fia674+Hhzh0D/h7kwzM2bNwEAly5dws6dO41+viAI8Pb2Rk5ODpYtW4YhQ4bo7Wce5IF5kA/mQh6YB/lgLuTBEvJQVlZm0HEGL9wAAB06dMDcuXMxd+7cJgVlCjExMYiOjtY9Lioqgp+fH8LDw+95M1xTUKvViI+Px6hRo6BUKs0aS2vHXBhn3rx5AIARI0bgoYcealIbU6ZMwcqVK3H9+nUsXboUAPMgF8yDfDAX8sA8yAdzIQ+WlAftKLPGGFUkmZJKpQIA5OTkwMfHR7c9JycHffv2bfB5dnZ2sLOzu2u7UqmUTVLlFEtrx1wYRrsYi4eHR5Pfr8ceewwrV67Ezp07odFo9K5T5kEemAf5YC7kgXmQD+ZCHiwhD4bGb/DNZE3N398fKpUKCQkJum1FRUVISkrC4MGDzRgZUevTnNXttEJCQuDr64vi4mLs2bNHrNCIiIiIRGfWIqmkpAQpKSlISUkBULtYQ0pKCjIyMqBQKPDqq69i6dKl+OWXX3D27Fk8/fTT8PX11buXEhFJSxAE3c1km7q6HQBYWVnpVrLkKndEREQkZ2Ytkk6ePImgoCAEBQUBAKKjoxEUFITFixcDAObPn485c+bg+eefx8CBA1FSUoK4uDjY29ubM2yiVqWsrAyCIABoXk8SAEycOBEA8PPPP6O6urrZsRERERFJwaxzkoYPH67746s+CoUC77zzDt555x0TRkVEdWmH2llZWTV7hciHHnoIbdu2xe3bt3HgwAGEhoaKESIRERGRqIzuSQoNDcXixYuRkJCAiooKKWIiIhmpeyNZhULRrLZsbGx0w2VjY2ObGxoRERGRJIwuksLDw3Hs2DFERUXB3d0dDz74IBYtWoT4+HiD1x0nopajbpEkBu2Qu23btkGj0YjSJhEREZGYjB5ut2jRIgBAdXU1Tpw4gQMHDmD//v14//33YWVlxd4lIgujXbShufORtEaOHAlXV1dkZWXh2LFjorRJREREJKYmL9xw7do1nD17FmfOnEFqaipcXFwQGRkpZmxEJANiLP9dl52dHcaOHQsA+Omnn0Rpk4iIiEhMRhdJU6ZMwX333YchQ4YgLi4OgwYNwq5du5CXl4dt27ZJESMRmZHYw+0A/SF391q8hYiIiMgcjB5u991338HT0xPPPfccRo4ciQcffLDZK14RkXyJPdwOACIiIuDo6Ijr16/j6tWrorVLREREJAaje5Ju376Nzz//HFVVVYiJiYGnpyeGDBmChQsXYvfu3VLESERmJPZwOwBwdHTUDc/lvCQiIiKSG6OLJA8PD4wbNw4rVqxAcnIyUlNTERAQgA8++IBzkogskBTD7QBgwoQJAFgkERERkfwYPdxOexPI/fv3Y//+/bhw4QLc3d0xduxYDBs2TIoYiciMpOhJAqD7UOXmzZsoLCyEp6enqO0TERERNZXRRZKXlxc8PT3x0EMPYcaMGRg+fDh69+4tRWxEJANSzEkCanulfXx8kJWVhbS0NBZJREREJBtGF0mpqal44IEHpIiFiGRIqp4kAOjRoweysrJw6dIlDB06VPT2iYiIiJrC6DlJLJCIWhep5iQBQPfu3QEAFy5cEL1tIiIioqYyuicJAH788Uf897//RUZGBqqqqvT2nTp1SpTAiEgepBpuB/xVJF26dEn0tomIiIiayuiepNWrV2PatGnw9vbG6dOnERwcjLZt2+LatWtc3Y7IAkk93A4A0tLSRG+biIiIqKmMLpI+/fRTbNiwAWvWrIGtrS3mz5+P+Ph4vPzyyygsLJQiRiIyI1MMt7t27RrKy8tFb5+IiIioKYwukjIyMjBkyBAAgIODg+4PqKeeegpbtmwRNzoiMjspe5K8vLzg7OwMQRDw+++/i94+ERERUVMYXCRlZmYCAFQqFe7cuQMA6NChg+5GkOnp6RAEQYIQicicpJyTpFAo4OfnBwC4ePGi6O0TERERNYXBRVKvXr3w7bffYuTIkfjll18AANOmTcNrr72GUaNGYdKkSXj00UclC5SITE8QBEl7kgCgffv2ALjCHREREcmHwavbLV26FDNnzkR4eDjee+89AMCsWbPQtm1bHD16FOPGjcMLL7wgWaBEZHrl5eXQaDQApJmTBPxVJLEniYiIiOTC4J6kl156CampqcjPz8cDDzyAX3/9FQAwefJkrF69GnPmzIGtra1kgRKR6WmH2gGAk5OTJOfgcDsiIiKSG6Puk+Tv74+9e/fik08+wYQJE9CjRw/Y2Og3wfskEVmOuivbWVkZvc6LQbQ9Sb///juqq6vv+plCREREZGpG/zVy/fp1xMbGwsPDA1FRUfyDhsiCSbn8t5anpyccHR1RVlaGq1evolu3bpKdi4iIiMgQRlU4GzduxNy5cxEWFobz58+jXbt2UsVFRDIg9aINAGBlZYXu3bvj1KlTuHjxIoskIiIiMjuDx8+MHj0aCxYswCeffILY2FgWSEStgJTLf9elvaksV7gjIiIiOTC4J6mmpgapqam6+QNEZPlMMdwO+KtI4uINREREJAcGF0nx8fFSxkFEMmSK4XYA0KNHDwAskoiIiEgepFmuiogsgqmH2128eFF3XyYiIiIic2GRREQNMlVPUufOnaFUKlFWVoYbN25Iei4iIiKixrSIImnt2rXo1KkT7O3tERISguPHj5s7JKJWwVRzkmxsbBAQEACAQ+6IiIjI/GRfJH3//feIjo7GkiVLcOrUKQQGBiIiIgK5ubnmDo3I4pmqJwn4a14SV7gjIiIic5N9kbRixQrMmDED06ZNQ8+ePbF+/Xo4Ojriyy+/NHdoRBbPVHOSAC7eQERERPJh1M1kTa2qqgrJycmIiYnRbbOyskJYWBgSExPrfU5lZSUqKyt1j4uKigAAarUaarVa2oAbsWDBAly8eBE7duyAlZXs61OLptFocOPGDeaiEUeOHAEAODg4SHL9aNtUq9W64XZxcXGYOXOm6OeihvF6kA/mQh6YB/lgLuRBjDz06NEDL730ksiRGc/Qv2dkXSTl5eWhpqYG3t7eetu9vb1x6dKlep+zbNkyvP3223dt3717NxwdHSWJ01BffvklCgsLzRoDUVNkZmZi586dkrUfHx+vuzZu3ryJzz77TLJzERERkekFBQWhU6dO5g4DZWVlBh0n6yKpKWJiYhAdHa17XFRUBD8/P4SHh8PV1dWMkQHz58/H2bNn0blzZ34aYmYajQZXr15lLgygUqnwzDPPQKlUit62Wq1GfHw8Ro0aBaVSCQ8PjwY/ACHp8HqQD+ZCHpgH+WAu5EGMPNx///0YM2aMyJEZTzvKrDGyLpI8PT1hbW2NnJwcve05OTlQqVT1PsfOzg52dnZ3bVcqlZL8kWeMefPmYefOnRgzZozZY2nt1Go1cyEj2utzypQp5g6lVeL1IB/MhTwwD/LBXMiDJeXB0PhlXZLb2tqif//+SEhI0G3TaDRISEjA4MGDzRgZERERERFZKln3JAFAdHQ0pk6digEDBiA4OBirVq1CaWkppk2bZtDzBUEAYHjXmpTUajXKyspQVFTU4qvwlo65kAfmQR6YB/lgLuSBeZAP5kIeLCkP2ppAWyM0RPZF0qRJk3Dr1i0sXrwY2dnZ6Nu3L+Li4u5azKEh2vu8+Pn5SRkmERERERG1EMXFxXBzc2twv0JorIxq4TQaDTIzM+Hi4gKFQmHWWLSLSNy4ccPsi0i0dsyFPDAP8sA8yAdzIQ/Mg3wwF/JgSXkQBAHFxcXw9fW95yIUsu9Jai4rKyu0b9/e3GHocXV1bfHfYJaCuZAH5kEemAf5YC7kgXmQD+ZCHiwlD/fqQdKS9cINREREREREpsYiiYiIiIiIqA4WSSZkZ2eHJUuW1HsfJzIt5kIemAd5YB7kg7mQB+ZBPpgLeWiNebD4hRuIiIiIiIiMwZ4kIiIiIiKiOlgkERERERER1cEiiYiIiIiIqA4WSURERERERHWwSDKhtWvXolOnTrC3t0dISAiOHz9u7pAs2ltvvQWFQqH31b17d93+iooKzJo1C23btoWzszMmTpyInJwcM0ZsGQ4ePIixY8fC19cXCoUCP/30k95+QRCwePFi+Pj4wMHBAWFhYbh8+bLeMXfu3MGTTz4JV1dXuLu7Y/r06SgpKTHhq7AMjeXimWeeuesaGT16tN4xzEXzLVu2DAMHDoSLiwu8vLwwfvx4pKWl6R1jyM+jjIwMPPLII3B0dISXlxfmzZuH6upqU76UFs2QPAwfPvyua2LmzJl6xzAPzbNu3Tr06dNHd1PSwYMHY9euXbr9vBZMp7FctPbrgUWSiXz//feIjo7GkiVLcOrUKQQGBiIiIgK5ubnmDs2iPfDAA8jKytJ9HT58WLfvtddew6+//ooffvgBBw4cQGZmJiZMmGDGaC1DaWkpAgMDsXbt2nr3v//++1i9ejXWr1+PpKQkODk5ISIiAhUVFbpjnnzySZw/fx7x8fHYvn07Dh48iOeff95UL8FiNJYLABg9erTeNbJlyxa9/cxF8x04cACzZs3CsWPHEB8fD7VajfDwcJSWluqOaeznUU1NDR555BFUVVXh6NGj+Prrr7Fp0yYsXrzYHC+pRTIkDwAwY8YMvWvi/fff1+1jHpqvffv2WL58OZKTk3Hy5EmMHDkSUVFROH/+PABeC6bUWC6AVn49CGQSwcHBwqxZs3SPa2pqBF9fX2HZsmVmjMqyLVmyRAgMDKx3X0FBgaBUKoUffvhBt+3ixYsCACExMdFEEVo+AMK2bdt0jzUajaBSqYQPPvhAt62goECws7MTtmzZIgiCIFy4cEEAIJw4cUJ3zK5duwSFQiH8+eefJovd0vw9F4IgCFOnThWioqIafA5zIY3c3FwBgHDgwAFBEAz7ebRz507ByspKyM7O1h2zbt06wdXVVaisrDTtC7AQf8+DIAjCsGHDhFdeeaXB5zAP0vDw8BA+//xzXgsyoM2FIPB6YE+SCVRVVSE5ORlhYWG6bVZWVggLC0NiYqIZI7N8ly9fhq+vL+6//348+eSTyMjIAAAkJydDrVbr5aR79+7o0KEDcyKh9PR0ZGdn673vbm5uCAkJ0b3viYmJcHd3x4ABA3THhIWFwcrKCklJSSaP2dLt378fXl5e6NatG1588UXcvn1bt4+5kEZhYSEAoE2bNgAM+3mUmJiI3r17w9vbW3dMREQEioqK9D71JcP9PQ9a3377LTw9PdGrVy/ExMSgrKxMt495EFdNTQ2+++47lJaWYvDgwbwWzOjvudBqzdeDjbkDaA3y8vJQU1Oj900EAN7e3rh06ZKZorJ8ISEh2LRpE7p164asrCy8/fbbeOihh3Du3DlkZ2fD1tYW7u7ues/x9vZGdna2eQJuBbTvbX3XgnZfdnY2vLy89Pbb2NigTZs2zI3IRo8ejQkTJsDf3x9Xr17FwoULERkZicTERFhbWzMXEtBoNHj11VcxdOhQ9OrVCwAM+nmUnZ1d73Wj3UfGqS8PADBlyhR07NgRvr6+SE1NxYIFC5CWlobY2FgAzINYzp49i8GDB6OiogLOzs7Ytm0bevbsiZSUFF4LJtZQLgBeDyySyGJFRkbq/t+nTx+EhISgY8eO+O9//wsHBwczRkYkD5MnT9b9v3fv3ujTpw86d+6M/fv34+GHHzZjZJZr1qxZOHfunN78SDK9hvJQd75d79694ePjg4cffhhXr15F586dTR2mxerWrRtSUlJQWFiIH3/8EVOnTsWBAwfMHVar1FAuevbs2eqvBw63MwFPT09YW1vftTpLTk4OVCqVmaJqfdzd3REQEIArV65ApVKhqqoKBQUFescwJ9LSvrf3uhZUKtVdC5pUV1fjzp07zI3E7r//fnh6euLKlSsAmAuxzZ49G9u3b8e+ffvQvn173XZDfh6pVKp6rxvtPjJcQ3moT0hICADoXRPMQ/PZ2tqiS5cu6N+/P5YtW4bAwEB8/PHHvBbMoKFc1Ke1XQ8skkzA1tYW/fv3R0JCgm6bRqNBQkKC3rhPklZJSQmuXr0KHx8f9O/fH0qlUi8naWlpyMjIYE4k5O/vD5VKpfe+FxUVISkpSfe+Dx48GAUFBUhOTtYds3fvXmg0Gt0PaJLGzZs3cfv2bfj4+ABgLsQiCAJmz56Nbdu2Ye/evfD399fbb8jPo8GDB+Ps2bN6RWt8fDxcXV11Q2Po3hrLQ31SUlIAQO+aYB7Ep9FoUFlZyWtBBrS5qE+rux7MvXJEa/Hdd98JdnZ2wqZNm4QLFy4Izz//vODu7q63IgiJa+7cucL+/fuF9PR04ciRI0JYWJjg6ekp5ObmCoIgCDNnzhQ6dOgg7N27Vzh58qQwePBgYfDgwWaOuuUrLi4WTp8+LZw+fVoAIKxYsUI4ffq0cP36dUEQBGH58uWCu7u78PPPPwupqalCVFSU4O/vL5SXl+vaGD16tBAUFCQkJSUJhw8fFrp27So88cQT5npJLda9clFcXCy8/vrrQmJiopCeni7s2bNH6Nevn9C1a1ehoqJC1wZz0Xwvvvii4ObmJuzfv1/IysrSfZWVlemOaeznUXV1tdCrVy8hPDxcSElJEeLi4oR27doJMTEx5nhJLVJjebhy5YrwzjvvCCdPnhTS09OFn3/+Wbj//vuF0NBQXRvMQ/P985//FA4cOCCkp6cLqampwj//+U9BoVAIu3fvFgSB14Ip3SsXvB4EgUWSCa1Zs0bo0KGDYGtrKwQHBwvHjh0zd0gWbdKkSYKPj49ga2sr3HfffcKkSZOEK1eu6PaXl5cLL730kuDh4SE4OjoKjz76qJCVlWXGiC3Dvn37BAB3fU2dOlUQhNplwN98803B29tbsLOzEx5++GEhLS1Nr43bt28LTzzxhODs7Cy4uroK06ZNE4qLi83walq2e+WirKxMCA8PF9q1aycolUqhY8eOwowZM+764Ia5aL76cgBA+Oqrr3THGPLz6I8//hAiIyMFBwcHwdPTU5g7d66gVqtN/GparsbykJGRIYSGhgpt2rQR7OzshC5dugjz5s0TCgsL9dphHprn2WefFTp27CjY2toK7dq1Ex5++GFdgSQIvBZM6V654PUgCApBEATT9VsRERERERHJG+ckERERERER1cEiiYiIiIiIqA4WSURERERERHWwSCIiIiIiIqqDRRIREREREVEdLJKIiIiIiIjqYJFERERERERUB4skIqJWbv/+/VAoFCgoKGhWO8888wzGjx8vSkxitiXnc3/xxRcIDw83ybnqs379eowdO9Zs5ycikisWSUREFmL9+vVwcXFBdXW1bltJSQmUSiWGDx+ud6y2MLp69SqGDBmCrKwsuLm5SRqf9pwKhQJWVlZwc3NDUFAQ5s+fj6ysLL1jP/74Y2zatEnSeP744w8oFAqkpKSY/NwAUFFRgTfffBNLlizRbXvrrbd075GNjQ08PT0RGhqKVatWobKyUvQYnn32WZw6dQqHDh0SvW0iopaMRRIRkYUYMWIESkpKcPLkSd22Q4cOQaVSISkpCRUVFbrt+/btQ4cOHdC5c2fY2tpCpVJBoVCYJM60tDRkZmbixIkTWLBgAfbs2YNevXrh7NmzumPc3Nzg7u7eYBtVVVWSxdfYucXy448/wtXVFUOHDtXb/sADDyArKwsZGRnYt28fHnvsMSxbtgxDhgxBcXGxqDHY2tpiypQpWL16tajtEhG1dCySiIgsRLdu3eDj44P9+/frtu3fvx9RUVHw9/fHsWPH9LaPGDFC9/+6w+02bdoEd3d3/Pbbb+jRowecnZ0xevRovd6empoaREdHw93dHW3btsX8+fMhCIJBcXp5eUGlUiEgIACTJ0/GkSNH0K5dO7z44ou6Y/4+5G348OGYPXs2Xn31VXh6eiIiIgIAcO7cOURGRsLZ2Rne3t546qmnkJeXp3ueRqPB+++/jy5dusDOzg4dOnTAu+++CwDw9/cHAAQFBUGhUOh62/5+7srKSrz88svw8vKCvb09HnzwQZw4cULvvVQoFEhISMCAAQPg6OiIIUOGIC0t7Z7vw3fffVfvUDcbGxuoVCr4+vqid+/emDNnDg4cOIBz587hvffe04vr9ddfx3333QcnJyeEhITo5R4ANm7cCD8/Pzg6OuLRRx/FihUr7ioAx44di19++QXl5eX3jJeIqDVhkUREZEFGjBiBffv26R7v27cPw4cPx7Bhw3Tby8vLkZSUpCuS6lNWVoYPP/wQ//nPf3Dw4EFkZGTg9ddf1+3/6KOPsGnTJnz55Zc4fPgw7ty5g23btjUpZgcHB8ycORNHjhxBbm5ug8d9/fXXsLW1xZEjR7B+/XoUFBRg5MiRCAoKwsmTJxEXF4ecnBw8/vjjuufExMRg+fLlePPNN3HhwgVs3rwZ3t7eAIDjx48DAPbs2YOsrCzExsbWe9758+dj69at+Prrr3Hq1Cl06dIFERERuHPnjt5xb7zxBj766COcPHkSNjY2ePbZZ+/5ug8fPowBAwYY9B51794dkZGRejHOnj0biYmJ+O6775CamorHHnsMo0ePxuXLlwEAR44cwcyZM/HKK68gJSUFo0aN0hWIdQ0YMADV1dVISkoyKBYiolZBICIii7Fx40bByclJUKvVQlFRkWBjYyPk5uYKmzdvFkJDQwVBEISEhAQBgHD9+nVBEARh3759AgAhPz9fEARB+OqrrwQAwpUrV3Ttrl27VvD29tY99vHxEd5//33dY7VaLbRv316IiopqMLa/n6euXbt2CQCEpKQkQRAEYerUqXptDRs2TAgKCtJ7zr/+9S8hPDxcb9uNGzcEAEJaWppQVFQk2NnZCRs3bqw3nvT0dAGAcPr0ab3tdc9dUlIiKJVK4dtvv9Xtr6qqEnx9fXWvX/u69uzZoztmx44dAgChvLy83nPn5+cLAISDBw/qbV+yZIkQGBhY73MWLFggODg4CIIgCNevXxesra2FP//8U++Yhx9+WIiJiREEQRAmTZokPPLII3r7n3zyScHNze2utj08PIRNmzbVe14iotbIxlzFGRERiW/48OEoLS3FiRMnkJ+fj4CAALRr1w7Dhg3DtGnTUFFRgf379+P+++9Hhw4dGmzH0dERnTt31j328fHR9fIUFhYiKysLISEhuv02NjYYMGCAwUPu/k77vHvNi+rfv7/e4zNnzmDfvn1wdna+69irV6+ioKAAlZWVePjhh5sUk7YdtVqtN29IqVQiODgYFy9e1Du2T58+uv/7+PgAAHJzc+t9n7VD2+zt7Q2ORRAE3ftz9uxZ1NTUICAgQO+YyspKtG3bFkDt3K9HH31Ub39wcDC2b99+V9sODg4oKyszOBYiIkvHIomIyIJ06dIF7du3x759+5Cfn49hw4YBAHx9feHn54ejR49i3759GDly5D3bUSqVeo8VCkWTCyBDaAuOTp06NXiMk5OT3uOSkhKMHTtWb56Olo+PD65duyZqjI2p+55pixmNRlPvsW3btoVCoUB+fr7B7V+8eFE3j6qkpATW1tZITk6GtbW13nH1FY2NuXPnDtq1a2f084iILBXnJBERWZgRI0Zg//792L9/v97S36Ghodi1axeOHz9+z/lIjXFzc4OPj4/eHJbq6mokJyc3qb3y8nJs2LABoaGhRv2h3q9fP5w/fx6dOnVCly5d9L6cnJzQtWtXODg4ICEhod7n29raAqhdhKIh2tX/jhw5otumVqtx4sQJ9OzZ0+BY6zt3z549ceHCBYOOv3TpEuLi4jBx4kQAtYtN1NTUIDc3967XrlKpANQu5FF3gQkAdz0GanvLKioqEBQU1OTXQ0RkaVgkERFZmBEjRuDw4cNISUnR9SQBwLBhw/DZZ5+hqqqqWUUSALzyyitYvnw5fvrpJ1y6dAkvvfSSwTejzc3NRXZ2Ni5fvozvvvsOQ4cORV5eHtatW2dUDLNmzcKdO3fwxBNP4MSJE7h69Sp+++03TJs2DTU1NbC3t8eCBQswf/58fPPNN7h69SqOHTuGL774AkDtKnsODg66BR8KCwvvOoeTkxNefPFFzJs3D3Fxcbhw4QJmzJiBsrIyTJ8+3ah4/y4iIgKHDx++a3t1dTWys7ORmZmJs2fPYs2aNRg2bBj69u2LefPmAQACAgLw5JNP4umnn0ZsbCzS09Nx/PhxLFu2DDt27AAAzJkzBzt37sSKFStw+fJlfPbZZ9i1a9ddQxoPHTqE+++/X294JRFRa8ciiYjIwowYMQLl5eXo0qWLbiU3oLZIKi4u1i0V3hxz587FU089halTp2Lw4MFwcXG5a/5LQ7p16wZfX1/0798fy5cvR1hYGM6dO2d0z4yvry+OHDmCmpoahIeHo3fv3nj11Vfh7u4OK6vaX29vvvkm5s6di8WLF6NHjx6YNGmSbm6VjY0NVq9ejc8++wy+vr6Iioqq9zzLly/HxIkT8dRTT6Ffv364cuUKfvvtN3h4eBgV799Nnz4dO3fuvKs4O3/+PHx8fNChQwcMHz4c//3vfxETE4NDhw7pDaX76quv8PTTT2Pu3Lno1q0bxo8fjxMnTujmQA0dOhTr16/HihUrEBgYiLi4OLz22mt3zYPasmULZsyY0azXQkRkaRSClIPMiYiIqEGPPfYY+vXrh5iYGJOcb8aMGbh06RIOHToEoLYgGzlyJH7//Xe4ubmZJAYiopaAPUlERERm8sEHHzRpoQVDffjhhzhz5gyuXLmCNWvW4Ouvv8bUqVN1+7OysvDNN9+wQCIi+hv2JBEREVmoxx9/HPv370dxcTHuv/9+zJkzBzNnzjR3WEREssciiYiIiIiIqA4OtyMiIiIiIqqDRRIREREREVEdLJKIiIiIiIjqYJFERERERERUB4skIiIiIiKiOlgkERERERER1cEiiYiIiIiIqA4WSURERERERHWwSCIiIiIiIqrj/wOflxp0OvlYWQAAAABJRU5ErkJggg==\",\n      \"text/plain\": [\n       \"<Figure size 1000x1000 with 7 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Show the results\\n\",\n    \"yaw_angles_opt = np.vstack(df_opt[\\\"yaw_angles_opt\\\"])\\n\",\n    \"fig, axarr = plt.subplots(len(x), 1, sharex=True, sharey=True, figsize=(10, 10))\\n\",\n    \"for i in range(len(x)):\\n\",\n    \"    axarr[i].plot(wind_directions, yaw_angles_opt[:, i], 'k-', label='T%d' % i)\\n\",\n    \"    axarr[i].set_ylabel('Yaw (Deg)')\\n\",\n    \"    axarr[i].legend()\\n\",\n    \"    axarr[i].grid(True)\\n\",\n    \"axarr[-1].set_xlabel('Wind Direction (Deg)')\\n\",\n    \"\\n\",\n    \"plt.show()\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"jekyll\": {\n   \"layout\": \"default\",\n   \"nav_order\": 1,\n   \"permalink\": \"/tutorials/index\",\n   \"title\": \"Overview\"\n  },\n  \"kernelspec\": {\n   \"display_name\": \"floris\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.10.4\"\n  },\n  \"vscode\": {\n   \"interpreter\": {\n    \"hash\": \"853a8652e3619d46ff0e51baac54f380b0862f9ec17aef8c5e0b66472a177ac0\"\n   }\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"
  },
  {
    "path": "docs/layout_optimization.md",
    "content": "\n(layout_optimization)=\n# Layout Optimization\n\nThe FLORIS package provides layout optimization tools to place turbines within a specified\nboundary area to optimize annual energy production (AEP) or wind plant value. Layout\noptimizers accept an instantiated `FlorisModel` and alter the turbine layouts in order to\nimprove the objective function value (AEP or value).\n\n## Background\n\nLayout optimization entails placing turbines in a wind farm in a configuration that maximizes\nan objective function, usually the AEP. Turbines are moved to minimize their wake interactions\nin the most dominant wind directions, while respecting the boundaries of the area for turbine\nplacement as well as minimum distance requirements between neighboring turbines.\n\nMathematically, we represent this as a (nonconvex) optimization problem.\nLet $x = \\{x_i\\}_{i=1,\\dots,N}$, $x_i \\in \\mathbb{R}^2$ represent the set of\ncoordinates of turbines within a farm (that is, $x_i$ represents the $(X, Y)$\nlocation of turbine $i$). Further, let $R \\subset \\mathbb{R}^2$ be a closed\nregion in which to place turbines. Finally, let $d$ represent the minimum\nallowable distance between two turbines. Then, the layout optimization problem\nis expressed as\n\n$$\n\\begin{aligned}\n\\underset{x}{\\text{maximize}} & \\:\\: f(x)\\\\\n\\text{subject to} & \\:\\: x \\subset R \\\\\n& \\:\\: ||x_i - x_j|| \\geq d \\:\\: \\forall j = 1,\\dots,N, j\\neq i\n\\end{aligned}\n$$\n\nHere, $||\\cdot||$ denotes the Euclidean norm, and $f(x)$ is the cost function to be maximized.\n\nWhen maximizing the AEP, $f = \\sum_w P(w, x)p_W(w)$, where $w$ is the wind condition bin\n(e.g., wind speed, wind direction pair); $P(w, x)$ is the power produced by the wind farm in\ncondition $w$ with layout $x$; and $p_W(w)$ is the annual frequency of occurrence of\ncondition $w$.\n\nLayout optimizers take iterative approaches to solving the layout optimization problem\nspecified above. Optimization routines available in FLORIS are described below.\n\n## Scipy layout optimization\nThe `LayoutOptimizationScipy` class is built around `scipy.optimize`s `minimize`\nroutine, using the `SLSQP` solver by default. Options for adjusting\n`minimize`'s behavior are exposed to the user with the `optOptions` argument.\nOther options include enabling fast wake steering at each layout optimizer\niteration with the `enable_geometric_yaw` argument, and switch from AEP\noptimization to value optimization with the `use_value` argument.\n\n## Genetic random search layout optimization\nThe `LayoutOptimizationRandomSearch` class is a custom optimizer designed specifically for\nlayout optimization via random perturbations of the turbine locations. It is designed to have\nthe following features:\n- Robust to complex wind conditions and complex boundaries, including disjoint regions for\nturbine placement\n- Easy to parallelize and wrapped in a genetic algorithm for propagating candidate solutions\n- Simple to set up and tune for non-optimization experts\n- Set up to run cheap constraint checks prior to more expensive objective function evaluations\nto accelerate optimization\n\nThe algorithm, described in full in {cite:t}`SinnerFleming2024grs`,\nmoves a random turbine and random distance in a random direction; checks\nthat constraints are satisfied; evaluates the objective function (AEP or value); and then\ncommits to the move if there is an objective function improvement. The main tuning parameter\nis the probability mass function for the random movement distance, which is a dictionary to be\npassed to the `distance_pmf` argument.\n\nThe `distance_pmf` dictionary should contain two keys, each containing a 1D array of equal\nlength: `\"d\"`, which specifies the perturbation distance _in units of the rotor diameter_,\nand `\"p\"`, which specifies the probability that the corresponding perturbation distance is\nchosen at any iteration of the random search algorithm. The `distance_pmf` can therefore be\nused to encourage or discourage more aggressive or more conservative movements, and to enable\nor disable jumps between disjoint regions for turbine placement.\n\nThe figure below shows an example of the optimized layout of a farm using the GRS algorithm, with\nthe black dots indicating the initial layout; red dots indicating the final layout; and blue\nshading indicating wind speed heterogeneity (lighter shade is lower wind speed, darker shade is\nhigher wind speed). The progress of each of the genetic individuals in the optimization process is\nshown in the right-hand plot.\n![](plot_complex_docs.png)\n\n## Gridded layout optimization\nThe `LayoutOptimizationGridded` class allows users to quickly find a layout that fits the most\nturbines possible into the specified boundary area, given that the turbines are arranged in a\ngridded layout.\nTo do so, a range of different rotations and translations of a generic gridded arrangement are\ntried, and the one that fits the most turbines into the boundary area is selected. No AEP\nevaluations are performed; rather, the cost function $f$ to be maximized is simply $N$, the number\nof turbines, and there is an additional constraint that the turbines are arranged in a gridded\nfashion. Note that in other layout optimizers, $N$ is fixed.\n\nWe envisage that this will be useful for users that want to quickly generate a layout to\n\"fill\" a boundary region in a gridded manner. By default, the gridded arrangement is a square grid\nwith spacing of `min_dist` (or `min_dist_D`); however, instantiating with the `hexagonal_packing`\nkeyword argument set to `True` will provide a grid that offsets the rows to enable tighter packing\nof turbines while still satisfying the `min_dist`.\n\nAs with the `LayoutOptimizationRandomSearch` class, the boundaries specified can be complex (and\nmay contain separate areas).\nUser settings include `rotation_step`, which specifies the step size for rotating the grid\n(in degrees); `rotation_range`, which specifies the range of rotation angles; `translation_step` or\n`translation_step_D`, which specifies the step size for translating the grid in meters or rotor\ndiameters, respectively; and `translation_range`, which specifies the range of possible\ntranslations. All come with default values, which we expect to be suitable for many or most users.\n"
  },
  {
    "path": "docs/multidimensional_wind_turbine.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"ab10767e\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Multidimensional Wind Turbine\\n\",\n    \"\\n\",\n    \"Many external factors can affect the power and thrust curves of wind turbines. FLORIS supports the\\n\",\n    \"ability to define \\\"multidimensional\\\" wind turbines, where the power and thrust curves are defined\\n\",\n    \"as a function of external parameters. To enable this functionality, rather than defining `power`\\n\",\n    \"and `thrust_coefficient` as a function of `wind_speed` on the `power_thrust_table`, users should\\n\",\n    \"instead provide a path to a data file (described below) as `power_thrust_data_file`. Additionally,\\n\",\n    \"users must set the `multi_dimensional_cp_ct` option on the turbine definition to `True`.\\n\",\n    \"\\n\",\n    \"The power thrust data file should be a CSV file with the following columns:\\n\",\n    \"(`<external_parameter_1>`, `<external_parameter_2>`, ..., `ws`, `power`,\\n\",\n    \"`thrust_coefficient`). The external parameters can be any relevant factors that affect the turbine\\n\",\n    \"performance, and the values to be used will be specified at run time or in the FLORIS input file.\\n\",\n    \"For example, the external parameters could be air density, wave height, etc. The `ws` column should\\n\",\n    \"contain the wind speed values for specification of the power and thrust coefficient (stored in the\\n\",\n    \"`power` and `thrust_coefficient` columns, respectively). The wind speed, power, and thrust\\n\",\n    \"coefficient values should be defined for each combination of the external parameters.\\n\",\n    \"\\n\",\n    \"The user can then specify the values of the external parameters either on the FLORIS input file\\n\",\n    \"or using the `multidim_conditions` argument of `FlorisModel.set()`. The power and thrust coefficient\\n\",\n    \"are determined based on the specified conditions using a nearest-neighbor approach.\\n\",\n    \"\\n\",\n    \"The following code snippet shows an example of a multidimensional wind turbine definition and its\\n\",\n    \"corresponding power thrust data file.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"cc97a774\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"\\n\",\n    \"from floris import FlorisModel, TimeSeries\\n\",\n    \"\\n\",\n    \"n_wind_speeds = 100\\n\",\n    \"wind_speeds = np.linspace(0.1, 30, n_wind_speeds)\\n\",\n    \"\\n\",\n    \"fmodel = FlorisModel(\\\"defaults\\\") # Defaults to NREL 5MW turbine\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_data=TimeSeries(\\n\",\n    \"        wind_directions=np.zeros(n_wind_speeds),\\n\",\n    \"        wind_speeds=wind_speeds,\\n\",\n    \"        turbulence_intensities=0.06\\n\",\n    \"    ),\\n\",\n    \"    layout_x=[0],\\n\",\n    \"    layout_y=[0],\\n\",\n    \"    wind_shear=0.0,\\n\",\n    \"    turbine_type=[\\\"iea_15MW_floating_multi_dim_cp_ct\\\"],\\n\",\n    \"    reference_wind_height=-1,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Now, we need to specify what external parameters to run the model for\\n\",\n    \"fmodel.set(multidim_conditions={\\\"Tp\\\": 2, \\\"Hs\\\": 1})\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"powers = fmodel.get_turbine_powers()\\n\",\n    \"thrust_coefficients = fmodel.get_turbine_thrust_coefficients()\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots(2, 1, sharex=True)\\n\",\n    \"ax[0].plot(wind_speeds, powers, label=\\\"First condition\\\")\\n\",\n    \"ax[0].grid()\\n\",\n    \"ax[0].set_ylabel(\\\"Power [kW]\\\")\\n\",\n    \"ax[1].plot(wind_speeds, thrust_coefficients)\\n\",\n    \"ax[1].grid()\\n\",\n    \"ax[1].set_ylabel(\\\"Thrust coefficient [-]\\\")\\n\",\n    \"ax[1].set_xlabel(\\\"Wind speed [m/s]\\\")\\n\",\n    \"ax[1].set_xlim([0, 30])\\n\",\n    \"\\n\",\n    \"# Set a second multidimensional condition and rerun\\n\",\n    \"fmodel.set(multidim_conditions={\\\"Tp\\\": 4, \\\"Hs\\\": 5})\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"powers = fmodel.get_turbine_powers()\\n\",\n    \"thrust_coefficients = fmodel.get_turbine_thrust_coefficients()\\n\",\n    \"ax[0].plot(wind_speeds, powers, label=\\\"Second condition\\\")\\n\",\n    \"ax[0].legend(loc=\\\"upper left\\\")\\n\",\n    \"ax[1].plot(wind_speeds, thrust_coefficients)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"98fd51f6\",\n   \"metadata\": {},\n   \"source\": [\n    \"Note that this example is not meant to be represntative of a real turbine, but rather to illustrate\\n\",\n    \"the functionality. At this time, FLORIS only support a single external condition combination at a\\n\",\n    \"time, but multiple combinations can be run sequentially as is shown above.\\n\",\n    \"\\n\",\n    \"As of FLORIS v4.6, users can further specify array-based multidimensional conditions, where a\\n\",\n    \"different multidimensional condition can be specified for each findex. This allows users to run\\n\",\n    \"multiple multidimensional condition combinations in a single call to `fmodel.run()`. Further,\\n\",\n    \"multidimensional conditions can now be passed to `floris.set()` via the `WindData` objects\\n\",\n    \"(`TimeSeries`, in this case).\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"8c21f432\",\n   \"metadata\": {},\n   \"source\": []\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"c0b18ef8\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"multidim_conditions = {\\n\",\n    \"    \\\"Tp\\\": np.array([2]*n_wind_speeds + [4]*n_wind_speeds),\\n\",\n    \"    \\\"Hs\\\": np.array([1]*n_wind_speeds + [5]*n_wind_speeds),\\n\",\n    \"}\\n\",\n    \"\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_data=TimeSeries(\\n\",\n    \"        wind_directions=np.zeros(n_wind_speeds*2),\\n\",\n    \"        wind_speeds=np.tile(wind_speeds, 2),\\n\",\n    \"        turbulence_intensities=0.06,\\n\",\n    \"        multidim_conditions=multidim_conditions,\\n\",\n    \"    ),\\n\",\n    \")\\n\",\n    \"# Call fmodel.run() once and run both conditions in one go\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"powers = fmodel.get_turbine_powers()\\n\",\n    \"thrust_coefficients = fmodel.get_turbine_thrust_coefficients()\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots(2, 1, sharex=True)\\n\",\n    \"ax[0].plot(wind_speeds, powers[:n_wind_speeds], label=\\\"First condition\\\")\\n\",\n    \"ax[0].grid()\\n\",\n    \"ax[0].set_ylabel(\\\"Power [kW]\\\")\\n\",\n    \"ax[1].plot(wind_speeds, thrust_coefficients[:n_wind_speeds])\\n\",\n    \"ax[1].grid()\\n\",\n    \"ax[1].set_ylabel(\\\"Thrust coefficient [-]\\\")\\n\",\n    \"ax[1].set_xlabel(\\\"Wind speed [m/s]\\\")\\n\",\n    \"ax[1].set_xlim([0, 30])\\n\",\n    \"ax[0].plot(wind_speeds, powers[n_wind_speeds:], label=\\\"Second condition\\\")\\n\",\n    \"ax[0].legend(loc=\\\"upper left\\\")\\n\",\n    \"ax[1].plot(wind_speeds, thrust_coefficients[n_wind_speeds:])\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"eni\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.13.7\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"
  },
  {
    "path": "docs/operation_models_user.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"id\": \"ac224ce9-bd4f-4f5c-88b7-f0e9e49ee498\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Turbine Operation Models\\n\",\n    \"\\n\",\n    \"Separate from the turbine models, which define the physical characterstics of the turbines, FLORIS\\n\",\n    \"allows users to specify how the turbine behaves in terms of producing power and thurst. We refer to \\n\",\n    \"different models for turbine behavior as \\\"operation models\\\". A key feature of operation models is\\n\",\n    \"the ability for users to specify control setpoints at which the operation model will be evaluated. \\n\",\n    \"For instance, some operation models allow users to specify `yaw_angles`, which alter the power \\n\",\n    \"being produced by the turbine along with it's thrust force on flow.\\n\",\n    \"\\n\",\n    \"Operation models are specified by the `operation_model` key on the turbine yaml file, or by using\\n\",\n    \"the `set_operation_model()` method on `FlorisModel`. Each operation model available in FLORIS is\\n\",\n    \"described and demonstrated below. The simplest operation model is the `\\\"simple\\\"` operation model,\\n\",\n    \"which takes no control setpoints and simply evaluates the power and thrust coefficient curves for \\n\",\n    \"the turbine at the current wind condition. The default operation model is the `\\\"cosine-loss\\\"`\\n\",\n    \"operation model, which models the loss in power of a turbine under yaw misalignment using a cosine\\n\",\n    \"term with an exponent.\\n\",\n    \"\\n\",\n    \"We first provide a quick demonstration of how to switch between different operation models. Then, \\n\",\n    \"each operation model available in FLORIS is described, along with its relevant control setpoints.\\n\",\n    \"We also describe the different parameters that must be specified in the turbine \\n\",\n    \"`\\\"power_thrust_table\\\"` dictionary in order to use that operation model.\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"id\": \"71788b47-6641-4080-bb3f-eb799d969e0b\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Selecting the operation model\\n\",\n    \"\\n\",\n    \"There are two options for selecting the operation model:\\n\",\n    \"1. Manually changing the `\\\"operation_model\\\"` field of the turbine input yaml \\n\",\n    \"(see [Turbine Input File Reference](input_reference_turbine))\\n\",\n    \"\\n\",\n    \"2. Using `set_operation_model()` on an instantiated `FlorisModel` object.\\n\",\n    \"\\n\",\n    \"The following code demonstrates the use of the second option.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"2275840e-48a3-41d2-ace9-fad05da0dc02\",\n   \"metadata\": {\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"from floris import FlorisModel\\n\",\n    \"from floris import layout_visualization as layoutviz\\n\",\n    \"\\n\",\n    \"fmodel = FlorisModel(\\\"../examples/inputs/gch.yaml\\\")\\n\",\n    \"\\n\",\n    \"# Look at layout\\n\",\n    \"ax = layoutviz.plot_turbine_rotors(fmodel)\\n\",\n    \"layoutviz.plot_turbine_labels(fmodel, ax=ax)\\n\",\n    \"ax.set_xlabel(\\\"x [m]\\\")\\n\",\n    \"ax.set_ylabel(\\\"y [m]\\\")\\n\",\n    \"\\n\",\n    \"# Set simple operation model\\n\",\n    \"fmodel.set_operation_model(\\\"simple\\\")\\n\",\n    \"\\n\",\n    \"# Evalaute the model and extract the power output\\n\",\n    \"fmodel.run()\\n\",\n    \"print(\\\"simple operation model powers [kW]: \\\", fmodel.get_turbine_powers() / 1000)\\n\",\n    \"\\n\",\n    \"# Set the yaw angles (which the \\\"simple\\\" operation model does not use\\n\",\n    \"# and change the operation model to \\\"cosine-loss\\\"\\n\",\n    \"fmodel.set(yaw_angles=[[20., 0., 0.]])\\n\",\n    \"fmodel.set_operation_model(\\\"cosine-loss\\\")\\n\",\n    \"ax = layoutviz.plot_turbine_rotors(fmodel)\\n\",\n    \"layoutviz.plot_turbine_labels(fmodel, ax=ax)\\n\",\n    \"ax.set_xlabel(\\\"x [m]\\\")\\n\",\n    \"ax.set_ylabel(\\\"y [m]\\\")\\n\",\n    \"\\n\",\n    \"# Evaluate again\\n\",\n    \"fmodel.run()\\n\",\n    \"powers_cosine_loss = fmodel.get_turbine_powers()\\n\",\n    \"print(\\\"cosine-loss operation model powers [kW]: \\\", fmodel.get_turbine_powers() / 1000)\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"5d22f376\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Operation model library\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"id\": \"f2576e8a-47ee-48b5-8707-aca0dc76929c\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Simple model\\n\",\n    \"User-level name: `\\\"simple\\\"`\\n\",\n    \"\\n\",\n    \"Underlying class: `SimpleTurbine`\\n\",\n    \"\\n\",\n    \"Required data on `power_thrust_table`:\\n\",\n    \"- `ref_air_density` (scalar)\\n\",\n    \"- `ref_tilt` (scalar)\\n\",\n    \"- `wind_speed` (list)\\n\",\n    \"- `power` (list)\\n\",\n    \"- `thrust_coefficient` (list)\\n\",\n    \"\\n\",\n    \"The `\\\"simple\\\"` operation model describes the \\\"normal\\\" function of a wind turbine, as described by\\n\",\n    \"its power curve and thrust coefficient. It does not respond to any control setpoints, and is most \\n\",\n    \"often used as a baseline or for users wanting to evaluate wind farms in nominal operation.\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"ced1e091\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Cosine loss model\\n\",\n    \"User-level name: `\\\"cosine-loss\\\"`\\n\",\n    \"\\n\",\n    \"Underlying class: `CosineLossTurbine`\\n\",\n    \"\\n\",\n    \"Required data on `power_thrust_table`:\\n\",\n    \"- `ref_air_density` (scalar)\\n\",\n    \"- `ref_tilt` (scalar)\\n\",\n    \"- `wind_speed` (list)\\n\",\n    \"- `power` (list)\\n\",\n    \"- `thrust_coefficient` (list)\\n\",\n    \"- `cosine_loss_exponent_yaw` (scalar)\\n\",\n    \"- `cosine_loss_exponent_tilt` (scalar)\\n\",\n    \"\\n\",\n    \"The `\\\"cosine-loss\\\"` operation model describes the decrease in power and thrust produced by a \\n\",\n    \"wind turbine as it yaws (or tilts) away from the incoming wind. The thrust is reduced by a factor of \\n\",\n    \"$\\\\cos \\\\gamma$, where $\\\\gamma$ is the yaw misalignment angle, while the power is reduced by a factor \\n\",\n    \"of $(\\\\cos\\\\gamma)^{p_P}$, where $p_P$ is the cosine loss exponent, specified by `cosine_loss_exponent_yaw`.\\n\",\n    \"Similarly, the thrust and power are reduced by factors of $(\\\\cos \\\\theta / \\\\cos \\\\theta_{ref})$ and\\n\",\n    \"$(\\\\cos \\\\theta / \\\\cos \\\\theta_{ref})^{p_T}$, respectively, where $\\\\theta$ is the tilt angle, \\n\",\n    \"$\\\\theta_{ref}$ is the reference tilt angle under which the power and thrust curves are specified, and\\n\",\n    \"$p_T$ is the cosine loss exponent for tilt, specified by `cosine_loss_exponent_tilt`.\\n\",\n    \"The power and thrust produced by the turbine\\n\",\n    \"thus vary as a function of the turbine's yaw angle, set using the `yaw_angles` argument to \\n\",\n    \"`FlorisModel.set()`, and tilt angle (if applicable, for example for floating wind turbines).\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"b9a5f00a-0ead-4759-b911-3a1161e55791\",\n   \"metadata\": {\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"from floris import TimeSeries\\n\",\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"\\n\",\n    \"# Set up the FlorisModel\\n\",\n    \"fmodel.set_operation_model(\\\"cosine-loss\\\")\\n\",\n    \"fmodel.set(layout_x=[0.0], layout_y=[0.0])\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_data=TimeSeries(\\n\",\n    \"        wind_speeds=np.ones(100) * 8.0,\\n\",\n    \"        wind_directions=np.ones(100) * 270.0,\\n\",\n    \"        turbulence_intensities=0.06\\n\",\n    \"    )\\n\",\n    \")\\n\",\n    \"fmodel.reset_operation()\\n\",\n    \"\\n\",\n    \"# Sweep the yaw angles\\n\",\n    \"yaw_angles = np.linspace(-25, 25, 100)\\n\",\n    \"fmodel.set(yaw_angles=yaw_angles.reshape(-1,1))\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"powers = fmodel.get_turbine_powers()/1000\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots()\\n\",\n    \"ax.plot(yaw_angles, powers)\\n\",\n    \"ax.grid()\\n\",\n    \"ax.set_xlabel(\\\"Yaw angle [deg]\\\")\\n\",\n    \"ax.set_ylabel(\\\"Power [kW]\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"019abca6\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Simple derating model\\n\",\n    \"User-level name: `\\\"simple-derating\\\"`\\n\",\n    \"\\n\",\n    \"Underlying class: `SimpleDeratingTurbine`\\n\",\n    \"\\n\",\n    \"Required data on `power_thrust_table`:\\n\",\n    \"- `ref_air_density` (scalar)\\n\",\n    \"- `ref_tilt` (scalar)\\n\",\n    \"- `wind_speed` (list)\\n\",\n    \"- `power` (list)\\n\",\n    \"- `thrust_coefficient` (list)\\n\",\n    \"\\n\",\n    \"The `\\\"simple-derating\\\"` operation model enables users to derate turbines by setting a new power \\n\",\n    \"rating. It does not require any extra parameters on the `power_thrust_table`, but adescribes the \\n\",\n    \"decrease in power and thrust produced by providing the `power_setpoints` argument to\\n\",\n    \"`FlorisModel.set()`. The default power rating for the turbine can be acheived by setting the\\n\",\n    \"appropriate entries of `power_setpoints` to `None`.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"722be425-9231-451a-bd84-7824db6a5098\",\n   \"metadata\": {\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"# Set up the FlorisModel\\n\",\n    \"fmodel.set_operation_model(\\\"simple-derating\\\")\\n\",\n    \"fmodel.reset_operation()\\n\",\n    \"wind_speeds = np.linspace(0, 30, 100)\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_data=TimeSeries(\\n\",\n    \"        wind_speeds=wind_speeds,\\n\",\n    \"        wind_directions=np.ones(100) * 270.0,\\n\",\n    \"        turbulence_intensities=0.06\\n\",\n    \"    )\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots()\\n\",\n    \"for power_setpoint in [5.0, 4.0, 3.0, 2.0]:\\n\",\n    \"    fmodel.set(power_setpoints=np.array([[power_setpoint*1e6]]*100))\\n\",\n    \"    fmodel.run()\\n\",\n    \"    powers = fmodel.get_turbine_powers()/1000\\n\",\n    \"    ax.plot(wind_speeds, powers[:,0], label=f\\\"Power setpoint (MW): {power_setpoint}\\\")\\n\",\n    \"\\n\",\n    \"ax.grid()\\n\",\n    \"ax.legend()\\n\",\n    \"ax.set_xlabel(\\\"Wind speed [m/s]\\\")\\n\",\n    \"ax.set_ylabel(\\\"Power [kW]\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"4caca5fa\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Mixed operation model\\n\",\n    \"User-level name: `\\\"mixed\\\"`\\n\",\n    \"\\n\",\n    \"Underlying class: `MixedOperationTurbine`\\n\",\n    \"\\n\",\n    \"Required data on `power_thrust_table`:\\n\",\n    \"- `ref_air_density` (scalar)\\n\",\n    \"- `ref_tilt` (scalar)\\n\",\n    \"- `wind_speed` (list)\\n\",\n    \"- `power` (list)\\n\",\n    \"- `thrust_coefficient` (list)\\n\",\n    \"- `cosine_loss_exponent_yaw` (scalar)\\n\",\n    \"- `cosine_loss_exponent_tilt` (scalar)\\n\",\n    \"\\n\",\n    \"The `\\\"mixed\\\"` operation model allows users to specify _either_ `yaw_angles` (evaluated using the \\n\",\n    \"`\\\"cosine-loss\\\"` operation model) _or_ `power_setpoints` (evaluated using the `\\\"simple-derating\\\"`\\n\",\n    \"operation model). That is, for each turbine, and at each `findex`, a non-zero yaw angle or a \\n\",\n    \"non-`None` power setpoint may be specified. However, specifying both a non-zero yaw angle and a \\n\",\n    \"finite power setpoint for the same turbine and at the same `findex` will produce an error.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"5e3cda81\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"fmodel.set_operation_model(\\\"mixed\\\")\\n\",\n    \"fmodel.set(layout_x=[0.0, 0.0], layout_y=[0.0, 500.0])\\n\",\n    \"fmodel.reset_operation()\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_data=TimeSeries(\\n\",\n    \"        wind_speeds=np.array([10.0]),\\n\",\n    \"        wind_directions=np.array([270.0]),\\n\",\n    \"        turbulence_intensities=0.06\\n\",\n    \"    )\\n\",\n    \")\\n\",\n    \"fmodel.set(\\n\",\n    \"    yaw_angles=np.array([[20.0, 0.0]]),\\n\",\n    \"    power_setpoints=np.array([[None, 2e6]])\\n\",\n    \")\\n\",\n    \"fmodel.run()\\n\",\n    \"print(\\\"Powers [kW]: \\\", fmodel.get_turbine_powers()/1000)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"c036feda\",\n   \"metadata\": {},\n   \"source\": [\n    \"### AWC model\\n\",\n    \"\\n\",\n    \"User-level name: `\\\"awc\\\"`\\n\",\n    \"\\n\",\n    \"Underlying class: `AWCTurbine`\\n\",\n    \"\\n\",\n    \"Required data on `power_thrust_table`:\\n\",\n    \"- `ref_air_density` (scalar)\\n\",\n    \"- `ref_tilt` (scalar)\\n\",\n    \"- `wind_speed` (list)\\n\",\n    \"- `power` (list)\\n\",\n    \"- `thrust_coefficient` (list)\\n\",\n    \"- `helix_a` (scalar)\\n\",\n    \"- `helix_power_b` (scalar)\\n\",\n    \"- `helix_power_c` (scalar)\\n\",\n    \"- `helix_thrust_b` (scalar)\\n\",\n    \"- `helix_thrust_c` (scalar)\\n\",\n    \"\\n\",\n    \"The `\\\"awc\\\"` operation model allows for users to define _active wake control_ strategies. These strategies \\n\",\n    \"use pitch control to actively enhance wake mixing and subsequently decrease wake velocity deficits. As a \\n\",\n    \"result, downstream turbines can increase their power production, with limited power loss for the controlled \\n\",\n    \"upstream turbine. The `AWCTurbine` class models this power loss at the turbine applying AWC. For each \\n\",\n    \"turbine, the user can define an AWC strategy to implement through the `awc_modes` array. Note that currently, \\n\",\n    \"only `\\\"baseline\\\"`, i.e., no AWC, and `\\\"helix\\\"`, i.e., the \\n\",\n    \"[counterclockwise helix method](https://doi.org/10.1002/we.2513) have been implemented. \\n\",\n    \"\\n\",\n    \"The user then defines the exact AWC implementation through setting the variable `awc_amplitudes` for \\n\",\n    \"each turbine. This variable defines the mean-to-peak amplitude of the sinusoidal AWC pitch excitation,\\n\",\n    \"i.e., for a turbine that under `awc_modes = \\\"baseline\\\"` has a constant pitch angle of 0 degrees, setting \\n\",\n    \"`awc_amplitude = 2` results in a pitch signal varying from -2 to 2 degrees over the desired Strouhal\\n\",\n    \"frequency. This Strouhal frequency is not used as an input here, since it has minimal influence on turbine \\n\",\n    \"power production. Note that setting `awc_amplitudes = 0` effectively disables AWC and is therefore the same \\n\",\n    \"as running a turbine at `awc_modes = \\\"baseline\\\"`.\\n\",\n    \"\\n\",\n    \"Each example turbine input file `floris/turbine_library/*.yaml` has its own `helix_*` parameter data. These \\n\",\n    \"parameters are determined by fitting data from `OpenFAST` simulations in region II to the following equation:\\n\",\n    \"\\n\",\n    \"$$\\n\",\n    \"    P_\\\\text{AWC} = P_\\\\text{baseline} \\\\cdot (1 - (b + c \\\\cdot P_\\\\text{baseline} ) \\\\cdot A_\\\\text{AWC}^a)\\n\",\n    \"$$\\n\",\n    \"\\n\",\n    \"where $a$ is `\\\"helix_a\\\"`, $b$ is `\\\"helix_power_b\\\"`, $c$ is `\\\"helix_power_c\\\"`, and $A_\\\\text{AWC}$ is `awc_amplitudes`. \\n\",\n    \"The thrust coefficient follows the same equation, but with the respective thrust parameters. When AWC is \\n\",\n    \"turned on while $P_\\\\text{baseline} > P_\\\\text{rated}$, a warning is given as the model is not yet tuned for region III.\\n\",\n    \"\\n\",\n    \"The figure below shows the fit between the turbine power and thrust in OpenFAST helix AWC simulations (x) \\n\",\n    \"and FLORIS simulations (--) at different region II wind speeds for the NREL 5MW reference turbine.\\n\",\n    \"\\n\",\n    \"<!--<img src=\\\"powerthrust_helix.png\\\" width=\\\"600px\\\">-->\\n\",\n    \"![](./powerthrust_helix.png)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"40e9bcda\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"fmodel = FlorisModel(\\\"../examples/inputs/emgauss_helix.yaml\\\")\\n\",\n    \"fmodel.set_operation_model(\\\"awc\\\")\\n\",\n    \"fmodel.set(layout_x=[0.0, 0.0], layout_y=[0.0, 500.0])\\n\",\n    \"fmodel.reset_operation()\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_speeds=np.array([8.0]),\\n\",\n    \"    wind_directions=np.array([270.0]),\\n\",\n    \"    turbulence_intensities=np.array([0.06])\\n\",\n    \")\\n\",\n    \"fmodel.set(\\n\",\n    \"    awc_modes=np.array([[\\\"helix\\\", \\\"baseline\\\"]]),\\n\",\n    \"    awc_amplitudes=np.array([[2.5, 0]])\\n\",\n    \")\\n\",\n    \"fmodel.run()\\n\",\n    \"print(\\\"Powers [kW]: \\\", fmodel.get_turbine_powers()/1000)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"25f9c86c\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Peak shaving model\\n\",\n    \"\\n\",\n    \"User-level name: `\\\"peak-shaving\\\"`\\n\",\n    \"\\n\",\n    \"Underlying class: `PeakShavingTurbine`\\n\",\n    \"\\n\",\n    \"Required data on `power_thrust_table`:\\n\",\n    \"- `ref_air_density` (scalar)\\n\",\n    \"- `ref_tilt` (scalar)\\n\",\n    \"- `wind_speed` (list)\\n\",\n    \"- `power` (list)\\n\",\n    \"- `thrust_coefficient` (list)\\n\",\n    \"- `peak_shaving_fraction` (scalar)\\n\",\n    \"- `peak_shaving_TI_threshold` (scalar)\\n\",\n    \"\\n\",\n    \"The `\\\"peak-shaving\\\"` operation model allows users to implement peak shaving, where the thrust\\n\",\n    \"of the wind turbine is reduced from the nominal curve near rated to reduce unwanted structural\\n\",\n    \"loading. Peak shaving here is implemented here by reducing the thrust by a fixed fraction from\\n\",\n    \"the peak thrust on the nominal thrust curve, as specified by `peak_shaving_fraction`.This only\\n\",\n    \"affects wind speeds near the peak in the thrust\\n\",\n    \"curve (usually near rated wind speed), as thrust values away from the peak will be below the\\n\",\n    \"fraction regardless. Further, peak shaving is only applied if the turbulence intensity experienced\\n\",\n    \"by the turbine meets the `peak_shaving_TI_threshold`. To apply peak shaving in all wind conditions,\\n\",\n    \"`peak_shaving_TI_threshold` may be set to zero.\\n\",\n    \"\\n\",\n    \"When the turbine is peak shaving to reduce thrust, the power output is updated accordingly. Letting\\n\",\n    \"$C_{T}$ represent the thrust coefficient when peak shaving (at given wind speed), and $C_{T}'$\\n\",\n    \"represent the thrust coefficient that the turbine would be operating at under nominal control, then\\n\",\n    \"the power $P$ due to peak shaving (compared to the power $P'$ available under nominal control) is \\n\",\n    \"computed (based on actuator disk theory) as\\n\",\n    \"\\n\",\n    \"$$ P = \\\\frac{C_T (1 - a)}{C_T' (1 - a')} P'$$\\n\",\n    \"\\n\",\n    \"where $a$ (respectively, $a'$) is the axial induction factor corresponding to $C_T$\\n\",\n    \"(respectively, $C_T'$), computed using the usual relationship from actuator disk theory,\\n\",\n    \"i.e. the lesser solution to $C_T=4a(1-a)$.\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"1eff05f3\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Set up the FlorisModel\\n\",\n    \"fmodel = FlorisModel(\\\"../examples/inputs/gch.yaml\\\")\\n\",\n    \"fmodel.set(\\n\",\n    \"    layout_x=[0.0], layout_y=[0.0],\\n\",\n    \"    wind_data=TimeSeries(\\n\",\n    \"        wind_speeds=wind_speeds,\\n\",\n    \"        wind_directions=np.ones(100) * 270.0,\\n\",\n    \"        turbulence_intensities=0.2 # Higher than threshold value of 0.1\\n\",\n    \"    )\\n\",\n    \")\\n\",\n    \"fmodel.reset_operation()\\n\",\n    \"fmodel.set_operation_model(\\\"simple\\\")\\n\",\n    \"fmodel.run()\\n\",\n    \"powers_base = fmodel.get_turbine_powers()/1000\\n\",\n    \"thrust_coefficients_base = fmodel.get_turbine_thrust_coefficients()\\n\",\n    \"fmodel.set_operation_model(\\\"peak-shaving\\\")\\n\",\n    \"fmodel.run()\\n\",\n    \"powers_peak_shaving = fmodel.get_turbine_powers()/1000\\n\",\n    \"thrust_coefficients_peak_shaving = fmodel.get_turbine_thrust_coefficients()\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots(2,1,sharex=True)\\n\",\n    \"ax[0].plot(wind_speeds, thrust_coefficients_base, label=\\\"Without peak shaving\\\", color=\\\"black\\\")\\n\",\n    \"ax[0].plot(wind_speeds, thrust_coefficients_peak_shaving, label=\\\"With peak shaving\\\", color=\\\"C0\\\")\\n\",\n    \"ax[1].plot(wind_speeds, powers_base, label=\\\"Without peak shaving\\\", color=\\\"black\\\")\\n\",\n    \"ax[1].plot(wind_speeds, powers_peak_shaving, label=\\\"With peak shaving\\\", color=\\\"C0\\\")\\n\",\n    \"\\n\",\n    \"ax[1].grid()\\n\",\n    \"ax[0].grid()\\n\",\n    \"ax[0].legend()\\n\",\n    \"ax[0].set_ylabel(\\\"Thrust coefficient [-]\\\")\\n\",\n    \"ax[1].set_xlabel(\\\"Wind speed [m/s]\\\")\\n\",\n    \"ax[1].set_ylabel(\\\"Power [kW]\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"92912bf7\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Controller-dependent model\\n\",\n    \"\\n\",\n    \"User-level name: `\\\"controller-dependent\\\"`\\n\",\n    \"\\n\",\n    \"Underlying class: `ControllerDependentTurbine`\\n\",\n    \"\\n\",\n    \"Required data on `power_thrust_table`:\\n\",\n    \"- `rotor_solidity`: (scalar)\\n\",\n    \"- `rated_rpm`: (scalar)\\n\",\n    \"- `generator_efficiency`: (scalar)\\n\",\n    \"- `rated_power`: (scalar)\\n\",\n    \"- `rotor_diameter`: (scalar)\\n\",\n    \"- `beta`: (scalar)\\n\",\n    \"- `cd`: (scalar)\\n\",\n    \"- `cl_alfa`: (scalar)\\n\",\n    \"- `cp_ct_data_file`: (string)\\n\",\n    \"\\n\",\n    \"The `\\\"controller-dependent\\\"` operation model is an advanced operation model that uses the turbine's Cp/Ct\\n\",\n    \"surface to optimize performance under yaw misalignment.\\n\",\n    \"\\n\",\n    \"The `\\\"controller-dependent\\\"` operation model determines the wind turbine power output in yaw misalignment conditions, taking into account the effects of the control system. \\n\",\n    \"When the rotor operates in below-rated conditions, the models assumes that blade pitch is equal to the optimal value (corresponding to maximum power coefficient $C_P$),\\n\",\n    \"while the generator torque is scheduled as a function of rotational speed $\\\\omega$ according to the $K\\\\omega^2$ law.\\n\",\n    \"The $K$ coefficient is computed using the condition of maximum efficiency as shown in Chapter 7 of {cite:t}`hansen_book`.\\n\",\n    \"When the turbine operates above rated wind speed, the rotor speed is fixed and equal to the rated value, while the pitch angle is used to keep the power output equal to rated. \\n\",\n    \"The `\\\"controller-dependent\\\"` operation model solves a balance equation between electrical power and aerodynamic power, assuming the aforementioned control strategies.\\n\",\n    \"This yields the pitch and torque values that correspond to the current inflow and yaw misalignment. Based on these quantities, the power output of the turbine is computed.\\n\",\n    \"Because the balance equation must be solved, the `ControllerDependentTurbine` is slower to execute than some other operation models.\\n\",\n    \"\\n\",\n    \"The `\\\"controller-dependent\\\"` operation model considers the effect of vertical shear. Hence, the wind turbine can perform differently depending on the direction of misalignment.\\n\",\n    \"Vertical shear is computed locally at each rotor, so it can be affected by wake impingement. The model includes both the effects of yaw and tilt on rotor performance.\\n\",\n    \"To include the effects of shear, ensure that `turbine_grid_points` is greater than 1 in the main FLORIS configuration file.\\n\",\n    \"\\n\",\n    \"The `\\\"controller-dependent\\\"` operation model requires the definition of some parameters that depend on the turbine:\\n\",\n    \"1) Rated rotation speed (`rated_rpm`), generator efficiency (`generator_efficiency`), and rated power, specified in kW (`rated_power`).\\n\",\n    \"2) Three parameters that describe the aerodynamics of the blade, namely `beta` (twist), `cd` (drag) and `cl_alfa` (lift slope).\\n\",\n    \"These parameters are provided for the NREL 5MW, IEA 10MW, and IEA 15MW turbines in the \\\"floris/turbine_library/\\\".\\n\",\n    \"When using a different turbine model, these parameters can be estimated as shown in Section 3.5 of {cite:t}`tamaro2024beyondcosine`. \\n\",\n    \"3) Look-up tables of the power coefficient ($C_P$) and thrust coefficient $C_T$ as functions of tip-speed ratio and blade pitch angle.\\n\",\n    \"Approximate values for these are provided for the reference turbines in \\\"floris/turbine_library/\\\".\\n\",\n    \"4) Rotor solidity (`rotor_solidity`), i.e. the fraction of the rotor area occupied by the blades.\\n\",\n    \"\\n\",\n    \"Further details can be found in {cite:t}`tamaro2024beyondcosine`.\\n\",\n    \"Developed and implemented by Simone Tamaro, Filippo Campagnolo, and Carlo L. Bottasso at Technische Universität München (TUM) (email: simone.tamaro@tum.de).\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"6e4c5ba2\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"N  = 101 # How many steps to cover yaw range in\\n\",\n    \"yaw_max = 30 # Maximum yaw to test\\n\",\n    \"\\n\",\n    \"# Set up the yaw angle sweep\\n\",\n    \"yaw_angles = np.linspace(-yaw_max, yaw_max, N).reshape(-1,1)\\n\",\n    \"\\n\",\n    \"# We can use the same FlorisModel, but we'll set it up for this test\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_data=TimeSeries(\\n\",\n    \"        wind_speeds=np.ones(N) * 8.0,\\n\",\n    \"        wind_directions=np.ones(N) * 270.0,\\n\",\n    \"        turbulence_intensities=0.06\\n\",\n    \"    ),\\n\",\n    \"    yaw_angles=yaw_angles,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# We'll compare the \\\"controller-dependent\\\" model to the standard \\\"cosine-loss\\\" model\\n\",\n    \"op_models = [\\\"cosine-loss\\\", \\\"controller-dependent\\\"]\\n\",\n    \"results = {}\\n\",\n    \"\\n\",\n    \"for op_model in op_models:\\n\",\n    \"    print(f\\\"Evaluating model: {op_model}\\\")\\n\",\n    \"    fmodel.set_operation_model(op_model)\\n\",\n    \"\\n\",\n    \"    fmodel.run()\\n\",\n    \"    results[op_model] = fmodel.get_turbine_powers().squeeze()\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots()\\n\",\n    \"colors = [\\\"C0\\\", \\\"k\\\"]\\n\",\n    \"linestyles = [\\\"solid\\\", \\\"dashed\\\"]\\n\",\n    \"for key, c, ls in zip(results, colors, linestyles):\\n\",\n    \"    central_power = results[key][yaw_angles.squeeze() == 0]\\n\",\n    \"    ax.plot(yaw_angles.squeeze(), results[key]/central_power, label=key, color=c, linestyle=ls)\\n\",\n    \"\\n\",\n    \"ax.grid(True)\\n\",\n    \"ax.legend()\\n\",\n    \"ax.set_xlabel(\\\"Yaw angle [deg]\\\")\\n\",\n    \"ax.set_ylabel(\\\"Normalized turbine power [deg]\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"a269aa73\",\n   \"metadata\": {},\n   \"source\": [\n    \"__WARNING__: The power and thrust curves generated by querying tabulated data as a function of blade pitch and tip-speed ratio for the reference wind turbines is _not_ an exact match for the reference power and thrust curves found at the IEA Wind Task 37's [Github page](https://github.com/IEAWindTask37) or the NREL 5MW [reference data](https://github.com/NREL/turbine-models/blob/master/Offshore/NREL_5MW_126_RWT_corrected.csv). As such, results using the Controller-dependent model, which rely on these $C_P$ and $C_T$ tables, should be considered demonstrative only and not necessarily consistent with other results using the reference wind turbines.\\n\",\n    \"\\n\",\n    \"For example, the nominal power and thrust curves for the IEA 15MW, IEA 10MW, and NREL 5MW are shown below, along with their derivations from the provided demonstrative $C_P$ / $C_T$ tables.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"90d5c155\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"fmodel.reset_operation()\\n\",\n    \"for turbine in [\\\"nrel_5MW\\\", \\\"iea_10MW\\\", \\\"iea_15MW\\\"]:\\n\",\n    \"    fmodel.set(\\n\",\n    \"        layout_x=[0.0], layout_y=[0.0], turbine_type=[turbine],\\n\",\n    \"        wind_data=TimeSeries(\\n\",\n    \"            wind_speeds=wind_speeds,\\n\",\n    \"            wind_directions=np.ones(100) * 270.0,\\n\",\n    \"            turbulence_intensities=0.2 # Higher than threshold value of 0.1\\n\",\n    \"        )\\n\",\n    \"    )\\n\",\n    \"    # Simple model (using reference power and thrust curves)\\n\",\n    \"    fmodel.set_operation_model(\\\"simple\\\")\\n\",\n    \"    fmodel.run()\\n\",\n    \"    P_s = fmodel.get_turbine_powers()/1000\\n\",\n    \"    CT_s = fmodel.get_turbine_thrust_coefficients()\\n\",\n    \"\\n\",\n    \"    # Controller-dependent model (using demonstration Cp/Ct tables)\\n\",\n    \"    fmodel.set_operation_model(\\\"controller-dependent\\\")\\n\",\n    \"    fmodel.run()\\n\",\n    \"    P_cd = fmodel.get_turbine_powers()/1000\\n\",\n    \"    CT_cd = fmodel.get_turbine_thrust_coefficients()\\n\",\n    \"\\n\",\n    \"    fig, ax = plt.subplots(2,1,sharex=True)\\n\",\n    \"    ax[0].plot(wind_speeds, CT_s, label=\\\"Reference data\\\", color=\\\"black\\\")\\n\",\n    \"    ax[0].plot(wind_speeds, CT_cd, label=\\\"Cp/Ct tables\\\", color=\\\"red\\\", linestyle=\\\"--\\\")\\n\",\n    \"    ax[1].plot(wind_speeds, P_s, label=\\\"Reference data\\\", color=\\\"black\\\")\\n\",\n    \"    ax[1].plot(wind_speeds, P_cd, label=\\\"Cp/Ct data\\\", color=\\\"red\\\", linestyle=\\\"--\\\")\\n\",\n    \"\\n\",\n    \"    ax[1].grid()\\n\",\n    \"    ax[0].grid()\\n\",\n    \"    ax[0].legend()\\n\",\n    \"    ax[0].set_ylabel(\\\"Thrust coefficient [-]\\\")\\n\",\n    \"    ax[1].set_xlabel(\\\"Wind speed [m/s]\\\")\\n\",\n    \"    ax[1].set_ylabel(\\\"Power [kW]\\\")\\n\",\n    \"    ax[0].set_title(turbine)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"a04db676\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Unified Momentum Model\\n\",\n    \"\\n\",\n    \"User-level name: `\\\"unified-momentum\\\"`\\n\",\n    \"\\n\",\n    \"Underlying class: `UnifiedMomentumModelTurbine`\\n\",\n    \"\\n\",\n    \"Required data on `power_thrust_table`:\\n\",\n    \"- `ref_air_density` (scalar)\\n\",\n    \"- `ref_tilt` (scalar)\\n\",\n    \"- `wind_speed` (list)\\n\",\n    \"- `power` (list)\\n\",\n    \"- `thrust_coefficient` (list)\\n\",\n    \"\\n\",\n    \"An extension of the classical one-dimensional momentum theory to model the induction of an\\n\",\n    \"actuator disk is presented in {cite:t}`HeckJohlasHowland2023_yawed_adm` to directly account\\n\",\n    \"for power and thrust loss due to yaw misalignment rather than using an empirical correction\\n\",\n    \"as in the cosine loss model. Analytical expressions for the induction, thrust, initial wake\\n\",\n    \"velocities and power are developed as a function of the yaw angle and thrust coefficient.\\n\",\n    \"\\n\",\n    \"Note that the low thrust limit of the Unified Momentum Model is presently implemented in FLORIS, which returns the equations derived and validated in Heck et al. (2023).\\n\",\n    \"This low thrust limit will be accurate for thrust coefficients approximately less than 0.9.\\n\",\n    \"\\n\",\n    \"This section recreates key validation figures discussed in the paper through FLORIS.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"b824e63b\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"n_points = 20\\n\",\n    \"\\n\",\n    \"fmodel.set_operation_model(\\\"unified-momentum\\\")\\n\",\n    \"fmodel.set(layout_x=[0.0], layout_y=[0.0], turbine_type=[\\\"nrel_5MW\\\"])\\n\",\n    \"fmodel.reset_operation()\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_data=TimeSeries(\\n\",\n    \"        wind_speeds=np.array(n_points * [11.0]),\\n\",\n    \"        wind_directions=np.array(n_points * [270.0]),\\n\",\n    \"        turbulence_intensities=0.06\\n\",\n    \"    )\\n\",\n    \")\\n\",\n    \"yaw_angles = np.linspace(0, 50, n_points)\\n\",\n    \"cos_reference = np.cos(np.radians(yaw_angles))\\n\",\n    \"cos3_reference = np.cos(np.radians(yaw_angles))**3\\n\",\n    \"\\n\",\n    \"fmodel.set(yaw_angles=np.reshape(yaw_angles, (-1,1)))\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"powers = fmodel.get_turbine_powers()\\n\",\n    \"power_ratio_umm = powers[:,0] / powers[0,0]\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots(1,1)\\n\",\n    \"ax.plot(yaw_angles, power_ratio_umm, label=\\\"Unified momentum model\\\", color=\\\"black\\\")\\n\",\n    \"ax.plot(yaw_angles, cos_reference, label=r\\\"$\\\\cos(\\\\gamma)$\\\", linestyle=\\\":\\\", color=\\\"purple\\\")\\n\",\n    \"ax.plot(yaw_angles, cos3_reference, label=r\\\"$\\\\cos^3(\\\\gamma)$\\\", linestyle=\\\":\\\", color=\\\"orange\\\")\\n\",\n    \"ax.grid()\\n\",\n    \"ax.legend()\\n\",\n    \"ax.set_title(\\\"Figure 2 (a): Power ratio vs yaw angle\\\")\\n\",\n    \"ax.set_xlabel(r\\\"Yaw angle, $\\\\gamma$ (degrees)\\\")\\n\",\n    \"ax.set_ylabel(r\\\"Power ratio, $P(\\\\gamma)/P(0)$\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"44e95590\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from floris.core.turbine.unified_momentum_model import Heck, LimitedHeck\\n\",\n    \"\\n\",\n    \"n_points = 20\\n\",\n    \"yaw_angles = np.linspace(0, 50, n_points)\\n\",\n    \"\\n\",\n    \"ct_prime = 1.33\\n\",\n    \"\\n\",\n    \"heck = Heck()\\n\",\n    \"ai_umm = np.array([heck(ct_prime, np.radians(yaw)).an for yaw in yaw_angles])\\n\",\n    \"heck_no_spanwise = LimitedHeck()\\n\",\n    \"ai_no_spanwise = np.array([heck_no_spanwise(ct_prime, np.radians(yaw)).an for yaw in yaw_angles])\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots(1,1)\\n\",\n    \"ax.plot(yaw_angles, ai_umm / ai_umm[0], label=\\\"Yaw-dependent UMM\\\", color=\\\"black\\\")\\n\",\n    \"ax.plot(yaw_angles, ai_no_spanwise/ ai_no_spanwise[0], label=\\\"Low outlet spanwise velocity limit\\\", linestyle=\\\"--\\\", color=\\\"blue\\\")\\n\",\n    \"ax.grid()\\n\",\n    \"ax.legend()\\n\",\n    \"ax.set_title(\\\"Figure 3: Normalized rotor-normal, rotor-averaged induction for the yawed UMM\\\")\\n\",\n    \"ax.set_xlabel(r\\\"Yaw angle, $\\\\gamma$ (degrees)\\\")\\n\",\n    \"ax.set_ylabel(r\\\"Axial induction ratio, $a_n(\\\\gamma) / a_n(0)$\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"d17daafe\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"floris\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.13.2\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"
  },
  {
    "path": "docs/references.bib",
    "content": "---\n---\n\n@article{abkar2015influence,\n    title={Influence of atmospheric stability on wind-turbine wakes: A large-eddy simulation study},\n    author={Abkar, Mahdi and Port{\\'e}-Agel, Fernando},\n    journal={Physics of fluids},\n    volume={27},\n    number={3},\n    pages={035104},\n    year={2015},\n    publisher={AIP Publishing LLC}\n}\n\n@article{bastankhah2014new,\n    title={A new analytical model for wind-turbine wakes},\n    author={Bastankhah, Majid and Port{\\'e}-Agel, Fernando},\n    journal={Renewable Energy},\n    volume={70},\n    pages={116--123},\n    year={2014},\n    publisher={Elsevier}\n}\n\n@article{bastankhah2016experimental,\n    title={Experimental and theoretical study of wind turbine wakes in yawed conditions},\n    author={Bastankhah, Majid and Port{\\'e}-Agel, Fernando},\n    journal={Journal of Fluid Mechanics},\n    volume={806},\n    pages={506--541},\n    year={2016},\n    publisher={Cambridge University Press}\n}\n\n@article{niayifar2016analytical,\n    title={Analytical modeling of wind farms: A new approach for power prediction},\n    author={Niayifar, Amin and Port{\\'e}-Agel, Fernando},\n    journal={Energies},\n    volume={9},\n    number={9},\n    pages={741},\n    year={2016},\n    publisher={Multidisciplinary Digital Publishing Institute}\n}\n\n@article{dilip2017wind,\n    title={Wind turbine wake mitigation through blade pitch offset},\n    author={Dilip, Deepu and Port{\\'e}-Agel, Fernando},\n    journal={Energies},\n    volume={10},\n    number={6},\n    pages={757},\n    year={2017},\n    publisher={Multidisciplinary Digital Publishing Institute}\n}\n\n@Article{blondel2020alternative,\n    AUTHOR = {Blondel, F. and Cathelain, M.},\n    TITLE = {An alternative form of the super-Gaussian wind turbine wake model},\n    JOURNAL = {Wind Energy Science Discussions},\n    VOLUME = {2020},\n    YEAR = {2020},\n    PAGES = {1--16},\n    URL = {https://www.wind-energ-sci-discuss.net/wes-2019-99/},\n    DOI = {10.5194/wes-2019-99}\n}\n\n@inproceedings{Cathelain2020calibration,\n\tauthor = {M. Cathelain and F. Blondel and P.A. Joulin and P. Bozonnet},\n\ttitle = {Calibration of a super-Gaussian wake model with a focus on near-wake characteristics},\n\tdoi = {10.1088/1742-6596/1618/6/062008},\n\tyear = 2020,\n\tnumber={1},\n\tmonth = {sep},\n\tpublisher = {{IOP} Publishing},\n\tvolume = {1618},\n\tpages = {062008},\n\tbooktitle={Journal of Physics: Conference Series},\n\torganization={IOP Publishing: Conference Series}\n}\n\n@article{qian2018new,\n    title={A new analytical wake model for yawed wind turbines},\n    author={Qian, Guo-Wei and Ishihara, Takeshi},\n    journal={Energies},\n    volume={11},\n    number={3},\n    pages={665},\n    year={2018},\n    publisher={Multidisciplinary Digital Publishing Institute}\n}\n\n@article{martinez2019aerodynamics,\n    title={The aerodynamics of the curled wake: A simplified model in view of flow control},\n    author={Mart{\\'\\i}nez-Tossas, Luis A and Annoni, Jennifer and Fleming, Paul A and Churchfield, Matthew J},\n    journal={Wind Energy Science (Online)},\n    volume={4},\n    number={NREL/JA-5000-73451},\n    year={2019},\n    publisher={National Renewable Energy Lab.(NREL), Golden, CO (United States)}\n}\n\n@article{fleming2018simulation,\n    AUTHOR = {Fleming, P. and Annoni, J. and Churchfield, M. and Martinez-Tossas, L. A. and Gruchalla, K. and Lawson, M. and Moriarty, P.},\n    TITLE = {A simulation study demonstrating the importance of large-scale trailing vortices in wake steering},\n    JOURNAL = {Wind Energy Science},\n    VOLUME = {3},\n    YEAR = {2018},\n    NUMBER = {1},\n    PAGES = {243--255},\n    URL = {https://www.wind-energ-sci.net/3/243/2018/},\n    DOI = {10.5194/wes-3-243-2018}\n}\n\n@inproceedings{gebraad2014data,\n    title={A data-driven model for wind plant power optimization by yaw control},\n    author={Gebraad, Pieter MO and Teeuwisse, FW and van Wingerden, Jan-Willem and Fleming, Paul A and Ruben, Shalom D and Marden, Jason R and Pao, Lucy Y},\n    booktitle={2014 American Control Conference},\n    pages={3128--3134},\n    year={2014},\n    organization={IEEE}\n}\n\n@article{gebraad2016wind,\n    title={Wind plant power optimization through yaw control using a parametric model for wake effects—a CFD simulation study},\n    author={Gebraad, Pieter MO and Teeuwisse, FW and Van Wingerden, JW and Fleming, Paul A and Ruben, SD and Marden, JR and Pao, LY},\n    journal={Wind Energy},\n    volume={19},\n    number={1},\n    pages={95--114},\n    year={2016},\n    publisher={Wiley Online Library}\n}\n\n@Article{annoni2018analysis,\nAUTHOR = {Annoni, J. and Fleming, P. and Scholbrock, A. and Roadman, J. and Dana, S. and Adcock, C. and Porte-Agel, F. and Raach, S. and Haizmann, F. and Schlipf, D.},\nTITLE = {Analysis of control-oriented wake modeling tools  using lidar field results},\nJOURNAL = {Wind Energy Science},\nVOLUME = {3},\nYEAR = {2018},\nNUMBER = {2},\nPAGES = {819--831},\nURL = {https://www.wind-energ-sci.net/3/819/2018/},\nDOI = {10.5194/wes-3-819-2018}\n}\n\n@article{crespo1996turbulence,\n  title={Turbulence characteristics in wind-turbine wakes},\n  author={Crespo, A. and Hernández, J.},\n  journal={Journal of wind engineering and industrial aerodynamics},\n  volume={61},\n  number={1},\n  pages={71--85},\n  year={1996},\n  publisher={Elsevier}\n}\n\n@inproceedings{gunn2016limitations,\n  title={Limitations to the validity of single wake superposition in wind farm yield assessment},\n  author={Gunn, Kester and Stock-Williams, Clym and Burke, M and Willden, Richard and Vogel, C and Hunter, W and Stallard, T and Robinson, N and Schmidt, SR},\n  booktitle={Journal of Physics: Conference Series},\n  number={1},\n  year={2016},\n  organization={IOP Publishing: Conference Series}\n}\n\n@Article{King2019Controls,\n  author  = {Jennifer King and Paul Fleming and Ryan King and Luis A. Martinez-Tossas},\n  title   = {Controls-Oriented Model to Capture Secondary Effects of Wake Steering},\n  journal = {Submitted to Wind Energy Science},\n  year    = {2019}\n}\n\n@article{jimenez2010application,\n  title={Application of a LES technique to characterize the wake deflection of a wind turbine in yaw},\n  author={Jim{\\'e}nez, {\\'A}ngel and Crespo, Antonio and Migoya, Emilio},\n  journal={Wind energy},\n  volume={13},\n  number={6},\n  pages={559--572},\n  year={2010},\n  publisher={Wiley Online Library}\n}\n\n@book{jensen1983note,\n  title={A note on wind generator interaction},\n  author={Jensen, Niels Otto},\n  year={1983},\n  publisher={Ris{\\o} National Laboratory}\n}\n\n@inproceedings{bay2020towards,\n  title={Towards flow control: an assessment of the curled wake model in the FLORIS framework},\n  author={Bay, Christopher J. and King, Jennifer and Mart{\\`i}nez-Tossas, Luis A. and Mudafort, Rafael and Hulsman, Paul and K{\\\"u}hn, Martin and Fleming, Paul},\n  booktitle={Journal of Physics: Conference Series},\n  year={2020},\n  organization={IOP Publishing}\n}\n\n@techreport{wharton2010assessing,\n  title={Assessing atmospheric stability and the impacts on wind characteristics at an onshore wind farm},\n  author={Wharton, Sonia and Lundquist, JK},\n  year={2010},\n  institution={Lawrence Livermore National Lab.(LLNL), Livermore, CA (United States)}\n}\n\n@Article{fleming2019initial,\nAUTHOR = {Fleming, P. and King, J. and Dykes, K. and Simley, E. and Roadman, J. and Scholbrock, A. and Murphy, P. and Lundquist, J. K. and Moriarty, P. and Fleming, K. and van Dam, J. and Bay, C. and Mudafort, R. and Lopez, H. and Skopek, J. and Scott, M. and Ryan, B. and Guernsey, C. and Brake, D.},\nTITLE = {Initial results from a field campaign of wake steering applied at a commercial\nwind farm -- Part 1},\nJOURNAL = {Wind Energy Science},\nVOLUME = {4},\nYEAR = {2019},\nNUMBER = {2},\nPAGES = {273--285},\nURL = {https://www.wind-energ-sci.net/4/273/2019/},\nDOI = {10.5194/wes-4-273-2019}\n}\n\n@Article{fleming2019continued,\nAUTHOR = {Fleming, P. and King, J. and Simley, E. and Roadman, J. and Scholbrock, A. and Murphy, P. and Lundquist, J. K. and Moriarty, P. and Fleming, K. and van Dam, J. and Bay, C. and Mudafort, R. and Jager, D. and Skopek, J. and Scott, M. and Ryan, B. and Guernsey, C. and Brake, D.},\nTITLE = {Continued Results from a Field Campaign of Wake Steering\nApplied at a Commercial Wind Farm: Part 2},\nJOURNAL = {Wind Energy Science Discussions},\nVOLUME = {2020},\nYEAR = {2020},\nPAGES = {1--24},\nURL = {https://www.wind-energ-sci-discuss.net/wes-2019-104/},\nDOI = {10.5194/wes-2019-104}\n}\n\n@article{ainslie1988calculating,\n  title={Calculating the flowfield in the wake of wind turbines},\n  author={Ainslie, John F},\n  journal={Journal of Wind Engineering and Industrial Aerodynamics},\n  volume={27},\n  number={1-3},\n  pages={213--224},\n  year={1988},\n  publisher={Elsevier}\n}\n\n@InProceedings{nygaard2020modelling,\n  author       = {Nygaard, Nicolai Gayle and Steen, S{\\o}ren Trads and Poulsen, Lina and Pedersen, Jesper Gr{\\o}nnegaard},\n  booktitle    = {Journal of Physics: Conference Series},\n  title        = {Modelling cluster wakes and wind farm blockage},\n  year         = {2020},\n  number       = {6},\n  organization = {IOP Publishing},\n  pages        = {062072},\n  volume       = {1618},\n}\n\n@article{bastankhah_2021,\n  title={Analytical solution for the cumulative wake of wind turbines in wind farms},\n  volume={911},\n  DOI={10.1017/jfm.2020.1037},\n  journal={Journal of Fluid Mechanics},\n  publisher={Cambridge University Press},\n  author={Bastankhah, Majid and Welch, Bridget L. and Martínez-Tossas, Luis A. and King, Jennifer and Fleming, Paul},\n  year={2021},\n  pages={A53}\n}\n\n@Article{bay_2022,\nAUTHOR = {Bay, C. J. and Fleming, P. and Doekemeijer, B. and King, J. and Churchfield, M. and Mudafort, R.},\nTITLE = {Addressing deep array effects and impacts to wake steering with the cumulative-curl wake model},\nJOURNAL = {Wind Energy Science Discussions},\nVOLUME = {2022},\nYEAR = {2022},\nPAGES = {1--28},\nURL = {https://wes.copernicus.org/preprints/wes-2022-17/},\nDOI = {10.5194/wes-2022-17}\n}\n\n@article{Pedersen_2022_turbopark2,\nurl = {https://dx.doi.org/10.1088/1742-6596/2265/2/022063},\nyear = {2022},\nmonth = {may},\npublisher = {IOP Publishing},\nvolume = {2265},\nnumber = {2},\npages = {022063},\nauthor = {J G Pedersen and E Svensson and L Poulsen and N G Nygaard},\ntitle = {Turbulence Optimized Park model with Gaussian wake profile},\njournal = {Journal of Physics: Conference Series},\n}\n\n@article{SinnerFleming2024grs,\ndoi = {10.1088/1742-6596/2767/3/032036},\nurl = {https://dx.doi.org/10.1088/1742-6596/2767/3/032036},\nyear = {2024},\nmonth = {jun},\npublisher = {IOP Publishing},\nvolume = {2767},\nnumber = {3},\npages = {032036},\nauthor = {Michael Sinner and Paul Fleming},\ntitle = {Robust wind farm layout optimization},\njournal = {Journal of Physics: Conference Series},\n}\n\n@Article{tamaro2024beyondcosine,\nAUTHOR = {Tamaro, S. and Campagnolo, F. and Bottasso, C. L.},\nTITLE = {On the power and control of a misaligned rotor -- beyond the cosine law},\nJOURNAL = {Wind Energy Science},\nVOLUME = {9},\nYEAR = {2024},\nNUMBER = {7},\nPAGES = {1547--1575},\nURL = {https://wes.copernicus.org/articles/9/1547/2024/},\nDOI = {10.5194/wes-9-1547-2024}\n}\n\n@book{hansen_book,\nauthor = {Hansen, M.O.L.},\nyear = {2015},\nmonth = {05},\npublisher = {Routledge},\ntitle = {Aerodynamics of wind turbines: Third edition},\nisbn = {9781315769981},\ndoi = {10.4324/9781315769981},\ncollection={earthscan}\n}\n\n@article{HeckJohlasHowland2023_yawed_adm,\ndoi = {10.1017/jfm.2023.129},\nurl = {https://doi.org/10.1017/jfm.2023.129},\nyear = {2023},\nmonth = {mar},\npublisher={Cambridge University Press},\nvolume = {959},\nauthor = {K.S. Heck, H.M. Johlas and M.F. Howland},\ntitle = {Modelling the induction, thrust and power of a yaw-misaligned actuator disk},\njournal = {Journal of Fluid Mechanics},\n}\n\n@techreport{jonkman_NREL5MW_2009,\n\ttitle = {Definition of a 5-{MW} Reference Wind Turbine for Offshore System Development},\n  institution = {National Renewable Energy Laboratory},\n\turl = {http://www.osti.gov/servlets/purl/947422-nhrlni/},\n\tnumber = {NREL/TP-500-38060},\n\tauthor = {Jonkman, J. and Butterfield, S. and Musial, W. and Scott, G.},\n\tyear = {2009},\n\tdoi = {10.2172/947422},\n}\n\n@techreport{kainz_IEA10MW_2024,\n\ttitle = {{IEA}-{Wind} 740-{10MW} Reference Offshore Wind Plants},\n  url = {https://research-hub.nrel.gov/en/publications/iea-wind-tcp-task-55-the-iea-wind-740-10-mw-reference-offshore-wi},\n\tinstitution = {International Energy Agency},\n  author = {Kainz, Samuel and Quick, Julian and Souza de Alencar, Mauricio and Sanchez Perez-Moreno, Sebastian and Dykes, Katherine and Bay, Christopher and Zaaijer, Michiel B. and Bortolotti, Pietro},\n  year = {2024},\n}\n\n@techreport{gaertner_IEA15MW_2020,\n\ttitle = {{IEA} {Wind} {TCP} {Task} 37: {Definition} of the {IEA} 15-{Megawatt} Offshore Reference Wind Turbine},\n\turl = {https://research-hub.nrel.gov/en/publications/iea-wind-tcp-task-37-definition-of-the-iea-15-megawatt-offshore-r},\n\tnumber = {NREL/TP-5000-75698},\n\tinstitution = {International Energy Agency},\n\tauthor = {Gaertner, Evan and Sethuraman, Latha and Anderson, Benjamin and Barter, Garrett and Abbas, Nikhar and Bortolotti, Pietro and Scott, George and Feil, Roland and Shields, Matthew and Rinker, Jennifer and Zahle, Frederik and Meng, Fanzhong and Skrzypinski, Witold and Bredmose, Henrik and Dykes, Katherine and Allen, Christopher and Viselli, Anthony},\n\tyear = {2020},\n}\n\n@techreport{zahle_IEA22MW_2024,\n\ttitle = {Definition of the {IEA} {Wind} 22-{Megawatt} Offshore Reference Wind Turbine},\n\turl = {https://orbit.dtu.dk/en/publications/definition-of-the-iea-wind-22-megawatt-offshore-reference-wind-tu},\n\tinstitution = {International Energy Agency},\n\tauthor = {Zahle, Frederik and Barlas, Athanasios and Loenbaek, Kenneth and Bortolotti, Pietro and Zalkind, Daniel and Wang, Lu and Labuschagne, Casper and Sethuraman, Latha and Barter, Garrett},\n\tyear = {2024},\n}\n\n@article{fleming_sr_2022,\n\ttitle = {Serial-Refine Method for Fast Wake-Steering Yaw Optimization},\n\tvolume = {2265},\n\tissn = {1742-6588, 1742-6596},\n\turl = {https://iopscience.iop.org/article/10.1088/1742-6596/2265/3/032109},\n\tdoi = {10.1088/1742-6596/2265/3/032109},\n\tnumber = {3},\n\tjournal = {Journal of Physics: Conference Series (TORQUE)},\n\tauthor = {Fleming, Paul A. and Stanley, Andrew P. J. and Bay, Christopher J. and King, Jennifer and Simley, Eric and Doekemeijer, Bart M. and Mudafort, Rafael},\n\tyear = {2022},\n\tpages = {032109},\n}\n\n@inproceedings{katic_sos_1986,\n\taddress = {Rome, Italy},\n\ttitle = {A simple model for cluster efficiency},\n\tvolume = {1},\n\tauthor = {Katic, I and Højstrup, J and Jensen, N O},\n\tyear = {1986},\n\tpages = {407--410},\n}\n\n@article{zehtabiyan_rezaie_CH_2023,\n\ttitle = {A short note on turbulence characteristics in wind-turbine wakes},\n\tvolume = {240},\n\tissn = {0167-6105},\n\tdoi = {10.1016/j.jweia.2023.105504},\n\tjournal = {Journal of Wind Engineering and Industrial Aerodynamics},\n\tauthor = {Zehtabiyan-Rezaie, Navid and Abkar, Mahdi},\n\tyear = {2023},\n\tpages = {105504},\n}\n"
  },
  {
    "path": "docs/turbine_library.md",
    "content": "(turbine_library)=\n# Turbine Library\n\nFLORIS includes a library of predefined wind turbine models that can be used to quickly set up\nsimulations without needing to define the turbine characteristics manually. These include standard\nreference wind turbines as well as fictional wind turbine models for the purpose of demonstrating\nvarious features of FLORIS. These turbines are stored in the `floris.turbine_library` module.\n\n## NREL 5MW reference wind turbine\n\nFLORIS representation of the NREL 5MW reference wind turbine {cite:t}`jonkman_NREL5MW_2009`. Data\nbased on https://github.com/NREL/turbine-models/blob/master/Offshore/NREL_5MW_126_RWT_corrected.csv.\nSpecified as `\"nrel_5MW\"` in the `turbine_type` field of the FLORIS input dictionary.\n\nThe NREL 5MW turbine is the default turbine model used in most FLORIS examples and tutorials. It is\nalso the model used if FLORIS is instantiated in the defaults configuration using\n`FlorisModel(\"defaults\")`.\n\n\n## IEA 15MW reference wind turbine\n\nFLORIS representation of the IEA 15MW reference wind turbine {cite:t}`gaertner_IEA15MW_2020`. Data\nbased on https://github.com/IEAWindTask37/IEA-15-240-RWT/blob/master/Documentation/IEA-15-240-RWT_tabular.xlsx.\nSpecified as `\"iea_15MW\"` in the `turbine_type` field of the FLORIS input dictionary.\n\nThe IEA 15MW turbine is used in the following examples:\n- examples/examples_control_types/004_helix_active_wake_mixing.py\n\n## IEA 10MW reference wind turbine\n\nFLORIS representation of the IEA 10MW reference wind turbine {cite:t}`kainz_IEA10MW_2024`. Data\nbased on https://github.com/NREL/turbine-models/blob/master/Offshore/IEA_10MW_198_RWT.csv.\nSpecified as `\"iea_10MW\"` in the `turbine_type` field of the FLORIS input dictionary.\n\nThe IEA 10MW turbine is used in the following examples:\n- examples/examples_turbine/002_multiple_turbine_types.py\n\n## IEA 22MW reference wind turbine\nFLORIS representation of the IEA 22MW reference wind turbine {cite:t}`zahle_IEA22MW_2024`. Data\ngenerated using OpenFAST v4.1.2 and ROSCO v2.10.2. See\n[pull request](https://github.com/NatLabRockies/floris/pull/1146) for full OpenFAST and ROSCO input files.\nSpecified as `\"iea_22MW\"` in the `turbine_type` field of the FLORIS input dictionary.\n\nThe IEA 22MW is demonstrated, alongside other reference wind turbines, in:\n- examples/examples_turbine/001_reference_turbines.py\n\n## IEA 15MW multidimensional\n\nFictional IEA 15MW turbine model used to demonstrate the use of multidimensional power and thrust\ncoefficient data. Reads in fictional multidimensional data describing the power and thrust coefficient\nrelationships on wave period `Tp` and wave height `Hs` from `iea_15MW_multi_dim_Tp_Hs.csv` in the\n`turbine_library` folder. Specified as `\"iea_15MW_multi_dim\"` in the `turbine_type` field of the FLORIS\ninput dictionary. This data should be treated as fictional and for demonstrative purposes only.\n\nThis fictional turbine model is not currently used in examples.\n\n## IEA 15MW floating, multidimensional\n\nThe same as the multidimensional IEA 15MW turbine model above, but with an additional floating\nplatform tilt table. This model is used to demonstrate the floating wind turbine capabilities\nin FLORIS. Specified as `\"iea_15MW_floating_multi_dim\"` in the `turbine_type` field of the FLORIS input\ndictionary. The data for the floating tilt table was generated using OpenFAST with the UMaine\nVolturnUS-S Reference Platform by Sam Kaufman-Martin, as seen\n[here](https://github.com/FLOWMAS-EERC/IEA15_FOWT/blob/main/iea_15MW_floating_power-from-fixed.yaml).\n\nThis fictional turbine model is used in the following examples:\n- examples/examples_multidim/001_multi_dimensional_cp_ct.py\n- examples/examples_multidim/002_multi_dimensional_cp_ct_2Hs.py\n"
  },
  {
    "path": "docs/turbine_models.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"ab10767e\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Wind turbine models\\n\",\n    \"\\n\",\n    \"FLORIS generally represents wind turbines as actuator disks specified by a power curve and a\\n\",\n    \"thrust coefficient curve (both specified as a function of wind speed). We can easily investigate the\\n\",\n    \"power and thrust coefficients of a turbine by running a single-turbine `FlorisModel` using a range\\n\",\n    \"of wind speeds.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"cc97a774\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"\\n\",\n    \"from floris import FlorisModel, TimeSeries\\n\",\n    \"\\n\",\n    \"n_wind_speeds = 100\\n\",\n    \"wind_speeds = np.linspace(0.1, 30, n_wind_speeds)\\n\",\n    \"\\n\",\n    \"fmodel = FlorisModel(\\\"defaults\\\") # Defaults to NREL 5MW turbine\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_data=TimeSeries(\\n\",\n    \"        wind_directions=np.zeros(n_wind_speeds),\\n\",\n    \"        wind_speeds=wind_speeds,\\n\",\n    \"        turbulence_intensities=0.06\\n\",\n    \"    ),\\n\",\n    \"    layout_x=[0],\\n\",\n    \"    layout_y=[0],\\n\",\n    \"    wind_shear=0.0\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"powers = fmodel.get_turbine_powers()\\n\",\n    \"thrust_coefficients = fmodel.get_turbine_thrust_coefficients()\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots(2, 1, sharex=True)\\n\",\n    \"ax[0].plot(wind_speeds, powers)\\n\",\n    \"ax[0].grid()\\n\",\n    \"ax[0].set_ylabel(\\\"Power [kW]\\\")\\n\",\n    \"ax[1].plot(wind_speeds, thrust_coefficients)\\n\",\n    \"ax[1].grid()\\n\",\n    \"ax[1].set_ylabel(\\\"Thrust coefficient [-]\\\")\\n\",\n    \"ax[1].set_xlabel(\\\"Wind speed [m/s]\\\")\\n\",\n    \"ax[1].set_xlim([0, 30])\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"88d2ebce\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Prepackaged turbine models\\n\",\n    \"\\n\",\n    \"FLORIS ships with three reference wind turbine models: the NREL 5MW turbine\\n\",\n    \"{cite:t}`jonkman_NREL5MW_2009`,\\n\",\n    \"the IEA 10 MW turbine {cite:t}`kainz_IEA10MW_2024`, and the IEA 15 MW turbine\\n\",\n    \"{cite:t}`gaertner_IEA15MW_2020`. The\\n\",\n    \"turbine models used for FLORIS simulations can be changed by specifying the `turbine_type` keyword\\n\",\n    \"argument to `FlorisModel.set()`. See {ref}`turbine_library` for more details.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"7c1ec9ba\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"fig, ax = plt.subplots(2, 1, sharex=True)\\n\",\n    \"\\n\",\n    \"turbine_models = [\\\"nrel_5MW\\\", \\\"iea_10MW\\\", \\\"iea_15MW\\\"]\\n\",\n    \"\\n\",\n    \"for turbine_model in turbine_models:\\n\",\n    \"    fmodel.set(turbine_type=[turbine_model], reference_wind_height=-1)\\n\",\n    \"\\n\",\n    \"    fmodel.run()\\n\",\n    \"\\n\",\n    \"    powers = fmodel.get_turbine_powers()\\n\",\n    \"    thrust_coefficients = fmodel.get_turbine_thrust_coefficients()\\n\",\n    \"\\n\",\n    \"    ax[0].plot(wind_speeds, powers, label=turbine_model)\\n\",\n    \"    ax[1].plot(wind_speeds, thrust_coefficients)\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"ax[0].grid()\\n\",\n    \"ax[0].set_ylabel(\\\"Power [kW]\\\")\\n\",\n    \"ax[0].legend()\\n\",\n    \"ax[1].grid()\\n\",\n    \"ax[1].set_ylabel(\\\"Thrust coefficient [-]\\\")\\n\",\n    \"ax[1].set_xlabel(\\\"Wind speed [m/s]\\\")\\n\",\n    \"ax[1].set_xlim([0, 30])\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"bd2c8544\",\n   \"metadata\": {},\n   \"source\": [\n    \"## User-defined wind turbine models\\n\",\n    \"\\n\",\n    \"Users may also provide their own wind turbine models, provided that they contain the appropriate\\n\",\n    \"information. To include your own wind turbine model in your main FLORIS input YAML, use the\\n\",\n    \"`!include` specifier, e.g.\\n\",\n    \"```\\n\",\n    \"  turbine_type:\\n\",\n    \"  - !include path/to/your/turbine.yaml\\n\",\n    \"```\\n\",\n    \"\\n\",\n    \"You can also `set` the `turbine_type` to your own turbine using the path, e.g.\\n\",\n    \"```python\\n\",\n    \"fmodel.set(turbine_type=[\\\"path/to/your/turbine.yaml\\\"])\\n\",\n    \"```\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"cdd9ad19\",\n   \"metadata\": {},\n   \"source\": [\n    \"The following pages describe in closer detail how wind turbines are implemented in FLORIS and\\n\",\n    \"provide information on advanced wind turbine operation and modeling.\\n\",\n    \"\\n\",\n    \"```{note}\\n\",\n    \"The `TurbineInterface` and `TurbineLibrary` classes are now deprecated and will be removed in a\\n\",\n    \"future release. Users should simply use an instantiated `FlorisModel` to investigate wind turbine\\n\",\n    \"models.\\n\",\n    \"```\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"98fd51f6\",\n   \"metadata\": {},\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"floris\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.13.2\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}\n"
  },
  {
    "path": "docs/v3_to_v4.md",
    "content": "# Switching from FLORIS v3 to v4\n\nThere are several major changes introduced in FLORIS v4. The largest underlying change is that,\nwhere FLORIS v3 had a \"wind directions\" and a \"wind speeds\" dimension to its internal data\nstructures, FLORIS v4 collapses these into a single dimension, which we refer to as the `findex`\ndimension. This dimension contains each \"configuration\" or \"condition\" to be run, and is\nconceptually similar to running FLORIS v3 in `time_series` mode. At the user interface level, the\nlargest implication of this change is that users must specify `wind_directions`, `wind_speeds`, and\n`turbulence_intensities` (new) as arrays of equal length; and these are \"zipped\" to create the\nconditions for FLORIS to run, rather than creating a grid of all combinations. This is discussed\nfurther in [Setting and Running](#setting-and-running).\n\n## Setting and running\n\nIn FLORIS v3, users interacted with FLORIS by instantiating a `FlorisInterface` object, nominally\ncalled `fi`. The notion here is that the users \"interface\" with the underlying FLORIS code using\n`fi`. For FLORIS v4, we acknowledge that to most users, this main \"interface\" object, for all\nintents and purposes, _is FLORIS_. We therefore have renamed the `FlorisInterface` the\n`FlorisModel`, nominally instantiated as `fmodel`. To instantiate a `FlorisModel`, the code is\nvery similar to before, i.e.\n```python\nfrom floris import FlorisModel\n\nfmodel = FlorisModel(\"input_file.yaml\")\n```\n\nPreviously, to set the atmospheric conditions on `fi`, users called the `reinitialize()` method;\nand to run the calculations, as well as provide any control setpoints such as yaw angles, users\ngenerally called `calculate_wake()`. Some of the other methods on `FlorisInterface` also called\n`calculate_wake()` internally, most notably `get_farm_AEP()`.\n\nFor FLORIS v4, we have changed from the (`reinitialize()`, `calculate_wake()`) paradigm to a new\npair of methods (`set()`, `run()`). `set()` is similar to the retired `reinitialize()` method, and\n`run()` is similar to the retired `calculate_wake()` method. However, there are some important\ndifferences:\n- `FlorisModel.set()` accepts both atmospheric conditions _and_ control setpoints.\n- `FlorisModel.run()` accept no arguments. Its sole function is to run the FLORIS calculation.\n- Control setpoints are now \"remembered\". Previously, if control setpoints (`yaw_angles`) were\npassed to `calculate_wake()`, they were discarded at the end of the calculation. In FLORIS v4, the\ncontrol setpoints passed to `set()` are stored, and invoking `run()` multiple times will continue to\nuse those control setpoints.\n- To \"forget\" previously provided control setpoints, use the new method\n`FlorisModel.reset_operation()`.\n- When providing arguments to `set()`, all arguments much have the same length, as they will be\n\"paired\" (rather than gridded) for the computation. For instance, if the user provides `n_findex`\nwind directions, they _must_ provide `n_findex` wind speeds and `n_findex` turbulence intensities;\nas well as `n_findex`x`n_turbines` yaw angles, if yaw angles are being used.\n- Providing varying `turbulence_intensities` is new for FLORIS v4.\n- To facilitate \"easier\" use of the `set()` method (for instance, to run all combinations of\nwind directions and wind speeds), we now provide `WindData` objects that can be passed directly to\n`set()`'s `wind_data` keyword argument. See [Wind data](#wind-data) as well as\n[Wind Data Objects](wind_data_user) for more information.\n- `calculate_no_wake()` has been replaced with `run_no_wake()`\n- `get_farm_AEP()` no longer calls `run()`; to compute the farm AEP, users should `run()` the\n`fmodel` themselves before calling `get_farm_AEP()`.\n\nAn example workflow for using `set` and `run` is:\n```python\nimport numpy as np\nfrom floris import FlorisModel\n\nfmodel = FlorisModel(\"input_file.yaml\") # Input file with 3 turbines\n\n# Set up a base case and run\nfmodel.set(\n    wind_directions=np.array([270., 270.]),\n    wind_speeds=np.array([8.0, 8.0]),\n    turbulence_intensities=np.array([0.06, 0.06])\n)\nfmodel.run()\nturbine_powers_base = fmodel.get_turbine_powers()\n\n# Provide yaw angles\nfmodel.set(\n    yaw_angles=np.array([[10.0, 0.0, 0.0], [20.0, 0.0, 0.0]]) # n_findex x n_turbines\n)\nfmodel.run()\nturbine_powers_yawed = fmodel.get_turbine_powers()\n\n# If we run again, this time with no wake, the provided yaw angles will still be used\nfmodel.run_no_wake()\nturbine_powers_yawed_nowake = fmodel.get_turbine_powers()\n\n# To \"forget\" the yaw angles, we use the reset_operation method\nfmodel.reset_operation()\nfmodel.run_no_wake()\nturbine_powers_base_nowake = fmodel.get_turbine_powers()\n```\n\nFor more advanced users, it is best to group many conditions into single calls of `set` and `run`\nthan to step through various conditions individually, as this will make the best use of FLORIS's\nvectorization capabilities.\n\n## Input files\nAs in FLORIS v3, there are two main input files to FLORIS v4:\n1. The \"main\" FLORIS input yaml, which contains wake model parameters and wind farm data\n2. The \"turbine\" input yaml, which contains data about the wind turbines\n\nExamples for main FLORIS input yamls are in examples/inputs/. Default turbine yamls, which many\nusers\nmay use if they do not have their own turbine models to use, can be found in\nfloris/turbine_library/.\nSee also [Turbine Library Interface](input_reference_turbine) and\n[Main Input File Reference](input_reference_main).\n\nConceptually, both the main FLORIS input yaml and the turbine input yaml is much the same in v4 as\nin v3. However, there are a few changes to the fields on each that mean that existing yamls for v3\nwill not run in v4 as is.\n\n#### Main FLORIS input yaml\nOn the main FLORIS input file, the `turbulence_intensity` field (on`flow_field`),\nwhich was specified as a scalar in FLORIS v3, has been changed to `turbulence_intensities`, and\nshould now contain a list of turbulence intensities that is of the same length as `wind_directions`\nand `wind_speeds`. Additionally, the length of the lists for `wind_directions` and `wind_speeds`\n_must_ now be of equal length.\n\nIn addition, a new field `enable_active_wake_mixing` has been added to the `wake` field,\nwhich users may set to `false` unless they would like to use active wake mixing strategies such\nas [Helix](empirical_gauss_model.md#Added-mixing-by-active-wake-control).\n\n#### Turbine input yaml\nTo reflect the transition to more flexible [operation models](#operation-model), there are a\nnumber of changes to the fields on the turbine yaml. The changes are mostly regrouping and\nrenaming of the existing fields.\n- The `power_thrust_table` field now has `wind_speed` and `power` fields, as before; however,\nthe `thrust` field has been renamed `thrust_coefficient` for clarity, and the `power` field now\nspecifies the turbine _absolute_ power (in kW) rather than the _power coefficient_.\n- Additionally, any extra parameters and data required by operation models to evaluate the power\nand thrust curves have been moved onto the `power_thrust_table` field. This includes\n`ref_density_cp_ct` (renamed `ref_air_density` and moved onto the `power_thrust_table`);\n`ref_tilt_cp_ct` (renamed `ref_tilt` and moved onto the `power_thrust_table`); and `pP` and `pT`\n(renamed `cosine_loss_exponent_yaw` and `cosine_loss_exponent_tilt`, respectively, and moved onto\nthe `power_thrust_table`).\n- The `generator_efficiency` field has been removed. The `power` field on `power_thrust_table`\nshould reflect the electrical power produced by the turbine, including any losses.\n- A new field `operation_model` has been added, whose value should be a string that selects the\noperation model the user would like to evaluate. The default is `\"cosine-loss\"`,\nwhich recovers FLORIS v3-type turbine operation. See [Operation model](#operation-model) and\n[Turbine Operation Models](operation_models_user) for details.\n\n### Converting v3 yamls to v4\nTo aid users in converting their existing v3 main FLORIS input yamls and turbine input, we provide\ntwo utilities:\n- floris/tools/convert_floris_input_v3_to_v4.py\n- floris/tools/convert_turbine_v3_to_v4.py\n\nThese can be executed from the command line and expect to be passed the exiting v3 yaml as an input;\nthe will then write a new v4-compatible yaml of the same name but appended _v4.\n```bash\npython convert_floris_input_v3_to_v4.py your_v3_input_file.yaml\npython convert_floris_turbine_v3_to_v4.py your_v3_turbine_file.yaml\n```\n\nAdditionally, a function for building a turbine dictionary that can be passed directly to the\n`turbine_type` argument of `FlorisModel.set()` is provided:\n```python\nfrom floris.turbine_library.turbine_utilities import build_cosine_loss_turbine_dict\n```\n\n### Reference turbine updates\nThe power and thrust curves for the NREL 5MW, IEA 10MW, and IEA 15MW turbines have been updated\nslightly do reflect publicly available data. The x_20MW reference turbine has been removed, as data\nwas not readily available. See [Turbine Library Interface](turbine_interaction).\n\n## Wind data\nTo aid users in setting the wind conditions they are interested in running, we provide \"wind data\"\nclasses, which can be passed directly to `FlorisModel.set()`'s `wind_data` keyword argument in place\nof `wind_directions`, `wind_speeds`, and `turbulence_intensities`. The wind data objects enable,\nfor example, gridding inputs (`WindRose` and `WindTIRose`) and broadcasting a scalar-valued\nturbulence intensity (`TimeSeries`).\n```python\nimport numpy as np\nfrom floris import FlorisModel\nfrom floris import TimeSeries\n\nfmodel = FlorisModel(\"input_file.yaml\") # Input file with 3 turbines\n\ntime_series = TimeSeries(\n    wind_directions=np.array([270.0, 270.0]),\n    wind_speeds=8.0,\n    turbulence_intensities=0.06\n)\nfmodel.set(wind_data=time_series)\nfmodel.set(wind_data=time_series)turbine_powers_base = fmodel.get_turbine_powers()\nturbine_powers = fmodel.get_turbine_powers()\n```\n\nMore information about the various wind data classes can be found at\n[Wind Data Objects](wind_data_user).\n\n## Operation model\nFLORIS v4 allows for significantly more flexible turbine operation via\n[Turbine Operation Models](operation_models_user). These allow users to specify how a turbine loses\npower when yaw misaligned; how a turbine operates when derated; and how turbines produce power\nand thrust when operating with active wake mixing strategies. The default operation model is the\n`\"cosine-loss\"` model, which models a turbine's power loss when in yaw misalignment using the same\ncosine model as was hardcoded in FLORIS v3.\n"
  },
  {
    "path": "docs/wake_models.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Wake Models\\n\",\n    \"\\n\",\n    \"A wake model in FLORIS is made up of four components that together constitute a wake.\\n\",\n    \"At minimum, the velocity deficit profile behind a wind turbine is required. For most models,\\n\",\n    \"an additional wake deflection model is included to model the effect of yaw misalignment.\\n\",\n    \"Turbulence models are also available to couple with the deficit and deflection components.\\n\",\n    \"Finally, methods for combining wakes with the rest of the flow field are available.\\n\",\n    \"\\n\",\n    \"Computationally, the solver algorithm and grid-type supported by each wake model can also\\n\",\n    \"be considered as part of the model itself. As shown in the diagram below, the mathematical\\n\",\n    \"formulations can be considered as the main components of the model. These are typically\\n\",\n    \"associated directly to each other and in some cases they are bundled together into\\n\",\n    \"a single mathematical formulation. The solver algorithm and grid type are associated\\n\",\n    \"to the math formulation, but they are typically more generic.\\n\",\n    \"\\n\",\n    \"```{mermaid}\\n\",\n    \"flowchart LR\\n\",\n    \"    A[\\\"Deficit\\\"]\\n\",\n    \"    B[\\\"Deflection\\\"]\\n\",\n    \"    C[\\\"Turbulence\\\"]\\n\",\n    \"    D[\\\"Velocity\\\"]\\n\",\n    \"    E[\\\"Solver\\\"]\\n\",\n    \"    F[\\\"Grid\\\"]\\n\",\n    \"\\n\",\n    \"    subgraph H[FLORIS Wake Model]\\n\",\n    \"        direction LR\\n\",\n    \"        subgraph G[Math Model]\\n\",\n    \"            direction LR\\n\",\n    \"            A---B\\n\",\n    \"            B---C\\n\",\n    \"            C---D\\n\",\n    \"        end\\n\",\n    \"        G---E\\n\",\n    \"        E---F\\n\",\n    \"    end\\n\",\n    \"```\\n\",\n    \"\\n\",\n    \"The models in FLORIS are typically developed as a combination of velocity deficit and wake\\n\",\n    \"deflection models, and some also have custom turbulence and combination models. The descriptions\\n\",\n    \"below use the typical combinations except where indicated. The specific settings can be seen\\n\",\n    \"in the corresponding input files found in the source code dropdowns.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"from floris import FlorisModel\\n\",\n    \"import floris.flow_visualization as flowviz\\n\",\n    \"import floris.layout_visualization as layoutviz\\n\",\n    \"\\n\",\n    \"NREL5MW_D = 126.0\\n\",\n    \"\\n\",\n    \"def model_plot(inputfile, include_wake_deflection=True):\\n\",\n    \"    fig, axes = plt.subplots(1, 1, figsize=(10, 10))\\n\",\n    \"    yaw_angles = np.zeros((1, 2))\\n\",\n    \"    if include_wake_deflection:\\n\",\n    \"        yaw_angles[:,0] = 20.0\\n\",\n    \"    fmodel = FlorisModel(inputfile)\\n\",\n    \"    fmodel.set(\\n\",\n    \"        layout_x=np.array([0.0, 2*NREL5MW_D]),\\n\",\n    \"        layout_y=np.array([0.0, 2*NREL5MW_D]),\\n\",\n    \"        yaw_angles=yaw_angles,\\n\",\n    \"    )\\n\",\n    \"    horizontal_plane = fmodel.calculate_horizontal_plane(height=90.0)\\n\",\n    \"    flowviz.visualize_cut_plane(horizontal_plane, ax=axes, clevels=100)\\n\",\n    \"    layoutviz.plot_turbine_rotors(fmodel, ax=axes, yaw_angles=yaw_angles)\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Jensen and Jimenez\\n\",\n    \"\\n\",\n    \"The Jensen model computes the wake velocity deficit based on the classic Jensen/Park model\\n\",\n    \"{cite:t}`jensen1983note`. It is often refered to as a \\\"top-hat\\\" model because the spanwise\\n\",\n    \"velocity profile is constant across the wake and abruptly jumps to freestream outside of the\\n\",\n    \"wake boundary line. The slope of the wake boundary line, or wake expansion, is a user parameter.\\n\",\n    \"\\n\",\n    \"The Jiménez wake deflection model is derived from {cite:t}`jimenez2010application`.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"model_plot(\\\"../examples/inputs/jensen.yaml\\\")\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Gauss and GCH\\n\",\n    \"\\n\",\n    \"The Gaussian velocity model is implemented based on {cite:t}`bastankhah2016experimental` and\\n\",\n    \"{cite:t}`niayifar2016analytical`. This model represents the velocity deficity as a gaussian\\n\",\n    \"distribution in the spanwise direction, and the gaussian profile is controlled by user parameters.\\n\",\n    \"There is a near wake zone and a far wake zone. Both maintain the gaussian profile in the spanwise\\n\",\n    \"direction, but they have different models for wake recovery.\\n\",\n    \"\\n\",\n    \"The Gauss deflection model is a blend of the models described in\\n\",\n    \"{cite:t}`bastankhah2016experimental` and {cite:t}`King2019Controls` for calculating\\n\",\n    \"the deflection field in turbine wakes.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"model_plot(\\\"../examples/inputs/gch.yaml\\\")\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Empirical Gaussian\\n\",\n    \"\\n\",\n    \"FLORIS's \\\"empirical\\\" model has the same Gaussian wake shape as other popular FLORIS models.\\n\",\n    \"However, the models that describe the wake width and deflection have been reorganized to provide\\n\",\n    \"simpler tuning and data fitting.\\n\",\n    \"\\n\",\n    \"For more information, see {ref}`empirical_gauss_model`\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"model_plot(\\\"../examples/inputs/emgauss.yaml\\\")\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Cumulative Curl\\n\",\n    \"The cumulative curl model is an implementation of the model described in {cite:t}`bay_2022`,\\n\",\n    \"which itself is based on the cumulative model of {cite:t}`bastankhah_2021`\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"model_plot(\\\"../examples/inputs/cc.yaml\\\")\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## TurbOPark\\n\",\n    \"\\n\",\n    \"The TurbOPark model is designed to model long wakes from large wind farm clusters. It was originally presented as a “top-hat” model in {cite:t}`nygaard2020modelling` and was updated in {cite:t}`Pedersen_2022_turbopark2` to have a Gaussian profile. For the latter, Ørsted released the [Matlab code with documentation](https://github.com/OrstedRD/TurbOPark), which allows the verification of the implementation in FLORIS.\\n\",\n    \"\\n\",\n    \"The first implementation, the [`TurboparkVelocityDeficitModel`](https://github.com/NREL/floris/blob/main/floris/core/wake_velocity/turbopark.py), was released in [FLORIS v3.1](https://github.com/NREL/floris/releases/tag/v3.1). The second implementation, the [`TurboparkgaussVelocityDeficitModel`](https://github.com/NREL/floris/blob/main/floris/core/wake_velocity/turboparkgauss.py), was released in FLORIS v4.2 and shows a near-perfect match to the predictions of Ørsted’s Matlab implementation. As such, we will emphasize the use of the `TurboparkgaussVelocityDeficitModel` going forward, and suggest that new users use this model (by setting the `velocity_model` field of the FLORIS input file to `turboparkgauss` instead of the `TurboparkVelocityDeficitModel` (`velocity_model: turbopark`)) if they are interested in testing the TurbOPark model.\\n\",\n    \"\\n\",\n    \"The `TurboparkgaussVelocityDeficitModel` implementation was contributed by [Jasper Kreeft](https://github.com/JasperShell).\\n\",\n    \"\\n\",\n    \"Note that the original top-hat TurbOPark model ({cite:t}`nygaard2020modelling`) is _not_ available in FLORIS.\\n\",\n    \"\\n\",\n    \"The wakes as predicted by the `TurboparkgaussVelocityDeficit` model are demonstrated below.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"model_plot(\\\"../examples/inputs/turboparkgauss_cubature.yaml\\\", include_wake_deflection=False)\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Turbulence Models\\n\",\n    \"\\n\",\n    \"### Crespo-Hernandez\\n\",\n    \"\\n\",\n    \"CrespoHernandez is a wake-turbulence model that is used to compute additional variability introduced\\n\",\n    \"to the flow field by operation of a wind turbine. Implementation of the model follows the original\\n\",\n    \"formulation and limitations outlined in {cite:t}`crespo1996turbulence`.\\n\",\n    \"\\n\",\n    \"The default parameter values used in FLORIS for CrespoHernandez differ from those reported in {cite:t}`crespo1996turbulence` following subsequent calibration. However, {cite:t}`zehtabiyan_rezaie_CH_2023` argue that the sign of certain parameters are not physically consistent (and also misreported in subsequent literature). See the `CrespoHernandez` class docstring for more details.\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Wake Combination Models\\n\",\n    \"\\n\",\n    \"The wakes throughout the flow field need to be combined in a careful manner in order to\\n\",\n    \"accurately capture their coupled effects. A simple model is to simple add them,\\n\",\n    \"but this can result in negative velocities a few turbines into the farm. More careful\\n\",\n    \"methods are available within FLORIS and shown here.\\n\",\n    \"\\n\",\n    \"Each model is described below and its effects are plotted with two turbines in a line.\\n\",\n    \"These descriptions use the Jensen and Jimenez models since they highlight the differences\\n\",\n    \"in the combination models themselves.\\n\",\n    \"The upper plots show the turbine wakes individually to give a reference for the uncombined wake.\\n\",\n    \"The lower plots show both turbines along with their wakes combined with the chosen model.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def combination_plot(method: str):\\n\",\n    \"    X_UPSTREAM = 0.0\\n\",\n    \"    X_DOWNSTREAM = 5 * 126.0\\n\",\n    \"    X0_BOUND = -200\\n\",\n    \"    X1_BOUND = 1500\\n\",\n    \"\\n\",\n    \"    # Set the combination method\\n\",\n    \"    fmodel = FlorisModel(\\\"../examples/inputs/jensen.yaml\\\")\\n\",\n    \"    settings = fmodel.core.as_dict()\\n\",\n    \"    settings[\\\"wake\\\"][\\\"model_strings\\\"][\\\"combination_model\\\"] = method\\n\",\n    \"    fmodel = FlorisModel(settings)\\n\",\n    \"\\n\",\n    \"    # Plot two turbines individually\\n\",\n    \"    fig, axes = plt.subplots(1, 2, figsize=(10, 10))\\n\",\n    \"    fmodel.set(\\n\",\n    \"        layout_x=np.array([X_UPSTREAM]),\\n\",\n    \"        layout_y=np.zeros(1),\\n\",\n    \"        yaw_angles=np.array([[20.0]]),\\n\",\n    \"    )\\n\",\n    \"    horizontal_plane = fmodel.calculate_horizontal_plane(\\n\",\n    \"        height=90.0,\\n\",\n    \"        x_bounds=(X0_BOUND, X1_BOUND),\\n\",\n    \"    )\\n\",\n    \"    layoutviz.plot_turbine_rotors(fmodel, ax=axes[0])\\n\",\n    \"    flowviz.visualize_cut_plane(horizontal_plane, ax=axes[0], clevels=100)\\n\",\n    \"    layoutviz.plot_turbine_rotors(fmodel, ax=axes[1])\\n\",\n    \"\\n\",\n    \"    fmodel.set(\\n\",\n    \"        layout_x=np.array([X_DOWNSTREAM]),\\n\",\n    \"        layout_y=np.zeros(1),\\n\",\n    \"        yaw_angles=np.array([[0.0]]),\\n\",\n    \"    )\\n\",\n    \"    horizontal_plane = fmodel.calculate_horizontal_plane(\\n\",\n    \"        height=90.0,\\n\",\n    \"        x_bounds=(X0_BOUND, X1_BOUND),\\n\",\n    \"    )\\n\",\n    \"    flowviz.visualize_cut_plane(horizontal_plane, ax=axes[1], clevels=100)\\n\",\n    \"    layoutviz.plot_turbine_rotors(fmodel, ax=axes[0])\\n\",\n    \"    layoutviz.plot_turbine_rotors(fmodel, ax=axes[1])\\n\",\n    \"\\n\",\n    \"    # Plot the combination of turbines\\n\",\n    \"    fig, axes = plt.subplots(1, 1, figsize=(10, 10))\\n\",\n    \"    fmodel.set(\\n\",\n    \"        layout_x=np.array([X_UPSTREAM, X_DOWNSTREAM]),\\n\",\n    \"        layout_y=np.zeros(2),\\n\",\n    \"        yaw_angles=np.array([[20.0, 0.0]]),\\n\",\n    \"    )\\n\",\n    \"    horizontal_plane = fmodel.calculate_horizontal_plane(\\n\",\n    \"        height=90.0,\\n\",\n    \"        x_bounds=(X0_BOUND, X1_BOUND),\\n\",\n    \"    )\\n\",\n    \"    flowviz.visualize_cut_plane(horizontal_plane, ax=axes, clevels=100)\\n\",\n    \"    layoutviz.plot_turbine_rotors(fmodel, ax=axes)\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Freestream Linear Superposition (FLS)\\n\",\n    \"\\n\",\n    \"FLS uses freestream linear superposition to apply the wake velocity deficits to the freestream\\n\",\n    \"flow field.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"combination_plot(\\\"fls\\\")\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Max\\n\",\n    \"\\n\",\n    \"The MAX model incorporates the velocity deficits into the base flow field by selecting the\\n\",\n    \"maximum of the two for each point. For more information, refer to {cite:t}`gunn2016limitations`.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"combination_plot(\\\"max\\\")\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Sum of Squares Freestream Superposition (SOSFS)\\n\",\n    \"\\n\",\n    \"This model combines the wakes via a sum of squares of the new wake to add and the existing flow field. For more information, refer to :cite:`katic_sos_1986`.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"combination_plot(\\\"sosfs\\\")\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.10.6\"\n  },\n  \"orig_nbformat\": 4\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"
  },
  {
    "path": "docs/wind_data_user.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Wind Data Objects\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"FLORIS v4 introduces WindData objects.  These include TimeSeries, WindRose, and WindTIRose.  These objects are used to hold inputs to FLORIS simulations, such as the ambient wind data, and to provide high-level methods for working with wind data.  This notebook provides an overview of the WindData objects and demonstrates how to use them.\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## WindDataBase\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"WindDataBase is the base class for all WindData objects.  It provides a common interface for working with wind data.  The WindDataBase class is not intended to be used directly, but rather to be subclassed by more specific wind data objects. It is only important to mention that many of the methods in FLORIS that accept wind data as input will accept any WindDataBase object as input.  But is not typical to use it directly.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from floris.wind_data import WindDataBase\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"import numpy as np\\n\",\n    \"import warnings\\n\",\n    \"\\n\",\n    \"warnings.simplefilter(\\\"ignore\\\")\\n\",\n    \"\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## TimeSeries\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"TimeSeries objects are used to represent data which are in a time-series form, or more generally and data which is represented as a list of conditions without frequency weighting (i.e. not a wind rose).  In addition to representing time series input conditions, TimeSeries objects are useful for generating sweep inputs where most values are held constant while one input is swept through a range of values.  Also useful can be an input of identical repeated inputs which can be useful if some control setting is going to be swept.  TimeSeries represents data most similarly to how data structures within FLORIS are represented in that there are N wind_directions, wind_speeds etc., in the TimeSeries, the n_findex value in FLORIS will be N.\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### TimeSeries Instantiation\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from floris import TimeSeries\\n\",\n    \"\\n\",\n    \"# Like FlorisModel, TimeSeries require wind directions, wind speeds, and turbulence intensities to be of the same length.\\n\",\n    \"N = 50\\n\",\n    \"wind_speeds = np.linspace(3, 15, N)\\n\",\n    \"wind_directions = 270.0 * np.ones(N)\\n\",\n    \"turbulence_intensities = 0.06 * np.ones(N)\\n\",\n    \"\\n\",\n    \"# Create a TimeSeries object\\n\",\n    \"time_series = TimeSeries(\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities,\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Broadcasting\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Unlike FlorisModel, TimeSeries objects do allow broadcasting.  As long as one of the inputs is a numpy array, the other inputs can be specified as a float, which will be broadcasted to the length of the numpy array.\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Equivalent to the above\\n\",\n    \"time_series = TimeSeries(\\n\",\n    \"    wind_directions=270.0, wind_speeds=wind_speeds, turbulence_intensities=0.06\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Value\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"In addition to wind directions, wind speeds, and turbulence intensities, TimeSeries objects can also hold an array of values.  These values can be used for example to represent electricity market prices (e.g., price/MWh). The values are intended to be multiplied by the corresponding wind plant power at each time step or wind condition to determine the total value produced over all conditions.    \\n\",\n    \"\\n\",\n    \"If values are included in the TimeSeries object, they must be the same length as the wind directions, wind speeds, and turbulence intensities.  If included, values enable calculation of Annual Value Production (AVP), in addition to AEP, and certain optimization routines, such as layout, can be configured to maximize value instead of energy production.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Including value for each indices\\n\",\n    \"time_series = TimeSeries(\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities,\\n\",\n    \"    values=np.linspace(0, 1, N),\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Generating Turbulence Intensity\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"The TimeSeries object also includes functions for generating TI as a function of wind direction and wind speed.  This can be accomplished by passing in a custom function, or by taking use of the IEC 61400-1 standard \"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"Text(0, 0.5, 'Turbulence Intensity')\"\n      ]\n     },\n     \"execution_count\": 5,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"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nFasWKFx48Zp3759CgsLqzH+888/15QpU5SSkqLrrrtO69ev16RJk5Sdna2YmBhJUmJiorZv365169YpKipKW7du1T333KMuXbro+uuvd/dHBOCl6qoTqrQYbKcHWjCTYRge7fseFxenoUOHauXKlZIki8WiyMhIzZkzRwsWLKgxfvLkySotLdX7779vvXbllVcqNjbWOssTExOjyZMna+HChdYxgwcP1oQJE/T444/XG1NJSYlCQ0NVXFyskJCQxn5EAM1U9aGqkv1lsnkJfercTl/trbuuZDs94AbO/H57dAmsoqJCe/bsUUJCgvWan5+fEhISlJmZafc1mZmZNuMlady4cTbjhw8frvfee09HjhyRYRhKT0/Xt99+q7Fjx9q9Z3l5uUpKSmz+AIDt9EDL5dElsOPHj6uyslLh4eE218PDw/XNN9/YfU1BQYHd8QUFBdbHL7zwgv77v/9b3bp1U6tWreTn56e1a9dq5MiRdu+ZkpKi5OTkRn4aAC2RJ7bTs1QGND2P1wA1hRdeeEE7d+7Ue++9p+7du+vjjz/Wvffeqy5dutSYPZKkpKQkJSYmWh+XlJQoMjLSnSED8GLu3E7PjjLAPTy6BNapUyf5+/ursLDQ5nphYaHMZvs7MMxmc53jf/75Zz388MN65plnNHHiRF1xxRWaPXu2Jk+erOXLl9u9Z2BgoEJCQmz+AKA+1dvppV/qgqpduJ3eEdXb6VkqA9zDowlQQECABg8erLS0NOs1i8WitLQ0xcfH231NfHy8zXhJ2rZtm3X8uXPndO7cOfn52X40f39/WSwWF38CAL7OVdvpO7UNVPKWvFqXyqSqpbJKS9WjSouhzP0ntDnniDL3n7BeB+AYjy+BJSYmavr06RoyZIiGDRumFStWqLS0VDNmzJAkTZs2TV27dlVKSookae7cuRo1apSefvppXXvttdqwYYN2796tl156SZIUEhKiUaNG6aGHHlKbNm3UvXt37dixQ2+++aaeeeYZj31OAC1XY7fTm0ODJJNqzPxciANaAdfyeAI0efJkHTt2TIsWLVJBQYFiY2OVmppqLXQ+dOiQzWzO8OHDtX79ej3yyCN6+OGH1adPH7377rvWHkCStGHDBiUlJem2227TyZMn1b17dz3xxBO6++673f75APiG2uqEHOk6vXhitI6fKXfofbblFei1z36okUxV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3HbbbR6KyDtJMt555x3rY4vFYpjNZmPZsmXWaz/99JMRGBhovPXWWx6I0Ltc/H3Zk5WVZUgyfvzxR/cE5aVq+67+/e9/G127djVyc3ON7t27G88++6zbY/MmzABB9957r6699lolJCR4OhSv9d5772nIkCG6+eabFRYWpoEDB2rt2rWeDssrDR8+XGlpafr2228lSXv37tWnn36qCRMmeDgy73bw4EEVFBTY/HcYGhqquLg4ZWZmejCy5qO4uFgmk0nt27f3dChex2Kx6Pbbb9dDDz2kfv36eTocr8BhqD5uw4YNys7O1q5duzwdilc7cOCAVq9ercTERD388MPatWuX7rvvPgUEBGj69OmeDs+rLFiwQCUlJerbt6/8/f1VWVmpJ554QrfddpunQ/NqBQUFkqTw8HCb6+Hh4dbnULuysjLNnz9fU6ZM8ZlDP52xdOlStWrVSvfdd5+nQ/EaJEA+7PDhw5o7d662bdumoKAgT4fj1SwWi4YMGaInn3xSkjRw4EDl5uZqzZo1JEAX+etf/6q//OUvWr9+vfr166ecnBzNmzdPXbp04btCkzh37pxuueUWGYah1atXezocr7Nnzx4999xzys7Olslk8nQ4XoMlMB+2Z88eFRUVadCgQWrVqpVatWqlHTt26Pnnn1erVq1UWVnp6RC9RkREhKKjo22u/frXv9ahQ4c8FJH3euihh7RgwQLdeuut6t+/v26//Xbdf//9SklJ8XRoXs1sNkuSCgsLba4XFhZan0NN1cnPjz/+qG3btjH7Y8cnn3yioqIiXXbZZdb/rf/xxx/1wAMPKCoqytPheQwzQD7sN7/5jf71r3/ZXJsxY4b69u2r+fPny9/f30OReZ+rrrpK+/bts7n27bffqnv37h6KyHudPXtWfn62/9/K399fFovFQxE1Dz169JDZbFZaWppiY2MlSSUlJfriiy80a9YszwbnpaqTn++++07p6enq2LGjp0PySrfffnuNGs9x48bp9ttv14wZMzwUleeRAPmw4OBgxcTE2Fxr27atOnbsWOO6r7v//vs1fPhwPfnkk7rllluUlZWll156SS+99JKnQ/M6EydO1BNPPKHLLrtM/fr105dffqlnnnlGd955p6dD87gzZ87o+++/tz4+ePCgcnJy1KFDB1122WWaN2+eHn/8cfXp00c9evTQwoUL1aVLF02aNMlzQXtQXd9XRESE/vM//1PZ2dl6//33VVlZaa2V6tChgwICAjwVtkfU9+/Wxclh69atZTabdfnll7s7VO/h6W1o8C5sg6/dli1bjJiYGCMwMNDo27ev8dJLL3k6JK9UUlJizJ0717jsssuMoKAgo2fPnsb//M//GOXl5Z4OzePS09MNSTX+pk+fbhhG1Vb4hQsXGuHh4UZgYKDxm9/8xti3b59ng/agur6vgwcP2n1OkpGenu7p0N2uvn+3LsY2eMMwGQbtWQEAgG+hCBoAAPgcEiAAAOBzSIAAAIDPIQECAAA+hwQIAAD4HBIgAADgc0iAAACAzyEBAgAAPocECIDTMjIyZDKZ9NNPPzXqPnfccUezPubh6quv1rx58+odN3LkSK1fv77pA7rArbfeqqefftqt7wk0JyRAgA9bs2aNgoODdf78eeu1M2fOqHXr1rr66qttxlYnPfv379fw4cOVn5+v0NDQJo9x7dq1GjBggNq1a6f27dtr4MCBzepk+ffee0+FhYW69dZbXXK/N954QyNGjKh33COPPKInnnhCxcXFLnlfoKUhAQJ82DXXXKMzZ85o9+7d1muffPKJzGazvvjiC5WVlVmvp6en67LLLlOvXr0UEBAgs9ksk8nUpPG9+uqrmjdvnu677z7l5OTos88+0x/+8AedOXOmSd/XlZ5//nnNmDFDfn6u+Z/bzZs36/rrr693XExMjHr16qV169a55H2BloYECPBhl19+uSIiIpSRkWG9lpGRoRtuuEE9evTQzp07ba5fc8011n++cAns9ddfV/v27fWPf/xDv/71r9WuXTuNHz9e+fn51tdXVlYqMTFR7du3V8eOHfWHP/xB9R1F+N577+mWW27RzJkz1bt3b/Xr109TpkzRE088YR1TvYyWnJyszp07KyQkRHfffbcqKiqsYywWi1JSUtSjRw+1adNGAwYM0N/+9jeb98rNzdWECRPUrl07hYeH6/bbb9fx48etz5eWlmratGlq166dIiIiHFpeOnbsmLZv366JEyfaXDeZTHrxxRd13XXX6ZJLLtGvf/1rZWZm6vvvv9fVV1+ttm3bavjw4dq/f7/N68rKyrR161ZrAvSnP/1Jffr0UVBQkMLDw/Wf//mfNuMnTpyoDRs21Bsn4ItIgAAfd8011yg9Pd36OD09XVdffbVGjRplvf7zzz/riy++sCZA9pw9e1bLly/Xn//8Z3388cc6dOiQHnzwQevzTz/9tF5//XW9+uqr+vTTT3Xy5Em98847dcZmNpu1c+dO/fjjj3WOS0tL09dff62MjAy99dZb2rRpk5KTk63Pp6Sk6M0339SaNWv01Vdf6f7779fUqVO1Y8cOSdJPP/2k0aNHa+DAgdq9e7dSU1NVWFioW265xXqPhx56SDt27NDmzZu1detWZWRkKDs7u864Pv30U2uCc7HHHntM06ZNU05Ojvr27avf//73+n//7/8pKSlJu3fvlmEYmj17do3P2bVrV/Xt21e7d+/Wfffdpz/+8Y/at2+fUlNTNXLkSJvxw4YNU1ZWlsrLy+uME/BJnj2MHoCnrV271mjbtq1x7tw5o6SkxGjVqpVRVFRkrF+/3hg5cqRhGIaRlpZmSDJ+/PFHwzAMIz093ZBknDp1yjAMw3jttdcMScb3339vve+qVauM8PBw6+OIiAjjqaeesj4+d+6c0a1bN+OGG26oNbajR48aV155pSHJ+NWvfmVMnz7d2Lhxo1FZWWkdM336dKNDhw5GaWmp9drq1auNdu3aGZWVlUZZWZlxySWXGJ9//rnNvWfOnGlMmTLFMAzDeOyxx4yxY8faPH/48GFDkrFv3z7j9OnTRkBAgPHXv/7V+vyJEyeMNm3aGHPnzq01/meffdbo2bNnjeuSjEceecT6ODMz05BkvPLKK9Zrb731lhEUFGTzurvuust48MEHDcMwjP/93/81QkJCjJKSklrff+/evYYk44cffqh1DOCrWnku9QLgDa6++mqVlpZq165dOnXqlH71q1+pc+fOGjVqlGbMmKGysjJlZGSoZ8+euuyyy2q9zyWXXKJevXpZH0dERKioqEiSVFxcrPz8fMXFxVmfb9WqlYYMGVLnMlhERIQyMzOVm5urjz/+WJ9//rmmT5+ul19+Wampqda6mgEDBuiSSy6xvi4+Pl5nzpzR4cOHdebMGZ09e1ZjxoyxuXdFRYUGDhwoSdq7d6/S09PVrl27GjHs379fP//8syoqKmzi79Chgy6//PJaY5eqZs6CgoLsPnfFFVdY/zk8PFyS1L9/f5trZWVlKikpUUhIiAzD0JYtW/TXv/5VkjRmzBh1795dPXv21Pjx4zV+/Hj97ne/s/ke2rRpI6lqdg6ALRIgwMf17t1b3bp1U3p6uk6dOqVRo0ZJkrp06aLIyEh9/vnnSk9P1+jRo+u8T+vWrW0em0ymemt8HBUTE6OYmBjdc889uvvuu/Uf//Ef2rFjR51LctWqC6Y/+OADde3a1ea5wMBA65iJEydq6dKlNV4fERGh77//vkFxd+rUSadOnbL73IXfV3Uxub1rFotFkpSVlaXz589r+PDhkqTg4GBlZ2crIyNDW7du1aJFi/Too49q165dat++vSTp5MmTkqTOnTs3KH6gJaMGCICuueYaZWRkKCMjw2b7+8iRI/X3v/9dWVlZDiUbtQkNDVVERIS++OIL67Xz589rz549Tt8rOjpaUlVRcrW9e/fq559/tj7euXOn2rVrp8jISEVHRyswMFCHDh1S7969bf4iIyMlSYMGDdJXX32lqKioGmPatm2rXr16qXXr1jbxnzp1St9++22dsQ4cOFAFBQW1JkHO2Lx5s6699lr5+/tbr7Vq1UoJCQl66qmn9M9//lM//PCDtm/fbn0+NzdX3bp1U6dOnRr9/kBLwwwQAF1zzTW69957de7cOesMkCSNGjVKs2fPVkVFRaMSIEmaO3eulixZoj59+qhv37565pln6m2kOGvWLHXp0kWjR49Wt27dlJ+fr8cff1ydO3dWfHy8dVxFRYVmzpypRx55RD/88IMWL16s2bNny8/PT8HBwXrwwQd1//33y2KxaMSIESouLtZnn32mkJAQTZ8+Xffee6/Wrl2rKVOm6A9/+IM6dOig77//Xhs2bNDLL7+sdu3aaebMmXrooYfUsWNHhYWF6X/+53/q3do+cOBAderUSZ999pmuu+66Rn1/7733nv74xz9aH7///vs6cOCARo4cqUsvvVQffvihLBaLzbLcJ598orFjxzbqfYGWigQIgK655hr9/PPP6tu3r7UeRapKgE6fPm3dLt8YDzzwgPLz8zV9+nT5+fnpzjvv1O9+97s6G/UlJCTo1Vdf1erVq3XixAl16tRJ8fHxSktLU8eOHa3jfvOb36hPnz4aOXKkysvLNWXKFD366KPW5x977DF17txZKSkpOnDggNq3b69Bgwbp4YcfllS13PfZZ59p/vz5Gjt2rMrLy9W9e3eNHz/emuQsW7bMulQWHBysBx54oN4mg/7+/poxY4b+8pe/NCoB2r9/v77//nuNGzfOeq19+/batGmTHn30UZWVlalPnz5666231K9fP0lVW+bfffddpaamNvh9gZbMZLhqkR4APOCOO+7QTz/9pHfffdfTodhVUFCgfv36KTs7W927d2/QPZ555hl99NFH+vDDDx1+zerVq/XOO+9o69atDXpPoKWjBggAmpDZbNYrr7yiQ4cONfge3bp1U1JSklOvad26tV544YUGvyfQ0jEDBKBZ8/YZIADeiQQIAAD4HJbAAACAzyEBAgAAPocECAAA+BwSIAAA4HNIgAAAgM8hAQIAAD6HBAgAAPgcEiAAAOBz/j/TR8Zlo0gdzQAAAABJRU5ErkJggg==\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Assign TI as a function of wind speed using the IEC method and default parameters.\\n\",\n    \"time_series.assign_ti_using_IEC_method()\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots()\\n\",\n    \"ax.scatter(time_series.wind_speeds, time_series.turbulence_intensities)\\n\",\n    \"ax.set_xlabel(\\\"Wind Speed (m/s)\\\")\\n\",\n    \"ax.set_ylabel(\\\"Turbulence Intensity\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Generating Value\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"The TimeSeries object also includes functions for generating value as a function of wind direction and wind speed. This can be accomplished by passing in a custom function using the `TimeSeries.assign_value_using_wd_ws_function` method, or by using the `TimeSeries.assign_value_piecewise_linear` method, which approximates value using a two-segment piecewise linear function of wind speed. When using the default parameters, this produces a value vs. wind speed that approximates the normalized mean electricity price vs. wind speed curve for the SPP market in the U.S. for years 2018-2020 from figure 7 in \\\"The value of wake steering wind farm flow control in US energy markets,\\\" Wind Energy Science, 2024. https://doi.org/10.5194/wes-9-219-2024. \"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"Text(0, 0.5, 'Value (normalized price/MWh)')\"\n      ]\n     },\n     \"execution_count\": 6,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"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X7+OLl26aPzL398fANCvXz+cP38eHTt2rDOmZcuW6Ny5M+zt7TXqv3fvHq5cudJgrX379kV+fr7WBkeKvXv3YuzYsbC1tVUfs7Ozw6hRo7Bq1Sr873//w9WrV3H48GH1+1lZWWjXrh08PT2b/ftEloRXboisQEhICF5//XUoFAr1lRsAGD58OGJiYlBVVdWs5gYAZs2ahffffx9du3ZFt27dsGbNmkZDAGfOnAlfX1+MHDkS7dq1Q15eHt599120bdsWwcHB6nFVVVV45ZVXsGjRIly9ehXx8fGIiYmBjY0NXF1dMXfuXMyZMwdKpRJDhw5FUVERfvjhB7i5uSEqKgqvv/46Nm/ejMjISMybNw8eHh7Izs7Gjh078Omnn8LFxQWvvPIK3nrrLbRp0wZeXl5YuHBho9u7+/btC09PT/zwww945plnmjV/+/btw7Jly9Sv/+///g+//fYbhg0bhtatW+PAgQNQKpUat8qOHz+OsLCwZv0ukSVic0NkBUJCQvDgwQN069ZNvf4DqGluSkpK1FvGm+PNN99EXl4eoqKiYGNjg2nTpuG5555rMGRu1KhRSEpKwsaNG3H37l14enoiODgYqampaNOmjXrcU089ha5du2LYsGGorKxEZGQkli5dqn7/nXfeQdu2bbFixQr89ttvaNWqFfr164e3334bQM0tuB9++AHz589HWFgYKisr0aFDB4wePVrdwHzwwQfq21eurq548803Gw3Is7W1RXR0NL788stmNTc5OTnIzs5GeHi4+lirVq2wa9cuLF26FBUVFejatSu2b9+OHj16AKjZNr5nzx4kJyc3+XeJLJVM0NVNcyIiPXj55Zdx//597Nmzx9il1Cs/Px89evRAZmYmOnTo0KTvWLNmDQ4dOoQDBw6I/szGjRuxe/duHDx4sEm/SWTJuOaGiKgZ5HI5/v3vf+P69etN/o527dohLi5O0mfs7e3x8ccfN/k3iSwZr9wQkUkz9Ss3RGR62NwQERGRReFtKSIiIrIobG6IiIjIorC5ISIiIovC5oaIiIgsCpsbIiIisihsboiIiMiisLkhIiIii8LmhoiIiCzK/wfRRPOhs/f7fgAAAABJRU5ErkJggg==\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Assign value as a function of wind speed using the piecewise linear method and default parameters.\\n\",\n    \"time_series.assign_value_piecewise_linear()\\n\",\n    \"\\n\",\n    \"fig, ax = plt.subplots()\\n\",\n    \"ax.scatter(time_series.wind_speeds, time_series.values)\\n\",\n    \"ax.grid()\\n\",\n    \"ax.set_xlabel(\\\"Wind Speed (m/s)\\\")\\n\",\n    \"ax.set_ylabel(\\\"Value (normalized price/MWh)\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## WindRose\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"A second wind data object is the WindRose, which represents the data as:\\n\",\n    \"\\n\",\n    \" - An array of wind directions\\n\",\n    \" - An array of wind speeds\\n\",\n    \" - A table of turbulence intensities of size (n_wind_directions, n_wind_speeds) which represents the TI at each wind direction and wind speed.\\n\",\n    \" - A table of frequencies of size (n_wind_directions, n_wind_speeds) which represents the frequency of occurance of each wind direction and wind speed.\\n\",\n    \" - An (optional) table of values of size (n_wind_directions, n_wind_speeds) which represents the value of the wind condition.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"array([[0.16666667, 0.16666667, 0.16666667],\\n\",\n       \"       [0.16666667, 0.16666667, 0.16666667]])\"\n      ]\n     },\n     \"execution_count\": 7,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"from floris import WindRose\\n\",\n    \"\\n\",\n    \"wind_directions = np.array([270, 280])  # 2 Wind Directions\\n\",\n    \"wind_speeds = np.array([6.0, 7.0, 8.0])  # 3 Wind Speeds\\n\",\n    \"\\n\",\n    \"# Create a WindRose object, not indicating a frequency table indicates uniform frequency\\n\",\n    \"wind_rose = WindRose(\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    ti_table=0.06,  # As in Time Series, a float indicates a constant table\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"wind_rose.freq_table\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"wind_rose.ti_table\\n\",\n      \"[[0.09683333 0.0905     0.08575   ]\\n\",\n      \" [0.09683333 0.0905     0.08575   ]]\\n\",\n      \"\\n\",\n      \"wind_rose.value_table\\n\",\n      \"[[1.2225 1.0875 0.9525]\\n\",\n      \" [1.2225 1.0875 0.9525]]\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# Several of the functions implemented for TimeSeries are likewise implemented for WindRose\\n\",\n    \"\\n\",\n    \"wind_rose.assign_ti_using_IEC_method()\\n\",\n    \"\\n\",\n    \"print(\\\"wind_rose.ti_table\\\")\\n\",\n    \"print(wind_rose.ti_table)\\n\",\n    \"\\n\",\n    \"wind_rose.assign_value_piecewise_linear()\\n\",\n    \"\\n\",\n    \"print(\\\"\\\\nwind_rose.value_table\\\")\\n\",\n    \"print(wind_rose.value_table)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## WindTIRose\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"The WindTIRose is similar to the WindRose except that rather than specififying wind directions and wind speeds as arrays, with TI, frequency, adn value as 2D tables, the WindTIRose specificies wind directions, wind speeds, and turbulence intensities as arrays with the frequency and value tables now 3 dimensional, representing the frequency and value of each wind direction, wind speed, and turbulence intensity occurence.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 9,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from floris import WindTIRose\\n\",\n    \"\\n\",\n    \"wind_directions = np.array([270, 280])  # 2 Wind Directions\\n\",\n    \"wind_speeds = np.array([6.0, 7.0, 8.0])  # 3 Wind Speeds\\n\",\n    \"turbulence_intensities = np.array([0.06, 0.07, 0.08])  # 3 Turbulence Intensities\\n\",\n    \"\\n\",\n    \"# The frequency table therefore is 2 x 3 x 3 and the sum over all entries = 1\\n\",\n    \"freq_table = np.array(\\n\",\n    \"    [\\n\",\n    \"        [[2 / 18, 0, 1 / 18], [1 / 18, 1 / 18, 1 / 18], [1 / 18, 1 / 18, 1 / 18]],\\n\",\n    \"        [[1 / 18, 1 / 18, 1 / 18], [1 / 18, 1 / 18, 1 / 18], [1 / 18, 1 / 18, 1 / 18]],\\n\",\n    \"    ]\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# The value table has the same dimensions as frequency\\n\",\n    \"value_table = np.ones_like(freq_table)\\n\",\n    \"\\n\",\n    \"wind_ti_rose = WindTIRose(\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities,\\n\",\n    \"    freq_table=freq_table,\\n\",\n    \"    value_table=value_table,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Demonstrate setting value again\\n\",\n    \"wind_ti_rose.assign_value_piecewise_linear()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Conversions\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Several methods for converting between WindData objects and resampling to different bin sizes are provided\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 10,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Converting from TimeSeries to WindRose/WindTiRose by binning\\n\",\n    \"wind_rose = time_series.to_WindRose(wd_step=2, ws_step=1)\\n\",\n    \"wind_ti_rose = time_series.to_WindTIRose(wd_step=2, ws_step=1, ti_step=0.01)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### Aggregating and Resampling WindRose\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 11,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"<PolarAxes: >\"\n      ]\n     },\n     \"execution_count\": 11,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"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hQuBE5/5Dz/8kFtvvfWUZdiVlZVs27aN1atX4+joyKFDh3jooYdISUkhPDx8Ct4tEZHZgShARLRGEAR+/vlnNmzYwPHjx3nmmWe4+eabp8zrMDg4SGNjI/X19fT09GgSSF1cXERPxyxGJpPh7u6Ou7s7w8PDNDU10dDQQFFRES4uLnh6eiKXy09bj+Xaa6+ltbWVJ554AoVCQUREBD///LMmMbWurm5MsbimpiYiIyM1vysUCuBE2GbFihVccMEFPP/889TX11NXV8cdd9xxypgmJibs2rVLI3a8vLy46qqreOyxx3T91oiIzCrEUuwiWvHbb7/xyCOPcPjwYf7+979zzz33YGZmpvNxBEGgtbWVmpoaFAoFjo6OeHp64u7uPi0qpBqKiZZin0309/drvGADAwN4eXnh6+s7ZaWrFQoFzz33HO+//z433HADTz31FF5eXlMylsjMQizFrhumV91okWlHWVkZV155JStWrGDRokVUVVWxbt06nYuPoaEhysvL2bVrF/n5+VhbW7NixQqSkpLw8fE5byddkf/DwsKCoKAgli5dSkJCAkqlkj179rBnzx7q6urGVCvVBXK5nDfffJOioiIGBgYIDg5m/fr1dHR06HQcEZHzFTEEI3Jaent7ee6553j99de57bbbOHr06JRUeezo6KC6uprGxkYcHBwIDQ1FLpdPu54qItMHiUSiqcwaGhpKfX09FRUVFBcX4+Pjg5+fn06X9AYEBLBt2zYKCgp4+OGHCQ4OZvPmzdx6663i51REZBKIAkRkDIIg8J///Id169bh6+tLVlYWCxYs0PkYTU1NVFZW0t3djbe3N0uWLBG7mIqMGxMTEwICAvD396etrY2qqip27dqFq6srgYGBY8rHT5bIyEh++eUXvv32Wx588EHeffdd3nrrrXEXMxMRETmBKEBENJSWlnL//fdTVFTECy+8wE033aTTFSZKpZL6+nqOHj2KSqUiICCAhIQEMbwiMmkkEgnOzs44OzvT399PdXU1mZmZ2NvbM2fOHJydnXXyWZZIJFxxxRWsWrWK559/nuTkZG6//Xaee+65MWXpRUREzo3oPxSht7eXhx9+mKioKObPn09ZWRk333yzzsTHyMgIR48eZdeuXVRVVREcHMyKFSsICAgQxYeIzrGwsCA0NJSVK1fi5OREXl4eGRkZNDY2oqucewsL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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 2 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Generate a wind rose with a few wind directions and speeds\\n\",\n    \"wind_directions = np.array([260, 265, 270, 275, 280, 285, 290])\\n\",\n    \"wind_speeds = np.array([6.0, 7.0, 8.0, 9.0])\\n\",\n    \"freq_table = np.random.rand(7, 4)\\n\",\n    \"freq_table /= freq_table.sum()\\n\",\n    \"\\n\",\n    \"wind_rose = WindRose(\\n\",\n    \"    wind_directions=wind_directions, wind_speeds=wind_speeds, ti_table=0.06, freq_table=freq_table\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"wind_rose.plot()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 12,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"<PolarAxes: >\"\n      ]\n     },\n     \"execution_count\": 12,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAAikAAAHVCAYAAAA0K2vhAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOydd1gUB/7/X7tL7wjC0nsXAWkKCBbUNNPv0k1ySS6Xdt+cqaaZS3JR085075JLzKVdyqUXTUSxIh1Ueu9L753d+f3hjz03gALCLui8nmcedWZ25rPr7sx7PlUiCIKAiIiIiIiIiMgcQ6prA0RERERERERExkMUKSIiIiIiIiJzElGkiIiIiIiIiMxJRJEiIiIiIiIiMicRRYqIiIiIiIjInEQUKSIiIiIiIiJzElGkiIiIiIiIiMxJRJEiIiIiIiIiMicRRYqIiIiIiIjInEQUKSIiIiIiIiJzElGkiIjMUW655RYkEglbt27VWP/NN98gkUh0ZJWIiIiI9hBFiojIHMbIyIht27bR3t6ua1NEREREtI4oUkRE5jCJiYnI5XK2bNmia1NEREREtI4oUkRE5jAymYznn3+e119/ndraWl2bIyIiIqJVRJEiIjLHueKKKwgNDWXz5s26NkVEREREq4giRURkHrBt2zY++OADCgoKdG2KiIiIiNYQRYqIyDwgPj6edevWsWnTJl2bIiIiIqI19HRtgIiIyOTYunUroaGh+Pn56doUEREREa0gelJEROYJwcHB3HDDDbz22mu6NkVEREREK4giRURkHvHMM8+gUql0bYaIiIiIVpAIgiDo2ggRERERERERkd8ielJERERERERE5iSiSBERERERERGZk4giRURERERERGROIooUERERERERkTmJKFJERERERERE5iSiSBERERERERGZk4giRURERERERGROIooUERERERERkTmJKFJERERERERE5iSiSBERERERERGZk4giRUREREREZB5x4MAB1q9fj6OjIxKJhG+++UZjuyAIPPXUUzg4OGBsbExiYiIlJSVnPO6bb76Ju7s7RkZGREdHk5aWNkvvYPKIIkVERERERGQe0dvbS0hICG+++ea421944QVee+01duzYQWpqKqampqxbt46BgYEJj/nZZ5+xceNGNm/eTFZWFiEhIaxbt46mpqbZehuTQhwwKCIyh1Cp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AZgzvmMWC+yICJdFRi73WGPYMik4EonHWsOWRICa59xL5vPRaDSAFx8PXnw8Imu2udKdR8egO3IExuPN6Og2oafPhmdf1oDPo1C9SYhLa0TYeY0UH+824rW/DWDz5o2Qy6Pw/PPP49vf/jaAcwuVQAgUN6R7zgQrboOE5YbFYhENLj2fRQqbzfb5LoVCIczmpQXmz2bnzp3485//7DN+8cUX45NPPln28S8E5HI5xsbGfEowNDU1eSzGS2HBImXbtm0wGAw4duwYNmxwVQA9cOAAFAoF6uvrvQRGbW0tUlNTFyVQAFd67Fxi5Mx+DYHAffJzOGw4bf67qDCgXRvlPLApwElIo1AAWBQFmtBFjM9iwUwv7MNRbtGwiHRjxuHwEjXxBavQefo02VElQnQUC+MTTqgnnZiYtGNaw3yha2gaTp0OTp0OtuFhgMUGwLisN2fAEgpdIkYmc1lopFKIoyIRe9230NPVBbuA77LO8PmudOfkJMR+/SrEfv0qME4nTH39mPq/f8I6OYld+034fJ8rADchno3LdoigHLCjrWsaN954I2677Xv40Y/uwXe+8515hUogBQrgSgteaFNFf0BSpLBYLKKpsyRFAwBPcPv5Nhcw93fpchX75/u95JJL8Prrr3uNkWz8uhicTid++tOf4s0334RKpUJiYiJ27tyJhx9++Kx75d69e3HPPfegtbUVKSkpePjhh7Fz506/rOmaa67B/fffj3/961+gKAo0TePQoUP4yU9+4rn5WgoLFil5eXlISEjA3r17PSJl7969+OpXv4o9e/bgyJEj2Lp1q2d827Zti17M2UywgRYp7osWRbHmyupdMgwYUKz5rUAsUKBB5iLm/gZJ3dexgYDaiCgOBxyZDDhdCEwqlcFxWrHfeascl+8Qe72eYRiYzAwmppyYnHJictr1mDr958SUE6pxOwaGnVCNO6HTO2GxArTZDNpshl097hKcFIWotDQYr7gSXc8+/8V6uFyX0JLJwJnlamJLpeDIZJDTMzj2aQr2H3EVgevoseODz4yYvV+azRY88cQT+NWvnsK9994PANi4caPHx9vf34+urq6AVqslHYzI4/GIxVEAZIWDPzfRhUDyswX6mjzXfHOJFH8JJT6fT6QSsT946qmn8PLLL+PPf/4zCgsLcezYMdx0002QyWS4884753xPX18fLr/8ctx222146623sHv3btxyyy1ISEjAxRdfvOw1PfHEE7j99tuRkpICp9OJgoICOJ1OXHfddXj44YeXfNxFBXps27YNtbW1njr8tbW1uO++++B0OlFbW4utW7fCbDajvr4eN99886IXM59IIfGjc1tSWCz//sgZMK7Ak3lgE7RssE9fVEjNR9Jq45oPcJyOLRIKfL9ziqIgFlEQi1hIT1lYLyiaZqDV0S5hM/3Fw2CJBodtw/YtAoyoXEJHb3TApp2BY2YGVreriXFZZygKmGKAjPJ+sNlAdCQbhXl8yKUUTrRboDntXWGzXV4su92JJ554Al/+8qUwGAyenjqBFiiAy4wf7Dvk82W+8/mzAWSuzWebj7Q1J1Q4fPgwvvrVr+Lyyy8HAKSnu2LbGhoa5n3P73//e2RkZODZZ58F8EWhteeff94vIoXH4+HVV1/FI488glOnTsFgMKC0tHRB7ULOxqJFyt133w2HwwGz2YympiZUV1fDbrfj97931Yqoq6uD1WpdliXFfkYaKcMwcDqdPuP+hKZpCIVCcAWuzYsr9E9DQwHDh13IB3+euw4O5bJwzPe8P+GdnoMDiuh8JOYCADYocODyU7NYAtgd/jHVRkS4HhmzmvVO6RLQOsjgv3/L9nm9w8FgRuvE5DSNqRknhkbsaGmz4ESrDSq1ExodDZOZRu+AS8Ow2SJIJQwcTu/afGwOsHv3XrBYXPB4XLBYbBQXF0MikQT8t0DTNGw2G5G7ZYZh4HA4AvqZZkNRFGw2G5H5aJoO+LXrTOx2O5H5nE4nGIYh9tnm+i6dTqffYn4+/PBDnxpdDz30EB566CG/HH8huLNM3fD5/DldTps2bcIf/vAHdHV1ITc3Fy0tLTh48CCee+65eY9dV1eHHTt2eI1dfPHFuPvuu/2ydjcKhQJmsxlZWVl+SXihmEVI4Z6eHuTk5ODw4cOYmZnBvffei9bWVoyOjiIzMxMajQZPPPEE3nrrrSX5tA8dOoSvf/3rHsETJkyYMGHCzIdKpcIdd9yxbKG0c+dOjIyM4OWXX/Yaj4qKmtNqqdPpIJPJkPbLX8xZSXyx0BYLBh74fz7j//u//4uf/vSnvq+naTz00EN4+umnPQHFv/jFL/Dggw/OO0dubi5uuukmr9d89NFHuPzyy2EymZYdSG4ymfDDH/7QE4Dc1dWFzMxM/PCHP0RSUtKSOyEvSuZkZ2cjOTkZtbW1mJmZQXV1NQAgMTERKSkpOHz4MGpra1FTU7OkxbBYLHA4HFx22WVe4/v378eqVasQGxu7pOMuhDfffBO33347vpn3HWy/fSP+dteHfjluG3MMunQO4m+7dc7nr46OxZTDjj1ajV/mOxscisLjqRn4+VA/TARMpJUSGdL4fLw1OR7wuQDgnsRk/Lu/D3sf/Sne/0siqjYsP3uDZhhotTQmp52YnnFZRqZmnDDZUqFIvxmf/ud+TE3TUE+5XD4zGieMpjlaFVAAh+36C027AnhZLIDDcbl3zrwZZLEAqVSOG2+8ERs2bMC6detw7NgxsFgsrF+/HpGRkcv+bPNhNBpx4MABXHLJJQGbYzadnZ2w2+3EGht+/vnnWL9+vacLcyAZGxtDX18fNm3aFPC5AFdDt6SkJCQnJwd8LpPJ5CngRYKOjg44nU6vyqU9PT1+y/wUi8XIzva1jJJkaGjI67ycL3D3n//8J9566y387W9/Q2FhIZqbm3H33XcjMTERN954I6nlevHggw+ipaUFe/fu9bp27NixAz/96U/JiBTA5fLZu3evx5LipqqqCh9//DEaGhrw/e9/f0mLcfsXuVyuzzj7dNn2QMFisWA2m2EzuxS53ewfE6aVscJsdsA6j8HKzjCggXmf9yfu1GMHoflsjKvOCYm5AFe9GZrNgdlshsViBpfjHd/EMAyMJuaL+JIp38DZyWkn1BNOjE+6xIhOR4OeY/k52Wz870+5+Ms/J7wCXzkcQMinIJOyEB/LQUYaB0WreFi7hofkRD5kEhY6e23Yd9iMz/eZcPykFTQNcDkUBMIIrFu3Dvfccw++/OUve2XxuANn8/PzcfTo0YDGpVAUBRaLFdDf25nzBfr3PRuGYTyFBAMNi8Ui+l0CrpgiEvNxOK62FqQ+mztecfZ8bDabSL0bUkil0gWJ53vvvRcPPPAArrnmGgBAUVERBgYG8OSTT84rUhQKBdRqtdeYWq2GVCr1Szr+e++9h3/84x/YsGGDl5u4sLBwWdmCSxIpt99+O+x2u8eSAgDV1dW44447YLPZlhSPApw9CCrQAVpu3xnDuIIc/QUFCsxZKsrSYMACmZgN9zcY+NZjLpwAAnn5YByOWXVUDNCJpeAMDwMAfv3qDN58W4fxSZfomJp2YkbrxFxWYTYLYLEpMAzgdDK+2V0sFig+H+wIMTjR0eDExcMYHweROAJSeRS+dx2DB+6MQoTY99Pa7QyONltQe9CMp17Uoa7RDIfDJWZ4PCHWravA7bffjuuvv97rjvDMNGO3OTs9PR1sNtvv3ZNno9frfXzzgcRmsxGpWeKGREkDNzRNE82CIfnZgh00C5w9I3SxWK1WqFQqrzEOh4OYmIW1HCGJyWTy+dxsNvusQcQbN27ERx995DX2+eefY+PGjX5Z08TEBOLi4nzGjUbjss7JJYkUs9mM/Px8xM/qUFtdXQ29Xu9JVV4K8xU+IhGx7t4gHA4n2Dz/beMUWAA9v1XGybhqpZCAgct9wSJ0EbPSNIQLvIB4irmd0UeINhhmFXYzwKk3uKrUmkxgzlAc6nvE4PX1g8OlsL/OAqeTmavsyRcIhWBHRoIfHQW2TAq2xLfUPjti/mJuEw478teWYXyywSNQaJpBS6sVtYdclpL9R8ywWBiw2QCXy8eqVUXYuXMn7rrrrnnN1Oeqg+Lv7slnotVqiVWbBVxFHAPpvpqNO/gy0BWs3ZAUDYB/N+1QmguY+7v0pwj85JNPfPauvLw8dHR0+OX4/uQrX/kKfvGLX3ga9zU1NeG5557zyqp98MEHMTIygr/85S8AgNtuuw0vvfQS7rvvPtx8883Ys2cP/vnPf+K///2vX9a0bt06/Pe//8UPf/hDAF+kqP/xj39clhBa9C81PT19TsGQlpa2bCExX1GnuSoN+hv3hmEz2zwZPv6AwtmrtZG0pAAulw83wBdNhmHAWCyYttoQESGBqbXNp0uz02AEfbosvtNoAjNPMS+KzQaLxQabzQKbosBlseC0WMDMoT5mZmYQFRMDyKLBlsnAk7t7/EjBnl1FVioBS7j0svhuhq1WZBSsxoEPD+DlNzTYtd+EPQfN0Onp0/EmHKSlZePaa6/FvffeuyDrxEILtQVSqGg0mmVViFws81WaDgTu8vukinTNV6AyUJAURSTalczG6XT6/L+ZzWa/WOHeeOMNvPHGG8s+DilefPFFPPLII/jBD36A8fFxJCYm4nvf+x4effRRz2vGxsYwODjo+XdGRgb++9//4kc/+hF+/etfIzk5GX/84x/9kn4MuOqkXHrppWhra4PD4cCvf/1rtLW14fDhw9i3b9+SjxtSvXvcfRjO/KGRKL/s9nPaLDZweGyw2JRf+vdwwAFtmb8vCU3QkgIABqcTEjYb6kVEw9M2u6ux4Bnl6t2igzYaXeXq9Xo4jSbQZhNAM3AmJ0P6zDNQv/on14FOxxZxOBzwuFzwuFxwOFywIiPBMAysVissZgvMli/KXDNOJ2iagQAi8CAA7BSMMEK8tgyCjPTTpetdAgSpaUgWiZBSmO/vr80L+9Q0LN3d6IiKQXZkJN7qtuKHD02Ay2FDkZCMnTddiYcffnjRgd6LrSQbCKHCMAw0Gs2S26ovBYvFQkw0uOciZQEg+dmA81ukOBwOiMXeBRrd/d4uNCQSCV544QW88MIL875mLtG1detWNDU1BWRNlZWVaG5uxi9/+UsUFRXhs88+Q1lZGerq6lBUVLTk44aUSJFIJK6qoCaT18lIQqS4g5VMZlcHXq6AC6tx+VUwOeCCtszfW8JEO6Hg8pY9z0LROhyIsNlhG1P5WDdoT/M/A2id3jVmMoGZ67s/3dGYx+VCKBBAEhEBuSIB0dHREAgEGB0dBY/Hg0AgQHpaOkZGR2G32+CkaTjtdljNZnDZXAjZInBpPtgOHiIQgSgIwD/94J3+k8vwQTlcF14nHKjFexCtykfEurVeS9KDgSwAd60OnQ6W7h6Yu3tg7uiEU6MBAPSuXYev3HUn7rzzTtx1110e0bAUllrq3t9CxWg0gqZpIpkvADz1WEhZUkhabQCX5Yb0fDwemetJMETKmfPp9XqvjrthgktWVhZeffVVvx4zpESKWxHr9XovkUKi14bbJ262nhYpQo5fRAoXPDgt5nnvcLROJ3IFS/tvYGgatMXyRbzGLKHhac53Oo6DNhjgNJmguusu0J2dGHn/fa9jUaezKwR8PmRiMWRyOaIyMxEbGwuFQoHk5GSkpqYiMzMTOTk5iImJmfdu9Nprr8Xnn+yCnIqGzWpDrD0JPLvMIzrcAoRDc7+om7/Amz82xQGH4sM+Ne3z3JTDjhg/ZBo4TSZYenpdwqSjE/aJCQAATyBAYW4uLrvtNnz3u99FSkoKPvnkE/zsZz9bVgzHcnvx+FOoqFQqREVFEbM0GI1GsNls4pYUUlgsFmKCz22NJCWKgiFSznSdkQ7yDnN2nE4n/v3vf6O9vR0AUFBQgK9+9avLOk9CSqTweDzweDyfviEcDifgMSlukWJn7LCZ7X6LS+GABzAMGKsV1BwXD53DASmb7YrjsNl83ShzdAGm9S7BQZvN8E1FOd2sj8MFn8+DRCiETCaDXKFATEwMFAoFMjMzcdlllyEjIwPZ2dlISUnx68UmNjYWERwJShyVMM9YURBdgpEx9bnfuEDEkMCu9j3eqM2GCBYbMjYb2kWcL7TVCouyzyNKbKOjAAAOj4esjAx86ZvfxK233oo1a9b4vDcpKQmDg4NLFin+ahboD6HCMAwGBweXXcZ6MWg0GkilUqLuF5KWjfM53iYULCkGgyFsSQkRWltbccUVV0ClUiEvLw+Aq8dQbGwsPvjggyXXQQopkQK4XD56vd5rjMPhBLz0slukOGCD3ewAT7i8r4ZmaNhhhQMua4zh2HEAzGkRYvBYOVhSGSLuuQf9P7nft6IXAFAU2BwOuFwexEIBJBIJ5MnJiI6ORnx8PBISEpCcnIyMjAxkZWUhMzMTIpFo3nV1dXVBr9dj7dq1875muSQnJ8NMuyxSphkzxJH+TS+NoCWYGFH5jNsYBuN2O5J5fGhPu+3mgnE4YBkYgKWrG+bOLlgHhwCaBovDQWpyMrbu3InvfOc7qKysPOdaUlNTUV9fj4KCgkVfsP3dzXi5QmVmZgZms3nJ2XlLQaPREM0kIu1+ISlSLBYLuFwusUDduSwbgZ4v7O4JXW655RZPs0P3fjozM4OdO3fiu9/9Lg4fPryk44acSImIiJhTpJjN88d1+AOJROLqG0TbYbd4W1IYhoEdttMPK2yw+v6dssHJdsBB2WClLbA5ZwXLUhSm3n4HAMDicMDlcCEQ8BEZEYEoeSTEYjG+cdVViI2NRVJSEtLT05GZmYmsrCy/5+gLBAJMnHZfBIqUlBRYnRY4YIdxxgyRv0UKZBidGADjcIA646I1ZLMihc9H6yyRwtA0bMPDMHd1w9zZDUtfH+BwgGKxoFAosOXrX8eNN96ISy65ZNF39FFRURCJRBgaGkJGRsaC3+dvgeJmOUKlt7cXaWlpRO+OtVotUlJSiM13PrtfSFuJSKZyA/OLlLC7JzRobm72EiiA6+b/F7/4BcrLy5d83JATKXO1iScROMtisRAhlmBU34cZwzTGZL04yjkCK2OB1WFxdTOeBUVRkElliI6KRmJcAuIV8YiJiUFsbCxiYmK8HlwuFzExMUhOTvbZBBmGwQcffIDXXnvNJ3I9EMyX5u1P3KY+I/TQjRshT/TvnY4EcpfwUKnBT/ZOlR22WpErFMI2OgZzdzfMXd2wdPeAsdkAFgsx0dHYcckluO6663D11Vcv+yJLURSys7PR0dGBtLS0BYmcQAkUN0sRKgaDASqVCtu3b/f7eubDnUm0nMj/xWI0Gs9qafQnpN0vpK1ENpuNaCXduURR2N0TOuTm5kKtVvtkBo6Pjy+r3UDIiZT5LCmBFikAcOddP8R/P/wI4DLYuH09CstX+QgOtxCJjIz0i6mToiiPcCAhUvh8fsBFSn5+PiiKgpHRYaJ3GiVX+DclWAI5KFCwDgyAn5zk6qI7OQVzdzeaTWZs/+Y1GHvmOdAMA5lMhk1btuDqq6/GDTfcEJANKjExEV1dXeju7vYItPkItEBxsxihwjAMTpw4gdTUVGIbOPBFx1dSm4zdbofBYCDmXiLtfglGvA2paqzuTtlzWVIC+TsKs3CefPJJ3HnnnfjpT3+KDRs2AACOHDmCn//853jqqae8OjwvxpoZciJFKpX6tKvmcrlE2oE/9thjeOyxx9DS0gIul4uCgoKAzwmQEQ5uBAIBHA5HQIPeRCIRkhKTYRzRYUI5hei0SL/VnQFcGT5iSg5D/VFYBwZdacGnzxmbVAru9d/CCy+8gOuvv57IBYzFYqG0tBSHDh1CQkLCvD9AUgLFzUKFysDAAAwGw7JMsktBpVIhNjaWWNCsVquFQCA4b90vpDOXSGcSAfCx3Oh0OqSlpRFZQ5iz8+UvfxkA8I1vfMOTyeou8PqVr3zF82+KohaVCBNyIiUuLs6nCRLJTdw9n8k0f+ClvyHhgnHD4/FAURSsVmtA/cmlZSWoGzsKzZgetMOJqBQ5Jvtnlnw8G2PFDCYwjXHouNMw2DXA4AwwMYHiVatw+eWX47vf/S6Sk5PR2NiIoqIiondYkZGRyMzMxPHjx1FVVeWz8ZIWKG7OJVRMJhNaW1tRXl5O1HQPuERKeno6sflIl/sPRpAuyT4zpIvwuQtBzkatVmPHjh1E1hDm7NTW1gbkuCEnUhISEjA2NuY1JhAIYLVaifWKEAgEmJ72rcMRyPlIiRSKoiASiWA0GgPqXiotLcWuj3eDcTCYUM4gNitqUSLFwdgxgwnMYAI6zhQ0Dtf/R2ZGFq6/+BrU1NRg/fr1SE1N9XlvQkIC2tvbiVZNBVyxOCqVysftEyyB4mY+ocIwDJqampCUlDRnY7BAYrFYoNVqoVAoiM2p0Wggk8mIzUcy/gUga7lhGIZ45hKfz/epNTU2NkY0Gy3M/MxuOOxPQq7H9XwiBfgiEC3QkBQN7vlIfTYAkMlk0JyumhooSktLYXaYYIUF471TiMs6++bsZJyYZtToYU6hkbUP+6gP0ILDsCsM+Or1X8Ff/vIXDA0NoVfZg5dffhlXX331nAIFcNVpMRqNPgHYgYbNZqOsrAzd3d0YHx8HEHyB4iYzMxOrVq1CXV2dR4B3dnbCaDQSF3OA6w5YLpcTdU+QTncmLYpIWm5sNhsYhgm66ywsUkKHTz75BAcPHvT8+7e//S1KSkpw3XXXYWZm6Vb0kLOkJCYmYvR0MS03LBYLPB4PVquVSEt30qJBIBBgamqK2HxyuXxZJ81CcMc3aDGFid5prPmyd/AszdDQYRrTmICWPQkNMwkn7URUZBS+9KUd2L59O2pqapCVlbXoXiTubKqxsTGihckA13dbXFyMhoYGpKWlYXBwMOgCxc1si0pqaiqGhoZQWVlJ3M0DAKOjo0StKKSDZt2ZS6tWrSI2H+nCcRwOh1gK8lwCzGw2Q6PRIDExkcgawpyde++9F0899RQA4OTJk7jnnnvw4x//GLW1tbjnnnvw+uuvL+m4ISdS5rKkAGStGwKBADabDU6nk0hkPmnLjUwmQ39/f0DnSEpKQmpKGjRDkxjvnUZMeiQMLC2mnCpoWJPQsCZhd9oRIY7Atm3bsH2HS5QUFhb6xaWXkpKCrq4uZGdnE2u4NntulUoFpVKJNWvWhIRAcZOZmYnJyUkolUoUFxcTqxkyG7PZjImJCZSUlBCbU6fTgc/nE9vEzWYzHA4Hse/XbdkgGSMS7KJ4Y2Nj4HA4RONwwsxPX1+fJ9nknXfewVe+8hU88cQTOH78OC677LIlHzck3T0qlcoTFeyGZPCs2/dJaj6hUAiTyeTzmQOFXC6HyWSCzbb83kRno2b7Nkyxx3Bg7DOYzEZoc4cxyO/Gmm0F+PnjP0d9fT1mNDP4zwf/wV133YWioiK/xRwlJibCarUStVC5USqVGB8fR1ZWFlpbWz2un2DDMAw6OzsxOTnpWRvJ2Cs3AwMDiIuLI2IVdTM5OUlULGo0GkgkEmLpxyaTCTwej5hlw2w2Bz1zaWxsDPHx8cSyw8KcHR6P50k42bVrFy666CIAroKXZ2bsLoaQtKTYbDZMT08jOjraM046uFQsFsNgMBCpXRIREQGGYYgVJuLxeBCJRNBoNAENmLz++uvx3r/fR2ZBKuwOO5577jls27aNyN0em81Gamoq+vr6iN5pnRmDIpfL0dDQgIyMDOTn5xMtIz4bs9mMlpYWaLVaVFZWQiqVQiQS+a178kKhaRoDAwMoLi4mMp8blUq1qIrAy+V8j38xGAxEK71aLBafa1U4HiW0qKysxD333IPNmzejoaEB//jHPwC4WrEkJycv+bghJ0EjIiIQERExb4YPyXWQCrxksVhEgllnI5fLAz7fjh07MD0zhcOHD+GSSy4Bl8slGiiZkZEBlUoV8JYKbuYKkk1OTkZVVRUmJiawb9++gMcCnQnDMBgaGkJtbS24XC62bdvmcUHMFUwbaEZHR8FmsxEfH09kPsAl0LRaLdE5gyFSSM4XDJEyl7snLFJCh5deegkcDgdvv/02Xn75ZSQluaqBf/zxx7jkkkuWfNyQs6QAXwTPzu6aKBAIlmUyWixisRhGo5HYfDKZjGgfE/d8gcYdDxIXF4fGxkaiFzexWIy4uDj09vYuuQPnQjlbFo9UKkVVVRV6enpw6NAhZGZmIi8vL+BWFbPZjBMnTmBmZgalpaVzXtD90T15oTAMg97eXmRkZBCNE1Kr1YiMjCQmkBmGgVarRX6+fystnw2tVovc3Fxi8xmNRmJF1OYLCh4dHQ0HzYYQqamp+PDDD33Gn3/++WUdN+QsKYAr6HJoaMhrjLRoIGlJAchYNoI5nzvATaXy7V4cSPLy8tDf3x9Qa8pC0oxZLBZyc3M9VpXPP/8cnZ2dAbEO6vV6NDc3Y9euXeBwOKipqTnrHScpi8rY2BgsFgvxCqEqlYpoJpHZbIbdbifmfnE6ndDpdMTmYxgGRqOR2M2G1WqF0+n0qTkzPDzsuVsPc/4SkiIlNzcX3d3dXmMREREwGo3EgkuDIVK0Wu15Fzw7G4VCQVykyOVyKBQKdHR0BOT4i62D4raqlJaWYnJyEp999hmOHTsGtVoNmqaXvA673Y7BwUEcPHgQe/fuBcMwqK6uxtq1a8Hj8c75/kALFZqm0dbWhry8POKdcycmJogXjSMZNKvT6cDhcIgVjnMH+ZOaz2g0QigU+pw3XV1dRK1HYYJDSLp7cnNzvYrCAPBkAphMJiLBrGKxGGazmVgaskQiAU3TRINnhUJhwINnZ6NQKHDy5EnYbLYFbZz+Ij8/H7W1tcjOzvbrd7vUQm0URSE+Ph7x8fHQ6/UYHBxEU1MT7HY7pFIp5HI5ZDIZ5HI5IiIivM4/mqZhs9mg0+mg0Wig1Wqh0WhgMBgglUqRmpqK8vLyJbk2Aun6GRwcBIB5C/AFiomJCQiFQqLxE6SDWN3xKKRcaO5KuqSyauZKYGAYJixSLhBCVqS89tprXmMsFotoxo1AIACbzYbRaCRS64DFYkEqlUKr1RLrChsbG4vx8XFiIkUoFEIqlUKtVhOLvQFcVrHU1FS0t7ejoqLCL8f0VyVZiUSCwsJCFBQUwGg0eoTHyMgIWltbPY3V3BvQJ598AsB1fsrlcsjlciQlJUEul/slJTQQQsXhcKCjo8OvKeYLxe3qIRkD404/J4VWqz2vM3vmmm9ychIajYZ4scYw5AlZkdLT0+NjxXC7YEhE6VMUhYiICOj1emIFmdxxIstJ11oMCoUCra2tAQ8qnU1SUhIGBweJihTAFZuya9cuv4iyQJS6d59vERERnv9/hmFgt9vhdDphtVqxb98+bN++HXw+P6BVYv0tVLq6uiAUCokHOTocDoyOjmLTpk3E5jSbzdDpdMQziUhu1nq9ntiNFOASKWeWEejq6kJiYiJRsRQmOISkSMnIyIDD4cDQ0JBXl1R3XAop3KKBVHCWXC73CRgOJLGxsTCbzUQvOikpKWhvbw94g8MzEQgEKCwsRHNzM7Zt27bkTZ5kLx6KojxuMbc/PtACxY2/hMrMzAyUSiWqqqqIV/4dGRmBSCQimpqrUqkQFRVFzJ3pDpolne5M0lJkNBp9umWHXT2hwde+9rUFv/bdd99d0hwhGTjL5XKRmZmJrq4ur3G3u4cUpDNg3GnBpIJnORwOYmNjiQazCgQCKBQKDAwMEJvTTXp6OsRiMVpbW5f0/lBpFkiK5QbTOp1ONDU1IScnJyjl9wcGBpCWlkZUHJHOJCIdNEvTNFFR5M4kOvOGJixSQgOZTOZ5SKVS7N69G8eOHfM839jYiN27dy/LHRmSIgVwuXzOFCmkM25IiwapVAqapolaixQKBdRqNbH5AJdYGBwcXFY2y1KgKAqlpaUYGRlZdKn6C02guFmOUOns7ASLxQpK3IBWq4VWqyXmOgVc7qXJyUmiIsUdj0JKiOn1ek98IAnmyyQKi5TQ4PXXX/c84uPj8Y1vfAN9fX1499138e6770KpVOKaa65ZVtXvFSdS3Bk3JJBKpXA4HJ5+BIHGHTxL0noTHx+P6elpotV8Y2NjweFwMDIyQmxONyKRyOP2WWj69YUqUNwsRahMT09DqVSirKwsKL1VlEolUlJSiGaRjY+PByWTKBjl90lmEonFYp9zKCxSQo/XXnsNP/nJT7ziSNlsNu655x6fRJjFENIipbOz02vM7Y8nVXmWzWYTFw1yuZxo6fTZGTekoCgKmZmZUCqVxKxUs0lLS4NMJsPRo0fPac250AWKm8UIFbPZjIaGBqxatSoobh6r1Yrh4WFPXA0pVCoV8TLtMzMz53X5/bmyHWmaRk9PT1ikhBjuLL4z6ejoWJbVPGRFSmFhIU6ePOk1RlEUsXLubkj31ImLi4NarSa6eSckJBB3+aSkpMBgMBDvZQO4zqO1a9fCZrPh1KlT874uLFC8WYhQcTqdaGhoQHx8PHGR4GZgYABRUVFEBRLDMFCr1URdPSaTCXq9HrGxscTmJF0DZq706u7ubjAME7TzK8zc3HTTTfjOd76D5557DgcPHsTBgwfx7LPP4pZbbsFNN9205OOGZHYPAJSWlkKlUvk0kQpG+fgzmx0GEnfGDamiboDL5dPd3U2scB3gCo5OS0tDd3c31q9fT2TO2XA4HFRUVGD//v2QSqU+2QNhgTI3Z8v6YRgGzc3NYLFYWLNmDfFsHsB1N6dUKlFSUkJ03pmZGTAMg8jISGJzqtVqREdHE3NpkQ6aBVyi6MxyBY2NjSguLiaS5RZm4TzzzDNQKBR49tlnPXtmQkIC7r33Xvz4xz9e8nFD1pISERGBvLw8NDY2eo2TFimRkZGeCxAJgpFxI5PJwOVyMTU1RWxOAMjOzsbExASxDrxnIhaLUV5ejlOnTmFyctIzHhYoZ2c+i0p3dzcmJydRXl5OTOyeiVKphEgkIlqnBHD1JYqPjycaf6NSqYh+Tp1OBxaLRSzmxm63w2g0+oiixsZGrF27lsgawiwcFouF++67DyMjI9BoNNBoNBgZGcF99923rOtByIoUAFi7du2cIkWv1xPLDHGbjEm6mEj3uKEoComJiRgeHiY2J+BKR87OzkZbW1tQYlMAICYmBkVFRaivr/fU9AgLlHNzplDp6+vzWMX8Ufl2KdhsNnR3d6OgoICoFYdhGIyOjhKNR7Hb7cQziSYnJxEdHU3su9VqtRAKhT4tHsIiJfSRSqV+c7euOJHi7hlBKniWxWIhOjra60470CgUCszMzBDNuElNTcXo6CjsdjuxOQEgKysLer2eeEzMbNLS0pCfn49Dhw6hra0tLFAWiFuoHDp0CK2trdi4cSNRV8CZdHV1ISoqalnpjkthYmICTqeTqGCYmJiASCQimkk0OTlJ9LudK/6FpmkcP348LFJCELVajRtuuAGJiYngcDhgs9lej6USsjEpgEukPPPMM15jFEV5XD6kLogxMTGYmppCdnY2kfkEAgFkMhnUajWxhmwymQwSiQTDw8PIyMggMifgik3Jzc1Fe3s74uPjgxLHALjOK4ZhwGKxgraGlYjbvREsS5gbs9mM/v5+bNmyhfjcAwMDSElJIe7qISmKGIbB1NQU8vPzic051zW+p6cHNpsNhYWFxNYRZmHs3LkTg4ODeOSRR5CQkOC362hIi5TS0lKMjY35/CDlcjlR90t0dDQ6OzvBMAyxDczt8iHZNTY9PR1KpRLp6elEN+r09HT09vZieHiYeE8f4IsYlM2bN2NmZgaHDx9GRUUF0ayJlQbDMOjp6UFXVxc2bdoErVYbkO7JC6WjowMKhYJo5gkAWCwWqFQqbNu2jdic7kwifzXLXAju6y3p7s5nXg+OHz+ONWvWhINmQ5CDBw/iwIEDfg9aD2l3j0QiQW5uLo4fP+41Tjot2K3mSceljI+PEytcB7ia/7k78ZKEzWYjPz8fHR0dRD8v4Bskm5WV5YlR6evrI7qWlYK73H1vby82bdqE6OjoZZfQXw46nQ7Dw8NYtWoV0XkBYGhoCFFRUUTdLu7vl6QYdLt6SN28uINmzxRF4XiU0CUlJSUgFtWQFinA3HEpkZGR0Ol0xDY0iqKIx6VIpVLweDyic3I4HKSkpARlc05JSQGHw4FSqSQ253xBsqmpqdi4cSM6OzvR0tJCvHx/KGOxWHDo0CHo9XpUV1d7pdwGQ6gwDIPW1lakpaURbVjpnru/v98nfT3QuLN6SFo73UGzpNBoNBAKhT5B2GGRErq88MILeOCBB9Df3+/X44a8SFm3bh0aGhq8xkQiEXg8HtE7tpiYGKKCgaIo4lk+gKsD9cjICNGgXcD1eYuLi9HZ2Qm9Xh/w+c6VxRMdHY2qqiqP+4f09xGKaDQa7Nu3D2KxGJWVlRAKhT6vIS1UBgcHodPpiMZKuFGpVKBpmniV2WDFo5AMmp1LFDmdTjQ2NmLdunXE1hFm4Xzzm9/E3r17kZWVBYlEgqioKK/HUgnpmBQAqKqqws9+9jOvQmMURXmCWUnFDcTGxnrcEaRqQCgUCjQ1NREtjCWVShEdHY3+/n7k5eURmdNNVFQU0tPT0dTUhC1btgTsMy80zVgkEqGyshLNzc2ora1FcXEx8Q0pFKBpGt3d3eju7kZeXh6ys7PP+n9ztoJv/sRsNuPUqVNYu3Yt0R49bpRKJTIyMogGzBoMBphMJsTFxRGbc2ZmxlPtmxRTU1M+8SjNzc2gKApFRUXE1hFm4bzwwgsBOW7Ii5SSkhIwDIOWlhaUlZV5xmNiYjA0NERsHVKp1FPwjNQFIjo6Gg6HA1qtlmhqZ2ZmJpqbm5GTk0O8OdyqVauwd+9e9PT0BKR77mLroHA4HKxduxbDw8NoamrC6OgoioqKgrIpBgOdTofjx4+Dpmls3rx5wRVVAy1U3NVtExISiFoV3Gi1WkxPTxO/q1epVIiJiQGHQ+7S7S5UR+pGyeFwYGZmBqWlpV7je/fuRVVVVdAKBYY5OzfeeGNAjhvy7h42m42qqirs3bvXazw6OhozMzNE41IUCgXREvlsNhtxcXEYHR0lNifgKpMfrC7FbDYbpaWl6Ozs9HstnKUWaqMoCikpKaipqYHD4cCePXswNjYW9LTbQELTNDo7O7F//37ExcX5xJ8shEC6ftxunmDdVSuVSiQnJ/sUGgs0o6OjxEUZ6caJMzMz4PF4EIlEXuN79+7F1q1bia0jlHFnYJ75uP322+d8/RtvvOHzWn8UXZx9jdbpdGd9LJWQFykAsHXrVh+RIhaLicelKBQK4s3/UlNTMTQ0RDR4k6IoZGVleRp5kSYqKgoZGRloamry2+f2RyVZgUCAiooKFBYWoqmpCYcPHw5Kg8RAwjAMRkZGsGfPHoyMjGDz5s0oKChY8t1rIISK281TUlISlFRUk8mE4eFhZGVlEZ1Xp9NBq9UiKSmJ2JwGgwFGo5FoOv5cmUROpxP79+8Pi5TTHD16FGNjY57H559/DgC4+uqr532PVCr1es/AwMCy1xEZGYnx8XEArizYyMhIn4d7fKmEvLsHcImUxx57bM64lMnJSWI/oJiYGNhsNuh0OmL+2bi4OFAUBbVaTfRuJi0tDT09PRgaGiJaq8VNfn6+x+2z3Jbs/ix177aqKBQKdHd349ChQ4iPj8eqVauIpqEGgvHxcbS1tcFqtSI/P99vBcr86fpxu3kSExOJ9+dx09HRgcTERKJdlgFX0bjExESirka1Wo2YmBiiYnByctLnmuOORykuLia2jlDmzD3vl7/8JbKyslBdXT3ve9zeAH+yZ88ez+95z549AXEJrgiREipxKW73i0qlIiZSKIpCamoqBgYGiIoUFouF/Px8tLe3Iykpibgf2O32OXz4MKKjo5ec/hioXjxcLhcFBQXIyMhAV1cXamtrkZycjKysLOKb13JgGAYTExPo7u6GVqtFTk4OMjMz/f7/7S+h0tPTA71eH7QMD51Oh5GREdTU1BCd1+l0YmhoiGgBN4C8q8cdjzL7Og9cOPEoZ7pF+Hz+OV2KNpsNb775Ju65556zigSDwYC0tDTQNI2ysjI88cQTy67cW11djb6+PmRkZATMyrUi3D3zxaXExMRgZmYGDoeD2FqCkRaclpaG8fFxmM1movMmJyeDy+UGrahZVFQUCgsL0dDQAJPJtOj3k2gWKBQKUVxc7Kk4um/fPhw6dAijo6MhXV/FbrdDqVRiz549OH78OKKjo/GlL30JOTk5AdsIluv6UalU6OzsREVFRdAqjra1tSE9PZ14TZaxsTHw+XyitUpsNhumpqaIxsDMzMxAIBBcsPEoKSkpkMlknseTTz55zve899570Gg02Llz57yvycvLw2uvvYb3338fb775JmiaxqZNm/zSVDYrKwsZGRm4+eab8eabb/q9Ue2KsKQAwLZt21BbW4t77rnHMza7XgqpjJv4+Hg0NzfDbDbPWSciEAiFQsTFxWFwcJBoWjBFUSgoKMDx48eRlpYWlI0hIyMDOp0O9fX12LJly4KzGkh3M46IiEBpaSkKCgowMDCAU6dO4cSJE0hJSUFCQgIiIyOD3hPI4XBgYmICY2NjGB0dhVQqRU5ODlFL2VItKjqdDo2NjSgtLQ1aE8OpqSlMTk76ZJ2QYGBgAGlpaUTPofHxcUgkEh/BEEgmJiZ8Oi07HA7s378fP//5z4mtI1gMDQ15WWIXEpj9pz/9CZdeeikSExPnfc3GjRuxceNGz783bdqEVatW4ZVXXsFjjz22rDXv2bMHe/fuxd69e/H3v/8dNpsNmZmZqKmpwbZt27Bt27ZluWZXjEjZunUrfvazn8HhcHg2qtkFz0iJFPfdzOjoKNHAubS0NJw8eRK5ublEL1RxcXGQSCTo6ekJStlxACgqKkJdXR2OHz+O8vLyc35+0gJlNnw+H7m5ucjJycHExASGhoZw5MgRUBSF+Ph4KBQKxMXFEUshdfeWUalUmJiYgFAohEKhQFVVVdDcUosVKjabDQ0NDcjMzCQaNDobhmHQ1taG7Oxs4hk9BoMhKOnOIyMjZ934AoFKpfK5EWtubgaLxcKaNWuIriUYSKXSRf0uBwYGsGvXLrz77ruLmofL5aK0tBQ9PT2LXaIPW7du9Vi5LBYLDh8+7BEtf/7zn2G325Gfn4/W1tYlHX/FiJTi4mLweDzU1dV5dTpVKBQ4ceIE0eZ/ycnJ6OvrIypS4uPjcfLkSYyNjRG9cLitKYcPH0ZGRoZf0tYWC4vFwrp167B//350dXWd1ZoUTIEyG4qiEBcXh7i4ONA0jZmZGahUKrS3t+PYsWOQSqWQyWSQy+WQy+WQSqXLtmbYbDZotVpoNBpoNBpotVoYjUZERUVBoVCgoKAAEokk6BYdYOFChaZpHD16FBKJJChVZd2o1WoYDAZs2LCB+NxKpRKJiYlExZHVaoVarcbq1auJzWk0GmEwGHxuOD/66CNs3779vI9HWQqvv/464uLicPnlly/qfU6nEydPnsRll13m1/UIBALU1NSgsrIS27Ztw8cff4xXXnkFHR0dSz7mihEpbDYbX/7yl/HBBx94iZSYmBhYrVbo9Xpid4aJiYk4ceIE9Ho9JBIJkTlZLBYyMjI8FyySREVFIS4uDp2dnUGLrufz+Vi/fj0OHDgAiUQy53cQKgLlTFgslif4t7CwECaTySMkxsbG0N7eDofDAYFA4Hnw+XwIBALweDywWCxPfMvg4CAoioLVaoXVaoXFYvE8rFYrhEKhR/ikpaVBLpeHbOG5hQiV1tZWWK1WVFRUBE1cua0oeXl5xF2edrsdg4OD2Lx5M9F5R0dHIZfLicbeqFQqREdH+3zHH3zwAX74wx8SW8dKgaZpvP7667jxxht9LLPf/va3kZSU5Ilp+fnPf44NGzYgOzsbGo0Gv/rVrzAwMIBbbrnFL2ux2Ww4cuQIamtrsXfvXtTX1yMlJQVVVVV46aWXzpp1dC5WjEgBgK985St46KGH8PTTT3vG2Gw2YmNjMTY2RkykcLlcKBQK4p1X09LS0NnZCa1WS7wlvbsSbFZWVtBSbaVSKcrKytDY2AiBQOC1qYWqQJkLkUgEkUjkEVoMw8BsNsNkMnkJD4PBALvdDoZhPEUL1Wo12Gw2eDweBAIBZDKZR9CIxWLirojlcjah0tvbi+HhYVRVVQUtUBZwxQk4nU7ijQQBlyiVSqXLqjOxFIaHh33K0geauXoSjY6Ooqmpye93/OcDu3btwuDgIG6++Waf5wYHB73KB8zMzODWW2+FSqVCZGQk1q5di8OHD6OgoGDZ66ipqUF9fT0yMjJQXV2N733ve/jb3/7mt6ywFSVSLrroIlx77bXo6uryqp2hUCiI95pJTk7GqVOnkJ+fT+wOj8fjITk5GUqlknjwnkQiQXJyMtrb21FeXk507tkkJCSgsLAQdXV12LRpEyIjI1eUQJkLiqI8wmU+7HY7PvroI5SXlwd1ww4EcwmV/v5+dHR0YNOmTcQzaWbjcDjQ0dGBVatWEW8RwTAMlEol8Vgwo9GImZkZounOdrsdU1NTKCkp8Rr/8MMPsXHjRqLNDVcKF1100bzFNs/MhH3++efx/PPPB2QdBw4cQEJCAmpqarB161ZUV1f7NQttRaQgu4mIiEBNTQ0++OADr/H4+HhotVpYLBZia4mLi4PdbidecTQzMxPDw8NB6cq7atUqTExMEC/TfyYZGRnIz89HXV0dWltbV7RACeNidnpye3s7Tp06hQ0bNhC3IJxJW1sbRCIRkpOTic/t7rJM2r07PDyMuLg4ola58fFxRERE+AjS//znP/jKV75CbB1hFo9Go8Ef/vAHiEQiPPXUU0hMTERRURHuuOMOvP3225iYmFjW8VeUSAGAK664Av/5z3+8xgQCAeRyOdRqNbF1sNlsJCYmEi0mB3h3KSaNQCDAmjVrcOLEiaCIpNlkZWUhKioKPT09KCoqCguU84DMzEwoFAp0dXWhoKCAaE2QuZicnMTg4CBKS0uDEg8TjC7LDMNgeHiYuCiby9VjNBqxa9cuXHHFFUTXEmZxiMViXHLJJfjlL3+J+vp6TE5O4umnn4ZIJMLTTz+N5OTkZQVgrziR8uUvfxmHDh3C1NSU13gwiqylpKRgZGSEWJNDN9nZ2ejt7YXdbic6LwAkJSUhKioKJ0+eJD73bJRKJaamppCeno5Tp06ddz10LkT6+/sxNjaGjIwMtLe3E+3LdSYOhwNNTU0oKCgIirtpcnISGo2GeByMRqOB2WwmWsCNpmmo1WqfOXft2oWUlBSibvwwy0csFiMqKgpRUVGIjIwEh8NBe3v7ko+34kRKSkoK1qxZg48//thrXKFQYHx8nOjGHRUVBT6fT7QzMuDq2yCTydDd3U10XsAVP7FmzZqgun1mx6AUFxcjLy8Phw8f9hGuYVYOSqUSra2t2LhxI9asWROw7skLpa2tDUKhEBkZGcTnnl2ThXRm1sDAAFJSUojV8QFcRfJYLJaPa+8///kPrrjiipBImQ8zPzRNo6GhAU8//TQuvfRSyOVybNq0Cb/73e+gUCjw29/+FkqlcsnHX3EiBXBl+Zzp8pFIJBCLxUStKRRFIT09nbjrxV27RKlUEi+VD7jcPkVFRWhpaSHu9pkrSDYrKwsFBQWoq6vze0nmMIGFYRicOnUKHR0d2Lhxo8fFE4juyQtlYmIiqG4elUoFk8lEvMuy3W7H8PAw0tLSiM47PDyMxMREr++apml8+OGH4XiUFYBcLsfGjRvx61//GtHR0Xj++efR1dWFwcFB/PnPf8bOnTuXdU6tSJFy5ZVX4qOPPoLRaPSMubvTkt6kUlJSMDMz49MYKtBERkYiLi4OXV1dROd1k5SUhOjoaJw4cYLYnGfL4snIyEB5eTlaWlrQ1tY2b9R7mNDBbrfjyJEjUKvVqKqq8vk/DYZQcTgcaG5uDpqbh6ZptLW1ITc3l6g1A3ClWkskEqJtB5xOJ0ZHR33SnQ8ePAin00m8PkyYxfOrX/0K7e3tGBkZwZtvvonvfOc7fhXYK1KklJSUICUlxceakpSUhImJCaJZPjweD4mJiUEJZF21ahUGBwdhMBiIz+12+0xOTmJkZCTg8y0kzTg+Ph5VVVUYHR1FQ0NDUGJ2wiwMvV6Pffv2gaIoVFVVzVt7h7RQaW1thUgkCoqbB3AJBZqmiceiMAyD/v5+4vOqVCrw+XwfYfTmm2/iG9/4xnmXbn8+8r3vfc+rJIi/WZEihaIofOtb38Jbb73lNS4SiRAVFUVk05xNZmYmBgcHiW+KEokEKSkpywpKWg6ksn0WUwdFIpGgqqoKTqcTBw4c8LK2hQkNxsfHPbUV1q9ff86NiJRQcfdaKikpCYqbx+l0Bq0my+TkJKxWK/GsHncm0ezv22q14l//+he+9a1vEV1LmNBkRYoUALjuuuvw2Wef+eRgB8PlExkZCYlEQjwdGXC14Far1UHLbklMTER0dDSam5sD4mJZSqE2Ho+HDRs2IDY2Fvv27Vt2nn4Y/8AwDHp6etDQ0ICioiIUFhYuWAwEWqjYbLagZvMAQF9fH/h8flCaKPb19SE1NZVofxybzQa1Wu0jjD766CNERkZ6de0Nc+GyoirOziYjIwMVFRX45z//idtvv90zHoy+OoDrItrZ2YmMjAyid2HuDIT29nZs2rSJ2LxuKIpCcXEx9u/fj87OTr82gVtOJVkWi4WioiJIpVLU19cjKysLeXl5xO9Qw7iwWCxoaWnBzMwMNm/evKQibYvtnrxQ3E0MZTJZ0Nw8drsdXV1dWLduHXErjslkgkqlwo4dO4jO6+4PdKar76233sL111+/IrJ6mr/2J0glyxd2Or0TkQ/4YUHnISv6iv2tb30Lb775ptcYl8tFfHw8cWtKYmIiHA4H8VotAJCTkwONRoPx8XHicwNfNP/r7e31W1qyv0rdp6WlYcuWLVCr1di3bx80Go1f1hdmYbiLg+3ZswcsFgvbtm1bVhXZQFhUTp06BavVirKysqBtjN3d3ZDJZIiNjSU+d29vLxQKxVnbMgSCoaEhHyuKRqPBhx9+iOuvv57oWsKELitapFx99dVobGxEb2+v13hycjKGh4eJZniw2WxkZWWhu7ubeGYJj8dDTk5OULNa3M3/jh8/Dq1Wu6xj+bsXj0wmQ1VVFRISEnDw4EF0dHR4ugqHCRxWqxVHjx7FyZMnUVJSgvLycr+UWvenUOnv78fIyMiCYmMChcVi8fToIS2SrFYrBgYGkJOTQ3Rek8mEmZkZH9fWO++8g9WrV/vVIhtmZbOiRUp0dDQuvfRSnwDa+Ph42O124vUV0tPTYTAYglJULCMjA1arNah9dRISEpCTk4P6+volB9IGqlkgi8VCfn4+tmzZgrGxMezbt2/ZYirM/IyMjGDPnj2gKAo1NTV+7z/jD6EyNTWFU6dOoby8PKhNDDs7OxEXFxeU1g59fX2eyqAkGRoamrM/0JtvvhkOmA3jxYoWKcAXLp/ZFgQ2m42UlBTiacFcLhcZGRlBqV3C4XCQl5eH9vZ24mX6Z5Obm4vIyEgcPXp00dYKEt2MZTIZqqurkZCQgAMHDqC9vR0OhyMgc12ImEwmHD16FCdOnMCaNWv8Zj2Zi+UIFZPJhIaGBhQWFga1w65er8fg4CDxTseAKw5GqVQSt6IwDIOBgQGfAl9DQ0M4ePAgrrnmGqLrCRParHiR8uUvfxlqtRpHjhzxGk9LS8Po6ChsNhvR9WRmZmJ6ejoosQ+pqangcDhBK/AGuAJpS0tL4XA4cOLEiQW7n0gIFDduq0plZSUmJyexa9cuKJXKsAtoGVitVpw8eRK7d+8Gi8VCTU0NkSyVpQgVh8OB+vp6JCYmBi1QFnBt1s3NzUhPTyca5O9mYGAAYrGYuEhTq9VgGAbx8fFe43/961+xfft2on2DwoQ+K16kCIVC3HDDDXjllVe8xqVSKSIjIzE4OEh0PXw+H2lpaUHpq8NisVBaWore3t6gNtzjcDioqKiASqVCX1/fOV9PUqDMRi6Xo7KyEsXFxejv78fu3buJxzKtdBwOBzo7O7Fr1y4YjUZUVVVh7dq1AbOezMVihArDMDh+/Di4XC6KiooIrXBulEolrFZrUKwoTqcTvb29yM3NJR4H09/fj7S0NK9MO5qm8eqrr+LWW28lupYwoc+KFymAq+LdP//5T5+N2d1Xh/Smk5WVBZVKBb1eT3RewOXOyMnJQVNTU1DdPiKRCOXl5Whraztr1lGwBIobiqKQkJCAbdu2IS8vD21tbdi7d6/nbi/M3NA0DaVSiV27dkGtVmPDhg3YsGEDZDJZUNazUKHS2dkJrVaL8vLyoKajGwwGtLe3o6SkhHj5e8DlWuFyucStFiaTCePj4z6uns8++wwWiwVXXHEF0fWECX3OC5FSVFSEsrIy/PWvf/UaT0hIgN1uJ17MSyQSITk5OWhul5ycHLBYLHR2dgZlfjfR0dFYs2YNjh49OufGEWyBMhuKopCamort27cjJSUFjY2NOHToEFQqVViszMLhcKCvrw+7d+9Gf38/iouLsWXLFk9jwGByLqGiVCqhVCpRUVFB1NJzJgzDoKmpCWlpaUGJh6FpGt3d3cjOzg6KFSU+Ph5CodBr/JVXXsEtt9wSLoMfxofzQqQALmvK73//e58A2vT09AW5HPxNXl4eRkdHg5JBwmKxUFZWBqVSGVS3D+CKk3FvHLPjdEJJoMyGzWYjOzsbX/rSlxAbG4vm5mbs3r0bvb29F3QvIJPJhNbWVnz22WcYGBhAfn4+tm3bhoSEhJAqujWfUOnv70d7e3tQrT1ugunmAVzfhTu5gCROpxMDAwOeonxuRkZG8N///he33HIL0fWEWRmcNyLl6quvxvj4OPbu3es1np6ejvHxcZhMJqLrEYlESE9PD1pfHalUGhJuH8C1ceTl5eHw4cPQarUhK1Bmw+VykZeXh4suugj5+fkYHh7Gp59+iubmZszMzFwQ1hWapjE2NoYjR454Yk4qKipQXV2NlJSUkBInszlTqAwNDeHUqVPYsGFD0M83t5untLQ0KG4eh8OBrq6uoNRkGRkZAY/H87EevfLKK7j44ot9XEBhwgAruCz+mQgEAtx666148cUXsW3bNs+4UChEfHw8+vr6UFhYSHRNubm5+PzzzzE1NRUUc3hOTg7GxsbQ2dmJgoIC4vPPJjs729P0DwA2bdoU9A1jIbBYLCQnJyM5ORkajQYDAwM4dOgQxGIxUlJSoFAo5u3guxJhGAYzMzMYGxvD0NAQWCwWUlNTUVxc7GOiD2Xcd+uHDh0CAGzYsCHoLqnZbp5graW3txcikYh4LArDMOjr6/NpG2K1WvHKK6/4uOrDhHFz3ogUALjtttuQk5ODwcFBpKamesYzMzPR0NCA3Nxcoj5PPp+P7OxstLW1obKykvidi9vts3//fiQkJBAv2HQmXC4XNE2Dw+EQbWTmL+RyOeRyOQoLCzEyMoLR0VG0t7d7LvoKhQJRUVEha2GYD4fDgYmJCahUKqjVatA0jfj4eJSWliIuLm7FfR43s3/roXC+9fb2BtXNY7Va0dPTg/Xr1xP/P52enobBYPBxMb399tuQy+XE+waFWTmcVyIlLS0Nl19+OV5++WU8+eSTnvHo6GhERESgv7+feOGirKws9PX1QaVSISEhgejcgLfbp7q6OmgXa7eLx12b5NChQ9i0aRPkcnlQ1rMcOBwO0tLSkJaW5gnMVqlUaGhoAOCqeKxQKBAdHR3UAM35YBgGJpPJs+6JiQkIhUIoFAqsW7cOUVFRK74R48DAAE6ePIn169fDYDD4vSnhYtHr9ejo6MDGjRuD4uYBgK6uLkRHRwclWLerqwsZGRk+N4kvvvgibr/99hV/voUJHOeVSAGAH/7wh7j66qvx8MMPe0pdUxSF3NxcNDc3IzMzk+hG7Y5taG9vh0KhCMpdabDdPmfGoLg3wUOHDoV0XMpC4HK5SExMRGJiIhiGwfT0NFQqFTo6OqDX6yEQCDwWGLlcDplMBoFAQGx9DMPAaDRCq9VCo9FAo9FAq9XC4XAgMjISCoUChYWFQSkmFijc59uGDRsQExODuLg4AP7vnrxQQsHNYzKZ0N/fj6qqKuJza7VaTE1NoayszGu8vr4era2tuPHGG4mvKczK4bwTKdu2bUNGRgb++Mc/4q677vKMx8fHg8fjYXBwkHiVyfT0dPT29mJwcDAowWGz3T5ulwQp5guSzc7OBovFQl1dHcrLyz0byUqGoihER0cjOjoahYWFsNvtXuJgaGgIRqPRI1xEIhH4fD4EAoHXg8vlLljMMgwDq9UKi8Xiebj/bTAYoNFoQNM0JBIJ5HI5kpKSPKIkFFwg/oRhGHR1daGnp8fnfHPHqARDqPT29sJmswXNzQMA7e3tSExMDEpmU1dXF1JTU32sik8++SRuu+22oGdbhQltKOY8TFN45513cPfdd6O3txc8Hs8zPjQ0hI6ODmzfvp24eXF0dBQtLS3Yvn2715pI0t3djb6+PlRXVxNxQywki2doaAgtLS3Iz89HVlbWio1/WChu4aLVamE2m73EhcVigdPpBIvFAp/PB4fDAUVRnodGo4FUKgXgyryx2+2eRo48Hs9L8PD5fIjFYsjlckil0vPenO5wONDc3Izp6WmsX79+3o2PdGbZ1NQU6urqghooPjk5iSNHjmD79u3Eg58NBgNqa2uxfft2iEQiz7i7sWNvb6/fm0+SQKfTQSaTYaYrE1LJ8sW+Tu9EZK4SWq3W8xsP4+K8FCk0TaOgoAD33Xcfbr75Zq/x3bt3Y9WqVUhOTia6JoZhcOTIEYhEIhQXFxOde/YaGhsbYbFYsGnTpoBuXIvZDGZmZlBfX4+4uDgUFxefd3f4i8HhcHgJFoZhQNM0HA4HmpqaUFZWBi6XCxaLBQ6H4xEkF/J3ZjabUV9fDzabjfLy8nO600gJFZPJhH379iE/Pz9oPYJomsa+ffuQnJxMPB4PAJqbm0HTtI+r54YbboBIJPJpZ7JSCIsUcpyXt1csFgv3338/nnrqKa8aISwWC9nZ2ejq6iJe54KiKBQVFWFoaCgozQfdaygpKVl087/FsthNIDIyEtXV1dDr9Th06BAsFktA1rUS4HA4iIiIQExMjCcANzEx0RN07c4iiouLQ1RUFEQi0QUtUKanp7Fv3z7IZDJs2rRpQfE+y+mevFBCpYlhX18faJpGVlYW8bnNZjOGhoaQnZ3ts6Z//vOfuO+++4ivKczK47wUKQBw/fXXw2Qy4d///rfXeGpqKmw2G9RqNfE1RUREIDMzM6AC4VxwOBysX79+wc3/FstS71KFQiEqKyshFouxb9++oFfKDRP6DA4O4vDhw8jJyUFJScmixFoghYq7iSGPxwtqE0OLxYKOjg4UFRUFxd3X29uLuLg4H8vAM888g6997WtBEU5hVh7nrUjh8Xj4yU9+gieffNKnVH5WVlZQrCmAq8CbxWIh3p15NkKhEBUVFWhra/NrX6PlmtHZbDbKysqQmZmJQ4cOYXh42G9rC3P+QNM0Tp06hVOnTqGiomLJsUyBEipdXV3QarVYt25dUGOBWltbERcXF5SgdKvViv7+fuTm5nqNq1QqvPbaa3jggQeIrynMyuS8FSkAcMstt2BgYACfffaZ13h6ejqMRmNQrCkcDgerV69GW1sbbDYb8fndREVFoaioCEePHoXRaFz28fzl56coCjk5OVi3bh1aWlrQ1tZ2QZSgD7Mw7HY76uvroVarUVVVtewN2N9CZXR01FMwLZg1ciYnJzE2NobVq1cHZf7u7m5ER0f7FJB84YUXUFNTE7S4vDArj/NapIjFYtx1111ehd0AV22L3NzcoG2ACQkJkMvlaGtrIz73bNLS0pCSkoL6+vplNc8LRCCiQqFAVVUVRkdHceTIEZjNZr8cN8zKxR1/QlEUqqqq/NaOwF9CRavV4vjx4ygrKwtq8KPT6cSJEyeQm5sblFYGJpMJfX19PjWZNBoNfve73+HBBx8kvqYwK5fzWqQAwB133IGmpqY5Gw86nU4MDQ0RXxNFUVizZg2Gh4cxPj5OfP7ZFBYWQiAQ4Pjx40sSbIHMlJBIJJ506T179mBwcDBsVbkAcTqdaG1txeHDh5GWlob169f7vb3FcoWK1WpFfX09cnJyglJZejZdXV2eJIFg0NHRMWdNlueffx6lpaWorKwMyrrCrEzOe5ESGRmJ++67D/fff79PbEp+fj46OjqC0iVYLBajsLAQzc3Ny7JiLBcWi4V169ZBr9cvumMziVROLpeLsrIyrF27Fm1tbaivrw9bVS4gpqensXfvXkxNTaG6uho5OTkBq6WzVKFC0zSOHj2KyMhInxgM0szMzKC3txelpaVBiYfR6XQYGRlBfn6+17harcZzzz3nY9UOE+ZcnPciBQDuvvtuDA4O4r333vMaT05OBpfLRX9/f1DWlZ6eDrFYjNbW1qDM74bH42H9+vXo6+tbcLAq6aJYCoUCNTU14HK5qK2tDVtVznNmW09SU1NRWVlJpHT/YoUKwzA4ceIEHA4HSktLg1qM0Ol0oqmpCTk5OUGr4tre3o60tDRPSxI3v/jFL1BTU4NNmzYFZV1hVi4XhEgRi8V49NFH8dBDD8HhcHjGKYrCqlWr0NXVFRRrBkVRKC0txcjISNDdPhKJBOvWrUNzczOmpqbO+lrSAsUNj8fD2rVrUVZWFraqnMe4rSeTk5OoqqpCTk4OUavAYoRKb28vVCoV1q9fH7TGgW46OzvBYrGCUrQNcP2/TUxM+FiTlEolXn31VTzxxBNBWVeYlc0FIVIAV6aP3W7Hn//8Z6/x+Ph4SCQS9Pb2BmVdIpEIBQUFQXf7AK7voqioCEeOHJn34hwsgTKbM60qQ0NDYavKecBs60lKSgq2bNkStADUhQgVpVKJrq4ubNiwISgBqrOZmZmBUqlEWVlZUNw8DMOgra0N2dnZPgX1Hn30UXzzm99EYWEh8XWFWflcMCKFy+Xi8ccfx//+7/963X1TFIWCggL09PQErdJpqLh9AFfGz6pVq3DkyBGfyrihIFDcuK0qpaWlaG1txZEjR6DVaoO6pjBLg2EYjI2NeVlPcnNzg95v6GxCZWBgwNNpWS6XB2eBp5nt5gmWqFOr1dDr9T4F2lpaWvDOO+/gZz/7WVDWFWblc8GIFAD4xje+gbi4OLz00kte41FRUYiLi0NHR0dQ1jXb7TM2NhaUNcwmMzMTubm5qKurg06nAxBaAmU2CQkJqKmpgUQiwYEDB9DY2OiXui9hyDA5OYkDBw6gpaUFmZmZQbWezMVcQmVoaAgnT57E+vXrQ+K30NbWFlQ3D03TaG1tRV5enk/W1YMPPojvf//7Qen+Hub84IISKSwWC7/85S/x5JNP+lgJVq9ejeHh4YD18jgXIpEIJSUlaGpqgslkCsoaZpOdnY3MzEwcPnwYbW1tISlQ3PB4PKxevRo1NTWgKAp79uzBiRMnLugeQKGOVqtFXV0d6uvrER8fjx07diAjIyPo1pO5mC1UOjs70dLSgoqKCsTExAR7aRgbG8Pg4GBQq9v29vaCxWIhPT3da3zfvn04dOgQHnrooaCs63wmPT3dq0O6+3H77bfP+55//etfyM/Ph0AgQFFRET766COCK146oXdFCDBf+tKXUFpail/+8pde4yKRCDk5OUHtq5OUlITExEQ0NjaCpumgrGE2ubm5kEql6O7uRnFxcUgKlNmIRCKUlZWhuroaZrMZu3btQkdHR9BjfcJ8gdFoRGNjI/bv3w+JRIIdO3YgLy8v6EGn5yIzMxOJiYno6OhAfn5+UErNn4nJZEJTUxOKi4v9VthusZjNZnR2dmLNmjVeIommadx///249957Q0LMnW8cPXoUY2Njnsfnn38OALj66qvnfP3hw4dx7bXX4jvf+Q6amppw5ZVX4sorr8SpU6dILntJXHAihaIoPPPMM/jNb36D7u5ur+eys7PhcDiClpIMAEVFRbDb7UFzPc2mr68P09PTSElJwalTpzyun1BHKpVi/fr12LhxIyYmJrBr1y709vYGpR5OGBdWqxUnTpzAnj17QFEUtm/fjtWrVwe1dPxiGBoawsjICNLS0tDZ2Rk0i6sbmqbR2NiIxMREJCcnB20dp06dQkJCAqKjo73G//rXv2J0dBQ/+tGPgrSylYlOp/N6WK3WOV8XGxvr6YiuUCjw4YcfIisrC9XV1XO+/te//jUuueQS3HvvvVi1ahUee+wxlJWV+YQ+hCIXnEgBgNLSUtx000344Q9/6FPgbfXq1Whvb5/35Ag0bDYb5eXlUCqVQU1LdsegbNq0CWVlZcjIyMChQ4d83GShTHR0NCorK1FaWoqBgQHs3r0bvb29YcsKQUwmE1pbW/H555/DbDajuroaZWVlEIlEwV7aghkYGPC4eEpKSgLWPXkxuC2EwerNAwDj4+MYHx/3ydrRaDS477778Nxzz/nUSwlzdlJSUiCTyTyPhRS/s9lsePPNN3HzzTfPW6enrq4OO3bs8Bq7+OKLUVdX55d1B5LQtrEGkMcffxy5ubl477338D//8z+ecYVCgejoaLS3t6OkpCQoa5NIJFizZg0aGxuxdetW4umNcwXJ5uXlgc1m4/Dhw9iwYUPIu37cUBQFhUKB+Ph4jIyMoLe3Fx0dHUhNTUVmZmb4IhoAGIbB9PQ0lEolVCoV4uPjsWnTphVzzsymr68PbW1t2LBhg8dtkZmZCcB14Q9GnNb4+DiUSiWqqqqC5iajaRonT570xDjM5tFHH0VxcTGuuuqqoKxtJTM0NOQVOL4QS+N7770HjUaDnTt3zvsa9+9wNvHx8VCpVEteKykuFlnpVwAAQN5JREFUWJESGRmJp556CnfffTcuvvhirzu71atXo7a2FqmpqUG7sKampmJychKNjY3YtGkTsaC4s2XxZGdng8Vioa6uDhs2bPAx8YYyFEUhOTkZSUlJnpoSe/bsQVxcHNLT0xEXFxfUaqHnAw6HAyMjI+jr64PRaERaWhq2b9++oqwms3EL2rl+C8ESKmazGY2NjVizZk1Qs6DcwbIZGRle4y0tLfjjH/+Ipqam8O9pCUil0kX/v/7pT3/CpZdeisTExACtKrhckO4eNzt37kRCQoJPJUSxWBz0IFoAWLNmDex2O7HgpoWkGWdmZmL16tWoq6vD4OAgkXX5E4qiEBUVhXXr1mHHjh2QSqVoamrC559/jo6OjnAF2yWg0WjQ0tKCTz/9FEqlEmlpabj44ouxevXqFSlQaJrGiRMn0NXVdVYLkL+6Jy8Up9OJhoYGKBQKpKSkBHy++XAHyxYVFXndPDEMg9tvvx133nkn8vLygra+C4mBgQHs2rULt9xyy1lfp1AooFarvcbUajUUCkUgl+cXLlhLCuBKSf7d736HyspK3HjjjV51BrKzszE0NASlUulToIgUHA4H69evx759+yCVSn1S/PzJYuqgpKWlQSgU4tixY9Dr9SgoKFiRd01CoRCrVq1CXl4e1Go1BgYG0NXVhbi4OCQmJiI+Pn7FBHaSxmAwQK1WY2hoCAaDAcnJydi0aRPkcvmKPBfc2Gw2HD16FDabDdXV1ecUWaQsKgzDoKmpCSwWC2vWrAnad+zuVZSQkOCTtfPXv/4VAwMD+OSTT4KytguR119/HXFxcbj88svP+rqNGzdi9+7duPvuuz1jn3/+OTZu3BjgFS6fC1qkAEBZWRl27tyJO++8Ex999JHnx89ms1FSUoIjR44gPj4+aCl+IpEI5eXlOHLkCCIiIgKSzreUQm1xcXGoqqpCfX09dDod1q1b51PIaaXAYrGQkJCAhIQEmM1mDA4OQqlUorm5GVFRUYiPj4dCoSDS4C5UcceZqFQqqFQqGI1GxMTEID09HUlJSSv2/342Op0ODQ0NnuywhcZ7kBAq3d3dmJ6eRlVVFdhstt+Pv1CGh4cxMzODmpoar3GNRoN7770XL730UtCulRcaNE3j9ddfx4033uhzrn77299GUlKSJ/D2rrvuQnV1NZ599llcfvnl+L//+z8cO3YMf/jDH4Kx9EVBMeGmJ5ienkZubi5effVVryBaADh58iQ0Gg0qKyuDeofY39+P9vb2Bd3dLYblVpK12+2eKq/r168/ry5QZrMZarUaKpUKExMTEAqFnpS/qKgoosWz7HY7PvroI1x22WXEBIHD4cD4+DhUKpXHVOwWbLGxseeFMHGjUqnQ2NiIrKws5OXlLem3HqiqzCqVCseOHUNlZWVQS/BbLBbs2bMHpaWlSEhI8Hrurrvu8mRxrWRL2kLR6XSQyWSY6cqEVLJ80ajTOxGZq4RWq11wTMpnn32Giy++GJ2dnT5NHbdu3Yr09HS88cYbnrF//etfePjhh9Hf34+cnBw8/fTTuOyyy5a99kATFimnef311/Hwww+jtbXV60LgcDiwd+9eZGRkBM3t46alpQXT09PYsmWLX6L6/XVRdTcXGxgYwLp160Ki0JW/cTgcmJiY8FgSGIZBfHw8YmNjIZfLIZFIAnpxJiFSnE4ntFotNBoN1Go1JicnIRKJvITZ+bYBMQyD7u5udHV1obS0FElJScs6nr+Fik6nw4EDB1BSUrLstS0HhmHQ0NAADoeDtWvXej135MgR1NTU4Pjx48jPzw/SCskSCiLlQiEsUk7DMAwuvfRSJCQk4PXXX/d6bmpqCnV1ddi6dWtQLQU0TaOurg5cLhfl5eXL2jACcdc3NDSElpYW5OfnIysr67zb0NwwDIOZmRmoVCpMTU15Ghu6axvI5XLI5XJERET4zdrib5HicDig0+mg0Wig0Wig1Wqh1+vB5XIhl8s9xaLOJ8vYmTgcDjQ3N2N6ehoVFRV+s1L467dls9mwf/9+JCUlYdWqVX5Z21IZGhpCa2srampqwOPxPONmsxmlpaXYuXMnHnjggSCukCxhkUKOCz4mxQ1FUXj11VexevVqfP3rX/cKRIqOjkZaWhqampqC6vZhsVgoLy/H/v37cerUKaxevTqkzNIpKSmIiIjwxKkUFxcH1X8eKNwZQu7vjmEY6PV6z2Y/MDCAEydOAHClFMrlcshkMohEIggEAggEAnA4nICfRwzDwGazwWKxwGq1wmAweESJXq8Hj8fzCCqFQgG5XA6hUHjeisvZmM1m1NfXg81mo6qqyqfWx3LwR4yKw+HAkSNHIJVKg26dMJvNOHnyJEpLS70ECuCqiSKTyfCTn/wkSKsLc74TtqScwZ/+9Cc8+uijOHXqFCIjIz3jbrdPeno6srOzg7hCV/+TAwcOICsra9GdT0l0MzabzWhoaABFUaioqPDrBrBSYBjGSxRotVqYzWZYLBbQNA02mw2BQAA+n+8RLu6/8/l8sFgssFgsT+MwmqZx8OBBbNq0CWw2GzRNg2EYOJ1OjwixWCxeD6vVCoZhwOFwIBAIIBKJPKJELpdDIBBcEILkTKanp9HQ0ID4+HisWbMmYEJ6qb81mqbR0NAAh8OBjRs3BlXoMwyD+vp6cLlcHzdPXV0dtm/fjmPHjqGgoCBIKwwOYUsKOcIi5QwYhsFll12G+Ph4r6Aj4Au3T3V1ddAzPbRaLQ4ePIjVq1cvuA06CYHixul0orm5GZOTk1i7dm24ydhpGIaBw+GYU1CcKS7cQsT9d7vdDh6P5yVgWCyWj8iZ/eDz+SHfvI8UDMOgv78fra2tKCgoQEZGRsBF2mJ/c+5UY61Wi8rKyqAHJw8ODqKtrW1ON09JSQluvvlm3H///UFcYXAIixRyhEXKHAwPD2P16tV46623fPLPT506hcnJSWzZsiXorozJyUkcOXIE69atO2dRHpICxQ3DMJ6y4qmpqSgoKAhvmEskGNk95xPujsFGoxGlpaWIjY0lNvdifnutra0YHR3Fli1bgm6BNBqN2Lt3L9auXetzffnJT36CAwcO4NChQxfkbzosUshxQVecnY/k5GQ899xzuPXWWzEzM+P1nDuAra2tLRhL8yImJgZlZWU4duzYWSteBkOgAK7YjczMTGzduhVarRa1tbWYnJwkNn+YMG6hXFtbC7FYjG3bthEVKMDCK9P29vZicHAQGzduDLpAcTqdOHr0KFJTU30EyuHDh/Hyyy/jjTfeuCAFShiyhEXKPNx0000oKSnxqtAHfNGleHBwEGNjY8FZ3CwSExNRWFiII0eOQKfT+TwfLIEym4iICFRWViIzMxNHjhzByZMn4XA4grKWMBcOJpMJhw8fRnd3N8rLy1FSUhI0K9S5hMrw8DA6OjqwYcOGkMioct+EnRlrYjabcdNNN+F///d/g55xFObCICxS5oGiKPzhD3/Af/7zH/zrX//yek4sFqOkpARNTU0wmUxBWuEXZGRkIDMzE4cPH4Zer/eMh4JAcUNRFLKysrB161ZoNBrs3bsXU1NTQV1TmPMTd+zJbOtJKNTumU+ojI6Oorm5GeXl5V7B+sFibGwMg4ODWLdunY9L+8c//jGioqLw4x//OEirC3OhERYpZyE5ORmvvfYabr31ViiVSq/nkpKSkJSUhGPHjoGm6SCt8Avy8vKQmpqKw4cPw2AwhJRAmY3bqpKRkYG6urqwVSWMXzGZTKirq0NXV1fQrSdzcaZQGRsbw/Hjx0OmCKI7dqe4uNjHovP222/j73//O/7+978HPR4vzIVD2KF4Dv7nf/4HtbW1+OY3v4lDhw55RbivXr0a+/fvR3t7OwoLC4O4SpelYtWqVWAYBvv37wdN02ft4BpM3FaV+Ph4NDU1Ye/evSgtLUV0dHSwlxZmhcIwDAYGBtDa2oqkpCSUl5eHlDiZjbuOyqFDhwBgQYHvJKBpGo2NjUhMTERycrLXc0qlErfccgtee+21gDY6DRPmTMKWlAXwq1/9CjRN+1RUZLPZWLduHfr6+jA+Ph6k1X0BRVEQCARwOBxgs9k+hZdCDbdVJT09PWxVCbNk3NaTzs7OkLSezIVQKIQ7sTJUOm13dHTAbrejqKjIa9xms+Gaa67BDTfcgK997WtBWl2YC5WwSFkAfD4f//d//4c//vGP+M9//uP1nEQiwZo1a9DY2Aiz2RykFbpQKpXo6OjA5s2bkZqaikOHDnnFqIQiFEUhOzsb1dXV0Gg02L17N/r7+0PChRYmtLHZbGhtbcWePXsgFApRU1MTEi6TczE6OorGxkaUl5ejsLDwnFk/JFCr1VAqlXPGoTz44IOw2+341a9+FaTVhbmQCbt7FkhOTg5eeeUV3HTTTWhubkZKSornudTUVExPT6O+vh6VlZVBScs7MwbF3Qzu0KFD2LRpU8jn3kskElRWVmJ0dBTt7e3o6elBQUEBEhISLsiqqGHmx+l0QqlUoru7GzKZDJs3bw6JgNOFMDw8jObmZh8Xz3JK6C8XvV6PY8eOoaSkxOc68eGHH+LVV1/FsWPHgp4WHebCJGxJWQTXXnstvva1r+Haa6/1cUu4y2s3NzeDdH28uYJk3TEqGRkZOHjw4IrIpKEoCklJSaipqUF2djZOnDiB/fv3Y2JiIthLCxMC0DSN/v5+7Nq1CyMjI1i3bt2KEihKpRLNzc2oqKjwEigLraMSCOx2O+rr65GRkeEThzI8PIwbb7wRv//975Gbm0t0XWHCuAmLlEXy61//GhqNBo8++qjXOIvFQkVFBaanp9Hd3U1sPWfL4qEoCnl5eSgoKEBdXV1I1HVZCCwWC+np6dixYwcSEhLQ0NCAw4cPQ6PRBHtpYYIAwzAYHR1FbW0tenp6sHr1alRXV68I1w7gWn9bWxs6OzuxadOmOdcdDKFC0zSOHTuGiIgIn5onDocD1157Lf7nf/4H1113HZH1hAkzF2F3zyIRiUT45z//iQ0bNmDt2rW46qqrPM/x+XysX78eBw4cgEQiQUJCQkDXstA04/T0dPB4PDQ2NqKoqGjBvX6CDYfDQW5uLtLT09Hd3Y2DBw9CoVAgPz8/JApehQk8ExMTaGtrg9lsRl5eHtLS0sBirZx7K5qm0dLSgomJCVRWVp6155c/uicvhra2NphMJlRVVfm4VO+55x5otVr85je/CegawoQ5F2GRsgQKCgrw17/+Fd/61reQnZ2N4uJiz3MymQxlZWU4fvw4tmzZErBYkMXWQUlMTASPx0NDQwMsFgtyc3NXTKwHj8dDYWEhMjMz0dHRgdraWqSmpiIvLy/sJz9P0Wg0aGtrw8zMDHJycpCZmbniSrA7HA40NjbCaDRiy5YtEAqF53wPKaEyODiIwcFBVFVV+WRCvfrqq/jb3/6Go0ePQiQSBWT+MGEWysq5JQkxvvrVr+KBBx7AFVdc4ZN+nJiYiKysLNTX18Nms/l97qUWaouJicHmzZvR19eHkydPEo+dWS5CoRClpaXYunUrrFYrdu3ahZMnT8JoNAZ7aWH8AMMwmJqaQkNDAw4ePAiZTIYvfelLyM3NXXECxWazoa6uDna7fcECxU2gXT/T09M4ceIEysvLfSySBw4cwN133423334bGRkZfp87TJjFEu6CvAwYhsG1116L0dFR7Nq1y6suCcMwOHr0KOx2OzZu3Og3E7U/Ksm6e5pIJBKUlZWFfE2J+ZiZmUFvby/GxsYQFxeHzMxMxMTErBgL0WI4n7sgO51OjIyMQKlUwmg0Ii0tDVlZWYva2EMJvV6P+vp6SCSSOVN6F0ogqkabzWbs27cPubm5HquNm4GBAZSXl+PnP/85brvtNr/Md74S7oJMjrBIWSYmkwlbtmzB2rVr8corr3htkA6HAwcPHvSIgeVunv68aNlsNhw7dgwWiwXr16+HWCxe1vGCidlsRl9fHwYGBsDn85GZmYmUlJTzqnT3+ShSLBYL+vv70d/fDy6X6/l/W2lWk9mo1WocO3YMGRkZWLVqVcj95g8ePIjo6GisWbPGa21GoxGbN2/Gpk2b8Lvf/W5Z81wIhEUKOcIixQ8MDQ2hvLwcjzzyCG6//Xav5ywWCw4cOICEhASsXr16yXME4q6Kpmm0tbVhcHAQ5eXlxFvY+xun04nh4WH09vbCYrEgOTkZ6enp58WP/nwRKQzDYGJiAv39/VCr1YiJiUFmZibi4uJWtAWMYRj09vaio6MDJSUlPum8y8Efv32n04nDhw+Dx+OhvLzcy7JL0zS+8Y1vYGpqCp999tmKPr9IERYp5Fi5tywhREpKCv79739jx44dWLVqFWpqajzPCQQCbNy4EQcPHoRAIEB2dvaijx+oZoEsFgurV6+GRCJBfX09CgoKkJGRsWI3CzabjbS0NE9xvYGBAezfvx9SqRRpaWlISkpa0XfpKxmz2YzBwUEMDAyApmmkpqaioKDgvMjScjqdngyeQNRtWW4wrTvVGHD1CTrT9fz444/j+PHjaGhoCAuUMCFH+IrtJzZu3IiXXnoJV199NQ4dOoT8/HzPcxEREdiwYQMOHToEPp/vVa32XJDoZpyWlgaJRIKGhgbodDqsWbNmRaV5nglFUYiOjkZ0dDSKioowNDQEpVKJU6dOISkpCQkJCYiJiTmv3EGhiM1mg1qtxujoKNRqNWJjY7F69WooFIoVfX7NxmKxoKGhAQzDoLq6OmDZZksVKgzDoKWlBUajEZWVlT7n/D/+8Q8888wzOHz4MGJiYvy+7jBhlktYpPiRm266Cb29vbj44otx+PBhJCUleZ6Ty+WoqKhAfX09eDwe4uPjz3k8EgLFTVRUFKqqqjyZFevWrTsv0g/dsQ4ZGRnQaDQYGhpCS0sLbDYb4uLioFAoEB8fHzJN3lY6BoMBKpUKKpUK09PTkEqlSEhIQFFR0XlxPs1mcnISjY2NiImJQUlJScBF71KESkdHByYmJrBlyxafhqO7du3CzTffjLfffntZrugwYQJJOCbFzzAMg1tvvRX19fXYv3+/j+l3ZGQETU1N2LRp01kvMiQFymycTidOnTqFkZERlJaWBrwgXTBgGAY6nc6zmWq1WkRGRkKhUEChUCAiIiLkXF6hGpNC0zRmZmY836XJZEJMTIznu1ypGTpng2EYdHV1obu7G4WFhUhPTyd6viz02qBUKtHZ2TlnEbnjx49j27ZteOmll3DDDTcEesnnHeGYFHKERUoAcDgcuOqqqzA9PY3PPvvM50J9touH+/lgCJTZjIyMoLm52RM7cD67RiwWi2eTnZiYgFAo9FhYoqOjQ8I1EUoixW63Y2JiAmNjY54aQfHx8VAoFIiLizuv434sFoun43l5eTlkMllQ1nGua8TZboZ6enqwefNm3Hffffjxj39MasnnFWGRQo6wSAkQZrMZF110EaKiovDOO+/4XLjb29sxMDCAyspKr+DBUBAobgwGg1fA3fkQ5HguHA4HJiYmoFaroVKpQNM0YmNjERkZCblcDplMFhSREEyRYjabodVqodFoMD09jcnJSURERCA+Ph4JCQmIjIwMOctTIBgfH0djYyPi4uJQXFwcdDE237VibGwMjY2NKC8v93Erq1QqbN68GV/72tfwq1/9ivSSzxvCIoUcYZESQGZmZrBlyxZs3LgRf/jDH7wu5O6mY8PDw6isrIRYLA4pgeLG6XR60pSLi4v9mloZ6jAMg5mZGUxMTECj0UCj0cBisUAsFkMul3tEi1wuD7hwICFSGIaBxWKBRqPxiBKNRgOr1YqIiAjPZ46Pj78gBKsbmqbR0dEBpVKJNWvWIDU1NdhL8nDmNUOlUuHYsWNYu3atj6tWp9OhuroaRUVFeOONN0LCQrhSCYsUcoRFSoAZGRnBpk2b8O1vfxuPPfaY13MMw6C1tRWjo6NITU1Fb29vSAmU2YyNjaGpqQnx8fEoKiryCcK7ULBarZ7N272Zm81miMVij2Bxixd/fkf+FimzBcnsz2K1WiGRSHw+S7CtBsFCp9Ph+PHjoGka5eXlZ20QGCzcQiUvLw8dHR0oKytDYmKi12usVisuvfRSCAQCvP/++0F3Ga50wiKFHBfmlYcgSUlJ+PTTT1FZWYnY2FjceeednucoikJhYSE0Gg06OztRXl4ekgIFgMes39LSgj179qC4uPi8DKo9F3w+H/Hx8V5mdKvV6rE8zMzMoK+vD2azGRwOBwKBAAKBAHw+3/P3M//N4XD85i5hGAY2mw0WiwVWqxUWi8XrMXuMpmlIJBKPdSQvLw9SqfSCFSSzoWka3d3d6O7uRmZmJvLy8kI2LiszMxN6vR6tra3Iz8/3ESgOhwPf+ta3YDQa8cEHH4QFSpgVRfhqRID8/Hx89NFH+NKXvgQej+fVF6Ovrw8ajQaJiYk4deoUZDJZyJaoFwgEqKiowPDwMJqamjA6OnpBW1Xc8Pl8xMXFIS4uzjPmFgpnPmZmZrz+TdM02Gy2R7BwuVxQFAWKosBisTx/dxs8T5w4AYqiQNM0GIYBwzCgaRpWq9UjQBiG8RJI7kdUVJTPWFiQ+DLbehKI4mz+RqVSYWhoCCkpKejp6UFsbKznZsfpdOLGG29Ee3s79u7dG7LXljBh5iN8hSJERUUFPv74Y1xyySXgcDi45ZZbPGbaTZs2ITIyEq2trTh48CA2b94csj5/iqKQkpKC2NjYC96qcjZ4PB54PN5ZTbcMw8DhcHiJFrvd7iU+3H93OBwA4BEWswUMi8UCj8fzstKExcfioWkaPT096OrqCnnriRt3kKzbxaNUKj11VGQyGW666SY0NTWhtrY2XKzt/7d351FN3vn+wN8hIAHCviWsQVbZRJYiIAIuFfXWnrlep7ba1nbstLW3Hemu7Z3xtudap3Ntp2fGllN7a52pM2r1the1tgoSZVERBVER2YUACYvsZM/z+8OT50cKKCiEBD6vc54DJE+SbxCf553v9/P9PsQs0ZHMiJKTk3HixAmsWrUKd+7cQUREhEENSkREBDgcDgoLC5GcnGzSY5P6XpXm5ma2VyUiImLKVtyciTgcDqysrGBlZXXfWge1Wo26ujqEhIRQd/0U6OnpwdWrV6HRaMyi9wT4/9OMhxfJ6hd8KyoqwsGDB3H58mWIxeJxLR5JiCmi8m4jS01NxbFjx/DBBx+gvr7eoAaFw+EgPDwcIpEIhYWFuHPnzjS29P44HA78/PyQkZEBnU6HvLw81NXVQafTTXfTCBkXlUqFq1evorCwEB4eHkhPTzeLgNLQ0ICysjLEx8eP6MX09/fHt99+iwsXLuDMmTMQCATT1EpCHh71pEyD9PR0HD9+HI899hh4PB5eeOEF9j4Oh4OwsDBYW1ujuLgY8fHxJn+QsbGxQUJCAtrb23Ht2jU0NTUhOjoarq6u0900QkbFMAyamppQWVkJJycnpKenm+wQ63AMw6CqqgoNDQ2jLtSm1Wrx/PPPo7y8HOfOnRtRREuIuaGQMk3S09Px448/YvXq1dBoNHj55ZcN7g8ICIC1tTVKS0tNbm2GsXh4eCAjIwN1dXU4f/48hEIhDQERk9PT04OKigooFArExMRAIBCYxWJ0Op0OFRUVkMlkWLRo0YjhYI1Gg2effRZlZWUQi8VUJ0ZmBAop0yg1NRU//fQTVq5cCYVCgaysLIP7vby8YGVlhZKSEiiVSgQFBZn8wdTCwgLBwcHw8fHB9evXkZeXh9DQUAQEBJh8ESKZ2ZRKJaqqqtDc3IzAwEAEBwebTYGxVqtFaWkpBgcHsXjx4hGX2lAqlXj66adRWVmJ/Px8qkEhM4Z5/A+dwZKTk5Gbm4tVq1ahvb0dO3fuNAgi7u7uSElJwYULF6BQKBAZGWnyQQUwHAK6ceMG6uvrERYWBl9fX7NoP5k59EXH+um55jK0o6dWq3Hx4kUwDINFixaNmPLf39+PX/3qV+jt7UV+fj7c3d2nqaWETD4qnDUBCQkJKCwsxD//+U/85je/Yaeb6jk5OSE1NRUymQyXL182q8JUfTHivHnzUFVVhfz8fEilUtBCx2SqabVa1NXVITc3Fx0dHUhKSkJiYqJZBRS5XI7CwkJYWloiKSlpRECRyWRIT08Hl8ulgDLLtLS0YOPGjXB1dYWNjQ2ioqLYa62NRiwWs8sWDN+kUqkRWz1x1JNiIkJDQ1FcXIzMzEz86le/wqFDh2Bra8veb2dnh9TUVFy4cAFFRUV45JFHYG1tPY0tHj/92ipeXl5obGxEWVkZ+Hw+wsPDqbiWTDqGYSCRSFBVVQUul4sFCxbA09PT7Hrwuru7UVJSwl7Q8JfX2qmvr8ejjz6KxMRE7Nu3b9YvqjibdHd3IyUlBRkZGTh58iTc3d1RU1Mzrplpt27dMqhnGr4IpSmikGJCvLy8cO7cOaxZswbLli3D8ePHDar3ra2tkZKSgvLycpw9exaJiYnTdqn4B8HlchEYGMhep+j8+fNwc3NDaGioWUz7JKaNYRi0traiuroaarXarIcXJRIJysvLERYWhsDAwBHvoaysDCtXrsSTTz6J3bt308UCZ5k//vGP8PX1xb59+9jbAgICxvVYDw8PODk5TVHLJh/9ZZsYJycn/Pzzz/D09MSiRYvQ3NxscL+lpSXi4uIgEolQUFCA1tbWaWrpg7OyskJYWBiWLVsGPp+PoqIiFBUVob29nYaByITpdDrcvn0beXl5uH79Ovz8/LB06VL4+fmZXUDRXx396tWrSEhIGLVYPj8/H+np6Xj99dfxySefUECZQfr6+gw2pVI56n45OTmIj4/HunXr4OHhgQULFmDv3r3jeo2YmBgIhUIsX74cRUVFk9n8KUF/3ffQ0dGBl19+GX5+frC2toZAIMCKFStQVFSE9evXIzMz02D/n376CRwOBzt27DC4fceOHROaQmxjY4MjR44gNTUVycnJqKysNLifw+EgJCQEcXFxKCsrQ1VVlVme3Hk8HiIjI/Hoo4/C1dUVpaWlOHfuHFpbW83y/RDj0mg0qKurw+nTp1FbW4vg4GAsX74cgYGBZjmTTF8g29raisWLF486Q+fIkSP4l3/5F3z22Wd4++23HziE3evYBgAikWjU+oVdu3Y91Hsk9+br6wtHR0d2++ijj0bdr76+Hl988QWCg4Px888/4+WXX8Zrr72G/fv3j/ncQqEQ2dnZOHr0KI4ePQpfX1+kp6fjypUrU/V2JgUN99zD2rVroVKpsH//fsydOxcymQx5eXno6upCRkYG3nzzTWg0GnYaY35+Pnx9fSEWiw2eJz8/HxkZGRN6bS6Xi+zsbOzYsQMpKSk4ePAgVqxYYbCPUChEamoqLl68iL6+PsTGxprNlMrh5syZg7CwMAQFBeH27du4du0abt68yU5lpk+KZDiVSoWGhgbU19ezBYNCodDsek2GGxgYwMWLF2Fra4vFixePqC9hGAa7du3Czp07cfjwYaxevfqhXu9exza9Dz74wGChSQD3vXwDeTjNzc0G9SJj1R3qdDrEx8dj586dAIAFCxbg+vXryM7OxrPPPjvqY0JDQxEaGsr+nJycjLq6Onz66af4+9//PonvYnKZ3xnNSHp6elBQUACxWIy0tDQAd5ebfuSRRwAA1dXVGBgYQGlpKRYuXAjgbvX0u+++izfeeAMKhQI8Hg8KhQIXL17Ec889N+E2cDgc/Od//idCQkKwdu1afPDBB8jKyjI4GDs4OCAtLQ2XLl1CQUEBEhMTDQpuzYmlpSUCAwMhEokgkUhQXV2NyspKiEQiiEQiWhRuluvt7UVDQwMkEgmcnZ0RFxcHd3d3sw4nwN1ejUuXLsHPzw/h4eEjQvnQ0BB+85vfoLi4GAUFBYiJiXmo17vfsU3P3t7e5Fe7nmkcHBzGdc02oVCI8PBwg9vmzZuHo0ePTuj1HnnkERQWFk7oMcZGH1HHwOfzwefz8cMPP4w6LhgSEgIvLy/k5+cDuLtWwZUrV7Bu3TqIRCKcP38eAFBcXAylUjnhnpThNmzYgPz8fOzevRvPPfccFAqFwf1z5sxBUlISXF1dIRaL0dbW9sCvZQq4XC78/f2xdOlSLFiwAN3d3Th9+jRKS0vR2dlJQ0GziFarhUQiQWFhIQoKCgDcXQQxJSUFHh4eZh1Q9EvcX7x4EZGRkYiMjBwRUCQSCRYvXozm5mZcunTpoQMKcP9jGzF9KSkpuHXrlsFt1dXV8Pf3n9DzlJeXm/zKxBRSxmBpaYlvvvkG+/fvh5OTE1JSUrB9+3ZUVFSw+2RkZLBDOwUFBQgJCYG7uzsWL17M3i4WixEQEDDhP55fSkhIwKVLl3Dz5k1kZGSMCCIWFhaIjo7G/PnzceXKFVy7dg1arfahXnO6cTgceHp6IikpCRkZGeDxeCgpKcGZM2dQV1cHlUo13U0kU2RwcBA3btzAqVOnUFVVBYFAgEcffRQxMTFmNaNtLHK5HMXFxWhpaUFqauqoNWvnz59HfHw8YmJicObMmUmbKjqeYxsAvPPOO2yg0W/6oEimV1ZWFi5cuICdO3eitrYW//jHP/Dll1/ilVdeYffZtm0bnnnmGfbnP//5z/i///s/1NbW4vr169i6dSvOnDlj8BhTRCHlHtauXYvW1lbk5OQgMzMTYrEYsbGx+OabbwDcvf5OUVER1Go1xGIx0tPTAQBpaWkGIeVhelGG8/LywtmzZxEcHIyEhIRRF+7x9vZGeno6urq6UFBQgIGBgUl57enG5/MRGRmJFStWICQkBK2trfj5559x6dIltLW1mX0gI3drTRobG1FQUIC8vDwMDQ0hPj4eS5cuRVBQ0IxZB6S9vR1isRg8Hg9paWmjhq79+/dj2bJleO+997B3795Jf+/3O7YBwFtvvYXy8nKDLT4+flLbQR5MQkICvv/+e/zzn/9EZGQkPvzwQ/z5z3/Ghg0b2H3a2trQ1NTE/qxSqfDGG28gKioKaWlpuHr1KnJzc7F06dLpeAvjxmGo73xCNm/ejNOnT+P27duoq6tDUFAQioqK8Lvf/Q5vvfUWfv3rX6OlpQWBgYFobW2FUCjE119/bfDH87AYhsHu3buxY8cOfPXVV1i/fv2IfbRaLSorK9HU1IT58+fDx8dn0l7fVPT390MikUAikUCtVsPLywu+vr5wcXEx62GA0ajVavz4449YtWoVrKysprs5k0ar1UImk6G5uRnt7e1wdHSEj48PvL29zWaxwvHS6XS4efMmGhoaxrxoqEajwTvvvIN9+/bh8OHDWLZsmdHaN/zYJhKJsHXrVmzdutVor29O+vr64OjoiO7quXCwf/iZZH39WjiH1KO3t3dcNSmzCRXOTlB4eDh++OEHAEBgYCB8fX2Rk5OD8vJytgjN29sb3t7e2L17N1Qq1aT1pOhxOBy8+eabCA8Px1NPPYWSkhLs2rXL4NMWl8tFVFQU3NzcUFZWhs7OTkRGRprl7J+x2NvbY968eQgLC0N3dzeam5tRUlICLpfLnugcHBxmXGAxdzqdDp2dnWhpaUFrayusra3h4+ODiIgIs1qyfiKGhoZQWloKjUaDtLS0UWfJSKVSbNy4Ea2trSgpKUFQUJBR2zj82EaIqZg5Z6xJ1tXVhXXr1uH5559HdHQ07O3tUVpaio8//hiPP/44u19GRgY+//xzBAUFGaxrkJaWhr/85S9sge1UWLVqFS5duoQnnngCKSkpOHToEObOnWuwj1AohKOjIy5fvoxz584hLi5uRozpD8fhcODi4gIXFxdERUWhvb0dEokEBQUFmDNnDjw9PSEUCuHq6mqW62fMBCqVCjKZjN24XC68vb2RnJwMJyenGR0kW1tbUV5eDm9vb0RGRo76N3j69Gls3LgRy5cvx/fffz+lU33He2zr7+8fcV0XW1tb+qRPjIpCyhj4fD4SExPx6aefoq6uDmq1Gr6+vnjhhRewfft2dr+MjAz87W9/Y+tR9NLS0rBv3z489dRTU9rO4OBgnD9/Hm+99RZiY2Oxd+9erFu3zmAfW1tbthq8oKAAwcHBCA4OnpHrj1hYWEAgEEAgEECr1aKrqwttbW0oKyuDWq2Gh4cHBAIBPD09Z9xwgqkZGBiAVCqFVCrFnTt34ODgAIFAgMDAwBkfTABAqVSioqICHR0dmD9/Pry9vUfso9Fo8Ic//AGfffYZ/vKXv2DTpk1T/nsZ77Ht97//PX7/+98bPPbFF19Ednb2lLaPkOGoJmUG+f777/H8889j/fr1+OSTT2BjYzNin+7ubpSVlcHCwgKxsbGz5lMRwzDo7e2FTCZDW1sbO6bs5uYGV1dXuLq6mnSthznUpMjlcnR2dqKrqwudnZ2Qy+Vwc3NjQ6G5rt/zIFpbW3H16lW4uroiOjp61DV+mpub8dRTT6G7uxuHDh1CRETENLSUPAiqSTEeCikzTGNjI9avXw+5XI5Dhw4hLCxsxD5arRa3bt1CfX39jO5VuRe5XM6eTDs7OzE4OAgnJyeTDS2mGFJ+GUqG/w7d3Nzg4uJiMm01FqVSiWvXrqG9vR3R0dHw9vYetWfk2LFj2LRpE/71X/8Vn3322awKcDMBhRTjoeGeGUZ/4cH33nsPCQkJ2LNnD55++mmDAyWXy0V4eDiEQiHKysrQ1tY2q3pVgLvXR/Lx8WFnPQ0/4V6/fh2Dg4Owt7eHo6MjnJyc4OTkBEdHxxlVeDwRSqUSPT097Nbb2wu5XM6GkqioqFkZSoZrbW1FRUUFnJ2dsWTJklF7T1QqFbZt24a9e/ciOzt7yoeDCTF31JMyg508eRLPPPMM0tLS8Pnnn4+6GBT1qoxOLpezJ2P9iVmpVILP57OhRb/Ala2t7ZTXERirJ0Wr1WJwcBADAwPo7+9n37tCoYCdnZ1BYHNycprVoURvvL0nV65cwaZNm2BpaYlDhw4hODh4GlpLJgP1pBjP7PxYOEusXLkSN27cwJYtWxAREYE9e/bg17/+tcE+v+xVkUgkiI6Ohru7+zS12jTY2NjAxsbGYMlouVzOhpbOzk40NjZicHAQHA4Htra2Bitz2tnZwcbGBtbW1ibV+8IwDNRqNRQKBeRyOQYGBthQMjAwALlcDi6Xy74PV1dXBAYGwtHRkQLJLzAMg8bGRty8eRNubm737D35r//6L/zpT3/C22+/je3bt8+YhekImWqmc/QkU8LDwwPfffcdDh8+jC1btuC7777Dnj17RvSqODs7Iz09HQ0NDSgpKYGHhwciIyNHLb6drfTBZfhF13Q6HYaGhgxO9BKJBIODg1AoFGAYBpaWluDxeOxmbW0NHo8HKysrWFpashuXyzX42cLCYsQncoZhoNPpANzt9dBoNOz2y59VKhUUCgWUSiUUCgW76XQ6cLlc8Hg82Nvbw87ODl5eXmy44vF4M37mzcO6c+cOKioqoNFoEBcXZ7D8wHDl5eXYtGkTGIZBUVERFixYYOSWEmLeaLhnFpHJZNiyZQvOnTuHzz//fMRUZT2FQoEbN26gra0NoaGhCAwMpCGgB8AwjEFQkMvlBoFheKAYHjT0IWS8uFzuiIBjaWkJKyurUcMRj8eDpaUlBZEHoFQqUVlZiZaWFgQHByMoKGjUdU+G95689dZbeO+996j3ZAah4R7joZAyyzAMg0OHDuHf//3fsWTJEuzZs2fMoZ3Ozk5cu3YNOp2OhoCMSKfTQaPRsGFFP0STn5+PJUuWsMMu+nBCAXLqDR/acXV1RVRU1JgzcvS9JzqdDvv376fekxmIQorx0NFtluFwOFi/fj1u3LgBjUaDiIgI/O1vf8NoWdXNzQ1paWkQiUQoKSnBpUuXMDQ0NA2tnl0sLCwwZ84cttdDP8wEwKBnxMrKigKKEXR1deHs2bOoq6tDXFwcEhMTRw0og4ODeO+995CcnIw1a9agtLSUAgohD4lqUmYpT09PHD16FEeOHEFWVhb27t2Lv/71r5g/f77BfhYWFggMDIS3tzcqKyuRl5cHkUiEkJAQWrGVzGh9fX2orKxEV1cXgoKCxhzaYRgG33//PbKysuDl5UW1J4RMIvoYNotxOBysW7cOVVVVSElJwcKFC/G73/0OPT09I/bl8XiIjY1FWloahoaGkJubi6qqKqjVauM3nJApNDQ0hMuXL+Ps2bOws7PDsmXLEBoaOmpAqa6uxsqVK/Hiiy9ix44dFFAImWQUUgj4fD527dqFsrIyVFZWIjQ0dMwhIAcHByQmJmLhwoXo6OhAbm4u6urqoNVqp6HlhEwe/XoneXl54HA4WLp0KaKiokbtMdQP7cTExCAoKAjV1dV47rnnaPiNkElGwz2EFRYWhlOnTuHo0aPIysrCl19+iT179owYAgIAV1dXLFq0CDKZDJWVlaivr0dYWBh8fHxo1ggxK2q1GnV1daitrWXrsMYqXtQP7WzduhU+Pj7Uc0LIFKPYTwxwOBz827/9G27evInU1FQkJSVhy5YtIy7Zrt9XIBAgIyMDoaGhuHnzJs6cOYOmpqYJT6MlxNhUKhVu3bqF3NxcdHR0ICkpCQsXLhwzoJSVlWHFihV46aWX8MEHH6CwsJACCiFTjEIKGRWfz8dHH32E8vJyyGQyBAUF4f3330dvb++IfTkcDvz8/LB06VIEBgaiuroaubm5qK+vp2EgYnL06wCdOnUKHR0diIuLw6JFi+Dq6jrq/rW1tXjyySeRkpKCmJgY3Lp1C5s2baKhHUKMgP6XkXsKCQnB0aNHkZeXh6KiIsydOxe7d++GQqEYsS+Xy4VIJMLSpUsRERGB27dv49SpU6iurqYCWzLtBgcHcfXqVZw+fRoDAwNITk7GokWL4OHhMeoQpVQqxSuvvIKoqCjY2dmhuroaH3/8MZydnaeh9YTMThRSyLgkJibizJkzOHDgAP7+978jJCQE+/btG7WnhMPhwNvbG+np6YiNjYVMJsOpU6dQWVk5arghZCr19vaitLQUZ86cgUajQVpaGhITE+Hi4jLm/u+//z6CgoLQ1taGK1eu4KuvvmKvmE0IMR4KKWTcOBwOMjMzceXKFezatQsffvghoqOj8cMPP4w6E4jD4cDT0xOpqalYuHAh+vr6kJubi7KyslGnORMyWRiGgVQqxfnz53Hu3DlYWVlhyZIliIuLG7PmRKFQ4JNPPkFgYCAKCwuRm5uL//3f/8W8efOM3HpCiB4ti08emEqlwpdffokPP/wQQqEQ7777LtatWzfqehJ6fX19aGhoQHNzMxwdHREQEAAvLy8a378PtVqNH3/8EatWraKrEd+DSqVCU1MTGhoaoNPpIBKJ4O/vP+rVifX6+vrwxRdf4NNPP4VAIMBHH32EzMxMmqVGxkTL4hsPhRTy0ORyOb7++mv86U9/gqWlJd5++208++yz91yRVqVSobm5GQ0NDdBoNPDz84O/vz/s7OyM2HLzQSFlbAzDoLu7G42NjWhpaYGTkxPmzp0LoVB4z/Db0dGBzz77DH/9618RERGBbdu2YfXq1RROyH1RSDEeCilk0qjVahw8eBC7du1Cd3c33njjDfz2t7+Fvb39mI9hGAYdHR1obGyEVCqFu7s7RCIRPD09qXdlGAopI6lUKrS0tKCxsRFDQ0Pw9fWFSCS670G+qakJ//3f/42vvvoKixcvxvbt25GamkrhhIwbhRTjoZBCJp1Op8OxY8ewc+dO1NTU4NVXX8Vrr7025hRPPblcjqamJty+fRsajQbe3t7w8fGBi4vLrD+BUEi5S6vVQiaTQSKRQCaTwcHBASKRCN7e3rC0vPfalDdv3sQf//hHHDx4EGvWrMG7776L2NhYI7WczCQUUoyHPqqSSWdhYYHHH38cFy5cwJEjR1BcXAw/Pz/89re/RUVFxZiPs7GxQWhoKJYvX47ExEQAwMWLF5Gbm4vKykr09/cb6y0QE8IwDDo7O1FWVoaffvoJlZWVcHBwQEZGBtLS0uDv7z9mQNHpdDh58iRWr16NBQsWwNLSEhUVFTh8+DAFFELMAC2LT6YMh8PBkiVLsGTJEpSXl2PPnj1YuHAhEhIS8Oqrr+Lxxx8ftVeAw+HA1dUVrq6uiIyMRHt7OyQSCcRiMezt7eHj4wNvb2/Y2NhMw7sixsAwDPr6+iCRSCCRSKDT6eDt7Y2kpCQ4Ozvft2ett7cX+/btw549ezAwMIAXX3wRe/fuhZeXl5HeASFkMtBwDzGqO3fu4Ouvv8aePXugVCqxefNmbN68GX5+fvd9rFqtRmtrKyQSCbq6uuDo6AiBQACBQAAHB4cZPSQ0G4Z7dDodurq6IJVKIZVKoVQqIRAI4OPjAw8Pj/vWKDEMg9LSUmRnZ+PgwYOYP38+Xn31VaxduxZz5swx0rsgswEN9xgP9aQQo3JxccGbb76JrKwsnDp1CtnZ2QgKCsKjjz6KF198EZmZmWOehK2srODv7w9/f38oFArIZDJIpVLU1NRgzpw5bGBxc3OjolszoVar2X/H9vZ2WFhYQCAQIDIyEu7u7vetMwHu9pocOnQI2dnZqKmpwdNPP43i4uJRL4xJCDEvFFLItOByuVi5ciVWrlyJ5uZm/M///A+2bNkChUKB9evXY8OGDUhMTByzd4TH47GBRavVorOzE1KpFGVlZdBoNPDw8GADCw0LmQ6GYdDf34+Ojg5IpVJ0dXXB3t4eAoEACxcuHNdQDnB3Zs/Jkyfx7bff4tixY4iMjMRLL72EJ5988p6zyQgh5oWGe4jJ0Ol0OHfuHA4cOIDvvvsObm5u2LBhAzZs2ICQkJBxPQfDMOjt7YVUKoVMJkNPTw/s7Ozg5uYGNzc3uLq6mmVoMdfhHn0o6ezsRFdXFzo7O6HVauHi4sL2fNna2o7ruXQ6HYqLi/Htt9/i8OHDcHR0ZP8+aFVYYkw03GM8FFKISVIoFDhx4gQOHDiAEydOYP78+di4cSOeeOIJeHp6jvt51Go1urq62BOkuYYWcwkp+lCi/30PDyX637mTk9OEhuMqKytx4MABHDhwAH19fXjiiSewceNGJCcnz+g6JGK6KKQYD4UUYvLu3LmDI0eO4MCBAyguLkZycjLWrFmDNWvWIDg4eELPNVpo4fF4cHJygqOjI/vV1IKLKYYUhmEwMDCA3t5e9PT0sF8ZhoGLiwtcXV3h5uYGZ2fnCYUSrVaLkpIS5OTk4NixY6itrcWaNWuwceNGZGZmUhEsmXYUUoyHQgoxK83NzTh+/DhycnJw5swZBAQEYM2aNXjssceQlJQ0rkLL4dRqNfr6+tDT08NuAwMDsLa2hpOTExtaHBwcYGtrO22f3Kc7pGi1WgwODqK3t9cglOh0Ojg4OLC/KycnJ9jb20+4cHlwcBCnT59GTk4Ojh8/Do1Gg9WrV+Oxxx5DZmYmHbiJSaGQYjwUUojZ6u/vZ09sJ06cAMMw7Ilt+fLlcHR0fKDn1Wg07IlYfzIeGBgAh8OBra0t+Hw+u9nZ2YHP58Pa2npKA4wxQgrDMBgaGsLAwAAGBgYwODjIfi+Xy8HlcuHg4MD2OD1oINFrbm7Gjz/+iJycHOTl5cHPz4/tIUtOTp5w4CTEWCikGA+FFDIjaLVaXLhwAceOHUNOTg5u3bqF2NhYpKenIz09HYsWLXrg0ALcLdqUy+XsSXv4SVwul8PS0hK2trbg8XgGm7W1tcH397pC9L08bEjRaDRQKBTsplQqDX5WKBQYGhoCwzBs8NJ/1X/P4/EeKohJJBKcPXsW+fn5EIvFaGxsRHJyMh577DGsWbMGoaGhD/zchBgThRTjoZBCZqSWlhacPXsWYrEYYrEYdXV1BqElNTV10g4GGo0GQ0NDGBwcHDMAKJVKAHfXerGysoKlpeWoG5fLZb/qAwGHw4FOp8P169cRERHB9lwwDAONRgONRgOtVst+/8tNpVJBq9XCwsLCIDT9MkTZ2dnB1tZ20taYaWlpYX//YrEYDQ0NiIuLY/8NUlJS6IBMzBKFFOOhkEJmhV+Glvr6esTExCA+Ph5xcXGIi4tDZGTklBVlMgzDhpexwsTwwKHVaqH/r8kwDHQ6HTo6OgxWXuVwOGyouddmZWUFHo8HKyurKRuS6uvrQ1lZGS5fvozLly+jpKQE9fX1BqFk0aJFdAAmMwKFFOOhkEJmpZaWFhQUFLAn1StXrkAulyMqKgpxcXGIjY1FXFwcoqKiYG1tPd3NnfbC2eF6e3tx5coV9vd2+fJl1NTUwMvLiw18CQkJ1FNCZiwKKcZDIYUQ3O2tqKurY0OL/gQ8ODiIkJCQUTd3d3ejzfYxdkjR6XRobm5GdXW1wXbr1i00NDTAx8eHDST6bSLr1xBizkwhpLS0tOCdd97ByZMnMTQ0hKCgIOzbtw/x8fFjPkYsFuP111/HjRs34Ovri/fffx+bNm166PZPJSqfJwR3h06CgoIQFBSEJ554AsDd4FJfX4+bN2+yJ+lvv/0W1dXVaGlpgaOjIxtYgoOD4ePjA6FQyG7u7u4PXCg71VQqFaRSKdra2tDa2oq2tjY0NTWhpqYG1dXVqKmpgUajQUBAAPse9evSREdHw8PDY7rfAiGzVnd3N1JSUpCRkYGTJ0/C3d0dNTU1cHZ2HvMxDQ0NWL16NV566SUcOHAAeXl52Lx5M4RCIVasWGHE1k8M9aQQ8gAGBgZQW1vLhpeamhq0tLSgra0NbW1t6O7uBpfLhaenp0Fw8fT0hL29Pfh8Puzt7Q2+H36bfiaQhYUFLCwsoNVqceLECWRmZoLL5UKn00Gr1UIul6O/vx/9/f0YGBgY9fu+vj42kOhDSVdXFzgcDjw8PODl5QWhUAgfHx+DnqKAgABaOI2QUUx3T8q7776LoqIiFBQUjPs13nnnHZw4cQLXr19nb1u/fj16enrw008/PVC7jYF6Ugh5AHw+HzExMYiJiRn1foVCAalUyvZS6DepVIra2lqDIPHLcDFRFhYWbLgZLfQ4ODggICAAycnJbCARCoXw8PCgtUgIeQh9/bpJfZ6+vj6D262trUeticvJycGKFSuwbt06nD17Ft7e3tiyZQteeOGFMV/j/PnzWLZsmcFtK1aswNatWx/+DUwhOkIRMgV4PB5EIhFEItGEHqfT6TA0NASlUgmdTsdu+inEwzf94nIPu34JIWRi5syZA4FAAP+4xkl7Tj6fD19fX4Pb/vCHP2DHjh0j9q2vr8cXX3yB119/Hdu3b8elS5fw2muvYc6cOXj22WdHfX6pVDqibszT0xN9fX2Qy+UmdykQPQophJgQCwsLdgE1Qohp4vF4aGhogEqlmrTnZBhmxIeNsWYW6nQ6xMfHY+fOnQCABQsW4Pr168jOzh4zpJgrCimEEELIBOkXQZwOQqEQ4eHhBrfNmzcPR48eHfMxAoEAMpnM4DaZTAYHBweT7UUBgMlZWpIQQgghRpGSkoJbt24Z3FZdXQ1/f/8xH5OUlIS8vDyD206fPo2kpKQpaeNkoZBCCCGEmJGsrCxcuHABO3fuRG1tLf7xj3/gyy+/xCuvvMLus23bNjzzzDPszy+99BLq6+vx9ttvo6qqCp9//jkOHz6MrKys6XgL40ZTkAkhhBAzc/z4cWzbtg01NTUICAjA66+/bjC7Z9OmTWhsbIRYLGZvE4vFyMrKQmVlJXx8fPAf//EfJr+YG4UUQgghhJgkGu4hhBBCiEmikEIIIYQQk0QhhRBCCCEmiUIKIYQQQkwShRRCCCGEmCQKKYQQQggxSRRSCCGEEGKSKKQQYsI6Ojrw8ssvw8/PD9bW1hAIBFixYgWKioqmu2mEEDLl6AKDhJiwtWvXQqVSYf/+/Zg7dy5kMhny8vLQ1dU13U0jhJApRyvOEmKienp64OzsDLFYjLS0tOluDiGEGB0N9xBiovh8Pvh8Pn744Qcolcrpbg4hhBgdhRRCTJSlpSW++eYb7N+/H05OTkhJScH27dtRUVEx3U0jhBCjoOEeQkycQqFAQUEBLly4gJMnT6KkpARfffWVyV+9lBBCHhaFFELMzObNm3H69Gncvn17uptCCCFTioZ7CDEz4eHhGBwcnO5mEELIlKMpyISYqK6uLqxbtw7PP/88oqOjYW9vj9LSUnz88cd4/PHHp7t5hBAy5SikEGKi+Hw+EhMT8emnn6Kurg5qtRq+vr544YUXsH379uluHiGETDmqSSGEEEKISaKaFEIIIYSYJAophBBCCDFJFFIIIYQQYpIopBBCCCHEJFFIIYQQQohJopBCCCGEEJNEIYUQQgghJolCCiGEEEJMEoUUQgghhJgkCimEEEIIMUkUUgghhBBikv4fVtVq9yMe3SIAAAAASUVORK5CYII=\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 2 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# The downsample functions of  WindRose/WindTiRose allows for\\n\",\n    \"# aggregating the data into larger bin sizes\\n\",\n    \"wind_rose_aggregated = wind_rose.downsample(wd_step=10, ws_step=2)\\n\",\n    \"wind_rose_aggregated.plot()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 13,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"<PolarAxes: >\"\n      ]\n     },\n     \"execution_count\": 13,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAAiAAAAHVCAYAAADIPkArAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOydd3hUZdqH7zMzyaT33ntCCQkppBBSAEFAEF0Ve3d1bau4FuxrQ2yr4ioqn7oW1roiKoqUJJBCgBRKEhJI7wXS62Rmvj/YzBppCSRTwrmvay7IyXvO+5zJzDm/87xPEdRqtRoRERERERERES0i0bUBIiIiIiIiIhceogARERERERER0TqiABERERERERHROqIAEREREREREdE6ogARERERERER0TqiABERERERERHROqIAEREREREREdE6ogARERERERER0TqiABERERERERHROqIAEREREREREdE6ogAREdFTbr75ZgRB4OWXXx6xfePGjQiCoCOrRERERMYHUYCIiOgxJiYmrFmzhra2Nl2bIiIiIjKuiAJERESPmT9/Pi4uLqxevVrXpoiIiIiMK6IAERHRY6RSKS+99BJr166ltrZW1+aIiIiIjBuiABER0XMuu+wywsPDeeaZZ3RtioiIiMi4IQoQEREDYM2aNfzrX/+iuLhY16aIiIiIjAuiABERMQASExNZuHAhq1at0rUpIiIiIuOCTNcGiIiIjI6XX36Z8PBwgoODdW2KiIiIyHkjekBERAyE0NBQrrvuOt5++21dmyIiIiJy3ogCRETEgHjuuedQqVS6NkNERETkvBHUarVa10aIiIiIiIiIXFiIHhARERERERERrSMKEBERERERERGtIwoQEREREREREa0jChARERERERERrSMKEBERERERERGtIwoQEREREREREa0jChARERERERERrSMKEBERERERERGtIwoQEREREREREa0jChARERERERERrSMKEBEREREREQOjq6uLBx54AG9vb0xNTYmPj2fv3r2nHZ+WloYgCCe9GhsbtWj1SGQ6m1lERERERETknLj99ts5dOgQn332GW5ubnz++efMnz+foqIi3N3dT7tfSUkJVlZWmp+dnJy0Ye4pEZvRiYjoESqVip6eHgYGBlCpVJpXU1MTJiYmWFtbI5FIkEqlSCQSTE1NMTU1RRAEXZsuInJB0d/fz+Dg4LgdT61Wn/Q9lsvlyOXyk8b29fVhaWnJDz/8wJIlSzTbIyMjWbRoES+88MJJ+6SlpZGSkkJbWxs2NjbjZvf5IHpAREQmgP7+fhoaGqivr6ehoUHzamlpoauri66uLrq7u0f829XVRU9Pz5jnkkgkWFhYYGlpiaWlpeb/w/9aWVnh7OyMq6srbm5uuLq64urqirOzMzKZeAkQERkr/f39WJvaMkj/uB3TwsKC7u7uEdueeeYZnn322ZPGDg0NoVQqMTExGbHd1NSUjIyMM84THh7OwMAA06dP59lnn2X27Nnnbfu5InpARETOge7ubo4cOUJpaSmlpaUcOXKEuro6jdBob29HKpXi4uKiueG7urri5OSElZXVGQWDpaUlcrlc4+WQSCQMDQ2xefNmLr74YqRSKSqVCqVSSV9f30mC5o//7+jooKmpSWNbfX09ra2tCIKAo6OjRpR4eHgQFBSkefn5+WFsbKzrt1pERO/o7OzE2tqaBBYjw+i8jzeEggw2U1NTM2J55HQeEID4+HiMjY3ZsGEDzs7O/Pvf/+amm24iICCAkpKSk8aXlJSQlpZGVFQUAwMDrF+/ns8++4ycnBwiIiLO+xzOBVGAiIicBrVaTXl5OUVFRRqhMfyqr6/H2tqa4OBggoKCCAgIwNPTc4TYcHBwQCqVjostCoWCzZs3s3jxYoyMzv+CNzg4qBElw16a6upqjag6cuQIg4OD+Pr6jhAlQUFBhIaG4uzsPA5nJSJimAwLkGQuRSaMgwBRK0jjBzo6OkYIkDNRVlbGrbfeys6dO5FKpURERBAUFERubi7FxcWjOkZSUhJeXl589tln52P+OSP6X0VEOBF7UVZWRm5uruaVl5dHb28vQUFBGqFx4403am7EDg4OBht7YWxsjKenJ56enqf8vUqlora2doTo+umnnygpKaG8vBx3d3ciIyNHvFxcXLR8FiIiFy7+/v6kp6fT09NDZ2cnrq6urFixAj8/v1EfY9asWWddsplIRAEickFSW1tLRkYG+/btIzc3l/z8fPr6+pgxYwaRkZFcffXVvPrqq0yfPv20LtDJjEQiwcvLCy8vL+bPnz/idx0dHeTn52tE2oYNGygtLcXV1VUjRqKjo5k9ezbW1tY6OgMRkQsDc3NzzM3NaWtrY8uWLbzyyiuj3regoABXV9cJtO7MiAJE5IKgrq6OtLQ0zauiooLw8HCio6O57rrreOONN5g2bZoY8zAKrK2tSU5OJjk5WbOtq6tLI0pyc3P54osvKCsrIyIiQjM2ISFBFCQiIuPEli1bUKvVBAcHc/ToUR5++GFCQkK45ZZbAFi1ahV1dXV8+umnALz55pv4+voybdo0+vv7Wb9+PTt27OC3337T2TmIAkRkUvJHwVFeXk5kZCTJycm89dZbJCQkjHqtVeTsWFpakpiYSGJiomZbXV0d6enppKWl8eCDD1JeXn6SIBH/BiIi50ZHRwerVq2itrYWOzs7/vSnP/Hiiy9qYsSG47qGGRwc5KGHHqKurg4zMzNmzJjBtm3bSElJ0dUpiEGoIpMDpVJJdnY2P/74Iz/++CMlJSUawTEZbnbjHYSqC4YFSWpqqsYLFRcXx9KlS1m2bBnBwcEGG1MjcmGhD0GokwHRAyJisHR1dfHbb7+xadMmNm/ejFqt5pJLLuH5559n/vz5ortfz3B3d+faa6/l2muvBaCmpoZffvmFTZs28fTTT+Pp6cmyZctYtmwZs2fPFmuUiIhMcsRvuIhBUVNTw48//simTZtITU3Fz8+PZcuW8f333xMXFzduaa8iE4+npyd//vOf+fOf/0xPTw/btm1j06ZNXHXVVSgUChYvXszSpUu5+OKLRTEpIjIJEZvRieg9x48f5/333ycxMRE/Pz++/vprFixYwKFDhyguLmbNmjUkJCSI4sOAMTc359JLL+X//u//aGhoYPPmzXh5efH888/j7OzMlVdeyQ8//DCupa9FRER0iyhARPSS/v5+vv32Wy677DJcXV356KOPuPLKKzXBpStXriQwMFDXZopMABKJhNjYWF566SUOHTpEfn4+wcHBPPDAA7i4uHDXXXeRkZGBSqXStakiIiLngShARPQGlUpFamoqt99+Oy4uLqxatYqwsDAOHTpETk4O9913n047N4rohilTpvDCCy9QXl7Ojz/+iCAIXHrppfj5+fHEE09QVFSkaxNFRETOAVGAiOicmpoannnmGby9vVmxYgVmZmZs2bKF0tJSnn32WdHTIQKAIAjMnj2b9957j4aGBt5++22OHDmiKX72/vvv09XVpWszRURERokoQER0glKpZPPmzSxbtgx/f3/y8vJ49913qaur4+233yYmJkZMyRQ5LcbGxixbtoyvv/6axsZG7rzzTj744APc3Nz4y1/+QkFBga5NFBEROQuiABHRKseOHePVV18lICCAO+64g5kzZ3L06FF+/PFHli5darA1LkR0h7W1NX/+85/Jzc0lNTUVhULB7NmziY+PZ8OGDWLgqoiIniIKEBGtUFBQwO23346npyc///wzr732GpWVlfz973/Hy8tL1+aJTBKioqJYv3499fX1rFixgmeffRYvLy+eeeYZ6uvrdW2eiIjI7xAFiMiEoVar2b59O/Pnz2f27NlIpVJycnJIS0vjT3/6k+jtEJkwrK2t+etf/8rhw4f55JNPyM3Nxc/Pj9tuu43S0lJdmyciIoIoQEQmAJVKxcaNG4mNjeXKK68kISGB6upq3n//fUJDQ3VtnsgFhEQi4eKLL+ann36ioKAAlUrFjBkzuPLKK8nLy9O1eSIiFzSiABEZNxQKBZ9++imhoaHcc889rFixgurqap599lns7e11bZ7IBU5ISAgff/wxpaWluLm5MWfOHBYuXEh6ejpiSywREe0jChCR86avr4933nmHwMBAnn/+eR544AHKy8tZuXIlFhYWujZPRGQEXl5evPXWW1RWVjJr1iwuvfRSZs+ezY8//igWNxMR0SKiABE5ZwYHB1m7di0+Pj6sX7+eNWvWcPjwYe644w7kcrmuzRMROSOOjo48//zzVFdXs3z5cu644w4iIiI0jQ1FREQmFlGAiIwZlUrFF198QUhICOvWreODDz4gPz+fFStWiP1YRAwOKysrHnnkESorK7npppu48cYbSU5OZvfu3bo2TURkUiMKEJFRo1ar+eWXX4iIiGDVqlU8/fTTHDhwgEsvvVQsGiZi8JiYmPDggw9SVlZGYmIi8+fP57LLLqO4uFjXpomITEpEASIyKnbv3k1KSgrXX389N954I6Wlpdx8882ix0Nk0mFtbc3zzz/P0aNHcXd3JyIigttuu42amhpdmyYiMqkQBYjIGSkpKeHyyy9n/vz5zJkzRxNcamJiomvTREQmFBcXF9555x0OHTpEX18fwcHBPPzww7S1tenaNBGRSYEoQEROSXd3N4899hgzZ87ExcWFo0eP8vzzz2Ntba1r00REtIq/vz8bNmwgMzOT/fv3ExwczMcffyxmzIiInCeiABEZgVqt5ptvvmHKlClkZmaSnZ3Nu+++i4uLi65NExHRKTNnzmTLli28//77PPvss8yePVss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bt++nXvvvfeU+8TFxbF9+3YeeOABzbatW7cSFxcHnBDsCoXipM+HVCod98JixsbGvPbaayQnJ3PTTTexY8cO3n77bczMzMZ1HhERQ0AUIJOI//znP9x2221cc801vP7665iamurapAlHrVbT0tJCbW0tDQ0NmJiY4OHhwbRp07CwsNC1eSK/QyaTabwjarWa48ePU1dXx969e5FKpbi7u+Pp6XnWLICVK1dy0003ERUVxaxZs3jzzTfp6enhlltuAeDGG2/E3d2d1atXA/DXv/6VpKQkXn/9dZYsWcKXX37Jvn37+OCDD4AT2U1JSUk8/PDDmJqa4u3tTXp6Op9++ilvvPHGhLwXl1xyCQUFBVx77bVER0fz9ddfM23atAmZS0REXxEfCU/DzTffjCAIvPzyyyO2b9y4EUEQ6O7uxsjIiC+//HLE76+++moEQaCysnLEdh8fnxEpfuNJf38/9913H7feeisffvgh77777qQWH2q1mvb2dg4dOsSWLVvIy8vDyMiI2bNnM3fuXIKDg0XxoecIgoC9vT0zZsxg4cKFhIWF0dfXx86dO0lNTeXIkSP09fWdct8VK1bw2muv8fTTTxMeHk5BQQG//vqrJtC0urqahoYGzfj4+Hg2bNjABx98QFhYGN9++y0bN27U1AAB+PLLL4mOjua6665j6tSpvPzyy7z44oujKkR2rnh6epKamspll11GTEwMH330EdqoinC2axtAWloagiCc8vX74F0RkfNB9ICcARMTE9asWcOdd96Jra3tiN9ZWFgQFRVFWloaV199tWZ7Wloanp6epKWlcfPNNwNQUVFBVVUVc+fOHXcbjxw5wooVK5DJZOTl5eHn5zfuc+gLCoWC2tpaKisr6enpwc3NjYiICBwcHMTlFQNGIpHg7OyMs7MzCoWCxsZGampqKC4uxtHRER8fH5ydnUf8je+9997TLrmkpaWdtO3KK688YwaYi4sLH3/88Xmfy1iRyWS88MILJCUlcf3117N9+3bWrVs34cG6Z7q2/Z6SkpKTPFIXajC7yPgjXrXPwPz583FxcdG4cv9ISkrKiItdcXEx/f39/OUvfxmxPS0tDblcrllzHi82b95MdHQ0ycnJZGRkTFrx0dHRQUFBAVu2bKG6uho/Pz8uvvhiIiIicHJyEsXHJMLIyAhPT0/i4+O56KKLsLOz4+DBg2zdupXDhw/T39+vaxMnhIsuuoj9+/fT1NRETEwMR48endD5znZtG8bJyQkXF5cRL/H7JjJeiJ+kMyCVSnnppZdYu3YttbW1J/0+JSWFkpISjbs3NTWVhIQE5s6dO0KApKamEhcXN24FmtRqNa+++ipXXXUV69at44033ph0dQVUKhV1dXVkZGSwa9cuABISEkhKSsLb21uv+5SIjA+mpqYEBwdz0UUXERYWRnt7O1u3bmXfvn0cO3ZMK8sV2sTFxYUtW7awePFiZs2axbZt2yZsrrNd20REtIEoQM7CZZddRnh4OM8888xJv5s9ezbGxsYasZGWlkZSUhKRkZG0trZSUVEBQHp6OikpKeNiT39/PzfeeCNvvfUW6enpI5Z/JgMKhYKjR4+ydetWioqKcHFxYcGCBYSHh2NjY6Nr80R0gCAIuLi4EBsbS0pKCiYmJuzevZv09HTq6uomlRCRSqW89tpr/OMf/+DSSy/l7bffnrDzO9O1bRgPD48RTQrFQFmR8UR8jBwFa9asYe7cufztb38bsd3MzIzo6GjS0tK45pprSE9P5+GHH0YmkxEfH09aWhpqtZrq6upxESD19fVcdtllSCQS9u3bd9q6B4bIwMAA5eXlVFRUYGFhwYwZM3BxcdF54zMR/cLCwoLp06cTEhJCdXU1hYWFFBcXExgYiKen56RZHrjpppsIDg7msssu48CBA/zzn/9ELpeP+zynu7YNs2vXrhHxKGL9HJHxZHJ8WyeYxMREFi5cOKL/xDApKSmkpqZSWFhIX1+fptdDUlISqamppKamYmZmRkxMzHnZsGfPHqKiopg6dSppaWmTRnz09fVp1vjb2tqIjo5mzpw5uLq6iuJD5LTIZDL8/PyYP38+QUFBGq9ZWVkZQ0NDujZvXIiNjWXv3r0UFBQwb948mpubx32OM13bAHx9fQkICNC8vL29x90GkQsXUYCMkpdffpkff/zxpIZXKSkpHDlyhA0bNpCQkKAp6Z2YmEh6ejppaWmapZpz5fPPP2fu3Lk8/PDDfPTRRxPyJKRturu7yc/PZ9u2bfT19ZGQkEB8fDyOjo6i8BAZNRKJBC8vL+bOnUtoaCi1tbX89ttvHD58GIVCoWvzzhsPDw927dqFl5cXUVFRFBQUjPscp7u2iYhMNOISzCgJDQ3luuuu4+233x6xPT4+Hrlcztq1a3niiSc022fNmkVzczM//PDDaZ8uzoZareaZZ55h7dq1fPfddyxcuPC8zkEf6O/vp6SkhOrqatzd3UlOTtbb/iAihoMgCLi5ueHq6kpLSwtHjhyhvLycwMBA/Pz8DLrXj6mpKV988QVr1qxhzpw5/Pvf/+aSSy4Zt+Of7toGJ5pZ/jHzyN7eXlyKERkXRA/IGHjuuedOKs1sYmJCbGwsXV1dJCcna7bL5XLN9nOJ/xgaGuLOO+/k448/JjMz0+DFh0KhoKioiG3btjE4OEhycjIRERGi+BAZVwRBwMnJifj4eKKioqirq2Pbtm1UVVWNe1l1bSIIAo899hgff/wxK1as4JNPPhnX45/q2gYQHBysqV47/MrNzR3XuUUuXAT1ZAohnyT09fVx7bXXUlpayq+//oqnp6euTTpnlEolFRUVlJaWYm1tzdSpU89Y+Ejk1CgUCjZv3szixYvFp88xoFarqa+vp7i4GEEQmDJlisHHF6WmprJ8+XIef/xxHnnkEYM+F0Ols7MTa2tr5oY9ikx6/kviQ8oBduxfQ0dHx1lbEUwmxCUYPaO9vZ1ly5ahVCrZtWsXdnZ2ujbpnBjO/jl8+DByuZyoqCgxvkNE6wiCgLu7O66urlRVVXHgwAGOHj3KtGnTsLe317V558RwAcRFixbR2NjI66+/Pmmyf0QuLEQBokfU19dz8cUX4+3tzVdffWWwHTLb2to4cOAAAwMDTJs2DXd3d1F4iOgUiUSCr68vnp6elJWVkZ2djaurK9OmTRu3AoHaZObMmWRlZbFgwQKampr45JNPJl0xQpHJjyib9YSSkhLNuvX3339vkOJjcHCQ/fv3k5mZibOzM/PmzcPDw0MUHyJ6g0wmIzg4mHnz5qFWq9m+fTtlZWUGGR/i5+dHZmYmJSUlXHLJJXR1denaJBGRMSEKED1g7969zJ49m2uvvZb/+7//M7gy42q1msrKSrZv305fXx8pKSmEhIQYdOaByOTG1NSUqKgoZs2aRWVlJWlpabS2turarDHj7OxMWloaKpWKuXPn0tLSomuTRLREV1cXDzzwAN7e3piamhIfH8/evXvPuE9aWhoRERHI5XICAgLGPZh5rIgCRMdkZWUxf/58nnzySV566SWD8xa0tbWxc+dOjhw5Qnh4ODExMZibm+vaLBGRUeHo6EhKSgqenp7s3r2b3Nxcg2t4Z2lpyc8//4yvry8pKSk0NTXp2iQRLXD77bezdetWPvvsMw4ePMiCBQuYP38+dXV1pxxfUVHBkiVLSElJoaCggAceeIDbb7+dLVu2aNny/yFmweiQXbt2sWTJEl555RXuuusuXZszJpRKJYcPH6aiooKAgAACAwNFj8cEImbBTDx9fX0UFhbS1NREaGgonp6eBvVAMDQ0xE033UReXh47duzA1dVV1yZNWiYqC6ampmZEFoxcLj9l4cm+vj4sLS354YcfWLJkiWZ7ZGQkixYt4oUXXjhpn0cffZSff/6ZQ4cOabZdffXVtLe38+uvv573OZwLogdER6SlpbF48WLeeOMNgxMfx48f17isExMTxeUWkUnB8LJMZGQkRUVF5OTk0NfXp2uzRo1MJuPTTz9l1qxZJCcnn/ZJWER/8fT0xNraWvNavXr1KccNDQ2hVCpPCqA2NTUlIyPjlPtkZ2czf/78EdsWLlyo0wq4ogDRAWlpaVxyySW89NJL3H777bo2Z9QolUoKCwvJysrCy8uLOXPmXFA56yIXBi4uLsydOxcjIyNSU1Oprq42mI67UqmUjz76iPDwcBITE0URYmDU1NTQ0dGheZ2uiralpSVxcXE8//zz1NfXo1Qq+fzzz8nOzqahoeGU+zQ2NuLs7Dxim7OzM52dnToT2qIA0TK7du1i6dKlPP300/j5+XH8+HFdmzQq/uj1CAwMFGsPiExajI2NiYyMZObMmQbnDamqquL6668nNjaWuXPnnvaGJKJ/WFlZjXidqe/XZ599hlqtxt3dHblczttvv80111xjUNdlw7F0EpCZmcmSJUv4xz/+wSOPPMKUKVPIzs7WaxGiUqkoKioiKysLT09P0eshckHh6uo6whtSW1ura5POSHl5OcXFxcyePZtPP/2U2NhY5s2bJwamTkL8/f1JT0+nu7ubmpoa9uzZg0KhwM/P75TjXVxcTvocNDU1YWVlhampqTZMPglRgGiJPXv2sHjxYl599VXNsoufn59ei5De3l4yMjJoamoiMTGRoKAgg1LXIiLjwe+9IQcPHiQ/P5+hoSFdm3USw+IjLi4OOzs7zXLMzJkzmTdvnkGmGYucHXNzc1xdXWlra2PLli1ceumlpxwXFxfH9u3bR2zbunUrcXFx2jDzlIh3Ey1QXFzMokWLeP7557nzzjtH/E5fRUh9fT1paWlYW1uTmJgoej1ELnhcXV1JTk6mp6eHnTt30tnZqWuTNPxRfAwjlUr517/+xZQpU1iyZAk9PT06tFJkPNmyZQu//vorFRUVbN26VVN/6ZZbbgFg1apV3HjjjZrxd911F+Xl5TzyyCMcPnyYd999l6+//poHH3xQV6cgCpCJpra2loULF3L33Xdz//33n3KMPokQpVLJgQMHyM/PJzw8nLCwMDHDRUTkvwwXfHJ1dWXnzp1UVVXpPED1dOJjGJlMxueff46FhQVXXHEFCoVCB1aKjDcdHR3cc889hISEcOONN5KQkMCWLVs0afoNDQ1UV1drxvv6+vLzzz+zdetWwsLCeP3111m/fr1OO62LdUAmkLa2NubMmUNcXBwffPDBWWsKnO1CMtF0d3ezb98+BEEgKipKLCimR4h1QPSP5uZm8vLycHR0ZMaMGTr5u4zlmtHZ2UlSUhLTp0/nX//6l7iceh6I3XDHB/ETOEH09fWxdOlSAgICeO+990ZV0EiXnpC6ujrS09NxcHBgzpw5ovgQETkLTk5OJCcn09/fT3p6utaXZMb6wGJlZcUvv/xCVlYWjz76qBYsFBE5M6IAmQCGhoa4+uqrEQSBf//732Pq7aJtEaJWqykuLqagoICIiAimT58uPhmJiIwSExMT4uPj8fDwYNeuXVpLeT1Xb6mLiwtbtmzh008/5bXXXptAC0VEzo5hdT0zANRqtSbYZ+fOneeU3jScRpWdnT2hyzEKhYK8vDy6urpITEzE0tJyQuYREZnMCIJASEgIVlZW5ObmEhgYSFBQ0ISVcT/fpdqAgAB++eUXUlJScHZ25oYbbpgAK0VEzo4oQMaZp556iq1bt5KVlYWtre05H2eiRUhPTw85OTmYmJiQmJiIsbHxuB5fRORCw83NDXNzc3Jycujs7GTmzJnj3tl6vOLEIiIi+M9//sOyZctwcHBg0aJF42iliMjoEH3t48jHH3/Me++9x5YtW3B3dz/v403UckxLSwvp6ek4OjoSGxsrig8RkXHC2tqapKQkBgYGyMjIoLe3d9yOPd5B6vPmzeOjjz5ixYoVHDx4cBwsFBEZG6IAGSeysrK49957+eabbwgJCRm34463CKmoqCAnJ4dp06YRGhoqxnuI6IR//vOf+Pj4YGJiQkxMDHv27Dnj+OHvlYmJCaGhoWzevPmkMcXFxSxbtgxra2vMzc2Jjo4ekYaoLeRyOfHx8djY2LBz585x+d5OVIbcihUr+Nvf/sall14qFioT0Tri3WccqKmp4fLLL+eVV15h7ty543788RAharWaoqIiDh8+TFxcHN7e3uNspch4oFKpGBoaQqFQMDg4SH9/P319fbS3twPQ39/PwMAAg4ODKBQKlEqlzutQjJWvvvqKlStX8swzz5CXl0dYWBgLFy6kubn5lOOzsrK45ppruO2228jPz2f58uUsX758RFvxsrIyEhISCAkJIS0tjQMHDvDUU0+d1C1UW0gkEsLCwggKCiIrK+u8glMnOj3/ySefJDIykiuvvFKsESKiVcQ6IOdJb28vc+bMISoqinXr1k1Y4Bmc+4VIpVKxf/9+WlpaiIuLE4NNdYBSqdSIh/7+/hGv328bHBwc87EFQUAul2NiYqJ5nepnuVyuFx6vmJgYoqOjeeedd4ATn09PT0/uu+8+HnvssZPGr1ixgp6eHn766SfNttjYWMLDw1m3bh0AV199NUZGRnz22WfaOYkxUF9fT15eHqGhoWMW/tqqDdTT08Ps2bOJj4/n3XffnbB5JgtiHZDxQQxCPQ/UajW33HIL5ubmrF27dkLFB5xbYOrQ0BD79u3TCCVdNR26UBgcHKS9vZ2Ojg7a29vp6uqiv78fhUJxklCQy+WYmZlhZ2c3QjRIpVIEQUAQBCQSCYIgMDQ0xObNm1m0aBFSqRS1Wq15KRSKk4RNb28vbW1tJwmb4Tmsra2xsbHB2toaa2trrVW7HRwcJDc3d0SbcYlEwvz588nOzj7lPtnZ2axcuXLEtoULF7Jx40bghID5+eefeeSRR1i4cCH5+fn4+vqyatUqli9fPlGnMmrc3NwwNjYmJyeH/v7+UWfIaLMwobm5OT/88APR0dGEhobyl7/8ZULnExEBUYCcFy+99BI5OTns3btXa4GcYxEhg4OD5OTkIAgCc+bMEStojjPDYuP3gqO3txczMzPNDd7T0xNTU1ONB+J8RaogCCeJBWNj47MWjlOpVAwMDNDX10dfXx8dHR00NDRw+PBhFAoFlpaWGkFiY2ODlZXVuGdwALS2tqJUKnF2dh6x3dnZmcOHD59yn8bGxlOOb2xsBE5UJO3u7ubll1/mhRdeYM2aNfz6669cfvnlpKamkpSUNO7nMVYcHBxISEggOzubgYEBQkNDz/hZ0EVVZG9vb/7zn/+wcOFCpkyZQnJyslbmFblwEQXIOfLDDz/w8ssvk5GRgaOjo1bnHo0I6evrIzs7G3Nzc6KiosR+LueJWq2mra2N1tZWjejo6+vDzMxMc+P29vbGxsZGL7OKJBIJpqamGg/YcJaWWq3WxJi0t7fT1NRESUkJCoUCCwsLbGxssLGxwcnJCQsLC12ewmlRqVQAXHrppZrGWuHh4WRlZbFu3Tq9ECCAprFjVlYW+/btIyIi4pTfS122ZEhISOCtt97iiiuuYO/evfj6+mp1fpELC1GAnANFRUXccMMNfPLJJ4SFhenEhjOJkO7ubrKysnBycmLGjBl6se5viAwNDdHc3ExTUxONjY2o1WocHR2xtbXF19cXa2trvRQbY0EQBMzMzDAzM8PNzQ04IUr6+/s1oqSxsZHCwkLMzMxwcXHBxcUFW1vbc/pcOTg4IJVKaWpqGrG9qakJFxeXU+7j4uJyxvEODg7IZDKmTp06YsyUKVPIyMgYs40TiZmZGXPmzGH37t3s3r2bmJiYEZ4mXfeDArj99ts5cOAAl156Kbt378bMzEwndohMfkQBMkZ6e3u56qqruPfee/nTn/6kU1tOJUK6urrIysrCw8ODqVOnTnhcymSjr6+PxsZGGhsbaW1txdTUFFdXV6Kjo7Gzs7sgxJwgCBpviaurK/A/MdbY2KhJmXVycsLV1RVHR8dRL+8ZGxsTGRnJ9u3bNfEZKpWK7du3c++9955yn7i4OLZv384DDzyg2bZ161bi4uI0x4yOjqakpGTEfqWlpXqZ7SWXy5k9eza7d+8mJydHI0L0QXwM88Ybb5CSksL999/P+vXrdWqLyORFFCBj5K9//Ss2NjY899xzujYFGClCwsLCOHToEF5eXkyZMkUUH6NArVbT0dGhER2dnZ3Y2dnh4uLC9OnTxYyh/yKTyXBzc8PNzU2zHNXQ0EBxcTH79u3DwcFB4x052xPzypUruemmm4iKimLWrFm8+eab9PT0cMsttwBw44034u7uzurVq4ET37mkpCRef/11lixZwpdffsm+ffv44IMPNMd8+OGHWbFiBYmJiaSkpPDrr7/y448/kpaWNmHvyfkgk8mIjY0lJyeH3bt34+zsTGlpqV6Ij2H7/v3vfxMeHk5KSgrXXXedrk0SmYSIAmQMbNiwgf/85z8UFBRMSIDeueLn50d/fz+5ubl4enqK4mMUdHd3U1VVRW1tLUNDQzg5OeHv74+zs7PBL6tMNIIgYGdnh52dHdOmTaO7u5umpiYaGho4dOgQVlZWeHp64unpecr3csWKFbS0tPD000/T2NhIeHg4v/76qybQtLq6eoSnKT4+ng0bNvDkk0/y+OOPExgYyMaNG5k+fbpmzGWXXca6detYvXo1999/P8HBwXz33XckJCRM/BtyjshkMmJiYkhPT6eoqEhvxMcwHh4efPLJJ1x77bVER0cTFBSka5NEJhliHZBRcuTIESIjI/niiy9YunSprs0ZQVdXF5mZmVhbW3P8+HG9u5DpC0qlkoaGBqqqqjh+/DguLi54eXlp4hL0GYVCwebNm1m8eLFeZzMNDg7S2NhIVVUV7e3tuLq64u3tjYODgyiKT0F5eTlFRUVYWloikUiIi4vTq4cbgIceeogdO3aQnZ2ts8Ju+oZYB2R8EAXIKBgYGCAuLo7k5GTeeOMNXZszgu7ubjIyMjTLLhUVFXqzjqwvdHd3U1FRQU1NDcbGxvj4+ODp6Ylcfv4XDm1hKALk93R1dVFVVUVNTQ1GRkZ4e3vj7e0tepj+y+9jPqysrMjJyUGtVhMbG6tXImRwcJCEhARiYmJYu3atrs3RC0QBMj7oz6dcj3n44YeRSqW8/PLLujZlBH19fWRmZo5YdpnoLrqGglqtpqWlhfLyclpaWnB1dWXWrFnY29uLT+JawtLSkunTpzNlyhQaGhqorKykpKQET09PfH19L6gL7R85VcBpTEwMu3fvZs+ePcTGxupNwLOxsTFfffUVM2fOJCUlhcsvv1zXJolMEkQBcha+//57Pv30U/Ly8vTqyW1wcJCsrCxcXFxOyna5kEXI0NAQtbW1lJeXMzAwgI+PD2FhYWIFWB0ilUrx8PDAw8ODjo4OysrKSE9Px97eHj8/P5ydnS8oUXi6bJfhmJDMzEzy8vKIjIzUm/fF19eX9evXc9tttzFz5kyxPojIuCAKkDNQW1vLrbfeyocffqi5qesDQ0ND7N69G0tLS2bMmHHKi9SFJkKUSiWVlZWUlpZiYmKCv78/Hh4eeh/bcaFhbW1NREQE06ZNo7KykoKCAoyNjZk6deoFIUTOlmprZGREXFwcu3bt4tChQ0yfPl1v3pMrrriCHTt2cO2115KRkSF+t0TOG/3w8ekharWaO+64g2XLlnHllVfq2hwNKpWKffv2IZFIzvqENB5ddPUdtVpNdXU127dvp7q6mpkzZ5KcnIy3t7d4gdRj5HI5wcHBXHTRRfj4+JCfn09GRgbHjh3TtWkTxmjrfMjlcuLi4qirq+Po0aNatPDsvP766xw/fpzXX39d16aITAJED8hp+Pjjjzlw4MCIlt+6Rq1WU1BQQF9fHwkJCaO6wU5WT4haraapqYmioiKUSiVTpkzBw8NDb54WRUaHVCrFz88PT09PysrKyM7OxtHRkSlTpkyqGJGxFhkzNzcnLi6OjIwMjI2N9aagmqmpKR9//DEXXXQRS5cuZcqUKbo2ScSAEQXIKaipqeHBBx9kw4YN2Nra6tocDUVFRRw7dmzMjeUmmwg5duwYRUVFdHd3ExwcLHo7JgFGRkaEhITg6+tLaWkp6enpuLu7ExISYvClwM+1wqm1tbUmMFUul5+2VL22iY+P5y9/+Qs333wzmZmZepWxI2JYiEswf2B46eWyyy5jyZIlujZHQ3l5OdXV1cTFxZ1TLv5kWI7p7OwkJydH85Q8f/58/Pz8RPExiZDL5YSGhjJv3jzUajXbt2/n4MGDDAwM6Nq0c+J8y6s7ODgQERHBvn379Op7+/zzz9PR0SEuxYicF6IA+QMfffQRBw8e5M0339S1KRqam5spKioiJibmvDqSGqoI6e3tJS8vj/T0dMzMzLjooosICQkxmHoYImPHzMyMyMhIEhMT6enpYdu2bZSUlDA0NKRr00bNePV2cXNzY8qUKezZs4e+vr5xtPDcGV6K+fvf/05RUZGuzRExUEQB8jtqampYuXIlH374ITY2Nro2BzhRRGvfvn3MmDFjXJZODEmEqNVqysvL2bFjB2q1mrlz5xIaGmpQBcREzg9ra2tiY2OJjY2lqamJHTt20NLSomuzzsp4N5YbTlfes2cPSqVyHCw8f+Li4rjnnnu4+eabDUoYiugPogD5L8NLL5dffjmLFy/WtTnAieqXOTk5eHt74+XlNW7HNQQR0tPTQ2ZmJmVlZcTExBAZGYm5ubmuzRLREfb29syZM4fAwEBycnLYv38/CoVC12adkonoaisIgiblvqCgAH0pYP3cc8/R2dnJa6+9pmtTRAwQUYD8l08++YRDhw7xj3/8Q9emACcEUW5uLmZmZkydOnXcj6+vImTY65GamoqlpSUpKSk4Ojrq2iwRPUAQBHx9fUlJSaG7u5u0tDS984ZMhPgYRiqVMmvWLFpbW/UmPdfU1JRPPvmE5557juLiYl2bI2JgiAIEOH78OA8//DBr167Vm6WXoqIienp6iIqKmrDUUn0TIT09PWRlZWm8HmFhYWKEvchJmJubEx8fj7+/v8Ybog9LABMpPoYxMTEhJiaGkpISGhsbJ2SOsRIbG8sdd9zBfffdpzeeGRHDQBQgwJNPPkl0dDTLly/XtSnAiViUqqoqYmJiJjzQUh9EyO+9HhYWFqLXQ+SsDPc9SklJoauri9TUVJ16Q7QhPoaxsbFh5syZ5Obm0tXVNaFzjZa///3vHDx4kG+//VbXpogYEBe8AMnNzeWTTz7h7bff1osiVp2dnezfv5/IyMjzyngZC7oUIcNej6NHj4peD5ExY25uzuzZs3XqDdGm+BjG3d0dX19f9u7dqxfeHxsbG1599VVWrlxJd3e3rs0RMRAuaAGiUqm45557WLlyJYGBgbo2h6GhIfbt24e/vz/Ozs5anVvbIkStVlNRUSF6PUTOm1N5Q1pbW7Uyty7ExzAhISEYGxtz8OBBrc57Om644Qa8vb154YUXdG2KiIFwQQuQTz75hIaGBh5//HFdmwLAoUOHMDIyIjg4WCfza0uEKJVK8vLyKC0tZdasWYSFhYk1PUTOm2FviJ+fH7t376asrGxCYxJ0KT4ATT+oxsZGampqtD7/HxEEgX/+85+8/fbblJSU6NocEQPgghUgbW1tPProo7z55pt6Ueq5traW+vp6oqKikEh092eZaBHS19dHRkYGvb29JCUl4eTkNO5ziFy4CIKAv78/s2fP5siRIxQUFExI3Qxdi49hTE1NmTlzJgcOHNCLpY+wsDBuv/12MSBVZFRcsALkySefJCoqSi8CT7u7u9m/fz8RERGYmprq2pwJEyHHjx8nPT0dKysr4uPjz6mkvIjIaLC1tSUpKYnOzk4yMzPp7+8ft2Pri/gYxsXFBW9vb/bt26cXRcqee+459u/fz3fffadrU0T0nAsy2i8/P5+PP/6Y/fv36zzwVKlUsm/fPry9vfWm2RSMfwO76upqDhw4wJQpU/Dz89P5+y4y+TE1NSUhIYGCggLS09OJiYk57zR7fRMfw0ydOpVdu3ZRWFjIjBkzdGqLjY0Nr7zyCg8++CCLFi2a1AUEO4KtkBqf/4OUcrAf9o+DQQbGBecBUavV/O1vf+P+++/Xi8DToqIiBEGYkGJj58t4eELUajWFhYUcOnSIWbNm4e/vL4oPEa0hlUqJiIjAz8+PjIwM6urqzvlY+io+4EQ8SFRUFDU1NdTX1+vaHG644Qbc3d31prCjiH5ywQmQrVu3kp+fz2OPPaZrU2htbaWqqorIyEidxn2cifMRIQqFgt27d9PY2EhiYqIY7yGiEwRBIDAwkKioKAoKCiguLh5zfII+i49hzM3NCQsL48CBAzrvHiyRSFizZg2vvvqq1jKSRAwP/bzrTRAqlYrHHnuMVatW6bzi6dDQEPn5+UyZMkVr9T7OlXMRId3d3ezcuRNBEEhMTNT7cxSZ/Li4uJCYmEhdXR179uwZdS8ZQxAfw7i7u2Nra6sXqblJSUnMnj2bl156SdemiOgpF5QA+frrr2lpaeHee+/VtSkUFRVhamqqibXQd8YiQpqbm9m5cycuLi5aqeYqIjJaLC0tSUxMRKlUsmvXLnp6es443pDEB5zw9oSFhdHc3KwXSzGrV6/mvffeo6qqStemiOghF4wAUSgUPPnkkzz77LM6zzRpaWmhurqamTNnGlQ8xGhESH19PXv27CE0NJRp06YZ1PmJXBgYGxsTGxuLvb09GRkZp01fNTTxMYyJiQkzZsxg//79Ol+KCQsL409/+hPPPPOMTu0Q0U8uGAGyfv16jIyMuOmmm3Rqx9DQEAUFBUydOtUgo8PPJEJqa2vJy8sjMjIST09PHVkoInJ2JBIJM2bMwNPTk4yMDDo7O0f83lDFxzDu7u7Y29tz4MABXZvC888/z1dffcWhQ4d0bYqInnFBCJCenh6ee+45XnrpJZ33GSksLMTU1BRfX1+d2nE+nEqEVFdXU1BQQHR0NK6urjq2UETk7AiCwJQpU/Dx8SEzM5OOjg7A8MUHnDi3GTNm0Nrael6ZP+OBr68vd9xxB0888YRO7RDRPy6IOiBvvvkm3t7eOi861traSk1NDSkpKQa/NPH7OiE+Pj5UVFQQExMj9nMRMSgEQSAkJASpVEpmZiZeXl5UVVUZtPgYxsTEhNDQUA4cOICjoyPGxsY6s+WJJ54gICCAzMxMZs+erTM7RPSLSe8BaWtr45VXXuHll1/W6U1fpVJx4MABQkJCDHLp5VT4+fnh5OTE0aNHmTZtmig+LiD++c9/4uPjg4mJCTExMezZs+eM47/55htCQkI0N8XNmzefduxdd92FIAi8+eab42z16QkMDMTBwYGysjKmT59u8OJjmOGsmOLiYp3a4ezszMqVK/Wm75aIfjDpBcg777zDzJkzSU5O1qkd5eXlqNVqg8l6GQ3V1dU0NTXh5+dHUVGRVrroiuier776ipUrV/LMM8+Ql5dHWFgYCxcupLm5+ZTjs7KyuOaaa7jtttvIz89n+fLlLF++/JQxAd9//z27d+/Gzc1tok9jBOXl5bS0tODn50dhYaFmOcbQEQSB6dOnU1NTQ1tbm05tefDBB8nPzycjI0OndkwGlEolTz31FL6+vpiamuLv78/zzz9/xvo2aWlpCIJw0quxsVGLlo9kUguQnp4e3nrrLVatWqVTO/r7+ykpKWHGjBl6W3BsrNTW1nLgwAFiYmIIDQ3VShddEf3gjTfe4I477uCWW25h6tSprFu3DjMzMz766KNTjn/rrbe4+OKLefjhh5kyZQrPP/88ERERvPPOOyPG1dXVcd999/HFF19oNXX79zEfoaGhBAQEkJWVdVJgqqFiYWGBv78/Bw8e1GmDOBsbG+6++25Wr16tMxsmC2vWrOG9997jnXfeobi4mDVr1vDKK6+wdu3as+5bUlJCQ0OD5qXLApGT4254GtavX4+3tzcLFizQqR2FhYU4OztPmiWK+vp6CgoKmDVrluacJrqLroh+MDg4SG5uLvPnz9dsk0gkzJ8/n+zs7FPuk52dPWI8wMKFC0eMV6lU3HDDDTz88MNMmzZtYow/BacKOA0KCsLX15esrCy96DA7HgQGBtLf3091dbVO7XjwwQfZsWMH+/dfgI1PxpGsrCwuvfRSlixZgo+PD1dccQULFiw461IogJOTEy4uLpqXLh+KJ60AGRwc5LXXXmPVqlU6jf1obW2loaFBqxfViaSpqYm8vDyioqJOUs6iCJn8tLa2olQqcXZ2HrHd2dn5tK7cxsbGs45fs2YNMpmM+++/f/yNPg1nynYJDg7G09OTzMxMent7tWbTRCGTyQgNDaWoqIjBwUGd2eHs7Mytt97Kyy+/rDMb9JnOzs4Rr9PVcYmPj2f79u2UlpYCsH//fjIyMli0aNFZ5wgPD8fV1ZWLLrqIzMzMcbV/rEzaLJgvvvgCMzMzLrvsMp3ZMBx4GhwcrPPiZ+NBZ2cn+/btIzw8/LSde8e7i+5kRaFQ0N/fP+I1MDAw4meVSoVKpUKtVmtuGtu2bUMikSAIAjKZDBMTE0xMTJDL5Zr///4llUp1fKZnJzc3l7feeou8vDytPSycLdV2uEGkQqEgJyeHOXPm6DyF/3xxcXHBxsaG4uJiwsLCdGbHww8/THBwMEePHiUgIEBndugjf6yf9Mwzz/Dss8+eNO6xxx6js7NTk8GlVCp58cUXue666057bFdXV9atW0dUVBQDAwOsX7+e5ORkcnJyiIiIGO9TGRWG/Y06DUqlkjVr1vDoo4/q9AJcUVGBWq3G399fZzaMF4ODg+zZswc/Pz88PDzOOFYUISMZGBigo6OD9vZ2zauvrw+pVHqSeLC2tsbJyUkjHobFRnd3N7m5uURHRyORSFCr1SgUihGipbW1dYSQgRPr/zY2NpqXlZXVed1IHRwckEqlNDU1jdje1NR0WlHq4uJyxvG7du2iubkZLy8vze+VSiUPPfQQb775JpWVleds76kYbZ2P4Voa2dnZ5OXlER0dbdDp84IgEBoaSlpaGt7e3jrrh+Xj48NVV13Fq6++yvvvv68TG/SVmpoarKysND/L5fJTjvv666/54osv2LBhA9OmTaOgoIAHHngANze30xbbDA4OJjg4WPNzfHw8ZWVl/OMf/+Czzz4b3xMZJZNSgGzcuJGenh6uv/56ndmgUCgoLS0lIiLC4ANPVSoVe/fuxdLSkpCQkFHtc6GKELVaTXt7Oy0tLSPEhrm5OdbW1tja2uLr64u1tTVGRkajvqENp24P7zcaO/r6+jTCp6mpidLSUgYGBrC0tNQIEmdn5zGlhRsbGxMZGcn27ds1dXVUKhXbt28/bY+luLg4tm/fzgMPPKDZtnXrVuLi4oATrdtPFSNyww03cMstt4zattEw1iJjw23ud+7cSWlp6YgLuCFiYWGBr68vRUVFxMfH68yOxx57jKioKJ555hmtZzzpM1ZWViMEyOl4+OGHeeyxx7j66qsBCA0NpaqqitWrV4+p2vesWbN0mpU06QSIWq1m9erV/O1vf9Np4Z2jR49iaWk5KVrQFxYWMjAwwKxZs8b0BHihiBClUklLSwuNjY00NjaiVCpxcnLCzs4OX19fbGxstN6QTxAEzMzMMDMz01SmVavV9Pf3097eTkdHBw0NDRw6dAgLCwtNQJqtre1Z/8YrV67kpptuIioqilmzZvHmm2/S09OjEQs33ngj7u7ummyHv/71ryQlJfH666+zZMkSvvzyS/bt28cHH3wAgL29Pfb29iPmMDIywsXFZVxv+Oda4VQulxMTE8OuXbuwtLQ0+BtmYGAg27Zto6WlRWeB8dOmTWPhwoX84x//4NVXX9WJDYZMb2/vSQ+2UqkUlUo1puMUFBTotHL1pBMgqampVFZWcvvtt+vMhv7+fsrKyoiPjzdoly1AVVUVtbW1JCYmntNNdLKKkP7+fpqammhsbKSlpQW5XI6LiwuRkZHY29vrpddLEARMTU0xNTXVXHQUCgXNzc00Njaye/duJBIJzs7OuLi44OjoeMrlmhUrVtDS0sLTTz9NY2Mj4eHh/Prrr5pA0+rq6hHnHx8fz4YNG3jyySd5/PHHCQwMZOPGjUyfPl07J875l1e3srIiIiKC3NxcjTfLUDE2NiYgIICioiISExN1do1atWoV8+fP58knnzTo91MXLF26lBdffBEvLy+mTZtGfn4+b7zxBrfeeqtmzKpVq6irq+PTTz8FTlQE9/X1Zdq0afT397N+/Xp27NjBb7/9pqvTQFDrMjF8ArjssssICQnRaa75/v376e/vJyYmRmc2jAfHjh0jOzub2NhYHBwczutYk6G/hkqlorGxkaqqKlpaWrCxsdF4DiwtLSf0Qq5QKNi8eTOLFy+eMG+KSqXi+PHjGk9Of38/7u7ueHt7j8ozoq+M52evpKSEqqoqkpKSTrs+bwgMDQ2xbds2ZsyYoVOPTmxsLNdee61Ws5/Gg87OTqytrYm86kWkxibnfTzlYD+5Xz9BR0fHqJZgurq6eOqpp/j+++9pbm7Gzc2Na665hqefflrj+b/55puprKwkLS0NgFdeeYUPPviAuro6zMzMmDFjBk8//TQpKSnnbf+5MqkESFVVFUFBQRw5cmREQJs26e7uJjU1leTkZCwtLXViw3jQ29tLeno6ISEh49Y4z1BFSF9fHxUVFZone29vb7y8vLSa2aQNAfJ71Go1HR0dGg+YmZkZPj4+eHp6GlQ2yHh/5tRqNfv27WNgYID4+Hi99HSNlsrKSo4ePcrcuXN1dh5ffPEFzz33HMXFxQb1XupagEwWDOcvPgrWrVvHkiVLdCY+AA4fPoyHh4dBi4+hoSH27NmDm5vbuHbtNaQ6IWq1mmPHjrF37162bdtGV1cXERERXHTRRZMmrfpMCIKAjY2Npsy6v78/1dXVbNmyhUOHDtHT06NrE8/KRAheQRCYOXMmQ0NDHDhwQKeVRc+X4eukLouTXXHFFbS3t7Nt2zad2SCiOyaNAOnv7+fDDz/kvvvuO+M4tVrNjh07KCoqGncb2tvbaWxsHHWmiD6iVqvJz8/XFC4abwxBhLS0tLBr1y52796Nqakpc+fOJSYmBicnJ4NdhjgfZDIZXl5eJCYmEhcXR19fHzt27GDfvn16Wyl0Ir1tMpmMWbNm0djYOO4pwtpEIpEwZcoUSkpKGBoa0okNcrmcO++8c1QlxEUmH5NGgHzzzTc4OTmdtencjh07mDdvHtOmTWPBRQv49ddfxxw5fDpKS0vx9vY26KfjsrIy2tvbNfUmJgJ9FSHt7e1kZWWxZ88eXFxcWLBgAdOnT5803YvPF0EQsLOzIzo6mnnz5iGTyUhNTdXEPOkL2ljqMzMzIzo6msLCQr36DI8VNzc35HK5Tr0gd955J1u2bKGqqkpnNojohkkjQN5//31NG+8z8eabb2Ils2Uas9iblseiRYsICQ7hvffeOy+3cldXF01NTQZd2a+rq4vDhw8TEREx4QF2+iRCuru72bdvHxkZGVhbW3PRRRcRFBSk9dRZQ8LMzIzw8HCSk5MZGBhg27ZtFBUVoVAodGqXNuOM7O3tCQoKIj8/H6VSOaFzTRSCIBAYGMjRo0fH7UFsrLi7u7NkyRLWr1+vk/lFdMekECAHDx4kLy+PG2644YzjKisr+fnnn3Eb8sVV8CJyKJkokuks6+Oee+7BzdWNRx99lJqamjHbcOTIETw9PQ3W+zG89OLj43NSTYaJQtcipL+/n/3795OamopUKtV4xnRZP8bQsLS0ZNasWcTHx9PW1sbWrVs5evSoTm7IughyDggIQCaTcfjwYa3MNxG4ubkhkUiora3VmQ133nkn69ev17mAFdEuk0KAvP/++1x11VXY2tqecdy6deswkhjjyongK0EQsBEcCCWWePXF2Ha58Obrb+Hj48tVV1112u6ef6S3t5e6ujqD9n4cPXqUwcFBpkyZotV5dSFC1Go15eXlbNu2jYGBAZKTk5k5c6bBikd9wM7Ojvj4eCIjI6mpqWHHjh20tLRobX5dZVhJJBJmzpxJRUWFzj1558qwF+TIkSM6C6pdsGABJiYmbNq0SSfzi+gGgxcgfX19fPbZZ9x5551nHDcwMMAH73+Is9ITqXByGqGpYE6gMIN45SICVaH8+v1vxMfHEx0VzZdffnlGZX706FFcXFywsLA47/PRBV1dXZSUlBAREaGT3jnaFCE9PT1kZmZSVlZGTEwMs2bNMuiMJX1CEAScnZ1JTk7G39+fnJwc9u/fP+EBjrpO77aysjL4pRhPT0+GhoZoaGjQyfwSiYQ77riDDz/8UCfzi+gGgxcgP/30E87OzsTGxp5x3Pfff09b+3E88DvjOJkgw1MIYNbQfMKZTWV+Lddccw2WllYsXLiQI0eOjBg/MDBAdXU1gYGB530uuuD3Sy+6rM0x0SJk2OuRmpqKpaUlKSkpOitDPdkRBAE/Pz9SUlLo6uoiNTV1wrwhuhYfwxj6UoxEIiEgIECnXpAbbriB7du309jYqJP5RbSPwQuQzz//nOuvv/6swafrP1yPmWCJHLNRHVcQBBwEV8LVCTjjwZBCydat2wgKCmbq1KkaV2FZWRn29vY66yx5vhw9ehSFQqH1pZdTMVEipKenh6ysLI4ePUpMTAxhYWEGVUzLUDE3N2f27NkT5g3RF/EBk2Mpxtvbm56eHq0unf0eT09PEhIS+PLLL3Uyv4j2MWgBcuzYMX755Reuu+66s46NjYulj24ypZspVufSoT4+KqU/pFbQSiPeTnEkTX+QANdkjh6p4tJLL8XdzZ3Dhw9r+p0YGsNLLzNnztTJ0supGE8RolarqaioIDU1FQsLC9HroQNO5Q1pbW097+Pqk/gYxsrKiuDgYINdipHJZPj5+XH06FGd2XD99dfz+eef62x+Ee1i0ALkm2++ITIyEn9//7OOfeGFF6isrOTxJ1fRZ9vJXnawT7aDavURFOrB0+5XTyUqVHg4RGJsZI6f6xySpj9IqM9lREfNprKyEi9Pb6655hqam5vH8/QmFJVKRV5eHr6+vnpzAR9mPESIUqkkPz+f0tJSjddDTKvVHcPeED8/P3bv3k15efk5u/r1UXwM4+/vj5GRkcEuxfj6+nLs2DG6urp0Mv+f/vQnDh06ZLDvn8jYMGgBMrz8Mlq8vLy49tprOd52DIAeujkiHCBD+JlD7OG4unnERVGtVlNLBY42wZgY/y9QUSKR4moXyrKll1O0rwMbM1++/PJLXFxciYmJYffu3eN3khNEWVkZQ0NDelu19XxESH9/P5mZmXR3d5OUlCR6PfQEQRDw9/cnPj6e0tJS9u/fP+baE/osPsDwl2Lkcjnu7u5UVFToZH4bGxsuueQSvvjiC53ML6JdDFaAVFRUsGfPHq666qox7ffJJ58gl5oQw3zch/yQS0xQqpW0GTWRx05yZFupUB9mQN1HGy300omXY9RJx3HzscDMwoj6MoFw/6uYM+1+vBxjyN1XQFxcHJ6ennzwwQc6K+5zJvRx6eVUnIsIaWtrIz09HQsLC2bPno2Jyfk3ihIZX+zs7EhKSqK9vZ3MzEwGBgZGtZ++i49hLC0tCQ4OJi8vzyCXYnx9famurtZZTY7rrruOL774wqD77IiMDoMVIBs2bGDBggVjerpVKpV88vEnOCjdsBRsCBRCiVcuIox4rBT2CAj0KruplBSTwWYK2YuxzBwbi5Ob24VGOVKc34py6MSXxFRuQ7DHRSSFriTEcxHHmru58847sbK04r777qO3t3fczv18KSoqwtPTU68v4sOMRYTU1taSmZmJv7+/3ourCx1TU1MSEhIwMTEhPT2djo6OM443FPExTEBAABKJxCB7xdja2mJlZXVOBRnHg8WLF9PW1jbqOkwihotBChC1Ws3nn38+quDT35Oenk5DYwOueGu2SQQJjoIbYcSTwGL81FMxFcxRo2ZIomBwqIedB//Bkbod9A60AWBmYYRPkDWFuScH08mkxng5RpMw7T5m+l+NXOLIO++8g4WlFYGBgezZs+f8Tv48OX78OC0tLQQHB+vUjrFwNhGiVqspKipi//79REdHExAQcEE2jTM0ZDIZUVFReHt7s2vXLurr6085ztDEB5xYbpo6dSqlpaUGWd3Tx8eHyspKnXgh5HI5V155pRiMegFgkAKkoKCAmpoali1bNqb9PvvsMyxkVlhz6ouYXDDFRwghRnkRkSThpHJHgpTBoV4qmzLJKFzL3tJP8Qgeoraik6720wevCoKAo3UQ4f5XI5XKMbF0pKy8gpiYWGxtbXnnnXfGZPt4MHyj9vf3N7ilidOJEJVKRW5uLvX19SQmJuLs7KxDK0XGiiAIBAcHExkZSX5+PuXl5SN+b4jiYxhnZ2csLCwoKyvTtSljxs3Njf7+fp3FsVx//fV8/fXXBineREaPQQqQjRs3snjx4jF1Ke3v7+fbb77Fccj9rE/HgiBgKzgyTYgmkUuYQgRWwoky7519tcyIdufL7z7kcO0WuvrOnPnScPwgSuUgQSm3EX7507iHLaS7b4j77rsPY2M5119/PYODpxcy40lzczNdXV0GWzL+jyJEpVKxb98+urq6mDNnjljR1IBxdXUlLi6O4uJiTRqoIYsP+J8X5OjRo6OOc9EXZDIZnp6eOltCSkhIQCqVkpmZqZP5RbSDQQqQH3/8cczejx07dtDd040EKUPq0atqmWCEu+BHNHOJ5SLmhS5EJpORsyebmua9ZBevY/fh9dS25jOkHCkk1Go1Na37sPGYitzCDiMTC9xDLyL88qfwm30tRhYOfPHFF5iYmhEVFTWhkefD3g9D7/I6LEKysrLIzMykt7eX2bNnT3j3XpGJx87OjtmzZ1NaWsru3bsNWnwMY29vj6OjI6Wlpbo2Zcx4e3tTX1+vEy+ERCLhkksu4ccff9T63CLaw+AESE1NDQcOHGDx4sVj2i8mJobo6FmUcYhdkp85yG6a1LUo1aOPUrcQrElJmkvmrixsLXyxMT8RS9LZW09R9Y+kHXiNwqqf6OipQ61W095TQ3dfE85Bs0ccRyKV4eAbybTFK5my4F5s3KeRm5uHn38Abm5ufP/992M6t9FQW1uLQqHAx8dn3I+tbXx8fDAzM+P48eNMnTpV7F47ibCxscHb25umpibc3d0NWnwMM2XKFCorK+np6dG1KWPCysoKS0vL08bmTDTLli1j06ZNYjbMJMbgBMhPP/3E7Nmzx3xhsre3JydnN4H+gShVQ3QYtXKQ3WRIfuIQe2hR16M6ixiRyaX4xXqyI207gW5ziQ6+gcTpDxDgmoyx1AyVeoj6YwXklPwfWcXvUVL7G3JzO6xcT90nRhAELJ18CUy6ibDlj+MSkkhTyzEuv/xyzMzMePTRR8cljU+lUnH48GFCQkIMPjNkeNlFKpUydepU9u7da5D1FkROTXl5OZWVlURERFBfX2+Q8RN/xMrKCnd3d4MsruXh4UFtba1O5p4/fz41NTWUlJToZH6RicfgGmJs2rRpzMsvwxQWFnKk7Ai+hNCv6KVV0oBCpaDNuInGwWqMpXLsla644IEtTkiEkfrMN9qTY63HaK7vImCqCwAmxlb4uSbi6zKH492V1DTvo7mjmJ7+VgRBAoJAWcYGnAJjsXT2O7HtFMgt7PCKXIr7jAW0lu+lsTidV155hddef4N5c1P4+uuvz7nfTGVlJVKpFE9Pz3PaX19Qq9Xk5eXR09PD7NmzMTY2RiqVkp2dbfCuepGTYz4sLS3JzMxEIpHg6+ura/POi5CQELZv305AQADW1ta6NmfUuLu7U1RURF9fH6amplqd29zcnPnz57Np0ya9LZg42bn88svHvM+6detwcnIa1ViD8oB0d3ezY8eOcxYg3333HcZSOb5MYRqzSFBdwgzisVU4IZPIGFQOcMyogXwyyJL+QrE6b0R11MBEb1LTd+BmH3ZSIKsgCNhb+hLufyUpMx4mxHMRciMr1Colx6v3c3jbe+zf+BL1h7Yz2Nt5WhulRnKcgxOYcekqgpJvw9zBh61bt2JnZ09gYCA5OTljOmeFQkFJSQlTp041+NTUwsJCOjo6iI+P1yy7THQXXRHtcKqAUxsbG+Li4igsLNRZm/jxwszMDF9fX4qLi3VtypgwNTXFwcGBuro6ncy/bNkyMQ5Eh2zcuBFjY2Osra1H9fr555/p7u4e9fENygPy22+/4evrS2DgqZc0zsY3X3+DvcoZiXBiGUIqSHHCDSfcUKqUHKORRkUNx4VG+pV9tMhqqRsqx1Rqho95IF7hV/Pyh+mEOF1zxnmMZKZ4OUbj5RhNZ28j1c37qD9ewGBPG7UFv1Bb8As27lNxDIzFxi0YQXLysoggSLDxmIqNx1R62xpoPLyLsvJ9xMbGYW1txQsvvMC999571nMuKyvDwsLC4NNTq6urqa6uJjEx8aSA0+FmgKInxDA5U7aLnZ0dM2fOJC8vjzlz5mBlZaUjK8+fwMBAtm3bRmtrKw4ODro2Z9R4eHhQXl6uk+y5Sy65hLvvvtvg3rPJxNtvvz1qj8a33347pmMblAfkXLJfhikvL6ewqBAHtdspfy8VpDgJ7swQYpmjvoRQYrEZckQqSOlT9uKf6EnpkVJaWlqpat5DZ2/9qIKjrMxcmO5zCfPCHyPU53IsTV0ANe31xRxJ+z/y//MctQW/0N917LTHMLN1xS/uKsIvfxqPsIvp6Vdy3333IZVKSUlJob+//5T7DQ4OUlZWZvDej+PHj3PgwAGioqKwsLA45RjRE2KYjCbV1t3dHX9/f3JycrSWsj4RyOVyAgICDM4L4urqSldXF52dp/fcThRubm7MnDmTzZs3a31uEUhNTR3TA90vv/yCu7v7qMcbjABRKpX89NNPLF269Jz237RpE1KJFHvO7gmQCjKcBQ9mCHHMUS9lOjGkJMwlPW0narWK6uYcdh9ez67CtzlSv4OuvqazihGpRIar3XTiptxBwrT78HOejUQwYqi/m/rC7Rz44SWKt77Hscp8VMqhUx7DyMQCt9D5hF/+FDYe01CpVKSlpWFqbo6XlxeFhYUjxldWVmJjY4O9vf3o3yg9o6+vjz179jBlypSzqnBRhBgWY6nzERwcjLW1NXv37tXL/kqjxc/Pj87OToP6fBoZGeHq6qqzYNSlS5eyadMmncx9oZOUlIRMNvqFkoSEhDGVRDAYAbJ//34GBweJi4s7p/03/bAJC7UNEsaWBSITZPg7BOMb6IOQbcU0ZmGPMwIC/YMdVDZmkl38PplF71LWkE5P/+k9GcOYyW0JcEthXvijeDnOgv+Kl67mMsoyPif/22eo2vcDve2NpzmCmu7WSmxmJeB5y31YBE+npqaW6aEzsLCw0DTBq6io0CxPGCJKpZKcnBycnZ1HfR6iCDEMxlpkTBAEIiIiGBwc5NChQ1qwcGIwMjLCy8vrpIqv+o6bm5vO0nEXL17M9u3bDbKx32QiLy+PgwcPan7+4YcfWL58OY8//vg5eyYNRoCkpaWRmJg4JjX2exwdHelQHyND+hMH2E29upIB9amXLv6IT5Q7DYdbGOpW4Sp4ES7MJollTCUaO5wBgd6BY5Q17CSz6J9kFa2jojGTvoH2Mx5XECR09jVg7RrMzCv+jlfEUmRyc5SKfppKMjj006sU/vIWLUdzUCr+V0nxeNUBhvp7sI1OwMzLF/erbsbvr09gG5tIr0LBnXfeSXJyskGvm6rVavLz85FKpYSFnRz0eyZEEaLfnGuFU5lMRkxMDHV1dQbZ5G0YPz8/Ghoa6Ovr07Upo8bJyYm+vj66urq0Pnd4eDgqlYoDBw5ofW6R/3HnnXdqCuqVl5dz9dVXY2ZmxjfffMMjjzxyTsc0GAGSmppKSkrKOe//5VdfkpeXx1PPPoV3pCvFQi67+Il90jTK1UV0qo+fdhnFN8qDyr0j3Y8ywQg3wZuZQgJJLGUqUVhhA0B3fzNH6newq/Btdh/+kKqm3fQPnrx+2jtwnPbuGhz8ojAyscBlShIzr/g7Uy/+K3Y+4YBAz7EaKnZ/Tf63z1Cx+xu6W6tpPpKFmW8gxg7/W5IwsrHDacEyAh76O06LLueSZZfy1VdfYWxiQmhoKE1NTef83umC8vJyjh8/zqxZs5BIxv4xFUXImfnnP/+Jj48PJiYmxMTEnLVJ4jfffENISAgm//08/X5NXqFQ8OijjxIaGoq5uTlubm7ceOONp3xiPt/y6mZmZkRHR3Po0CHa2trGvL8+YG5ujpOT04RWPh5vZDIZjo6OOrmOyGQyEhMTSU1N1frcIv+jtLSU8PBw4MT1IDExkQ0bNvDJJ5/w3XffndMxDUKAKJVKdu7cSXJy8jkfQxAEZs6cyZNPPsmevXtoamriX//6FxddlkKLRQ172EGW7FcK1ftoUtdqyrXL5FI8ZrhQsff0659GgjFugg/W2GMsM2eq1yXYmHsA0NnbQEndVnYeepM9JR9R3bKXAcWJiogNxw8ikRlj4zl9hJ0WDl4EzL6OyKtfxDduBXJLR1RKBS1leyj69S26WyqRWdmg7Du5sqLEWE5o8jx8/PwosnXH1MuPQ4cO4eLmhr29PVu2bDnn91BbdHV1UVxcTFRU1HmVWBdFyKn56quvWLlyJc888wx5eXmEhYWxcOFCmptP3dcoKyuLa665httuu438/HyWL1/O8uXLNUshvb29J8T9U0+Rl5fHf/7zH0pKSk4KGB+v3i4ODg4EBQWRl5dnsG55Pz8/qqqqDMp+FxcXGhtPtyw8sSQnJ5OWlqaTuc9Eh59Ah/84vPz0P0lArVZr4q+2bdumqUbu6elJa+vJneFHg6A2gDq3ubm5zJs3j2PHjk1IJU+FQkFWVhY//fQTmzZuovRoKRJBip3gSEJ0IktvXMy/7/3pjMdQq9Vk8guODlOZ4nXiDzOo6KGp/TB1xwro7B2ZR29r7k3P4HEs3QPxT7jurDb2dbbQVJpF8+EM4L9BeBIpllNnYBMRi6mPv6bI2VXejvQrVWyqPRGPMtDcQFvOLjr27wWVCmMjIx566CFeeumlMb5TE49arWbXrl3Y2dkxffr0s+8wCgy9qRmc+Ixu3ryZxYsXn3cvnxNtCaI1HZlVKhWenp7cd999PPbYYyeNX7FiBT09Pfz00/++A7GxsYSHh7Nu3bpTzrF3715mzZpFVVWVJuZhPP8GKpWKXbt24eDgwLRp0877eNpGrVaTmpqKv78/3t7eujZnVPT19bF161Yuvvhirbc/mOh7wFjp7OzE2tqagMdeQio//87iyoF+jr78OB0dHXqbaj537lw8PT2ZP38+t912G0VFRQQEBJCens5NN910TsuiBuEBGY7/mKgPnpGREUlJSbz66quUHCmhvLyct95+k4j5M/COcWXnnlRypFspURdwTN2ESn1yFH4X7fTTi5PN/yr2GRuZ4+kYSWzIbSSFriTEcxEWpieycNp6qhgc6uFYVQElOz6ktTwX5eDpY1JMrRzxibqU6GtfJjDpFkxt3UGlpKtoPzWfvkf5Wy9yLGM7Rn09zLAxJ6f1f0s+cidXXJZehf/KZ3BIWYRSZszq1auRSKUkJyefNo1XFxw9ehSFQsGUKVPG7ZiiJ+R/DA4Okpuby/z58zXbJBIJ8+fPJzs7+5T7ZGdnjxgPsHDhwtOOB+jo6EAQBGxsbCZEAEokEmbOnElFRYVB/k0FQcDHx4eqqipdmzJqTE1NsbKy0skyTHh4OGq1mv3792t9bpETvPnmm+Tl5XHvvffyxBNPaOrCfPvtt8THx5/TMQ2iEFlaWtp5xX+MFV9fX+69917uuecefvnlFxQKBXK5nE0/bCK/aRdGUmNsVU7Yq51xwBW5YEIL9cgkcmwtT/00Izey0BQnG1B00dRWTFXLXvoGjtHRUEpH/WEEiRQb9ynY+czExn0qUtnJTxmCRIqt53RsPacz2NtJ05HdNBbtYKijjdYdm4kxgQo3K8oOHMA8IGREkTOZmQX2c+ZjF59MV9F+jmelkZ6ejqm5OZ7u7vz888+EhoZO2Pt6Nrq6uigpKSE+Pn7cxaZYrOwEra2tKJXKkwrTOTs7n7ZXSWNj4ynHn84d39/fz6OPPso111xDa2vrhHmfrKysCA4OJj8/n+TkZL14Mh4LHh4eFBYW0tnZqbdPvX9keBlG220dpFIpiYmJpKWlERERodW5L3TKy8vx8/NjxowZI7Jghnn11VfP+bun9x6Q8Yj/OFeGg9yWLl3K+++/T31DPQUFBTzz96fxiXLnsJD330DWVOqpxMbCE2EUb6ncyBIvp1nMmXYPidMfINj9IkyMbVCrlLTVFlG26zPyvnmKo7s+o63m0GnrghibWeEZtoCoq1czZcE9WLoEsmDBAn79cRN1//4/yt54jtYdvzDYNjI1WJDKsAqNxPvPK/G69X9pvDPCwjVpvNpGpVKRl5eHr6/vhIkD0RMy8SgUCq666irUajWPPPLIhC99+fv7I5PJDLLRm7GxMe7u7gaV0ePi4kJzc7NOYlf0NQ5ksjNjxgymT5/O448/fspgdRMTk3NeFtZ7AVJQUIBEIiEsLEzrc7e0tODk5KTJwhAEgbCwMJ544gly9uymubmZzz77jAWXz0MpU9LaeZS0A69xqGoTTW3FDCkHzjLDiWZ23k4xJE6/nznT/0qQ2zxMjKxRK4c4Xn2AI+kfk/fNU5Rl/Zv2umJUqpO/+Ce66vox78r7cXb1oKbfAamxGcqeLo5lbKPi7Rep/te7dB7KRzU0NGI/U8/fpfHGJWnSeKVSKQsWLEChUIzfG3oGysrKGBoamvCmUxe6CHFwcEAqlZ7kRm9qasLFxeWU+7i4uIxq/LD4qKqq4sMPP6S2tnbCvU0SiYSIiAiDXYrx9vamtrbWYIJRra2tkUqltLe3a33u5ORkdu7caTDv1WShtbWV1atX09zczLJly3B1deWOO+7gxx9/PO/le70XIDt37iQhIUEn7tWz1dFwcHDg+uuv56uvvqKzs5233nqLmZGhHOs6zP6Kb0jd/yp7S/9FVdPuURUoMzW2xsc5jsTQvzJn2v0Eus3FWGaJamiQ4xV5lKauJ/+bp6nY/Q2djUdQ/6EiZLivFYU13dj6ziLyqueZfsnD2HvPBKCvqpyG7z6j7LWnad7yAwPNI93nRjZ2OF20lICH/o5NbCIqlYqtW7dibGKCp6cn1dXV5/AOjo6enh5KSkqYOXOmVv7OF7IIMTY2JjIyku3bt2u2qVQqtm/fftoif3FxcSPGA2zdunXE+GHxceTIEdavX09jY6PWlrosLS01SzGGViXVzs4OuVyusyJfY0UQBBwcHM456+F8GI4DOdUygMjEYWJiwtKlS1m/fj0NDQ1899132Nvb8+ijj+Lg4MDy5cv56KOPaGlpGfOx9T4L5rrrriMkJISnnnpKq/MqlUo2b95McnIylpaWY95/165drF27lh07Ujl27BigxsTYGifrEBytA7C18EYiGV0ITu9AG/WtB6hp3YtC2YsgSFCrVcjkZtj5zMTeeybWzj48uMyPL3bW09g20vPSeDiD6tyNyKxtGGpvA4kEVCpM3L2wiYzDclo4EuP/pbvWffMJ/W0N2F69mK4tGfQXlYFEgqlczscff8yKFSvG/H6cidzcXE2lS22ib9kxAwMDdHR00NfXR39/v+alVCo1X24HBweMjY0xMTHBxMQEuVyOubk51tbWoy7S99VXX3HTTTfx/vvvM2vWLN58802+/vprDh8+jLOzMzfeeCPu7u6sXr0aOJGGm5SUxMsvv8ySJUv48ssveemll8jLy2P69OkoFAquuOIK8vLyWLduHW1tbURGRmJra4udnZ1WMiZUKhU7duwgMDDQYLJKhjl69CjNzc3nHMinbSoqKqivr2f27Nlan3vu3Llce+213H777Vqf+/dciFkwp+LIkSNs2rSJH374gZycHN544w3uueeeUe+v90Goubm5XHfd2dNUx5u2tjaMjIxO2/zsbMyZM4c5c+YA0NzczNq1a/nuu+8oLc2luiUHiSDDwcofB+sgHK0DkBudXuSYyW0JcE8iwD2Jnv5j1LcepKI5g6GBXppLs2kuySQ6Jp6enrs4euQI5vaeIyqHHqvKw9w/BI/r7kDR0cax3bvo2LOT/voaGuuqafrlP1iFRmIdEYvM0oruw4ewvWYxZuEhmIWHMFjbSOdvWfRk5nH1NddoakJ8+OGH5/Te/J6Ojg7q6+uZN2/eeR9rrOgyMFWtVtPZ2UlTUxNtbW20t7fT39+Pubk5ZmZmGnHh4OCATCZDLpdTW1uLi4sLKpVKI1b6+/vp7u5mYGAACwsLbGxssLOzw8XFBVNT01POvWLFClpaWnj66adpbGwkPDycX3/9VRNoWl1dPaL4W3x8PBs2bODJJ5/k8ccfJzAwkI0bN2rSpOvq6jS9Oi655JIRc6WmpmolfksikTBlyhQOHTqEh4eHQQWkurq6UlRUhEKhOO8Ua23g4ODAoUOHUCqVWn+fIyMjyc3N1bkAETlBYGAgDz30EA899BDHjh0bs0dZrz0gXV1dWFtbU19ff9r16YmipKSErq4uoqKixvW4KpWK7777jg8//JCdO3cxMHBiDc3CxBknm2AcrQOxMnM7Y+nxIeUAqQdewzkkASTGtJRmcNstN6AGPvzgA4zNbLD3jcTeJxxBasTBTS/j+qcbsJo+U3MMtVpFb8VRmrf+yGBjncYrIjW3QNnbjdurD2PkOPKGrOzqoTttD51bMlF19YBEYPrUaeTk5GBmZnZO70d2djaWlpbjVvPjXNCWJ0StVtPS0kJjYyONjY0MDg7i5OSEnZ0dNjY2WFtbn/YGdLY6IH19fXR0dNDe3k5rayvHjx/HysoKFxcX3NzcJvypSh+8SWq1mvT0dNzd3QkMDNSJDefKjh07CAkJwc3t1N269Qm1Ws2WLVuIjo7WeqPLL7/8kjfeeOOslXsnmgvVA1JfX09GRgbNzc0jljsFQeC+++4b8/H02gOSn5+Pq6ur1sUHnIj/GEtb4dEikUi48sorueyyy7CztUMYkNBPH939TfQ0NlPeuBMjqSmO1kE4WAdib+WHkXTkB7yl4whqtRLn4ATkFnZ4zbyY+EQP/vXNZiQyOYO97TQUpdJQuB2p8QlhYGzvOOIYgiDB3C8I3zsfQtnXy/H8PRxP/QVlTzcA9Y++jln0DCyTo5GH+CIIAlJLc6yXpmC1aA69ew/RsXkXhw4dwtzSEhsrK3755RdiY2NH/V4M3yh1nVY30Z6QgYEBKisrqaqqQqVS4erqSlhYmCYgdDwwNTXF1NRU810ZHBykqamJxsZGdu7ciaWlJT4+PhPiHdAH8QEnLoJTp05l3759+Pj4GIQ3YRhnZ2caGhoMQoD8Pg5E2wIkIiKCAwcOGIy3aDLxySefcOedd2JsbIy9vf2Ih+RJKUByc3OJjIzU+rxKpZLjx49PaOZNTk4OXd1dRDMXC6xoo4Vm6mmV1DGo7KOh7SD1x/cDArYWXjhaB+FoHYiZ3J7mjhLMbN2RW5y42DtZG2MqN6LfegaRK0Lp62ik5ehemo9koRzsBUGg6oM3MHZ0xio0EsvpMzG2/d+FQ2pqhmN8Mo7xyfQ31NK05Qf6q8ro3XuA3t0FSB1ssUyZhUVCJFIbSwSZDPO4cMxiwxg4Wk3Xrxm05xYSNzseI6mM55577pQVNX+PWq3WVNI7n3Lr48VEiJC+vj5KSkqoqanB3t6e6dOn4+Lick69bcaKsbExnp6eeHp6olAoqK2tpaysjKKiIvz9/fHz8zvnxo6/R1/ExzCOjo5YW1tz5MgRpk6dqmtzRo2rqys5OTmoVCqtfD7OFwcHB+rq6ggODtbqvAEBARgbG1NYWKjpSyKiHZ566imefvppVq1aNW6fUVGAnILh+A9zc/MJm+O3335DLjXBSml74okCVxxwRa2KoJcuWtWNNAo1dKnbaOuuoq27mtK6rciNrFAoe7H1CUelHEIilRHkZk5FUy9K1QklambjinfUMrwil9LX3kBTSRYtZTkMtjTRmvoLrTs2I3dxx2pGJJbTwjGystHYZeLqgffN96BSDNJ2MI9jW35A2dpG+7e/0f7tb5iGh2CRPAvT0EAEqRSTQG9MAr0Zam2ja/tuunbksGrVKlY9/jjz581j8+bNp3xSaWhooLe3F39//wl7j8fKeImQwcFBjhw5QkVFBS4uLiQlJenUrWpkZISvry8+Pj60tLRQXFxMeXk5wcHBeHt7n/PFRN/EB/zPC5KZmYmvr+9p42D0DVtbW+DEtUfbXoVzwd7enoMHD2o9DmQ47To3N1cUIFqmt7eXq6++elwFst4LkKuvvlrr8w5fBMbSAn6sbP1tK9Yqh5PmEAQBc6wwxwpvghhCwXGaaaKWY0IDA4pOBEHKsfJ9HK8qwNo1mOtnryS37OS0OEEQMLN1wzf2Cnxi/kTv8TqaSjNoLdvLQGMdLU31tPy2CRMPH6xCZ2I5NQyZxYkbpcTIGPuIWOwjYhlsO0bL1p/oLt5P3/4S+vKLkVhZYJkcjUViNDJHW2QOttiuWIT1pXPpycyj85cMtm3bhrGJCR5ubmRmZuLl5QWc8H4UFxcTHBw8Lk/h48n5iBC1Wk1FRQXFxcXY2dmRkJCAjY3NBFk6dgRBwMnJCUdHRxoaGiguLqasrIywsDAcHR3PfoDfoY/iYxhbW1ucnZ0pLS3VSf2gc0EQBE11WUMQIBYWFshkMjo7OzXiSVsMB6LedtttWp33Que2227jm2++Oat3eyzo19X/dwyX5daFB6S9vR1ra+sJO35PTw979u7BWx2MGvUZhY5MMMIJd5xwR61W000HTeo6mqimT9mDpK8JdycbnnjkAYakFth6TsfGfcp/M2H+p1QFQcDc3gO36RfRWrYX++SLGWxtoquwgP7aSvprK2n+ZSOm3n5YhUZgOWUGUrMTHiBjW3vcr7oJ5eAgR9c8DsZGqDq76fgpjY5NqZhM9ccieRZmEVORmMixnBeHRUoM/QdL6fw1g9qiMrx9fTExNmbdunUsXLiQoaEhvU2XPBcR0tPTQ35+Pn19fURHR+Pk5DTRZp4zgiDg5uaGi4sLlZWV5OTk4OnpybRp00YlCPVZfAwTHBxMeno6ISEherHENxpcXFwoLi42iOZ6giBgbW1Ne3u7TgTIW2+9pdU5RWD16tVccskl/Prrr4SGhp7k2X7jjTfGfEy9FSAFBQW4uLjg6uqq9bnb29sn9OaoVCqxtrKhvK2IRlkVlkN22OKALY6YYXlaQSIIApbYYIkNAUxDoR7EL9KVspJyuru6UdNFX0cT9Qe3IjU2xcZ9KjYeU7F2DUZmfMIV3VZzEEEqwy4uCYmxHPXl19FfV82xXTvoKS2kr7qcvqoymn7+FjO/IKymR2ARMh2piSm9ZYdBpcL12fuRWlnQvmkH3Vuz6T9cQX9RGYKZCRZzIrFIisbY3RnTsBBMw0IYrG2i87dMejJyufnmm/n73/+OUqlk4cKFE/Yeny+jFSFqtZqqqioOHTqEp6cnsbGxeufVOR0SiQQ/Pz+cnZ3Jz88nNTWViIiIMz6BG4L4gBN9Yuzs7KisrNR6nMK54uTkRG5uLt3d3eec/q9NbGxsdFIRNTIykv3794uBqFpm9erVbNmyRfN9+mMQ6rmgt1fKwsJCnTRGGxwcpLe3d0Jd51ZWVlRUlpOZmUlaWho7tu8gPz8fpUqJqcwMK6UdNuoTgsQcq9P+cY0EY8JmhVK3t5m5XE4nbTSr62gQqhgc7ON4ZT7HKnJBELB09MXGYyrHqgow8wvSFB4TBAmmHj54XHMrarWKvpoqajZ8CAP99JaX0ltWAj9KMA+YwlB3J8bebhi7n6gXYX/dUuyuvYTB8lpaP/yGoYYWurZm07UlE2M/TyxTZmEWMwNjD2esLoqnJ30vIbNnMGXKFG6//Xaee+F5vD29OHTokF5ecM8mQpRKJQcOHKCpqYmYmJgxL2PoC+bm5syePZvy8nKys7OZPn06Pj4+J40zFPExjL+/P/v37ycwMNAgAjtlMhkODg40NjZqOo3qMzY2NpSWlmp93sDAQARB0MQxiWiH119/nY8++oibb7553I6ptwKktLRUJx+ujo4OTE1NJ7x6o5WVFYsWLWLRokUAdHd3k5WV9V9Bkkpu3j6GhoYwkZmOECQWWGsEiUwuxWOGKxmf5J1wiWKHNXYEEsoetoOpCSCls7eWruZyuprLQSJB2tdO0+b/YBE0BVOfACSyE08RgiBBZmkFA/043H0NUhtL2r/fxkBxOT1Hik8U7hcEWt7ZgHlsGKYzghCMjZD7e+L+8kpUA4N0bNtN539+Y7CilmPlNRz/bBPm8TNRdvdgbGfODY/fQZm6Gd/7Y6n4Kp+qI1VY2VhhYmzCTz/9xNy5cyf0fR8rpxMh/f397N27F5VKRVJSksEEO54OQRDw9/fHxsaGPXv20NHRQWhoqObGbWjiA06ktkqlUhoaGiYkpX4icHFxoa6uziAEiLW1NZ2dnToJRA0ICNDZPeJCRS6Xj3v1W70WIBdffLHW521vb9dJ4KCFhQULFixgwYIFwImI4+zs7BOCZEcqe/fsoXRIgVxmgrXSHmu1PTFhMXS19NBe1zniWAr1IJ20M9VhCR4OEajUKjp6aqk/fpCGY/tR9nbTnptF+94MBJkMM78gLIKmYR44he7DBxFkMkxnBCMxlePy2B2oVSoGSio59uVPDFU20JtbSO/egwjGRphGTcc8Zgam0wOQyI2xXZKI7ZJEFI0ttHzwLYqyarp37kMQQG5kTECfMz/I9+B+UTBu84NoL2yk4ut8GneWMe+i+QhqeOihh3j11Ve1/jc4HX8UIcbGxmRlZWFvb094eLhBVd08G/b29iQlJZGTk0N2djYxMTFUV1cbnPiAE6LK29ubyspKgxIgBw8eZHBwUCsl7M8HMzMznQWiBgUF6cT7oi8olUqeffZZPv/8cxobG3Fzc+Pmm2/mySefPONySFpaGitXrqSwsBBPT0+efPLJUXs0/vrXv7J27VrefvvtcToLPRcg999/v9bn1ZUA+SNmZmbMmzePefPm8fzzJ2pK5OTkkJaWRuqOVHJyckieEcPugkz2k4WN2h4bHLHEhjZaADV2lr4ASAQJthZe2Fp4Mc1rCf2DnTQeL6GmJYc+xXF6jhTTU1oEgCCXI7GxRFHXiLGfJ4JEgiCRYDLFD/e/349aqaT/cAXHP/+RofpmenfvpzcrH8FEjvmsUMxiwzAJ8cXIxRG3p/+CWqmkM7uA9n9tJCEhgbrqWv79yBu4JgfguXQ6dmFuRDy3mL7GTqq+P0jVpoO89tprvPb6a0RGRJKVlaUXF+JhEZKVlYVEIsHHx4cpU6ZMaKaUrjAzM2POnDnk5OSQmprKwMAA8fHxBiU+hvHy8uLw4cMGE1dhamqKhYUFra2tel+UTBAETRyIKEC0y5o1a3jvvff417/+xbRp09i3bx+33HIL1tbWp71vVlRUsGTJEu666y6++OILtm/fzu23346rq+uo4vH27NnDjh07+Omnn5g2bdpJ8Tf/+c9/xnweeilAFAoF5eXlBAUFaX3ujo4OvczOMDU1JTk5meTkZJ599lkGBgbYtm0bFRUVlCaVkpWdzZGBgxhLjZEqZUglxgwO9WBibIVEGPmEbmJshY9LND4u0ahUStp7qqlu2ktzZynqgQGUCgWNz69DYmaCSdiJfjAmoUFIzU0RpFJMpwXgvvpB1ENKug4cpvPfm1E2H6c7M4/unfuQmJtiFhuG+awZyIO8sU6IxDohkktMPNn6w4+oh1Q0pB6lflsppi6WeF0aisfCEEL+MpuAm6Kp23KYiq/zyc3NxcTMBBurE8sCunZLOzo6IggCQ0NDODs7T0rxMYxMJsPZ2ZmioiIsLS31ujz0mZDL5bi4uFBVVWUQ2SVwIo24vb1d7wUInFiG6ejo0Pq8QUFBfPrpp1qfV1/Iysri0ksvZcmSJQD4+Pjw73//+4wl6tetW4evry+vv/46AFOmTCEjI4N//OMfoxIgNjY2XH755eNzAv9FLwVIRUUFMpkMT09Prc47NDRET0+PQVxsjYyMUKvV3Hjjjdx7770MDg6yb98+0tPT2bBhA4WHCtlT8hESQYaNhSd2lj7YWnhjbeaORPI/QSKRSLGz9NV4S/oG2mk4VkRlcwZDvf307jlAb3YBCALyAC9MZ07BNCwEI3cnBJkUq4hpWEVMOyFGCorp+OInVMc76E7dQ/f23UisLDCPCyMgKQ63KcHsrjqChZ8DQffEceCZLfQ1dlHyQTYlH2bjFOeD19JpeC2bjtelobTsqaLi6wKO5dYQFBKEVJDy7rvvcscdd2j9/e7r6yMrKwtfX1/kcjm7d+82uCWJsVBeXk5JSQlxcXGUlpayZ88eYmNjDSKY8494e3uTl5fH1KlTDUI0Wltb09TUpGszRoW1tTVlZWVan3eyekA6O0cup8vl8lOmkcfHx/PBBx9QWlpKUFAQ+/fvJyMj44ypsNnZ2cyfP3/EtoULF/LAAw+MyraPP/54VOPGgl4KkNLSUgICArS+tt7T06PpPKrvdHef6NliaXmii66xsTHx8fHEx8ezatUqent7+fe//813333H3r37KGtIR61WIRGkWJv/T5DYmLsjkfzvY2Aqt8HPLR4/t3gqm7I5Ur8dUwcvelurGThSxcDRatq//hWprTVmESfEiMkUPwRjI6yipmMVNR21YojOgmI6Pt2EqrObrq3Z+Fm4UNBvxrHMPNwuCsY50psFP9+JomeQond2Ure5mJbdlTRnVmBsa4bX0ml4LJ5KzBvL6ao4RuU3BdRuOcyf77yTP//5zyxfvpzvv/9eK++1Uqlkz549ODo6apZdBEHQSRddbfDHgFMbGxt27dqls8y088XBwQGVSkVbW5tB/K1sbGwoKSlBrT5zjSB9wMLCgp6eHq3bGhQURH19vcEsrY2WPz50P/PMMzz77LMnjXvsscfo7OwkJCQEqVSKUqnkxRdfPGPn+MbGRk3H62GcnZ3p7Oykr69PJ4H0eitAdLH8Mvxh1vcvPfyvWNrpbDUzM+O2227TVAvs7+/nq6++4ttvv2VPzh7KG3eiVqsQBAnWZh7YWfpgZ+mNtbkHUsmJtb3j3VVYOPowZcE9qNVq+rtaaTmym8biNJRtHXSl7aFr+26QSTGdHohp+Im6HzI7a6yjQ7GODkU9qKBzzwGig2axbctvCFIJ9VtLaCtswP2iYFznBhH26HzCHp3PsZIGCh7/hYHWHo5+vo+jn+7FPsIDr6XTmfpAMsF/jqf6p0Iqvy1g48aNCFIJXh6eFBYWTthFSK1WU1BQgCAIhIWFad7viW5gpytOle1iZGRETEwM6enpWFlZ6eUS5ZmQSCSaKqOG8HeytrZGoVDQ19d3zl2mtYW5uTkKhYLBwUGtPrg5ODhgY2PDkSNHmDlz5tl3MBBqampGeOBP955+/fXXfPHFF2zYsIFp06ZRUFDAAw88gJubGzfddNO42RMREcH27dtHHeOTkJDAV199Neqgb1GA/A5DUtNjDZY1MTHhpptu0nw4BwcH+fbbb/n666/ZvTuHiqYMyht3IiDBytwNOwsfjndV4up9Ii1WEARMrRxxD1tAU8ku7JMXIrG153jarwwda6HvQAl9BYcBMHJzwjRyKqZhIcj9PfGYM4tAiwBezlvNlLviOLx+N331nRz9bB9H/7UXC29b3C4KxjUlkHnf3YpKofyvANnDsf11HMurRWYhx3PxFDyWTMPv6pk0ppVR/lUe1aXVWNlYITeS8+2332rWRMeL8vJyWltbSUpKOskjN9lEyJlSbc3NzYmOjiYnJwcrKyutBx2eLy4uLpSUlBhEgzqpVIqlpSXt7e16L0CMjIyQy+X09PRoVYAIgqBZhplMAsTKympUIQAPP/wwjz32mKZVSWhoKFVVVaxevfq0AsTFxeWkpb2mpiasrKxO6/0oKChg//79o762FRQUMDAwMKqxoMcC5EyupImip6dnQhvQjSfnGyxrbGzMtddey7XXXguciH/5/vvv+eqrr8jKyqayIQu1oKbu4G+01xVh5RKIpbMfqiEFapUSi5DpyB1dsJ0+E7VaTef+vTT+8CUAivpmFI2tdP6YhmBmwsXXX0NZsBSZvyU+V0Xgc1UEyn4F5T8c4uj6LLqr2ij9KIfS9buxCnDE7aIgPBdPJeiWGPqau9jz8A/0VLZR+d1+Kr4uwHqqM15LpxP79p/oKmul9OMcju2r4ZJLLgHgjjvu4IMPPjjv97irq4vi4mLi4+MxMTE55ZjJIkJGU+fD0dGRoKAg8vLySE5ONqj04+Eqo4byHR8O7jSEQFQLCwu6u7u1/tmfrHEgo6G3t/ekeCypVIpKpTrtPnFxcWzevHnEtq1btxIXF3fGuebNm4darR6VXWNdPdBLAVJXV6f1AFQ44QHR5x4ew6jVajo6OsY1XVgmk3HllVdy5ZVXAicEyQcffMD//d//UVxcTENRLQ2F2zXjOwv2Yurjj6mXH1K5CYPHW5FYmOOx9nHU/YN07j1I13dbUXV0EW7vwp7du2ndW03WPd/iPNsXpzgfAq4KJ3DFTIZ6Byn/Jo+yT3PpPNpCZ1krh9/LxHqqM+7zg4l54zLktmZU/VpI8RvpdBQ3c7BoO0VvpeO2IASZ6Yklo4U3u5L+TRMffvghH67/kOCgYPbv339OT2YqlYq8vDx8fX3PemE1dBEyliJjAQEBNDQ0cPjwYYPJKoETT+rDVUb1qQPz6bCxsTGYQNRhAaJtPDw8qKur0/q8+sDSpUt58cUX8fLyYtq0aeTn5/PGG29w6623asasWrWKuro6TbbQXXfdxTvvvMMjjzzCrbfeyo4dO/j666/5+eefTztPRUXFmG3z8PAY9Vi9FCD19fU6Uf6GsgTT1dUF/C8AdSKQyWTcfffd3H333cCJQMz169fz7rvvcvDgQY7vToesVEBA7uLGUE8XapUSVd8AUnNTbJKisUmKRqZSE24VzNe7UgFoL2ygvaiRkvezkDuY45zgh1OcD/5XRxF0UyxDvYOU/msPld8U0FHcREdxE0Vv78Q2zA33+cHM+/ZWBKnA3id+on1/A7U/FyL5r+h29JTz0i/hFOxo49ePGigpKcHM3AQTuRl79+4dk/u9rKyMoaEhQkJCRjXeUEXIWCucDrdDT09Px9XV1WDOE064oBsaGgxGgBhSIOrx48e1Pq+bmxuFhYVan1cfWLt2LU899RR33303zc3NuLm5ceedd/L0009rxjQ0NFBdXa352dfXl59//pkHH3yQt956Cw8PD9avX3/GFNyJjvcS1KP1rWiJ7u5uLC0taW1t1Wpb6sHBQX755RcWL16s9w2OampqqKysZM6cOVqfW6lUYmFhiaRfhgwZXbSjRg1SKSiVABh5OGMy1R+TED8iZoRxpZ03z3edSNVTdvXQmZpD509pMKBAkEpQK1VIjKTYR3riFO+DU5wPpk6WKLoHKH4/k9qfCkEtgFoNEgH7CA/c5wfjnOBH+5Fm9j36I2qFEgGQygSiF9mTeIUTg/0qtnzSQFFWBxKpAGqBNWvW8Le//e2M59jX18f27dvPqfjWRJUsVygUbN68eVw/n+dja2lpKfX19SQlJen9DXKY3t5etm3bxqJFi/T+Oz40NMTPP//MggUL9L7M/7BHLCUlRavzfvvtt6xZs4a9e/dqdV44kS5rbW1NwGMvIZWfenl2LCgH+jn68uN0dHQYRBmI8ULvPCANDQ0YGxtr/cmqp6cHY2Njvb8wwf8yYHRBUVER/f19RJCInXBiuUqhHqRV2Ug1pXTRgaK2CUVDC12/ZeF1hyl7zWs4fmgv8hBfTIJ9sV02F9tlc1GrVHQfLqfz0x8YamilZU8VLbsrKQQsvG1xTvDDY0EIoQ8kM9Sr4NBbaTRsK+VYXi3H9tUgSCU4xngx45F59NS0c/RfexhSqMnZfIzsTa04eMhJudqZS+50Z8/mVjL+08Ijjz7Mww8/zNy5c9m+ffspz7GkpARnZ+dz+gwaiifkfIWSv78/FRUV1NXVjcnlqkvMzMywsLCgpaVF72MrZDKZJhBV3wWIubm5TlJxXV1daWho0Np8IuOPXgoQFxcXrT9V9ff3nzbQUN9ob2/XWSpkTk4OAIMMMKDuRy6YYCQY44oXrngBoFQP0aE8RhnFBAQE8PPPP9OVmUPXtmwAZC4OGg+JWbAvli8/dGK/9i7avt9Gz659dFe10VObR9kXucjMjXGM9cE53pdp9ycBsH/NNloyK2jeXUVzViUS2YnPyz1vB2HvKeHVG4/QWjvAt29UIwBhc2255UV/jtUPsO2zRnbs2IFEKuBg78jRo0c1Tx1dXV3U1NSc19OcvouQ8fDSSKVSQkJCKC4uxs3NzWAKlBlSldHhMueurq66NuWMmJiYoFQqGRoa0uoDnKurK01NTahUKoP5/ImMRC8FiC6+cIYkQIbdf7ogMjISUxNTDvWfECLmMgvMhqywVNtghS1W2GIsmGCHM/YSF/x9/HEs8yVKKaGcYo7TxFBjK90tx+neceIYMic7TKYGYBLii82lc7FZlkLdyjW4LArmWFY1g8d7aUw7SsP2UhDAZqoLzrN9CbktDrmdGXnPbuZ4fj0SKfzz/lKMTSREzLclepEDhZlt7Ph3M/tT28nf1oa1gxFz/uSIqYWMvVuOUVXYgq2dDVKJjO+//x4nJye8vLzOOxZIX0XIeC4ReXp6cvToUaqqqvh/9s47vq3y7N/X0Zb33it2HCfO3nsCL6OUQiktpQUChbaMUgqF0pay2rKh0DILLeUt7a9QCrxAmSFxlhPH2cuJ4xFveUse2jrn94csxc60HVtHcs6Vj2Lr+Oh5bq1zvud+7jFu3LgRsnB0iYmJCZmr5ujoaNra2uQ244xotVpUKhV2uz3gAsTtdtPW1hYSyQMKJxJ0AkSuANRQESButxu32z0st2xHRwf//Oc/GTduHBMmTGDcuHFoNEP7CMycOZNeay81NTXs2LGDHTt28Pnnn7Nr5y5vLAhgEMKIFGOYkDERjyjS2thBjJDADGkxRfwfeekriYvIobJpA+1dlbhbOuhp305PkbePgRDhrX0QMy6RidctwJgcia2lm33PrKNtWw3mAybMZc0c/vMWbyDr4lxyvzOLyHHxbPvVx/RWtrPtsw62ftyOIVzFkisSyZtt4IPnm7C0uPj09UZECQoXRnPhDam01NrZva6Tm394E398/k+sW7eOF198cciv7/EEmwgZ6fgUlUpFQUEBZWVl5OTkhEQsSExMDIcOHQqJ4E6j0YjdbpfbjDMiCAIGgwG73T6qgfHHYzQaiYmJobGxUREgIUrQCRC5PCAOhyMkBIjdbkelUg3rSuPuu+/mb3/7m/++RqMhJzuHwsmFTJw4kYKCAiZMmEBBQQEJCQmnPEALgkBOTg45OTlceeWVuN1udu7cSTrj6BI6sUo9tNLI1LyJVFQdYYP0EUZVGAYpHBEPHo8Toy6aWeO9RXQkSaLH3kpV0yZaLYcRe6wIahVlf9pI2Z82YkiMIH52Jmkr8ply53L08RHUfbqPw69sxdHWS93HB6j9v30IGhUJszNJmJ5OzXt7iU7QYGlzU/xhG5vekwiLUrPi6mRcTjfF77dzqMTCwWILYVFq5lwYz6p5V1C6vYSXXnqJl15+ifzx+ezbt++sCiwFiwgZreBYXyaCyWQK+qUC8BZ6CpUqo3q9PiQECHiXYYZSgGqk8MWBzJgxI+BznwvExsYOWqgPJxMqKAVIQUFBwOe12+2yLWv4aG5uxm63k5qaesoW9A6HA71eP6yrt7KDZaSQxXim0Es3VncP1spuiqu2sfbTInpc3dDnxYiKjKagYAKFkwsHCJPx48efINT27N5DopDGJGYDXkHhwMa8vNk0V7YRSQw2qQcbVkCgyrSBKtMG9JoIosMziApPIyoslUlZFzFd8002HPgjhoQ0VFoDnbV7sbf20PjlYRo+KwNAHx9OwuwMCm9fStz0dJwuF/t/v4buijZaS2uhxPscwqK0LL4iiZQ8De8/30Rnk4sN77YguiUi4zTMPC+OvRs6MTe72LuuizuuWcTrbz1L7rQIOkwOjhw5Qli4EYPeOOQ03v7ILUJGS3yA1wuSk5NDTU1NSAiQUKoy6juph4K3xucBCTRKIOro8txzz/l/b29v53e/+x0XXnihv3jZli1b+Pzzz/nNb34zrPGDToC0tLSwbNmygM9rt9tlbULX0dFBQcFELBYzAAlxCaSlp5Odk0VGRgbp6elkZGT428B3d3cP2d1ZWVlJJIkYhDAMhBFPv8ZEbvDgwUaPV5x0d1O/vYWK3UexSm/j8HgPLoIgkJGeQWFhIQUTCygoKGDbtlIskhkTtYQRSTiRGIQwsvOy2PdZOfMFbwdGBzbMtNNKIxbacbittFgO02I5jE/46DThON29qGwRZE5cSs7cK9Dow3D0dtKwbw3tVdtxtPfS+NURGr447H1MbBjxszLIvmwqMZOSqVtziJp/76GpykZzjQ3RA4YINfO/Fk9yroa1b7XR3eFm03utiB6JmCQd51+8FIvFwoYvdyGJoDOoiE/TYbeK9JqtTJ02GSQVjz32GPfee++Q31+5RMhoig8fWVlZHD58WLaGVkPFF9wZ7IGoBoMBSZIC3mdlOMjlrUlOTg6Zgm2hSP+y7ldeeSWPPPIIt99+u3/bHXfcwQsvvMCaNWv42c9+NuTxg06AdHV1yZIHLXcMSE1NDRaLmQlMR40GR4eN9o4uGvdvx63ZjF2yYXfb+PrXv05hYSEXXXQREeERpKamkpWdTWZmxgCh4vvpW0qx2Wy0tbeRyKmzZ9SCmgiiiaCfJ8jj9Wi4cGClh16pG2t9Nzsb9rFlXQk97i5ESURAYD/b/A8zqsK5edy32VaxmR7J5hcmSaSTLBxL23RKdkopwkYPRl0MNqcFBBXWjgYOf/UqALqwGMITsomIz6Bg1U2ExWUgiW4a9q+ltWIrzs5+QaqANtpA6rLxxM1IB52K8te2YO+wUfpZB6JHQhAgb0YEyTkatn/ehbnFybjkWWzcuJHYJB22Hhe2HpHOZieiB9RaAY9LAkR+8Ytf8Itf/II5c+YMuf5AoEVIIMQHeNfi4+LiMJlMIRGMGhMTg8lkktuMM6JWq9FqtbJfHA0Gg8HgL5AYSKKiomSZ91zk888/54knnjhh+0UXXcR99903rDGDToD4CpEFEkmSZI8B8R0Qk0jHIBznGnZ7f3jwMCV2GqpOgSnMw95rw15hY19FGbs0e3AINqxuK5J0rB+AVqslJTmF5JRk1Co1ZeIOKoX9GDCiE40YMKLHiIGwAT/VwrE+H4IgoMOADgMxJAywS5RE7PTSSzfdWOiinTZMxKfGAhK7Gkvw4PE/RI2GcCIJl6III5IwInBgJS91OXmp3hRbl9tGZ3c9jR276Oypw2m14KzbS2fdXm8xMkAXHktEQjYZ0/4HY3Qq5eteQ5uShrujHZfFTtOGCprWHfG+BpF6UpbnETUhieYt1VgOmKjc3UPVXpBEiE81Mnv2TN5//z90mJyo+p66oAE84HFLIOBz0gCwfft21GqBiIgoampqBl0WP1AiJFDiw0dKSkrICJDo6GgOHz4stxmDwudZkHt5+Ezo9XpaW1sDPm9kZKQsZeDPReLj4/m///s/7r777gHb/+///m/YRUODToB0d3cHvBy6p6+C51AzQkYSnxtRx6mvdNSCmujYaMyNXaQIWQP/2HeOlyQJJ3bs2HBgw+6y4ai3UV/fQoQqGofahsNjx4kDMCPgXVuWGFgQV4sOgxCGXvSKkhOFihGVoEYlqPqERCSJpNEjddGGiUXTr6a3y8Oc/NX02FqxWBvotrVgdXTQ5TbThblvJu+8lU3raWzfQ4QxiXBDAuH6eHKSFzI5++toNUbcHgf7j35Ei+UgGn0Ezl4zHVYLHbV7/KLEZWokcspMDKmZ6BKSsNbXYN62CVe3DdPGKkwbKkECTbiO6IlJtO+oByAzuYDeHisVR6rQaAUiEsDcJOFxgKDyihQf/e+Lotdjl5gYiyiqePvtt/nWt751xvd6tEVIoMUHeAVIWVkZLpcr6Iv5hYWF4XA4QqJ+hFyxFUNFq9XidrsDPm9ERERIpCqPBR5++GFuuukmioqKmD9/PuCtC/XZZ5/x2muvDWvMoBMgcnhAfF8cOQVIa2srerUelXj6DqPhcUYaDpx6zVMQBPR9YuEEJO+tnkoOsZuFE2/G4erB7urC5jDT6+jA7ujE7urG7bHRLZrp7hMpkn+AY2jRY8CIQTomSlw4AYiINGLtcRMdnk50eDrpzDhmhiRhd3XRa2uly9pEe/dReu0t2J1d2Jxm2roqBnhxNGoDEYYE7E6vqzV30dUYopLQ6sPpbq+hpXwLXaYjiC473Qf20H1gt1+UaGPiMEyYhD4pFWdHO91le3H3WmnfWY/QV919/oK5lFXuxBCuwt4rYmnG7/E4lfgAUKm8IsT78RH5zneuQhThW9/6Fv/+979P+z6OlgiRQ3yA90QQFhYWElVGfcsZdrs9JAJRQ0GAaDQaWQSI4gEJHKtXr2bSpEn88Y9/5L333gNg0qRJbNq0yS9IhkrQCZDhBFeeLW63G5VKFdCrIbPZzHPPPefPZS8pKcHpcbJdsw61qEEtatCiQ4MOLVr/7/pYLa0drdikXrToUKMZcoS8Ewc6tZHIsBRO90p7RBcOZzd2VxcOVzdWewdWRwc2pxm704LrNCLF7DxAVV0v6/a8jEEXhVEXg0EXjV4XhUEbhUEXRbghgbioceSmLh0wp9XegaW3ifbuCrpszdgc7Zh766HPW1O+7nUABJUafUQ8xpgUUiYuxRCVhD48Fpe9h+bDxVg7anGZO3B1menev+uYKIlNQJ+cSs+hfQDk5ebz8X8/xmHzqgutXoWgEnH0em1SqUH0HBMfPiHi63yt0XhFiO/+u+++i0olkJ6ewZEjR065tDfSIkQu8eEjPj6ezs7OoBcggiD4lzZCQYDIkd46VOQUIEoMSOCYP38+//jHP0ZsvKASIE6nE6fTGfAlGLfbHXDvxx/+8Ad++8hv0Wn0ONwO/Cdud7t/H6HvH4I31gLAGHsbJZ3rqKbav49W0KEVdGgkbd9N1ydYvMLl+N9t9KLVhJ0xvU+t0hJmiCPMcOqTmSiJOPu8KA5nN1ZHBxZrI8mJ6VjM3XhEJ922ZrptzQiCCm/vw+M8KeqwASLFoIvEoI0mK2keapWOrYf+zPil1xGZlEuv2URn7V66Wypx9pqxd7Vg72rFLOwfGPtiiCQ8PhNjdDI2SwtdpnL0Gdk4W5pxdbbhMreDSoW6r6bJ0Y42pKR4aOnEaRMRVP2ExrEQFr8Y8d9X+TwgA5EkqK+vJyLCiFqto6Sk5KS1CkZKhMgtPsAbWxEqKZGh4lkwGAy0t7efeUeZkUuAREREKAIkgFRWVvLGG29QVVXFc889R1JSEp9++ilZWVlMnjx5yOMFlQDxudLk8IAEWoB0dnYSrY1ljnsVEhIe3Lhw4saFGxcuXLj77rskJy6cSFoPkZGRuM0i4epI776iG6fo6IvpOMax2I5j/w/AAWt2/x6NSo9GY0CnDkOrCUOrMaJVG9FqDGjUBv/v3p9G/zZVX6SmSlBh0Hk9GoQfGz4vexzN9b2cP/PXdPbUUVr+BuMWXY1GF4a1s4nejgYcPa24bN24HVa6bSa6bSYEVH3xKANtrtj4v4TFZaCPiEMXFkNi3nx04dHowmJQa3Ts/+8zhOVNRBI9OFtMuGxWXKYjdDdXIUlexeCor0HQatGnpKNLSMLldJKm9b7/dfvL8K/JAJJ07Hfw/glhoPg4Xrv5lmTgWHNg783JzJkzEQSB+++/n0ceeWTA485WhASD+ABvdklZWVnI1K0IBc9CqBQj8wmQQL/3yhJM4Fi/fj0XX3wxixcvZsOGDfzud78jKSmJPXv28Je//IV33313yGMGlQDp7u5GEISAu0XlECA9PT2oJO9JXBAENGjRcPrgvcjYcESPyMSueUjisZNjHRUcZg9LJt+G2+PA5bHjdttxe+y4PHZcbisOdy8utxWny4rTbcXp7kWU3N6/e2zY6OwbTfAeQCROKgR8qAQNGrXeL0x0mjA0GiPaPoGi0afSaKqmrauJbqs3ZiU8LgNDZCIx6ZNOOqbH7cRlteDoNWPrbKK3ow5bdxuO7jY8TjvWjnqsHQ0IKpXX2yENtM1aeQh9WiZh2bloomLQRMWg0utx9XRjq6nAVnUEyeXCYWrA0dIEEuSsXEFVVRUSoImIwi1KYOvxKgcAtQo8Iic4bgSvABFPEhNyKiRJ4re//S2//e1vT0jjHa4ICRbxAd6USLfbHRJVRkPJAxIKdvqOnx6PJ6DHUmUJJnDcd999/O53v+Ouu+4a4CRYtWoVL7zwwrDGDCoB0tPTQ0RERMCvnuQQIL29vQji0GJONHoNbqdngPgAEPGgUWkJ0w/vBCSKHr9Y8f3cV/MBqFUk5i/A0WvGZe3C5ejB47ThcdkRPS6/kPE5XwRU/uBNQ/h32FP+Ofsr9vvn2ffRkwCoNDrUWiManRGNIQKNPgyNLgyN3ohaF4ZGZ0QXHo0xNqVvexi2rlbK1/6Z7B/+DHVYOA5zB46GGmw11TjbW3F3m5GcLhyNdTia6o+pAelEAaXLzUATH4Pb5SZlQh6mtlZQqXB3mb07qPoFAntOVBSCWoUkigPFhjBwKeYk0/Z3sLB9+3YEQSAyMpLa2lpiYmKGLEKCSXyAt26F0WjEarUGvQAJFc+CWq1GPJ2qDRJ8x89AH0sjIiIUD0iA2LdvH//85z9P2J6UlDTsTKRBf1JeeeUV7rnnHjo7O/0fsJ6eHmJjY1m8eDFFRUX+fYuKili5ciUVFRXk5eUN2hi5ioF5PB7U6tNnn4w0VqsVRAERbxGvwYgulVpAdJ94MHLjRqUafuqjSqVGpwpHpw0fsD154hLSppx/xseLbhdupw2Py+b96bQRF5+ALnkqiY4InNYuHN3tuJ02RLcD0e1EdDtx2Sxg8Y4hCGoQvF6CAakmx1Hz52fRRMeiNoahDgtHHRZO+LjxqIxhqA1h2Btr6T6wm8Rbr8bZa8VT34zzaCPutk7E7h5weXBW1eOsbgCViphFq+hoaT3m8VAJCHotks1z4uRqFYgS0slEiUo1YPvJzhknEyXd3d3+fgvvvPOOP433TCIk2MSHj1C5YjcYDJjNZrnNOCMqlSokBIgviD/QcSBGoxGbzXbW46xevZo333zzhO0XXnghn3322VmPPxbwdZI+vtbPrl27SE9PH9aYgxYgK1eupKenh+3bt7NgwQIANm7cSEpKCiUlJQPEw7p168jKyhqS+AAQRTHgQmA05+3u7ub3v/89TqcTrVY74FZbW0s7JtbiTWdSoUYtqFAJapAEVKhQCSp8/wRU5GhycIrL2C1tQui3vQczHtHJobrPvY9RaRAEdV+dDjWCqu9nv20q1cD7Qt823+9utw2P24nbafOOp1YjCCf32Kg0WnQaLXCsgq1OqyFm3Hw0qXNO2L+q+F/0OlvI+sFPkSQJyeXEY7ch2m147DZcPT04W5txdbTi7jLjtvbgsVqR7DYk0YPb0onb0rdkJAjeaFHwnuH7xEvrn46L1FapUIUZUMUaUIWHoYoKR9BoiI2Pp7q6GnWEDo/dBR4JydZ3AlUJCCrBKywkTuoN8dkgnaXTTpIkrrrqKgC++c1v8tRTT51ShASr+IDQ8SxoNBp//Z9gRhCEvsDt4EcOW1Uq1YjNedFFF/HGG28M2BbsFWgDydVXX80vfvEL/v3vfyMIAqIosnnzZn7+859z3XXXDWvMQQuQgoICUlNTKSoq8guQoqIivvGNb7B27Vq2bt3KihUr/NtXrlw5ZGPkKgw0Wl+av/3tbzz5xJNEaWMQEZEQvf8kEVH0oBLUSJKIhIQoeRAlD+A65Xi9Qhxuj5s2TiwjLYgq6tq2MyBQ4QxxHKdFEGja/xVN+78asE0Q1AgqFYKqT9io1AgqDYJKg0rt/V2r08O3nqJi0z/pttqP209Nd+tRHN2ttK37FEHdJ27UGlCr/b/r4xMwJKf47wv9/ta+4UtsTdWkPHArqFRIbg+S04nkcOHq6sJxqBpXnQl3RxdSrxXR4QSHC7HHithjBfq6NqpUxF0Tg9lixtPrOtFFIUonLHedQH+RMkK89957vPfee1x++eUALFy40L/mevToUcrLy4NSfEDoeEBC5cQeKnaCfAJkpDxEer2elJSUERlrLPLoo49y2223kZmZicfjobCwEI/HwzXXXMP9998/rDGHtFi3cuVK1q1b56/7vm7dOu699148Hg/r1q1jxYoV2Gw2SkpKuPHGG4dsjJwCZDTiTlwuF1q1lrnu8069U9+yg+9fPRVUcIBlU3+KKIlIkgdJEhElD2mZ0ahVBuZOWI0keQb83SN62Hf0PyTmzSM8IdsrbESP/+Zxu5EkF6Lb1bcE4kIU3UhuF6LoQvK4kUSRXksTKq0OQadDcjlBEpFECakvnkKSRO/J1nOSE3Yfvk6+nQ1l3gCxvhSSY5k5IqjUtG9ee2wMSTrleKei4e4nT/4HlQpBrfIKGo0alcGA6HKDKBGRE4dKq0alU6PSqgmPiUBI1BM1PgFbdy+eLhei0w3u09ui0gjepyWBx+chGWE++OADHA4HFovFn5oezOIDvBUxnU6n3GackVBa2gglARJoQuV9HAvodDpee+01fvOb37B//356enqYOXMm+fn5wx5zyALkzjvv9Ee679q1i+XLl+NyuXjllVcA79q1w+E4Kw+Iy3VqL8Bo4PF4EEVxVOYNM4ahFQcfn2GUwggTwogIP7H3Q0x0OAJqkuJyTvibKHmoaP6E+IwJJIybNWx79/33acKnTiNh+YXDerwkSej7jkP5P/sNDqeLxnffRApXEXftN8DjQfKISH05qpJHAtHj9WJ4RNwOB5LVhtRrQ+y1IdodSDYnosOBY38FaqMGQ3IEnh4XHo+I5BZBlBBF0TuWJPVVMJV8Lwx43KD3Lg96mm30d7wLbrDXdeFq6EEjCGhVOjDq/H9XCRKSrxWMJHHSEJVRrDxeVFSEVqvl+uuvR61WM336dCIjIwP+HRksoijidruD1j4fo/mdH0lCxU4fLpcroLZ6PJ4RW0r7+OOPT6hB9atf/Ypf/epXIzL+WCElJQWbzUZeXt5ZBxwL0hDkdUVFBfn5+RQXF9PZ2ck999zDgQMHaGxsJDc3F7PZzKOPPso//vEPKisrh2zM5s2b+da3vuUXMwoKCgoKCqfCZDJx++23n7XoWb16NQ0NDbz88ssDtsfFxZ3U29jV1UV0dDSZrzyIynj2iROizU7djx/GYrHI0g1+MFitVn7yk5/4g3XLy8vJzc3lJz/5Cenp6cPqiDsk+TJ+/HgyMjJYt24dnZ2dLF/u7V6alpZGZmYmxcXFrFu3jlWrVg3ZEPC60zQaDZdccsmwHj9cjh49Snt7O7Nnzx7RcV944QUefuBhFomnfz6+6qASIg1UU0UZiwpvGbD8IkkSKZmRfO1b03n1mTUDll+kvpiSA7UfEj9uNuHxmX1LJn1LMP2XYyQRSRy4PCP6/i6JdDVXoA4LQxsd693m8Xj393ssfON4vAGbovfv9I2JJKHT6XjzzTe5+eabvSly/fNPh4sgIKgFJFFCUJ3C1euLeZHwe0LOxDPPPMNf//pXDhw4cHb2jRKXX345V199NbNnz2b79u2oVCrmz59PbGys3KadlMOHD+N0Opk6darcppyWpqYmqqqqWLx4sdymnJbe3l42btzIRRddJLcpZ+SLL75gwYIFAT2BVlRUjFgCQXh4OOPHjx+RscYiv/zlL9mzZw9FRUUDPo/nn38+Dz300OgLEPAuwxQVFfk9ID6WLVvGp59+yrZt27jllluGbAgcW88LdDdNtVqNIAjDmtfj8WCz2Whra8NisWA2m7FYLHR1dbFlyxYsPRY2qP7rD0CVJPFYQKrkFR3Hd6IFWLPj6RO25VvzuVCcwOZ9fzmpLYKgpv7gpv5b/OU6/f/3P3dL3v/81VJ9IsHSCU0Ng3sBhGOjIwigEvxXI6IGXBoPqAQQQdAI3gBWrRq1Ro2gV6HWqdHotaiNWtQGLZpwPZooHfoIA/oYA0KUHn2YAZVG5Y3d0KoRtGpUGhV7HvmM9AQn1z+ci9Mu4rR5cNhErF1urN0e788uD71dbv/vPWY3PWYX1m4P9h7ve6fRaE6ayqdS4xc7oighDdHT6+sRM1iWL1/Ov/71L38gXP9sF18Q6sSJEyktLQ3aOBBRFNHpdEHfEVelUqFWq4PezrM5NsmBL8svUKjV6qDvaDxW+OCDD3j77bdZsGDBgHifyZMnD2vFA4YpQG677TZcLpffAwLeg+ftt9+O0+kcVvwHBCagqLS0lH//+9/+vjNOp5OMjAwSExN54okn6OrqYu/evTjsTjyiiNi3BitK3kBMbxyA5O/NMpjL7F6x68yG+d5QSULQakFQedNe1Spv9odKgxARiVqjRZ+WgaDRIKi13p8aLWqNFtQaBK0WQadDo9MPyCrx/bQ31WEu2UjCrd9FFWbwPl6r9j5W4w3aRNP3OG3fNnXftkF+0dv6UmBX/vN6rKrTl7uWJAmPzYWrx4Gr24G7x9Hvdyeu1k4s/f7m7LLj6rbj6nbgNFsxH5a49/xdJx27v4CQRGlAGXUfHZ0dxMXFolL37d+X1eu095Vd9wx8f1WqY2XWT/dRPZ34MBgMnHfeebz11lvExMScdJ/jU219oi4nJwe1Wj3iXXRHCrvdHnQ2nYxQKBcPoWMnyGPrSCYuOBwOTKaBGYYajYaEhIQRGT/UaW1tJSkp6YTtvb29w37fhyVAbDYbEydOJDk52b99+fLldHd3+9N1h4NKpRr13PybfnAzhw6UYVSHI6BCkASWr1rGnIWz2fjBFhySg246SY4pRK3TDayT0a9+Rmf3UTpt9WTNvqwvJVWDSq3pl57a73f/do338epjKamqvn0AWiu3Ub3lbfLve9S/rT8pBh3asDBybr5r2M9fbTBiLtmIoWAc6piz77njrePhRrT2BY1a7XisNhwOB61fVtDUYsLV48Dd7RUWzi4Hri6vgHD3OnDbXN5A0ZPRl+LqnYiTFwATvMJBqxcwRKiJSdaRmR9GzuRwDBFav2ekx+LG3OykvdFJe5MDc7MTh02ks6OTmJjYPnEiIKjA4zi1qBT7dcHVauFUS8++j3FYWBiXXXYZb7zxxqCL7J2pzsdId9EdSRwOhyzFBIeK2+2WpebQUFEEyOkRRXHE5vzss89OOHcVFBRw6NChERk/1JkzZw7//e9/+clPfgIcy3p6/fXXWbhw4bDGHLIAycnJOWlaWHZ29lmniwWihoBKpSJRTGeSdCzeI9WWTbwhkRksoYUG9rKFSVmXoNOcupx0NQJmexNJ+cN74U9qm9rruhRdLtT6Ew+OIhLqs/yyqfpSZEWHAzVeASK53YhWe5+I6Ptp7fez1zbw9x7rsW12x0kLdHV2dtL+UQVHDh4EFccExPEfEQHQCKh1GtRGLbpYI+HpMURNTiE2PxFthAFdlB5NpAFNmBbJI1LzwT7K/rSRHzyeh7XLQ6fJQWezk7ZGBx1NTuoOtrPxPwNLA6s1AhIg9kuvFVRgtnSSlJpAcrYGtUZLt9lNd/sxVeHTgSfznrhcA7vjRkZGcvXVV/PHP/5x2CfhwRYZC1YRIlc146ESKnbKVZpgqIiiiCiKAW9pYbPZMBqNZz3O3/72N/72t7+dvUFjmEcffZSLL76YgwcP4na7ef755zl48CDFxcWsX79+WGMGVS8YX13/0VTSYWFGPAxsb+20udEavSd/Nd4zjiiePqpardIieka23oFK4626J7mc/rTR/rhECY1K8LVb8SOJHkS7fUA10RN+2mx4HDZcnd4iXM1P/AXJ6fIKCNdpAhVUqmPLQyfrrSLgLVGu1XjPxlYb0VNSsKocTL1+CUby0Ebo0UYZ0Ebq0YbrvDU6ToLb5sLe2oO9rQd7Sw/mg83e+6092Jq7sbf24Oqy+5/8X+6rRFD1lag/SYxGdJKGjHwj42dHoNVqsXa5aa6x01Bho7XWjsctYWpqZnLhZNoaPXhO8jr0Fx5qjYDHLaFSqUhISOC2227jgQceOPVrN0SGWuE02ESILx4q2PvAQOh4ajweT0gIEF8Jdjmaeh6fOqswOixZsoTdu3fz+OOPM3XqVL744gtmzZrFli1bhh10HlQCJDIyEkmSsFqthIeHn/kBwyAiMgIPA89ULrsLrcH7Uqj6BIj7DOJCrdb5s0hOtlwyFCRJxONyILq98RK9VeWodHqveLAdExFtHifqyb+k852/0tna4hUWDjvS6VLQhH4Col8HWU+7ud8+eGNA9FpURgOq6Ei0KfGoMpLRx0ShDjeiCjd6S5iHG/2xI8fjONqA6cEXmPyTZZBuICs7D4tBiyRJuCx27C3dmFt7sLf29gmNXq+waOnG3taLxzbweQhqbxCt1L//jUpAZdCgjw8jdmoqKf8zgajUGDx2N9YGC711Zlq21dCxs55es4cDm7s5sNnbLVOt6RMqfcNpdNBqriFvfC4Z+WE0VlhxOb2vj1or4HF5xUZKSgr33Xef3/U4Ggy3vHowiZCuri40Gs2IXJGONna7nejoE2vtBBuh4qnxCZBAL2t1d3cP6MyqMLrk5eXx2muvjdh4QSVAfEq2u7t71ARIZGQkknCcALG50fV5QDR9VaU84ukFiEbl9VZ4XA7UOiOi24nHacPt8jZjczvteJzWvuZs9gGN2tyOXtwOa9++dr/wAEAQML3/zwH3vSICkCS6u7sJs/fS3NYy0CCVGkGjQaU3oA6PQBsdgyYuCV1kFGqjEZUhjJYvPkA/KZuYb1/kFRK6s49WlzwePOZuPJ1dOOqaANj7+Brmrs7C0W1n7f/+DUeHdaCIAASN96ru+O3qCC3hGTEkLxpHwuwsDEkR6OPCEdQCzg4rPXVmems76a0301PTSdkTRdhauo/FkfRL0XU7JVALaCP1uMx25l4UhyFCQ/XeHurLrbidEgf3HEUlaHCZoxE9dnJyMnnwwQdZvXr1Wb82g+Vse7sEiwgxm83ExMSERMyC3W4PiT4foeKp8XXBDfR7393drXhAAojH4+H999+nrKwMgMLCQr7xjW8M2/MVVAJEp9Oh0+lGtb1yZGQkotpDfyeI0+b1gDgkO068MSjt3dVYHZ24PDbcHjtutx2Xx4HbY8PltmFzmgHY/cHvEN3O09S56Ot021cLQzpNp1dUKgS9HrXeiCYyGnV0DPq+zq/ebq9GeiSBgmt+gNBjR20MQ9DpB/2l79xahCSJaGIHl6cvOpx4OrvwdFpwd3h/ejq7cHdYcLeb8XRYvL1V+j13QaOit9ZM3d5qcrKzsbf0vZcaNUKYEW16IoY5kzFmpaOJi0YdE4WgUWM7UEHLk39h0Z+u8paErzXTtqOO3jozPUc76K3rxGN3D5jHL15UAtooA3Ez0sm4YjJqvDZYyluwlDXTfbQdlRq2ftzu92yo1Wry83N58skniY2NpaSkhIyMjEG9LiPJSDWWCwYRYrFYQsKrAKHjWQgVO30CJND09PQoHpAAceDAAS677DJMJhMFBQUAPPHEEyQmJvLRRx8xZcqUIY8ZVAIEvAKhu7t71MaPjo6mSzSzU70et+DCJTkJsxu5Vv8NNqs+8UZVo6Kica3/MQKqYwKCgQJCdPVPMxUQ1BrUWj0afQS68Gj0xmjUujA0+jA0OiNqnRGNPsy7TWdEowtDrTWw/7M/oM/NIflr3zqt/T2CioSkZKo1Q3+NNOGRuCzeGBux14qnT1S4O7vwdBwnLjq7kOzHpdD64kH6Zyr5xI9ajXHeFHSFeRiSEyA7n9S4VLLffOwEOyRRxNNhwdXUinVXGW5TG46j3rojG2845v0R1AISgj/IVaVTE5YRQ8Y3ppAyPxttlJHuqja6DrdiOdKCuayZHXd/5PWGCCCovSLFaDQyefJknnzyyZOmiO/bt4/29vaAC5CR7mortwhpb29n0qRJAZ1zOEiSFDKeBbvdHhJX+HIJEGUJJnDcdNNNTJ48me3bt/sLIXZ2drJ69Wp++MMfUlxcPOQxg06AREREjKgAcTqd3H777Rw8WEZHezstLa2IeOhwt/r3kazeE5zRaKS3txeVSotGrUenCUOrDkevC0erMaJVG9CqjVSY1hOdMYnkgiX9BIUR1VnEgmj1EbitvWfcr8vlIVJ76nkkUcTd04W724K7y3cz4+q2YK2rxtPbTe1NvwH3cRGbvsDQ/hktgoCg06OJjiEsK5ewrHFoomK8t8hoVH0HnIqnHyDigvnEXHG+/6E9Gj1RggZHZR0uUytuUxuuplZcDS24WtqPzS8IXmHjOXZfiArHOG0CUSvmI4QbabrvWab+4jzC0qKxHG6ha7+J2nd2Y220eANSBRBUKiSPSHh4OPPmzeOFF16gsLDwjK8nQHJyMrt27WLatGkBcyGPtPjwIZcI6enpwWq1nrROQLDhcHiFdagIkFCoQyGnAAkFgTYW2L179wDxARAbG8vvf/975s6dO6wxg06AREZGjugSzM6dO3nttdeIJwUj4USRSDzpaNCiRYcWHRqHFtEjkhaejVnjZmbe1acds659Jxp9GBGJ2SNmp1YfgbXbfNp9RJcTc1c3RtFN174duPoLDEsn7i4zHmvvwOUgXwxJvwBURA+oVKj0BrRxiRiycjGmpKL1iYuoaFSawcWHSB4PmsgouteVIOh1XqHR2IIoaIn57e9p+d0r3uJyapXXMyFJXpuMBnRZKYQtnU1YXhaapDh/YKunpxdnTRP2w9U4jzaAWmDfE18dez4qwCMRGRnJkiVLePnll8nOHv57ER8fj9vtxmKxnLIw2EgyWuLDhxwixGQykZCQIMtJaKhYrVb0en1IZJeEyhKMy+VSlmDGOBMmTKC5uZnJkycP2N7S0jLsEvZBd7QYaQ+I7+CbzQTihFNfndksdhJjEmitrzrjmDpNGC77yIkkSZJQ64y4TFX0VpQdExbdFlwWM25LJ+5uC6LDzsSvf53CwkKa3vuHV1iojlsSAQSVBo0hEmNMMmFxmYRFJaALi0EXHsP+T/9A3NLziF9y3pDs8/T24GxvwdneirOtxXtrNeGydPqFjfmdz/rsEWnoO7hnTiykpq4OtRZSH7wNVXTEAC+Dp6sH59EGrNsP4DjagLOqDk9nX+VYlYB3AUwgKiaaVatW8dJLLw0ogDcSqNVqkpKSMJlMoy5ARlt8+Ai0CDGZTKSnp4/qHCNFKMWqhMpSkVx2dnd3y55+fq7w2GOPcccdd/DQQw+xYMECALZu3cojjzziryLuY7D9gIJOgERFRQ14ImeLz33p4vRZLb2dNuJi43Ec3XfGMfWacHrtgxNJkijisnfjtFr6bmZcNgvOXu/vjt5OXLZuJNEbYFn/j74UJ5UKEE6ogNVhNhOfmERs5lTC4zLQhkWjD49BFxaDNiwatUbH6dCHx+Eyd5z0b6LLibOjDVdbn9Bob8XRasLZ3oLk7Pf69a++pVIhGMMxpKYRPnkW4anp6OISUOn0mFwSC394B5a3/kZvYwWSJGHbfQjn0QacRxtwVNUjdvUJub7sFY1KTWZmJldccQWPPfZYwGpKpKamcvjwYQoKCkZtGSZQ4sNHoESIzWajo6NjxJs5jhZmszkkBIjH48HlcoWEAJErq6irq+usvJ8Kg+fSSy8F4Nvf/rb/GOkrPvr1r3/df18QhEFXNA86AZKUlERzc/OIjRcTE4NarcHpOX1PEmunzdtzw33mOAydNgKztRXR4+onLCy4fL/bLDh6OnBZLX2ekv4ZMt6GbJIkwYCMGAG1oEWvjSQqLJ1wYxwGXRQGbRQGXRQ6TQRF+55GlziZ5NQs8pevHs7LgT4iDntzE72Vhwd6NFpNuLv7CT+Vqq+rrNdGQatDE5dARP4kwrNz0SUko4mO8farOQ5JknCZO6hugLieLqw1VbhaW2i487F+Y0toNRqyx43ju9/9Lg899JCsDbdSU1PZu3cvHR0dxMfHj/j4gRYfPgIhQmpra0lKSgqJ+h/gFSC+KP5gxm63IwgCOt3pLyqCAYfDIUuH5ubmZs4///wz76hw1qxbt27Exww6AZKamkpTU9OIjadSqYiPi8fZevoS772dNmJjY3GLTjyiC1H0YHd14XB1YXd2D/jZZW3E6bay/f8d135YUCEIgrc9/XE1xzVqA0ZdLOH6RMKNsRh00Ri0kRh00ei1UWjUZz7IGHTRtLU0EW4489vmcdqxdbVg72rF3vfTZjFh62oFSaT+rVf7XqB+3gxBQGOIJDIhG3tPB6IeMq+7BbXx1F4ISZJwdbbjaKrH3lSPvbEOe2MdosPO3lWrOO+883C2NWMwGMjMzOTGG2/k7rvvDrrunmq1mqysLKqrq0dcgMglPnyMpggRRZGjR48ybdq0ERtzNPF4PHR3dwck1uds8XkVQqWuihyemqampmH3HlMYGv2bz44UQSlANm7cOMJjptDW6r26lyQJJw4cWLFjx4EVBzbGdSQQEe890a7d8yTScXW9BUGFgIB4/HYE9CoDBtFImBSFXjJiIAwDRvSE0Y2ZA2xjceGt6LVnF61t1MXQ0lSHRi1g1Kmw2l04ejqwDRAZzdi7WnA7jnlyBKHP49InigS1DmNUAlHpE4mMz8IQlYQ+Ih6V+tjHoWHvF5iObERlOHZVK0kirvY27E112JsasDfWYm+qP7Y8o1KjQiIqKoopc+dw0003eeuueDwhcRAdN24ca9euHbH+EiC/+PAxWiKksbHRXy02FOjq6kKr1YaEtyZU4j9AviUYRYAEjs8++4yIiAiWLFkCwIsvvshrr71GYWEhL7744rA8YEEnQNLS0mhsbBzRMTOzMjm47wvMmjZs7l7EfksfGo2GlKQU1NGQXzieVatW0dvbS0lJCSpUGNVh6DxhGCSvqDAQhh6j/3eNoPWngp4MX+Exu9MyLAEiSRIut5VeRzuSJNJefxir1UbT1jcpL9vTL+NF6BMaPm+GGl14DOEJOUQnjcMQnYQxKgmNIWJQYsAYnYzHZsVcuhlXRyu2hjocpgYkd1+59D6xERsTw8yZM7n99tu5/PLLB4whiiL//e9/QyZSPTw8nJSUFMrLy5k+ffpZjxcs4sPHSIsQURQ5fPgw48ePDwmBCcfiP0LBXpvNFhICRJIkWTwgNpsNs9lMWlpaQOc9V7nnnnt44oknAG/tpLvuuou7776bdevWcdddd/HGG28MecygEyAjvQQD8PDDD5OYmEhaWhrp6elkZGT4fyYkJKBSqWhqauLQoUN89dVXfP7551x00UUs5EKMYvgpxcVgMOItKW91dBIdfuosAY/oxurowGpvp9fRRq+9nV57K7329gFl4QVBzdGj1WSkxFF+UEKtMuARnYTFZ5E6aQnG6GT0kQlnDEbtjyh6sJlNWDvq6e1ooLe9lt6ORhAEWj59D1Rq1ALEx8Yyb9487rrrLs4778xZNCqViujoaMxmc0gIEICJEydSVFREXl7eWdUXCDbx4WMkRUhdXR2iKIZUEKCvXHwoYLFYBp1NICculwtRFAMuQJqamtBoNCFRJ2UsUF1d7a+t9J///Ievf/3rPProo+zcuZNLLrlkWGMGpQAxmUwj2hF31qxZ/PWvfz3tPgaDAbvdGyfiO6DasfoFxHDRCFq0kg6bo9NbgdHV5RUXjnav2LC30WNvxeE6llUj0Ncnpa/qqkrQYNBFExOeQWRYCl1tGpbMuQJ152IEQaC0/E2E8Gjic2ae0R7R48LqExvt9fS212Izm/yeGkGlJsxoYHLhRBYsWMAPfvADFi5cOOznHxMTQ2dnJ5mZmcMeI5BERkaSmZlJWVnZsIvrBKv48DESIsTj8XDo0CEmT54cEvU0fHR2djJx4kS5zRgUZrM5JJYX7HY7arU64HVAmpqaSE5ODqnPXyij0+mwWq0ArFmzhuuuuw7wlroYbuZqUAoQp9M5atkIpyI8PByn04nL5fILEBu9xJI45LHckgsrPVjpppduQKC6uZgq00ZEqV8/E9RI/ZrSaNRGIg3JRIWlEhGWRLghnnB9AlrNwCuLnnYdk+fEIgjeaq4RxiTazDUn2OFxO7F1NtHbUef1bLTVYutq9i/bqFQawsONTJs2lfPPP59bbrmFvLy8IT/f05GUlMS+fftGVFCONgUFBXz11Vd0dHQM+eQc7OLDx9mKkMrKSvR6fcjU/gBvAbKenh4SE4f+nQ40brc7ZIJle3t7CQ8PD/j3W4n/CCxLlizhrrvuYvHixWzbto23334bgPLy8mG3sQg6ARIREUFERARNTU0BFSA6nQ6tVktvby8xMTEkJyZjaz11Sq4oidix+kWGlR5s6l5sdGPzWP37qVUaPKIbXwsZARUGXQzRYelEhiURbkgg3BCPUR+LShhcKffWJisJyUZfexoijUnUte2gy3QEq7mpT2zUYO9qwxd4qlJpiIgIo3DWLC688EJuvfXWgJw8EhMTcTgcdHd3h4Q7Gbwl+QsKCti1axcrVqwYdIvxUBEfPoYrQrq6uigvL2fRokUhIyrBWywtPj4+6DKwTkZXVxd6vT4kYkB8AiTQKAIksLzwwgvceuutvPvuu7z88sv+88enn37KRRddNKwxg06AwLFA1OF01zsbIiIi6OnpISYmhvH546lorcUpOQaKDLqxa6z0eLr8wawqQYVKUOH2HPNuhKnDMYoRhImRhBOFGycV7GfJ5Nsx6mPOys7WFjMSElbhMEeqDtDZXQOSyKE1rwACKrWa6KhIZiyYz9e+9jV+9KMfyXbVp1arSUxMxGQyhYwAAcjLy6OxsdG/zHAmQk18+BiqCBFFkV27djFu3LiQep7gFSChkq0TSsGyPT09svRjaWxsVAJQA0hWVhYff/zxCdv/8Ic/DHvMoBQg6enp1NXVBXxenwABGJ8/ns3Fm2nmmB1ajRa3x+NvA68SVESoozC4I4iQoggnkrC+m1rsu2ruO37YJSsV7KfH3jokAeJ0W+m2NtFlNdFlbcJibcDutHBB5WNoIlrocdUwYVIOubm5LF26lJtuuinoqjympKRQU1PDhAkT5DZl0KhUKmbNmsX69etJTU097ck2VMWHj6GIkIqKCtxud8jEUfhwuVy0tbWNSHZTIAilYNmenh6ysrICPm99fX1IHVMUTiQoBciECRM4cuRIwOd1uVx8+OGHrFp5Hk2mY6nABo2RMDGSMHcEYUQSjteroZeMCB5hUFkyeoyo0dJjayYxOv+k+zhcPXRZm+i2muiyNmKxNvqDUwVBRWRkJJMm5zJ//nwmTZrERRddxIwZM0biqY8qycnJ7NmzJ2Qaa/mIjIxk0qRJlJaWsnz58pPaHuriw8dgREhrayvl5eUsXrx40MtSwUJLSwsRERGyLBUMB4vFEjLeGrk8IOXl5f7y4OcaOTk51NScGPd366238uKLL56w/W9/+xs33HDDgG16vd6feCEXQStANm3aFPB5d+3ahUqlQm+KpJC5fUIjEo2nb834LLyhgiAQIUXTbWvuy4bppsva1O/WiLOvDLwgeNNXp83wZqJ87Wtf47zzzhsQZV5bW3vSD2AwYjAYiImJobm5OaRSNsF7YjabzWzbtu2EE+9YER8+TidCent7KS0tZerUqbKU3D5bQmn5JZSqtbpcLhwOR8CFnSRJlJeXn7MekNLS0gH9Vvbv388FF1zAVVdddcrHREVFcfjwYf/9YFjeC1oBcqa02dEgLS2Nnp4eMsjDIIxMEzRJkrBjpRszIm5azOUU7X0al8cGgEpQExsXw+y501i4cCHf+MY3WLJkyRlTy2JiYti7d2/IZJekpKRgMplCToAIgsCMGTPYtGkTe/bsYebMmQiCMObEh4+TiRCXy0VJSQmZmZkh9/6BN26lubnZ38Ez2LFYLCFTrbW3txetVhvwfjVtbW2YzWby80/uTQ5Vjk9n1ev1J60we3xM3+OPP05eXt5py6ULghB0IjxoBUhFRQUejyegrt7CwkIOHDgAMW6wDP3xkiRho5cuOummk15VF91qMw63180VGxtLsiGR8ePzWLx4MZdffjlz584dVh67z+UZKtklKSkpHD58GJfLFRJZCP1Rq9XMnz+f9evXU1ZWhl6v59ChQ2NOfPjoL0LmzZtHeXk5BoNhUMG4wUhbWxsqlSpkPDe++I9QuLDo6emRJQW3vLyctLQ0WZZ+RpPj6yU9+OCDPPTQQ6d9jNPp5K233uKuu+467fvQ09NDdnY2oigya9YsHn30Udm/00EpQMaNG4fb7aauro6cnJyAzZubm8tXX31FVE44zj2n31eSJKx004XZKzbUFrqx+LvupqaksWjePGbPns3s2bOZNWvWiKaMqVQqoqKiQqZaYlRUFFFRUdTX1zNu3Di5zRkyBoOBRYsWsWHDBjweD4sXLx6T4sNHbm4uoiiyZcsWIiMjWbp0acgWfKqpqSEzMzMkTujg9YAEWyD5qZDL1rG6/FJXVzfgeD6Y/joffPABZrOZ1atXn3KfgoIC/vrXvzJt2jQsFgtPP/00ixYt4sCBA6et4fHNb35z0La/9957g97XR1AKEK1WS25uLuXl5QEVICqVio72DpLGx1G/55gLRJTEPrHRSTfmPrFhxuXx9kXJzMhi+bwlzJkzh1mzZjFz5kySkpJG3d5QqzKak5NDdXU1OTk5IXMy6E9rayuSJKHRaGhubiYuLi4kn8dgcLvdNDc3YzQa6e3tpaurKyQFl8PhwGQysXLlSrlNGTShVK3VYrHIUotjrAoQ34XaUPjLX/7CxRdffNqU5IULFw6oaL1o0SImTZrEq6++ym9/+9tTPq6/uJQkiffff5/o6GjmzJkDwI4dOzCbzUMSKv0JSgEC3mWY8vJy/ud//ieg86rUKtLGp1Ai7fZ6NjRddItm3KK3xse4nFz+Z8F5zJo1yy825DowJyYmcuDAgZCJA0lPT2ffvn2YzeaQcYf78MV8LFq0CJ1OR3FxMTabjRkzZoRcRsiZsFqtlJSUoNfrWblyJbW1tSPeRTdQ1NbWEhcXFzKuepvNRk9PT0j0N5EkCbPZzKRJkwI+t68Q3rlOTU0Na9asGbL3QavVMnPmTCoqKk67X/8Gc7/4xS/49re/zSuvvOI/5nk8Hm699dZhe+GDXoAEmnHjxmGxWDgk7GR8Xj4rFlzErFmzmD17NjNmzAiq5Y7ExET/ASsUmr1pNBoyMzM5evRoSAmQkwWcLlu2jNLSUjZt2sS8efNCImBwMLS3t7Nt2zbS09OZMmUKKpVqxLvoBgpJkqipqZHlBDlcTCYTcXFxAQ/qHA5WqxW32y3LMbG8vPy0Sw7nCm+88QZJSUl87WtfG9LjPB4P+/btG1ITub/+9a9s2rRpwAWXWq3mrrvuYtGiRTz11FNDsgGCXIC8//77AZ/38ssv59NPP6W9vT3oT5IajcZfZTQUBAh4Bd769espLCwc1Pqm3Jwq28UXE7J3717Wr1/P7NmzQ6LHyKmQJMn/XKdMmXLC0mcoipDm5mY8Hk9IlesOpXRhX/xZoD2AoihSUVExJpdghoIoirzxxhtcf/31JzQCvO6660hPT+exxx4D4JFHHmHBggWMHz8es9nMU089RU1NDTfddNOg53O73Rw6dIiCgoIB2w8dOoQoisN6DkErQCZPnswjjzwS8Hl1Oh1hYWG4XK6Azz0cUlJSqKurC5l0tKioKOLi4jh69OgJH+Rg40yptmq1mhkzZlBTU+NPUy0sLAy5LJ/e3l527dqFzWZj4cKFp+zBFGoipLKykpycnJAJnnW73bS1tTF16lS5TRkUvnLxgebIkSNIkuT/PJ6rrFmzhtraWm688cYT/lZbWzvgc9/Z2cnNN9+MyWQiNjaW2bNnU1xcTGFh4aDnu+GGG/jBD35AZWUl8+bNA6CkpITHH3/8hCJngyVoBcjMmTMxmUyyNByKiYnBbDYHJJD0bElOTmbv3r04HI6Q8CiAt8/Knj17yM/PD9qTw2DrfAiCQE5ODomJiezevZuioiKmT58eEp8dURQ5evQoBw8eJDMzkwULFpyxpXqoiJCuri46Ojr8wXKhQEtLC2FhYSETr2I2m2XxLu3YsYPp06eHnNAfaf7nf/4Hqa+z+fEUFRUNuP+HP/zhrHq2ADz99NOkpKTwzDPP0NTUBHi7199zzz3cfffdwxozOI/+eOtcFBQUsGPHjoDPHRMTg8UyjEIgMmA0GomKiqK5uVluUwZNcnIyGo0maCu5DqfIWHh4OIsWLSIvL4/S0lKKi4sxm82ja+gwkSSJxsZG1q1bR1VVFfPnz2f69OlnFB8+cnNzmTRpElu2bKGjo2OUrR0ehw8fJisrK2REOYTW8oskSVgsFlmqte7YsYPZs2cHfN5zHZVKxb333ktDQwNmsxmz2UxDQwP33nvvsJfhglaAAMyePVsWARIbG0t7e/sp1WWwkZqaislkktuMQSMIApMmTeLw4cO43e4zPyCAnE2FU0EQyM3N5YILLiA6OppNmzaxffv2E6obyoUkSbS0tLBhwwb27t1Lbm4uq1atGlbsSjCLkM7OTpqbm0MqRkCSJJqbm0NGgPT09MgWgKoIEPkZTrrwyVAEyEmIjY3F5XLR29sb8LmHQ0pKCi0tLQN6AwQ7qamphIWFUVlZKbcpfkaqvLpOp2Py5Mn+/j3r16+nuLiYxsbGYQdrnQ0ul4uqqirWrl3Ljh07SE1N5fzzz2fcuHFntQQWjCJEkiQOHjxIbm5uSGUmdXZ2AgR94LuP9vZ24uLiZAlA3blzpyJAZKC5uZlrr72WtLQ0NBoNarV6wG04BG0MCHgFyNNPPx3wedVqNXFxcbS1tYXEemxUVBQ6nY729vaQiD0Ar7egsLCQkpIScnJyZHeVj0ZvF6PRyIwZM5g0aRJHjx5l//797N27l9TUVFJSUkhISBi1A7jT6aS5uRmTyURzczNRUVHk5+eTnp4+onMGW0xIa2srFovFHyQXKjQ1NZGUlBS0MVHH09bWJkutkoqKCpxOp+wlxM9FVq9eTW1tLb/5zW9ITU0dkdpTQS1AZs6cSVNTkyxrowkJCbS1tQW0EutwEQSB5ORkTCZTyAgQ8L7GcXFxHDlyhClTpshmx2g3ltPr9RQUFDBhwgRaW1sxmUzs2bMHp9NJUlIScXFxREdHExMTM6zAOkmSsNvtmM1mLBYLbW1tdHR0EBUVRUpKCgUFBaPqKg8WEeLzfuTn54dcgGJzc3PIVD+VJIm2tjZZWirs3LmTadOmhdz7OxbYtGkTGzduZMaMGSM2ZlALkMjISCZMmMDOnTuHVDBlJIiPj6e6ujpkqoympKSwZ88epk6dGhL2+igsLGTDhg3k5uYSFjYyHYiHQiC72gqCQFJSEklJSUydOpWuri6am5tpb2+nqqoKm81GeHg4YWFh6PV6DAYDBoMBjUbjX7qpra1FFEXsdjsOhwO73U5PTw8Oh4PIyEiio6NJT09n9uzZAV2CCAYR0tjYiMPhCLn0zJ6eHnp6ekKmjkxPTw8ul0sJQD3HyMzMHPG4yKAWIHAsDiTQAsQXBxIqVUYTEhJwOp0hV+Y8OjqatLQ0Dh06xKxZswI6dyDFx/EIgkB0dPSAOgoOhwOLxYLNZsNut2O322lra8Pj8fgFiMlkQqfTYTAYiI6OJjk5mbCwMKKjowedxTJayClCRFGkrKyMiRMnhlxpfJPJREJCQshc1be1tckS/wFeAXLNNdcEfF4FeO6557jvvvt49dVXR2xlIOgFyJw5c1i7dm3A5/XFgbS3t4eEAFGr1aSnp1NbWxtSAgRg4sSJrFu3jpycnICdtOQUH6dCr9efcgnN5XLxySefMG/evKA+UcklQiorKxEEIWQaM/rwlYsPpYyd9vZ2WeI/PB4PO3bs4Nlnnw343Arwne98B6vVSl5eHmFhYScch4YTiB70AmTZsmU8/PDDeDyegCvuUIoDAcjOzmbLli1MnjxZ9qvhoRAeHk5BQQG7du1ixYoVo/4+B6P4GEsEWoR0d3dz+PBhFi1aFDJBnD46OjpwOByn7WQaTMgZ/7F7924EQQiZSrFjjeeee27Exwz6s9SMGTOQJIk9e/YE3EWfmJhIZWUloiiGxIEtNjYWo9FIY2MjWVlZcpszJPLy8mhsbOTQoUOjGuGuiI/AECgR4kvLHDduXEi+nzU1NWRkZITMspHFYsHj8cgS/1FUVMSyZctC5rUaa1x//fUjPmbQn1XVajXLli07obRsIIiNjUUQhKCpcXAmfGXBjx49KrcpQ0alUjFr1iyqq6tH7fVWxEdgCUSdkMrKStxud8hkkPTH6XTS0NAQMh5WwJ9pJ4cIKCoqYsWKFQGf91ymfxHFrq6u096GQ9ALEIAVK1bIIkAEQSAlJSWkypxnZGRgsViCpvrmUIiMjKSgoICdO3eOeFE1RXzIw2iKkK6uLg4fPszMmTND8qq4vr6e6OhoWaqJDhe5ysV7PB42bNigCJAAExsbS0tLC+BtURIbG3vCzbd9OAT9Egx4Bchvf/tbWeJAUlJSOHDgQMgUvtHpdKSlpXH06FGmTZsmtzlDZvz48TQ1Nfnbwo8EiviQl9FYjhFFkV27doXs0oskSRw9epS8vDy5TRk0NpuNrq4ukpOTAz63L/5j+vTpAZ/7XGbt2rX+79fatWtHvMRDSAgQueNAbDYb3d3dIZENA94D/ubNm5k0aVJQZ0ycDEEQmDlzJuvXryctLe2sTy6K+AgORlqEVFRUhOzSC3hTWR0OBxkZGXKbMmiam5uJi4tDp9MFfG4l/kMeli9fTnV1NePGjRsV71NICJD+cSCBFiAajYbExESam5tDRoDExsYSFRVFbW1tSF1h+YiMjGTSpEls376dZcuWYTAYhjWOIj6Ci5ESIW1tbZSXl7N48eKQPSFVVVWRnZ0dUvbL2a23qKiIlStXyjL36ZiYZUIbfvaCzNXrpG4E7BkN8vLyyM7OZuXKlaxatYoVK1aMmHAOiRgQgJUrV7Ju3TpZ5vaVOQ8l8vLyqKqqCpmOvseTm5tLXFwcpaWlw2rgpoiP4ORsY0KsViulpaVMmTIl5Ord+Ojt7aWlpUWWVNbh4na7aW1tlWX5xe12s2HDhqAUIOcCa9eu5frrr6eqqoqbb76Z7Oxs8vPz+dGPfsS//vWvs4qRDBkBsmLFCjZs2CBL+/aUlBR/vn6okJqaiiiKISecfPiWYjweD3v27BmSkFLER3AzXBHidrspKSkhPT09pDJHjqeqqorU1NSQ6tbb0tKC0WiUxQu8e/duVCpVSMa0jQVWrFjBQw89RFFREZ2dnXz55Zd897vfpaysjNWrV5OWljbsGMmQESDTp09Hp9OxZcuWgM9tNBqJiYmhqakp4HMPF5VKxbhx46iqqpLblGGjVquZP38+zc3Ng34eivgIDYYqQiRJYufOneh0OlkbF54tLpeL2trakOtX09jYKFuxtE8++YTzzjsvpJarxioGg4FVq1Zx//338/DDD3PHHXcQERHBoUOHhjVeyAgQtVrNpZdeykcffSTL/BkZGdTVBesq3cnJycnBbDbT3t4utynDxmg0Mm/ePMrKyvzpYKdCER+hxVBEyOHDh7FYLMydOzckigKeiqqqKqKiokLq8+lyuWhqapItYPajjz7isssuk2VuBS9Op5MNGzbw8MMPs3LlSmJiYvjxj39MZ2cnL7zwAtXV1cMaN6S+yV//+tf58MMPZZk7PT2dzs5OrFarLPMPB51OR15eHgcPHgzZWBCAuLg4pk2bxvbt2+np6TnpPor4CE0GI0IaGhqorKxk/vz5smRgjBQOh4OKigomTZoktylDoqmpicjISFnqlTQ2NrJr166ANyNVOMaqVauIjY3l1ltvpaWlhR/96EdUVlZy+PBhXnvtNa699tphV94OKQHyP//zP1RXV1NeXh7wuX2Nwurr6wM+99mQl5dHT09PSBVTOxlZWVlkZWVRUlJyQiyOIj5Cm9OJkI6ODnbt2sXs2bNDqmDXyThy5Ajx8fGyNHI7G+rr62Xzfnz88ccsXLgw5F6zscTGjRuJj49n1apVnHfeeVxwwQWkpqaOyNghJUAiIiJYtWqV7MswoeRN0Gq1FBQUhLwXBGDy5MlER0dTXFyM0+kEFPExVjiZCOns7PQ3V5Qr/XOksFqtVFdXh5z3w2az0dbWRnp6uizzf/jhh3z961+XZW4FL2azmT//+c+EhYXxxBNPkJaWxtSpU7n99tt59913aW1tHfbYISVAAC677DLZlmFSUlKw2WxYLBZZ5h8uOTk5eDyekIthOR5BEJg1axbh4eEUFxdz5MgRRXyMIfqLkNraWrZs2cLEiRNDKl31VBw6dIi0tDSio6PlNmVINDQ0EB8fL0vGTm9vL2vWrFHiP2QmPDyciy66iMcff5ySkhLa2tp48sknCQsL48knnyQjI2PYgeEhJ0AuvfRSNm/eLEtgpUajITU1NeSWYVQqFRMnTuTQoUMj3mMl0KhUKubMmYMoihw8eJC5c+cq4mMMkZubS05ODrt27SI9PT0kC+kdT1dXFw0NDSFZtVXO5Zc1a9aQmZlJQUGBLPMrnJzw8HDi4uKIi4sjNjYWjUZDWVnZsMYKOQGSmZnJtGnT+PTTT2Wbv76+fljFseQkIyMDrVYbkp1yj+fo0aNYrVbi4uI4ePCgfzlGIfQxm83U1NSQnJxMfX19yHSiPh1lZWXk5OQQHh4utylDoquri+7ubtnSbz/88EMuu+yyEe8/ojA0RFFk27ZtPPnkk1x88cXExMSwaNEiXnrpJVJSUnjxxReHXe4h5AQIyJsNk5iYiEqlCrmgTkEQKCwspLy8HJfLJbc5w8YX87Fo0SIWL15MWFgYmzdvDqkicQonp6Ojg82bNzNhwgQWLFgwal10A0l7ezutra1MmDBBblOGTE1NDWlpabL0kxJFkY8//liJ/wgCYmJiWLhwIc8//zzx8fH84Q9/oLy8nNraWt58801Wr15Ndnb2sMYOSQFy+eWX88knn9Db2xvwuQVBIDs7OyQ9CUlJSURGRlJRUSG3KcPi+IBT33JMZGQkGzdupLu7W24TFYZJU1MTW7ZsYdKkSYwfPx44+7LtciNJEgcPHmT8+PHo9Xq5zRkSbreburo62SrObtq0CY/Hw+LFi2WZX+EYTz31FGVlZTQ0NPDWW2/xgx/8YMSWRkNSgMyYMYPMzEzZvCDZ2dm0tbXJIoDOBp8XpLKyErvdLrc5Q+JU2S4qlYrZs2eTlpbGhg0bQs4zda4jSRKHDx9mx44dzJw584QKoaEsQpqbm+np6QnJOJbGxkYMBoNs8VVvvfUW3/72t0Oum/dY5Ec/+tGoefBCUoAIgsD3v/99/vGPf8gyv8FgIDk5OSS9IHFxcSQmJnL48GG5TRk0Z0q19Qmr6dOnU1paSkVFRcinHJ8LuN1utm/fTk1NDUuXLj1lrEEoihCf92PChAkheRI9evQoOTk5ssRfOBwO/v3vf/P9738/4HMrBJaQFCAA11xzDV988cVZ5SCfDePGjaO2tjYks0oKCwupq6sLiYP5UOp8ZGRksHjxYiorK9m5c2dIvjfnCjabjU2bNuFwOFi+fPkZ01NDTYRUVFQgimJINs3r7Oykq6uLzMxMWeb/5JNPiI2NZeHChbLMrxA4QlaAjBs3jnnz5vHOO+/IMn9CQgJ6vZ6GhgZZ5j8bIiMjKSgoYNeuXUF9kh5OkbHY2FiWL19Ob28vmzdvDrmlpnOBjo4O1q9f74+mH2x8RKiIkO7ubg4fPsysWbNCsoFadXU1WVlZsnlu/vGPf/C9731PyX45BwhZAQLw/e9/n7feekuWuQVB8HebDUV3f15eHhqNZthdDEebs6lwajAYWLx4MREREaxfv/6MTewUAoMkSVRWVlJcXMyECROYPn36kBvLBbsIEUWRnTt3Mm7cuJCsT+NwOGhoaJCt+JvZbObjjz/me9/7nizzKwSWkBYgV111FTt27KCyslKW+TMzM+nt7Q3JbrMqlYpZs2ZRXV0ddAfykSivrlarmTlzJhMmTGDbtm3s2bMnpNOPQx2fR6qqqooFCxaQm5s77CvcYBYhlZWVuN3ukCw6Bl7vR3x8PJGRkbLM/5///IcpU6aE7OunMDRCWoDEx8dz8cUXyxaMqtFoGDduHEeOHJFl/rPFtxQTTPESI9nbxeelWrlyJT09Paxbt062mKFzFUmSqKqqYt26dURFRbFy5coRaSwWjCKkq6uLw4cPM3PmzJBcenG73VRVVfnToOXgrbfeUoJPzyFCWoDAsWUYuZZB8vLyaG9vx2w2yzL/2TJ+/Hh0Ot2wS+mOJKPVWC48PJxFixaRn59PSUmJ4g0JED6vR2VlJfPnz2fatGloNJoRGz+YRIgoiuzatStkl17AW3gsPDycxMREWeavq6tj06ZNXH311bLMrxB4Ql6AXHrppTQ3N7N161ZZ5tfr9WRlZYWsF0QQBGbOnMnRo0dlPYiPdlfb470hRUVFijdklOjv9YiMjGTlypWjdlILFhFSUVER0ksvHo+HiooK8vPzZQv+/Pvf/855550X8p2PFQZPyAsQo9HItddey6uvviqbDePHj8dkMtHT0yObDWeD3Esxoy0++uPzhuTl5VFSUkJJSYlSQXWEkCSJ5uZmioqK/F6P6dOnj6jX42TILUK6urooLy8P2aUX8Dad8zXblANRFHnttde4+eabZZlfQR5CXoCAt1LbO++8Q2dnpyzzh4WFkZ6eHrIlzkG+pZhAig8fgiCQm5vL+eefj9FopKioiF27dmGz2QIy/1jE18dlx44dZGZmsmrVqoC68uUSIWNh6UWSJI4cOSKr9+OLL77Abrdz2WWXyTK/gjyMCQEydepUZs2axd///nfZbMjPz6euri5kT2L9l2ICldUjh/joj8FgYNq0aaxcuRKPx8NXX33FgQMHlO66Q6C7u5tt27ZRXFxMfHw8F1xwAePHj5fFEyCHCAn1pRfwll0XRZGMjAzZbHj11Ve56aabQrJqrMLwGRMCBLxekFdeeUW2YNTIyEiSk5ND2gsSGRnJxIkT2bFjx6h3l5VbfPQnIiKCOXPmsGTJErq6uvjyyy9DvmvwaGO1Wtm1axdFRUXo9XrOP/98Jk2aJPsJJJAipL29PeSXXnzej/Hjxw+5JstI0dDQwH//+19uuukmWeZXkI8xI0CuuuoqWlpaKCoqks2GgoICampqQtYLAt6sntjYWEpLSxFFcVTmCCbx0R9f2+l58+ZhMpn44osv2L9/f8g1HRwtJEmivb2d0tJSvvrqKzweDytXrmT69OkYDAa5zfMTCBFitVopLS1l8uTJQfUZHiqNjY04HA6ysrJks+HVV1/lwgsvHHZLd4XQZcwIEIPBwM0338yf/vQn2WyIjo4mJSUlaKuLDgbfUozb7Wbfvn0jPn6wio/+JCYmsnTpUhYuXIjdbmft2rWUlJTQ3NwcklVvzxa3201NTQ3r169n69atGI1GVq1axZw5c4iIiJDbvJMymiLE7Xazbds2UlNTQ7LXiw9RFCkrK6OgoGDUA4VPhcPh4NVXX+UnP/mJLPMryIs8n7pR4sc//jH5+fnU1tbKpugnTpzIunXryMvLIyoqShYbzhaNRsO8efNYv349UVFRI1aWORTEhw9BEIiLiyMuLg6bzUZ1dTW7du1CpVKRnZ1NVlYWRqNRbjNHDUmSsFgs1NTUUF9fT1hYGDk5OWRmZsp2shoqubm5AGzZsmXEPnOSJLFr1y40Gg1Tp04N6X4ltbW1ALJ6P959911iYmI4//zzZbNBQT5C40gySLKzs/na177Gyy+/zGOPPSaLDREREWRlZVFWVsb8+fNlsWEkCAsLY968eWzZsoWIiIizzmgIJfFxPEajkcLCQiZOnEhzczM1NTUcPnyYmJgYUlJSSElJITIyMqRPRuC9Iu7o6MBkMmEymbDb7WRkZLBo0SJiYmJC8vmNtAgpLy+ns7OT5cuXyxYzMRK43W4OHTrEtGnTZH0ef/rTn7jttttC+rVUGD5jSoAA/OQnP+Gqq67i/vvvJzw8XBYbCgoKWLNmDR0dHSF3su1PfHw8U6dOZfv27SxbtmzYr2coi4/+qFQqUlNTSU1NxW6309zcjMlkory8HL1e7xcj8fHxIXNAdblctLS0YDKZaG5uRqVSkZyczOTJk0lMTAwZb8fpGCkR0tjYyJEjR1i6dOmgO/gGK1VVVRiNRtnqfgCUlJRw4MABrr/+etlsUJCX0D+6HMfKlSsZN24cr7/+Oj/96U9lscFgMJCXl8fBgwdZvHhxSF45+sjOzqarq4uSkhKWLl065CyHsSI+jsdgMJCdnU12djYej4fW1laam5vZuXMnbrebpKQkYmJi/De5s0PAu3xgt9sxm82YzWY6Ojpob2/3Z3AtWLCA2NjYkP68noqzFSFdXV3s2rWLWbNmER0dPRomBgyn08mRI0eYN2+erO/1Y489xo9//OOQfz0Vhs+YEyCCIPDLX/6SO++8k1tuuQWdTieLHePHj+fo0aO0tLSQnJwsiw0jxeTJk9m6dSs7d+4c0kFrrIqP41Gr1X7vx7Rp0zCbzbS2ttLZ2Ul1dTU2m42wsDC/GImOjvaLktE6AUiShM1mw2w2Y7FY/D8dDgeRkZHExMSQmprKjBkzZPMUBprhihCHw0FJSQnjx48nLS1tNE0MCEeOHCE2Nla2ni8A+/fv5/PPP+ell16SzYZQJicnh5qamhO233rrrbz44osnfcy///1vfvOb33D06FHy8/N54oknuOSSS0bb1NMy5gQIwBVXXMGvf/1r3nrrLW688UZZbNBqtUyYMIH9+/eTmJgYMi75k6FSqZgzZw4bNmzg0KFDTJo06YyPOVfEx/EIgkBsbCyxsbH+bQ6Hwy8COjs7OXr0KFarFbVajV6vx2Aw+G/976vVagRBQKVS+Uvkm81m1Go1kiThcrmw2+04HA7sdvuAm6+OS2RkJNHR0SQnJ1NQUEBUVNSYWFYZLkMVIaIoUlpaSkxMDBMmTAiEiaNKT08P1dXVLFmyRFY7nnjiCa677roxIejkoLS0dEDbjP3793PBBRdw1VVXnXT/4uJivvvd7/LYY49x6aWX8s9//pPLL7+cnTt3MmXKlECZfQKCNEbzCt944w0ef/xxDh48KFuRIFEUKSoqIjMzk/z8fFlsGEm6urrYuHEj06dPP23VxHNVfAwFn3joLxiOv+/xeJAkCVEUEUURt9uNTqdDpVIhCAIajWaAeDmViFE4kcF8RiVJYs+ePXR2drJ06dKQF26SJLF161bCwsKYPn26bHZUV1czceJEDh48SF5enmx2nA1dXV1ER0dzwSc/Qht+9l52V6+TLy95lbq6ugHZk3q9flDxRnfeeScff/wxR44cOalX9Tvf+Q69vb18/PHH/m0LFixgxowZvPLKK2dt/3AJ7W/Uafje977HAw88wPvvv8+3vvUtWWxQqVRMmzaNrVu3kpGREfJpm1FRUcyZM4fS0lLUavVJA9gU8TE4tFotWq2WyMjIQe3vcrn45JNPOP/884MiniTUOZMnRJIkDh48SHNz85gQHwAmkwmz2czs2bNltePpp5/mm9/8ZsiKj9EkMzNzwP0HH3yQhx566LSPcTqdvPXWW9x1112nXNLdsmULd91114BtF154IR988MHZmHvWhP636hTodDp+/vOf89hjj3HllVfKFmyVkJBAamoqBw4cYM6cObLYMJIkJycza9YsduzYwbx580hKSvL/TREfCqHE6UTI4cOHqaurY8mSJYSFhcll4ojhKyxYWFgoW1wceEXQX//6V7Zu3SqbDcHMyTwgZ+KDDz7AbDazevXqU+5jMplOiEVMTk7GZDIN29aRIHQDEwbBTTfdRE1NDV988YWsdkyePJnm5mZaW1tltWOkSEtLY8aMGWzbts3/nBTxoRCKnKxianl5OdXV1SxatChoK70OlSNHjmAwGGQtOgbw3HPPsWrVKlmXgIKZqKioAbfBCJC//OUvXHzxxSEZTzNmPSAA4eHh/PSnP+Wxxx7jwgsvlM0Og8FAQUEBe/fuZeXKlSEdkOojIyMDURQpKSkhOzub2tpaRXwohCT9PSFZWVnU1dWxePHikK1kfDw9PT1UVlbKXhLAbDbz0ksv8cknn8hmw1ijpqaGNWvW8N577512v5SUFJqbmwdsa25uJiUlZTTNOyOhfyY8A7fffru/a6ec5ObmIggCVVVVstoxkmRlZZGcnExVVRWFhYWK+FAIWXJzc0lMTKSqqorJkyePmdoUkiSxb98+MjMzB2RmycEf/vAHZs6cKXsGzljijTfeICkpia997Wun3W/hwoV89dVXA7Z9+eWXLFy4cDTNOyNjXoDExsZy77338otf/ELWRmK+gNRDhw6Nme6qVVVVtLS0MH78eA4cODBmlpgUzj3Ky8tpa2sjLy+P/fv3j1oX3UDT0NCA2WweVOr8aNLc3Myzzz4rW4uMsYgoirzxxhtcf/31JwRJX3fddfzyl7/03//pT3/KZ599xjPPPMOhQ4d46KGH2L59O7fffnugzR7AmBcg4E1Rqq2tlT3iNyEhgczMTHbt2hXyXVX7x3xMnjyZadOm+TvGKiiECpIkcejQIf8SxZQpU0ati26gsdvt7Nu3j2nTpskaeArw+9//nlWrVrFo0SJZ7RhLrFmzhtra2pPWuqqtraWpqcl/f9GiRfzzn//kz3/+M9OnT+fdd9/lgw8+kLUGCIzhOiDH8/LLL/PHP/6Rffv2yZpS53a7/d1yfWvPocapAk4bGhrYtWsXs2fPlrXHxFjEl4Z7ySWXKGm4I4Qv1bauro5FixYNiPkI9aBqSZIoLS1FEATmzp0rqy2+Za3t27czefJkWW0ZKUarDojFYhkzsUeD4ZzwgIA3I8blcvHmm2/KaodGo2HGjBkcPHgwJJdiTndgTk9P96fo1tXVyWShgsKZEUWRvXv3Ul9fz5IlS0446J8sOyaUaGhooL29nWnTpsltCg888ADf+c53xoz4UBg5zhkBotVq+d3vfseDDz6IzWaT1ZbExESysrJCbilmMFeFaWlpzJs3j3379nHgwIGQen4K5wZOp5OtW7fS3t7OkiVLTplqG6oixG63s3fvXqZPny571949e/bwn//8h4cfflhWOxSCk3NGgAB8+9vfJikpiRdeeEFuUygsLMRms4VMVsxQXNJJSUksW7YMk8lESUkJLpcrQFYqKJyerq4uNmzYgFqtZunSpWdsxBdqIsRXPj4pKSko6kL88pe/5JZbbiE7O1tuUxSCkHNKgKhUKh5//HEee+wxzGazrLZoNBpmzpxJWVkZPT09stpyJoazHh4REcGyZcuQJIkNGzYE/XNUGPuYTCY2btxIeno68+bNG3QsTSiJkIaGBjo7O5k6darcprB+/Xo2b97Mr371K7lNUQhSzikBAnDBBRcwc+ZMHn/8cblNISEhgezsbHbs2IEoinKbc1LOJhhPq9WyYMECUlJS2LBhAy0tLaNkpYLCqZEkiSNHjrB9+3ZmzJjBpEmThlyQKxRESG9vL3v27GHatGmyL72IosgvfvEL7rnnHhISEmS1RSF4OecEiCAIPP300/zxj3/kyJEjcptDYWGhPxo/2BiJTABBEJg8eTJTp05l27ZtVFZWKnEhCgHD4/Gwc+dOqqqqWLJkCenp6cMeK5hFiCiKbN++nczMzKBYevn73/9OY2MjP/vZz+Q2RSGIGdOl2E/FzJkzueGGG/jJT37Cp59+Kmt5YrVazZw5c1i/fj0JCQmyl8b1MdJpiJmZmYSHh7Nt2za6urqYNm2a0ipeYVSx2Wxs27YNlUrF8uXLMRgMZz3mmbroysXBgweRJCkoMk3MZjP33nsvL7744hljbEKdb6bsxBhx9qdRW4+bL0fAnlDjnPOA+Pjd737Hjh07ZC9OBt54ienTp7Nz507ZM3Rg9GogxMXFsXz5crq6uiguLsZut4/Y2AoK/eno6GD9+vVERUWxaNGiEREfPoLNE2IymaipqWHOnDlBIeofeOABpk+fzpVXXim3KQpBzjkrQGJjY3niiSe48847sVqtcptDRkYGaWlpbN++XdZ4kNEuwGQ0Gv0tztevX6/EhSiMKJIkUVlZSXFxMfn5+cyYMWNUTsrBIkJsNhs7d+5k+vTpQdG5d8+ePbz++uv86U9/ktWzrBAanLMCBGD16tWkpqby6KOPym0KAFOmTMHlcnH48GFZ5g9U9Ue1Ws2sWbOYMGEC27ZtY8+ePUqqrsJZ09vby+bNm6mqqmLBggXk5eWN6klQbhEiiiI7duwgNTWVjIyMgM9/PJIkcdttt3HHHXdQUFAgtzkKIcA5LUBUKhUvvfQSzz77bFAEpGo0GubMmUNlZWXAe6oEuvS0IAiMGzeOlStX0tPTw7p165RmdgrDQpIkqqqqWLduHVFRUaxcuTJgmRdyipBDhw7hdDqDIuUWvIGnNTU13H///XKbohAinNMCBGDWrFmsXr2aO+64IyiyM6Kiopg+fTo7duwIWO0MOftehIeHs2jRIvLz8ykpKVG8IQpDwuf1qKysZP78+UybNi3gvZ7kECENDQ1UV1czd+5cWXtb+TCbzdxzzz08++yzQbEUpBAanPMCBLwBqaWlpUERkArejJHs7OyAVBENhqZbx3tDioqKFG+Iwmnp7/WIjIxk5cqVJCYmymZPIEWI2Wz2N32MjIwc1bkGy4MPPsjUqVP51re+JbcpCiGEIkDwZmc89dRT3H777bJXSPVRWFhIeHg427dvHzXPTDCIj/74vCF5eXl+b4jb7ZbbLIUg43ivx/Tp04PCCxAIEWK32ykpKaGgoCBoUva3bt3Ka6+9xgsvvKAEnioMCUWA9LF69WqmTp0aNIVzBEFg9uzZWK3WUSlSFmziw4cgCOTm5rJy5Uq6u7uV2BAFP8Hm9TgZoylCPB4P27ZtIyEhgfHjx4/o2MPFZrOxevVqHnjgASZOnCi3OQohhiJA+hAEgddee4333nuP//73v3KbA3hLmc+fP5+amhpqa2tHbNxgFR/9CQ8PZ/HixX5vyI4dO+jt7ZXbLAWZaGtrY+PGjVRUVASV1+NkjIYI8TWZkySJGTNmBI2n4YEHHiA6Opqf//zncpuiEIIE5zdYJjIzM3n22Wf54Q9/yP79+4mNjZXbJCIiIpgzZw7btm0jIiLirAVDKIgPHz5vSEpKCocOHWLt2rVkZ2dTUFAge68LhcBgsVgoKyujvb2d8ePHk5eXF7TCoz8jXTG1qqqKlpYWli9fHhTFxsD73F588UW2b98eEu+JQvCheECO48Ybb2TatGlBsxQD3vb2hYWFlJSUnFVmTCiJj/6EhYUxa9Ysli9fjs1m48svv+TQoUNKtswYpre3lx07drBhwwYiIiI4//zzKSgoCKkT3Uh5QhobGykrK2PevHkYjcYRtHD4+JZeHnzwQQoLC+U2RyFEUQTIcfiWYj744IOgWYoB78EsKyuLLVu2DKuEeaiKj/5ERUUxf/58Fi5cSGtrK2vWrKGyshKPxyO3aQojhMPhYN++faxduxZBEDjvvPOYMmVKyHq8zlaEtLW1sXPnTubMmRNU39vf/OY3xMTEcPfdd8ttikIIEzqXEwEkIyODZ599lptvvpkDBw4ExVIMeDNjHA4HW7ZsYcmSJWi12kE9biyIj/7Ex8ezZMkSmpubKSsro6qqiokTJ5KRkRE0a+MKQ8PlclFZWUlFRQWJiYksX76cqKgouc0aEYa7HGOxWCgpKWHatGlBk/ECUFxczMsvv6wsvSicNYoH5BTccMMNzJgxgzvvvFNuU/wIgsCMGTMwGo2UlJQM6sp/rIkPH4IgkJKSwooVK5g4cSJlZWUUFRVhMpmCoqCcwuDweDxUVlayZs0aWltbWbhwIfPnzx8z4sPHUD0hvb29bNmyhQkTJpCVlRUACweHzWbjhhtu4MEHH2TSpElym6MQ4ijy9RQIgsCf//xnpk6dyr///W+uuuoquU0CvOXj58yZQ3FxMTt27GDu3LmnvOofq+KjP4IgkJmZSVpaGkePHmXXrl0YDAZyc3PJyMgImoA9hYE4HA6OHj1KdXU1Op2OmTNnkpycPKY9WIP1hPi8nOnp6UGTbuvj7rvvJi4uTll6URgRFAFyGjIyMvjrX//KDTfcwOzZs/0HELnRaDQsWLCAjRs3snfvXqZNm3bCgftcEB/9UavV5OXlkZ2dTX19PZWVlRw8eJCcnBxycnKCJnjvXMdsNlNVVUVDQwPx8fHMnDmTpKSkMS08+nMmEeJyudiyZQsxMTFMmTIlqF6Xd999l//3//4fu3btUoS9woigCJAzcMUVV7Bu3Tq+853vsHnzZnQ6ndwmAaDT6Vi0aBEbNmxAo9FQWFjoP1ida+KjPxqNhpycHLKzs2ltbaWqqoo1a9aQmppKTk4O8fHxQXVQPxfweDw0NTVx9OhRzGYzmZmZYyrGY6icSoS43W5KSkrQ6XTMmjUrqD6nVVVV3HTTTfz1r38lJydHbnMUxgiKABkETz31FIsWLeK+++7j2WefldscP0ajkcWLF7Np0yYEQWDSpElUV1efs+KjP4IgkJSURFJSEj09PVRXV7Nt2zZ0Oh3Z2dlkZWWFbGZFqNDd3U1NTQ11dXVotVpycnKYN29e0Ih4OTlehERFRVFSUoIgCMybNw+VKnjC85xOJ1dffTXXXnst3/zmN+U2R2EMoQiQQaDX6/nXv/7F7NmzWbFiBZdddpncJvmJiIhg8eLFbN68GYvFQkdHxzkvPo4nIiKCqVOnUlhYSFNTEzU1NRw6dIiUlBSysrJISEhQXMojhNPpxGQyUVNTg9lsJi0tjblz5yqep5PgEyHFxcVERkaiVqtZsGBB0GWW/PKXv8TlcvHUU0/JbYrCGCO4PulBTH5+Pq+++io33HADu3fvJjMzU26T/ERGRpKVlcWRI0fIzMwMmrThYEOtVpORkUFGRgY9PT3U1NSwe/duXC4XSUlJpKSkkJycrHhGhkhPTw8mk4nm5mba29uJiooiMzOT+fPnK96OM5CVlUV1dTVms5mFCxcGnfj4+OOPee2119i+fTsGg0FucxTGGMH1aQ9yvvvd77J27Vq++93vUlRUFDQHi6qqKqqrq5k9ezb79++nrKyMSZMmKVecpyEiIoLJkydTWFiIxWKhubmZqqoqdu/eTWxsLCkpKaSkpARNu/NgQpIkOjo6MJlMmEwmrFYrCQkJpKWlMXPmTMLCwuQ2MSTwxXzo9XqysrIoLS0NKu9lfX09119/Pa+88goTJkyQ2xyFMUhwnEFDiOeff5558+bxwAMP8Oijj8ptzgkBp9HR0RQXFyNJ0oDAVIWTIwgCMTExxMTEUFBQgM1mo7m5GZPJxKFDhzAajX4xEhcXF1Rr84HE7XbT0tLi93QAJCcnM2nSJBITEwddFE/Bi9vtZuvWrQiC4F92UavVI9Y7ZiTs++53v8sVV1zBNddcI6stCmMXRYAMkbCwMN555x0WLFjA7NmzufLKK2Wz5WTZLpGRkSxevJji4mJcLhfTpk07Z0+aw8FoNPpTd91uN62trZhMJrZv344oiiQmJhITE0N0dDQxMTFjcolBkiRsNhtmsxmLxUJnZyft7e2EhYWRkpLCvHnziIuLU8TtMHE4HGzduhWtVsu8efP8ntSRbmB3Ntx1111YLBb++Mc/ymaDwthHESDDoLCwkL///e98//vfZ/z48UyfPj3gNpwu1TYiIoKlS5eyZcsWSktLmTNnjhJkOQw0Gg2pqamkpqYiSRKdnZ20tbXR2dnJ0aNHsVqthIWF+cWI7xZKoqS/2PDdLBYLLpeLyMhIoqOjSUlJYdq0aURERMhtbshjtVopLi4mOjqaWbNmnfC9DAYR8tprr/HPf/6T0tJSZTlNYVRRBMgw+cY3vsF9993HZZddRmlpKUlJSQGbezB1PoxGI0uWLKGkpITi4mIlIPAsEQSBuLi4Aa+30+n0n7DNZjM1NTVYrVaMRqNfjERFRWEwGDAYDOj1etm8BqIoYrfbsdvt2Gw2v839xUZMTAypqalMnDiR6OhoRbSOMBaLhS1btpCWlsbUqVNP+VmQU4Rs3LiRO++8k//+97+MGzcuYPMqnJsoAuQs+NWvfsW+ffv41re+xZo1awJygh9KkTGdTsfChQvZsWMHmzZtYuHChUpF0BFEp9P5a434cDqdA07u9fX12O12XC4XgiCg1+vR6/V+UdJfnPh+V6vVCILgv/VfQpMkCY/HgyRJSJKEKIq43W7sdjsOhwObzYbD4fCLDd92p9MJeFPKjUYjUVFRpKamMmnSJKKiohSxMcq0tbVRUlJCfn4++fn5ZxSicoiQmpoarrzySp555hlWrFgx6vMpKAiS0rnrrLBarSxdupTZs2fz6quvjuoV7nArnIqiyJ49e/zNvpTMjsDj8XhOEAY+cdD/vk8oDAWfsDmdqJHbA3Mu09jYyM6dO5k6dSrZ2dlDemygqhr39vayePFiFi1axEsvvTRq84wVurq6iI6O5uWdczFGnP11vK3HzS2zSrFYLOdUhWDFA3KWhIWF8cEHHzB37lymT5/ObbfdNirznM2BSKVSMWPGDMrKyti0aRPz5s0jPj5+VOxUODlqtZqwsLAzrqmLouj3bPT3crhcLtatW8eqVavQ6XR+z0j/nwrBhSRJVFdXc/DgQWbPnk1qauqQxwiEJ0QURa6//npiY2N5/vnnR3x8BYVToQiQESAzM5P333+f888/n0mTJrFq1aoRHX8kroIEQaCwsBCj0ciWLVuGdTWmMPr4lluOXxLxZUoYDAYl5TUEEEWRvXv3YjKZWLRo0VkJh9EWIb/73e/YuXMn27ZtUz5bCgFFyc8cIRYuXMgLL7zAVVddxaFDh0Zs3JF2wY4bN4758+dz8OBB9u7diyiKI2ClgoKCD4fDQXFxMWazmWXLlo3I9zY3N5dJkyaxZcsWOjo6RsBKL2+//TZPP/00H374IQkJCSM2roLCYFAEyAhyww03cMstt3DhhRfS0NBw1uON1vpvYmIiy5Yto62tja1btw4r7kBBQeFELBYL69evR6/Xs2TJkhFNYx1pEbJmzRpuvPFG3n77baZMmTICFiooDA1FgIwwv/3tb7ngggu46KKL6OzsHPY4ox18Fh4eztKlS1Gr1WzYsIGurq4Rn0NB4VyisbGRjRs3kp2dzZw5c0alVcNIiZCdO3dy5ZVX8sorr3DxxRePoIUKCoNHESAjjCAIvPLKK+Tm5nLZZZdhs9mGPEagIt99lRjT09PZuHEjTU1NozaXgsJYRZIkDh06xK5du5g9ezYFBQWjGhR8tiKkoqKCiy++mAceeIBrr712FCxUUBgcigAZBTQaDf/6178AuPrqq3G73YN+bKDEhw9BEJg0aRIzZsxg586d7N+/X4kLUVAYJHa7neLiYurr61m6dOmwMl2Gw3BFiMlk4sILL+S6667j7rvvHkULFRTOjCJARgmj0ciHH35IZWUlt9xyC4MptxJo8dGf9PR0li9fTltbGxs3bqS3tzeg8ysohBotLS0UFRVhMBhYvnx5wOs3DFWEdHV1cfHFF7N48WKeeOKJAFiooHB6FAEyisTGxvL555/zxRdf8MADD5x2XznFhw9fD5nY2FiKiopobGyUxQ4FhWBGFEXKysrYtm0bkyZNYtasWbKlrw5WhDgcDi6//HJSU1P5y1/+ojSoVAgKlDogo0x6ejqff/45S5YsITExkTvuuOOEfYJBfPhQq9VMmzaNhIQEdu/eTWtrK1OmTFFKdSsoADabje3bt+NyuVi2bFlQVK08U50Qt9vN97//fXp7e/noo4+UWh8KQYMiQALAxIkT+eSTT7jgggvQ6XT8+Mc/9v8tmMRHf9LS0oiJiWH79u1s2LCB2bNnB8XBVkFBLpqamti9ezcpKSlMnTp1VLJchsupRIjH4+H666+nrKyMoqIiwsPD5TRTQWEAih8uQMybN49PP/2Ue++9l9dffx0IXvHhIywsjCVLlpCcnMyGDRsoLy9XAlQVzjmcTic7duxg165dTJ06lZkzZwaV+PBx/HKMx+PhhhtuYNeuXXz11VdKobExRkNDA9///veJj4/HaDQydepUtm/ffsr9i4qKBjS59N1MJlMArR5I8H2LxjCLFi3iv//9L5dccgkdHR1Mnjw5aMWHD5VKRWFhISkpKezatYumpiZmzpypeEMUzgmamprYs2cPsbGxrFq1CoPBILdJp8XnCdm8eTP/+te/2LFjB0VFRSQnJ8tsmcJI0tnZyeLFi1m5ciWffvopiYmJHDlyhNjY2DM+9vDhwwOO3/27eQcaRYAEmKVLl/LRRx9x6aWX8thjj/G1r31NbpMGRVxcHCtWrODQoUNs2LCBCRMmMH78eCWYTWFM4nQ62bdvH83NzUyZMoXMzMyQafiXnZ3NL3/5S7Zv387GjRtJSUmR2ySFEeaJJ54gMzOTN954w79t3Lhxg3psUlISMTExo2TZ0FDOHjKwYsUKPv74Y371q1/x2muvyW3OoFGr1UyePJlFixZRV1fHxo0blQqqCmMOk8nE2rVrcblcrFy5kqysrJARHx6PhxtvvJHdu3ezYcMG0tLS5DZJYQh0dXUNuDkcjpPu9+GHHzJnzhyuuuoqkpKSmDlz5qDPJTNmzCA1NZULLriAzZs3j6T5Q0YRIDKxYsUKPvnkE+6++25efvlluc0ZEj5vSEJCAhs2bKCsrGxIxdYUFIIRm81GaWkpO3bsoLCwkPnz52M0GuU2a9C43W6uu+46SktLKSoqIj09XW6TFIZIZmYm0dHR/ttjjz120v2qqqp4+eWXyc/P5/PPP+eWW27hjjvu4M033zzl2Kmpqbzyyiv85z//4T//+Q+ZmZmsWLGCnTt3jtbTOSOCNJgKWQqjRnFxMRdffDEPPfQQP/vZz+Q2Z8h0dnayd+9enE4nU6ZMISUlJWSuFkMJl8vFJ598wiWXXKKkUY4woihSWVnJ4cOHSU1NZfLkyUEf63E8DoeDa6+9loMHD/LVV18pMR+jTFdXF9HR0by8cy7GiLOPZLD1uLllVil1dXUD4jP0ej16vf6E/XU6HXPmzKG4uNi/7Y477qC0tJQtW7YMet7ly5eTlZXF3//+97N7AsNEiQGRmUWLFrFmzRouueQSWlpaePTRR0PqBB4bG8uyZcuora1l9+7dxMbGMmXKFCIiIuQ2TUHhjLS2trJ3714EQWDBggUhmSnS3d3NFVdcgcViYd26dSQmJsptksIwiYqKGlSAf2pqKoWFhQO2TZo0if/85z9Dmm/evHls2rRpSI8ZSRQBEgTMnTuXTZs2ceGFF9Lc3Myf//znoEzzOxWCIJCdnU1qaqq/3kBeXh75+fkh9TwUzh1sNhv79++npaWFiRMnMm7cuJAMqG5ubuaSSy4hISGBdevWKcL/HGHx4sUcPnx4wLby8nKys7OHNM7u3bsD1r/oZITeN26MUlBQQHFxMdu3b+eKK67AarXKbdKQ0el0TJ8+ncWLF9PS0sLatWupr68fVB8cBYVA4Ha7OXz4MF999RUqlYrzzjuPvLy8kBQfVVVVLF68mIkTJ/LRRx8p4uMc4mc/+xlbt27l0UcfpaKign/+85/8+c9/5rbbbvPv88tf/pLrrrvOf/+5557j//7v/6ioqGD//v3ceeedrF27dsBjAk3ofevGMGlpaWzYsAGLxcL5558/rFbbwYBvWaagoIADBw6wfv16WlpaFCGiIBuiKFJdXc2aNWtobm5m4cKFzJ49O+RiPXzs2rWLRYsW8fWvf52///3v6HQ6uU1SCCBz587l/fff5//9v//HlClT+O1vf8tzzz3H9773Pf8+TU1N1NbW+u87nU7uvvtupk6dyvLly9mzZw9r1qzhvPPOk+MpAEoQalBis9m45pprOHz4MJ9//jmZmZlymzRsPB4P1dXVlJeXEx0dTWFh4aCK5SgMRAlCHR6SJNHQ0MChQ4cQBIFJkyaRmpoaUnFWx7Nu3Touv/xyfv3rX3PPPfeE9HMJVUYrCNVisZxTRR4VD8hpaG1t5ZZbbiErKwu9Xk9KSgoXXnghmzdv5uqrr+aiiy4asP9nn32GIAg89NBDA7Y/9NBDZGVlDXpeo9HIu+++y9KlS1m0aBEHDx4ciacjC2q1mvHjx3PBBRcQGxvL5s2b2bZtG93d3XKbpjCGkSSJlpYW1q9fz4EDB8jPz2flypWkpaWF9An73Xff5dJLL+X555/n3nvvHfZzOd2xDSAnJ+ekZbsff/zxkXw6Ic/VEe1cG9l21rerI9rlfiqyoEQInoYrr7wSp9PJm2++SW5uLs3NzXz11Ve0t7ezcuVKfv7zn+N2u/2BluvWrSMzM5OioqIB46xbt46VK1cOaW61Ws0rr7zCQw89xOLFi/nXv/7FhRdeOFJPLeBotVoKCwvJzc3l8OHD/joF+fn5REZGym2ewhhBkiRaW1s5cuQIFouFCRMmMG7cuHlRUAAAGH9JREFUuJDv5ixJEo8//jiPPvoo77zzzllXUD7dsc3HI488ws033zzgccp3VWEkUQTIKTCbzWzcuJGioiKWL18OeEscz5s3D/BGHPf09LB9+3YWLFgAeJv93Hfffdx9993Y7XYMBgN2u52SkhJuuOGGIdsgCAIPP/wwEyZM4Morr+SRRx7hZz/7WUhfwRkMBqZPn05eXh5Hjhzx96nIz89XlmYUho0kSTQ1NXHkyBGsViu5ubnMmzdvTCxXWa1WfvCDH1BcXMzGjRuZMWPGWY13pmObj8jISKWMu8KooizBnIKIiAgiIiL44IMPTloOd8KECaSlpbFu3TrAm4u/c+dOrrrqKnJycvzFYIqLi3E4HEP2gPTne9/7HuvWreOZZ57hhhtuwG63D3usYCEiIoKZM2dy/vnnYzQa2bx5M8XFxbS2tirBqgqDRhRFamtrWbt2Lfv27SMjI4MLLriAgoKCMSE+6uvrWbZsGXV1dZSWlp61+IAzH9sUFAKFIkBOgUaj4W9/+xtvvvkmMTExLF68mF/96lfs3bvXv8/KlSv9yy0bN25kwoQJJCYmsmzZMv/2oqIixo0bN+T87OOZO3cupaWllJWVsXLlSpqams5qvGDB10b6ggsuIC4ujtLSUjZs2EBTU5MiRBROidvtprKykjVr1lBeXu6PM8rLyxsztWe2bNnCnDlzmDFjBmvXrh2xrqWDObYB/OIXv/CLFd9t48aNI2KDggIoAuS0XHnllTQ2NvLhhx9y0UUXUVRUxKxZs/jb3/4GePu5bN68GZfLRVFREStWrAC85W37C5Cz8X70Jy0tjfXr15Ofn8/cuXPZvn37iIwbDOj1eiZOnMgFF1xAeno6e/fuZc2aNVRUVOB0OuU2TyFI6OnpYd++fXz++efU1dUxefJkzjvvPLKzs0OylsepePPNNzn//PP59a9/zWuvvTbiabZnOrYB3HPPPezevXvAbc6cOSNqh8K5jZKGO0RuuukmvvzyS2pqaqisrGT8+PFs3ryZn/70p9xzzz18+9vfpqGhgby8PBobG0lNTeWvf/3rgPzss0WSJJ555hkeeughXn/9da6++uoRGztYEEWRpqYmqqurMZvNZGRkkJOTEzRtpAPNuZyGK0kSzc3NVFdX09bWRmpqKrm5ucTGxoZ0PNTJcLvd/OIXv+CNN97gnXfe4fzzzw/Y3P2PbTk5Odx5553ceeedAZs/lPCl4XaW5xIVefYBzl3dHmInVJ1zabhjw1cZQAoLC/nggw8AyMvLIzMzkw8//JDdu3f7A7rS09NJT0/nmWeewel0jpgHxIcgCPz85z+nsLCQa665hm3btvH444+PqWJEKpXK/zpaLBaqq6vZtGkTkZGR5OTkkJ6ePmZc7Qonx2azUVtbS01NDZIkkZOTw8yZM0O2eNiZMJlMfP/736exsZFt27Yxfvz4gM7f/9imoBAIlCP4KWhvb+eqq67ixhtvZNq0aURGRrJ9+3aefPJJvvGNb/j3W7lyJS+99BLjx48f0IFy+fLl/OlPf/IHq44Gl1xyCaWlpXznO99h8eLFvP322+Tm5o7KXHISHR3NjBkzmDx5MvX19VRVVbFv3z5SU1PJzMwkISFhTLnfz2VcLhdNTU3U19fT1tZGUlIS06ZNIykpaUy/x19++SXf//73ueCCC3j//fdHNd11sMe27u5uTCbTgMeGhYWdU1foCqOLIkBOQUREBPPnz+cPf/gDlZWVuFwuMjMzufnmm/nVr37l32/lypX87//+rz/+w8fy5ct54403uOaaa0bVzvz8fLZs2cI999zDrFmzeO2117jqqqtGdU650Gq1jBs3jpycHCwWC/X19ezcuRPwep0yMjKIiYkZc275sY4oirS0tFBfX4/JZCI8PJyMjAxmzpyJ0WiU27xRxe128+CDD/L888/zpz/9idWrV4/653ewx7YHHniABx54YMBjf/SjH/HKK6+Mqn0K5w5KDMgY4v333+fGG2/k6quv5tlnnx3zB2/wxge0tbVRV1dHU1MTBoOBjIwM0tLSxlTRpLEWAyJJEh0dHTQ0NNDQ0IBarSY9PZ3MzMxz5gq7rq6Oa665hs7OTt5++20mT54st0kKg0SJARkZFA/IGOKKK65g5syZXH311SxYsIC3336biRMnym3WqCIIAomJiSQmJuLxeDCZTNTX11NeXo7RaCQ1NZXk5GTi4uLGtAs/FHC73bS0tGAymWhubkaSJNLS0pg7dy7x8fHnlOfqo48+YvXq1Xzzm9/k+eefJywsTG6TFBQCjiJAxhg5OTls3LiRX//618ydO5cXX3yRa6+99pw4uPuuotPT0/0nu+bmZkpLS5EkieTkZFJSUkhKShoTXoRQwGazYTKZMJlMtLW1ERYWRkpKCvPmzSM2NvacE4VOp5Nf/vKXvPbaa7zyyiujvkSroBDMKAJkDKLVannyySdZuXIl1113HR9++CEvvfTSiBUyCgU0Gg1paWmkpaUhSRKdnZ2YTCYOHz7Mjh07iIuLIyEhgYSEBGJjY0O+V0iw4HQ6aW9vp62tjba2Nrq7u4mLiyMlJYWpU6cSEREht4mysXPnTlavXo1Go2HHjh3k5+fLbZKCgqwoAmQMc/HFF3PgwAFuvfVWJk+ezIsvvsi3v/1tuc0KOIIgEBcXR1xcHIWFhfT29tLa2kp7eztHjx7F5XIRFxdHfHy8IkiGyPGCo6uri8jISOLj4/2VgcdSevhwcDqd/P73v+epp57i3nvv5Ve/+tU5/5ooKIAiQMY8SUlJ/Pvf/+add97h1ltv5d///jcvvvjiOeUNOZ7w8HDCw8PJyclBkiR6e3tpa2sbIEiio6OJiYnx3yIiIs655YLjcbvddHV1YTab/bfu7u4BgiM+Pn7M1ukYDrt372b16tVIksTmzZuZOXOm3CYpKAQNigA5BxAEge985zusWLHC7w156aWXxmy67lAQBMHf56K/IOns7MRsNlNTU8PevXuRJIno6Gi/MImKiiIiImJMxpJIkoTD4aCnpweLxYLZbMZisdDd3Y1er/e/BqmpqcTGxiqC4yT093rcc889/PrXv1a8HgoKx6EIkHOI5ORk3n33Xd5++21uueUWvzckMTFRbtOChv6CJDMzE/CekHt6evxX/XV1dXR1deFyudDr9URERBAeHu5/nM/DEuzLOC6Xi97eXnp6eujp6Rnwu9vtxmAw+EVXWloaMTExGAyGcyKg+WzweT1EUVS8HgoKp0ERIOcYgiBw9dVXs3LlSm655RYmT57M008/fc5kygwHQRCIjIwkMjLSL0rAe5XrO2H7BEp9fT29vb14PB60Wi0GgwGDwYBer/f/7ruv1WrRaDSo1Wr/z+G+B5Ik4Xa7/TePx4PL5cJut/tvDodjwH2fjf27naakpPhFlFLqfmj09vby6KOP8oc//IGf//zn3H///YrXQ0HhNCiFyM5hJEni3Xff5Wc/+xnjxo3jhRdeYPr06XKbFfL4ljBOdeJ3OBw4HA5cLhcejwdRFP2P1Wg0/psgCP6bJEn+AE/ffVEUBwgOH2q1GrVa7RdAJxM/vt+VE+TZI0kS77//Pj/72c9IS0vjpZdeUrweYxylENnIoFzinMMIgsBVV13FxRdfzO9+9zsWLFjAD3/4Qx5++OFztuvsSCAIgv8EPxj6C4n+N0mS/De3283OnTuZMGGCX5yoVKoBgsXnRTnXg2UDSXl5OXfccQc7duzgySef5Prrr1defwWFQaJ8UxSIiIjg8ccfZ9euXRw8eJCCggL+93//F8U5FhhUKhU6nc7f6CsuLo6kpCR/4bTU1FRSUlIA/NuSk5NJTEwkNjaWyMhIjEYjWq1WOfkFiN7eXn79618zY8YMxo8fT3l5OTfccIPy+isoDAHl26LgZ+LEiXzxxRe8+OKL/PrXv2bp0qXs2bNHbrMUFIIGSZJ47733mDRpEuvWrWPz5s288MILxMbGym2agkLIoQgQhQEIgsC3vvUtysrKWLp0KQsXLuTWW289oS23gsK5xq5du7jwwgv58Y9/zCOPPMKmTZuUWA8FhbNAESAKJyUiIoLHHnuM3bt309zczPjx47n//vuxWCxym6agEFAqKir47ne/y+LFi5kxYwaHDx9m9erVynKLgsJZonyDFE7LhAkT+M9//sNXX33F5s2byc3N5ZlnnsFut8ttmoLCqGIymbjtttuYOnUq4eHhlJeX8+STTyrLLQoKI4QiQBQGxfz581m7di3/+Mc/+Pvf/86ECRN44403BqR/KiiMBSwWC/fffz/jx4+nqamJnTt38vrrr5ORkSG3aQoKYwpFgCgMGkEQuOiii9i5cyePP/44v/3tb5k2bRoffPCBkjGjEPLY7XaeffZZ8vLy2LRpE2vWrPEHnCooKIw8igBRGDIqlYprrrmGQ4cOccstt/CjH/2ImTNn8q9//UvxiCiEHF1dXTzxxBPk5OTwv//7v/z9739n3bp1LFiwQG7TFBTGNIoAURg2Op2O22+/naNHj3LzzTdz3333UVBQwJ///GccDofc5ikonJbW1lbuv/9+srKy+PDDD3n99dfZtWsXF198sdKWQEEhACgCROGsMRqN3HbbbRw5coQHH3yQ559/nnHjxvHMM8/Q3d0tt3kKCgOora3ljjvuIDs7m+3bt/Phhx+yadMmLr30UkV4KCgEEEWAKIwYWq2Wa6+9ln379vHyyy/zzjvvkJ2dzYMPPkh7e7vc5imc45SVlbF69WomTJiAyWRi06ZNfPbZZyxbtkwRHgoKMqAIEIURR6VS8Y1vfIOtW7fy7rvvUlxcTFZWFj/84Q/Zu3ev3OYpnEOIosinn37K1772NWbOnIlGo2Hv3r288847zJo1S27zFBTOaRQBojBqCILAqlWr+PLLL9m8eTOSJLFgwQKWL1/Ou+++i8vlkttEhTGKxWLhueeeo6CggBtvvJG5c+dSVVXF66+/zoQJE+Q2T0FBAUWAKASIGTNm8Nprr1FfX8/Xv/517rnnHrKzs3nggQeora2V2zyFMYAkSZSWlvKDH/yAtLQ03nnnHR555BFqamp46KGHSEtLk9tEBQWFfigCRCGgxMXF8fOf/5yKigr+8pe/sGfPHsaPH8+ll17KRx99pHhFFIaMxWLhz3/+M7Nnz2bVqlXo9XqKi4spLi7mu/+/vfsLaar/4wD+ditdsWle6Jxt1USLQsucFboig0J7wgWF1HNTERZaFOlFpRV1EUFBBF1UVFBBdVEZuSwDsSYmSqlBfyw3nZatTUKs+Td187mIzu+3J/39qtk5094vODC/7px9zubOefs953zP338jODhY6hKJaAQMICQJuVyO1atXo7i4GM3NzUhOTsaOHTsQHR2NXbt2oaamhoOb0agGBgZQXFyMrKwsqNVqnD9/Hjk5Ofjw4QPOnDmDBQsWSF0iEf0fDCAkOZ1OhyNHjuDt27e4efMm+vv7kZGRgbi4OBw+fBhWq1XqEikAeL1ePH78GDk5OYiKisKePXswZ84cPHv2DLW1tdi+fTtUKpXUZRLRD2IAoYAhk8mQlpaGCxcuwOVy4fjx43jx4gUSEhKwePFinD59Gu3t7VKXSSJraGjAgQMHEBMTA5PJhKCgINy9exd2ux1Hjx7lUOlE4xQDCAUkhUKB9evX4/bt23A6ncjOzkZRURG0Wi2WL1+OkydPwmazSV0m/QYejwfV1dUoKChAfHw8kpKSYLPZcPr0abhcLpw9exZGo5FjdxCNc0HDPNBO40hbWxtKSkpgNpvx8OFD6PV6mEwmZGZmIiUlBZMmTZK6xN9icHAQ9+/fx19//YXJkydLXc6Y6+npQVlZGcxmM0pKSjA0NIQ1a9YgMzMTGRkZCA0NlbpEIoHb7UZYWBg6rTEIVcn9X16XB+Gz7fj8+fMf9bc+MbfWNGHpdDrk5uYiNzcXXV1dwk5r3bp1GB4eFnZaq1atQlhYmNTl0v/Q1taG+/fvw2w2o7y8HDNmzIDJZMKtW7eQmpo6YcMkEX3FHhCaEDweD2pqanD37l2YzWY0NjYiKSkJaWlpSEtLw9KlS8d1IJkIPSDv379HRUUFHj16BIvFgtbWVqSmpiIzMxMmkwlz5syRukSiH8IekLHBAEITksPhQEVFBSwWCywWC5qbm30CybJly8bVF308BhCHwyG8/xaLBS0tLTAYDMJnYDQax9VnQPQNA8jYYAChP8K/A4ndbkdiYiKSk5NhMBhgMBgQHx8fsINWBXoAcbvdePbsGerq6lBXV4cnT57Abrf7BI6lS5f+URtXmrgYQMYGAwj9kRwOByorK4UdZn19Pfr6+pCQkACDwYCkpCQYDAYkJCQgJCRE6nIDKoB8/vwZ9fX1wvtWV1cHm82G6OhoIcwtWrSIPRw0YTGAjA0GECJ8vY9Ic3OzEEi+7Vx7enowe/bsEaeIiAjRLgUVO4B4vV60tbXBarX6TI2NjWhpaYFWqxXCxrdJrVb/9rqIAkEgBBCHw4F9+/ahtLQUvb29iI2NxaVLl5CcnDzqPBaLBfn5+Xj16hV0Oh0OHjyILVu2+F3/r+Jp5kT4eufe2NhYxMbGYsOGDQC+hhK73Y7Xr18LO+CrV6/CarXC4XAgLCxMCCNxcXHQarXQaDTCFBERAbnc/43T7zAwMACXywWn04kPHz7A6XTi3bt3sNlssFqtsNlsGBoagl6vF9bRZDIhLi4O8+fPR2RkpNSrQPTH6uzshNFoxIoVK1BaWoqIiAjYbDaEh4ePOk9LSwvWrFmDnJwcXLt2DeXl5cjOzoZGo0F6erqI1f8He0CIfkF3dzeampqEYGKz2eBwOOB0OuF0OtHZ2Qm5XA61Wu0TStRqNVQqFZRKJVQqlc/j/24LCQmBXC6HTCaDTCaDx+PBvXv3kJGRAblcDq/XC4/Hg76+PnR1daGrqwvd3d0jPna73ULY+BY4Ojo6EBQUhMjISERHR0Oj0UCr1fr08Oj1+oA9J4ZISlL3gOzfvx9VVVWorKz84dfYt28f7t27h5cvXwptGzduxKdPn/DgwYNfqttf7AEh+gVKpRKJiYlITEwc8ff9/f1wuVxC78K3yeVyoampySck/Ds4/CyZTCYEl5ECTWhoKPR6PVJTU4WwodFoEBkZybE2iPzg7vKO6XLcbrdPe0hIyIjnoJnNZqSnpyMrKwsVFRWYPn06duzYgW3bto36GtXV1Vi5cqVPW3p6Ovbs2eP/Cvwibn2IfgOFQoFZs2Zh1qxZPzWf1+tFb28vvnz5Aq/XK0wej0foDfk2BQUFYerUqVAoFByWnEhEwcHBiIqKwkxD65gtU6lUQqfT+bQdPnwYR44c+e65drsdZ8+eRX5+PgoLC/H06VPs3r0bwcHB2Lx584jLd7lc352npVar4Xa70dfXhylTpozZuvwoBhCiACKTyaBUKqFUKqUuhYhGoVAo0NLSgoGBgTFb5vDw8Hf/SIx2BZ7X60VycjKOHTsGAFi4cCFevnyJc+fOjRpAAhEDCBER0U9SKBRQKBSSvLZGo8G8efN82ubOnYuioqJR54mKivrubuLt7e0IDQ2VpPcD4N1wiYiIxhWj0YjGxkafNqvVipkzZ446T0pKCsrLy33aysrKkJKS8ltq/BEMIERERONIXl4eampqcOzYMTQ1NeH69es4f/48du7cKTynoKAAmzZtEn7OycmB3W7H3r178ebNG5w5cwY3btxAXl6eFKsAgJfhEhERjTslJSUoKCiAzWaDXq9Hfn6+z1UwW7ZsQWtrKywWi9BmsViQl5eHhoYGaLVaHDp0SNKByBhAiIiISHQ8BENERESiYwAhIiIi0TGAEBERkegYQIiIiEh0DCBEREQkOgYQIiIiEh0DCBEREYmOAYQogH38+BG5ubmYMWMGQkJCEBUVhfT0dFRVVUldGhGRX3gzOqIAtn79egwMDODKlSuIiYlBe3s7ysvL0dHRIXVpRER+4UioRAHq06dPCA8Ph8ViwfLly6Uuh4hoTPEQDFGAUiqVUCqVuHPnDr58+SJ1OUREY4oBhChATZo0CZcvX8aVK1cwbdo0GI1GFBYW4vnz51KXRkTkNx6CIQpw/f39qKysRE1NDUpLS/HkyRNcvHhR0rtYEhH5iwGEaJzJzs5GWVkZ3r59K3UpRES/jIdgiMaZefPmoaenR+oyiIj8wstwiQJUR0cHsrKysHXrVsyfPx8qlQq1tbU4ceIE1q5dK3V5RER+YQAhClBKpRJLlizBqVOn0NzcjMHBQeh0Omzbtg2FhYVSl0dE5BeeA0JERESi4zkgREREJDoGECIiIhIdAwgRERGJjgGEiIiIRMcAQkRERKJjACEiIiLRMYAQERGR6BhAiIiISHQMIERERCQ6BhAiIiISHQMIERERie4fb+55v72A904AAAAASUVORK5CYII=\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 2 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# For upsampling, the upsample method is available which can\\n\",\n    \"# interpolate the data via linear or nearest-neighbor interpolation\\n\",\n    \"wind_rose_resampled = wind_rose.upsample(wd_step=2.5, ws_step=0.5)\\n\",\n    \"wind_rose_resampled.plot()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Plotting\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"There are several plotting methods available to help visualize wind data objects\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 14,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 2 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 2 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"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awMAADDN6Ss3u3btUrt27ezbK1as0J49exQQECBJGjp0qLp27aqXXnrJ9VUCAAA4yekrNyNGjND48eOVn58vSWrcuLHmzJmjjIwM/ec//9H8+fPVrFkztxUKAADgDKfDzfbt2xUeHq7rrrtO69at0+LFi/XFF1+oQ4cOuvnmm/XDDz8oMTHRnbUCAABcktO3pSpXrqwpU6YoNjZWI0eOVNWqVfXyyy8rIiLCnfUBAACYYvqB4saNG+ujjz5S//791blzZ73yyivuqAsAAKBcnA43p06d0uTJk9WvXz9NnTpV/fv31/bt27Vz507ddNNN+s9//uPOOgEAAJzidLgZMmSItm/frttvv10ZGRkaOXKkateuraVLl2rmzJn629/+pilTprizVgAAgEty+pmbLVu26IsvvlDTpk01fPhwNW3a1L7v1ltv1eeff64ZM2a4pUgAAABnOX3l5qqrrtLChQv1zTffaMGCBSV++dvf31+zZs1yeYEAAABmOB1uFi9erC1btig6OlqJiYmaP3++O+sCAAAoF6dvS1177bXatWuXO2sBAACoMKeu3BiG4e46AAAAXMKpcNOqVSstX75cZ8+eLXPe/v37NXLkSD399NMuKQ4AAMAsp25LvfTSS5oyZYpGjRqlHj16qF27doqIiJC/v79Onjypffv2adu2bfrqq680ZswYjRw50t11AwAAXJRT4ebWW2/Vrl27tG3bNq1YsUJvv/22vvvuO505c0YhISGKjo7W4MGDNWjQINWsWdPdNQMAAJTK1M8vdOrUSS+99JJ2796tkydPqqCgQD/88IPWrVunMWPGlCvYHD58WPfdd59q166tgIAAtWnTpswHl7OzszVw4EA1a9ZMlSpV0vjx402fEwAAWJfp35ZypZMnT6pjx47y8fHR+vXrtW/fPs2ZM6fMkFRYWKjQ0FBNnTpVbdu29WC1AADgSuD0R8Hd4ZlnnlFkZKSWLFliH2vUqFGZxzRs2FAvvPCCpF+/ewcAAOD3vBpu1q5dq169eik2NlYpKSmqV6+eRo0apeHDh7vsHIWFhSosLLRv5+bmSpKKiopUVFTksvNcWPP3/wn3oM+eQZ89gz57Dr32DHf12cx6NsOLX2Lj7+8vSZo4caJiY2O1c+dOjRs3TgsWLNCQIUMueXzXrl117bXXat68eaXOiY+PV0JCQonxxMREBQYGlrt2AADgOfn5+Ro4cKBycnIUFBRU5lyvhhtfX1+1a9dOqamp9rGxY8dq586dSktLu+TxzoSbi125iYyM1PHjxy/ZHLOKioq0adMm9ejRQz4+Pi5dG7+hz55Bnz2DPnsOvfYMd/U5NzdXISEhToUb07elunTpomHDhik2NlYBAQHlLlKSwsPD1bJlS4exq6++WitXrqzQur/n5+cnPz+/EuM+Pj5ue3O7c238hj57Bn32DPrsOfTaM1zdZzNrmf60VHR0tCZNmqSwsDANHz5c6enpZpew69ixozIyMhzGvvnmmxK/OA4AAOAs0+Fm3rx5+vHHH7VkyRIdO3ZMnTt3VsuWLfXcc8/p6NGjptaaMGGC0tPTNWvWLB04cECJiYlauHChRo8ebZ8TFxenwYMHOxy3e/du7d69W3l5efrpp5+0e/du7du3z+xLAQAAFlSu77mpUqWK7rrrLq1Zs0Y//PCDBg4cqGnTpikyMlJ33nmntmzZ4tQ6N9xwg1avXq1ly5apdevWevLJJzVv3jwNGjTIPic7O1tZWVkOx0VHRys6OlqfffaZEhMTFR0drdtuu608LwUAAFhMhT4KvmPHDi1ZskTLly9XnTp1NHToUB0+fFh9+/bVqFGj9Nxzz11yjb59+6pv376l7l+6dGmJMX6lHAAAlMZ0uDl27JjefPNNLVmyRPv371e/fv20bNky9erVSzabTZI0dOhQ9e7d26lwAwAA4Eqmw039+vXVpEkT/f3vf9fQoUMVGhpaYs4111yjG264wSUFAgAAmGE63GzevFk333xzmXOCgoKUlJRU7qIAAADKy/QDxdOnT9epU6dKjOfm5uqWW25xRU0AAADlZjrcpKSk6OzZsyXGCwoKtHXrVpcUBQAAUF5O35b68ssvJf36SaV9+/bpyJEj9n3nz5/Xhg0bVK9ePddXCAAAYILT4ebaa6+VzWaTzWa76O2ngIAAvfTSSy4tDgAAwCynw82hQ4dkGIYaN26sHTt2OHxKytfXV3Xq1FHlypXdUiQAAICznA43F37vqbi42G3FAAAAVJRT4Wbt2rXq06ePfHx8tHbt2jLn/uUvf3FJYQAAAOXhVLi58847deTIEdWpU0d33nlnqfNsNpvOnz/vqtoAAABMcyrc/P5WFLelAADA5axcvwr+Rxf7Uj8AAABvMB1unnnmGa1YscK+HRsbq1q1aqlevXras2ePS4sDAAAwy3S4WbBggSIjIyVJmzZt0scff6wNGzaoT58+evTRR11eIAAAgBmmfzjzyJEj9nDz/vvv65577lHPnj3VsGFDtW/f3uUFAgAAmGH6yk3NmjX1/fffS5I2bNig7t27S/r1Zxn4pBQAAPA201du7rrrLg0cOFBXXXWVTpw4oT59+kiSvvjiCzVt2tTlBQIAAJhhOtzMnTtXDRs21Pfff69nn31W1apVkyRlZ2dr1KhRLi8QAADADNPhxsfHR5MmTSoxPmHCBJcUBAAAUBGmw40k7d+/X0lJSTp27FiJL/V74oknXFIYAABAeZgON4sWLdLIkSMVEhKisLAw2Ww2+z6bzUa4AQAAXmU63Dz11FOaOXOmpkyZ4o56AAAAKsT0R8FPnjyp2NhYd9QCAABQYabDTWxsrDZu3OiOWgAAACrM9G2ppk2batq0aUpPT1ebNm3k4+PjsH/s2LEuKw4AAMAs0+Fm4cKFqlatmlJSUpSSkuKwz2azEW4AAIBXmQ43hw4dckcdAAAALmH6mZsLzp49q4yMDJ07d86V9QAAAFSI6XCTn5+vYcOGKTAwUK1atVJWVpYk6eGHH9bTTz/t8gIBAADMMB1u4uLitGfPHiUnJ8vf398+3r17d61YscKlxQEAAJhl+pmb9957TytWrNBNN93k8O3ErVq1UmZmpkuLAwAAMMv0lZuffvpJderUKTF++vRph7ADAADgDabDTbt27fTBBx/Yty8Emtdee00xMTGuqwwAAKAcTN+WmjVrlvr06aN9+/bp3LlzeuGFF7Rv3z6lpqaW+N4bAAAATzN95aZTp07avXu3zp07pzZt2mjjxo2qU6eO0tLSdP3117ujRgAAAKeZvnIjSU2aNNGiRYtcXQsAAECFmb5yU7lyZR07dqzE+IkTJ1S5cmWXFAUAAFBepsONYRgXHS8sLJSvr2+FCwIAAKgIp29Lvfjii5J+/XTUa6+9pmrVqtn3nT9/Xp988olatGjh+goBAABMcDrczJ07V9KvV24WLFjgcAvK19dXDRs21IIFC1xfIQAAgAlOh5sLvwberVs3rVq1SjVr1nRbUQAAAOVl+tNSSUlJ7qgDAADAJUyHm/Pnz2vp0qXavHmzjh07puLiYof9W7ZscVlxAAAAZpkON+PGjdPSpUt1++23q3Xr1vyeFAAAuKyYDjfLly/XO++8o9tuu80lBRw+fFhTpkzR+vXrlZ+fr6ZNm2rJkiVq165dqcckJydr4sSJ+uqrrxQZGampU6dq6NChLqkHAABc2UyHG19fXzVt2tQlJz958qQ6duyobt26af369QoNDdX+/fvLfFj50KFDuv322zVixAi9/fbb2rx5s/7xj38oPDxcvXr1ckld5fX77/kp7fuAUHH02TPos2fQZ8+h155xOfTZZpg885w5c3Tw4EG9/PLLFb4l9dhjj+nTTz/V1q1bnT5mypQp+uCDD7R371772L333qtTp05pw4YNlzw+NzdXNWrUUE5OjoKCgspV98VcrBf8w+N69Nkz6LNn0GfPodee4c4+m/n3t+krN9u2bVNSUpLWr1+vVq1aycfHx2H/qlWrnF5r7dq16tWrl2JjY5WSkqJ69epp1KhRGj58eKnHpKWlqXv37g5jvXr10vjx4y86v7CwUIWFhfbt3NxcSVJRUZGKioqcrrUspX0zs81m09mzZ11yDtBnT6HPnkGfPYdee4a7+2zm39mmw01wcLD69+9v9rCLOnjwoObPn6+JEyfq8ccf186dOzV27Fj5+vpqyJAhFz3myJEjqlu3rsNY3bp1lZubqzNnziggIMBh3+zZs5WQkFBinY0bNyowMNAlr6MsH374odvPAfrsKfTZM+iz59Brz3BFn/Pz852ea/q2lCv5+vqqXbt2Sk1NtY+NHTtWO3fuVFpa2kWPadasmR544AHFxcXZxz788EPdfvvtys/PLxFuLnblJjIyUsePH3fZbamyflOL/1fgOvTZM+izZ9Bnz6HXnuHuPufm5iokJMQ9t6VcKTw8XC1btnQYu/rqq7Vy5cpSjwkLC9PRo0cdxo4ePaqgoKASwUaS/Pz85OfnV2Lcx8enxC218jIMg/u5HkCfPYM+ewZ99hx67Rnu7rOZf2c7HW6io6OdeoD4888/d/rkHTt2VEZGhsPYN998o6ioqFKPiYmJKXF5a9OmTYqJiXH6vO7wx/9S+YfGPeizZ9Bnz6DPnkOvPeNy6bPT4ebOO+90+cknTJigDh06aNasWbrnnnu0Y8cOLVy4UAsXLrTPiYuL0+HDh/XGG29IkkaMGKGXX35ZkydP1t///ndt2bJF77zzjj744AOX12fW2bNn9eGHH7rsO4BwcfTZM+izZ9Bnz6HXnnE59NnpcDN9+nSXn/yGG27Q6tWrFRcXpxkzZqhRo0aaN2+eBg0aZJ+TnZ2trKws+3ajRo30wQcfaMKECXrhhRdUv359vfbaa17/jhsAAHB58OozN5LUt29f9e3bt9T9S5cuLTHWtWtXffHFF26sCgAAXKkqebsAAAAAVyLcAAAASyHcAAAAS6lQuCkoKHBVHQAAAC5hOtwUFxfrySefVL169VStWjUdPHhQkjRt2jS9/vrrLi8QAADADNPh5qmnntLSpUv17LPPOnzVcuvWrfXaa6+5tDgAAACzTIebN954QwsXLtSgQYNUuXJl+3jbtm313//+16XFAQAAmGU63Bw+fFhNmzYtMV5cXGzq58gBAADcwXS4admypbZu3Vpi/N///reio6NdUhQAAEB5mf6G4ieeeEJDhgzR4cOHVVxcrFWrVikjI0NvvPGG3n//fXfUCAAA4DTTV27uuOMOrVu3Th9//LGqVq2qJ554Ql9//bXWrVunHj16uKNGAAAAp5Xrt6Vuvvlmbdq0ydW1AAAAVJjpKzc7d+7U9u3bS4xv375du3btcklRAAAA5WU63IwePVrff/99ifHDhw9r9OjRLikKAACgvEyHm3379um6664rMR4dHa19+/a5pCgAAIDyMh1u/Pz8dPTo0RLj2dnZqlKlXI/wAAAAuIzpcNOzZ0/FxcUpJyfHPnbq1Ck9/vjjfFoKAAB4nelLLc8995w6d+6sqKgo+5f27d69W3Xr1tWbb77p8gIBAADMMB1u6tWrpy+//FJvv/229uzZo4CAAD3wwAMaMGCAfHx83FEjAACA08r1kEzVqlX14IMPuroWAACACitXuNm/f7+SkpJ07NgxFRcXO+x74oknXFIYAABAeZgON4sWLdLIkSMVEhKisLAw2Ww2+z6bzUa4AQAAXmU63Dz11FOaOXOmpkyZ4o56AAAAKsT0R8FPnjyp2NhYd9QCAABQYabDTWxsrDZu3OiOWgAAACrM9G2ppk2batq0aUpPT1ebNm1KfPx77NixLisOAADALNPhZuHChapWrZpSUlKUkpLisM9msxFuAACAV5kON4cOHXJHHQAAAC5h+pmbC86ePauMjAydO3fOlfUAAABUiOlwk5+fr2HDhikwMFCtWrVSVlaWJOnhhx/W008/7fICAQAAzDAdbuLi4rRnzx4lJyfL39/fPt69e3etWLHCpcUBAACYZfqZm/fee08rVqzQTTfd5PDtxK1atVJmZqZLiwMAADDL9JWbn376SXXq1Ckxfvr0aYewAwAA4A2mw027du30wQcf2LcvBJrXXntNMTExrqsMAACgHEzflpo1a5b69Omjffv26dy5c3rhhRe0b98+paamlvjeGwAAAE8zfeWmU6dO2r17t86dO6c2bdpo48aNqlOnjtLS0nT99de7o0YAAACnmb5yI0lNmjTRokWLXF0LAABAhTkVbnJzc51eMCgoqNzFAAAAVJRT4SY4OPiSn4QyDEM2m03nz593SWEAAADl4VS4SUpKcncdAAAALuFUuOnSpYu76wAAAHAJ0w8Uf/LJJ2Xu79y5c7mLAQAAqCjT4aZr164lxn7/PA7P3AAAAG8y/T03J0+edPhz7NgxbdiwQTfccIM2btzojhoBAACcZvrKTY0aNUqM9ejRQ76+vpo4caI+++wzlxQGAABQHqav3JSmbt26ysjIMHVMfHy8bDabw58WLVqUOr+oqEgzZsxQkyZN5O/vr7Zt22rDhg0VLR0AAFiI6Ss3X375pcO2YRjKzs7W008/rWuvvdZ0Aa1atdLHH3/8W0FVSi9p6tSpeuutt7Ro0SK1aNFCH330kfr376/U1FRFR0ebPjcAALAe0+Hm2muvlc1mk2EYDuM33XSTFi9ebL6AKlUUFhbm1Nw333xT//znP3XbbbdJkkaOHKmPP/5Yc+bM0VtvvWX63AAAwHpMh5tDhw45bFeqVEmhoaHy9/cvVwH79+9XRESE/P39FRMTo9mzZ6tBgwYXnVtYWFjiPAEBAdq2bVup6xcWFqqwsNC+feGnJIqKilRUVFSumktzYT1XrwtH9Nkz6LNn0GfPodee4a4+m1nPZvzxEowHrV+/Xnl5eWrevLmys7OVkJCgw4cPa+/evapevXqJ+QMHDtSePXv03nvvqUmTJtq8ebPuuOMOnT9/3iHA/F58fLwSEhJKjCcmJiowMNDlrwkAALhefn6+Bg4cqJycnEv+jmW5ws3mzZs1d+5cff3115Kkq6++WuPHj1f37t3LV/H/O3XqlKKiovT8889r2LBhJfb/9NNPGj58uNatWyebzaYmTZqoe/fuWrx4sc6cOXPRNS925SYyMlLHjx93+Y98FhUVadOmTerRo4d8fHxcujZ+Q589gz57Bn32HHrtGe7qc25urkJCQpwKN6ZvS7366qsaN26c/vrXv2rcuHGSpPT0dN12222aO3euRo8eXb6q9esPdDZr1kwHDhy46P7Q0FC99957Kigo0IkTJxQREaHHHntMjRs3LnVNPz8/+fn5lRj38fFx25vbnWvjN/TZM+izZ9Bnz6HXnuHqPptZy3S4mTVrlubOnasxY8bYx8aOHauOHTtq1qxZFQo3eXl5yszM1P3331/mPH9/f9WrV09FRUVauXKl7rnnnnKfEwAAWIvp77k5deqUevfuXWK8Z8+eysnJMbXWpEmTlJKSom+//Vapqanq37+/KleurAEDBkiSBg8erLi4OPv87du3a9WqVTp48KC2bt2q3r17q7i4WJMnTzb7MgAAgEWZDjd/+ctftHr16hLja9asUd++fU2t9cMPP2jAgAFq3ry57rnnHtWuXVvp6ekKDQ2VJGVlZSk7O9s+v6CgQFOnTlXLli3Vv39/1atXT9u2bVNwcLDZlwEAACzKqdtSL774ov3vLVu21MyZM5WcnKyYmBhJvz5z8+mnn+qRRx4xdfLly5eXuT85Odlhu0uXLtq3b5+pcwAAgD8Xp8LN3LlzHbZr1qypffv2OQSN4OBgLV68WFOnTnVthQAAACY4FW7++MV9AAAAlytTz9wUFRWpSZMm9u+3AQAAuNyYCjc+Pj4qKChwVy0AAAAVZvrTUqNHj9Yzzzyjc+fOuaMeAACACjH9JX47d+7U5s2btXHjRrVp00ZVq1Z12L9q1SqXFQcAAGCW6XATHBysu+++2x21AAAAVJjpcLNkyRJ31AEAAOASpp+5AQAAuJyZvnLTqFEj2Wy2UvcfPHiwQgUBAABUhOlwM378eIftoqIiffHFF9qwYYMeffRRV9UFAABQLqbDzbhx4y46/sorr2jXrl0VLggAAKAiXPbMTZ8+fbRy5UpXLQcAAFAuLgs3//73v1WrVi1XLQcAAFAuTt+WmjFjhh555BF16tTJ4YFiwzB05MgR/fTTT3r11VfdUiQAAICznA43CQkJGjFihO644w6HcFOpUiWFhoaqa9euatGihVuKBAAAcJbT4cYwDElSfHy8u2oBAACoMFPP3JT1/TYAAACXA1MfBW/WrNklA87PP/9coYIAAAAqwlS4SUhIUI0aNdxVCwAAQIWZCjf33nuv6tSp465aAAAAKszpZ2543gYAAFwJnA43Fz4tBQAAcDlz+rZUcXGxO+sAAABwCZf9/AIAAMDlgHADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAshXADAAAsxavhJj4+XjabzeFPixYtyjxm3rx5at68uQICAhQZGakJEyaooKDAQxUDAIDLXRVvF9CqVSt9/PHH9u0qVUovKTExUY899pgWL16sDh066JtvvtHQoUNls9n0/PPPe6JcAABwmfN6uKlSpYrCwsKcmpuamqqOHTtq4MCBkqSGDRtqwIAB2r59uztLBAAAVxCvh5v9+/crIiJC/v7+iomJ0ezZs9WgQYOLzu3QoYPeeust7dixQzfeeKMOHjyoDz/8UPfff3+p6xcWFqqwsNC+nZubK0kqKipSUVGRS1/LhfVcvS4c0WfPoM+eQZ89h157hrv6bGY9m2EYhkvPbsL69euVl5en5s2bKzs7WwkJCTp8+LD27t2r6tWrX/SYF198UZMmTZJhGDp37pxGjBih+fPnl3qO+Ph4JSQklBhPTExUYGCgy14LAABwn/z8fA0cOFA5OTkKCgoqc65Xw80fnTp1SlFRUXr++ec1bNiwEvuTk5N177336qmnnlL79u114MABjRs3TsOHD9e0adMuuubFrtxERkbq+PHjl2yOWUVFRdq0aZN69OghHx8fl66N39Bnz6DPnkGfPYdee4a7+pybm6uQkBCnwo3Xb0v9XnBwsJo1a6YDBw5cdP+0adN0//336x//+IckqU2bNjp9+rQefPBB/fOf/1SlSiU//OXn5yc/P78S4z4+Pm57c7tzbfyGPnsGffYM+uw59NozXN1nM2tdVt9zk5eXp8zMTIWHh190f35+fokAU7lyZUnSZXQBCgAAeJFXw82kSZOUkpKib7/9Vqmpqerfv78qV66sAQMGSJIGDx6suLg4+/x+/fpp/vz5Wr58uQ4dOqRNmzZp2rRp6tevnz3kAACAPzev3pb64YcfNGDAAJ04cUKhoaHq1KmT0tPTFRoaKknKyspyuFIzdepU2Ww2TZ06VYcPH1ZoaKj69eunmTNneuslAACAy4xXw83y5cvL3J+cnOywXaVKFU2fPl3Tp093Y1UAAOBKdlk9cwMAAFBRhBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGAphBsAAGApXg038fHxstlsDn9atGhR6vyuXbuWmG+z2XT77bd7sGoAAHA5q+LtAlq1aqWPP/7Yvl2lSuklrVq1SmfPnrVvnzhxQm3btlVsbKxbawQAAFcOr4ebKlWqKCwszKm5tWrVcthevny5AgMDCTcAAMDO6+Fm//79ioiIkL+/v2JiYjR79mw1aNDAqWNff/113XvvvapatWqpcwoLC1VYWGjfzs3NlSQVFRWpqKioYsX/wYX1XL0uHNFnz6DPnkGfPYdee4a7+mxmPZthGIZLz27C+vXrlZeXp+bNmys7O1sJCQk6fPiw9u7dq+rVq5d57I4dO9S+fXtt375dN954Y6nz4uPjlZCQUGI8MTFRgYGBFX4NAADA/fLz8zVw4EDl5OQoKCiozLleDTd/dOrUKUVFRen555/XsGHDypz70EMPKS0tTV9++WWZ8y525SYyMlLHjx+/ZHPMKioq0qZNm9SjRw/5+Pi4dG38hj57Bn32DPrsOfTaM9zV59zcXIWEhDgVbrx+W+r3goOD1axZMx04cKDMeadPn9by5cs1Y8aMS67p5+cnPz+/EuM+Pj5ue3O7c238hj57Bn32DPrsOfTaM1zdZzNrXVbfc5OXl6fMzEyFh4eXOe/dd99VYWGh7rvvPg9VBgAArhReDTeTJk1SSkqKvv32W6Wmpqp///6qXLmyBgwYIEkaPHiw4uLiShz3+uuv684771Tt2rU9XTIAALjMefW21A8//KABAwboxIkTCg0NVadOnZSenq7Q0FBJUlZWlipVcsxfGRkZ2rZtmzZu3OiNkgEAwGXOq+Fm+fLlZe5PTk4uMda8eXNdRs9AAwCAy8xl9cwNAABARRFuAACApRBuAACApRBuAACApRBuAACApRBuAACApRBuAACApRBuAACApRBuAACApVxWvwruCRe+3Tg3N9flaxcVFSk/P1+5ubn84qwb0WfPoM+eQZ89h157hrv6fOHf2878SsGfLtz88ssvkqTIyEgvVwIAAMz65ZdfVKNGjTLn2Iw/2Q81FRcX68cff1T16tVls9lcunZubq4iIyP1/fffKygoyKVr4zf02TPos2fQZ8+h157hrj4bhqFffvlFERERJX5U+4/+dFduKlWqpPr167v1HEFBQfyD4wH02TPos2fQZ8+h157hjj5f6orNBTxQDAAALIVwAwAALIVw40J+fn6aPn26/Pz8vF2KpdFnz6DPnkGfPYdee8bl0Oc/3QPFAADA2rhyAwAALIVwAwAALIVwAwAALIVwAwAALIVw4yKvvPKKGjZsKH9/f7Vv3147duzwdkmWEx8fL5vN5vCnRYsW3i7rivfJJ5+oX79+ioiIkM1m03vvveew3zAMPfHEEwoPD1dAQIC6d++u/fv3e6fYK9il+jx06NAS7+/evXt7p9gr2OzZs3XDDTeoevXqqlOnju68805lZGQ4zCkoKNDo0aNVu3ZtVatWTXfffbeOHj3qpYqvTM70uWvXriXe0yNGjPBIfYQbF1ixYoUmTpyo6dOn6/PPP1fbtm3Vq1cvHTt2zNulWU6rVq2UnZ1t/7Nt2zZvl3TFO336tNq2batXXnnlovufffZZvfjii1qwYIG2b9+uqlWrqlevXiooKPBwpVe2S/VZknr37u3w/l62bJkHK7SGlJQUjR49Wunp6dq0aZOKiorUs2dPnT592j5nwoQJWrdund59912lpKToxx9/1F133eXFqq88zvRZkoYPH+7wnn722Wc9U6CBCrvxxhuN0aNH27fPnz9vREREGLNnz/ZiVdYzffp0o23btt4uw9IkGatXr7ZvFxcXG2FhYca//vUv+9ipU6cMPz8/Y9myZV6o0Br+2GfDMIwhQ4YYd9xxh1fqsbJjx44ZkoyUlBTDMH59//r4+Bjvvvuufc7XX39tSDLS0tK8VeYV7499NgzD6NKlizFu3Div1MOVmwo6e/asPvvsM3Xv3t0+VqlSJXXv3l1paWlerMya9u/fr4iICDVu3FiDBg1SVlaWt0uytEOHDunIkSMO7+8aNWqoffv2vL/dIDk5WXXq1FHz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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAAkIAAAGwCAYAAABFFQqPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAuiklEQVR4nO3deXhU9b3H8c8Ak0AgIWJCFgg7EmUToWBQIQgkoFKhXhewl0gRrxZugaAoFlm1qQtKtVSsFqNWcKtErF6aGBJQiSDQaPGBKHGJlSS4ACEJJCM59w8vcx2zw8wZJr/363nyNOd3zvnNd77PCX56lhmHZVmWAAAADNTK3wUAAAD4C0EIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYbfxdwNmupqZGBw8eVGhoqBwOh7/LAQAATWBZlo4dO6bY2Fi1alX/eR+CUCMOHjyouLg4f5cBAABOw5dffqmuXbvWu54g1IjQ0FBJPzQyLCzMa/O6XC5lZmYqKSlJTqfTa/OiNnptD/psD/psD/psD1/2uaysTHFxce7/jteHINSIU5fDwsLCvB6EQkJCFBYWxh+Zj9Fre9Bne9Bne9Bne9jR58Zua+FmaQAAYKyACkLbtm3TpEmTFBsbK4fDoYyMjAa3z83NlcPhqPVTUlJiT8EAAOCsFlBBqKKiQoMHD9aaNWuatV9BQYGKi4vdP507d/ZRhQAAIJAE1D1CEydO1MSJE5u9X+fOnRUeHu79ggAAQEALqCB0ui688EJVVVVpwIABWrZsmS655JJ6t62qqlJVVZV7uaysTNIPN3S5XC6v1XRqLm/OibrRa3vQZ3vQZ3vQZ3v4ss9NndNhWZbl9Ve3gcPh0MaNGzV58uR6tykoKFBubq6GDRumqqoqPfXUU3ruuee0Y8cOXXTRRXXus2zZMi1fvrzW+Pr16xUSEuKt8gEAgA9VVlZq2rRpOnr0aINPfbfoIFSX0aNHq1u3bnruuefqXF/XGaG4uDh98803Xn98PisrS+PHj+fRTB+j1/agz/agz/agz/bwZZ/LysoUERHRaBAy4tLYjw0fPlzvvPNOveuDg4MVHBxca9zpdPrkj8FX86I2em0P+mwP+mwP+mwPX/S5qfMF1FNj3pCfn6+YmBh/lwEAAM4CAXVGqLy8XAcOHHAvf/bZZ8rPz1enTp3UrVs3LVq0SF999ZWeffZZSdLq1avVs2dP9e/fXydOnNBTTz2lLVu2KDMz019vAQAAnEUCKgjt2rVLY8aMcS+npqZKklJSUpSenq7i4mIVFRW511dXV2vBggX66quvFBISokGDBumtt97ymAMAAJgroIJQYmKiGrq3Oz093WN54cKFWrhwoY+rOj1BQUHu3wP0fnUAAAKecfcInQ1++gVwjX0hHAAA8A2CkM3qCz2EIQAA7EcQAgAAxiIIAQAAYxGEbFbfjdHcMA0AgP0IQn7w09BDCAIAwD8IQn5SXV2tjIwMVVdX+7sUAACMFVCfIwScDj6zCQBQH84IoUXjM5sAAA0hCKHF4jObAACNIQgBAABjEYQAAICxCEJosfjMJgBAYwhCaNH4zCYAQEMIQmjx+MwmAEB9CEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMFZABaFt27Zp0qRJio2NlcPhUEZGRqP75Obm6qKLLlJwcLD69Omj9PR0n9cJAAACQ0AFoYqKCg0ePFhr1qxp0vafffaZrrzySo0ZM0b5+fmaN2+ebr75Zv3jH//wcaUAACAQtPF3Ac0xceJETZw4scnbr127Vj179tSqVaskSeeff77eeecdPfLII0pOTvZVmQAAIEAEVBBqrry8PI0bN85jLDk5WfPmzat3n6qqKlVVVbmXy8rKJEkul0sul8trtZ2ay5tzom702h702R702R702R6+7HNT52zRQaikpERRUVEeY1FRUSorK9Px48fVrl27WvukpaVp+fLltcYzMzMVEhLi9RqzsrK8PifqRq/tQZ/tQZ/tQZ/t4Ys+V1ZWNmm7Fh2ETseiRYuUmprqXi4rK1NcXJySkpIUFhbmtddxuVzKysrS+PHj5XQ6vTYvaqPX9qDP9qDP9qDP9vBln09d0WlMiw5C0dHRKi0t9RgrLS1VWFhYnWeDJCk4OFjBwcG1xp1Op0/+GHw1L2qj1/agz/agz/agz/bwRZ+bOl9APTXWXAkJCcrOzvYYy8rKUkJCgp8qAgAAZ5OACkLl5eXKz89Xfn6+pB8ej8/Pz1dRUZGkHy5rTZ8+3b39rbfeqk8//VQLFy7U/v379ac//UkvvfSS5s+f74/yAQDAWSaggtCuXbs0ZMgQDRkyRJKUmpqqIUOGaMmSJZKk4uJidyiSpJ49e+qNN95QVlaWBg8erFWrVumpp57i0XkAACApwO4RSkxMlGVZ9a6v61OjExMT9c9//tOHVQEAgEAVUGeEAAAAvIkgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAY7XxdwEAWoagoCD375Zl+bESAGg6zggBOGMOh6PBZQA4WxGEAJyR+kIPYQhAICAIAQAAYxGEAACAsQhCAM5IfTdGc8M0gEBAEAJwxn4aeghBAAIFQQiAV1RXVysjI0PV1dX+LgUAmowgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGCsgAtCa9asUY8ePdS2bVuNGDFCO3furHfb9PR0ORwOj5+2bdvaWC0AADibBVQQevHFF5WamqqlS5dqz549Gjx4sJKTk3Xo0KF69wkLC1NxcbH754svvrCxYgAAcDZr4+8CmuPhhx/WrFmzNGPGDEnS2rVr9cYbb2jdunW666676tzH4XAoOjq6ya9RVVWlqqoq93JZWZkkyeVyyeVynUH1nk7N5c05UTd6bQ/6bA/6bA/6bA9f9rmpczosy7K8/uo+UF1drZCQEL3yyiuaPHmyezwlJUVHjhzRa6+9Vmuf9PR03XzzzerSpYtqamp00UUX6Xe/+5369+9f7+ssW7ZMy5cvrzW+fv16hYSEeOW9AAAA36qsrNS0adN09OhRhYWF1btdwJwR+uabb3Ty5ElFRUV5jEdFRWn//v117tOvXz+tW7dOgwYN0tGjR/XQQw9p5MiR+uijj9S1a9c691m0aJFSU1Pdy2VlZYqLi1NSUlKDjWwul8ulrKwsjR8/Xk6n02vzojZ6bQ/6bA/6bA/6bA9f9vnUFZ3GBEwQOh0JCQlKSEhwL48cOVLnn3++nnjiCa1cubLOfYKDgxUcHFxr3Ol0+uSPwVfzojZ6bQ/6bA/6bA/6bA9f9Lmp8wXMzdIRERFq3bq1SktLPcZLS0ubfA+Q0+nUkCFDdODAAV+UCAAAAkzABKGgoCANHTpU2dnZ7rGamhplZ2d7nPVpyMmTJ/Wvf/1LMTExvioTAAAEkIC6NJaamqqUlBQNGzZMw4cP1+rVq1VRUeF+imz69Onq0qWL0tLSJEkrVqzQxRdfrD59+ujIkSN68MEH9cUXX+jmm2/259sAAABniYAKQtdff72+/vprLVmyRCUlJbrwwgu1efNm9w3URUVFatXq/09yHT58WLNmzVJJSYnOOeccDR06VNu3b9cFF1zgr7cAAADOIgEVhCRpzpw5mjNnTp3rcnNzPZYfeeQRPfLIIzZUBQAAAlHA3CMEAADgbQQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxTisIff/993rrrbf0xBNP6NixY5KkgwcPqry83KvFAQAA+FKb5u7wxRdfaMKECSoqKlJVVZXGjx+v0NBQ3X///aqqqtLatWt9UScAAIDXNfuM0Ny5czVs2DAdPnxY7dq1c49PmTJF2dnZXi0OAADAl5p9Rujtt9/W9u3bFRQU5DHeo0cPffXVV14rDAAAwNeafUaopqZGJ0+erDX+73//W6GhoV4pCgAAwA7NDkJJSUlavXq1e9nhcKi8vFxLly7VFVdc4c3aAAAAfKrZl8ZWrVql5ORkXXDBBTpx4oSmTZumTz75RBEREdqwYYMvagQAAPCJZgehrl276oMPPtALL7ygDz/8UOXl5Zo5c6ZuvPFGj5unAQAAznbNDkKS1KZNG/3yl7/0di0AAAC2anYQevbZZxtcP3369NMuBgAAwE7NDkJz5871WHa5XKqsrFRQUJBCQkIIQgAAIGA0+6mxw4cPe/yUl5eroKBAl156KTdLAwCAgOKVL13t27evfv/739c6WwQAAHA289q3z7dp00YHDx701nQAAAA+1+x7hDZt2uSxbFmWiouL9cc//lGXXHKJ1woDAADwtWYHocmTJ3ssOxwORUZG6vLLL9eqVau8VRcAAIDPNTsI1dTU+KIOAAAA23ntHiG7rFmzRj169FDbtm01YsQI7dy5s8HtX375ZcXHx6tt27YaOHCg3nzzTZsqBQDvCwoK0uTJkxUUFOTvUoAWoUlnhFJTU5s84cMPP3zaxTTmxRdfVGpqqtauXasRI0Zo9erVSk5OVkFBgTp37lxr++3bt2vq1KlKS0vTVVddpfXr12vy5Mnas2ePBgwY4LM6AcAXHA5HrWXLsvxUDdAyNCkI/fOf/2zSZD/9I/W2hx9+WLNmzdKMGTMkSWvXrtUbb7yhdevW6a677qq1/R/+8AdNmDBBd9xxhyRp5cqVysrK0h//+EetXbvWp7UCgDfV9+8rYQg4M00KQjk5Ob6uo1HV1dXavXu3Fi1a5B5r1aqVxo0bp7y8vDr3ycvLq3U2Kzk5WRkZGfW+TlVVlaqqqtzLZWVlkn74BG2Xy3UG78DTqbm8OSfqRq/tQZ/9h557H8ezPXzZ56bOeVpfuuoP33zzjU6ePKmoqCiP8aioKO3fv7/OfUpKSurcvqSkpN7XSUtL0/Lly2uNZ2ZmKiQk5DQqb1hWVpbX50Td6LU96LP9uPfRdzie7eGLPldWVjZpu9MKQrt27dJLL72koqIiVVdXe6x79dVXT2fKs8aiRYs8ziKVlZUpLi5OSUlJCgsL89rruFwuZWVlafz48XI6nV6bF7XRa3vQZ9+qrq6u8wbpn/4bDO/geLaHL/t86opOY5odhF544QVNnz5dycnJyszMVFJSkj7++GOVlpZqypQpzS60qSIiItS6dWuVlpZ6jJeWlio6OrrOfaKjo5u1vSQFBwcrODi41rjT6fTJH4Ov5kVt9Noe9Nl3LMvyuFeIe4N8j+PZHr7oc1Pna/bj87/73e/0yCOP6PXXX1dQUJD+8Ic/aP/+/bruuuvUrVu3ZhfaVEFBQRo6dKiys7PdYzU1NcrOzlZCQkKd+yQkJHhsL/1w+q2+7QHgbFddXa2MjAzOBAFe0uwgVFhYqCuvvFLSD+GkoqJCDodD8+fP15///GevF/hjqampevLJJ/XMM89o3759uu2221RRUeF+imz69OkeN1PPnTtXmzdv1qpVq7R//34tW7ZMu3bt0pw5c3xaJwAACAzNvjR2zjnn6NixY5KkLl26aO/evRo4cKCOHDnS5BuTTtf111+vr7/+WkuWLFFJSYkuvPBCbd682X1DdFFRkVq1+v9sN3LkSK1fv16LFy/W3Xffrb59+yojI4PPEAIAAJKaEYT27t2rAQMGaNSoUcrKytLAgQN17bXXau7cudqyZYuysrI0duxYX9YqSZozZ069Z3Ryc3NrjV177bW69tprfVwVAAAIRE0OQoMGDdLPfvYzTZ482R0sfvvb38rpdGr79u265pprtHjxYp8VCgAA4G1NDkJbt27V008/rbS0NN1333265pprdPPNN9f5ic4AAACBoMk3S1922WVat26diouL9dhjj+nzzz/X6NGjdd555+n+++9v8EMKAQAAzkbNfmqsffv2mjFjhrZu3aqPP/5Y1157rdasWaNu3brp5z//uS9qBAAA8IlmB6Ef69Onj+6++24tXrxYoaGheuONN7xVFwAAgM+d9neNbdu2TevWrdPf/vY3tWrVStddd51mzpzpzdoAAAB8qllB6ODBg0pPT1d6eroOHDigkSNH6tFHH9V1112n9u3b+6pGAAAAn2hyEJo4caLeeustRUREaPr06frVr36lfv36+bI2AAAAn2pyEHI6nXrllVd01VVXqXXr1r6sCQAAwBZNDkKbNm3yZR0AAAC2O6OnxgAAAAIZQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACMRRACAADGIggBAABjEYQAAICxCEIAAMBYBCEAAGAsghAAADAWQQgAABiLIAQAAIxFEAIAAMYiCAEAAGMRhAAAgLEIQgAAwFgEIQAAYCyCEAAAMBZBCAAAGIsgBAAAjEUQAgAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgrIAJQt99951uvPFGhYWFKTw8XDNnzlR5eXmD+yQmJsrhcHj83HrrrTZVDAAAznZt/F1AU914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P/XNN9+411dUVGj69Onq0KGDYmJimnTZ6euvv9aWLVs0adIkj3GHw6EnnnhCV111lUJCQnT++ecrLy9PBw4cUGJiotq3b6+RI0eqsLDQY78TJ04oMzPTHYT+9Kc/qW/fvmrbtq2ioqL0H//xHx7bT5o0SS+88EKjdQKmIQgBcBszZoxycnLcyzk5OUpMTNTo0aPd48ePH9eOHTvcQagulZWVeuihh/Tcc89p27ZtKioq0u233+5ev2rVKqWnp2vdunV655139N1332njxo0N1hYdHa333ntPX3zxRYPbZWdna9++fcrNzdWGDRv06quvavny5e71aWlpevbZZ7V27Vp99NFHmj9/vn75y19q69atkqQjR47o8ssv15AhQ7Rr1y5t3rxZpaWluu6669xz3HHHHdq6datee+01ZWZmKjc3V3v27GmwrnfeeccddH5q5cqVmj59uvLz8xUfH69p06bpv/7rv7Ro0SLt2rVLlmVpzpw5td5nly5dFB8fr127duk3v/mNVqxYoYKCAm3evFmjRo3y2H748OHauXOnqqqqGqwTMI7Pv98eQMB48sknrfbt21sul8sqKyuz2rRpYx06dMhav369NWrUKMuyLCs7O9uSZH3xxReWZVlWTk6OJck6fPiwZVmW9fTTT1uSrAMHDrjnXbNmjRUVFeVejomJsR544AH3ssvlsrp27WpdffXV9dZ28OBB6+KLL7YkWeedd56VkpJivfjii9bJkyfd26SkpFidOnWyKioq3GOPP/641aFDB+vkyZPWiRMnrJCQEGv79u0ec8+cOdOaOnWqZVmWtXLlSispKclj/ZdffmlJsgoKCqxjx45ZQUFB1ksvveRe/+2331rt2rWz5s6dW2/9jzzyiNWrV69a45KsxYsXu5fz8vIsSdZf/vIX99iGDRustm3beuw3a9Ys6/bbb7csy7L+9re/WWFhYVZZWVm9r//BBx9YkqzPP/+83m0AE7XxXwQDcLZJTExURUWF3n//fR0+fFjnnXeeIiMjNXr0aM2YMUMnTpxQbm6uevXqpW7dutU7T0hIiHr37u1ejomJ0aFDhyRJR48eVXFxsUaMGOFe36ZNGw0bNqzBy2MxMTHKy8vT3r17tW3bNm3fvl0pKSl66qmntHnzZvd9N4MHD1ZISIh7v4SEBJWXl+vLL79UeXm5KisrNX78eI+5q6urNWTIEEnSBx98oJycHHXo0KFWDYWFhTp+/Liqq6s96u/UqZP69etXb+3SD2fS2rZtW+e6QYMGuX+PioqSJA0cONBj7MSJEyorK1NYWJgsy9Lrr7+ul156SZI0fvx4de/eXb169dKECRM0YcIETZkyxaMP7dq1k/TD2ToA/48gBMCtT58+6tq1q3JycnT48GGNHj1akhQbG6u4uDht375dOTk5uvzyyxucx+l0eiw7HI5G7wFqqgEDBmjAgAH69a9/rVtvvVWXXXaZtm7d2uClulNO3Vj9xhtvqEuXLh7rgoOD3dtMmjRJ999/f639Y2JidODAgdOqOyIiQocPH65z3Y/7deqm87rGampqJEk7d+7U999/r5EjR0qSQkNDtWfPHuXm5iozM1NLlizRsmXL9P777ys8PFyS9N1330mSIiMjT6t+oKXiHiEAHsaMGaPc3Fzl5uZ6PDY/atQo/c///I927tzZpNBRn44dOyomJkY7duxwj33//ffavXt3s+e64IILJP1w8/IpH3zwgY4fP+5efu+999ShQwfFxcXpggsuUHBwsIqKitSnTx+Pn7i4OEnSRRddpI8++kg9evSotU379u3Vu3dvOZ1Oj/oPHz6sjz/+uMFahwwZopKSknrDUHO89tpruvLKK9W6dWv3WJs2bTRu3Dg98MAD+vDDD/X5559ry5Yt7vV79+5V165dFRERccavD7QknBEC4GHMmDGaPXu2XC6X+4yQJI0ePVpz5sxRdXX1GQUhSZo7d65+//vfq2/fvoqPj9fDDz/c6Acy3nbbbYqNjdXll1+url27qri4WPfee68iIyOVkJDg3q66ulozZ87U4sWL9fnnn2vp0qWaM2eOWrVqpdDQUN1+++2aP3++ampqdOmll+ro0aN69913FRYWppSUFM2ePVtPPvmkpk6dqoULF6pTp046cOCAXnjhBT311FPq0KGDZs6cqTvuuEPnnnuuOnfurN/+9reNPhI/ZMgQRURE6N1339VVV111Rv3btGmTVqxY4V7++9//rk8//VSjRo3SOeecozfffFM1NTUel+vefvttJSUlndHrAi0RQQiAhzFjxuj48eOKj493368i/RCEjh075n7M/kwsWLBAxcXFSklJUatWrfSrX/1KU6ZMafAD/8aNG6d169bp8ccf17fffquIiAglJCQoOztb5557rnu7sWPHqm/fvho1apSqqqo0depULVu2zL1+5cqVioyMVFpamj799FOFh4froosu0t133y3ph8uA7777ru68804lJSWpqqpK3bt314QJE9xh58EHH3RfQgsNDdWCBQsa/bDC1q1ba8aMGXr++efPKAgVFhbqwIEDSk5Odo+Fh4fr1Vdf1bJly3TixAn17dtXGzZsUP/+/SX98Kh9RkaGNm/efNqvC7RUDstbF+4BwM9uuukmHTlyRBkZGf4upU4lJSXq37+/9uzZo+7du5/WHA8//LDeeustvfnmm03e5/HHH9fGjRuVmZl5Wq8JtGTcIwQANomOjtZf/vIXFRUVnfYcXbt21aJFi5q1j9Pp1GOPPXbarwm0ZJwRAtBinO1nhACcfQhCAADAWFwaAwAAxiIIAQAAYxGEAACAsQhCAADAWAQhAABgLIIQAAAwFkEIAAAYiyAEAACM9b9ce9fOz1shqAAAAABJRU5ErkJggg==\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"wind_directions = np.arange(0, 360, 10)\\n\",\n    \"wind_speeds = np.arange(0.0, 30.0, 5.0)\\n\",\n    \"freq_table = np.random.rand(36, 6)\\n\",\n    \"freq_table = freq_table / freq_table.sum()\\n\",\n    \"\\n\",\n    \"wind_rose = WindRose(\\n\",\n    \"    wind_directions=wind_directions, wind_speeds=wind_speeds, ti_table=0.06, freq_table=freq_table\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Set value\\n\",\n    \"wind_rose.assign_value_piecewise_linear()\\n\",\n    \"\\n\",\n    \"wind_rose.plot()\\n\",\n    \"\\n\",\n    \"# Plot with aggregated wind directions\\n\",\n    \"wind_rose.plot(wd_step=30)\\n\",\n    \"\\n\",\n    \"wind_rose.plot_ti_over_ws()\\n\",\n    \"\\n\",\n    \"wind_rose.plot_value_over_ws()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Setting FLORIS\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"WindData objects are used to set wind direction, speed, TI, frequency, and value in a FlorisModel (or UncertainFlorisModel).\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### TimeSeries\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 15,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# TimeSeries\\n\",\n    \"\\n\",\n    \"from floris import FlorisModel\\n\",\n    \"\\n\",\n    \"# Create a FlorisModel object\\n\",\n    \"fmodel = FlorisModel(\\\"../examples/inputs/gch.yaml\\\")\\n\",\n    \"\\n\",\n    \"# Set a two-turbine layout\\n\",\n    \"fmodel.set(layout_x=[0, 500], layout_y=[0, 0])\\n\",\n    \"\\n\",\n    \"# Make a set of inputs with 5 wind directions, while wind speed and TI are constant\\n\",\n    \"wind_directions = np.array([270, 280, 290, 300, 310])\\n\",\n    \"wind_speeds = 8.0 * np.ones(5)\\n\",\n    \"turbulence_intensities = 0.06 * np.ones(5)\\n\",\n    \"\\n\",\n    \"fmodel.set(\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    turbulence_intensities=turbulence_intensities,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Is equivalent to the following (but now we'll include value as well):\\n\",\n    \"time_series = TimeSeries(\\n\",\n    \"    wind_directions=wind_directions, wind_speeds=8.0, turbulence_intensities=0.06\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Scale some of the default parameters to get reasonable values representing USD/MWh\\n\",\n    \"time_series.assign_value_piecewise_linear(value_zero_ws=25 * 1.425, slope_2=-25 * 0.135)\\n\",\n    \"\\n\",\n    \"fmodel.set(wind_data=time_series)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 16,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stderr\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"\\u001b[34mfloris.floris_model.FlorisModel\\u001b[0m \\u001b[1;30mWARNING\\u001b[0m \\u001b[33mComputing AEP with uniform frequencies. Results results may not reflect annual operation.\\u001b[0m\\n\",\n      \"\\u001b[34mfloris.floris_model.FlorisModel\\u001b[0m \\u001b[1;30mWARNING\\u001b[0m \\u001b[33mComputing AVP with uniform frequencies. Results results may not reflect annual operation.\\u001b[0m\\n\"\n     ]\n    },\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Turbine power have shape (5, 2) and are [[1753954.45917917  354990.76412771]\\n\",\n      \" [1753954.45917917 1320346.28513924]\\n\",\n      \" [1753954.45917917 1748551.48278202]\\n\",\n      \" [1753954.45917917 1753951.95262087]\\n\",\n      \" [1753954.45917917 1753954.45908051]]\\n\",\n      \"Farm power has shape (5,) and is [2108945.22330688 3074300.74431841 3502505.94196119 3507906.41180004\\n\",\n      \" 3507908.91825968]\\n\",\n      \"Expected farm power has shape () and is 3140313.447929242\\n\",\n      \"Farm AEP is 27.50914580386016 GWh\\n\",\n      \"Expected farm value has shape () and is 74778713.9788151\\n\",\n      \"Farm annual value production (AVP) is 655061.5344544202 USD\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# Run the model and get outputs\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"# Get the power outputs\\n\",\n    \"turbine_powers = fmodel.get_turbine_powers()\\n\",\n    \"farm_power = fmodel.get_farm_power()\\n\",\n    \"expected_farm_power = fmodel.get_expected_farm_power()\\n\",\n    \"aep = fmodel.get_farm_AEP()\\n\",\n    \"\\n\",\n    \"# Get value outputs\\n\",\n    \"expected_farm_value = fmodel.get_expected_farm_value()\\n\",\n    \"avp = fmodel.get_farm_AVP()\\n\",\n    \"\\n\",\n    \"# Display\\n\",\n    \"print(f\\\"Turbine power have shape {turbine_powers.shape} and are {turbine_powers}\\\")\\n\",\n    \"print(f\\\"Farm power has shape {farm_power.shape} and is {farm_power}\\\")\\n\",\n    \"print(f\\\"Expected farm power has shape {expected_farm_power.shape} and is {expected_farm_power}\\\")\\n\",\n    \"print(f\\\"Farm AEP is {aep/1e9} GWh\\\")\\n\",\n    \"print(f\\\"Expected farm value has shape {expected_farm_power.shape} and is {expected_farm_value}\\\")\\n\",\n    \"print(f\\\"Farm annual value production (AVP) is {avp/1e6} USD\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"### WindRose\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"WindRose objects set FLORIS as TimeSeries, but there are some additional considerations.\\n\",\n    \"\\n\",\n    \"  - By default, wind direction/speed combinations with 0 frequency are not run\\n\",\n    \"  - The outputs of the functions get_turbine_powers and get_farm_power will be reshaped to have dimensions num_wind_directions x num_wind_speeds ( x num_turbines)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 17,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Fmodel has n_findex 4 because two cases have 0 frequency\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"wind_directions = np.array([270, 280])  # 2 Wind Directions\\n\",\n    \"wind_speeds = np.array([6.0, 7.0, 8.0])  # 3 Wind Speeds\\n\",\n    \"\\n\",\n    \"# Frequency matrix is 2 x 3, include some 0 frequency results\\n\",\n    \"freq_table = np.array([[0, 0, 1 / 2], [1 / 6, 1 / 6, 1 / 6]])\\n\",\n    \"\\n\",\n    \"# Create a WindRose object, not indicating a frequency table indicates uniform frequency\\n\",\n    \"wind_rose = WindRose(\\n\",\n    \"    wind_directions=wind_directions, wind_speeds=wind_speeds, ti_table=0.06, freq_table=freq_table\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Set value and scale some of the default parameters to get reasonable values representing USD/MWh\\n\",\n    \"wind_rose.assign_value_piecewise_linear(value_zero_ws=25 * 1.425, slope_2=-25 * 0.135)\\n\",\n    \"\\n\",\n    \"fmodel.set(wind_data=wind_rose)\\n\",\n    \"\\n\",\n    \"print(f\\\"Fmodel has n_findex {fmodel.core.flow_field.n_findex} because two cases have 0 frequency\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 18,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Turbine power have shape (2, 3, 2) and are [[[             nan              nan]\\n\",\n      \"  [             nan              nan]\\n\",\n      \"  [1753954.45917917  354990.76412771]]\\n\",\n      \"\\n\",\n      \" [[ 731003.41073165  523849.55426108]\\n\",\n      \"  [1176825.66812027  876937.12082426]\\n\",\n      \"  [1753954.45917917 1320346.28513924]]]\\n\",\n      \"Farm power has shape (2, 3) and is [[             nan              nan 2108945.22330688]\\n\",\n      \" [1254852.96499273 2053762.78894454 3074300.74431841]]\\n\",\n      \"Expected farm power has shape () and is 2118292.0280293887\\n\",\n      \"Farm AEP is 18.556238165537444 GWh\\n\",\n      \"Expected farm value has shape () and is 53008780.071847945\\n\",\n      \"Farm annual value production (AVP) is 464356.913429388 USD\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# Run the model and collect the outputs\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"# Get the power outputs\\n\",\n    \"turbine_powers = fmodel.get_turbine_powers()\\n\",\n    \"farm_power = fmodel.get_farm_power()\\n\",\n    \"expected_farm_power = fmodel.get_expected_farm_power()\\n\",\n    \"aep = fmodel.get_farm_AEP()\\n\",\n    \"\\n\",\n    \"# Get value outputs\\n\",\n    \"expected_farm_value = fmodel.get_expected_farm_value()\\n\",\n    \"avp = fmodel.get_farm_AVP()\\n\",\n    \"\\n\",\n    \"# Note that the nan values in the non-computed cases are expected since these are not run\\n\",\n    \"\\n\",\n    \"# Display\\n\",\n    \"print(f\\\"Turbine power have shape {turbine_powers.shape} and are {turbine_powers}\\\")\\n\",\n    \"print(f\\\"Farm power has shape {farm_power.shape} and is {farm_power}\\\")\\n\",\n    \"print(f\\\"Expected farm power has shape {expected_farm_power.shape} and is {expected_farm_power}\\\")\\n\",\n    \"print(f\\\"Farm AEP is {aep/1e9} GWh\\\")\\n\",\n    \"print(f\\\"Expected farm value has shape {expected_farm_power.shape} and is {expected_farm_value}\\\")\\n\",\n    \"print(f\\\"Farm annual value production (AVP) is {avp/1e6} USD\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 19,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Fmodel has n_findex 6\\n\",\n      \"Turbine powers and farm power are now computed for all cases\\n\",\n      \"Turbine power have shape (2, 3, 2) and are [[[ 731003.41073165   80999.08780495]\\n\",\n      \"  [1176825.66812027  191637.98384374]\\n\",\n      \"  [1753954.45917917  354990.76412771]]\\n\",\n      \"\\n\",\n      \" [[ 731003.41073165  523849.55426108]\\n\",\n      \"  [1176825.66812027  876937.12082426]\\n\",\n      \"  [1753954.45917917 1320346.28513924]]]\\n\",\n      \"Farm power has shape (2, 3) and is [[ 812002.4985366  1368463.65196401 2108945.22330688]\\n\",\n      \" [1254852.96499273 2053762.78894454 3074300.74431841]]\\n\",\n      \"Expected farm power and value, AEP, and AVP are the same as before since the new cases are weighted by 0\\n\",\n      \"Expected farm power has shape () and is 2118292.0280293887\\n\",\n      \"Farm AEP is 18.556238165537444 GWh\\n\",\n      \"Expected farm value has shape () and is 53008780.071847945\\n\",\n      \"Farm annual value production (AVP) is 464356.913429388 USD\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# It's possible however to force the running of 0 frequency cases\\n\",\n    \"wind_rose = WindRose(\\n\",\n    \"    wind_directions=wind_directions,\\n\",\n    \"    wind_speeds=wind_speeds,\\n\",\n    \"    ti_table=0.06,\\n\",\n    \"    freq_table=freq_table,\\n\",\n    \"    compute_zero_freq_occurrence=True,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Set value and scale some of the default parameters to get reasonable values representing USD/MWh\\n\",\n    \"wind_rose.assign_value_piecewise_linear(value_zero_ws=25 * 1.425, slope_2=-25 * 0.135)\\n\",\n    \"\\n\",\n    \"fmodel.set(wind_data=wind_rose)\\n\",\n    \"\\n\",\n    \"print(f\\\"Fmodel has n_findex {fmodel.core.flow_field.n_findex}\\\")\\n\",\n    \"\\n\",\n    \"# Run the model and collect the outputs\\n\",\n    \"fmodel.run()\\n\",\n    \"\\n\",\n    \"# Get the power outputs\\n\",\n    \"turbine_powers = fmodel.get_turbine_powers()\\n\",\n    \"farm_power = fmodel.get_farm_power()\\n\",\n    \"expected_farm_power = fmodel.get_expected_farm_power()\\n\",\n    \"aep = fmodel.get_farm_AEP()\\n\",\n    \"\\n\",\n    \"# Get value outputs\\n\",\n    \"expected_farm_value = fmodel.get_expected_farm_value()\\n\",\n    \"avp = fmodel.get_farm_AVP()\\n\",\n    \"\\n\",\n    \"# Display\\n\",\n    \"print(\\\"Turbine powers and farm power are now computed for all cases\\\")\\n\",\n    \"print(f\\\"Turbine power have shape {turbine_powers.shape} and are {turbine_powers}\\\")\\n\",\n    \"print(f\\\"Farm power has shape {farm_power.shape} and is {farm_power}\\\")\\n\",\n    \"\\n\",\n    \"print(\\n\",\n    \"    \\\"Expected farm power and value, AEP, and AVP are the same as before since the new cases are weighted by 0\\\"\\n\",\n    \")\\n\",\n    \"print(f\\\"Expected farm power has shape {expected_farm_power.shape} and is {expected_farm_power}\\\")\\n\",\n    \"print(f\\\"Farm AEP is {aep/1e9} GWh\\\")\\n\",\n    \"print(f\\\"Expected farm value has shape {expected_farm_power.shape} and is {expected_farm_value}\\\")\\n\",\n    \"print(f\\\"Farm annual value production (AVP) is {avp/1e6} USD\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# WindRoseWRG\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"The `WindRoseWRG` is a data object which is used to represent within FLORIS the information in a Wind Resource Grid (WRG) file.  `WindRoseWRG` is a type of WindData object, like `WindRose` and `TimeSeries`, that\\n\",\n    \"is used to store wind data in a format that can be used by the FLORIS model.  `WindRoseWRG` is different that `WindRose` however because the internal data holds the information of the WRG file and then a `WindRose` object is created \\n\",\n    \"for each turbine in a provided layout.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 20,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from floris import WindRoseWRG\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 21,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Read a WRG file (from examples)\\n\",\n    \"wind_rose_wrg = WindRoseWRG(\\\"../examples/examples_wind_resource_grid/wrg_example.wrg\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 22,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"WindResourceGrid with 2 x 3 grid points, min x: 0.0, min y: 0.0, grid size: 1000.0, z: 0.0, h: 90.0, 12 sectors\\n\",\n      \"Wind directions in file: [  0.  30.  60.  90. 120. 150. 180. 210. 240. 270. 300. 330.]\\n\",\n      \"Wind directions: [  0.  30.  60.  90. 120. 150. 180. 210. 240. 270. 300. 330.]\\n\",\n      \"Wind speeds: [ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17.\\n\",\n      \" 18. 19. 20. 21. 22. 23. 24. 25.]\\n\",\n      \"ti_table: 0.06\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# Print some basic information\\n\",\n    \"print(wind_rose_wrg)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 23,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Aggregate the wind speeds and directions\\n\",\n    \"wind_rose_wrg.set_wd_step(5.0)\\n\",\n    \"wind_rose_wrg.set_wind_speeds(np.arange(0, 30, 5))\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 24,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Set a turbine layout within the grid points of the WRG file\\n\",\n    \"layout_x = np.array([0, 500, 1000])\\n\",\n    \"layout_y = np.array([0, 1000, 2000])\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 25,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# Set up a FLORIS model with the above layout and wind_rose_wrg\\n\",\n    \"fmodel = FlorisModel(\\\"../examples/inputs/gch.yaml\\\")\\n\",\n    \"\\n\",\n    \"fmodel.set(layout_x=layout_x, layout_y=layout_y, wind_data=wind_rose_wrg)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 26,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAABdAAAAHxCAYAAABtdJ4RAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdeVwVZf//8ddh3/dVQRaVzQVEAUEUEHdLS7M0LfU207J9z+q25S61/U4ztdW7TW+rO5fMcsHUVFTUTNlEAVEBZd+3c+b3Rz/OVwIUFDyAn+fjcR7JMDPnmmOe91yfueYalaIoCkIIIYQQQgghhBBCCCGEaEBP1w0QQgghhBBCCCGEEEIIIToiKaALIYQQQgghhBBCCCGEEE2QAroQQgghhBBCCCGEEEII0QQpoAshhBBCCCGEEEIIIYQQTZACuhBCCCGEEEIIIYQQQgjRBCmgCyGEEEIIIYQQQgghhBBNkAK6EEIIIYQQQgghhBBCCNEEKaALIYQQQgghhBBCCCGEEE2QAroQQgghhBBCCCGEEEII0QQpoAtxFV988QUqlYrDhw9fdd3o6Giio6Pbv1FCCCGEaBHJcSGEEKLzkhwXQnQEUkAXnZZKpWrRa9euXbpu6g3z6aef4u/vj4mJCb1792bZsmW6bpIQQgjRJMnxhj766COmTJlCjx49UKlUzJo1S9dNEkIIIZolOf5/srKyeOWVVwgNDcXW1hYHBweio6PZvn27rpsmhGgjBrpugBDX6ssvv2zw83/+8x+2bdvWaLm/v/8Na9Ovv/56w97r71atWsX8+fOZPHkyTzzxBHv27OGRRx6hoqKCZ599VmftEkIIIZoiOd7Q0qVLKS0tJTQ0lOzsbJ21QwghhGgJyfH/s2HDBpYuXcptt93GzJkzqaur4z//+Q8jR47ks88+Y/bs2TpplxCi7UgBXXRaM2bMaPDzgQMH2LZtW6Pl16qqqgojI6NWbdPa9dtKZWUlL7zwAuPHj+e7774DYO7cuWg0Gl577TXuv/9+bG1tddI2IYQQoimS4w399ttv2tHnFhYWOmuHEEII0RKS4/8nJiaGs2fP4uDgoF02f/58goKC+Oc//ykFdCG6AJnCRXRpnp6eTd4C/fe50Xbt2oVKpWLt2rW8+OKLdO/eHTMzM0pKSrTrVFRUMG/ePOzt7bGysuLee++lsLCwRfv973//y+uvv46bmxsmJibExsaSlpbWqF3x8fGMGTMGa2trzMzMiIqK4vfff7/qccbFxZGfn8+DDz7YYPmCBQsoLy/np59+uuo+hBBCiI7mZslxAA8PD1QqVYvWFUIIITqDmyXH+/Tp06B4DmBsbMy4ceM4d+4cpaWlV92HEKJjkxHoQlzmtddew8jIiKeeeorq6uoGV7AfeughbGxsePnll0lJSeGjjz4iMzNTG8pXsmTJEvT09HjqqacoLi7mzTffZPr06cTHx2vX2blzJ2PHjmXgwIEsWrQIPT09Pv/8c4YPH86ePXsIDQ1tdv9Hjx4FYNCgQQ2WDxw4ED09PY4ePdpmIwGEEEKIjqqz5rgQQgghul6O5+TkYGZmhpmZWau3FUJ0LFJAF+IyVVVVHD58GFNT00a/MzIyYseOHRgaGgJ/jRR75pln2LRpExMmTLjqfo8dO6Y9AbC1teXRRx/lxIkT9O3bF0VRmD9/PjExMfz888/aE4B58+bRp08fXnzxxSvO55adnY2+vj5OTk6N2mxvb8+FCxda9TkIIYQQnVFnzXEhhBBCdK0cT0tL44cffmDKlCno6+u3alshRMcjU7gIcZmZM2c2GdYA999/vzasAR544AEMDAzYsmXLVfc7e/bsBlfPhw4dCsCZM2cAOHbsGKdOneLuu+8mPz+fvLw88vLyKC8vJzY2lt27d6PRaJrdf2VlZbPzvZmYmFBZWXnVNgohhBCdXWfNcSGEEEJ0nRyvqKhgypQpmJqasmTJkhZvJ4TouGQEuhCX8fLyavZ3vXv3bvCzhYUFrq6uZGRkXHW/PXr0aPBz/QM96+dsO3XqFPDXCUNziouLm30QqKmpKTU1NU3+rqqqqtmTECGEEKIr6aw5LoQQQoiukeNqtZqpU6eSmJjIzz//TLdu3a66jRCi45MCuujSmpsLTa1WN3kbVXsVmpu7ZUtRFADt1ey33nqLoKCgJte1sLBodv+urq6o1WouXrzYYBqXmpoa8vPzJbSFEEJ0SjdLjgshhBBd0c2Y43PnzmXz5s18/fXXDB8+vPWNFUJ0SFJAF12ara0tRUVFjZZnZmbi7e3dqn2dOnWKmJgY7c9lZWVkZ2czbty4620mPXv2BMDKyooRI0a0evv6kD98+HCD9hw+fBiNRtPsSYAQQgjRkd0sOS6EEEJ0RTdbjj/99NN8/vnnvP/++0ybNu262yWE6DhkDnTRpfXs2ZMDBw40mN5k8+bNZGVltXpfq1evpra2VvvzRx99RF1dHWPHjr3udg4cOJCePXvy9ttvU1ZW1uj3ly5duuL2w4cPx87Ojo8++qjB8o8++ggzMzPGjx9/3W0UQgghbrSbJceFEEKIruhmyvG33nqLt99+m4ULF/Loo49ed5uEEB2LjEAXXdp9993Hd999x5gxY7jzzjs5ffo0X331lfYKc2vU1NQQGxvLnXfeSUpKCitWrCAyMvKqT/xuCT09PT755BPGjh1Lnz59mD17Nt27d+f8+fPExcVhZWXFpk2bmt3e1NSU1157jQULFjBlyhRGjx7Nnj17+Oqrr3j99dexs7O77jYKIYQQN9rNkuMAmzZt4o8//gCgtraW48eP869//QuACRMm0L9//+tupxBCCHEj3Sw5/r///Y9nnnmG3r174+/vz1dffdXg9yNHjsTZ2fm62ymE0B0poIsubfTo0bzzzju8++67PPbYYwwaNIjNmzfz5JNPtnpfy5cv5+uvv+af//wntbW1TJs2jQ8++KDZed1aKzo6mv379/Paa6+xfPlyysrKcHFxISwsjHnz5l11+wcffBBDQ0PeeecdNm7ciLu7O++9955c/RZCCNFp3Uw5/v3337NmzRrtz0ePHuXo0aMAuLm5SQFdCCFEp3Oz5Hj9BfBTp05xzz33NPp9XFycFNCF6ORUSv1TE4QQQgghhBBCCCGEEEIIoSVzoAshhBBCCCGEEEIIIYQQTZACuhBCCCGEEEIIIYQQQgjRBCmgCyGEEEIIIYQQQgghhBBNkAK6EEIIIYQQQgghhBBCCNEEKaALIYS4aSxevJiQkBAsLS1xcnLitttuIyUlpcE60dHRqFSqBq/58+frqMVCCCGEuJxkuRBCCNF5ddYclwK6EEKIm8Zvv/3GggULOHDgANu2baO2tpZRo0ZRXl7eYL25c+eSnZ2tfb355ps6arEQQgghLidZLoQQQnRenTXHDXT67kK0g4MHDxIZGcmpU6fw8PDQdXN0burUqWg0Gv773//quilC6NzWrVsb/PzFF1/g5OREQkICw4YN0y43MzPDxcXlRjdPiA5N8rVry8/Pp0ePHqxfv55x48bpujlCNEuyXIirk8wW9VauXMkbb7zBqVOnMDY21nVzhOi0OS4j0EWX88ILLzBt2rRGJwpJSUmMGTMGCwsL7OzsuOeee7h06VKL97tx40aCg4MxMTGhR48eLFq0iLq6uutq6759+4iMjNR+MTzyyCOUlZW1ePtPP/0Uf39/TExM6N27N8uWLWu0zrPPPsv333/PH3/8cV1tFeJ6VVVVUVJS0i6v4uLiRsuqq6uv2qbi4mIA7OzsGiz/+uuvcXBwoG/fvjz//PNUVFS0y2ciRGfSVL7OmjWr0e2VKpUKPz+/RttrNBrefPNNvLy8MDExoX///nz77bdNvldHy+xff/2VOXPm0LdvX/T19fH09Gx23fY4ztbssylFRUXcf//9ODo6Ym5uTkxMDEeOHGmwjr29Pffddx8vvfRSi/crbj7tleXXmuMgWS5EU5rK7IMHD/Lggw8ycOBADA0NUalUV9xHS/qaAOfPn+fOO+/ExsYGKysrJk6cyJkzZ65rn02prq7m2WefpVu3bpiamhIWFsa2bdtavP3fJScn88wzzxAUFISlpSWurq6MHz+ew4cPN7l+exxna/bZlJbUE2bNmkVNTQ2rVq1q8X5F1yU5fh0UIbqQo0ePKoCyb9++BsuzsrIUBwcHpWfPnsq///1v5fXXX1dsbW2VwMBApbq6+qr73bJli6JSqZSYmBhl9erVysMPP6zo6ekp8+fPv662mpiYKAMGDFA++ugj5YUXXlCMjY2VMWPGtGj7lStXKoAyefJkZfXq1co999yjAMqSJUsarRsaGqrcc88919xWIa5XZWWlYoSJArTLy8LCotGyRYsWXbFNarVaGT9+vDJkyJAGy1etWqVs3bpVOX78uPLVV18p3bt3V26//fZ2/HSE6Piay9eZM2cqxsbGypdfftngtXHjxkb7eO655xRAmTt3rrJ69Wpl/PjxCqB8++23DdbriJk9c+ZMxcTERImIiFDc3NwUDw+PZtdtj+Ns6T6bolarlYiICMXc3Fx5+eWXleXLlysBAQGKpaWlkpqa2mDdxMREBVB27NjR8g9H3DTaM8uvJccVRbJciKY0l9mLFi1SDA0NlYEDByo+Pj7KlcpBLe1rlpaWKr1791acnJyUpUuXKu+++67i7u6uuLm5KXl5ede0z+ZMnTpVMTAwUJ566ill1apVSnh4uGJgYKDs2bOnhZ9MQ08++aRiY2OjzJkzR1m1apXy5ptvKj179lT09fWVbdu2tftxtmafTWlNPeGZZ55RPDw8FI1Gcw2flOgqJMevjxTQRZfyyCOPKD169GgUDA888IBiamqqZGZmapdt27ZNAZRVq1Zddb8BAQFKYGCgUltbq132wgsvKCqVSklKSrqmto4dO1ZxdXVViouLtcs+/vhjBVB++eWXK25bUVGh2NvbK+PHj2+wfPr06Yq5ublSUFDQYPnbb7+tmJubK6WlpdfUViGuV3FxsQIokYxTopnYpq9IximAkpWVpRQXF2tfVVVVV2zT/PnzFQ8PDyUrK+uK6+3YsUMBlLS0tLb8SIToVJrL15kzZyrm5uZX3f7cuXOKoaGhsmDBAu0yjUajDB06VHFzc1Pq6uq0yztiZp8/f16pqalRFEVRxo8f32wBvT2OszX7bMq6desUQFm/fr122cWLFxUbGxtl2rRpjdbv27evXHQXTWqvLL/WHFcUyXIhmtJcZufk5CgVFRWKoijKggULmi2gt6avuXTpUgVQDh48qF2WlJSk6OvrK88///w17bMp8fHxCqC89dZb2mWVlZVKz549lfDw8Ctu25zDhw836h/n5eUpjo6OjYp57XGcLd1nc1pTTzh8+LBcIBeS49dJpnARXcqPP/7I8OHDG92O9v3333PLLbfQo0cP7bIRI0bg4+Nz1bnBExMTSUxM5P7778fA4P8eG/Dggw+iKArfffddq9tZUlLCtm3bmDFjBlZWVtrl9957LxYWFldtU1xcHPn5+Tz44IMNli9YsIDy8nJ++umnBstHjhxJeXn5dd3iJkRbMMAQA1UbvzAEwMrKqsHrSnP8PfTQQ2zevJm4uDjc3Nyu2OawsDAA0tLS2u6DEKKTaS5f66nVakpKSprdfsOGDdTW1jbILZVKxQMPPMC5c+fYv3+/dnlHy2yAbt26YWhoeNX12uM4W7PPpnz33Xc4OzszadIk7TJHR0fuvPNONmzY0Oj22pEjR7Jp0yYURbnq8YqbU5tn+TXkOEiWC9Gc5jLb2dkZU1PTq27fmr7md999R0hICCEhIdplfn5+xMbGNsiy1vZf/+67775DX1+f+++/X7vMxMSEOXPmsH//frKysq56XH83cOBALCwsGiyzt7dn6NChJCUlNXr/tj7Olu6zKa2tJwwcOBA7Ozs2bNhwxf2Km4Pk+LWRArroMs6fP8/Zs2cJDg5utPzixYsMGjSo0TahoaEcPXr0ivut//3ft+/WrRtubm5X3b4pf/75J3V1dY32aWRkRFBQ0DW3aeDAgejp6TXaPiAgAFNTU37//fdWt1WIrkRRFB566CH+97//sXPnTry8vK66zbFjxwBwdXVt59YJ0TE1l6/1KioqsLKywtraGjs7OxYsWNBo/s2jR49ibm6Ov79/g+WhoaHa39e/V0fL7NZoj+Ns6T6v1Kbg4GD09Bqe9oeGhlJRUUFqamqD5QMHDqSoqIiTJ09ecb9C6IpkuRDNu1pmt0RL+5oajYbjx483m2WnT5+mtLS0Vfu8Upt8fHwaFIvr3wf+7994W8jJycHBwUH7c3scZ2v22ZRrqScEBwdLPUB0CJ01x6WALrqM5ORkgEb/+LKzs4Gm/6G5urpSUFBwxYcbXG37CxcutLqt17vP7Oxs9PX1cXJyarDcyMgIe3v7RtsbGBjg7u5OYmJiq9sqRFeyYMECvvrqK7755hssLS3JyckhJyeHyspKAE6fPs1rr71GQkICGRkZbNy4kXvvvZdhw4bRv39/HbdeCN1oLl/hr8x65pln+Pzzz/n222+ZMGECK1asYMyYMQ0e2pmdnY2zs3Oj0XD1OVifWx0xs1ujPY6zpfu8Upuae5+mtvf29gaQcwbRYUmWC9G8K2V2S7W0r1mfVS3JmNb2X5tqU2uy7Frt2bOH/fv3c9ddd2mXtcdxtmafTbmW8x1vb2/JdtEhdNYcN7j6KkJ0Dvn5+QDY2to2WF7/j7Cp20dMTEy06zR3e8nVtr/SLevNudo+639/pe2NjIya/F1z29va2pKXl9fqtgrRlXz00UcAREdHN1j++eefM2vWLIyMjNi+fTvvv/8+5eXluLu7M3nyZF588UUdtFaIjqG5fAVYvHhxg5+nTp2Kj48PL7zwAt999x1Tp04Fms/Zy3P48v92pMxujfY4zpbu83rbVK/+71nOGURHJVkuRPOulNkt1dK+ZkuzrDX7vFKbricLW+LixYvcfffdeHl58cwzzzR4b2jb42zNPptyLfUEW1tbKisrqaiowMzMrNl9C9HeOmuOSwFddDl/n7Ozfp63pkasVVVVNVinKVfbviXzyLX1Pk1NTampqWnyd81tryhKs3PXCnGzuNqcvu7u7vz22283qDVCdC4tnRP78ccf56WXXmL79u3aArqpqWmLcrgjZnZrtMdxtnSf19umevV/z3LOIDoqyXIhru56nmPR0r5ma7Ostf3Xv7fperLwasrLy7nlllsoLS1l7969DeZGb4/j1MX5juS76Cg6a47LFC6iy7C3twegsLCwwfL625rqb3O6XHZ2NnZ2dld8uMHVtu/WrVur23q9+3R1dUWtVnPx4sUGy2tqasjPz29y+8LCwgZzuQkhhBAt0Vy+NsfU1BR7e3sKCgq0y1xdXcnJyWl0wlyfg/W51REzuzXa4zhbus8rtam592lq+/q/ZzlnEEKIzqe1md2UlvY167OqJRlzLf3Xv7epNVnWGjU1NUyaNInjx4+zYcMG+vbt2+D37XGcrdlnU67lfKewsBAzM7N2H0wgRFclBXTRZfj5+QGQnp7eYHn37t1xdHTk8OHDjbY5ePAgQUFBV9xv/e//vv2FCxc4d+7cVbdvSt++fTEwMGi0z5qaGo4dO3bNbTp8+DAajabR9nV1dWRlZTV6AJkQQghxNc3la3NKS0vJy8vD0dFRuywoKIiKigqSkpIarBsfH6/9PXTMzG6N9jjOlu7zSm06cuQIGo2m0fZmZmb4+Pg0WF7/9yznDEII0fm0NrOb0tK+pp6eHv369Wsyy+Lj4/H29sbS0rJV+7xSm1JTUxtNxdbSLGyORqPh3nvvZceOHXzzzTdERUU1Wqc9jrM1+2zKtdQT0tPTJduFuA5SQBddRvfu3XF3d28yhCZPnszmzZvJysrSLtuxYwepqalMmTJFu6y2tpbk5OQGV3L79OmDn58fq1evRq1Wa5d/9NFHqFQq7rjjjla31dramhEjRvDVV181eLr2l19+SVlZWYM2VVRUkJyc3GAu0uHDh2NnZ6edO+ryNpmZmTF+/PgGyxMTE6mqqiIiIqLVbRVCCHFzay5fq6qqGmRYvddeew1FURgzZox22cSJEzE0NGTFihXaZYqisHLlSrp3794gnzpaZrdGexxna/aZnZ1NcnIytbW12mV33HEHubm5/PDDD9pleXl5rF+/nltvvbXRiP6EhASsra3p06fPdX4aQgghbrQr9YlbqjV9zTvuuINDhw41eL+UlBR27tzZIMtas8+8vDySk5OpqKho8D5qtZrVq1drl1VXV/P5558TFhaGu7v7NR3rww8/zLp161ixYgWTJk1qdr32OM6W7hP+ejjs2bNntT+3pp5Q78iRI1IPEOI6yBzookuZOHEi//vf/xrN971w4ULWr19PTEwMjz76KGVlZbz11lv069eP2bNna9c7f/48/v7+zJw5ky+++EK7/K233mLChAmMGjWKqVOncuLECZYvX859993X4CpuRkYGXl5ejbZvyuuvv05ERARRUVHcf//9nDt3jnfeeYdRo0Y1KDocPHiQmJgYFi1axMsvvwz8dXv8a6+9xoIFC5gyZQqjR49mz549fPXVV7z++uvY2dk1eK9t27ZhZmbGyJEjr+FTFUIIcbNrKl9zcnIYMGAA06ZN0454++WXX9iyZQtjxoxh4sSJ2u3d3Nx47LHHeOutt6itrSUkJIQff/yRPXv28PXXX6Ovr69dtyNm9vHjx9m4cSMAaWlpFBcX869//QuAwMBAbr311nY7ztbs8/nnn2fNmjWkp6fj6ekJ/NVBHzx4MLNnzyYxMREHBwdWrFiBWq3mlVdeaXSs27Zt49Zbb5U5UoUQopNqrk+cmZnJl19+CfzfCOn6LPPw8OCee+4BWtfXfPDBB/n4448ZP348Tz31FIaGhrz77rs4Ozvz5JNPatdrzT6XL1/OK6+8QlxcnPYhg2FhYUyZMoXnn3+eixcv0qtXL9asWUNGRgaffvppg+N/+eWXG23flPfff58VK1YQHh6OmZkZX331VYPf33777Zibm7fbcbZ0n/DXXWFRUVHs2rVLu6yl9QT46+J4QUFBg3MzIUQrKUJ0IUeOHFEAZc+ePY1+d+LECWXUqFGKmZmZYmNjo0yfPl3JyclpsE56eroCKDNnzmy0/f/+9z8lKChIMTY2Vtzc3JQXX3xRqampabDOn3/+qQDKc88916L27tmzR4mIiFBMTEwUR0dHZcGCBUpJSUmDdeLi4hRAWbRoUaPtV69erfj6+ipGRkZKz549lffee0/RaDSN1gsLC1NmzJjRojYJ0R6Ki4sVQIlmojJCdUebvqKZqABKcXGxrg9TiC6rqXwtLCxUZsyYofTq1UsxMzNTjI2NlT59+ihvvPFGo3xUFEVRq9XKG2+8oXh4eChGRkZKnz59lK+++qrJ9+tomf35558rQJOvv79/Wx9na/Y5c+ZMBVDS09MbLC8oKFDmzJmj2NvbK2ZmZkpUVJRy6NChRtsnJSUpgLJ9+/arfibi5tNeWS45LkTbaq5PXN+vbOoVFRXVaD8t7WtmZWUpd9xxh2JlZaVYWFgot9xyi3Lq1Kkm29aSfS5atEgBlLi4uAbLKysrlaeeekpxcXFRjI2NlZCQEGXr1q2N3uPJJ59UVCqVkpSUdMXPqT4zm3v9PUvb+jhbs8/m/o5aUk9QFEV59tlnlR49ejTZBnHzkBy/PipFuY7HMwvRAcXGxtKtWzft1fUbacWKFTzzzDOcPn0aZ2fnG/7+TTl27BjBwcEcOXKk3ed+FaI5JSUlWFtbE81EDFSGbbrvOqWWXWyguLgYKyurNt23EOL/6DJf20NHzGxde+yxx9i9ezcJCQkyAl000l5ZLjkuRNvrapndGqGhoXh4eLB+/XpdN6VDqK6uxtPTk+eee45HH31U180ROiQ5fn1kDnTR5bzxxhusW7eOzMzMG/7ecXFxPPLIIx2qI75kyRLuuOMOKZ4LIYS4LrrM1/bQETNbl/Lz8/nkk0/417/+JcVzIYTo5LpaZrdUSUkJf/zxB6+++qqum9JhfP755xgaGjJ//nxdN0WITk1GoAshhGh3MgJdCCGE6Nxk5JoQQgjReUmOXx8ZgS6EEEIIIYQQQgghhBBCNEEK6EIIIYQQQgghhBBCCCFEE6SALoQQQgghhBBCCCGEEEI0QQroQgghhBBCCCGEEEIIIUQTpIAuhBBCCCGEEEIIIYQQQjRBCuhCCCGEEEIIIYQQQgghRBOkgC5EG5g1axYqlYolS5Y0WP7jjz+iUql01CohhBBCtITkuBBCCNF5SY4LIdqbFNCFaCMmJiYsXbqUwsJCXTdFCCGEEK0kOS6EEEJ0XpLjQoj2JAV0IdrIiBEjcHFxYfHixbpuihBCCCFaSXJcCCGE6Lwkx4UQ7UkK6EK0EX19fd544w2WLVvGuXPndN0cIYQQQrSC5LgQQgjReUmOCyHakxTQhWhDt99+O0FBQSxatEjXTRFCCCFEK0mOCyGEEJ2X5LgQor1IAV2INrZ06VLWrFlDUlKSrpsihBBCiFaSHBdCCCE6L8lxIUR7kAK6EG1s2LBhjB49mueff17XTRFCCCFEK0mOCyGEEJ2X5LgQoj0Y6LoBQnRFS5YsISgoCF9fX103RQghhBCtJDkuhBBCdF6S40KItiYj0IVoB/369WP69Ol88MEHum6KEEIIIVpJclwIIYTovCTHhRBtTQroQrSTV199FY1Go+tmCCGEEOIaSI4LIYQQnZfkuBCiLckULkK0gS+++KLRMk9PT6qrq298Y4QQQgjRKpLjQgghROclOS6EaG8yAl0IIYQQQgghhBBCCCGEaIIU0IUQQgghhBBCCCGEEEKIJkgBXQghhBBCCCGEEEIIIYRoghTQhRBCCCGEEEIIIYQQQogmSAFdCCGEEEIIIYQQQgghhGiCFNCFEEIIIYQQQgghhBBCiCZIAV0IIYQQQgghhBBCCCGEaIIU0IUQQgghhBBCCCGEEEKIJkgBXQghhBBCCCGEEEIIIYRoghTQhRBCCCGEEEIIIYQQQogmSAFdCCGEEEIIIYQQQgghhGiCFNCFEEIIIYQQQgghhBBCiCZIAV0IIYQQQgghhBBCCCGEaIKBrhsgREej0WjIz88nOzubixcvUlpaSllZGaWlpU3+ubq6Go1Gg0aj4fjx42RlZTFu3Dj09PS0LzMzMywtLbG0tMTCwqLRn62trXFxccHV1RULCwtdfwRCCCFEp6UoCqWlpWRnZ5Obm0txcXGzWV5WVkZFRYU2xzUaDVu2bCEgIAAvLy/09PTQ19fH2Ni4yfy+fJmTkxPdunXDzs4OlUql649BCCGE6LSqq6vJzs4mOzuboqKiZvvipaWllJeXo1arUavV2hwHGD9+vLY/bmhoiIWFxRWz3N7eHldXV5ydnTEwkFKZEKIh+VYQNxVFUbh48SKpqamcOnWK8+fPc+HCBW04X7hwgZycHOrq6rCxscHR0RErK6smA9bd3R0LCwtMTEy0wTxw4ED+97//MX78eFQqFRqNhrq6OiorK7VBn5+f36jzXlRURHZ2NjU1NVhYWNCtWzdcXV21r27duuHh4YGPjw+9evXC3Nxc1x+lEEIIoROlpaWcOnWK1NRUzp49q83v+izPzs6mvLwcExMTXFxcsLa2brKz7OjoiJeXF2ZmZujr62uzvLCwkN69exMSEoJKpUKtVlNdXa3N7ZycnEad95KSEi5evEhJSQlGRkbai+KX57mbmxs+Pj74+Phgb28vRXYhhBA3pZqaGtLT00lNTSU9PV2b4ZdneUFBAfr6+jg7O2NnZ9fkhWtLS0u6deuGubk5BgYG2hy3sLCgtLSUsWPHavvkNTU1lJWVUVZWRmFhIVlZWY2yPC8vj0uXLqFSqXBycmrQF6//b8+ePfHx8cHd3R19fX1df5RCiBtIpSiKoutGCNHWysvLSU5OJjU1tdGrpKQEd3d3evfujZubmzYQXVxccHJywtbWFhsbG/T09Kiurqauru6KL41GQ/0/o6qqKgCMjY1RqVTal76+PgYGBtr//v1laGiIsbExlZWVFBYWkp+fz8WLFxsU9jMyMkhJSaGkpETbCe/du7e2M+7r64u3t7cEueiQSkpKsLa2JpqJGKgM23TfdUotu9hAcXExVlZWbbpvIYRu1NXVkZaW1mSOZ2dnY2tri4+PD56eng06t05OTtjb22Nra4uRkVGLclytVgN/XWRXFIXq6mrgryzX0/trtkM9PT1tXjeX5cbGxqjVaoqKiigsLGyQ49nZ2Zw9e5ZTp05x4cIFbfv/nuV+fn6Ymprq7HMX4kraK8slx4XoehRF4cKFC032ydPT0zE0NKR37954e3s3KFA7Oztrc9zCwoLa2lpqa2uvmOF1dXXaDP97jtf3x+vvKGsqv+tfRkZG6OnpUVJSQkFBAfn5+eTk5GgL++fPnyctLY0zZ85gYGBAr169tPld//L398fe3l7Hn74QTZMcvz5SQBedXllZGceOHSMhIUH7Sk5OxsbGBl9f3wYd1B49euDs7IyiKJSVlVFZWUlVVRXV1dVUVVWh0WjQ19fHxMQEExMTjI2Nrxiy+vr66Ovra0eRVVdXc/DgQSIiIrSFbI1Gow325gK/traWqqoqbVsURdEW1evbYmZmhrm5OVVVVVy4cIEzZ840OBFJS0vD0NCQoKAgBg4cqH35+vpKUV3onBTQhRDNqaurIzExkYSEBI4cOUJCQgLHjh1DUZRGHVMvLy+6deuGkZFRgxyvf9XV1aFSqbQZbmJigqGhYZP5Xb/88hxXqVQUFBRw4sQJwsPDMTAwQFGURjn+959ra2u15xLV1dWo1Wrt1C/1OW5qaoqFhQWKopCTk0NmZqZ2JH1qaiopKSmUlZXRp08fgoODtTkeGBiImZmZjv+WhJCOtxCiaYqicPbsWW1fvD7L8/Pz8fLyapDjPXv2xM3NDWtrayoqKigvL2+Q4zU1NQAYGRlp89PIyKjZvnj9n+sL5fDXnWrHjh3T9skVRblin7z+VV1drc3y2tpaVCoVxsbG2iw3NTXF3NwcY2Nj8vLyyMrKanSx//z583h4eDBw4MAGWe7o6KjLvyIhAMnx6yUFdNGpqNVqjh8/zu7duzl06BAJCQmkpKTg7OysDacBAwbg6+uLmZkZ5eXllJWVaf+r0WgwMzPDwsICc3NzzMzMGhTL6zva16q2tpYtW7Ywbty4a95P/VXz+vCuf1VUVGhvO6upqcHIyEg7j5u5uTmmpqZkZ2dz8uTJBgUIPT09goKCCA4OJiwsjOjoaLp3737Nx3itPvzwQ9566y1ycnIIDAxk2bJlhIaGNrv++vXreemll8jIyKB3794sXbqUcePGaX//8ssvs3btWrKysjAyMmLgwIG8/vrrhIWFadcpKCjg4YcfZtOmTejp6TF58mT+/e9/yzzzOiAFdCFEvczMTHbt2sXBgwdJSEjgjz/+wMDAgAEDBhAcHExwcDABAQE4OztTWVmpzb7y8nJqamq085HX57ipqWmDHDcyMrqu6VGuN8sVRaGurq5BhldXV2tzvLy8nIqKCvT19bXHUf/f0tJSkpOTOXr0qLYQUVBQgL+/PwMHDmTQoEFERUXRp08f7ej4G0my/OYmHW8hBEBxcTF79uxh37592oJ5YWEhffr00fbJ+/fvj7u7O2q1ukF/vLKyUpt/9dlX3x+/vF9+PRnXFn1ytVrdYKBdVVUVlZWVDeoLiqJoawv1x6LRaDhz5kyDAX5paWm4u7trP5vIyEgGDx6MiYnJNR/jtZIcv7lJjl8fKaCLDq2+YL5r1y527drF7t27UavVDB06lNDQUAYMGICPjw8mJiYUFxdTVFRESUkJenp62rnL6zumFhYW2nlO20tbhHVL1NTUaMO7PsBLSkooLS3FyMgIGxsbrK2tsbCwIDc3V1tU379/P0eOHKFnz55ER0drX926dWu3tgKsW7eOe++9l5UrVxIWFsb777/P+vXrSUlJwcnJqdH6+/btY9iwYSxevJhbbrmFb775hqVLl3LkyBH69u0LwDfffIOTkxPe3t5UVlby3nvvsX79etLS0rRX+MeOHUt2djarVq2itraW2bNnExISwjfffNOuxysakwK6EDevs2fPsmvXLuLi4ti1axdZWVkMGjSIiIgIbbHcwcGB0tJSbZbX1dU1mLf88kJze+Yr3JgsV6vVjS7y18+lDmBlZYWNjQ1WVlaUl5eTkpLC0aNHOXjwIL///jsmJiZERUURExNDdHQ0AQEB7V5QlywX0vEW4uZUXzCv75MfPXqUXr16MWTIEAYNGkS/fv3o0aMH1dXVFBUVUVRURGVlJWZmZlhZWTXIcAsLC+3UKu3lRuS4oigNLvLXv0pKSqiursbCwgIbGxtsbGxQqVTaovrhw4fZvXs3BQUFhIeHa/vjYWFh7V5QlxwXkuPXRwrookNRFIWkpCR+/fVXbcG8rq6OYcOGER0dTUREBG5ubhQVFVFQUEBpaSl6enragnF9SJmbm+vk4Vw3qoDenLq6OkpKSigqKtIWIUpLSzE0NMTa2hp7e3uMjIz4888/2b17d4MToOjoaGJiYhg1ahR2dnZt2q6wsDBCQkJYvnw58Ne0Nu7u7jz88MM899xzjda/6667KC8vZ/PmzdplgwcPJigoiJUrVzb5HvVhsH37dmJjY0lKSiIgIIBDhw4xaNAgALZu3cq4ceM4d+5cu180EA1JAV2Im8fFixf55ZdftAXzs2fPEhISQnR0NEOHDsXf35/q6mry8/MpLi6mrq5OWzCuz3IrKyudTT+myyxXFKXBhYT6PFcUBWtra2xtbbG2tiYjI4Pff/+dXbt2sXfvXszMzIiKiiI6OprRo0fTu3fvNm+bZLmQjrcQN4eqqiri4uLYuXMnu3btajQAKzg4GENDQ/Lz8xsUy+v74vVZbmRkpJP26zrHq6qqGvTHi4qKtEV1W1tb7OzsKCoqIj4+nt9++424uDgKCwu1BfURI0YwePDgNj8PkhwXkuPXx0DXDRCitraWvXv3snHjRjZt2sT58+eJiYkhJiaGp59+Gnd3d4qKirRPxa6ursbe3p5evXrptFjeERkYGGBnZ9egAK5Wq7XhXVBQQF5eHiqVittvv525c+diaGjIn3/+yZ49e1iyZAkzZswgMjKSW2+9lQkTJlx3J7ympoaEhASef/557TI9PT1GjBjB/v37m9xm//79PPHEEw2WjR49mh9//LHZ91i9ejXW1tYEBgZq92FjY6MNaoARI0agp6dHfHw8t99++3UdlxBCiL8oikJiYiKbNm1i48aNHDx4kAEDBhAbG8uyZcsICAigurqavLw8CgsLSU1NxcHBge7du9OnTx8sLS3lWR3/n0qlwsrKCisrK9zd3QG0z22pz/FTp05RVlZGeHg4t9xyS4OC+oYNG3jyySfx9vZmwoQJ3HrrrYSHh1/35ytZLoQQXdvFixf56aef2LhxI7/++iuOjo6MGjWKxx57jODgYIyMjMjPzycvL4+0tDTs7e2xt7fHy8sLa2trnRXLOxqVSoWpqSmmpqa4urpql9cX1QsLC8nKyqKwsBAvLy8GDRrEG2+8oS2o79q1i2XLlqFSqRg/fjwTJkxg1KhR1z3dieS4ENdPCuhCJ4qKiti6dSsbN27k559/xsTEhFtuuYW3336boKAgSkpKyMvLIy8vj5qaGuzt7fHz88Pe3h5jY2NdN79T0dfX1xbVvb29tR3x+s83Pz8ffX19br/9du6//37q6urYtWsXmzZtYuHChXh7e2uL6dfSCc/Ly0OtVuPs7NxgubOzM8nJyU1uk5OT0+T6OTk5DZZt3ryZqVOnUlFRgaurK9u2bcPBwUG7j7/filZ/geHv+xFCCNE6tbW17NmzR1s0z87OZsSIEcyePZvPP/8cgEuXLjUomLu7uxMUFCQXvltJpVJpp7OpL6pXVVVpCxmXF9RvvfVWzM3NOXz4MD/99BO33XabthN+6623MmrUKCwtLVvdBslyIYToWpq6+D1o0CAmTJjAwoULcXBw4NKlS+Tl5XH69Gns7e1xcHDQDmLTxXM4OjMTExNcXFxwcXEB/rpzvLCwUPsw0vqCekhICEuXLuXMmTNs2bKFF154gWnTpjF8+HDthXE3N7dWv7/kuBDXTwro4oYpKSnhf//7H19//TVxcXEEBARw6623snnzZtzc3Lh48SIXL14kJSUFFxcXKZi3k8s74l5eXg0K6hcvXuTSpUv4+Pjw5ptvYmFhQUJCAps3b+b2229HURQmTZrE9OnTGTp0qM5PnGJiYjh27Bh5eXl8/PHH3HnnncTHxzc5h5sQQojro1ar2blzJ19//TU//vgjpqam3Hrrrbzzzjvai985OTmcOnUKJycn3NzcpGDeTkxMTOjevbv2oeD1BfVLly6RkpKCubk5Dz/8MK+88goZGRls2bKFF198kbvvvpuRI0cyffp0Jk6ciJmZmY6PRLJcCCFupMTERL766ivWrVtHdnY2I0eO5B//+AdffPEFiqKQk5NDdnY2VVVVODs7S8G8nRgYGODo6KidJ7yurk57t/jp06cpLS1l4sSJzJs3j7KyMnbs2MG6det4+OGHCQwMZNq0aUybNk17HqBLkuPiZiEFdNGuampq+OWXX/j666/ZsGEDfn5+TJ8+nffeew9jY2NycnLIz8+ntrYWV1dXevfujbW1tXS0b6C/F9Tr6urIy8sjJyeHlJQUzMzMeOihh3jllVdIT0/nu+++Y/LkyZiZmTF9+nSmT5+ufYhIUxwcHNDX1yc3N7fB8tzcXO0V+L9zcXFp0frm5ub06tWLXr16MXjwYHr37s2nn37K888/j4uLCxcvXmywfv2JSXPvK4QQoiFFUTh69ChfffUVa9euRVEUpk2bxubNm3F3d+fixYvk5uZqL34HBQVhb28vU7LcYJcX1BVFoaioiJycHM6cOUNpaSkTJkzg/vvvp6ysjJ9++onXXnuNuXPnMmnSJGbMmMHw4cMxMGi+WyBZLoQQndeFCxf49ttv+eqrr0hOTmbChAm8/fbbBAcHU1RURG5uLqmpqTg5OeHl5YWzs7MMYrvBDAwMcHJywsnJiYCAACoqKsjJySEnJ4e8vDyCgoIYM2YMxsbG7N69m2+//Zbnn3+eYcOGMWPGDCZNmoS1tXWz+5ccF+L6yWVE0eYURWHfvn08+OCDdOvWjYceeghvb2/27t3L+vXrGTRoEGfOnCEvLw83NzdGjhxJdHQ0vr6+2qdUC90xMDDQFkFGjx5NeHg45ubm2k74vffeS0JCAsuWLSMjI4PQ0FCCgoJ46623OHfuXKP9GRkZMXDgQHbs2KFdptFo2LFjB+Hh4U22ITw8vMH6ANu2bWt2/cv3W11drd1HUVERCQkJ2t/v3LkTjUZDWFhYiz8PIYS4GaWnp/P6668TEBBAVFQU+fn5fPbZZxw4cIA777yTgoIC0tPTsbKyIjIyklGjRhEYGIiTk5MUz3VMpVJha2uLv78/MTExjBgxAldXV3Jzc8nMzGTIkCFs2rSJHTt24OTkxKxZs3Bzc+Pxxx/n8OHDKIrSaJ+S5UII0bmUlJTw+eefM2LECDw8PNi6dSuPPPIIiYmJPP/88xgbG2un7ggKCmLs2LGEhobSo0cPKZ53AGZmZnh7exMREcHYsWPx9fWlsrKSlJQUunfvznvvvceJEycYP348y5cvx8XFhTvvvJMNGzZQU1PTaH+S40JcPxmBLtpMbm4un3/+OR9//DGFhYVMmTKF9evX4+npyYULFzh//jzV1dV4e3vj6up6w5+ILVqvvhNe3xEvKyvj3LlznDp1CgMDA5555hkWL17Mb7/9xtdff83ChQuJiYlh/vz53Hrrrdq/4yeeeIKZM2cyaNAgQkNDef/99ykvL2f27NkA3HvvvXTv3p3FixcD8OijjxIVFcU777zD+PHjWbt2LYcPH2b16tUAlJeX8/rrrzNhwgRcXV3Jy8vjww8/5Pz580yZMgUAf39/xowZw9y5c1m5ciW1tbU89NBDTJ06VZ72LYQQTaiurub7779n1apV7N+/n1GjRvHSSy8RERFBfn4+2dnZpKWl4e7uTv/+/TvE9B/i6uo74d7e3tTU1HDhwgXOnTtHQUEBkydP5qGHHiIlJYW1a9cyfPhwunfvzv3338/MmTMbPJRcslwIITq2+oFsK1eu5LvvvsPf35/p06ezfPlyNBoN586dIzk5mW7dujF48GBsbW1l8FonYGhoqL3LTKPRcPHiRc6dO0dOTg4DBgzg1ltvpbS0lO+//55HH32Uf/zjH9x7773MmzcPPz8/7X4kx4W4PlJAF9dFURR27drFypUr+fHHHxk2bBiLFy8mNDSUS5cukZOTQ2ZmJm5ubgQHB2NqaqrrJovrYGFhgZ+fH76+vhQWFnLu3DmSkpJwcXHhvffew8DAgB9++IEnn3ySBQsWcN999zF37lzuuusuLl26xD//+U9ycnIICgpi69at2oeSnD17tsG8ehEREXzzzTe8+OKLLFy4kN69e/Pjjz9qp4rR19cnOTmZNWvWkJeXh729PSEhIezZs4c+ffpo9/P111/z0EMPERsbi56eHpMnT+aDDz64sR+aEEJ0cGlpaaxevZrPP/8cOzs77r//fj799FMqKys5f/48ycnJuLm5ERkZKdOsdXJGRkZ4enri6elJRUUF586d48yZM9oO7aJFi9i7dy+rV69m4cKFTJkyhfnz5xMeHi5ZLoQQHVRxcTFffvklK1eu5Pz589x7773s2bMHa2trzp07R1paGi4uLvTv3x8nJyeZz7wT09PT0z6MtLa2luzsbM6dO0deXh7jxo3jvvvuIz09nc8++4ygoCAGDx7M/PnzmTRpkuS4ENdJpTR1n6YQV1FWVsaXX37J8uXLyc3NZfbs2dxzzz0YGhqSmZmJnp4ebm5uuLm5YWVlpevm3jC1tbVs2bKFcePG3TQj7DUaDZcuXSIrK4ucnBysrKxwd3fn5MmTfPzxx/z888/ccsstPPzww0RHR0vh5SZVUlKCtbU10UzEQNW2/zbqlFp2sYHi4uKb6vtGiOuh0Wj45ZdfWLZsGTt27GDixInMnTuXXr16kZmZSVlZGd26dcPNzQ1HR8eb6rv7ZstyRVEoKSnh3LlznDt3DpVKhYeHB2VlZaxZs4Y1a9bQs2dPHn74YaZOnSqDIW5i7ZXlkuNCXJvExESWL1/Of/7zH/r27cu8efOIjo7WPp/EwcEBNze3m+7u75stx+Gvh4mfP3+erKwsysrKcHNzw8LCgh9//JFVq1ZRWlrKvHnzmDdvnoz8volJjl8fufQoWuXs2bM88cQTuLm58cknn/DUU09x+PBhJk+eTEZGBiUlJQQHBzNy5EgCAgK69D8e8Rc9PT2cnZ0ZNGgQo0ePxs3NjfT0dPT09PjXv/7FsWPH8PX1ZcqUKfTr14+PP/5YOyeaEEKIG6u8vJwPPvgAX19f/vGPfxAaGsrx48d54YUXqKmpITMzE09PT0aPHk1wcDBOTk43VfH8ZqRSqbC2tqZPnz6MHDmSfv36UVBQwPnz55kxYwbHjh1j7ty5vPPOO7i7u/P888+Tk5Oj62YLIcRNSVEUfvrpJ2JjYwkODqaiooJff/2VL7/8Ejc3N1JSUrCysmLEiBFERETQo0ePm6aIfDMzMTGhZ8+eREdHExkZiUqlIjk5mUGDBvHrr7/y6aefcvjwYby8vJg6dSqHDx/WdZOF6HSkgC5aJDk5mdmzZ+Pj48O5c+fYuHEja9euxd3dneTkZGxsbBg5ciRhYWHS2b6JGRoa4u3tTUxMDGFhYVRXV3P69GkmTJjAoUOHeOKJJ/j3v/+Nl5cX77zzDqWlpbpushBC3BQKCwv517/+haenJ2vWrOHll19m//79jBw5ktTUVNRqNREREURFReHp6Smd7ZuUnp4erq6uhIeHExsbi4WFBcnJyfj4+GjP/U6ePImXlxcPPPAAZ86c0XWThRDiplBXV8e3335LUFAQc+bMITY2lhMnTvDII4+Qn5/PxYsX6dOnD6NGjcLf31+eU3ITs7GxITAwkNGjR+Ph4UF6ejoqlYo333yTw4cP4+LiQlRUFKNGjSIuLq7Jh4cLIRqTArq4ovrR5UFBQejr6xMfH8+LL75ISUkJOTk5+Pv7M2rUKPz8/OSWXqGlUqmwt7dn0KBBjBw5EltbW1JSUujRowcbN25kxYoVrF+/Hg8PDxYtWkR+fr6umyyEEF1SdnY2zzzzDB4eHuzYsYP//Oc/rFu3DkdHR1JTU3FycmLUqFEEBwfLw8REA+bm5gQEBDBq1Ch69+7N2bNnqa6uZvHixezZs4fS0lICAgKYPn06f/75p66bK4QQXVJVVRWrVq3C19eXhQsXMm/ePPbv38/QoUNJTk5GX1+fqKgohgwZQrdu3WR+c6FlaGiIl5cXMTExhIaGUl5eTkZGBnfffTd//PEH4eHhTJ48mfDwcDZs2IBGo9F1k4Xo0OTbVTSiKAo7d+5k5MiRREdH4+HhwbFjx3jwwQe1nafIyEiGDh1K9+7dJaTFFZmYmODn58eoUaPw9fUlIyMDExMTvvzyS9atW8f+/fvx8PDg8ccf59y5c7purhBCdAlnzpxh/vz5eHt7k5KSwk8//cTKlSsBOHfuHH369GHEiBH07t0bY2NjHbdWdGT6+vr06NGDqKgoBg8eTGlpKdnZ2Tz99NMcPnwYa2trQkNDufXWW9m3b5+umyuEEF1CaWkpb7/9Nt7e3ixbtoxFixYRFxeHv78/KSkpODs7M3r0aAIDA2XaVHFFKpUKBwcHQkNDGTFiBKampiQnJzN69GgSEhK44447eOCBB+jfvz9ffvkltbW1um6yEB2SVD5FA7t27SIiIoI77riDIUOG8McffzB16lROnTqFSqUiOjqakJAQbGxsdN1U0cno6enh7u5OTEwMgYGBZGdnU1tby7///W9+/fVXsrKy6NWrF/Pnzyc7O1vXzRVCiE4pMzOTWbNm4e/vT1lZGXv37uWNN96guLiYS5cuMXDgQKKiouQCuGi1+rvLBg8eTFRUFHV1daSnpzNnzhyOHz9OQEAAY8aMYfjw4Rw4cEDXzRVCiE6poqKCxYsX4+Hhwffff8+KFSvYuHEjrq6unDp1Ck9PT0aOHImPj49MtyZazdTUlH79+mnvEk9KSiI0NJR9+/bx8MMP88orr+Dj48OaNWtQq9W6bq4QHYr0nAQAR48eZcyYMUycOJFbbrmFhIQERo0aRVJSEqampowYMYIBAwZgaWmp66aKTk6lUuHq6srQoUMJCQmhsLCQgoICFi1axP79+8nPz6dXr14sXLiQoqIiXTdXCCE6hUuXLvHYY4/h5+eHRqMhISGBp59+mgsXLlBWVkZERASRkZHynBLRJqysrBg4cCDDhw/HwMCA5ORkbr/9do4dO8aQIUMYMWIEkyZNIikpSddNFUKITqG2tpaVK1fSq1cvfvzxR9auXcuaNWswMTEhIyMDPz8/YmNj8fLyQl9fX9fNFZ2csbEx/v7+jBw5km7dupGcnEzv3r3Ztm0bL7/8Mi+//DJBQUFs2rRJ5kgX4v+TAvpN7vTp00ybNo0hQ4bQr18/jhw5QnR0NElJSdjZ2TFy5Ej69esn85uLNqdSqXB0dCQiIoIhQ4ZQWVnJ+fPnWbRoEdu2bSM+Ph5vb2/eeustKisrdd1cIYTokEpLS3nllVfo2bMnp0+fZvfu3Tz55JOkp6dTV1dHVFQUYWFh2NnZ6bqpogsyNzcnMDCQkSNHYmlpSWJiIuPHj+fo0aO4uroSHBzMnDlzyMrK0nVThRCiQ9JoNPz3v/+lT58+vP/++/z73//mm2++Qa1Wk52dTWBgIDExMbi7u8udY6LNGRoa0qtXL0aOHIm3tzdpaWm4ubmxc+dO5s6dy5w5cxg6dCh79+7VdVOF0Dn5Br5J5eTksGDBAvr06YOZmRlHjhzhzjvvJCkpCVtbW0aMGIGfn5/MiypuCFtbW0JDQ4mMjKSkpITCwkJWrFjB119/zbfffouPjw+ffvopdXV1um6qEEJ0CDU1NSxbtoyePXvy66+/smHDBt58801yc3OpqqoiKiqKgQMHyryo4oYwMTGhT58+jBw5EnNzc5KTk5kzZw4HDx6koqICX19fnn76aXlouBBCXGbbtm2EhobyxBNP8PTTT/Pzzz9jY2NDZmYmQUFBDBs2DFdXV7lzTLQ7fX19PD09iY2N1T4/JzAwkPj4eEaOHMnYsWO59dZb5aHh4qYmBfSbTGVlJa+++iq9evXiwoUL2rmuTp06haGhIbGxsQQEBGBkZKTrpoqbkI2NDREREYSGhpKTk4NKpWL9+vUsXbqUxYsX069fP3755RddN1MIIXRGURR++OEH/Pz8WLVqFatXr+aLL76gqqqK/Px8IiIiCAsLk8K50AljY2P69evH8OHDURSFjIwMFi5cyM6dOzl+/Dg9e/bk7bfflgeUCSFuaomJiYwcOZI777yTKVOmsHfvXnr16sWpU6fw9fUlJiZGCudCJ/T09PDy8mLEiBG4urqSmJjIqFGjOHLkCN7e3oSGhjJ79mxyc3N13VQhbjgpoN9ENm/eTN++fdmwYQNbtmzh9ddf58KFC9TW1hIdHU1QUJBM1SI6BEdHR4YNG0b//v1JT0/HycmJ7du388ADD3DXXXcxefJkzp49q+tmCiHEDZWamsrYsWOZN28eCxcuZNOmTZiZmXHu3DmCg4MZMmSITNUiOgRzc3MGDhzIsGHDKC8vJz8/nw8++ID//ve/fP755wQFBREXF6frZgohxA1VWlrK008/zcCBA+nbty8JCQkMGTKEpKQkevToQWxsLD169JDCudA5AwMDfHx8tFO0paSkcM8993D48GFKS0vx9fVl2bJlcoe4uKlIAf0mkJ6ezoQJE7j33nt56qmnWL9+PeXl5RQWFjJkyBBCQkLk4aCiw1GpVHTr1o3hw4fTq1cvUlJSGDBgAIcOHcLKygp/f3/eeOMNqqurdd1UIYRoV+Xl5bzwwgsEBQXRq1cv4uPj6dWrF2lpafj7+xMdHY2zs7N0uEWHY21tzeDBgxk8eDC5ubkoisLmzZuZPXs2EydOZNq0aZw/f17XzRRCiHalKApr167Fz8+PgwcPsmfPHmbMmEFiYiL29vaMGDGCnj17ysNBRYdjZGRE3759GT58OPr6+qSnp/Pqq6/y7bffsnz5cgYOHCjzo4ubhhTQu7DKykpeeeUV+vbti4uLC4cOHaJPnz6kpaURGBhIREQEtra2um6mEFekp6ennY/Nzs6O5ORknnjiCX7++WfWr18v07oIIbqs+ulaAgICiIuLIy4ujjlz5pCYmIirqyvDhw/H3d1dCueiw7O3t2fo0KEEBASQkpJCeHg4hw4dQk9PD39/f5nWRQjRZZ08eZLY2Fgef/xxlixZwqeffkpubi4ajYbY2Fj8/f0xNDTUdTOFuCIzMzMGDBhAZGQkeXl56Ovrs3XrVu666y7GjBnDzJkzZVoX0eVJAb2L+umnn+jbty+bN2/m119/ZcGCBSQlJeHo6Mjw4cPp1q2bdLhFp2JgYECfPn2Ijo6mtLSUiooKfvjhBx555BGmTp3KpEmTZFoXIUSXcerUKcaOHcv8+fN5+eWX+fLLL8nPz6empoaYmBh8fX1lpJroVFQqFe7u7sTGxmJtbU1qaioLFy7khx9+4IsvviAwMFCmdRFCdBllZWU89dRTDBo0iAEDBrBv3z7c3NzIzMwkJCSEkJAQmT5VdDo2NjYMHToUX19fkpOTiYmJ4dChQ9oHhn/wwQeo1WpdN1OIdiEF9C6moKCAGTNmMGPGDJ555hnWrVtHSUkJFRUVREdH4+/vj4GBga6bKcQ1s7S0JDw8nH79+pGamkpgYCCHDh3C2tqavn37snr1ahRF0XUzhRDimqjVat59913tdC0HDhzAy8uLM2fOEBwcTFhYGObm5rpuphDXzNDQkL59+xIVFUVhYSFqtZpNmzZx3333MWHCBObPn09paamumymEENds586d9OvXj4MHD7J3717uvvtuTp48iZubGzExMTg5Oem6iUJcM5VKhYeHB7GxsZiZmZGWlsYrr7zC2rVrWb58OZGRkSQnJ+u6mUK0OamkdiEbN25k3rx5hISEEB8fT05ODmlpaQQFBeHi4iIjzkWXoVKp6N69O87OzqSkpJCUlMSTTz7JlClTmDdvHt999x2ffPIJPXr00HVTxd+oo4NQGZi07T7rqmDXhjbdpxC6kJqayj/+8Q9yc3P56aefsLGxITExkd69e9OrVy8ZcS66FCsrK4YMGcK5c+c4efIkYWFhxMfH8/DDD9OvXz8+/fRTYmNjdd1M0YS2znLJcdFVlJWV8eyzz7JmzRoWL17MuHHjSE5OxsnJidjYWBlxLroUIyMjAgMD8fDw4Pjx4+jp6fHrr7+ybNkyBg4cyCuvvMLjjz8u568dkOT4tZER6F1AQUEB99xzDzNnzmTx4sW8/fbbpKamYm9vz/Dhw3F1dZXiueiSLp/WpaCgACMjI3bv3o2Hhwf9+vXj448/ltHoQogOT61W89577xEcHExISAjbtm2jurqaiooKma5FdGmXT+tiYWHBmTNnWLVqFU8//TS33XYbDzzwgIxGF0J0Crt27aJ///6cPHmSAwcOEBwczOnTp2W6FtHl1U/r4uPjw8mTJ5kxYwZbtmxh9erVDB06lJSUFF03UYg2ISPQO7lNmzYxb948goODiY+PJzs7m6ysLCIiIrCzs9N18zq9uro6qqqqqK6upqqqSvuqra1FURQURUGj0Wj/XFxcDEBCQgJ6enro6emhUqm0Lz09PYyNjTExMcHExET7Z2NjY/T0Ot/1rA8//JC33nqLnJwcAgMDWbZsGaGhoc2uv379el566SUyMjLo3bs3S5cuZdy4cQDU1tby4osvsmXLFs6cOYO1tTUjRoxgyZIldOvWTbsPT09PMjMzG+x38eLFPPvss5w+fZqTJ0/yyCOPcPvttzNv3jy+//57Pv74Y9zd3dvnQxBCiOuQlpbG7NmzycnJYdOmTdja2nLy5En69OmDh4eHXAC/ThqNplGGV1dXU11d3SC/L8/znJwc4K8s19fXb5TlRkZGGBsbY2pq2iDTO+NFjo6U48899xzdunXj6NGjBAUFceDAAR566CH69+/Pp59+yvDhw9vnQxBCiOtQVlbGc889x5o1a3jjjTcYN24cSUlJuLm5ERoaKg8IvU6KolBTU6PN78rKSm2uazSaJrP87zl+eV9cpVJhYGDQIL/rXwYGBp3yvKsjZfkjjzzCsWPHqKqq4pdffmHZsmUEBwfz6quv8thjj3XKcyUh6kkBvZMqLi7mkUceYePGjbz77rsMGTKE1NRUvLy88PPzky+mq1AUhcrKSioqKhp1qi//ua6uDpVK1WTB++9BrFKpMDc3Jy0tDXt7e/T09BoV2NVqNRUVFRQWFmrfo6amBqDJwvrlLwsLiw51ArZu3TqeeOIJVq5cSVhYGO+//z6jR48mJSWlyXn99u3bx7Rp01i8eDG33HIL33zzDbfddhtHjhyhb9++VFRUcOTIEV566SUCAwMpLCzk0UcfZcKECRw+fLjBvl599VXmzp2r/dnS0hKVSkWvXr1wdnbm6NGj2tHor7/+On379uX9999n1qxZnfKkSAjR9SiKwvLly3n++ee57777eOyxx0hNTaW8vJyYmBjMzMx03cQOr6amhrKysmYz/O8Z+/ecvTy/L/9zZWUlxcXF2NnZNcpyjUZDbW0tpaWlDd5XURQMDQ2bzO/6Zebm5piYmHSYHOpoOQ7g6OhITEwMiYmJpKen8/HHH7N161YmTpzIvffey1tvvSX/NoQQHcaePXuYOXMm7u7u7N+/n+LiYk6fPk1oaKjMc94CarW6QY7//VWf64qiYGBg0ChbjYyMGg1Wq8/YnJwc7O3tUalUjQrsdXV1FBUVNXgPtVqNvr5+oxy//GdTU1MsLCw6TI5Dx8tyMzMzwsPDyczM5OTJk9xzzz1MmDCBuXPn8sMPP7BmzRp69erV7p+LEO1Bpcj8Bp3O4cOHueuuu+jVqxcffPABubm51NTUEBwcLKPOm6AoChUVFRQXF1NUVERRURHFxcXU1tZiamrabMH678HcErW1tWzZsoVx48a1uNjd1Oi4pooB1dXVmJubY2Njg42NDdbW1tjY2OisqB4WFkZISAjLly/XHoe7uzsPP/wwzz33XKP177rrLsrLy9m8ebN22eDBgwkKCmLlypVNvsehQ4cIDQ0lMzNTO5+5p6cnjz32GI899lizbVMUhdOnT5OcnKy9On7fffcRHR3NqlWrsLKyuo4jF9eipKQEa2trhkYvwqCN50Cvq6tiz65XKC4ulr9b0Snk5+cza9Ys/vzzTz777DPs7Ow4f/48AQEBeHp6dqiOWUdRU1PTIMOLioqoqKi4Yn7/vVjeUq3N8stHx13ponxlZSXGxsba/K5/6aqo3pFzHODSpUscPXoUc3NzrK2teeCBBygsLGTdunX06dPnGo9aXI/2ynLJcdHZqNVq3njjDZYsWcLrr7/OrbfeSnJyMt27d6dPnz4datBTR6FWqykpKWmQ5SUlJejr62v75M31y42NjTEwaPnYz2vJ8fo7z5vK7/qR71VVVQBYW1s3yHILCwud3U3ekbO8oqKCY8eOUVpaiq+vL++99x5ffPEFq1atYurUqddx1OJaSY5fn843Z0Qbqx+RumTJkgbLf/zxR1QqFWVlZRgaGrJ27doGv586dSoqlYqMjIwGyz09PXnppZfapa2KovD+++8TFRXF/fffz4oVKzh16hR2dnbExMRI8Zy/PqPy8nLOnz/PyZMn2bdvHz///DM7duwgNTWV6upqXF1dGTx4MOPHj2fkyJEMHTqU0NBQ+vfvj4+PDz169MDJyQkrKyvtSPP2pKenh6mpKba2tri6uuLl5YW/vz8DBgxg8ODBREdHM2bMGMaMGUO/fv2wtLQkPz+fo0ePsmXLFrZv386hQ4c4deoUly5d0o62a081NTUkJCQwYsSIBscxYsQI9u/f3+Q2+/fvb7A+wOjRo5tdH/6600KlUmFjY9Ng+ZIlS7C3t2fAgAG89dZb1NXVNfh9/Wj0qKgoCgoKMDExYffu3eTn5xMcHMyRI0daecTX5mrfL/DXfImXj5y4/FV/+6EQonmdKccB9u7dS1BQEIaGhuzcuRO1Wq0dde7l5SXFc6C6upqLFy+SmprKwYMH2bZtGz///DN//PEHxcXFWFtbExgYyNixYxkzZgzR0dHazp+fnx+enp64urpia2uLqalpu3dqVSqVtjDu7OyMh4cHvr6+9O/fn9DQUIYNG8aoUaMYP348oaGhODs7U1lZSVJSEr/++itbt25l//79JCYmcuHCBSoqKtr9+R0dPcfh/0ajW1hYkJmZyX/+8x9uu+02wsLC+Oyzz27IM04kx4Vof50tx7Ozsxk1ahRfffUVcXFxhIWFaec6r8/3m51araagoID09HSOHj1KXFwcP/30E/v37yc7OxtjY2N8fHyIjY1l3LhxDB8+nIiICIKDg+nTpw89e/ake/fu2NvbY25u3qri+bVQqVQYGhpiaWmJo6Mjbm5u9OrVi759+zJo0CCGDBnCiBEjGD9+PMOGDdNOsZeZmcnu3bvZsmULu3fv5vjx42RmZlJcXIxGo2nXNkPHz/L60ei+vr6cPHmSOXPmsGbNGhYsWMD9999PRUVFK4/42kiWi7YiU7gAJiYmLF26lHnz5mFra9vgdxYWFgwaNIhdu3Y1uEq2a9cu3N3d2bVrF7NmzQIgPT2dzMzMdpmjsaCggNmzZ3Ps2DF+/vlnTE1NSUtLY/DgwTg4OLT5+3UWdXV1XLp0iYKCAu2V7Lq6OqysrLCxscHV1RV/f3+srKw6/bQ2xsbGODs74+zsrF1WXV2tHYlXWFhIeno6lZWVmJmZaa+IOzg4YGNj06ZFmby8PNRqdYO2ADg7O5OcnNzkNjk5OU2u31wgVVVV8eyzzzJt2rQGVzEfeeQR7d0W+/bt4/nnnyc7O5t333230T4sLS21Dy5JSUlh5cqVrFu3jqFDh7JkyRIeeuihdi9WXen75XIpKSmNrtbKrZ9CtExnyHGNRqMdqbZ06VJGjx5NYmIifn5+9OzZ86YtnCuKQmFhIZcuXdLm2eU5Zmtri6enJzY2NhgZGem6udfFwMAAOzu7BgMe6urqtCPyiouLSUlJobS0FENDQ+3oNjs7OxwdHdv0PKaz5LihoSGBgYG4uLhw5MgRJk+eTGRkJDNnzmTHjh2sXLlSO/1Le5EcF6L9dYYcB9i2bRszZsxg5MiRfPrppyQnJ2Nvb09MTMxNXTgvLy8nNzdXm2X1OVZ/17Svry82NjaYmpp26vMdlUqFlZVVg+96RVEoLS3VnsNkZWXx559/oiiKdqS6ra0tTk5OmJi07V24nSHLVSoVnp6eODo6cvjwYWxsbNi7dy/33XcfYWFhrFu3joCAgGs5/FaRLBdtQQrowIgRI0hLS2Px4sW8+eabjX4fExPDDz/8oP05KSmJqqoqHn300QaBvWvXLoyNjQkPD2/T9v3+++9MmzaN4OBg4uLiOH36NIaGhkRHR2NsbNym79UZVFZWkpOTQ25uLpcuXcLU1BQHBwe6d+9OQEBAlyiWt5SxsTFOTk4NvtT/XlRPTU1FX18fFxcXXFxc2rwT3h5qa2u58847URSFjz76qMHvnnjiCe2f+/fvj5GREfPmzWPx4sVN/ntQqVT4+flhb2+vvUIfERHBjBkz2LlzJ5999tkVQ/R6Xe37pZ6Tk1Ojq/pCiJbp6Dmem5vLPffcQ3p6Ojt37kRRFDIyMm7aB37X1dVx8eJFbZYrioKjoyO2trZ4eXlhbW3d6YvlLdVUUV2tVlNcXKzN8j///JPq6mocHR1xcXHB2dm5zTvhba0tcxz+6txHR0eTkJCAoaEhe/fu5YEHHmDgwIGsW7eOAQMGtNuxSI4L0f46eo7X1dWxaNEi/v3vf/PBBx8QHh7OiRMn6NOnz0059ZqiKBQUFJCTk0NOTg4VFRXaLHNxcekSxfKWuryo7u7uDvz1+ZSVlWkvKKSnp3Ps2DFsbGy0ffL6Z3h1ZG2Z5ebm5gwdOpTExETOnDnDV199xccff0xYWBjLli1j5syZ7fp5SJaLtiAFdEBfX5833niDu+++m0ceeQQ3N7cGv4+JiWHx4sVkZ2fj6upKXFwckZGRDB8+nFWrVmnXi4uLIzw8vM06NRqNhjfffJPXXntN+0TvxMREfH196dWrV4f/wm0riqJQXFysDeiSkhJtOPfp06fdRx51Nn8vqms0GvLz88nJyWmzTriDgwP6+vrk5uY2WJ6bm4uLi0uT27i4uLRo/fqgzszMZOfOnVedQyssLIy6ujoyMjLw9fVtdr36W8ETEhKoqalh165dPP744wwYMIC1a9cyePDgK77Ptbra94sQ4vp11BwH2LFjB9OnT2f48OGsXr2alJQUbG1tiY6OvqlGq9Vf/M7JySEvLw8zMzNcXFwIDQ3F1tZWZ3OHdkT6+voNiur1o9tycnLIzMzkjz/+uO5OeGfMcVNTUyIiIrR3la1atYpvv/2WyMhI3nzzTR588MF2OTeWHBei/XXkHM/KymLatGkUFxeze/duKisrOX/+PEOHDsXa2rrN3qej+/vFb/jr4qa/vz+Ojo431TnN1ahUKiwtLbG0tNQW1auqqsjNzSUnJ4fU1FSMjY21OW5vb39N50GdLcv19PTo27cvDg4OHDlyhClTpjB06FBmzZrFjh07+Oijj7CwsLjaYV8TyXLRFqS38v/dfvvtBAUFsWjRoka/GzJkCEZGRuzatQv468p2VFQUAwcOJC8vj/T0dAB+++03YmJi2qQ9ZWVlTJkyhdWrV7Njxw7CwsJIT08nIiKC3r17d/niuVqtJjc3lz/++INff/2VvXv3UlpaSs+ePRkzZgyRkZH06tVLiuctoKenh6OjI/369WPEiBEMGzYMW1tbMjMz+fXXX9m9ezepqamUlJS0eD5RIyMjBg4cyI4dO7TLNBoNO3bsaHbER3h4eIP14a/bIC9fvz6oT506xfbt27G3t79qW44dO4aenl6Lbq2qH5Hi4eFBUlIS7777Lo888gixsbF8+umnV93+Wl3p+6Wem5sbFhYW2pc8IE2I1uloOa4oCu+++y4TJ07ktdde45///CcnTpzAx8eHkJCQLt/RVBSFoqIikpOT2bVrF9u2beP8+fM4OjoSHR1NbGwsffr0ueZO482kfnSbj4+Pdj51Dw8PCgsL2b17N9u3b+fPP//k0qVLLZ5ztbPmuJ6eHv7+/oSFhXHq1CnGjBnD5s2beeONN5g9e7b2AW9tTXJciPbX0XIc/roTfNCgQfj5+bFp0yZyc3MxMTEhOjr6piieV1ZWkp6ezv79+/n5559JSkrC2NiY0NBQRo8eTXBwMN26devy5zRtwcTEBA8PD8LCwhg7diz9+vVDrVaTkJDAzz//zOHDhzl37lyrnmfWWbPcxcWFmJgYysrKMDY2Zs+ePZw7d46IiIhGzzRoS5Ll4nrJCPTLLF26lOHDh/PUU081WG5mZkZISAi7du1i2rRp/Pbbbzz99NMYGBgQERHBrl27UBSFs2fPtklgZ2RkMHHiRBwcHNi2bRtpaWnY2NgQHR3dpW9prqmp0Y5Ou3jxIkZGRri4uDBgwADs7e07/LQjncHlt5j5+Phc8Uq4g4PDFS/UPPHEE8ycOZNBgwYRGhrK+++/T3l5ObNnzwbg3nvvpXv37ixevBiARx99lKioKN555x3Gjx/P2rVrOXz4MKtXrwb+Cuo77riDI0eOsHnzZtRqtXYuNjs7O4yMjNi/fz/x8fHExMRgaWnJ/v37efzxx5kxY0aLp2FRqVT4+Phop3SJjIxkw4YNTJ06lePHj/POO++0y4Nqmvt+qbdnz54GF4TkRFSI1usoOV5VVcX8+fPZtm0bv/zyCyqVinPnzhEZGdmlbwvVaDRcunRJm+V1dXU4OTnRs2dPnJ2du/Q5zI1U3wn38PBArVZrP/OEhATtXKj1d5ldKUs6a44D2gsxR44cQa1Ws3PnTu69917tNA+urq7X+vE2S3JciPbXUXIc4LPPPuPhhx/mrbfeYvjw4Zw4cYL+/fvj7u7epQezFRcXk52d3ejO7379+rXb6OCbzeXTq9YPOMjJyeHUqVMcOXIEe3t7XFxccHV1xczM7Ir76qxZbmpqypAhQ0hOTiY1NZXPPvuM9957j5CQEL777juioqKu9eO9IslycT2kgH6ZYcOGMXr0aJ5//nntPGr1YmJiWLduHSdPnqSyspLg4GAAoqKiiIuLQ6PRYGZmRlhY2HW1Yffu3UyePJlp06bx+OOPc/LkyS49ZUv9/GkZGRlcuHABS0tLXF1d8fX1xcrKqksec0dypU64np4eHh4e9OjRA1NT00bb3nXXXVy6dIl//vOf5OTkEBQUxNatW7UPJTl79myDUYURERF88803vPjiiyxcuJDevXvz448/0rdvXwDOnz/Pxo0bAQgKCmrwXnFxcdo5/9euXcvLL79MdXU1Xl5ePP744w3mYGspe3t7oqOjOXToEPr6+toT8rFjx7Ju3bo2n5f4St8vAF5eXl26sNZRLF68mB9++IHk5GTtdABLly5tcKthVVUVTz75JGvXrqW6uprRo0ezYsWKRg/cER1PR8jx7OxsJk2ahEajYefOnWRlZWFpaUlUVFSXPQkvLy8nMzOTs2fPolKpcHV1lYvfN8iVOuHHjh3Dzc0NDw+PJh8m3tlz3MTEhPDwcJKTk0lLS2PdunX885//JCQkhB9//JFBgwa1ep9XIjnecUiWd10dIcfr6up46qmn+Oqrr9iwYQOWlpZkZWUxbNiwq05j0VnV1tZy/vx5MjIyKCsrw9nZWS5+3yAqlQpbW1tsbW3x9/enoqJCOxDh5MmTODg44OnpiYuLS5N37HXmLNfT0yMgIAB7e3sOHz7M/Pnz6du3L+PGjePdd99l3rx5rdpfS0iWdwydNcelgP43S5YsISgoqNG8TTExMfzrX//im2++ITIyUtshHDZsGKtXr0ZRFO2tZddq9erVPP7447z33ntERkaSmJhISEhIlzzRq66uJisri8zMTKqrq3F3dycqKqrLnpR0Bpd3wjUaDbm5uWRmZpKSkoKTkxMeHh44Ozs3COCHHnqIhx56qMn91d9iebkpU6YwZcqUJtf39PS86hQywcHBHDhwoOUHdRVGRkbahwBlZWWxadMmHnvsMUJDQ9m4cWObPxG8ue8XceP89ttvLFiwgJCQEOrq6li4cCGjRo0iMTERc3NzAB5//HF++ukn1q9fj7W1NQ899BCTJk3i999/13HrRUvoMscPHz7MbbfdxvDhw3n11Vc5efIk3t7e+Pn5dbkLwhqNhuzsbDIzM8nLy9PeMebk5NTljrWz+HsnvKioiMzMTPbt24eZmRkeHh64u7s3uJDT2XNcpVLh7++PlZUVR48e5cUXX6R///5ER0fzySefMHXq1DZ7L5Ac7ygky7s2XeZ4QUEBd911Fzk5OezatYtLly5RV1dHVFRUlyskK4pCYWEhmZmZnD9/HktLSzw9PenevXuXveDfGZiZmeHt7Y23tzeVlZVkZWVx8uRJjh8/jru7Ox4eHo3uBOjsWe7s7MywYcOIj4+nf//+bN68mTvvvJPjx4/z/vvvt/n/j5LlutdZc1wK6H/Tr18/pk+fzgcffNBgeUREBMbGxixbtowXXnhBuzw0NJSLFy+yYcMGnn/++Wt6z9raWh5//HHWrVvH5s2bMTMz48KFCwwbNqxLzfFdP9o8PT2d7Oxs7Ozs8PX1xdXVVUaodTB6enq4urri6upKZWUlmZmZ/Pnnnxw/fpwePXrg6enZ5Kj0zkhPT4/+/ftjZWXFiRMneOedd/jiiy8IDw/n66+/5pZbbmmz92ru+wXg4sWLjeZutbe3lxPYNrZ169YGP3/xxRc4OTmRkJDAsGHDKC4u5tNPP+Wbb75h+PDhAHz++ef4+/tz4MCBdnvYrGg7ushxgLVr13LfffexaNEiJk6cyIkTJxgwYADdu3e/5n12RBUVFaSnp3P27FkMDQ3p0aMHwcHBbfrANtE2bGxssLGxoU+fPpw/f57MzExOnjxJ9+7d8fLyatWUKR1d9+7dMTc3195S7ufnx4wZM/jzzz957bXX2myefcnxjkGyvGvTVY4nJSUxYcIEAgIC2LRpE0lJSXTv3p2+fft2qWd11NXVkZWVRUZGBhUVFbi5ud10D0TtLExNTfHx8aF3795cunSJzMxM4uLisLOzw9PTE1dX1y7z/6alpSXDhg3j8OHDaDQafvvtN6ZNm8aoUaNYv349Dg4ObfZekuW611lzvGv8a2tjr776aqOHMJmYmDB48GBKS0uJjo7WLjc2NtYuv5b51oqLixk7dix79uxh9+7dKIqCWq3uUsVztVrN2bNn+e2334iPj8fExISYmBiGDBmCm5ubFM87OFNTU/z8/Bg5ciRBQUEUFxezfft2EhISKCws1HXz2oynpyfh4eGkpqZyxx13sHLlSqZOncp7773Xpu/T1PcLoL2YdPkrISGhTd+7qyspKWnwqq6uvuo2xcXFANopexISEqitrWXEiBHadfz8/OjRowf79+9vn4aLNncjc1xRFBYtWsT8+fP59ttvGT58OOnp6URGRnaZ4rmiKOTl5XHw4EF27NhBeXk5gwYNIjY2Fh8fHymed3AGBgZ4eHgwbNgwoqKiMDAw4Pfff2f37t2cP3++xQ8e7ehsbGyIioqioqICS0tLdu3axfr165k0aRIVFRVt9j6S4+3nWnIcJMu7ohuZ4wDbt29n8ODB3HXXXbz33nucOHECf39/+vfv32UKlBUVFZw4cYJffvmFzMxMevbsyejRowkMDJTieQenUqlwcnIiJCSEUaNG4ezsTGJiItu3b+fUqVOtevBoR2ZkZMTgwYNxdnYmIyODH3/8EXt7e0JDQ0lNTW3T95Isbx9dPcdVytXuzxDtJicnh7Fjx+Lq6sqHH35IUlISPXr0ICAgoEsEdVVVFRkZGWRkZGBoaIi3tzfu7u7t8oDGjqK2tpYtW7Ywbty4Ln2VsqysjPT0dDIzM7GyssLb25tu3bp1if9vKyoqiI+Px8jICD09PSZOnMisWbNYsmRJlzg+XSkpKcHa2pqh0YswMGjbYltdXRV7dr3SaPmiRYt4+eWXm91Oo9EwYcIEioqK2Lt3LwDffPMNs2fPbhT2oaGhxMTEsHTp0jZtu+jc6urqePDBB/n555/ZsGEDpaWlqFQqQkNDu0RRWa1Wc/78ec6cOUNFRQUeHh54eXld9YFWnd3NkOW1tbWcPXuWM2fOoNFo8PLywtPTs0tMUaBWqzl+/Di5ubn4+Pgwa9YsNBoNGzdubPPnm9xs2ivLrzXHQbJcXL+1a9cyZ84cVqxYQVBQEBcuXCA0NBR7e3tdN+26KYpCfn4+Z86cITc3FxcXF7y9vbGzs+vS063dDDmuKAo5OTmcOXOGwsJC3N3d8fLy6jJT4tbfAe/n58cnn3zCp59+yk8//URoaKium9apSY5fn65byezgTp06xejRoxk6dCgvv/wyJ0+epF+/fnh4eOi6adetoqKClJQUzp07h4ODA8HBwTg6OnbpkL7ZWFhY0K9fP/z8/Dh79ixJSUmcPHmSXr164enp2anvKjAzM2Po0KEkJCRQVlbG9u3bue2228jNzeWTTz7psidhXUFWVlaDk0ZjY+Mrrr9gwQJOnDihDWohWqOyspK7776b1NRUtm3bxtmzZ3FwcCAwMLBTfwfCXxcG0tPTOX369E1zAfxmY2hoSM+ePfH29tZ2wFNTU+nRo0env6tAX1+foKAgzpw5Q2JiImvWrOGJJ55g6NCh/PLLL7i5uem6iaIZrc1xkCwX1+ff//43L774Iv/973+xt7cnPz+fqKioTn+huL64mpKSor0APmLEiC4zBadA+9B2V1dXiouLOXPmDL/99hsODg74+fl1+mnaPDw8sLS0JD4+nnvuuQdnZ2diY2P57rvvGD16tK6bJ5rR1XNcekI6kJCQwNixY5k1axb3338/J0+e7BIPC62urubUqVNkZGTg6upKdHR0l5mGRjTt8g54dnY2ycnJnDlzBj8/P9zc3DrtRRMDAwNCQ0M5fvw42dnZbN26lTvvvJOJEyeyfv167YMtRMdiZWXV4lEXDz30EJs3b2b37t0NiikuLi7U1NRQVFTU4Ans9aN2hAAoKipiwoQJqNVqNm3aREpKCh4eHvj7+3fa7z34awTI2bNnSUlJwcTERB4KehP4ewc8JSWF7du307NnT3r16tVpLxqrVCp69uyJiYkJR48e5Z133mHJkiVERETwyy+/4O/vr+smiia0JsdBslxcO0VRWLhwIR9//DFbt25Fo9FQV1fH0KFDO+33Xr38/HwSExMpLy/Hx8eHHj16yAXwLs7a2poBAwYQEBDA6dOn+f3333F2dsbPz69T12Ps7OwYOnQo+/fvJyoqipUrVzJp0iRWr17N9OnTdd080YSunuMyH8ENtm3bNmJiYnj22WeZNWsWp06dIiIiolMXz+vq6rQdrtLSUoYOHcrAgQM79Ze1aB2VSkW3bt2IiYnB19eXpKQkdu3aRW5u7lWf4t1RqVQq+vfvj4eHB2lpafzvf/+jsrKS2NhY8vPzdd08cY0UReGhhx7if//7Hzt37sTLy6vB7wcOHIihoSE7duzQLktJSeHs2bOEh4ff6OaKDujChQvah219/fXXJCYm4uPjQ0BAQKctNCuKwoULF9i5cydpaWn07duXYcOG4ezs3GmPSbSetbU1oaGhREREUFBQwPbt20lLS0OtVuu6adese/fuhIWFkZSUxFNPPcXMmTOJjIyUebA7OclycT3q6uqYM2cO3377LTt27KC6uhojIyPCw8M7dfG8uLiYAwcOcODAAZycnBgxYgTe3t5SPL+JGBsbExAQwIgRIzAyMmLXrl0cO3aMyspKXTftmllYWBAZGUlxcTE9e/bku+++44EHHuDdd9/VddPEdeisOS7fpjdQ/fxqH330Ef369ePcuXNERkZ22kKzRqMhMzOTlJQUzMzMCAsLa9OnI4vOR6VS0aNHD7p3705GRgZHjhzB0tKSgICATjnvqEqlws/PD2NjY06ePMnnn3/OU089RWRkJL/88gs9evTQdRNFKy1YsIBvvvmGDRs2YGlpSU5ODvBX4cjU1BRra2vmzJnDE088gZ2dHVZWVjz88MOEh4fr7GnfouNISUlh9OjRxMbG8uKLL3LixAmCgoI69ZQQly5dIjExkcrKSu3DeeR5Dzc3Ozs7IiIiuHjxIomJido7y9zd3TvlBRVHR0eGDBnCgQMHuOuuu3B2dmbUqFGsXbuW8ePH67p54hpIlotrVVFRwV133UVmZia//vorGRkZODk5deqHhZaXl5OcnMyFCxfw8vJiwIABLZo2QXRdJiYmBAYG0rNnT5KSktixYwdeXl707t27Uz7rxNTUlMjISOLj4zE3N+eXX35hwoQJ5OTkyHPKOqnOmuNSQL9BVq1axVNPPcV///tfHBwcKCwsZOjQoZ1yHjJFUTh//jzJycmoVCoCAwNxcXHplJ0q0T709fXp2bMnPXr0IC0tjX379uHo6Ii/v3+nfLCJl5cXxsbGHDlyhDfffJO3336biIgIdu7ciY+Pj66bJ1rho48+AiA6OrrB8s8//5xZs2YB8N5776Gnp8fkyZOprq5m9OjRrFix4ga3VHQ0x44dY+TIkcydO5d//OMfJCYmEhoaipOTk66bdk2KiopITEyksLCQ3r17yyg10YBKpcLZ2RknJyfOnz9PUlISaWlp+Pv7d8pzPhsbG+3I8/DwcD755BPuvPNOPvnkE6ZNm6br5olWkiwX16KkpITx48ejUqnYsGEDSUlJeHl54efn1+m+0+Cv6VNTU1PJyMige/fuxMbGdvq520XbsrCwICQkRHvOt337du05X2d7Xo+hoSHh4eEkJCRQWlrKjh07mDhxIvn5+axevbrTHc/NrrPmuPSUboDly5fzwgsv8NNPP6FSqaipqSEyMrLTXf1TFEU7Uq26ulo7Gkmu+InmGBoa4u/vj5eXF6mpqfz222+4ubnh5+fX6S4edevWDSMjI+Lj43nsscewsrIiOjqanTt34ufnp+vmiRZqyZRCJiYmfPjhh3z44Yc3oEWiMzhy5AgjR47k6aefZsKECdrp1zrjA5rKyspITk4mJycHLy8vBg0a1OnOR8SNo1KpcHNzo1u3bmRkZPDHH3+QlpZGQEAA9vb2um5eq1hYWDB06FAOHDhAjx49WL9+PXfeeSdqtZoZM2bounmiFSTLRWsVFxczZswYrKysWL16NX/++ScBAQF4e3vrummtVltby+nTp0lLS8PR0ZGoqKhOOUBJ3Dg2NjaN7izz9fXtdHcd6uvrExISwh9//KF9TtmECRP4xz/+wWeffSZF9E6ks+a4FNDb2Xvvvccrr7zCTz/9hFqtxtDQkNDQ0E73j7uwsJDExESKi4vx8fHBy8ur0x2D0B0TExP69+/f4DYyT09PfHx8OlXhxsHBgcjISPbt28esWbMwMDDQFtEDAgJ03TwhRDs4dOgQo0aN4oUXXmD06NFkZWUxdOhQLCwsdN20VqmqqtLOHejm5kZsbGynu5ApdEdPTw9vb2969OjB6dOnOXDgAPb29gQEBHSqwo2JiYl2Ohdra2u+//577rjjDtRqNTNnztR184QQ7aCoqIhRo0bh6OjIhx9+yJ9//tkpp19Tq9Xa6VMtLCwIDw/vdBcyhW45OTnh6OjIhQsXSEpK4vTp0/j7++Pq6tpp7sKonwEhKSmJ9PR0Nm3axG233ca9997LmjVr5G5K0a7k/6529O677/LKK6+wefNm6urqMDU1ZdCgQZ2q8FxbW8uJEyc4f/483t7ehIaGduqHqwjdMjc3Z9CgQRQXF2tvI+vbt2+nmlfV2tqaIUOGsG/fPu6++25qa2sZNmwYv/32G3369NF184QQbejgwYOMHDmShQsXMmrUKLKzs4mMjMTc3FzXTWsxRVFIT08nMTERJycnoqOjO+2zV4TuGRgY4Ovri6enp/bOMk9PT/z9/TtNp7X+NvD6uVTXr1/PHXfcgUajYfbs2bpunhCiDRUVFTF8+HAcHBz48MMPOXHiBMHBwXTr1k3XTWuV/Px8jh49ip6eHgMGDJCHfItrplKp6N69O66urpw9e5bjx49z5swZBgwY0GnOb1UqFf7+/ujp6XH69Gk2bNjA+PHjmTFjBl999VWnOR8RnU/nuV+jk/nggw947bXXeOuttygpKcHExISQkJBOVTy/ePEiO3fupLKykuHDhxMQECDFc9EmrK2tCQ8PJzg4mMTEROLj4zvV08GtrKwYMmQImZmZREZGMn36dGJjY0lOTtZ104QQbSQhIYHRo0ezYMECAgICOmXxvLy8nH379pGWlkZYWBihoaFSPBdtwtjYmH79+hETE0NRURG7du0iPz9f181qMQMDA8LCwgCoq6tjyZIlPPLII/znP//RccuEEG2luLiYUaNG4eTkxPz58/nzzz8ZOHBgpyqe19XVceLECfbv34+npycxMTGd8jkUouPR09PD09OTESNGYGVlRVxcHGfOnGnR1BodgUqlws/PD29vb5KTk3n11Vf5888/mTVrFmq1WtfNE12UFNDbwYoVK/jnP//J5s2b6d27NyqVCrVa3Wm+jGprazl27BiHDh3C19eX8PBweSCJaBcuLi4MHz4cQ0ND4uLiOHv2bKf5d6JWq9FoNOjp6TFv3jzmzp3L8OHDSU1N1XXThBDXqf6BoS+99BJ33XUX+vr6aDSaTnNCXj/qPC4uDgsLC2JiYnB0dNR1s0QXZGFhQWRkJF5eXuzfv58///yTuro6XTerRRRFQa1Wo6enR2BgID/88AMPPvgg33zzja6bJoS4TiUlJYwZMwZHR0dWrlypHQTWWb6f4K9R57t27aKgoICoqCh69eolhXPR5gwMDOjfvz9hYWGcPn2a33//nfLycl03q0UURaGurg49PT2srKzYsGEDCQkJzJkzB41Go+vmiS5ICuht7LPPPuP5559n06ZN1NbWYmZmRmxsLBqNhvj4+A7f+a4fdV5RUUFMTAyenp4S1KJdGRkZMXDgQAYMGNBpRqMXFRWxb98+fH19GTZsGGfPnmX69OnMnDmTmJgYMjIydN1EIcQ1SkxMZMSIETz33HOMHDmS3NxcoqKi8PT05Pfff6e0tFTXTbyi+lHnp06dIiwsjMDAQLl7TLQrlUpFz549iY6O7jSj0Wtra9m/fz9GRkaMGDECPT09zMzMWL9+Pffffz/ff/+9rpsohLhGFRUVjB8/HisrK+20LYMGDWLw4MH88ccfZGVl6bqJV6RWqxuMOh86dKjcPSbanaOjIzExMVhaWnaK0eiKopCYmMi5c+eIioqiZ8+enDp1ig0bNrB//37mz5/fodsvOicpoLehjRs38sgjj/DDDz+g0Wi007YYGxszePBg1Gp1hy2iy6hzoWuurq4NRqNnZWV1yNCrL577+PjQq1cvLC0tiYiIID09nVmzZjF58mRGjx7NpUuXdN1UIUQrZWVlMXr0aB588EHGjx/PhQsXGDJkCObm5vj5+eHh4dFhi+gy6lzoWv1odE9Pzw49Gr2+eG5oaEhoaChGRkaEhYWhKApWVlZ8/fXX3HvvvezatUvXTRVCtFJdXR1Tp04FYNWqVdo5z11dXXF0dCQsLKxDF9ELCgqIi4uTUedCJwwMDAgMDNSORt+3b1+HHI1+efF8yJAhWFhY4Ovri5eXF2fOnGHDhg1s3bqVf/7zn7puquhipIDeRvbu3cvdd9/NF198gYmJCYaGhoSEhKCn99dHbGho2GGL6BcvXiQuLo7y8nIZdS506vLR6CdPnuTgwYNUVVXpullafy+e17OysiIiIoLTp0/z2GOPERQUxPjx4ykrK9Nha4UQrVFQUMDo0aO1DyHKysrSFs/h/+Za7IhF9IqKCu2o89DQUBl1LnRGpVLRq1cvoqKiKCws7HCj0f9ePK9/NpGBgYH2PN3V1ZVly5YxceJEjh07ptsGCyFaTFEU5s2bR3p6OmvWrOHEiRMEBQU1mPO8oxbR60ed79u3Dw8PDxl1LnTK0dGR6OhoLCwsOtxo9KaK5/V8fX1xd3fn7NmzbNiwgRUrVrB8+XIdtlZ0NVJAbwMnTpzg1ltv5e2338bDw4O6uromHxja0Yrol4867927NxERETLqXPDhhx/i6emJiYkJYWFhHDx48Irrr1+/Hj8/P0xMTOjXrx9btmzR/q62tpZnn32Wfv36YW5uTrdu3bj33nu5cOFCg30UFBQwffp0rKyssLGx4cUXXyQsLAwDAwN27tzZIUajN1c8r2dtbU1YWBiJiYksWbIEKysrJk+eTE1NjQ5aK4RojYqKCm655Rb8/f155plnOHXqFOHh4Q1OyqHjFdEvH3Vubm5OTEwMTk5OOm2T0L2OkOOPPfYYAwYM0I5GP3HiRIc4722qeF6vvoheWlrKwIEDee655xg7dixnzpzRUYuFEK3x4osvsn37dr777juSk5MJCAjAzc2t0XodrYheUFDQYK7z+meoiZtXR8jx+fPn07NnT8LCwkhLS+sQo9GvVDyHv87TAwICcHR0pLCwkA0bNvD888/z3//+V0ctFl2NFNCvU2ZmJqNHj+axxx4jIiKC4uJiBg8e3OzIr45SRP/7qHMvLy8JasG6det44oknWLRoEUeOHCEwMJDRo0dz8eLFJtfft28f06ZNY86cORw9epTbbruN2267jRMnTgB/FaWOHDnCSy+9xJEjR/jhhx9ISUlhwoQJDfYzffp0Tp48ybZt29i8eTO7d+9mwYIFHWY0+tWK5/Xs7e0ZOHAgJ0+e5OOPPyYvL49//OMf8hATITqw2tpa7rzzTgwNDXnnnXdITEwkNDQUa2vrJtfvKEX0y0edh4SEEBQUJKPORYfK8Xnz5mlHo18+LYEuXK14Xs/IyIjw8HBycnK47bbbuOuuu674+QkhOoYPPviAVatWsWHDBjIzM/Hy8sLb27vZ9TtCEV2tVnPy5En27dtHjx49iIyMlFHnokPl+P3336+dG71+NHp6erpOBrZdrXheT6VSERgYqB0Y+s033zB79mx27NhxI5sruiiVouthnZ1YXl4ekZGRDB8+nEcffZT09HSGDh2qvd37Smprazlw4AD6+vqEhYU1eyLf1hRFISkpiTNnztCnTx+ZrqUVNBoNVVVV2ldNTQ1qtRpFUVAUBY1GQ2lpKefPn6d3794YGBigUqnQ09NDpVKhr6+PqakpxsbGmJiYYGRk1OE++7CwMEJCQrS3Omk0Gtzd3Xn44Yd57rnnGq1/1113UV5ezubNm7XLBg8eTFBQECtXrmzyPQ4dOkRoaCiZmZn06NGDpKQkAgICOHToEIMGDQJg69atjBs3jnPnztGtWzdqamo4fvw4ly5dIiQkBAcHh3Y4+qa1tHh+uczMTE6cOIGPjw9jx45lwoQJvPPOOx3u7/tGKikpwdramqHRizAwMGnTfdfVVbFn1ysUFxdjZWXVpvsWXZuiKPzjH/8gISGBDRs2cPLkSYKDgxvc7n2lbZOTk8nMzGTIkCE3tNObk5NDQkIC3bt3p0+fPlI4byFFUaiurqa6ulqb5Wq1Go1G0yDLU1JSAPDx8dFmeX2O12e4iYkJxsbG2qn6OoqOmuOKopCWlkZKSgq+vr43dF7flhbPL1dSUsLevXvx9fXlpZdeIjU1lbi4uJu+uNVeWS45Lq7H2rVrmTt3Lj///DM1NTXY2toSFBTUou+YS5cuER8fT2BgIO7u7jegtX+pqKggPj4ePT09BgwYIP/ft5CiKNTV1TXok9fW1mrzuz7Ls7KyKC8vx8fHB319fW1/XE9PDyMjI22Gm5iYYGBgoOvDaqCj5jj8NQjz2LFjWFtbExwcfMPOP1taPL9cXV2d9mHhSUlJPProo8TFxREcHHwDWtxxSY5fn471bdGJlJeXc8stt9C3b1+eeuopkpKSiIyMbFHxHP5vJPqBAweIj4+/IUX02tpajhw5QmlpKVFRUTd9J+ByGo2GsrIyysrKGgRyVVWVtqNdPxVHfdgaGxujr6+v7Vjr6elRUVEB/HVSpFKpGnTILw/7uro6VCpVg/D++8va2hoTk7YtNF5JTU0NCQkJPP/889plenp6jBgxgv379ze5zf79+3niiScaLBs9ejQ//vhjs+9TXFyMSqXCxsZGuw8bGxttWAOMGDECPT094uPjuf322zEyMmLQoEFkZGRw4MAB+vbti6en5zUfa0tdS/EcwMPDg6qqKk6fPs2PP/5IbGwsLi4uPPPMM+3YWiFEay1cuJC4uDh++eUXkpKS6NOnT4uK5/B/I9EBfv/99xtSRL+8CBkUFNTkrek3K0VRqKqqori4uFF+X/6zoigYGhpq89fAwEDbsa5/1au/Vbk+y9VqtXaf1dXVANqO+OVF9fo/W1paYmFhccMKxR05x1UqFb1798bR0ZH4+HhKSkoICgq6Iee+rS2ew1/PNgkLC2P//v288cYbzJ07l0mTJvHTTz9hZGTUrm0WQrTcjh07mDNnDv/9739RFAVzc3MCAwNb/L1bPxI9Pj4e4IYU0fPy8jh06BDdu3enb9++He5CrC7V1tZSXFxMRUVFszmuVqvR19fXZm79oLTLs7w+v8vLy1GpVNriukajoaamRrs/RVEwMDBoNsfNzc2xsrK6YYMdO3KOAzg5OREdHc3hw4fZs2cPYWFhLa5/XatrKZ7DX9OyhYWFsXfvXoKCgnjhhRcYO3Ys+/bto2fPnu3aZtF1SQH9Gmg0GmbOnImxsTFvvfUWJ0+eZPDgwc3e7t2cG1lELy8vJz4+HhMTE4YNG3ZTn/zXF8uLioq0r5KSEgAsLCwwNTXFxMQEMzMz7OzsGoTp1Uab1dbWsmXLlqs+wK2urq7RCUFVVRXl5eXk5+dTUVFBeXk5xsbG2NjYYGNjg7W1NTY2NpiYmLRLZzwvLw+1Wo2zs3OD5c7OziQnJze5TU5OTpPr5+TkNLl+VVUVzz77LNOmTdNemczJyWk0Z6+BgQF2dnaN9uPp6YmFhQWHDh2iuLiYfv36tdtJ57UWz+v5+PhQXV1NTk4OGzZsYOTIkfTq1YtJkya1Q2uFEK316aefsnr1anbu3ElGRgbe3t54eXm1ah83soiuVqs5duyY9u63+k7PzUhRFCorKykqKqK4uFib5TU1NQ1yvL6I/fdO8dXOternD71Slms0mgY5fvmfS0pKqKqqorS0VNtBrc9wa2trLC0tb9oct7GxISoqioMHD7J3715CQ0MxNTVt1XG21LUWz+vZ29szaNAgDh8+zMcff8ykSZN48MEH+fjjj2/qO8qE6CiSk5OZPHkyH374IQ4ODtTU1DBo0KBW9w1uZBE9IyODEydO3LDBQB1ZTU2NNsPr/1teXq4tXNdnt62tbaMBZ/V3hzWnJTmuKAo1NTVN9skLCgqorq6mrKyM2tpaLC0tG2S5lZVVu4xc7ww5bmRkxODBgzl58iS//fYbISEhODo6tuo4W+pai+eXtzU8PJw9e/Zwyy23kJ2dzS233MKBAwdaXbsTAqSAfk1ee+01EhIS2L59u/Z272udUuJGFNEvXbrEoUOHcHd3p0+fPjfVVe76aVXqO9fFxcXaK671Aejl5dWuHdqmGBgYYGBgcMUrtrW1tZSUlGjbfuHCBUpLS7VF9fr229jYtFvnsy3VzzOsKAofffTRNe/HwcGBqKgo4uPj2b9/P4MGDcLY2LgNW3r9xXP4q7DWr18/Dh8+TFVVFV988QUzZ86kZ8+eBAYGtml7hRCt8/vvv/PII4/w448/UlBQgLOzM76+vte0rxtRRK+srOTgwYOoVCqioqJu6N1JunZ5sfzyLK/v0FpbW2v//tqrQ9sUPT09TE1Nr5i/9ecg9YWB9PR07QX7ywvqNjY2N/Qc5Fq1VY6bmJgwZMgQ/vjjD3777TfCwsKwtbVtw5Zef/G8nouLC/369ePEiRN8/fXXxMTEsHz5ch5++OE2ba8QonUKCwuZOHEiDzzwAMHBwdqLy9f6b729i+gajYYTJ05w/vx5Bg8efEOno+wIampqGl30rqiowNTUVNufdXd3x8bGps37dc1RqVTaAXLNTTnx9wv2ubm5pKSkUFtbi4WFhbbt7VlUb0ttleN6enr069cPKysr4uPjCQgIaPNn6l1v8byeqamptoj+8MMPk5yczN13383GjRtv2J0Fouvo2P/CO6Dvv/+ed955h507d5KWloavr2+Lb/duTnsV0RVFISMjg5MnT9KvXz88PDyue5+dQW1tLbm5ueTk5HDx4kU0Go022Ly8vLCxsbmht1RfK0NDQ+zt7bG3t9cuq6ura3ClPjs7m9LSUiwsLHBxccHFxQU7O7trOjYHBwf09fXJzc1tsDw3NxcXF5cmt3FxcWnR+vVhnZmZyc6dOxucpLi4uDR6KEpdXR0FBQXNvq+ZmRlDhw7lyJEj7N69m7CwsDaba6stiuf1VCoVwcHB7N27F29vb55++mkmTpzIoUOH2u1KvRDiys6ePcukSZNYunQp1tbW1NbW0r9//+vKhPYsohcWFhIfH4+TkxOBgYE3xcm+RqMhPz+fnJwccnJyqKys1I7+cnV1xc/PD2tr6w7/Wejp6WFtbY21tTU9evQAGt8Fl5mZyfHjx9HX18fZ2RkXFxccHR2vaV7RzpTj+vr6DBgwgDNnzvD777+36fzDbVU8r+fh4UFZWRnnz59n/fr1jBkzhoCAAGJjY9ukvUKI1qmrq2PatGn4+Phw3333kZqa2iZ3WLdXEb2mpoZDhw5RU1NDVFSU9uGGXZmiKJSWlmpzvLCwEDMzM+1FYw8PD6ytrW9YsfxaqVQqzMzMMDMz09Z86qeMq8/x3NxcUlNTqa2txcHBQdsnv5YBbp0px+GvfKy/O7ykpIT+/fu3yWDNtiqe17O0tCQkJIT4+HhWrFjB2LFjWbhwIUuXLr3utoqby80zFLkN/PHHH8yaNYsvvviCiooKHBwcrrvAVq++iK5Wq4mPj0etVl/X/jQaDcePHyclJYXw8PAuXzwvLy/n9OnT/P777/z888+cOnUKc3NzwsPDGT9+PJGRkfTt2xd3d/c2HeX1+OOPY2lphZmZOSYmZjg5/nX7lJOTMyYmZpibW2Bv78CRI0fa5P0MDAywt7enZ8+eBAcHM3z4cMaNG4e/vz/V1dUcPHiQrVu3cuTIES5cuEBtbW2L921kZMTAgQMbPKFao9GwY8cOwsPDm9wmPDy80ROtt23b1mD9+rA+deoU27dvb3BBoH4fRUVFJCQkaJft3LkTjUZDWFjYFT+LkJAQ3N3d2bNnD9nZ2S0+1ua0ZfG8nr6+PqGhoeTm5nL33XcTGhrKHXfcoZ1TXwhx45SXlzNx4kRuu+02YmNjKS4uJiQkpE1O9uuL6B4eHvz++++UlpZe9z6zsrL4/fff6d27NwMGDOjwBePrUVtby7lz5zh8+DBbt24lISEBtVpNv379GDduHDExMQwYMAAvLy/s7Oza7LPYtm0bVpbWmJiYYWRkgqGhMfb2f13gdHBwwsTEFHMzC1566aU2eT89PT2srKzo0aMH/fv3Z+jQoYwbN47Q0FCMjY1JSkpi69at7N+/n/T0dCorK1u8786W4yqVip49/x975x3YVn397edeTe+9tx3PeMSJYyfODmGXFkp5C6VAKJRRKLuMQgeklD1aaCHQ9kdpy2pLKbuF7MSOncTOcLz33kO2bGvd+/4hy7EjOYQktgzV81fie3X1lSzr3PP5nvM5CeTm5nLkyBGOHj2KLMsn/XodcabFcxtpaWl4enqiVCp54YUXuOyyy6irqzsj13bhwsWX47777qO5uZkXXniBiooKli5desZ8mG0i+qFDh2hpaTnt6+l0Onbs2IFKpWLVqlVfa/FckiR6eno4cuQIn3/+OTt37mRgYICYmBjOPfdczj77bHJzc0lKSiI4OPiMiedDQ0MEBQahUqlRKpQoFEr8/PwB8PPzR6lUoVarSVu48Iw8nyAIuLm5ERYWRmpqKsuXL+fcc89l3bp1BAUF0dbWxmeffcb27duprKxkcHDwpGPbVy2Og9XubPXq1ZN5tG1GzKlypsVzG0FBQaSlpVFVVcU777zDK6+8wl//+tczcm0X/zsI8uneqf6P0NPTw9KlS7nuuuu48MILGR4ePq02sZkwmUzs3bsXhUJxypXoBoOBffv2YTabyc3N/VoGalmWGRgYmNzVHhkZmbbjO1ev2cfHF4NRwM8vAUEUcdNqefaZu7nr7qcZGzMgSSa6Og8SFBSEUqnEzc0NHx8fAgMDCQsLIyYmhpSUFJYuXUpCQsJpiziyLNPf3z/5vtg2ek52J/ztt9/mmmuuYfPmzeTm5vL888/zzjvvUFlZSUhICFdffTURERE89thjABQUFLBmzRoef/xxLrzwQt566y1+/etfU1JSQnp6OiaTie985zuUlJTw4YcfTvNn8/f3n6wUOf/88+nq6uLll1/GZDJx7bXXkpOTwxtvvHFSr7u9vZ2SkhISExNJSko6pQ2S2RDPp9Lf309BQQELFy7k29/+Nrm5ubz88svzvhPiTDFbE7/hf2fqt4vTQ5Zlvvvd79LV1cVrr71GeXk5q1atOuOfGVmWqayspKmp6ZQr0W3JQ1NTEzk5OXa+lF8X9Hr9ZLzq6+vDy8trMl75+vrOyffj8uXL2bt377Sfubm58eabb3LFFVdMCtgqlQoPD0/c3d3w9PQkMDCQoKAgoqKiSEhIIDs7m5ycnDMi4oyMjEy+L/39/Xh7e0++Lz4+Pid8X76qcXxkZISioiI8PDxYsmTJKVXgz5Z4PvX6O3fuJCQkhD/96U/85z//obCw8H8q7sxWLHfFcRcny2uvvcbdd9/N9u3baW1tJSUl5UvPLzkZenp6KCoqOq3umI6ODkpKSkhISCA5Oflrec8/tfO7q6sLhUIxGa8CAwPnxNLk5Zdf5uabb0bUaBFVGmtO7ubG65t/z9U33MyoXo/FMIZsNuHm5oYoimg0Gry8vPD39yciIoKkpCTy8/NZuXKlnZ/4qWA0Gqd1xCuVymnvy4ni01c1jpvNZkpLSxkYGCAvL++UPMZnSzyfev1Dhw4xODjI2NgYl112GVu3biU3N/eMPs98xhXHTw+XhctJYDQa+c53vsOyZcu44oorqK2tZc2aNbNSCXa6di5DQ0MUFRXh5+fHsmXL5r0P15fF1u7c0dGBJEmTvqfBwcGnlGydLgqFiEKhQqv1QZItKBXWNSgVbqjUSgSsN0o9PT14eIQwPDxOW1s/JvNRJMv0CmRvb18GBvpOS0QXBGHS9mXhwoWTSXh7eztHjhzB29ubyMhIoqKiHO76f/e736Wnp4ef//zndHZ2smjRIj799NPJQNvc3Dxtffn5+bzxxhs89NBD/PSnPyUxMZH33nuP9PR0ANra2nj//fcBWLRo0bTn2rZtG2vXrgXgb3/7G7feeitnnXUWoihy6aWX8tvf/vakX3d4eDgeHh4UFRUxPDzMokWLvtRnf7bFc7DeoGRmZlJWVsYbb7zB2rVrycrK4kc/+tGsPJ8LFy6m8+ijj1JcXDw5vyQnJ2dWbvBO187FZDJx4MAB9Ho9q1evPuPJg7MZHx+nubmZ1tbWyc3vsLAwsrOznbLhbzAYQBCIuOj7CAoFgiCiVVvjR8RFVzJmMNKz8xOMQ30MDg4wODgAQE1tHTKALMFkLYrArl07Wbly5WmtydPTkwULFrBgwYJpSXhdXR1KpZLw8HBiYmIcfn6/qnHc09OT1atXs3///klrti/z2Z9t8Rys9+h5eXns3LmTW2+9lfLycq688kree++9r3V3iAsX84XCwkJuueUW/vWvf9Hb20t4ePisiOdwenYusixTXV1NTU0NixcvPm271/mGxWKhvb2d5ubmaZvf+fn5c7b5PRXbDI3ISzbiGZsEgEZhXUPCD+/FYJHpLdpK97YPGRsfR+Xlx5h+jP6BAZqamigtLQXg2WefBVHkogsvnIx7p4parSYqKoqoqCgkSaK3t5fOzk4OHTqE0WgkJCSE6OhogoOD7d6vr2ocVyqV5OTkUF1dza5du770Z3+2xXOw3qNnZmayZ88egoKC2LRpExdffDH79+//2v2dupgdXBXoJ8HNN99MUVER7777LmVlZeTn5+Pv7z+rz3kqlehnogp3PmJr625qamJkZISIiAiioqLw9/ef1YGow8PD7Nu3j9LSUurq6mhtbaWrq4uBgQFGRkYYGxtjWDeMBRmVuxeCQomb1o0/b36Ra268lbGxUSSTEfPYCACBQQvx9AxBpXJHpfZAoXRDFERkZDrbD9DTXYYknZ51z4kwGo10dnbS3NzMwMAAoaGhxMTEEBQU9LX5rNhsbCwWC3l5eSflPTcX4vlUjh49SmdnJ0qlkgsuuICPPvpo8sbl64yrAt2FM/n3v//N97//fbZu3crAwACxsbEkJSXN6nOeSiW6rQrX3d2dnJwcp2wMzwayLNPV1UVTUxNdXV0EBgYSHR1NSEjIrL5Gm+9saWkp1dXVtLS0THqx6nQ6xsbGMRgMjI2NknrvUwii9V5LoxD4xdI4Ht7XgMEiU/9/z2Do6cRzQRo+C5dgGR/FMqrHPDqCWa/DrBvCONCLWa/jl7/8Jb/4xS9m5fXYkvCWlhba29vx8fEhJiaGiIiIr03BxKl0X8yFeD6V7u5uiouLWbhwIeeddx7f+c53ePTRR2f1OecLrso1F86ira2NJUuW8OCDD5KXl4fJZGL58uWzmgvCl69EN5vNHDx4kP7+/lOuwp2v6HQ6GhsbaW1tRaPREBMTQ3h4+KxvfldUVFBcXEx5eTnNzc20t7fT19eHTqdjVD9qnRGmGyLq0uvwSrTatBwfx3t2/4ee3f9B5eNP4s0PASBLEpbxUcz6YcwjOky6QTo/e5eI0JAzYt/jCJs3fGtr66QQHhMTQ3R09Cl5ps9Xvmz3xVyI51MxGAzs2LGDmJgYnnjiCcrKyti1a9e89+Q/E7ji+Onx9bjbnkXefPNN3nnnHXbv3k15eTlZWVmzLp7Dl69Er6uro7KykiVLlhAWFjbr65sLhoaGqK+vp62tDS8vL2JjY4mIiJgTQaG3t5ewsAjM5qlV4oJV/FZ5oFK5M24YQ5LBLTyGuKt+DBzb7Y6//m4MFhnT0AA1L22yvp7xNgZHW7CMjyJbzNOeTxCVs578qtVqoqOjiY6OZmRkhKamJg4cOIBSqSQ2NpaYmJjTHr7jbDQaDStWrODw4cPs2LGD/Pz8E36Bz7V4DlYfVZ1OhyAIPP3001xxxRUcOnToa2vR4MKFs2lsbGTjxo28+uqrjI+P4+/vT2Ji4qw/75etRO/v72fv3r3ExMSQlpb2tdjYHB8fp6mpicbGRgCio6NJT08/Y161X0Ra6kLq6mun/ERAqdQgiipEhQpJsmA0jAIgmUwoNI7vsySjERnQBIbinZzp8Jzh6jJa3v0Tq1atOsOv4hiiKBIcHExwcDAZGRm0trZSX19PWVkZkZGRxMfHn7Hhtc5CEAQWLlyIt7c3xcXFZGRknHCOz1yL5wDBwcGkpqZSVVXFW2+9xerVq1m1ahXnnXferD+3Cxf/i5jNZr73ve9x3nnncfbZZ9PS0sLq1atnXTyHL1eJbjQaKSwsRBRF1qxZ87UQ4ywWC21tbTQ2NqLT6QgPDycvLw9/f/85uU+55557eOaZZ6b9TBAUCKK1Y0xGRpKsM78k08zzpWzHRPWx34kgiijdPVG6e0JQGJLZTMcnb08O/Z4NBEHA29ubtLQ0UlJSJosLqqqqCA4OJi4uzmFV+leNsLAwVq1aRVFREXq9nuzs7Bn/XudaPAerZpCXl8euXbv4+c9/zmWXXca9997Lb37zm1l/bhdfbVwC+gmoqanhxhtv5PXXX6erq4vo6OgzNo37ZDhZEb26upra2lry8/MnW5i+qsiyTEdHB/X19QwODhIZGcmqVavmfPdekiTMZiORUSsIC1+CWuONUqnFYjFiMukxmUZpadpNT/dRJNPMgzKkKQJ81P+7AW1QKLIsIxkNWEaHMY0MYx4eonvnxyjG9XPx0gBrq/TChQtJTU2lo6ODhoYGqqqqiIqKIi4u7iu9ayiKIllZWWi1Wvbs2cPy5cvx9fW1O88Z4jlYb5xycnLYsWMH69evZ/v27Vx11VV88sknc5IIuHDxv4TJZOLyyy/n8ssvJyMjg+7ubhYtWjRnicnJiuh9fX3s3buXlJQUEhIS5mRts8ng4ODkBnhgYCCZmZmEhITM+Xdce0c7gkKFbLEN1JYxm8cBAwqNdrLiHEA2m0DjuBLHGsvlaYn38RiH+kAQWLNmzZl7ASdArVYTHx9PXFwcAwMDNDY2sn379slB41/1BDwqKgo3NzeKioqQJMmhTYMzxHMb8fHxDA0NodfreeGFF7jqqqs4dOiQqwXchYtZYNOmTXR3d/Paa69x9OhRVq1aNafi9MmI6AaDgcLCQtzc3MjJyfnK2zqNj4/T2NhIY2MjKpWKuLg4oqKi5rwzbseOHZP/VmjcUHp4o/D0QunhicLNA4XWjd6924CTFdBnrrg1D1st2mzWJ7ONKIqEhYURFhbG2NjYpJ2MSqUiPj6eqKior3R3mbe3N6tWraKwsJD9+/eTk5Njdx/oDPHcho+PD9nZ2Rw6dIg//elPrFy5knXr1nHxxRfP2RpcfPX46v5FzjIGg4Hvfve7XH/99cTHxzMwMEBaWtqcr+NEIrosy1RVVdHQ0MCKFSu+0i1iZrOZxsZG6uvrAYiLiyM3N9dpFdFWWxOR/v5ahnTNGA06jIYRZPk4ixVRgXwSwRpAnHgtgiCg0GhRaLSo/YIA6N7xkVNEa1EUiYiIICIiYrLif8eOHV/5BNwmWikUCgoKCli+fPm0zSVniec2VCoVOTk57N69m8cff5wNGzbw5JNPcv/998/5Wly4+Drz4IMPMjY2xr333kt5eTlr1qyZ82Tki0R0W3t4eno6sbGxc7q2M8nxG+BRUVGsXbvWqRXRSqUCUVQQsuZSlF4+KD29Ubpbk25BFBnrbKXhtWeBEyfesskEknRCAd001I8ginO+SSAIAv7+/vj7+5OWljaZgCuVSuLj44mJifnKCjmBgYEsX76cwsJCJEmatrnkTPEcjvmo7tixg7y8PC688EK+973vsWXLlq/s++3CxXxk69atPPPMM2zfvp2qqioyMjKckvOeSEQfHx+noKAALy8vlixZ8pUuiBkaGqKurm5yAzw7O9up+aCts37BTQ+h9nXsAjBQWohlTI9s/oI4Dihm2CgHMA72A7B69epTXe4p4+bmRkpKComJibS1tVFfX095eTkxMTEkJCR8Ze1dtFotK1asoKCggOLiYpYuXTpNy3KWeG4jIiKC3t5eBgYG2Lx5M9deey3Z2dkn7Hxz8b+NS0CfgZ/85CcoFApuu+02jh49ytq1a50WDB2J6KIoUl5eTktLCytWrPjKVgxLkkRjYyPV1dW4u7uTnp5OaGjonL3XkiRx5MgRPvroIwoLC6msrKSjo5OxsTEQBAyM4hkdjZdXMkoP74ndbk8Ubu7oKg/RW/j5F+x2myb/PVPiLcsSpqF++hQqlEo1Xl4eREVFkZ6ezpo1a7jooovmpKLJtgublpZGY2MjJSUlk5Xqc2FbNBskJiYiiiIFBQUsW7aMgIAAp4vnNnx9fUlNTaW6upq//vWvbNiwgVWrVrFixQqnrcmFi68TH3/8MS+99BK7du2isrKSzMxMpw3knElE7+rqYt++fWRmZs5qy/Bs093dTXl5OQaDgfj4+DnfAG9qauLDDz9k165dlJWV0draxsiIHkmyIGq0+GbmOnzc1Lg8NV4fj8Uwbj1fNfNrMg72I1skRFGBm9aN4JAgkpOTycvL44ILLiA3N3fW7220Wi3JycmTCXhtbS01NTWkpKQQFRX1lRR1/P39yc/Pp7CwEIvFQlJSktPFcxtKpZKlS5eyc+dOfvGLX3DBBRewadMmfvnLXzplPS5cfN3o6uriyiuv5Nlnn8VoNE7Oz3AWjkT0sbEx9uzZg5+f3wltKuY7er1+Ig/ucMoG+PDwMJ988glbtmzh4MGDNDQ0MDiow2y2xmbLmB5mENBFlRrLmP6EcVwyG0EQEE/QuWAasgro3//+97nmmmvw8PAgLi6O5cuXc+6553LuuefOupCtUCgmXQ/6+/upq6tjy5YtxMXFkZiY+JW0W1Wr1axYsYLCwkKKioom47azxXMb6enp7Ny5k4yMjMmu1Z07d35t5hC5OLO4BHQH/Otf/+L111+f9D3Pzs6eM7/OmZgqou/duxdPT086OztZuXKlU79wThVZlmlra6OiogKFQkFWVhahoaFztrv92GOP8fzzz9Pb248k2fzIBdzcAvDwjEEQBxgZbkfjH0TEhVc4vMZYRzPIMuaJxNoRU6vTFTMI6OZhHQAWi4mQ0CzMZgPVNS0cOXKEN998k5tuugmVSkNkZDgffvjhrHdCaDQakpOTiY+Pp66ujoKCAoKCgkhNTf1KbtQkJCSgUCgoLCxk4cKFVFRUOF08txEfH09vby8Ajz76KFdccQUHDx78ym5YuHAxX2hra+Pqq6/mxRdfZGRkhNDQ0Dm1YHPE8SJ6UlLS5D1GRESEU9d2qgwODlJeXs7g4CCJiYnExcXNWYV/YWEhV1xxBW1tHdPmlWi1vri5B+Hp5cfQYAOW8VEko8HhJvbUn81UuSbLMsiS3fnHYxzoAVEEycLY+CjNLa00Nbfw3//+l02bNiEIIn5+fvz0pw9w9913n+rLPilEUSQqKorIyEja2tqorKyktraW1NRUwsLCvnKdZX5+fpMVbCaTid7eXtRqtVPFcxve3t6kp6dTWVnJ66+/zrp161i9ejXr16936rpcuPiqI0kSV199NWvXrmXNmjW0tLSwdOlSp39/TRXRDQYDDQ0NBAUFkZWV5fS1nQrj4+NUV1fT1NREZGQk69evn/WhoDZMJhP5+fkcPVpuLV5DBkCp1KLReOPmFoxOZx3maRrqwy3M8X2cLTZ/oYWLICKqTmTFZhXQBaUKVGp0Oh2HDh3i0KFDvPzKKyBJqNUaVq5cwZYtW07lJZ80giAQEBAwWfxVXl7O559/zoIFC4iPj//KWbuoVCqWL19OUVERe/fuxcfHh/b2dqeL52DdtLDZq953331861vf4qGHHuKJJ55w6rpczE++Wn95c0BjYyM/+MEP2Lx5M319fURERMwbP0OVSkVeXh5bt26lv7+ftWvXOv0L58siy/JkpZrJZJqsiprrG45f/epRTGaB8IhcvLwj8PQMw90jCEFQYDAM0diwjZHhdowDvTNeYzKRNp9gt9sWyEURQeH4z822240g0N9fi7t7EAEBybi7ByAq1EiSGf1IJw0N+3nooYd49913T+k1f1lUKhUpKSnExcVRVVXFjh07iIiIICUlZc5urM4UsbGxjI+Pc/jwYWJiYuaFeA7Wm6Ps7Gy2b9/ON77xDbZt28a1117Le++995W8CXfhYj5gGzb2jW98g9zcXNrb21m2bJmzlwUcE9FHRkY4cuQIGRkZX0nxfGRkhIqKCrq6uoiLiyMnJ2fOq6IeeOABmpqaCArOQDERK43GYfSjPQz010w716QbQBMYaneNqRXlMybe0jHrtpk7yWSM/b0gSwStPBdNYCiGvm4MvZ0YutoxDHQjyxL9A/384he/mHUB3YYgCERGRhIeHk5TUxOHDx+mtraWtLQ0AgMD52QNZwofHx/y8vLYvXs3bm5urFy50uniuY2YmBh6e3sxGo08/fTTXHnlla7h4C5cnCZPPvkkdXV1bN68mbKyMlauXDlvKkJtgnlJSclXVjw3mUzU1dVRW1tLUFAQa9asmfNCqTfeeIP9+/fj7h6Ml3cAZss4hrEBzOZxzObxY2K3IEyK244QJ2xZ5BPl5EYjAscsVR1hGuwHQcAzPpWob2/EMj6GobeT8Z4ODN3tjHW0YOhuZ+v27QwMDMzZ7DlfX1/y8/Pp6emhvLychoYGkpOTiY6O/kp1PNi0rG3bttHf38/q1avnjZbl5eVFVlYWZWVl/PnPf2bVqlWsW7fONRzchR0uAX0KZrOZK664gssvv5z09HS6u7vnbIjEySDLMtXV1QiCgJeXF0eOHJlxsOh8pL+/n/LycnQ6HUlJScTFxTlt7RER4bS1DREcmsWwro3W1kJGRjrR67umDf4064eRJcu0QWM2JoO6LCPLssMbJ1sgF5Uz3/BN7naLCnyWrsDY30NfTzMdHfuRJxJ3jZs1QK9aterUXvBpoNFoyMzMJCEhgcrKymltZF+V6fK2gXYRERG0trYSFRVFQECAs5cFWNvacnJyKCgo4LnnnmPt2rW88MIL3Hbbbc5emgsXX0l+9atfTRs2tnr16nlVqdPd3U1XVxfh4eFUV1cTFBTkVJ/wL8P4+DhVVVU0NzcTFRXFWWed5TRfzszMTHbs2kVP9xEA1D4BaILD8AlahiYwFJWvP42v/waw2qs4FNDVUwV0x4n3yVixWcZHJ6vU3aMX4BE9fRCsZDIy3tNB05svOSVZFEVxcgBcXV0dRUVFk57pX5X5OSaTibKyMvz8/BgZGaG2tpbk5GRnLwuwblRkZWWxY8cO1q1bx7Zt27j66qv55JNPvnKimgsX84HCwkI2bdrEli1bqKqqIi0tDV9fX2cva5KxsTEqKysJDQ2lu7t7Mrf4KmCxWCbtU728vMjPz3da5+t5550HosjoWA+agFC0obF4By9HExSGJjAUpac3zW+9jL6l3ipuz4BNQP+iCnSZEw8RNQ70giCi9rPmiAqtG+6RcbhHHhti3fGffzB4uHjOxPOpBAUFsXr1ajo6OigvL5/sLAsPD/9KxBqbliVJEr6+vhw9epRly5bNGy0rKiqKnp4eRkZGJoeDHz58eNKH34ULcAno03jqqacYHBzkvvvuo6ysjDVr1sybP2iAiooK2traWLlyJWq12uFg0fnI8PAwFRUVdHd3k5CQQF5entMqCPr6+njrrbcAGB3roWTfSwiiAk1ACJrIcAKDstAEhoAMLf/8I8gyJt0gal97sXVq4i1bzNZ2r+OYnPh9At9UWwW62jeA4FXHdjlliwVDXxfjXW0MHtkHzQNOnQrt4eHBkiVLWLBgwbQ2soSEhHklTh3P8Z7njY2N7N27l/z8fKfc/DjC39+f5ORk6urqeO2117jooos477zzSEpKcvbSXLj4SnHgwAGefPLJyWFj6enp88p6qqenh3379pGdnU14eDiVlZUOB4vON0wmEzU1NdTX1xMcHOzU4aAGg4H333+fqqoqkKwV3/45q1Fo7YV8QeuOPD6KaajP4bUEQURQKpHN5hkHgk8fBu5YQDdNqYyzJd5TEVVqVF6+yCYjubmO/djnAqVSSXJyMrGxsdTU1LBz507Cw8NJSUlxulXhiTje81yv17Nnzx4UCsW86Sg7fjj4mjVreOWVV7jxxhudvTQXLr5SjI6Ocs011/DLX/4SQRDw9fUlLi7uix84R4yPj7Nnz57JyvPe3l6Hg0XnG7Is09LSQmVlJSqViuzsbEJCQpwivMqyTFFREW+88QaCIOCTnkP4BZc7PFftH4S+qQbjoOM4DjabVGFyUKjD5zQaAPmEFejjfd0gWVD7zdyhNdragJeH8zqxBUEgPDyc0NBQmpubOXLkyGRnWVBQkNPW9UVMHRi6cuVKtFothYWFFBcXzws7Nhu24eDLli3jnHPO4aabbnJ1hruYxvxVveaYsrIyNm3axGeffUZlZSUZGRnzKpm1VXytWLFiMsk5frDofPnisWGxWKioqKChoYHo6Gg2bNiAVjvzru9sMD4+zltvvcVf//pX9u3bj06nw+avBhB27nfwzcy1s1eRjIbJf5uG+mcQ0Kd4p5qM4FBAN9mdezzWHXUBdcD0Vl9BoUAbHI42OJzR1nrG2xrnxQ2kj48Py5cvp7e3d7KNLCsra17uzjoaGBobG4skSRQWFpKfnz9vKloWLFhAd3c3Hh4e/PCHP+Taa69l586d8+7v2oWL+YrBYGDjxo3cd999gHVjKiYmxsmrOkZfXx9FRUVkZWVN2rY4Giw6n5BlmdbWVsrKyvD29mbFihVzvvEoyzJbt27llVdeYefOXXR1dSPLE7YqogLJZHQongO4BYYy1t6EcWhgxuuLSjUWsxlphtbvqd7oM3mn2irjBIUCpafjDZux9iYAbrjhhhnXMldoNBrS09OJj4+nsrKSrVu3kpiYSFJS0rxrB3c0MNTb25vly5dTUFCAKIrEx8c7e5mAtc0+JSVl0nbiu9/9Lueeey6xsbHOXpoLF18ZHnroIYKCgrj00kupqalh3bp180a8MhgMFBQU4OfnN2nb4miw6HxjaGiI0tJSjEYjqampREZGzvl7WlNTw+9//3s++eQT6urqJ4eDglWUngnVxODQL7RVFYVpXeTHI5lNIMkzxnHJZASTYeI5HXcpSyYjht5OspYunfF55gpRFImNjSUyMpL6+nqKi4sJDAwkMzPTaZ2BMzFVPJ/qeb5s2TIKCgrYv38/S5cunRf3H0qlkpycHHbt2sUjjzzCihUr+Nvf/sb3v/99Zy/NxTzB+Z/SeYDZbObaa6/ltttuQ6vV4uvr69QJ38djq/rKz8+fllzbBotaLBaKioqwWCwnuMrc0t/fP+lvtXbtWrKysuZUPN+8eTPx8fF4eHhy7bXXsnXrNkTRn7j4DWQvuQGF0gMEAYth3KE3uajWwESANc7QMjZVFJ+p9duWeJ+wXWywF0TRoUhvY6SpDqVC5Morr+Tf//43ZrN5xnPnisDAQFatWkVaWhqlpaUcOHAAo3HmG5e5xpF4biM+Pp7ExEQKCwsnNlWcj80Pva2tjTvuuIPu7m6ef/55Zy/LhYuvDI888ggqlYprrrmGvr6+eeVJ2t/fz969e8nIyJiWXNs80WNiYtizZw/Dw8NOXOV0xsfHKS4upqysjKysrDnv2iktLWXJkiWo1Vo2bNjAO++8w8gIREWvID3zSvz8k0CyMNraOOM11P6ByJKE6QSVa7ZqtJlavyWj0e7c47FZsam8/RAEx7fWYx3NgMBvfvMbnn/+efr7Z25Hnyvc3d1ZvHgxq1atoqOjgx07djA0NOTsZU3iSDy34evry7Jly6ioqKCpqcmJq5xOQkICGo2GyMhILr/8cq6//nrrIFoXLlx8Ibt27WLz5s289NJLVFRUkJWVNefzNWbCaDRSWFiIl5cX2dnZ0+4vbCL6oUOHaGlpceIqpyNJElVVVezatYuQkBDOOuusOZ09ZjabufDCC/Hy8iYpKYnnn3+ehoZ2AoMyiV9wHiGh2QAY+3uwGMYdXkPta60GNw8PzvhdKqo0CAgntHAxjVuHlM7cSXZso932nMcz1tkKskxfXx/33Xcf5eXlMz7fXKFUKklKSuLss89GqVSybds2Wlpa5k3cmUk8h2ODRcfGxjhw4ACSJDlxpcfw8fEhMTGRpqYmXnrpJX784x/T3t7u7GW5mCe4BHSsQ0pGR0e56aab6OrqmldJd2NjIzU1NSxfvtxhG/p8E9EtFgtHjx6loKCAmJgYVq5c6ZSKuttvv4OWlk7CInLJXLSRVWt/QXbODYSGL2Z8fBCVyipoj7U1zngNt8AQEBXTWrOnMnUHe6Yd78kK9BN4hY/1WtvFVDO0i1kM45gHrcOp3njjDS6++GI0Gi3R0dFce+21FBcXz3jt2UYQBKKjo1m3bh0mk4mtW7fS2dnptPXYOJF4biMxMZH4+HgKCgrQ6/VzvELHuLu7s3DhQqqrq3n11Vf5+c9/brUpcOHCxQnZv38/zz33HJs3b6aiooLMzMx5M6NBp9Oxd+9eUlNTHVbEzzcR3VZ1vnXrVhQKBevXr3eKv+ZNN91ESUkpAYFppC78f2RkXUNgUCqDQ80cPfIWA/3VAIx3tkzOCzkelW8gIH9B5drE8LGZBHTzF3ugT1qx+c88NHK0tQEEgc8//5w777yTgIAAfHx8Oeecc/jrX//q1Ps3X19f1qxZQ2hoKLt27aKystLpieyJxHMb/v7+LFu2jCNHjtDW1uaEVdpj2wxvamripz/9KTU1NWzevNnZy3LhYt4zOjrKD37wAx555BH0ej1hYWGEhtrPrnAGFouFvXv34ubmxpIlSxxWys43EX1oaIidO3fS1tbGihUrSE1NnfOu1t/97nd8/PHHiAo/4uLPJn7Befj6J9DfX0197ad0dR2cPNe6yWyPrcBMtliw6B3fH4lqDTLTN7ztMJ+4K3xySKkgoPL2dXjOWHsjAHX19Tz51FMsXLgQtVpDdnY2jz76KH19M2/WzzZqtZolS5aQnZ3N0aNHKS4uZnzc8abEXHEi8dyGWq1m+fLlDA8Pc+jQoXkj/CcmJiKKIsnJyVxwwQXceOON82ZtLpzL/7yAXlZWxq9+9SteeeUVKisrSU9PnzdtL729vZSVlZGXl3dCm4n5IqL39/ezfft2ent7WbNmzeQXjzMICwtDrfYkYcF5yLKFuppP2FvwNIW7n6Di6DuY5DGQZUZbG2b8MlT7B1s90GcS0KdZuMw0fMwayBUax58pWbIgj41Yn2+GCvTxjombMEEgNGwJMbFrCQ1bSn+/gddee428vDzc3Ny5/vrrHT5+LnBzcyMvL4+0tDRKSkqcWo1+MuK5jaSkJMLDwykuLp4XVf0AMTExeHp64uvryw033MC1117r9I0xFy7mMzbrlvvvvx9ZlgkMDJy0SHE2RqORoqIi4uPjT2gzMV9EdFvV+ZEjR1i0aBE5OTlO24hYtmwZIGM2j1Nd9W+OHPozLe2FyMHehGz4FlGXWWOebDFj6HG8cWvzI58pjsOxWD7zENGJWCYIDjvWAKs3q6iY0TdVliyMtTaCLKHy8YeJKvUR/SifffY5V111FSqV1VbFdAIP19lEFEVSU1NZuXIlHR0d7Ny502nV6CcjntsICAggJyeH0tJSBgcH526RJ8DT05PU1FRqa2vZvHkz9957L42Njc5elgsX85qf/vSnhISEcMkll6DT6cjIyHD2kgCrCHjw4EEEQSAnJ+eEue18ENGPrzpfs2aN02Y+feMb3wDAaByhof4z6ms/RWfpxmtRDtH/74ck3/EoCm8/EETG2h0L6FPtVIwnzMnlE1agYzFPOdce232CyssXYYbf8VhbEwgi2pBIvJOzULh5YjIZOXjoEA/97GcEBgYSGBDItm3bZl7HLBMWFsb69etRKBRs3brVadXoJyOe29BoNOTn59Pd3U1dXd0crnJmRFFk8eLF1NfX88gjj7Bv3z7+8pe/OHtZLuYB/9Me6CaTiY0bN3L77bej1WpRKBTzxrdMr9ezb98+MjIyCAiY2drDhk1Ed4YnusViobKykoaGBpKTk0lISHCqh9XY2BiLFmXx3r//za4djyBLFtQ+AXgkJxMQk4h7dAIm3SANrz2LZUyPeXgQlbf9jYXaLwBkacbKtamDQWcK2LLZBII4Y9u3SXcsOZ0p8R7rsLYmi2oN/aONGDv6AAFP7zAiIpejUKjp6Snn//7vz7z66qtO656wVaMHBQVx6NAhtm7dyqJFi+a0euTLiOdgXXN6ejqFhYWUlJSwdOlSp3efCILAokWL2LZtG7fffjvnnHMOzz33HPfcc49T1+XCxXzl4YcfRqPRcNVVV1FZWcn69eudvSTAmsTu27cPHx8fkpOTv/B8m4gOc++JLssybW1tHD58mKCgINavX+/UCn5Zllm6dCkIIjpjF/7L1uIZn4I2NGoysZVlGdRaMI4z2t6ENsR+08TWhi0ZDVjGxxx6pYsaawX6TJ1ktg1yUaWeMT6M93aBJDkcIApMCPzWBDbmez9C6ebBaFsj+sZq9PVVjPe0I8sSR8sreOedd7jyyitP8O7MLrZqdJsAk5iYOKcFEV9GPLcRGhpKcnIyRUVFrFmzZs7n7TgiPj6e9vZ2QkJCuOKKK7juuuv47LPP5oXHqwsX841du3bx6quvUlhYSEVFBTk5OahU9rOlnEFtbe1kcdjJfB850xNdp9NRUlKCJElOmVlyPGazGYVSiQkD4RdegWd8CkqP6fc1XrFJDB4unrErXKHRWm1VTQaryB0Ra3eOqFaDJGMZ01ttViQLFoUIxDHW0YLBckxAtt0PiBrttJhus3pT+888iHO4qRZkCd/MXPwXr0CWZQy9Xegbqxipr2K0qYa+/j7uueceDhw4cPJv1BlGrVaTk5NDe3s7hw8fpr29fU7tdL+MeG5Dq9WSm5vLnj178PLyIiQkZA5WemK8vb2nWbn84Ac/YMOGDYSHhzt7aS6cyP+0gP7kk08yNjbGjTfeSHl5+bwZUmIymSgqKiIiIuJLDUBzhoje399PaWkpSqWS1atXO7SZmQvMZjN//OMf+e1vf0tlZRWSZAFBwCM+hZD130RzXDBUaN1AEECWGWtvdiig23a8Z5r6LYgigkKJbJl5+JhkMiIIwsyDx4Ymrn2CdrHRtiYQRbxTsgg//7uYdAPom2rRN1TR2XAYy5geQVQQEhw0Lz6/tmr0lpYWDhw4QFhYGOnp6bPuYfhlxXMboiiydOlSduzYQVVV1aSA5UxsVi5VVVW8+uqrXHDBBXzjG9+YF2tz4WI+sW/fPp5//nl27txJZWUlWVlZ88a6paysDKPRSF5e3kl/NztDRB8fH+fw4cP09fWxaNEipyYGW7du5dFHH2X37j0YjQZrbPQNIGjluXbnCoKAV2wiw7VHrQM6s/PtzpkqaJuG+lFo7UV2hUYLCCewcLH+XFA5jmGyLGPRDQLyjIPHbANEFe6eEz7pAp5xyXjGJcO6izAND9Hx6TuM1FdxySWXOLzGXGKrRg8LC6OkpISOjg6ys7Px8fGZ1ec9FfHcxoIFC9DpdBQXF7NixQqnD+C2Wbls376d+++/n7Vr17J582Zuvvlmp67LhYv5xujoKNdeey2bNm1Cr9cTHh4+L8QzgM7OTqqqqli5cuWXEh/nWkSXJImamhpqamqIj48nOTnZad+BjY2NPPzww7z33r8nuoJkkCS8kjIm4u103CJiGTxcxFhbI7IsO7xf0gaGMN7ZOvNcMpW1At002EfDa89ar+vmBt9aQ9ObLzE2NmY9URBo/ddr1n8rFCjdPVB6eKH08MHQ12XtJJtBQDfpBsFgvY77hIgvCALaoFC0QaEELF2DvqmGpjdfYs2aNSf5bs0u4eHhBAQEcOTIEbZu3UpmZiYRERGzqhecinhuw8/Pj0WLFrF//35Wr17tFBvg40lMTKSjo4Pk5GQuvPBCbrjhBj744IN5obm4cA7/s2UQdXV1PProo/POukWWZUpKStBorK28X5a5snOxfTkWFBQQFRXFqlWrnCKe7969m3Xr1uHm5s5NN91EVVUdIaHZ+PknggyWsVE78RxAEBW4R8WDqGC03fHwKVtFuGV0BGkGew9bQj1j4j1RuSZ8wcASpacPgmh/oyPLMiNNtSBJuEfEAdYhZb4ZS4n45vdJuu1hIi/ZiCxZWLRokcPncAa2avT169djMBjYtm0b3d3ds/Z8pyqe21Cr1eTl5VFXVzdvfFRjYmLw8vLC29ub66+/nh/96Ecu7zUXLqZgsVi48cYbue+++5AkiaCgoHlTFdLY2EhbWxt5eXkolV+uVmEu7Vw6OjrYtm0bgiBMep3PNW1tbVx99dV4eXlx1llnsW3bdry844iMyrdarbXUYRkfdfhY94g4kCRGWxocHldo3WHCdmXG1m+VBkRh5mHgEz9XzBDHLaMj2KrLZxw81t4MgoB7VLzDpEvl5YNxoA9PD3fc3d0dXsMZ2KrRQ0JC2LVrF9XV1bMWh05HPIdj3VuyLM8bH9WpVi4vv/wy999//7yYE+PCxXzi0UcfJSgoiIsvvhidTndK+e9sMDw8zIEDB8jOzj6hlepMzJWdy8jIyDSv87S0tDkXzw0GA7/61a+IioomLi6e1157DbPZjfgF51hPkCRG6isdPtY9MhYAy/jojHZrGv9AEKYUnh3HpC2LRkXEYz8i4olbifjVjQCEP3IDoQ9cYz0uywTd/G2Cb/suAddcgOc5S1ClhyN5W6zXlqUZLVVtG+GCUoUmyHF39Uh9JYgijz76qMPjzkCj0ZCTk8OiRYs4cuQI+/btmzWruNMRz21ERkYSFxdHUVGR0yztpnK8lUtxcTHvvvuus5flwon8zwrot99+O1dddRWenp74+PjMG+uWyspKhoeHWbp06Sm3ec62iG4ymdi7dy8dHR2sXr2apKSkOW9JHR0dJTg4mFWrVrNjx058/RJJz/w+K9c8RErapYSEZgIyY22NmEdHHF7DPTIeJAtjrY4T76kB1KQbcHiOYqKqembvVAMyMyfetup2RyI/TAjsJgNg3aE/HkEQMQ8PAQLPPPOMw2s4Ezc3N5YtW0ZKSgrFxcXU1dWd8aT2dMVzG97e3ixZsmTe+KjaxIC2tjbuuOMOKioqePvtt529LBcu5g2bN29Gp9NxzTXX0NvbO2/8Um3zS5YuXXrKYuhsi+iyLFNVVUVJSQkZGRksXbrUKZX755xzDlFR0fzlL39BFH1JSrmYFasfJDHpGyhV7rbFMlJX4fDxbhOJt2mwF8v4mMNzlL4BIAgnmGeiRkBAnnEYuHHivBPHccDqb+6A4aYagMmNcLtrDPRi7O+eN/ZDU1EoFKSmprJixQqamprYv3//GZ8Zcrri+dS15ubm0t3dTX19/Rld46kSHx+PRqMhJiaGc845h3vvvdfZS3LhYt5QXV3Ns88+y/PPPz/ZRTYfrFumzi85nZkqsy2id3d3s3PnTgICApzmdf7MM8/g4eHFz372M3p6hoiJW0fe8rtIy/guksWMQqkFUWS4+ojDx6v9g0Bh/Z2PzVDUpvINBEnCNFMFui0+SzKauHA0MaGoIqxDvdVRIajCjm1uu2cn45mfgc85efhfdhZB13+L0PuuArUKZPkEG+HWtbmFxzgsegPQVR3G29NzXhRlHk94eDjr169HkiR27NgxK/eVpyue20hNTcXT05P9+/fPi81wm5VLc3MzTzzxBHfeeSd6vd7Zy3LhJP4nBfQPPviAwsJC7r33XlpaWsjMzJwXbRhtbW3U19eTm5t72nYXsyWiDw8Ps2PHDgRBcKply/bt2+np6SE0bDH5q35KRtZV+PhE09ZaxP59v6Oy/J8TZ8qM1JY7vIZNkB7vakV28P4o3D2tNi/MPIDMZs0yowe60QiyfAILl4ETtovZgrWo1s54zmDlIURR4Pnnn6ehwfFmwO9+9ztiY2PRarXk5eVRXFzs8Dwbf//730lJSUGr1ZKRkcHHH3887fi7777LOeecQ0BAAIIgcPDgQbtrrF271mpfI4rExsZy9913s3//fg4ePHjGPo9nSjy3ERoaSlJS0ryYXA5WK5fk5GQaGxt54oknuPvuu502XNCFi/lET08PDz74IM899xw1NTWkpaXNC+uW0dFR9u3bR3p6OoGBjpOwk2W2RHSz2cz+/ftpbm5m1apVREZGnpHrngrbtu3A3SOY3OV3kpl9LcgShw6+xt6Cp2lq3mH1ShVEdDMk3tqQY2sf63A8gMw9KAwEccbEW/iiIaLmEwvok51kHt6IDroNLONjWHQDIMuTgv/xDNeUATA0NMR///tfh+c4M44LgoC/vz+XXnopR44cYffu3YyOOu4K+LKcKfHchpubG7m5uVRUVMxq59vJIggCmZmZ1NXV8cgjj/Duu++ya9cuZy/LhQunI8syP/7xj7nuuutQq9UEBATM6dykmZAkif379+Pl5XVGrBNnQ0SXZZm6ujqKi4tJT08nIyPDaZYtr732GpJkISv7Wpbk3opK5c7Ro29RXPgczW17UAeHWCvQa486zLcFQcQzZgGIihkFdFtR24xzyWzx2eR4c1c2HovvgtZeY5HGDGCwnqOaYZbJcFMdiCLukY43wg19XZgG+3Bzc+OFF17AaLTXBpwdx7VaLStWrODw4cPs3LmTrq6uEz7/yXImxXOwxs0lS5YwOjrK0aNHz8gaT5cFCxZgNptZvXo1kZGR86rLwMXc8j8noI+NjXHbbbfx61//mtbWVhISEvDw8HD2shgcHKS0tJQlS5acMVH6TIvo3d3d7Nq1i7CwMPLy8pxaIXDeeefh5uaOwaBjaLCJwwdfZ8/ux6mr/QSCfIj45vfxTEw/YeLtHmH1l5ctFsZ72u2OC4KAwscaRGcU0Ce83GaqXDONj4EszThEdKy3C2TpC3xTBdyj4hxu8ljGRxlvrUeSJF599VXi4xMICQnlrrvumqyifvvtt7nrrrv4xS9+QUlJCVlZWZx77rkzJpYFBQWTA69KS0u5+OKLufjiiykrK5s8R6/Xs3LlSp544gmH17Dxwx/+kI6ODjo6OtixYwfr169Hp9NRUFBw2gL1mRbPbSQmJuLv78++ffuQJOmMXfdUSUhIQJIk8vPzSUhIYNOmTc5ekgsXTueBBx5gzZo1JCYmolarv9S8kNnCbDZPzi+JjY09I9c80yL66Ogou3fvxmAwOHUT3MayZbmM6ntoqPuMPbt+TXX1h8gBnkR88/sk3/YIwesuAllipK7CoZWaqFSiDo4AQZy5cs0vACTLjBYuCrUGGRl9Sx31f36Wuv97moa//BaAhr+9SH/JbsCaHDf/44+0ffQmXds+oK94O0PlJeibrdXlav+ZBoFPCPuiAjcHg04BBsoPAgI7duzg3HPPxd3Ng29+85scOnQImD9xvLq6mm9/+9v4+fmxY8cO+voct9OfLGdaPLfh7+9PVlYW+/fvZ2TEcRfiXOLr60tMTAwDAwM8+OCD3HLLLWe8it+Fi68a//rXvygtLeWuu+6ira1t3nSRHT16lPHxcRYvXnzGCuzOpIhusVg4ePAgNTU15OfnEx0dfUbWeKrcfvvtyLJEQ8NWCidycSEkgMhLNpJ02yNEfec6wFpspm+pc3gNt8g4kCyMtjY6PG6zVTUND6KrOkz/gd107/yE9k/foeXd/6Nz679BtP6uZAe5m2SYyNMFAUFlv9Ft7jnWaa7Q2FePyxYLxq5Wq6XqF2yEd3X3cNttt6HVupOTk8Nbb72FLMvzJo63tbVx/fXXk5WVxb59+6itrT2tKu8zLZ7bUKlU5OXl0dzcTHOz4wKJuUShUJCRkUFVVRXPPfcczz33HFVVVc5elgsn8D83RPSJJ54gKCiIs88+m7q6OhITE529JMbHxykuLiYpKemM77yficGitl1uW2vdfLC7KSgoICQkmMbmOgb6a3ALjSL07EvwTl2E0s26ISKIIiM1ZegbqpBMRsTjBoAptO4ovP2w6AYYa2/GLdT+dbkHhTKsG5hxkKioPnEFumQ0TDvveIxDvRPtYjPtdteCwIy73ZNt7aKIv98CVCoPhnVtPPfcczz//G9IS0vFYDBw/fXXc+211wLw8ssv89FHH/GnP/2J+++/3+6av/nNbzjvvPP4yU9+AsCmTZv47LPPePHFF3n55ZcBuOqqqwCrz++JcHd3t/tMr1y5koMHD7Jz505yc3NPyVdwtsRzOGadsnv3bg4dOsSiRYuc2qEiiiIZGRns27ePZ599llWrVnHttdeSmprqtDW5cOFM9u7dy5tvvjl5479ixQqnd5HZ5peo1eoz7t96pgaL9vX1UVxcTHh4OBkZGXNuvXY8HR0d+Pj4IAsyA6MtBK25AN+FS1B6HhP1vRYsBEA2m9A31eCVYP+95xmbSH93O6NtjQ6fZ7Jyrb/H4XFRpQFJBiWo0kIRFArUE/cLqtRQhCPDMCwiuCuRvMyYhjuxdOmxDI0g25Lyk+gkcwuNRFA4SNxHRzB2WpND22Byo0Xigw8+5IMPPiAwMAiVSsm11147b+K4r68v3t7eFBYWkpGRcUobWLMlntuIiopCp9NRVFTE6tWrnW4LkZKSwpYtW7jiiiv485//zO9//3tuu+02p67JhQtnMTo6yp133snjjz9Oc3MziYmJ82L+Q1NTE62trbPynXEmBosaDAaKi4uxWCysWbPG6VYhBoOB1tZWBFFkWN9B8Ppv4pO+ZDIXBxCVnmjCYjB0tTBcfQTP2CS769iGco53tyGZzXbdXMfyZNk6BFQUUfh4ofDxQOHljujhBu1WEVg2mBDcpufdssE2k0zl8H7R1H1MQK/5/SMoPDzQBISiDQpHExw+UQhnvb5beKzD92LgaCmIImoff8zDOiSzkZLSg1xxxRVcc81GPDzc+e53vztv4ri3tzceHh4UFxej0+nIyso6JY1oNsRzG56enixdupSioiI8PT3x93dskzdXhISEEBAQgFqt5rrrruO2227j008/dXoO4mJu+Z+qQK+vr+fJJ5/k+eefp6qqivT09C893OtMY7FY2LdvH/7+/rMm5p9OJbrFYqG0tJS6ujpWrFjhVPFclmX+8Ic/EB4ezqpVq63BQpbxXbSMuI134r94xbSA7RlvTbRlixl9Y7XDa3rFJoEoMtZ2gkGisjTZon08osYNEDCN6DD0d2OYSNAN/T0YB3qxGK2erDIgS9Pfd8lshgnPVtvO+vHHTT3t1rbvGYK1rvoIiCKawFBGFXq6OksxGHUEBi8kKDidiopaamtrp1V7i6LIhg0bKCwsdHjNwsJCNmzYMO1n55577oznn4i//e1vBAYGkp6ezgMPPMDo6CgKhYLFixcTFxfH7t27v/TQztkUz20olUry8vLo6uqa0RZnLgkODiY4OBhRFLnpppu49dZb54UnnAsXc43FYuGWW27h/vvvR6fTERkZ6RTPz+OpqqpiaGjotOaXnIjTrURvamqisLCQlJQUsrKynCqeFxcXs3TpUiIiIvnoo49AklFo3QjIXTtNPAdQaN3QRiVY/VNrZuomi8U288TR96LNz9SkG3B43LrBLSP4eBD0w4sJ/MFFBFx1PgCB11yI28J4EATcshIJve8qIn51I9G/vYu4P/+c2D89hCYp+oQb4WNtTda276h4h8dtNnOiRkvy7ZuIuvQ6PBJSEBQKQKB/YIiOjg7++9/Pjq3ZyXEcIC4ujmXLllFeXs6RI0e+VMfWbIvnNtLS0nB3d58XPqpqtZq0tDSqq6t5/vnn+fnPf37G2udduPiq8etf/5rw8HDWrFmD2Wyetfv5L0NfXx9Hjhxh6dKls9adfjqV6ENDQ+zYsQM3NzdWrVrlVPG8p6eHK664Ai8vbx5++GFkSUI2mfBOypiWi9vwW7gYJInhqsMOv4vdwib0BUlivNs+L1R4TBQNyBByz5XE/fWXxLz0EyIf/xFhD24k6KZLJs+VDPZ2bJMCusbxpoh5QkBXRYUQfNt38T4/DyFMy3BbBR2fvkPbv/8CgNovCIXW/n03jeisObskEX7hFSTd/ggR37oaj7hkEESMRgMDAwO88cabk7FyPsRxPz8/1qxZw8jICHv27PlS3eGzLZ7bCAoKIi0tjeLiYsbGHM+6mUsyMjJoa2vjrrvuorS0lH/961/OXpKLOeZ/qgL99ttv5/vf/z4eHh6Iouh0nzVZljl8+DAWi4Xs7OxZ3b06lUp0W2U8wJo1a9BqtbO2vhNhsVh48sknefyxx9EN61CpPIhLOBuzeYyWpl0MVx5GPvvbdpVdolqD54I0RuorGa4uwyvRvirQLSKWwcNFjLY6Hjal8gsEWcY4ML1yTQA8VQriYqKR1BKicQjFvv8QHBwM5OJ7aDujo6NkJiVitljQle6geet7jEkSSndPq1eq+tj76SjxNthuIATh2I3FFCSzieHqMpAlgvLPxjslC0NfF0NHSxg6sh/T8ABqjRdGg8Husx4SEkJlpeNp6J2dnYSEhNid39nZ6fD8mfje975HTEwM4eHhHD58mPvuu4+qqireffddBEEgMTERLy8vDhw4gE6nIyUl5Qv/BuZCPLdh81EtKCjA09Nz4nfrPNLT09myZQu33XYby5cv5+9//zv/7//9P6euyYWLuebVV19laGiIq666ivLycrvkwhm0t7dTV1fHqlWrTnt+yYk4lUp0SZI4evQora2t5OXlERTkuEp6LvjPf/7DrbfeSm1tHYIgEhq2GD//BZSXvYWht5Ox9qbJKrSp+C1cTEdLHcNVR5DP/Q6CMF38t80zkQzjmAZ7UftNf43qCT9T2WzCMj46mdzLkgW1yUCwpxu+aWmo/LwJFz1RIJAlWoX8JNEDn+AIRtJHEcKjEFCgx4It/RfdtRi7+ies2Ow3wmVZZqS5FiTJ4SBwOLYR7p2UiajW4JW4EK/EhVjGx9BVHqR//24MvR2I4vT46Ow4DhAYGMjq1aspKipi79695OTkfOHfwFyJ52D9m8nJyWHnzp2Ul5ezcOHCWXuukyE6OpqmpiYCAwPZsGED9957L3/+85+duiYXLuaampoann32WbZu3UpVVRWLFy92mn+3Ddv8koULF572/JIv4lQq0dva2igtLSUpKYnExESnVbw2NjZyww03sGXLViTJgq9vPFExKykv+wcWaYyBQ3sJXn2+3eO8ktLp/PxfmPXDjHe12nV9i2oNyoAQzP3djLU14R4+vatJEAREb38kXT/S6DjClCIAFQJ+7p5ok5NRq9WEih6oRU8SRGusTxI9GfTwJzA9HYuHBjdUDGOeEsnB1DNoLUiLC8Mzf7qVkDRuoOv5txk7XId79Ewb4VafboWbB24RMQiCiE/qInxSF2HWD9N/YA+9Bf9FluVpBQzzIY7bfNEPHjzIjh07yM3N/cLClLkSz23ExcVNdpStWrXKqd8X7u7ukwNFH3/8ce644w7OPffceWEJ7WJu+J8R0D/99FP27NlDcXExlZWVkwMVnEljYyNdXV2sWbNmTr4IvoyIPjg4SFFREYGBgSxatMhpX1R/+MMfuOP2O9GPjqDV+pOc+m1Cw7IRRSW6oRZamnZhGR9FV30En9Rsu8d7J2cxUluOrvoIYef/v2kBF5j0MTMN9WMe008m1ipRINRdTeaSRQj+KvwDg4hKDsFLpcRLrcBTpUAUBEZSv8eIToekFMFDQ7ibNen+/o9vRgCkfh0qlQoffz80ShUGs4mhUT0DuiH6u3vpa1/O4PAIyjB/2vRG+sdNk+F8dKLtWxMU5tACRt9UA7KEoFDgGW8VVTQBIQSvPp+gVeeib6ql9b3XAbjgggtO91fxpbnhhhsm/52RkUFYWBhnnXUWdXV1JCQkANahnatWrZpsH1uyZMmMXSFzKZ7b8Pf3JzMzk/3797N27Vqntpe6ubmRlJREY2MjTz75JHfffTcXXXSR09s3XbiYKwYHB3nwwQf5v//7v8nBobMpWJ8MOp2OkpKSMzq/5ER8GRHdaDSyf/9+xsfHWb16tdNu7o8cOcI3v/lNGhubUChUxMSuITIqH7XGi1F9DwqFGxbZwEDJHocCuldiOh2f/h3LmJ6x9ma7c1Se3gjunsijI4y2NU0K6AIQ5KYiLCCCrO98Bz8/PwJ9JXy9ZXy9vPDz9UWtVjM2lsDwhuWYLGYUSn8kZMJF6/fqBcoQLOvOR1x5Np6+vnhqtFhkmRHMDMkmdJKZtu9dxcDAAKNaDT0dtfQKGhT+wYhqDabBPjBbK98cvTbJZJyoQJfxSpqetCu0bvgtWo55VE/Pzg5uuumm0/1VfGlOJo57eHiwatUqSkpK2LlzJ3l5eTN+JudSPLdh81HduXMnPj4+Th2aaxsoumvXLjZt2sTSpUu5+eabWbZsmdPW5MLFXHPXXXexceNGNBrNvBgcarFYKC4uJiwsjLg4x5aZZ5qTFdFlWaaqqoq6ujpycnKc9l5ZLBbOO+88tmzZiizLBAWnExO7Bi/vCIyGYby8wxgcqGOgtICgFedMdFAdQ+XthyowDFNfF8PVZQ5tU71jE+nv77GbZ+KtUhDuqWHhZd/BQzIRkphMoCoSb0GFt6DETVBg1kgM/uQnGI1GRF8fZKWCMNFaqHa+Mhg5wQduScbNwx1vjbc1h5fNDMtmdLKZzmVn0ROUwHhUAMOiB23SOKNYO8dFrYbxxk6QLLhHOP58DJQftG6Ep2TZbfIrPbzwTEiht+C/LFyYdqq/glPmZOK4rTu8rq6OPXv2sGjRohlj5VyL53Asdu7Zs4eDBw+yZMmSWX/OE7FgwQJaWlpYs2YNkZGRPPHEEzzyyCNOXZOLueN/QkCXJIn777+fBx98kI6ODhISEubkj/1EjIyMcPToUZYtWzanAtjJiOh9fX3s3bt3Uqh05kbDT35yL+MGE2np3yU4JBNBEBkaaqa5aSe93da2ZwSB/gO7HQroXgusgUoyjDHa1ojHcS3Uav8g1G7uxEVHkeMpEh8bRISHhiA3FeNmibYhT5p1nfT39aLvG0ZvAZ3JwrDRwrDJTNu2D+kv2o7n6iyCb74UzbjIY9o0XhBaGJctNNzyMwAin7kN74hQvAUl3loV3lolap2ExmIhfkEiUWE+hLqrsUjQMWqgTW/gSJM3ZVHRjAc7Hg4zXFMGgohHXIqdwC4IImq/QKRxa4tWT8/0Cvqurq4Zb8JCQ0Pt2opPdP7JkpeXB0Btbe1kwAarB9vq1avZt28fhYWFLFu2zM530BniuY3o6Gj6+/spLS0lPz/fqX8PCxYsoLm5mRUrVhAcHMyLL7446Y3nwsXXnSeeeILs7GxSUlLo6Ohw+uBQSZIoLS0lLi6OsLCwOXvekxHRDQYDBQUFk63ezvR/fuihh2hsbCQmdi3RsWtQKrUMDjRQWfEufb2VCEoVWCSGKg4SsuFiu/ZvpYcX6tAojF1tDNeUORSifeKT8RruIzPQk4UxAYR7aAjzUCMAnaNGGuLiGOjpobK5Fr27Ep0oMayUGVaBvrufvtc+BKWC+L8+DIAGayx/3lhP0+9eZ7S0Gv8rziHoolV4CUq8UeItqPAcM8PwMEFBQQSHhxEbGYWbmxvNzc00trXTONSBkJhIe/8QSg97UVnfUA3ICEolHnH2vrCyLDNYth/ALvbNpzhuE8QrKyvZvXs3y5cvt5tv4gzx3IanpyfZ2dmUlpYSEBDg1I1nX19foqOjGRoa4o477uD+++9n27ZtTi/qceFiLti1axc7duygpKSEyspK1q1b5+wlTQ4CnOshpl8kosuyzKFDh+ju7mbVqlVOHfr92Wef8fnnn+Pnv4Ck5G/i7hHEqL6HyvJ36ewsgYkCNcuYnuGaI3inLLK7hl/6Yrq3f4Su6rDDKnW3iFgCGitICvZlaaQf4e4qwt3VeKqVdPQN0BIWQl93Fy3t7TRGeqKTzehkEzrZzCgW6m95GNlgIvzRm9AmRE7G8d8Y6+nZtpfeP7yPNiWWyF9ejwdKfATlpAhvaWzGz92DxNgFRCqDCRDV9ElGWuQxWsZ1eMXEUW+pd9hJZjGMMz4xTPz4jXAbuqrDANxyyy3Tfj6f4rggCCxYsAAvLy/279+PyWSy21ByhnhuQxRFli5dytatW2lvbyc8PHzOnvt4bANFDxw4wOOPP84FF1zALbfcYtcx4OLryf+EgP7mm2/S39/Pt7/9bSorK51e6SHLMqWlpURHR896m5gjTiSi9/T0UFRUdMpDoc4055xzNu+88w4enmEM9NfR2LidoYF61H5BhJ17KSq/QJrfepmx1gYMvV1oAqd/cSncPNBExGHoaGK4pgyPqHgUAsR7u5Hq506ctxtBf/srOp2Olv4hegxmKvr1tOkNDBktyBYLFS++CIDP4SokkxmzfgjLmB7zqB5pfAwU4qS32jSmeM2LGjXjSIzLRrpl69Cx/qJdDP57F9rQCIJWnYdbYBiRoUFEeLoR4aHmrCWZXHfJN5AEgY4xM9WDY1QO6OkaMyHLEoPlpSBLeKdkOXzvBg/uBSAzM5MtW7Zw8cUXA1bRZ8uWLdx6660OH7d8+XK2bNnCHXfcMfmzzz77jOXLl5/U72wmDh48COBQaFKr1Sxbtox9+/ZRUFDA8uXLJytLnSme21i4cCHbtm2jsbFxzqpTHCGKImlpaRw+fJhHH32U733ve/zwhz88pUGsLlx8lWhvb+e3v/0tn3/+OTU1NeTl5TldcKqtrcVisUyK2XPJiUT08fFx9uzZg4+PD4sXL3b6sNBbb72V999/H6XKnaHBJhobt6EbbEITEEL4BZfjlZxJ1e8eAaOBoSP7CMhda3cNv4WL6epsYbjqMCFrvwFAuLuaFD93Fvi4E7bkAWSLmabWNvqAfd062vUGesZMSEDd2//C0FqH/xXn4HvuqsnrKgFtU4f1P2bH82GMI3qQJEStGhMy/bKJfkwgjzHe2ET7X/+K4KYh7v9+hmSowbt+hDC9RKSHhsXpKXznwvPwcPege9xEvW6cygE9DcPjSPKxjXDPhIWISvtNjrG2Rkz93fj7+8/7OC4IAqmpqahUKgoKCli2bNnkwC9niuc2wsLCaG9v59ChQ07//khJSeGzzz7juuuu4+WXX+bTTz/l/PPtBSUXLr5OyLLMfffdxz333EN3dzdxcXFOtz0YGBigvr6e1atXOyVWziSi27SC/v5+p/udA2zYsAGNRossS1gkE0cO/43e7qMoPbwIWn0efouW0/Hfd9FVlNJfssehgO6VlEH39o8w9nVhHOxD7RuAt1pBqp87Sb7uRGZ/C/drLqG1tZXG5gp2lZdTV1tLQ0MDFm93BJUCU3sv2pRYwpdcb3d9QaNGNpgc5uQ2X3TBTY0EDGOtPkceR5ZlGv78Okgy4ZtuROsVhTsKIkUtkYIb4eMiN998M6GhofTqRmjWjVI9JlM9OMa4RULfYN2AEdUaPKLt81TJbGbwcDEKhYKysrJjP5+HcRysNjHLly+nsLAQi8UymXs7Uzy3odVqyczM5NChQwQEBKDR2HfozxXBwcH4+Pjg5+fHhg0b2LRpEy9OaEYuvt587QV0o9HIz372Mx5++GEaGhpITk52aiUWWIeZGgwG0tLmvo3HhiMRvbe3l3379pGVleXUYaFTefXVV/nHP97lYMmrmIx6tCFRRF6yEa+kdARBRJblCc+0HgZKCwg9+xK7a/gtXMzocB9LAj1ZkxhMoq87o2YLlQOj/LelnyM7tlD98d/xiE0i5vLpLdKCQgEaNzCMMdJWgzoiCEWsD2qfCBTe7hgaOtAXHUUyGO2ed+oQk+OngQOYegZAITDe2UrL3/8AQK1agyYoFE1gKIOHilAoFKy4axOxYUEk+7qzLsKXEZOFI62dqFKSKa+omKyyn4psMdN3YDeCIHLkyFHKysqIjY3lggsu4Pnnn0ev109OAb/66quJiIjgscceA6yzAtasWcMzzzzDhRdeyFtvvcX+/ft55ZVXJq/f399Pc3Mz7e3twLHqjdDQUEJDQ6mrq+ONN97gggsuICAggMOHD3PnnXeyevVqMjMzHf6uFQoFS5cuZf/+/ezZs4f8/HzGxsacLp6D9e9l0aJFFBcXExwc7NQb/rCwMGprawkNDWXx4sU88cQTk787Fy6+rjz88MNceOGFkyKxMzafp6LT6aiurmbFihVOszhzJKIrlUr27NmDv7//rM9WOVnOPvtsFixIpK7uv8iSGbewaKLO+gGeC9ImW50Dc1bRW/AZ/Qd24790tV0LtFdSBv07PyY9LpoNYR6khQagVYjUDI2yv0dHXVMLRS8+iiTLpNz1GKJqurWPR1AohrYGzD2DdusTNcfOlWXZ7j2T9ROJt9beLshkGzwW7D95rZFof2qAGqDprt9gae9h4XeuYWFuPgt83LhsQTAqUaB6cJQtAR4ccHfDO8VxXOwv2QMI9Pf387vf/Q6VSsUPf/jDeRvHwVopL4riZEeZt7e308VzGxkZGWzdupWWlhaiox13980FGo2GBQsW0NraygMPPMADDzzAueee6/TNLhcuZpP333+furq6yRkmOTk5Tl2PxWKhtLSUxMREp1Z3Hy+iR0REUFJSwtDQECtXrnTaDLKpKJVKbr/9Np588kn2F72AyieAsPO+g0/6UsQJ603/JSvRlZcw2lyHoa8bTcD02VEa/2AUPv7EBPqxxk/J4vQIQt3VNA+PUzkwyvbWAbY/8QCGkWHcMhfgkbcQ9bK1hEX+P0StmtFDNXQ+9mdMXX0O1yhq1EjoHQrostEEooDoIB+X9OMgWQ1UVcFW7+9RLFRLeqrRM/DJVgb+uQ2vAD/iomJIT00lLy+P7yyOoq6rj/09WnaFhTHmH25nXQMwXH14siP8xRdfpL29nYcffpgXXnhh3sZxf39/VqxYQUFBAZIkkZiY6HTx3EZERATt7e0cPnyYpUuXOm0dgiCQlpbGnj17+PnPf86KFSu48847p1X1u/h68rUX0Ddv3oy7uztr166ltraW2NhYp65nZGSEiooKli1bNqPX81wxVUTfuXMner2e7OxsIiIinLquqXh7e7Nu3Rq2bNlCyPpv4r90zbTkVhAEgnLX0vHJ2wweLiJ4zQWTdiYBWiUL/T1ITrmE6Bu/R11dHXU9/WxtG6Rz9JjgbfCx+qWOtTchy5Jd4q4JDMXQ3oDvxavxOXd698Lw9gPo95Zh0ttPhZ4awKcm6DbGGjvAIhH0o0txS4vD2NKNsbkTY3MnwxUVE0/uRo+oobd7mP3dwygFgQQfLTFjg9xxxx1o3dyo1VuoGBilclCPwWK9AdBVlyEbx0EQ8PGOYmioiXvuuYef/OQnpKWl8emnn062GTU3N09L2vLz83njjTd46KGH+OlPf0piYiLvvfce6enHhrC+//77kwEf4PLLLwfgF7/4Bb/85S9Rq9V8/vnnk0l+VFQUl156KQ899JDd+zAVm4hu81I1Go0kJyc7VTy3ERwcTFRUFAcPHnSqlYstYBcVFbFp0yY2bNjAj3/8Y6e2srlwMZtUVVXx+uuvs3fvXhobG1m1atUXP2gWkSSJkpIS4uPjv3DQ0mwzVUTfvXs3oigSEhJCVlbWvBDPbfz2t7/hggsuxDczl7Dzv2u3Nr9Fy+kt+AzTUD/6plo8Y612JlqFSJq/O6lJIcSv+QvDOh1l7T28OyrRoBtjIuQha72t+a8sM9rWiKhUMd7djqGnA0NvJ+M9HWCxYOrqt1uboD2WUMsmM4J6epGFNGpNfB0l3ubuARAEVOH2GzqS0YSl3WqfNuYdRFm/nrJ+PUIDhHuoSVAYueRb3+S2W2+hacRA5eA4Rwf0DBrM1muPjqArLwFBQFSokS1mnnvuOZ577jni4uLmbRwHiI+PnxTR3dzccHd3d7p4DtZut6ysLEpLSwkKCnJqVWdCQgINDQ18+9vf5je/+Q1vvvkmV155pdPW48LFbGKxWPjpT3/KQw89RHNzM4mJiU6fYVJVVYUoiiQmJjp1HXBMRN+7dy91dXXIsszKlSudWmF7PI899hhPP/MsCk9vFtxwv51Y7BYeM72obcPFAIgCLPBxI9XPg8QXf4tWIXK4spo9HUNUDY4yZpYmryGGRMFYJZr4CLzPmi6OqkKsG9WWwRFki8Xu+W0xWjI6ENANJhBERK2DON5j3QgX1CpEb/sCqZHyehBAuWEJugvy2VbVzMdb/4l7cz9ZoVHk5uby/377W3r1Y1TrJcoH9LSMGCYf31O802pxI0kIgpJ3332Xd999l+DgYP7973/P2zju6+s7KaJ3dnYyOjrKypUrnW6DbPND37Ztm9OtXPz8/AgJCUGhUHDFFVfws5/9jDfeeMNp63ExN3ytBfTh4WE2bdrEK6+8Qk1NDampqU6t7rC1Y8XExDi9es6GSqUiLi6OAwcO4O3t7fRBLo545plnyF68GH1TjcPWbp+0bDr++08kk5HR6sOsXLuOpcFeRHlqqRka5WD/KI8/+mu6aisIWnUeQflnT3u8W5i12l4yGjD2907umMuyjGV0BLW7BwZR4bByzZZ4SyOjdsdkWwBXiAhK+6RRslWuhQSgDPRFGeiLe7ZVNOh/+3MG39uBe1T8NKHBLMtUDY7x/otPIemHWXrlD8lbtpzV4T5cHB/Ikb4R9nUPU1e8w3qjoNYwNNSExs0Pd60/g4ONHD1azvXXX8/rr79OdnY227dvt1vbZZddxmWXXWb3cxsbN25k48aNMx6Piopix44dMx4/EaIokpCQwK5du1Cr1fOmGwIgLS1tXli5BAYG4u/vj5eXFxdeeCEPP/wwmzdvdtp6XLiYTR566CGuueYaJEkiLCwMHx8fp66npqYGSZJITk526jpsCIJAdHQ09fX1WCwW4uPj55V4DrBu3To8PNzRVR4iZP23UGinC5cqb1/cE9IYbahk4MBuMjIyyQn2Ij3Ag65RIxUDo/z9w60cfPevuIVFE3fNHdMeL4gKNOExGDqaaH57M8gyiCKqsEDUUcG4RS1AX3DEYeWa6DalAt1oguMEdNlgTYQdbYSbewZAFCYT+6kYGyesYRQiXds/xCM6AY+YJLShEbTpjRzY8m/69+8kZskyzrryOlL83Dk32p8G3Rj7uofZtc8aQ5XunnjEpaArL0EUVQiINDQ0cP75F/D4449xww03zLs4DtYqsZqaGvR6PRkZGU4Xz23MFysXlUpFcnIyDQ0NPPzww/zsZz/jsssuc7qo6MLFbPCXv/yF8fFxLrroIiorK4mPj//iB80izrZucURAQAC+vr709/eTmZk5r8RzsN5rrMhfzq5du9A31eAZn2J3fGpRW8q53yI33J/FQV5IMlQM6HnnSAOfP/swZrOFpNseRuk+XYz1jklkrK6c8epmu+dXBvpa/yHLmPuGJju/Jp9/QkCXT9AVLp6gk0wZ7GffgSbLmKqaQZLRJkUjqlW4ZSTglmGtMj6wt4xPHn4Yd08vLnjwcdICvdmYEsqwycL+7mEKK+swdlpfS/CaC9BVHGa8uxWFUkN3dzfr129g48areemll+ZlHLdpQ83NzcTFxTldPLeh1WrJyMiYF1YuKSkpbN++nXvvvZfFixdz8OBBFi1a5LT1uJh9vtYC+rPPPktSUhILFy6ktbV1xmnCc4XNuiU1NdWp65hKd3c3Bw8eZPHixTQ2Ns44WNQZDA4OcvXVV/Phhx8hyxIjdRWMtTfhFj7dm11UqUndcCH5kYGsW38Wo6KSfV3D/K26i1HbrnbkAqgpZ7jqsJ2ALqo1KH0DMQ/20rdvh7VyrcdauWYZ1VtPEgRrpdlx2BJqedRgd2wyWDtIuiWDcdJvVekg8daXN4Aso/YPsmspN/R1YxnRATDgG86W1gG2tA4Q5q5mabAXG5NDuOD+u/jkk09ojMzAYDTSV7SdgerDqFTueHqGUXa0ggsuuJCOjnaH770zGRwcpLCwkNTUVIaGhigoKGDFihXzIqlUqVRkZ2dTVFTkdCuX1NRUdu/ezYMPPsiyZcu466675o2g58LFmWLfvn18/PHHlJSUUF1dzfr16526nqGhIWpqapxq3XI8Y2NjFBYWEhERgVqtnvzOPH6wqDOQJIlNmzbx2K8fw2A0gCDQt28HwavOszs3asUGktISOO+88/ANCqa0T8/vjrTRPWaNpYYAa3fcWEczZv2w3VBOr5gFGDoaUceGEXTDxagjgxFU1ttcY1s3+oIjmHuH7GLq1Ipz2WCC4/NDozVWO7JwGWvqBovkMI6P17QA1qRf8rTQU/gZ3ds/QuHujkdsMrracpBlTMEx7O3SsbdLh5dKweIgL86N9ufCay5lS4QPxf1jiOnLCV57If37dzJQUoAgK9DpRrjxxpu4/PLLnWo/4Aib57mnpyeJiYns27eP5cuXT3qiO5v5YuUSGxtLXV0da9eu5ZlnnmHz5s38+Mc/dtp6XLiYDcbHx/n5z3/Or3/9a+rq6khOTnZqF/Z8sW6ZiizLlJSUYDabJztxlUrlvCki+s9//sPGjRvp7OwEQaR7x0d4xCXbCc6+adlEDzZzwXnnkZYeS9XgGP+s66F2aAwZkAV3JJUazKOM1FXgmzG9ylwbbv0+NtS2IksSwpTNDUGpAK0Kxk2YewbtBHTRfUJAd1SBbrSK6o7iuLlnopMszL640dTRBxYJBAFNgn2H/nhlEwgiivBYyocMlA/1oBQEFvp7sDTEi7PPWsxe97v5vOgApuUbCFh2FqNNtfQWbkHfVA2CyB//+EeSkpK49957Hb31TsPmed7d3U1eXh6lpaVotVqSkuwHnjuD+WLl4uXlRVRUFMPDw/zoRz/igQce4JNPPnHaelzMPl9bAb2np4enn36aDz74gNraWhYvXuzUiqzh4WEqKipYvny5061bbPT29lJcXMyiRYuIjIwkNDTU4WDRuUaSJB566CGeeuppzGYTgUFpjI0Ooh/rpHvHx8RccfPkuQnebuSHeZOYew0Fu3fz6K82MZ573mRVuQ2v5Ay6tr3PeFcbpuFBVF6+0457J6TQX1rA4MFClEH+aOLC8F6ahyoqBHPvIP1/+QRT58yVa/K4/W63LYALjqrWegetx1RKFD7TRVhZkjBVNwHQV7iFoSP7cI9ZgGdsMp5xydahY1hb5VSex278OkaNvN/Yx2uvvUaah8hF37qY0PBw9nUPszc2ga7ODvr2bmHgyH4QYOFC53nwz8TxA0MlSWL//v2TgpCz5xeAtc1yPli5+Pr6EhoaiiRJXHPNNTz00EP8/e9/d8paXLiYDWRZ5v777+f2229ncHCQmJgYp25aSZJEaWnpvLBusWEwGCgoKMDf35+sLOtAaUEQ7AaLOoMPPviAjRs30t/fj7t7EKEB0XR2HKCveBv+OatQull/lwFaJfmhPixeGktDfRRvv/02NYInfss3TLueJiAEhYc3Fr2O4dqj+GVNt1Rzj4wFScYyOIwmbnpLrzJo4vdltmAZ0qP0PaaSC4KAoFYhG03TZpdMMjEQ3KGFS0cXcMw3dSr6ygYQRTxXZuF/2VnIZjPjNa2MHa5BX1QOExsKnlPmmAybLOxoH+TjPUX4VBRy/vnn86uL86gYGKWgU0PT2m8QuOws+g/somfXp6hU6nlTEWbD0cBQWZYpLCwkPz9/XvztqNVqFi1axIEDB5xq5SKKIikpKVRUVPCrX/2KG264gY0bN86LzS8XLs4Uv//97wkICCA/P5/6+npiYmK++EGzSGVl5byxboFjHeo6nY4VK1ag0WhQqVR2g0WdQWNjI5deeiklJaUoFGqiY9bQ3LSD8a42RmqP4pVotRPRKkSWBHmxPNQbsn7Eh++9x+//8hYB3/nhtOsJgoBfRi59+3aiqz6CT3oOht5O9A3VjDRVM9ZaD1hzaFNbD+qokGmPV0aEYq5rwdQ9gNvC6WsV3TQgCg7juGwwgSzPbMUmiqhC7Td4DbXWjXB1dKhdQZwsy+h2lYAs4Z18zE/cLMsc6huhtKMP3dsvcu4553Dfj39Ev0mmoHOII2IiHrGJjHU00/b+37AM9bFhw/T7HWfjaGBofn4+e/bsQaFQzAufb0EQyMrKYuvWrbS1tTnVgjg5OZktW7Zw8803s2TJErZt28a6deucth4Xs8v86FmaBZ5++mlWrVpFSEgIXl5eBAcHf/GDZomp1i0BAQFOW8dU+vr6KCoqIjMzc7Iy3+aJbrFYKCoqwjKRNM4ln3/+OUFBQTz22GNotYFkL7mBjKyrWJB8AUgS+qYa9M11JPm6cWtGBJcnBtOpN/J0aQu//8cHVFRVTQzdmo7aNwCltzUwDtcctTvuFhEHkoQqKoToF+4i5K4r8PvOejzzFuKWbg0Sph77CvRJ71Sz/XtlayFz1C5mq2ZXBtm3i5nae0EGlApCfvJ9PNZlMa7vpP3jt6h+8Zd07/4UBAHvlCy760omI53FO9i6ZQtPf17MX6q68NcouWtRFFcuTSPt4u/js3AxyMw7y4/jxXOwJpc5OTlotVoKCwsxmRyIG04gLS0NvV5PQ0ODU9eRmppKa2srd955Jx9++CFHjhxx6npcuDiT7Nq1iwMHDvDDH/6Qnp4ep1e9zDfrFqPRSEFBAT4+PpMDQ22e6DExMezZs4fh4eE5X1dHRwc5OTl885vfQqcbIznlEnKX30Fi8kUIggrZbKavaBsBWhVXJAZze2YUWoXIH8o7eP4z60yW7v27kCX7uOqXlQuCwHCV/XedNtQqMlgGhjEPTH/doloFKmtRgNlhLJ/YDHdQuWYbLnZ8LJctFhi3nu/IwsVwuA4kCW2StaJOUCpxS43F/7tn47kqCwQB96h4uxZ2gO7iHRwuK+PlDz/n2UOtDBrMXJ0cyk0Lw1kQ7Ic22LpBcN11P5g39gPgWDwHiIuLIyUlhcLCQoaGhpy8SiuhoaGEhYVx8OBBZFl22joiIyNRqVSkp6eTkJDA73//e6etxYWLM83o6CiPP/44Dz/88LywU+3v76ehoYHFixfPi+9OWZY5dOgQ/f395OfnT1pR2DzRDx06REtLy5yvy2w2c9NNN5GQsICSklIiopaxfOW9JCSeh39AMggC3Ts+Qi3KbIj0477F0aQHePBpcz+PF1by7rv/pKu2grHOVrtreyVlgCwxUnuUmt8/Qv0fn6J710dIbkZ8Ll6FMGHVYuvimopbbAgoRIdxXNSqQRAcxnHj6BhIkuOZZO09YLE4juO1raBQoE2Ntb9mUyforR3osiQhmaYX0w1VlNLe1sbrb73DEyVNlPQMsy7Cl3uyo8kN9kLjF4BpeJCQoCAWL15sd31n4Ug8B/Dx8WH58uVUVlY6Pf+1odFoyMzM5PDhwxgM9m4Ac4WbmxtxcXF0dnZyzz338Mtf/tJpa3Ex+zg/cswCg4ODvPTSS9x///3U19eTmprq1Orzuro6jEbjvLFuGRkZoaioiLS0NLvWVWeK6H/+8585++xz0elGSU69hJy8W/H2iaattYjysrcASEpO4absOC5LCKa0Z4QnSpr5rHUAnclCUN5akCR05SVYxu2Heh5LvA/bHXOPiAXA1NpttVeZgirEWi0ljxmQRsenHZtMqB28T7YdcMHBbrdpwk/d0eAx2w2DJj4CjyUpBFx5LpGP/4iYzffjf9X5YDaDLFtvQI5jqLwUJAmFmwfeyRk0Do/zRk03zx2yXvPOrEguzc0kZ8niebF7bMOReG5DFEWWLl2KQqFg//79Tk10bdisXMrLy9Hr9U5bh4eHB9HR0YyMjLBx40Yef/xxp63FhYszzWOPPcYtt9xCZ2cn8fHxaLVap63FZt2yePHieWHdIkkSRUVFeHh42HXYOVNEHxsbIzo6hgMHSoiIWsayFT8hPDKXocEmDpa8iiyb8PP15f8tTuG2jAjGzBJPH2zm73U9tOkN+CxcAoKIRT/McG253fW9kjJBlhlprMZiGGe8u52+ou00vfMKtS8/OnmerWpsKopQawGDudt+kOikHdtxlWuydGy42fGt3+Y+3cSFRRT+020AzIPDMHEtzQJ7+0DdzlKQZbyT7TfCTbpBxhoqQZLwW7KSQYOZT5r7eaKkmYqBUa5KCuEHi+JZkJjISy+9ZPd4ZzGTeG4jISGBBQsWUFhYyNiY/T2aM0hPT0en09HcbO+3O1cIgkBqaiq1tbXcf//9PPfcc/Pm/XHh4nT505/+REREBAsXLkStVjt14J/NuiUpKWneWLdUV1fT3d3NihUr7O5xnCmiZ2ZksnnzZry8o8hddjtJyd/EYjFSXvY2/X1VKBUKzlmeyz2ZkcR5a/m/ig42H22nrF+P0icAt5hEEEUGSgvsru0WEQMKpdWqdEEooQ9cQ8wfHyTsoWvxu2Qt3svTQSE6jOOqkACQcWirKmg0gGAXxwHkEWv+7tDCZWJeiTLYXkAfOVAJFgvaJPsuAP2+chAEBJWS9o/epPrFX9D20Zvom2qQJAs9e7eCIOCXnY9JULC3S8fzh1r5sLGPFWE+3JEZSX5eLv/4xz/sru0sZhLPbfj5+bF8+XKOHj1KR0eHk1Y5nYiICAIDAzl06JBTNYLExEQGBwe58sorKS0tpaDA/rPv4uvB11JA/93vfkd2djahoaH4+Pg4tep7eHiYyspKsrOz54V1i8lkoqioiJiYmBmHIDpLRO/p6QEkEhLPJzwil8GBRvYXv0h15XskrFjBwy+8zMO//AWHSw7w8Htb2dM5hHnKF6VnfDKimweyxcxg2T6769sSb31zHZbxMSSTkZH6Srq2vk/Le/9nPUmWMdRP9wUXtRpQWP9UTMcNEp2sQHfwfW3bAbd5sk3F3D0ACoXD3W59ZQMoRLTJ01scFd4ek4K9JigMta/957rXFqwXr0BQHPu8DRjM/KOuh1+8uJmwsDAeeughqqqqMJvN9gufY04knttQKBTk5uYyOjpKebm9qOIMbFYupaWlTg3YCxYsoL29nVtuuYV//OMf1NfXO20tLlycKUpLS9mxYwfXXnstfX19Tt3ws1m3JCQk4Ovr67R12LBVrFkslhmr6Jwlog8PD2OxWAgITJlIuA2UHX6D0gOvoA7w4JZfP8tLL72Mp4cHv9j8Z95r6EVnPHaPodBo8cvOB0FkwEE3mTYkAkHtBpKF2s2PUv+np+ne/TGShxnfS1fjvjh5IvG2r3pzS4gEUbSL43DMjk0yTt9An1rJdnwFuq0CThnoO82nFZh8flV4IAqP6fYg5r4hLB1WSzizfhiTbroQMHBoLyCgCQ7HLexYkYNRktnRPsjP3/mEprpaHvv1r9m/f79TN3FtfJF4biMxMZGQkBCKi4ud0uV4PGq1mqysLMrKypwqWoeEhKDRaMjIyCA4OJjXXnvNaWtx4eJMYTKZeOqpp7jvvvuoq6sjKSnJqQVtlZWVKJXKGXONuaa9vZ3a2lqWLVs2o42Us0T0wcFBFEotmYs2onXzp6F+C0WFzzKgq+OS2+7l5T/8kfXr1/Ob3/2eV8paaR6ZXv0bmLsWJImhsv12RW2CIOKXmWvdfPbxwD0r0dolNoE2KRosEuNVDgaJhviDJGHqcrARbovjDgR0aWR04pzpObksy8gj1vUdn5NLBiNS39CxNR3H0PYSkGUCrv0Gkc/egc9FK9B31dH05kvUvvwrzAO9APhlLz/2fMDRfj3PFFbwjzff5LrrrsNkMtHd3W13/bnmi8RzG/7+/ixevJiSkhJ0Ot0cr9IxmZmZ9PX10d7uvNluarWa2NhYuru7+dGPfsRjjz3mtLW4mF2+dgL66Ogozz//PPfeey91dXVO9TezWbfExsbOC+sWWZY5cOAA7u7upKWd2P/aGSL6PffcQ3h4BLU1n3Lk8N84WPIqvjEhPPCbl9j04xsZVblx9zMv8uZbb9H8+b/tREtBEAladhYAAwf22B3XBIYgunuCLNH45u+p+s1DNL/zCoPVB1DGByBGBoEgOK5cC/AB7Fu/pybU8nHvkW0HXHSzr5ocP0G72HhpDVgktMkOgvWuUgBU3n6Y9dMFkbGOFkwDPQD4LVpm91hDbxfl2/7Do48+yk9/+lM+//xz/vOf/1BfX480pcpuLjkZ8dyGSqUiLy+PpqYmp7QzOmLhwoWMjY05tZXNw8OD8PBwLBYLl112GU899ZTT1uLCxZni8ccf5/rrr2dwcJDo6OjJtmZnUF1djSRJTreQsdHQ0EBXVxd5eXkn3Jh3hogeHBzMxo3X0NdbQWX5PykqfBa9sZ2rH/glLzz1GHERofzmv3t46qmnKP/8Q0y6Qbtr+C9eAbKEvrEa40QCOvU1+WVZE2/RR3uscu3Bjfh+aw0euQtnTLxVIf4gzFC5NhGn7SrQjRObzAoR4bj32nY/4GjwmKGmxboR7qDtW3+gEgDRXUtf8TZqXvoVjW/8jsHDxVjGRukt3g7IBOSsthObZMlC7Ufv8Nprr3HzzTfzzjvv8Pnnn3P48GHGx8ftnmsuOFnxHKy/v8zMTERRdLp1io35YOUiCAKJiYnU1dVx77338tRTT82LAgcXLk6HN998E41GQ15eHqIoOrX63Gbdkp2dPS+sW4aGhigpKWHx4sVfWA3vDBH9rbffwmI2UF72DsV7n6OpcRtrL7+K37zyKhflL+Wz1kHuuutu9u3awdDRErvHe8YnI2qtRW1DR/fbHfdKzgSLhH5fxbROLwBNojX/NbX1II1NF+ZtebPZkYCu1YAsTw4MnYo85rgCXdJNbECLAspAn2nHjA1WMVbh4zmpA9gwdQ8g9w2BIOCxJAV1eCB+31lP1G/uJOwX12NRySCKeCVl2M1dA+gu2MLnn/2Xm266id/97vfs2rWLPXv2MDBgf38yF5yseG4jPDychIQEioqKMDp4v+eaqVYuzroXAmunXXd3N9dddx2ff/65y1r1a4rzI8gZ5o9//CNRUVGkpKTg5ubmVO/z+vp6jEYjKSkpTlvDVGx2Ezk5OSdVAeAMEf2DD97HYhlnYKCaHzz4CM898gu0Hl785lArHzT24Z6zFmSZ8a5WRursK5F9M61TmI0DPYw21007JgiCdcdbFDCNDeJ3xdlEPn0b0S/dS/CPL8NvvfWx49UOWsbiw0EQ7BJvQX0soT4+8ZYMRhBFhx7opvo2YGInfepjxg3IE8Fcmzi9XUwaM2CqtIoCIw0VVL/4S5refpmhoweQTEZ69u88YbDu2P4RTNw0NjX3c+utP2bTpk3s2bOHLVu20Nvba/eY2eTLiOc2PD09ycnJ4dChQ067yZiKUqlk0aJFlJeXMzo66rR1JCYm0tzczJ133slrr71GZ2en09biwsXpUlNTw7///W9uvvlmOjo6nFotptPpJgeRzwfrlu7ubsrLy8nNzT2pwYfOENH/8Ic/4ObmTkf7flZd+l1+//LL5C1M5a2abv5U0clgUDRK3wCQZXoKPrN7vCYwBE14tLUK/WCh3XHvpAywSJgHR3BbGD+tck0zUSVmqGu1S8pVIf5gkTA5snCZ6BQ73jvVFtcFtf0Aa1PPoLWTLNS+QGKkpMq6Ee6gak23swQEAd9L1hDzyv0E3XQJspdM+ydvU/37h8FkRNRo8U5dZPfYoaMlSHprxdfgkJ5nn32BW2+9lY8//pjPPvuMurq6ORWBv4x4bkOhULB06VL6+vqora2dg1V+MRkZGeh0Olpb7TsX5gqbuLhy5UoEQeDtt9922lpcuDhdJEni8ccf5yc/+Qn19fUsWLDAadXnkiRx8ODBeWPdYjAYKCoqIjExkbCwsJN6zFyL6KtXr2bDhrPo6y0nZEEcT77yJ37wrQvY1zPCc4daODJiwX+ZdUhi985P7IrIBEEkKN9a1NZ/YLddXPKISgAEJP0YhurpG95KX0/QWmOuoW76d7JtYLdFp0c2Td9kFLRqkCTMo/YCqjQxr0TUTi/GMNlmkvl7IxwXv8ZrW0EU0abE2H12Rw9UgmC951D4TB9Kro4KQe7TgSThv3il3VpMukH69+8EwGgy8f4Hn3LNNdfw5z//mZ07d1JSUjKnovSXFc9tJCcn4+Pjw759+5xWiDcVm5VLWVmZ09ag1WqJjo5Gp9Nx7bXXuqxVv6Z8rQR0k8nE008/Pa363FnB2mQyUVVVRUZGxrywbmlpaaGpqYm8vDxUKvtEcCbmWkRfvHgx5517Lk889muWJsXzh/IO3q7tpt9gDZJq3wC8s5ZNDC/5GFme/oWtcPPAc+GSGX3XvJMzQZKRDUZ8zs1DHRk8+RnRJEZZLVyqm+wep40Inmj9Pk5AF8XJxFo6PvE2mkAQHAro0pBVJD++At1QNyGsB/lOC8gAo4dqrMeC/YjZ/ACB130Ti9pA2wd/o/rFXzJy9IA1WC+xD9bjXW2M1pZZjy9dw7hZh6hQcuRIAxs3buSll15m9+7dHD58eE6qnk5FPLcRHBxMamoqRUVF88InNCgoiLCwMCorK522Bm9vb4KCgtBqtZx99tk899xzTluLCxeny5NPPsnll1+OwWAgIiICd3d3p62loqKC6OjoeWHdMjIywv79+8nMzMTf3757aSbmWkQXRZEXXvgtP/7xj7nx0ovY0jbI78vaqB0am1iPSNjZl4AsMXhoL8bBPrtrBOWtB1li4GAh0nExyS0iFkQReczAeGXjtGOqsADrMZMZY8v0lmjbhrW5c4bKNUGwa/2etGJzMHhsvL3HOnx8IqGffIwkYW7pAuzbvqXRcUy1bSDLeCxNQ3TX4rVmMWE/+wFRv70L2VMDgojfouWIKvuhpZ1b3reK74uW4R6fhMUyTnePjgceeJCf/vRBiouL2b17NyMjI3brPdOcinhuQ6vVkpubS1VV1bzY8FWpVCxcuJCKigqnWcuIosiCBQuor6/nnnvu4fHHH58XooQLF6fC+++/z9DQEGeffTZms5moKHsP6bmiubkZSZLmhXWLJEns27cPf3//L93VNtci+j//+U8u/MY3eOLBe+k1yTx9sIW9XTosE1p4YN46EBWYhwcZPFJs93jfzFwAjP09jLZaO3Ulo4HBI/to/scfABkUIvr99vmTNjsZRMEqYk9BdNeCaM3bzb2D049N5NsWvYPccOI+wt6KzXoNR51kI4frQZbtLFUBhrYdAMBzWbr943Zau8XV/sG4R9vbD3bu+hQEq01b8NpvIAkWxsaN/OlPf+G6665j27ZtfP7553MSG09VPAfrveXixYsxGo1OFa2nkpGRQWdnp1OL7KZaq/7zn/90Wat+DXG+snsGeeONNyZbxerq6pzaKlZTU4OPj49TK+Bt9Pf3c+jQIXJzc7/UF6MNm4i+d+9eioqKyMvLm5VKPEmSqK2t5Uc/+hF///s/+McnTxGz8W7E4zYgQladh+5QEYaeDoarjuCdMn0IV9DSNYwcPYCu6jBm/TBKD6/JY5qQSBAVyAYTY0cbcM86ZvGjibNWAViG9Jj7hlBOadeyVq5ZZhhaokI2muxbvw0mEKb4pNte5+g4yDIIAsqJSeM2DLUzt30P7T0Coojn8gwUXu54b1iK94almDr76P3j+4wdqbMG6yj7YN2x7UMQRDzjkwk961sErTiHnj3/pf/ALtQqTz788L/s3VvIm2++ybZt28jOziYw0P5m4kxwOuK5jfj4eIaGhiguLmblypVOrwxNSUlh69atLFiwwGnVLUlJSRQWFvKTn/yECy+8kAceeGBeiH7H052tQXGG7TgsBhm2n9FLunASbW1t/OUvf6GwsJCWlhbWrl3rtLX09fXR09PDhg0bnLYGG7b5JdHR0XbDv08Gm4gOsGfPHlasWIGXl9cXPOrU6OrqIjIykp6eHm675Ra8v7kRbfD0+zHP+FTUQeEYezvp2f0fIr7xvWnHvRIXIqg0SIZxhqsO4bNwCbIsM97VxlB5CQgiKEC/vxK39GMxTxAE1ElRGCubMNS0oIkJnTymmhgQZu7XIUvSNN9yUasG0X742KSA7mgYeJ1VCD++k8wm3IvuWpTHVaePHqy2riUy2L5y3WyBAavw7Zedb/d8g0eKkcb1iBotIWsvQqF1Y7S1gc7P3oMuHTU1TVx77bW8/PLLDA0NkZqaSnx8/KwUkpyOeG7D19eX7OxsDhw4wKpVq5xeGRoREUFtbS0NDQ1OE9qio6Opqqri/PPP55FHHuGjjz7ioosucspavogzHctdcfzrgyzLPPbYY9x99900NTWRkJDgtPt0s9lMZWXlpHWUM5FlebJQadGiRaf03WwT0YuKigBmbWNCr9dz+PBhrr7qKjZt2kRPUDwBMGdM/wABAABJREFUeWunnaPQuhO86ly6d3xMz65P8UnPQVSqph33WpjDcEUJPbv/y6CXN7qqQ8gmE9rkGLw2LGX4833oi8rwv/Lcae+HZ1o843uPYnDQFS76eiL1D2PqHpgmfNuqy22d3NOwWDcj7YaB9/TP2ElmrKgDWZ7sbJu81Mgo5maruO2xNHXaMVmW6XtvO4B1Htlxv2PjYB/DE5sNIWu/gWd8Cr4ZS+nZ/R8GSgvQDSu455572LhxI7IsExYWRkZGxpcqfjxZTkc8t6FUKsnLy2PHjh14e3sTGxt7xtf5ZdBqtcTHx1NeXk5+fr5TCmlt1qpms3nSWnU+DXyfiiuOnxpfmwp0SZJ44oknuPfee6mvr3dq9fn4+Dj19fWkpqY6dVgKwNjYGMXFxaSmpp6WmD/bleg6nY5du3bR0tLCypUrWbw4m7HeLvr2brFfi6c3AcvWHatCP65Cxy00EnVAKCAzcMh6g2Ho7aRr+4fUbv4VSBZQiIzur5j2OEGpRBFirSQ7fsdbFWINrKZO+0o522728a3fksEEsmy3220bYKbw80JQTr+hHDlU67DtWzZbMBQdBUnCPXe6f70yxB9Ds7XazT9nld1nbqy9ibHGKpAlgtdcaH1urRuhZ32LhOt+gjIkGJNphIGBQfLz84mPj2fv3r0cOXLkjFejnwnxHKwiSVZWFoIgzAsfVQ8PD2JiYqioqPjik2cJf3//yU27xYsX87vf/c5pa3Hh4lR59tlnueCCC1CpVISEhMyayPtF2BKLBQsWoNXaz7GY67Wc7PySEzHblegmk4nS0lL2799PSkoKP/zhD+nrH6D947ft4rQgCISd822QJYbKDmDom14tLogKApefBYJAX/EO+oq2U/+np2h47VmGKvfhvmiB1T+1qMzu+98zO2likOj0xFv0dAMBkCQsA9NfuzBRgW4Xxyf+f3zSDWDpt1qpqEKP6ySrbQFBQJsSaxePh3YeAlHAI2+h3fUG/mMdHuoRl2I3JFwym+jc+j4AgfkbUGit9j3ukXHEbbydsPMuw2gZw2A0smDBApYtW0Z9fT179uw540NGz4R4biMiIoL4+Ph54aMqCAKpqalUV1djMtkPoZsLFAoFCQkJk5Zsjz32mNPvb1y4+LJs27aN2tpaLrnkEvR6vVNFtfr6etzc3E7aKmU2aWhooLOz8wvnl3wRs1mJLssy9fX1bNu2DS8vL7797W/T2dlJ986PMQ7ad2/5L1kFShVm/TCDB/farzV3DUgSo03V6Lvq8L1kNVEv3E34wz8k4OoLAGsVuKmtZ9rjNEnRVsvW6ma770D1gqjJx03FFqclvQMPbMl6jeMtXMY6ekGS7DbCzf06MFlAqUATGzrt2GhJlXUdsWF2hXDj5Q2gs1p69hVtpXfv1mlDVDt3fAyCiFtkHB5xyQAo3T0JO+dS4jfehejtBYKAQqFg/fr1GAwGtm7dSldXl/1rOg3OhHhuw93dndzcXMrKyubcDtYRiYmJDA0N0dPT88Unz+IaplqrdnR0OG0tLs48XxsB/T//+Q8DAwNs2LABs9lMZGSk09ZSVVVFcHDwl2qxng0sFgvFxcWEhIQQHx9/2tebDRFdkiSqq6vZuXMngYGBrF27lubmZp588kkAego+w9BnHzQCl60HQcA40GOtRjuOoPyzQJbpK9pG/Z+fo+4PTzJwpBC3pUn4X3W+NfEuLrdL6j1z062Jd830G5LJ1u/eQbtAbgvGDlu/ZdnBbrfjwWOyLGOstNrHHC+gj1c2WjvdfD3RxEdMP1bRiDQ0AgqF1Rv2ODo+ew8EEe+0xXZVgJqAEDxirEL2Y4/9GpVKRUJCAmvXrmVwcJDt27fT12e/aXAqnCnx3IZCoSA3N5fe3t554aOalJRET0/PGXu/TnUN9fX13H333bz44otOFyRcuPgyDA8P8+qrr3LnnXfS2Njo1CHgXV1djIyMkJBg39Ez15SXlzMyMkJOTs5pV9DNloje3d3N1q1bGRsbY/369fj7+3P55ZcjSxbGO1scWqp5RMWjjYoDUaBn93/sjvtl5VkT6J52unZ9hHJBEKH3XU30S/cScuflIIBlYBhj0/Q2Z01StHWQaOV0OzZBEBA8rHZADgeCyxOzS6YwUwW6bDJbK8YBZdB0Cxd9eQMI2A0Cl01mDIeqQJKtw06nIBlNjPy3CASZ8e5Wu6R78OBeZKMBhbunnaeqIIhog8ORzSYWpqWxcuVKAgMDWbduHd7e3mzbto36+vozIsSeSfHcRkpKCt7e3vPCRzU4OBgfHx9qamqctobY2FhGRka47LLLKCsro7jY3hrBhYv5zHPPPcctt9xCR0cH8fHxTrMyNRqN1NTUkJaW5vSCtp6eni81v+SLmA0RXa/XU1BQQG1tLXl5eWRmZvKrX/2K3t4+ZEmi4z9/t8+B1RpC11m7ZHr2/BfJND2GakMiUPkFgSDgvSEHv2+vQzURM0W1Ck1WAogC+n3T55qpo6xFf9LIqJ1Qro0MBoXCcRzHOk9sKlPXbGfhMtFJZutQs2HbgNfER9gNEB/aVQqCgOdye/uW/vet88g88haiXZxA965PqHlpE107PmK0rZGRilKQJULWfsPuM6n2C8RiGEepVLJ582bc3NxYtmwZKSkp7N+/n5KSkjOyuXsmxXMbAQEBpKens2/fvjO+af9lUalUJCUlUV5e7rQNaG9vb4KDg9FoNJx11lm8/PLLTlmHi9nhayOgv/jii9x44420tbURFxfntFaxkZERmpubSU1N/eKTZxFZljl48CCCIJCZmXnGbhzOpIhuNBon2/Tz8/NJS0vj/vvvJzt7CZ2d3ajVvgDW6rXjvc617gSvOg+AHgfDS7ySs0AUkQxjSG4WQu66gpjN9xF0/TfxOX85iAKWoREMExO2bWiTJxLv4waaKHw8AKsti3Sct5pgGz52XOJt0o+CJNsl3ubuAWu7WNj0CjNz7yBIEoJGhSpyerfA0N4joBDxWJZh97vsf3+HdTioxULtHx6na/uHmEaslXH6lnrGO5oAefL9moqhr5uePf8lIiKCO+64Y/Lnnp6erFy5kri4OAoLC6mpqTmtIHSmxXMbWq2WvLy8eeGjqtVqWbBggVMDdlBQEBqNhvT0dDw9PfnnP//plHW4cHEqvP766yQnJxMaGoqvry9+fn5f/KBZwJZcJCUlzUrb7JehpaWFxsbGLz2/5EScSRHd9l7t27eP5ORkli9fztatWwkJCeXzzz/H09Na9de17QNMw4N2jw876xKQJHQVpYx3T4/HSg8v3JMyAfBak03I7d/FPTsJQaFAUCrRLElxmHjbNplNnX1Wy7QpqGOtm8imbkcCujyzhYvH9C4Ec98QAAofz2lDTAHGS60i+fFt32PlDSCDMtAXdXTItGP6vWUgyfx/9s46PI7z6uK/meUVrJjZIMnMTDEkhsShxmFqqEnTpg2Vm7RNkzTUQBtmspM4YAiZMWYGybIsZqbV8sz3x+yutJZTBSRNkk/nefTY3p135t1dee/ce889RxNhwTRuEDXbPufkc3+netNqnM0NVG1aDUD09Pln1Eav+Ow9RI2GnTs7GIBarZYRI0b4ZQ137979vZLv3iieg/L7OHbs2B+EjqqPhV5QUIDdfgYWYx9Ap9ORmppKbW0t1113Hf/5z39U2Uc/+vFdUFBQwJo1a7jyyiupr68nPT1dtb2cPHmS8PBwoqOjVdsDKIXpPXv2MHz48B4l1/VkEb26uppNmzYRHBzMWWedhcPhIDMzk7/97W+YzVEgS1gLT9CSe7DL2vBRkxAMJjw2Kw37t3V5Pmb6OSDLNH+5qwtxzTJzLEgy1t2BcVwQRbTeIrqjy1R4BMhS1zhu8pmBB05P+81GRRFBF1gMd1V7TURPY6C35RQpkqpZgfrnktOF84iijW4eH9gIdze14jiUD5JE+JK5xNx6ESnP3EXIvHE07N9K0VtPe+VUszEndf1/Ubt9De62Zl5+6SV/fBUEgdTUVD8bfdOmTbS0tHRZ+03RG8VzH9LS0khMTGT37t194qf2v5Ceno7D4aC8vFy1PQwYMIDi4mJuu+02XnjhhX5S208IP4kCen5+PuvWreOKK66goaGB1NSuZg99hdzcXJKTk1UbO/ehtLSU2traHk1yfOiJInpLSwubN29Gp9Mxc+ZM7HY7gwYN4rHHHiM4OI4Jk3/DqLE/B0nCVl5E0+GuDBxlbEyLq6WRpqN7Ap4TtVrCxs0EUUQTGkzQhKH+DrIgipimjACxq4yLcZAyFuYoKEd2d7wuQRDAyzQ/vRPeEbBPG/32jnCd3u22VdaCLHU1EPXeIBgHpwRos8qyTPvmA+CRCDpNvsXd1IbjoBKs4/54HSHzxtF4aDv5zz9A5ZfLqfj8AxBEwkZOQh/elfFetuodkGRSUlK6FFEEQWDAgAFMmzaNgoIC9u/f/50+694qnvsQFhbGyJEjOXDggGoJrw8DBgygra2tx0ftvikEQSAjI8MfsPsT7378WCDLMv/5z3+4/fbbKSoqUjXpLisrw+PxqK7laLVaOXToEOPGjevxe4qeKKK7XC52795NRUUFM2bMICkpiSuvvJLzzluMyyUzbMTVjJ3wS/T6EMUAc81HXc5hikvCPHAYiCK1W7/o8nzMxFkgSbRtPYRkC2SVhc0Yc8bEWzToEUOVprf9VGDibRqQABqxC3NNMBmUAnoXKTY3iGIXE1Ff4n66xrnUbkdud4AoYBgQOC3W4vUxCZo8rGsjfPlGEMCycAoxt15MyjN3E3L2BBoObOPUiw+B24UuNJzwERO7vEf1ezbjqKvCEmohLy+vy/PR0dHMnDkTj8fD1q1bvxM7rLeK5z5otVomTJhAWVmZ6s3wiIgIYmJiOHHihGp7SE9Pp7q6mhtvvJEPPvhAtXuKfvTj2+LZZ5/lwgsvxG63k5iYiKGHPW++KWw2G4WFhd9L9qwn4JNgS0pK6pX6xPctosuyzMmTJ9mzZw8jR45k5MiRvPHGG6SnZ3DyZD5p6bMZP+kOEpImAVD15Yd47O0B5xA0WuLnXgBA3Vfr8DgCc7HQzBEgavA0tGA7FDgxbB6lGKk6CysU2ZROCJ4wFDQi9tOnwmMiQJJxVQdO/Aq+OO0OzFVlb+NYMAQ2u2VJAm/M18UGEjbs+3LOKKlqP6oYQuoSotAnBObVrRv3gShiHJKOPlFp2mgjQom8aj5x917luygxsxZxOuzV5dTv2ohW1JzRBNzHRk9OTmbr1q3fSRKkN4vnPgwbNgydTsexY8d6/NzfBhqNhqysLHJzc1WbbIuMjMRkMpGdnY3FYmH58uWq7KMfPY+fRAH92Wef5eKLL8Zms5GUlKRasG5qaqKqqorMzExVru+DzWbjyJEjjBo1qte0W79PEb2yspKtW7eSnJzM+PHjWbt2LWlp6Zw6VUBaxhzGjL8VAZETOR3JdvX6FbjbAgNrwNjY1i+QTut2Ro+brhTgD+Z16VJbpo4EScK6K/ALXmMJBr0W3B6cpYEJiy8YdmWuKdqpXSRcWpUkVTCcPi5WAZLcpYBuzSlUAu9pbt/OokpweRCDTF064a0b94IoYBySjnnEQCKvnE/Kf+8h7OJZNOcdwNVQjSCKRE89m9PRdHg3jipFq3XHjh1ER8fwwQcfdDkuLCyMmTNnYrVa2bZtGzbbGdzNvwa9XTz3ITk5maioKA4fPqyqXqhvbCwnJ0e1fSQlJWG1Wjn//PM5dOgQ+/d3lTjqRz9+aFi/fj319fXMnDkTSZJU0yv1eDzk5OSQlZWlqjmxb4osOTmZ2NjY7hd8B3yfIrrVamXr1q14PB5mzJiB0+kkNTWVpUuXEh4xiIlT7iQiciCnTn6G09kKskTryaO05B3pcq742eeCpDxvqwpMlI3xKQhGM7LTRdv2QwHPmUYqMcVVWt0lLhsnDAHx6+XYXKc3wr0MdGdz4H2G7HSBIHQxA3fXNoJGRH/aJJnjlMJ20qfEBTDTZUmifcshkKQu8i2O4ko8NYqRWcjMMco+w0OIvPIckh79lX/CLmbmQoTTfiedTfXUbFJMwpuamhg7dhy//OUvu2rG6vVMmjSJ6OhoNm/e/K20QXu7eO5DUFAQw4YN4+DBg6oztbKzsykpKTljIaMvYDabiYmJQavVMmvWLF588UVV9tGPfnwbtLe388orr/CLX/yC0tJSVRvhJ06c8E+zqYn8/HxcLhdDh3b1vegpfNciusfjYf/+/RQUFDBt2jSSkpK46KKLuOmmm9Fqgxgz/hekZcyluuog1VUHlTUOG9UbVnU5l2XoWDTBoUhOBw17twQ852ptQRcVB6JIy5pdAc+JZiM6b7O5fV9uwHNGrxyb40SgHJsvf3ZXn1nCxad37odDqQ+IpxXQPU3K97sYbArQRpc9Hjw1TR176ITmbQeVRvikQPkWWZJo/HgTSBKW+ZM5HQ0rNityqtmju8ipypJE6SdvgqjB7fFw++23M2bMGBoaAjXnffdsPvPtEydOfONcsy+K5wCiKDJmzBjKysqoqanpfkEvIjk5GUEQKC4u7v7gXoAgCKSnp1NUVMRtt93GM888o8o++tHz+NEX0G02G6+99ho333yz6sH6+PHjpKen94i22XeFL+mOj48nLi6u+wXfA9+2iC7LMnl5eezbt4/Ro0eTlZWFIAg89thjuFxOho24grT0OVRXHWD37qdol1pIuewXaC2RSC4XVes+6XLO8FGTEfRG3G0tNB3qGF1uryimar33eFGgdcPegHWmYYomvKuirosxqHGEkpSfnnjrBiaCKCgSLJ0gGvUgdjUf87TZO57vBGelYrChPU1vzbYnBySpy9i3X75l4pBAZro/WMuKLI1vP2YjYRfMRAg1gyAQMW46uhBLwDnd1lYqv1SK5RqjCQQRj0dgyZIlLF68uMvoldFoZOrUqYSEhLB582YaGwPfgzOhr4rnPowYMYL6+npVx7VAGWFzu92UlZV1f3AvQKvVkpqaSkNDA1ddddUP1vm7H/3ojOeee44bbriBiooK0tLSvrfW93dFUVEROp1OVR8VUMzGrFZrr7PnvksRvba2ls2bNxMdHc2kSZPQ6/V8+eWXVFRUEJ8wjhGjrsVhb2bP7v9QXrGb2DnnEzZuBgCVXy7vwk4zRMQQMnQcCCI1mz8DQJY8NB8/QNGbTyJ72W7NX+wM1DI16NFnp4HQNfEOHpKh6KefHsdjwsEj4a4KTEz9ZuDNgcy6Dg300xrhNY2KHMtpjXB7fqky9p2dFvC4o7ACPB7E0KAuzPSG1TtAIxI8fRSa4MD7x+ZN+0AQ0EfGEjpkdODeZJmyFW+DIKIxGpFlCb0hhGeffZaUlFQKCwsDX6MoMnz4cIYOHcquXbu+kS56XxXPfUhOTiYsLIwjR7o2WvoSISEhJCUlkZub2/3BvQTfNNkvfvELXnzxRdVH4vvRj+6wbNkyUlJSSEpKIjQ0VDUZttbWVkpLS8nKylLl+p33ceLECUaPHt3r353ftohus9nYtm0bVquVmTNnEhYWhizLrFixEpMpgvGT7sBsiuTokXfIPb6c4MyhJF10PcgyTYd3YS05FXA+QRSJP/tixX9s5wY89nbsNRWUrXyL/BcfxNPWoJiJHjyhSJZ2gmXuBBAErLsDSW2Ggcp9mKO4skOGBdCEKxN5ktUW4Fvil0w9La75CG6nG4j6PclOmyRzliqFX210OBrvNBsoebdt59EzNsLbD+SB040mLATz2EAipaOgHMfhU4BMzIyucqoN+7fhaqxFEEUEjQadPogDBw4SH5/A+++/3+X4hIQEpk+fTnFxMfv27es2NvRV8dwHn+H9wYMHVTPkBuWeJzs7mxMnTqgWP5OSkrDZbCxevJjDhw9z4MABVfbRj57Fj76A/v7775OYmEhycjKhoaGqdZpra2tpampS1fQMoKSkhJaWFoYN62ps0Rv4pkV0t9vNvn37KCoqYvr06SQkdHRfH3/8cURRQ2nxNo4dWUru8Q8JzR5Jxg13E5w2mOQLrwVZoiX3IK2nAiVXBI2W+HkXAlCz9Qta849T9O5/KXrzKexN5YQumAySTMu63cidvjwFnRbDiEFKwD5NxiV41GBlZCw/8AbElBgDwteMfgtCV+1UhzJu3lkDXZZl8I6hd2agy243UqNSuDAODCzcWNftVeRbTtNasx082RGsxwQGa9uBPDyV9aDREjlpNqej/MsPQQZDdDyDbvsLUZPn4PY40BlCWLVqFXFx8eTkBL4vGo2G0aNHM2jQILZv3/4/b9D6ungOYDAYGDlyJIcPH1ZVysU3NpaTk9MjRrvfBWlpaVRWVnL99dfz7rvv0tzcrMo++tGPb4KKigpWrVrFVVddRX19vWoybC6Xi7y8PLKzs1U1HLNarRw/fpzRo0f3iQb7Ny2iy7JMYWEhu3btYujQoQwfPtzf6FiyZAlRUdFUVx+hsGAt+/Y8hxxsIOP6u4gcP5O4mQsRTUF42tv8RfLOiJu5wK+xWr3pU/JfepjylW8hRBmIvftKEARcZTVdGtuWOeOArjroxsHJIMs4TpQEFIn9DPSa05hd3kkxT1vghJWSnMtdpdhOloHUVYqtbefRM459t+xQGuHBk4YFNMIlmwPb1v3gkbCcMylgjaetnZaPN4Esew3HAm/ZW47vx15ZjCAKpF19B0kXXY9H9KDRGikvr2DQoExeeeUVTkdqaiqTJ08mLy+PQ4cOfe14c18Xz0H5XRw5ciTV1dXfaUS9J5GVlUVVVRVNTU2qXD8qKgq9Xs+oUaMA+Pzzz1XZRz/68U3x/PPPc8stt1BcXKyqBFpOTg4pKSm9Xij8X5BlmQMHDpCent6juuf/C9+0iN7Y2MjmzZsJCQlh6tSp/ml1QRC4+OKLsNnqKS3Zzu5dT9PYUkjSBdeSeN6VhA4eTsiw8SAIVHy2rMvkd8igYejCIpFcTgrfepqCVx+jvaaIyGsWkvLsPeizM0AQaFkfSGoLGpsFsoztWGGAb4kmyKTIp3okHJ3MwgVBAG/MDpBV1WpAVO7dOsd9v4TLaZ5krppGEEV08YFSLI6TX9MIP1mmeJVEWtCnBpIUG5ZvUIxSz5nYZVKs5uWVyutMz0QXFngtV0sj1etWABA353wyfn432ohIEECSNFx66aVcfvnlXZrdFouFmTNn+hshXzcd3tfFcx/S0tIICgpSXcolPj4es9nMqVOnuj+4F6DVaklOTqahoYErrriCF154QZV99KNn8aMvoP8QgrXvy2ngwIHo9fruF/QSbDYbR48eZeTIkX26j+6K6Ha73f/lPnPmTCyWQDb0qFGjePTRR2huKaGuPoekC64hYdHlaAxKQDfFJSnsNUGg8vP3kZyBOqiWoWPRmIORHO2ULn8Zt2gj5reXk/TvO4i8ZiGCyYDUZsO6O7AgbJkzDuSu+qm+kTF7bqCRqDY2AjyeLom3MvqtGIt0huQ1MRE6Jd4+A1IxyBhQWPfdGOgSoxHNHbI7rppGZKsNwaDzs+Z9qHlFCcieFisVf30Ju1dDXZYkal78GEQRrTkIR61y7pbcg+S/+DDHH7kHa95hkCUSFl2OqNMTM2MB0TPm4/YoNy719XVcd911nA6Hw8ETTzzBI488wtatW3nggQe66JWqUTz3ISEhgZiYGA4dOqSqlEtSUhI6nY6ioiJVrh8cHExERAQREREMGzaMt99+W5V99KMf3wSvvPIKc+bMASAuLq7XpMe6w6lTpwgJCek1yZRvAl/SnZyc3KfGZ90V0WVZ5vDhw5w4cYLJkyd3aXJotVq++mo7suSiuHAj4WOnkH7NrzFEKe+lqNN7m+Eyjfu30V5x2kh2aDiWMdMAgfqd69ENjCXxwVuJ//P1BI3LJuicicr499pAPxTz6EyFaZ5ThKetgz2ujQpTjMTb7QFTY9pI5f7D09gaYD7ui8eSLbD5KjvdIMtdJFycJUpxtzMDXZZlXCWK9NvpBfS2dXvO6GNS+8LHyl8EqHtphT+OA9R/oox8AzQe2YWjodYfx3MevZfyVe8AirGoISKa0MHDiZl1Lug0yLIHj8fF7bf/itNht9v561//yq9+9Ss2bdrESy+91GVyS43iuQ8mk4nhw4dz6NAhVaVcTCYT6enpHD9+vPuDewE+87iysjJuuukmnn/+eVX20Y9+fBPs37+f48ePs2DBAhwOB4mJid0v6gU0NDRQU1OjupyqT7qlr1nw3RXRy8vL2b59O4MGDTojM37ZsmUkJCRQVLAOTWQ4GTfcTWjWSP/zCXMvAI0WV1MD9TvXB6wVBIH4+ZcA4KyvIeKq+SQ/+Rss8ychGvVE/mxWJ1JbR/zVhAYpsVSSaD94MuCcprEK2c1xGqnNL+PSidQmCAKCVzqtM2Nd9km4mM7AQBdAGxM4KdF2MO+MjfBmr49J8KRAH5OG5RtwFVYoNYVdxwLiuP1EMa4CJb5aC3IpXvYcdTs3+ON4/kv/Ul5nYjphoyZhiIwhYtIsdJYI3G7lnmbZsmVdJsrsdjt33nknF198MZ988gkrVqzoUiRWq3gOymcxevRoysvLVZVyEQSBIUOGkJ+fr9r9RFpaGhUVFVx//fW8884738lzqB8/LPyoC+iHDh3i0KFDLFq0CLvdHsBq7ktUVFRgt9vJyMjo/uBeQl9Kt5wJX1dEt9lsbN++neDgYKZOnfq1+vR33nknAzIykD1uRH3X4knczIWIBhNuaws1274MeE4QReLP+RnIikFIwn03EDxxqDIKJQhEXDYPRIHmL3cGrDOPVKYFHCdL8bR0mGrpkhTXb3dNQwAbzR+szzj6LSM7Tvti9t4cdB4Z83XKtbGn6aaeLPN2uwMliNr35oBGxDw2O8A5vPmLHUj1zSAIxP/1BvSpcVQ99Dqe5jase3KQmtoQTXo0kUEUv/tfit79L2Ur3sIydCxovOcRhIAuuS4kjIjxMxCNygj55Zdfzun47W9/y6pVq7j//vvJyMggJSWFZ5991l+sVrN47sPw4cNpbGxUVcpFEASys7PJy8tTbXwtLS2NoqIibrnlFp5//nlVGwr96MfXwePx8NJLL3HzzTdTUlKiWiPcbreTn5/PkCFDVGWfFxYWYrPZelUv9evwdUV0SZLYv38/tbW1zJgxg8jIyDOuHzRoEH/60x8BARAQNNqA54NSBnrZayIVny4LKGADxE47G1C+pyznTMSQ0VGAiVgwRTET/eowntaOQrkmyKTEbFlWRqg7weAzBe/EWhdEEXQakGXc9R16534JF3vg97XLagNJ7mIiKnub4Z0Z6Iqsi4wmLNhfqAcUmTi7E8FkCGC0tX51GOvOo8rru+KcgDjuabHStno7SBJh58/AXlfKqZf/Rdknb2EZOgZTWse0Y1BaR4FG0GgIHzsNU4LS4Jg4cQKnwxfHX3jhBaZOnUpbWxurV6/2J5dqFs99SEpKIjw8XHUpl0GDBtHU1PStNON7EikpKTQ2NrJkyRLWrl2rWlO+H/3oDi+88AJXXHEF9fX1pKSkqPK9IcsyOTk5DBgwQLVGPPStdMuZ8HVF9JKSEg4cOMC4ceMYMGDAGe91RFFk8+bNCKIGyWlHYzQHPK8xmkhafBUgU/vVWhz1gX5hwWmD0UfFgSjgaWxF0Ha8fuOQdASzEam1vcv0t2XBFBBFrHsDG5bBIwYrBfTTps/0WSkgnMmXzBvLO5HaJG9s60xQA6/JuKfrJJn9sGJ0aswMLKBb1+/xyrd0NMLbvjpC00cbQRAwjcnEkJHoj+MANS9+AoKA5dxpxN17NY62Omo2rUY0moiaOg/ZpUy5RU6e7Z8yk91uwoaNI8xrGm42m0lJCdyLL44vW7aMq666ih07drB3716/brqaxXMfzGYzQ4cOVV3KJSoqioiIiDOarPcFQkJC/ObkmZmZvPPOO6rsox89hx91Af21115jyZIlNDY2kpycjFar7X5RD0OSJHJycsjMzFTl+j74pFuGDx+u2h5OL6K3tbWxfft2IiIiGDt2bLeatsePH0en11O24i1cLacFxE7stYbdm7FVBepLhwwejjbEgux00/zFjsDnpo8CScZxohhneUcXVDTq0acnKIn3/g6dS0EU0Xi70Y5THdfRRoUB4K5vDihGCkYDSHIXCRe8Y9GdR79942KnO3db9x73druTAx5v+vwrhbU2MbCY0vjJZgCCpo7AlJVK1I2LEfQ6WjbupfZFhdEWfvFsEv55C9G3XYytUmH7NecfA7cTnSUCY1wSjfu2+c8ZNmwc+rBIJLtSGJg1a1bANZubm3nllVd44oknmD17NpMmTWL06NEkJiaydu1aGhsbVS+egyLlMmLECNWlXGJjYwkJCVFtbCw+Ph6Px8Ps2bP9Onn96McPDevXr8flcjFmzBh0Oh1RUVHdL+oF5OXlER0d3Wej1meCT7pl1KhRqt1PnF5Eb25uZt++fTQ3NzNt2jTMZvP/XP+Pf/yDESOG07B3Cy0nDnd5XmGvaXDWV1O/Z1PAc1pzMGETZ4Mo0rBsbUCc1cVGoEuLU8xGNwcaI1sWTFYS79OmyYInDgWNposcmyZCKW4HMNd8SfdpI+k+M/DOGuiS06U07I16NMEd74cjv1QxAj9t7Lt19zGvj8nQgKZ104cblXOHmLEsmOyP462b9lH3wQYQRUzDBhBx+dkkPfkbdAlRIEDDvq20n8oBQcAQFUfTwa/85wwbNg5L9mhs1UoD+fHHHw/Yy+lxfPz48SxcuJDCwkLWrl1LW1ub6sVz+OFIuej1egYOHMjx48dVaULr9XoSEhJwuVzMnz+fN998s8/30I9+dAebzcbSpUu59tprqaysVE2GraamhubmZlVzEF/DuS+lW86E04voRUVFHD58mIkTJ3ZLtBs4cCCPPfoIjvoaKtd81OX50MHDMXsbtxWfvYcsB8qAJSy8FCSZ5i934m7oaFR3JrWdbiYaND5bYaDvyw2Iw8bBKSBJ2E8zEjUmxIBG08WXzCfH1jknl50uEIUuUmyOQiW26DqR2jxWG7jcCAYdusSOKUBneS043YghZn9zHqD5022KaaksE37hrIA4bjt6Cnd5LYJeR9j5MzCPycQ4MBFdYjSOhipqtyiyXNqQMKz5HfcvYcPGETV5jn9S76WXXgq4Jzw9jo8bN45bb72VN954g23btlFbW6t68dyH1NRUgoODVZdyGTJkCIWFhbS3t3d/cC8gNTWVoqIibrzxRl577TVV9tCPnsOPtoDudrtZtmwZl19+OZWVlV06c30FH8tVretDh3TLqFGj+kQv9X/BV0R3Op1s3LiRqKgoRo0a9Y0YfXq9ni2bNyO5HJR9/GYXdlpQ6iBCho7xa6/JUsfzgiCQsOhyxdxkxRYlAHohmo2YZ4z0jn/vCTjn1yXepsnDQBQDmWtaDWhEZJcbqRNjXZFwkXG2nDaS43UB7yzh4q7xjoud3u3OLQICx749be14aptAq/Gz5QEkux3J6xzu00wVRBHT8AFYdx1DttrRhIcQOm8CgigSMmM0YogZfVo8zsoSkGUSFl5GcEY27eVFHXuoLqfy8w++Vv5n3759uFwu5s6d639s+PDhPPvsszQ1NbF161YGDRqk6o2rDz8EKRcfC/3UqVOqdN5FUSQpKYn6+nouuuii/o53P36QeOeddwLiuBrsb7vdTnFxMdnZ2X1+bR980i0pKSl9Kt1yJviK6CkpKWzZsoWWlpYAndTusH//fkwmM+Wr38XZGMjc7WCvQe3WL3A21gU8HztlrqJdnl+m+Hx0QuSlZ4MMLV/uRO6k2x00Tkm8bQfzAqTUDJkp4PFgPxEox2YYpMTZzsw1/6SYO/C+wxfrhYBJMq/x2GlG4G1H8kGWMQ4OLB61fLbD62PSwVqT3W5c5bUgoMRqrdYfx23HCrGu3QWSRMQVZyv70+uQbA4si6fjabeCIBA5YRYhmSMC4rjkclL8/ovgUQoQpxfAzxTHs7Ozee+992hsbGTjxo2Ioqhq8dwHo9H4g5ByycjIwGazUV1d3f3BvYCUlBTKysq44ooreOedd/qnyfrxg8OqVauIj48nPj6esLAwQkJCVNnHiRMnGDRokKq58KlTp3C73aobmEJHEf3AgQMcOXKEyZMnf+P7izvvvJPp06bRfGQ3TUf2dHk+6dzLQAZbeRFNh0+TVktIxZiQBpJEk5fw5YOP1GY/XoizouP+QBtpQQgxIztc2I4XdTzuNfh01zUHTovHRoBHwnWaL5lfju30ArogBuTjAJKXJd45J3d45VeMg1MC/Epadh72NsI7fExktxtHQQUA+pQ4DAOT/HHcnldKzfMfgSAQtng6mhCl2W7PLyN0zniMY7NBEDFExRE2bFxAHAeoXPcJzjpFIvV0M/kzxfGsrCyOHTtGdXU1O3bsoLi4WPXiOSj3k6NGjVJdysVisRAfH8/Jkye7P7gXEB8fj9PpZN68eRw8eFC1ffSjZ/CjLaCvX78eURTJzMzEbDYTGhra53uQZZlTp06RkZHRLbu6N/fgk25RU7e1M9xuN06nE51Oh9Vq/VqDqjPh5MmTCDLYKoup3rS6y/MJ8y5SCts1FTR0Yk8D6IItoDcgO1w0f/ZVwHMRi2cqzLVN+5DsHYmYeUyW0vE+nB/g5B08JANkCXteYOItet24OyfevsRabmzr+oK0moAAbC8s7zIu5mmxgltCDDIFBPH2/SdAFDGPHBTQNW/dorD6tHERfodyAE1IEM4iJdhGXDo3QPLF02zFVdekBPKRkwhKHYg2KAS3VSn6e+w2ipY9D8j+RPV0Q5Kqqir0en0Xo16tVsvKlSv9n/cPJbkbMWIEjY2NlJWVdX9wLyEyMpKQkBBKSkq6P7gXkJycTGVlJZdffjlLly5VzYW8H/04E9rb2/noo49YsmQJNTU1JCUldb+oF1BUVER0dLQq9xE++KRbTk+U1IIsy7S1taHT6XA6nd+qgFlQUIDBoEf2uCn96HUkV+Bahb2WiSzJVHzxQWDMkGX08akgCjQsXRPwnGnkQNBrcdc2YTtW4H9cYwlGDA9BdrmxH+143JAaD4CzuCqgsG7KSACNeEYGuq/x7YOvGS8GNMKbQBQURngn2HbneAvonRrhzW1ITa0Ieh2m4QP8jzsrvI0DGULndsisaCzBOAorlNg/YUiAjI2nqQ1HWTUIArqQMKKnnRMQxwHKPn8Pd3OHzNzRo0cD9vh1cTwqKorPP/8cvV6P0+n8wcQKn5TL4cNdpxn6ClqtlvT0dAoKCro/uBcQFRWFKIpMmjSJyspK9u7d2/2ifvSjD/H2229z1VVXUVZWplocb2xspKWlRVXz0paWFlWlW84Eq9Xqr1F8G/atw+Hws54rv/gAe01FwPPa4FC/3nn1+hUBcUiWJUIGDvHqne8JKHKLJgPmmaPOSGoLWTAZNKIiX+qFIAhovUxweydSmzY2QpFiO11W1VtAD5Rw8Wqgd5Jikz0e8EgIOi0aS5D/cWtukTJJlhnYCG/7fGcXHxNPSzt471EsCyf7CSAaSzCuijo8dc2IZiOWhVM61jS14Wm3Y9t+UCG0LbocbYgl4P1ryT1I04GOOsbpjOWvi+OxsbHs3LkTrVaLJEmqTmF3xg9FymXgwIGUlpaqsgeNRkNCQgJWq5WFCxf2k9p+5PjRFtA7s9aSkpJUYa01NDRgtVpVZZ+XlpaqLt3SGXa7ne3btxMTE8Ps2bORJOmMxqKnQ5ZlfvnLX3Lttdeh1Soa3A17NncZAdcYzX72Ws3mT3E1N+KxWalc8xGnXn0UTZABZJnmVdsCOtX6pBg0MeHIdidtX3WcUxNsQhMTBm4PNq/mGYBxUDLISrDunMAbMhSd/c6Jty+x9rR03Jj42HGiIZAF4TipFFJ1nQxLHPllIAoYs1IDfo+bPt+haK2dLt/y8SaALiYmztJqkGW0cZEETx8VsAZZQm5tR9QbiT3rvMCnZJnST95UpFsERbsW4Oyzz+62Q9rU1ERbWxtms5lZs2ZRW1vLkSNHfhBFdL1ez8iRIzly5AgOh6P7Bb2EjIwMCgsLVXlPQkNDMZvNZGVlIYoiGzZs6PM99KMfX4eVK1eSlJREdHQ04eHh3cqD9AY8Hg9FRUWqepi0t7dz/PhxRo8eraoUnA8+NnxbWxtnnXUWaWlpZzQWPRNWrlzJkCFDaW5uQZAFHHVVVK37pMtxSedeDsi0F5+k+dg+ZEmi4cBX5L/4IK46ZbLPWVJF+55OibQoEnrRLCXxPm3825d4d9ZVFbQaBEsQSBLO4g6za21MOMgEjH4LOq0S/077npZtSuzo7GXiqm0EQQxohMsuN3K7HbQa9Kkd4/FWXyN8TCaivuN+oHnbIQAM2eloIzoaN1K7Ham1HWSJiEs72GXeq2DfdwJkmfiFlyLqAtl0TYd303b8AL4YDnD11dfw6quv8r/gcrloa2tDEARmz55NSEgIO3bsUJX17YNPyqWmpqaLYXlfIi0tjfr6elpaWro/uIchCIJ/muziiy/uT7z78YNCXV0dX3zxBRdccAFNTU2qmYcWFBSQkpKiGvvcR2hTW7qlM0pKSjh69CiTJ09m0qRJX2ssejoqKipIS0tj48aNaDRmZEmi9KPX8DgCC7JhIyZgiElEcrmoWqvIh1pLCyh4/d/UbvkMQpV7usaPNgWsi1g8QyG1bdwbQF6zTB4OHkmZpu4Ui81ThoNG9LPDAXQxYQBdGehenfMACReHC5ADTER90jLamPCAXLp922GQJAydGuHuxlakNhuCUY9pSIdXmcvHoNfrCJoyomMTMriqlcJ++MVnnWZeKtO0eqvyPoydiik+ULrV0VBD2Yq3Ah57+umnueSSS/5nHinLMjabjdbWVmbMmMHw4cPZtWuXXxNdbfikXNQy5QYICwvDYrFQXFzc/cG9gKSkJMrLy7n88sv7p8l+5PhRFtCtVquftVZbW6tat7ugoIDU1FTVEl6Px0NOTg5Dhw5VXboFwOl08tVXXxEeHs7IkSPR6/VnNBY907pZs2bx7LPPERqazITJvyEmdgwAFavfxdlUH3B8aOYIzCkDkD0SJctfJv/Fh2g6voeIy+eR8vSd6AckIrvdNK0KZKhHXTUfhK66a+HnzeiSeItmI+h1yDYHrsqO65uy0kAUTyugGzCbzQRrdIQLyucQ5FJMIwwhgaNTnkbfuFiH3lqblzHXudstOV2Ko7coKCx533tVXoPUqAR9nZddB0rybjuiaG1HXDYvQGfVXdfkZ9VJTjt1O9Yhud24ra1og0Jo2LuV9qITCKJA+jV3EJo9StlXWztDhgxl3bp1AMTFxeF0OmlqagI6DEPb2trIzs7GZDIxdepUqqqqVA2QnREfH09ERISqo1IJCQl4PB5Vxr99ibePhf7222/3+R760Y+vg4+1Vl5eTnJycvcLegHl5eXodDpVZVNyc3OJj49XTf+9M2RZ5tChQzQ1NTFlyhQMBsMZjUXPhAcffJALLrgQQdAxeuzNDBt5tSKrdmgnTUcDWbMKe20JAJVrPqTg9cep+nI5pnGDSX7yt0TdsBgEQdFC7zTFFj53gjI1tjc3QFvVMmWEknjvPh4o7zJpaBcDMl1sBEiSP8EF5bvSGBpMSEgIIWhJFpRGfpDehMlkChj9thdVgscTOPZdpGipGgYkBZimNa3e1qURLksSbZ9tB8A8LLBxYz2omFwFzxiDPjEmYA2y7K+N1+1cj6u50R/H7TUVVHy2DIDYOecTM3ux8ro0Wm644QbuvvtuoGsc9xmGNjY2Mnr0aHQ6HWPHjsVkMrFjx44fBBPdaDT6x9O/zURjT8JgMJCYmEhhYaEq1+8cx/unyfrxQ8IHH3zAuHHj0Ov1xMbGfq0MZG/CZrNRUVGhaiO8oqICm81GZmamanvojPLycr/meWRk5Ncai56OnTt3MiBjAFVV1QwcfC6Tpt4FiLiaG6j8/P1ADzBB8PqTSbTkHqRo6bMUv/MfCIKEv99M8gO/UMy/N+1XzLS90Cd2kNqsOzqmpHTxUWDQ4Wluw1nQwXgPGpIBnsCpcEGrBVFAtjmQ2jsK+zqziZDQUIIkgThBKVwHCRqCg4ICGuE+SVVdfMd9lyzLeLz5vbHThHf7vlxFvmX8kMD4vkFh0JtHDAxokDsKykGS0ISFEDJ3fMD7K+h14DUrbzl5FGvRSX8cl1xOipc+BwgEpQ0m+ZKblDWiluXLlzNq1CicTmeXOO4zDK2pqWHMmDEEBweTmppKdnY2O3bsoLm5+YyfdV9CEARGjBhBSUnJNyJj9BbUJLVFRkai0WiYMGECNTU17N69u/tF/fhBQn2q03fAypUrSU1NJSoqCpfLpQprzWazUVVVxezZs/v82j4UFhb6b+rVhiRJ7Nmzh6CgIEaPHu3v5vo00Xfu3MmuXbuYOHFiwFhbS0sLo0aNorCwkLj4sWRmX0BtzVFqaw8DApLbTemHr5J+7W8QtR3BKfG8qzj537/hqK3EkJVK7G8uQxumaO7F/OIiyu55hubPv8KyaIr/cfPYLBAEnEWVOE6VYxigvG/mcdnwykra9+Qg3+zxF59NwzKw7T+BI7+UsIRYkkQj0WOnYApOI3pwOjH6FEIELSHDh6B7d2HA+/EXyzB4S+kg22QPLbKbFtlFxa9+TWNzM87IZMpkO5Wyg/Ydh0CSAwxE7UcLFEfvIRlogk3+xxs+3gyigCY0CEduMSGTlcmD+jU7QZbRhIUEJuqyTNUTSwEQLcGELZpK/fvraCvMBQR0YZFUr/8EgPj5SzDFpxA9cyEtOQcACUnWcPbZ57Bt21bGjh2LTqdj/fr1zJkzh6+++gqtVktFRQWTJ09W3kuzmSlTprB161Z/AFcb2dnZbNmyhYyMDFW+K0RRJC0tjVOnTnVr3NMbSEpKIjc3l0suuYR58+ZhtVoJCgrqfmE/+tGLqK2tZc2aNTz88MMUFhaSkJDQ53uQZZmCggIyMjJUmWIDJQaWl5erei/RGfn5+VRXVzNjxgy/5rlPEx1g+/btTJ06tYvG7Q033MCrr76GOSiakaOvx+Nxcvz4+/7nKz9/H2NsEsboju/AsBETaNi7BUd9NS5rEwn/uEWZ/gJCZo6h7o1PcVXUYt15lGAvu0sTbMY4OhP7wTxaN+4l/GLlfdNGhSGYDEht7Tjyy/wyKkEjBtO2di/2kyVEMpUEwUhi0mD0119PZEw0cfp0QtESKmgxvhHI+gJ44d9PAeCSJSWO46Z6+gLqB4zGPiKNatFMmWSjPqcQNCKmrE6NcLsTd3ktaETMowb7H7cdOQVuZXTc09wh/easqEOqbwFBIPxnZwXso3HNLqURrhGJ+dUS6t/8nFOvPYrWFIwpKYOid58FQSBk8Agixk3H1dxIzYaViDotsiDy+OOP4/F4uP/++/1xfPHixezYsYOKigqqq6uZOnUqoMSscePGsXPnTvbv38/48eNV+//hgy+GlpaWqnZfMWDAALZu3Up2dnafFwl902QZGRlotVrWr1/POeec06d76Ec/zoR33nmHK6+8krKyMtV0v30ybGrpPUuSRE5ODpmZmT+IKbLGxkYOHDjAuHHjAsgBviL6rl0Kkex04sJHH33EJZdcCgiMGHUtlrA0co69D7LSsGvJPYg5ZQARY6b61+jDo4icsZD6LZ/RXpxP5LWLCD1nol++1Dx1JO07jtCwfAOxt1/iXxd11QKq/72U5i93EjJrjP/x4LkTafv8K6x7c/x5uu9PR34pSBLRGiPJgomp111HeHAIcYZ0wvRBhApagu+6r8v78ciiq2DRVUiyRCtKTt6YHEbVbSasEWaaxBBKJTu11cqUky4x2s9kB2hcsUWRb+mUX0t2J7avlOK/aO4ozEtuN/bjSqM1/NK5AYV1V2Wdf6ot+hcX0brlAMXLnkMbFErwwGzKVi/D3daCNiiExMVXIXmnwAzRcThqKjh8+DBDsoewb/8+fxy/6KKLOH78ODt27KCmpoZZs2b5r5eRkYHL5WLXrl0B93RqITg4mJSUFHJycpgwYUL3C3oB8fHxHDt2jMrKyj7POwRBIDExkbq6Oi655BLeeecdJk6c2Kd76EfPQP1v+e+At99+2x+s1bqRLigoICYmRrVClMvlIi8vj3Hjxqme2ICis+l0Opk4cWIXPfj/VURfunQphYWFxCeMY3DWhRQVrqe4cAOWoWOJmbmQ/Jf+5R8BT5jfEXh1IRbiFyyh8vP3cZXXBuh965NjMQwbgON4AU2fbCHqukUACBoNIRfMoHXFFprX7iJmwEUAaMNDEELMSK3t2PNKMGenkyKYmHb5ZcTNszNoaDbRxjDqJSclUWaKDhWQcyKXnGQzLbKbhro6cu95EpdWZNCLf+RB4xB+V/oVhXc9SWh2Bpl/vIFQQUewzYNcWkpUUgJDNWGcJ5rQIVD8579x6tQpGjKzyMNGEy6av9wBsqyw57yQ7E7avWPfYRfMpOGdLzFkJKBLiaPlrS8AiLhmAYIgUPPf5WgjQtFnJOIsKAe9VhkLFwVi7riMuhc/QWq14qirUnTRR0wkZOAQ7NXluNqUTnXkpLOo37kJkCkuLmbKlCnccMMN/OY3v+G2224jOzubBx54wD8a6ENwcDDjx49n586dBAcHExnZwbZXAxaLhYSEBHJzcxkzZkz3C3oBaWlp5OXl0dLS0uc6y2azmYiICKKjo0lOTmblypVcfvnlfbqH/w+46KKLvvWa559/npiYmO4P/Ani/fffZ8KECWi1WmJiYlRhrTU0NNDe3q4a+x0gJyeHtLS0H0RTq7q6mhMnTjBt2jRMJlPAc/+riC5JEq+99jomUwRjx99Kc3MJx468izYsnIHX/ImKLz6kvTiPso9eI+P6OxH1Bv85ky+6nvwXHkSy2pA7jXILWg0xv7iImmfep2HZOoImDvU3tyOXzKH8wAla1uwm7IKZ/seDF0yh9ZPNWPfkYBycQqSgZ9KIsUTcFsbAzMEkG5Kx46FMsnNSo6HgZD4loxJp0SjF8Zw/PENbaSXJL/4eg8nEQ8YhXPPz6/E4nAz57+8JMwcTihbXkaOEh4QyMDKO2boQwgU9VWdFkZ8wguqkUIoFI+WyHduRfEW+ZcSggBHu+neUeB08dQStG/dhGJCIYWASFQ8oOqfBs8agiw73x/HQ+ZNpeuNTZbEs465rIvbOy6h9/mOcZTW47HZkhx19WCSxs8/DUVPhj+NR0+dTv2MDktXJ0aNHsVgs3HDDDdx5552UlpZisVh48cUXu8RxjUbD+PHj2bx5MydOnFDdEE8URbKzszl27BhJSUmq6AtbLBbCwsIoLi5m0KBB3S/oQQiCEOBp8vbbb/cX0HsB/XH826GwsJDdu3fz+uuvc+LECVVIIj4ZtrFjx/b5tX0oLi5GEARVJV19sNvt7N69m6ysrDN+Hv+riP7b3/wWSXIzdsIv0euD2b/vBWz2BpIvvgGPzUrFZ8uoWvcxpviUAOmRmEln0bR3Cx6bFXddU4D3V9TV8ynZfgjrtkM4L5iJPkn5v2Iem6mQ2gorcBRWYEhXipmWGaNo+3Qb1l3HiLh0LiZEMo2RzL75JgakpjHAmIlGEKmQ7eTHx1CdX0RFRSH21GhaZBfFy9dQ+elWIm9aTPjkkTxoHMItz/+L5k0HSLv9MuLHDydU0CGczMPc2EhSVhqTtLHECgbaElLJv+8+Sj3t1IjB5EtWHDY7ntpGBJ0W04iB/tfVtGU/iCK65FisO47SOjQDw8Ak6l5V/Ns0UWGEzBjlj+Phl82j8pG3/FNknrZ2Iq8/l/q3Psd+OJ+2Uzm421pAFEk49wrcrc0d+fiEGTQd2Yu1KI/KqqqAON7S0oLVauWtt97qEscBBg8eTGtrK3v27GHKlCmqa/NnZmaybt06GhoaVJE6EkXR72miBnEnOTmZLVu2cOmll3LllVfy+OOP/yBUJH5K6Is4/qMroNfW1rJ27VoeeeQR1X753W43xcXFqnXPQDHbtFgsqo6d+1BUVER5eTkzZsz42s771xXRlyxZwj333Et19RGczjbq63KJmbmIyEmzEQSB1MtvpejNp2g6uIOg5AwsQztukMJGTKRuxwZcLfU0LF1D9I3n+5+Luel8Su94gpa1uwg7dyraqDAAws+eROtHm2jbdojIqxegCVKKBJHnz2TAqUammlMZbchCA5xIaOTwV5+xfv8uHDecQzseJI+DojfeQBsdRspsJZB6dLJizKLT4hsI8jhdOJ1OrJKbStlBpezAXlJKxfLlmMdmETcpBgEIqW4l6KNtDB47kvGGSC4RzFTKdrYPHc/uNhn3uGz/a2raegBEEdOIgVjmTwYEGj9Y7x9j16XEEexlpLvrmpAlSRkfB6KuOxfRbKTxvXW4ahvRxUYgudzgcGGMSSBu3oW0HD/gHwEHqN+5EVBMSXwF1/vuu4/S0lL+9a9/4XK5OOecc3j22We7fN5RUVEMHTqU3bt3M3PmTFWY352RlZXFhg0bGDhwoCpGgQaDgaSkJAoKChg1alSfXz8pKYmSkhKuvPJKv39EP3oWn3zyCUuWLOlSePw6vPvuu7S1tf2/Tbzfeecdrr76asrKylQzzjx16pSqMmz19fXU1tYyb948Va7fGa2trezdu5dRo0Z1Maby4euK6KIoMn36NLZs2cLJE6upqjpAcHomiedfjcZgJPnCazj53AM4m+qo+Px9Ehdf5W/868OjiJi+gIbtX1D7wickPf5rP2MraNIwhJdX4q5poG3rIT9LzZCegBhqxtPcRvv+EwSNV35/wqaNIOFYBRMTspiiH0iUoKdA287hlv289+5SbD8/m5YQ5dyF776N3G4neXqKf4Tb6nHhcrlwO5wYvP+PXXYHtvZ26nQS9ZLiq1Lw0cegEUk/ZwCCQyQIDdrnP2BAegYjxi9kod6CE4ndumZ2jh5NxcQOzVR3fTOukmoEg47IaxehT0tQ4nhjK3gk0GiIvEz5fXB7jb+rn1wGgoh5XCbBU0fS+N46GpatRRcXiT4rFWduMYJWS/LFN9BenB8Qx6u9urSiqGHFihUAPPLII1RVVfHXv/4Vj8fztXFcr9czceJEtm7dSmhoqCr3252RmJhIfn4+hYWFDBw4sPsFvYCMjAyOHj3KgAEDupBFehuJiYnk5ORwySWXMGfOnP5psl5Afxz/dnj33Xc555xzsNlsxMfHq1KcKysrw2AwqJYPu91uTpw4wYgRI/r8O+F0eDwedu/eTVRUFAMGDPja476uiH7X3Xdxxx2/oSD/S6zWamS9lrRrfo0xWpEMbS3MozX3IKUfvcaAG+5GY1RyO0HUkHrpLRS89jjNn20neNpIf0FcGxZC8NwJtG3YS8P764i78wpljUZDyHlTaV21neY1u4i55UIA9CmxxCXEM37sOKbLiQwwhlEt2zkaG8mGDRv4oPEUbeMykIC6vN20LN9EpGEBlmTFqLNZcuF0OHHZnf6c3NnQit1upxEXTtkGso3S5R/hKqwgLlWHOdqBDgHj0i0kujQMXTSb6boEgtByvLWCrXPnctzd4r83kWWZ5mVrQZKIvHwerqoGJY43tYFXrjbyqvkIGo0/jjdt2IO7sh4xxEzElfNpXrHFH8ct502j2Ss7Gz/vItwtTZQse97/eZWvetf/96VLlb8/8cQTNDU18etf/xpJkr42jguCwOjRo9m6dSuHDx9m1KhRqhIvjUYjGRkZ5OTkMGXKFFX2kpqayokTJ2hubsZisfTptUNDQwkKCiIjIwODwcC6detYsGBBn+7hp46+iOM/ugL6Rx99xPjx49FoNKpprVVUVGA0GlVj1tpsNgoKCpg6darq7PP6+nqOHj3KpEmTur2RP1MRPTw8nEOHDjJ4cCb1dbnEzr2AyHEz/GvMCalEz7mA2vWfUPH5exhjkzBExQJKUEi99CbyX3iI1nV7CJk+yq8jrouNwDxhCO17c2n8eBPRN10AgDYsGP3gZJwnS7FtPcTkhfMYrwkn8+Ih1FRUsu/oYV5PC6JYtuERZQo//hhEgbSrZiAa9H4WmbuhBVmSEESxQxu1kzanz/07wLCktgk0GnRxyu+NDJTnnKR25w6OWmQ2T0nAjIYB1Q4GxifwjwcewGXUcsjTzC5PI4VL14AkYZmvdJct8ycRMms0Rdf/A4DoGxf7fx8S7ruRyiffBRmMQ9IJOWssgiAQPGkYAHUfbsD1wQZEg5GkC69H1OoIGzGBsBFKU6jp6F4qVr9LQkIC5eWKoVtTUxP79+/nySef/EbJa3p6Oi0tLezevZtp06apOtYYFBREWloaOTk5qo1Lpaens23bNlU8CxISEjhy5Ajnn38+999/P42NjYSHh3e/sB/fCk8//fQ3DsDLly/v5d38cFFSUsKePXt46623yM3NJTY2ts/3YLfbqaqqYs6cOX1+bejQrBw4cCAGg6H7Bb0Ip9PJrl27SE9P79ZT5uuK6Bs3biQ7O5u8vH0EZ2SR/LMb/Cw0jcFI+lW3c+rlR2jJOUBQygDCR0/xnzN28mya9m3BXddE08ebiLhUKSALokjs7ZdQ9chbNLy/juBpIxTdUyDqmkXUPPshLV/uInPCGCZqwhmRngV/Hse+ffv4tCaf/DARBxJlX23EmV9G7NQMgrxNaW1sBK7CClw1jf4Cum8Mu7P5GLIMWo2f5S55x6+1kRb/62tuaqZk336OlBax/2ej0DgqyZCNJNc1cvPNNxMWE0Wu1MZuTyNbVn0GokjIWWMRTQYs8ydhmT+J0j8+i6uwkrDF09FYFBmChPtupH3/CaoeeQvBqCfq54vRhof447j9VBkVf1KS7IRFl2OIisUQFeuP446GGgrffApcLvJP5mE2m3G5XBw4cIB7772X5cuXd1vwCg0NZcyYMezbt4+goKA+TzY7QxAEhgwZwt69e0lNTVWFtRUfH8+RI0eoqanpc7atb5osMjKSlJQUPv30U5YsWdKne/j/gP44/s3x3nvv8bvf/Y7y8nLVGOBFRUWkp6erlg8XFBRgMpmIj4/v/uBehM+/RJblb1QkPVMR/de//jXl5eU88uhjaAxGBlx7F9rgDtJR4qJLyS8rwN3WQvnqd0m++Ab/dYyxiVjGTKX54A5qn/+YxAd/0TE1dtk82tbtpn338QC2ecTCqbSu2Ip12yGCr1nMpOA4xmgsRD3zH44eOcLuE8d4LyuaRly0tRRSs2kjIYwhepyidW9MjKVFFAOMREWjAWQpII57Wtq9z3XUjNxeTXafGbgLmRNfbOCQw8WRszPROezECwaS9uQw/+yz+eXAgZRgY6+niR35x5HbHWijwzCNGIh5lIhl/iQa1+2m8dVV6JNjCZqgNPYT7rsRT4uV4lseAiDqxvMJnjiUUC8hQLI7KL79MRAELEPGEDZqMoIg+OO45HZT8t7ztJcV8fhjj7J48WK//OB1113HSy+91K10kUajYeLEiWzevJmCgoL/2VzpCwwaNIi1a9dSU1Ojyv2/Xq8nMTGRoqIiRo4c2efX95mJXnbZZSxbtqy/gN4L6O04/qMzEV25ciUXXHCBKtpFPhQXF5OamqpasM7LyyMmJkb1Alh7ezu7d+9m6NCh39j8zFdE72wsmp6ezsqVK0AUady/HY/NGrAmatx0ggZmI3skSj96Fcnp8D+nD48mbOJsEAVqn/8YuZOxUtT153ldvvcFmIUNuO4Crrj8Cv511s84XxtPmWTjMWc+v/ztHbz63AucKC5EQknWNNFhIMk4CzvMTDDowCPhaVK0SwWdFgTBb9QJigkonYvrgL28BiQP2piOz61l6wHwdLh9t+Nh3fJPePyJJ7jj87dZ6irDJGi4Q5fBQ3/9G2edu4DgER2jw/Ufb1SYaaMz/ZqvAPYTJdh2HgdRIPrmCwJ+V23HCmj5YAOIIrFnnYc+LHCEqvVUDhWrlQ63jy3tMwwdPHjwt2J+DR8+HK1Wy4EDB1R3mx48eDC1tbXU19d3f3AvICwsjODgYH9Doi+h1+uJjo7GYDCQnZ3NF1980ed7+Klj48aN32oc8fPPP/9B+FeogVWrVjFt2jQcDgdxcXGqsNZKSkqIiopSjcFZXV1NW1ub6omMJEns3buXkJAQsrOzu19ARxG9s7GoKIocPHgQo9GEtfgktorigDWGqDgSF18FQOXaj7BVlXWcT9SQesnNiuHoii04SzsMl02jByNagvE0tNC6cb//8bBJw5g7ZzYPXH8bv9Slo0HgTWcJv3zrGZ586im2b96CA6WpbZ42EjRigJGocZjCCnfXNvkf8zW8fQ1w/+OdNEx9BuKdjccc+aWgETFmKw18DzKHc47z8iuvcMdTD/O0s4Aa2cESbSJPXHw9l1x8MQnzp3WsL6zAVVCBYNRjObdDW1ayO6h6/B0AIq9ZiDa8Q3fe09ZOxf0vgSgSnJGFJXt0wJ5drc0UvP4kkt2OJSSE0NBQv2GoTqdjwoQJ3/j/XXx8PIMGDWLXrl04HI7uF/QioqOjsVgsqhmDC4JAamoqxcXF3R/cC0hISKC6uprzzz+fVatWqbKHnzL64/g3R1FRkZ9FKsuyKibYzc3NtLa2dtv47S04nU5OnjzJkCFDVCe0nTp1itra2m/13X4mY9F//etfTJwwHo+9ncZDuwKOF7U60q68HZBpyz9O/e5NAc/Hz1bMv53FlbR82bFWE2wi5IIZIIo0vLeu43FLMGPmz+b3d9/DXy3DyBDNrHHXcm/Oeu6//35WLX2fRpR4bBycohiJ5nZ89+piI8DjUQxBfXs06UGScbXb/I9JNuXvQidSm2x3giD4J9QlpwscLsRgk98gvMLVznsvvsq9f/g9f2s+wj5PM5M0ETw4YAa//OUvGbJkkb+RLrvdNL62GiSZiCvODpCxqX7aO0U2NstfWAel6VH52DvINgeiwUTcvIsCfo9kSaJk+au0lxYiCgLZ2dl+8kVZWRlTp079xrr/JpOJCRMmkJOTQ01NzTda01vQ6XQMHjyY48ePq1YbSE1NpaysTBVDbp8O+qJFi/jss8/weKcW+tEz6Is4/qMqoFutVtavX8+8efNobW1VZWSupaWFpqYm1TRT29raKCkp+caJbm/B7Xaza9cuEhISSE9P735BJ5ypiL5gwQJefP55nI31lLz/MpKrkxaqIJC8+Bo0JjPOxjoqv1zu/8JtPXWc1mN7lGBZVUfTyq3+ddrwEILOGg0INH64kVjBwFW6JP6RfRbpAzJ4+smn+POBL1jjqaVWdhIydyKIAta9Of5zBE0fCYKAPb8j2fcFW3dNg39/gl6rMNW8kJ0uEISAbrf9cD7IHd1uAEeecsPSufht/eowyDLGcZnkSVaWusr5xT//wtatW7n00kv5qymLuZpotFYHrSu2gSQRflmHBIDsdlPx0OsARFw61894B3A3tVL5T+U50aineuMqWk91vN72imJKP3jJ/+/PPvuMJUuWfKfiOShaY+PHj6epqYm8vLxvtbanYTAYGDhwoKoBOy0tjaKiIlWuHRcXR3V1NYsXL+5PvHsBM2fO/FZTFtOmTVOdeawWVq1axeLFi6mqqlJFM1WWZX8jXA34EqDMzEzVtQ+PHTuG3W5nzJgx36oAcKYiuslkorCwAFEQKHn/Rey1VQFrLEPGYBk+AWQo++g1PHYlqXU21VPlNbMGgdoXPkb2TnQJgkDsby4DoHH5BgxOiQXaGP4aNJTzL1vCl2vW8Ou3/8P77gpOye2EnDUOZBnrrmP+6wYPzVAS77wS/2Om1ATQaPwFcQDBaABRQHIEFtA7N8JdNY0Bk2QA1j3HwSMFxPGWL3cAMkETh1IpO/jcXcPvt33CSy+/zPAJ4/hH6hQu1SYSJeipfuY9ECD8wll+WTmA2pdXKFNk2WmEnNXB7pQliYp/vgYeGdGop60gl5rNnyHLynvmsdsofOMJZJcTkGlsamLo0GFs2bLlWxfPfRg8eDARERHs3r0bqdO0XV/Dx0IvKCjAZrN1v6AXkJKSQnV1tSrXj4uLo76+ngULFvDpp5+qkvz/lNEfx785Vq1axcyZM2lvbyc2NlaVAnJxcTEJCQmqxdG8vDy/x5CaqK6uJjc3lwkTJnxj2QIfzlRE37lzJ+np6dRu/ZzGgzsCjteHRZD8sxsBqNm0mvbSAgAkl5PqDSv9EiYNS9co8iVeRF4wC2QJ28E8HCdLGSeGcY9+IHfe+AtKSkr49V/+yAvOIg5KzcgZcSAoObKnRSHVaSMtIAi4KuqQ7Eoj188er+ogRvnitdTc6n9Mdijfk76cXHa7QZbRhIcgaJVY6CysBFHAmJXm/1225xSBKGAaNoA2k4avPA081nCUP/zu98jAn+dexG26NAaLwTSu3Q0yGDJTMI3sILq1H87HfrQQQa8l6obFAf9PGr/YgeNoAYJGRHLaKf34NdxeEqEsy5R/uoz2ohOAjIzAokXnsmLFim9dPPchIiKCESNGsHfvXtra2rpf0ItIT0/H6XSqQioDCA8Px2w2q3J9s9lMSEgIGRkZyLLMzp07+3wPP2X0RRz/URXQ165dS2pqKqGhoURGRqoi31JSUkJCQoIq1wbFcCw5Odlv3qUWDh06hE6nY/jw4d9p/ZmK6DfddBN/+uMfsFWVUPbxG8idOnKi3kDaVbeDLNN8bB+N+7dTuWY5pR+8jH5APHH3Xg0yNH64EWdFnX9d1JULiIqI4PqR0/itLoN22cMjznz+W36QA4cP0bx2t/9Yy+yxIJ2WeI8YBALY8zox17LSAHB1Yq4JhsDfhzNJuLgqlX35Ar5kd4LLjSY8BG2EMiLnLK8Fj4Q+JRZdjHKcx2qjYd9xPv3yCx52nOQ9VzlZmmD+ZM5i0bnnEjptNIbUjiJU3fvrwOlGnxqHZWHHmLwsSVTcpxTHTSMGkvKfuzEOTaN0+cs07N2Ko76aorefAQRCh4whYvxMMjIyWLx4MevWrfvOTEmDwcCECRPIz8+nurq6+wW9iAEDBtDW1qbaPhITE2lra6OpqanPrx0bG0tDQwMLFizgs88+w+Vydb+oH98J+/fv58iRI/5/r1ixggsuuIA//vGPOJ3O/7Hyp4+WlhY2btzI3LlzVdOOraurw+12qzZyXVpaisfjUa2A70NZWRmlpaVMnDjxOxUgzlREj4uL48D+/chuN8XLnsPV3BiwJmH+z9CGhuFqbaJ89bs0Ht5NwauP4XI0EfeHa0Er4sgvo3X9Xv8aU3YapqQYFs+ex5+NmaQIZt50lfKo/SRrvvyS2i92KOwxQJ8WD4KAo6Bc0RUHdIlKccNxqtxfmNfGRoAkBY5+m/QgiAFmpuAdCffCXlELkhTQCPc13X0FdFmWse7JARm/PjtA9Wsr2L1rF/+tOsQTzlMA3K0bwM/PvZiIpARCz+mQF3MUlGPddliZIrvlwoCku/7DzbiKqhBNBpIe/RURV5xD3c71lH3yJu72Ngrfehq31YouNIyERZcTFBLCb+/8Ldu3bycjI+M7TXwIgsCoUaPweDwcO3as+wW9iPDwcGJiYlRrypvNZqKjoykpKen+4F64dmhoqF/C5quvvurzPfx/QX8c/99YuXKlqo1wj8dDWVkZaWlpfX5tUKawCwsLVSe0tbe3s2/fPkaOHPmdJ9PPVEQ/efIk4eHhVH6xnJYThwOODxmQTfikWQCUfvw6bUV5FLz+OE1HdhF57SJMY7OQPRK1L6/0E5ZEox7LpfOZMHEiv48ZzdnaGLZ46vm7K493PnyfimMnsOcWAYp8m3H4QJBl2vef8F9XGxcOsozjlFL0FM1GQJkk67iOEq899Z0K6N58R/Tm6u46xZyz8yRZ21FlqsmY2dEIb1y9DSSlEe5D05odFJYU8+bxnfzdkccJycrVuiTuHDCJgRkZRF5xjj9eSw4nVY++BUDk1Qv8uT4oMb7pjc8AiPnVEuL/cj32+gqK3noKR0MN1Vs+p+XYXhAFEhZdji40jGuvvZb6+gbsdvu3Lp77kJKSQkpKCrt371aV+azRaMjKyiInJ0eVprza02SxsbHU1tZy7rnnsnLlSlX28P8BvRXHf1QF9JUrV3LeeeepGqxLS0tVS3obGxuprq4mMzNTlev7UFlZSXV1NePGjftehimnF9Hdbje5ubkgy7QV5FDx+XsBTGFDRAxJF14HQNWGFTQd2U3k9ecS9/urMY/JJGj2WJCh7sVPkGUZMxouDMvgv88/h0ar5d4XnuQjdyV1spOwmWPAI2HdfVwx/cCbZGtEnMVV/q65PiMRJBlHXscXrGlwMmjEwJExX1fbu1/J4QbkAOaa3G5XxsWiwwAleCKKGLPT/Me0bFKCZZBX4xSgac1O0IiEzBiNGGwiR2rjqbqj/OeJJzn77LN54o57GSNaEFCK9K0rt4EsE33rxX79OYDa1z/FXduIxhJEzK+WIJqNxN59BZaFU6ha9zGnXn4UZJngjEwSF13O6PN+xj/++SDLly/n3//+NwsXLvzOn7XFYmHYsGEcPHhQ1cKt2mNjOp2OxMREVQK2yWQiNDSUpKQkTCYTW7du7X5RP74TbrnlFn9xp6CggMsuuwyz2cwHH3zAvffeq/Lu1MWaNWsYMGAAZrOZqKgoVZhjxcXFpKSkqGL45fF4yM3NJSsrSxXpGh/sdrvfUOr7yNicqYh+4MABZMmDp91K0dLncLd3MJ0EjZb0K28HQaAt/xiVny3DPGkISY/cjnnkIOJ/fy0A9W9/gbuhBRGYpAnnuX8/zZQpU3jk8Ud5rjWPfMmKNtKCNiEKqd3ub3wLgoB5rKLR3r4vV3lMFBFDzMhOF64yZXRZFxsBshzAXBONBhDOIOHSqRFuP1IAsuwf8ZYlCdlqRzDq/YV6V2k1SDKGjER/wuyqrENqbEMTFoJ5TCbVsoP33OXc9Zc/ER4ezrP/foqFQUkYEZE9HoVhDkQsCZwis+UU0vLhekAm9reXoY20ELZ4OrF3XUFbYQ55z/8TZ0MtGnMQqZffRuyoCTzw76ewWq088M8HycrKprm5+Tt91lqtlnHjxlFcXExdXV33C3oR2dnZlJSUqMaiS01NpaSkRJX7CF/ivWjRov7EuxfRH8e/Hs3NzWzevJnZs2fT3t6uCgPb50emlpzpiRMniI+P/1rT7b6ALMscPHiQ+Pj47z0Zf3oRvaSkBIfdAciUrXgLa0l+wPFxM87FEB2Pp91KyfsvQLCWxIdvw7JgMrG//BkgYzuY54/N6YKZ+y+5ittuvZXPPlnB/YfWsMvTiFuAsCvngyjS0onUFn7edBBFZcLLi6AZ40EUcHSaCkevRXa6kKzKRJCvSO5p7YgNsts70eYtrrtqvZNk8Z0mybYcBEkOaITbD+eDIPi9U2RZpvmjzeCRsJwziXY8rPfUcvfyl8k7eZIHHnyQm4dNI1pQ9lD3xmrwyBiyUgOmyDxtNsq9hDbLedMJGj8EU3Y6if/8BbJR4NQrj9GwYx0gkHT+NYQNH89t9/+T6TNm8Je/3seFF17EunUdUjjfFkOGDEGj0Sg1FxWRnJyMKIqqTWYnJSXR3NxMS0tLn1/bNxXeH8d7F70Vx380BXSPx8Pq1atZuHAhdXV1qhTQKysr0el0qpmH5uTkkJ6e/q3Hs3oSTqeTQ4cOMXz4cIxG4/c+X+ci+osvvsiqVauxWNIAaD66l5rNnwYcH5o5grDRU5TRK0swIdM7jFKirzsXNAKOE8WMK7DyJ8NgYgUDT9tO8uST/6boy604ipWRctGgJ2jSUJBlWjcqTDdB8BauBbB6E29RrwO9Fk9TG+4G5QvWxzxzn25aAsguZUxMdrpAkv2BXJYkkHzjYspYifXgCZAljIM7GjItaxQ5mqAJSrdblmWaP9wEHimAnVb3xqfs2beXv6x8mzVyPQt1sfxWPwDDm+tBEAhbPB1DWge7sv1AHm1rdoEgEHv3lWhCfM7pImEXzlJ03QFTQipJF15HYoiJG4YksKm6jW1Vyuv+4osvOH6840bm2yIlJYXQ0FCOHj36nc/RE0hLS/MzV9SAmrprcXFx1NTUcO655/bLuPQi8vLy/P4BH3zwATNmzODdd9/l9ddf58MPP1R3cypDbfkWh8NBZWWlao3woqIidDqdapqt0GE2FhMT0yNeMp2L6OvWreNPf/ozen0IOq0ZV3MDJe+9GOBdogsNI2XJzb7FhM4Z7y9Sm4akYxo9GNnlJmLtYe7WD2SWJooVcg1/fOZxDu3eS8uXHeOu0TcsBlGgZU2H3mrYuVNBEAIT70lKTPXJsYneGNi5ES4Y9SDTRcLFZy4K4CpR7iH8o+PltYDCPvebiq7doyTdkzsa4fVL1yiv9ZyJ/sa27XghpcdyefyV53neWUiGGMQfDYPJPlSNbHOiT4nDsqhjiszT3EblP14FIOKyeZiGdUyFmcdmoc9OBZcTUa8n7fJbCYmM5PqseJwaA+/kVeN2u2lqauSuu+468wf5DRAcHEx2djYHDhxQVT4kJCSE5ORk1QoAcXFxeDweamtrVbl2dXV1P3Otl9Efx78eX375JZmZmRiNRtUa4UVFRar5kbW2tlJWVuY31FYLxcXFtLa2MmzYsO4P/gbwFdEPHDjALbfcQrvNRqglHWSJkg9exl7dIXchiCKpl/0CRBEkGfO4LPSJykShaDYSe+cVAHiWb+FaIZGb9KnkSlZ+v2sVn3/5JbVL1/gbkGEzx4AkYd15DE+zUvg2ZqeBJNF+6CSSdyoseIRiHmrv5GeiCVOY2L5Y7tM5l9rsHS/My7T2kd3sFbUgB06SeWqaQBTRew1OnUWVyj4yU9GEKiQD+/FCkCQMg5L9ObZkd1D57he8/dZb/L1kJ+2yh7v1Azm3PRTntqMgCsTccmGHVrosU/nAq4r/WVYqEZfN9e9BFxtB2OJp4FFia/yCSwjNHMH8lAhGx0fy0vEK6q02ZAGuufqab/y5ng5RFBk9ejSFhYU0NDR0v6CXIIoiQ4YMIS8vT5X7Cb1eT0JCgiqktvDwcL/MbUFBgWq+Lj919FYc/9EU0Hfv3o3b7WbAgAEEBwerYvxVUlKiWrBubm6moaGBQYMGdX9wL+Lw4cOEh4f3aPKv1Wp58sknaW5u5r77H2DMuOsJC1eCZP3ODdTv3hxwfPy8C9EGWXA3NFPz3EcdY1t6HcPuu5W//e1vzIvJ4LWmPF5yFVOpk7BcOkcxKX2/o2MbcdnZIMu0rN3tH+sOWzgVCEy8DZlKocWRrwRsbWwkeKQAY1Jfgu1jrrlabCDL/kDuMxztzCRr23pI0Tf1jou5G1vB4UQbG+FnstlzijqCdaoSrN1NrVi3HwZRJOyiWeyVmnjIcZK9+Tn88/d/5oqfX0fkxbP913HXNVH1rzcBiLr+XIwDOj47yeGk/E/PgdODITKGlEtuIskSzM+HxLOpvIntVS0YY5SbiaCg4G+td98ZvhHwiooKVaVcNBoNgwYNIj8/XxX2mE93raKiovuDexi+Arqv4622setPFbIs+0cS161b55/eSE5OVp25qSY8Hg+ffvopCxYsoL6+XpUCellZGeHh4d95/PX7QJIkTp06RWZmpqqGY2VlZTQ2Nn5nCbYzQRAEdu3axYcffsg//vEP5p5zJylpM0CWsNeUU/rR6wGybMFpg4mYOBsEqP73u36dU4CkX13K9ddey+8vvY5txSd4xHmSQ1KLooUuQ+Mnm5HaleTYOCQdRMUg1OktbhsGp4AsYzt6CsmmFO6DJgwNMBIVBAE0GqQ2mz85F416kOUuDPTOxmNSWzuA3wy8LadQmSTL7GjItG7aB7Lsl2+RnC7adyum3qGzxwHKd0TVv5cCEH7ZPEpEJ886C1lal8fPssbxpz/8gYG/utxfbJclibK/vACAeUwmlvOmB+yx7u3PcRw6haDRkHLpLYTGxnN9Vjw2t8Q7edUIIWGIRiOCRsu11177bT7aLsjIyMBkMn2vhnpPYPDgwVRWVtLe3t7n1xZFkZSUFFVkXMLCwtBqtYwZM4aSkhJOnDjR/aJ+fGv0x/Gvh9oT4T4pRLX8yAoKCkhMTFTlPsKH9vZ2jh07xujRo3u0gdHa2so//vEAP//5z7nyqj8wOOtckAVkt4viZc/jbOqY2tKag0m/+lcANH24kfbDHSz1oHHZzL74fJ586F9Yi8r5pyOPtZ5aTNO9pt55Jdi8x4t6HeaJXlLbpn0ACFoNurQ4cHuwHVEkz/SpcSDJ2E8U+/MXgzendXkL6P6J8M5SbJIMGtGvd+44WgiS3EGIa2wFWcaQFu83DW/+wutjMqlDvqX25ZUgyVjmT/I/1rB8HQgiQVOGY0+KYLm7gsfsJ4mvbefJJ59k4q1XBkjF1H+4HmdJFWKwidjfXBYwKW47VkDt8x8DEDPrXMJHTmJ+SgQjI4N56XgFTbIGXZgiP3fxzy7+Fp9qV4SGhjJ48GAOHDigqpRLXFwcBoNBNVJbWloapaWlfS4jIwgCsbGxtLW1cdZZZ/WT2noJvRXHfzQF9JUrV7Jo0SLV2Ocul4u6ujrV3NYLCgpISkpSTXsdlHG5mpoaRo4c2aPJ/y233MJHH33Mf/+7DIslnnlzgrDZKokYNwOA6g0raD62z3+8IGrIuPYOkKF9z3FavtiJAEzRRPDnoWdRbW/j13f8hu0vL/WviVg0HZBp35eL/ZTyJa2Li0QMD8HT0ILtoNL502coxWL78UI83nEwy5zxoBGxn1TW+brdnQvo/gTby1yTGgMDufu0cTFZlpEaWxF0WvQpsQC0bD8IokjwpGH+97f2pU+UYL1gsv9aNS98DIKAZcHkDu30ljZev/fv/P73v2fynFncGZxJgmBEdrsp++NzIAgETx9FyJzx/vPIHg8V972Eu64JQSOSsOgykiMs/uL5tspmGvZtpXzVO4SEhFBVVfm9px9MJtMPQsolKSkJm81GfX199wf3MARBICEhgaqqqu4P7mFYLBa0Wi2jRo2isrKSnJyc7hf141tj3LhxPPDAA7z11lts3ryZRYsWAVBYWEhsbKzKu1MPO3bsQBAE0tLSCAkJwWw29/keqqqqVIvjvv/zatzD+GC32zly5AgjRozoUfO7L774gp///AY++GAVx3NbueySTOzth7AMG6eMYRflUf7pUr/RJUDsrIXoI2PxtLRT88z7yJJEmmDinrBhDJs1lTvvuoulf3sUt7cIrk+IQp+Vimx30vyZov0sCAKWJbMDxr8FUUQ/OBk8CnsNUBrHHgl7bgfTyM9C90q2iUaDootu7WQOKYqBEm0eCU1okD/Jtq7bC1KHgai7rglcbnRJMf6GefOWgyCKBE0ejsai3D+07s9FttrQJUQTPGWE//xf/PFRfn3HHbjCg/jzwGmMFcMAqH1jNZ66ZrSRFqJ/+TM/mw2gfvU2Wj/9CkSImjyP8OS0gOJ5a0UJhW8+jWS389nqVUyfHlh8/7YQBIHRo0dTUlKiCgPbB7PZTGxsLIWFhapcPyEhgerqatUS79bWVubMmdPPQu8l9MfxM8PtdvPZZ5+xYMECGhoaVHkvqqqqiI6OViUndjqdlJaWfmdfqJ6AT7olISGhR31kWltbGTVyFHv37mXpe3s4f/EYQoJyMcbEY4xJwGO3Ubz0OdzWDn1xU3wKUXMuAEGg5qn3cDe0EIKW63UpXHfFlfznP//hkd/9mfpcpQguiCKRt14EokDDsrX+QnjkFecoPmdf7vKT2iIumQsa0e8zImg1YNQjtbbjqVekyAxD00EUcHt9yXzxWrJ3yjHljolwAGehwqT3SbE58ktBEyip2rb9sOJj4pVvcTe24q6sQwwx+zXRpXY7Lat3gCwTcckc/9rclWv505/+zNqd27lz9vmcr41Dh4D9RDEtyzcBEHfXFWjDOvzsHEWVyoSZIGCMTyZy4lkBxfPa5haK330Oa0k+P//5z3nmmWe+5afbFQMHDkSr1aoq5SIIAhkZGRQUFKhC6oqIiEAURVXqAXFxcVRVVXHeeef1F9B7Cb0Vx380BfTVq1ezaNEiqqurVUk+a2pqVEv4HQ4HZWVlZGRk9Pm1O+/h8OHDPSbd0hlbt2wFZKJjJ/Dww08ATv7276dJmnchMfMuAqB89bu0FXQU+7TBoaRe8UsA3Cu/4iZ3HLO1UbzmKmH1AB12WzvW7Yf9ybOg0xJ+zXkKC/29Tiz0n58Lokizd/xbEAQMQ9JAUrTbAIyDlETc7tVBFwQBRAFPY6ufUSeaDCAKfiMzn666L5DbfONiPmNQX+AfmOTvPjev2AqS5JdvcTe14a6sV4L1BIXJ5q5rwn4gD0GvI2zxDP/rqPzXmyAK1GVE8rRYxlGplV/rM5i0rxbZakeXGE3UjR3u37IsU/noOzhLqhGDTGjCgtEd3MTPs+LYVN7E1oomqjZ/RtXaj9FqtdTU1PQY08In5dLZ1KGvodVqSU1N5dSpU6pc38cE7+uuvyAIxMXF0dLSwty5c//fBuwtW7Zw3nnnkZCQgCAIfPLJJwHPX3fddQiCEPAzf/78b3z+J598kv3793P77bfzpz/9iYEDBwKwfPlypkyZ0s3qny58cVytRrjT6aS+vl614kdBQQHp6emqaK9Dz0u3dMa2bduQZYm4hDGsXLmRL75YzT8f/hcjL76GjOvuBKDl+H6qN6zyJ0mCIJJ+5a8AAcexQuYWOrlFn85OTwPPGqqoEV14mq00dJoci7v9EpBlmlZtxeNlg4fPmwSSROvmA37GecTFs5XE2ztNJpqNoBEVLXIve13nbV77R799iXdLR3EAQfBLtPk0VrWdJslc5TUgCBgGKiy45s37QRQI7uRj0vj25yApmqmgfA51z3wAkkzEFWd3SL9sPYinvgm7Scv7MQ6Wuso4TxfLNe0RyNuOgeiVYAvqaGQ3bT1A89tfAGDISMR6cBvXpFn8xfPmojwK33gSyWHjow+Xf6vvsf+FoKAghgwZwsGDB1WVchkwYADFxcWq7MHXkFaDjexLvP8/y7H1x3F1sGPHDnQ6nf9eXq1GuFqN6OLiYsLCwrBYLKpc37eHnpRu8aG9vZ3WtjZCQhIoL3fw0EP/4pabb+SC3/6etKt+hc4SjqulieL3XsDj6JBIiR43HVNSOpLNQfLaY9xrGIgLiUdcp8jLjgVRoPaFT5C939Ohk4eDXo+zsMLvVaKLjUAM85LaDinMdNPwAUojfM9xf1HdNCxQxsWYGAOC6JdV9emcc1pMEDoV0H0yMb6cvHnDXkVSxdsId9U0gNuDPj0BbVQYAI0frlemyOZN8Eux1r/1OYgiIbPH+lnm7oYWmpeuQ/J42J1t4QnnKVJEE3dpMzC8uQGAyKsWBEytuaobKP/js4BSF7BXljJDrvcXz6vrG8h/6RFslcWcc/bZvPLKK9/2oz0jfihSLklJSTgcDlUa8r68WA1SW3R0NDabjbPOOoutW7fS1NTU53v4IaA3Y3lvxfEfRQG9pqaGY8eOMW6cMvqqhmGImsG6qKiIiIgIQkNDuz+4l3DkyJEel27x4bPPPyM4OISD+1+lrOwArx4sxBgUzNWZscSNm07ktHkgy5R++BrtFZ3YYzo96YMG89gjj1B39CQP1x/mpGRFE2Qi8tdLlID94if+8eyws8eBKGA7nO93+g4Zm43P6MQ3/hVx8WyvcYlSsNdGWkAAZ0FFR8HcbAJZ9uuii0Y9CKJ/9FtqVRJ7X0LuGxfzdbvbcouUbneWEkAlmwO5tR1NWIifBd+4fF2XYF31zPt+jXOfjnnL/lycBeVoQsxEXjkfDzJfumt4aM8XzMoawT333E3KPVcHdN9rX1qB/fBJBIOOhL/8nAn/vIO/3Hs3H3y0nA25BZR/9p7XwATcHg9z5nR01r8vfFIulZWVqgQsHzIyMqipqcFqtXZ/cA8jNDQUvV6vSuIdGxtLTU0N8+bNY+PGjX1+/R8CrFYrI0eO5L///e/XHjN//nwqKyv9P0uXLv3aY30oKCgAYMSIERw5ckSRpbrvPv/zjz76KG+88cb3fwE/UmzYsIG5c+dSU1OjShG7urpatYS/ubmZpqYm1bTXoUO6ZcSIET1+7r///e+MGzeOkqJNnMj5iM9zi9nf7OLGoQkkJ6eQ5h3zbtizmfrdnb93ZCIzBvPnP/+ZEaGxPHxsI5s89chAwp+uV2TWPt/hnxzTRoVhGjMY2emmedU2QGlgG7LTkJ0u2rYfAsA0NF1JvPflIruVuK1LVn7nHKcU9plpRCYIXUe/3bWdDKWEjjjurm0CjeifJJNsDvBI6JJi/BruLZ9+5fUxUZrejuJKcLjQp8b5i+wtu46C041hQJLf8NTTZqPhuQ9Bkon+xUWIeh3HpFYerNyP61Q5jzzyCMPuuNov5QbQfiSfhv8qGo5RN51Pxv238LeH/0lDSSHPf7aBhhOHKV76HCCDIHLllVf1aILm8+Q5duxYj53z2yIiIgKz2UxpaWn3B/cw1E687XY7U6dOZefOnarI2KiN/jiuDjZs2MCcOXOoq6vrUfbzN4XT6VSN+S5JEoWFhaoS2npLugWU/OC++/5Ka2s5+/e/QE55BW/mVnDh4ETGxEeQcd2daIwmHLWVlH74KrLHV6SWCU7KYMnPfsYvL7mS1zZ8xtuuMtrxEHbOeMSwEFxVdTSt3Aoo351Rd1zSwUL3Mc5vUIhuPk8TUa9DE2lBstqxn1DkskLPGqdIwHj9THSxkeDxKEVvQDQq74l8GkHJF98BcHkQg0z+uO04XgR4CXNAy7q9yuS2txEuSxKt6/eBDKFzJwDgaW2ndeM+ECC8k2xqxQOvKFPi507DkJ5ArezkGfsp1q76lAcfeIDZ115KaKepcndTG6X3PA0ymMdnk3D/jfzi8X8wfnAGD770OpVVVeS/+BAerxn7l1+uYfXq1d/l4z0jfghSLhqNhrS0NP93b1/DF8f7mgGv1WqJiorCYDAwcOBAtm7d2qfX/6GgN2J5b8fxH0UBffPmzQwfPhxZlomKiupz7VBJklRjvkuSRFFRkaqjYlVVVb0i3eJDeno6p07lYzAaAAG708nruVXoRIGrM2NJmL6AsJETkSUPJe+9iKO+mpbcQySc2sNDD/yDNTu28tgjj1L6zHv+IGyZPAJtfCSehhYaP1SSdUEUibj1IhBF6pcqY2OCKBK6cAqIAq0bFDNRY1aqYlyy/4TfFFQTHorscuMsrQFAG+/VTfMn3gYQQHYqx0s2e8fjdOin+/TWrOuVbrdxkNLtbtmXAxqRoMmKfMuZgrWrugHniRJEsxHLQqVrJjmc1D3+DsgQddMFCssOcFXVc+DBF7n77ruJzB7AncnjCEe5qaj/aANtG/ciaDTE/+Fa0lNSuT1mOOtctaxa/yX5Lz9Cy9E9CBoN0dPOQRBEvvrqK26++eYe+8x9Ui6HDh1STcrFZDIRFxenyvi3mol3ZGQkVquVSZMmsW3bNlWldHoaLS0tAT8Oh+OMxy1YsIAHHniACy+88GvPZTAYiIuL8/98k8btiBEjGDZsGH/84x/ZvXt3l+eNRqMqZls/BLS0tLBv3z7Gjh2Lx+MhLCysz/egVhwHOHXqFMnJyarJsDkcDo4cOcLIkSN7ZQ+iKLJ7927GjBkDKCzrtaX17Ktp5YYh8aQOGETKpbcAULNxNU1H9uBoqMW+Zhl/v/NXEBHCvb/7HYceflnRIwW0YSGEXbsARJHa5z7yF8JjfnGxMur92Vd+Jln0jYsBaP5ipxLbtVq0cRHIdqfiJQIEnzMRRAG7Nx6bUmNA1HQa/fZ5lnRioMuyP/F21TSC3BHHHafKQKPB5B379lhtyO12tNFh/mJ97UsrQFZk2Hyxvf6/H4IkKexz7z1V1WNvgyAQMnscpiGK14js9pD3u6d46OGH2V9ZxJ+mnUeWqEyCOQrKqfrn6wBEXD6PmDkTucU8AFdsGM+sW0nhBy9T9tFrAISPmYreEkG73cbw4cN7THLEJ+VSWlqqyvizbw9qjn+rlXhrNBrCw8MJCQkhNjaWHTt29On1exP9cfyHjU2bNjFz5kzq6+uJiorqfkEPw9cI/76Skt8FVVVVCIJAfHx89wf3AnxTZImJib3WvLj//vt55JFHkCUPMjL5Da28faKK89OjGJsUTcYN9yBotbSXnKJ81bt4nA5qP1vGddNGM++8hfzhD39g3TOvdsiuCAKJ992o+Jd8uBFnhUIcCh2dhRhkwlVWg3W3MikWMjYLkGk/eMIvrWa5VJFxafeezz8VfkIh1PllVauUArqg1YJGBE9gnPObi3qJbr44LksSssOJJjzUL4vasmYnyDJmr49Jy57jIAiYxw/xH1P78icgCljmd8ipNu84jLuqAW2UhfCfneW/du1rq/jgrXd58tUXuemCJSzQxSKgSMCU3v0kuD0Ys9OI/fWlLDYkMCkjiycOb+LEutWceuEhZJcTY2wiodmjQIALLrigR2VXfFIuavpppKWlUVtbS1tbW59fOzo6GofDQWtra/cH9zCioqKoq6tj1qxZbNq0qc+v31v4pnEceieW93Yc/1EU0Ddt2sSsWbOoq6sjMjKy+wU9jIaGBkRRVCXhr6qqQhRF1UbOJUni2LFjZGdn97h0S2fExMRQUV6G2WSk7JM3qd7/lb+Ifk1mHMkLLyUoIxvJ6aDoraeZbnLyy9t/yVueMvZMSwGNgO3QSX93GyDhLzcoSfaqbQoLDLBMGQFaEceJYuxHle5U+AUzQZJpWbcb2e1GEEW0yTHIThe240pxNXjGaKCjEG4aqYyAdIyM6UEGyauBLtuUP32Jt6dRYbT5E29v59zg7XY3v7cOPJKftda6NwfEwGBd9cQ7yn4vPsvfNa95/iOQBcwThvh12iSni9LfK1088axRvGSooUhq5zeGAUQfLKX5/Q0giMTefSUDMgdzqz6Nte5aNguNCGYjuD2IOj0pl91K9LRziF94KQAvvfRSj42NgSLlYjabVZNRAYWFXlJSokrXXa3EW6fTERYWRmxsLEajkX379nW/6EeC5ORkLBaL/+ehhx76zufatGkTMTExZGZmcuutt36jAlFdXR0PPfQQNTU1LF68mPj4eG666SZWrVqF3W7vdv1PGdu2bSMjIwODweDXHOxL+BrhasRSp9NJeXn59zJh/r7Iy8sjIiKiVxN/QRDYt28fEydOpOnAV5SveJs1xbX+Inp69jDizr0SgIpPlxJ2cAMP/vmPHDO7eSfOgZwRh9TuoPrJpX72WPj8KYihZlxlNTR/ruiea0KDCJo2EtnjoWnFFgD0iTEIZgOushq/Uagv8bbuUxLv4CEZIIMjz2cIrphx+ZhrfgmXtk5sXkn2F9btxwpBkvxxvHnLQfB4MAxW4njrzuOK1vmk4QiCgGRz4MwvQzAZCPLqnCtrJIzDMjANVViMrUfycZwoRgw2E3HlOf5LVz/9HpLVjjYphvWDzXzoquBaXTLTrUbF/BuwLJpK7OJZ3KxPwyZ7eN1dipwY4T9HzKxziZt3EclLbkKjM1BWXs68efO+1+fcGUFBQQwePJijR4+qZkqdmJiI0+lUZaIrKioKp9NJS0tL9wf3wrUbGhp+col3fxz/4cJut7Njxw4mTpyI3W4nIiKi+0U9DDUnwgsLC0lLS1PNBLy2tpbGxkaGDBnSq9e55557ePihh3DUVlH45lPkllb6i+jj0xIYcMO9ClM89yDNH77In264iqihg3haV0nbBRMBqPnPB/7YqouNIPT86SBD3Yuf+GNF3L1Xg9DBQhdEUWFnCwIt6/cAEDp+CHgkrLuOIcsymtAgEAQcRZX+nB1BwF3X5D+vaFBy8s7wEczctU0giugSlOaPs7RGMQLPVqYDPa3tyHYnuoRo9N5jGl5e6ZVhU16bu6mN9l3HEXRaws5X5FSldjv1T3/QMUXmnfpuOZBL69o9CBqR8nOG87SzgDGihes0ydT+5WXkdif61Hji7rmKxaZERmvCeNZZSFNkx6RkUNpg0q64jYRFV2BOTMcjy4wfP6HHJqhFUWTkyJEUFBRgs9m6X9ALMJlMxMfHU1xc3P3BPQyNRkN0dLQqpLaoqCjq6+uZOXNmfxz/H/i2sby34/iPpoA+Y8YM1brdvmCtRsAsLi4mNTVVtWBdWlqKLMt9MnYeERFBXV0d4eFhVH7xARVfrQsoomdc8nPM8Sn8+rZbmTlrFk+1nyRHtCGajSQ9eBsAje+txXZMKYxrw0IIu3IBCAK1z3+sBGdBIOo3l3nHxtYowTjYjDY5FqnNhnW3kmiHLfEm3l4Zl+AJQ7xGot4C+sAURU+1M3NNlpG9bF7J+6dfi83lRjQbEc1GhUXncqONjUATYkZ2e/DUNiEGmfyaaPUvrQBPR7B2ltfiKq5GEx5CyFzFCNRRXEX7jqMIBh1RPz/P/z5WPvwGON0Ys9OIuHQuEvChu5IVBYf47aizmDx5MjG3X8KgUcP9xfMNLWWU3v0UruIqNCYzaVf9iqBkJbkPGzaOyEnKeNrNN9/cYyPggiAwZMgQ8vPz/2dnsjcRERGBwWCgoqKiz68dGRmJ2+2mubm5z6/tS7x/agG7tLSU5uZm/88f/vCH73Se+fPn8+abb7J+/Xr+9a9/sXnzZhYsWNBto8VoNHLeeefx8ssvU1lZyYcffkhkZCS/+93viIqK4oILLuDVV19V1XhPLXRuhKsRx+vq6tBqtao0wsvKyggLC1NNhs1qtVJUVNTrSbcPO3fu5Nxzz6Ul9xAlH7zClwVV/iJ65rhJxJy1mNmzZ3P3b3/De2VH+cLYgoySTAsGHY4TJTS+vx7wstfuvwmAhvfW+RPy6J+fB5JM85c7/VJqETcuDjATDRmTpSTeO5XEWxsTDrKMPa9E+XeURZFiq/KNfnsL6DZnx4uRZX9hvf24994iViFy2LzarT4D0eYP1nl9TJT3uWnVVkWGbe54RL0OWZJoeOljkCQiL1cK5bLLTe3Db4IM0Ted79c3b955hPY9xxGMOmLvugJRr2O/1Mwz9ceYQTi33HwLITPHkHDVQm4xpGOTPbzqLKbi5RU0L98IgkDCwsuImjRb8XaJiCbpousARYLhhRde6KmPm4yMDGw2G5WVlT12zm8DjUZDcnKyaol3TEyMaol3XV1dfxz/GvTH8Z7Hrl27iIiIICwsjPDwcLReecm+gsfjUW2SrK2tjYaGBlJSUvr82qCwz48fP86gQYP6ZJLtd7/7HW+8/hrulkYK33yS4wXF/iL6hIGpZFz3W1JSUnjo/r9SaG3gZWMtVjxYJo8gaPJwZKeb6ieW+ie5Iy+dB3ot9twi2jbvBxQ2uRgRiruqnrZtivxa+IVneUlte5DdHkSTASHYhLuuCVeZMgWuiQ4DtwdncTUAgkkPbg+eZqWgLBh0cFpD10c8c9c0gtBhIGrdlwOyjHGwkn+3bD3kNf1W5FtcNQ3Ire3oEqIweqfDqjvLqYYGAVD5xLsgQPBZY/3NcXdDC3X/ehuA6FsvQp8UQ7Xs4N/2fOSCSv5+171EZCQT/4drOT8kxV88LzlwlIr7XgTAMnQMKT+7EVFvQNRqSbr4enTBYbRZrZx99tk99nmHhYURFxenqqFoamqq6qS2vobFYkGSJMaMGcPBgwd/MjroPRXH4bvF8t6O4z/4AnpNTQ05OTmMHDkSURT7PAGVZZmqqipVWGvt7e3U1taqFqw9Hg+5ublkZ2f3GVvQZDKxefNmAGo2fUrp+pW8llOpFNGzEvjjP/5BWno6v/v97zj44Iv+USx9ciwRN10IgkD1k8twe0eww8+dghhkxFlY4ddUCxmdiWDU4zhVju2AYhQae9vFIAo0f7lTOWbUYCXx3n0MWZLQp8QpI2O5SoKmi40AubOEi15hsrUpnVvfDYNo0itMOhm0cUqwdpZUgUb0j323HclX5FsmDkUQRVy1jV2CdeW/3lRez5K5/kS83Btco65d6HfybvxyJ47cYjQhJmLuuMxvUGrPL2P5Xf/g8ccf5zd33cn508/yF8/X1xdR8qvH8dS3gigQv/BSjDGBBnPBGVkgCEgSPaofHBkZSVRUFHl5eT12zm8DQRBITU39f5d4R0ZG/iRHxkJDQwN+DAbDdzrPZZddxuLFixk+fDgXXHABq1evZs+ePd/qvRIEgSlTpvDwww9z/PhxDhw4wPTp03n99ddJSkr6n1pvP0X8EMa+Y2Nj+7wZLcsyRUVFqmqf5+bmkpiY2Kf3T8uXL8disWAtzqN46fN8kV/uL6JfetEF3HTLLfzzn/9k1X2P4/QmxaJeR9K/bgegacUW2vcr48S6uEiFlSbJ1L20AlmWEc1GQs+ZpBiKfrwJgNCJw0CWaPvqMJ7WdkSDHjEkCE9TK86iSsV8KNiEZLXhrm30M9dcnSfJANnhDHgtfmmX+iZlP7ERyLKMbLUhhpjRRocju9x4mlrRWIIxDEhElmWFHS/JhM5TZNiavtiuTIyNH4JhQCIANS987NU+HUKQd1zcVd1A/ZPvgQyxv74UXYwyqiq129l2+wP8/g9/YMzECfz69ts7iueOIsoeeZM2L2svbMQEwkZMCHgdhshY9GGRIIpovPcGPQGtVktmZiY5OTk9Jg/zbZGamkplZSVOp7P7g3sYaiXe4eHhOJ1OJkyYwK5du34yOuj9cfyHC18jXK04Xl9fj06nU8XAs7i4mLi4uO/8+/h9UVFRgcPh6FP99WuuuYZzFy3C3W6l8K2nOXoiz19Enz9qCA8++hiff/45T//p7zRu2ONfF3P7zxBDzTiLq6h763NAkVFN/JsiBVr3xmd++bWE318DQOP765HdHjTBJrRJsUit7X4ZmLALpoMo+P8dMncsCB1GoppoJUb6psJ9MdsPUfQ3yG0nihXvEm8BvXXjfqWAnulthH+8MaARXvvKSgAs8xUZNnd9M45jBYhmA5aFUwFoyylUHgsyEXmlYm4oezyU/u4/IEDo/MkEe6fQZFmm4NE3+Ptf/kp1fR0PPPQgl0QM8BfP8zfvpOphJefXhUUSv2CJP5cH0BiMmFMyQJZ6PN5lZWVRVlamipQJKE1hnU6nSjyNjY2lqampz6eMRFEkMjISrVbLoEGDfjI66D0Vx+H7x/LeiOM/+AK6T/9ckiRV9M/b2tqw2WxER0f36XVBCdY+mQU1UFBQgMFgICEhofuDewi1tbVeV1zlc67ftZGi1ct4I6echCADAy1BvF1mo7XdgSO/jJp/L/OPeofNGYtx+AAkq52ap97zM84T/6Horja8uwZ3XROCIBB9z1UBLHRDegJoNDhOFOMsr0HQadFEhCC1WHEUVCBoNaDT4q5uwGO1oY0OUwrm1aeNfntvCHzaa4Jep7DjRAFdnHKz2frV4QC376ZlawPkW2pfCgzWjuIqPLVNaGMjCJkxSnkty9YoLPMh6QTPVDRnnaXVNL6mGIvE3nkFWq8unLOiloo/Pw9AfoaFVVItC7WxHPe0sq7yJCW/egzZ7lBMztITqPriA1wtyk2ILMvU795M8dLn0Gg0rFu3pseZD0OGDKGoqEi15C85OZnGxkZVbhj6ddB/HMjIyCAqKor8/PzvfI5BgwZx1113sWXLFioqKnqUOfJDh9r6575GuBqstcbGRmw2W5/G0c5obm6moqKCrKysPrumLMvMmzeP5uYmQMRWVUrhW0/zWW4xlVYns5PC+aS4kSKXBtnhovKBV/16p7qYcKLuugIEheXlK25HXjUftCK2I6ewfnUYQJE7kWVa1u/FVdOAoNFgnjoCJJlWL8Mt7JLZAYm3z7TTJ/OCXotscyC12/0MNZ+XiQ++xFu2uxAMOsRgk3cMXMCYpYzztx7KUxrhk4YhiCLW44Ugg2nUYHQxEchuD41vrQFZIuKyuYAyWWbddghBryXqBmWKTHK6KL33GWXvF5+FedRg/+Mldz4FThetkWZe0VUxShtGGDpeay+g+M/PYTuUj2DUEzx1BE2Hd9OSd8T/GtpLCzj16mM4mxq441e/4sYbb+yJj9qP1NRUZFlWxcwTICQkhPDwcFWuHxsbS3Nzc58n3j9lHfTeQH8c//5QuxGu1kS4JEmUlpaq1giXJImcnByysrJ6tPnZHZ566ilWrf4U0CA57RS9818OHT7MZ0V1zEsOp6DVyTa3wsCue+mTDt1zjYakh28HZFrX7KLtKyUWGVLjME8ciuxwUvfmZ4BCgNMmROGua/LH7djbfwaiQIuX1BY6YyxIMtZdimF18OhsEMQOWdUhaUAnWVXTacU6QfDH9/bDJ4EOSVVPXROCTos+JRbJ6UJqbUcTaUGfEofscmM/lI9g0BE8fRQAlY+9C0DYRYqcquz2UPPgGx1TZMHKFFnVk8uQrXYMGUlEXtUhzVb36ipsh04i6TQsi2xH1GiYrInkdWcJeSvW0vDsRwCEzB6Hq6WRqnUdkjfuthaK3n2W5qN7GTp0KDt37vxOn+vXITg4mJSUFHJycnr0vN8UgiCQkpKiCqnNaDQSFhZGdXV1n1/7p6qD3lv4vrG8J+L4D76A3rnbrYb+eVVVFdHR0X0+piZJEiUlJaoFa6fTycmTJxkyZEif3aj4mDRtbW1kDbmY1HRFNqT12F7OMdhocbqoaXewJDuJrFv/CKKG9oMnqPUy0gDi77kKwajHnlNE4wfKCLguLpKQsyciuz3UeQvMwdnpiCFmnCXVtO9RzEsirjzbO/6tdNEtl84FscO4xJChMMYc+WWKSQngrvaNfntHw+q8chyShKDTIoiid1xM8Afrtm1K8m/MTEGWZVwlVQgGPaZhGchuN/bDJwOD9YOvgywTcfnZCBoN7oYWmlduA1Eg+pYLFa1Vu4OyPzwLQORVC/xSMO6GFsruflp5PQunMOzCc1ioi2GHp4HhYghJy3aAW8I0JIOE+24g9p6rwCBS8uGruNpaKH73Wao3rMASGkpjQwNz5szpsc/bh9DQUBITE1UL2AaDgfj4eEpKSvr82rGxsbS0tPS55pxPBz0mJuYnp4PeGygrK6O+vv5b6UdXVFTw/vvv85///Ienn37a//PMM88QGRnJoEGDenHHPyyorX/e2tqKw+FQrRGelJTU5/cQPuTk5JCWltajk0Pd4bbbbmPr1m1ExwxnzNibFKZUQx3pRftJDTGwv7aVRWlRjLnsBozxKXha2ql84DU8rUoTNXT8EIKmjkJ2uJQRcLcbQaNRmuEC1L26Gk9bO6JeR9iFswBo/HATANFXL1SK6l/uRJYkQqeNDEi8LbPHKXJsXh8STbgyveWqbeoolLsDx0IFk165x5BldDERCIKA9dBJkDvkWxrfXRPQCK9/TjEKtcyfpDz/sSKrEjx9NPrEGGWK7C9KYzvy2kX+KbKKf74OLg+m4QMIv1gxIZMlibI/PIvUYkWfHEfavddyRVA6RVI7LtnD3AONOIuq0ISYSfz7zUT/8mcEjR9C+ep3sFWXU7NjA0Xv/AdPexvr163lySef7MFPW4EoimRnZ5Obm6vK+DXgnybray12g8FAeHi4qvqp/Yl39+iP498Pp+uffxND1p6Emo3wqqoqv06yGiguLkYQBJKTk/vsmuvWreO3v70Tgz6EyVN+i1YbhOxxI+/4nLmJFvbUtJIZbmbWlMnELrwEZKh+chn23CIAtGHBxPz5egBqn/8IZ4UilRDzy5+BANbth2k/pBSz43/nZaF/sAHZ5caQFg8aDfacIpzltYpMikGHs6gSd30zusRokDqmwoNGDAJRVIy+6ZBr8RHsEEDwapL78nZtTARSux1kGcPAJASNhtY9x0AUCZ40DEEQaN6wG0SRkFljEU0GXDUNuAor0ISF+CfLal9ZCR4J8/hsgiYMBaB5+0Fse3MRTQZi77rCXzNo+GQTrev2IOi0xP/5ei5MGYpR0JAjtXJRWwieVTtBEIi+7WKib76AqJvOp+ngDhr2baW9tIC85x/AVlbI7bffztGjR3ulmZKZmUlNTQ0NDQ09fu5vgpSUFOrq6npM3/3bQC1S209VB7238G1jeW/E8R9FAf2H0O3ua/jMkNQyDz158iQWi6XXXL7PhIsvvpiioiJSUmdiNIZRUrSJ0KxR3PKLX5AQYeH+fz7IS4eL0YkC148aQNLc80GGtk37aVy2FlDct5Mf/RUATR9vpt0r0RJ17ULFxXtfrt/tO+FP1weYl1jmTABJonXTPiS7k9CJw0GSsO46CkDIoikgin4DUHRaPM1tSnLvY6B7pWOQvRpseEfMOo2LSc1tCCYDuvgonEWVIIqYx2UhaLU0r9+jBOuzlGBtPVGM1GpFnxLnT8zLvGzyiMvm+UfJy/78gjJyNmmYMuoOeKw2Su54AmSZ4BmjGXH1hdxqSGetu5a3j+/i0Qcf5o5f38H4SxcT9/urEY0GtGHBxN57Jc7GGk4++3fayxUT1dbWtl5laGdlZVFRUaGKHjgoAdun99+X0Ov1REREqBawGxsbmTVrFhs3buzz66uJtrY2Dh48yMGDBwHFGOrgwYOUlJTQ1tbGPffcw86dOykqKmL9+vWcf/75DBw4kHPOOed/n9iL119/nfT0dG644QYee+wx/v3vfwf8/H/Dpk2bOOuss1TTP/c1wvuSuQWKDFp5eblqjfD6+nrq6+sZPHhwn13znXfe4YUXXiQkJJ6BgxZy/Pj7GCJjmTr3bK6/8nL++c8HeWfnYfbVtHLj0ARG/ewakMFV00jVw28g2ZWR5JjbLlKa3EWV1L/9BQCG1HhMY7KQbHbq3/4SgPCLzgJZpm3LAZwVdWgswWgiQ3HXNmE7VoBoNiIY9bjKanDVNKD/P/beOzyqemv//uw9PTPJTHolgQChd6kqoKLYsPeOiAgWBFERpQjSRMGOYgMLgqJURYr03nsJhPTeZibTy97vHzsJcp7fOcfzPDLj6+G+rlzGZJK1J7OZ9V1r3eu+m6UocmynlYGprrnSkAhU1ipFriiCdGEDWNTrkOxOEATUycr9a1+zq143NR1ZkgiWVCFG6NG3ziBodxKssqGOt2Do2ALZH8D60ybleu9WiAG1SzYge/zo2zYjsr+yRWb9dTu+MwWozEYSnrsXQRSRZZmSN74gUFqNOt5Cs9eG8JS5FW45yMc1J3ll1At0atWGR54cQurUp9A2SUQQReKfvhNNciy5X79L1Zaf65+JwLlz5y7OCw+kpKSg0+kuaox/F9/tdodFQzQpKSnszLVLefxSHr+Y2L17N7GxsWHTP7fb7fh8vrCcIQoLC0lPTw+LH1kgEOD06dMhlVMtLS3lpptuRhBUdOz8GDln1xCUPDTtczWvT5zIqqU/8eWyVY1yLlf1vQrREguSROmMrxSpUsDUrjnmm/ogB4KUv7UQyetD1GqIH/soiAKV85YheX1oEmPQZKYQtNZh/20fADEPXauQ2tYrpLbIqy9TGu/7TynyazoNgSorwToX6oQYxUi0QcIl4h+2yWT5/IDc7VW2zC0mHKfzQCWib62c0ayLGnxMlEZ4zbdrQZKIuk7xIyud/hUgE33PNYhaDf6yahwb9ytbZIOVLTJ/RS3V7y8BZBJH3Yc6RpHOs205qPx+USDppYe5q2UXuqgsfOjJYcabb1KUfZbxE8bTZOwjRPbtAkDUVd0w33Q55euXkfftBxAIgCA2vuddDOj1epo3b86JEyfCYgyu1+tJTEwMyzZZUlISlZWVIScBmM1mZFmmW7duHDp0iNra2pDGDzcuZi6/WHn8L91At9lsnDhxgvbt24dF/9zr9VJbWxuWBnppaSnJyclhSdZut5vc3NyQGY41YOPGTYiimujYFhw7+i0R6S24a+gI+vS7iikzZlJ+8ihnvn6fzw/mIHicPNG7A5bLOwGKXqrtlx0AqGPNxL/8cP0K+GJFtkWlInHiEIW99vlyJJcHbXoSqjgL/pIqnDuOImjU6Do0R/b4cOw8iqjXIkTo8ZdW4y+twtimGcgSnmyl8BYjFUZfoMrWOO0OOuplSGS5kZXuPKjouKoTY+oZdkrRLYgiVd/8CkEJU8922NbsoubLn0GScJ/IxXO2iIqZX4MkE/PgQARRxLZxH5LVgTYjGXVMFIWj3yH3wQkEiipQmU3EP1XPSPf5yR85G/wBUKlw7TxKzfSvWFJ4nJV7tlEyYR779u3jswVf8uyNd+Ie8zHn7nuNc/e9Ru3STcg+P0gy+sRUzO0vQ5IlevbsddFe+4iICJo2bRo2FnpcXBySJIUlaYVTxqWqqorLL7/8T18D/Ktj3759dOnShS5dlEPq6NGj6dKlCxMmTEClUnHkyBFuueUWsrKyGDJkCN26dWPr1q1/WMNt/PjxTJgwAZvNRl5eHrm5uY0f4WouhRM7d+6kT58+Yd0kC0cer6ysRKfThUWvVZZljh8/TosWLUKq2bpgwQJkWSI5tTsnTnyPX/bSY/BzPPfUk8xd+D1HDx0k75v3Wb7rALvzyxjWOZOMLu0RTAa850oon/MdciCIIIqNw3D7r7tw7FIG2Ykj7wXAsWk/7hO5CGoVMQ9dD4JA7ZINAMQ+fZdSeNf7nkTd0BsEAde+U4haDYgivvxSZH8AQ3fF36PBz0TQaUC6sGgUdFqF2SYKaOq9TAIlVaAS0TZLxpldoMi39GiLoFJRUq9fGqi2UzJ+HmUf/ACCQNR1PdDERxOwOpSGuigQ/+RtOHcfp+DZt6mZvxokGfOgK1DVny8qPlyC92Q+gkaF7PZy7umZvD9xKh8d3ULO029SVVTCtC8+ZmDf/jT9fk9jHs97dDK+4goISog6A/FXDARkhg0bdtFMsxuMwc+cORMWLXKVSkViYmJY8mlSUhIVFRUEAoF//+A/EdHR0fj9frp06cK+ffv+q+TYLuXx0GLnzp1cfvnl1NTUhC2PJyQkhHwQHggEqKio+I82F/5M5OTkEBEREdL427Ztw+fzEhubRVXlcSrKD9P0tod5cfiTHC+vZvHixZSu/p7d637hqxNF3NYslr7dOqHv0BzZF6B06peN8msxD92AOiEaf2kVVZ+vBCCyQws0zVIJ1tip/VEZ/CW/+DAAtT9uQPL6MF/TUyG1bdyH5PURPehKQMBVT4LTt2oKgPdsoeITEgziL69voOu0IIoXNNAbiG5IMup4C4Ig4Ph1NwSl84PwSitiZAS6lmnULFoHvgAIApUf/Yhj5zECZdWoE2KI7NdFIa+9OheA2EduxJNdQOGoORQ+9zYApr6dMbRvDkDdkTNUf/Sjcm16LRUzv2bd5Pd4+9wuDk/4EMfeE8yZ+yEScKc7ujGPn7vvNRy7j4EgAAJxfQagMkSwbft25s2bd1Fee4AWLVpQV1dHRUXFRYvxr5CSkhKWPB4ZGYlOpwu5QbQoisTExKBSqWjWrBl79+799z/0N8LFzOUXK4//pRvoBw4coEmTJo1yA6FuJpeXl2M2m0OuQS7LcthcxgHOnj1LQkJCyNfzvvjic0RR5Mih+aDT0m/wcK5vGse3ZyqIuWc4aqMZT0UpJ+fN5LVRz2GIj+GV0WNoOv1pAKq/+gXHdsXFO7JLK4xXdkH2+OsL8gDGFk3Qd2xBsM5FdT1jPeXVx0CAmsXrkINBEocpRqQNumuWQZeDIODcd0opaGVFO1WWZXQZymHGX1HbONmWXOc1MCWvD+vP2xWWOcrPNZisaNOVzQLvyVxQq5DcPqq/+gUE0DZPQ9+iCaVvfIHs9qJrlYGhYwskl4fqT5YBMlE39qbigyXoOjRXin1RIGh3Eqi0KsYlL7wLTjeIAm2efYBpb87ArhVY9upMqmZ9C0DM/dexae9udhbnMOH92bT48CUMnbNw7VJW3WO696XZQ8+SfP3d6GISKCouZsyYMRfnxQeysrKoqqoKC3tMFMWwFd6JiYlUVVWFvPC2WCw4nU46der0Xyfh0r9/f8UE8B8+5s+fj8FgYM2aNVRUVODz+cjLy2PevHn/0TaQy+XivvvuC7lUyV8RwWCQgwcP0q5dO/x+f8j1zz0eD1arNSzbXOHSawWlee90OmnevHlI43766ackJiaSfWo5ttpcWt07lMGXZbGlxEpl2yuUgazfR97Cj5g74SU27NrO5Fdfo/t7r4BOjfvIGSo/WYosSaiijCRMGgIIVM79EV9JlcJee+URhb32yVIknx9z/daVc8cRfIXlyrAbcO07RaDGjuX6+u/XF97qlDgISnjzSjGkJiir35W/K7z/oYEuGnR4cksbN8lkfwAkCV3TFEStBuu3a+rlW9pRt/0w/nPFiiH3pCfQpCXg3q2shVtu6w9AccMW2b3XErQ5qXhvcaMGvKFzFjXfrsVXWE71onU4dxxBUKsQBJHHRgxj+PRJlMgeCid9Cj4/hvbNEYYP4p15H/P0c89yxWeTsTx6g3LhgSCGlHSaDxlD/BUDibmsL5Is1/vMXBwkJCRgNpvJzc29aDH+FcI1kDaZTBgMhsbt0VBBpVIRGRlJfHw8Wq2WEydOhDR+OHEpj4cWDT4mVqs15PUhhHcQbjAYiIyMDHnsQCBATk4Obdq0Cek54o477uD666+nsvI4uefWE9vragbfcA1+SWKtXUXKHY8DULFxFWvffp1pM2fw1IgR3PzqSPQdmxOsc1M65UuCdieCIJA2fQSIAo4tB7FvVOqN1FcfA1nGtnIb3vxS1NGRaNs2RXK4sK/dg6BWo2ufiezx4dx5VGFyCwLuE7lILg+RN/QCUZFjEzT1sqpl1UC9hIsgIDcMciUZ0aBDcnsB0NRvkjXIzehaNsF5MhdUinyLc9dxrMs2A0pzXJuRRMV7i+rlVK9FUKmwLt+M7Pahb9MUTWo8Fe99jxQIgADqpFgc247iKyzHm19K5bQFgOKLduPTQ5g0czolaj9HX5qD72wRqigjiROH8NbcD+nYvRuDv36X5PGPg1ZFsMqGSh9Bxv1PkdD3RlIHPQiyzPDhIy5ag1uj0dCyZUtOnz59UX7/v0O45E0FQQjbNll0dDQ2m41u3bpdqsn/xFx+sfL4X/pU8PtkHeqiG8KXrBvW1MIx4ff7/RQUFNCiRYuQx77nnns4ezYbvU5LnMnAA62SWZFbSYHDi0ofQYthY9HGJRBwOfD4fMzz5qIRRIZn9SZl3GMAVHz4Y6OmWsJTtyOaTXjPFVP97VoAkl54EGSoW7sbT3YBmqRY1KnxBCqt1G05hDrOghChx5dXijenmKhre4Es49yjNJVFswnJ5SFQXoOhWxugfvW7QVut0tr4fKQ6F/Yf1oFXYQTVLlqL/bt1IINt5TaKRr4FMqhjorCu2IKg14EM0bf1JXbIIGSPD2SZ2AcGIggCxW98AQJYbumL+2A2hvaZONbuUZ7rM/ega5aC7dddFI2fR7DKBoJI07uvZ3zfWzmdZsSeZkGq15iNf+p2LLf2BWDJqX3Yg17uKdPiOZoDgCGtGYlX34KgUiOqNaTeqjD63357Nnl5eRfl9dfpdDRp0oScnJyL8vv/HcJVeEdGRmIwGEI+6dfr9ej1ejIzMykpKQnLgeHviiFDhvDDDz+E+zL+EsjOzkaSJBITE4mMjAw5e6y8vByLxfJfNwg/d+4cTZs2DfmafUZGBkVFRXTu3BmVSsVD7ZpQaHOysVgx8E696T7iel0LUhDJ7eIXbyl7ZCvPmFvR/YNXQRRxbD1EzXdKzja1aor5liuR/UHKZy9E8vmJ7NASTZNEAhW1WJdvQRBFYofdCqJIzffrEQQB86ArAKjbsA+V2QQqAc/pfIJ1rkZGuvdMIep65loDA71hGP57iHotrn3KGUCTGIM3v+yCtW/f2SIErQZ9+8xG7xVTv64YstIJ+pT8r89KR20xYd92kGCNHW1GMuYbe2NbvQNBo8i9ma7sTNLLD6Nrlkzl5yuxLd8CKhWiXsvN99xJi+5dWO4vxX1MyZG6VukkvfQwol7LwWNHWXZ8L49rMxBW7Kq/bgNN7hiMJtICQEL/m9BGx5NfUMj06dP/9Ne+Ac2bNyc3NxdJki5ajH+GxMRE6urqQm5K3lB4h+MMYbFYsNvtdOnS5b+u8L6YuJTHL8T+/fvp3LkzdXV1Ia/J3W43NpstLIPwhjwejkF4YWEhERERIZetUalUrF69mtdeew0EkWuaJZFmUPNtdjlBGSxZ7Wn68HMA+K3VnJGdfOEv4G5NCje/8qySn6uslE5fgOTxIhp0pM18BoCqz1fgzS9DjNATO1whrVV+rAzNk0crNbp16SYkt5fEEXeBIGBbo2yTGS5rBZKE61A2xtZNQZLw1m+FoxYJ1NiRJUlhmwso29T1EPVaReJFpUKTFKvIk3j9qJNiUZkiqP1qtaJl3qMt1lVblb+DJZKo63oQcXU3kEFlNmHs2Y5gnYvaejmW+GG3Y1+9E01yLMHqOtRxFlKnPoWuWTK1yzZT/PKHgGJsevm9t3JX7/4sj3ZjPVMAQQmV2UTqG8PQpiZgtdt4f/daBhpSSPnlMPgUKZGk6+/GmKHoNJuatSK66+VIssRVV1110e6BjIwM6urqwqKFHk5504Y8Hmr5GrPZjNVq/a9soF9MXKw8/v+LBrrNZgt5spZlmcrKyrCx1hITE0PeaAAoKCjAZDKFhV0Ayht2VVUVkyZNYsO6tfz03iwCLgcAokZL88EvoE9pCrJM7vi5fJC9E40gMLLbAJKG3w2yRPlb3+LJKfrdCriAffUOnHuOK+y1Fx8AUVQSdiBIyjjF5KT2+/XI/gBxw28DlYht3W7FTVujxnumkKDNQUSfDoCia25onqJooucU48tXWOb8znysWZ8EXtqtaKLFZJh4cdegxu/dPKUrvnIryDKBilr8xZXITjeiVo3k9eHYdQIEEKOM6Ful4zieiz+vFHV8DJY7+uM5U6hoq6Osp5v6dMDQqSWOHUfw55WiiokCSeLJnlezLlDJD3M/w7ZcORAYurYisn+3xmupWvIbU4Y8Q1pyCg88+jDR91+LuygX27F9jY+RgwHUBqPCIHA4/syX/AI0NHM9Hs+/f/CfjISEBBwOR1iMSxITE0O+MgZK4R0IBMjKyrqUsP9ETJ8+nc2bN9O/f3+effZZRo8efcHHfxMaim6n0xkWKZNw5XGr1UogEAjLINzhcFBZWUnTpk1DHhtArVZz8OBBZs+ejV4l8OYrY3CV5Dd+P6Hf9SReeycA1fNXsfiXlewO1vJsbDsu+2AcCMqQ2bpqGwAx91+LOikGf3ElVV8oRuCpE58AWca6dDO+4gqi+nYFlYBr70m854qJvqO/Yia6bg9yMIixd0eQZVwHT2Pq0goEAc/ZQoVxDvjrmWuC4X+uhAo6Db5CZcCpTozB+vN2Ze27VTr+0ioQBCK6tUYQBQJlSrFpHtgLye3FvfMoqEQErRrJ46Pqwx9BlokffgeCSoXr8Blknx9NajxxT9yCIAio4i14T+WBKJA2/E6CdS4yOrblvYMbyB/7AQCqmCh0TVMQ1Mo5UZYkvpv0Jof27Wfs2LFE9uqALEiUrvupsRCUfF40URaQJY4dO/YnvuIXIjExEbVaTXFx8UWL8c+g0WiIjY0NS+GdkJAQlpV3i8VyqfC+CLiUx8+jpqaG3NxcWrRogVarDflAuqqqCovFElI5MjhvXBqOM4Qsy5w7d47MzMywNO8BpkyZwsoVy7n9lkFMeW0chbu3NOaTiNSmNH/iZYUVfjCbbW9/xufuXO7WpnLrzLGooiPx5ZdS/tZC5EAAbVoCMY/cAJJM+dvfIrk8mPt1Ux6XW4J9rVJzG7q3RnJ7sa3egTomCiFChy+3BG9uCXEPXA+iiHPPiUaWuedMIbIkIUZEgCQRrK1TBuGyjPS7Brqg0+IuKIVgEHVijGImqhIxtGmKLMv488sQDDr0LZvgy1VkzqIG9kRQqaiol2VTx1sQRPG8F9k9A9AkxeI5lYe/uBJEgcQxD6IyGtC3ysC5/QgAkdf1QHZ7ubZLD96rOsa+YZPB4UbQa4no1gp1nKX+KmUOfrSQ9+e8w+jRo8ns1xNd6wzKf1tK0KMMhWUpiDrCBLJMaUnpRXvtNRoN6enpYZOrCqe8qd/vv6i+b/8vWCwW6urq6Ny586U8/ifiYuXxv3wDvXPnztjt9pAX3g6HA0mSQq67Dor+eThYa7Isk5ubG9ZkDYqBabt27dBqtbgKz3Hu81m4ivMAEEQVzR56BlNWRyS3l9yJn/De4U1oBIFRA24l4f7rkINByqbNx1dSicpkIHHKk4DCTveXVRPZtQ3q5Fj8JZVYV21DHROFtkUTgrV12Dfux9StLUgyjm2HCTrdmPp1BsB54DSWa7qDSjES1STGKPpsG/ZR/vZCAFTa+n9SAuhMGgK+IAhKA12lUb6XkBVFx1syEEQQRIGhP13T+NwlX4DKD5ZQ9f5ikJU1NDkQpGLqFyDJxA+/HVGrIVhjR/b40LVII/bB6wFwH89FdntRRUbQ5vE7ADhsDPDdG2/j2HQQQadB366ZogGLUnCrYs3ITg9Op5O3vpvPoOuup7negunKzpSt/wlvVRllvy0nd8G7SB4XU6dMoX379hfttY+MjCQuLu6isdz/FTQaDXFxcWFJ2NHR0WGRrrFYLNhsNrp27XopYf+JmD59OmvWrKG8vJyjR49y8ODBxo+Laf7zV8T+/fvp2rVr2DbJwrlunpiYGJb1/3PnzpGSkoLBYAh57AaUlZXRvHlzsrKycNus5H39PjUHtjcW37HdLm9cA6/6YiULFy9mV6CW55I60e3dsQDUfPMrdVsOXrgCvmk/dZsPKOy1J24FASo/Wao0pUffp7DQF69H1GnRZCQRtDlwHThN7L0DlMJ770llFVyS8Jyqb+qLIoEqK7IsN/qZNEDQqBFEUdneEkXUsWbcR5QtN13LdMXHRJIw9miLN1/Z4lGnxqNrmkzpnO8A0LdMR6pzU/LGF4CA5ZYr0TVNxnm2ENntBZVI0pgHEXVanGcKcO1UmtsZox/mziRl0+27U7spfeNLAGIevB59VjpBmzLMrjt4mmCNHWT4dNn36ONjuKVVF/StMqg7dRjb8f1Yj+3j7CfTcOaf5eqrr+brr7++GC+78jcTBDIzMzl37lxYTMjCVXhHR0fjdrvxer0hjXspj18cXMrj53HgwAGaNWuGIAhhkVQNVx6vra1FkqSwDMIrKirw+/2kpqaGPHYDvF4vKpWqfvPATtm6nyhe+S2ST3mP08Ul0nL4eFCpce07yZapH/GZM4e7dWnc9sHrCHod7uPnqPjoJ2RJwnLj5WiapxKosipSbbJM6tThANQsXEugykri03crw/EVWwk63MSNuANEEdva3WiSYhsH4bI/gComCtnjw19ajSZFYekHKmvrN7plZO95aUzRoMO1W5G40iREU7f9MAQldFnpSvNbJWLs3pag0wMyIApEXX0ZzhP5yC4vquhIZYN913GClVa06UmYb+qD5PURtCq5OH7oregykpUBwK87AYi8pjvX91WY4j94izjw1BRFfq1TSwwdWiA5FcJYoNpGwO6EoMT2/XvYfOYYI265B31KPJLfS+naH3GXFXHuy9lUbltDQkICBw8dvKivf7NmzSgtLQ25lAooebyqqirkvh6iKDaywUMJvV6PTqejRYsW5OXlUV1dHdL4f1dcrDz+l22g22w2zpw5Q1ZWFmq1moiIiJDHj4qKCnnx63a7sdvtYZl2NxgghTNZV1ZWUlhYSJcuXZg+fTo6rYaAy0neNx9Qs38bsiwjCALptz1CzGX9kH0B8t74nHd2rUEjCLxw5yNEX9MDye2j9I0vCdTYMbZogvm2/sj+AGVvKyvgaVOGAVC7ZAP+smqSxyrmJdYlG5D9AYx9O0MwiGPLIWLuugZExbhEU6+d6jp4WmGhoTTNn1p5LQBSUCkWRZWA1qDCXuZGVIlEpxupKXAgqgWadI3DZfUCAhnd49BHKg1tQQUjN95I13syEFTK4TRQXkPByNkgy0QO6I6hTTMch7MVQxStmsRR9yOoVVhXbcV7Og+A7m88x10xiu7tj1Nm4zl6DlVkBKlThqGKNAIQdLopHDUH75lCBI2a+KfvgqdvYUXeMR7vcRVJD92IoFOT8/ksavZupkmTNGxWK+PGjbvo90BmZiZ5eXlhWf8O9wp2qJ/zpZWxi4O3336bL774gpMnT7Jp0yY2btzY+LFhw4ZwX15IEc4Gut/vDxvzPVzyLYFAgMLCQpo1axby2A3w+XwcOnSI9u3bc+ONN9KzR3eQJcrW/nhB8W3Jak+TBxQPk9offuObL75kV6CGkU260XHGSAAq5/6E6+BpRJ2WJm8pK+OVny7HV1CGeUB3RFME3uxC6jbuJ7JLG9CocB8+gye7gKTRyraZfc3ueoaXjPtQNpLPjxChI1hjJ2hzIEbokL1+JKcbMUJhVjY0fgWdkp8JBFHHRiGIIrLTgxgdiTo6EvfB0wgqAX9FLeUffA9AsLKGmh834j1yVvl/u4Og040vpwh1vAXLnVchuTyUj1dMwKIG9kKTFIu/rLrxa6JBx6jeA/HKylZb1WcrQRCIH3Enlnp5GoDKL1ZQOVNphkde15OkqU/xg9HGLbfcQopTIuKy1pT8/B0lqxYiBgNs2byJ33777aKfbZs0aYLD4QjLYDhchbdGo8FoNIb8OUdGRhIIBGjbti2HDx8OuZ/K3xWX8vh5hFtS1Wq1hi2Ph2sQnpubS0ZGRli20Rtw5MgRYmNjadWqFZMnTwbAfvIg5+bPwVutbNtooiy0emYiokaP52Qum8e/w2e2M9yjb8Id86aBWoVzxxGqv/4VWZZJmzgE1Gqcu48rudliwnxbP+RAkKovVyHqdRj7dkb2+rH9vB1T1zaKlOq2w0guD9oWqcheP+4TuZj6K6aD3jOFGLu2An7nSybJ+F3nG7+iXosvV2FsaxJjqNtwAFDk1Sq/WFHvY9IW15ki5evtm6Mymyif/gUCMuo4C7IsUfnOdyBJjVtkRWM/Uh7frhmR/boi+wPkP/sWBCXQqBj81JNkqRT9/GOvvAdBCdOVXUga8yCCSrmv6g6epuDpWeAPoG2WQvpbI9nU2oQxMZYBMU2JfvA67CcOkjt/Nt7KUiZMmEB5eTkZGRkX9fU3mUzEx8eTn5//7x98EWJHRESEbTs71HlcEITG97jMzEwOHDgQ0vh/V1ysPP6XbaAfOnSItLS0sBmIhuuQUF5eTkxMDFrt/9ThvNjIz88nPT09bIY5gUCAQ4cO0bZtW4xGI4MGDcLr9RIb20opvv9h8h3boz+oNRCUKJj1FbN/W45GEBj71LNEdskiaHVQOvVLgk43sfcNQJ0Sh7+oguoFPyvstUdvAkmmct4yRKMBfYfmBO1O7Ov2EP/oTSArZqIqswkQcB09qzh6iyKBilqcqxVJFG2Emph0E1qj+rz5mCCgjVBTccaGFJSITjOy+5uzSAGZtM4xbP7wBLIs0/raVEpzbACkdY4lIlrLgR/yQZZpeVUyUSkGpFo7giiga5ZCwOagYrqyShbZryvqmCjsOw5R8+1aZY08OZ7n0rpyNEIpugPFVajjFT02bZNEhbEmiuQPnUagwoomMZrU6SOIvLIzAFtVNuw2O1dlOwnanVDfRKittWIymUJyHyQkJCCKYlg0uZOSkqiursbXYDwTIhiNRkRRDMvKmMPh+K80Er2Y0Ol0XH755eG+jLBDkiQOHjxI+/bt8fl8Id/oslqtGAyGkK99u1wu7HY7CQkJIY0LUFxcTERERNhk2ACOHTuG2WwmPT2dDz/8kJ07d2GxNAOE88V3jVJ8m5o0I6JpFgD21Tv56t2P2OWvYUyrK+jw2pMgy5TP/g7PmUI0yXHEPnYjSLIyDHd7G3VVq79eTaC2jsSxgxUW+qJ1ypaYWsR9LAd/WTW61hnI/gDuoznoOyo+L56zRajq16cDlVal8BZFxSgUELUa5PrBpjoxRjFFUwtItXWUTPgYQQA5KGNdvI5gqcIYSutgwVqvhZ7Y2kywsqbR3EzXLAVZlikY9Y4yCDfo0MSaCVjrKBz1DgCRnbJISkjELQf5bt3Pyh9VJZL00kNE9lUaBoEaO67DZ6hbvw9BqyHhuXuJf3wQgkZNiexhXW0+zz3zLL5DZxtfl0BQChlBQqPRkJaWFpbC22g0YjKZwiqnEkqoVCqioqKIj49HrVZz8uTJkMb/u+JSHj+P30uqhrqRLctyWKRcgbDJt7jdbioqKi56g/Rfobi4mKqqKjp16kRubi7PPvscGo0Rvc6Cr7aKc1++jf3UYQBUBiMJ/RR5Fl9+GZtemcWn1Se5x5jBHZ/OAFGRUrWt2IqgVpP+zigAqr/6Bc/ZImLuHYCgVePafwrnnhMkDL1NMRj9eTtSnQvjlZ2Q/QHqthwi+rGbQSXi2neSqH5dQaXCc7YIQ7tMUInn8zgg/c6XTNBrCdodIAio4y0Ea21K/k2OxXsqH0GjxtCxBdXzfgIUQ9LK79chSBKyJOM9U4gvtxRBJaCOi0I0Gqj8ZvV5KZhOWciSRMHod5BdHtTx0cSlJNNVbeH7quzG6zAPulJpvqtVBK11+IorqHxTGYJHXd+H1MlDUcdZCCDzTc0Z7rn7bowbjoLQsOEuhHRI2rRpUwoKCv6rtskatrrCEfcSqe3PxcXK43/ZBno4kzWEr4EermTt8XgoKysLa7I+fvw4ERERNGvWjE8++YRt27YTG9eG+IR2ygMEsbH4dpcXU/jj56iMOqIH3wIyFH34PW+tXIxGEHht3KsYM9Pwl1ZRNvNrhXU+bTiIAnW/7aNu6yHMN/RGNOrxnMjFsfUQSS88AID1p00gCqjiovCXVeM5macU24Eg1Qt+Bo3CBrh/bh9UWgG31YffE0RjUPH7/KI1qjm6qkAxBm1i5OSvylQ7rVMsh5cqRWXWVcmsHLMXAGOMjq0fn0QQBTrelkHZ8VrqytzIkozWoKLq0+UUDH9T+d3pikGL80Q+Ve/9CKKAMS2J3h06s9Zdyo9jpwGgio4kdcow1HEWJJcHz+kCnDuOgCRj7NOB1Okj0KYpTR5ZlqlZs4v33nuPa7r3pm3HTqTcdD/RXS/H4XQwduzYi/r6N0AQBDIyMsJSeEdERBAZGRnywrth8hyOlbEGI9GioqKwNBz+jhg5ciTvv/9+uC8j7MjOziYQCJCcnExkZGTIDS3DmcdjY2PDNgjPyMgImwxbWVkZpaWldO7cmaKiIkY9PwqNJoLmLW9EVGtBrbmg+K7Y/Auu/DPEDbkF1Coc2w8zf/psdvmqebHbtbR79kHkYJDS6fPxFVdgvr4P2hZpBCprqZy3DJXZSOSNfZB9Aarn/4yxTTqCQYvnRC7u4+eIe/QmhYX+216iH7vpfOF90+WKHNuZQvTtFba+v6J+9VsQGs3HBIOOoNWBqBbxHDtH/guzkQMycc0j8WQXIQdlbp7SlcseaoYgCpji9cSkm0CAqGQDj37VDwFAAGRwHzxJ/lMzkOpc6Fs3JaJjC1yHz1Dw9FsgyyTfNYBYj0xaqxZMmzkT22ZlRTtqQA8iuigMO/epfLzZBchuL5qkWFJnjMBU788C4Css58vnXiUQCHDPPfcQc1lf0m57FGSJq6++OmT3QoOhbKiZ4BC+wttsNoet8L5kJPrn4lIeP49wGog2EEsiIyNDGtflclFXVxeWmrygoID4+PiQb983wOv1cuTIETp27IhGo+G6a68jGAzQpt1daHWRoNYgB/wULVtA2YYVOM6dpuy3ZURecxma9AT85bVsfHEmn5Qe5V5zM26fp5hW13y3lrpN+1HHRBH//N2ArJiDO90kTXsKBIGqz5cj+wNKXg8EsK7YSvxgxUPMvmYXEZmpEJRw7D6ubJYFg3hO56NOjAHA3yDhAvjLzxtginod+AKooiORJRlk0LfKUPK7KCDqNdhWbQePQtLTBlzU/bQZOSjz+Hf90ZnUgIwclNFIXgpHvU3dzzsQ9BoMHVvgOZVH0WsfE6y2o2uWQpwlmvat2vDm3jWceVshvhm6tSb2wYEIgoC/0ornVD7+okplCD7qfuIevRGh/pwcdLrZ8+Y8Vq1axbPDR2DKaEGzR0YiavXMmDEjZH5dCQkJyLIclvowKSmJ8vLysBh62my2kMe91ED/83Gx8vhftoF+8ODBsK19h2vaHQgEqKysDMvad2FhIXFxcRiNxpDHBsUgprCwkM6dOyMIAi+OeQlBEMlo1p8z2Ssxt7+MViOnoI1NwldbRe6COXhKC0l66SGiB/Yg8fWhAJR8uYI3v/0CDSITZk7FEB+D90whFe8uRlCJJM+qdwGftwxfYTlps54FoHr+z8i+ABG9OiC5PNh+3UX8mAdBJWJfu5v4x29Wmu8b94PPjyBAydFaImKUJG0rcaKN0Jx/QrKMNkJN6dFaACxpRrx1ASJidETE6JACMqkdY1BpRbzOAFHJBs5sLmPbx6cRBAh4grhqfchA62tTadk/GZVORBRl1PHRxDx6E65DZyif/Ckgk3x5VzwllZj6d2X+I8+Dx4s6KRbZ48OTXYAnp0hZKZMkEAXinriVqOt6UrdhP978UjzZBeQ/NQPn+r2UlJTw3aLvGDnyeWI7dieh7w2IWj2zZr0VMnPP9PR0KioqcLlcIYn3e4Rz4h0uHXRZlmnRosWllbE/CXv27GHBggVkZmYyaNAg7rjjjgs+/ltw8OBBOnbsiMPhCEsjO1wD+HDJt9jtdux2O02aNAl5bFAkcxqkWwwGA08//TSBYIDmLW/gzJlVqCKMtHpmEtHd+yH7leK7etcGYu67lqhre5Dx8VgEvQ7XoWw+Hz+NXZ5KXr76NrLuvxnZ46d0ypcEqqykThwCGjXOnUexr9tD3MM3KGviu4/hOnCaxIlDGlnokVd1U7xKftuHPkmRYHPuPUFEsxQISniyCzB0awOiQKBh9VsAvErTV6q1U/TmV0hBifiWUVCnFNe3TrsMQS0giNCyXzL7vjkHyFw+tJUyIJeh2z3NWDF+H0G/hMGsZfS2m4lvHgUeH6JGJObRm4i8rifuw2cgGCTmii50FKMozDnHkdMnqdt3ApXZSNSNfXBsO4Rz30mq5v9M6aRPATBe0YnU6cORHG5sv+zAc7aIsncXUfTi+wRdHt577z1uvfVWOt90J1GtO2Fq3pb8gkKWLl0akvvBYrFgMpnCYibaUHiHWhYtnHncarXStWvXS3n8T8KlPK7AZrNx7tw5WrRogUajCbm3RkMeD/VQuGEQrtFo/v2D/0TIstw4CA8Xjh49SlxcHKmpqaxYsYKcc+dISOxInb0Yu72QpvcNI+3eYSAI1OzZRMEP89CkxBH3+CDSpj+NvmNzgjYnm16cyScFB7kvtiW3fDQFgMpPluHcf4rIXp0wdM0iaK2j4oMl6JPiMPRoS7DORfWidcQ9dD1IMrZfdyJ5fKjiLPhLq/CcykOdGINkd+LNLQGtBn9RhWKoHZQIlNWcZ6DX+4QAjV/TJMfWy7TIqGIiqfhsGVJAQnZ7qP1+PUjQ5e6meGw+ECDz8gQOLMnD6wiADA9+fiXpXWMhCKIKLLf0Jfq2/rgPnsafW4o61kynTp2pzM0n3yJyYvrnCsmtd3u8p/Jw7juJbfthCp99CwB1ShxpM59BHR2J7ZcdePNLqVm9g/whU/EXVbJo0SJ0ej33DXsaQ0oGCf1vQpIkBg0aFJJ7QRRF0tPTw+JNFhOjDEVqamr+zSP/XDQM68JlJNqpU6dLefxPwsXK43/ZBvqpU6do3bo1Docj5GvfTqcTSZJCPu2urKzEYDCEPC4oDfT09PSQxwXlsHD8+HGysrIaG/hXXd0fWQ5y+OCXCHo9SdfegUpvoPmQMcT0uEppBAOO7UeQA0GMrTJoMud5EKDsx9+Y/ulHaBCZ9OE76KJMuPafovKzFeiT44kbcgtyUKL87YWIei2RA3sgebxUf72axKfvVMxLlm1GF6+swDt3H8d1JAckGbVOxegtN2EwRqCtiuHeh+5i1KhR9Pbfw4wJb/Hdd4pp2Dtz3uXR3qN49YVJDB06lMyI9mQ0zSCjWzx7vlUMyNpcm8qPo3eDDH2HtyG5nUX5e0gyVbl1BP0SWoOa617pSMnRGoI+CSkgE6isxfrD+sa/gaASUeWW0//Zx1j+6psQCGK8vBNps54l6vpeVH6ylJJXP0Z2ehRG+tThRA3ojqjV4NhxhOLXPqFkwjwkmxMxQk/iyw+zVePA47DTLVJEpY8g/oqBSFKQhx56KCT3hMFgID4+nqKiopDE+z3+2wrvyMhI6urqaNOmDdnZ2f/+By7h38JisXDHHXfQr18/4uLiMJvNF3z8t+D06dO0adOGurq6sBhyh0t3vaqqKiystcLCQpKTk0Ne8DcgJycHo9HYeJa49dZbEQSR7FPLsFvzSR30ACqdnuSrB9Hk/hGNP+fcf4pAbR0qk4GMT8YiWkx4zxby6Uuvs9NZzmt3PUKL6/sStDspnTofye0l/d0XAKhe8DO+cyUkTx8OgkDlp8vQJ8QgRkbgPVOI+8hZ9B2bI7k8OHcfR50aj+Rw480pRqXRkOxXcbkunmFPDuPlrgOYfvODzJv7MW+m9gZg1hvTmfXsi4x8biRPvvIIbdu2wRRlxJJmBEmmSbc47JVOEASyrkoh66pkEBQflC0fneLU2hIAbpzYBSkoUX7SCjJI3gAVsxZQXm80Khp02HYd5eDO3YiRRjyF5YrE2htPEfvwDUQO6EH5nO+w/7oTBIi+bwCJz9yNqNMiaNTYN+yj5LWPGw1IDZ2z8D0ygF9++YVrYhRGW+LVt4As8dhjg0NyP4AyDA9HHo+OjkYQhJAX3haLJSxGopGRkTgcDtq0acPp06dDGvvvikt5XEF2djbx8fFoNBqioqLCIqkajr93WVlZWAbh1dXVBIPBsMQGxTi1rKyMDh2UraaePXtiMBioKD9Cbu5vxPa6mojUpkQ1a0XWM5MQjUrPwl9ahSe7AEEQSBn7KMb+XZHcHja+NJO5Z/fwYHJbBs1+TZFlm/MdntP5JL3wEEKEHvehbGwrt5E08l4A6tbuxnu2CPM914AkYV22mfgGT5O1e4h5fBCIIq69J9FlppCYkEDbWomHHnqIsQ8NYWL7q/nkk0/4/MVJALzzzju8HNWWV8aN4+5Bt9HsYCEWswXHhv14DmQjqgWe33QTADqTmgFjOiqeZjLk7a7k1LpiEKDzHRmkd4sle6OS16WATO3366lZtA4QQFDk3Yr3HiH+8i7kLlmLoFaR9OLDJDx3L1EDe1HxwQ9Uv/8DAMae7UmbPgJNUiyCRk3d1oMUj/0I64JfANA2TSbpzaf5/LtvubppIga1SHSnnmij49m4aXPI8lt6ejrl5eUhlzcVBIHExMSQk9rCuRWuVqsbBxahPkf8HXGx8nho96n/IGRZJjs7m4yMDMrKykK+wmS1WsNiIFpRURGWotvpdOJwOMISG2h0eM7MzGz82vLly5k/fz5Dhj5J0Gmnasc64q8YiKjRknTVTURktqLou4+w/bIdz5lCEkfdjyY5jvQPX6Lg2beo/HU7U51uXn1+NJM/+5Dxjw3DsXE/aouJmHuvxb79ML7TBVR+upyEZ+6mbsMBHFsPEdm3C6arL8OxcT+2X3Zgvr0/dUs3Uv3Zctq2bctVV11Fl4puLPxmKDW11Tj1NWxdthdXXglndxdRV+hn3LhxfPjBh/R4pDnZv1bTun0WlqpMZkyfgVqrIjcnl/g795LeX2L9W0fRmdS0GpDCqgkH0OhVPL1mIHMHrQPgupc7EvAFqMl3otKIPPZtf2wlTpY8vxuAziMe4KVr7+CXyhy+efJlAMw3XU7MgwMRRBF1cgJSncLijrisDQkj7mw0SRN0Gnxl1YrRiShgGXQlljuvQtRqkNo2Y+H8nxgxZCibFv9M1S5FzzUlJSVUtwXJyckUFhaSlZUVspigvNmqVCpqa2uJjY0NWVyz2dxoJBrK9x6TyURBQQFZWVmXGuh/Er788stwX8JfAtnZ2bRv3x6n0xlyVnSDgWioG+jV1dUYDIaQeUb8HmVlZbRp0ybkcUFZ+T579iy9e/dubLAMGTKEXr160bdvX2pqaqjcvpbkG+5Ba44hMqMFWc9NJufTN/GeLaLopfdJHH0/hjbNyPhgDIUvf4i/uJJPR41Hfut1Jgx9mgk2B3k7D1A24yuSxz9Owqj7qXh3MWWzF5I28xkMXbNwH8im9ocNJL3+BCWj36Xmu3Ukjx9M/tDp2NfsotWIe+l4vIZuMe3JWLgQv9/PuXPnyPGW8/PyFVitVvwBP1fc1o2betzFmv1LsZd4SIhKoa2lJ2PGdMUSbaEmp5Inh6biSi9k0ZO/IQdlLrs/k8/u+Q1kuGN2T/L2VbB/YS5Z/ZPJ6p/MrF4rABjwUgfaXpfGewNWgwCWTq2YNGECLinApKHP4rfVoctMJemVR1CZIvBX1GD7ZQfIMuqEaBJfeBBdhtJckdxeqr79FX+Rsl5t6NiCuCduRZOgEAB+3f0z18VeR/LpPHasWgyAyRS6TcPk5GSOHTuGz+cLqaRRQ+FdUVFBXFxcyOI2GInabLaQeiCYTCY8Hg/Nmze/lMf/JFzK4wqys7PJysrC4XCEZUvZarWGnI0dDAapqqqiY8eOIY0L5xv34fAjk2WZEydOkJmZiV6v1IrJyclUV1dx/fXXs2XrVmzH9mPMaImpaRZqYyStnp5I4bIFOM4eo3TyF8Q8MBDzzZeT+ORt1MSZsf6wgU1jZyFPGsmI9lcgTxnDqglvUzp9AalThpH+7mjyh0ylZtE6dFlNSJw4hPLXv6Dy46Wkvfk0tiUbsK/bg/nmy0FQSG2pj91C5wEDuLxHP1o81BIdIsV1tZyOtrJz23ak6ADFH/5AcpuWPPvwYD757DOiH7wO4/FjZHXrTM/rbyHl8afwSE4O7zvG6fLDnFxTgqAS6HJXM/Z+ewZBJdDp1nR6PdGCj2/6jQiLlqtHtef7kTsBgWa94rnng968e80qPKfyEAxanp77FpdFJfH6J++Su3YHol5H0iuPom/ZBMnnx7n/NLIvgKBREzf01kZPE1mWcR49q5icCgLqOAtxw24jooPi1VLaoyknTxynt9bE18uX4KutQlSrQkZMMRqNjfKmaWlpIYnZgMTERLKzs2nXrl1I44ZDB10QBEwmE5GRkej1es6dOxe2M/3fBRcrj/8lGegVFRXY7XYSExOJiIgIuQN1uMxKamtrG9dVQomysjLi4uLCwlqTJIkTJ07QunXr/6GP+9hjj1FVUU6zpk2p3r2JnM/exJmvGGJFZbQga+QUVAZTY/HtPpmLOiaKjHmvgE5D9baDTJk6DbUgMOXLj9HqdFiXbsb2605SJwwBrRrn9iPU/baX5BkjFPbavKXEPXKDYl6ychvxl3dh0M238PHHHzPpjfH4/T5+3vkjQ58awuODh3CAn1ny0xIOnzhAQVUOR48eBRTmZaVUyKZNm/hl50+Me/UVHnzwQTa5FrJ69a90uqwDl/sfZNKkSdz59A38POEAggC9Bmdx/JdCfM4AGT3iaHdjE+bepDTTb5jQmZgMEz+O2QMoLs1j+g5iVcHJxuZ5zIMDiX34BgBKZn5N1dwfQBSIefgGEl94ADFCjxwIUvHJUopGv4vscKNtmkzq9KeJuf86RK1yDwgaNccEB8UFBfQyyshuJwsWLOC99967+DdFPZKSkqitrQ35BFYQhLCwwU0mE4IghHxlzGQy4XA4LjXQL+FPR3Z2Ni1btsThcIS8oWy1WtHr9SE3ELVarWHJ4w6HA5fLRXx8fMhjg5Lz4uPj/8fQsV27dlRXV3PvvffiLDhLzqczqN67BVmSUEeYyHp2EpEtOyA53ZRO/gLrqm0gijSZ9Sy6thkEqm18+twr7KgtYvKYl0lv3xpvTjHlcxZh7NYaw2WtCNbaqfxoCUmjHwABbL9sR3B5UcVa8OWX4j2ZT+9+VzL+sad4vXV/MtLTWfHDj4wcOZIHH3yQn899xZdffsnRvAOk3ipy8sRJnOmKB0dxbR6b129l0aJFbK1bwhNDh/Dxb9P4dO5niKLILe0eZcakt7jroduJio/AYw+Q3C6a9K6x7Pv6HBqdioHjOvHVo5sI+iVaX5dK9wea88OonQgqgQhDBOMeG4bT62Hio0/hs9Vh6NiC5AmPozJFYN96gMLnZoM/gLF7W9JmPN3YPLfvPU7e42/gPZGLGBlBwnP3kvTKo43NcwA6Neenn35iYEYc7tJCHn30UQoKCkJ2XxgMBqKiosJiCh4dHR2Wra5wMNe0Wi0ajYaUlBTy8/NDJrd3CX9/NDTQnU5nyPN4uCRVbTZb4zAs1AgX8x2UTXibzUbLli0v+LrBYGDz5s18+cUXyC4HBYs+pnjVQoJuJ4Iokn7HYFJufghkmZpvf1V0zV0eYu64irjhd0BQYvOEd/hg/wYebt+bG14cjuwLUPrGl8huL4njhwBQPmcRusQ4NE2T8JdUYl21nZjBNwNQ+9MmOgy+i5HPPssbsV247vqB7N2xkw9LDnHfA/fzykdz+OS7r1nz668cryrhxIkT7Nq1C4DTuTnsWbOeFctX8NaEyTzzzDM8P/EpFv/2JXm5edxx/T08kDWKxx55jN53dWDTeycRBLjiqTZ8evtGkOGGCV3I3VPJua0VGGN03DrzMk6sKcJbJ4Es8+h9D9DNEMf4mdPIXbsDldlIypRh6Fs2wV9RQ96QN/AXlqFOiCZ12vDG5rm/rJr8J6djXbReIbPdciVps0c2Ns8B9K2b8s0Pi7iyVVM0Zfk0b55JWUlJSH2FwiVvGh0dTV1dHcFgMKRxw5HHQanJXS4XLVu2vFST/4Xxl2ygZ2dnk5aWhizLYWFxhWNdTJIk6urq/qvW1IDGQu6fycdER0fXu+fK+O215H/3ESWrvyfocaM2GMl6dhL61KYXFN9ihJ6mn45DjIyg9tBJJk+YiFoQmfzVJ2i1Wqrn/4xz13Ey3h8DQNWXqxB9AfQdMglU2bAu20LCnVfzyP0PMDmxGz179uSrr77ip+IPmTfvU37+egNxnZXJvL3UjRyUsBY70Ro1COL51UZRFBDVAjEZRmrynSDK5OUWsGnzRtYXLebJYUM5fvw4t/a+jxG3jKX/gH50vbsZ62YeRVQJ3DixK/Pu/E3RY7uzKe1vbMKc/quQgzIDH7+caW9O5YfvFrFw5HgQBOKH34Fl0JUE7U7ynpiO5/AZVFFGUiYNxXLT5QiCgPN0PrmPTcax+SCCTkPs4JtJfWNYY0EuyzL2PcfJHTwF54YDfPXVV9x6661Ems0XxcX4X0Gv12M2m8NSeIejgR6uxr3RaMTr9ZKZmXkpWf8f0LVrV2pra//w46+44oqwaAOHCr/fJJMkKeSFaLgG4eFcNw/XINzpdJKfn/8vmTKDBw8GSUIOBCj/bRm5X72Lp7IMQRRpcvujJF53j1J8f6MU37LbS+prQzBe0ZFgnZtPnh7L9sp83pj0Ok1aNsd9OJvKectIev5+hAg9rgOnsf2yk8RXB4MgUvnxUlInP8k1AwYwsVVfhjz2GPv27+PxwY8zY8YMtmzZwjXTWiCowG31IqjAXuZCY1AK0uqzikGXJkJF0CdjiNay/eNspKCMuaWa3bv2smzrIl7/+CWWLFnCwBuu5fK6h7n37nsZ8HwnPrp5LQDXvtSBk+uLKDluw9LExM2vd2XJ6F2UnbCR0iKO9xe8RV1NLZMefQq/y43pik4kvfgQgkZNyYwFVM1dCqJI7GM3k/D8fYgReoJ2JwWj5lA1ZxHIMpH9u9FkzihMfTo0sv99xZUUjHmX8lnfsHLlSuLi4ujduyd6vT7kpJRw+4qEywgslBAEAaPRSFRUFAaDgZycnJDG/7vgUh7/n/g9Az3UNbnDoWhYhzpuuHTX6+rqcLvdYRmEN7DPs7Ky/uk54s4772z8m9iO7+fsJ9OxnzqELMtY2nahxfDXQBBw7T9F0dgP8RWWE9W3CwmvPQayzNY3PuS9rat5rPc1DHzyEYJ1LkqmfIG+SQKmq7shOdxUvLeY1IlPAFC7ZAPGDi3Iysrixf638NoN9+B2u3lp/DjGfvg2q1atYv/7XxPw+XEfPQv1b/WeM4XKJ/5A43Nz7jgOwL0f9kZUC8S3M7Hqs40s/n4xv0nzmfHmDDJap3K59wFGjx7NgCe6s++7s0gBmaxrUkjvFsfSF/YgCHDXO72oOGNj5Wv7EVUC078ZR7/+V/LKc6Mo3HMYTVIMqW88hTY1Hvum/fVD8CDGXh1ImzECbZNE5GCQis+WU/j8HKQ6F7pmyaTNuJDMFnS6qZi7hIKnZpB76gy7du/hvvvuxeFwhPweCZe8qcFgQKPRhJwN3sBAD/X5wWg04nQ6L5Ha/g8IRR7/S0q4hDNZy7KM1WoN+aqI3W5HFMWQNxn8fj/V1dV06dIlpHFBWZE7ffo07du3/6eratnZ2Xz77UJMpmRUGhO22jNYj+ym7swxkgfeRUSTTPw1lSArWmU13/yK53QBCcPvIOPjlyl84T1sp/KY9NJYJs2YzutfzGXi48Op+OAHkl55hIQxD1ExeyHlb39L6vSnyX9yOhn5NkaOe5mik2d4/fXX6fCMmZ2791ImJhARo6Wu3E2ra5M5vb6EkmO1yBLUFDhJ7RB9QQPdbfMhy4qBqByE5I4Wfnv7CLIEie0i2VJ9kgOlW9g3fTPNozoydOhQTm07hcWyg25D0ji0NBdrkZOEVmaufbkj7123mqBX4qp7ejD0tufYcmwtK1YuRxAFYh6+kch+XXEcO0vFG/MBZZU74Zm7UUUZkTw+Smd9jfdELsiKnEvc44NQx5xf/3KfzKXsrW+R3V6QlIRR26QNOVYXd91xB7fddlsjwz5UaCi8Q63Pb7FYKCkpCWlMOD/xDuW6agNzLTU1lYKCAtxud8hNov4OOHToEIcPH/7D7ONDhw79rfXtysvLqaurIzExsTG/hRLh0D9viPuP7K1QoKysjNTU1JDHBYV9npqa+k/XiYPBIA8/9DCCoKJp5tXk5qzDU17MuS/eIq7PAGJ7XYMzR9HuRi02Ft9JLz5E4oi7qIq3YF+6mXlPj0V+ZypTZ0znldFjKN5yEJXFRMb7Y8gbPIWahWtImTgETWocZneQp1RNiH8gi2+++optW7cRDAZR61UMfLUTa6cfpvBAFVJApvBgDdoINd66AAGvwnKqzLHDFaCNUI7JMekmCg5UA1BxzoYgQJvrUtkw+xgafREpjwU5OsfKkCcHEx1pZm9qGa6sKtJ7xjL3hvWodSJ3v9OTzR8c5+zmcuLTLEybNQVv0M2MGTPw+/3o22cSP+JOpDoXBSNnI3t9qCyRJI5+AH0LhVRSu3Ibtd/+CgJoEmOJG3Y7hjZNG//W/spayt9djO/sed1xMSaRTdU+HnrkEUaNHMnHH398Ee6Cf46kpCRycnIIBoMhbd5HRUURCARwu90hlYI0m81hMVwzmUwXFN6hrmP+DriUx/8nsrOzueuuu3A6nSGvUcMlqRqu80NZWRnx8fEhZRY3oKSkBK/XS7Nmzf7pY4YPH04g4Cez+XWcy1lL0OOiaNlXmFq0I3ngnTjPnVLqcYOOQJWN4nFziRt2G5FXdEZ882nKXvqQ7bM/Q3J7eH7g7QQdTtYv/JHSGV+RMmEIrkPZeE7kYl2xlbjhd2D/8heuKwhy3dQ3WLrkR956663/saXrrW+Wyx4fQY8PUS1Q882vAEgORcJUdnmQ3G4ATm8uRQrIJLezsH+xTJOucSx/aR/WQhftjFHMHfEp9953D09eP4bPP/kSrT6fgWM78t41ii75da90QmMUmP/gdgRRYMrnL5MZ1Y4xI1+irLwMldFA8sShqCINFE/7Au+xPFCJxD12M5EDuitktrOFlL/+GQRlBJ2GmAevJ2pAd4T6+1zy+qhZtB776h1Q/zVBo2G7HMmYvu1YtmwZe/bsoUePHn/eDfBv0CBvWl1dHdLm/e/JZaHc7mzoP4baw8lkMlFRUXGpgf5/QCjy+F+6ge50OkOqIQjnDURDbXjWkKxDPe0uLy8nMjIy5DrzAMXFxajV6n+pq/3A/Q8gyxKp6Zdz+uSPxPe9AXdpIY4zxyhaOh91pJmgy0H6XEXCpPD5Obj2n6Ro7EckvfggTWaPpPj1z6jLLmTC6BeZ/PZMJn36AZOefJbyWd+SMvEJIrq3wbX3BHVfrGL0x7PpHpXEV99+x+plKxBEgcidmYginNtezoCx7flt5nGqzzqRAjJFh6oRRLAVO2nWMx5+9/Ll7a1ADirGo6JaoEmXWEqO1BKdbmTt1CPIQZnOdzblx9G7qYzbRnxVgGRbVz786AOytdt4/Z6P0UWouWtOLz6/bwPuWj+9b+zKiAdeYM22n/ns7a8RRAEpIGNfuQX32SJcO44oBmP3DMBya18EUcS+9xhVsxXtU1WUibgnbsHYvW3jdXpzSyid+RWSzQmyjDY9keh7r6Xm2zU4c0+zqeoanrjuOhYtXkxtbS3R0dGECklJSZw5cybkhbfZbKauro5AIBDSg6zFYiE3Nzdk8eC85prJZCIiIoKcnBzat28f0mv4u+Caa675w2yFUL/XhxrZ2dmkp6cjSVLYNslCrbveYB4Yaga6z+ejpqaGbt26hTQuKM+5uLiYq6666p8+Zs6cOVRWVZGe0ZfS0gMYM1oS2bIDZet/omr7WmoP7iToqiNxzINEdMmieMoX+LILG4vvuLsHoI21UPXpcuY9+wrynClMm/0W40aOonjFVlRmE0mTnqTs9U8pn/Mdd7/zOrfoUti2fRtTv/sWZ60Nc3IEye0tjaaesgSn1peg0gpU59UR3zKSyro6XLXKIdpeqhTeaq0KQSUQk2Gi+HAN0Rkmdn5+BlkCUQeCSqDjbRl8P2w7QZ/MAdMK7N9ZmDRhEqX6k4y9fToAN0/uxrmd5exblIslLoqZ707H5XHx3IMv4/f7EUTwnMil+qcN2H/YCChGoAnP3KXooFfWUvTKXGSXB1Qi0Xf0x3JLXwSNkp+CNgdlH/yA92iOYmJqNGC5oz+gEAt2ns3nqivb06lTJ6ZOncqrr756Ue6H/xfMZjNqtZrq6uqQnulVKhWRkZFYrdaQnnEtFgsulyvkuu+X5Nj+HFzK4+fRsEmWnp5OaWlpWBro4RqEt2rVKuRxy8vLQ64xDcrrfPbsWVq2bPlPa628vDwWLvwOkykZj8eKqNWTdvujFC1dgCPnJGc+mQ4BP5FXdSN+2O3YVu+gesEvVH6wBE92IXEP30D6Ry9R8PQsds79BsntZfSd9yG5vGxYtpLy2QtJf2skeUPewPrjRnpPfZ4H58zGVedg7KTXyD16CoDb51zGsjH7yeyTQN7uCoJ+mTbXp3JydTEDXuzAb7OPkXl5Iue2lzcy0pPbWTi3343OpOHUWoVpWnpSYai2uiaZ9W8exZwSwdFVBVRUlHPQt46ds3Yw9NFh3PzAdXw44X2koEz7m5uQ2Teej65TpFUnz3uJ5pb2jBoxhpLiUlQakaDDTe3itTh2HlOG4NFRJI15EF2zFCSfn9JZ3+I5prDlI7q3IW7weTKbHAhQu2IL1h82gCCCKBB5VTci+3el5PXPyDuwl0PNUxl0883cf//9Id00EgShkdQWava72WwOOQNdFEWioqKw2Wwhb6A35PGtW7eGLO7fDRc7j/9lG+h9+/bF4XBcYCwZCthsNiIjI0M+7Q7Xunl5eXlYzENlWebcuXNkZmb+yxs3Ly8PQRDJz92I2hhFXM+rEVQqnCUFFHw3l4DLAbKM68BpIq/qRtPPX6XkjS/xni6geNxc4ofdTtqkoZS9uxjn7uOMf2YUk9+bzaQP5zDpmVGUTptP6hvDaCEbeGbwk1ThZ9Qb4yk7fpbodCO1hU4OfH+OK4a3YuuHp3FV+JAlmdO/lSCIUHq8FrVOhdcRQJZRJu/1KD6sJOfsTSVIARlRLSCoBFpfk8LOL89gTolgy4cnQIYrh7fmu6c3IQibeeW7x8lyXMnYlyyUNN3Hign7qMl30u2qjowa+hIrf13K1/MWExGt5YF5V6DWisy9eR3+HUcQTQYSR96LoX1zgg4XxePnESivAVkmamAvYu4d0Ggi6iuppHTGVwQra0EGTUocMfddS0T3tgiCgORwUTn3J87l5lMcp+Waq6/mqaeeYvHixRf13vg9oqKi0Gq1VFVVhfQ+NRgM6HQ6bDZbSI1EG1bGwmEk6nK5GgvvSw30/xz/m8FHOAqlUCGcxmMNBqKhbmQ3nB9CzR4rLy9vlG4INfLy8oiPj/+XQ5J9+/YBMtXV2Xhc1WQOGII+Pomodl3IXzwPb5nCIHMfzcHQLpO0SUOxrd1F9Rerzhffj9yAKtZC+fT5fDryVeRZrzPtndmMe24UxV+vJv6Zu0i/7Woe79yXNCGWuUe2sP2TT5ACMtHpEdQWuOgzJItT60rYvygXtU6k7ISVxNZmyk/ZiM0wUZldh6vWB4CzRmmke51+BMAYo0NUC6R3jeXw0nzimkexac5J5KBMTHMjUhCyrk5m1YS91Ba4ULe30Tv2Jma/PYe1p5ag1rn47a3jRFlMvD13Bo66OkYPGUcgGOCWqd1od2MTpndZ1tg8bzBiAyj/dDnO3/YCoGuVTvyTt6NNVQpYyeWh4pNluHYfA0FAMOiIvq0vUQN7Iep1SD4/tuVbqdy9kZ2ZyQwaNIi33norpA303xfeoSbFNDDXQmmArtVqiYiIwGq1htxItKys7FID/f+AS3n8QpSVlTWS2Ww2W1hq41APwoPBIHV1dSGvycM5CK+trcXhcPzLv3V+fj6yLBEMeikp3kPi1bdgataKVs+/QdmmVdTu2QSA91wxvpJKzDf0QduhOaUvfUjduj14zxaRNPp+Mj4dR/5TM9g9/wfednt54eFHkTxeNq1eQ+XnK0ib8RxXH6vlxua9+NVRxFdjxyJJEr0GZ7L7q1xO/FKCKELOtnLa3ZTG8VVFJLY0c3pdCfYyhWUeYdGij9Ig1Mtma40akCG6iZGyE1YiYnQcXloAMpQerQUBut3bjA1zjqOP1GCI1rBt1wFs8mQeefgRxj83lR9WfUeTxwO8O0Bhok/8aAwt4zswctgLlJWW0fHWdG6c0IXlY/dwct1+5Tq6tSZ+xJ2ojAbqDpykctZC4H+S2WRJwrpuD7ULfob6nojpik5E33kVmkSFRRvZtwvVe7aw/fKrGHHVVXzz7cKQk7ySkpI4evQo7du3D+nw0GKxcPr06ZDF+33cUJNxjEYjfr+fZs2aXcrj/0uEIo//ZTXQW7RogcvlCovx2H+LbqokSZSXl4dF/7ympgaXy/Vv35Q2bd5E+/bt8HhrCThs1B7agRwMYExJp/WoqZg7KOtLVfOWUTrlCwKVVlInPkHc4JuR/QEqPviBqi9Wkvj0nUTd1AdXjY3xw0ei1euYMGcW6qBM83WneHXsKyxdupRXn3oGq1cxX3JUerhyeCtkGewlHmRJ5sCSXDQGFRXZNiJidQS8ErpIJXk1SLY0wFmt/J7SY1YADi/LRw7KVJ6zgwCdbs+g8lwdliZGjizPA6D3kCzmPPU1zz77LLHNTPQ13IO3UEWnnm15+blXWPLTEr6etxhLmpHB3/ZH8gWZO0iZhCPLxA29DX27TGpXbiX/iWkESqvQJMeSMmUYcYNvRozQE6iyUvjS+xSNfpdgRS3qOAsJz9xN2lvPYezRrjEpGru3BbWKc/Nn89M3C7jxxhu5++67/4yX/w/j94V3qPHfZCRqNBovMdf+j8jIyPiPP0KtRRxKhFOKzWazodfr0ev1IY0bLv3zcOXxYDBIXl7evyU6fP7559xzzz04ncr7eO3BHQQcdtQGI80fG0XqnYNBELCv3U3h6HdwHTyN+bpeJM8eCSqRunV7KJ7wKbrUOJKmPQPAZy9OZMupI0x7dzapqalol+9i0n1DqHXU8dyIp9m7/FekgJKQLx/aGgTY/ulpIiwaqnLstOiXBAIktzMjiAL6SC2CSsBtrW+c25VGemWOFSkoU37WhhSQCQRkBFGg+RUJBP0S6d3jWD/jGLIk06JPHNZiNwmtzOTnFfDyy2PZc2w7D189nPxvJUyRRmbPm4m1ysYLT7yKRJB73u9Fq2tSmNP/50YJONOVnbDcciXu/FJyH30d58b9CAYdcU/eRsrEJ9CmxiN5fVR8uoy8x9/Atec4gk6D5Y7+ZHz4IpZb+yHqFfNcQaMm4rJWWA/t4rs3XqVVq1bccMMNf/7N8G/QkMf/G/TIwxW3QTv1kvnY/x6X8viFaGCfB4PBsEmqhromt9vtqNXqkA+kwzkIP3fuHOnp6f/SQ6Vfv37MmjULKaj4g9izj+IuLUAQRZKvvoWWI8YjGoz4CisoevF9apduQp8UR9P541ElxeDLK6Xo5Q/w5hbT9IvXEAw69ny/klnzP2X40Cfpd801+Pec5ElDBpf1v5IxL73EN+OnIyEhqAQcVX5EEU6vK6Hbg82V7dkYPYJKoOhQDVJApvhIDXJQprbIicagRq6X69ZGqBFUAtFNjAiishEecAdJamvhxK9FqNQi2ZtLQVDq8LXTjiKKAt2GNOG1EdOYNftN7rnrXuzfJoIMr84ZReuUzjw/bAxlpWX0fjyLm17vytKX9nDqN+Wco46LIuH5+wAoGP0OlW8trCez9aTJnOcxdm+rmORuO0Tuw69Tu+AXkGSMPdqR9vZIEkbc2dg8BzB2b0PQUcfmaWM4k53NjTdcH3KyRnx8PF6vN+Q1qsViCYuRaDjyuEajQafTkZKSQllZGXa7PaTx/w4IRR7/yzHQZVkmNzeX5ORkSkpKQp5I7HZ7yAtRSZKw2+0hPyTU1tYiCEJIJTkakJ+fT1pa2r9982/fvj1Lly6lRQvFjbps3VKqdm0goe+NmNt1I/X6u4nvfQ1nP5mG51Q+hWPeI+beAZhv7IO2QyYlL7yHfd0ePPWTb3V8NDXzV/HaU88x5cN3mfPh+8REmHjzo/cp6t4U+VfwnC0io1ccBXurKT9pB1nm8NJ84ltFUnm6juZXJpKzrZyEFpHkVnkxRGlxVHhx1XqRg+eLw6BPQmdS43UEiEo2YC91Y4rXk7OlHJVa5MCSXJCg061N2DL3NJY0I9V5dXjsfpr2sLBs/1e0F65i1sw3iTAbWLRwET/9sJSkNtHc+1Fvdn6Zze4FyhpY78Etyd9fTeWCVVTO+wnZ5QO1ipi7r8F80+UIahVBm4PStxfiy1aMW1UxUcTccw2mKzsj/O6Nw19RQ/W3a3DtPt74tT379jF06FC6du36Z94GfwhJSUkcOnQo5HEb2OChhCAIREVFYbfbQ9qIMxqNlJeXk5mZyblz50IW9xL+vsjNzaVnz55h0U0N9b+fBlit1pCvtsqyTHl5Oc2bNw9pXFDYiRqN5t8+Z6PRyKJFi1i7Zi1Wm5Xag9uxHt5FTI9+xPW8CnPLDkS+MIOcz2fht1ZTNvNrjH06EvfYTTSbP4HClz9oLL4Tnr+PlPdGUzJyDp+/+gbyxJeZ8c5s8PhY8/NqNmTqcLldcDKPhFZmKrJt/Pb2MRLbmCk/YaPHY5ns/ToXQRAQBAFbsQeQsZd7EARwWZXGuc+jVN6VOYqJXfGhGgDObCyp30IrRg7KmFMjKDxQTfubmvDL1KMIgkCfwS1YPu4AukgNUp8C3n5zDi+88AI+lYvSklLGv/Q6gkbioblXotYIzOq9EmRI7x5HQksz+xYdwVtUgT+vDGQZY+8OxD56E2qLCTkQpPq7X7Gt3AaiAGoV5hv7YBl0JarI8zIlkttL7dqd2H7YCPWmXw6Xi507d9KvX78/+1b4t4iLi8Pn84VcT9RsNnPq1ClkWQ4pYy4qKiosg3C/3096enrIpeAu4e+J3NxcmjVrhsvlCnked7lcSJJEZGRkSOOGU1I1HINwr9dLaWkp/fv3/7ePHTNmDHv37uX777/HXZJP7oJ3iGzZnoR+N6KLS6LVc5Op2PQz1bs3ULt4PY7tR0gYficZc0ZR+c1q6n7eQdnU+UTfO4Cmn44j/7m32bdyDW96fbw04mnuuf0OrFYrM/dtpFz2IFXWgASo4NjKQvo9344t75+gOseBLMkcWVEAskzuzgoEFZSdsAJQW+jEYNYSsCsmokFfEEEAj9ULsozPE0AQIa6ZifLTNtpen8rRVYUYY3UcWpoHQN8RbVg0dCfI0Ox+LS+OeonXXplAr77diYyMZNRTYygrK2PAix3ocmdT5vT9Ga8zQESMlj6Pt2L920cpnfk13mOKzIomLYH4Ybejb6kQB+sOZytN9aAEkkREt9ZE3zMAXcb5e0CWJFwHs6n8bDlSbR2oRAhKrFmzhoceeijkeU2lUhEfH9847AkVfm8kGkoddLPZHJYGttFoRKvVYjabyc3NpVOnTiG/hkv41/jLMdDtdjtut5vo6Gj0en3IE5jH4wlL0z4cBqK1tbXExMSE/G/s9/spKSmhadOmf+jxI0aMACA2rg0AgTobJT9/R85nM7GfPoKnrAgkCX2XlhAIUvPtGorHfYzg8dNswQTUyXGNxbc2OZbE0ffjcbj4bdGPJMXEUlxdwdFtO6ldsh4xOhJBJSAiotaKZG8spfNdTUGA2PRIBFHAW+dHEMDvlhBVgqKDKoC7fvUbAEHRWI1KjkBQCUQm6xBVAvFZJgRRoNkVcTirvMS3jGLL3NOKHvptTcj+rRRTrI7mVySw4/MzbN6xEVOUCZ8zwNaN22nWO5EH5l3Olw9uYs/XOeiMau75oDf9n2uHzqjCX21HdnjQt21Kk7eew3JrX2Sfn5IZC8gfNgNfdgGqKCNxjw8i/b3RRPbvhqBSIUsS9n0nyBs+k8LnZuPac6LRuCTuioEk3z6YDRs28PPPP/+Zt8IfQnR0dKO2cCjRYOgZahgMBjweT1hiJicnU1paGtLYl/D3RElJCSkpKXg8npAzwcORxyE8G2wOhwNJksIyMMjLyyMjI+MPnSEWL16M1WYjIaEDyDJyMED1rg2c+WgKVTvXE3DYCbodqJungkaFc9dRCp+fg2PXMZq8PZKomy9Hcnkpmzof9/YjZHz6CqhE1n7+LVpE1AY9GzduouzNbzD074ogKjrmra5JxmP3k9hS+fscX1UMsiLDBjL5+yqRJSg9VosUkHHVS7dIfqXp7LH7AfA5AuhManyOAOaUCKxFykD82HJlIF2ZY0cAejzcnGVj9yPLMjdP7srXD2/j8OHDeKjDqDKz8ofVaCNFHv26HyfWFvH5/ZtAhiuGteaBT64g4zILSDL+3FJUMVEkjX2ExJH3ooqKoHbFFnIfnoTt5x2gEoka2Iv0D8YQ+8DAxua5r7iC4smfkTd4CrbFGyAQRGU2gUpF86FjWb9xMyaTKeRMLpVKFZacajab8fv9uOsN5EKFcORxjUaDSqUiOjqasrIypPrBySVcwv8W4c7jer3+v0ZStaEmDzWKioqIjo7+Q4MKu93Ojz/+hNGUBLKS9+vOniDns1kUr1qIz1qDp7wQMdKIOjkOf0kVxa/Npfrr1cTefQ1JU4YCULt4PWVvfUuTN59Bk5bA0U07KCstJTklmQ0bN1C8YCWmy9o0bpFd82JbBBEOfZ+LSi2Qs7WMmAwjbqsPc1oEQb+E1qgh6JcQVOCq9aLSnr9vbCUupIBMyUkrsgyF+6qQJTi9oQQ5KFN4qApkaHlVCtYiFwmtzOxblINcT1D7ZcpBCvOLya3KJt6cyL4dBymvKOfW6ZeR0jmWWb1W4rH7yegez9Al19BmYCpyUMZ7/ByoRGIeGEjajKfRt2yC43QeuYMnUznzG/AHMLTPJHXqcJJefKixeR6sc1H19WpyH5xI+dsLkWrrUEVHAgJxfa7leI0TQ0QEJSUlf/Ld8O8RHR0d8jwuCEJYdND1ej2BQIBAIBDSuJdq8r8+/nIM9AbWuU6nC3myBiVh63S6kMa02WyYzeaQN7Ib4oYapaWlmEymPzS9rKmpYe3adURFNaG2Noe4PgOwdOhBwY9f4Ksup2jpfAStFkGjJuXFh5FcHgpfnYuvsJziVz7CcsuVpM0YQc1Pm7Av39I4+b7x3Qk8nNCaNyZP4f6nh/HqpIlMnTAJyedD1Ajk7qqg6wMZHPgun+wNyptXg+FY0aEaBBGKj9QiSzKe2iCCSmxkrgFodCo8HvDYvciSTMWpOqSgTMHeGqSgTP7uasVgVC+CDB1uSWfT+6cQ1QLdH2nOb28fo2VWCya//jpfLfia+Lh4ps+ayqHYFcy+ciWyDEltLNw5uyfuWg8zLlvWeJhRRRlIfPEhBEGg7N3FuHYeBUFoNBWLurYHolZZ0ws63NQu3aQ4fSOAJKGKicI8sCeR/btR9uY3uEsLiL/8Wjb9OI+bb7455JprGo0Go9GI1WoNqQ56w8pYqJ+vXq8P+bBAp9NdStaX8KeitLSU+Ph4XC5XWArvUBtjezyesBiINhgchbrJ4PF4qK6u/sN6rWNfHguAz+9AH59CxkPPULZ+Kbaje6nYvJrK7euQA37SRj+AymKi8rPlODYcoPLDJTi2HiJu6K1E9GpL2bhPqF28Hs/pAjrPfY1n1U1Z+uOP6FITmPrmDF598WWKNx5AEyHidQZwVHoRRDiyvIC4lpFUnakjoXUUFaftRCboqCv3ImoE3DYlfzuqlPfehtVvyS+j0avwe4MY4jT43EFUOgFBhMhEHc4aL837xZOzqRJzqpFDP+UBcOVTbfhx1C4iIiKY/fEMCnKKWf3zFzw/ciTHjOt498mF1JV70Js03PZmd9I6x/Lhjb/iqDz/3p/w9F3o2zTF9tteqj9fAQggQORV3Yi+vR/qOItyrcEg9t3HqPlsBbJL+XlBq8HUtwtR13ZHZY6kYMSbOM6dolo04HA4OHPmDK1bt/4/3gX/GRrWodPT00MWM1xGonq9PuQN9Ia4FouFYDBIZWVlWDyOLuHvg9LSUpKTk/F4PCG/l8JRj4MyCG/ZsmVIY/p8PlwuV1hq8qKioj9MaJs4cSLBYIDIyFSczgpaPPUaztxsStf9iO34AWzH9gMycUNvJeqa7jj2Z1Px1tfYftmBc/dx4ofdTtP548l/7m3cR85Q9PKHpI55iMGqNBxWG9N/WMwLz44k4A+wZfkWJagAm987RWJbM2XHbbS5IZlTa8qIiNZTW+RCZ9Qiqt1ERKkVgpsoKM3rOn/jddvKFVNwb10AUS0Q8EpY0ozYSlyKD0q2DXNqBIeW5CIIEJWsp/KsnSZd4zj1WzEem4+Rr4ygXWYHXnttPKOeH8W0r8ayZNUiVry6HwSFsd5nSCtWTtzH8VVFSmBZJmpgbyy3XIkrv4SKN+YjOT0K6a9NU2LuuxZ9q4zG6/SeK6bi45/wF5QrG2ayjKFjC6Ku60lElywq3v+BujNHie97E1u3bMFus/H000//GbfBH4bFYiE/Pz+kMRvihrpxr9VqEQQBr9cb0j7ApZr8r4+/XAO9IVl7vd6QF92SJOHz+cKimxou3fXU1NSQxy0rKyM5OfkPPbbhjcNuV0zGzO26oY2Oo8UTL+GtKif/h88IOGohKFEy+XNi7r+OjDmjcOw7QcXb32FdsRXHzqPEP3UHxl5tKR07F93mYzxy51A+rzjBwYMHOfnM87z+7tuMe+1Vpr0xldY3JHFkeQEHvssnpb2F0uNW0rvEUHColui0CKrzXOhMajw2PwhgK1USs9vqRaReP04AQRSUYlwGvyuI1qjG7w4SmaLDUe4jJjOC0uNWjDE6TvyqPL8eD2ay4e3jtGjRnMlTp/DtgkUsX76cXo9l0dLXhLj9lyFLK+n+YHP6P9uWb57YStkJG7IEHW5tQte7mvHVY1sonfw5vpziRlMxy619MV/fq1EX1ZtfSvkHSwgU1idpScbQuSXmgT0xdGqJUN+MMfXrQvX8nwk46rDpTFRWVnLs2DE6d+78Z90OfwgNiTOUB3i9Xo9Op8Nut4eUFdIQM5TQ6/XIskxcXNylZH0J/2fIskxpaSmxsbF4PJ5/qat5MeDxeELO5LJarZhMppBrUobr/FBeXo7FYvlD5yVZlqmqrgZkrLW5xPW5FpVOT+pN95N0zW0U/7wIx5mjABS/9jEx911L/BO3EnP3AApffA/3sXMUjX6XmAcG0nT+eApGzsF7LIeHnBaOmev4/pdVSHVO5GcDvDF9GuPHjcOtsuL3Bik+UkPr65M5vbaMYL0si73UAzJIQRBVAmqtiM+vMLKd1R5E9YVkhiBBBEHAXuRBDsrU5DkRVQKlx2yotCI5myqQJdCZ1dhKXDS/Montn53CoI9g1ofTKc2tYvq06cRlmTim2khWbX9Unp9Ibqvnjrd7cmRVAYuG7wAgsbWZGyd2YeWEg5TP+wmpyg6SDLKijf57U7GgzUHlN6txbTusbIwFJTSp8ZgH9sJ0ZWdEw/nmU0SnlthO7Cem65Xs2bMHp9MZ8ga62WwmLy8vpDEb4obaSDScDXRBELBYLJSWll5qoF/C/wmlpaX06dMnLM3scLDeg8FgWCRVbTZbI3kwlPB4PNhstj8sHXP8uCLtWVFxFHWEEY3ZQnSXXlg69aB631YqNqwAUOrGSivmQVfQ7OuJlMz8Cu+xXEqnfompX1fSZ4+i8vMVuHYf54rjVuKv68br335G5ZZdTHd7eOXFl5TG+ebNdL6rKYd/ykeq56id+rUMlUag6FA1glqg/KQVAGet0jwXBIW17rb5UAnK2TPgrp+Iy6COEPA7wVWjENxqChwggVw/Nc/qn0T2pnIMFi1+tx9rsZsRo4fRtW13XhrzCrX2Kg4YVtKHu9EWJKGLLOaOWT2IsKiZ2X05yKCP1HDd2E5UZNvY/e1uHDuOItkdIMnomqcRc/+1GNorsnuyP4B1/T5qF/4KgSDIMqLRQNSA7kRecxmahPNn2cgrO1O282tUGi179u6iT58+IZdxsVgsuFwufD4fWq02pHFD7e0hCEJjLg+lSoRer288s1yqyf+a+Ms20MORrBtYn+FgoDdr1iykMf1+Pw6HI+SHhGAwSEVFBa1atfpDj2/Xrh1ffPE5Y8eOpaKignNfvEVU227EdLsCQ1IaWcNfpXzHeqq3/ILnVD4l4z8holtrYu67Vkna0+bjPZVP6eTPibzmMjI+HsuTNgvr161jw08/kDDuUSpmfM3EkS8wYcIExo0bx7Rp02h3SyonVpVQU+ACGfIP1CAIUJWjmKf43UEElXCB5rnXEcBg0DR+v2H1DEBUC/g9AWQJ6sq8IEFtgRskUKlFpIBM0yvi2LUgh8zmmUyZNoXvvlKa51ePbs/x1QW8vmQm7855l5fnDSPbfoBZvVaCAOaUCG6a2JWM7nH8NucoclDGl1OMoNNgvvkKLDddjhihRw4EsK7ZQc03ayEYBElGNEUQdW13Iq++DE38hVr4ciCIKkIPksSZD18HYO/ejmFxiDebzdTW1oY0ZsPKmNVqDWkzTq/XU1FREbJ4AGq1GrVaTUxMDOXl5QSDwb+1MdYlXFzYbDY8Hg/R0dFUVVWFRYot1IV3uNa+rVbrvzXjvhgoKyv7w0W3IAhs3ryJESNGsGfvXqp2rMNVlEtMtyuIbNmO9DsH462uIOfTGQRr7FR+9CPWpZuJuf86mn46jtqV27AuXEP1gp9xbDtEymuDubJURqtS8/7wMcQ8eiPWVdv46v2PCDxgZfLrk5kwaQK6OCd15W5OrS4lKslAbZETY5wWZ7UPlUbAWc8293skRLWAFJDP5+2GmY8AkhtAVljpAoiigEavwucKYDBrcFb7SO5gpuyEjagkAwX7KtFrDMx8ZyrleVVMnz6D9B4xpHWNZcrdn/D8SAPjpo6hsMU25t66loBXQq0T6T+yHZfd15zcA5VUnbEp2nD1GujRd1+NNiUeWZZxnDhH9YdLCFbblceIIsbeHTBf2xNdVpML/r3JsoyvoJxAwI+vKI/iojz2dujAjTfeGJbC2263I0lSSDcmLBYL5eXlIYsHF65+h2ODrYG5FmqywyX8vfD7mjxcEi6hRF1dHWq1OuQbbOEahJeVlREdHf2H+x6LFy/m+eef55uFCwk46zj78TRiLrsSS4cexPXoR2y3Kzj98RtIdTasy7dg+3Un0bf3I/mFh/CW1lA6fi6OrQdxHThF3JBbaH99P25tfSUvvfQS7maxmG+9ksPLtzB96lTGvvQyArDjl+2YUwxUnrHRpFM0RUet6GPUOCv8aCNFfHZJyXPOer3zenUynzNAhOnCBq+oFvDZlUa5zxUANQQ8EvpYNXXlXiITDZzeUIYgCkSnR1By1MqwZ57gsg49GfvyOBz+Wm59qxsfP7yCY1fUMnzEUxyM+4nFL22m9JgNWZLpcGs614xujxSU2TDnGLI/iGytQ5ueRMz912Ho3BJBEAhUWSn/ZCneoznKAFyS0LVKxzywF8bubRE0F+aNQG0d7hKlNsxfNJfieqPbUJ89tVptY9xQev406JGH+vzQwAYPJf4xj1/CXw9/yQZ6g95aqB2/G5r2oV6FDoc5i91uD4tMTlVVFVqt9j8ynxg8eDAmk4l77rkHORjEdnwftqN7MCSnE93tCpxnjqJv05SoO/tT8ea3uA5m49p/CuMVnUgYdgcBl4/S8XOp27ifq6LTib/zDt7+dQnB2joqZn5N7GM3Uf3Vz0yePJnps99g3KvjmDZ1GkltzZSdtGFK0uKo8KPSQ9ADsiQT9J3XlvzHRvoFEFCYbr9rpguCgCZCwO+ViUzSU1fpwZJmJG9bFZmZmbwxbQqLvlnMipUrGDiuE+tmHUEOysRmRpETvY3O/oF8OWEpgkqgz+NZ9HmiFbu/zmbhsG0XFMMpk4ehy0giUGOndM5CvEfPNSZpfZumRF3XE2P3Ngi/K+4krw/HwdPYftyAv7CyUQe9oZCvqqqipqYmLIV3OEyxIiIiQq6d+ldZ/Q6HmdH/nxEdHf2H/03U1NRc5KsJL0pKSoiIiECtVodFii0cG2xutzvkRbcsy9hsNjp06BDSuA3vEW3atPnDP9OtWzc2bdrU+DdyFZ7DVXAWtSmK6K5XIHndCBoNqVOHUfbOYvylVZTPXoi2WQoxD1xH0/njKXr5I7y5pYgfruS2t2bx9tFNBLw+quYtw9S/G94IHQsXLkSjV/HGlCm89tprJLQNUn7crmiZy+C2Kv8N+uXG3C0HZf5JBkdUCRd8LgVlpKCM16EU644qLyodlB61otKIeB1+NKKOabPeoKKwhhkzZtDq+iTKT9Wy5cMKNAYV5c0O0jXqcX6e6sbvCtL8yiSuf7UTrmo3s3qvOH9ekGUSX34EY5csJJ+f6sXrsC3fqnxPklDHWYga2IvIfl1QRZ0/Q8qShDenmNoVW3DvP6Uw2Bvem0SR09nZjQynUJrIN2jsOhyOkBqQhSOPazQaRFEMeS3TcH64xFz73+FSHr8QJSUlxMfH43Q6Q55TvV5vyGvjhjz+3yKp+p8al0ZHR7NgwQJ27dxF9pls/LYayn9bTsWmnzF3uAxjegukOhvxT9+F61gOzs0HqVm0Duuq7UTfdTXNvhxP5ZcrcWw4QM0HSxj/0QesdRSTX1oCBQVomyRguesajvz4G9OnT+fV8a/CRwJ7j+4EUaDwUC2aCBWOUh+CCN7a814eDfkZaByIC+KFr+MFtbgoIAdkZGQ8NQGQlQ00gISsSEqOWhn61BB6dO7FuHGv4tM6aHttGouf2gUyBFqWU0sp4roWlBxdrpDZJnUlqbWZ+Y9spibPQcPBIv6ZuzFd3hEAx74TVH2yDNnpBhkEnYbI/t2IGtAdbZMLN4b8FTXYNu7Fvno3eHyKiagogiwTCAaJj4+nrKws5MOXhq3wUDbQDQYDsiyHXKIxHDV5Q8zk5GS2b98e0th/B4Qij/8lG+gN0+64uLiQxg7HtFuW5bAU++GcdiclJf3Hh5OZM2cCIgigT2mKr6Ycd1kh7lULAdBqk9AnxZH51UTq9h6j8t3vce44inPHEaKu6U76ey+gXrOf+++8mylTpuAxQfyIO6j8YAnVX6xEZTbisTkZ98JrTJ7+eiMTXaMTqSvzoVILBJy/K7FFFGdwlIb6P0ODFlvj55JSrPtcytfqyj2odSpqC51kZmYyZeoUFn/3PatWr6Tb/c1YM+0wAJ1uzyAiTsuMuxbw1FMGRr/4PDlNf6PwcBWzeq1AEAVElUC3ezPpdl8mXzywmarv1+E7VYDs8oAsI+i1RF7VjagBPdCmnk96ksuDfcdxrD+uv8DlW9CoUcdbCFTaaDlsHAXff8q6desYPnx4yM1uLBYLbrc75Ctjer0eh8MRsngNMcPVQAcl8ZSWll5qoP+HeOeddxo/r66u5o033mDgwIH07t0bgJ07d7JmzRrGjx8fpisMHRryeDgk0Rqk2MKxCh3qAtjpdCJJ0h8y//ozUVlZiU6n+4/jzp07FwCDMR4/HtSRZjxlRVRuXa1IiQUlJK+fJm8/R7DaRtHEefjySymbOh9922YkPHMXst3Bc4ldWLlsOQd/+5WkVx6lbM5CHJsPoDIbQYav5n+DIAhMmfIGr732GlEpAerK3KgjBIL1EuOCQGNu/n3h/Y/4fcEtBeXzub9+OI5M4+9UG0RUkpbJ0yZRXVrLjBkzaD0okeMripCDMvEtzVz5TGsWPb+FnO4uRj43ktTbRIyZ8Omd6/F7JOSgTLPeCfR5ohU/vrAH544j1Cxahz+/tLEJHtGtNVHX9sDQoXmj3JocDOI5mUf1ovX4zhY2SrMB6Fo2QdBq8OWUEtO9P1XbfsVoNDayD0OF3291hbKBHo6cKggCOp0Or9cb8gZ6bW3tJeba/xKX8vh5NEixxcTE4Ha7wyLFFhsbG/KY4Rj6h2OTLBAIUFFRQdu2bf+jn6uqquLM2bOYIlNw1JUQ2bozdacPYz28B+uhXcqDBEgYeivy44Mof/973PtOUf3lKqwrthJz7wCi7riKq/dV4qtzsmD8a8Q9cgP2LYfwnS3Ct2wTBGWOHD3C1DemMm7cOPgYdh3ehqcmgORX8posXUhg+30Ol//RP/l3LYfGwbl0foguCAKiFiQ/RCbpqThTx+NPDKZnt968+uqrCHE+ZJvEnq9z0Eaouen1rqx/8wgTl83gvXfeY/D4u7AMcPPdU9soO2kDGcypEXS7pxkb3ztBoKKGik+W4tx8UMnjkoQ2PYmo63th6tMRUa/UtbIs4y+uxLpqK45tRxRJl/pcro6zYOzRFtuaXcR270/17o2sXr2am266KWx+JqGEKIqNbPC/ewO94XkmJSVdyuP/C4Qij/8lG+gdO3YMS1M5HIkzXLIx4dRN7dSp03/0Mx6Ph/0HDiKKKiQ5QPodj6GOMOGzVlO8+nvc+WfwFZZT8OzbRFzWGvPAXjT7+nXqNu2n6tPl2H/bi33jfmZ+8C47PZWczMtB9vhxH81R2OffrUWqU6RZZG2QCeMmMmnyRMaNG8f0mdNBDhL0/25q/buE3TDl/meQgzKCun7K/btkff4BEPAGyWyWyeQpk/l+8ff8uv5nYpsa2b8oF5VG5Ipnstg+9wxBv4TGoKI44QBXpPdi02ca1qw9giAIdL4tg8ufbIUuUsMvkw/gq/PBwWyQZLTNUjAP7ImxdwdEnZKkgzYHtg37sK3cqpiO1TPTRZMBY4+2RHRrg6FDc/xFFRSPm4u3phJj8zZU79qI2WymvLw8pA303xuJJiQkhCyuXq+nuro6ZPEaYgaDwZCvfv+jaUmXLl1CFvvvgEcffbTx8zvvvJPJkyfzzDPPNH7tueee44MPPmD9+vWMGjUqHJcYMoR77RtCn1PDITvX0IgM9dZceXk5iYmJ//EgfN4n8wBwOytJHfQg5nbdCHo9VO5YR82eTSCKlIz/BG16EuYbe5M+ZxTeihrKX/+8UaLt/ueeIqJJEj99uQN/eXsqSGMAAQAASURBVA1l0xcQdX0vPOeK8ecoxl1pXaJZ8OXXSEGZKVOmMP618ThFNwG33MgIk+v/K4gXFt7/r2b6BXm+oTCXz58FBEDUCqhlHZNen4i1ys6MGTPI6BPN0Z+Ua+p8Z1NKj9fw0/N7kCUZf3oVNYZCMq19eOP2qchBmbSusVz1bFvSOsdy8MdcPFYvbD8MkowqykjktT2Iuvoy1LHKoEby+bEfPIF14VqC5TWNw29UIoaOLTB2b0tE19aoLSY8p/IomfQZ2igLyDJr167luuuu+4+2CP4MmM1mbDZbSGPq9Xr8fn/IpcnCWXhfaqD/73Apj5+H1WrF6/USHR1NdXV1WKTY/hvyuN/vx+l0hrwmr6qqQq/X/8cDvjlz5iDLEj6/g6g2XUi79WFkScJ2+ghlv/6A5PMo5LQFvxB1XU/iH78F8em7KZ35Fd5TBVR+9COtenbjlpdeYfL6Hwm43FR9tgJdqwyibrkC+zLFPDSrXxJHNh1h2tRpShP9E9i2ZzNBTz0pTfV7gtr5pvkFdbbcMCQ/f0aSgxdunyEoRDgpICALMo4KD4MHD6Z3jz5K8zzRTdkxO3JQJqG1hbQu0SwdsweAlI4Gzhi2c3WrWxhx09PU1dURmWig39NtaH9TE8rPWpHnyNR+/5vSxFepMF3ekahre6JrnoogCAqRMqeY6kXr8BzPqT+jKGcVbdNkjD3bYbysDZq0BMXQMrcUT1UZKkME33//PVdeeSVutxuDwfC/uxH+F7BYLBQUFIQsXgMapE1CHTMcRLpgMEhCQsKlPP6/QCjy+F+ygT5w4MCwFd7hSNYajSbkesPhMBD1eDy43e7/uPGq1WqJtkRTW6s0Mst+W05UVgdMma1pdv9wyjf/QvXO9SCKuA6cxrX3JJqkWKJu6E3Tz17Fum4PmaerSNSbmDjyWSyDrkTy+7H9tJnq+T+jy0rHm12AoBKQ/DIqbZBJEyczYfx4Xhn7CtOmTsPn911QMEN9of0vmucNkAMXJuvG31HPYMtslsnrk1/nhx9+YN3m1QS8QSrPOrCkRWCK17H5nVMgQ6trUmhzfRIrXtlLxWVzGfbkMMp02fQe2gKPy8sX92/EVeNrnLSrInQkvvIY+uZpAASqrFR9vRrH5oPgD5yfaidE1yfotuhapjUy2kBJ3qLRgDPvDLrYRJAldu7cSZ8+ff6j1/DPQANzLdQN9FAXwOFe/b5UeP/fsWbNmvqtmQtx/fXXM3bs2DBcUWjx+wb6f4sU23+T7nptbS0tW7b8j38uq1UWp7NPA1C9bwtBr4fIrA4kXTWIqKyO5H39LogivsJyKj9eStWCX4ga0J3UqU/hr3Ngf2sxN/e8kqmvT0WMiST+hfuonL0I+5rdiGYjcqQRbA4K99WQ0CqSr7/6BikgKU308eMpLi6+4Hp+X3QrX+ACploDpID8/2ys/z6f63URjH9tPHZrHTPfnIk+VkXOtkrUOpG2N6Zy6Mc8ECAmw8SAMR1YPeUg49ZOY97H8+h9bVcy7tCT1NrCkud3UnigpnH1XJOWQMxd1xDRtRWCWoXk9mJduwfrkvVIdtf5jTGDDuNlbTB2b4OhY4tGw/AG6Fo0QdBp8dVWIqhUijl5r14hbypbLBby8/NDFg/OD9O8Xu/fnrn2e+3Ubdu2hTT23w2X8nhpoxRbqGtjCE9ODVceD4eBaMMm8X86GOnYUZEi8Xns+E4epCImnqisDphbd8LcqgPZH0wi6HIi1bmw/rQJ69JNGLu3JebeAWibJFEy+TPuuvYGVi5bTvb2LSS99DCV81fhPVOI92whqlbpBE8XkL2pjNgWRo4cOcK0adN4ZdwrIMts2rRZyd3/r+Z5/aZ3Axo+l4LSBTn8glpcRmmi19fljz76KH16X85rr76GL8JJzeE6kKH19Umc3VRBRbYNTYSKq59vT87OMqbc/QmTJiVz+923UpF8jA6DmrDts1OKoWj931adGKOYe/ftgspkQJYkHEfPUvvtGgIFZfWTfAlEEUP7Zsrw+7I2qGP+56aWoWNzbEu3ok9Op7DwHCaTCavVGtIGutlsxul04vf7Q7qZEq6cGmoiXUMfICYmhtLS0pDL5v6dcLHy+F+ugd6gyej3+0Mq1QDh0U0Nl2yMy+UKeWPDZrNhNBr/4zdbURSpqqrgs88+Y8SIEdhPHsR+fD+CSo0xszWuonMYe7QjcfT9uHKLqZz9Hf6yaqq/XEXNt2uI7N+Ve8c8w/oTR/HY6vB8/xuiUU/M/ddhW7sb75lCAOKam6g8Uwcu0BglJk+ZwvhXxzdqovuD/vMJ+/9RTAv/ol/zjxPvhs+bN89k0qTXWbJkCSt+WY5c7zKe3MlM2VEb1iInpjg93R/IZMvck2RvKkUOytSZi9FGw2Ude/DxoEUgKL8vJsNEt/syiYjWsXzsXgJVVkqWbMRzuN65+v9j77zDo6qzN/65d3rJpPcQQuhSlK4UKSpY194L/tS1rGsvWOhIs+uqsHZdRVexYKMoAtJ7bwkQ0nsyyfR27++Pm5kkgAUIM67J+zw8SYaZ+70zc2fe73nPOe9p2Exos9MxDzoNY//Tmtm5BCF5fXjzSrFvy0Hy+qha82Po/4xGI1arNexf6GazGYfDEbb1IDLDQ4Kt3+EWH7VaLTabjbi4uLC35v3VEB8fz4IFC3jkkUea3b5gwYKwtyRHAsHBu5Hg8dZkxeZwOMJ+PUmShM1mOyG7mm+++YZNmzZx0UUXUVFWRFlpIWVLvsCQmgmiCkSRDh9NRrK7KJ8zH/fWXOq+X03dt6swnNGFKyc9QpnkZk9uDgQk7Gt2Yjl3AL6aOlyb9jUuJEDFfhvGeA0ff/wxkiQfJaIf2Q0mNHidh5LiR1CbFORtqbGKPRh0m6JMTHh6Ag67g2efm43P58VXAdFpJlx1XnZ+U4SoFjjz1s7sWVzE5/evQ5ZkEjtryffv4rqxV/Ho7RPwuQPIkozOrOaMK7LYvqAAMSEaffcsauYvpW7RWnD7QslvVZwF06CemPp3Q9+tPcIRQrgsSfhKq7DvPoRz2WZkj5eqNT+F3keNRkNdXV1Yu8kiweNNOTWcAnok9g9arRav19vG4y2ANh6PHI8HAgF8Pl9EusLDnZR2OBxhj8eBEx4Cee2113LOOedw8803s2jRIqrW/ETV6iVoLLHoU9oRcDpIn34P2vbJ1Hyzkrovl+HYuBfH+t1o0hLpdvUFnNGvL3P/+x+8h0soe/Y/6E/rQNSIvlg/W4p0QInJdRYNNXlOVAbYsWMHM2fM5Mknn0QGVixfoZxME/H8mEnuJh1jUkBWuskaRPOjRHRg7C1jGTp0GOPHj6eqrpJApYRGpyI6zci+xWWhYjZUKBarAuijtRxWb+Xiv13PA499z6Lp2xr0AOXY2vQE0p9/APwBbJv2UPPRIqTq+sbkt06DsW83RTQ/ozOi8ehr3l9rw51TgH3VNpzbc8Hrx5mfi6hSh+xUUlNTj/u9PFHodDo0Gk3YOyci2dUVTgiCgFarxWw24/F4IhJf/FVwqnj8Tyeg22w2jEYjDocj7FXZkfAwjcSHwufzIUnS/5RtjCiK3HLLLdx99z8QVWokyYssS9hzd4Mo4Niwm9IZ72Ma1IOMZ+5G0GmofO87HCu2EnegkvaikecWLiTpwetwbN6HY+U2aj5ZgirOArEWqKmjMseGKVmLo9yLzxHAh4tp048Q0SWvYnt6ROB9pJAsqkVEtYAsEwq4m3mhB2Q6durI5EmTmf/FfBZ8vUA5jgo0elFpF5Ohy7nJ5K2qYvlre5EDMp1HpHD61ZksfXYX778+j4svvhiE/9Lt3DT6XZtNu77xFO2s4vsJ2wCoePm/SgubSsTQIxvTwB4Y+3VDHdvcu9Zfa8Ox9xD2ZVvw7C8Ary80qASxsSwvOTmJu+66i++//z7sQ/OCQ8/CidbU+q1SqfD7/ZjNZmw2W1jX/qthypQp3HHHHSxfvpxBgwYBsH79ehYtWsRbb70V4bM79bDZbJjN5rDbEEFkODVSVmyRSBbU19cjiuIJD3fr37+/whsNrdWCVo+rtCA0qLpo3OuYz+xJwg3no3nsZmzLNlP1wfd4dh1iuCmV9z/6hLjrzkPQaah+7zvqf9oAooi6Wyb+fUonmdaoxu8N4LL6kSWYN28eyIRE9JKykmZ8HKo+a4Ijh48BzRLowaA7JJ47HcyaNQufzweAIU6LtUgRitNPj8NR42bNOzkgQ3yWmWH3dCdnWQkvPPwmb7zxBjHmOFTZPvpfl0330emK8P59Ac4tOeTfOZNQS3dmCqZg8juzuY2O5PbgOVCEbfV2HBv3ItsbBmc2WLQBoFIhyLBr1y42bNgQEsnChWCFtCRJYe0SiVTlWrhbv9VqdRuPtxDaeFzh8UAgEBEeh9bBqZFK+lut1hPqJANISEigc+fOLFq0CGQJQaPDV1+Lz2YFoHT2h5jP7KlUnr8/CVdxOZXPzcNXUslQr4lfli/H1zGNxKtHUP36fNz78nHvyUPfMxv3rkMIKgGv3YcpQY+j2gOCrIjoMxURHRlWrFgBUmPx2q/NMWmKYIK8mYVLA8aOHcuwYYp4XlZWhiCCyijgcwSoPmzDnKAnoZOZ/UtLEETQmtQMvr0LWrOK/0z5ht6zh9M7eyA26wr6XtOBMy7P4tCacr6buIXDtz2D7Gq0S1VFmzENUuJxQ48OCE0+X3IggLegHPuWHOwrNhOotIbieALBbIFynE8/mUd0dDQVFRUn9D6eDFqLmB2puWQqlSr0/Wez2doE9BPEqeLxP52AbrfbMRgMOByOsBN2a7KNUalUYR8IY7VaTyrb89VXXyHLAWR/IOSf6q2touznb7Dn7sK16yCuHQcUL7Uu7TAP6kn8a+dwiZjMmvXrqdq6DzbvQRVjJubKkbj25OHZe1jJWqNku51VvlA7mKAScDmOFtG9XqVMPFiNJgeUKd4ANLykkl86yt6l6eCSkHg+fz4LFixoNmzU6whgSFDjs0vk/lwRGiqW2MXC5nkHObCyHDkgs03axN/vvoOnfriJfXv28uVjG3BWe5r5teq6tSd6zJkYT++MaFCuMzkQwJNXgn3dTuwrtxGoVdrTmpKzKs6CvmsmosmA7aeNZN/+GKU/fEZtdSkqlYqoqCisVmvYBfRwe5/pdDrFcy4Crd/hfq7BwDsqKirsQf9fDbfeeivdu3fn1Vdf5csvvwSge/furFq1KkTgf2XY7Xbat28fEQE9Ujyu1WojkvSP1ADyE+0+8vv95OcXoNGaMHTsQsalNxNwO6nespqqlYvxFZZTW1xB7edLUSfFYj6rF2mT7qB7fCpqrZa1P/6MJEuKl+jZfRB0WmyL1+Lfp/hxxrU3UZ1nVyzX1I28O2+eMnC8aSX6ke3eTRF8fsHKdEElKBq21Bh0m8xNxPOZs/BL/tDj3XU+tCa1MrdkR01oqFjvyzPYPO8wXz+xEQC1TsWh8v088sZt5KrW8d34rXw7YXPjuQmg756FaWAPTP27oU6IARQBxF9pxbEjh/rF6/EXVykiuUoFgYByznot+s7t0HXJRNc+hfIXP8HS5XTq922luro6Yn7koAhk4Ww5j5SAXlVVFdY11Wo1sixjNBrbePwk0cbjdqKioiLG48H9dyTWbQ1rejyekyoaXLRoEYKgQtRq6fLANJBl6g7uoeyH/yLVO5T5Y0vWK/ZiA08j4f8uJqprFmdH9WTC+PHUHzwEi9ai75mNrmcX6r9Zhnt3HgBx2UaqDzhwVLqRRUIV4s1EdOCXVb8clfz+IzgyGT527FiGnT2M8U8r4jkoOkCgIQcd285ETb4DR7UbjV5Fv+uyKdhayfJX9yhcLctszl3D1bddSvcnVfz8yi5eO3+REosLArLLgyYtEdOg0zD1Pw1tdlro2g7YXTj25mD/aSPufYfB06SArUE417ZPRd+1PfpOGbj3F2D/ZQeS28X8+fMZNWoUubm5Ye8Kj5QfeWuZoaJWq1Gr1ahUKux2+wl1i7Th1PH4n05AD2ZZRFGMiIdpW7b71MFqtdKxY8cTfvzhw4dDv9dsXYPf5cCY3oGYnv2x5+4ibcqd2FZvx/bzJjw5hXhyCqmbt4QB77/PG4FdpE2+g+qPF+HZX4D1y+UgCKjiLQSq6xFE8NT70FpEvPVyqCItJKI/M5UJ4yfy1FNPMWPmDLwe73GTdvD+R4rnQPNp4CK4awPIAZnUnrG4bR7y1lZweH0lsizTcUgyfa7KojrfzqqVq3A79Xz57mallTxBR7dz0+kyMpVvJ25FbJeMoWdH7LsOUv/tKrx5JYr/eROxXNBq0HXKUALtzu3QdWqHOkZpJ/Rb7dh+2oi3ugJ9chrWcmUgWrBlLC0t7YTfz+NFJALgSLV+R8p7PVi5Fu6g/6+IQYMG8fHHH0f6NCKCSFagt5ZEuCzLEVn3ZH3Xa2trkWUJn9eBb+9WKuOTMKRnEdt7ENWrlxB73RjEKBM1ny7BX1GL9dtVWBf8wvXjHmeNYR9JT96Cc2su9YvWKvM8JAl1ciz+8loAqvPsaI1qvE4/yM1tWkIi+jPKYNEjPdGboSEODT7+SL43mhTP85B4HvArPB4S5WW8Dj9eh5+oJD2WNAMlO2pZPScXKSATnx1F/+uziUo3svjbJVxz6Q28d9+zBHwSap2KTmcns+/HEsxn9yHpH1ci+/x4DpdS9ckSXFtzkJ3ukL8qshKka9slo+vaHn3nDHSd26FJiW8200QdHwNyAGSZDz74gBtvvJH9+/ef8Ht5IhBFEa1WGxEBPRLBfiQS4aBY7bVVoJ88WjuPR1JADzePS5IU9u8lUJ5rQkJCWNe0Wq2YzeaTel/r6uqR5QABj4vynxdgSO+AKT0LQ2oGklnCcs0oat79Fl9eKfZV27Gv2Eq3USOpvr4d9Rf0I1HuS9U7C3DvycO965Ayx8SpfF/WHHIiiAIqjUDAKzW6pokNIvqsmTz5hCKir1ixopm9WsgTvamWfAxdOVi41lQ8L68sb3af4DFrC52otCJZA+LJ31zN+g8PIEsyeouGPldm0XlkKuvfWsffRlzNF2N3Upiv2NAIKoGY68dg7t8dTUo8sizjK6mi5vOl2FZsQaqxHVVdroqzoO/WHn2nhpg8KxVB0/g+CVoN9UvWg6hi8+bNREdH4/F4cLvdrSIpHYmqdwj/DBWNRkMgECAqKqqNy08Sp4LH/1QCeiAQwOl0YjAYwk7WQeKMROAdbuKMxMbE5/PhdruxWI4eiPFHMW7cOOrr63n//fcpK87HVXQYhS0VZnRu2ouxVyfirhiJoNNgXbKezNxqvG4361//D3JAQpMaT8zlw/HbnNiXb0GyKl9KMRkm6suc+BzByd00qwp3Od1MnTaViRMm8tSTTzFjRmMl+vEgOzs7JJ5/8+03yo0Nw0QV8VzZBGgtAj6nTNkeK7IkY4jR0uuSTOrLnOQuL+XgaoXkK3sIPPrYI+wRfqHrqDSSu0ZTnW9nw4e52MudsGQ99T9uUNZoqLTTpCWg79oeXed26DtlKJO9fyVZpY4xI5qNOEvyEdQaZEkiJycHi8USdpE1Uq3fkWgZ0+l0Ya8eC1q4REVFkZeXF9a1/4o4ePAg7733HocOHeLll18mKSmJhQsXkpmZSY8ePSJ9eqcUkQ68w+1hGglO9Xq9yLIc9nVtNhuZmZkn/PjExETmzZvHjBkz2L1nD5Wrf2w2ydOxaS+WcwaQPvnvqJNicew8SO373zOgT1+eeOopyg4dQjQZiBrRBzExBtvCtfgrFPFcH61FVIOzWuHmo21ZjkNEl389QW40Gpk4YSIOR3PbFkFoHFomS4Aa1GoRW4UbW6UbUSXQfXQ6pngdOxbks3j6dkSVgCiouOPmuxl961lYzpBoPzARt81HwdZK7Ku3YV+1vaG6vEmQHW1qEMuVpLcuOw1R99s+xZp2SXjLawBYunQp99xzDzabLeyVa5Fqw3a5XGFfM9zPM7g3MhgMbUF3C6C183gwER4JUbnNiu3UwW63n1Q8DrBkyWIef/xxVqxYQc2W1bBppfIfDXZsxj5dSLzjUnTtU/HX1FH51jecOXAQy5f8RMXnnyvWor07YejZEdvKbfgOl4aOHZdppDrPQUA+ekCooBLYsb15JfqKFStCjw15oqubxInHoHNZOkI8ryhvVswWXFMANCYVnno/h9ZVIQdk0s+II+usePb+UMza93JZ/58DSH6ZLUO2cNE151Jo3o7OrObLRzYgq0Uq5n6J51AxeH+lgK1LZigmV0X/th++JlXRjFR6A2VlZajVakwmEzabLayf09ZipxKpQro2W9WWw6ng8T+VgB4cLKTX68MedAfF0NZQDR4pj1hRFE/KNkYURWbOnMlDDz1EcnIyAOroOPy2OpADWL9bFSIldVIs+u5Z9L78Igp1ARLuvpzqeYvxlVZjXbASJAnBqEd2ulHpRGoLHc0I9kgClSUZt8vN1KlTmTixoRL9OEX07OxspkyZ0qzyPLQhaPgZDL59Dhk5AMldLbhtXurLXGycdzA0JTzjjHi6nZtGx0FpRKtiKF1nZ83by5EluZmFi6BVY+jREV2Xdko2u2P6MQeUyH4/vgor/vIaXPkVuHfm4CsqR7K7ICBRs2F5s/ch0lng1pBlj0TrdyAQwGw2t7V+nyRWrFjBBRdcwJAhQ/jll1945plnSEpKYvv27bzzzjvMnz8/0qd4SmG32yPqgR7uADhSnBps8QwnWqLK6frrr+f6668nJiZGacfVaJWg26t4eFfuV+xYRJMBfbf2dLv0PNCocY8djfb9b/AeLsG2YqvC91p1iLvddd6QpzkyjT9p5HRBJRzTzuVI/Jq1i9FoZOJERTyf/dxsfD5foz1b0zVlEGQBv1siKlmPPlpDTZ6d3QuLGoR2iM000e3cdDoPT8GurcIiJDH/4a8JeOSG2SpAQAa1iK5TZrMgWx1/dOu9LEkEam34KmpwF1fg2XkIz6FiAlYb+ALN7tu9e3f0ej2yLOP1esP6mYnU/qG2tjbsa4a79VsQBNRqdch/PdzJkb8S2ng8chYukeJxrVYb9u73SBXvnSyPn3766SxevJhLL72Ub75RCsLU5mj89joQRar/s1BJRKtV6DqmY+iWRdc+vdmQqcNUdjqOtbtwbc/FtTVH6Qg3aAi4fAgC1BQ4gUYeVqrKG7vDEY62c2kqogPIAek3Va6Q53nQtqVJ11lTj3RZAE+9H41BRVKnKKry7BRvq6F0Zy1SQEYXpaHrqFS6jEwlJitAbGE27z39Hzz1fhAErB8ubCxgS09E3zUTXad26Du3Q5OeeMwCtoDdhb+8Bl95Da59ebj2HCZQZUX2eEN7moDTTnRaOtB64tTWNEOlzVa1ZXCqePxPJaAHMyw6nS4iFeiCILQa4ozUmi2xkV+0aBEAgkpN57ufQhBEyn/+huoNyzEMPA33zoP4K2qxV9eROvBcdm1aQtX336Lvkon+3EwkAezLtxCosCKIAgGPhN6iwe8L4HdJzcXz4O8iICnP40RE9CPF85BgLger1eRmwX5w01B5sB7JL6PSinQckkx8JxPl++op3FxN0dZqlqp20fPli4nXpXFYLCG5Wwzt+sST1iuW1W/txxmVQsq4mwGQnG6FjIsrcG/ci+dwieJ/7vM3iA2C4rsWaB5oC2o1mqgYvLVVzJgxg06dOlFdXR2RyiqtVtsq2tRUKhWSJP3+HVsQTcm6Ldt9cnjiiSd45plnePjhh4mKahzYO2rUKF577bUInll4EMnhY5IkRcyvNdxrRmLwWEutK8sydXX1ALS/6nZM7Ttjzz9AwSdvYDyrJ+59+UhWG86t+0mITuNQZg5lU95Em5VK9AWDIc6Ce+NuPPsLQ0ljlUZEZ1bhrPUdnQRvasUi8JsiuqgWmhbFh9BUPG9aeR60XpMlGrvXmnil2ys92MrdIEBaz1iyBiXiqHWTu7ycte/lsPa9HMRbs4nVJRPwyMRkmDBEayndXUvCHZcSNaIvgloRYGWfH19FLc4t+3Fsz8W1J49AVS2y29dYNa9SKRXrTaroBY0a2ecHBDIz2/HSSy8Byvd+uK/f1tL6HRTNJUkKu3eqwWAgEAiEfb/0V0Ibjzd2koV7vke4PzPwv8+pxwO3201sbGyLHGvPnj0IoorYfkNJOedSZFli3wtPospMQvD58JVU4dlfgK6inrj/M7LhsefxmLSYh/RGl5WG60ABzo17kTzKDBFZBkOsCle1P5RsDvGx3Pznb4nox+LwII4cGBo8ZlPhvOmwcATwuQKU7K5DlmQsqUY6D09BYxTJWVbKzu8K2LGggJzTndx/3wN46v2IahH96V2UpHfnduiy0xtnkUkSgZp63HsP48otwLUlF19ZJZLd3WTgd4MeFWjyRFSiYufilxBkmby8Q0Dr4dRIFdJFKiZvs3A5eZwqHv/TCehGoxFZliMmoIcbPp8v7MM8I9Xi3lIBWmPQ6if39alo4xLxWqsBiBrcm7jLR6BJjkP2B+hs6s7SjeuQvX5cOw7i2nWokZxQhGqtSYW73oeoFhqOe4R4DtDke/N4RfRjVZ4HhfOmhB3cEIgqASkgozWqMcRocNZ58bsC5CwrRVzZWF0elWygXZ94HLpqrnh0FCM7pOKyeqnIs7J3cQlVB22AjUM3TAhlv48VWItGPerEWDQpcaiTYpXfE2NRJ8VQ/+NGXOtzyLhsLIfeeyFk7RHMAkdiaEkkvMGD11y4IAhC4zUSJgQF9LZ2sZPHzp07QwJdUyQlJbUKf/kgl0diGHgkuNzn84W1tRMiE+z7/X4CgUCLrOt2u0Pfc/mfzEGf0i5UAWbs1YmYMWeiTo5HNOro6bRw+GARqES8h4rx5pc2aYFWI3n9RCXrsVW4cdUf4VkuNPLtkVz7ayL6sb56f008D0FozIDLkoygFpD9SkeYMVGD3ynhdQQo2VlL2d46JL9y/lqTmozT41BnuRjQfRCGGy8CGWry7Xxw8wpqF6yg5rOfkByuxkBa1TBgTGoukKvjo1GnxKNJikWdFKv8TFT+AeTfMR2V0YTT6Qw9rrV4g2u12ojwOBARLg9+RsPd1v9XQhuPR26WSbgrTCEy8XjQiu1/eXBpwB9AliVqNq7AfmgfmqhoZL8PbYwZy5gz0STHoU6IpkNtgLLaapwEkBuK3OwrtioHUauQJZm4DmZqC+y4qvyNSekGNIvJm+D3KtGPxDHF8wYEE+zNbFVlZc+gj1ejEkTc9T7qS51s+Twv5JEuqgVSesZg6SORkJDA6Pv6seRfm4m5YiSeokqs36/GW1BOoN6u2LiAUrAm0FwgFwRUcRY0yXHK65bYnMtVMWbqF62j+qNFyCi8Bq1HQBdFEbVajc/nCyuvtcXk/7s4VTz+hxlx7ty5PPbYY9TW1oaI1G63Exsby5AhQ1i+fHnovsuXL2fkyJEcOHDguIZGOhwOTCZT2CfdAhFrc4zEupFojWvJYP/222/H4XDwySefsH79epz2eiV4FaDi5U9D94tKjCfprXcoFr3EXDoMdWIsfq8X1/rdeA4qXmSiWsTrUCqug8I00MwG5deez7FEdEHV/L08lngONLOLaVa9BkgNGwS/N0BdiUK0Gr2K1F6xpHaPwZSgp77MQcGWag6sKmO1djO9e/Xm2Wu/QVSLyJLUfNOhUTcI5PHKz6RY1IkxIUIOZsSPBXViDH6HDZVR8WRrKqBHovVbp9OFPfAWRTHsxCkIQkSy3bIsYzAYQnZaJ4Nbb72VDz74oAXO7H8PMTExlJaW0qFDh2a3b926lfT09AidlYJwcbler8fhcLQKLo+EaB8pHg8GMCcLg8HATz/9yHPPPcfKlStxlBUCAogCVW9+HbqfoFGTPmsWy6oriD5vIOrkOESdBsf2A7h3H0SqdyKoBGwV7tBIlMaBY43BLxztiQ7HFtGPGhj6e+J5w7Gb7hvk4E8JHOVeZEk5n6Su0WScHkdUsgGf10/RlmpK91pZWLCSMS9dxb9GLkYiEBLxA5VW5ReVqATSyXGok+PQJMagTlSS3prEGESL6TevQbmhlV7UaJt9v0eqiizcAWEkAuCgABgJLhdFEZVKddJc3sbjrZvHExISItJJJsty2AX0SPG4SqX6nx7SunzFciZNmsTy5cs5fPgw3upyUKlwbtmPc0vDkGpBYMDNN5DXScR8Vi80yXGoos14C8qwb9xLoLwGBKgtcCAHUBLfvyKeh35v0rX9R0X03xLPQ2s17VhrkqT2WgNIASUmt6QqBWyxmWY0OpGS3bWU7LKydt4eSgaWULVaBlGgZOKbR3V1q6LNCocnB/lbicnVSbGo4ywIv7NnVsWYGwoBG69VvV4fEYuycMfjEDkujwSPu1wuzGZzG4+fBE4Vj//hb+yRI0dit9vZtGkTZ555JgArV64kJSWF9evXN/syXrZsGZmZmcdF1ECIpCMRAEdKQI9Elv2v0Bp3//33c//996PR6PD7vXS662lKli7AmbsTTfsU/JVWslLTqaiooHz5BiWqbprlFZX3OrVHDPUVLuzlrlCAC3Iz8fzXst7HEtGbXkO/Kp7T2OLd5JZGj7cGyLKMoAYC4HMHKNhYRdHWGmRZbnY+eYcPceWVV9BxWDIx6SZi0o3EpJtY8OQm9IN6kfSPq37ztZRlGfwBJLcXyeVB9nhDv/sra5G9Xur2bgGgsrISUNqZNBpN2Fu/I0FikSLrSIj20Ng21hI4//zzee+99wClmqlLly4tctw/O6677jrGjRvH559/HkqGrF69mkcffZRbbrkloucWLi4Pckxr4PJIifbh3ju0pBUbKC2Uo0aNYsCAAWzatIm0i65D8vsoWzwfdbtkpHoHOD1kpWew5+VXqSspBilw1EAwOSCT2NFMTaGTgFfhh6OS4E2C7SPxW3YuBoOBxx9//DfF8yAkv3zUujKyst1o4PeK/XVUHqhHEJon7UvrS/H5fQwc0wuHpobtX+ej65hB/C0XhCrPfm3Yd+PrEED2+JBcHiS3F9ntRXIHf/cgqFVIPm+z5xCpKrJI8FukOPV/ncub8ji0Hi5v4/HWFZNHSrSPRJFBS9rHZmZm8t577/Hmm29y1z33EH1aX+IHjeTQO88hRBkR9VoCdXY6pGaQs3UHtmVbFHW8SbwralRIvgBJ3aOoPezEa1eEalEtIvmlZjFv6PcjvlZ/T0T/I+J58PjHLqKTEVTKqdeXuthTXowgCkgBqdm5HDx4kE49urNf71cS3cGOsMRY1AnRCL+TLJFlORSHyw2xeOh3j1cpAGw4n5qaGuLi4iJmUSbLctg/q5Hi8kit2cbjJ4dTxeN/WEDv2rUrqampLF++PETWy5cv59JLL+Xnn39m3bp1jBgxInT7yJEjj/tkggFhawlGofUE+36/P9Rq1JIINGSDa7etIVBfA0D0mDMR9To6tOtInVFF2tS7kBwuvIUVOLfn4C2uRKpVvFeLd9QgqsRQtdexBoc1rWg7EkeK6C+++CIAWVlZPPXUU8cUz4+1TvBvUa0sJgWUIaLB2yzJBuIyzcRkmLAkGzDEaDHGajHG6ojSRRNjiqX9wARqCxwUbKpk749F+D0B7Ot24dx1ELx+JF9AER+CZP9rZCAKysSW0CA2gYrlPwBw2WWXhe4WbC8KJ1pLNXgkg/2WTFLodDpSUlIAwm5xEUnMmDGDe++9l3bt2hEIBDjttNMIBALccMMNjB8/PqLnFi4uD15PrYHLIxF4R4rHT0WLe02Nwt3W7etRmRSPQsvZZ6COtWAymZTB8vdcQqrLhafSinv7fjyHywhU14XaoavzHc0q1o4MfkXVb3eVHSmiB8/piSeewGaz/a543nRdQVQS4pJfBqnBAU4AU4KOmAwTce1MWFKMGON0Co/H6NCZ1XjVdnoM78i2ncr+xFtWRdV/flAS224fsteH5A+AP6BUoEny7/B4wz9Q7idDQPLSqXPn0N0ixePh5tRIJqX/17m8KY9D6+HyNh5vXTF5a4nHgVPSVVBQoAz/rtu1CbXJAoA2LQHLOQMQ9TqSe3VlT5qetDMS8NTW49l7GM/+fPyVdYpFGVCx10bTlyNodRbE0cVnzXGkiL5hwwYAbrjhBs4666zfFc8b11Uq3EWViByQFMe0hphcZ9YQnW4kLtNEdJoRc7weQ0M8bojWUr2siri0FNTecvyVVjxFlUgOB5LDjeT2IXu8yH4/cjMe59hcLjTh8dCAchkEEbVaE0qCRILHm/JbOK/h1lJIB42xRRuPnzhOFY8f17fnyJEjWbZsGU888QSgZLUff/xxAoEAy5YtY8SIEbhcLtavX89tt9123CcTSbKO1JrQJjCcDHr36sX2XTup3rAi1O8VbP92nXce9sEaSqbMPfqBogCyjCXZgEorYq914bMd/QUlqoVfjU+DaCqiP/bYYwA8/fTTfP7558cUz38LxwrwJb9MXbGT+lInwgYhVD0fDIijoqIY8/4drHw15+gA3+tHqmneKi1o1AhaNYJWg6DVIOq0CHptk5/K7YE6O87N+4jpOwTrltUMHz6cyZMnN742raSKrLWI9n+Gtf8q0Gq1vPXWW0yYMIFdu3Zht9vp06cPnZsIV5FEOLhcEIRWY4vWJjCcHO655x4eG/cEzpJ8hccFgZqPFwMog87Ouoz88XOO/l5qeP4avQpzkgGXzYW7LtBsZglwlLXar6GpiP78888D/KHK8yMhS/LRA8xkcFR5cFR5KNlZq7yOwdOSZWRJpsfsi9n1VTEb1x5UOt8cbrwHio88vAK1CkGvQWzgcUGnQdRrEXTahp8N/6fTImg1uPfm4S0oRydqyc3JaXxtWlE1VyR4LRL7B2jZwLu1oo3HW19M3lqq3oEWX/fmm29m5qzZSKJA9YbloFLh2V9A5X5FWOfF/pR98gMlGzc2f2CTlzw6zYgckLFVO5GOdAcRfl9Ah+YierBwb/DgwTz99NN/SDwPQT5awAfw2H3NOsmCir8syQgCXHNVKmaHh7r//vT7a4gCgkaDoFU38nWQy4NxuVYTissFnYb6xeuRHC583saK89aWIG4NFi6noqitNeJU8fhxC+gPPvggfr8fl8vF1q1bGT58OD6fj7lzFZFy7dq1eDyek6paCwQCyLIc1oE/Pp8PQRDCumbwAxEIBMK+brjXDAQCSJLU4mvOnDWTK6+6iqiuvZDdHhzFB4m74xL8FVbiUrLBrCe6Z6eGFigPsteP7PODRzkPXx34kFCjQ22gIePcvGpLDsi/K6IDPPfcc8yePRuARYsWsWTJkpMbciGAOUGPIVqLMU6HzqxBq1eh0oto9Co0ejUanQq9UVnjqplDQeNHrVdTX+ZkyawdJNx5GYau7UGnVkhao/7DG0TXroOU78kntf9QPHu3IIriUe+f1+sN63UkyzJ+v/8v/3mRJOmUfF5+C8HqheDzbQl89913mM2Kf34kRIRIIyUlBZfLRceOHcPucflbCAeXB6+hcA/u+yvx259tzeB3REuv+cADDzBp0iREg4nYvkOoWrWY2LsuQ7A7iXbJBCQJS69OBJweZJcb2RtQKrhcjRG2uzKAgJbgSA9BJTSK1A0CtfwHiue/+uoroqKimD59OgBz5sxBrVaf1OdXqUzTYIzRoY/WojGoUOtFNDoVaoPC42q9iqhUPUNuOo2DZftxBzTE335Zo0DeEDyHkt/HKX7UfPoj9moH6iOumdbCqZGIK0AJgr1e7ynpwPwt+P1+RFFsES5vyuPQ+ri8NfO4JEkR+Y74K/HbbyG4ViSeZ/A7oqWQnZ1Np47ZFBYWknHZWIq+/gDTsN7oOrfHV16DIcaCLisNS31WgyWJT+Fxtydk5+KpUnQRnWgAwzF4XD72LJMjkZubywsvvMDTTz8NwLPPPktdXd1JxeR6swZ9jBZjjBZDjBatUY1GL6LSqdHoVez+oRBHjRfDGV2IiYkj85GbmvG3GIzDddpGHlcfv32PtCUXn1TT7JoJBAIR4VRQdIBwfi8GtbrWoj0AbTzeAmhpHhfk43gFDxw4QOfOnVmzZg21tbU89thj7N69m5KSErKzs7FarcyYMYOPP/6YgwcPHvfJrF69mquuuipE/G1oQxva0IbwYvfu3cydOzfUjnmiuPXWWykuLmbOnDmA4rfWt29fst4dj2hsuXkIAJLTzeHbnqGurg6LxdKixz4ROJ1O7rvvvtDQlpycHLKzs7nvvvtIT08PVYxFCqeay6Ojo5k2bRrt27c/BWffhja0oQ1t+D3ccMMNbNq0ie7du5/wMY7kcTh1XN7G48eHU83jN9xwAxqNhiuuuOIUnH0b2tCGNrTh9/Diiy9yySWX8Oijj57wMdp4vOV5/Lgk+E6dOpGRkcGyZcuora1l+PDhAKSlpdGuXTvWrFnDsmXLGDVq1AmdjCiKqNVqevToQWVlJf379z+h45wIrFYrmzZt4txzzw3bmrIss3DhQkaOHHlylcrHiVWrVtG5c2eSk5PDtuaOHTvQ6/UtOrBg9erVXHjhhSCqGr3DGoaAIsOIs89m8ODBzJgxo/FBIV/vYKV5w92P1XLdBMH7/pqHatDz/IcffuDaa68lJycHj8fD888/j9fr/UPPJ5hpb9oyJqrBEKMjNtNAVIIZWZbxOv14HX48Dh9eVwCj2sSLM1/h5ltuwu/7nSylQIO/eWNG/zd9VAFUagj46d+/P0uXLg3dvGzZMnr37k18fPwfen4tgS1bthATE0N2dnbY1jxw4AB2u50zzjgjbGtWVlayZ8+e0HdsOODz+fjxxx/p169fi/kcm0wmOnXqBEB9fX2LHPN/AU8++STbt29n+fLlnH/++aHbzz33XCZPnhzxwDscXN6vXz+qqqqU7+gw4qeffqJ///7ExMSEbc2NGzeSnJxMZmZm2Nbcv38/Xq+XXr16hW3NsrIyDhw4wNChQ1v0uAkJSfh8nobOr+Y2ZdFRUcydO5ebbrqpsQpHEEKcJaqb8LjcODvkWBBEEETxmG3ZoHhCjhs3DofDwZw5c3jzzTexWq1MmzaNkpKSP/RcBAEE1RFriKAzqYnLMBKVakatEfG6/HgcfrxOH157AJ/Lz9OPTuTLr75i4/qNvzLErAmOnFUiy4qf6q+dVMPrpdFoqKqqCv3X7t27UalUdOvW7Q89v5ZAYWEhJSUlDBo0KGxr1tfXs27dOkaPHh22NQEWLlzI8OHDw+o3unbt2lDysiUqTJvyOLQeLm/jcZEuXbpgNpvp3r07iYmJLXn6v4nt27djNBrDapdz+PBhqqqqwqo91NbWsnXr1hN+j04EkiSxaNEizjnnHHQ6XYsdd9iwYezYsUOxVpPlkMWa4oUiM/2ZZ/jqq6/YtGmTcrPQ+N+iurEzWqaBx3+L/tQisiT9atx+ww03MHjwYJ577jlmzZqF2+3mnXfeYdWqVcd+wDGGjItqAVlqMrNMQOkUSzIQ396M1qjG7wngcfrxOnyU7rICcM0N1xNtjuKtN9/89ScQWkRo3PfA7/O4KChzzIC6urrQf1VUVLBv3z7OPvvs31+zheDxeFi6dCljxowJ6yDcn3/+mT59+ij2fmHC5s2biY+PJysrK2xrBrWHxMTENh4/CZwqHj/uGvaRI0eyfPnyULY7iLPPPpuFCxeyYcMG7rnnnhM6maDPj0qlQhCEUzKs6teg1WqRZTmsawahVqvDuq4oioiiGNY1g+0SLblmfn4+LpeLqK6n46kuRYjXk3zfNQgGHaJOi14yYVInEHX3Zfgra/FX1OItrsS9+9BRxzqWeN0UokpA+pW2sezs7NDA0CVLlnDttdcyc+ZMHnvsMR566CFmzJjxuyK6qBaQXMc+vsPmoqrIitgkKBdUAjqzioRsC/0v74CExD0/jgIBvE4/xdtr+PyBdSTccSnqxBhlonfTSd5ur2JpE/zd5VYGlbk8jffzKEPLgti8eUuz9y/4eQn3ZyYSnxeVShXWNVUqVdg/o8FmpOD3QxtOHF9//TX//e9/OfPMM5tZJvXo0eOEKsFOBU41lwevoXB/P0Ti8yqKYtj3LGq1Gp/PF9Y1g2u19Jr19VZEnR5L195Yd6yn3auPhDxAdSjXUdID11JXWhHicveOHAKuI9ppG4Z+ScFB2cfAr3moGo1GHnvssdDA0OCe5eeff2b8+PGMHz+e4uKj/cgFMTR+BaEhgd8sqG8IzF0OsFbYENUVoaBcEJWAPDrNQKfzUkhoF815E7tT+/JhcrZ7SH7sZiSPF8nlRXZ7juJt2d3A654mvzf8kxts6ySPD9ntVRLlgoDL5cbj8TRr5Y3E56W1cGok90mRmJPwV0Ibj4uhWSbh/ryq1eqIcGq419RoNGHXHoJ7/ZZ+Tw8dOoTL5SJlzFWULZ5P0oPXoe/WHlGvQ1CrkDXxxF0xEnOPRHyVtfgra3HtOkSgpv4oAfso8foI/FaCeezYsaGBoVarFYAXXniBhx9+GK/Xy4oVK373ufxqTO4EW42d0twqBAjpAiqtcj6yAOYBpyFGmUgZ+ASyx9fA240cLjfweLPfXV4lTm/4PcThTndDPO5F8nhC4jmiyBNPPMELL7zQ8Gf4dZ2gFZBOpwvr7IDWpj0Ef2/DieFU8fgJCej33nsvPp+vWXXk8OHD+ec//4nX6z0hrzVoFNBby1AjaD3ThLVaLR7PkRNBTg5dunQBQcRXVw0IePYXUPXed/jKa/BX1iKkt+OqadOoeOmThsytCA0VbIJKQK0TUetVaAxqJK+Eo1o5P0EEBKGZz9pviedTpkxh/vz5LFiwINRJ0HSw6FNPPfW7IvqRG4Gm56DSCsR1iCKlawzOWg81+Q7qS5246/wUba0hT+2gKLaI5674VtlsNOExx758zAkW9O1TUcdHH5ffmt9qp+DuWaRfegtVa39Cqq8J/Z8syxHx9YzEwJ3WMiDwVKzt8XhCQ3tsNtvv3Puvg8rKSpKSko663eFwRGSw5rFwqrk8yDHh/vy0pkHDfwUeBxBFFZLHjeRXBPGaeYvxVSgBtmRzUvPuu2i/WE31vn2gUikVWrIiQKs0QR5XEZACeOsCSP6G46qPrjY/1mtmNBqZOHFis4GhQQH9888/x+/388wzzxxTRD9SLD+yAl5UKYG1oAJzop7UXjGoBBXV+XasRQ68Dj9VB+zU5eejv9DCazd+TXlpOQAFD72MKjYKXccMDGf2wJCWiDoxFlF//LxrW76Fyrlfhp5vEF6vt5mYHg60lgGBQUSCy4NDU1ti7aY8Dq2Hy9t4vHXF5JGIxyO1d9BoNHg8nhbtfo+JiaGyshK/XamMrvloIeqkOHxl1QSsNvL+cS9RViuVH30JKlERzCUJBFBpBNQ6NRqDiKgFj1XCY1f2A8cSy3/tJRs7dizDhg1jwoQJlJaWhp7frl27QoNFgd8U0Y+1Xug2AfRRatJ7x2GM1VFb6KSmwI6zpnFfFF9Sz8ZNP5P3ww/KDWoVYpQBbXoSxkGnoc/OQNcpAzHKeNzfI7I/QMWrn+HYuIfa2trQ7ZGKx4FWweV/hZi8jceb42R5/IQEdJfLRbdu3ZpZgAwfPhybzUbXrl1JTU09oZMJfqG3FlE5Uuuq1epQ5jBc0Ov1zdqNThaSJHH5FVeCAO6yIuVGlQrn5n3K76JIYVUFWp2WTjdeTF37eES3l6p/f0nA4UFnUuOu9+FzBvCo/c2CbCUgln+3hfpI8fxI/FERXVA1EeuDXVwSaIwCaq0Gl9VL5f56qg/akfwSokYguXs0g27qhDFWT8fAAOr9lXQfna4E5YV2PHbl/XWt2oZrzXYlgRDMXKtViBYT2sxkDH1PQ98uEU1iDKo4S7PBZJLNAYDGEkPA5SSqyUbL5/MhSRJ6fct6Wf8e/H5/WFvFIDLEGakNAtBMPDpZLFq06IT54H8Z/fv35/vvv+e+++4DGjeYb7/9NmeddVYkTy2EU83lwWE7wa6ycKG1BPuR4nGPx9Oi30/XXXcdkqSozvV7toBKhWPD7oaKaRD0WvKKCzltzHCqL+mLiIj1m5V49udjSTFSV+LE75Hw2P1KArnJ2yD5peb8ytHv1bHE8yMxb948gGOK6MGK9qPWCf0to49V4bYGsJW5cVSWIwUU8d+SYmDY3d1J6R6NwRmPT/aScqYebX48hVuqwe8nUFGLs6IW57pdzYoAEAUEox5NajzG3l3Qd2mHOjEGdUIMovboKqmAw6VUAUrNBV23290qeDwSyfcgp/6vc3kbj7deHm9NMXkk1lSpVPj9/rDv+YNc3lL4/vvvyc09AEDV6h9BpcJfa8Nf1RD3a9QcKitm0JlnkmC6DHVcNM5tOdQvXIspTofT6sVj8+G1A+IRBWwNwrUgNHaPHcNx5Sjx/Ejs2LHjD4noTeP+YPe55JcxxKvx1ku46/0cWlMRKnLTW9T0ubo93c7LwO8O0DG6I/OXLsZwRmd8JdX4q61ItXbctXbcuw4pRQCyFOoKQ6dBHR+N/rQOmHp1Qp0UizoxBpXp6OSGoFYRcLhAlunYsWPo9tbC49D6CulaakhrG4+3LI8f9zuSlZV1TIJp3779SROP2WzG4XBEJDCMRBY4uG64NyY6nQ632/0/vabNZqO8ohwkCbUlBr/LRrtn70OdGAOiiLewAs+BQgqrK0m3+jnwsTI8gAarMXe9D71FTXS6CVEUKNtbd1QQrFSNHSFuN/z6e+J5EH9ERA8e/8gA3OeU8Lt9CCLEZ0eR3iuO0j1WKnPrKN1hZcETm5FlmaefGs6W3B3EdTBxziM9iUoy4Lb5eHHodxjO6IKhexa+8hp8ZdX4SqsIWO1INfW4a+pxb89VPOSbeMsKeg2qhFjUKYq3uc9WR8Bpx5KR3ux5hbulM7huuDcJwQqccCISZO33+xFFEafTSVRU1Ekf7/333+f9998P/V1fX090dPRJH/d/ATNmzOCCCy5gz549+P1+XnnlFfbs2cOaNWv+UPtoOHCquTz4fR/uTXakqshaC4+DUsnSUt/DXzfwpy4lA09ZEelT70STloCg1xKorsN9oIhCr4P2UXF8Oett8Dd0kYkCdSVO1AYRS4oBbZSK6gMOfM5AM8s1OXAMHm/AHxHPg/g1ET0Y0Df1SUWmyT4CvDbFUsYUryVrSCL2Mi/FO2qoK3Gx9MWdCKLAmPPGkDM4B4/Dy/njz+CrcZtwp2UTc+nZ+MtrFA4P8Xg1/korst2FN7cIb25RQ0Vfw0wTAI06VL2u7d4eX24hglqD4Gu+t44Ep0ZizUAgEBEeh/AL6H6/H6/XiyzLJ83lR/I4tB4ub+NxM3a7PWIxeWvhcUmS8Pl8Ya0gbun9w6xZswA5xOMxfxtG9PlnIlpMyC4P7gNFlNd4yU7LoGbiIiSnsragEnBUexDVAqZkPTFpBupK3NjKXc3t1mTFGz3Ir0d2hf+eeB7Er4nowT1C072CcIR1q9saQA7IqA0iWQOTUWkECrdU46zxsPXzfLZ/VUhcTBzX/dvMoQMHiLr1Akw9Oiqid019iMNDfF5aja+iBtnlwV9cib24EvvSTcpzDBa8qUREswFNu2T0Z3RGn5qIv0KpPB8wYEDjubUSHofWFZOr1WpsNlsbj58EThWPt0yZYQshKioKr9eLJElhJ+tgu2O4capaon8Ler0+7IF3S68ZHR2NIMsY2mWjS0yldstqbMu34N5fgOdQcci7O1eTTlZCMr8YtIhmE4HKWobc2ZWcZaVU5tbjttUR/E7UGFT4PYFmQrkckEEEpIZKs4BMdsdspkz+ffE8iN8S0UPVa0dk3BGVYrOYLAO1eS6qDtiozrODLJPRN57+13akpsBO0bZqOnbqyJdffsnevftZ81YOkl9GpVGelJAah+WCs5pVpMl+P74KK/6KJmReVoOvtApfZS2yy4u/sBx/YTmoRIq/+RAkmYqKCsaOHcsHH3zQogLK8SAShH2kX2w4EImq95Yk69aOoUOHsm3bNmbNmkWvXr1YsmQJffv2Ze3atWEd+hgpREVF4XA4QtVVLTmo6vfwV7I2+S1EgseDSdOW/B5OTEigqKiIxMGjKfryXeoWrkFye3Hvz0eyOQHYPWgQN91wg3IOKXEEymo47fwMXFYPhzdUUpPnCInmap2I39s4K0QOyM0C4yDPHo94HsSviejNBPoml56gUvjdkm7EVePFUe1l7/clSAGZqFQDw/7elYBfpnh7Dd26dyE35wD7lpSS83OZUgWXuxX3oRKiLx6GeXBvVBZT6NiyJBGw2vGVVzcX2EuVvyWnu7F6ff2uZl1ogwcP5ttvvyUuLi4iXO7xeMIeuHm93rB+D0FkBfTgd0Mbl5842ng8itLS0ogI6JGIySPB4xqNBpVKhdvtDquA3tL7h6FDh7Jq1SriB46g9PtPsa/Zgb+2Hve+fPxl1QDU6PUYz7uSeHMUNUYdgao6ohL1ZA1MZP/PpdjL3TirPEgBGVEjgCgje5rwq9wQM8snJp4HcSwRXW6ScAeOEtKDleZag4a6EicHV5YhSzIao4qzbu9MYraFkl21xHmyKCwsxF1ejfeFj6n0K1XmqlgL5lF9sQw9A/XIfs04IWB3NeHwavwVtYq4XtZQ8FbnwFN3CM/uPOqadKHdd999TJ8+nauuuioicWok9g5+v59AIBB2Lo+EaO/3+zEYDNjt9jYePwmcKh7/0wnoAC6Xi0Ag8Dv3blkE2yPCPZQrUmJ2VVVV2Ndsydbvuro6VCoVzsJDOAuVoaDW71YpAaIook6JI/r8wdQO6sgZgoWoihzsq7YDsPqt/SArgnla7xgc1T6qDtQT8Daf6B3KfjcR07Ozj088D+LXRPSgZ3moLa2BqNV6Ab9TxpqntGplnZmAzqTlwMoyCjdVU7ytBskv06lfBrExsYycmUX2dgPF26vJ31xNbb4dANeS9RxeuA5EAVViLJZzB2Dq1x1NajzatISjzlOWZQJWO/7y6lBAbl2wEpXJhMfn4cMPP2T06NGcffbZESPOSAT7CQlHv1anEkExOxJrtgnoLYOOHTvy1ltvRfo0IoKoqCjsdjvx8fER4fI/Ioa2JPR6fWhYVTjXbGk7lT+6bkvuWYLf50VfvgsqUeFpUQBJRow2YTqzJ+6LR9AuI5Pka0dTs2Y7kkpg9w+FytBOAZK6RWGI1lOwsZKArzlnNxPOG5LjJyKeB9FURJ8waQJFBUVHd6k1/FSpIeCDukInsiQT295IZt9EDvxShq3UxcLp25EDMsZYDb1uOY0Syw6u7DuIou3VHFpTQWVuPf7CcqrnfkE1KL7vUUaMg3oQPaIfuqwU1HEW6N7hqPOUnO6jKt5ce/Pwl9Wwdu1aRo4cyaZNm5AkKezBqNvtbmY3Ea41w/08g9dVJLjc5XKh0+nC3iX4V0Nr5/GcnJxQIjycUKvV//OFXse7rsViCfuaLYXExEQQBEq++QhEAX95DfYqqxKT67UYurbHcukIyiQ3fe6+gVXfLcJZU099mYtdPxQi+WUsqXoSukRRuLEGnzNAw/xwhccbhnU37RQXVAK33HTLcYnnQRxLRD9mFXqDDqDWibhqfbisPnRmDV1Hp1C2q46KnHrWvZuLjOLj/tDUC9B19tDp7BQO/FKG/vTOeHIKCNTUUTd/GXVfrVBeE60GfddMzOefialbFrqO6eg6ph91npLXh7/SqnB4RWMXmmvnQXJycrj+hhu56qqrWk0FutvtDvuwVGiLyf/XcSp4/E8loBsMBkRRxO12h52sNRoNoiji8XjCLqC3hso1vV6PIAi4XK5mA6xOFOedd16za8Q4qCcxfxuKrn0qsj+Aa0cujo17WLtmDpdOmYb3l+1IDieCCKMe7I612MOOb/LJX18NAqgNIjqLGke5N0SYSmW4QtqCSqBD+w5/yLbl1+B2u5n2zDQmjJ+giOgzZ+D1eEPBfoi0BQh4QFBBSu9oynbWkb+hClmChE5mzhzbhcPrK8n5uZQ0Uzb5+Yd548GFRKcbuXhyHy6Y0Ae33cdLw75HnZqAymLGk1tIoLyG2nmLqf3kR5AkBL0Wfa+ORJ8zAF2nDFRmZaCJOjYKdWwU+m5ZSC4P1i+XkzzyYiSvh7IlX9CxY0ecTmeLDp/5o69fJIgzEoF3pPzs1Go1drs97JUMf0UEAgG++uor9u7dC8Bpp53GpZdeGvZNWCQQbP1OTk6OmE93a1gzEq3fBoMBl8vVIsf69NNPOXDgQOhvwaQn/o6/Ye7ZCUGvxZNbiGPTXvZOfZOamZ1J31dBeV4JAH2v64A5Xs+2L/Op2GdDUNkBgeh0A3XFzpA/6ZEB8cmI50EERfRpU6aFRPRQ8N2k7TzgkxXe7mzCXuGhNt+JtbAAjVHFuU/2xl7qYu+SYnBosIjxjLv5M+qdVobe04UR/zyNzx9YR+I/ryZQZ8e9Lx/3vsNINieOnzbiWLZFqURTq9C0SybqgjMxdeuAOjEGQRAQjXp0HdLQdUgLnXfVB9/jWp+Lr6YKi8WCy+VCrVa3ceopXFOn04U1wSXLMoFAALfb3cbjLYDWzuM2my1i8zYiUegVCARaRSGdwWCgoqKiRY4lSRKPPv5442RPSSbu5vMxD+qJOiEGX1k1jk17sX6yiJ2Vatr7/SzZlguSTGa/eLqPyWDPoiIKt1Rjq/AgB2RMiTp8jgA+lx9ZbphNdoQ9WlA8nzh54nGJ50H8logeRJDL/V4JQ7wGo0VPdZ6NXQuKkJHpf30HotNM7PuphOIdNSTQjq//9TMHfilDiDaRdM+VqKJN+Eqr8OQU4M4pwL3nML6yatw7D+LenUeVJClV6vHRRA3vi2lAd7TtkhBUKkStBm16Itr0xMZzkmXyb5+BqNei9iv7TqfTGTF+i8Sa4a4Gj2RMbrPZ2rj8JHEqePxPtQMQBAGz2YzL5Qr7UA1BEEIkFs4LNVJidriDfVEUiYqKoq6urkUE9Ph4xZ87/bJbKP76Q4ynd8KbX0bt/J9x7TigZHhVInZJoqK2hjEzn2DRi2/gOVzG0hf3hkgy/YxYRFGkcEs1Aa8vNDg0VLXWQNpHiecNti7HC5fT1ViJ/uRTzJw1E4/bc1QLeFSSjvpSN6U76lBrRXr8LZ0DP1dQdcDO95O3olILXDStLxe0v4Kdu3dgiNFSV+zkk7vXIAVk9FHK5s8y5kyizxuEHAjgLShXyDunAPfewwRq6nFt3Itry37l9RIE1MlxmEb1xdyrM9p2yXgLywHQJaRg3bEeQVQxcOBANm3aRGxs7Em/j8eD1kSckSbrtmz3yWH37t387W9/o6ysjK5duwIwe/ZsEhMT+fbbb+nZs2eEz/DUIioqKqKB9//6jI8/ArVaHarSC6eAHh0d3WIDwTt27AiCQMJZ51C3bxu6nu1QqdRU/2chjo17kOwuxctMkvhl/VrOv+MmDiTrqP9hDVs+zQsF1FHJelJ6RXNgWQV1JS5kGUSNjNzQ/BAU0Q06A5MmTcJut5+weB7EJ//9BDhCRG8inguigMakQvJKVB90gCzT7YI06gpdlO6qZemzO0GS6XN1FldcfTlltkKwePBW+Vn20p6QFuE6VEj85aOIuWgIsizjr7Q2BuJ7D+MtqsCXV0LN3K+okZXqezHKhOmsHpgH9kDXMQPRoAS53oJyNCYLvpoqhg8fjtVqjYgHZqQ4NdxBaKR4HJRO3jYePzm08XhUyAM93J1kkYhTW1MhXXR0NDk5OS1yLFEUEWQZTVwS5uxu1B3cjr5rFvU/bcSxYTe+kirFQkyGX4yreOrJp1iY4KNo5vsUbK6mYHO1wpcGFR3PTuXwugocVR6QQWtU4XUGGovZGn4GbVsmTp5ISVHJ75+jWmw+eVRQOPr3BosKKuVBxhgdjmoPrmofKT1iiE1XRPPN/81DliCpm4WHvrySTnInPlw4R9kL1DkovHc2sgT6MzqRcPNFRI3oByi2LZ7cQoXH9+crRW5VVqxf/oz1q+UgSaDToO/egehR/dB1aqd0mwGBWhuS04Wk8pGWnobb7cbj8YS1gwEUfouJiQn7mpGYn+Lz+SJa1NbG5SeOU8XjfyoBHRTCdrvdyLKMJElhHT4WqaFc4W79Dj7PcLd+R0dHY7VaW2QK8GOPPcaixYspXTQfQa2m6s2vlf8QBRAEDH26knDbxSDJrC7MZUBUEgsOl4EAGr2K4fd24dC6Gg6tKkdQCWgMIuYUPbV5iueqLDe2e2d3aD4w9MgM9fFAUAnN7FyefOJJZs6eicfVIKLLMiq1iK3Cg9ogknpaHIWbq9g+vxBDtJrR43uxb3EpBRurWPNCPje9ls76bXO4d+EYyvfXsX9pCXuXFGMrd4EA1e98S82nPxJ75UgsI/qh65BG9JgzAfDX2vDkFuDeX4B7Xz6ewyX4y6qp++Qn6j79SRlGplZ66LzVFbiKDqMSBURRxGq10qHD0W3jpxKR8FuLFHFGYmPSRtYthzvuuIMePXo0SzTV1tZy6623cuedd7JmzZoIn+GpRdPAO9wCuk6nw263h3XNoGgfbk4Ncnk4A6eYmJgWC7wHDBiAKAhUrfkJTUw89l+2Yv9lqzIQMyChTk8g7raLMXbIYPO2w1yckIH0yw4l+BXg9Cuz0GhVbP7vIQ4sqwBZJql7LOV7apH9AoKqQUQXaC6ez24unh+L00X10TMoBJFmle3NKtEnTqCosKjxvloZr1259rPPTOTwhir2LykFZEY91J2qQw52/1DEls8Pc/NZmSxetZgr/zUQURbZ/3Mpe5cUU7qrFvvCddgXrgeViGlwL+KuGoV56OmYh54OgOT24DlQ1BCIFzR4xzuwLdmAbemmhmICFdoOKXgPl2FIyQTg9ttvx2q1hp1nfD5fRKzY3G532K3YIimgt9Qw8NaMNh5vTIS3VNfRH0Uk4vFIFdJF4rlaLBY8Hk+LfUe1a9eO/Px8XEYTgdo6SsbPDSW/RbOBmKtGYRnRj5o9edidDjJX5FDUEGOn9Yqh+3kZrPsgl31LikCGuCwTjioPXlegwea0kadvvfVWhg4d2kw8/724XPJLzeaTNK1k37l757EHi4qg0Ql4nTKOGg9J3aOxl7ko22OlbLeV7hekk5BlYctnh6jYV0/llwY2pK2n62VJjHmmJ98+vZkDv5SBSsS9NZei7a+CLKPNTifmpjGYTu+EsU8X5XQCAbyFFSFBPVjk5t6Wg3tnQ1GgAKqEGLRd2ivPIeDnjDPOwGq1Yjabw95JFqn5KZFYEwh7tb3f70cQhLaY/CRxqnj8Tyegm81mnE5FxPT7/WEV0P8KwzX/6JqyLId9qFJMTAzl5eUtcqzvv/9emcTtVq4VtBrMI/oSd8VIVBYjzi37qXprAa4dB6iLiebKf79J+/btUWe6UWlV/PT83gbhXEX3C9PYtaAIa4ELjUGFqBLwugLIcoPnedPKc+HYQ0Z+D0cOMPN4PY0i+jhFRPf6PBCAgFcirqORmoNOCrdU0XlUCo5KDyU7a/lxxk4saUZu/Wg4SYWns3XrFjZ9s59N3+7HGKfl2jlncs4jPSnZWcsHN69ANBuQ7C5qPlpEzYcLQafBct4gYi44C3V8NOqBPTAN7AEoXmvevNJGAt+Xj2RXXt/iH+ZBQEKr1fLhhx8SHR0d9sq1SA0QhfATZ6SGs6hUKmw2W4skuVoztm3bdlSXRmxsLNOnT2fAgAERPLPwoLW2fvv9/r9863d0dDT19fUEAoGT3p9t3rw5NCjOZ60BQUDXrT1xYy9E3z4Vb0EZ9T9uoHL2x8heH7nJ3Tnv/DF89cUXnHlrFzZ+fECxSZFlelyUQf76Kir21gJgjFfjqFREcqPByKRJE7Hb7cx+dha+hiHjR/JyCELjAEhRLSKqxZCtWzAKDz523rx5IMC0qdOYMHE8RYXFyuO9ENfeRG2Bg7wNVVhS9LTrm8Cu7wpZ9uo+RBGueOks9NVxJCUn8tP3y/F87UEQYPS43tz09lCeO/NbDKd3Rvb6ce89jOOXbTgaZrnoemWTcN0YtFmpGHp2xNCzI6AMF/WVVDXrNvOX1+A9UAwqEVdRHgBz587lwgsvVLoAwgiPxxMRK7bWEuwHedzhcLS1fZ8k2ng8sjweTLb91QvpIjFDRaPRYDabsVqtpKSknNSxZFmmtrYWxEZ+USXEEDf2Asx9uhGwu7At20Thwy8TqKln8ZVOLrr4ItasWcOI+09jy2d5LH1xFwCpvWJRaUSKtiiDRy2pBupLleSNHJC59f9uZeiQRvE8ZLnaJC4XAOmPxOYNiXg5IB97sKgMPo+MzqJCQKRyfz2iCvrfmMWOr4rYt7gYWSrmrDs6k949kTEpY3j+2efZsWtH6Hx02amkTvw7rh252NfvxrlpL96DRVQ88x4EJFSp8cTeMIaoM7qgy0pFl5VK9OhBwLGL3AKVVlxVdaE5MbW1tRw8eLBVdZJFas1IDBH1er0AbVx+EjhVPP6nE9CjoqJwOBxoNBr8fn9YhavW4p3atPU73AL6/v37W6RK78033wRk9O064SnPJ+vd8QRsTmxLN1L/4wYCVpuS/dZq0F03io2eai6/7hpenv0cgkpApRUY9Whvtsw7yI4vC0GGDkOSyFtToVQhRGtIjc042vNcbh50CyoBZLnZ8NGmUP6fZgG60DA01OM7WkQXzBLuOh+1eU7aD0ygbI+VAyvKEdUC50/qzaaP8qg6aOO/d27g3XfvYk/cEsYIp7Pxo4PU5Nt5//qVIMtk9FG+KNIm/x0EAcfGPTjW7cJ7uJT671dT//0qEFUYz+pB3KXD0WQkITYMNdF3zYRLhirt4hW12Fduo3b+z2ii4/DW1fLSSy8xefLksNoGgNKS3Bo8TJuuG060+a21HLp06UJ5eTk9evRodntFRQWdOnWK0FmFD1FRURQVFbUaC5dg67fb7f7LC+hGoxG1Wk19ff1J23hNnDgRAH16B9zFeaRNvhNth1Qc63ZR8tYCPAeLQ1Vs5hF9WZ2m5ur2l/Lt1wtY+65SBd//xmxsFW52f1eEIEJSFwt1xS6c1X40BhVaUceECROx2x3Mfm42Xo+vmZeqICqdX79WnYYsK9VrTdB8yBjM+7ihEn3qM4yfMJ6S0mK0Rg21hU5M8ToMMToqc+upKy5k2L3dqNhXz/6lJcx/YC1PP/00pca9/O35Pmyad5BDaytYPGsHi6YrQnnslaPQd25HoN6Bc8s+7Ot349pxAM/2gxTvnAuyhKZDGgnXj0HfPQtBrUKbkYQ2IwnLqP4ABGxOPLmFuPYepu7blSCIvPjiiwwaNIh+/fqd1Ht4vAjyeGvgVLfbHfZZMU0T4W08fnJo4/HIWbEF991utxuTyRS2dVvLXDJQYvKWENB3795Nfb2NIInGXHo2sdedh3tPHhWvfY5jwx7FH12W0bRPYcfwDlyb1oXOnTuz/NU9IEBqzxg6DklhzTv7kWXQWTREpxioyK1XhG41jL2pQTyfNIGS4tJjDvuUA7Iyx1tUbvs1hOL4JkO/jyWiG+LVOCt9CIJE1uB48lZVsXlePpkDE0jvFceGD3NZ9+4BRo/OxnOznQETElB9lsWOBfn4vRKeQ6UUPPgiSeNuJvm+a5D9fly7DuHYsAfH+t0ESqupevlTqgISYrSZmKtHEnVWb1QmgzKP7FeK3Oyrt+PNL2PlypUsWrSIsWPHntR7eLyQZblVWbGFe+8AjcPAoU1APxmcKh7/0wnoCQkJVFdXk5mZicfjCTtx2my2sK0XXDMSrd9BP/JwZi0tFgter7dFgophw4axcOFCYnv0pbTwAIfvmIHsbRjIKctoslJIffQmZEmm9otlzPt2Oi+/9BJftE+n//2pHF5XzY8ztiOoBBI6RmFO0JO3WhmoEtfRSLSczJTJU5j/xdEDQ5sOJfutanRB1eCHekQiXJYbfNwCMu6Am2nPTGXC+Ik8/fRTTJ8+A1OCjoBHomBzNZZUA9lDYtm7uJjF03bQaWQKQ/7eFUtOFwryC5l23ftkDkzgjs9HUbyjhk2fHCJnWQlFW5UqvIp/f0Xy/dcQe9lwYi8bjr/KimPjXuzrduHJKcC5agfONTtBBl3PbOKuGIm+ayaCKCIIAprkOAS9FkGtpuPfx1Gz6Rc6xusjQib19fVhr4yOxAZBkiQ8Hk/YA2+Px4NOp6OqqorExMTff0AbfhUzZ87k/vvvZ/LkyZx5pmKZtG7dOqZOncrs2bOpr68P3TfcvoXhQEJCAtu2bUOr1baKpHSw9dvj8YS11TIqKqrZtRQOCIIQ8kFvCQH9h4WLMKa3x1dXRcmkNxEMOmSXBwQBwWwg8d6rMXbPon7xOhbdO4kLZj/HeeedR4VlH4mdoln60k78Hgm1XqTn3zLY9lkBCJDcLRpbvo8J45WBobOfm43X7W02rBuZZp7lwd+b4shKtmMF7YJKCIno06dP5+mnnqaktJjEztFU5NThrPUy4NZstnx8mFVz92OM0XDTu8PI/8ZN7569ufv2u3EFbIyddzaCJLLlszy2zj+M1+mnZOK/EaKMJN5/LebhfYka0Q/J5cG5NQfH+t04t+7Hd6iE0lkfKBVtybFEX30Oln7dQ97nqigjxr5dES0m6r5dSfrfbkKz/RckSQp7YFZfXx/2duTWZMUW7Cxt4/GTRxuPK/G4Wq2OCKfqdLqI6ACRsFOpr6+PiK1qdXX1SR+nZ8+eqFQiqug4DGlZWBf8gn3dLvzlNYodmwCWS4cTf8UInFtzKJj1AYvHVHPdddcx55OXOe/x3iyZsZ1Vb+4DGfrd0IFd3xRSedCGMV6Hz+nnxmtvZtiwYUwYP56SktJQN3jjvLLmw8KDRW2Kh3lzBGedQaOnuvJHExH9qScRBFi+YgUZ/eIp2lRN3qoq+l+fzf6lJRRsqKRgQyVXvnIWRRtquXzo5Xz0zqesWL6cS2cPYOQDPdj5bQFLZu0Am4Oyp/8NIsReeQ4xFw/BeEYXEu74G+79+YqYvnYXAauNmne/p+btbxEMOiwXDiZ6ZD/UCTHKeTcpcvMeLkH0qJHcLjp06BB2nnE4HMiyHNbPJrQeK7agS4TNZiM6OjrsHXt/JZwqHv/TCeipqamUlJTQpUuXiPiRV1ZWhnXNSLV+x8TEtNggsD8KtVpNTEwMlZWVZGZmntSx5s6dS/usDpQu+gxUIrLPB4KA5bJhxF8+koDNifWr5dQv3QSAHZlFixbxyLiHeXr8UzitXgQRLpxwOstf20t1nh1DtAZLqhGzP4EpUyYz/4svFM9zDSAdEXQHjiTrowNvQWgcSq7cQEhMb1qx7nK7mTptKhMnTGTCpKeZNnk6ogFSusVQuqcWW5mLC6eezi//2s+BZWV4D2p54aVxfLPvfYxxOgo2VvHswG/odl4ql80eiKPGwwc3LcdW4cabW0jhAy8i6DTE//1Sos7sRfQFZxF9wVkE6uw4Nu/DsW4Xrl2H8Ow8SOnuPJAkNFkpxF11DoZeHXHtOIgxIxtRrcGRf5BeI6+nc+fOJ/X+HS9kWaauro7u3buHdd3WZhtjNpspKSlps3A5SVx88cUAXHPNNaGAKGgJcckll4T+FgQh7MO5woEgj0fKoiwSrd+ReK4xMTEUFhaGdU1QhnhXVlaSlZV1UscZNGgQOo2Gmg3LlRtUIrLLg65XR1L+eTWCQYftp40UvP45ksMFMrzz/juMe2wc09+YwKL/bgNgwE3ZVOTUh8TzLuemULS6nokTJ+LyOpn97GxQBUKJ6yNFdGjg8KZDxo4BUSWEBPXmx1Bu+/QLRUSfMWs6Tz3xNMU5xXQ7P5V9C0vZ+P4hht/fnUOrKijcUs2nd65lznuvkePfiC5VpmaXj39fvBRzkp7b5o1iyN+78uKw7xFNBqR6JxUzPwBJJmrMIOKvORfz4F6YB/dC8vpw7TyodJmt302gvJaaOV9SE5AQLSYsfxuBZUhP1LFRuHYeQNTpkDxuevXqhVqtDnsleCR8191ud0iQC/e6kWo3b+Pxk0cbj6fi9/txOBwRqZCOlJ1KuAvpoqKikCQp7LZL8fHx7N+/H0mSEMWjZ34cDwYOHMjatWvx1lSCSsRfXoMYbyHx4esxZmfg2pZL8fh/480vBUHgi++/4ZXZzzP6wnOZd+dXCKJAYucoOg1NVbrLBOgyKoWDv1Rw8423cPbws3n6yacpqyhVFgzy9hEFbUfG5UfSm6hqFM+V+yg/g48TVAK5h/cwc+ZMnnryKQRRYPnyFZx2YQb7fyph82d5tOsTR7fR6Wz8+CBfPLiOfzx4F7pkmZqoPGQZFjyxCUGAq+cOJjrdhMeSgGg04Nyyn9rPf6L2vz+i7ZJJ8j+vwtC9A4buHYi/5UK8h0pwbNiNfe1O/BW11H21nLovloFGRdSIfljOHYg2MxlkGdfOg1g69cFQdojo6Oiwc2pdXR0Wi+Wkr5vjRWuxjQnqAFVVVW08fpI4VTz+pxTQS0tLI1JFZjAYwk7WarU6Iq3fMTEx5Ofnh229IFJSUigrKztpAf2ZZ55pZL6ARMozd2Hs1I5AnZ2aT5ZQt3hdKKhNuP1SjKd34pNp79GvXz/OHXY+OZ5NpPWI5Yep20GAzsOTqTxgaxDPp/DlV1+wYMHXxKYbsJa4UetF/O6AUj3etPo8GHDLSla7KZqSdNPAG2jwXhPQmlR4HQHUUYTsXKbMmMTEJydTfdhG36s7sOWzPH6YuJ0x43tTdcDBdf3u5puvv2XJplXc8+15bPviMKve2s/+paXM7r+APtdkodKpMfbvhvmsXtQtWocnt5Cq176g6l+fYzyrFwm3XIQ6xoxlVH8so/ojOd04t+xX2sO35eA7XEb5S58og0sAY+de+GxWqCqhZ48eJ93yd7xwuVz4fL6wV/lEwsPU7Xaj1WojsjHR6XSUlpa2EfZJYtmyZZE+hYiiKY+HO1Gr1Woj0vodiWA/JiYGh8OBz+cL6/4hJSWFgwcPnnTgnZOTg8fbuM+LvWoUMX8bBrKMbdkWauf/TKBOGQhrGNSD5LuvIOeN+az8ZSVXn3szh/fO4JJp/Vnw1CZcdV5MCToy+yaQv6qWSZMm4ZXdzJwxC22UiL3Sq/A1Te1ZjlFR/mveqQJHi+cNx6DhJZB9MP+rzwCY9ewMnnj8KfYtLGb4Q91Y9XoOv7y+j8z+cVww8QwSC3pRX+Fg2sSXue3L4VTts/PzK7upPmTjlXN+QKVRTjZ10h3ILg91i9fhWLsL2+L12BatQ52eSPL916Brn4qpXzdM/boh//1SxSt9wx7s63Yh1TuwzluI9aPvEfRaZIMWY0omjsM5DLzxKnr37n3C792Joq6ujrS0tLCuGeyuCneyIFL7hyCPB6ut2nBiaO08bjAYiI6Opra2Fo/HE/YK6UjE5JEopBNFEYvFEhoGGS7ExMSgUqmorq4+6W6VzVu3hX5XJcSQMeMeVCYDrt2HKJnwbzwHikAUUCXGkj7tLhyb9jJnzhzuv/9+FsUv55wZ3Vn37/0h8XzI3Z1ZPTeXsWPHMuKc4Tz5+FOUVZSiUov4JalZ7H1kcVszHHG9SlLzOJwmHeEAKo2Iy+bncNV+ZsyaoYjoKoFli5fT65J2FGyupnBLDWV76rjxraEc/MTFsAEjePgfDzPwwXTOvLUTy1/bS87SEj67aw1yQCb2svOJHdYHf5WV+h83UP/TBrw5BRQ+8BKCXkPc7ZdgGXw6uo7p6DqmE3vdefiKK3Fs2I1j7S68heXYftqI7ccNIAjoe3QgUO9A1GgYMGAAsiyjVodXzotEIhwiN8sk3B3hQR2grKysLR4/SZwqHv9TCug7d+6MSDVXpKd+h7OtNSYmhh07doR9Q5SSkkJubu5JVwfu2qUMHEkYMpqq1UuQrQ3C+Q9rkAMBkCHmunOJvXgo9YvXU/jwK8g+P3PffoNJkybz0gf5LH1hGwAXTT2D5a/sJSU2g6nTpvDVgi/56quvadc3joJNNai0Ij5noDlBH6NS7dd80KEx8BZVAhIySKAxqPDY/VhSDNgq3GSdmaiI6JMmMv25KTz96CS2fXWYi6f2ZeEz21gycye3/fMmkrNjeXbON1Tm1fHCkO+4/PkB/HPRGNZ/eIB1H+SybX4+siRj7mzCdFYvzENOx3O4lLrF67Cv3IZz7U4K1uxEFW8h7q7LMffqhGjUYx56OuahpyN5vLh2HFDIe+NeZLcX56Hd5L6+kyFDhuB0OsPetmW1WomKigprRSlExsM0EhsEUJ6r1+vF5XK1EfZJYvjw4ZE+hYgiNTWV8vJytFptRDg1yOV/9dZvnU6HwWCgrq4urG2t0dHRqNVqqqqqSEpKOuHj7N27FwBzp544C3ORHG7sK7dT89lPBGqUtkp9746kPHwjnoNFFI17HX9FDe/tOsxbH87ltsdu4F//eA+AXn9rR32Zh4LVtUyePAm/ysu0p6ajixFxVCsivSFai7veiywCDZa+ig+6wt+/NRS8qbiuVKoBCBgsalz1fmI7mLEetqGP0fDfzz4FGWa/MJNxjz7Jipf2cdG0M1j9Zi4FG2vQ2+O5Y/rfeOXjWXgcPuac/xPdR6fy9/nnsHdxEcv+tYf6EmWAd9V735H66I0k33cN/psvxLZsE/WL1+EvrqT4yTmgEom9fgzR5/ZH1GpCA0Xjb70Iz8HihiB8J/6qOvD6cNbmYjKZ6N69W9i/5/1+PzabLSIV6OGuPg9asUWqWq4tEX7yaO08DgqX19TUAOHfm0aqAj1SfuR1dXVkZGSEbU1BEEJFbScroPsaEuGm7K74fFZ8RRWUf/oj7r2HQRQRo80kT74djUZD1Ztf4dyyn2ogt2QPz7wxnkfuehK3zUdUsp4+V3Xgl9f3MnbsWM4ZPZJxjzxJWXkp0Wkm6kqdxGaasBY50UWp8dj9R1mlNrVoaRanN4nbBZUyhFNG4X5RIyD5ZMSGuWW2Ug+FqoPMmDmDp596ClEtsvTbn+l2TirJXaLZv7SEz/+xgXc++TfrDiylrLyUBU+WYozTcPfXo6m5vQvLXtnN4fWVWOd8ifU/i0iZeBtx148m9qpR2Nftom7hWryHiqme8xXVr3+BcXAvEm66EHVsVGiOSewVI/FV1ODYuBfHul14cgtx7zoEgkD1+mUMnD6dvn37ntR7dyKwWq2kp6eHdc1IWrGdrF3hiazZVtDWMjhVPB7eEsc/gEi3fvv9/rAPSzGZTNjt9rCuGcxyh3tdi8WCVqulqqrqpI7z6aefgijiKDiIymSm/PmPsX67EtnnJ+riIXT4eAqm07tQPP7fVH/4A7LXB7JM99st/PTTEi4ZdB06s4br3xzCj7N3kRKbwbRnprLgh6/54vOv6Dg0iYLNyqbRnKhHUAlEpekQVAIas0KwR4rox7JxAYXMVVrloyYFZERBebyoUX66bV5EUSBvdQWdRycxdcpU/E6Y+co01IKG7ydv4ca3h3Javy6MHnwxMyc9x43vDWbI37siiAJfj9vEm1f8xKCxnbh34Rg6D1eqw+3LtpB30yTqftqItn0KSXddTvu5TxB30wWoE2IIVNdTOes/5N00iepPfyTgUIZViDotpgGnkXTv1WS9/RQp424BSUZQqxkwYACLlywJtb2EC5HKdttstoh4vIU72JdlGY/HQ01NTajqqA0njkWLFrFq1arQ36+//jpnnHEGN9xwA7W1tRE8s/Ag2Pptt9sjEoxGooMtEjwOiphttVrDumbTwPtkcOmll2IwGHAW5GJIy6Luu1VUzv2SQE092k7taP/20yTfdy1V731H6bR38Vcpn50Rj3Xl4wXvc2bGeSQmJHHVq4Mp32+jcpeDyVMnI+n8TH5yKmoTStJbhvb943HXezEn6SAAuig1gkpAbRSaWa2JaiFUqd4UckAGUfl/rUmNHFCK25xWHyq1QG2ejfjsKGzlbrqOTuOTT+fxwzeLePbFWWRkZvD9xG2cdXsnup/Tjn/ceS+ffvwZmRcbuOKFgRhitOz7sYzZ/b8mPsvEPd+cx+DbuwDg2ZPH4dueoeyVTxENWmIvH0Hm64+R/PD16Lu1B5+f2o8WcviWKZRMfw9fqbK3EkQRfed2xN94Pu3+9Sjps/9JzCXDAOjXrx+FhYW0b591Uu/f8aKurg6dThf2ADgSAzUjZcXWZuHScmjtPA6QlpYWsWR4JHQAs9mM0+lEkn6jIuoUIBI8Do1d4bL868njP4LhZ58NgMYSh7ewnJJJb+HeX4BgMpAy427az3kc79ZcCh9+Bee2XAA6DE1gbcli9I5Yzuw7hD7XtKfrOemKeH7rWM69cBTjHnmS0tJSOp2dSl2Jg5gMA7X5DkDGXecLiefK0FBAxREWLU07wcXQYFE5IKPSiogqAUOCGlkCSzs9PneArMGJyDL4PQEOFuUwfcYM7rz9TkZfeA77lpbiqndz7qO9uPmWmynKKWXFxiXcMX8UqT1icFR6eWHId+T+UsoNbw5l+D9PU4ab1jsoffw18h94Ab/VRtSwM8iYcQ/pM+7BPPQMEEWca3ZRcM9sDt/7HPbtOaH3RJMUR8xFQ0ifdheZc8eRcMff0CTHEWWx0K1bN848azB79uw5qffveBC0VA13TB4caKzVasO6bqQGkAcT4eHu2Pur4VTx+J9SQC8tLY1I5jnY+h3uwDs4CTucaNoyFk60VOCdmZlJSlISrsKDBByKaGEa0Y8OH00m/spR1HyyhOIn38CbX4YqNYF2/3oE0aDls3+u5b13PiQ2MZqpc57gs3vX0i41k2dmTuO7JQv4fN4XdDgzgaJttQiCQI/z06grcWJJ0WMr9qDSCPjsMiqdCDLoozWIagGNsXlltCA2BOGCQuYagwpRLRCTYUIKyESnG3HX+0g/PQ6fS6LraCXQ2bOwkPbD4pg6ZQp+u8yzr09Ho9ay4L7tPPnkOFbvWMbeXft5efgPZJ2ZyO2fjSS5azS2cjcvDP6OrV/lIWpE1NEmTMNOBxmq3/2WvJsmU79+J6JJT8xFQ2j36sOkPHELht6dICBR980v5N8+ncKnXsdzqLjxeajVICpm7h1uvI+Bg4ewcdMmli5delLv3/EiEmQtSRL19fVhF5Mj4bfm8/mQJIna2lpSU1PD3ur+V8Njjz0WGkyyc+dOHn74YS688ELy8vJ4+OGHI3x2px4Gg4GYmJhQ63e4g1G9Xh+aXh8uRILHI7luSwXeDz30EJLXgyNvPwDqjCQy544jfdqduLblUPjgS9hXbgW1ipRn/oH+tCwWTt3Gok+Ws2rNLzz35nRWv5KLvcjH1OmTQe9nwqOTQS2T0i0Ge7WH9NPjyN+kDEvz2AINnWRKEO13Np6/xqhSbNqafP+pTQ2/NyTMJb+MqBYQRIG4DlEIgkByd4UjPE4faq3Inh+KGHZvV+bNm8f3Xy/kuRdnkdm+HYun7eTmK/8PfZyKr77+ko//bxUHVpZxzzfn0fvSTGQJ3rtxBR/euoKqPBvqGBOx15yLYNDhXLebw2OnUvH2ApBkTAN7kDbxdjKevx/LuQMQtBrcOw9S+NDL5N0xnbo125VuPBq6MtqnoOuiWOcNv+JatuzNoaqmOqxDaIOJ8Ej4rkeCxyNhxRa0q2mrXDt5tHYeh8jG5JFIhBuNRkRRDPtw7iCPnyyfHi8SExPxeDwn7fs+f/58EASs29YCAug0JI+/nQ7vPI0KgeKn54aK2WKuO5e4my8gb1UVS17ezJw5c/jHfXcTr05j07yD3Pp/tzL6onMY9/ATlJaWctbfO5G7vLShG1xCECGpuwVBJZDQxYygEjDEa5QucIlQAlxtbDIYXAApICkFcCgV6H6vhBSQ8dkl5ICMu8YHwOG1laT1jMVe5aHj0CT2H9jDM9Omc8etf+eCy0ZTuKUWfX4a5180mrc++Dfbvipg3p2ruOntYYx+8nTUehWr38rh2UEL2PTpIXQdUkl69EY0qQkEymspvO8FCh9/DX9NPbrsdJLuuUIpbrthNKo4C1J1HRWzPyLvxolUf7KEgL1xL6uOicJy7kAEvY7B519MYUUVlRXlvPHGGyf1/h0PnE4nfr8/7MPAgzpAuPcPkfJAb+skaxmcKh7/Uwro5eXlaDSaiNqphBOtMfAuLS09YVFlx44dpKamhkR407AzyHp/Isl3XoZrdx6FD79C3XerAUh69HrazbyHmk9/RHJ5AbhwWm+WVXxGvLc9d915NzNmT+eHpd/yyQefk9ozBrctgMfuo/uYNPYsKQUZtEYNgiiQ1D0KQSUQn21CEAW0Rg2SX8bnDDS0dCsQRDDH60MV6j6XH8kv4/f6QQaNXgQJ6ssciKLAnu+L6XVpJlJAprbQTmJPM5MnTcFnl3jhzVlMmTKFzb/sxNpjH+c+2gtBhHl3rGL9B7nc+tEIzn28FyqtyMrX97FvSTGWS4eT/I+ryHjhfkwDToNAgKpXPidv7FRsO3IRRBHjGV1IfeIW2r3yMNEXDUEw6PAdKqX46bkcGjuFmkXrkTxe7L9sRRufRI+unfFLErn79zNs2LATvwCOE7IsRyQADlaThnuTEKkhKWq1moqKijaybgHk5eVx2mmnAfDFF19wySWXMGPGDF5//XUWLlwY4bMLD1JTU6mubhAtwxwERyLwjo6OxuPxtBrhPiEhAa/Xe8Jru1wuRowYwYxnZwOgbpdEu1cfJvP5+5E9Psqmv0/Fa58jOdyYh/elw4eT8OXm496XDwJ0OjsZ34gDHNxewAN3PMqM2dMQDAGeenASAdnPwFs6cWhNBfooNY5qD4JKoPuFafhcflK6R+N1+olKM4AAMelGRLWAJdmozDeRFFsXAK1ei6gWiUk3hWadeGw+ZFmmJs+GqBYo3lZLUtdo7BUe+t/YCWRY+fp+ht93GvPmzePbr37g2Rdn8dDDDxEtJ/Phkjlc9+ZgDNFadn5byL8v/4kxT53ODW8NxZJipGy3lZyfS9EO6E7sFSNo//pjxFw+HEGjxv7zJvJumUzNf39E9gfQZiSRcNsltP/3E8TfdgmalHhku4vq178g76ZJVLz5Ff5qZQ6BfeU2otLb0SMjhfWrV2LU68M6V6Suri4i3U2RSMBHgseD63q9XtxudxuXnyTaeDzyXeGR0AEiwakWiyU0SDScUKlUJCYmUlJScsLHePLJJxUrN1lGMOpJGncj2R9MwtAxleqPFzUWs6XEkfXueIzdsrB+sxIEAZ1Fw+BnE/nmxy+5efTdPPDg/Yy++Bwef+gJSkpKuXhqH9a9exCAnhdl4qh2k9IjhvJd9YhqgepcO8jgrPQp3WMy6ExKd5klqUn3cEMCXK1RI6oFkrtEIwgCCdlR+D0Sab1i8bklTrsoTbmrJKMzqtmxoIDR43qxe88upk2Zzv/deDv3PnQXN15xK8++MIuL/tWd9N5x2Ks8PDvoG7LOiufuBefS4awk/G4JR7UbzEZMfbuS8dx9JP7zKtQJ0fgKyij4x7MUT3mLQL0DVZSRmEuGkfnaoyQ/dhOGntkgydR9u5L8O6ZT+NQc3AeKkGUZb1EF3sMlDB46jK179oEoMmXKlJO7EI4DVqsVi8USdkvVSOgAkiTh9XrbhoH/D+NU8fifUkAPBALY7fawB8AQGc+16OhobDZb2Ke4R0dHh33AGygZb0EQqKioOO7Hvv7665x++umUlSuPtYweRPK9VyF7vJS/+hllMz8gUFOPrkcHOvxnEtqkeIqfeAPHmp0A3LtoDNZCJ58+uYy333qb8849j7yCQ3z05idEpxvI6BVHyc4aLCkGag47QIABt2RTmVuPKUFLybY6BAGqcu2ATH2pU7FiAbSmpiMFBCxpRkCpUg94ZVQaEUeVB41RRdVBOwkdo7BXehl0SycASnfXEJ9toTLXRvaQJKIytDw763kSjWkkZyTy7zfn8uGNy4lON3LjO8PQR2vZ9UMRr573A32u7MBdX59L+/6KD27Nhz9Q/tbXaFLiSX7oOtJn/kMhZK9PsW25bRr2vXkAaJLjiL/xfNr/+wkS774cbbtk8Piwfvg9h8dOxb56B+bs7gxItrBq01ZkhLBmu4MDRMNNnEGybk2Dx9rIumWg1WpxOhUP459++onRo0cDEBcXF/bKpkihqQ96uLk8EjyuVqsxm81h59Smg0TDCZVKRXp6OgUFBcf9WLfbjTnKwooVK1Bp9Qh6Le1m/xN1XDTWb1ZS+MgruPbkIZgMZL7xGAm3XEjFq59R/d53IMmMfKg7g27pzPu3LOPVV/5F+w6ZJCWmMOmR6fj9Pq54YRCr5u4DAfpc1YHaAjtJHaPI+bEMWYKAT5ljEpNiVAonorRIfhlnbeN1KqrFhp9KFVtUih5RLdCubwIgkD04GVmGbuenIogQn2UCWWbdO/sZeFNHZBm2f32YATd25JN5n1B4qIShg4fw3n/eZs28Pax5Zz93zD+H9N5xOKo9PDvwG4yJGu786lwGje2svE7LtpD/8EvIkkzcNeeS+dqjWMacBaKIdcFK8m6eTO13K5ElCdGgI3r0IDJeepDUCbdh7NsNELAv30LBvc9R8OCLODbtZdTfrqTG7iRn9y4uu+yyFrgS/jgiYcUWTGpFYt1w87gsy7jd7pAVW7iHrv/V0MbjzQeCtwYeh0Y/8nBCFEWioqIiEpO3a9eOgoKCE6p+T89ox6xZsxB0yqyojJn/wNynG87tuc2L2R6+lsyXHsK2fAslk99Csjka/MLP49N7VvPR3M8oLSthxPARvPL8vygpKeGSmf1Y9opiTXLeE73Z9sVhAFRqFYJKoNuYVEAgc0AcCJByWrRS4NbZjCCAWtco8AajOL9XUorePEoSXB+rbRgELiMHZHJ/KseSZqRsbx0jH+wOMnw7cSuXPzeAnbt28Pmn8zlnyBjW71zFptVbmfu3H7l+zmDOHNsZZHjz0p/Z+V0B1752FpfO6o9KLeLZeZC8myfjOlxC1NAzaPfywyTc/jdEiwnPvnzy75xJyXP/IWB3IYgipn7dSH3qVtq99CDR55+FoNfiO1RMyYS55N06lfJ3FhCfmkaPjGQWffEZsdHRxMfHn+jbf9yIlKVqpPYPEBkrtrZOspbBqeLxP52ArtfriYuLo7q6Go/HE3ZR2Wg0hl7ocK6pVqvDviGLi4ujtrY27J7vgiDQvn178vPzj/ux69evByBx2PkknHUu9T9voua/P1Lw4Es41u0CjYqUmfeQPv427Gt3UfzkG/gqatF0SEU0aHn9/MUse2U32dnZPPzEg6zc/hOJlhTuvPvvjPhnDzZ8dBBBgP7XZVO210p0qoHcn8tBhO6jMxAEgc6jUpH8MkldFEE3NkMRymPbmZp5p5oTFM/09N5xCCJ0GJwEgkCPC9ohqASyh6YgSzLbv8knPjuK6jwHQ+7shlojsvyVPVw+ZTCTJ01i+7btVFrLeeHtGegNOr58ZD3l+638vSH4dtZ4ee7Mb/C4vIx8sIeyuEaFY9kW8sZOwXmoCF2HNFKfupXUSXeg65iO7PRQMfVdDt89G0+eUnkgajVEjehH+ux7SZt2F6bBvUAlgiDg37+V7hYd33/2CVFmEx07djyJK+D4UFVVRXR0dESy3ZHYJDgcjrAPLnW5XBgMBoqLi9v81loAQ4cO5eGHH2batGls2LCBiy66CICcnJywDomKJNLT0ykuLsZgMIS9KjsSPA6RqQbX6XSYTKZQtX84kZWVRVFR0XHvIfLz85GkAGpLDO2uuA3Z7aXq3W8peuJ1auYtBn+AuBtG0+GdpwnYnBSNex3Hht0Iei26Dqkse3EvH/3fSrSinpkvT6XKU8z+3TlMmDCBuz+7kG/HbwYRrnx+AGvfywUZMvomEPDJ9Lwkg8oD9egtGoq2VSOIUJFbh6gWcFm9qBoS4iptQ6u3qAjokl9p99bog23hSsBdtKkWtVbF3sUlDLixEwhQmWcjtUcsdSUuNAY142eNw2wys2TpIh59/FG69u5I3tpKPr1nNTe+NTQUfL99+TLWfbCfYXd3U14ojZpASTX5d0zH+t0qRIuJhLEXkvnKw5iH9wFkauf9SN5Nk7Au24gsSQiCgKFHNimP3EDma48Sc+lwRLMBf1kNSBKDMpNZ9MP3IIq8/vrrLXg1/Dbcbjd2uz3sw7isVismkwmNRhPWdSPB4x6PB1mWqaqqIi0trc2K7STRxuOR53Gv1xv25HCk/Mjj4+NPej7YiSAlJQVJkqisrDzux1Y1FMJl3/YI6qhoKl6f37yYrXsWWR9MxHhaR8pfnEf1hz+AJKMf0BNntZdXRv1ARW49d91/B+07Z/D9wu/45z/u4+bpF7F9fj5Oq5ceF2Ww+ZNDCKLAuY/0pGhrNTqTioMrKpAlGb9HEf51Ri2yJCOiUkRy19H6UcCj3GYrc4MMZbtr0ehVlGy30n5gIj5PgDNv6YgsySyeuZOhd3cDGRY+s40HX72VK664gk8++YShA0dw7T2X4XMFeH7odwy5sytXvDAQjU7FL2/s4+2rl9L9vPTQTDICEmVP/5viae8gSxKW8waS+a9HiLt+DIJBh3tLDvl3TKf8jflITiVppElNIP6WC2k/9wkS/n4pmvQk8Pjw7S9kxOCz2L1vP+Ulxdx7770n8rafMKqqqoiLiwvrmkFL1XDH5E6nE71eH3YrNpfLFRLQ22Lyk8Op4vE/nYAO0KlTJwoLC1GpVGFvZ4rUQK5IBN5msxmDwXBCpHmyyMzMpKKi4rhFjrfffhtRpaJm4wpMHbqADNavViC7PIoH+geT0KclUvnW11S+Ph/Z5yf+tkvImHonmqx0RLVAx07ZzH5pBiu2LubFya8zYfLTnH3eEPq4LyIhMYEb3xvC8n8pWe9BYztjLXKQ2NHMzm8KlMBZUvzT2vVNQFQJpPeJU7LeHc2IYjBgkTHG6hAEiEkzAQIxKXrkgIyz1o0ckNn62SGSu0XjrPEy7N4uyAGZb57YwMXP9GNA/wEMcl+NnFbPq3NfYtwDTyP7BF55fzZGs4Gfnt3Fmvf3c9PbjcH3O1ct573rl6PrkErmyw9jGtQDfAHKnv43JdPfR/L6MHTPIm3qnaSMuxlNeiKS1UbxU2+Qf/8LeAvLgQYro87tSP7n1bR/43Es55/Feeedx969eykuLCQhISGs10xZWRkpKSlhWy+ISLSb+/1+bDZb2DcJDocDs9nMgQMH6Ny5c1jX/ivitddeQ61WM3/+fObMmROaVr9w4ULOP//8CJ9deNCpUycOHDgQkeGawe6qcPuJRqJyDSA5Ofmk54qcCGJiYjCZTBQVFR3X47p27UrH7Gz89VYCLgfauERsP23EV1KFOjWB9m8/TczFQ7Et30zx03PwV1nRndaBrHfHYxpyOqJawGgy8tJbs5E0Ph6+40meeeYZoroI9LdfQbdOpzH4/zqz+h1lWNn5k09ny+d5IMtIPhBVAn2vz0KWILN/PJJfxpKiVAvroxWhVWtQOsqCjO6oagi499WDAPkbK7GkGqgrcTLwlk4IIjhrXZgT9BxeW8k5j59G++x2XNxxLJ07d2LO5y8w9423WLJkCVMmT6XnoC5UHrTxxsWLGHF/j1DwverfOTx35reIWjWpU+4k7vrRoFZRM28Jh++cia+yFnVCDEl3XU7GCw9gGtAdJJmat74lb+xU6tbtDF336vho4q49l/ZzxpH0z6vp2Kc3HbOz+Xnh92hUKnbs2NECV8EfQ3l5OdHR0WGvym5NtjEOhwO9Xk9eXl4bj7cA2ng8sjweHDgcia6u+vr6sM9uCfJ4uPctoiiSmZlJXl7ecT92/ITxIAhUb1iBObs7npwCHGt3KjNLpt9F+sTb8RVXUjTuNZyb9yEYdLR/+yniLjsbQatG1IjcN+4uRowYztNPj+edd95jbd6PXNx5LH3Sh2CK0xGTZqKmwE5S1yi2fV2AoBI4847OuOt8pPWMoXh7DSqNQPGOGgSgtlC5Tr3O5okXXZRiuWqM0+F1BkjuFo3fLdHr0kwElUDHoQnIAZmlL+6m19+UmSSOahedh6Rz05W3MijpfH7Imcdnn33G1EnTuHrMjdzy6JXIfpkXhnxHuz4J3PbfkcRlmqk6aGNWvwXs+6mEhNsuIeWJW1DFRuHZc5jDY6di27gbUacl5m/DFIu2yxSLNseq7Ry+7RmqPvgeyaPYzop6LZZzBpDx3H2kTfk75v6nMWbMGBZ9+w0QXptRt9tNXV0dycnJYVsTlAGioihiMpl+/84tiEgU0smyjMPhoK6uDr/fT1ZWVljX/6vhVPH4n1JA79KlC7m5uZjN5rATdqQC4EjYqbTUQM8TgdFoJDk5+bgJW6vVMmH8eAIuB/nz3oCAhBBlVHzD7rwUf0UtxU/PxfbzZlCrSHv5QaKG9qZs9n/w7DtMdqeOzHphJqv3LuX1Ke8hqASu+agvjz3xGBUVlbw+5zX8q5ORAjLnPt6TVf9W2sAH3NAZd72PjD6xHFxZBrJM+T4rUkBGFFQIAkTFGaGh4keWwBijtIVLkh9ZkinaXQsCHFxZTsYZ8fg9AQbf0RU5ILN42g76XZuN2Wymp38UDz/2EB9++CHj73uG6+achV/y8sjdT4Cs4qX3ZhEVZ2TzvDy+enwDox7qGQq+BZWA3+lGFW0i+YFrSX7sJlTRJty7DnJ47FTqN+5CEASMfbqS8ew/Sbr/GtQJMQQqail67F8UPv4vfKWNFRCqaDNqjYYLL7yQNeU2jO2yycvLo3v301r0evg1BAIBKioqwi6gR2rKeH19PVqtNuwig91ux2QykZOTQ5cuXcK69l8RmZmZfPfdd2zfvp3bb789dPtLL73Eq6++GsEzCx+6dOlCTk5ORHg8KioKSZIisn/4Xx7oebwQBIEOHTpw6NCh4157+fLlIIgUfvEu3ppKEAUSH76WzJceRNCoqJjzJZVzvwJ/gIQ7LyXt6f/D+s1Kaj5ahF5r4F8fvkBA5eWR25/C6/Vxw/tn8ebHc5j/2Rc8Oe4JLhhwNdZDbiwpBoq31AIw8uHT2PtjMbIsU7HXhqASyOybiCBCt3OUKp/khs4yvUUR0uUGDcVp9aHWiTiq3KT1jCXgk+l7dQcEATx2HxqDml3fFXP++DMQELB9Fc/zs5/n4IGD3HH9Pxg1qQtJXaN5998fsHzVUiaMm0SfEd2xV3h46exv6XR2Sij4FkSQfAFUJgMxl55Nu+fuQ98lE9nmpPC+F6h45xvkQABtWiLJD11P+ox7FIs2n5/qVz8n79ap1G/eG3pPBI0a05DeXHTuaFZt2oIqqzt+SWLEqFFhs0iIVCI8UgFwpOa2mM3mNh5vIbTxOHTu3Jnq6mq8Xm/Y+RQiE5ObTCZEUTzpwZrHi4SEBPx+f0Q0iA4dOlBRUXHcRYsTJkzAEhVFzcYVWLevA8A0sh8dPpyEoUM69T9tpHj8XPzV9eh7diTrnafxFpZTOuUtZL/EY9PuY8igoUyeNpFD+/LpPiaNiugcJo6fyOgxo3n13y+S970NZDjr1q5U5tZjTtSzf0kZgihw2vntAOh2bhpepx9jgh5HtQeVVsDnCoRmmciSMutElqBdn3gEEbqMTEUQBSzJOuSAzKq5uXQclkLAL9N1VDI6kxrfviimPDaTrOz2PPTAg0jtaxh0Syd2bN/BtCnTuHTYddwx8VqQ4ZVRPxCQA/zfvBGcdn5jZats1GA8owvtXnwAy/lngixT+dJ/KXj4ZQL1DkSjnrhrz6Xdvx7FMuZMUInUL17P4bFTqZ7/M7JP6fATBAF91/YMHj0SgFy/FpXRzLhx45gzZ87JXgJ/COXl5cTGxobd0iRSlqqR4HGPx4Pf76eoqIgOHTqg1WrDuv5fDaeKx/+0AnpOTg4mkykiFeiR8BONZOBdXl4e9sAboGPHjuTn5x/Xa+33+/nkk0+UPwSB+LEXkvXmk6gTYnBs2E3RuNfxFVeizkikw3sT0BgNlEx5B9fuQ2R36MDkCZNZtedHXn7iLRDg4V8uYvGM7ZTmVvH1qnksK/qScwdeyOTJkzBrYnBUe2g/IJ6t8w8jiAL9ru2I3yOR0TeOkl21CCLU5NuR/DIBnxQqV5MlGbVJ+aM816a0defUk3F6PAG/TN+rleq3DR/lkn56HG6bn/OuOptXX/0Xkl3FWuOn7CvfRl2Jiz2Li7jmX2fh8Xp44NbHUKHmxbdnEpsSRc7yMt67cRldz0njtv+OVAagVVvJ+79n8FdZMfXrRrsXHyTq3AEgy1S99F8KHnmFQL0DQRQxD+5Nu5ceIuHvl6KKNuMrKKfwoZcpmvQmvopaAg4XPR0ikqimMCqV1DFXAmA2hycLXF1djVarDbuXZ3DjHO4BosFgP9ybBLvdjk6n49ChQ22BdxtaBJHkcVEUsVgsYQ9Eo6OjcbvdYfdtjY+PJxAIRGQPkZGRgcfjOe6upKlTp4bUaUPfbmS9N4Go/j3wllRS/NQc7L9sBbWKzNceJersPlR/8AO1n/6I0Whk4sSJ2OttPHLHU3jcXq54fiC1h51s/fwQi5YsYoN5PkK1gVdffZW7XrqSnd8qPu1+twyyzKBbO3FodTnIMmV7rYCAIVaPIEJGf6U12RivJDEDfgmVVsTn9JPaIxZZgq7npCEIij+6oBLY/OkhBt/eBQQoWu7kxdef4/zRF/DJyjfZJ67C6/Hy5hU/ct0bg4lONTL3xXdZs+0XnnhgPIMu7o3HEeD5wd9iTtDzf/NGkHFGPMgyBfc+R/2abWhSE0ideBsJf78UQa/FvnQTebdOw5GrPC9ddnqDRdvt6LLTwOOj6vl5HL5zJq49SpGCek8hQ/r2Z2O9RNqF16CxxIEshyU4CwQCVFZWRsTLMxICutPpxO/3h33f0iagt6GlYbFYSElJobS0FI/H0yrsVARBiMi6oiiSlJQUkaI2g8FAamoqBw8ePK7Hfffd/7N33uFNFfr/f52T1SZp2nQ33YWyV9kKKMuFAoIibkAQBEURFEUQByAiU0URQXDhnggKsmTI3qPM7r1X2qQZ5/z+OG2Q672/6/1eSLzK+3nyPBqS80l7Tvo5n/F+v9dR3VAviUFGYt+YTMTY25EdLkre+orSld+DWyL0kSFYnhtJ3aEzFMxejVzvZMQDD9AmPoXZr73M2aMZxLQ3c/2EVnw/7QBnzp7hRMz3HN59goXzFzLjvcfY/tZpEGDQ7E4UnKxAo1dxYVcRgiAQ3V7x/2p5kwVkMATrcNndCOLFWsocZ0QQBaLbKTJi2kBF8mXfR+lEtw/GaXdzzUPJyG6ZH58/ycwlU5n+3HQ+/+hLToX/RGFRIR+P2EXPR1rQ+tZYjh45zty5r3BLpzuZ8Op9AKy8fRt5ZyoY9EpnbnimHQBlb31DwYKPEbQaQkfcimXWODSRwbgKSskaO5eKH3YiyzLqICOhI24ldsmTGHt1AAGqvvmFjAdfonzdTmSXG1mS6BsUx9aDRwnvN5jANp1BEL0mKfV3GoT7Kq7VasXf35+0tLSrefxPjD91A90Xm2s6nQ5/f3+vJ85Gypi3Nd+Dg4ORJImKigqvxm2MbTKZ/nDC/uSTT9D6+SlNmZ7tiV/+LIG3XANuN6Uf/EjRok+R6x0EDr2euPmP46qsIW/GchxZhSR37cSs+fP46puveX3aSgDGb+jP8bXZnN6Yh0orcMei7qye8Q2PP/44oR103NVmAiMeHMHNj3en4FQFGoOK9F+LENUC14xsjtshERSjpzyrkS7mgt8MIjQa5etVkVVLSIIRt0OmRX/F4dtabsPPpCHvaAXDJt/E9GnTaePoT6rjV+bMnsOyYeu5Y1E3tP4q9qw+j3+ghtvndcFut/PofVMQBTXzl80hPCGIwtNVLLt1I446F4IoIJoDweki+7EFVO88gqj3I2z0ICwvjkEdZsaVX6Ik7fU7kGUZQa3C1K8LsW9OIfiBWxD1fjjO5ZDz+EIKZrzL3XcMY3thNTJQum8bCCLvvffeZb0W/hUKCgqIiIjwekO5kfb9d5h2N9LFSktLUavVxMbGejX+Vfw1kZycTHl5uU8317ydxxuNRH1RePtKxkWlUtG0aVNOnz79hwbx2dnZBAYGsmLFCjSxEUTPnUDU1PsRdVqsu0+Q9+zbOAvKUMeFk7j6eVRBRorf/JLqDXvQG43MWf0ONtnNU2OnY6utp8+TrQiON/LjS0cAGP9jf76ZvZOZL7zAaes+OnErzzzzDA+/OZhDn6UjSxDZ3IzkkmlyXQQ5h8uQJZmqgjoEUSQw3Ago22qgaKYGRimbazHtgxHVAmFNA5Al+HXFWVrcEI0gCLTsnMS48eN44q7nEGNqmfrcU3y9eDNdH2xKbKdQbJUuti0+wb3v9sDfpOH1l5dz+MIeJo95luvv7oTklFnUax21ZXbstW5Ueh0IAqVLvyZ/3ocASp5eNAl9x+bgdFH0/Lvkv/I+kl0xuvJvmYhl1jgipyoSbXJNHQWz3iNzwjz61vpz4sw5qoIisaadxlFRQr++fb2i7VlSUoJOp/P6QNrhcGCz2byeU6uqqjCZTF73bbnaQL+KK4FmzZqRkZGBRqPx+jDcV8tlvmaT+QLJyclkZWX9IWlVt9vNNddcw8CBAxH8tYRNuIP4Zc+gCQ/GkVtM3rS3sf56HDTKENx0XQrVWw5QtOgTcMuMf/0Vrr+xP1MnT+PEr+cwx+q5e1lPvpy0D1e9xPUTW5K2q5ClC5Yx/81XSTamMPPJWQy48wZOrctFUAkMmtuFrP0lCCIUplYgqgWi2ygDcEu7YIUhrr5YwwVZ9AgiBFoMyBKcWpuFKUqPrcJBp+FJyJLMnuUXGP3U/byx+E1C9BHMX/0ya79bR2l6Fb0fVzzG3rxhA7e91JGka8I5tP8oC16fR7+Wt/PE6yNAgE8f2kXqhmwqc5Xviqj3x3b4HJlj5+KursUvOZaY1x7DfGdfEEUqPt1E1sNzcRYqPjaaMDPh44cSs+Bx9J1agCxT+ckmMka8RMTGE1jCIzjm9sdtt1FxZDd6fz8GDhx4uS+H38HlclFcXOx1+RbwnaSq1Wq9yiS7in+KP3UD3Reaa+CbxOkrI1FfFt6CINCqVSsuXLjw/3V3r6uro3Xr1tx3//3QME0On3AHKpMBV2kl+S+soHrDbhAEIl95hJA7++HILiR/xju4Sitp0a8HLz7zLD/lnOa7r78FYMy3vaktcrB5/gkAHt90Cz+/ehyHzU2rIRF89uOHvPzSSyS3T6S/30imPDWFCW/exbltRUgumYqcWhDgmoeaYy21o9IKOGpdHro3gL1GmX7X1ziJTQlBVAvEdgxBluHwh7mMnHI3CxcupLthIGX1hTw28THKAs6T3DsSl0Pi6HeZDJ7bRTEXu2sbTXpGcvNzHbDb7Uy4ezIqUc3c12cR3TqMqgI7q+/5BW18BNHzJxL60EAQRUqXfUP+qx8iu934tUggZv5Egm7vDaJAxZrNZI2d65FsEbUagm7toRiPDe2NoNXQu10Ksiyz7uPV2ApzqTpxkKBAE/369bsyF8VvIMsyRUVFPtta+7voptpsNmRZJicnh6ZNm3q96L+KvyYCAgKIiooiLy/PJ5trviy8fUHB9mXhnZiYiN1up6Cg4P/7urFjx5KQmOjZWIucci+6RAuy00XJqh8ofuNzZIeLoDt6EzdvIrLLTcHcD6ndexKDOZBX3n+HOtnFq4sW4nS5SBmWQIchiXz5xF4kSWbASx3IOVBO5t5iNP4iFRFpTBj/KMUlRfSPvIfnn36JwfcOIGNnGYJKoOeYFtiqHPgHaajIrkVyXUzgUc2Vv/9ut4w5TmFcWdoGI7lkTqzLwRxrwFkrMeDevjz91FT6+o+gSUo0z01/jgWz3qDX40rhs3zwzwx5rQt+Jg0n1uVSWWzj3nd7otaJzHtqKaeKD/HoPU9x07hrkCVYdtsmSs5VEvnCw1hmjUMVaMR+7AKZD8/FXWVFHWwi8qn7CH/yHsQAvSLPNmo21QdOAcp9lb5jg0TbxGGoQ4II0+jp2+1aPv7kU+xFeZT+ugkEkc8///yyXwv/DEVFRT4ZhFdWVqLX671OgfbV/UNtbS0ajYaMjIyrhfdVXDb4cqktKCgIq9X6t7l/iIiIoLq62uuGraBs+1ssFs6cOfP/fd3XX3+Nv17P3r2KZIt5aB8CrktBEARqdh0lb9rbOIvK0cRHkbjqeVQhgVR8s43SFd+DDBPenU+3mCbM/mA5BQUF6EO0jPvuBjbMOUpZejWhiUba3BLHttdPAnDdq9FMenISP//8M/fffz+P3jadYXcMQ2PzR5ZkWt4UTfahMiSXTF25A0GAVjcokmwq9cU2V1C0QWGLu2XFPPxcNS1vsCCqBOKiYxn7yMO8PHEBPXv0ZNXqVYx/YBLdHo9BFAU2zDpO53ua0KRXJE67m6+e3MPQhd2IaBHI3u2HeGv1Yq5LuI2nlj+EqBJY+9xhDqxJI2TkbcQunoRfqwRkq42scXOxnkxHUKsx39GXmNceQ5doQbLWkTNpMSUrv0d2KYuU2uhwIqfcS/Sc8fi3SkSQZIZ3uJavv/6a8sICyg/tQnY5mTFjxpW4HH6H0tJS/P39vT4IlyTJJ7VxVVWVZ6nWm6itrb0qqfo/gD9lAz05OZnKykrsdrvXp93gOz1yX8QF3xbewcHBhIWFcfbs2X/5miBzMKmpqQR37Ens0NEgCFSu3UndkXPkTl1KfUYBotlEwnvT0SfFYDudSd7Md3HX2Gg99CZmTniCn/LP8fFTLwHQ9b4kDIF6vn5yHwB3v9WNnMNlnPk5D1EFPR9uyd7V5zhz5iwlKft5cvIkSktL6RZwK0sXv8WUaZOIdraiWbNmRLcMARn8g3Q46hSt80ZUFdowhvshuWSSUmJo37YDoYWteGH28yxfuoLuHXrw86afGTXyIeranaeyvJIPR+7kpuc6oNaI/PrOWWI7hijUcGDpLRvoeFcivca3wG6zM374k6gENbPmvkBStygEEepzShEkGdON3bC8PFYpvo9fIHPsXFwVNYhaDcHD+xM991G08ZFINXXkPLmEklXfI7sUnTVR70fwsH40WTqVex58kI/XrKHy1GEy3l8EssSbb755pS6HS1BdXY3D4SAkJMQr8X4LX9C23G63TwxErVYrer2eCxcuXE3WV3FZ0bi5ptVq/1ZGor4ovMPDw6mpqfmPjbkvB9RqNc2bNyc1NfVfGq+1b9+eFStW4G9JIGHEJNSBQZS88y3OwjLyZr5Lzab9IApEvjKO4Dv64q6ykv/SSuynMzCGhzBnxdvUuV3Mefo56ssqQZa54al2/PD8IaoLbMSmmEnuZeHnV48BMGH9TWx7/RTlleU4e6czfcFT/Lr7V+4cPpRn75/D01OeJqa2He3bt6frsBaUZf6GSSZAcKIivyG7JIKiDYhqkZC4QJo3b05TvxQmPz2J9957jxR9f8qsxTz66KMUNN9HYUUe2ftLaXVzDDEdgrFVuUjfXcjQBd2QZZlPRu7EFKVn+FvXIojw0piFnK89yuhbH2fwU9cpvywZnLX1+DWNIWbeY0rxXWsja9yr1Jy4AICxW2tiFz+J8bqOijzbos/IfuoNXJXKcEIQRYw92hO75ElGPT+VX/ftJfP8aTLeX4StIJvOnToSHBx8Ba+Khh9Flq/Svr2Aq0yyq7hS8GUD3c/PD51O5/XlssDAQJ8YiWq1WoKDg31Wk7do0YK8vLx/+fueP38+dw4bhqzREXvnaEytO1L59S848kspWfE9JUu/Qna6MN/Vl9hXJ4BKpHT1Oiq+2AICPLr6dbqGxTPrwxWk/7wLgIc+7cuxb7M4sVYxCB39RT9+fPkIbpdM70mtOLE2m4qCGo4X7mPV9gWsXLmSTte3444mE5gzZw6jx46iZWw7LLGRVObVIqhETBaFSabWXlwICmxglZ3ZnEu7a1tyXc/ruXPAPSxcsIhefsOJbRXBnFfm8NmhZVQFZSPLMtmHS+k1vgUAK4dvZdArnTCG+pH+awlpewq4e9m1BEXr2fbDHlavfZtrIm5h6qoxqLWKJ1l9TiEqk4Go50YSdEcfkKF4zirFx0SW0caEY5k1lpCRtyFoNdRsPUTGqFnYz2V7PreuSTRRM0YxcOEMAoIC+fHHHyla/wklO39Cq9Ywbdq0K3It/CMKCwt9MgivqalBEASMRqNX4/rq/uHqBvr/Bv6UDXSj0YjFYiE/P/9vtbkWHBxMWVmZ1+OGh4djtVp9MqwAaNmyJVlZWf80vs1mw+l0ovI3ENbrJoyJzQnp1oeKzzZROO9DJFs9hutTiH/raUS9H7UHT1MwZzWyw0m70Xcw/b7RbChJZ82UF0GS0DSNYf+adF7v+yN1lQ5a9I8iukMYP758BEQY800f9qw6h8sh0fHuRE78kE1uTh7Ha7ez4IuZLH/3HSK76GkS0ooZ02dwi3Y8ixcv5snJkxh03V3cd5+ig/bAAw9wS8odPP3kVFauXMmDbZ9mzJgxiKVGqlSFPDX1KdZlrOR8zVHstnoCIvxJ6hmB2yVTmlFDn0kKVWz57Zu4bkJLYjqEYK9ysnbGQXqOa0HHuxKx1dp59J7JqAQVzz8/HY1aiyi7yXxYaZZfWnzbyR4/j5pj5wDQxUcSPecRgh+4BUGjpmbzITJGzbkkafc2x1ItuNizezf62CaKQaoosmLFiit/UaAk6/DwcK9vRLtcLiorKzGbzV6NW1VVhUaj8fq0+2qyvoorBV/qoJtMJiRJ8npcs9lMeXm51xv3Wq2WkJAQnxXecXFxgCLR8s+Qm5sLQGjPG9FHxhJ9673Yz2SSM2kxjqxCxBATCSuVIbizuJy855fjyC7ClBDD7Ldfp052MWfGTOryilGFBYEoMK/z95zfVoBKJ3Dfyuv4+TWFRdZxWAJFZ6vI2l+CWifir9dwfncOP/28nh+y3+O5ac9RbM1DXx/C+AnjefLWWcx/cTHPPPsMPaIH8NBDD9HGcC0ADz4wkrv6jmDJosXcrHqE56Y/R4e2KWgiJBYvXsyExx4hJ/AwxSXFbJhz2FNsfzxmJwNeSEEA1j1/hOi2ZnpPVMy3l974E7EpIQxd0BUEmH7PPDJdx7nv+vF0ubkNAMUvr6DmUOqlxTdQ8sr7FK/4DlmSUBn9CX9kCFEzRqEOCcSVV0L2I/MUvdSGxk+0xkDH6ES+2r4ZtTEQQatIw2RlZZGZmXklLoVLUFlZicvlIjQ09IrH+keUlZV5PY83Goj6Qne9kUmWnJzsFWmeq/h7wJd5HHxTkxuNRlQq1d9OxsVgMBAfH8/p06f/6b+fOKGwtk2tOhLQtDVRN9yBqNaSO3kJNVsPNgzBH8F8e29kp4vi17+g5ud9oBKZ+NFbdAmy8MpXH5L23SZQqVCbjSy9cYNHgm3ixltI3ZBLxp5iNH4qOt2VxK7lZ0CGe5f1YP+nF9i3dx9F7fYw7pGx7Ny5A6lGzbBhw3hzyVtMuu0lZs6YSYp/f0aPHs2wO+8CYMSIEfS03MbcuXN5+eHFTJ/0IjfffBM6o5Z1G9YyYsRI8pvsJzU1lU2vHqfXIy1Blln/whG6PZhMSFIAlTm1FJ6p5I5F3RAE+HbyQWQ33PtuT/RmLevf/4Uvfn2PLoE38viSB5HdMtathyhYsAYEgeBh/Yh85gEEPx3WLQfJfnwR7lqbIh13c3diFz3hMQPPn9kgz1an+OmoEBiU0Ja1F47hdLnQBCmLZZIss3r16it9Wfh0EN6Yx33BYPNVA12r1V5lkv3J8ae9w2revLnPNteCgoJ8YiQaERFBUVGR1yfeGo2GsLAw8vPzvRq3ESaTiejo6H+asP39/Rn90Cjc9joKNnyFy1pNXW6G59/Dpj1IxLghCIJA9daDFC1cAy43HSc/xLMDhrOxIouPp7yo0MKH9SNm1jj8WiQgqgV0RjW3v9aVrUtOUVfhIKlHOBqtlgOfpCFLMjc+3Y6Dn6SBDDc83Y7TP+dw8MAhsoyHeX76TMY88hBrjr7O5198jirKga3W5mn2yrJMdWU1+dWZvP7mEnaZ32fSlMeZN/c1qhLOk5OVw0+zT9BpeCKyW2bNmJ30fqwVslvmi0d30/GuJCJbBVFb7iB1cx5D53fFL0DDqfW5pB8q4cZn29O8n4Vaax0TRz5NVa6d5557DkOrpuB2kz3hNZyFZb8vvl/9kOLl3yBLEoIoEnRrD2IWPo5fqwRwOpWkPfcD/G0u+qnD+PD9D/GLjCH+3vE0efgZdKFR7Ni5k8OHD1/Ra0KWZfLy8nwi31JSUoK/v79Ppt2+0F2/2kC/PBg6dOgffvxd4MvNtUYjUW8XwI0Nu/Lycq/GBaXw9lUeF0WRli1bcubMmX9677R+/XoQRPJ/+ARXnRVr2sV8b+zTifg3n0LU+1GfVUjejOW4SqsIateMlxfMo052M3f2HGrTclBHBBO35EmC773Jo2868edbSNtZxOkNuYgi3DS9A1sXn0RQCYxY04tDX6QjqAQGzunI2S35ZOVkor4xn0WvL+SRcY+wVf0eb731FulZ56mzKQ0ijUoHgN1mo05Vyccfr+H1b1/k1Y+fY/YrsymOPsH57DNUFdTR5tZY1FqR0z8X0GFIAgHhfhSmVmII9aPH2OYgwKr7f+GaUc1I6hGBs17i88d206yPhQEzUwCYOnQux7P2MWH4FJJ6dFaMx+d/QuWGvQiieGnxve2wUnxbFZq/f5smxCx8nMDbeoAAlZ9sImv8PBx5xdymjmB79lnyD50g+tZ7aTZhJkHtulJSUsKECROu6DUBkJ+fT0REhNcbui6Xi9LSUq8X/DabzWcGoo1MsubNm3s19l8JV/P479GsWTPOnz+PXq+npkF+y5vwRQNdEASfyZtGRkZSWlr6/5U2vZJo1qwZJSUl/3Shb9WqVei0OsoPbKc26wK1Wedx19WBIKAKDfIMwSVbPQVzP6B2/ynQapj40Vt0MoTz6k9fcm7NDyAIxC9/hojnRiHq1IhqgYGvdgIBNs49BgKM/+FGDnychr3GSXKfSLIOllJdYCMoWk/m/hLKSspJLT/EN9vW8NTUKaxzvMnCpfPYs2cPNmctbrcbg1HZOne6nMh6Oxs3buTZaVP5+Mx8nn12Gp9+9yElfmk4XPUIQGL3cGQZ1DoV7QbHI4gC+z85z20vdUR2y3w69lciWwTSf6piELr05g0EhPtz7/KeaPxUfLFgA1/uXUWXoJvoe9stiCY9tsNnyZ3xLrIkoU9pTsy8R9HGhuMurSTr4Veoz1Du2dShQUROG0H4Y8MQDX6KPNvo2VTtPs61KjNOycWPi9/FnHItTcdNw3LrPbhcTiZOnHjFr4mysjIkSfIJI9xXjXtf6K43Lv0UFxej0+mIjo72avy/CryRx/+0DfRWrVpx4sQJTCaT12VNdDodfn5+Xo9rNpsRRdEnhXdcXBxZWVle35prRMuWLSkuLv6nNysrV64kNCSU6jNHubB8Lra8LMRAA3HLniGgXTKyLFPx3XZK3/0OZOj08mM81eMWNlbn8vHTLyPV2jH26UTwkN7UHTqD/UwmkkvmsQ03k3OkjCNfZgAyd71+LbuWn0GWodeE5qTvLqa60EZgtJ7CM5XUVTgIiPQn75hyfpr1iSQnLY/9B/ZTEnGKT7/8hA8/VMy+Pv74Yz7/5jNOVx3g1MlTlBdUEdXGDDKEJwdiCNFRW1pPk56RGMP8qMiuJaypiWb9LMgynNmSw20vdQQZ1j5zED+ThiHzuyLLMp+P/pV6q5PBr3YmJiWU6lIrzzw+HX1cFDNenEnY7X1AlsmZtJjac1m/L763HyX7sQW4axSqvyY8mKjpowgbPxTBX4f9RBq3nLJy4sI5Dv28lcj+QxAEEbW/AWdlGSpRRbt27a7o9VBRUYHNZvNJA70xWfvCuNQX0+7q6moCAgI4efIkLVu29Hr8vwoCAwM9D5PJxJYtWzh48KDn3w8dOsSWLVt8oo3rK/gyj4Nv9Mh9WXjHxMRQUVHhkyYHgMViISAggNTU1N/9W/fu3Xng/vtw1dVw4Z05lO3bBoJA+PSRhD88GEEQsJ3OIP+Fd5GsNkKu78iLM2dSJ7uYt3ABNcfPIwboiV0wEXdFDZXfbUdywz0reiCKAutfOgwCPPRlb85vL6QwtRK/ADWB4UaOf5eN7JZp3juaM1vykVwygWEGStNrEDUCJfnlHD9+nH0ZO9hydD3vf/g+aXpF3/XTTz8jx3CU/fv3c3x7Gpa2ZpBl0nbn07yfBVEtUJ5XTZvb4hBFgbQ9xVz3aCuQ4cMHt3PNQ80wxxoou1BD/vEyBr3SCUOwjow9JZzakE2HoQlc/5iymT77sSX8cuoIL055hvYzJ4BaRfkH6yn7eAPApcV3WRVZD7+CPU3Z7Bd1WkLuu5noOePRWEKRqmpp+sNxIu3w8WuvE9C8HYb4pqj8/HFZq0EQefLJJ6/o9SBJEjk5OR52gjdRXFyMXq/3ySA8ICDA68y56upqAgMDOXHixNU8/l/gah7/PZo0aYLT6aS8vJyamhqvL3n5ylckKirKJ3ncaDRiNps9rC1vw8/Pj+bNm3PkyBHcbvcl/6ZWq/n5540giGR/tZLcb99HdrswDbiWuDcmI+r9FPm1F1dgP5OJaPTn8Q+X0sk/lNe2r+XMu18AELdUGZiXf/QTktNNk57htL0ljk2vHcdR56LdoDgEFexZfQ5kGDq/Gwc/VQbhdy3rztkt+YhqgUGzOpF9WNE/D08O5Oi+k/y8aSPHKnfw/vvv8+N+xffss88/I8PvEPuO7SYzPZuotkEAHPsmi2Z9LUgume9nHPQstX0ydhc9x7VAALYtTsXSxkyn4UkIAnz++G46DU+kxY3RSC6Z1Q9sI6ypibvfvhZRJfLZqz/xypIFjHtoDLcvnok63IwzI4/sJxYjO11owoOxzBpHQO9OIMnkTXub8m+2IsuyIlXSsz2xi5/EcG07kEH12S/c5DKz+svPkGQI63kTgiAiuZRFhd69e1/xayIrK4vY2FivD8KdTqdPBuEul8tnkqqiKJKWlkaLFi2uMsn+j/BGHv/TnpmOHTty6NAhnyXOv+PEu/EPlS/g7+9PmzZtOHr0KA6H43f//uGHHwACksuJf5eWxL81FbU5AFmSKPvgRyo+2wRA5wVPM6Vtb36uy+eTabNxV9Tg174p4Q8PxllYRvHSLz3HPPVjDutmHkZQCdyzqheVubUc+zYTWZLpObYlBz9NU5L1W92UZK0SuPmlFHKPlSGqBa59uAXlObVIbomAcH8cNkU7tRFOm5tAix7JLXNuez4xHYIRVQL5p8to0T/a89+dhichiLDtjZNcP6ElsiTz/TOHCEs20X1kMgjwwcjtJHQN4/pHGyjgN29ApRa5643uhDYJoN5Rz6xF89EIIk89MJrIB24FoGjmCqoPKc2MS4rvihqyxs71SLYIgkDA9R2JXfwkfR4YRrt27XhrzjzQ6tCYggAo3rkRyVnPjBnTUavVl/sSuARZWVnExMRc8Tj/iEbj0r+LXmsj3by2tpaysjLat2/v1fh/JaxevdrziIiI4K677iIjI4NvvvmGb775hvT0dO6++26fSBn4Ch07duTcuXM+o0IHBgb+rSjYOp2OqKgosrKyvB4blDzSoUMHcnJyKCkp+d2/r1q1ClEQkJxOxCAjcW9Pxdi2KQC1B1IpmL0aud5J5JA+PD9xMnWymwXvvEXVnuOg1RD35lMgQ9HiT5Hq6kGWObelgE2vHaeuvJ6E7mGExAWybckpBFFg5Ce9OfFDNi6Hm+b9osg+XEZ9jRNznIH8kxUgQ2TLQCpzlK3z9oNicda5QJbR6H6vnVpTZCO6XTCyBLuWn6N53ygkl8yPLxyj47BEJLfM98/sp+1tsQRG6ynLtGKvcnLrix2RJZkPR+3EL0DLHYu6AfD9M4ewlti5dkwzOt2dBMAHS5ayx1HKlA59SJk9EUGnoerH3RQs+RRZli8tvmWZ/OnvUPbVZs/ygy4pmphXHyVp1GDGjBnDW6+/SVVeIabmyt92a8ZZrGmnSUyI54YbbrhCV4KCwsJCVCoVYWFhVzTOv4r9d8njjXEDAwM5dOgQnTp18nr8vwqu5vHfQ6vV0rZtW86cOaMYRXp5QBsYGEhNTQ2uBp8mbyEsLMxn8qbx8fFkZmb6bKmtadOmaLXaf8oMv+6662iSlKj4ZjUMwUMfuAVBEHAWlZM34x0cOYrU2mPvLaGjLpgFB34m9fWPAIicNwF1SCCV327HdvwCSDK1FS4OfpZO6k+5IMCtL3Vk7+rzuOol2g2No7qwjvTdRQgCmC0BnNtWgOSSMYT4UXCqAkGE2vJ6JJeM1qhWvEwAU4Sf8qEFxd8kKFoxBA+OM6I1qKmrcJDYLQyVRiTvaDlNe0ViCNVRnmnFEKIjZVgigiCw9Y2T9H68FXqzjozdJZRkVHLriykEWvQUn6nm4CdpxHQIYejCriDD8b0HeTv7EMPNTRk8bxrauAjcZZVkjX8Nqc6OqNUQNu52wh4ZAmoVlV9tI/e5t5HsCutAZTIQ8dgwop55kMcmPcGOHTvY//ladNFJqPz0uO11FG9fjyiq+Oqrr67oteBwOMjPzyc+Pv6KxvlnKC4uxmg0YjAYvBq3urras0zrTTTm8cOHD1/N4/8FvJHH/7QN9E6dOnHkyBGfULDBdzrojYW3t5OmSqUiNjbWZ4U3QGxsLEFBQR6NtUYsW7aMAQMHImhVhD9xF1GT70FQq5BdLorf/JLqDXtAELjm7eeZ3KQbP9sL+XTmPJyF5WjiIoia+gBSvYPCBWuQHS5Mg3pi7NWen2YdpTKnltAkAwkpoWx/KxUEgZuea09FTi3pe4oRBAhNCOT0xjwkt0zTruEet++QeCPlmVaQQVQJOG1ufru07HK4CWoovM9vK8DSNhjJLbP73XM06xOF5JZZ//wR2g+JBwT2f5RGWFMTrW+OAUHgyFcZ9BzXAlOkP8Vnqsk7Vcq1o5uReE04rnqJT8f/is6ooXlfC7IkU3MqjdnLXkcjCDx5+z1YHrkDBCid/ymVm/YD/L74nvkuZV/87LneAoMCeej2YXyen4pVdoHTwfm3Z5G35XsqjvxKgNHIiy++eEWvA6fTSV5eHgkJCVc0zj9DRUUFkiR5xVztt/Clgagsy5w5c4ZWrVqh1+u9Gv+vilWrVvHUU09dsoWoUqmYPHkyq1at8uEn8y4iIyOxWCxkZGRgt9u9TkluzOPezqfh4eHU1dV5XbYGlMI7Jyfnd5tj3oLBYKB169YcOXLkEimXCxcuoDcYkCSJwAHXEL/0adTmAACqtxygaNEn4JaIHns7z943GpvsZvGaVZRv2gcqleJzotVQ/slG6i/kIJoDCB5xK4c+T+f499nIMty99FpSf8qhLKOGgHAdQRYDBxpk2G6b1ckzCL91dgdyj5YjqASuG9eCipxaRLVAVKsQ6mtdyBJo/C8Ob/1NWjR6Fa56iYgWQQiiQHlmLfFdw1DrVBSdqSKyZRCRrYJw2d3UVTkUvXMZVt+/jbhOoZ48//WUvUS3C6b/lLYAvDVgI5JLps2tDaaPbonlD09mr6OMJ5v3IGXuJESDH7b9p8mbuQJZkn5XfFd9s53cZ95CsinfL0GtYvRtd3BKtnK8Shnk5K39iKzPl1O48WsQRLZu3XrFr4WsrCzi4uK8zuby5SDcF7RvUApvrVZLamrq1cL7MuFqHr+ITp06cfjwYZ/Uxv7+/uh0Oq8v02k0GkJDQ30yDLdYLNTX1/uEkQ7KMDwlJYXMzMxLPoPb7aZFixakpaWhaxp9yRC8PrOAvBnv4CqrRts0mkeXvkZHjZlFJ37h5Lz3QBYIf340+ngLdcfOU/GlYiwa8cwDlOS7+HnuMQQRRn12HdZiOwfWKHKqA6ancPiLDARRoP/TbcncX4LT5iYs2UTxuSrcDglTpJ6KhkF4SIIRR63SQDcnKPcYyEoDPTjOgKAScNhcRLdV6jxBFEjqEYEgCtRVOOh0l7LUtmNZKj3GNEdUCexbfQG1TsXN0zsoeX34DrR6NXcu6YYoCvw87zgVOVZiOigSJ6JKYPukV3i36CR3mRIZOGcqfs3jkWptZD7yKq5K5d4woHcnomeNQx1swplVSObDc3HkFnt+3/06dyemeVO+yVUW4WzpqZx98wUKNnyJVG9n2rRnr3iTNzc3l6CgIK/LkoHvB+G+0l2/Ogi/fLhSefxP20Bv1aoVDoeD0tJSnzhh+6qBHhYWhs1m81nhXVBQgN1u93psUBJ2+/btKSoq8tywDBgwgAmPPoqo1oAMmnBFX1bRV/uQ2r0nQa3i2ndfZGJUezY5ivh8zmLqM/IRgwOIeWU8AKXv/YAzrwR1dCih995M4G29PNviIz/qQ9HZKk5vzANkOg5LvJisp7Sl+Fw11YU2/AM1uBwSxWerEEQBBKjKr0MQlYLNVe9Wnm+A2yF5pt0VuXUK9RvI2l9KXOdQNHoVZelWjKF+NO9nQRAFck+U0Gu8Yl6yYc4x1FqRW19o2F57YCeyDIPndkZv1pG1v5Q3blrPruVnMF6fgqDXUb7lIPM+ex+NIPDEDUOImXI/qATKV/1A2ac/A/y++P5uFzlT30Sqs3OHxkKGVMvpBCOxiycR0K8LAFWHdoAss3bt2it+HeTk5BAQEOCTIrTRZdzbtKnq6mrUarXXDUQbp91Hjhy5mqwvI1wuF2fOnPnd82fOnPF6LvM1OnXqxLFjxzAYDF7Pqb4yElWr1T4rvENDQ9FoNBQUFHg9diMSEhIwGAweKZdly5bRrHkLnC6lqa8KClCG4LJMxTfbKF3xPcgQ+/QDPH3TMKV5/t1nlHyzDQSIe3MKKqM/1r0nqfpxNyAQt+BxTP06owoJAgHuercHsgy/LE0FAUZ+3IfM/SVUZNeiD9Gg9VdzZpMyCI9tF0bukTJkSSa2UxgVObVIbpnAKD2OOheyJHv01RsRaDEo9yB+KsKbmZDdMiq1SNPrlMK7qqCOzvckIUvwzeR9tLophpAEI9bieipza+k7uQ1+Jg3nfymkIreWzvcm0byfQh1f2PMHPh69C7+m0eiaxSPV2lk+cRp7XeVMSuhCx1cnoQ4OwJGWS86U15EcymDikuI7t4jMh1/BkV1IZzGIGNGftZpyLC+MIXTMYASdltqs8zgqS7lj6JArPqCura2ltLTUJ/ItjQ0fbw/CfWUg6nA4qKurIycnh5CQEGJiYrwa/6+Kq3n8Ihob6IGBgX8bVjj4jk3WuNTmDaPnf4WAgABatGjB4cOHcblcnD9/noAAE2fPnkXQaBB1WlQmZenGdiqd/BdWINXa8e/SgkfmzKSjOojF5/dwYtZykGRCHx2CsXUirtJKil//XNlenzEGQ0pz/No1AwHiu4QSmRzMruVnkCSZ7g81xe2UOPJVJrJbpuOwJI98y4CX25N7tBwE6DayKZW5yn1ey5tjPIzwwAjFywRZxlHrIjDagCBAZW4d0R2CEUSB7GMlNO8bheyW2bLwBB2GJgCw7/0LGMP86HxPEoIosOGVIzTvZyG5dySSW2bTa8cJTw7kluc7ALDstk2suHMrqgB/DH06A7Bl/IusKDvDXfo4bp05CX3H5uBwkT1hHs4iJU/pEi1Ev/oY+vbNwOki96k3qNh0kGBBw23qCD5352O87wYsL49FExGCZK+l+swxjAYDs2fPvqLXgCzLZGZm+mT7XJIknzLCfTUIv7qBfnlxpfL4n7aBrtFoaNeuHadPn0YURaqrq70aPzAw0CdGomq1mrCwMJ8k7ICAAEJCQny6hd4o5XL48GGaNm3KTz/9hKlFB5qOfQ5daBSFr31MfUY++S+txH46A8FfS48VL/FYaGs2OYv5YtEybKfSEfx1xC2ahCCK1Gw5iHXHERBFYuaMR5YkSt75BgSRlLuS0Pir2fbGKQSVwO3zOuKyuzn6dUOyHq4ka0El0G9yKwpTK5AlmeAEA9YSO26nhEavxmlzezbRGyG5ZQwhOkS1gLPOhTHEj4AIf1z1EiqNSPJ1UQgqgbLMGjrepeiufTVxH8HxRtoOjEMQBX597wyJ14TTekAMILB22gH0Zh13LOoKgLXQQfDdNxA+/g4sMx5C0Kgo+nIzCzZ9g0YQmHjNzcQ99xCCRk3VD7soWvqlZxszoHcnomc/gjo4AFdeCQlrdtNU9ucrp2JoIur9CBsziNCHB4OkvGfUqFFXdCNClmXS09NJSkq6YjH+f/i7Tbsbt+WuTrsvL0aNGsXo0aNZtGgRu3btYteuXSxcuJAxY8YwatQoX388r6JTp04eOTZvF8CiKBIQEOCTgt9XhbcgCCQmJpKWlub12L/9DCkpKeTm5jJ+/HgmPPoomqBgmox+mpDufSn/ZCO1B09TunodFV9sASD+pXFMueYWbLKb1zd/R/FH6wGIWfgE6mATjrxiSt7+GhCIfOURRH8dld9tx11WCUBSx1COfptJdYGN0CQjxjA/DjVopt75RnfyT1ZQW1aPIVQLMuQeVwzSNP5qyrKsnuZ4vdXV+ENc8jMFxxpAAKfdTUyHEES1QGlGDc36WJDdMj/PO0bLG2PQGtTkHi1HlmSun9gKWZJZff8v+Ju03Phse5BhxdDNgEJTN0X643bKEBlG5MwxRD37INrYSNylVax8bhZ7XRU8bkmhwyuT0ESF4CqqIPuxBUh1yqLDJcW3y41r0VcMJowvnfnYUMzCTf27EPPaY9Aw4F+3fj0bN268kpcA6enpREVFeX0oDBcH4d7OpzabDafT6fXCu6qqCn9/f44fP07Hjh29/nP/VXE1j19EYx73lSyar+RcIyMjKSsr+6fSolcaiYmJ5Ofn+2ypDRT9e61WyxdffEHzFi2xO53E3D6CuDvHYEvNoOz9H7HuO0XBK+8jO5wE3tydsU8/SUd1EK/nHOT4i28hu92Yh/fD1KsjstNF4cJPkOwOjP26YGydgP1sNjVbDoAMA2d3pjzbytFvs5AlmT4T23Dqp1wcdS5iOyvb3Wc25SG5ZCwtQ8g9VoYgCrToH01FrsIki+8YhrPOhSAK+BuV7WxZlnHYXARZ9EgumbyjxYocm1tm9/KzNL0uEgRI3ZSHMcyP5D4WBEEg53gJ3Uc1Q6UROPZNNk67m5ue64BaI3Lwk3SspXbaDY6n7eA4BBGsZXaiZj1C6OhBBA64FmSZzY/MZGX1ee7yi2XA0+Mx9u4IkkzOE4uoz1QWHVRGfyKevg/z8P4gQM2H67mzUMshZznnJWUw4NcsjpjXHkOXFAOiSG2djSlTplzR819SUkJ9fb1PzCzLy8sRBAGz2ez12L4YhEuSRHV1NVVVVVRXV9O2bVuvxv+r4krl8T9tAx0upYx5O3H6+fnh7+/vE/qUrwpvUJJlRkaGT7crYmNj2blzJ+PGjcPSdyDRg+5HbTASe8doBLdA3rS3cWQXIQYa6LH8BR4NasEmVwlfLV9N7T5lIz3+zacQtRrq0/IoXf2DctyFjyNqNVT9tAdHRj4IcOSLdF7v9yPpu4oQRGh5Q/wlyVpUCZz+ORfZLdNqQDy5x8oRRLhmdAsqGqbdwbEGZdoNiBrlKyWqBGS3Qg0zReqRG36dMR2CEVQCNUU2mvVRJt4b5x4lvkso5jgDdZVObNUOeo5rAcCOpWdwOyX6P90Orb+K1I15VObWEtM+hL5Ptgag/KstyE4XukQLkU/fD6JA/rKvWXRgExpB4NEOvYl78WFEPy21u0+QP+s95AZ6vy4hiuhXH6PtgH488vBYFsx+hex1uzxNdtnlovrn/WhDIwjp3pfMrCxCw8KZNm3aFTn3xcXFuFwunyTr2tparFYr4eHhXo9dXl7us5uEqw30y48FCxYwdepUFi5cyHXXXcd1113HokWLePrpp5k/f76vP55X4csGOijm3GVlZV6PGxkZSXl5uU8K77i4OKxWq8/o3wB6vZ5z587Rq1cvmnXrSdLIyehCwgm/fgDGpq0oWrCGmp/3gQBNF07iybbXY5PdLN29kcJ3vgYg/MUxaC1hSPZ6ihasQXa5MQ/rgz4xGkd2IZXfbQcZkOHtQZvZOOcYAPe/dx1VBXWc+6UAZJmYNqEe+ZabpnegNL0GZ50bfbAGWZapyq31MNLqrb9fmnA7JYKi9YgqkcrcWqLbmpFcMgc/S6NJrwgEES5sL0Tjp6LDkHgElcDBL9Jp3s9CWLIJe5WTvNQyWt0cTdK14bhdMtveOIlfgIY7l3RHdsu4swtxlVQi+uuIem4E6tBAHGn5rH5tCXvdFTwe1oYOsx9Hl2RBqqkjc/w8XBWKFnFj8R113y1Mnz6dzT9tYPPLbyDVX7z2qjfvBxki+g7CJai4+ZZbuOaaa67IkojT6SQ7O/tvNwgvLy/HZDJ53UD0Ku37yuBqHr+Itm3bYrVaPc0db9eIjXnc23Jser2egIAAiouL//2LLzOMRiNhYWFkZGR4PXYjBEGgWbNmuFwubr71VpJGTcbUoj2G+GSibryD6k37KF78KbglzPffwsiHRpGiCuKNwqMcf/4tZLsTY5/OmG/vDUDpBz/iyCxAFRJI2OiByE4XJcu+Voa7Klg+dCvvDNwEAorMmYAiwybAkNe6knu0DHu1E1OUv9LgPlyG7JYxhvhRmVOLLMkERuupr3UhCBel2GQJ6sptHj+T1I35WNooNVfe8Qr0Zh0x7UOQ3TK2KgedhiueJl8/sR9DsI6uDyYjiPD99AOYIvzpM0mpv1fcoQzDb57WHq1BgwBU/3IIQRAIvv9mDD3agdvN5kdeYGVtOsN0Mdw8YRSBt/VUYj/7FjXHzim/a1HEPKQ3kc+NZOz4R9C4Zd4YNwVn4cX7V/u5bOrTcgnp0htdhIVFixYRHBz8T7XqLwfS09NJSEjwek4DPNvn3h4IOxwOrFarTyRVAc6ePUubNm28rr/+V8WVyuN/+ga6LyfevjT0rKio8LpeLCjarWq1mry8PK/HboQgCOzduxdJkrj32hRouGFy11mRnEqjWhMdSo+lzzPB2IxNrhK+/eQzZYItCMS9MUVxAq+po3DhGpBlQsYMRBMZgrO43GM4GvfW04Q9eie2aheiWmD4m92RZZkDaxqS9byulGXWUJZhReMvotaqyD1SBgg07RnuMR5r3j9aMR4D1FrlK6XSip4bPXOsIuPidkpEtw8GSebctlya9IxAUAlk7itFEASPidj6lw8TFG0g5c4EBJXAliUnMATruGFqOwBWDNtCTZGNC7sabujcEnmzVgLg36YJ4RPvAiB37vssPrUDjSAwofm1xM9+BJVJT/2ZbHKeftNDAw82BvDUQ+P4JvUAR48dpXLNjxTMeg/J7qD8iy04couJvu0+InrfRtKoKejCInn11Vdp3rz5ZT/36enpJCYm+sR5urCwkJCQEDQajVfjNtLUIiIivBpXlmWqqqqw2WyUlpbSoUMHr8b/K0MURaZOnUpeXh6VlZVUVlaSl5fH1KlTfXIj6kt06tSJs2fPolKpfLJB1pjHvV14+/v7YzKZKCoq8mpcUBh8cXFxpKenez32bxEYGMi69euZPOp+dG7lfkZyOHDbbMoL1CLJb0zlscSu2GQ3bx/9hbwln4AMoU8Ox9giAVmWKVn+Hc6icjSxEZjv6IssSRQv+wYQCBk7mOi5E7A5NYgqgegOZvRmHUe+ykAQBLqPSkaWZU7/rMi3JPeKIvdYGQjQYWgidRUOnHY3Gj/le9loPtaIRr3UQIsByS1RfK4SSztFGiR1Qx7+Ji2xnRQjImuZnZRhCpts66KTCIJAnydaI0syn475FUEQuHlGB0SVwN5VF6gurCN1Q64SR4TcqW8i2etRBRqJmjFK0T4/dIaP31vFXncFE4Na0H7mePzbNlFo4I/N9xTXoijy2NB7qDZp+eirz7GnZpD5yDwc+aXYTqVTte5XwnvdTEjX3jQd+yyBbbqwd+9eDMaAy24en52djdFo9LqECihFaF1dnc+MS72dx+FqA/1K4WoevwidTkebNm08VHhvy4yGhIRgt9u9bmAKvl1qS0pKIjMz02eeJqCc+/nzFzDivnuJVSufQ5ZlXNaLygAhk4bz4OAhpKiCWFp2iuMvvI27pg6/9k0Jf3gwADU7jlCzeT8IEDvvUQRBoOK77TiLylDHhBO/bBqa1kqjGlmmy/1NyDtWTsn5arQGNcYQP498y83Ptae6yIa1xI7GX/kulmXWIEvgF6BRanJBQO13sZaszLERZFEa6CVpNfgHagmM1uN2yMiyTIv+FgRg30fnSegaRlCMgbpyB7YqB90ebIraT8W5zQXUW510vCuJyFZB2GtcHPjyAmm/FlFf40QQBKq/20ntuSwEUSR8/FD82zRBrnewdeLLvGfPYJjGwo0PDif4nhuVzzL3Qyp3HfV8zhs6dKX79b1YuGYV9ZXV5ExaTNXuY7itNorf+hp9XBPCew8g8YEniOw/hMqaGlq1acPKlSsv63m3Wq2UlJSQmJh4WY/7R1FQUOCTfFpUVITJZPKZpOpV+ZbLiyuVx//0DfTDhw/7zEg0KiqKoqIirxfefn5+BAYG+qTwFgSBJk2acP78eZ+5fwNs2rSJt99eRouEOFJs+dRmp5H50RtI9Xb8U5rT/bWnGa9vwiZXCd+vXUvlt9sBiF08CbU5QCmw3/wCd6UVXctEAvt38xTislvCfGcf1EEBqAL0SA43Wr2KxGsilWR9oRqdQYUx1I9zWwsQRLh2dHNkWSanQTdVH6S7SBfrHOoxLFHrlWm3WnfxSxkUY0BUi1Tl1xHdNhhZhr0fpqEzakjoEqYk3MI62g6MQ6UWObepAFmSFfMSUeDgx+m46t20HRRHbKdQXPUSb964gbxzdURMuRd1SBCOC3lUrNsFgLF7G0IfGghAzvPLWZp5EI0g8Eh8ZxLmTEAdGoSrsJzsxxci1toZpY3jjGTlYCszUc+NQtT7YT+TTebYuVT9sJPwXjfjH6loavqFW4gZMhIEgfPnL1zWc15ZWUlZWZlPtNbAt1troih6fQPdarUiSRJnz56lZcuWVw1ErxBMJpNPzHf+LIiKiiIyMpKsrCxsNpvXB8NhYWE4HI6/ZeFdUFDgEz+VRjz00EPY6urIzMjkzkg/XFXlZK5Zii0vA8HgT7O3pvFodAdsspt3zu4ld96HIMkEjxyIqZtCX63euJfaPSdAFImeNVZ5bsNeHBn5iEEGAvt2QR1uxlldh+SWGf7mtbgcbg5/kYEsyfQa15KSCzVU5dehNapRaUTyjpYjqgTa3hbn0U01RSnFkrPu0kaFIICj1qUYgstwenMe5lgDOqOG+mplCN28rwVZht3vnSEkIYC4LqHIEpSmV9OkZwRRbcw47RKZh4oIijbQ+7FWACy9aSN7P7iAeXh/9Ne2B0km97m3kWUZTXgwUTNGIWjUVG/Yx6fffcVedwWPBTSj3TOjMXRvA26JnEmLqU/PY4A6gjBBxxpdGZZXH0WXGAX2enInL6FgwRr0sUmEdO0DgMrfgGXAXejCLDhdTnbv3n3Zzrnb7SYtLY0mTZpctmP+JygqKvL4AHgTvtRrraqqQqfTcerUqauF9xXC3z2Pw6U66N6uydVqNeHh4T5baisqKvIJMzssLAydTudTaVWz2czLL7/Ee++t4qFr2uFfVULhz19TskuRAQufPpL7e/ZXmudVZzj+8jJcpVVo4iKIevp+ABzZhZS8+x0AEbPGIer9cOQUKbW7DNEvjEFlMiDZnciywKC5ihTVwc8UGbbb53a+OAh3ySRdG0HeMYVhl3StwhqubGCSCYKAw+YGWb6kFq/Iq8UUqQcB7DVKzR6bEoKgEqjMrSW5TxSyDPs/uqAstQ1PBAF+mnUEf5OWa0YpOu1fPbkXUSVw20sdQYZNs0/wzZT9GLq2IvihQYBM0QsrcVvrENRqIqbcizY+CndVLdueeY336rO4U2Oh35CBikSqAOVLv6L8ux00FQ3cpo7kfVcOuifvxHRjdwDK3viSrGfeRK6rJ/q2exEEEUEUCe7ci+DO14Ek8fHHH1/W837+/HksFotPNqFramqw2Ww+YYT7qhdQVVV1dRB+hXE58/ifuoHeunVr6uvrKSsro6qqCpfL9e/fdBkREhKCw+Hwuv46+LbwjouLw+12k5OT45P4oNws7d27h9dem8/Aa7sQfn4/kstJQJ8UOj8zhvF+iWxylbBu22bKP/oJgOhXxqOJVDTSKr/9BdvxCwhaNZZpDwJg3XEE+6l0BD8NQQ1bbOWfbARRwD9ES2l6NQc/S0dUCwyaoxiAnP45D1mCTsOTqMipxV7tRGdUmuSVubXIMgRa9J6tNf+A3zTQG+YPQRa90rzPrCKiRSCiWqC6QNnAa97PgizL7Fh2Gn+TltYDYhBVAme25BEQ7k+nuxXzkh9nHUYQBG59IcUjzRr5/GgMXVoRMeVeEAQqPt6AI1u5Zkw3diPoDqVYTp+yhLcLjqERBMZGtiNh9ni0MeHINXUMPG3D5XLxlUvRPfdv20TRWEuMAqdT+Rn8DJ7zIssSBT9+DgiMHDnisp7z1NRUEhMTfZKsnU4nZWVlPkmavtJrraiouCrfcoVQVFTEAw88gMViQa1Wo1KpLnn83dCpUyeOHDmC0Wj0uqyISqUiLCzMJ6aakZGRFBcX+6TwNhgMxMbGXjFq7x/Ft99+yw8/rCXA34/r3cXUlxSiCjHRfOlUJoS1xia7WZ51mJw57yG7XATe2oOgm7sBCl257MMfAYidPxFRq8FZXE55gyF2zGzFJLxq3S6oV5rZucfKOfNzHvZqJ2HNTKh1KsXHRBToNUFhTWUdKkVyyQTHGz0N9CY9lE0np93lkXMBQBBw1Lk81O/8ExUIgqCwyQSoq6inWZ8okOHIF5mAcr8gu2W+mrRX2UJ/vDWyW+aL8XsB6HJfE8KSTQgqAePtvTAP6U3YmMGKxnlhhXJfAujio4h85gEQBSo+/pnPd2xir7uCR/VNafP4/QTcoHihNN2YyjUE8Z4zCzsS6pBALC897Cm+sdUjaHXIv7kOy/fvoL4kn7CQUAYNGnRZzjVAZmYmGo3GJzJs4Lst8LKyMlQqlddp3/X19dTW1pKVlUVQUJBPTFv/qriaxy9Fp06dOHDgAGazmYqKCq/Hb2xkextBQUGoVCqfSMEJgkDLli05d+6c13sgv8WQIUPo0qUzO3fu5IHmEdjPHAFBIHruBO5J6aE0z2vPc2LuShy5xaiCA4iZ/QiCKCLV2SlcsAYkGfPwfhiaxPyGRQbBo29DZfDHfjYb29FzIMvUlbuozK1tqMFlmvSKpPB0JdYSO35BGkS1SO6xMkS1QLcRydirHdRbXai0SvJWzMDxMMsArCV2VBoRQ4gO2a0U6NHtgpElmVObcjHHGAhJCsBll3DUuWg3OB6VWuTMpnxkSabLfU3QGTVk7S+ltrye8GaBdB/RFEEA0Wwk/Ml7MPXtjOlG5f4l5+k3kSUJ0U9H1LQRqMOCcOaWsn32Ut5zKE30Pjf0J/yJu0El4rf9BA9IEXzjzCdTtiGo1YSOuo3wicMQNGqosCLLgqe3AGAvyqNs/y8IgsBHH3102c53dXU1ubm5tGjR4rId8z9B4yBcrVZ7Na4kSRQXF/tUAu7gwYNXa/LLiCuVx//UDXStVku3bt04cOAAOp3O6wlbpVL5bOIdFRVFcXGx101MQfm5W7RowZkzZ3xKG4uKimLlyhW88cabTJ48me4THqDDuHsYr1Oa5z/u20VJQwIOe+YBdElKwVZ39BwVX24FIHbB4whqNa5KK6XvK6Zk0bPHIwgCtftTcWQXgU5DTZWKd4dsIfWnXCS3TNPro6guslF4uhJRI+Bn0nqm3S1vVuKUZVoV7bVQP2XaDeiDFcfv3ybtwGg9slsmbUcRaq2K8GaByBK46t0k944EGU6uU4YVHe9KQnLL/PD8IQCuaTAvOflDLvVWJ0HRevyDtADkz/sQUEzEQkcpG+e50972mIuZ7+xLQL8uIMtceGIhy8pS0QgCD4e0JP7FsYybMonmTZN5ecIkbPklns/7j8V38YYvyP52FZLLSfmBHdRmXyDYbL6sdLHi4mIqKytJTk6+bMf8T5Cfn4/JZMJgMPz7F19GyLLss2l3aWkpoaGh7Nixg169enk9/l8ZI0eO5PDhwzz//PN89dVXfPPNN5c8/m7o1asXO3bsIDQ01Gd65L7I44GBgWg0Gp8Nw5s3b05RUZFPGHy/xaFDh3ht3mtc0707948bTfKiyTwS2Byb7GZFwXFyXl6BZHNg6NaakPtvBsBdZaVo4ScABI+5HU1UqDKIfldhkQUO6oU62ISr0krVul9BlvFrYuGLx/awdvohBFHgjgVKIdtYhHcYnEhdRT1VeXWoNIJCIc+pRVQJNOkZiSzLOO3uf/QPxVnnIihayQ22CkVXPKZ9MIIokLmviMAoPWHJJtxOGXu1g2a9o9CbtZRn1VJf6yShWxixHUNwu2TObctDVIu0GxiH7Jap+Xo7Up0d0U9LxJT7EFQiVT/swpqqyO/4t0ok4om7QVC20L48tEtpovsl0Wr0nfR9YjTjx4/ntdlzOL9jn+cz/2PxXZt+hvPLXsZRWY69KI+i7esAgd27f71s59npdHLu3DlatWrlEyNLm81GWVkZUVFRXo/dmMe9/XOXlZVhMpnYs2cPvXr1umogehlxNY9fil69erFnzx5MJtNll336I4iIiPCJvKkgCERFRZGbm+vVuI2IjIzEYDD41BgcYM6cORw4cICysnKen/k8SYue5M7kFFJUQbxlu0Dqog+oP5eN4KcjdsETCGoVsixT/PbXuEor0cRFYB6iLHZVb9iLIz0P0WTwMMTLPtkIooimRRyb5p/g7Vt/RnbLtB8ShyAIyiBcJdBnksJOyz5UhuSSiWwRRGVeHQDGUGUBq77WiSzJaH6zgV5XqVw35hgj0CCr2i5YGX5/puTbFv0sCCqBEz9m4x+opdXN0YoX2qZcdAYNPcYoW+ifT1RYW+1uj0eWQaq0Yj2hsLJDHrgFbUIUUlUtJcu/BUBlMhA1YxSqAH/qUzPZ/daHrHJmc6fGwvXX9qDVzHG8/PLLbPppA2tfffOSYbexR3uiXxmPOiwI2Wnn/LLZ1KSdRnI6yP3+I5Bh1qxZxMbGXrZzffr0aeLj471eEzciNzcXi8Xi9bilpaWo1WqvG4E7nU6qqqooKSnBbreTkpLi1fh/ZVypPP6nbqAD9O7dm+3btxMaGuqThO2rwruRZuCrLfCYmBg0Gg2ZmZk+iQ+K+/ONN97Env17WfH+Kp7sN5hHtQlscpWw4cRBihZ/CrJM8LihBKQom2XOkgqK3vgcBIHQKfeiDg0CoGz1OuR6J/oe7dFaQpHdbmWLTRCIeXkcsa9PQd+lJQDth8QjCALntipGo+1vVyRFco+WIapFUoYqemAVDRrogih4NtADwhQaeKMmG+ApvDP3KU3qmA4hiGqBgtRKAsL9iWwZhOSSqS2vx9LGTHjzQFx2icrcWgwhOrre3xRBhPeGb2Hl8F+oLa1HNPghlVRS9etRJW6/zhh6NlDApy9DlmUEQSB09EDl53JLXHh8Ae9UnkUjCEwLakO37t155fPVVJaVkztlCfVpF3Xv/7H4tp5P5dxbL1P0i1J079mz+7LplMuyTGpqKsnJyWi12styzP8UWVlZPtncslqt2Gw2n+i1lpWVYTAY2Lt3L7179/Z6/L8ydu3axZo1axg/fjy33347gwcPvuTxd0NjHjebzT4rvKuqqrDb7V6NKwgC8fHxPqNf+/v7k5iYSGpqqk/iN6JHjx7kF+Qzc+ZMburbj2eMLbHJblaWnSZ71nu4q+vQJscS/vhwAGS3m6Iln+GuqUPXOomg/gojzLrzKPaT6aBVE3z3DQBUfrcd2e3G2K8zUbPHEzr2dkDxIQmON1KRY6U0rRq1VkRn1HgG4dEdFH3uitxaZBQmmcvuBlkxAfdAlnHUudHq1egCNLidyvqXpa0Z2S2z532laG7RPxpBFDj2fQYqjUjKsEQEUWD728rvvvfEVspW+pP7+XrKfrYsOonaHABA/qsfAKCNDiPskSEAFM9ajbtKkd8xdG1F6Gjl70bJ3A/5/twR9roreEKXxCO9b2XFke0cPXqU8re+puz7Xy753f+2+Hbbarnwzmxyvl7VUHS/TNOmTf/7E9yACxcuEBAQ4BPaNSja6+Hh4V7XLv0zDMJ/+eWXq3n8MuNqHr8UrVq1Qq/Xk5mZidVq9Xo+bZQ39UVNHh8fT15enk+W2gRBoFWrVly4cMEn3miNmD17NkePHmPea68i6/2YEd9daZ7b0zj9zhfUHTkLahVxr09G9FNquap1u6g7eBpUKqJfehgAZ3GFh0UWPWssgiBgO36B+rNZCDoNsS+OJWbhEwg6RYar35NKw/z0xjxkt0zrm6Jx2t0Un61CEBXGd2M9HttZ8SNxWBtkVX/TQLc3SK6Z4wyIKkU6NaypCZVGpKZY+b026xuF7JbZ/oaStxuX2ta/cBhQ2GX+gVoKT1ay/oXDrLxrGyqjH8hQ8uqHSA4ngkZNxJP3IOg0WLcfofqQwgLUhJmJmvEQglaNddcx9n72raeJPq1dP1LFOj768nNsR8+TN/0dj08ZgDY2gpi5E9B3bgnI5Hy5gvPvL8ZRUUKL5s2YPn36ZTvP5eXllJSU0KxZs8t2zP8ElZWVWK1WnzTQfTUILy8vR6/Xs3fvXnr27Ol1Cbq/Mq5UHv+faKD/8ssvhISE+GRzrbHwtjWaXnkRjYW3L7TIGxP2uXPnfHLDkJaWhiU6GrvDgeWm4eQVVyA7nKgQycjPpbBBKzXwzr4E9ekIgOx0UbTwE2S7E8O1bTB1UXRGaw+epnbfSRAEIsYrxWnNjqO4ispRhZvRxkaAKFB/ThlW9HlCcdc+vUlpoPcYozTnlWm3RHizQOqtTuprnKg0DXSxBg10c4JSEGsbnL/dTonABtMSa4lysxndzozkkjn0uVJ4N+9vQRDh0FfKdkHnu5NAhu+eOwBAtxHJqHUqKnNtWDESPWc8kVMfBEmmbOlXSHV2BEEgbMwgNJHBuIoqKPt4A6C4eodPvAtdszjkegcXnlpCnrMOk6CmQnbiN+ZWjL1SQIa86cuoO36prvlvi2+pvg4kiXnzXr2siTU/P5/6+nqfGZVUV1dTXV19Waf3fxSFhYWEhYV5naZWV1eHzWbj/PnzhIWF+Uyv1lfYsWMHAwcOxGKxIAgC33333SX/LssyM2fOJCoqCn9/f/r378/58+f/8PFjY2N96iHxZ0PHjh1xOp0UFhZSVVXl9Zzi5+dHUFCQT+jfcXFxlJSUUFdX5/XYAMnJyVRWVlJcXOz12G63m6SkJA4dOoS5Y0+cEXGU5hcSgIrs+hpy5qzGVVKJKsJM9MyHPEVLxRdbsJ/OBJ0GyzMPKMeqslK6eh0AMbPGIYgizpIKqjftA0km9MEBCIKA/Vw2qET6TG4DwNkGH5PO9yl/43KPlSOqBbrcr5h2l2cpTLLAKD2OBv1zUXPx1liWwVGnXK+NuVxyy1jaKJ4VxecUib9mfaKQJZmd75wDIOUOxQD14Jp0ZFkmtmMoideEI4gCZ3/JJ2zCHUQvfAKVOQDH+VxqGrbXjD3aE9BfkWbJeWapZxPN1L8L5mH9AMh7bhkZJYXoUOFCorZjImET7gBBoOrTzRS/t+6Svz+XFt/grK6gVcsWzJgx4789xR7Y7XbS0tJ8tn0uyzJZWVk+8VCpqamhvr7eJ4Pw0tJSTCYTu3bt+ts10K/mce9CEAR69+7Nrl27CAwM9NlSm69kXIxGI3l5ef/+xVcAISEhhISEcO7cOZ/Ef+yxx3h+5kz8IqIJ7j2ItOOnCJBEKiUHWZ/+hHXHEUAgbvEkVAFKnrSdSvfIkcXMexRRp0WWZUpXKCwy04Br0ISZkWWZ8jWKnGrYU/cC4MwpQq53Ygzzw8+kSKxW5NSi9hfR6tUUpFYgSzJBMUqsihwrgkqg6XWKfFd9Q02OeDEXOW3Kc4EWRQe9IqcWlUYkslUQyFBvdRLZMghDqA57lROXw42lrZmwZBNOu0RFjhWNv5qe4xRZk2PfZWG86Vpi33waY8/2ABS9+SUAmnAz4Y8NA6B0/hpcpZWAkoujnn0QRJGqb3aQtv0AdiT0iOQFiES/PA5VgB5HViE5U173MMoBRL0fEU/eQ/ADt4Ag4C4vRkBg7969l+08Ny60NWnSxCdyqqAstDUucXoTvh6Eh4SE/G0H4Vcyl1+pPP6nb6B3796d0tJSqqqqqKio8LoGmE6nw2w2+yRhR0dHU1dX5zP6dXh4OAEBAVy4cHnNIv8d9u/fT7PmLXDLED98LK269+CF557li+9/YPnKlYyLaEtKm3YYe3ck5M6+nveVfrAeR1YhoklP+IQ7AZDq7JSu+B4EgfBpDyCo1UgOJxWfbwbA8qyij1578Ixn22vlsG2sf+EwOYdKEQBTpB57jZOyzBoEFag0omfarQ9RpuyOOheCAAEhDRIuemXq7bS50Ju1qHUirnqlELa0VTbfzv+iXFNK4Q17Vyl/DFrdHINGryL/WAVOuxs/k4awJorpgaTTomsSjV/zOKXIFgTy5yu6Z6KfzkMBr17/KzXHleOJWg1RzzyALjqcscPvo7lVYIHtHAgw2i8JyyNDCRxwLQCFr7xP5Y7Dl5wPbWwEMa8+ir5hy3/+/PmXzZhOkiROnz5N8+bNvd5EbkRmZiYWi8UnE19fJuugoCB27txJ7969/3a079raWtq3b89bb731T//9tdde44033uCdd95h3759GAwGbrrppj+8cbVkyRKeffZZnzJ4/kxQq9Ue+rfRaPxbybj4+/sTHh5Odna212ODIoWXnJxMamqqV5tBDoeDqKgoMjIyCOt1M/E338H0SY9TXe/i6aeepqtTz/Drb0AM8Cf21UcRGrQIaw+epvL7HQDEvvYYQkNeKG1kkXVvowy9QZFqkyFwYE9EnRa3tQ7rrmPgltgy/wTfP3eQrYtOIsvQ5V6lgZ5zWKF9x3VUtqTLs5VcptKInka5SvubBrokexrrwfFGBFGgpsiGn0mLOdaA7JZxOyXCm5kIiPDHYXXhtLkwRepp2isSQRS4sFvR329za6yivSqBsWd7VHo/QscMBln2bK8BhI4YgDYuEqm6juK3vvZ8lqChvQm4sRs9evRghLkZq8vOsMtdzgRtIk2u70bEU/eBWoV18z4KF65B/o0En6f4bpDIOX3mDFu3br1s5/vcuXOEhYURHBx82Y75n6CkpARJknyif944CPe2LnZ9fT01NTXk5OSg0Who27atV+P7GlfzuPfRuNTmSzm24uJin8iL+pJNBtCyZUsyMzO9PowfNmwYb739NvrYJsTfO4F7B99Gr779eOqpp6hJy2FS95swGAzEzJ/oYX27yqspWvIZIBA8djBaizJctO48iu1EGqhVhNyn5KLafadwZBciGvQYWyt5uuqnPSCKWEvsfDxmF19M3IsgwjUPKTKfeUfLEUSBzvcr/1+ZW4sgQGi8Uis3LrX9Fq565f4nKFqP5JLJPNzACm8fjKgWyD+p+Ju06BeNqBa48Gs+giB4ltp+mHEQgJY3XvT3COjdCdFfR8iDAxD9dNgOpFKfqeR7Q6cWBA5S5DFzpr6J7FQ+k1+LBCIm3U2UxcLU9r05lJ/Bu05FE/2auGQss8ehDg3EXVZN1sSFuCprPPEEQSDo1h5EzRyN6K9DFgVeeuml/+b0XoLi4mJqamouKzPtP4HL5SI3N9cng/Dq6mocDgehoaFej11aWkpwcDDbt2//WzbQr2Quv1J5/E/fQPf396d79+7s27cPrVbrM+MSXxTearWamJgYnyXsxi30tLQ0r1H1zp07R/dre4BGQ8L9j5HcsjUPtYril/wqjugi2PLzJpa+9RZTn3mGoeNHe95Xs+MINZsPADIxvynGyz7ZiLumFm2zWIxtlIRQs/kA7soaNAmRaKKUP5TVG/aAKBD6yBDE9m05/kMOgiiQfL3S3Mw/UQ4ynkZ2RYPxWEwHxbTUaXMhqAQPXUyjUyOIjY11QXH+lpUpWlC0Hj+TBqfNjSzLhCYFKPRxm0S91YlWr6b94HgElcCa0TtYedc2JbFrRBynMnCVVQEQcu+NiEY9jtNZWE8qQw5tTDih424HoGTuB7jKle04vV7PC/NfpXXbNjz37DSOznmX5fYMNILAaF0iEQ8MwDy8PwDlb39D2Q87LzkvgkaFZLUh6vyU5qvZfFmK76ysLARB8Jnxldvt9lmyrq+vp6KiwicF/1+V9t3IJmh8/Cu66y233MLs2bMZMmTI7/5NlmWWLFnCjBkzGDx4MO3atePDDz8kPz//d1Pxf4Xhw4fzyy+/0KRJEwICAggODr7k8XfEbwtvX22ulZSU+MSIKyEhwWdsMoDExETq6+vJz8/3WsyoqChKSkqIvGEoMdfdxEMto7C5JL4slcgprWD69On07NmT5999Az+dMnh2FpZRvFTZ4AqdfA+aMGXLu/bQGWr3ngRBJnzCHQA48oqx7jyiyLjdpeSuml8Og1vCL6UZgUP7cv6wkqdFFQSE++N2ShScqgAB/E1anDYXtgoHQkPfs7FRrv2NBBsyVDaYfgdZ9Ajixfwfm6LIsRWfr1IK7/4WRJXA2c3KlmKnuxUz0a8f38+Xk/byw/OHEDWKwXjlz4peuaFTCwzdWisU8HcUPUZBoyZi8j0IWjW1vx6jat9J5XlB4J4xo3js8YnMnz+fdRNmsr48g73uCiZoE0ns3I6o6SMRtBpsh8+RN/PdS2jggiAgN5itCmoN/W64gcmTJ//X57rRxLJVq1b/9bH+r8jMzCQuLu6yScv9J/DVILxR//zXX3/l+uuv98nPfiVwNY//edG7d29+/fVXn+mgm0wmtFqtT2LHxMRQU1NDVVWV12OD4qlisVg4c+aM12IOHz6cr776ioDkNsTdNZZbky20DzGy6nwplaYIZs18EavVyqJVy4mOjQFAdrkpWvIpUq0dv3ZNCerbBWhgkb2vsMiiX3oYQaW6RE41qmGhzZFbrDDQRIGw8UMpsQVQmVuLLEHHOxsG4UeV4U3TaxsG4Vm1SC7ZwxJrlFX9LdxOJb8HWhRZ1bTtyhKbpV0wkktm/xqljm7WJwrJJbNl/ikAWg+IReOnIvdoBRteOcqygZs9xyxs8CJTmQyEjBgAQN4L73qG18HD+ysMcLuTgvkfe97XoWtnFixZzM6dO3nj0akcP3nSI+fSPSKB6Fnj0MaEIdvsZD++EGfhpcMqQSUi1TtR+RlYvHgxbdu2/a+HSo3b582aNfOZhEheXh56vd7rZtyg5PHw8HCvD8KdTieVlZUepmrnzp29Gv9K4Y/mcbiyufxK5fH/ibutP4MOuq8K7/j4eHJzc30iowIQHBxMWFgYZ8+e9Uq8X3/9VXGtVqmJCwtRmud5lfySlkfe9x8hu9wcyE/nHXcW/TVh3KW24M4uouTd7wAIe/ZB1EGKjIrtdKbSVJdloqYqNHDJVk/F19sAiJx8HwCOnCIlWatETL07ETp6ELrWSciyzHUTlIIw91g5gkqg60gleVfm1iKIAkm9lOTtqHOBIKDxU7blNH6qS7TRzXFKwq4trUcQBGI6hCCIjVNzgRY3KMYlpzcqJjUpwxKR3TL5Jyup9Q8j6vmHCLqzPwgChYs/BZSNstDRgwAofvUjT6Ec0LODYh6KQO60twh1q5mkbYKsUfGGI53yOiv20xnkLvuS5fWZShNdm0D4kD6EjlGOV7VmI8Xv/4Asywrl7r0fqL+QS9ywh4m/7zHQ6OjX/waefPLJ//O5djqdnD17lpYtW/qs8MvLy0On0/mkGCoqKiIwMNDreq3w19U/j42NJTAw0POYO3fuf3yMjIwMCgsL6d+/v+e5wMBAunXrxp49e/7QMZYsWcK7777LqlWrWLp0KYsXL77k8XeEr3XQAwIC0Ol0PondqAntCyYbKMP45s2bc/r0aa9t7inLDgKGwCBGtVCa5x+fLSRnw5e4qivILyxiiTuDAI0fj2mTMDlkChesQXa4MPZsj6mrIqWmsMi+A0Eg7Kn7EbVKYVf+2WYQRILu6Y+gUSNLkjIIl2XCH74d85DeGG9WmFVtBykD2qKzVbidEsZQpWHfaDzWaMzdmK91xkuLx6o8ZQMssGFzrehcJdBQeLtlTm1Q8nazPlFIbpktbyiFd9I14Zgi/ZFcMlmn6wl9+HaiXhoLskzFBz8iN9xThoy8TWmW7z5BfZayvaaJCPZQwMsWf4ZQVMGDmli6qYN505XJKVs5uFxkT3mdH2tyPE30+FbNsbw4BlGvw5FRQM7Tb+CuVQYA1n2nqPhyC2E9b6Lp2Gn4R8WzePFi2rRp819dF6dPnyYmJoaAgID/8zH+G9hsNoqKinw2CK+srLw6CL+MuJrH/7xo1aoVBoPBZzrogiD4bKlNo9EQHR3tU0ZCixYtyMvL81oTf9euXQCo/PwZkBRG+xAjK0/nk37kIFXH9+Gw21lZn8VJlY1J2ia0EI2Uf7KR+vM5CH4aop66z3Os0vfXI9ud+HdqgS5R0be27myQUw0JRNdE2eyu/nkfiCJBw28k4PqOhI5VmmpqPxFDsA5Zlsk5XNYg4aLU1o1MMp1Byd1Omwv+gVgruS9uoINSfwOKkSiQ1eBTFtc5FI1eRVWeDckto9Wradew1Hb48wwMN1xD3FtPow4NxFVUTn2GsphgvC4Fv1aJ4HRT9skmAASViohJdyPqddhPpFHx8wF6qYJ5SBPP95SwzqlcxwUvv8fJtPOeJnpXczSWFx9GlxwLTjc5k5d44jhLKihasAb/qDiSH5lGSNfenDx5EqMx4L/q1eTk5OB0OklISPg/H+O/RWZmJvHx8T5hRftqEF5eXu6px/9K+ueXI4/Df5/Lr1Qe/59ooPfp08enOugBAQH4+/tTUlLi9dhBQUGYTCaf0b8BWrduTU5Ojld+9yNGjKBD+3bERUYwpn0CW87nsT2ziOzP38VRWYYqPBDLC2PIFupZXJ+GBR3jxTgCA0wE3NKdgPaKNrfkcFKy7BsQBYIfvROVQWlSVv24G6nOjq5lAppwZbutetN+JVkPU0zJpDo79lPpICsaZxd2FpK2qwhZkolvoH1X5NQiiBAWrzg1N9LFNH7K5FLlJwKCZ6MtKNqAqBapyFGSvJKwBTL2Nsi49FaMS35Zmkrx+WpOrL14voPu7Id/6yQCb+qOaPTHcSEXZ4HSBDJ0baVIq0gypSu/97wnZMQAtLHhtG/agidU8ZyQqlnlzMYdaVY21NRqancdJ//zDbzryEIjCDykiSekfzfCnxiuUOc27qNg4WdUfredmm2HiLr5LvQxiRhik2gy+mn8LfEsWbLk/1x8p6amEhAQQFRU1H/83ssBWZZJT08nKSnpb5Wsf6t/Hh4e/pfSP8/JyaGqqsrzmDZt2n98jMbC7B8bIhEREX+4aBsxYsT/9/F3RMeOHXG5XD7TQfdl4S2KIgkJCaSlpXk9diPi4uJQq9VeG4a/9NJL6PX+PNylOTVVlXx8tpD8rWupOnFAMe+e9yj1ZgPvODLIlOp4Up1EU1MooslA2PihnuOUffIz7qpatE2iPWbh9Wl51B1IBWTMA3oCYDt2HldpFaLZhDpYYYrV7TsFgkDR6WpO/JDN6Z9zEQRIuUNpqDdukkc2DwIuNtD1Zt0lP0tNkdIkCmrYbju7RSlko9uaQcaTr2NTQtAZ1dQW11NTZOPgp+lUF9oQVQLqxGhMfTujS4rGcE1bEATKv1OkatTmAEIapFXyX1zh2V4zdG5J4G09CQsP41E5BqMsssSRRqHKReRT96GNiUCutZPzzFJ+rMvzNNFjk5QNNlWQEXdJFdlPLKL24GlKln6FqWUHQnvciNpoIuG+CYR07c2pU6f+z8V3YWEhxcXFtGjR4j9+7+VCZmYmYWFhGAwGr8cuLCwkKCjIJ3qxv9U/79Onj9fjXylczeN/XvxZdNALCwt9wuhKTEwkJycHh8Ph9dgABoOBJk2acOTIEaQGf4wriXXr1iGKKgantKSNQcWK1DyyUk+St1bZpg4eOxhjl5asdxXxtTOfB1XR9NaEgYzCBtcoS2V1h89Su+cEyDIRE+8CFN+y8gY51aip9wNK/V3zy2GQJIJuUDbXaw+kgiDgskvs+/A8ZzbnU1/jRKNXIQgCbqeEtdSO0NDRkmUZl93NP5Z1ckMDPSDcH0EUcNqUPGuK8EcfrMNVLyFLMiqNSPJ1UYgqgcy9xZzZnMeFXYXK+9UqzHffgDokEHMD863gNUVGVRAEwh4eDAJUr9/l2RpXB5uIeOJu1CoV9/rH0FcI4R1HBgelSoIGX4fplmsAxdvkVG6Wp4nexRhB1PRR6FOagSyTN+1tavefonDex4iijtghIxE1OiL6DiJmyEjq3S5atmrNm2+++R+fZ7vdzqlTp2jTpo3XN7AbUV5ejtVq9Ykfmd1up6qqymeD8Eb986t5/Pf4b3P5lcrj/xMN9O7du1NWVkZlZSXl5eU+2cb2VeEN0KRJE9LT031G/zYajbRs2ZIjR45c8S18URTZsmULs2e9zFdffsUHs2eQ/eUK7MV5iEY/Yl6Z4NlAq5SdPD9/LkX5+SxcuJDuI4Z5jlP5zS+4SipQhQYS2EMx93DX1FG5duclCfySZH2jYtxVd+QsuCWEoACObijmi8f2UHCyAmQwRSqN+PJsq0IXi1YKNkedC2TZ00DX+KlAuNhYD4rWI0sSxRmVAFjamZElmQOfpAMQ3T4EP5OGunIHK+/cwoGvc/Bvp0jOFL+jaKCKflrMQ5U/rgULPwGUhB06eiCCWoV1x1Hqs5RrVK3VMPKlaUx9+mmWv72MNb9spPHq0SVFE/H0fSAI1Hy3k8INuy5popuvaUfkM4pevP1wKhWfbyake1+C2nbx/H7VRhMJ914svgMCTP+RuU5xcTE5OTl06NDBZ/rb5eXl1NXV+SRZu91uiouLfdJALykpISgoiB07dvzl9M9NJtMlD51O9+/fdJlQXV19yX///x5/RzTqoO/evRuj0eiTgbQvC++EhATKy8t9dv5FUaRjx46kp6d7RQrv2Wef5d1336XWauXFyY+T9d2HlO3/BQDLy2PRRiuaqBLw/sa1fPrhR7wwcyYPvDELsaGAs5/JpGbz/ktYZIBC+RZFzKMGI6iV11Zt2AuiSPCYgYCS7+2nM5Vtb5sfP8w4xL4PLoAokNxboZpXNgzCk/spN+aNDXRjxKXNUFulQj1tzPelacpGelhTEyqtiK1CaaaIapHk3krh/eaNG9i88CT6DslIMtTtOeHRQDUP6wuyRNXXW5HsynsD+nZGlxyLXO+i7MuLFPGe9w1lwaJFnD1zlhdeehGrrBxD1PsR+dxI1CEm3KVV5L+4kp/qCzxN9GiLhejZj6CJCEauq6dowRq0IeFYBtzt+ZsviKrfFd+rV6/+w+fY4XBw9OhR2rRp4xMmFSi5NDMzk6SkJJ/E99Ug3G63U1NTQ3Z2NlqtljZt2nj9M1wpXM3jf2707t2bbdu2ERoa6pM8Hhoaisvl8omUSlBQEEFBQT7VQm/evDmSJP1Hhrj/V3To0IENG37iuuuuY/qzz3B0zbvkfL0KZInAO/t45FkA9uZc4PkZzzNo0CCmvfs6geENOb7OTsm734IgEDr5bkQ/hfFVvWk/7ooa1NFhaOOUv6E1O48iO5zo2iR5Xle79yTIMn4t4tj6xmm+fWo/gEditTKvFuSLzDFXvYQsc4mBqEor0njbJ6oEjOF+HllVgJgOwQiiQElDbm/WV2GTfTZhN99M2U+9LhB1uBkkifrzOYDiY6KODEGqtGI7nQmAJioUc4M3W95LKz3Hj23XkleXvUliYiKTH32MjFrlHkwQBEIeuAXDtYp/Re7Tb3C6JP9iE90vlIgp92Ls2QGAokWf4iquJO7OMagNFxlfpubtSBo1BY05hMefeIJBgwb94XMsyzLHjx8nNDQUi8Xyh993uZGenk5cXJzP/MjMZrNXc00jSkpK/pL653/1PP4/0UD38/OjZ8+e7NixA4PB4LPCu6ioyCeFd1RUFJIk+ayBD5CUlIROp+P06dNXNE5lZSV79+6lc+fOZGSk46qzYsvLBJVIzLzHPJvkAFU/7KJq30kWL3mdbZpqxugSGKqOguxiKtfuAFnG8vxoT7FYuXYHslOhjzVuqNXs+H2ytu5LBVEkcuIwYpZOVZrNgD5E4zlWeZaySa43N1C/bW4kt4xKp3ylNH5qkGUctsYGugFZgguNmmutzSBAWaYVl8NNzuFSAsL9EdUCQUOuJ27Zs0ROvR/R6I8rrxRXpRIvoF9nVEFGXLnFHqMSdWgQwXcr2/P5L60kUtYySduElMBIFp7awY4dOyhf+hWOvIvfG33bpoRPVAYOle//SNmeY5c00QPbNyNq5mgEnVZxCz9zHLf9UuMaQaUivM9ADPHJ2Ow2Ro4c+YfOsdPp5OjRo7Ru3donG2ONSEtLIz4+3ifmpWVlZWi1Wkwmk9djFxYWEhERwYYNGy6hRF2FgsZmyD/KbRQVFf1/GyVms5ni4mJAKbLMZvPvHo3P/13Rv39/NmzYQEREhE/kTEJCQnC73T4x5tbpdMTExJCenu712I0wmUwkJydz5MiRKyrl4nQ62bNnj4fd43Q4qD5zFICIKffil3xxaFmflkfpqh/YsGEDb2YeoKcxike1iYS4RIobWGTmhwajMim5wnYqHdvJNBAFgvp1VOIVlmE7dh6QPVvqdYfOKEV3SjOiX32M+HenIer9kN0y4ckNXiY5tQiiSGgDk8zZ0EAPtBgv+XnsNQ3PRykb6PU1yhKHqBaJat3AZCuyUXy+GkFQqOKiOYC4Zc8Q+ewIZeNcJVL16zEAtJYwjL1SQBAp+7yB6i2KhI29XTnWdztRl1Rzjyaa+/3i+cFZwIqP3qf2ZDoVm/Z5Ppc6yEjUjIcQDX44MgsoWLiGn5xFnia6JSRUGVYkRIEoUF+UT33p7793pubtCL9uALLkZsKEx/7weT5x4gRBQUE+GUI3Ijc3F51OR1hYmNdju91uReffBw30oqIizGYzW7ZsoV+/fn8Z/fPLhat5/Mqhf//+7Ny5E4PB4JO6WBRFwsPDfVYTJyUlkZGR4ZUN8H8GlUpFSkoK58+fv6JDhEZNbEmSaNasGcXFxVgvnEKW3OivaUfwHX09r5XsypD2/NlzPP/FaowhZqbqmtJaDKDss024q2rRxEdg6tLa83qPnOqUez3xqn9SJBnCRt0GgKuyRmlYqwQsL44l/r0Z+HdsDqJI+8EJwEUplpAmSt5uHISrVBcb6Gqt4j3SCHNsg6xquTIcV1jhMpl7CrGW2LFVXmQYRC+YiOWVRxWvFUmm+N1vASVnB999A8iyYtrd8D0IGtgTjSUUqcpK5Yb99FKFMEXbhPwgDS9/vIKykrJLmuuCKBI+4Q78WyeBLJPz1BucqSrxNNE7a4IJGz8U0y2KJJ3sqKcq7fc6+LrgcGKHjgJZ5ocffvjDUkN5eXmUlZXRrl27P/T6KwGbzUZBQYHPBuFFRUU+2T632WxUV1d7pJo7derk9c/wZ8f/JZd7I4//z9xxDRo0iLVr1/psEzw4OBhJknxiYiqKIomJiT4tvAVBICUlhaysrCtG2ausrGT37t00a9aM5ORkvvnmG5AlJem53FT9tBu54YbFdiqd8k83AmB56WH2aKwscKQRKeh4JrgdbVq3IfCOvh4TMld5teLqLcmENxSpsiwrmqlA2IhbAUX6xXbkLEgSfi0UHS53hTKRNkYYSN2QS9HZKqwldhDwNNTrrU6QL0q4aHRKsr5YkCuFd2GqcrOjM2oIjjeCBAt7rmfNmF2UF9QjuWRqD51BUKsR1GpM/bqAKFDx7S8AiFoN5jv7KcdaeNGQxHRzd/yTohk2cDBPaBI5LdWwyJFGeWsLgQOuBQFyn1uGZL9o4mC8pi0hI5WblJLXP6fy2NlLmugByXFEvzxWaeJXl3N++VycNZferFUc3kVt1nmQZR588ME/dJ5PnTqFwWDwqc5aXV0dRUVFJCYm+iR+QUEBERERXt/+biz4AQ4fPsyAAQO8Gv9/AYmJiURGRrJlyxbPc9XV1ezbt49rrrnmX75v69atHi39rVu3/tPHtm3bLov57v8qBg4cyLZt2zAajT4rvP8TCv/lRlJSErm5uT6jfwMkJycjiuIVk3JpbJ5rNBq6du3KSy+9dMmgsGrdr7irlYLXXVNH4cI1IEPAgB4UJJhZ4LhArmRjiq4pt3TrgTo4kKAbFFMlWZYp/2Sjsmn+yBCEhqZhowyb6dZrPc/V7julvO7265X3OpxIdQrN+/jabPKOl1OaXo3kkgj6DZNMECDwHzbQ620XJdr8g7TKbUnj5lr7YES1wDuDNrHyzi2c3JiPoBKQKmoQjcrAP/CGruCWqPjgR88xzXf2AWRqftqD26polGtjIwgafB2dOnfiGWNLDKh5rf48h/0dhD8+HGSZylXrqE+/yPbSRAQTNX0UgkaF/ch5ild9zwZXsaeJHmUKwjLzIUWbFcj4YDHWjEvPvb04n+LtPwHQu/d1f+g8FxQUUFRURPv27X3GYvK1DFtpaSk6nc4n2u+Nm+9r1679j7YN/y64msevHJo1a0Z8fDyHDx/22UDal6zwxqaNL5fazGYzSUlJV0zKpbF5npubS48ePejZs+fFvzNqNfWn0qi/kOt5bcny73AWlSEGGtA9cAPvObNZ5yziHtHC6FbXYDQYiHr2olxCo5yqtmkMWosy/LSfSsdZWIZg8EMbrcil1h1Ulvb0XRWGjajV4CoqB0ki91gZGXuLyT9ZCQI0v16RA22su1Xaiy0ute5SWRJzjAFRLVCZc1EHXZZg86JTvNH/Jza+cgyVQQcCHuNtQ7fWiAY/XLklnqU2Q9dWaGLCkevsWA8pn1VQqwkbN5TI8AieatadXoKZlY4svnMXYp4wFFWAHmdOEWVfXWSaCWo1EU/dizY+CrneSc7UNzhbW36xia42E/LgLZiHK0tPpdvWkr/1h0vuoSWng7zvP0YQVZhMgX9IHtVut3P8+HHat2/vk+3rRmRkZBAeHu6TpTqXy+UzRnjjIHzDhg3ccsstfxn988uJ/0su90Ye/59poA8cOJDt27ej1+t9VnhHRUWRk5Pj1biNSEhIoKKiwmfu33BlpVx+2zxv2rQpVVVVtGzVCkGtIeHBJ4joO5iqdb9StPBTHPklFC3+FBAIvOsGzzZbmexg7rcfs/bbb5k+fTpj774PI0rSrPh6G0gSxl4dUAUqU+pLknWsMnm0Hb+A7HShiQtHaKSRn8sGlUh5noPvnjnAe3dtBRm0hosJ2WFtKLB1jRroKiRJ9kzCG01L6srrKUit4PjaLERRQFQL6HumED13AjFvPYOgUePMLkJ2KduBAf26gCRT8/M+jy5qQO+OqEICcZdUYT+r0AgTVQbmvTKXHj168Nwzz7I2/wzuhnF78L03oUuKAaeLglc/vOS7E3hzd4KG9AagcO4HVJ/PuqSJboiNJHr2ONQhJqR6G+eXv0J9mTLVs6afoXDzdwCMHj2aBx64SLH/VyguLiYvL4+UlBSfSoekp6cTERGBXq/3emy3201+fr5PqHKlpaVotVq2b99O9+7dfbK192eA1Wrl6NGjHD16FFBu3o4ePUp2djaCIDBp0iRmz57N2rVrOXHiBA8++CAWi4Xbb7/9Xx7z+uuv9+SH3r17c/311//Lx98VTZs2pUmTJhw4cMBnA2mLxUJubq5P2GSBgYGYzWafmpBdSSmXf2yeq1Qq2rZtS3V1NRF9B5Nw/0ScOaXkzViOI6eI4je/wF1pRR0ZTOj9NynHQObztKO8/NJL3DrgVuYtfZ0YUWlE1x06Q31aHmhUBF6rbEtJ9Q6qtx4EScI8UGn+SrZ66o6fB0lSTLgA+znluynrtPw46ygfPLCdrAPKMkBAuNIwd9S5EMSLZuCNcNsv3u80mpYVnKzg7JZ8KvNqkVwyboOByOkjiV85A792ySAK2M8q2ui65vFoLGHItnqPEZgmPJiAPp1BFCn7UGmsB6Lm0XseZPKUKXyyZg3zf/qCKhp02dsnE3SHIuGWN/Nd3NaLjDBdQhSRUx8AUaB200FKv956SRM90j+AqGcexNBVMUXP/nw5ValHAHBZq8n5ciWy24UlysL69ev/7Xl2OBwcO3bMp9ItoOQzm81GTEyMT+Ln5ORgsVi8fi/jcrkoKSnB7XZz/PhxbrnlFq/G/7Pgah73HQYNGsT69et9NpCOjIykpqbGJ1I6jUttaWlpPpNWhSsn5fKPzXOj0cjs2bP59rvvMCQ0J3nsc2hNYRS89B7WXceo3rjXo28eM2e8R1Ztv72ESTOexWA08uaK5XQOjkGgQU71+0vlVAGqNioybOaGhTaA2r2Kj0nQrT0ARQ7G2cCm/vW9C3w67ld2LjuNqBIIbdrgSdZQd6v9Ltbojf/t2RKPNoAM+ScqyNhTTPbBhsVAGcIfv4v45c9ivvsmkKFqnWKkKmjUBPRtWGr77hflucYtdEmm5M0vkSUJNQK3tOrIkjfeIDMrk0nTppImK/laZTIQMfkekKH66+3YTl1cjBT9dERNG4E6NAipqo7cGe9wrr7qYhNdFYR5SG9CRyuDjMr928hZ9zGy5EaWJfLWfYK9pABRENi7d8+/bYjLssyxY8cICwvzqXSLy+UiKyvLZ9vnBQUF6PV6nw7Cf/jhh7/1IPxy53Jv5PH/mQZ6YmIiLVq0YN8+hb5aXl7u9c8QHx9Pbm7uFdcB/2fQarXEx8dfcQmVf4ekpCT8/PxITU29bMf8x+a5w+EgOiYGp9NF7B0PobfEEdL1emLveAj7iXRyn3oDqa4ebVI0wUMubks5i8op+2wT69evZ17uAQJFDc/pmtHfbsS55yRIMiEjLm7cNmqmmn/zXO3+VFCJBN95UdrCnpoJbomY16cQ/+40gu9TCv3w5EDPa+obTUT9lcJboxNBhtoKZbPMz6RFo1chu2H1Pb+w7vnDVJZLSC4ZRAFdogWVnxb/9skgithOZyjHCTcrzwkCdYeUrTFBrSL4LmULXfP5DkZp4hirTSBVZePlLV+Tlp5O/qzVF+lhahURTyq6c/Vnsylf/+slv3/zXf2UQh7In7kca07BJU10fXgIllmPoLGEguQibeVrVB7fT+63H4As07lzZ1auXPlvz3OjdEurVq180rhuhM1mIzMzk+TkZJ/ELywsRKPREBoa6pPYV5M1HDx4kJSUFFJSUgCYPHkyKSkpzJw5E4CpU6cyceJExo4dS5cuXbBarWzYsOHfGsU1adKExMREHnroIT7++GNyc3Ov+M/yv4ZBgwaxbt06nxbev2VieBvJyclcuHDBp1voJpOJZs2aeTYILwf+WfP8hhtu4OTJk4R060NI1+vRxySS+OCTqGQtuc8sxXb8AggQ/eLDns1xWZIoeecbUlNPM2PT52SpHUzUJnG/OgbtpiMgCoRMuMPzeuuvx5Ft9WgSozwyL3VHz4FbQtskxvM6ZRCuIvyRO0hY/TyWOY+AIICgSLFAQ+EtXGSSNcLtuNgkMccaEFQC79+/na8n7+PC3gplS626Fn3bpohaDYYurUCSqfyhofAWBEw3dweg5IOLDWrz0N7Kew+dY4DLzDRdM9QqFXPO72LL5s1UrPwBV2XNxdff0Qe/1kkgyeS/uNLDyAPwb52kbKkD1V9upXzjnkua6BFaPeFPDCegn5Lr89Z+ROm+rWR/9R6u2hr8tDqOHT/2h6RA/gzSLbIsc/r0aZo0aeITGbb6+noKCgqIi4vzeuzGzfdt27bRo0cPQkJCvP4Z/gy4msd9h8Y8HhYW5pM8rtFosFgsPtMiT0hIwGpo68WbAAEAAElEQVS1emQCfIErIeXyz5rn77//Ps/PfAG/8Ghih45EExBI/N0TMLXoQPHSLylrYFZFPjfSI48KUPnddorPpjF36RLWi2UM1ETypLYJMYeykB1O/No2QROhbIm6SiupO3hG0VZv0AN3W23YUtMBGV2S0uC1N+iPaxIiiX9/JjGLJqFNikZyyZ5FtcYGuk5/MY9r/JS85nYoOTPQokdyy2xecIJPH/mVXSvPI/orkqz+bZqgCjSi76QYY9fuP+Wpp039G5baNl5catN3aoE20YLolmmbbmWaLpkUVSAr7Om899knWM9nU7X7uOez+DWP9/QRCuasxlV+cQikMhmImjFKYX4XlJH3yvucc9V4muidxEBMN3RVcr0oYk09QsYn71C09Qdqzh4HWebzzz+jZcuW//Zc5+XlUV5e7lPpFlDkVA0Gg09qYoCsrCwSEhJ8Ngh3OBycOnWKm2++2avx/0y4Ern8Sufx/5kGOvi+8Dabzfj7+5Ofn+/12KDQ5srKyigrK/NJfLgo5ZKdnX1ZGhD/2DwHiIuLo9ZqJXrgfRgTm3teG9C0NQHJbUCSQSNimT7S8wdPlmVK3v0OJBlDz/ZUx5hZ5cxmhSOLJlaBd5a9wx1PT0BrVApsV2mlopEqSZ5NNtnlVty+3ZLHwNNdZcVVWglqFaKfDpXJoOiCA/ZaB9uWnGTfh+epLbUDIKqVz6PxVxL3kc8z+WDEDt66bbPH8TtqxkMkrH6eyOdGAQ0T9gYYurYCSaLy+x2e50w3dgNJouS97z3PxfbqzBNTn+K1F16mpLiYV+rP8bO7hIAh16MKNuEuraRy6wHP69WhQYQ/fhfIMlUfb1CaCQ0QBIHQMQMbbhYEcqe9TW1x2SVNdP+gACwvPYw2NhIEmfwfP0NyOQkPj2D37t1/6Fz/GaRbAM6ePUtERITPNCwzMzOJj4/3erKWZZnCwkICAgLYvHkzAwcO9Gr8PxN69+6NLMu/e7z//vuA8p14+eWXKSwsxG63s3nzZpo1a/Zvj7t161ZGjBhBeno6Dz/8MPHx8SQnJzNu3Dg+++wzn+h+/9kwcOBA1q9f77PCWxRFYmNjfVZ4h4eHExgYyIULF3wSvxFNmzZFrVZz5szvtTT/U/yz5vmoUaPYvHkzgW06E977Ns9rtUHBhPW8WcnjgOWFMZ7GN0DVT3twZOSDVk3AkN6scxUxt/4ctUWlLHjuBcaNH090V8UY3CPDJkDYyIt/zxrlW8xDe3ues5/JBLcbv6YxiDqtElOWEUTYNP84u987S96xchCE3zXQXfUSHz+8i+VDt3JuawGC0OhV8gyx7z73/9g77/CqynSL//Y+NTnpvfeEhB5KaAKCCKIi9o5dxLGOdextnHGwjzPYxq7YxlFRsYvSQ+/pvfeenLr3/WPnnOTkRAElbPRmPc997nh2+1LIu7/1rnctNH4+YHMgWZVRb+8Jysa7Z2eea+Pte9w4BJ0Wa26Zy7LFKziAC++4kRdffJGw+i7+ZS3mLVsF5rQofGZPAFGgdnmfVZsgioTfeC6ijxe2qgYa3/3WbZ0+U0b1qdNe+4LO7P3uJLrGSMhVi/E7SRl7rV/zOebaCgRg46YNh7SBra6uVt26BZRmcHd3N8nJyao8v6KigsDAQFVVa59//vn/60b4cB1XD9OmTcPhcFBWVkZHRwfd3d0Hv+gIIyEhgYqKiiHN8/g56HQ6UlNTOXDggKoq9P5WLr/1+zAYef7dd99xxZVXovMPJO68pYh6RdUsarWEHX8qgt4AsozvqdPxHpPiupe1vJbWT34CGaLuu4IdcjuPWfLZ1lHHshkn8fBDDzHphj7bz/bvt4IAPrMyEXobot07ckGSMWQkujfCRRHT8RMRRBF9VAhyt7L/zn6jkHUv5LB/tUKUGf30rvs7xW3vX7+J/5z/I98s3wuA4O9D7NM3E//6/ZhmjAONxkXSa4P80CdGgUPGVqk0SnThQQo/IAgKh4Dyd2bOtZfwzFNPcXJIEp9ZanjaWkSJ3u6qx03/+hBHV49rPf6nzHAR9FX3v+iaOgdFOBd5z+UIei3WvDJqnnuffEenG4nuM30MEXdcDDKYK4to3voTAA899CBnnXXWQX/WPT09x4R1i8ViobCwkJEjR6ryPtHR0UFLS4sqYoCGhga8vLxYs2YNM2fO/H+dqzEUtXyo6/jvikB3bryDg4NV2XgLgkB8fLxqG2+DwUBKSgr79+9XtWD7+PgwevRotm3b9ptemgYjz2fOnEldXR1hs0/Gf2Sm2/ltOTtp278dgOiHrkH07us8df60A/P+YhAFQq9a7Po8t7SYO6+/iX//61/MmzKTuwypHK8Jxr5uj0ex7skpQe6xoAkJcAWKOgupPjnadU97XTNoNLR3Gdm+uoE1K/LpaVfUhJ/ftwOAXR+VAtDRI9LmGwtjx6KLUWxiRB8vRC8DupgwBL0OqaPbpSTzzhwBgoB5f3G/z9LQBPoitXUR0tDFudoo7vJKxysphhtvvJHnbr2HDqk31MyoJ/TqxSDLtLy8yuXTBuA9Ps1l11L90H9wtPUdEzQawm46D0NaLEgSFXc+R3druxuJTk0zttomNEZvQECn1ZGTc+CQPLvKysqoqalR3bqlo6ODioqKQ+rODwW6urpobm5WpVi3tbVht9vZtWsXMTExpKenH/U1/NFx/PHH8+CDD/Ljjz/S0tLCt99+ywUXXEBOTg6XXXYZUVFRjBo1Su1lqoqpU6ciCALFxcV0dnbS1dV11NcQHx9PbW0tFovl4CcPAUaOHElxcTE9PT0HP3mI4LRyKS0t/U2igMHI85UrV/L6G2/gHZtE1MLz3P7mW9uaqV79HiDgf+F8jGl9Cl5bXTPN734DQNQ9l7tGwVvtZp594BFuvfVWIiaO5h7jCM7URuJf3oy1vA50WqV2oeSYdO9Qcky8xijkqmSxYi2vBQG0wcrkmL1OmWKUdTr2rGll3WvFlG1tRJZkNr6az+f3bXf7Ops0EdhSMtCPTUOySzgcDrSBvgiCgGFEvBLSWaR4k2sDfBTrGFlWmgGA6G3EZ9Z40IjYf9zJPE0o9xjSmDJhEsuffJL7b7mDkrq+n0PwxSchehmwFlfRta1v8lDj70P4ny8AoOOzdXTvdh/f9zsxi8CzlXC3+qffpXtvoRuJHmKWMeeUIhr63p9WrnzHpfz5JXR0dLBz507GjRunqnWLU32elpamivpclmXKysqIj49X5dm1tbX4+Pjw/fff/79uhA8Vhuv4waHVajnllFP48ssvVduTBwUFYTAYVBO1JSYmYrPZVJ9QGDFiBIIgsGfPnl/NDQxGnre0tLBg4ckIWh3xF1yL1rsvXFuWHFR9+hayzYYuPpyQC0/qd0xSAsAR8FkwzeVnbkPmo7feYdm1yyjpbOaG0DFcpYsnTfJSckwkmcB+waSuRvjivklzc14ZSBKmjETXs2yNrQDk7TKz6b0Ktn9YgqgVaKvtcdXxtt6g0XqLPz1RyeinK2GNstmKLjIEQRQxpsSCw0HX5n2u55myRoIg0PbDNtdnTlFbyxurmSj682d9MhenTuTb7dlcf+ON/PD1N668UlPWSGVfj0D9v//ruocgCIT+6Sw0gX44mjuo7yeQAzDERxBx5yUKH7BpP/VvraZA6nKR6BNEf+U9B8U/HUFk4cKFLsXuL8HhcLB161YiIiJUtW4BKCgoICgoSFX1eWRkJHq9/uAnH2EMT4QPLYa6jv+uCPSsrCz0ej0FBQV0d3fT2dl58IuOMGJjY2ltbVXFdw2UkYTu7m5Vw0tA6fxHRUWxZcuWX2VpMxh5Doo6F0Gkde82rK19SntLYx3VX7wHQOCVizAk9IVj2Fs7aHSOkN16kYv8BpTNuCiSF+vNE/YiVtlqGSX48tQZV3DtNcsYe2HfH63uXvsW39OOc31mzlP8z00zx7k+s9U2gcNB6PXnEvPsbSS8dj/0+qWX1ynPbmxTOrq6yGDCrjub4CUL8R6TDBoNtt6NuyCKGHqJeaenm8bXG+MIZVPmDGjRihrmXXUxjzzyCLdGKJvcp61FvO/XTrNWQjZblReNXniPT8M0bQyIInVPrXT7vgeeMxdjRgLIUPWw+wi4qNcRcccSdFGhYLFTcee/6Onq4iVrGRqzlSvkSPyiEki5+m78RmZis1kOaeSoqamJvXv3MnnyZFWtWwByc3OJi4vDx8fn4CcPAcrKyggPDz/oCPFQoLa2lrCwML744gsWLVqkaiPj/wOMRiNz587l3nvv5aGHHuLGG2/Ex8fniCh+f8/QaDSccsoprF69WrWNt4+PD0FBQZSXlx/85CFAYGAg4eHhQxbkeajw9fVlwoQJ7Nix41eNgA9GngNs2bIFgJ6aCjqL+37fJbudyv+9hmS1YkiPJ2jRTNex/lNk3lNHubJNADrW7MDe2EZ1VytvejXxb2sxBkHk7uTp3P/AA5xwy1I0vX/PevYWIVttaCNDEPVKc9dSXAWSjCYsqG/tvXXY98Qsop/8M/Ev34v3lFHIDpm6NiPlNb2N4d4/k+E3nUfI5acqm2fAsq/Pu9SYGqtYtu3Jd33m2nh/v8X12fjT5nPjddfz1KJLSRa9+cBWzbOOUspifUAUaHj+Y9e5Gl9vgi9XlPt1T61E6lXZAXhlJBB0wXwAah97U5mS64eAs+bgO2+ycvzR1zEXVvKVvZ5NPQ1cp4knQmci4aLriTr5fEDg8ssvP6gtotVqJTs7m8TERKKjo3/x3KGGU3Wq1jRbc3MzFotFFfKhtbUVh8PB9u3bSUxMPCRF9TB+PYbr+M9j0aJFrFq1SrVAT7VFbRqNhvT0dHJzc4ckyPNw1pGVlUVdXR3FxcUHv2AABiPPQQnqk+w2JKuFlh0bkOW+r7F+3Vd0VxSBViTqnitcCnGA9q82K41jnYbQ3mwTUPbOHT9so6uzi++TDPzNkk+l3MOF2mie/ftyTjv/XPzDFCJVMluV5rAk4TWyjyy39GaZ6GMVUt7R2gl2Bxh0RD12A3HP30XI0tOR7DLdssFVxy2S8v+DLzqJ0KtPJ/jik0AjgqXPSs+QqmRpdG3v+7dtmjwSZJmO7/smuqMnjOKiKy7jhcef5kSC2epo4VFLAdsSjNitVlrf+NI1jSYIAiFXLkLQaujZkefmea4xeRFx64UgQNeaHXT2I+5BqfPhf75AOb56E40fr6FA6uIVaxlnC+FkWoxELjyXxEtuRuPlzVdff82HH3540J/17t27kWWZcePG/eK5Q43u7m5KSkoYOXKkKs93OBxUVFSo2gg3mUysWbNmuBE+xBiKOv67ItBFUWTRokV8+eWXhISEqFKw9Xq9qr5rWq2WtLQ0cnJyVFWhA4wZMwatVsvOnTsPay0/R54DrF+/Hh+TCWtLIyWvP0N3RTEOi5mKj15Blhx4TRxBwLwst2uaXv0c2WLDkB6Pd2bfZsKcV07PrnyQJYJOm40M7JHaeezHT7j77rsRjAZuDB/LLfpk5orBBFW2gkPCf8rovnvkloJDwpSe6PrMVqMQ+9pQZdxGliSlgAsC4bcpQZpBF/USyz19CkdtaCBIDsxVfZ55xrQ40Ih09iuqpqyRaLU64vObOEsbyQOGEZw1ZRbbd+zgqiuu5L2OEmplixJecsF8kGTqV3zk8mMDCL70FASDDkt+uZt6TRBFwm46T0kSr2mi4a2v3b6XGpMXkXdfhibAB7mjm8r7XqRtbwH3X3czBi8T995/P0aTN9GLLiRw4ky2bt1KSkrKz44Odnd3s2XLFkaNGqVah9mJlpYW6urqVNtwSpJEeXm5apt+J4E+3O0eWlitVtauXctDDz3EnDlzCAgIYNmyZbS0tPCvf/2LkpIStZeoOk477TQ+++wz1TbegGvjrVYdzcjIoKKigo6OjoOfPISIjIwkLS2N7Ozsw1Lk/xx5DvDUU08xdcoUZLuNio9eoSn7R2XD8N3HmOuqEYw6Im6/yK2J1/nTTmWKTICwpWe4PpcsVpo//B6A8BsVNXulbOathjyWLr2GnAMHuGjybO43jOB0bQQJtT1o9Dp8F81w3cOSXw6igGlmn8raXt8CGg3G+L5mvGxWNtOhy84k/HZlvFwYoEzS9dZ9W20f4WxMjQFZpmtdn8+paVIGyDKh5W3M14Ryhz6Fa+MmYtGJ3Hb77Ty95VsOSMrPPmDRTAStFnNOCdaKvrFSnxnj8BqdDAjUvfCR2zr8T53RO7EGlfe/iGzrEzIIgkDIFYvwnqyQ+NX3v0hPTgmv3P1Xvv3+B/76178RGxdPwNgsYs64lB6LhfCISIqKigb9WUuSxLZt2/D19VVtessJh8NBbm4uGRkZh+TXPhQoKysjJibG7Xf+aKGmpobw8HC++OKL4To+hBiu4wfHggULXIK2xsZGbDbbUV9DbGwsLS0tqgjqnM/XaDSqBoMDeHl5kZWVRU5OzmH5sv8ceQ7KO9Jf//pXAJqy11D50WtIVgsdBfto2qTU5Kh7LnOzYLPV902RRd55CYKub0JIqeMCprkT0Qb40oGdr+z1/Om+v/DRx/9j5snzecAwgiW6WEZVWzAZjOjiwlz3sFbUI1ttiD5eLsLe2Qh3TpYByBYbCBB40nRXHTdmJIIoIPXWeEEUXddIZuW9RxcZgmDUI3ebXZYquuhQtKEBBPv6k9Vl4BpdAnd7pZOcOZZ//fvf/PnxR1nvaMaKhFdGIsbRShBm82d91qbakAAlaBSo+cdbLnIdwJAUTchlSqO8/pn3sFa5W+OaJmUQcvXpALS//z3tP2xj8yvv87dH/sq111/PnBPmYQyLIvGSm9D6+HPu+efz3HPP/ezPu6ioiIaGBo93NjWQm5tLVFQU/v7+Bz95CKBmHllLSwuyLLN161ZSU1NVs6L7o2Mo6/jvikAHWLx4Mf/73/+IjIxUbWwqPj5eNd81UNTfzs6ZmhBFkcmTJ9Pa2kp+fv7BL+CXyXNQvrfV1VXEx8XhsHRT+u4Kyt5doajRNSLh153jtunu2pZD15b9IEmE33yB63NZlmla+TWIIv4XzHdTpbd/uZnikhI+0jbyoCWPdY4mYnsE/vHgI7zw0oucFZxCqmhCtDsU5RooAZq997U3tACg8VFGmGWLzfkNcT1DMCjdbkdPX3dbGxYIMlj6keWG1FhwSHSv34MJDZPEAG446QzeevNNrph9EhLwhrWcx+xFfFtdQEd3Fy1r+kbJvCemo0+IBIeDln4dcm2AD8FLFgJQ9/S7buo1bYCv0tWWZTq/3OBGsIPi+xZ57xWIXnoctU3UPPoasm8I79RY0Wk0XJwWjl6jIWLe6YTOPImioiKioqI8QvHsdjvZ2dlERUWRmJiImnC+JCYlJak2el5bW4soioSGhh71Z3d0dNDR0UFxcTF2u50ZM2Yc/KJhHDbmzp1LYGAgf/rTn6ivr+eaa66hqKiIvLw8Xn75ZZYsWaJK6Nyxhvnz51NaWkpbWxtNTU2YzeaDX3SEERkZic1mo7Gx8ag/GxQVfFxc3DGhZExNTSUoKIitW7cekpLul8hzUN4NNm3axGWXXQZA3ZpVlL79HK27NgEy4Tefj8bU93fY3tpJY2+4ZvhN57vZs7V/nY3U0YUmLAivjL460rFmG60tLXxetIdHbQWstFWhkwWumXsKb772OtfPPY0Joj9eiJhzy0EG06h+jfC6ZpAkFyEOIPU2vEVD3/uCc/PubLRoQ5TNntyvOa5PjAJRwNHYikaGdNGH82PH8J9XX+VvDz9CmEXgO3sDD1ly+V93ORXl5TS+2RcmqvH1xn/RcSB4jnmHXL0YRIGeLTmucHFQCIDQ685CE+CL1NpJ7Yv/c/sZCKJI2A3nuCbaah56BUd9G5s0oWxr7OKqkZGEGnX4jRhL/HnX4JBl0kaks327u3UNKPklZrOZCRMmqD65VFJSgl6vV00Fb7Vaqa6uVqURLssyVVVVhISEsGrVKhYvXnzwi4Zx2Biu44cGPz8/5s6dy1dffYWfn58qVioGg4GIiAjVCGxBEMjIyCAvL0+VBkJ/BAUFMXbsWLZt23ZIDYVfIs+duOeee3j//fcRRZGOohxK3niGqlVKLofpxCyM6Qlu92t46RNkh4RxYrpLOQ6KJ3rXhj0gSYRc0KdKt5RU05lXyo8//cQKbTVPWYtolC3MD0nkjTfe4JEHH2aWJphgQa80wgHvrL4mrtOKzZjRbx1mKwiiawINQDBqQRBcNR5AF66EL9vqlD29IIquyTdLWQ3RgpEF2jCe+PtjvPTSS4x3eJMndfBXSz6va+vYsWMHXVv3u90z6LwTQZJo//Bbt32330lTlb263UHjO1+6fY99503GNH0MiAJV97/kIvRd186dROB58wBofOkT2r/JpiE6nXcKGlicGML4EB/0AcEkXnIThqBQbrzpZu655x6Pn2VdXR25ublkZWWpasEGynRDVVWVqlaiauWRAVRWVhIZGcnHH388XMeHCENdx393BPqCBQtob293BZeood4KDg7GaDSqRuCLokhGRga5ubmqkfhOGAwGsrKyKCgoOOjL08HIcyd8fX0pLi7i5IULQZIw11WBLIPdQe3yt13jylK3mcaXPgEBAq44FW1AX/Hv2VOIJU+ZEgjsDcwCpVhbiipBEPDOTMOKxFZHK0998BZLLr2Udw5sQYfIhboY/u49muV/f4xlN1zHVF0wUYIRua1LUXr166o7O9po+xHoTl/wfuNhutAAAGwVdXghkiqaOHlcFrfddhvP3no3DxnSOU4bRI1O4r5nHufqq6/mvaIdFMmKz7zf/CxwSLS9951rMy8IgtLZlmRa31jt1tn2nTNR8WaVoe4ld381r5GJro543ZPvKLY0/aCPCiHy7ssRNBoQBDB4Y9fqeD23Fp0o9JLoIqEz5hNx4pnU19cTHBziemmTZZkdO3ag1+sZM2bMz/6sjxYaGhpoa2sjNTVVtTUUFxeTmJioWrGOiIjg/fff59xzzz0k3/phHD7WrVtHcHAwc+fO5YQTTuDEE08kMjLy4Bf+P4OPjw+nnXYaH330EcHBwVRVVR31NWg0GuLi4lRVEqalpVFXV0dLS4tqawCljowfPx673X5QH9WDkef98dprr/Hcc88hCAI91b1Te1otDc//j+69fSGqTa8pU2T65GjF+qQXUreZlo9/BBnCbzjH9bnscND+9WaQZYLOm4cM5EudvLl7PVdecSUPPf4YTVoHc7QhPGLIYPnVN/Lnm29mQfp4kgVvDIjYqhtBll2TZM7nAQj9Nt6ivrfW9yrSBK0WTYCPEkBqtRMjGJnhHc71t97Ck08+yd+NIzlbF4UMvLZ1DUsuvZSnP3yLHVIbNmRM08YgeBmw1zS51HMA/idPRzDqsZbWYC7se7fUhQcRdM4JgKd6TePjTfitF4Ig0LN+Dx1rd7p9/xVbtovRRYeBKOKwO9CafPmusoWt9R0uEt0Un0rCRdeDTsfkrCmsXr3adY+ysjIqKiqYMmWK6nXDZrORn59PRkaGakR+WVkZAQEB+Pn5HfVnt7S0YLPZ2LVrF76+vkybNu3gFw3jsDFcxw8dF154Ie+88w4xMTGq7YkTExMpLy//VXaiRwIRERH4+Pj8KvuUI424uDji4uLIzs7+RUL/UMhzJ84991x27dqFt5cXluYGJIcD9Aa6vt9G66c/uaxAO9ftwryvGJAJv/ZMt3s0v/stiCI+p0xD49tn5dn2TbZinXrqDARRpE62sNpczc033MC1117LPoOFdNGHO/UpPDHnHO65917OX3wWo0Rf/NEqNVQjYkzqa6hKZgsIgkvIBiDo9CAIyP325NrwINBocNQ1EyLoGS/6c8n5F/DwI4/weOocrtMnEiEa+bGrhssuu4y7/nwbPzqaaMeONtAX70kZoBHdRG3G1Fi8xqeBKNL0vx/7ni+KhC47UxGufb0FS0kfXyIIAqFLT0cbFoTcY6Hm6fc83sECTp+N34Kprv/WBwRT1G7m7bxaF4mu9fEj4eIb8YqM5W9//ztXXnml6/yOjg62bdvGuHHjjomwypycHOLj4zGZTAc/eQjQ3t5Oc3OzKo1QSZKoqqoiICCATz/9lAsvvPCor+H/A4a6jv/uCHS9Xs8555zDe++9R3h4uCoFWxAEkpKSKCoqUm38Ozo6Gp1Od0yMEfr7+x/UR/VQyXMnRFHkiy++UFQ+skz0aRcTf8GfsNe0Unn7c3Ss3UnTO1/j6OxGExpIYD9bF1mWaX7naxAFAi45ya0L3fb1ZhBFfBfNcI2AybJM5+Z9WM1mSuN9+dBezcOWPB749kM+//xzpBB/Jor+XKdP5PGwyTz//PP87W+PskQXy+naCObqw5g7dy4zZ85itOgLQKZ/BLNmzWLe7ONZoA3jHG0UyxIm8cQTT/Dy08/xqHEk5+miSfQOoKy2mpdeeol7G3fwjLWYbx0NNMb4gyjStnaHa+3GkYloI4LAasN8oO/n7jUutTewDJq/7BsbEwSB0GtOBwF6Nu91U68B+C+aqRR6QaDygZfdNuYAhuRowm+/WNmcF+6j6quPsDgkNxJdJwoETTyO6NMuprOrk5CQUNdEQltbG5MmTVJtzNoJ54tiamqqagRAW1sbra2tqnmtVVZWEhYWxgcffMBFF1101Nfw/wWtra289NJLeHt7849//IOoqCjGjBnD9ddfz3//+18aGhoOfpP/J7jooot45513iIqKUm2aKjExkbq6ut8Uhv1b4OXlRVJSEgcOHFDl+f2h1WqZMmUKtbW1P/tecTjkuRPXX389d9xxB8gyPmljSVl6N8aACGoffZ3G17+gc+MeurL3gSQRcYv7RqL1s/XIZiv6+Ag3T/Tu7bk4WjsRfb0x9LNg6dqagywK1I2M5Ct7PU9ai7infBOvvfIqVXW1pOj9uEgfy6OGDFY88FeWL1/O1WGjOEsbyXxNKCdMnsasWbPI9AllVG8tnz5tGnPnzmWuEMwZ2kgu0cXy6AMP8cILL/AP37Es0ycwTvTH7KXlf598zP3rP+Wvlnz+Z6+hJMobu9VK5zfZrjWKeh1+cyeBKNL88VrX5xqTFwGLZ4EA9c994PZ98D9lBrqYMLDaaXznW7djxuQYgi85GYCGFR8pYan9IHobibznMrRBfmC3UvTGMzgsZg8S3SsylsQlN6Lx8ubURYtYuXKlW36JWhvd/igsLMTPz4+wsDBVni9JEiUlJSQlJany/IqKCqKionj33Xe58MILVX+3+qNiuI4fOs444wzy8/NpbW2lqalJlWDs4OBgvL29VXuPEASBkSNHUlhYqFoweX+MGjUKb29vtm/fPihHcTjkuRNjxoxh//59IEuIBiNp19xDcNbxNL/3HTUPvYK5oILG1z4HIOy6s9H49JHk5vxyuncqwd7BZ/aFhDo6u+lctwscEoEL+6Zie/YVI1tsNDksbNR08JKtjHstuTzxr3+ye9cuwkLDOEUbzn2GETx37lKefvJJ/jzjZM7XRrNQG8bc5NHMnjWLrNgUVx3PShvJ8bNmMzcsmVO14Vyki+Gucy7huWee4Zlpp3OHPoXjtcGYgoNYt3YtDz/7BPdZcnnTVsHuUA1dkh25qwd7S59o03/+FA9RG0DQefNAkuj4fD2O9i7X54aESPxPnQGCQM3f33SzXRWNBsUPXRSw7C5QBAL9IAgCwZeejGnqaBAEyt59np6aCg8SXWP0Iv6CazElpPHqq69x+umnu/JLEhISiI2NRW00NzfT0NCgan5HcXExMTExGAyGo/7shoYGRFFk7dq1pKamMnr06INfNIzDxlDX8d/l29fFF1/MBx984CLQ1SCxY2JiMJvNqo1/Owt2fn6+6mNjAFFRUaSmppKdne3xAnW45LkTf/3rXyktKyMgczr+Iydgiksm+fLb8UkaTcOKj5RQD0km8s4lbgEmXdn7lU2kRuNGrDs6uulcvxskicCF012fW8tqcTS1gV6LLrLXqgUo3b6XtevXsaqrghW2Uu615PDAhs94/vnnWZO/l0qpBxmI0Xpz/PHHs3D+fGZqlZGwGb6RLFiwgKmTsghERxcO8oVu/vfZKpYvX869nfuUMTBbBauL9rBz926a8vr5oE/KAEmi87u+zrYgCPjPnwoCNL3ztdvnigpdov2979zGyfRRoQSeeTwIULP8bTeSXBBF5UXH3we5o4vaf33g8W/Je2wKYdefDUD77k00bvwWqyR7kOh+6ePxjknCYjFz7bXXUlhYyJQpU1QpTgNRXV2NxWJRbdMLfcVajaTv5uZmbDYbO3bswN/fn+nTpx/8omH8KphMJk466SQee+wxsrOzaWxsZPny5Xh7e7N8+XJiYmKGX5Z6cdJJJ9HR0aHqNJm3tzcRERGqKsdSU1Npa2s7LN/SoYLTR/XAgQMe3vS/hjwHxXJj+eNPoA8MJebUC9D7BRB33jWEn3A6Hd9tpf6fH4AA/hef5OZjam/tpO3z9YqP+LVnud2z7ctNIIoumzJQski6Nu8Dh4Tf1L6pp8acQrZv387neTt51VbOw5Y87m/ayZNPPMknn31KodyFGYlgUc+UzIksWLCA2YZwZmuVd4G5M2Zx/PHHEykYcCBTLnXzQ84u/r1iBfdv/4p7Lbm8YCvl08ZCNqxbT8mavo2vITka0c+E3GPF1tA3ZeB7wmSQJLp+3IbUTxHnf9JURG8v7HXN9Ozt8yMXtBpFvSZJdH69EUtZjdv3w2/+FExTRoMoUPngy26j46DYtkXeezmitwFHZxvFbz2HZLN6kOiG4HCCJs1CliTuuONOtm7dysiRI1WxHRsIs9lMUVERI0eOVE197vw3ERERcdSfLUkS1dXV+Pv7s2rVKi6++OKjvob/Lxiu44cOX19fFi9ezEcffURISIgq02ROUVtxcbFqorbg4GCCg4MP2c50KCEIApMmTaKzs5O9e/e6fU9+DXnuxMSJE0EUiT9vKVqTD+HHn0r8BX/CUddO9X0vIlts6OIjME0f6/a85pXfKMK1s+e4Wbd1/LgDHBKGtFi3CfKuLQdcqnQnulvb2bd5K5+v/oL3xDqWWwu523KAR5//JyvfWcleexst2PBBy+ioeE6cN4+5MWmuOn58+ljmzZ1Lil8IekTqJAtbm6t47bXXuP+Vf3OXJYdnrMV8JDbw7bffkrdxGw56J71FEdNkRW3evbVP7GAcnYQ2zFPUZkiMwjtrJIgije9/4/Y9DDxrLpogP6SOLppWrXU7po8NJ3Tp6QA0vf4F5nz3kHvnnt04UvFzL3nrn1ia6jxIdFGnJ/z4U0GA1atX8/nnn+Pj46NaWGd/OH//kpOTMRqNB79gCGC1WqmsrFSNE6isrCQmJoaVK1cO1/EhxFDX8d8lgT59+nR8fX3ZuXMnNptNlfFnrVZLQkKCqhvvsLAw/Pz8KCgoUG0N/ZGWlkZYWBgbNmxwedr+WvJ8z5493P/AAxhCI4k4oc8fSmP0Iuqkc9B4K8XWZ/FM9NF9aiTZ4VACTASB0KtOQ9D2Wa24inVqLNoAX9fnXVv2gyjgM2dC331kWQkQlWQMKUoytwxUl5axZ/8+dlhbWONo5FN7La8Ub+P+++/n/mef4HlrKQDP9xRxzz338PDDD/OevYrV9jrWO5rZVlpAXl4ebY19limGlFhlrGtP34uXPiESTYAvWGxYq/uaND6zMkGjwVpchb2pT+3vNSpJKaqCQNOqn9y+lwGnzVK83ixWGj/4zu2Yxteb8FsvAgTMW3LoWOPpf+ozfSzBl54CQMO6r2jescGDRG/89r90VxYzbdo0zjzzTCZPnqzKiPNAOBwOcnJySE9PVy0wxWKxqF6so6Ojh1VrKsBkMhEUFERQUBCBgYFotVpycnIOfuH/A+j1es4991zee+89IiIiVBv/TkpKoqysTLXxb51OR2pqKgcOHFA9GBwUH9UJEyawbds2F6n/a8lzh8PB2LFjQRCIPetyRL3SUBUEkeDJs/BJVV5exSB/gk52b+y1fvITssOBYUQchoQ+lbm1sh5zTilIkqLG6oWlqApHWycY9ejC+kaUzfnloBHdrGGaa+vJyckhe98e1jma+cJex7u2Kh5+5GHuuecenrOVsMKqbIgfe+NF7r//fl6v3ssqey0/OprY0lTJ3v37qKvoI4sMKYqyq2df3zuhIPY+VyPSvmmv63N9VEjvJlikc2Pf56LRQMCZxwNQt+JDt98HY0oMfidNVdRrj7mr1wRBIHTZGWhDAsFso/qpdzx+l3QRwUTeczmCToOtqZbSj15FlhxuJLqxMp/6n1YTERHFww8/TGxsrOr5JU7k5eURFhZGUFCQamsoKioiMTFRlRpaX1+PRqPhxx9/JD09/ZggQ/6/YLiO/zL6T5OpVcejo6OxWq2qTgeMHDmS0tJSurq6Dn7yEEOn0zFt2jRqampc7xa/hTxfuHAhzc3NRMw7A6+IPhWzKS6ZsNmLlP+QJCJuvdCtwdmzp1DZS8sywace5/pcliTav9rUa8N2otvnXdn7wSHhP6VffS9QyGRdXF/z0opM/rZdbN26lWxDN1/b6/nQXs2TH7zJvffeyxMFG111/KkNq7n3/vv497rV/M9ew3eOBrIdLezYsYOiLTtcZLnGz4Q2JABk2WUXCyiB3A6Jls/WuT4TBAG/BVMUUdvKPlEbQNC5igq96/vtbnt10agn9OrFIMu0v/+9h32q76xMfOZMVMK/H3lVeafpB0GnJeK2i9DHRgAyRa8/ja2txY1EH2WUKH//JfQGL+688070ej0TJ05UPb8EFB/2jo6Ow+KDjjRKS0sJDAxUJbzUbrdTU1ODTqfjhx9+4IILLjj4RcM4IjjSdfx3yaSIoshFF13EypUrVR//rq+vV61YCoLA6NGjKS4u/lnrlKO9nnHjxhEUFMSGDRuor6//VeS5w+Ega8oUBI2W2DMvR9S62240bPwWR3cXgq83oWef4Hasc90uJVTEoMPnuHGuz2VJov3r3mJ9/olu13Rt3geSjN/MPgLd0dSG1N4FWtEtYdxe1wxybyCo8969QaFiv866K3l84CY2MhgEwc371JiqEOg92X2dbUEQME0Z1bvx3uP6XOPjhc+McaARaf5qk9u9nSr0jo/Xuo2NCTotocvOAEmm8/MNHuo1Y0oMwZcoSr7Glz5xBaf2h//CaQScPhuA2m8+ou3ADqySzGsHqpFaG7lu8UlMmzqVP//5z8yYMUO1EeuByMvLQ6vVqjq2VlpaSnBwsCoNBafXmp+fH6tWrRq2bxliSJLEli1bWL58OQsXLiQgIIDp06ezYsUKIiIi+Pe//31M+GQeK3BOk4WFhak2TRYUFITJZFI1lDspKQm73U5RUdHBTz4KiIqKYvz48WzZsoXa2tpfRZ4DzJw5k87OTiIXnoshxF2121VRTEfOLgAi73CfIrM1tND+bTZIskuR5UT7N9kgiphOmOhmz9a15YDisbpgitv55pxSV+PcCXu9Un/1yX2+qbIkKfkmAyD0Boq6sk5ACR51SPQU9dVKXWQwgpcBrDY3BbhpUgY4JDpW99mrAYqfqSTR9M5Xbr/3fidmofEzIbV00j0g4Dvo3HnKsdZOmlatczsmehmIuE0ZAbfuK1HU+wNgSIwi4vaLQRQwl+ZT8dlKZFniu8oW1u/P54YTpjBmzFgefvhBUlNTVFV790djYyMVFRWqksatra20tbWpYsMGw6q1o4nhOn54WLBgAd3d3RQVFdHR0UF7e/tRX4NGo1Fd1Obn50dcXBy7du06JprhJpOJGTNmUFFRQW5u7q8mz//zn//w1ddf45eRSWCme6PbYTFT+93HgID/+SeiC+trcPZXn/udPw/R2DeR3LO7AHtjGxh0SjO5F+a8MqSuHgRvg9tEmjm/QmmEz+hTt0vdZqXWCkLfnpteD3RZHpBlogNJdq/jvft4R5s7h2NMjwdRVJ7ZC68xyQg6LY6GVhydfZZ/vrN7RW1F7qI2fUwYpuPGgSjS8IZ7aKj3+LTe0FCRmife9vhdCbn8VHTRoeCQqPr7G27NclBqfeTdlyqB5g47ha8/jb27k6J2M69tzeXM9BhmTZvKn2+6gbFjx7JgwQLV80tAEWLs3r2bjIwM1dajtg1bTU0NJpOJ1atXM3PmTGJiYlRZx/8HDHUd/10S6KB0vD/77DNX8rfUG2JxNOHl5aX6+HdAQADJycns2LFDle/BQAiCQGZmJl5eXmzatImkpKTD7jROnDgRi9lM1KKL0AcEux0z11XRtPkHQCbilgvciqZss9P8vqKwDlt6uhKA2YueXYMXa2t1gxImJgoYkqL6ntM7OuVUlTlhq2kCSXIFgkLfxlrj1/dCIgwo6E5oQwNAFN0IdH1CJIgiUlsXcj8VpGvj/aU7Ue4ME+38YoPb+ca0OLzGpypjYx+scbvGmJ6A7wmTQBSoWf6WR0H2WzAVU9YoJQX84VfcXhCcMCRFQ+9eumrV23QU7Kd01Ts88Jc7CQoK4vbbbycrK4uoqCiPa9VAS0sLxcXFTJgwQTXVtdrFuq6uDq1Wy5o1axg1atSwam2IERAQwLRp03j22WcJDg7m6aefJj8/n/Lyct544w0uu+wy1QiYYxHTp0/H39+fHTt2YLPZaG5uPvhFRxjHwvi3RqNhwoQJ5ObmqmJlMxhiYmIYOXIk2dnZyLJ82OT5s88+y6bNmwkYN5WA0ZPcjkl2G9VfvAuCgM8p0zHEu5PrLf9dAzIYxqe6TZhJ3WZlkkySCDp1putzWZbp2rwXJAn/fvYtjq4ebDXKBJcuou9dwlbXDKKIV2pfgJTstDcbQBiLBiV8TDL3WaM5G+iW/DLXZ4IguHzazQX9Nt6jkhD0OqTWTuytfWoy08R0xd6lswdLv9BQUa8j8GzFJ7b+hf+5AtpA8TMPcanXvvMM/46LIPSq0wBofudrevZ7vptqQwLQ+PuARqQzZyfV335C654tvPjwPaxfv5EHH7yfpKQkjjvuuGOCPLfb7ezcuZOMjIzDIn2ONIqLi4mNjVXFhs1ms1FbW+tSoA+r1oYWw3X88KDT6Tj//PN5//33VZ0mS0xMpKGhgc7OzoOfPEQYOXIkXV1dlJaWqraG/vDx8WHatGkUFhZSWlp62OR5Y2MjS5ctQ+cfTNTCcz1qQt2Pn+Po7kQM8iVo0XFux7q2HMBaVgOCQNBCd+K97Sslj8z/7Llu93Tat/icNNXtfHNuKTgkvNP6/t0599GCj5fbuU4bU9HY97faSaZbW/uaO6Kvt7JPd0hue+LBpsJFvQ6vcakgCnRvz3V9rvHxxmf62MFFbWfPVcRxW/a5TZIDBF9yCoJBh72ywWPyW9TrFCW/ToO9tIaGAep2AMHLgD4mDCQJuaeL4rf+SXdVKd/98+8sf/xJ/nTtNUyaNInFixcfE+Q5wL59+/D19VX1b2dNTQ2iKKpiwwZ9jfC33357uBE+xBjqOv67JdBHjhxJRkYGP/74IxqNhrq6OlXWkZycTFlZmarBISNGjAA4JrzXQAlMbGlpcTU3nHYuh4o9e5SR5vYDO3GY+/zUZclB1RfvAgJeM8bgleE+Wtz+7RYcLR0IPl5uo90AbV8pnqn+Z81xK9bdWw+AIOCVNcZNAaeMfWvwGXAf54ZVG9qnQHdurMVgX7dzBb1CoPcnuRXlmgNzWZ/frajXoY8LB8BS2uc7a8xIQDDqkTt73EbJjMkx6OMjQJaVUbd+CDpPUaF3fbcZe7O7CiToggWIJi+kpnbFQ7b/Wl0j4AFgtVO9/E3Xxl2WZVq/2EDd0+/imzYWU3I6CAIVH71CW85Oxo0bS0REBL6+vlRVValmhdAfDoeDHTt2kJaWpqqVTHl5OVqtlvDwcFWe7yzW77zzzrD6/Cjg8ccfJycnh6qqKt5++22uvPJKkpOT1V7WMQtBEFzTZNHR0aqOfztHK9VCUFAQCQkJ7Ny585hQr9lsNiorK/H19aWjo+OwmxvPPfccAD0VJZjrq92ONW74FltrM4KXgZBz57kds1bV07lWIcnDLjvV7VjHul3IVhvaqBBXXgmAraIOe0MraESlId0LSy+RrQkPdFe41zWDMKCO906SoXEnCASDFkTBNWkGvY1wwNHiXmONaXGKLcuBfjYuOi3emSMU/9R+inJBq8Fv3mQQBZo+dLdW8507EU2QH3KXWclt6QfTpAy8J2Uo6rWn3vX4XfE9fiI+syf0BpW94fYeYM4ro+reF9GgJ2SaMonXtmM91avfIzwsgilTJuPl5YXValWVhOqPAwcOYDQaVc0w6erqoqqqSnXV2ueff87s2bOPGZHCHxXDdfzwcdFFF/Hhhx+qOk1mNBqJjo5WdS+s0+nIzMxk//79x4SViyzLVFZWotVqEQSBioqKw/rZ/POf/0SWZRxd7XQU7HM71lVRTOvOjSDLCuHbr8He3041+NKT3abFbLVN9OwuAEkiYG5fc12WZbo2KTkm/tP6+ajb7a7JaH1iX313EuiGOPf9ldyt7Mn7K9AFg/K/5dZ+09mCoOx5QRHY9cI1Fb7FPdzdNDkDJNlj/+x3Yj9RW78pNl1EMD7HT1BU6L0Bq05oA3xcGS6NL3/iFk4KoIsMIfRPSv5Y5xcb6er37uBo76LmkVfp2VNE+NzFCDod9tYmSt/6J6IkseDEE5BlGYPBoBo3NhB1dXVUV1czfvx41RrzsixTUFBAUlKSKmswm800NDTQ1dXFvn37OOussw5+0TB+NYa6jv9uCXRQxr/ffPNNYmNjKS8vP/gFQ4CgoCBCQ0PJy8tT5fmgWNpkZmZSWFioupWL0/N8xIgRzJ49G39/f9avX39YyezLll0DQHveHopfeYKu8kIAmrauxVJfDVqBsMtPc7tGMlto+UhRXYddc4b7Zrm2iZ49hb3FerLbdZ2b9oEs43/8eLfPlbFvh5sCXeqxIHUpX4fo1TeKJputIAjovN274M7iLbltvJUNuzW/1O1cY3o8aDRY+oWGCFoN3hPTQSO6FU/oHf+Woeld9860ITEK78nK5rrhndVuxzQ+XoRcoXjVNb/9lYd6TfQ2Et6bAm7Lr6T145+Q7XYaX/qE5re+JHjKHGJOv4TY0y/DKyoeBJEZ06dz6623Mm3aNI4//ngcDgdbtmxRnUTPzc1Fq9Wq6rNmt9vJy8sjIyNDlWJtsViora1FEATWrVvH+eeff9TX8P8N11xzjarJ8r9HXHzxxXz22Wf4+PhQWVmpyt8OjUbDiBEjyMnJUXWSKyMjA5vNRmFhoWprAHfP89mzZzNu3Diys7MPazP2xBNPoNVosbQ2UPL60zRt+QlZljDXVdG4+XtAJvzm8xWFdz80v/8dCCLGaaPcVOOyLNPeu3ENHmjDtuUAiALeM8e6/a0155crSvOBjfCaRnBI7lZsToW51n1yTNDrgQEK9CA/EAWwOdwU4oaUGJAkeja5Ew2myco0WevqDW6f+82dBDJY9hS5qdMFrZbAcxR7uoZXVrk14QFCrlikqNPKaxVF/gCEXHEquqgQkGSqHnsN2e6gY+1Oqh95FWNgBAlLbiLsuAWEzJgPQGRkJI8++ghpaWksWLCAhIQENmzYoPo0RGNjI+Xl5WRmZqqqhs/NzSU6OhpfX9+DnzwEKCsrIzY2ljfffHNYtXYUMFzHDx9Tp04lODiYzZs3I0mSal7kI0aMoKqqShUbGSdCQ0OJjY1V3cqlv+f5zJkzOe644ygrKzusvJVly5YRHhqGZLNS9dk7VK16G4e5x22KzDQ/C2OyuxVF57rd2GubQKfBb85Et2Pt324BUcQ4eaRbqKi1uBpHawfoNOhi+ibPLCU14JAQTEY3It5e1wyigDbF/dnOWu0kzQHXdY4O96aGNkKxnHGbCo8PB42I3G1xC/n2nqCIx6ylNW7vA4aUGEUEJ3mK2gJ7M00sewuxlLoLNHznTMQwQtlL1674gIHwmTIKv4XTQIC6p1Ziq23CWl5L1d3PY69uJeHC6wjOmk3cOVeBIKLT6bjjtj8zYcIETjvtNKZOncru3btVtScE5X1y165djB49Gm9vb9XWUVVVhdVqJSEhQZXnl5eXExISwgcffMCiRYtU8WD//4ShruO/awJ9yZIlbN68GYvFQl1d3WGRtEcSGRkZlJWVqdptDggIICUlRVUrl4GBoaIoMmHCBEJCQli/fv0hb8ZWrFjB6tWrMej12DpbKVu5guovP6BhreIjFnbtWWgGjGy1rd6I1G1GDPRT1Fn94CrWk0a6XWdvbMXaW9C8RvUpiySzFWu5QhQYEvrGfGy9vqmCdx95rpxvAVFwK9bQj0AfZPTbVu8efGtIiQGHg84BxdfUG1zS+oW7f6rP9LEIRj2OxnaPouwML+nZsM81vu6639TRvWNoIjXPvOfxEmWIj3SR7C0ffk/lX1bQuXYXUadcQPjxpyIIIqJOT9w5V3HyGWdy/fXXYzAYiImJQavVMm3aNNVJ9ObmZkpKSsjMzFQ1MLOkpASj0aiaWqy8vJygoCDeffddFi5cOKxaG8YxifT0dCZPnsyqVaswmUxUVXlmMBwNxMXFIcuyas14UIj8zMxM8vLyVCMvBwsMjY2NJTMzk61btx7ylMDpp59OeXkZyYmJyJKDuh8+pWzlCqo+XwkIGLMy8B7r3uC0FFfRveWAoj6/aKHbMfP+YqXpqxGVxnI/dPbmmPjPyHS/JrcMJAmfdPdpNXuN0jwezIpN1A0k0HUg9DbKnZ9pNErIN+Dop/B2Bo476lvciHWvzDQQBezVjTi6+t5TtSEBeE8YAaJIy7eb3Z7rO2u8onS32mj/fpvbMW2QH0EXnQT0qtda3X9XRIOe8FsvRNBqcJQ3UHbnczSs+Aj/kROJP38ZWi8l1yX0uAWMO2kxjz76KNXV1cyaNQtRFElPTyc+Pl5VEv1YsW5pa2ujurqa9PT0g588BGhvb6e1tZWamhpKS0s555xzVFnHMIbxSxAEgauuuor//Oc/xMXFUVJSoso6TCYT8fHxqoe8jho1iu7ubtW+D4MFhvr5+XHcccdRWVnJ7t27D4kriIqKorq6yiXAacvZRdHL/6D685XYWpvBqCP0ggXuz7bZaX7/WwBCLl/k7k9usdL+wzaQJIJ7c7Wc6NqyX8k3mTXJsxEuCHhNcv8brEySCXj1m0aDfrW8vwLduR/vdueJdGFBoNEoZLzzXK0WQ6KyX+qfCabx9caQFgcCdO8q6DtfEPCbr1jONL33jfv9QwNdk2b1L3/qdkwQBEKvOR0EsO4tUb7+AQi+aAH6xGhAoOK+l5QJMo03SZferAjZAFNcCmnnXMF9992Pv78/ixYtQq/XExoaypQpU1Qn0fft2+fKB1ALkiSRk5PDiBEjDsuK8EhBlmXKysqIiori1Vdf5eqrrz7qaxjGkcXvmkAPDQ3lzDPP5K233iI8PJyysrKDXzQE8PPzIzo6mtzc3IOfPIRwdlrUGF8bSJ474QwWjYmJYe3atdTW1v7CXfqwcOFCGhrqmTZVKUqte7KRJQldSjSmaWPcznV0dNP66TqQZcKuOd2t8EoWK+3fb1U8U8+Y5XZd17YcEMAwMsGtwFuKKkGWEf1MCP3UaM4Cq48OdbuP1KtA71+sAZeyrv/G2zn6jcXqRl4be5XulgL3Iuc9LhU0Io6GFrdgUNGox7d3NKzp0x/drtHHhmOaPhZEkfo3v3A7JggCIVedhqARsZfW0PmTp3rNd85EfGZlKmGnlfXELL6UgDF9yn1RgNPTY7nw/PP42xNPcfoZZ7J9u+LhpjaJ7nA42Llzp+rWLVarlYKCAtVC2GRZprS0lOjoaP7zn/9wzTXXHPU1DGMYh4prrrmGF198UdWNtyiKZGRkkJeXp+oETVBQEImJiao0wwcjz52Ijo5m8uTJ7N69+5AVbJGRkRQWFnLHHXcgCCLdlaVYGmpAkAm/6nSP852BY96zJ7lGq51o+1rxTPU5dYbbqLittglbZT0Iiu2ZE7LD4fIWN/RTqElWm6uWiv0Cwp2bbsHLXREvGHQgu4eIQp+nev9muMbH29Ukt1b02bRpTF4YMxJBEOje4T6t6HdilhL+/ek6Nx9WQaNRLNlkaHpztcfz/eZNxpCsbKxrV/yXgdBHhRJ67ZnK11bVSMC4KUQtPA9B0/dOMy7Eh7uvvpSvN27h/gce4Pbbb1eeLQiqk+gHDhzAy8tLVesW5zoSExNVU8456/irr77KkiVLMJlMB79oGMNQAZdffjlr167F4XCoKmpLS0ujoaFBlUwVJ7RaLePHj+fAgQNHXVw3GHnuhI+PDzNnzqSlpYVNmzYdkv2sKIq8++67rF69GqPBgL27g/bc3YBM2LKz3CayAdq/24qjpQO89PjOGu92rHPDHuQeC2KAb2/96ltz5yYlx8TvOPeJMXNeOQhgGuPecLfVNimTZP2s2ABki5JnIgxGoPe4f73asEBFcFZd7/a5MS3OYyocFFU4CLT9sNX98+PGIhh0OBrbsJS4W9YFnD5byT4rqlS83PtBHxWqqNQFqHvuQ7cGOyhkfsQtFyAYddDZDXovEi66AZ1f39ccatRxx+nzwS+Q++67j1GjRvUdU5lEPxasW0CpoxqNRjUSv76+HofDQXZ2NiaTiXnz5h38omEc0/hdE+igjBe9/vrrLgJdLfV1eno61dXVqlqoOBXfhYWFtLa2HrXn/hx57oQgCGRkZDB+/Hi2bdtGQUHBIW2+fX192bhxI6+//joCAsgStuIamld+7VYEW1etQ7ba0EQEK+rqfujcsAfZbEUM8PEYMevarIxZ+5/gbuuijH0LGKeMcvvcVtcy6LiYbLaCjKcCvTfApP/GV9TrEH2VjZijrW9kWxsehOhtBEly8zsXvQx4jUoGUfC0cZmnbLzNm/bj6HQvuoG94SWWnQVYytwV6rrQQAJ7R+AbXvJUrwmCQMiVixSPWVGk5sdVSL2EkpdW5PL0SBJ8jazYX0P3hLkIOj1ZU6a6lJtqkujHgnULQEFBAQEBAYSGhh785CFAQ0MDDoeD7du3o9frWbBgwcEvGsYwVMLZZ59NQ0MDJSUldHZ20tLScvCLhgBRUVEYDAbVSHwn0tPTsdvtFBUVHbVn/hJ57kR4eDizZs2iurqaLVu2YLPZDune//jHP9i/fx/+fr0WGJJM/b8/cgvW6tlfTM++IpAkQs4/we16e2Mr3dtylUb4gmlux7p6c0wMY9MQtH1rtlbUK8Ggei0a3z7y097Q+7ul17lt6JwWLuIAKzZRpwVZdpskA9CFBYLGPRAcnHZsosfG25Q1EmSZtm+z3T73GpuCNsQf7A66t7uT66bpY1xWLO1fD8gtEUVCrzkDkLHuKVK+DwPgM20MfvOngCDQujsba7NCEgjAibGBnJ4YyrsFdewOSMQrOoEnn3ra5V2vJonutG5Re9Pd2NhIc3MzqampBz95CGC326moqCAgIID3339/uBE+jGMa4eHhnH766bz11luEhoaqJmozGo2kpKQcllXJUMBp5XI0c01+iTx3wtvbm5kzZ6LT6Vi7du0h290sXLiQlpZmpk/rq8HN73zt1hRW7FR/ACDsysXuvuiyTPtXm0CAoPPcCURbVQP2+hYQBIW87neNObcUJNklNHNdM0gmmSzLrkDw/u8DoqE3k8zi/s6iCw0AWcZW4D5ZZ0iNVabCB9ixeU9KV/bWe4rc/M5FowHf2b2itlU/uV2jDfLDf8FUEAXqXvrE43ch4LRZ6MKDweGg7nV3r3RQJtXCbzgPZBm5s532A33CtxEBXlw7Opq9TZ28X2vFd9JsiouLmdbvZ6QWid7fusXLy+vgFwwR7HY7+fn5qtmpgkLgx8fH8/LLL7N06VJVp+OHcWTwu/8Jzpw5k/DwcH766SdEUTxkhfORhre3NwkJCaqPjfn7+5OSksLOnTuPSjPhYOR5f0RHR3PcccdRXFzMjh07cPRTW/0SSkpKkGWJ0NknEzpjAe1fZVNx89O0r9mOvbGVti+VEJOwqxe7b4jl3rAPodfWpB8c7V1KV1sGr/HuHknOz30GhJQq42IiXpEDFegWkGUPAt2pQPfceCuea24jY4LQOxomYM53L3CmrJFKcMmAjbc+JqzXP02gY4CSXB8Vgs/sTEWF/upnDIT/SVPRx0UAAnUvfOJxvP8IuL25kcqv/0u4l47rRkfTY5d4cX81rRY7huBw4s9bigykpqa5GkhqkOjHinVLT08PJSUljBw5UrU1lJSUEBcXx4svvsjVV1+tysjaMIZxqDAajVx22WW89NJLxMbGqkZgC4LAyJEjKSgowGq1HvyCIUJ/K5ej4eV6KOS5E76+vsyaNQuHw8G6desOWV1nMplo7+jAOy6ZmDMvx17WQOXtz9H01pc4Ontc6nPTSVPRBrp7Tbd/vxUE0I+IV/zH+6HLmWMyZ4Lb504C2+ihWlPqri7cXbXmGvv2HZBlYtApG9cBCnCn0tw+kEBPiVUCxXa5TwKaem1nrPkVbk11QRSV8W/BM0xUEEWCzj8RZJnm97/zaJTr4yIIWDQTBIG6f37goV4DCF6yUAlWFUVK3n0ercPGRWnhjAny4fl9VeS39iBqdcSdfRWG4DBuvPlmPv74Y+X5KpDoTuuWkSNHqmrd4iSiUlJSMBgMB79gCFBZWYm3tzerVq0iMzOTMWPGHPyiYQxDRVxzzTW8+uqrREZGqipqS05OpqOjg/r6+oOfPIQYNWqUa08w1DgU8twJrVbL5MmTiY2NZd26dYccoG40Gtm3bx+iTk/8Rdeh9w6mdvlb1Pz9DayV9bR9uQmpy4zgZ8I03f3vlaWgwmWP6jNgklyxbxEwZqW7ke72xlak9i4QBLThQX1fq92uqNwBbXDfO8FAgtwJQdcbImpz34u6csmq3T37jakKWW8tq3UjvHVhQS5/9p597gIH5zSZImrrdjsWsHgWgkaDo7qRnn72L8ratIQuOwMkGfO63fTsL2YgvDPTFCU7UPPVh/TUVDAz0p/zU8P5pKSBbytbkIGQGfMJzJzO5s2bOfPMM13Xq0GiHwvWLQBFRUV4e3sTERFx8JOHAN3d3dTV1WG1Wlm3bh2XX365KusYxpHF755AFwSBP/3pT6xYsYKEhASKiz3/8BwtpKWl0dTURGNj48FPHuJ1AEMebHo45LkTAQEBzJ49m66urkMKF+3o6ODhv/4VQ2gkIVPmEDrjRFKu+gum6FQaX/yYilufBUlCGx/p5mMOYMmvwFbRW6ynj3U71rUtB2QZbWyYW4iJLEmY88pAlt3GvgFstY3gcHiMi0lmK0gSon7A6LfR08IFFLU5ouCpXEuLBUGg84D777DT79VWUoPUbXY75r9girK5/vB7N89VgMAz5yjX5ZUrX1P/tWk0yni3LGHZleehbgfFqiZ02RkAZBhllmZEsLOxk3cL6rBKfS8UXlHxxJ51BVabldjYWFdj5GiS6MeKdQso/+7Cw8MJCAhQ5fnd3d3U19djtVpZu3YtV111lSrrGMYwDgfXXnstn3zyCUajkaqqqkMaLR4KhIWFERAQQEFBwcFPHkI4rVyGuhl+OOS5E3q9nqlTpxIWFsZPP/10SIFxU6dORUYg8qRz8UsbQ/KVdxI6fT7t326l/LrlinWaJBHSW7eckG12JcdEkgnqDeRywt7c7vIo9R4wfeYMEDUN8Fm39/qm6tLcN3UuAj3AnbwX9AqBbu0cED4WFggOiZ4id89+Q+/G27zXPQhWGxLQ27SGnj3uv1uKHZuAvaIea5U74eM9eaQSUAY0ffIjAxFw1hyXgn2gZRsom/PwP1+AYNARavLi6uQAdKLAin1VNJj7yAaN0Yu485ehNflx1tnnsHmz4sl+tEl0p3VLYmLiwU8eQtTW1tLd3U1ycrIqz5dlmeLiYhISElixYgXXXXedKusYxjAOB3PmzCEsLIwff/wRURQPmZg90tDpdKSlpamuQtdqtWRmZg65lcvhkOdOOP+2Z2Zmsn37dvLy8g76vbrhhhtob28nfO5pmGKTiT9vGTFnXIa9vJnK25+j5aM1IMuEXnkawgAhU9tXm5UMkxMmIxrd98tdm3pzTGYO3gjXxYe7CeTsDa0gy6DVuBHurua06K40Fpxh5Q73dylXkHi3xe1r1wT7K9PisoytNzPFCVPWSBAF2tbucftcHxuu1H9R8Aj31viZ8D9lhtLsfvkTj/26MT0B3xMmgShQ8/RKJKtnIyDwnLkY0uPRG40sDtEwLdyPlw9Us6ep7/dKEAQiTjwT3xFj+fiTT7jppptcx44miX6sWLdYLBYKCwtVs1MFRdAWERHBq6++ytlnn01YWNjBLxrGMY/fPYEOcOmll5KTk0N9fT2tra2q2agYDIZjYmzMaeVSVFQ0ZEnov4Y8d8JoNDJjxgx8fX356aefftGnLisrC9khEXXy+QiiUiR1/oHEnLaEmDMuQ7baQZIJ6w2+7I+2r53FepJnsc7eD4KA/7wst89tNU3IPRYQxT6/8n7HoF/B7YXc45n4DSAadCAKnt6pYYEgeI5+G1Jile71gFFsbaAvhiTFK65754AR76yRiD5eYLbSs9t9w64LC8SvtyDXvfKpZ2BoYhT+J89wqdcGkvMAvtPHcuFfbuaWW27hn08/xRc79jPYb7ZPUjrRp15IR0eH2+/D0SDRZVlm7969x4R1S0dHBxUVFWRkZBz85CFCSUkJ4eHhvPLKK5xzzjmEh4ertpZhDONQkZKSwrx581i5ciVBQUGqjX8DjBw5kpKSEtU8XJ1wWrkM1WTbryHPnRBFkdGjRzNq1Ciys7MpLi7+2fee5cuXU1NTQ+hx8zEEKRNcok5P6IwTSb76LwiCFgQBn0Uz0Pi5ezx3Ze9H6uwBox6vMe5kpmLfArqkKA8f1p6cUpAkl5LM9TXXNyuh4gOCx+Qei0KsmwZYuOiV0W+p1V1RpnMq10rd/U71seGg1YDVjr210+2YacooEAVaf9ru9rnGz4RpymjQiDSvdg8MFwSBoPPngyTT+fkGz8BQvY7QpWeALNPz0y56DngqHXVhgcy65zoef/xxdm7J5ul3/ovZ4dmU0fn4EX/BtQg6PcfNmuVSbx4tEr2mpoaKigoyMzNV3XRLksSBAwdIS0tD2y8H52iiqakJs9nMgQMHaG9v5+yzz1ZlHcMYxuFAEASuv/56/vWvf6kuaktISMBmsx1y8PVQISQkhLi4OLZt23bIk9eHg19DnvdHVFQUM2fOpKysjO3bt//sPq2uro5/r3ger6h4AsYr+WSCIOA3YizJV96Jd1wKOCTEYH9Mk933QPbWTsU21SERtNDdhs1W34y1V+w2sMab8ytAo8Fn8kBLVWX/rBkwkea0YkPjTm8JvXUcyf0dRWPy6rNbbXcnoo29E94edmyTlanwnuw9brklgGLVIsk0//cHD5Lc/9TjEAw65OZ2hYMYgKALFiCavKDTTMuHP3gcFzQaRvz5Eh599FEiwkK546FHqer03LcLokj0oovxjknkn889xxtvvOE6djRI9J6eHnbu3Km6dQsodqrBwcGEhIQc/OQhgMPhoKysjNDQUF5//XVuuOEGVdYxjCOPPwSB7uvry6WXXsqLL75IdHS0qgU7OTmZ7u5u1axknPD392fMmDFs3br1iHe9fwt57oRzRD01NZWNGzdy4MABjxeL999/n9y8PIImzcQrMtbjHu15ewABfUY8xhHuajK3Yj3AM1XqNiujV7LsGqt2wtxbKPWpMe52MHYHjmZllH4gse70YxcGhIgKeh0Iootgd0IbGgAOB+YB3uTGXsW71NblQbqbpowEQaBtrXtXW9Bq8TtBSfgeVJ12xvEgCDjK6+nZ7amoDDxnLpoAH7DZqXvDXb0WLOj5kz6RuVnTuP+Zx9m0JZvSD17EYfYklWSHg65S5f6lpaU8+eSTfV/vEJPoJSUl1NbWkpWVpbqvWE5ODnFxcaqNntvtdrdiff3116uyjmEM49fg+uuvd9Xx0tJS1ca/AwICCA8PH/IproNBo9GQlZVFaWnpEd/s/BbyvD/i4+OZPn06BQUFbN682aPp0NPTw11334M+KIyQKXM8ru8pL0Iy94AoELz4eI/jig2bQNBZczwUbcomVMB/rnuOib21A0eTIqRwqr6dsNU0gcOhNLL7QbJYQRQ867jTiq3DnQx3TqLJA0a1Ba0GQ2IUAJYC942396QMkGQsO/KRB9RB//lZ4JDo/n6bR9CZV2aaErgmCjR++D0D4TUmGZ+Z4xX12jPvuqnX9Aicro3gT6Nm8MGO9bz66qtUf/s/uqtKPe4D0FNdhmS14LDbOemkhX1f1xCT6G1tbezYsYPMzEzVgzIrKiqQJImEhATV1lBcXEx8fDzPP/8811xzDfoBE47DGMaxiiVLlpCfn09tbS1tbW1HNZOrPzQaDenp6eTm5g4JcX04GDVqFIIgsGvXriMqsPut5LkT/v7+zJ49G4vFwpo1awadpM/KykKWZSIXnocguNdih7mbnsoSxU51EPV5x5ptIMtoYsLQR7srcLu25oAgoB8R77I+dcKcUwoOh2uyywnFUhX0ae6fu/bOGvfGZ/+6PvD77wws95gKT40BAY+pcH1CJJoAX8VyJddd6GGaMgrRZBxU1Kbx8XJZrtW/8pkH+a7x8SKkVwzY9tk6jzDSSWIAfwkbT52vhnvvuYf6nF00bviWwWBtacTW0owgaLj66qVux4aSRLfb7WRnZxMREaG6dUt3dzclJSWqCtoqKysxGo2sXr2a1NRUpkyZotpahnFk8Ycg0AGuu+46PvjgA0wmE5WVlaopx7RarWtsTK3NvxPx8fHExsaSnZ19yGFfB8ORIM+dEASB5ORkZvUqnX766SfXi5bD4WDJJZegNfkSNmuhx7Xm+molSEOWCF1yssfxjh+29hXrWHcFbvfOPKVLHujrKpxOWPLLQSNiyhzh9rm9sVUZFxNFxAEbbKm7N3xsYIioQQ9C78a8H5wKdluxe3EUvY1oI4KVdRS7j4V7T1ICyCy7izxGu3xPmAySjC2v3OMFoH94Sf0rn3p0xEWjgdClp/eq13bSc6AEAThOE8Rt+mSqHT3c89/XKNi6ExCQOjuoWPW22wuIw9xD+fsv0bZvGzqdN6KoYexYd8ucoSLRGxoaOHDgAFlZWap3ultaWqivr2fEiBEHP3mIUFZW5vJMzcjIGC7Ww/hdYcGCBfj5+bF27VpEUaSqqurgFw0RMjIyqKioOKrhiYPB19eXSZMmsXv37iMWrnqkyHMngoKCmDt3LgaDgR9++IGysjJXjZg2bRqSw07UyechDNjUyg4H9T+tBiDwrDlofNz/hltKqhVrF1lWArr6wdHepWyuZVkJ9up/XW+OiCY0wC1IDPpNkg2wYlOs1gSPDbzLO7XLXemlCfBRVG4yHt7kxhFKkOjAPBN9XDiaYH+QoWe/u1LcMCIeXZSizu9Yt8t9Df1U6N3fb8NW7/l7ELxkIaLRAO3dtH60BoBEwZvb9CnEiF48uvt7vnz1HQStFhAo/fBl7F19v9uyLFO/7iuqP1+J0eAHskxWlntjYqhIdIvFQnZ2NikpKURFRR2Re/5aOBwOcnNzycjIUK0h39HRQV1dHXa7nW+//ZalS5ce/KJhDOMYga+vL5dffjkrVqwgNjaWwsLCg180RIiNjUWj0VBaWqraGqCvGd7Y2HjEvh9Hijx3wmAwMH36dJKSkti8eTN79uxx7dWef/55yssrCJl2AsZQTy/pxg3fIEsS2phQvDLdc8Vkh4P2rzeDLBN8pmcTvWvz4DkmktniUqYbkqPdjtnrmkHUYByQSeYKAzcMINC1Guj9ey4P2EPrevfdtvrBpsJlzNty3e8lCMo0mUakbZO7jYug0+I71ylqW+PxtfovnKZMy3V20/HTTo/jpqmj8RqXCqJIzdMrkR0O/NBypS6OU3ThvNWYy3NPPIW9l3xvWP81ncXuE4qdJXmUvvVPBLuELNmJjIz0eM5QkOiyLLNr1y40GoUDUHOKDCA3N5eoqCj8/f1Veb4syxQWFpKYmMi//vUvbrjhBtW/J8M4cvjDEOjp6enMnz+f//znP4SFhak+NiZJ0lFNO/45jBo1CqPRyI4dO35z1/tIkuf94efnx6xZs4iOjmb9+vXk5ORw6qmnYrNaiVxwDqLeM8Cpfu1qEEQMmWkuexMnlGKd3Vusj/e4tjP7AIgi/idmeRzrySkFx2Bj38qGVQzwVEY5Q0IHtXCR8bRw6d24O1o9N5/GdOfG2125po8OdRHvPXs8rVqcBbf92y0e93SGl0gNbXRtOeBx3DtzBKapo0EUkd75nmu18czWhPBi/X7+fd9fqXv3a0KmnkDMoiUAdBfn0LRFeTGwNNdT8sYzmKvLEQQNsmzjyy9Xc+KJJ3o850iT6F1dXWzdupUxY8YQFBR08AuGEM4X2aSkJIxGoyprkCSJoqIiEhISePLJJ7n99ttVWccwhvFrIYoit956K8uXLycpKYmCggLV7NB8fHyIi4tTPRgcIDw8nPT0dLZs2fKbxQFHmjx3QqfTMWHCBCZOnEhOTg7Z2dl8+umn7N6zh4DM6XjHeHpat+7JxtbeAloN/gunexxv+yYbNCKGqaM8rF26d+QqTfLQQLQDfMvNvY1wnyz3sW9ZkrA3tQKeBLrUYwHhZ+o4eKjCBVFEG6xszOwDN96pvUGiW/a5XyMImLJ6N94bd3sc81ugNDyb//uDx++9cXSS8n4gijS89w0DofEzEXzZKQB0f7mZU7t9WaqPZ521gYf+s4I9D67AGBxNwpKb0Bi9wGKm7KPXkCUHks1K1Sdv0rjhG/R6P8zmVm666SZeeOEFj+ccaRJdkiS2bt1KYGCgK79HTZSUlGAwGIiOjj74yUOEwsJCoqOjee6557jgggtUXcswhvFr8Oc//5mPP/4YjUZDTU0NnZ2dB79oCOAMBs/Pzz9iQrJfC6PRyJQpU8jLy/vNU+pHmjx3wilsO/7442lvb2fNmjXU1NRww403ovMPJGT6PI9rrK1NtOzapAjaLj3VgyTs3p6Lo7UTtBpMWQOsXVo6sBQoXIn3hAGN8KIqRbjmZXDLKoNetbjD4WGpKvX0Zpl4ee7DBJ3W7RwndGGBoNF4BIIbkqNBEJC7zR4B3d6T0pWJsZ92eQjT/OY5RW0VHqI20dtIwBmzQYDGN77wEMQJgkDIVachaESk+lZG7WvkDkMq3bKD+3/8mK9vfBhHXTvxF12HKXEECCLl/3sda1szsizTvH0d5R+8jF70wmpuZ9SoURQUuAeaO3GkSfSCggKam5uPiWnw9vZ2qqqqSE9PP/jJQ4Samhrsdjs7duygo6ODCy64QLW1DOPI4w9DoAPcddddPP/884SGhlJSUoLVaj34RUMAURTJyMggLy9P9bExURSZNGkSHR0dv4kIGCry3AlRFBkxYgQzZ86kpKSEhQsXMmbOAnxTR3mc211VSmfhAaVYX7jA43jXtlwcbZ2g0ShhH/0gWW307MwDScI0yb2QOzp7sNcq6rSBpLyzsOpSPK1k5F6Fuefotw6QPS1cQnq7oZLssSk3pvRuvHd5WgeYpigkd9vGPR7H/OZPAUmibfUGD8W7xt8H/5OnKyr011Z5jI0BhFx2CicvOoVn/vp3ygqKuP/bD1hz06PYa1qJv+BPhM06Gb/0sQRnHQ9A/ZrPadjwLaVvPAvdZhx2KyaTF3v37mH+/Pke93d97UeIRLfZbGRnZxMbG0t8fPyvuseRRENDA21tbaSmph785CFCZWUloiiyZs0avLy83BLYhzGM3wsuvfRSmpqa2LNnD1arVVU7tBEjRlBfX3/ElN+/BcnJyYSGhrJly5Zf/V4xVOR5f0RERDB37lx0Oh1dXV3MW3AS4bNP8ThPslmpX/cVAEHnnejhYe7o7KZz3S5wSAQvnOFxfWf2fhAF/OdN9jhmzi0Fh+Qx9u1obneFiIkm9w22EgYue0yYOb1TJZtnrdKFK41bj9HvXjs2R12Lh1WLaXKGEj66fo/Hxtt35ngEnRa5vQvzAC9zRYV+opKTsnEv1kr3sFEAn5njGX/yCTz77LNENlv5W946Vt7yEO3fZBN+wmLizl2KV3g00adfoky0VZdS881HlL75TzoLD6DVemG3d/HCCy/wzDPPeNy//1qOFIm+d+9e7Ha76r7noPz7yM/PVzVwrKenh8rKSry9vXn77be58847VVnHMIbxW5CQkMA555zDv/71L6KiolRVoYeHh+Pj40NRUZFqa3AiICDAFdr5a/9uDhV53h8+Pj7MmDGDpKQk1q9fz+WXXUbCogsRtTqPc+vXfqnkhyRFYRyd5HG87avNIIoEnHpc7wRUH7q3KbyEJirUo0muBIELGCd4NlZtNYrFjG6gpapzP+7jOZHsrOUun/ReaEMDQZLoGRDgLRoN6KIU72wnye+EV0ai4p1us2MZME2uCw/Ca2zKz4ra/OZPQfTxBott0OO60EASL1vMPffcw5mpmbxRupNnHn+CsmdX4pM0iuTLb8cUk0T0aRejNfmAw07Zh/+h5sv3qf32Ywx6P8zmFhYvXszevXt/0f7rSJHoNTU15OfnM2XKFAwGT9Hj0UZOTg4JCQmq2cHJskxBQQHJycn84x//4NZbbx22YfuDQZ10nCHCtGnTmDhxIitXrmTOnDmUlJSoZqcQHR1NYWEhxcXFqpJqAHq9nilTprB27Vr8/PyIiYk5rOuHmjzvD39/fy655BJOmDeP+65fysbadn6qbsXiUNRYsixTv+ZzEESMWRke9iwA7V9tAlEg4NQZHsW6Z08hss0OXnp0A651FkjB19tjM2+rawaNBq9IzyAKyaJ0kD1Gv/U6kGUPBbqg1aLx98HR1omtvhlDfN94lSFV+dnY8iuQZdltE2ealEHbZ+swb96H/Kez3UbTvTPT0AT64mjpoHPjXvzmTHR7pv+i42j7ajNyWzcda3e5HY8UDJwRmoD/eaP529/+xt69e5VrxkwmYt4ZaAx9REPY7FPoriyhp6aChnVfYjAGYDG3kpyczPbt2w9pVMpJom/atIktW7aQlZV1WEFdsiyzfft2jEYjo0Z5NliONpwvs2lpaeh0ni+XR2sNzmJ9ww03cMcddwwJOXYkcNaIXRh8juz3ydJp48mDnzaM3wGMRiO33HIL//jHP3jzzTcpKCggIiJCFULLaDSSlJTE/v37mTFjhqoEnyAIjBs3jg0bNrBr1y4mTJhwWOs5GuS5E3q9nscff5zi4mKuu/nP1Frhi7JGmsx9ZHLzjvU4ujvBoMNvvuc0WMePO8AhIQT6Yhjoc9pjUSaxJFnxFe8H2WZ3eYc6iWwnnES34Ovt8b2TzVaQJA8FuqsxbvNsWmjDg+BAqad1WrA/Gn8TjrYuLCU1bhNtxhFxCF4G5B4L5rxyvDISXMdEbyM+s8bT8eMOmj5fT8wodzLCmJ6A19gUevYVU//Ol8TceanrmDca5utCmXLVn3jnzbf4fNUqJEnCGBFD3GW3YAjpG7v3SUgj9LgFNKz/mtZdm9HovJAlCY1e5ocf1jBz5kyPr3UgnCQ6wIYNG1zB8IeDkpISqqurmT17tmphnf1RUFCAv78/oaGhBz95iFBYWEh4eDgvvfQSJ598sqr+rQfDka7lw3X8j4W//OUvTJo0iVtuuYW8vDxGjBihitWiU4W+adMmEhISVJsSdSI6Opr29nays7OZNWvWYRFrR4M8d0IQBJqbm7np5j9z8+13MC0yis9KG8lv7VNju+xUgdBLTvaoq9bKelcz2HfuJI9ndGbvA0HAf+5Ej2PmvHKQwSfDfXpNlmXsDa0AaMPcp49dFi4Bnt8XUa9D4mdsVWUZW6GnZaAxPR5bbRPm/HK8x/cR+YJWg/eEdLo276Nry36Pdw2/+VPo2VNI25cbCTxnrhs/IBr0BJ41h6bXv6D53W/wmzvJxTmIwGRNIItOvoDt27dz480309nejsbbRPTiS/DPGN+3bi8TMWdcRunbz2FrrKW1qR6dzoTV2s6DDz7IAw884PH1DAYniZ6dnQ0otkeHg/b2dnbs2MGECRNUs0vpj6amJhoaGgadhD9aaGhooKuri+LiYoqKirj66qtVW8vBMFzHfx3+UAp0UFTozzzzDFFRURQXFx/xwMJDhSAIjB49mry8PNVG1/rD6aO6a9euwwp0OZrkOUBRURFNTU188P4H3Pvw34jVw23j45ge4YdGgK7SfLori0GWCDnP84+jtbJe8UWVZMUbfAC6sveDRsR/ziSPQu8c+zZmejY8bHVNIHmOi8kOB9iVjfVABbpo0IEkYx0QMga9G2/AXueubNTHhCljZpLs6rA7YUiNUbrWkkxPzgB1migqKnRBoPnjNR7j3xofbwIWHQeCQOMbq5GsNgLRcYEumpv1yVTLZp6kjHxLK4gigsmPqIXnupHnoKSAx5x+KaLBAAhYzK2ceeaZ5OfnH1bh/C1K9JycHDo7O5k0aZLqY2KgbHjtdjuJiZ4WBUcLzlExp6plyZIlqq1lGMP4rVi2bBm5ubmUlZXR2dlJU1OTamtJTU2lq6uL8vLyg588xOjvo3o4arqjSZ478dmqz9m6fTs3Xn8D9VUV3Dg2hsWJIfjqNDjMPTRu/A6A4AvmezSfZUlSGuGyTPAZx3uOhO/KV5TkPl7oo93JTktJtXJMq1H8xvvBSXTr4j09XF1h4APW4lKkS54Eui5U2XgPHP0GMKTFgyB42LEJGg2mySNBIw5qqeY3TwkTte7Mx94bhNofgefNA0nCurMAc1ElOgRO0IRwjyGNMMHAU7Yi1hk6XRk80YsuciPPnQiZcSKm+FQQRBy2HqKjIyktLTkk8tz1tfwGJXpDQwP79+8nKysLb2/vQ75uqNDW1kZxcTGjR49WrVFmsVgoKysjKCiIF198kbvuukuVdQxjGEcCo0aNYv78+bz88suqW6sGBwcTERHBnj17VLOF64/09HR8fX3Ztm3bIeelHU3y3Im//OUv1NTUcNetf+bLH37knORQrhoZSYyPQvjWr/0SRBF9egLG9ASP69u/yQZRRJeR6BHc7ejsUch1WfaYCJclCXNeGciy4kXe/7rWTkUIR28WST9IZquihvceRIHeW9sHToU71+UYpN4anFPhOweZCs8aqUx+f7/F43fKOzNNWZtDonPjXo9rfedOUo7bHbSt3gDAGNGX2/UpnKAJ4V1bFe+Z2ujsaAcgeOoJbuS56znRCYTPPU35D1lCEOx89tmqQybPnfi1SnSr1Up2djbJycmq55eAkmGya9cuRowYoaoSvr/6/MYbbzwq/1aHcXShPvt0hDF//nzi4uL49NNP8fLyoqys7OAXDRFCQkKIi4s74qnbvxbh4eGMGDGC7OxszGbzQc8/2uQ5QFJSEiNHjgRkCvft5darL+f5t95lQrA3t4yLZYS5HlGjxeu4ceijPNXgrmKd7lmsZbuDrq0HwCF5qNYApVg7JEzpnkSorboRZDwJdEuff5lzPKzvv3vDxzo9PWt1EUEgih7KNUGjQd9rH2MZuPEWRcU/TiPSPoiNi++ciUpoaX0rlsJKj+P+J09HMOrx1ek5uU7LXwxKo+Af1gI+sddiFSH0mjOUNXe107R1rcc9AHR+AcQsvgSQiYyM5KOPPvpVRPavIdErKyspKSlhypQpx8Q4VEdHB3l5eUyYMEE1xffwqNgw/mjw9fXl+uuv5/HHHycxMZH8/ME9HI8GdDod48ePZ9++fXR3ezZDjzaMRiNZWVnk5uZSV1d30PPVIM8BrrjycpBkOlpbeereO7nj/ocwWLu5dXwssww9eGk14G3Eb5BGd8/uAuyNbSAotiQD0ZW9X8kxmeOpaDPnl4MgoB+V5EGE2nsnyYyxgxHoyjvRQAsXnIp0GY/3ONfo9yD11tirmu/c70kamSYpNi7tP2z1uKchMUp5BxAE2r/b6nnf5Bi8J6aj0ekYn9fG3YY0xmj8eM1Wzku2MhpkKwGLjlMCSUWRis/fHfT9UxBEohcvQeNtQtRo2LNnDxERnt+Xg+HXkOhdXV1s27aNMWPGEBwcfNjPPNKQJIkdO3aQkpKiqoKupKSEoKAg3nrrLaZNm8bkyZ7/NoYxjN8T7rrrLl544QXVrVUBxowZQ1NTk6rh5E4IgsCECRMwm83s37//oOerQZ4D3HTTTei0WiRJ4qP/vMg1Vy8lNy+fKzMiOS/WB/+eVpAkQpac5HGt1G1WJskkieBFx3kc796RC5KM4G9yBXk6YatpchHd+tgwt2P2ul5BhZcBYcDeU+qxgCi4skv6wzldNnAqXOu0gXFIHsec02P2khoP+1PvcalKkHiXBdsASzVBo8HvxJ8XtYl6HYFnnwBAVE49N2jiOUsXxTpHM49ZC9gvdWBIjML/5BkgCNSv+RxbhyfBDxA0aRa+qaNBEHjqqSc55RRPy7xDweGS6M78En9/f9XcHgYiNzcXrVZLcnKyamtobm6mpaWFxsZGsrOzueGGG1RbyzCGDn84Al0QBO6++26efPJJEhISKCwsPOTu7lBg5MiR9PT0qNp574+UlBRCQkIO6qOqBnkOys9v//79vPjii+h1ykZ/4xeruOHyS3nvf59wzikLefqpJ5l9ybke1/Yv1kGLPD1Tew6UKGPaGhHjiDi3Y7LD4bJwGRggKssy9t4QUd3A4LF+xXZgIXd2u6X2QRTooYEgeHqngjLiPViQKID3RGXj3T2If6o2wBfTZCWgrOnzdZ739fbmkrtv4cUXXySw3cJTHbm8a6uiWe5rAuijw1wBJ/VrPsPa0uhxHwCfxBGEzJhPTU0Ny5YtG/ScQ8HhkOgtLS3s2rWLSZMmHfao+FDAuelOTExUNcS0oaGB7u5uioqKKCkpOaZHxYYxjEPFTTfdxPr162ltbaW5ufmwJqeONMLDw4mKijpmmuGBgYGMHz+ebdu2/SJhqRZ5DvDcc8+xY8d2EhKUWluWk8ODNyzjkX+uIM7HyPPPP8+F9906qO2V0zPVa/YEDzs1yWqje0dvjsnkwRrh5QrxPsrTi9VW1wyy5NFch/4K9J+xcAGX6s0JZ0PdmZ3SH4aUGJBlrHsKPX5nvMamgFYDFhvWkmqPa/0XTAFZpvXz9R4e6gAnXHkh/3zmGU6ZchzvF+3kGWsxhVJX35q1WkKXnaEo1WvKad2T7XEPAK23D7FnXIYkSb3ChV+HwyHRnfklMTExx0R+CeBq0KkZYmqz2SguLiYyMpLnnnuOu+++W7W1DGMYRwpTp05l8uTJvPPOOwQGBlJSUnLwi4YIBoOBcePGsWfPnkMSkQ01dDodU6ZMoaKi4hfFfmqR5wCnnXYazc1NLFy4EFly0NXWxkuPPsgNt9xOXX4OTz31FDfefxfhyQke13as24VstYG3Aa/xnpPdrkb4INYuzv2vJi4cYcB7i2uSLMZTRCebrYDgMREOIBp79+QDSHLRaED0Vqat7Q3uU+G6qBDXO4G1YoBHupcBr1FJIAp0bfFsgvjOndQnaivwJKRHzJ3OA488zN133cX2Xbv4myWfjY5m+u/sA8+Z26uyl6lc/b7HPUCpv1GnXIDON4Abb7rpN+UGHQ6Jvm/fPqxW62HbCQ4VmpubKSkpYcKECapOpxcUFJCQkMATTzzBsmXLVOUHhjF0+MMR6ABnnHEG3t7e/PDDD2i12iOSLvxrodVqyczMdNlOqA1BEBg/fjzAz46OqUWe98fSpUtpb2/jsssuQ5bsOOx2vv7wXf503XX8sG0zF4ekcb0+kTSxLyDCVay9DHhnem6EurceUMjzKaM8CrK1vE7ZHAugGzAS7mjrcm2cXQGgvXCFgIqexcOpZJO6B1GghwYqQWKlg3iupfaOjG3zDH31GpOsWLzY7FgKPFVvfvOV8W9L9gElSBUwIDJTE8w9hjTGZ4zi0SeX8+gjfyX3s+89rgcIWDxL8ZUTBco/e+dnCaPQGfPxjkvhxZde5ptvvhn0nEPBoZDoHR0dbN68mfT0dMLDPX3v1UBRURF2u13VlG9ZlsnPzycpKYnly5cPj4oN4w+DkJAQrr76ap566ini4+PJy/McoT2aGD16NB0dHapOtfVHTEwMiYmJbNq0aVBlvJrkuROZmZkUFxfz4osvYuzdhO5b9yP3PXA/Tz31FFMT0rjLkMY0TSA6lBpqq22iZ3eB0ghfOM3jnj17i5Q6r9MqJHU/yLKsBIhKsscx6A0ek+Q+xVk/ODfVHmHgur7JMo/Rb+d9bHYPct2QqKjIsTuwN7a6HRONerzHKCFjg9m4mKaNQfAygM2ukAyAAIwUfblZn8TZkRl8uWcrN9x0E1/985VBa7QxLQ7fE7NAFKj56r/YOts9zgHwjkkk/PhF1NbWcs455wx6zqHgUEh0u93Oli1bjpn8ElDedwsLC1XfdJeWlmIymfjoo49ITU1lzpw5qq1lGMM4krjrrrt49tlniYqKoqioCJvNdvCLhghRUVGEhYWxe/fuY6IZbjKZmDx5Mnv37qWmpsbjuJrkuRM+Pj6sXr2a7du3kZSUAMg0VpSx4p/PcNNNN+EdHMhdhjQWacPx743Wk2WZ9i83ARC4aKanUtxspbu3zg82EW7ptVT1GTdIgGhds7KXj4v0OOYKER1Mgd5LoA8MEYVeURueojZBFF0WMoOJ2hQbF5nWNds87xnoi/ekkSCKNH2x3vV5pGDgIl0MN3mlUu+rYdmyZbz96JN0N7V63EM0GghdejrIMj0lubTneU6fA2iMXsSedQWSzG9qhsOhkeh5eXlUV1czZcqUYyK/xOFwsGPHDkaMGKGqwK69vZ36+nqsVitfffUVt9xyi2prGcbQ4g9JoGs0Gv7yl7/w97//naSkJHJzc39RbT3UCAkJIT4+np07dx4TBVuj0TB16lR6enrYvn27G4l+LJDnTuh0Ol577TWqq6uYM+d4BATsNhur3v+Iqy+7gp3bd3CRJpo79ClMFQMxf7cdgMDTPIu1LEl0bt4HDgn/aWM8nqWMfYM2MdrjWnt9b0HVaT1CSWVnJ3sQcsI1LmbxHFl0buDtlQ0ex5zFWm7vxtHlTr6Leh1e49N6N96eHW/jyES0EUq307Aln8XaCO43jGCixp8PbFU8Zy+ldpTiU9by0RocHZ7Ei6jXKVYukoy1uozWPZ4p4aC8WMQsXoLGy5uTTznlNzWIfolE7+zsZMOGDSQkJKj+O+lEe3s7eXl5ZGZmqhrWWV9fT0dHB7W1tWzZsoXrr79etbUMYxhHGrfeeiuff/45VquVhoYGmps9J3aOFnQ6HZmZmezfv/+YsHIByMjIIDw8nA0bNtDT01crjgXyvD+cDfGbb74ZnVYDksTewiJuuvAy3v7oQ6bZfbnfMIJTtOFoN+aAKKKJjnAL2Haiq7cR7jtzvGetbmhB6q1phl4rtP6wOSfJBlGgu8LHBirQBcFFonso1/xMrmO2Aco10ahHH6OMng+0YwPw7vVPbV3jadMi6nX4zZ0Eokj3V1uZqQnmLn0q5+ii2O1o52+WfHal+SM57EjldXRvz/W4B/T6y/t4AzKVX7w36DkAQVmz8UkZxX8/+h/vvz+4yu1Q8EskurO2S5JEVlbWMZFfIkkSO3fuVN26xWazUVBQQFxcHE8++SR33XXXMaHoG8YwjgTmzZtHYmIiH374IX5+foeV3zEUGDNmDC0tLceElQsohOXEiRPZvn27my3bsUCe98eECRMoLCzkvffeIygoAGSoa+/ksZvu4N5//I3AZjP3GNJYooshsrQFW+9klu8gVmvduwuU/DC9DkOip3d2T04pOCSPiXBAmQiXB6/jiqhN9shVASW8E0HwqOMAushgEITBp8LTlKnwrgOeTgLeExQBldzY7vp6+8P/xCyQJGxbc0nv0bFMl8BN+mSsssRjlgK+CnPQY1LW1fK/NR7XA3hnjsA0ZTSIIpWfv4vDPPj7pzE8msj5Z9LS0vKbAzR/iUQvLCykuLiY6dOnHxP5JaBko+n1etU5ggMHDrjU50uWLDkmfOGHMTRQ/w12iLBkyRI0Gg1fffUVBoNBdQuVjIwMLBaL6utwQq/XM23aNDo6OlzE/rFEnvdHREQEjz/+ODISQZNmkXrtfZjGTOOdp1ZwxYVLWPXNl0ztMfLC35Zz+eWXkzLP02vNUlDp2lh7jfH82hQCXcRnrOcxZ0HVRHqO4UjOTrbOswPr6oBbPNUWLi91sxXZ7t7c0Qb6ogn07V23Z/fXNDlDCS75cbtnWKggMOvS87jnnnt49KQL8EXDS9ZSnrEWs19SNrO+8yaj8fdRNu+fDu5zbkyPx5AeD6JIzdc/r17TmnyJOeMyHA7Hb/ZAG4xE7+7uZuPGjcTExKiq9O4P56ZbbesW58t1SkoK99xzD7fddtvwqNgw/lCIjY1l6dKlPPTQQyQnJ5OTk6NqEzosLOyYsnIRBIGxY8cSEhLCxo0bMZvNxxx57oRGo+Hpp59GRkYfGELqsnuJPPl81n31E9dfcAlPvLCCoBYzy8+5kjtuu42ZV5zNQApRdjgURbZD8ggdgz6FmBDs5xrXdsLR2eNSkGtDB9l499bpwUa/nfkmAzfegiCg7Q0qHTRIdER8rx3bIHV8Qm+9bOvGWlXvcTx94RyWXnUVLz30N8bbvfjSXs8jljzWOBqxIaOPDsVnZiaIIvVvfOFh6QYgehvxP3n6QdVrgiAQfeqFaH38uPCii2ho8GzsHyoGI9ElSWLbtm3Y7XamTp16TCjWQFHRCYKgqnULKCPf/v7+rFy5kri4OBYvXqzqeoYxjCMJQRB49NFHeeyxx4iOjqawsFBVCxWDwcDYsWOPGSsXgMjISDIzM9m6dSsNDQ3HHHneH+eddx4xMcqEV9JF15Gw5EaqG7t5cOkN3PSXO2koKuf6xMk8/sQTLLxqCd4Bfh73cNq3+M3O9GiEOzq7XbZog02SWasbQZIGreOy2QqSNLgCXa/7WQJdGxoAojh4HU+JAYeEeXeh53VBfq7csq6tnlPjoaPTOPuSi1mxYgVnG6IpkDp5xJLHh/ZqWrEhiCJB580DWabj+23KlNwgCDhzNkgS2CzUfr9q0HMAAsZNxW/kBL77/nuef/75nz3vUDAYiV5cXEx+fj7Tpk3Dz8/z56oGmpqaKC0tJTMzU9XGc1NTE42NjXR3d/PJJ59w3333qbaWYQw9/rAEular5dFHH+Xhhx8mPj6egoICVcfGjjUrF1BeIqZPn05LSwtbtmxhw4YNxxx57sTixYsRRA0h005A62UibOZJpC67j6DjTuKbd1dx46VX8vfl/yAoKZY7QsZyvT6RSWIAht5f8a4t+0Ejoh+b7LGxBjDnlIIkYRis2907LuYV79lJdBbiwe7pCiNzeG5stUF+yng3YB8k+duYFgeiMLgP+oQRyrVdZqxlitdZsKDnJG0Y9xlGsCRrDkUlxSxbtowXN35LmeypYg88Zy4AbZ+vx97sTo5bSqqpfvA/WHLLQBBBclD7zf881uGEKTaJsNmnUF1dzZIlS372vENBfxJ906ZNbNiwgYiICEaNGnXMKLIKCwtVt24BqKqqwmazsX//fvLz84dHxYbxh8Q999zDmjVrqKurc41HqoljzcrFacsWEBDAhg0b2LBhwzFHnjtx6623YrNaCZt9MqJWR8CYySRfeTuxZ11J7oFSHrr6Bq677jqqa2u5InM2d+vTmKcJJQCllppzShUSXADjaE+Pc0t+BWg0+GR6NnNdG2ON6OGrLkuSooajL7ukP1yB4INtvHvDzwZVrqUqG+/OnZ4KcY2/j+t9w2njYkRkqiaQm/VJ3BI9Aa+wYB546CHue+k5dkptDHyTCDxrDiAjN7TSucGdHHe0d9Hw8ie0vP8dotELBIHKL97DYfa0lAPnCPjlSLJMeoZnc+Jw0J9EX79+PZs3b6anp4epU6cO6nmvBlpbWykqKiIzM1NVNbwzIykiIoLly5fz2GOPHTPvOsMYxpHCiSeeyPjx43n55ZcJDQ1VNRgcjj0rF4Do6GjGjRtHdnY227dvPybJc4Dy8nJ27dmD/+iJGILD8Y5OIO7sq0i64jY6df6s+MuDXHHZ5fzw/fecPHceDxpGcI42ijjBC1CyRLq35/y8fYtTOGbQKXvlAXCGiA7aCO+xgDx4I1w0KAT6YHVcsVV10FPhGczuUsH3WLC3elqTmbJGgiDQ9uMu5TlAuujDZbpY7jeOIHPGVN58602uXrqU76x1dOEumjNNGYUuJgxEgeYP3K1VZYeDtq82U/PQK4gG5b2lbe8WukoLPNYBvX7oJ52DPjCE666/YVBboMNBfxJ9586d5OTkMHXqVAICAn7TfY8U7HY7O3fuJD09XVXrlv6CtgceeIA//elPxMZ68knD+OPgD0ugA5x55pnExsaycuVK/P39KSgY/A/O0UJwcPAxZeUCYDQaGTNmDLW1tfj6+qqaXPxzWLduHVXV1QRNnoXW1PcHUmMwEjx5NgkX/AmAA3v3sdJayUOWPHY72pmjDeERQzpX6+KZ4RVGSGAQftPGetzf3tyOo5dENg7mm1rXDHI/1Xg/OMe+BW+DxzFXB1yWPX7egkbjUpkPtvE2pMWBDJ37PEcdNT7eeGUkkDZiBCfZ/Lldn8Kd+hQiBSMf2Kr4qy2fz6vyaGptGTRMFMD3+Aloel9MWj5SxsbsrZ00vPQJVXc/j9xsIf6Ca4k++TwAOvL30J6/d9B7OSxmzLWKH/vbb7/Dxo0bBz3vUKHVahk/fjytra1IkkRGRsYxs6Fsb28nPz9fdesWSZLIyckhNTWVe++9l/vuu++YCFYdxjCONMLCwrjtttu49957SUlJ4cCBA6rWz2PRykUQBEaPHo3FYqGrq4tx48Ydc+Q5wD//+RyGkHB8R/TVYUEQ8U0dRcKF16ELCKa+vp7Pmop42JrHKnsNiaI39xjSuEWfzHw5iOTUFPTj0/oa1P1gzikFhwNjiufGxVlnxRDPDXn/DfVACxfo24xLg3in6sKDQKMZvI73rkOqbx1U9WbKGkV4RATHCcEs0yXwiCGDaZogsh0tPGjJ5d2uUgry8uhcsx1H5yBZKuFB+M6ZCKJIw9tfItvtyHYHbas3UnHzM3Rt2Ef4CYtJuuwWBI0WrGbqfhhcvSbLMt0VyoRkc3MzN91006DnHSqcym69Xk9jYyNjxoxBr/dsTqgBp19qamqqqtYtoKjgw8PDef7555k2bdqw9/kw/pAQBIHHHnuMZ599loCAAMrKyujq6jr4hUOIsWPH0tLSQmWlZ56UWoiJiSEoKIiqqipGjhx5zJHnAAsWLABZJvS4BW6fG8OiiD71QoImHIfZbOarzRt5SihnhVUJjl2mT+B+wwhO7/Ijc9QYdAY9XqMSPe5v7vU/NwzSJJd6LEhdytTAoBYu3cqxn63jwuB13Lm/t5V7BnBq/ExoeifNLINNk03OwOTtzfSkVC6UI3jEkMF5umjqZAuPWQt4SVPNxuxsHJ3ddG/3zPIRRJGg808ESaZr014sZQrp3b2nkMo7V9D0xhf4pY4jeendeEUngChS8dk7SDbPdwoAc10VksWCjMyMGTMGPedwEBoaSkJCAuXl5SQlJR1Tk865ubno9XrVuava2lo6OzupqKhg8+bN3HXXXaquZxhDj2NjjnKI4CzYZ555Jueffz45OTkkJibi5eWl2poyMjL48ccfKSoqOiaU3q2trWzfvp20tDSqqqrYsWOH6oqcgTjnnHMQtFqCpwy+sWjdkw2CgBDoh3FkIt04WOdoYp2jiRBBz4hWmenjJ3LF+RdRK1vYL3Sx39FOpawUWrOz2+1tUKxNBkAJHpOUDvUAuILHfDx9wIR+m0XZZvfoiOsignE0tw86MmZMiQVZxl5QiexwIGg06BFIFX0YLfqRfv+jiDYHO/bt5Rt7PXlSJ+Z++jS/+Vl0/rQDe34F1qp69NFh7mvTagk6dx4NL/yPju+3InobaP92K4IgEj53MUETZiBoNIq1z96tdJUXUvnFe4yIS0Fj7Pv3011ZQtWqd5C6u/APSKSttYSffvqJ6dOne3xNh4quri42bdpETEwMHR0dbN26laysLNXHvo8V6xZQAsc0Gg1r166lq6uLpUuXqrqeYQxjKHHLLbfw73//mwMHDuDl5UVVVZVrhFgNhIWFER0dza5du5g2bZrqDT6bzUZ2djYBAQHodDo2bdrE9OnTVX3XGYhly5Zht9uInH0KguD5ftFTVYqtVVGW+c2bjATslTrYK3XgjYZ0wUSipOORhx7GIsoc0Jo5IHVQIHVhR0YyW7BWKtMJhtTBGuFNIIp4JXh6o/cntwdXruk9znNCGxoAskRPpadyTRcZjGDUI5utWIoq8RqVhADECV6M0vgxcvESQk+/kv3797O7rY73TXZa5L5JSdPEdEQ/E1J7Fx0/7SDgFM/NcOAZx9Px4w5o66LhP6uw5JRhq28mYOwUwmYtdIkOwo8/ldrvPqZ1Tzb+oyZgik913cPe2U716vfoLM4lKCiN5uZ8fvrpJ49nHQ4cDgfbtm1DFEWSkpLYunUrM2bMOCYavfn5+YiiSGpq6sFPHkJ0dHRQUVFBSkoKK1asYMOGDaquZxjDGEpkZWWxcOFCnnnmGa6++mpyc3OZOHGiauvR6/WMGzeOnTt3EhoaitFoVG0t0Kdi7ejoICMjg927d2MwGAgLCzv4xUcJ+fn55OblEzB2CvqAYI/jkt1O2z4lUDPotOMQBIFK2cyH9mr+Z68hWfQmqa6RZcuW4RfgT77GzH6pgxxHB529ymxzbpli05bhSa73b1SLfibP5zv35INNkhl0IP9cHe/d33eZXXvu/jCmx9O1aR/m/HJFcQ4ECTpGi36MTEgg6Y1ZVFRUsK+8gvUJbVTIPThlHhofb3ymj6Vzw26aPl/nur4/vCemo0+IxFpeR91Ln6DzMdGzOx+vmARiLr0ZrwilGR+18DyKXnkcqaudhvVfEz5nkesesuSgYcO3NG78Fh/fSCxaicrK3+7zX1xcTFlZGaNHjyYnJwcfH59jQl3ttG6ZPXu2qu/gsiyTk5NDWloaF154IXfccQfBwZ7/Nobxx8Kxw5IOEebOncuUKVN44YUXCAsLIy/Ps/t3NOG0csnNzXULWFID/T3PMzIyOO6442hra/MIFlUTX375JXX19QRnzUHrNUixtNtp2bERZJmgU2d4/BFtlK189vWX3Hv/fVz5wJ38KDcTJhi4Vp/IA4YRXKCLZpYuhPSRIwmaPGrQNTiDQZzBn27PN1tBFNAPQqD374APOjIWFggacVDlmj4xkqCQYCZPmsS8Hh+u1sXziCGD07QR9ODg9bZCLr30Up7+x3K2Vha5kecAxuQY9PERIAi0fzN4CKjPzHFow4KU0bMvNhI4egopS+8mePIs18uDIAhEnnSOQnhYeqhb85ny9Tjs1K9dTek7/0IvG9DpfGhrLeXMM8/kjjvuGPR5h4KOjg7Wr19PZGQk48ePZ/r06YMGi6qBY8W6xW63k5+fT1JSEg888ACPPPIIBoPnBMQwhvFHga+vL/fee69LhZ6Tk6N6jRo1ahSdnZ2qW7n09zyfMmUKkyZNIjAwkA0bNhwzCnmHw8HLr7yCMTwan5TB62zz9vUgiugy4tFFhrgd68bBxvz9PP73x7jkkktYaalAAs7SRfGIIZ0rdXHM7fJm4oQJ+AcFeFwPvRYuwuCTZP0VaYJ2kEDwXos2eTAFelggSDL2QUa/BVEkcHQKo0aNYpYQxEW6GB40pHO1Pp4AQce3NHHVHX/mwQcf5Ms137mR5861+M2brIx2r1o3qM+5NiQAvxOngCjQ+eMO9N7BJF12C1ELz3Wb2AucMANjeIyiXlvVp15rz9tD0X8ex1JZQUBAEs3N+cTFxfHFF194POtQ4azZZrOZGTNmMGrUqEGDRdVAS0vLMWHdAop6LjY2lieeeILFixeTmZmp6nqGMYyhxqOPPsrrr7+OVqulurqatjZPC8ujicjISMLDw1W3chnoeZ6Wlsa4cePYsmULtbWeqmi1sHDhQhAgdMbgIZUdebuVkEsBfGaNdzvmQCbP3sELy59i6dKl/GPn91RKZqZrgnjAkM4N+iQWacKYHB5PVFQUXoNYqjr3y4K/aVDS1Jlz8rMWLsiDW7H129/bmzwzv0xpcSTGxzPFFMZZ2khu16fwF30qGaIv+6R27vjoVf5866288eprlPcjz53wOzELHJJL1DYQgiAQdMF8kCTsRVXYSuqJOf0SEi66wUWeAxhCwgmZPg8QaMpeQ0/v9LelqZ7SN/9J48bvCApKpbO9FgEb//3vhx7POhwUFBSQm5vLtGnTSE5O/tlg0aONY8W6BaCiogKHw8HOnTspLy//zdN7w/h94A+tQHfiscceY8aMGVxxxRUUFhaSnJys6j+4/lYuM2fOVKVzNlhgqNFoZMaMGWzcuJGtW7cyadIk1cfAL774YkSdnuDJswc97l6sB998dG3aB5KMJjOVHVIbO6Q2NAgkid4kiSYy/MM4+bbbCAgMoF62UimbqZR6qJB6qOxpR+odnf5ZCxdBGDx4rB+BLpktaAZ0y10jY3VN+KMlRvQiVvQiRvAixmDE56WXqayspLLHQq5/J5/aa6iXewu/v4gmKgSpsp7urQfQL/b8/vgtmErjS5/Q/m02Qeef6OH7Kmg0BJ0/j/p/fgCyTMDYrEGbFPqAYEJnnUT9ms9p3b0ZY3g0rTs3YWmsJSgoleamQnQ6LW+++cZv8kBvb29n48aNxMbGMnLkSCWgrdcTfdOmTWzZskU1JbrTumXGjBmq/5soKirCZDLx8ccf4+/vz4UXXqjqeoYxjKOBa665hqeffpp169YRGxtLaWkpSUmeI75HCzqdjvHjx7N161bCwsLw9vZsog41fi4wNDMzk927d7NhwwamT5+OyeT5d/1o4pJLLkGy2wk7/tRB33fsXR205+4GWSJo4eDTS11blNAxkiIpMtgpstfwsb2GSMFAmuhDmE3k8ssvJyoqinbBQaXUo/yfbKZC6qG6tgkcvxA8BiAO/i7mUqD3/LxyTW7twiBBjNZEjGB01fKQex6lubmZkvoaGiQLm+3NlMjdrpa3MC4ZyqppW79rUIW539xJtH78E7R10rO7EO9Mz8DLgNNn0f7dFpAcmOJTMYZ7quwFUSTq5PMofv0ppK526tZ8hmQx07Z/O34B8Zi7m2hrK+XSSy/ltdde+9XvpXa7nezsbCRJYvr06S7Pc2fjecOGDaop0Z2b3GPBuqWlpYW6ujqioqJYuXIle/cObpE3jGH8kTBixAiWLFnCo48+yn333ceBAweYNm2aqmsaM2YMP/zwA5WVlaooa38uMDQ2NhZRFNm2bRsTJkwgKsozh+toYteuXRSXlBA04Th0fp51FKB52zoQBHxmZ6IxeU7AmXPLXBYsLalhfOdo4DtHA75oSdf4EN0ps+jkU0j4UwIOnYaq3v24Ust7aKtvAVFAGzu4Kl+y9OaSDWrhogdJdtm89Ieo1yH6eiN1dCPXtxAdHkmM6OWq5ZGLMrCdaKG4uJgGycHXkjL5bemt5Ob0aIX8zivH0dmNZoCozpASgz4uHGt5He3fbCHk8lM91uA1NgVDaiyWoiowmvAdMW7QOhwy7QTa9m/H1tZMxaq3CR4/lfq1/8femYfFVZ79/3Nmh2HfdwKENYQkJJAEspjUva3autfWtmo369bavrYurUur9dVqa/VnXVK1an3d6lJ3s68QSCBAgJCw7/vO7Of8/hhmQsKcAQ0BUudzXV4XZp4555lhmPt5vs99f++P0ap98fWJpK+3hvT0dHbs2EFoaKjL92kqJEmipqaGuro68vLynJ7nDk/0wsJCgDnLRK+qqkKr1c65dYvNZqO6uprk5GQuuOACfv/738/5etvD7PCVENCXLVvGxRdfzKOPPsott9zC4cOHWbVq1ZzOyWHlcvToUVJSJm+ITieuxHMHWq2W/Px89u3bx759+8jJyZmz7Na3336bvr5+wtZfeIJtyEScwXrdMpQ+k8eY27qdXa31E5qV2JA4Ko5yxDhAw+8eAJtI+kO3kJSURKzCi2SFng2qEPy1akZeeYX+/n4MUQEMY2NQsjAkWRmSrLQEhNG1YAHayEgCBA1K7MEuWFBjVaqwLViASqEgSeFLkDIAP9T4CSr8BRXeF16F79euIDAoCJVKRadkolkycEQcZrO1m7KX/k3Pp/vwWZ1J2E2XT3pt+pWLGGjrZmD3IQJcCOg+eVn0/vMjJKOZ4V2l+J+7cvI1VmWifmsblo4eurZ/SNwVP3L5PgevWM9geTGm3i46PnsbL30Ien2EM1Bv27aN8PBwl8+dDl1dXRQXF5OYmEhqauoJi4a5FtEdfqmJiYkEBrpeNM4WBoOBo0ePkpmZybe//W1eeumlOc+i8+BhNtBqtTzwwAPcdddd7Nixg6qqKmJiYubUV9lh5VJSUsLq1atn9W9RTjwHezbTkiVLqKioYNeuXeTm5s6Z7ZTNZuP/Xn8dr+gF6Be4Xuv0lxYAEuh1eC+fXOEjSdL4QbiI/0l9TNolE+02E+3/eAlD+TEiLj+bzEsvcB5ILxP8CRW0WO5/hP6+Pka8VYyo1QxLVoYkC4OSlR7VMJqEBGwChAoaREA1HstDBA3WmBgsw1Yi/YKJVvjjK6jwE+yx3C8pDq8nMwgMDETvradfMtMi2kX7A9IANWWHOfqH50ClJOGfv0c46TPivSKdgXd3YKtvxzowgirgRBs5VUgA3tmpjJXU0PvhbpcCuirAF/8L8hj8cDddOz8hcGmeyzWTLjya4Nyz6N2/nf6De1CqtPZD8L6j6PU+/Oc/H3Puuee6+3W6xWAwUFhYiFqtZvXq1SfEaUdjUZg7Eb26unpeWLdIkkRFRQWJiYncddddXHfddfPC0tGDh9ng97//PcnJydx6660MDAzQ2dl5SvuHU2WilUtwcPCsHobLiecOoqOjUSgUHDhwAIPBQGJi4pzZVVx00UUICiUhq7/m8nFDRwuG9iYA/M+ZvN+E8YbZSgXqlFgU3sctc4axUmQbYPPOAnpf/AB1dDgr//xrYhQ6YgQv1qqCiRJ0KC5dyMDGyxmymRlV6+1xnOOxXBkTh9lgJNgnANUJe3INquAQfOLi8A4KI0XhZ4/fgsq5L/d++H/x9/bBz98fE6JTtN9u7aXZMkzx9+9BstqIuv/H6FLiTnhd2uRYFD5eiCMGxg5U47s++4THBUHA79xV9Dz/nnxS23gWevv9m7B2tTJaX41P4uQmqwqVmqgLr6TxX/8Pa18XnVvfJzAomcGBRsymQe666y7+8Ic/TPHblEcURcrLy2lvbyc/Px8/vxP7xsy1iN7d3U1jYyNnnXXWnNsn1tbWotFo2Lx5Mzabjeuvv35O5+Nh9vhKCOhgLxvLzMzk+uuvZ2BggI6ODiIiIuZsPiqViuXLl7Nnzx78/f1nbfHgTjx3oNFoyM/Pp6SkhB07drBy5co5yda57rrrUOq8CFq+xuXjE4O137m5LseMFVXaM8RD/VFHTPakMte3g238BDkmiEpxmEpxQolxyTHE17cTGBFOyu3fw3880CYqvPEV1PisPR/duq+j0mpQqtUoxoP1bZokbID1j3/EZrMxplEwpLAvEoYkC/XiGD2D7dQ9+zb9A/34PHoj1pPigJAQATYbI6VHcXXWrl+RzsDb2xCbu7D2DKAKCTjhcYVOg+9Z2Qx9tp++/+zC75zcScFGUCgIuvocOv/8L0bqqhhrqcc7ZrLvnKBUEvX1q6h/6S/29360B6VSxX333cfvfvc7l+/9dJAkibq6OqqqqsjKyiIuLs7luLkS0SVJorS0FIVCQWpq6mm/31RUVFQQGRnJ3/72NxYvXmwvp/Tg4SvCd77zHR577DFeeeUVzj77bKqqqliyZMmczmnRokXs2rWLw4cPs3jx4lm5pzvx3IGjsaher2fv3r1uv19PJ5dddhmizUbY+q+7LrkWbfQf3G2vgjp/9STvUQBzUyfWngEAvFe4ENhFEWNNI0gSLIigThqjzjbGuKUqaovI8B1/JygoiIU3X02gVxB+gppIhY5UVPjE+OF9330oVSpUGh1KcMbymzWJ2H7wU6xmCwZERlUqBiUrw5KVDtHIESzUvPQi/V09qK6/ACnlRP91W/x4BpjVhqW9F030iRlh2sQop8/5WHGV3bLlJPzOyWXsQDWWijosnX32xqUnEXDRWoY+LUAyW+jdv42wdRdOGgMQuuY8BitLsI4MYrOa6Os7xtlnn81//vOfU/IA7uvrY//+/YSHh5OVlSX7mZwrEb2lpYWGhgbWrVs354fOzc3NjI2NMTY2xpYtW6ipqZnT+XjwMJtER0dz22238etf/5qXXnqJ8vJyQkJC5rS6MzIykq6uLgoLC1m7du2s7S/ciecT55aXl8f+/fsZGhqS/X49nezZs4fmlhaCc89C5TO5ETdA30G7DZsyOgRt0uQqKEmSGC0oB9vkg3AHxpomEBR4ZSygTTLSZjOynwHA7jls+ts7ePeMEHvxRqICF+MrqAhATbzCC19BxaV3/Aa1Wo3aW4dCUDgF9Fs1idjy4rFmn4PJYmFMpWNoPBluAAtN4hhNBTto21eCLTsZ5bfyT7RhUYImLgJTXSvGmqZJArqgUKDPyWB4ZwmDew5NEtABfNZk0fvyR0gmi2xSm1dGArpFiRirGmj9/F1SfpzqsmeMPm4h/otzGawoAkmiv+8okZGRbN68mYyMyR7r08VkMlFUVITVamXdunWyh0lzJaKPjo5SXFzM4sWL57zB7tjYGDU1NSxatIgrr7ySp556yllx5+G/n6+MgJ6YmMivfvUrfvnLXzrLJUNDQ+c0YAcGBrJkyRKKi4tZt27dad9ITEc8d6BSqVixYgU1NTXs2rVr1svHXnzxRYaGhgjfeDEKjesM+L4Du0FQoIwORpfkuqHcyL4KkCT881yLLPZgLaCIDUNQT/5zGGjtoK+xkRa1lUHbwKTHu559k5G95fh/I5/g75yHFgUP6TK4x1SNCZGGnz2EODRKxG+/j/eSE7OerGojTYcPAxA/NDKpganO4f82Moa1fxhV4ImfD82CSJSBvtj6hxktrsL//MllkH5n5zL0SQFS9wDGynq8Fk22PPBekY4mPhJzcwetm99l4fdvcyl0eEXGEbR8LX0Hd5O8cCGbN28+JUHGZrNRVlZGZ2cneXl5U2ZIzoWIXltbS09PD+vXr59z65bu7m66urqIiIjg6aefpqioaM5P3z14mE0UCgVPPfUU55xzDt/+9repq6sjPj7eWV46Fzi8x3fs2IGfnx/x8fGn9X7TEc8dCIJAYmIiPj4+FBcXMzQ0REZGxqwJiAaDgffe/w/ecQvRx7kutR0+ehjrqP3Q2u9rk8VjcNi3CAjhQS6beVvaepw2LNqFk9cCo129tLW10dbWxoiXGYWt94THRwrK6HriDYTgABKe+pX9OuOx/Pemalqe/TfDO0rwOyeXkB98fdL1m9ubsbR0EdrWie9JArrS1xtVaCDW7n6MNU2TBHRBoUCfu4jhbcUM7il1KaB7ZS1EFeKPtWeQoc/3E/zd8yeNUfp64/+NfAbe2WH3QV2+9gQPdAcKtYaoC6+k6fVn0Ov1/Otf/+Kiiy6aNO6L0NTURFlZGRkZGSQkJLiNS3Mhog8MDFBaWsqKFSvm3C/VYrFQWVlJamoqF154Iffff/+cJvN48DAX3HXXXbzyyivs3r2bBQsWcOzYsTlPUlm8eDH79u3j4MGD5OTknNb19XTFcwdBQUGsX7+ewsJC9u7dS05Ozqw2Pb300ksRlCqCV25w+bjNMMrQ4YMgigReONmKDMBU14ptYASw7ztdYaxqAFF0GcdFoK3qKLa+Ifot2dTZTuwfJhpMNPzwAQDinvwVqpAAZxz/namavuLDdD76Kui9SNx016Tr9w11MVBXj3eghggmvwZtajymxnaMR5pgsgML3ivSGd52AHNZLaLRhEJ3onah0GnxXZ/N0OYi+t7f6TKpDSDoqnNou+cZbP3dDB8pwy9tqcv3KmLjNxk5WoFkNnLbbbfx6KOPntJndnBwkMLCQgIDA1m1atWU++vZFtEtFguFhYVER0ef9nX2dKioqCAqKoq//OUvZGVlcemll871lDzMIl+p2v/f/OY3dHR0sHXrVjQaDUePHp3rKREbG8uCBQsoLCzEbJ7srzlTfBHx3IEgCKSmppKdnU1JSQlHjhyZtSYrN910E0pvHwKXufbGsxlGGao8AJJ8sLb2DGBuaAfAO0cmWB9ptPunuxCWYbzxmEKBV7QbvzVRdOm3Bsd92CTT5N+tMsAHlPY/QVeNRFXhQc4SN9PRpkmPC4KAfuUiUCoY3F3q8v6amDC0qfH2RqGfFLgcIwgCQVedA6KEpaOZ0Xr5Rruh6y5A5e1DQ2Mj0dGTMwymi9FoZO/evQwODrJ+/fpp2ws4RPTZaCza2dlJdXU1ubm5s7pQdYUoipSVlZGamsrtt9/OjTfeyKJFrpvxefDw38zq1au54ooruPvuu0lKSqKsrGxOm38B6PV6cnJyKC8vp7e3d+onfEm+iHg+kbCwMNatW0dnZycFBQWnda0xkUsuuQRJtBG23nU2NEBf8U4QFHgvT0MV5DqzbbTA3sckIN/NQTiAv8+kXiMwHscBNGoULvqViI7GY96u7YAErRoE101EAWd1m6s4DqBLjQOlAlPN5DgOoM9JB5uIpaoR26hh8v0VCvzOXWWP45/uQzRbXFwF/L+e7+y90rP3c5djAHwSUvHLyGZ0zEBw8OTKvOkiiiIVFRVUVFSQm5s7bXsBh4g+G41FjUYjhYWFpKamzguhuqqqCj8/P958801UKhU33XTTXE/Jg4dZR6/X89hjj3HHHXcQHx/P0aNH57zptUKhYMWKFQwODp7WqpAvKp478PLyYu3atXh5ebFjxw4GBgZO2xwn8vnnn9PZ1WXPPvd2PdeBsiIkmw3USnxWu67EG9tfCQoFiphQl7He2jeErc/ewFPnooGoZLVh67fHCrWrZuCGCc3AtZNjubNXmcV1/FSFBYLNhqHZddNWXXIM2ETGyo+5XHN6LU5yJuKNlbrWl/zOyQVRROoZxFhZL3OfWLyWpoBSQevm95BEm8txSi89Eed+G1EUaW1tPSXxvK2tjV27dhEfH8+KFSumnZzmENFPd2NRSZI4ePAgWq2WzMzM03af6dLV1UV3dzc2m41nn32Wv/3tb56Etq8YXykB3dvbm7/+9a/85je/ITY2lmPHjjE6OjrX0yIjIwMfHx8OHDiAKIpTP+EL8mXE84lERUWxdu1ampqanKU9p5Mnn3yS0dFRQtech0LtekNrD9aiPVjnuS4FGy2qAgHw1qJNmJw9L0kSxupGECV0Lk67ASwdvWCzuWw8BiCOOTp+y228Hc3HJm+8BYUCVZDdGsfVxlsQBLTJsSAI9hNvF+hX2Dfe1mOt2IZcf5b9z1sJksRYUSXW3skd7yWbDdvgsL1BG9C25T0kyfXnUKnVEXn+5VjMZr7xDRdH8NNgYGCAnTt34uXlxZo1a/Dycu1vL8dsiOjDw8MUFxezdOnSOfc9B3smvEKhoLCwkJqaGn7/+9/P9ZQ8eJgz/vSnP7Ft2zbq6uowmUw0Nbn+fpxNQkNDycjIoKio6LQIAV9WPHfg4+PjtK/YuXPnaRUtAUZGRvh882Z8EtPxjl7gcoypp4Ox5jqQRPxclDMDWNp7sLR2A26y1mqaQKnAZ7HrLHdLZ5+90izC9UGtaDSDQkDj47pcWaFRgzQ+zgWq0EBQKbF09rt8XJscC6LIcPkxl497ZSQ4N/djB10fYPuelW1vcmqxMbq3zOUYS0sXygBfUCroO7Ab84BrQR8g4msXo9BoOP/8ydns08FsNlNYWEhnZyfr1q0jLMx1koEcsyGiO9YIISEh88JjfHBwkKamJoKCgnjggQd46qmn5qQpugcP84FLL72UJUuW8PjjjxMdHU1FRcVcTwmtVsvKlSs5duwYbW1tM379LyueO1AqlSxfvpyEhAR2795Na2vrjM/xZK6++moUag3BuWe5fFySRPoO7AIk/L6Wi0I3eT8sSRIj+8rtfUzkDsKPjguwaiUqF5ar1p4Bu00boAoNmPT4xPgsuEhqcya6WVzvGR3XlLr6XQrk2oXjor7RjLV7cqxXaNR24VuhYLTwsMt7aGLD7esBhXxSm7VnwC7E20SkkUEGyotcjgPwS1+GfkEKr7/5JrW1tbLj5JAkiSNHjnDw4EGys7Mn9SCbDrMholdXVzM8PExOTs6cW7A5qufT0tL4xS9+wa233uqsqvPw1eErJaCDvQlGbm4ujz76KDExMZSXl8/1lBAEgeXLlzM2NkZlZeWMXvtUxXMHfn5+rFu3DrPZzK5du05rpsAdd9yBoFTik+R6szwxWKuCAzDVtrgMdiMFFYCAX/6SSY27AKxd/Ygj9tehdXHaDWBpt2cTqlycdgOIBns3b1fBGo4HbLmNt3p8Q2+Vy1xLsQvoIxWuA6MubQHC+GJltLjK5Rh9bgaK8QarQ5uPB2LRbGHos0Kab/0L3X9/B+9oe0mUtbeT4SPyfxe+yZn4pizmk08/o6SkRHacK1pbW50lm8uXL//Sm8fTKaI7hIGEhARiYlwfrMwmBoOBI0eOsGDBAn7961/z5z//ec7L0D14mEvCwsL4wx/+wG233UZycjKVlZWzllXtjoSEBCIiImb8O+lUxXMHDruZyMhIdu7cSWdn54zN8WQuvvhiJFHEL03eo77v4B4Y9/e0DQy7zKy2H4QL4OuNJt51BrGxsgFs4vEN7klYusYryWJc95qRjGZ7rxQXWWvgiO8SolwGelgg2EQ3mWuxIAE9g9hGJq+dBLUK7+xUtxtvpZ8e/cpMUCrofX+Xc80jSRJjh47Sdt8m2n7/HAqbGkFhj6vduz9xeS0Ald6XiK9dwsjIyBdufDU8PMzOnTsRBIF169Z9aS/S0ymiS5LEoUOHkCSJpUuXznl2mCRJlJWVkZCQwL333svFF1/MunXr5nROHjzMJYIg8Le//Y3nn38eq9VKT0/PaY1J08XPz4/s7GwOHjzI4ODkpKMvy6mK5w4EQSAlJYUVK1ZQWlpKVVXVaavC27x5M729ffgkpsvaqY7UHcEyNC4o22xYx7PIJ2Jp6cLaZR+jlzkIN40fhHulu65kciaaKQUU+smJVxMrvV1Zsjoz0CV735STcdrD2STE4clxWhUagGL8kN3orppMFBktrJCvFDtvFYiTk9rMbT10P/MOTbc+jrGiAU1IOAgCHds/RLS6vpYgCESefzmCoGD1atcV+3JYrVaKi4tpbGxk7dq1p2TTezpF9NbWVurq6sjNzUUjk6w4m9TW1qJSqdi1axeNjY3cfffdcz0lD3PAV05AFwSBJ554ghdffBGDwUBfXx8dHa43PbOJY2Pb1NQ0Y9l0MyWeO9BqtU6v6h07dpyWUvV3332XsbExBBTUPvsnOj5/53hgHmekrtr5b4JRov2Bf9B8y+P0vbnFnjEO2IZG7cFYktxnrQFo1S4zzCWbDWufPbi5KhcDkAz2gO2qLByOZ6BLcplr4UGgVMqWfmsX2jPXbI0dSC5OzQWV0v76lPIbb0GlsnvLKgQGPt6LtXeQ/re30vTzR+l54QO8Q+NJ/OHtLLjmZrzjkkBQ2LPQZcrGACLO+TaCSsVZZ7n2wzsZSZKoqqqitLSU5cuXk5KScsob2tMhoouiSHFxMT4+PqSnu/7czDaHDx8mMjKSp556ipSUFK666qq5npIHD3POT3/6U3x8fHj11VcJDAykqsr1AeJsIggCWVlZqFQqSkpKZmRTO1Pi+cQ5Llq0iKysLIqKijh2zHU58qkgiiI7duxEodLS9tH/0fTGc4y1nFiubDMZGSjbD5KIOiiE7qf/TdNP/kT3s+9gqKp3bnBHCux9TPzyl7iMGbahUaxd9vipTXZfSaZ2kbUG4wfcguAycw7G47gkOSvOTkYVGmB/XCaOa+IiQGX/vZmOut5cOjbeY8VVsgfu/ufmgk1EbOvBWN3A8M4SWu94io6HXoIBKzHf+gFJ1/2KsDX2rPLBimJMPfLrW//FOXjHJvLCiy9Oe93Z2dnJzp07iYyMZOXKlafcNOt0ieh1dXV0dXXNyN/MTOBoHNra2srHH3/MI488MtdT8uBhzklNTeXWW2/lF7/4BampqZSXl2Ozye89ZovIyEiSk5MpLCzEZHL9vf9FmCnxfCIRERGsXbuWlpYW9u/fj0XGmuRUuOWWWxEEgaHqUuqe/18GysetWibQV7zLfhCu9WZ4ewlNP3+E9odeYmTPIbvNKTC6v9JeQRXggzrGdbWSsaoBbKI9ccwFjkQzISTA5VrAecAt4PLxiYlukmnye6UK8Xf+LFcVrkuJA0HAVOM6jnsvS7Uf+IsSxoo6l2P0Kxc5DwCGNhdhrG6g48//ouX2vzJWVEPYugtI/undxFz8fZAkJMMo/SV7XV4LQBMQTOi68+nu7ua+++6THTeRsbExdu3ahclkYv369fj7+0/9pCk4HSL6wMAAJSUlLF++HD8/1xZ/s4mjcWh8fDx33HEHjz322Jw3M/UwN3zlBHSAhQsXcvvtt/OLX/yCtLQ0ysvLT7styXTw8fFhxYoVlJWV0dcnX3o7HWZaPHegUChYsmQJaWlp7Nu3j6NHj87o5jsuLg5BUCDarPjowxk8VMTRv/+R1v+8irHLXk7XV2xvHqqJiGPhT+4i/js/Rx+5kKEP9tJ82+O03vV3eja9by/1Ugp4LUpweS/7abcS70WuT7utvYMgOsrFZDLQxwO2bAb6+IZcNgM9NAAkEUt7j8vHJzZSMdW7Lid02LgYDh1FHDO6HOP7tRz7azGaabrpEQbe3YV/8lIW/vi3xFx8Lbpwu5952LoLQRIRhwcYKC92eS0Ata8/4Ru+ydDQILfeeqvsOLBnUBcWFtLS0sLatWuJjIx0O/6LMNMiemVlJQaDgeXLl895xhrYfdYcGTlPPfUUTz755LyYlwcPc41SqeSpp57iwQcfxM/Pj+bm5lOOmzOBQqEgJyeH/v7+U/ZRnWnxfCKxsbHk5+dTW1tLcXHxjIgEDhQKBb4+vohWE97eoVjaO2h45W80vPw3ho9WIEkigxXFSONZVQnfvYWFP7mToOz1GA/W0X7fJppv+jM9//gP5jp7ibpero/JBEFaK5Oh7oivcpVkktEE0oQMtZNfj0Zt7xEy7NomzXnAbra6jMGCSum0kZPLXPNeluq0UTOUufZP1abGo46yNyFtv38T3f/vbdSqAOKv+hkJ196GX2oWgqAgMDsP5bhXbdeOj1xeC8az1y64Aglhyuw1URSpqqqiqKiIrKwsFi1aNGOxaKZF9K6uLqqqqsjNzf3CFnGnA5PJRGVlJSkpKdx2223ce++9M7oO8uDhTObuu++msbGR3bt3o1Kp5kV/MoCUlBQCAwMpKio6JXvV0yGeO/Dz82P9+vVYrVZ27do1477oiYmJSJKIRuOD2qKk7cPXOPb3P9K7fwc2kxFzfw+j9dUgiUSffxkpP7+XyPMug14LXX97k8Yf/4nOJ95geMdBECX8ZQ7CRbMF03jPMtmK8M4+UCrlK8nGE9qQqWyemOjmak8uqFT23mTIV4VrU2JBgBEZOzalrze68b5jo/tlktrUKny/tsKe1PbOdtrufR5rXQ+R519O8k/vJmTlRpRaHbrQCPwyskFQ0LnzY2wm1/t7gOCc9WhDI7nvgQcYGRmRHQfQ3t7Ojh07CAoKIi8vD63WdWXBl2EmRXSj0cj+/ftJSUmZF/1LJEmivLzc2Th08eLFXHbZZXM9LQ9zxFdSQAf47W9/S0dHB59++ileXl4cPuz6i262CQsLIz09nf3792MwTG4mNR1Ol3g+kYSEBPLy8mhsbGTXrl0zljWUnZ1NU1MjGzduYGS4HZvViI8+grFjR6j7x6M0vPKkM1iH5q63N9KMSyL6wqtIuek+oi++Fo0y0F72rVCgz1mEIBNMDVUNYLO5D9bjOILqyThOseU23oJWA4IgW/qtCg0CUcLU2uXycaXey56ljpuN95JkZzPSsRLX/qnqsEC8liSDQoHKN4CUG39H5LmXogkMOfFaMQnoE9JAoaBj+weIbgRpr6h4BKWSJ598iqGhySV7kiTR3NzMtm3bUKvVrF+//rScIM+UiN7Y2EhTU9OMZNXNBBaLhZKSEtLT07ntttv42c9+Ni+ap3jwMF/Iy8vjiiuu4I477iA5OZmSkpJ5kb3m8FE9evQo7e3tX+oap1M8dxAYGMj69esRRZFt27bNqOdrV3cnt9xyC1brMCZDP15ewUgDIzS//Q9qn/kTPfs2A+CXkY3K2wdNYAhha89n4U/uYsE1N+G7IJORnYfsorJaiS4t3uV9HGXfygURLmO9JIpYuwcAdwfhZpAk2WbggtOKTS6OH7+ubCPRFHsjUWN1o8vHFd46dBkL7JZtctVkgoDfeeNe8RIsuOYm4q/4MfoFySeIEgq1htD8cwEYPlqBoV0+u1zlpUcXGklbeztvvvmmyzEDAwPs2LGDjo4O1q5dS2ys6zXTqTBTIvrIyAjFxcUsWbJk2s3JTzfl5eUEBgby2muvoVQqPY1DPXiYgF6v5/HHH+fXv/61sz/ZTFqnfFkEQWDZsmVYrdYv3az8dIrnDjQaDatXryY6Oprdu3dTVVU1Y/3UPvjgP7z88ssEBOgZGW5HpfJGi56ubf/h6FP30/LuP+3Z5xodfimZKHVeBC5dbT8U/+ldhOR+DUtNhzMGy1WEm+vbYHzO2iSZSrLOPrCJ8paqDlFcNo4frzCTawiuCgs6fi8X6BbGgCghtvfKrgf0uRkADO8tm5St78DPkdQGBK/cSNIN/0PgklUoVCfOPXTNeYAEFrO94bosAvr4hUg2m2xfE7PZzIEDBygpKSEzM5MlS5acFj/xmRDRbTYbRUVFBAUFkZycPMMz/HK0tLTQ39+P2Wz2NA718NUV0L29vXnuuee44447CAoKorm5me7u7rmeFmA/8Q0PD6ewsPALi4GzIZ47CAoKYsOGDU5Ll5nKRo+JiWHLli20trZw0UUXYRjrwmIawVsfhrmzA0GhBLUW35QTO30r1Br805cSdeFV9sAkis5AdjLimNHZmEwn45vqPIEO9HHpoQ44y9PcbrwVgryFi6Ok3GCWzVLXpcXbN94yjUQVXlq8MpNAITBSKO+h73fuShBFrEMDWIYGZMeFrb/A3iVcpmzMZjTQsfld6l/6C1ptAKJom3QK6zg5Pnz4MMuWLWP58uWn1bvsVEX0vr4+ysvLycnJmTflWBUVFfj6+vL+++/T1tbGAw88MNdT8uBh3vHoo49SVFREQUEBKpWK6urquZ4SAP7+/k4fVVcHjO6YDfHcgU6nIzc3l0WLFlFaWkpxcfGM+Mmr1Wr++te/Mjo6zG9/+1uUSjOG0W40Gl+UZrCO2bOkgrLzT3ieICjwjk0k8txL0YZGgSjisyoTQeY9MFQ3gk3EJyPR5eO2/mGw2TfmclZsotEMoih/EO74d5kYrfDSovDWAfIbb21yLNhEjNUNsptqfe4iQGK0oAJJJob5rl3q9HcdbZZvGhawZBUqHz9AoHP7h5MelySR/kMFHHvmT1h6e1CpvLn+uhtOGCOKItXV1ezevZvIyMgZK/WW41RFdIvFQmFhIfHx8adF5P8ytLW10dXVhUql4g9/+AObNm2aFwf0HjzMJy699FLy8/O5++67SUpK4uDBgzMmAp8KKpWK3NxcOjo6aGho+ELPnQ3x3IFCoSA1NZW1a9fS2dnJjh07Ziwb/bvf/S6dnR289dZbREeHMjLciiAo0euCMXW3gyQSsnwNgvLEA2xNQDCh+ecQuHiVvSJcp0aXGufyHsaaJrv1SZAfSh/XVUOWth5AOu5VfhJOQXuKg3D7WDd9yRQK+Tg+Qdw3HWtxOcZ7Rbr99Zqtsgfm6vAgvLIWgkLBWNMxBMG1xqANCsV/cQ4ICrr3fI7VMLkKbqy1gfqX/kJf8W70+jD27NnDwYMHTxjT3t7O1q1bsVqtbNy48bTHx1MR0R39Qmw2G8uWLZsXIrXRaKS8vJy0tDRuuOEG7rzzznlj8+phbvjKCugA55xzDldddRW33HIL6enplJaWzgsrF4ePqlKppLS0dNqi9GyK5w6USiWZmZmsXr16xrPRIyMjee+99xgY6OfHP/4xiCNYLWNIoo3g5fkoZDLLR2orsXfsAu+lKS7HGGtbnN28tUnRLsdMWS5mtTo35nLNx+wlY4J8sJ6woXf4uJ6MbqF94z1WIe9Vq8/NGG9Kcli2cYn3shSUgfbmk30HdrscA+AVEYtvcuaksjFJFOkv3cexZx5koKSAmNg8NGr7glCv19vHjGedb926FZVKxcaNG2etVPnLiugGg4H9+/eTkZFBaGjoaZ7l9Ojs7KStrQ0fHx/uvvtu/vGPfzjfYw8ePBwnODiYZ555httuu42IiAjq6+vnhZULQFRUFElJSV/IR3U2xXMHgiAQGxvLxo0bsdlsbN26dcay0VUqFQ8++CBDQ4M89dRThIT4YhjrQZBAFRiKV/QCl8+zjo1gGPdN917h+iBcstow1do3sdOpJJvocToRh+3KVM3AceGb6rz2+KZetiG4w45NAnOT60Z5+uVp9qWLTcQg45+q8Nbhs24pKBV0F26X7VWiUKkIXXs+IDHWeJTRxuO2CGPNddS/+BfaP36DIP8kQsMWYbWMndDUe3BwkB07dtDe3s6aNWtIS0s7LdlqJ/NlRXRJkiguLsbb25uMDNefl9nGZDJRVlZGeno6P/3pT7nlllvIzc2d62l58DDvEASBp59+ms8++8xZEX6qFmgzhbe3Nzk5ORw+fHjaiXazKZ5PxN/fn3Xr1hEZGTnj2eiXXnopDQ0N7Nmzh2XLshgZbnf2KglYukr2eUPVpQD4rFosm4xmPNIEAvhkJrl8XJIkrN323mfyVmz2XiYavbfLxyc2FnVbTSbg7Kd2MgovrdNGTa4qXB0W6PR5H90/dVKbob0JQ4drMR5wVpMh2ujdt8X575ahAVr/8yoNLz+BakwkLn4dRuMggqBwft4mZp1nZGSQm5uLTqeTvddM8mVF9Lq6Ojo7O1m5cuW86F/iaEgeHh7Oc889h1ar5Te/+c1cT8vDHPOVFtDBnr129OhRPvvss3ll5aJUKsnJyaGvr29ai4i5EM8nEhwczFlnneXMRp/JxmQ+Pj4888wzjIyOOC0sApfmyY4fOlIGggKvzCRnVtjJmGqaQKFACA2QHWPp6APRXbnY8c202wx0AUSDa+8yhZ/eGdTdZq4BGMzOBcTJeC9Ps/8ggaHMtTeboFDYA7YgMFBWiM04ucu4g9C154MkgsVEX/FORuqqqHvhz7R/8iZBfklEhC+hpWkPoyOt3H333fz73/+e9axzV3xREd2RsRYREUFCgmuv/NnGYrFQWlpKeno6P//5z7nuuutYv379XE/Lg4d5y8UXX8zXv/51fvWrX5GSkjJvrFzA3iTN39+foqKiKec0F+L5RE7ORj9w4MCMZKODXSC58cYbaW1t5YknnkCSREJy1slmF40cq3Qecnsvcb2mMTd1gNX+nk7sFzIRZ1zV62Tt3ESDfTMtH8fH45goOQWDk1FHBIEgyMZxZbA/Cl/7IajcxlsV7I9m3Mfd7cb7bHszUUwGho/Kr1kDMnNQ+wUCAp3bPsDU103LOy/R8OqTqAwicQvW0993jI62g5x99tdobGpwZp3v2rWLiIgI1q9fT0BAgOw9TgdfVESXJImKigrGxsZYsWLFvMhYg+PWLf/6178YGxvj3nvvnespefAwb4mIiODJJ5/k5z//OXFxcfPGygXse9zFixdTVFQ0re+juRDPHSgUCtLS0li7di0dHR0zmo0Oduu84uJi2tpa7aJ3Yjoaf9d2WZaRIaeFmF7GvkWSJIzVDSBKxw+aT8I2OIJkse/n3PYkUwgIcs3ABcG535arCleHBoJNxNTi+pAbQJfmsGOTt0bTr1wECoGh3aWyawbvZSlOe9i+g/JJbRr/IAKXrQZBQe/+7Zh6O+na9Qm1zz7E2NFq4hasR5Ikmhp3EBERQnFxESkpKXR0dLB161YsFgsbNmwY7zE3u7Hxi4ronZ2d86p/CZxo3fL444/z4osveqrIPHgEdD8/P55//vl5aeWi0+lYuXIltbW11NbKl+rOtXjuQKVSObPRGxoa2L1795TNLL4IgiBQWVWNPiENTYDrYC1azIzUVoEk4i1j3wLYA58oyZ52w3jjMUmSLfue6KHmtvRbOr5Bn/S4IKAKtmfFyW28NbFhzqAvu/EO8HWWlo3K+KcC+G5YDuPxc6Bsv+w4XVgUfunLQKGge9cnNL3xHFqzmtj49fT3HqWtrZh169bS3t7G/fffT0tLC1u3bkWpVM5q1rkrpiuiW61WCgoK0Gg0ZGVlzZtNt8O65b333qO9vZ2HHnporqfkwcO854knnqC4uJi9e/fOKysXQRDIzs5GFEW3zcjmWjx3MDEb3Wq1snXr1i/t4y7Ho48+iqBS479oueyYoepDIAh4LU1BoXPd5MpZ9u2lQRUS4HKMtasPlAq00WGy95LG47Mgc+A7MTNdkqnwUoUF2ku/ZTLXBEGwl68rBNk4Dsc33sN7DsluvLUJUWgSo0EQ6DuwS/ZaglJJ6LoLAAljRzO1zz6EsbGBuAVnIdlEmhp2EBLsz44d2/n8888RRZGdO3c6s87T09NnJevc5dy/gIheXV1Na2vrvOlfAidat/zxj3/khRdemLXMPw8ezlSuuuoq8vPzueuuu1i4cOG8sXIBiI+PZ8GCBezdu5fRUdcNpedaPJ+Iv78/69evd2ajV1dXz+h7+eSTT4IkEXiSDdtEhmvK7T8I4LXY9X7b2tmHOGLv+SZXSWbtPJ48pnZYn56EOJ6BrpCpCIfjWeiiQcZW1bHfHzPJVnNrx6vCDZW1sjFavyLdbiU7asRU2+p6LkolfufYk9oGy/Zjc2HP4iBk9dkICvsetfa5h+ndt5WI8Gz8/RNoatiBxdzHww8/TEtLC5mZmRw4cICDBw+SkZHBypUr51SMnq6I3t3dTVFREcuWLZs3/UsMBoPTuuVHP/oRd955J4sXL576iR7+6/nKC+hgt3K5+uqrufnmm0lLS6OkpASLRb5Udzbx9/dn9erVVFdXU19fP+nx+SKeT8SRjR4YGMj27ds5evTojGQD3nfffYg26yTP1ImM1B9BstkFU70jK/skJFHEeLQJkGSz1iRJwto1Xi4WKiPWTzjBlrVw0WpAkpwbdFeoIuzXlyv9FpRKNIlRAJhq5IOPPjfD3oBsXxmSVaas21uHNjH6ePm3JL+YCl17nrPJia9vDGbTCM2NOwgPD2bnzh3s2LEDb29vZ9b50qVLWbFixaxnnbtiKhHdZrNRWFiIQqEgNzd3zkSCk5lo3XLPPfd4rFs8eJgmQUFBPPPMM/ziF78gMjJyXlm5OL6PTCYTxcXFkzax80U8n8jEbPSSkhIOHDjwpRubT2RwcJCmlhYCMleg1LoWFG0mIyMNR0CSZPuYgKPsW8A7I1H2ANTS2QeihDpcfkPmKOeWtXDRTO2dqgoNBNGGsblD9j665FiQYLTcdZUYTNh4mywYj7j2T5UkyZ6VL0mMNdVi6pHPlvPPyEYTGAqCgErtjY93GE0N27FaB3nkkUdob28jLy/PmXUeHh4+J1nnrpiOiF5TU0NDQwN5eXnzpn+JyWTi0KFDpKen85Of/IRbb73VY93iwcM0cFi5bN68mfJyu/g6X6xcANLT04mKimLv3r2MjZ1YxTufxHMHE7PR29vb2bFjx4yti5544glUPv74JLrea8Pxg3Dv7DRZYdt49Pi+VhPn2jLV0jl+MK1WylaNS0YzSMhmoMPxZDd5C5cA58+ydmwOkd8qjvuyT0azINJpmequmsxrcZKz0m6grEh2nNrXn8DsNfaEASA8bDHtbcX09lRx2WWX0d/fx69//Wva2trmPOvcFVOJ6L29vezfv5+srCyio13b6s42rqxb7rjjjrmelod5wvxQjeYBjzzyCMeOHeOzzz5Dr9fPGysXgMDAQFavXs3hw4dpbDy+oZqP4rmDidnoLS0tbNmyhaamplOydXnsscdQ+fjhkyTfuGH4SBkoFGgWRDozu0/G0trtLN/SyZx2i8NjzkwzlbvT7nFkS781apAk2dNuAHVYECiVsplrALoUeyNRQ1WD7BjvnPHGJVYRQ+XxwxZJkjDVtdLz4gc03fiIvfGJBOLoEKP1R2Svpw0Kw3/xChAUDA+3oFZbefrpp2lpaSY3N5fy8nK2bt2KWq1mw4YNREVFyV5rLpAT0R3/L4oiK1euPMH3dS4xm81O65Ybb7yR66+/nnXr1s31tDx4OGO46KKL+MY3vsEvf/lLUlJSOHjw4LzoawL2ppqrV69mdHSUgwcPOmPhfBTPHTiy0Tds2IAoimzZsoXKyspTSjD4/ve/D6JI4DJ5G7aRuioYP2TwzpbfnNvLvkV0KfINsSxt9koyOSs2AGnc21whV0k2MQPdXem3BAwbZBuAapNj7TF6aAxrn+vGsurYcKdX+8kbb2vfEAPv76Ll9icYeGcHjH9W+g7ukX1tgkJB2PoLQZKwWsYYHKznhz/8IYOD/fzyl7+kvr6ezZs309XVNedZ565wJ6IfO3aMY8eOkZeXh5+f3xzO8jiOTXdQUBCvvvoqBoPBY93iwcMXIDw8fJKVS3+/a/vK2UYQBDIzMwkLC2Pv3r3OQ+X5KJ5PxJGN7hD/CwsLT6lf2cGDBxkeGSFoeb6sr7nNMMpYc639IDxH/iDcVNMESiXalDjZZuH2nmQKNJHyfapEowkkSXY/DsdjuVwcVwX5wXimt1xVuDo61CnEy1WTCYJgryZTKhjcXXKC9iGazAzvLqX9jy/Q9vvnxuO4QPd+90ltIas2Ot+fjo5ScnKWc/ToEd58801GR0fZuXMnZWVl8yLr3BVyInp/fz8FBQUsWrSIuDjXTWbngqamJgYGBjzWLR5cMn9WyXOMn58fmzZt4o477sDPz4+2tjZaW12X3cwFQUFBrFq1ivLyclpaWua1eD4RRzZ6eno6R44cYdu2bXR0dHxhIf3QoUMMDQ8TmC0frCWbleGjFSCK9sAlgzPgKQRno4+TmRg4T8nCRWsX0K0j8qVZqrBAeyORZjeea8kxYBOxNHfK2sFookJRjWfZje6vxNLRS/8722m5/Qla73ya0d2HCczIJfFHvxn3qxPoK5Yv/wYIzT8PsJcuDg4OcP3111NdXc3mzZsZGxtj/fr1ZGdno9W6LrGfa04W0c1mM8XFxZjNZlatWjVvxHNJkjh48CABAQG8/fbbdHR08OCDD871tDx4OOP461//yoEDB9i1axdeXl6UlZXN9ZScaDQa8vLyGBwcpKSkBLPZPG/F84l4eXmRk5NDfn4+/f39fP7551+6suzDjz7CKzIOXbh8ltFQtb2PiXZhDKoA10KEtXcQW79dANAudCOgj8dyubJvsG9oQT4DfaK1i1z8VYUdv76la8DlGG1ilDODbGLW3Qn3EgT0ufaN99DuUmwjYwxvP0D7A/+g6eeP0P/GFrz8o4m76qcELssHQUF/yV5ns29X+KYuRhsaiVKloqOjnU2bNtHT08PWrVupq6sjKyuLtWvXzousc1e4EtHr6+s5cuQIq1evxt/fdbLEXNDQ0EBfXx+CIPDggw/y4osvztv1kQcP85Urr7yStWvXcscdd5CSkkJxcfG8qQwXBIGsrCyCgoLYu3cvRqNxXovnDhQKBampqZx99tl4eXmxfft2SkpKvlRl2fe//31AICBrpeyY4Yl9TLJTZccZqhrAZrNbnMlg7ewDCdQRwbJjRKMZRFF2Pw44s+DlMtAFpRJlgD1zXE5AFxQKZ/W6Wzu25en2XiX9I5gb2hk7dJSup96i8cd/ovvJt2BAIuqCK4n51g8ACXF0iJE6eetBld6X4JyzQBB48cUXKCwsJDg4mH379rF//34iIyM5++yz503WuStOFtEHBwfZt28faWlpLFiwYK6n52R4eNhp3XLDDTdw1113eaxbPJzA/FCP5glnn302119/PT/4wQ94++23KS0tJSAgYN5YKISEhJCbm0thYaFzQzGfxXMHjiy26OhoGhoaKCkpwcfHh4yMDIKD5YPhRK699loAAt0E69GmWkSzPSjKNSuB8YCnVKBLiZMV453lYoK90acrTrBwUbkWPpwlayb5hZ8qNNC+yBgYQbLZXJ7ATxQITMdaZL3k9CsXMfjBHoY372d4834EtRrflMVE5F+CT0IKgsJ+7cDsNXRueZeRumrMA71oAlz/HjQBQQQuXUVrRTH79u1jcHAQHx8fVq1aNe3f3VzjENH37t3L1q1b0Wq15Ofnz6uT5Lq6OoaGhtDr9fz+979n69at8+Z7x4OHM4mgoCBefPFFLr30Unbu3ElnZydNTU3zJrPF8f2za9cutmzZgr+//7wWzycSGBhIfn4+XV1dVFZWUldXR1paGrGxsdPKWn7xxRexWiyEubFhE60WRmoPgyTahWQZJgrQ2iTXYrxt1OC0T5NrPCZZbfZNLu6s2KZp4TKOtasPTVTI5OvotKijQ7G0dGGqacJH5qDfOyedwY/2wrCBxh8/BBJ4xyURef7l+KUuQamzZ5ap/QLpL94JwODhA7L2doJgz0JvfmsTjz32GOeeey4mk+kL/e7mGseaF2Dnzp1IkkReXh6BgfKVBbPN4OAghw8fJjMzk/POO4877riDnJycuZ6WBw9nHIIg8Pe//52lS5eyZcsWli5dSmlp6bxpEiwIAsuWLePAgQNs27YNQRBYs2bNvBXPJ6LT6cjKyiIpKYmqqiq2bNlCQkICycnJ07LgtNlsHK6swi81C5XeV3bc0JFD9oPwlBiUcvvoMSOWVnvfObcH4e29IIruK8kM7q3Y4Li9i1wcB7tIb+sbctq4ukKXEofxSCMj5ceQ666iS1+AoNMgGc203vU0iBKaoFBCcjbgv2g5mkD7GkGSJNQBwVgGeukr3o1vkny2fvDKs+gt3skjjzzCokWL6OjoICEhgeXLl88L+9Tp4BDRCwoKUCgUpKSkkJQk349utrHZbBQVFZGYmMiDDz5IYGCgx7rFwyQ8AvpJPPzww+Tn5/P4449zww03UFRUxNq1a+fN5laj0SAIApIknXENiRQKBYmJicTGxlJbW8u+ffsICQkhIyPDbfmtzWajvOIwvimLUfnIj3PYtwj+etnMcgBjVQPYRHQpU5x2KxWoQwNlF2vOE2yl/GLOGchFCUmSXF5rYoa7tXfQbulyEqogP5T+PtgGRzDWNMkL6CvSGXzfnlUeuu4CgnPWo1BPDqoBi3Po2v4Bks1Kf8lewjd80/X8gXO/fQUbf/p9ysrKuOSSSwgPD58XC9gvgkKhQKvVMjQ0hI+Pz7wSDPr7+6mqqmLRokVs3LiR++67j1WrVs31tDx4OGM577zzuPnmm/n+97/Pf/7zH8rKyggMDMTXV36zN5solUrUajUmkwmdTjevvo+mQ1hYGKGhobS1tVFVVcWxY8dIT08nMjLSbWz4zW9+g0Krwy99qeyY0foapwWKt7uD8CP2g3B1RLBsk9GJHqZyG+/pWbEdXyrLlX4rNGoUvt6Iw2OymWsAurR4LO299nWI3JiUOBTeOsQxI/r4FKK+fjVqF2sfbVAo3nELGWuuo694J4HL8mTf/7SsZfx4+cMsiIkiKiqKpKSkebOunS6CIKDT6RBF0fk3NF+wWq0UFxeTlJTEPffcQ3R0NHffffdcT8uDhzOW0NBQ/vWvf3HhhReyfft2ent7aWxsnFeZqjqdDqvVipeX17ypaJ0uer2eFStWMDAwQFVVFZ9//jnJyckkJia6fS0///nPkUQbgdnyNmyi2cRI3ZGpD8JrW5xZ6nKWqoDT4tSdgC6O2ffkclZscDypTS6OA6jDgzAeaXRrq6pNtjcSpXcI29CoywMCQaXEe3kaowUVKDVexF/1U7RhUZNitCAIBGWvoXPr+4zWV2Pu73GK6yfj7+vLzXfeQ35GCm1tbZxzzjnzzqplOmg0GhQKBTabbd5pWeXl5ahUKkpLS53JtGfa37aH08+ZtWubBbRaLa+//jovvvgiR48eBaCyUr4BxGzisG1JS0tj5cqVlJaW0tQkXz40X1Gr1aSlpXHOOeeg1+vZsWMHBw8enNSQxcGtt96KJNrcNg+VRNF+2i2KKASBwY/2Ym7tnmQVYxsadZ4qy3X7BrB09oN0vMGny3s6ArC7YD3hMUkmC32ix7q7jbc2NR4UgmxjMQDtwhgUPt4A2AxjLsVzAKXOC7+MbFAo6D2wG9EyeTGREuDFTYujOT8lmv8UlvDzm26itbX1jBPPHfYtBoOBjRs3IkmSy8aic4HFYqG4uJiUlBT+53/+h/T0dG6//fa5npYHD2c8999/P35+fjz00EMkJCRQXFw8I82sTxWH57lWq+Wss86iv7+fgwcPTmosOt8RBIHo6Gg2btxIYmIiZWVl7Ny5k+7ubpfjW1tb6ezqJmDJKhQq+Zg5NH4QjkJgePsBDFUNLptiG6sb7AfhqfGy17JMyCBTBbk+fJ+WFZtSCUr7ctlh9+IKRxa6XPMxAN3CGLDZMNW1IppdrwkEpdLe00SpwDLQ61I8dxC0fA1IIua+bsaaJjcnDdapuTo5jB8tiqJDUvHTn/6U3//+92eceA5QW1tLZWUleXl5JCQkyDYWnQvKysrQ6XQUFBTw6aef8uqrr56R77EHD/OJ9evXc8cdd/C9732P1NRUKioqGBwcnOtpOT3PW1tbWb9+PYGBgezZs2dGGm3PNgEBAaxevZrc3Fza29vZvHkz9fX1smuSl/75TzRBoXjHymcN2/uY2OO2saqB0f2HEccm24yZaprs8V6vlY3RotGEOGp/X91asc1QBrpjT25pd90gFMbj+DhydmyA3fvdJmIzjKLQaGX3zwGLVyCMrzH6SvZOelyrFDg7JpDbl8YSFhvPr397Jz/4wQ/OSPG8v7+fPXv2kJKSwurVq2Ubi84Fra2ttLW1ERgYyM9+9jNefPFFYmPltSIPX108AroLkpKSeO6557jhhhsICwujqamJ9vb2OZ3TyZ7nYWFhTk/0hoaGOZ3bl0Wr1bJ48WKnqLllyxaKi4sndQj/xz9eQB0QjHecvF2NobUBm8EuwGu8Aul/7XNabv8rzTf9me6//5uR3Yew9g2dWPY9IQCejKW9B0TRZTa4A9FgBoUCpbd8ABOmUfqt0Hs5x7ndeKfEggSGyjokmYWNoFCgz80ApYK+imK3XvNB2Xn2Rm1WC0NVpQCoBIHsUB9uWhzN5UlhHOwe4fHSFmr0kUgIXHzxxbLXm49YrVYKCwsxm83k5+fj7e3tsrHoXCBJEqWlpfj4+LB582b27t3LSy+9dMZlo3rwMB9Rq9W89tprvPnmmxw6dAilUklFRcWczunkhqE+Pj7k5+czODjIgQMHzjgRHezVPQkJCZx99tlERkayf/9+du7cSUtLywmv55prrgFJJHDpatlrSTYbwzXlIIpogyMY2XKQ9vuep+GGB+l45BUGP96HubkT0WjG3Ghfk7k7CLd29tpjdJCfbHOyiYK424232p6BJOeBDuP+rAoBS4ebg/AJ8zXXt8mO06+w+6ea+3sw9cj3R/FduAilt902oO/Abue/J/jpuCYlnFuzYjBYRf5c2szWQRADwnj9zTcxm+UFhPlITU0NR44cIS8vj+DgYNnGonNBU1MTnZ2deHl5cfPNN/PKK68QGRk5p3Py4OG/hbvuuouoqCjuvfdeFi5cSHFx8Zyv3Sd6nvv5+ZGdnU1QUBB79uyRTQab74SGhrJu3TqysrKoq6vj888/p6am5oRY8fnnn2M0GAjKXuM2mWqo2n4QrtB5Y23oo/Ox12i44UFa73mWvje3YKiqRzRbMFY3gSjivUhejLd0TjgId5eBbnQI6PJWJgqtGhQKWQ905z1sItauftm9ttLfB+W44G9y44PuvSTZefg+VFMuO07ppccvfRkoFPRNSGoL1Kq4MD6YO5bFk+Cn4x9V7fzrWA/GuHT6+wd4/fXXZa85H+nt7WXv3r2kpqaSnJws21h0LhgdHaW0tJSMjAx+8IMfcN111/HNb7quzvfgwVOTIMMVV1zB1q1bueGGG3j11VcpKSnB398fb2/vWZ+LXMPQkJAQVq1aRUFBATabbV55SH0R9Ho9y5cvJzU1lfr6evbt24ePjw9JSUkcPXoUg2GM8Lxz3AfrmvLxrDUVC665GclqYbS5ltH6I4wermF4+0FgfIOsVIBehypAvpzfWS4m45sK48FaENyWi03ckNsz3Sb74wmCgCokAEtrt/vS74Ux9lI3q4SltRtNbLjLcfqcdIa3FoNhFGNnK14Rrg8KvCLj0IZFYepqx3a0lK9deC4rw/0Zs9jY2zFISc8IFtEuwKv0vgTlrKO1cBu7du1i7dq1svOcLzjEc0mSWL16tbPc2+GJ7mi8kpubOyflWY2NjfT29hIUFMSvf/1rPvroI0JD5TvMe/Dg4YsRFxfHCy+8wLXXXsvu3btpbm4mJCSE6Gj5Bpani5PFc0d2qk6nIz8/n3379lFUVMSKFSvOyMxVlUpFSkoKCQkJNDU1UVVVxeHDh0lISCA+Pp5du/fgHbcQbZD8d9xocy2i2Z6lFnn+5XhFxmHsbGGk7gijjTX0vfKJvU+IVg3iNMq+O/tAEFCHT3EQPo7bWK5RIxnN7ku/QwNAULjNXFNHhjh9UY01TbIZ9F5ZC0GlBKuNoZoyQkPOcT0vpZLAZXn07P0cY301S32UrE2IwF+roqhzmA8amhg02zMBBUEg7Kyv0/jqk1x22WW8//77svOcL0iSxJEjR6ivryc/P9/ZMHSiJ/qePXvIz8+fE4um4eFhysrKWLRoERdddBG33HIL55577qzPw4OH/1aUSiWvvPIKS5cuZcOGDSxcuJCysjKys7NnfS4ni+cOz3NBEFi6dCllZWXs3r2b/Pz8M7KPkSAIREVFERkZSUdHB3V1ddTU1BATE0NiYiI/+clPEJQq/DNXyF5DtFoZPnYYRJGg7HzC1l2AeaCX0fojjNQfYeijAgbe3maPb+MCtS55CkvVcVQhAbLjHLF5qjiOcNwv3RXq0JNsVWV0AF1qPKOFhzFUy1eFK7y0eGUmYSg7xnD1IUJWbpAdG5idz2BFMSASMdDGufkrSQnwprJ/lBer22kaOT7noOx8egu38aMf/Zgrr7xS9przie7ubgoLC8nMzDzBhskhohcWFgLMSca3w/c8Li6Oxx9/HIVCwcMPPzzr8/Bw5uAR0N3w+OOPs3LlSp555hmuuuoqiouLyc/Pn9XNrZx47iA4OJi8vDz27duHzWYjOTn5jLPYcODj48PixYtJS0ujqamJ6upq2tra+M4136UudjFDMs+TJImh6lIQRQIWLUVQKBA0WnyTMpzNOKwjQ4y11NP++TvYTEPoFyXKzkM0mRGH7RkEbhuWGM0gHC8Jc8XEQO6u9FsdEWwX0N1krmkSokAhgChhPNosK6DrFiUiqFVIFivDNeWyAroArP7mpWT7q1m9ejU1PYO8cayLY4MnliBKNhsDFcUMVZaAJHHjjTdSXi5/kj4fMJvNFBYWolAoWLVq1SSBfK5F9IGBASoqKk5oNrZ+/fpZu78HD18VLr74Yn74wx+e0Bzcz89vVsU2OfHcgVardcbx/fv3k5OTc8Z6LqrVapKSkkhMTHRuwA8fPsxNP7+RUqMKeWkZe/a5QgEqDV5RcQiCAq/IOLwi4wjNPwfRYmastYHegq2MNtSAUkDtolmnA0t7L9hsbgX0Eyxc3GWuadSIMI3MNRuW9h7ZnieCQoF2YQzGijq7j7tMgpNCq8E7ayFjpUcZqjpEaJ5rAR0gefV6vr4wko0bNzJisVHQOUTphANwB6PNdfTs+gSAjz76GLPZPK8bjznEqubmZmem50TmWkS3WCwUFRWRkJDAQw89hL+/P/fff/+s3d+Dh68KUVFRvPzyy1x22WXs3LmTjo4OGhsbiY+Xt/CaaeTEcweCIJCVlcXhw4fZvXs3q1evdtvfaz4jCAKRkZFERkYyODhIXV0dO3bs4LrrrmN3dS1tXl7YZAqcRxtrkKx2ezLf5EwANAHBaJblEbgsD0kUMXa1MVR9iN6CLcAUFeHjB+FoVU4Pc1c4LNHcVpJp1SAIbivJTmgI3tknL6AnxzJaUIGpphHJakNQudaG9DkZGA4dxdDehGV4ELWvv8txgTELyLriKjbmrSI4JIQDg2b+09DjPAB3YBnsp2ffZmxGA8MCfPrpp5x33nmyr2c+0NnZSVFREVlZWcTFTT4smWsR3VGdevToUV588UUOHjw4r9dGHuYej1eAG7y8vHjjjTd46qmnaGxsRJIkDh065NYWYyaZSjx3EBgYSH5+PvX19ZSUlMwLn9dTwbEBz8vL44m//Y2kRYv5VW4KP0iLYFGQHsVJe1JjZyvWYbsnnm9Kpstrqnz88E3ORDSOAlOcdk/wTVW7KxczmUHCbUCfuCF3d+KtCgsCpdJt5ppCq0ETYxfNjW5KxrCJaOIjQKGwHyychI9ayboof365NJYbzltP/8Agt956Kw//7f+dIJ6LFjN9xbs49vc/0v7x6wToogkPX0JFxWGqqqrk7z/HDA8Ps3PnTjQajUvx3IFDRJ9tOxej0UhhYSGpqanceeedREdHc9ddd83KvT14+Cry8MMPIwgCjzzyCAkJCU5bp9lgKvHcgUajIS8vD1EU2bVr1xlbBu7AsQHPz8/nnnvuwWix8LNz87k1K4a8CD+8VCcuPyVJZKja3sckIGMpgjB5eapQa/BZkIKgsm+CdWkJCG4sryzt06kkm6aFy/hj7jLQJ97HNjAiO06XHAcKBWMVx2TXk5LNZj8kF0VM3W2YB048XFcJAkuC9dyQHsnteRlEJiTx58ce4+c33sj+9n6neC5JEsO1lTS8/DcaX30S+kdZkLARm83K//zP/8jOca6xWq0UFRXR1tbGmjVrZIUoh4g+23YukiRx8OBBdDodBw4c4O233+a11147Yw++PHiY75x33nncdNNNfO973yMtLY3y8nJ6e+UbPc4kU4nnDgRBYNGiRfaqq1276OjomJX5nU78/f1ZtmwZb7zxBgcOHODSC87lN9nxXBgfRKhucswcPjJ+EK7zRucigUtQKPCKiEETcPxgW5sYJXt/S2cfKBRoouSr1ySbDcZ7pcj1MoHxpDbpeMNRVygDfJy2KxP7qJyMNjnWXhUugblJ/vesjj5+yD98dLKN4AJfHZclhXLninjO2vg1/vOf/3D9ddfxbkHJCeK5qaeT1g/+xdG//5HhyjISEr6GAiU33nij7L3nGkmSqK2tpaioiGXLlrkUzx3MlZ1LQ0MDbW1thISEcMMNN/Dcc8+dsY4OHmYPz0pvCtLS0nj++ee59tpr2b59O52dndTV1Z32P67piucO/P39WbduHfv372fPnj3k5ubOu87GX5QHH3yQAwcOcvBgCbE5eZzz9W9yQUoCFy8Ipqx3lKr+UeqHjfasNUEBkoR+QYrs9YxdrfYgyzROu8dRuWlYIhlMIIkILhYQDiYGcndNS9ShASCKWNq6ZTPXAHRp8ZhbuzFWNhyfhyhiburEUH4MQ+lRDEca7QsJpQJzXzem3k6CwiNJCfBmUZCelABv6ocMfNbUR2X/KK2HjtDX3gFtbVi/Zvc47zu4h/4Du7GZjISHZxGSsIiujjI6Ow+hVKrnrb9nR0cHBw4cIDExkbS0tCmrMWY7E90h1oeEhPD222+za9cuioqKzkjLBg8ezhS0Wi1vvvkmOTk5ZGVlsXTpUoqLi1m1atVp7TkwXfHcgVptrwaqqKhgx44d5OTkEBIin2F9JtDS0sLhSrudy+sfb2HDxd9mfXYW58UFUd0/RmXfKEcGDPQ1NWAbs4vOjqw1V0iSxFhLHUiSvS+I3DiLFduAXUydjm8qHPc5d4XjMNxtHA+bmLnWiyrQdTa0LjnWXrputPusOjLkrb2DGMqPMXboGIayY/bGaUoF2ESGa8oJW7meRD8vMoL0LA7SM2q1UdQ1zGtHO+msaaHp0CHA3ojVNyWLoaoSegu3YerpwNc/lvRFVzA62kVT4y5AIDk5Wfa1zCVjY2MUFhai0WhYv379lJlgc5GJXl1dzfDwMN7e3tx444289dZbnmZjHjycZu6//37279/P7bffziOPPML+/ftZv379abVXna547sDxfeTr60txcTGpqaksXLjwjK0Od/Duu+8xMjLMh1t3kvuNS/ja2nxuyoqmbdRMee8I1f1j9BpM9kbgokhgxjK3r3mspQEEBZqYULeJaJaO8UqyiGDZMRPjsmLKg3DJbSWZoFCgCvbH2tXvti+ZdkGkMz4ba5rQJtqtAcUxI4aqBgxl9j25pbPXWT0+VH2IoOx8orw1pAV6kxXig49aSWn3CP+vvJX2wRGO7NiJZLXQd2A3XlHxjLXU01u4jZFjh9Ho/EhaeD5KpYamhh2IooXoaHk9Yy6x2WwcOnSIrq4u8vPzCQyUX4c5mO1M9J6eHioqKli0aBHf+MY3uPbaa7niiitO6z09/HfgEdCnwZVXXkl5eTlXXHEFn376KZWVlfj6+hIWFnZa7vdFxXMHXl5erFmzhtLSUnbs2EFubu60vrDmKy+++BJKhZqomFy6K6rYVLiLl/0CWfn1i8lbtYrLF4ahVggcJIdClYnq/lEUavkgbA/WAkgSmgXyArCzXExhb/Aph2g0gyi5DfyKaTQRhfEN/vhJtjg8htLPtXeedmEMfFaItauPgfd3YTrWgqGyHnFkDEGtxjtuIeFnfRPv2ETMn79Bbk4O+UsTSIgKp33URHX/GB819tJnOp5tHbgsz9l8rPH1ZzD3dCIICqKicvAPWEBH2wEOl72KQqHi0ksv5fnnnycgIED2tcwFkiRx7Ngxjhw5wtKlS4mJmf6CYrZE9IkVLC0tLfzhD39g586dREREzPi9PHjwcCIJCQm89dZbfP3rX+c///kPAJWVlWRmyou1p8IXFc8dKBQKsrKy8PPzo6CgYJJf5JnGvffeC5JIVPRKxoZ6ePevf+J9lYaUtRs462vnsDYhlsuSwqgJVbJ38CKKiorQx8sLu5aBHkSjvVJKu9CN/3n3gPNnd5VkzoxyAbebfYXOIaC7qSQLOV6abensQ5e2wOW4iQf4A+/vBAmMh+vtG21BQBcRQ9CSfHwWLmK04HMyoyNYtTabpVkLGLPaqO4f45WaThqGjc7r6BNSUPsFYhnqp3P7B3R+/i5WwwhBIakkLd7AYH8jR6r+jSjayMxcxAsvvMCKFfI+tnNFT08PRUVFREdHk5mZOe0DrtkU0VtbW6mrq2PhwoVs3LiR+++/n/PPP/+03MuDBw/HUavVvPHGG+Tm5vLSSy9x6aWXsn//ftasWXPa1u1fRDyfSHR0NHq9nsLCQoaGhli6dOkZmyxTUVHByMgwQcGpqNRe7Hv9Zfb86wXC0haz8RsXkZ2RxvlxwXQPj7Ln8kspKirCKFMR7mCsuRYkEV2aexsea4e9MlvOSgVOrAxzl4EuaDUgSUhuLFUB1OHBWLv63fYlE9QqNPGRmOtaGSmowNo3hLGqAVNtK4gi6oBA9AtS8V1zCdbeDiKHO8hZsYLVS2PQqVQcHRxja0s/lX1jWMcr0RQaLQFZufSX7GOo8iDm7g6M3W14+4SRknYJNpuZ5qbdmE1DBAUF8cQTz/KjH/3I7WuZC4xGI/v370eSJNavX4+Xl7yWcjKzJaKPjo5SVFRERkYGt956K9HR0Tz66KOn5V4e/vvwCOjT5P7776eiooKf/OQnPPvssxQXF7N27doZX6B/WfHcgVKpJDs7m9raWvbs2fOFxcT5xCWXXMz/+39P09y4C1+/WOLi12M2j7DvrdfZ9dqLeIVGkb56Dal6JZdccgnxCxbQOGyiqn+Mqv7RE0RigLHWekBAsyDCbZMR63i5mDoiyO2G2uGh5q7sG5XSKdpL7jbeExYGls4+NwL68UDS9/pmvCJjCcrKRx+fjD56AQmBPqQFepMeqMfvgtUcKjvEtq1beTMjn2GLa2sfbUgEXjEJGFobMPd2kZB4NhqNL20thbQ070WlUvOd73yHp556at4J52A/5S4tLaWnp4c1a9Z8qTnOhoheW1tLd3c3oaGhXHTRRWzatGlOmiB58PBV5ayzzuLPf/4zV155JTt37qS+vh5fX98Z91H9suL5RBYsWICPjw9FRUUMDg6yePHi05otf7q46qqr+Oc/X6GttRCt1p+Y2DwQFDTuP8Dft32KytuXBbn5pAV4sXzZMr5/7bX0mkWqx+N484iJiSYnYy0Nzp/dNRA9ofHYVBYuCgGFTuv2dTgy0CWD/MZbUKlQ+vtgGxxxu/FW+ulRhfhj7RlkeEsx2tBwfGJS0a9Oxjt+IZGBAc44HnvJensJ9P797DVp6cb1gb0gKAhcnk/X9g+xDg0QGr6YsIVZ9HQdprL8/xAEgRUrlvPss8+ydOlSt691rmhoaHD2Bvkyh0azIaIPDAxQUlJCZmYmV155Jeeccw6/+MUvZvQeHjx4kCc4OJj333+f1atXs2jRIqKjoykpKWHFihUzmuV9KuK5g4CAANavX8/+/fvZvXs3ubm5X0hMnC+kpaURFhZOV9cRFAo1oWGL0er8GOxs5P8e/SOvK5WEpC8lMymerIRY7rr7bhRaL6oHDFT3j3Js0IB5Qk8O69gIlkF7jHRXES7ZbFj77B3Qpm/FNkVfMlFCHDXKjgFQhQdCpRJLm7uuLaBLicPc2IGpuhFbSz9eMQkEnbMS/YJkAkLCSAvSkx6oZ6GfjsG+XoqKivjnlj10h8TLesgHLsuj/+Ae+2sZtZCeeSVjI13UHfsEq9VIREQkDz30V37wgx+4ndtcMTAwQGFhISEhIV/60Oh0i+hWq5X9+/cTHR3Npk2bqKqqYv/+/R4LNg/TxvNJmSYKhYKXX36Z1atX89e//pUf/ehHFBYWsn79etRqNwLqF+BUxXMHgiCwcOFCZ/nY0NAQ6enpZ1z52JNPPsn999/Pb3/7W15//Q2aGncgCEqCQ9LQ60MZM/RR8sG/OYjIa6+9Ru6vHyIzKpS0QG/Oiwuiz2ihqn+M2iEDraMmxprrpnXaPZ1yMbCXaQEIbsqLBUGwN/Q0W6a2cHHcv7NXVhhQRwYjeGmRDCaCV6wj44JvE6PXkhLgRWqgN6IoUTUwxsdNvRRt20LTJ28CkByWitpffvERlL2G1pZ6JJuVpoYdWK1GvL28ue2223jooYfmrR2QwWBg//79CILA+vXrT2mep1NE7+zspLq6moyMDM4991xuvvnmM6ZzugcP/0389Kc/paysjKuuuop3332X8vJyfH19CQqSbzT5RZgJ8dxBSEgI69evp7CwkH379rFixQq0WvdC73zj7LPPxmAY5cknn+Qvf/krjY37kCQJX98Y4uLXYbWaaNq3l2OmYT549x2Svv19lq/KIy3Qm2tTIxCBI/1j1AyO0TJior21ARRKlIE+sgfNMKGSTJLsnqYy2JuBC26z1mC8mmyK5mMAqvAgbIMjbku/AXRpCxjZW47aP5glP72TKL2GJD8v0gP1+GuVHBs0cLBnmH8WN3PwCXtjysjzJAKX5cleM2BxLl07PgJJor/3GN2d5SgUSs4771yefvppEhIS3M5prhBFkYqKClpbW1m1atUp2RadThHd0b8kJSWF3/3udygUCv7+97+fcWtrDx7OdBYtWsSrr77Kd77zHTZv3szAwAA1NTWkpqbOyPVnQjx3oNPpyM/Pp6ysjB07drBy5cozrjpcpVLR2dnB1q1bueuuuygqKsZms6LVBRAduwqFQsVAcwPbKorZBgQsyibvOzc49+NXalXUDho5MjBK07CJ2tpG57W17g7CewZhXHh3Z8UmfSELl/Hn2GwIMuszdai9KtzS1efeVjU5hqFP9gGQ8oNfEBcRxgI/HWkBemJ9tbSNV35vaeln12O/xzLQi09SBnGX3yA7R11oJF5RCzC0N2EyDlB9+E0kSSI1NYXHH3+cCy64QPa5c01LSwulpaUzYlt0ukR0R/8SjUZDeXk5Tz31FAUFBWfc36SHucUjoH8BfH19ef/998nJySEzM5PMzEyKi4tZuXLlKWeGzZR4PpHw8HDWrVtHYWEhw8PDZGdnz5jYP1sEBQXxzDPP8Mwzz7B7927uu+8+du7cRU/3YRQKNQpBhc1mxCs6gRGlloLOIQo6h9AqBZL9vUkL9ObihBCCdWq6Hv8ztbW1dIR60a3woVk0MMrkrGxHI093wRqOZ6C7C9bAtAR0hbfOKYy72ngLQIigIVbhxdk33Ui8fzCJSUmotVo6xswcGzTwYnUHrROy9TQJxxeSQzXlBOesk72/X+piOnTeYDERFRXOnXf+lh//+MfzemPY399PYWEhYWFhLFmyZEZKI0+HiD48PExxcTGLFi3iRz/6EZmZmdx///2nPFcPHjx8Of76179y7rnn8utf/5o//elPTh/VU80Mm0nx3IG3tzdr167l4MGD7Ny5k5UrV8o2VJyvKJVKbr31Vm699VZaW1v53e9+xzvvvENT405AQKPxhfHIpYpLpqJvlIq+URRAnK+OtEBv1kUGEO6twZhyE7XHjtFkHKJP4UerZKRHmhxbHY3HVEG+bhuN2uO44L6SjPGNt0JANLjPXFOHB2E61oJZpiG4LypiFDrWff2bRK77OkmJiQQFB9NrtNAwbOSjpl5qBw3OJqB4B6AJCsPc18VQ9SG3ArrK2we/tKUMV5fi6+vFd75zHQ899NBp9wM/FcxmM0VFRZjN5hnzMj4dIvrE/iXvvfceW7dupaioaN4mF3jw8N/ON7/5Te666y4uv/xytmzZwpEjR/D19SUqSr4h5XSYSfHcgVKpZOnSpdTV1bFnzx6WLFlyRvZM2LhxI/v27cNsNvPYY4/x3HPPUV9fiCSJ6HQBznH6hYtoGDbSMGzkk6Y+QnRq0gK9yQzy4dzYIFQZkTSsTKe2vo7B6GRaMNIhmbBxYlr2xEoutZueZCf0MnFn4TLhMclkQfB2vUZThQaCKCIZzYgjBpS+J8YlDQqiBR2Ry1YSfGsUSUlJxMTEMmq10Txi4mCPvTfJxMpvv9Qseot2MFJbic1kRKmVjx1By/Np/U8D3npv8vLy+Mtf/kJ6errs+LlGkiSqqqqor68nJyeH8PDwGbnu6RDRjxw5wuDgIL6+vvzkJz/hzTffdK4XPHiYLh4B/QuSmJjIW2+9xTe+8Q0++ugjbDYbZWVlLFmy5EuLjadDPHfg6+vLunXrKC4uZteuXaxcuRK9Xj5raz6zZs0aPv/8cyRJ4o033uDJJ5+krKycoSEjfqlZJ4w12STnJhzAXHsYr+r9JCUlsTjrQtao/AlVaOmXzLSIRppFAy2SgXabAWnA/hx3fmuA00Ntqsw1QaOGUYO96agb1KGBmJs6UPaNEi5oiRZ0xCi8iFV4ES3oUCLQJhmpDeln++YdbNq0Ce/Lb0RSuF4AaPyD0IZGYupuZ+jIIbcCuqBUEbBsNb0FW9m+fdu8zVRz0NzczKFDh0hPTycxMXFGhf6ZFNGNRiMFBQUkJCTwl7/8hc7OTt55550z0orBg4f/FtRqNW+++Sa5ubm88sorfOtb32Lfvn2sWbNmyoaFcpwO8dyBSqUiJyeHI0eOsGvXLrKzs+dtI+epcJTMbtq0iZKSEv70pz/x+eebsVgEvGKTUOqOb1RFcG7CATCbML33PElJSWRcsIGlqlAiBS0WJFrGY3izaKRNMtDfNzS9SrLxOD7VQbi914ng9iAcxg/eBaBnkEDURCp0xEyI5b6o6JZMNEZqKN/7Me+9+y7WZRtQxco3pvdLy6Jn31ZGG49iM46d8B6dTFB2PkOVB/nWty7hySefdDvXuWZoaIjCwkL8/f1ZuXLljJZPz6SI7shYkySJtrY27rvvPrZv337G/g168PDfwh133EFZWRk//OEPefXVVzl48CA6ne5LV5SdDvHcgSAIJCUlnVAdnpGRMa8TleTQaDT85je/4Te/+Q09PT08/PDDvPHGm3R0GDGbjfgknij29hgt7G4fZHf7IAIw+slrROs1pK1awTJVAN9UeKFBoF0yTYjlBhr7RpzXUIUEyM7nRAsX+Vh+cl8yhbdrEduRQCcIArreEWL9QohReNn/E3SECVqGsdKiMlDRV8revXvp1YegW3WO7L19UxbTW7gNgNH6avzSlsqPTV2C4vN/o9Pp+PTTT2XHzQcsFgsHDx5keHiYdevWzfiB/UyK6I2NjdTW1pKSksKGDRu4995753VGv4f5i0dA/xJs2LCBRx55hMsuu4wtW7bQ3t7OkSNHvtQJ1ukUzx1oNBpWrVpFZWUlO3bsICcnh9DQ0NNyr9lAEASuvPJKrrzySi6++GLef/99fKdoVtJXX0Pf4UoO1x7l0JXLEcxd6FA4g2GMwosVQgAhag28/jpDQ0MMq2FUrWRIsjKIhWHJypBkZUiyMISVVhFsTOGBjj1gi4KAThIIF7T4CSr8UOEnqO0/C/afvX//BwK89Xh5eWGWRNokIy2igf22flpEA52SCREYG6il4/PPAUjoasMrQj6Y+KVm0d3TgaGlHuvoMCq9fGALXLKa3n1buOaaa9i7d6/b1zRXOBa3jY2N5ObmnrZGvjMhojsEtaCgIDZv3syrr77K/v3753U2oAcPXxVCQkJ4//33ycvLIyEhgbS0NAoLC8nLy/vC4vfpFM8dOARBPz8/Dhw4QHJyMikpKWfk5tvBsmXLeP311zl8+DCZmYvxS1nsdvxIawNNtbXU1tZSsS4RndmGEoEIQUuswosYwYuzVMFECjrUv/0DY2NjDJjGGFPrGGJC/Jas4/9vYVgUGEFy65sK4wfhAqhsEkGCGn9OjN++ggp/1OgvuRa/i3+In58foiTRJZlokYwcE0fZZu2hTTJiQkRSWan/6EOwiYQGxRLqRkD3Tc6kZ+9mAIaPVRKQKd/80yt6AZrgcF599V9s2rTJ7WuaS9rb2zl48CBJSUmkpqaels/xTIjokiRRXl7uzFi76KKLeO655+ZlA1YPHr5qCILApk2bWLduHXfddRf33XcfBQUFrFmz5gtXap1O8XwiYWFhzurwoaEhVqxYccZVh08kJCSERx55hEceeQS1RoN+QYrb7GrRZqOx/CANNhuHIzQE5dj1iGBBQ4ygI1bhxRKFP19XheN9/kLMG69gYHCQUb2eYUf8lqwMcfzndht0KxSIoui2x5kj4U2lUuFrlggWdPgJavzH47gfKnwFFX6pC9BvyiEgIAClUsmgZLEn2okGSqVBmkUDw9j7rHVUFDFWWoMuLJpENwK6V1QcSi9vbIYxhqrL3AroCpWKwKWr6SncTlNTE3Fxce5+BXPG6OgohYWF6HQ61q1b96UTUKZiJkT0jo4OysvLyczM5PLLL2fjxo3cfvvtMz1VD18RPAL6l+TGG2+ksbGRiy66iE8//ZTa2lq0Wu0XytydDfHcgUKhIDMzE19fXwoLC09L5u5csHXrVjTB4WgC3GeZjTXXgWhDuzDB+ZqNiBwTRznGKA4nF9PhOgxPvUtgYCDJv/geweGhzqAapdA5RW9fVCj++QoAoiRiA0QkxPH7/V6bigIBBaD4f885M47NkugU4B2b+VbRSJU0QnPhXlo+28ugcZSQv9wq+1q0SccbrhhaGtwK6L7JmXTvtp9eDx87TOCSVbJjNQFB6BPSKNxf5Pa9nCvMZjMHDx5kdHSUdevWnbbFrYNTEdEd5d46nY6amhruuusuNm/eTGJi4mmdswcPHqZPZmYmb7/9NpdccglvvPEGfn5+FBcXk5OTM+0qkdkQzycSFRWFXq93WrMtWbLkjN58A/zqV78CJHyT3R+EG1obQFCAJKKJs5cI25BolYy02oxAP2AXQnpu/DNBfv7EfetrROZlOzfIcQpv+8/jArj6ljvhFrsPtyjgjOWOQvL7tGn2OH5dBoob7J8JmyQxzAQxXrLSJ5ppYIzuzhbqnn6Dvr4+fO64BvWCCJevRVCp0C6IwlTbwlhLvdvXrYuIQenti21smOEjZW4FdEEQCFq+ho7P3uajjz7iwgsvdHvt2UaSJGpqajh69CjZ2dmnbLcwFacqotfU1NDW1kZMTAxnn302d955J1dfffXpmq4HDx6+IF5eXnzwwQfk5+fz1FNPccMNN7Bv3z7WrVs3bVu22RLPHfj4+LBu3ToOHDjAzp07yc3NPeOTa0pKSrBaLIScVBF+MsauViSbfdOtTYx2/nuvZKZXMnNIHHL+28Df3kLX0E1YZgqJ138bP0GFv6AiXKFlIXpnXPdatxDWXQbY47OIhG3Cnvxex548OwPluxc5rz8iTT5YbxeNDIoWjjz2LH3d3UhfW4bvxWtlX482JZaxQzUYO1sQLWYUavlG374pWQyU72foSBmi1YJCJb92C1xqrwq/5ppr2LVrl9v3dC7o6uqiuLiYuLg4MjIyTntl9amI6H19fRQXF5OZmcmPf/xjAgICeO655854DczD3OER0E+BP/3pT3R2dnLFFVfw7rvvcvjwYbRa7bQ2BLMpnk8kPj4eX19fioqK6OzsZOnSpTPiOTkXDA0NMTI6RkjWarfjRIsZY1cbAIayYzT+7BG0SVFo4iPQxkeiiQ1DFR6EoFBg6uilr6+Pvr4+bN5WFLZ+1xe1WOm96XHUajUh15yPX14WCgR0KLhNm8TfzQ0YsWED2h57FcPRZhSLE/D72bdk5zloHaa3oQGAIJN5vGTcjm1o1N7pu6kD07EWZ3O0sdZ6gla4CexhUah8/LGODNr9U90I6GD3XWuur+bee+/l3nvvdTt2Nuno6KC0tJTAwEDWrVs3a4LRlxHRHeXeVqsVo9HIDTfcwFtvvcXKlStnZc4ePHiYPueccw6bNm3iqquu4uOPP2Z0dHTatmyzLZ478Pf3Z/369RQXF7Nt2zaWLVt2RleV7dy5E21opNtG14BdaJbsW+Kmn/wJTWI02vgINPERaOIiUEeHotCosfUPM9w/wHD/AAZxhFZxQPaag//7L6SGDnyyU4n40bfsYvl4LL9Fm8ST5jqMiPR/vp++93ZgFW2EPPXLk5xaj2PRmmmurQVA3dl7goAumi2YmzvtsbyuFUt3PyiVjLU2IEkiguB6AyoICvxSF9N/qIDho4cRzSYUGvlmsv6LltO59T1+/vOfU1/vXpyfTUZGRigpKcFkMrF27Vr8/f1n5b5fVkRvbGzk2LFjpKSkcMEFF3D11VfzP//zP6d7uh48ePiChIeH8+mnn5KXl0dERATnnnvutG3ZZls8d6BWq1m5ciVVVVXs2LGDtLQ0kpKSzlhRz34QDr4LF7kdN9bS4NzDdv75X2jiItAmRKKJj0QTF44mJszZIHy4sY2+1i6GEkIYEgflr/lJIeYP9qJQKlnwxO0oEVAg4DUex/+fuR4jIsa2blr/+AI2mw39zd9GkyGf9Njc14mlqwef9m4mRgtJFLF09NrjeH0bhkNHnY1ODR0t6GPlE6V8kzMZOFQAwGjDUXwXZsiO1QQEo1+Qyt59+2THzAVWq5XDhw/T3NzM4sWLiY+Pn7V7fxkRfWhoiIKCAtLT07nzzjvp6+tj27ZtaLXyaygPHqbCI6CfAoIg8Nxzz3HJJZfwgx/8gJdeesnZ2TckJET2eXMlnjsICgpi48aNVFRUsG3bNhYtWkR8fPwZF7R/85vfgCROad9iaG8GyR7cQvLPRbJaMHa2MFy1n4FRu9+5oFahCg9GslhAqUTQqGS90QBsRjODg/ZgrrCZMI83MdNi3wB3SiZM42fffcYxDH19ePUH4a6gcGKDlIF/b0c0mrG0dGFu6cI2ODI+TzW68GhnU7Gx5jq3r10QBPzSsug7uIfR+iPYjAaUOvmMDJ/EdFQ+/jz++OPzQkA3m82Ul5fT2dlJZmYmsbGxs/45/SIiuiRJlJWVMTQ0hF6v56KLLuLpp5/2eKx58DCPueqqq+jq6uKSSy5hy5YtdHZ2Ul1d7bZp01yJ5w60Wi15eXnU19dTWFhIbGwsixYtmlEf6dmgr6+PMYOB0Gz5g2Cwb1rHWhsAu5eoV2QshvZmxvYdYfCjccsxQUAVEuDcfMN4MzA3DPcPYO7rw2wcQzWhGakjlndLZkyIDFqN9Pb0gCQRJIqyjUlVQX5OcWB0Txmm2hYsbT1YmruwdPXZ1yKCgDYkDF1ABGNDtUg2G6aeTnSh8p7avimL6S+xv86R+iOT+r5MRKnVEZCZQ0NZISMjI7MmCMkhSRJ1dXVUVVURHx9Penr6rH9Ov6iI3t7eTnl5OYsWLeLSSy8lNzeXP//5z2fcOtmDh68KSUlJfPLJJ5x11lmEhoaSkZFBYWEhq1evdrtmnwvx3IEgCGRkZBAeHk5JSQnt7e0sW7Zszr+zvwx79+1DFx6D2tf9wai94kpA5eNLSN45GNqbMFa2MrKz1JmZrvTTo4oIxtLeCxz3JJfDNDpKf38/glqFn2Rx/rsjjneNx3GL0kZPj73Bt8Zgwt3Riio8CEt7D6aaJvrf3oalvQdzcxeWtm4ki92+ReXnjy4sBjMdABha690K6PoFyQgqFZLVynBNmVsBHcaT2hqO8MADD3DPPfe4HTsb9PT0UFJSgpeXFxs2bJiTnnpfREQ3GAzs27ePhIQE/va3v1FUVMSePXvO+GoPD3PPmbXTmoeo1WreeOMNzj77bH75y1/y6KOPUlhYyJo1a1xm18y1eO5ArVazbNkyoqKiKC0tpb29naVLl0673G0+8Oabb6LS+6ILj3E7zl72bd/QBuesdwrIkiRhHR3G1NOBqbsDc383Q0fKQBSnbCAqTmgIOrUHumbSc1wxcYEw8MEeNEEhaAPD0C9ajTY0El1YFJrAEASFgr6De+j47G2sI0NYhgZQ+wXIXtc3OZO+Ynv510htJf6Llsu/LrMJXUQMQ7WVVFdXz2lnakfWeUBAABs2bJjTz+Z0RfSamho6OjqIiori7LPP5p577uHaa6+dgxl78ODhi3DLLbfQ0dHBRRddxGeffea0ZXNluzTX4rkDQRBITEx0br63bdvG0qVLz6hs9F/96lcgTW3fYurpQLLYBW6/tKX4ZyxzPmYzGTH1dmLqbsfc181ow1FnzFdPsfEWDfYGpVM2A9eqnQfxktGMIHPALiiVKAN9sfUNMbr/MOqAQDQBofjGZaLNDkcXFoU2JAKFWoN5sI9jT/8BsK9T3Ano+rgkBLUGyWJm6EiZWwFdEm1oAkNBFLnuuut444033L6204kj69xoNLJq1Sq3ySWnm+mK6L29vRw4cIDMzExuuOEGQkJCePHFFz3Nvz14mOcsW7aMd955h29+85u89tprBAUFUVxcTG5u7qS/37kWzycSHBzMWWedRVVVFdu3bz/jstE7OjowGo2E5ri3bwEYa6kDSUQfn0JQdj6QD2A/SO7rtu/JHf+JzQDTiONmQJg6jk+oRpCM7vfk6vAgDEollrYehj4qQBMYindwHNqFuehCo9CGRaLytn9mjj37EOa+bnt2vRsUKjU+iekMHz3M0JEyIs+/HEEhv35U+fqDQsFjjz02pwK61WqlsrKSpqameWEBPB0R3Ww2s3fvXiIiInjvvff4v//7P/bu3Xvaeqd5+GrhEdBnAL1ezwcffMCaNWt4+OGH+eUvf8m+ffsmLc7ni3g+kfDwcGc2+tatW8nMzCQuLm7eB22bzUZvXx8BS1dPOVeHv6gmMPSE7GtBEFD7+KH28cNnQYp9bHMdttFh1BHuPdUl04SO39PZeCsUUwvoEzqMh637OiErz5Id6xV1vGTK0NaA2m+p7Fjv2EQUGi2i2cTQkbJJArokiYw11TJQXsRQ9SEkmxUkuPPOO/n3v//tds6nA7PZTEVFBe3t7SxevHhOss5dMZWIXldXR21tLcnJyZx//vl873vfc5Y0evDgYf7zxz/+kc7OTi677DLef/99Dh8+jFqtPmFxPl/E84no9Xry8/PPyGz09957D5WvP9ow99Z3hvHsczgx/oE949o7Kh7v8X/v2vkxxu42BJUShZ/7DCnJaI/l02kG7kA0mt1WqKnDg7D1DeEVm0TCNT+XH+cXiNJLj80wylhLA4FL5e3oBKUK36QMhmrKGD5agWSzIihP/P2a+roYLC9msLwIy8ggSpWWzz/f7PZ1nS4mZp3HxcW5zQKdTaYS0QcGBigsLCQjI4M77riDwcFBe6+d09QczYMHDzPLxo0beeGFF7jmmmv4+OOPMRgMlJSUkJ2d7dxLzCfx3IFKpWLx4sVERUWdcdnot99+O0gSflNUhFuG+rGNDgP2ppoTEZRKdKER6ELttmdjrQ0MHykDpq4kE8fjuLsGojA5jrtDFRoAor2SPPlnv3PrV+4dk4h5oJex5jokSXK7Z/VNWcxwTTmiychYcx36+OQTHrcZxxisLGGwrAhDRxNKlY6BgQEaGxtn1S7FwcSs87POOmvefB7diegWi4WCggJ8fX05cOAADz30ENu3b/f0IfMwY3jSKWaI4OBgPv30Uz788ENefvll4uLi2LNnDyMjduuN+SieO3Bko69YsYLq6moKCgowGAxzPS23/PnPf0YSxSmz1iRJGj/tlvCOdd/gVZIkzAPTKxebGHgVU2y8Ba0aBAFpCgFdodWg8LEL/JbBXrdjdaGRCOPCzVQn3oJCiW9yJoJCyUhtFeJ4Fp+xu4PO7R9w7P/9gcbXnsZUV8+C+A3krrwNH58IPvroE7fXPR10dHSwbds2TCYTGzdunHeHOQ4R3dEk1Gq1l/E1NDRQVVVFeno6V1xxBXl5efzv//7vHM/WgwcPXwRBEHjmmWdYsGAB1157LYsWLeLQoUO0trYC81M8d+DIRt+wYQPDw8Ns27bNWao8X7HZbPQNDOCXmjX1QXhrA4JCgdLLe0qvdPNAD0igCvaf8rqiyV7uPdXGe+JBuTiNzDWUCiz97t9/QRDwil4AgsBYc63bsWDfeCOKSBYzo41HAbCOjdB3YBf1L/2V2mf/RH/RbkL9U8le8TMiI5czMNDP3r17p7z2TDIyMsKePXuoq6tj1apVZGVlzQvx3IFDRI+Pj2fPnj0MD9sFncHBQfbu3UtycjKPPfYYJSUlfPjhh55ybw8ezjCuuOIKHnzwQS6++GL8/f3p7++ntLQUSZLmpXg+EUc2ekBAANu3b6e2thZJkuu6MT/48MMPUfsHoQkOdztubOJBeLR7Mdg8IX5OJaBLRhNI0pQH4YLmeByaSkBXhwU6q84sA31ux3pFxYEoIpoMJ8zbFb5J6fYKOWDoSLl9LlYrQ0fKaP73C9Q88Xs6Pn8HL6sXmVnfJWPRFQD89re/dXvdmcZqtVJWVkZBQQGJiYnz8m/FIaIfOnSI5mZ7tYJDPFer1bS1tXHzzTfzzjvvsGzZsimu5sHD9Jk/K9r/AuLi4vjss88466yz0Gq1fPvb32bPnj1kZWVRUlIyL8XziTiy0cvLy+d9NvrTTz+NoNagj0tyO87c341ospdon5y1djI245izyACdtQAAfGJJREFURFw1wY/cFRM30ILWfWaSQqMGAUST+2ANduHePDJ1ABaUSnThsRjaGqb0QQf7xnvw8AEA2j76P0xdHZh6O1CpvQgLW0x4ylJE0UZHRwlFhU8gSTaWLlk65XVnCovFQnl5Oe3t7fP6cweTM9EjIiKoqqoiIyODK6+8kpiYGP7xj394yr09eDgDUalUvP7661x44YVcf/31bNq0iZKSEmw2Gw0NDfNSPJ/IxGz0goIC4uLiyMjImFcCpoM//OEPIIr4Ji+ecuxYUy2SKOIVnTBlbDD3doMkogoPmvK60riAPuXGe8Lj0pSZa/bNvnVkyGWm+ES8oxcwUluJZbAP69iIsyTcFT6JaSAoQBLp3ruZ3oLtjDbXIgBBwSkkZF6NXh9KV2c5FWUvYzaPoNN5kZnpPtFgpjg563zVqlXz8nMHkzPRlyxZQmlpKUlJSTz99NO8//777Nixw1Pu7cHDGcrNN99MX18fF1xwAZ988gm9vb0cOnQIlUpFa2vrvBQEHTiy0SMjIyktLaWtrW3eZqObzWYGh4cJXrFuythsaGkAhRJBAF2o+6ozy0AvKBQgSaiC3XUQG99fi+KU+3FBqQSlAmzilBYuE0V780AP2hD5w4ETqsJbG9AGydvoKb30eMcmMtZcx1BVCaJxjOFjlYhmIz5+USQmnUdwSBoD/bU01G9lZLgNhULJueee63a+M0lPTw+lpaVotdp5lXXuiomZ6DabjZaWFpRKJT09PVxzzTW8/PLLbNy4ca6n6eG/DI/CM8NkZGSwefNm/vrXv/L+++8THBzM/v37WbBgwbwWzx2o1Wqys7PnfTZ6Y3MzvgsXud2YwniwHmcqAX1itthUfmuS4QtauEjHN+ruUEcEgyBg7uuecqx3zAJQKDF2tTqzyuXwSUiFcZ+14SMVBKgjWbzkeyxddgNqtTeVFf/HoZJN9HSVkZ+/ml27dlFSWjLlHGaCzs5Otm7d6sw6PxMa2jpE9LGxMSoqKkhNTeU73/kOoaGhvPXWW6jV7j8THjx4mL94e3vzwQcfYLFY+PGPf0xaWppTRJ/P4rmDidnoQ0ND8zYb/fnnn0eh1U1ZHWYdHcYy1A+A9xRZazCegc54JrgbJIvVWaI99UH48cenLP0OCwSbCEiYB/vdjvWKindmuU20qXGFUudlTxoQFBhaGtCMSKSkXkTOqlsJCk6hpWkXRYVP0NS4g5iYMJ5++mnGxkbx83MvPswEo6Oj8zrr3BUOET0iIoL9+/cTFRXFpk2beOONN9i6dSsJCe4/lx48eJjf/O53v+NHP/oRF154ISEhIbS2ttLQ0EBeXt68FgUdhISEzPts9HvuuWf8IHzqg9qx5joQbejCY5xV1HI4KsKVgb5TjhVH7YlyCt3UVluC2h6XprZwmSCg97uvCteGRCCMW7yMtdZPOQfflMUgSdgMo5gaGoiLyWfFyptZsGAjQwONFBX8hZrq91Apx7j55pvp7+/jBz/4wZTXPVWsVivl5eUUFBSQkJDAmjVrzoi/k9DQUFasWMGhQ4cwmUwMDAxw1VVX8cILL/Dtb397rqfn4b8Qj4B+GsjKymLz5s088sgjPP300wQFBdHc3Oy0czkTCA8PZ8OGDWi1WrZu3UpDQ8O8Cdpvv/02ks1mD0BTYC/7ViKoVGhDItyOdQRrmI6Fy/GT6yktXDRqQEKyWJHGN+tyqEMDQaHAMjww5VivqHgQbSBJGDpa3I5VaLT4JKSAoEBAgbd3MLXHPqV4/99oatxJVFQwDz/8MGNjo+zatYs1a9a4vd5MYDKZOHjwIMXFxaSlpbFq1aozqoltS0sLRqMRhULBZZddhp+fH2+//TZarXaup+bBg4dTxMfHh48++ojR0VG++93v4uXlxejoKB0dHXM9tWnjyEZPTEykoKCAsrIyzOapK6Fmi9b2dqe9mDsMrY3On70ip6okMzirzqbrmwrTsHD5AhnoEw/gLQPuDy68ImMB+4Hx2BQCOoBvahZIdnHe1zeK7q4K9u/7C0ePvI9CMcr1119PS0sztbW1/PSnPz3th9GiKFJbW8u2bdvw8/Njw4YNc9oo9IsyNDREe3s7QUFBPPTQQ7zyyits3br1jEh48eDBg3sEQeCBBx7g2muv5fzzz6ejowONRjMvhWg5HNnoq1atoq6ujj179jA0NDTX03Ly8ssvo9B52e3I3CCaTRi72wDwipn6cNLc1w2iiDps6koyR4+xqQ7C4XjS21RxXOnjhTAuyE8VxwWFYjyWw1jTNKrCJxw2+OgjMRj6KSl+loqyVxgcPMbGjRvYs2cP/f39PPHEE7NyCN7d3c327dsZGBjgrLPOOqOa2FosFo4dO4afnx979+7liiuu4LnnnuOKK66Y66l5+C9lfqeHnMEsXbqUzZs3c/bZZ5OcnMw3v/lN9uzZQ15e3hnjp6jRaMjOzqajo4Py8nLq6upIT08nIiJiTr9UH3jgARAU9nLmKRhrrkUSbXhHJSJMYalh7h8vFxPFExp6ukIymu17XmnqDHSFVuPMMDNWNyLZbIgjBmxDo/b/BkewDYxg7RnE0tFr3xyLEpbhATT+8guHE0vG6tHHum+O4Zuy2O6BLpmpr99CRHgE1/3wJu65555ZLVO2WCzU1tZy7NgxQkND2bhx4xklnAPU19dTWVlJZmYmV199NaGhobz77rvodPKN5Tx48HBm4evryyeffMK5557Lo48+yrPPPktJSQmSJBETEzPX05sWgiCQlJREeHg4ZWVlbN68meTkZBITE+c0k/6VV16xH4RPJ2uttd5eQSXa0EXGuh37ZQ/Cp/ZOPf64qakDQatGHDNOiOOj2AaGsfYNYe08nnVunsI7VaHRogkOw9zbOT07tuRFdHz2NgBNjTvR63345je/we9+9ztWrFgx5fNnCkmSaG1tpbq6GkEQWLlyJaGh8mXr8xFHb6KkpCT+8Y9/sH37drZv305KSspcT82DBw8zhCAI/OlPf0IURe655x4+/vhjuru7KSkpYdmyZWeMSBgSEsKGDRuorq5mx44dxMTEkJaWNuf7p47OLvwzl0+5xzZ0NDv3wt4nNRB1hcPKVBUxDSs2RxPRKeI42A/LRcDaM4jxSCPiqBHb8Ci2oTFsQ/b9uK1/GGv3gPO6U2Wgg/1QYKy1AXNfFzajAaVO/vei8Q9CGxKBubeLnu7DqFRqli1bwq233so111wzq5/JgYEBKisr6e/vJy0tjcTExDPmbwKOe54rlUoMBgMPP/wwf//73/nOd74z11Pz8F+MR0A/jWRnZ7N161bOPvtsrFar0xN99erV+Pv7z/X0pk1ERARhYWE0NDRw6NAhjh07RkZGBsHBwXMyn8OVlSh1XgwfKcMnKR2V3vWBhM1ocFqheMUsmPK6jrJvhY+XXfR2g2g0O71Ip7XxFu2Lhvb7Nx1/QKlE5a1HpfdF6e2Ld0Ackm80g+VFAFj6e90K6Gq/AJTePtjGRqZsJArgu3AR7cCyZcv46KOPiIhwn5E/0zg8hGtqavDx8WH16tVz9hk6FWpra6muriYjI4OrrrqKwMBA/v3vf8/5ItaDBw8zj5+fH5999hkXXnghN9xwA88//zylpaXYbDbi46e2E5kv+Pj4kJeXR1dXF5WVldTV1ZGamkpcXNyc9Gt49NFHATB2tqINDkMTHC67aRtrrgdRRBMchlLr/pByYqbYlFZsxulbsU3cmPf/3+fHHxAElF5eKPW+qPR+6PShqDKS6S3YCpI0ZT8TAO+YBCz9PRg7mqf0TFf7BqALj0Ya7GXXzp3k5ORMef2ZRJIkuru7qaysxGQykZaWRmxs7BnX86Ovr4+CggIWLlzIs88+y2uvvcbOnTs94rkHD/+FCILA//7v/6JSqTj//PP58MMP6e/v5+DBgyxbtuyM+f5SqVRkZmaSkJBAdXU1W7ZsYcGCBaSkpKDRTJ19PdP885//RBJtWEdHGG08indMoqzdiqG1wd48U5KmtFQVzSZshlFgvDJ7Co5noE8toDvGjJUcYazkiPPfFVotSm8fVD5+qLz98IqLYcR2BHNPB6a+rimv6x0ZT+945bihrXHKJD+/tCV07/mMt956i29961uz/hkcGRmhurqajo4OEhISWLFixZx8hk4Fs9nMvn370Gg09PT0cNVVV/H8889z9dVXz/XUPPyX4xHQTzNLly5l69atfO1rX8NisXD11Veze/duVq5ceUaVuSoUChITE4mLi6O2tpaCggKCg4PJyMiYldIiB7W1tVgtFnRqP9o+eh0AXXg0+sRUfOJT8IpZgGLch8zQNqHse4pgDcfLxabKWoPxzLXxzb7DT02OiQE95tIfoguNQqnzRqHVTRIMzP3dTgHdPNCDnmS31/aOSWD46GHGmuuQJMntqbFK74tXZByVlVWzKp5LkkRLSwvV1dUolUqWLVtGeLi8WDJfkSSJyspKmpqaSE9P54orriA8PJy33nrLk3nuwcN/MX5+fnzyySd8/etf54c//CEvvPACFRUVmEwmkpOTz6jvsrCwMEJDQ2lra6Oqqora2lrS09OJjIyc1ddRW1uLWuNDX+F2evZ+jto3wB7HE1LxjlvobKYp2awYO5sBCe/plH0P9Do36VM3A59g4fIFmogG5awncFkeSq0OpZfeZebdUGUJlsG+aQnoXlHxDBwqAOwHClOtV3xTs+je9Qmxse6z8Wea/v5+KisrGRwcJCUlhYSEhHnfD8AVHR0dTuu4J598kn//+9/s2LHDY9viwcN/MYIg8OCDD6JWq7ngggv48MMPGR4eprCwkJycnHnfs2Eier2e5cuXMzg4SGVlJZ9//jkLFy4kKSlpVl/Hv/71L0DA3NJMY+3TKDQ69PEL0Sekol+QjCYw1LmucCR6Kb30qHwD3F73hEqyKeI4jDcRhSmT3+C4zYsuIobob1xjF869fFC4eN86Nr9Lf183lqEBJElEEORFbq8JWfVjrQ1TCui+yZl07/6Ujz76iEsvvXTKec8URqORI0eO0NTURGxsLF/72tfOyASwsbEx9u3bh6+vL62trXz3u9/lxRdf5PLLL5/rqXn4CnDmRIszmKysLLZv384555xDb28vv/zlLykoKCA7O5uoKPddqOcbKpWK1NRUFixYQE1NDTt27CAqKor09HS8vb1P+/2ffPJJACIjlxMcks7ocBu9fUfpP1BA774tCEoV3tEJeMclYu7vdlqyTEtAH9/oqiOmzop2WriolFOWrU3cmKt9A9EEyF9f7Tex6/c0Ssai4xk+WoFoMmAZ6EET6L6E2jcti67tH9LU1ERc3NQldKeCJEl0dnZSVVWFxWIhPT2dmJiYM0psciCKIqWlpfT29pKQkMA3vvEN0tLSeO211zye5x48fAVweKJfcsklXH755bz22mscO3YMk8lEZmbmGfW9JggC0dHRREZG0tTURFlZGUePHiUjI2NWbDgcPWFCQjOIT9iA2TRCf98x+mqP0nKoEABdaBTecUmofHyRbDZgmgfh/b32Xh8aBQq9+03hCRYuU3mgT3hcqfNGG+T+fdIEhtgF9Ok0BJ/QGHWstXFqAT15Md07P+b222/n1VdfnfL6p8rw8DBVVVV0dXWRmJhIbm7uGdso2/F5z8zM5J577mHv3r1s376dxET3FngePHg48xEEgfvvvx+NRsM555zDv//9b0RRZM+ePaxateqMW8/7+/uzevVqenp6qKyspL6+ntTUVOLj42clo3nfvgJ0ugBS0r6FSqWhv7+Ovp6jdB57B0kSUfv44x2fjHdsAmMtdSDZD8KnWi9ZJlifTVVJBiCZLcDUcRwmNhoV0IaEux2rDghCkkSQJKzDgyfs0U9G5eOHyscf68gghpapG4lqw6JQ+fjz7rvvsmnTpinHnyoOn/Da2lrCwsI466yzzhhL4ZMZGhpi3759REREUFxczC3/v737Do+6yh4//v5MS530XkhIAgkJ0hEsCCggNmy4dsWCimVdu6671v2tfnHX3tuCvTesSO8t0kJJJQnpvUwmmfr5/REyJhjJUELaeT3PPITJlDtDyJl77rnn/vWvfPDBB1x44YU9PTQxQEgC/ThJS0tj3bp1nHnmmVRUVDB//nx+++03rFYr8fHxPT28w+bh4cEJJ5xAYmLiH7aRdecHkDlz5vDWm2+xL3cx+3IX4+MbQXBIMqlpl6HTe1Jfm09tbS61G1djt5lBUdD5+qH3PXSVvNNmxWFuPeTVvGkP++95EV1oALoAX7SBRrR+vmj9vNEYfdB4eWCvqgfVvX5r7QO602o5xC1B0erQ+hhxNDW613MtMs7VU85clN91An3IcCqWf88999zD559/3uXjH6mamhp2795NY2MjQ4cOJT4+vk9WqkHrqeRbtmyhubmZ4OBgpk+fztlnn82rr77aZ1+TEOLw+fj48MMPP3Dttddy1lln8c0331BaWorFYmH06NF97veBRqMhPj6emJgY8vLy2LRpE4GBgaSmphIQENBtzxsdHU1SYhI5uXuoqtyNwWAkOCSFwYOn4e0dgqmxlNraXOr27KbFXO1ql+ZeAr0SnA5Ui4P9f30OXag/uiA/tAFGtP6tcVzr54PG2xPb/t+3ZXd1+Fj7nWZO26HjOLROvBWNFlt9TZe7wwzBYSh6A6rNirloH8HjTzvkY3uEhKP3C+THH3/schxHo7m5mczMTPbv38+gQYOYNm1an91tpaoqOTk5ZGVlkZaWxrx58ygrK2Pt2rXHvZ2dEKJn/eMf/yAsLIzzzjuP999/n5iYGFavXs3JJ598XIrBjrWQkBAmTZpEaWlph51lUVFR3bq4f9FFF/Lee++zY9u7aDR6AoOSCA8fwZCh52JpaaCuNpe6/fso3Z3umqt6RbsRx+uqXDvJyp/9BF1YILpgv9b5uL8vWj8ftEYfNEYvNAYDOFpbp7jXwqU11nc1H4fWXuVt47bWVh8ygQ6tu8IbMndgLs5HdToPWWCnKAp+ySOo2boWh8PRbZ8fHQ4H+/btIzs7Gz8/P04++WSCgrruK99bVVdXs3HjRhISEvjqq6+YP38+P/zwA1OmTOnpoYkBRBLox1F8fDxr167lnHPO4YYbbuCdd95x9ZEcOnRon6pga+Pt7c2YMWNISkpiz549LFmyhMTERBITE7ulQmnkyJGYmkxs376dZ599lqVLl7G/YDWF+StRFC3+AXEEBiURE3sqO7YtQFXteEV3ve3bVv/7ardvYio6HyO2hjpsFVU0m/JwmE2odnvHO2k0KIau/wu1D+huBeyAYJqbGrG60XPNKyLG9SGjuTifgBMO3Q/VIygMQ2AIixcv7vKxj0RDQwN79uyhsrKSpKQkJkyY0Gcr1aC1v9qGDRvQaDRotVqmTZvGX//6Vx599NE++f9VwGOPPcbjjz/e4brk5GT27t3bQyMSfYnBYODDDz/krrvuYtq0aXz33Xc0NTW5toH3xd93Op3OtdCZnZ3NmjVriIiIICUlBV9f32P+fBqNhuycbKqqqnjhhRf4+uuvyczcTmlJa/syH98IgoKSSEo6i6L966ivywedHo/gQ1eLAa6Kb0NIBMbBKa1xvKABy+5iHE0mnJaWgwajgFPtuoWLoqDodag2u5sT72BUVQWnA3tT4yEX8RVFg1fkIMyFua1Vel1QFAVjykhqtqzCarUe876lVquV7Oxs9u3bR3h4OFOnTu2Wn4PjRVVVdu3aRVFRESkpKVx22WX4+vqycuXK49qCUBxbEsvF0bjpppsIDQ3l6quv5rnnnmPChAmsXr2ak046qU/+XlAUhaioKCIiIti/fz8ZGRkddpZ1x5zlf//7H2+99Rbvv/8+//vf//jtt61k7d0DgMFgJCh4KNHRE2lurqEgfzng5k6yumoURYOKk8DhE7E11GEvr8eyLx+7qRFHs9mV2G5P404FuoceFAWntaXL2+rbnUNmravCJ+7Qbb68ouNoyNyOardhqSrDM+zQXQaMQ4dTk76af/3rXzz66KNdjudwqKpKYWEhmZmZGAwGxowZQ1hYWJ+eu7a1X0tNTeWFF17gs88+Y+XKlYwcObKnhyaOUF+N45JAP85CQkJYunQps2fP5qKLLuKzzz4jNzeXlpYWRowY0Wd/sfn5+TFhwgSqq6td28gSExOJj4/vlkMpRo4cycKFCwGwWCx8/PHHfPzxx2zevIX8vCWtW64O8I6O7/Lx2ld7B446Cd/ByR2+r6oqqs2K3dyE09pC6c+f01xS4N52sXav353KNUNACM2lhVjrqrusXNMYPPAIDsdSVUbT/twuH1tVVXzihlC7YyPNzc3HrO9ZXV0dubm5lJSUEBcX16cr1dq0769WWlrKlVdeyTPPPMO8efN6emjiKKWlpbFkyRLX3/tS70vR8zQaDc8//zyRkZFMnz6dL7/8Er1e7zokvK9tA29jMBhIS0sjISGBvXv3snz5cmJjY0lISOiWhEJISAhPPvkkTz75JKqqsnLlSt59911WrFhBcdEG9heuAVoTA15RcV22S1MdduymRgB844cQfvqsP9zGabfjaDbhtFio3bGJmk2tk3p3YrlicD+BrvcPggOfQ2x11V3ugvOOicdclIejqRFbQ22XlW4+sQnUbFrBo48+ylNPPdXleNzR0tJCfn4+eXl5BAQEcOqpp3brToTjwel0snXrVmpqaoiLi+Occ85hxIgRvP/++332/6n4ncRycTQuvPBCfvzxR2bNmsW9997L7NmzXeeUBQd33c6zN9JoNMTFxRETE8O+ffvYsmUL/v7+JCUldUsCVafTcd1113HdddcBkJeXx+uvv85PP/1EVlYGZaXpB8alw+l04BXR9dkd1ppKVKcDvV8gYaed/Yfvq04njhYzjhYz1poq9n/xNnAYh4hqFJw2a5e37ZhAd2NXeFS7XeHF+V0m0D0jYlG0Ot55551jlkB3OBwUFxeTk5ODw+EgNTWV6OjoPptfalNQUMDOnTsZPnw4Dz30EFu2bGHdunUMHtx1kaTo3fpiHO/9I+yHfH19WbRoEddffz0zZ87km2++oby8nE2bNjFmzJg+WcHWJjg4mFNPPZXy8nJyc3PJysoiJiam2ybg0NpOZs6cOcyZMwdoTXx+8cUXfPrpp/z4448dDvb4M+23ixkC/ri1SVEUFIMHBsOBCdeBiby9qo7C2//bur1bo+Dt7QXPvEDJP97A3NwMdkeHPqtuTbwDggAF1WbF0WJG5+VzyNt7xyZgqanEWl2Bo6UZrWfHpLjTaqGpMAdTXiamnF3YGmpBo+HNN9/kzjvv7HI8f8bpdFJWVkZeXh51dXXExsZy+umn4+Nz6PH2BbW1tWzatImIiAjS09P561//yoIFC5g9e3ZPD00cQkNDQ4e/e3h4dJok0el0sm1fHBVFUXjwwQcJCwvj/PPPZ8GCBcTHx7Nq1SomTJjQJyvY2nh5eTF69GiSkpLIyclh5cqVBAcHk5CQ0G0HQCuKwpQpU1zbcFVVZfny5fz66688/fTT7i2E19cArZNXvX/nyQ+NTofGGABG0Pn4uNrDlDz2dusBZFoNikbBy9MLnnme4odfp9ncjGq14TS3xm/34/iBcdVWdXkAqldUHDhbE+7m4nz8D0qgq04nzaWFNO3LxJSzh+ayQgB++OGHo06gt18ADwkJYfz48celF353s1qtbN68GZvNRmBgINOmTePCCy/khRde6HPtlgYSd+M4SCwXR++0005j1apVzJw5k/Lycu666y7Wr1/PyJEjj/tBzceSVqslKSmJuLg48vLy2Lp1KzqdjoSEBAYNGtRtSaqEhATmz5/P/PnzAcjKyuL999/nueeew+5lRGPoeuHStZMsMKTT7ysaDTpvX3TevqiO3wvmaj9bSsNPG0CrbY3jXq1xvOQfb2A2m1FtDhz1jYCC02brchxaD080Hp44LS3Y3Eige4ZHuz5TNBflw+iT//jaaqsw7cvElLuHpvwsVIedkpLSLh+7K20L4Pn5+ej1ehITExk0aNBx6YXfnVRVZe/eveTl5TF8+HDmzp1LbW0ta9euJSwsrKeHJ/5Ef4/jfft/1TFSWVnJvHnzGDRoEB4eHkRERHDmmWeydu1aLrvsMmbOnNnh9j///DOKovDYY491uP6xxx5z+2BGvV7PwoULueCCCzjjjDPw9PTE4XCwevVqmpqajtVL6xGKohAREcEpp5zCpEmTXJVla9eupaysrHVbczfy9vbmmmuuoaysDBRNa0DrgrW22nW6ts7Y9YElbRNonY8fAUPGYoxJxRiZjE9IIgA+oUkYI5Pxix+BX9KoP9zvUAz+QeBsPTTNduBg00Pxihzkun1zaSFOux3z/jwq1/xC/gcvk/n8P9j/xTs079lNmF8yI0bNQafx5P333+/ysTvTtr17yZIlZGRkEB4ezowZMxg5cmS/SJ7v37+ftWvXkpiYyKJFi7jrrrv4/vvvjzh5fqjfL9Da2klRlD9cnn766WP5sgaE2NhY/P39XZc/SyxlZ2cTFRVFQkICV155JYWFhcd5pOJY64k4DnD99dfz8ccfM2fOHNavX+/qpVpaevQTop5mNBoZPXo0M2bMIDg4mG3btrF06VLy8vKwuTH5PBqKonD66aczbtw4wL1t3+0nuAb/rnt8Oq1W12JAwNCx+A0ajjEyGd+woXgHtya8fcOHYIxJJSB5HFqP1sXpP7SB6YThSCrXDmguykdVnViqyqhJX8P+L/9H1gv/JP/9F6nZsBJfpx/D0i4hLHwkmZlZXT52Z5xOJ8XFxaxevZo1a9ag0+mYMmUKJ510Ur9Injc0NLBy5Ur0ej12u53p06czb948XnrppSNOnkssPz7cjeMgsbw/6olYPmLECNatW8fixYt54IEHGD58ODt37mTXrl3dPmftbnq9nuTkZGbMmEFycjL79+/nl19+ISMj47jkG4YOHcqTTz6JuaWly4VkANXpwNZYB4A+oOtdAO13dvvEDMVv8EiMUSn4hv8ex31CkzBGDcM/cRSeodGtVeJOh+uA8kNpq0K3Vnd9ILhGp8czLBIA84Fd4TZTA/W7t1Ly06dkv/ovct74N+W/fo22ppmEhOkkDT0Ph8PO8uXLu3z8ztTW1pKens6vv/5KXV0dY8aM4fTTTyc+Pr7PJ89tNhubNm2iuLiYIUOGMHv2bBRFYfny5UecPJc4fnz09zguFejAxRdfjNVqZeHChSQkJFBeXs7SpUuprq5m6tSp3Hvvvdjtdtdqbdu25hUrVnR4nOXLlzN16lS3n1ej0fCf//yH2NhYzjzzTF599VVGjx7NypUr+00FkL+/P6NHjyY1NZX8/Hy2b9+OVqslLi6O2NjYbm3zkZWVhWdoJBp91y1krHVVqE4HWh8jGjdW5dsm0B7B4YRN/n17mYe2dTIefvq5WBytH7rsTY3UprduRXdaD3/LWFeJg/YHspR8/zGO5qbW16L3JDAgkegh5xAUPAS93pf6ujwqK3bhdNrJy+v6lPA2qqpSW1tLQUEBxcXFBAQEMHz4cCIiIvp8gG6jqiq7d++moKDAtUVs7dq1rFq16qj6qx3q90ubJ554grlz53a4X189Hb0n7d+/v0Plb2er3RMmTGDBggUkJydTWlrK448/zqRJk8jIyJD3vA/rqTgOcN555/Hrr79ywQUXsGvXLh588EHS09MZOnQoQ4YM6fNbZz08PEhOTmbIkCEUFxeTl5fHnj17iImJIT4+Hn9//2577nfeeQfAvZ1k7Vqx6TvZSXYwp9UCB/5pwk47G6VdYtUVy6f+HstNObtbt427sRCu9fZF0epQHXZsdV0vhOu8fdEZA7A31lG3czP1Gek4LGYURYuffyyx0ScTFDQEX2MUJlMp1ZV7aagvwGq1UlpaSmRkZJfPAa0HgxYWFlJQUAC0VgtOnDixT+98PFhZWRnp6ekkJiaydOlS7r//fl5++WVXi4EjJbH8+HAnjoPE8v6qp2J5fHw8a9as4eKLL+biiy/mww8/pLi4mMbGRsaOHdvnf0dqNBpiY2OJiYmhtraW3Nxcli1bRlhYGHFxcYSFhXXbfG7Xrl2oDod7C+EN9a42KJ3tCD9Y+8K0gBPGYRwy3PX3zubkFat/prl0f+t9bRa02kMfGmsIDMVSWdq6U90N3jGDsVSWYWuoJfu1f7nOWPP2DSMsIJmgwUkEBCZis5qorsqkomInAIsXL3b759Vut1NcXExBQQENDQ0MGjSoz59VcrC2s4U8PT3x8vJiypQpzJgxgzfffPOoWgNLHD8++nscH/AJ9Lq6OlavXs2KFSuYPHkyAHFxcZx44olAaxLWZDKxZcsWJk6cCMCKFSt48MEHueeee2hpacHT05OWlhY2btx4RB/Q77zzToYNG8all17KTTfdxM0338zGjRtJS0tzrYT1de0n4KWlpeTn57N3717Cw8NdgftYv86m5mYCho5y67au7WJ/su37YG2909xJzre/jTs90Dtu/e66cs0QFIrG4IFqs6JYHSQlnYV/QDzePmGYTKXU1uSyd/eXNNQXoqpOtFodaWnDePLJJ7t8bKvVSlFREQUFBZjNZmJiYvpFX9SD2Ww20tPTaWpqIjExkdmzZ+Pp6cmWLVuOaotYV79f2hiNxj63fak38vPz67J1xllnneX6esSIEUyYMIG4uDg+++wzbrjhhu4eougGvSGOn3TSSWzevJkLLriAa665hv/973/k5ubS0NDAqFGj+kRPv64cPAEvKChg9erVGI1G4uLiiI6OPuZJhvT0dHTGAHQ+XX+QttZVo2i0rb1T3apAt7R2fNFoOiTP/4yib50AuFOBrigKer8ArLVVWNyoXAPwjh1M497tOK0txMVPISAoET+/WGxWE7U1uewvWENNTTYOhwVF0RAVFcm1197aZfLc6XRSXl5OQUEBFRUVhIWFccIJJxAeHt5vFsChdRE8OzubrKwshg8fztNPP83XX3/N4sWLOeWUU47qsSWWHz/uxHGQWN4f9XQsDw0NZcmSJdx2221MmTKFzz//HFVVXa3Z+kOCUlEUgoKCCAoKorm5mYKCArZv3w7AoEGDiIuLw9v70Enlw/X8888D7h4g+nui2u04foDi9pxcdd1X69lFAj0gCEXR4LRacLSYu7y9V1QcNQeK5vx0oUScMBP/gDg0Gh21NXlUV2eRlbkIS0td622Mfpx77rk88sgjXY69rq6OgoICioqK8Pb2dhUj9vXFnYNVVlayZcsWYmJi2Lp1K7feeitPPvkkf/vb344qVyRx/Pjp73G878/ojpKvry++vr588803TJw48Q8rJEOHDiUqKorly5czceJEGhsb+e233/j+++956aWXWL9+PVOnTmXdunVYLJbDrlxrM2PGDDZu3MisWbPIyMjg5ZdfJjMzk4aGBk444YR+M8nRaDRER0cTHR1NU1MTBQUFbN261XXoSWxs7DEJ3Onp6QdWu7uuWlOdzta+4Px5v7WDtSXQ3QnWiu73wOZW71Sjv6sfuzsr3oqiwSsqDnNhDg6HFYfTRl7ur9TX7cPhsAIKgYEBnH32WcyZM4eLLrrokD9PqqpSXV1NQUEBJSUl+Pv7k5CQQHR0dL9IAh3MZDKxceNGvL29MRgMTJ48mXPPPZdXX331qA/A7er3i+h5AQEBDB06lJycnJ4eijhCvSWODxo0iDVr1nDddddxxhln8Pnnn9Pc3Ow6lOxYHdrc09pPwIcPH05RURH5+flkZGQQExPDoEGDCAwMPCaL4lU1Nfi2qyg7FGttFarqRGPwROvR9e42p80CqoriZlxrOxDcnYVwAH1gCNbaarcr17yi4mjYs631OZwOykp+Y++uz7FYWntJenp6MW7cKGbPns1NN93U5eSkqanJVW2u0WgYNGgQI0eO7Dc/h+3Z7Xa2bdtGTU0Nw4YN49prr6WxsZHNmzcfVkumPyOxvPeTWN739YZYbjAYePPNN3nllVeYOXMmL7/8MieeeCKrVq1i3Lhx/arvspeXFykpKSQnJ7sWWZcsWUJoaChxcXGEh4cfk/Mili9fjkZvwBDc9c769q3YDjeBrtF1nUjW6PXgbEugu7crXD3QJtVaW41XZNcJdBdFob4un/x9y2gylQGg1epISBjM2Wdfy2233caQIUMO+Xg2m43i4mLy8/MxmUxER0dz0kknHbPPWL3Nvn372LVrF6mpqbzxxhu8+eabfPnll5x55plH/dgSx3u/vhLH+0dW9ijodDoWLFjAwoULCQgI4JRTTuHvf/87O3bscN1m6tSprq1hq1evZujQoYSGhnLaaae5rl+xYgWDBw8mLq7r1dU/M3ToUDZu3IjT6eTss88mKiqK2tpa1q1bR0tL1xVPfY2Pjw+pqanMmDGD4cOHU1NTw5IlS1ixYgV79+6lrq7uiHvPvfjiiwB4R3f972FvrHcd3uXOtm9VVVEP9H/VuLHqq2g0oGn9AOJOAl3RaNH5tk6MrTVuTryj41EBp9NGXs5i7NZSJkwYxzPPPEN1dRU1NTWuPt6dJc/tdjulpaVs3bqVX375hU2bNrmSyaeddhpxcXH9MnleXl7OqlWriIiIYO/evcycOZOHH36Yt95666iT5+De7xeABx54wBXY2y6rV68+6ucXXTOZTOTm5rrdAkH0Pr0pjnt7e/PJJ58wd+5cTj/9dMrKyggICGDlypUdtoj2F3q9nsGDBzNlyhROPfVUFEVh/fr1LF68mO3bt1NeXo7DjT6jnampqcHpcOAVFe/W7a3VFaCqbsVxaI3Hqup0a9INByrXFMWtSTeAISAYRaPB2dKMw42qde+ouNaEvqKwv3A1dbV7SEyM4a677mL37t00N5vZsGED9957b6fJc1VVqampYffu3SxbtoylS5fS0NDA6NGjmT59OikpKf0yeW42m1mzZg3Nzc0EBQVxxhlnEB4ezurVq49J8hwklvcFEsv7vt4SyxVF4fbbb+e7777jnnvu4Z133iElJYVNmzaRk5PT5/uiH6zt7LIJEyYwffp0goOD2bVrFz/99BObNm2ioKAAi8W9hePO7N9fhFdUnOussUOx1lahHJgzG9zqgf57PHZnV7iia1+B3nVc7thWtes5uT4gGI2HFzqdjuqqvZSWbCIwQMdll13Gzz//jNVqISsri+eff/5Pk+dNTU3k5uaydu1afvrpJwoKCoiPj+fMM89k9OjRBAUF9bvkucPhYNu2bWRmZpKWlsYdd9zBN998w8aNG49J8hwkjvcFfSWO97+M2BG4+OKLOeecc1i9ejUbNmzgp59+Yv78+bz99tvMmTOHKVOm8Le//Q2bzcaKFSuYMmUKAJMnT+aNN94AWoP1kVattefv78/333/Pgw8+yOTJk/noo48ICwtjxYoVjBkzpl+tfLfRaDRERUURFRWF1WqlvLycsrIycnNzXSfzRkREEBIS4vZK+MqVK9F4eKIP6LqivH1AdOfgMdVuoy34anTuJVk1Oh1Oq8OtBDqAISAEh6kBa617W7+9ogaB08lTTz3Fbbfd5lbfqObmZtd7XVlZiZeXFxEREYwbN46goKB+s+uhM06nkz179rBv3z7S0tJ46aWXWLBgAd9++y3Tpk07ps/V1e8XgPvuu8/1dZvo6K4PvxWH79577+W8884jLi6OkpISHn30UbRaLZdffnlPD00chd4UxxVF4eGHHyYtLY1rrrmGu+66i2uuuYb169czZMgQhg4d2u8mP9BaORIQEMAJJ5xAVVUVZWVlbN++HavVSmhoqCuWu1v188ILL4Cqdjjn48+oqvr7TjI34j6A80BhgjsL4a23M6AoCqrdvQS63j8IVW1dnLfVVaPt4kBzj7Bo0GgYlpLCokWLSEhI6PI57HY7lZWVlJWVUV5ejtPpJDw8nOTkZMLCwvrd1u6DlZSUsG3bNqKjo8nOzua6667jgQce4OGHHz7m/8cklvcuEsv7p94Uy8844ww2bdrErFmz2LVrF6+99ho5OTlUV1czevToY1Jo09t4eXm5zm9paGigrKzMdYZZYGAg4eHhREREYDQa3fod63A4sNpt+EXHu/X81tpqUJ0oWh1a765b5jitLaBoWu/jRrzr0FbVjcXw9nkBmxsHgiuKgnd0PJaiXDZv3szYsWO7fJ/azhkrKyujrKwMk8lESEgIkZGRjB49+pi31OltTCYTmzdvduWDzj77bOLi4ti4ceMxbxkrcbx36atxXBLoB3h6ejJ9+nSmT5/OP//5T2688UYeffRR5syZw9SpU2lqamLz5s0sX76c++67D2gN1tdffz01NTVs3LiRm2+++ZiMRavV8swzz3DCCScwe/Zs7rvvPq655ho2bdpEQkICKSkp/Ta5aTAYiI2NJTY2FqfT6ZqE79ixA4vF4vYkvKSkFK/YBLeCu/Uotou5E6zhQBsXq8X9BHpgMM3F+TjMJpw2a5er6m1bxpYuXcqDDz7Y6W1UVXV9GCorK6O+vp7AwEAiIiJIS0vD19e3XyZ1DmY2m9myZQsOh4MhQ4YwZ84cKisr2bRpE0lJSd3ynIf6/QIQEhLSbc8tOioqKuLyyy+nurqa0NBQTj31VDZs2NAvDm0e6HpTHAe44IILWLt2Leeffz5btmzhxRdfZN++fVRXVzNmzJhuPUS7J2k0GsLCwly9thsbGyktLXX1Wg0ICHDF8UNNwr/77jvQaPAM63riYjc1oDrsgHsHj8Hv1WeKmwvhrfFeQXU4UJ0OV5XcnzH4B7kOQ7PWVePZRQJdo9PhGRZNfn7+IZPnA3nxu43D4WDXrl3s37+ftLQ0Xn75Zd58803ee+89Lrzwwm57XonlvYfE8v6rN8XypKQkNmzYwJVXXsm0adP44IMPgNYk/dixYwkOdu/srL5GURT8/f3x9/cnOTmZlpYWV9zJzMzEy8vLlUwPDg7+07jz6aefgtPpVv9zAGtNBQB6vwC35qROq/VA21P3itraL5i7dS6Zf+DvY3PjXDJo3RVu2pfJiBEj/vQ1DPTF7zb79+9nx44dxMfHk5GRwfnnn88NN9zA/Pnzj0n7oM5IHO89+moclwT6n0hNTeWbb74BIDExkdjYWL777ju2bdvmOnigrZf3f//7X6xW6zFZ7W7vmmuuYcSIEVx66aWsWrWK1157jeLiYqqrqxk3bly/3IrbXvtJuKqqbk/C7XY7NrudAHdXuw/34LHD3C7WdjsHuLWNGw5Urh2ocrfV1+ARcujDLHRePuj9g9i6dWuH6x0OB9XV1a6kudVqJSwsjMGDBxMeHj7g+n+1tamJjo6msLCQU089lXPOOYcffvjhuB4O1P73izi+Pvnkk54egjhOekMcP+GEE0hPT+fGG2/ktNNO4/3338dgMLgm3739Q+LRUhTFdZjQwZPwrKwsPDw8XHH84El4dnY2nmHRaNxoH3a4fVMBHAcWtN2O4zoDHJgLO61WtJ6H/gzW4UBwN/uge8cMpva3kg7XtV/8Li0tpaGhocPitzs7zvqTtkMEFUUhPj6eSy+9FIvFwubNm0lOTj6uY5FY3nMklg8cPR3L/fz8+Pbbb/nPf/7DtGnT+Ne//sWsWbNYv369q1q7vxcgeXp6EhcXR1xcHHa73VXglp6ejtPpJCwsjIiICMLDwzskfxcsWADg3plkqoq1vgZVVd3aQQ6tRW0H8ufutVXtUIHedQJdozeg9fTGaWnGWuPmrvDoOFCdLFy4kLlz57qul8Xv39ntdnbu3ElZWRlpaWnMnz+fjz/+mHfffZeLLrrouI5F4njP6atxfMAn0Kurq7nkkku4/vrrGTFiBEajkS1btjB//nzOP/981+2mTp3Kq6++SlJSEuHh4a7rJ0+ezEsvveQ62ORYGzVqFOnp6cybN49JkyaxYMECgoKCWL58OWPGjBkwpwR3NQnXarX4+/sTEBDAli1bCAsNwdPN1W5bbTWggqKg9/Pv8vbOdklw91u46P9w30PR+we5+rJba6u7TKADGOMSCTTXkZ+fT319PXV1dTQ0NODh4UF4eDijRo0iODi421Z0ezOHw8Hu3bspLCwkLS2NV199lddee41XXnmFa665ptue193fL42NjZSVlXW4r7e3t1snWAsx0PX2OB4YGMgXX3zBa6+9xnnnnceDDz7IlVdeycaNG0lMTCQ5OXnATJwONQm32+34+fkREBCAv78/YeHhmIJj3XrcDjvJDqMHOoDG4N5CskZvaOvehtNq6TKB3mHrt7uVa1FxGIqyWLZsGeHh4dTV1VFfX++qTktISBiQi99tioqK2L59O3FxcezZs4fzzz+fK6+8kv/+97/duqNDYrkQ3a83x3KNRsP999/PpEmTuOyyy1i+fDnPP/88eXl5VFVVMXbs2AHze7l9e1VVVamrq6OsrIzs7GzS09Px9fV1tXQzmUwYQyPQudGOxdHchHqgSM0Q6F5lf+th4K1fK24shrc/88TdXeH6gGAs5UXut1WNiMVoNLJ69WomT55MXV0ddXV1NDc3ExwcPGAXv9s0NDSwZcsWDAYDUVFRnH/++Xh5ebF161bi4+O77XkljotjZcAn0H19fZkwYQLPPfccubm52Gw2YmNjmTt3Ln//+99dt5s6dSrvvfeeq9dam8mTJ/O///2PK664olvH+N5777Fw4UL+8pe/cMcdd3DTTTeRnp5OXFwcw4YNG3BJ0faTcIfDQX19vStpbLFYePXVV7GoUNJkpbjJ4vqz1mL/w2NZaloPHtP5+HW5JRs6VqC73cLF4IGiKG5tF4OOB6d0VrmmVSDc20C0jwfRPh5E+XgQPv5BrC0t7Nu3j7CwMBITEwkICMDHx6ffV0YcSlu1GsDgwYO5/PLLMZvNbN68mZSUlG59bnd/vzzyyCM88sgjHe5788038/rrr3fr+IToD/pCHFcUhVtvvZWTTjqJSy+9lJUrV/Laa6+xf/9+V0uX/t7n8mAHT8JNJpMrYbxr1y7+37/+hc7gQXmLjWKTheImKyVNFsqbrTgPOsPNWlsFGg04nW6dZQK/x3KNm31sFb3etTPMnViu8fRundDbba3jO/jxgCBPHVEH4ni0jweRYwehv3oWBQUFBAUFER0dTWpqKv7+/gNmkaUzdrudjIwMSkpKSEtL45lnnuHDDz/k7bffZvbs2d3+/BLLheh+fSGWn3TSSWzdupUbbriBKVOmuHaVtRW29cezyg5FURQCAwMJDAxk2LBhtLS0uBLGVVVV3HjjjQQGBlFlaY3jJQfieInZgsXRMZB3bKkaePBTdao1Cd76OIq267TW4fZABzAEhdBSXoy9qRGn3f6HXXE+Og3Rvh5EeXu0/uljIHDK+5SXl7t2jA0ePJiAgIAB05qlM6qqUlBQQEZGBomJiWzatInbb7+defPm8f/+3//r9vdG4rg4VhS1vx0l3c/t3r2bSy+9FKPRyDvvvENFRQV2u50xY8YQGOhesOnvgoKCaLY7mXDDnQyOjSba6EW0jwfhXgYsDmeHhHp1i43fXnqC+uoqPKPjib/y9i4f35S3l8LP3gQg6pzLCThhvOt7HlqFR8cP5vHN+zp8MMj/6FWa9+eiGDxJuev/dfkctsY6sl95Ar1eT9yp00k64xwiDiTMo3xbX4vN2fpaihqayS8uYU/6RjJ/bT2A9qmnnjqCd65/UVWVvLw89uzZQ3x8PJmZmdx4441cdtllPPvss/2+BVJv09DQgL+/P/esPRcP32P7IclisvHfU76nvr5eKgREr9fY2Mi8efP49ddfWbhwIRERERQXF5OWlkZcXNyAXvBsc8UVV/DJJ58w8vK5JA8fQUyAr2uCqtVAmdnaGsdNrQn1rB8+pyh9HTarlZR7nu6yLYuqquyZfy+oKn4pI4m54NoO3+8slldvWkn58u9AVRl87d/wiux6S3rOW/+Ho66KwMgYRt10HyFe+t+T5T4G9BoNZWYLxSYLBRWV5Gbnkv7JO0RGhFNYWHjkb2A/UlVVxdatW/Hy8sLPz49rrrkGDw8PPvnkEwYPHtzTwxtwuiuWSxwXfYmqqrz88ss8+OCD/P3vf+fyyy9n9+7dxMbGkpqaOqATpW0qKioIDw8n7uTTGTHtbAaFBrnin9GgpbrF5pqPlzZZKNq1nT1fLqSlpYWYC67FL2Vkl89R+MXbmHJ2o+h0DLt3fofvdRbHLTUV5L75NAAhp8wgbNLMLp+jfOUP1GxcgbeXJyNvuo/w8HDXwneUjwcBHjqqmltfx/6aenL35bPth6+oLy7EYbcdwTvX/zQ3N7Nt2zYaGhoYOnQoTzzxBIsWLeK9997j7LPP7unhDTgSx4/OgK9A72tSU1PZtGkTf/vb3zj55JN5/vnnmThxImvXriUhIYHk5OQBV41+MJOpCZvdxsrnn2CVVodnSCQe4VH4RMYwODGJwYNiiA30Z3JUAIEeWu54600cDgcNTWaaNHoarQ4abQcuVjsNVgeNNjuNVgcmm6PDli93+q1B6xZxVVXB3rrardcoGPVa/Aw6jAYtRr0Wo0HX+qdei58hGu+J72M0GnE4HJgcKhVmK/ur6/h5byY5OTkUZ2diqSjBUlsJqoqi0YFGw86dO7vlfe1LTCYTW7duxWKxMHz4cP7973/z2Wef8dZbb3HJJZf09PCEEAOY0Wjk/fffZ8GCBcyePZu5c+fy17/+lczMTEpKShg1atSAq0Y/WHZ2NioK2z56k22AITAUz7AoPMOjiElIIiE+jkFhwYwM8SXUS49v6l/RaP5GQ0MjZp1Ha+w+EMNbY3lrHG+wtn5ttdtcB3y6e4ioRq933cdptaBROBCzf4/jfm1x3NB6vfezz+Dn64NWq6XJ5qDGYqOozsTGzCLy8vaRl7UHc0kRlqpSnHYboKDVe1BXV989b2wfYrfbXa3XUlJSWLx4MQ888AA333wz//73vzG4uXNACCGONUVRuOOOOzj55JO59NJL+fXXX3n55Zepr69nxYoVjBo1qt+fcdKVb775BjQaCtYto2DdMnTeRjzCo/AMiyJ00GASExKIiwonzujNhHA//IZOR3/JWTQ3N9PoUGlyKjRaHQfF8tY/G6wOWhxOnJYWFEVB0bk5H28X7502KwrgrdP8Pgc/ELv9DL/Hdp/U6/C762YMBgMWm516u5OSxmayi0v5Jb+QnKy91BXuo6WiBEdzEwBavRdOR+tBoQP550BVVQoLC8nIyCAqKgqbzcbMmTOJiIhg+/btREd3fUi8EL2NVKD3Yd9++y0333wzJ554Iv/5z38oLS3F4XAwevToAVuNXlVVRWhoKElDz8PPP4bG+v00NpZiaiqlyVSO6nQAoPX0wRAUitbbB0tBFoGBgSRMPYvYsSd3EkBbk9u+ei1OVcXUbKG+uhKHw4HWLxAMHjhVcKqtm7sT/LzY19CMAmgUBY0CjoZaFLsNnU5HUFg4njotdqfqSswf/KGg0WZn14evU7m/gMbmZnTe/ljrq38fv94TH58IjL4R+BojMRpj8PENZ+uWN/D3Z8BWrrWvOo+Li6O4uJibbrqJoUOH8vbbb3drbzVxaFKBLsQfZWZmct1111FVVcVbb72Fn58fJSUlDB8+nEGDBg3YavSg4GAUJZSkoWfTUL8fU2MJjaZSTKZSHLbWs0Q0Oj2GwFD0QSGY92Xi7+tDWOJQhl18LUaDDr/2C9Ntk2G9Fq1GodnmoKaiDLvdDgZPtEZ/nCo4VNXVHibR34uCxgPPpYDa0ozTVI9WqyUgNAyjpwdOVaXJteDeLkl/IKbnr1tG4YZV1FRXoQ0IwdZQh9Pa+piKRou3TxhG3wh8fCMxGqMw+kVTvH8D+/J+xWq1oHPjANX+qH3VeVBQEHfccQfZ2dm88847TJ8+vaeHN6BJ5ZoQHTU2NnL//ffzwQcf8NRTTzFz5kz27t1LbGwsaWlpA/b3+IUXXsi33y5iwsl3Y2oso7GxCFNjGaamUizNda03UhQM/sEYgkKw1tfiYWshwN+PE264iwBf3z8Wmx2Ymxu0GmxOJ7U1NbSYzThUFX1wBM4DMbxtTp7o70V+QzOgoNWAoqrYqsrQarX4+gfgbzS2fiawO1zz8YaDFt4rCvLZ+9VCampqcHh4o9rt2JsaDrxKBU/vQHx9IvD1jcTXGImfXww2m5nNG1/kxRdf5I477uiZf4Ae1r7qPDk5mZdffpnXXnuNRx99lLvvvnvA/r/oDSSOHx35ye3Dzj//fE499VTuuOMOJk6cyPPPP8+ECRMGdDX6ihUrACgv24bNZsLPL4aQ0FQ8PANQVSfNzdU0mcppaiqn2VxNQ0kRNoeDiooKdE02Gmqa/vSxNQr46rWQm0HLri1otRoippyLd3gUWqU1WW7QKCT4ebG9yoTF4XQF8cotq2nMy8JmsxJ43jWYFB3NduchX0tJYzPNDQ04nSoRoYl4h03A2zsEH98IDIbWg0es1kZMjaXUVGeRn7eEpqZy7PaBuW2wreq8paWFtLQ0nn76aT7++GPmz5/PzTffPGATUUKI3is5OZnVq1fz3HPPcfbZZ3PLLbdwxx13sHfvXlc1+kBsN9VQ34BOZ6d4/wb8/GOIjB5PoncoiqLBYmmgqamcJlM5zeYqmioqcdht1NTUYA+3oKlr/tPHbas282wxUb/4M3Q6HQHDRhE84sQDC96ti94eWoVEfy/SKxuwOFon5KaifVSs/RWHw4HX6EmoMUmtu9IO8TqqTVYqKspbW8WofgQMGoW3dzA+PuF4egWh0Wix2y00mcowNZZQVrqV2pocVNXJnj17OOGEE475e9ubHVx1vmTJEu6//34uu+wyvv766349IRNC9E1Go5HXXnuN2bNnc/311/PVV1/x0ksvUVtby/LlywdsNXpmZiYA+3KX4OcfQ3BwMoPiJqPTeWCzNWNuqmidk5sraG6owVxfh91pw2Q249usorSY/vSxPbQKRr2O+p8+QmuzYPALIOasv7hiuFZRXHF8a7s5ud1up/CrD7Hb7egi4/A48QwarQ7sh6gntdqgpKQEAC+NL+Hh4/DyDsbbJwwfnzC0WgNOpwOzuRJTYymFBauprysAYPv27cfwHe0b2ledR0ZG4uXlxcyZM/H392fLli0MGzasp4coxFGRBHofFxwczEcffcTXX3/NLbfcwkknncQzzzxDcXExZWVljBw5kuBg906y7g8uuugizjzzTDZv3kxh/ipU9UDFttYDH98IfI0R+PiEExAwmMio8ZSVpJO/bykqdHnwmFOFBquDqqISKnZsB6eTwWmn4qX3d93GQ6twQUIo26tNHXqgl+YWUrd9K6rDwZBTG9D7BXT5WvQBQZj3K4CT8MhROB02zOYqqir3tk62TWXY7W2JAgVfX19GjEjjnnvuOcx3rW9zOp3k5eWxd+9eBg0ahNlsZsqUKSQlJbFjxw6pOhdC9GparZZ7772Xc889l+uuu47vv/+et956C09PT5YtW0Zqairx8fEDahHw4Yf/zrvvvktZ2RaKi9YDoCgavL1D8TVG4uMbgY9PGCEhKdjtLaRvfhVQujx4TAWa7E6qa+rI27EDgBCvEMJih3e4nYdWYdbgUHZWN7liuamsmsL0dAAiI4YQGN51/22Df5Cr7UtAYAIBgYNpNldTWvqbK45bWup+v73Bg0GDYjnnnDkDLnleUVHB9u3b8fLyIiEhgXnz5pGZmckXX3zBjBkzenp4QghxSGeccQYZGRncd999TJw4kf/7v/9jxowZbNy4kdjYWIYNGzagWk+1VV/n5++lvGwbbYd9engGYPQ9EMd9w4iIGI2XdzAb1v4Hp2JH5x/Y5ecdi0PF4rCRmZGB02zCEBpJw0Rzh9u0xfEd7ebkqqqyZ0s6oOJrsjFo5OQuX4fO2Pq5QqfT4ekZQGj4CTSbq6mtzqGocA2mxlLM5ipUtXU5XavVERoaysknn8mzzz57eG9aH9fU1MSOHTuor68nNTWVV199lVdeeYVHH32Ue+65R6rORb8gP8X9xIUXXsikSZNc1egvvPACJ554IuvXrycyMpK0tDQ8PT17epjdTqPR8PPPPwOtq8yrVq3i559/ZuPGjWRnZ1NZvo0Sm6XDfXQ6PXa7E33AoRPobZxWCwoKKqB0cVCZa1zteqU7D3r+P2PwD0Y9sJf8t82vdRhvYGAAY8eOYNy4ccyYMYNp06YNyJ65lZWVrp7vw4cP5+mnn+bDDz90VZ1rNJoeHqE42D9Cd+NnPLY7Yxq8HPz3mD6iEMdfSkoKa9as4dlnn+Wss85i3rx53H777eTk5FBQUMCIESMICnIvTvV1jz/+OI8//njrZHfPHhYtWsSaNWvYtWsXZaVZlJdtp20y/jsVQ4B7BQNHcpZJ+17p7e9/KG2fKxRFQ17Oz78/p0aLr68vSYkxjBx5NlOnTuWcc84hMjLSrcftT8xmMxkZGVRWVrqqzu+77z4uvfRSvvjiC/z9/bt+EHHcHetYLnFc9AdGo5HXX3+diy++mBtuuIEvv/ySl156ifr6epYuXUpqauqAac82bdo09uzZA7QukH7//fcsX76cbdu2UVhYSE1hFs4DrUnbKIqCV6D71fptsVij93Dr9q390nXgsLvaqXVFo9Oh9TGiWFuorclh84YX2h4MLw8vIqMiGDZsPKeccgrnnnsuw4cPHxD/vu05HA6ys7PJyckhJiYGh8PB2WefjdFoZMuWLaSmpvb0EEUnJI4fGUmg9yMhISF8/PHHfPXVV8ybN49Ro0bxzDPPYLFYWLp0KSkpKQwePHjAJBV1Oh2nn346p59+eofra2pqWLZsGZs2bWLnzp1kZmayr6AAna97W4OdVkvrPnBA43YC3dBWhIbTanXrPvqAIFCd/O1vf0On0zFhwgQmTZpEeHi4W/fvz5qbm9m1axfl5eUMHTqUzZs3c/XVV5OcnMyOHTsYPLjrykAhhOhttFot9913n6sa/auvvuLZZ59l2LBhrFu3jujoaFJTU/HwcG+y2NcpikJqaiqpqak88MADruutVitr165l/fr1bNu2DZvNxjfffIO+i51kbZy23+Owxu1DRI8ggX5gPKNHj2LcuHGMGzeOSZMmkZycPOAm2AdzOBzk5uaSlZVFVFQUYWFhzJkzh/z8fD7//HPOPPPMnh6iEEIckenTp5ORkcG9997LiSeeyEMPPcSVV15JZmama0E8ICCgp4d53ISFhXH99ddz/fXXu65TVZWMjAxWrVrFb7/9RkNDA198+WWXO8Lb31+121rPHDuMyn5Fp0d12HFa3IvjAIaAYJTaCq655hqGDh3KqaeeytixYwfMZ7FDKSsrY+fOnRgMBoYNG8YzzzzDe++9xyOPPMK9994rVeei35Gf6H7ooosuYurUqTzyyCNMmDCBu+66i7lz55KXl0dhYSEjRowYUG1dDhYUFMTs2bOZPXs2ABEREeiNASiKewsLTpvFVfimcfPUb0Wvd23jdnfFu23iHRER0SFxMJC1tWvJzMwkIiKCyMhIbr75Zvbs2cN//vMfrrjiigGflBBC9H3Dhg1j7dq1vPPOO9xwww2cfPLJPP3005hMJpYuXcqwYcMGXFuX9gwGA1OnTmXq1KkA3HLLLQDuJ9DbJcAVNyvQf69UV9xOoGs9PNEYPKmvr+eNN95w6z4DQUVFBTt27ECn05GWlsbzzz/Pm2++yZ133slPP/2Er69vTw9RCCGOip+fH2+++SbXXnstt912GwsXLuT5558nNDSUNWvWDMi2Lu0pisIJJ5zgalfmcDjQ6fVu7whXHXY4cFiouwVt0Dp3d1ia3Z6PAxgCQmgsL+Ltt992+z79XVNTEzt37qSmpoaUlBSWLl3KxRdfzIknnsiOHTtISkrq6SEK0S0GRinyABQYGMhLL73E+vXrWblyJZMnT6ampobo6GjWr19Peno6LS3uB47+rL6+3u1t39A28W5NhrvdwkVnaJdAd68CvW0FfuPGjW6PrT+rrKxkxYoVFBYWkpaWxieffMIpp5zCqFGjyMzM5MorrxywySQhRP+j1Wq56aabXBW6J554Ij/99BOpqank5uaycuVKampqenqYvUJGRgYAer9D90Bv07GFi3tx/PcWLmqHCvau6AOCqKqqcvv2/ZnZbGbTpk1s2bKFwYMHU1BQwMSJE9m9ezdbt27l6aefluS5EKJfOeWUU9iyZQt33HEHV1xxBf/4xz9ITEzEbDazdOlSCgoKUA9xiOVAsXLlSlDVI1gIVw4vga7XoyjuL4RDaxxva6s60Nntdvbu3cvy5cvx8vIiMDCQyy+/nH//+9+88847/PDDD5I8F/2aJND7uVGjRrF69WqeeOIJbrvtNm6//XZiY2NRVZUlS5awe/dubDZbTw+zR1ltdvSB7ifQHVaLKxnubgV6a2A/kEB3swe61tsXRasjOzvb7bH1R/X19axfv55NmzYRGxtLWVkZp5xyCps2bWLTpk08++yz+Pm5135HCCH6muDgYN544w1WrFjBjz/+yOmnn47JZCIyMpJ169axadMmGhsbe3qYPaqwsBCtty8aN7cKt06cWxdc3W/hcvgV6ACGwBCazOaub9iPWSwWdu7cydKlS9Hr9YSGhnLttdfyj3/8g5dffpnFixeTkpLS08MUQohuodPpuOOOO8jMzMTPz4/x48ezbNkyhg0bRlZWFsuXL6esrGxAJ9J/+eUXALdbuPweh1W3d5LB78Vvh7MQbvAPQnU6KCsrc/s+/Y3T6SQ/P58lS5ZQUVHBsGHDeO211zjjjDOYOXMmu3fv5vzzz5diNtHvSQJ9ANBoNMyZM4esrCxSUlKYOHEin376KampqdTW1vLrr7+Sk5ODw+Ho+sH6IafTicH/MCrQLS2twUGjQdG6d/BC+8Du7sRbURT0fgGUlpa6Pbb+pKmpifT0dFavXo3RaCQ4OJibb76Ze+65h2eeeYYVK1a4tv0JIUR/N378eDZs2MBDDz3EDTfcwN13301kZCQeHh6sWLGCrVu30tzc3NPD7BE1NTWHt5PMZgFN6yTP/RYu7SrQDyeB7h+Ew+l0+/b9id1uJzMzkyVLltDU1ERKSgpvv/02kydPZtKkSezZs4dLLrlEJtxCiAEhPDyc//3vfyxevJgvvviCGTNm0NDQwKBBg9i6dStr1qyhurq6p4fZI7Zt2wYcSSs2xe2FcPj9wFGnzer2gkXbmBYtWuT28/QXqqpSXFzMsmXLyMnJISUlhe3btzNhwgSKiorYuXMnjz/+OF5eXj09VCGOC0mgDyABAQG8+OKLbNiwgR07djBmzBhWrVpFamoqRUVFLFmyhIKCApwDaKKXkZEBqtPtYA2/B2xF6/4RAu0De2cTb1VVcVhasFRX0FSYQ/2udCrXLcFpt9HYaHL7efqDlpYWduzYwbJly9BoNMTGxvLEE09wxhlncOKJJ5KZmSm9zoUQA5JGo2Hu3LlkZWWRlJTEqaeeynPPPUdiYiIOh4OlS5eya9curG62CusvWixWDIEhbt/eabWitFWgu93CpTXRrigKDkvnLfCcdhvWuhrMxfk0ZO6getNKmsv2ozocA2pxo+28kiVLllBeXk5aWho//vgjo0ePpri4mN9++42nnnpK2rUIIQakk08+mS1btnD33Xdz2223cfXVV2MwGAgNDWX9+vVs3LiRhoaGnh7mcZWXl4fG4IHW071E7O8V5OrhtXAxGFoT56qK2knxoOp0Yjc10FxWRGPubmq2rqNhz1YA1q5d6/bz9AcVFRWsXLmSjIwMEhISKCsr44wzzuD1119nwYIFfP/99yQmJvb0MIU4ruQQ0QFo5MiR/PLLLyxbtowHH3yQl19+mUceeYQZM2aQnZ1NTk4Ow4YNIzIyst8nKX/88UcAtw8sgdYKdHC/fQt0rHCry9iCuWgfzpYWHC1mHGYT9uam1sNQ2tHpvVA0WpwDpOeazWYjJyeH3NxcQkNDGTp0KM899xwLFy7kmmuuISsri+jo6J4ephBC9Ljg4GBeeOEF/va3v/HII48wduxYbrnlFm6//XbKy8tZsmQJSUlJJCQkoHOzrUlf5nQe7kJ4Cxz4fKO4exi4RgMaLQoqlspSir5ZiMPSgrOlGYe5CbvZ9IcWbRqtHr3eG4Dt27czceJEt8fYF7VVqu3ZswetVktKSgpff/01F198McOGDWPx4sWcfPLJPT1MIYTocVqtlltuuYWrr76a559/nosuuoiTTz7ZVc27cuVKoqOjSUlJwdvbu6eH2+0qKyuPqKAN3N9JBm2L5gqgUrzoA1S7rXVObm7C3mzC0dJMW9vV1gfX4OHpB4qCyTQwitpqa2vZs2cPdXV1JCUlkZWVxUUXXURNTQ1PPPEEV199NVo3d+EL0d/0/1mV+FOnn346Gzdu5Msvv+Thhx/m2Wef5YknnmD8+PHs2LGDzMxMhgwZQlRUFBpN/9ys0HZAp7v91qB1xVtRlHb9ULv2+8q4gtrQhN7hi1briV4fhD7UB4PeG73BF4OHEQ+DEYOHHzqdB4UFq8jL+QWn09lv/w0sFgu5ubns27cPf39/0tLSeOutt3jhhRc4++yz2bZtG8nJyT09TCGE6HUGDx7M+++/z3333cdDDz3E6NGjue+++7jqqqsoLCwkNzeXhIQEBg8ejMHgfoVWX1JZWYnqdBzmxNtK2wT5sCrXdDq0qhOH1Ya2ogkPrQdaXSiGgHj0YT7o9T54eBgxGIwYPIzo9T6YzZVsWv8cW7Zs6bcJdKfTyf79+8nOzsbpdDJkyBBWrVrF9ddfj7+/PwsXLuSss87q90UZQghxuHx8fHj44Ye55ZZbeOqpp5gyZQoXXnghDz30EBaLhaVLlxIdHc2QIUMwGo09Pdxu02Q24xU+yO3bdzgM/LBauBhaW7g5NShldRj0Puh0/uh9o9AH+WAw+LTG8APzcoPBiEajZd3qpykqKjqs19SXqKpKdXU12dnZVFdXM3jwYJxOJzfddBM7d+7k4Ycf5tZbb8XT07OnhypEj5IE+gCnKAqzZ8/mggsu4N133+Wuu+4iOjqaf/zjHwwdOpQ9e/awZ88ekpKSGDRoUL9bbczKykLR6tB6u7+N2GmzoqgqyuEE6wMVblqthpDgFJKHXdDxMZ12rNYmrNZGzOYq6mr30dJSS11dPqrqJDc3lyFDhrj9fH2B2WwmJyeHwsJCgoODSUtL45NPPmH+/PmMHj2aFStWMH78+J4ephBC9HojRozghx9+YNWqVTzwwAO88sorPPjgg5x//vmUlJSQnZ3N4MGDSUxM7HeTn++//x4Aw+HsJLNZXAVmh7MYruj0KHYrOq0Ho8bc0OF7qurEZjNjtZqwWhoxNZbS0lJHc3MVADt37nT7efoKu91OQUEBOTk56HQ6EhMT2bx5M7NmzcJkMvGvf/2LK664ot8WAAghxLESHBzMf/7zH/7617/y2GOPMX78eK6//npuu+02rFYrK1asIDw8nCFDhhAYGNjTwz3mHE4n+sM5y6R9Av2wDhHVAwqoDpKHXYivb4Tre6qq4nBYsFoasVpN1NcVYrHU09JSi8NhpaSkxO3n6StUVaW8vJysrCwaGxtJSEhAo9Hwz3/+k8WLF/O3v/2Nb7/9Fn9//54eqhC9giTQBdB6OvhNN93EVVddxSuvvMLNN99MWFgYDzzwACeffDL79u0jMzOTxMRE4uPj0R9GoOrNysrK0PsFuF0VpapOVLsNRaNBcxjVfG0nfms0Gqqr9vDblgoc9hZsNjM2mxmn0/aH+2g0Wjw8PBg3bly/6i/W0NBATk4OxcXFREZGkpKSwv/+9z9eeeUVhg8fzieffML06dOlUk0IIQ7Taaedxrp16/juu+948skn+de//sWdd97JlVdeSWVlJb/++iuxsbEMGTIEHx+fnh7uMbF69WrA/YPHAByWFhRUVH6Pz+7Q6A1gt2KzNbEt/W3s9hbs9mZsNjN2+x/7oiuKBoPeQHh4OPfee6/bz9PbWa1W9u3bR15eHt7e3iQnJ7N06VJuvfVWzGYz999/PzfddBMeHh49PVQhhOhTBg0axLvvvss999zDE088wZgxY7jsssu488470ev1rF27lsDAQIYOHUpISEi/mC81NzejOhwY/N1fGOjYwuVwitp+v23m7q8BFfuBObnd3oyqHnwWnIJOp8fHx4u7777b7efp7ZxOJyUlJWRlZWG1WklISMBms3HXXXexevVqbrzxRrKzs4mMjOzpoQrRq0gCXXTg7e3Nfffdx+23386CBQv4xz/+gUaj4b777mPmzJkUFha6Ktni4+P7/InLDQ0N6GMS3L69amtNdKuq6jrF2x1tK+NJSUmUlJTg5dmMt7c3RmMYISEhhIeHEx0dTVJSEikpKaSmphIS4v6BaL2dqqrU1NSQk5NDRUUFsbGxJCYm8tprr/HOO+8wZcoUFi1axKRJk3p6qEII0acpisL555/PrFmzWLJkCf/+97+ZP38+t9xyC3PnzqWxsZFly5YRGRlJYmJin69ky8jIAEVB7xfg9n2clvZbvw+jHZtOj8HDA6PRiFbbiL+/Nz4+AQQFBREWFkZUVBSDBw8mOTmZYcOGERcX16+qr81mM3l5eeTn5xMYGEhKSgrffPMNV111FT4+Pjz00ENcccUV/bZdkBBCHC9paWl8+umnZGdnM3/+fE466STOPvts7r33XoKCgti8eTM+Pj4kJSURGRnZp2PNr7/+CoDe/zAq0G0WUDSgOg8vjusNgMqQIUOpqanG29sbb+8gAgISCAsLIzw8nPj4eIYMGUJKSgrJycn9ajHYZrOxf/9+cnNzAUhMTGTHjh3MmTOH3bt3c8cdd/D+++8TGhrawyMVoneSBLrolJeXF/PmzWPu3Ll8+umnPP300zz++OPcdddd/OUvf6GsrIwlS5YQERFBQkICQUFBfXIF3OZwQm015Su+R+8fhN7oj87HD52PEZ2PL4q243+RDtvFDmOC2NZjNSkpid27dx+bwfcBdrud4uJi8vLyaG5uZtCgQURHR/Pcc8/x6aefcsEFF7Bu3TpGjRrV00MVQoh+RVEUpk+fzvTp09mwYQNPPfUUI0eO5JprruH2229HVVXWrl2L0WgkISGBqKioPtmmrbi4GEWjoXzZd+j9gtD7BaDzbYvjRjSGP058ndYW12cWdw8RBVAMHii2Zqqqqo7Z+Hs7VVWprKxk3759VFRUEB4ezrBhw/jwww958cUXiY+P5/nnn+eCCy7okz8/QgjRmw0ZMoS33nqLRx99lGeffZYZM2YwceJE7r//fqKioti9ezcZGRnEx8cTFxfXJ9u0LV++HIC6nZtoqShB7xeA3tcfne+BOO7p/Yc8g9PaeiaZqh5eBbqi16OqKllZmcf0NfR2jY2N5OfnU1hY6Fp4WbNmDXfffTeVlZXcfffd/Pzzz/j5+fX0UIXo1SSBLg5Jp9Nx5ZVXcvnll/P999/z1FNP8dRTT3HDDTcwZ84coPUgTi8vL+Lj44mJiekz7V2cTieqw4HG4sC0/TcsLQ1w0LYtjcETnZcvWm9vNB6ecGB1X+XwDh5r65fe2Nh4zMbfmzU2NlJQUEBhYSFeXl7ExcWRmZnJQw89xK+//srVV1/Nzp07+11fdyGE6I0mTpzIt99+S0ZGBk8//TTjxo3jvPPOY968ecTExJCZmUlGRgZxcXHExcX1qfYuTqcTrcZA85691LXU4XR0bImm6PToPH3Qevui8fRE6+GJta4araKgaHWHtfiv0Ruw2f7Ycq0/slqt7N+/n/z8fKxWK/Hx8Xh4ePDOO++wYMECxo8fz8cff8y0adP6ZAGFEEL0JTExMTz77LM8/PDDvPTSS1x22WUkJCRw++23M2XKFFc7jqioKOLj4/tUcVtDQwMAzpJKavNysNvMHW+g0bTGcS8ftF7eaDw8sNZWwYHXdzg90DU6A6jqMRt7b+Z0OikrKyM/P5/q6mqioqJISUnhq6++4rrrrkNRFO677z6uu+66PrnwIkRPkAS6cItGo2HWrFmcd955rFmzhpdeeomxY8dy5plnMm/ePOLj4yksLGTXrl3ExMQQHx+Pv79/rw7crVuXVBITzyIsfDhOpwObrQmrxYTV2np4iM3ahNXWhM3ahMNswWJpOBCslcNb7dZqQVFoamrqttfT0xwOhytI19TUEBUVxbBhw1i0aBG33HILdXV13HTTTbz++utER0f39HCFEGLAGT58OB988AH/+te/eOWVV7jkkkuIiYnhtttuY8aMGVRWVrJs2TJCQkKIi4sjIiKi128Lb2w0ERKSyrC02aiqir3tIE9rWyxvjeE2WxN2Swv2Jgs4nGj1WpzK4b02jcEDq8PRTa+k56mqSm1tLfn5+RQXFxMQEEBiYiLbtm3jzjvvZNWqVVxyySUsXbqUE088saeHK4QQA05wcDCPPfYY9957LwsXLuT//u//uO+++1xnmTkcDjZu3IiHhwfx8fHExsb2+rZa+/btQ6fz4sQJfwXAbre45uJWS2Pr/PxALLfbm7G3WLA2WdAADji8tqqG1gS6w+Hot7umzGYzBQUFFBQUoNFoXOfXvf7663z44YeMGzeO//u//+Oiiy5Cp5N0oBCHQ/7HiMOiKAqTJk1i0qRJFBUV8cYbbzBnzhyMRiM333wzF154ISaTiTVr1uDl5UVMTAwxMTG9spptw4YNAFRW7MRiqcPTMxCDhxEPgxFvn1C02j+uZtfV7mNr+pugKIdXgX6g0s1sNnd94z5EVVWqqqooKiqipKTE9WFNo9Hw+uuv8/HHH5OWlsY///lPLrnkkn7VQ04IIfqq+Ph4nnnmGR5//HE++ugjXn75Ze6//36uueYa5syZg6+vLxkZGWzfvp2oqChiY2MJDAzslYvizc0taLRlFOxbgadXAB4e/hgMvhj9otFqPTod88plj6AoymH1TYXWCnRnP6xcM5lMFBUVUVRUhNVqJSYmhuTkZD777DPeeustHA4Ht9xyC++//z7h4eE9PVwhhBjwfH19ue2227j11ltZunQpL730EiNHjmTmzJnMnTuXxMRE9u/fz+7duwkLCyMmJoaIiIhemTTev38/AHm5v+LpGYCnpz8GDz+8vUPw9x+E0sli966dH9NQl43DYT+sCvS2tm01NTX9qs+31WqlpKSEoqIiampqCA8PJyUlhZUrV/LYY4+xbds2rrzySmmdKsRRkgS6OGIxMTE8+eST/POf/+Trr7/mjTfe4J///CcXXXQRV199NUlJSZSWlpKZmUlgYCAxMTFER0f3mlXwc845h7CwcGqq91BRvpPWxiy/02gN6HXeGAw+6A2+6HSe2O3Nru+bC3Mp/eULFJ2+tcIc8PLwgPE3U7HmF1osVlBVVLsdp90GTifNzc30B/X19a7JttPpJDo6mmHDhrF48WIeeugh9uzZw5VXXsmqVasYM2ZMTw9XCCFEJ7y9vbnxxhu54YYb2LhxI6+//jqnnnoqY8eO5frrr2fq1Kk0NDSwYcMG9Hq9a1HcaDT29NBdTjttEuvWrWNf3q+oB7VhUxQter03eoMPBoMvOp0XOp0HTqcNVdXgtLRQ8vNnaHT61jNPFAVF0eDpoW+N5at/ocVqRbXbUR12Wsr24+wn+fOWlhaKi4spKiqioaGB8PBwkpKS2LZtG48//jjff/89p59+Oi+++CLnnHOOVKkJIUQvpCgK06ZNY9q0aRQWFvL2229z8803YzAYuOGGG1xVxnv27GHbtm1ERUURExNDSEhIr1kUnzt3Lo89+jiF+StR1YN3eSno9V7o9a3zcb3eG53OQH19YVtnVSrXLG5t06bTtbZbVRS8PAwd5uSq04lqt2GprgBaz0/p6wl0h8NBeXk5+/fvp6KiAn9/f6Kjo9HpdHz88ce89957REZGcsstt/Djjz8SEBDQ00MWos9TVLUfltKIHrN3717efvttPvroI5xOJ5dffjmXXHIJERERFBUVUVdXR3h4ODExMYSFhfWafunNzc3s2LGDPXv2kJOTQ35+PqWlpVRXV1NbW0uTqYkWixW7zUZgYCBl5WV4ePqjN3jjcNpRnQ5AxdPTgwXvvsZ1N9xKc3MLoKDR6NBodJibKhg5Yji//fZbT7/cI2IymSgtLaWoqIimpiYiIyMJDg5m48aNfPzxx/z000+MGTOGa6+9liuuuEIOIREdNDQ04O/vT21WAn7GY1v90tDoIHBoHvX19fJzJ8RRqqmp4f333+e9995j9+7dnHfeeVxxxRWMHj2aiooKysrKMBqNxMbGEhkZibe3d08PGWidSGZlZZGRkUF2djb79u2jqKiIqqoqamtraWhooKXFgs1qQ1EU/PyNVFXX4eUTgtNhx+m0AyqqquLl5cGCd18/EMstaDRaNBodVosJ1dmM1Wrt6Zd7RKxWK+Xl5RQVFVFZWUlwcDDR0dEUFhby6aef8umnn+Lj48NVV13FjTfeyODBg3t6yKKX6a5YLnFciGPHZrPx/fff8+677/LLL78wfvx4rrzySs4880zMZnPr4duKQkxMDFFRUQQEBPSKZLqqqpSVlbF161aysrLIy8ujsLCQyspKampqqK+vp9ncjMVqxW53MGLEcNJ/+w1fYySq6sTptNOa2lLx9DR0iOOKoqDR6HE67TQ3VbFx44Y+2YrM6XRSVVVFcXGxa/d3bGwsNpuNb7/9lg8++ICioiIuvPBC5s6dy6mnntor/m1F7yFx/OhIAl10C4fDwfLly/nwww/58ssviYqK4qqrruKCCy5Ar9dTXFyMyWQiJCSEiIgIIiIies0k3B1arY74hOnExU/ucL1Br2Hezcm89kYmVlvHSrgN6/5L8tAYtm7dejyHesRUVaWmpoaysjLKyspoamoiNDSUyMhIsrOz+fjjj/nyyy8JDw/nqquu4oorriApKamnhy16KUmgC9H37N69mw8//JAPP/yQxsZG/vKXv3DppZcSFxdHSUkJ1dXVGI1GVxzvLZNwdyQmJlJVbWfs+Hl/+N6fxfLc7J8oLdmI1dpyPId6VEwmE2VlZZSXl1NdXY2fnx/R0dGYTCa++uorPvroI2pra7nkkku46qqrOOWUU3p933vRc2TiLUTfUlVVxWeffcaHH37I5s2bmTlzJldccQUTJ06kurqasrIytFqtK46Hhob2yjYvnbnzzjt58cUXmTTlMXS6jm1C/yyO19bmsS39LRYvXsz06dOP95CPSNvid1lZGRUVFeh0OiIjI/Hx8WHx4sV8+OGHbNq0iRkzZnDVVVcxa9asPpVXEceXxPGjI/sxRbfQarWu7WSvvvoqixYt4oMPPuCJJ55g/PjxzJ49m2nTpuHt7U1paSkZGRl9ahLudDppqC+kaP96tBo9ikYDKHh66oFkKip20NJiA1XFqdpxOmw47BZaWnr3pNtut7sqDMvLywEIDw9nyJAhZGdn8/nnn/PZZ59hs9m47LLLWLJkCePGjevV/1ZCCCGOTGpqKv/v//0/nnzySdatW8eHH37IRRddhL+/P5deeilnnXUW8fHxVFZWsm7duj41CbdYLNisLRQVrkOj1aFR2lq4KHh4tMby8vLtWCw2nE4HTqedxsYSnM7efYjowYvfZrOZkJAQIiMj8fLyYsmSJXz22WdkZGRw3nnn8d///pezzjpLzigRQoh+KCQkhFtvvZVbb72V3NxcPvroIx577DFKSkq48MILOf/88xkzZgyNjY3s3LkTi8VCaGgoERERhIeH4+np2dMv4U81NjYCUFK8Ca3WgEajQ1E0HeJ425y8tULdhrmpCmjdbdebtS1+l5WVUVNTg5+fnytHsmbNGl599VV+/vlnxo4dy5VXXsnXX3/d51vSCNEXSAW6OK6qqqr44osv+Oabb1i+fDmJiYnMmjWLs88+m7i4OCorK6moqECj0RAaGkpwcDAhISH4+Pj0qiRtWGg4lVWVHNw33cvLi48//pjLL7/8oH7nrWO/5Zabee21147fQLvgdDqpra2lqqqKqqoqampq8Pb2du0I2LhxI99//z0//vgjer2ec889l9mzZzN9+nTphyoOi1SgC9E/WK1WfvrpJ7788kt++OEHtFot55xzDueeey5jxoxxTfosFosrhgcHBxMQENCrKpv/8pe/8MUXX7q2e7fXeSxvjeNxcXHk5+87voM9BFVVMZlMrjheVdWaHAgPDyckJISsrCx++uknvvvuO4qKipg2bRoXXHABF198sfRDFYdNKteE6PtUVSU9PZ1PP/2U7777joKCAs444wzOO+88pkyZgkajoaysjLq6Ovz9/QkJCSEkJISgoKBe034V4PPPP+eyyy7H6XRyOHNyg95Axq6dDBky5LiO91BaWlqorq6mqqqKyspKmpubCQkJITw8nPr6ehYvXsyiRYvYsGEDY8aMYdasWVx++eUkJib29NBFHyNx/OhIAl30mIaGBlcw+OGHH1AUhXPPPZdzzjmHcePG0dLS4updajAYXME7ODi4VyTUnU4nFosFk8mE2WzG6XRitVrZu3cvw4YNw2AwoNVq8fPzw8vLC71e3yvG3JYwr66upqamBp1O50pyNDU1sWzZMhYtWsTKlStJTk5m1qxZnHfeeZx44om9Kvkh+hZJoAvR/9jtdtavX893333HokWLyM/P5/TTT3dNwg0Gg2tC6HQ6XbEmJCQEf3//Ho8pqqpitVoxm82YTCbsdrsrtmdnZ5OWloZer8fHxwcfHx88PDx6xZjbJ8yrq6ux2WwEBQUREhKCXq9n06ZNLFq0iJ9++gm9Xs95553HrFmzXDv/hDhSMvEWov/JzMxk0aJFfPfdd6xbt45Ro0Zx3nnnceaZZxIZGemaO5rN5l6ZULfb7ZjNZhobG7Hb7djtdlccT01NxWAwYDAY8PPzw9PTs1fsjrNYLB0Wvk0mE/7+/gQHB+Pv709WVhY//vgjixYtci1+z5o1i3PPPZfIyMieHr7owySOHx1JoIteoW0S3ha8c3NzGTduHFOmTOG0004jJSXFFWjaEupBQUEEBATg7+9PQEAABoOhp18GNpuNH3/8kbPPPrvHP1CoqorZbKaurs51qa2tRavVuj74mM1mtmzZwsqVK1mxYgX79+9n8uTJrqS5HCAmjhVJoAvR/2VlZbni+Nq1a0lMTGTKlClMnjyZMWPGoNfrOyTU2+J428XLy6vHF5qhd8Vyi8VCfX29K47X1NR0SJgbDAZ27tzJ6tWrWbFiBb/99hupqanMmjWLWbNmMX78+B5P+ov+QybeQvRv1dXV/Pjjj3z33Xf88ssveHh4MHnyZKZMmcLEiRMJDQ2lpqaG6upqV0I9MDDQNR83Go29Iub0pjhut9tpaGigrq6O+vp6amtraWxs7JAwLygoYO3ataxYsYI1a9bg6+vLueeeK4vf4piTOH50JIEueqWCggJXUrctsTt+/HimTJnCpEmTSElJwWazuQKR2WzG29u7Q0Ld39//uPf07KlgraoqTU1NrvejbaLtdDoxGo2u5MTBCfOCggLX+zplyhROPvlkjEbjcRu3GDgkgS7EwFJXV8eaNWtccXzr1q0kJSV1SKh7eHi44lVjYyN6vd4Vw9viuLe393FPqvdELFdV9Q/J8vr6epqbm/Hx8XG9H1qtloyMjA4J87aFirb3Njo6+riMWQw8MvEWYuCw2Wxs2bLFFcfXrFmDt7e3K95MnDiRsLAwV9yqr6/H6XTi5+fXYXHc19f3uFd999ScvH2yvO1iMpnQ6/Wu98PHx+cPCXNPT0/XQsWUKVNIS0vrFQsRov+ROH50JIEu+oSDE+qFhYWkpaUxduxYxo4dywknnMCgQYNcSfW6ujrMZjN6vR5fX198fX3x8fHp8HV39PDuzmDdttXcZDK5Lk1NTa4/AdcHFn9/fywWC1lZWWzdupX09HTS09MpKyuThLnoEZJAF2Jg6yyhHhsb64rjo0aNYujQoWi1WtdkvKGhAUVR/hDD2/5uMBi6JbnenbHcbrd3iN/t47nNZnMlywMCAtBqtRQUFLB9+3ZXHN+7d68kzEWPkYm3EANXZwl1Dw8PxowZw9ixYxkzZgwpKSkEBQV1SKrb7Xa8vb07nZN3186z7ozjTqfT1frt4Hje0tKCh4eHqxjA19eXsrIyMjIy+O2330hPT2fbtm14e3tLwlz0CInjR0cS6KJP2r9/P1u2bHFNKNPT06mpqWHYsGGuyXhaWhrR0dF4e3t3CHJtfU49PT3x9vbG09MTDw8PPD09O1w8PDwOe3J+pMG6redqS0tLh0v765qamlzjbp9EMBgMVFVV/WGSXVpaytChQ13vR9sHG0mYi54gCXQhRHv19fUdYnh6ejo5OTkdkuojR45k0KBBBAcH09LS4pqoNjY2YrFY0Ov1eHt74+Xl1SGOH/z14U5KjySWty1y/1kMb2lpobm5mZaWFtfiflsSwcfHh8bGRoqLi8nIyOiQLI+IiOgQx8eOHUtUVNSRvOVCHDWZeAsh2litVnbu3Nkhju/YsQMfHx/GjBnjuiQmJhIeHo7T6eyQbDabzSiKgo+Pzx/m4Af//XAL3440jtvt9j+N4RaLhebm5g7jbr8o4HA4KCkpISsry5Us3759O1qtltGjR3eI48nJyZIwFz1C4vjRkQS66BdUVaWoqKhDAN+1axeFhYUYjUaGDh3qugwZMoT4+HiioqLQ6/V/Otm12+0oioJOp3NdtFpth7/rdDo0Gg2KoqAoCk6nk7y8PBISEtBoNKiqiqqqOBwO16EmnV0cDgeA6wPDwR8c9Ho9DQ0NFBcXk5ubS1ZWluuSl5eHTqcjKSmJUaNGuQLz6NGjJVkueg1JoAshulJXV9dh19T27dvJyckBIDExsUMsT0hIIDo6GqPR6IrdB092rVYrwJ/G7/axvS2OAx1iuaIoqKqK0+k8ZAy32+2oqopOp/vDgrynpycGgwGr1UpJSQn79u0jOzvbFcezs7Mxm80MGjSIESNGdJhky2FhojeRibcQ4lCsVmuHheDffvuNvXv30tjYSGxsbIc4npSURGxsLCEhIR0S1wfPzVVVdcXwP4vlWq3WlZA+eE7ePrYfKoa3HSSu0Wj+NKGvqioVFRUUFhZ2iONZWVlUVlYSGhraoaBv7NixDBkypFccXCoESBw/WpJAF/2a2Wz+Q8K57VJVVYWvry+RkZFERUURGRnZ4RIeHo6/vz9eXl6u6jaNRvOHoOt0OgFcifLCwkLi4uI6JNYPDvYajQabzdahury6upry8nJKS0s7XEpKSigrK8PpdBIfH9/hg0fbgkBsbKwEZtGrSQJdCHEk7HY7hYWFncbxwsJC9Ho9ERERrtjdPp6Hh4cTFBTkqlL39PREp9O5Jsvt/2xb8AY6xPK22No+jmu1WvR6PXa73VWR1tzcTF1dHRUVFZSUlHQay81mM+Hh4Z3G8cTERDw9PXvyrRaiSzLxFkIcrrakc2dxPCcnB5vNRlhY2B/m4lFRUURERBASEoKvry+enp54eXlhMBhc1eLtL13FcY1G84ekO+BafG9ubqahoYHKykrKyspcsbt9LK+pqcHHx+cPcbwtlgcGBvbY+yyEOySOHx1JoIsBq7a2lpKSkg6B8eAgWVFRgclkcgVjg8GAr68vRqMRo9HoCuYajcaVMK+trSUgIMBVseZwODCbzTQ2NtLY2OjattaWeNfpdPj7+//hA8PBf4+Ojj7uh6IKcaxIAl0Icaw1NzdTXFzcafxu+3tZWRkNDQ3Y7XagNRHetuW6LY57e3u7qtfaYnl1dTUBAQE4nU6cTqerhUxbHG9sbMRmswGt1W5Go5GwsLBO43fb19HR0fj7+/fkWybEUZGJtxDiWGpre/Jnc/G2v9fV1dHS0uK6n4+PjyuGG41G1/lmGo3GtausLY63zcltNluHGG4ymWhubnY9pre3N8HBwX86F2+/OH+8DzcX4liROH50jv0pikL0EYGBgQQGBpKWlnbI2zmdTpqbmzskwNu+bmxsxGq1uibYbZf2E3GNRoO3t3eHpHv7ryUpLoQQQhw+Ly8vkpKSSEpKOuTtVFXFYrF0iN/tJ9Bms7lDDHc4HB1ieNt27oPjd/sEvEymhRBCiMOj1WqJjY0lNja2y9vabDZXIVpnsdzhcBwyjut0uk7n4m0JeNnNLYToiiTQheiCRqPBx8cHHx8fIiIieno4QgghhDgMiqK4+peGhIT09HCEEEIIcZj0er2rAE4IIXqCHP0rhBBCCCGEEEIIIYQQQnRCEuhCCCGEEEIIIYQQQgghRCckgS6EEEIIIYQQQgghhBBCdEIS6EIIIYQQQgghhBBCCCFEJySBLoQQQgghhBBCCCGEEEJ0QhLoQgghhBBCCCGEEEIIIUQnJIEuhBBCCCGEEEIIIYQQQnRCEuhCCCGEEEIIIYQQQgghRCckgS6EEEIIIYQQQgghhBBCdEIS6EIIIYQQQgghhBBCCCFEJySBLoQQQgghhBBCCCGEEEJ0QhLoQgghhBBCCCGEEEIIIUQnJIEuxDFSWVnJvHnzGDRoEB4eHkRERHDmmWeydu3anh6aEEIIIbogcVwIIYTouySOCyG6k66nByBEf3HxxRdjtVpZuHAhCQkJlJeXs3TpUqqrq3t6aEIIIYTogsRxIYQQou+SOC6E6E6SQBfiGKirq2P16tWsWLGCyZMnAxAXF8eJJ57YwyMTQgghRFckjgshhBB9l8RxIUR3kxYuQhwDvr6++Pr68s0332CxWHp6OEIIIYQ4DBLHhRBCiL5L4rgQortJAl2IY0Cn07FgwQIWLlxIQEAAp5xyCn//+9/ZsWNHTw9NCCGEEF2QOC6EEEL0XRLHhRDdTRLoQhwjF198MSUlJXz33XfMnDmTFStWMGbMGBYsWNDTQxNCCCFEFySOCyGEEH2XxHEhRHdSVFVVe3oQQvRXN954I7/++isFBQU9PRQhelRDQwP+/v7UZiXgZ9Qe28dudBA4NI/6+nr8/PyO6WMLIQY2ieNC/K67YrnEcSFEd5E4LsTvJI4fHalAF6Ibpaam0tTU1NPDEEIIIcQRkDguhBBC9F0Sx4UQx4qupwcgRH9QXV3NJZdcwvXXX8+IESMwGo1s2bKF+fPnc/755/f08IQQQghxCBLHhRBCiL5L4rgQortJAl2IY8DX15cJEybw3HPPkZubi81mIzY2lrlz5/L3v/+9p4cnhBBCiEOQOC6EEEL0XRLHhRDdTXqgCyGE6HbSA10IIYTo26R3qhBCCNF3SRw/OtIDXQghhBBCCCGEEEIIIYTohCTQhRBCCCGEEEIIIYQQQohOSAJdCCGEEEIIIYQQQgghhOiEJNCFEEIIIYQQQgghhBBCiE5IAl0IIYQQQgghhBBCCCGE6IQk0IUQQgghhBBCCCGEEEKITkgCXQghhBBCCCGEEEIIIYTohCTQhRBCCCGEEEIIIYQQQohOSAJdCCGEEEIIIYQQQgghhOiEJNCFEEIIIYQQQgghhBBCiE5IAl0IIYQQQgghhBBCCCGE6IQk0IUQQgghhBBCCCGEEEKITkgCXQghhBBCCCGEEEIIIYTohCTQhRBCCCGEEEIIIYQQQohOSAJdCCGEEEIIIYQQQgghhOiEJNCFEEIIIYQQQgghhBBCiE5IAl0IIYQQQgghhBBCCCGE6IQk0IUQQgw4r7zyCvHx8Xh6ejJhwgQ2bdrU00MSQgghxGGQWC6EEEL0XX0tjksCXQghxIDy6aefcvfdd/Poo4/y22+/MXLkSM4880wqKip6emhCCCGEcIPEciGEEKLv6otxXBLoQgghBpRnn32WuXPnct1115Gamsrrr7+Ot7c37777bk8PTQghhBBukFguhBBC9F19MY7renoAQgghBo6GRme3PWZDQ0OH6z08PPDw8OhwndVqJT09nYceesh1nUajYdq0aaxfv/6Yj00IIYTob451LD+cOA4Sy4UQQoijIXH8yEgCXQghRLczGAxEREQQNza/Wx7f19eX2NjYDtc9+uijPPbYYx2uq6qqwuFwEB4e3uH68PBw9u7d2y1jE0IIIfqD7ozl7sZxkFguhBBCHAmJ40dHEuhCCCG6naenJ/v27cNqtXbL46uqiqIoHa7rbLVbCCGEEEemO2O5xHEhhBCie0kcPzqSQBdCCHFceHp64unp2aNjCAkJQavVUl5e3uH68vJyIiIiemhUQgghRN8gsVwIIYTouySOHzk5RFQIIcSAYTAYGDt2LEuXLnVd53Q6Wbp0KSeddFIPjkwIIYQQ7pBYLoQQQvRdfTWOSwW6EEKIAeXuu+/m2muvZdy4cZx44ok8//zzNDU1cd111/X00IQQQgjhBonlQgghRN/VF+O4JNCFEEIMKJdeeimVlZU88sgjlJWVMWrUKH7++ec/HGIihBBCiN5JYrkQQgjRd/XFOK6oqqr29CCEEEIIIYQQQgghhBBCiN5GeqALIYQQQgghhBBCCCGEEJ2QBLoQQgghhBBCCCGEEEII0QlJoAshhBBCCCGEEEIIIYQQnZAEuhBCCCGEEEIIIYQQQgjRCUmgCyGEEEIIIYQQQgghhBCdkAS6EEIIIYQQQgghhBBCCNEJSaALIYQQQgghhBBCCCGEEJ2QBLoQQgghhBBCCCGEEEII0QlJoAshhBBCCCGEEEIIIYQQnZAEuhBCCCGEEEIIIYQQQgjRCUmgCyGEEEIIIYQQQgghhBCd+P9sMVF4/hicdgAAAABJRU5ErkJggg==\",\n      \"text/plain\": [\n       \"<Figure size 1500x500 with 6 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Within FlorisModel, the is set to a separate wind rose per turbine\\n\",\n    \"fig, axarr = plt.subplots(1, 3, figsize=(15, 5), subplot_kw=dict(polar=True))\\n\",\n    \"fmodel.wind_data.plot_wind_roses(axarr=axarr)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 27,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"[2296892.47124259 2297743.68483228 2342752.51651458]\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# Can get the expected power for each turbine\\n\",\n    \"fmodel.run()\\n\",\n    \"print(fmodel.get_expected_turbine_powers())\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 28,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"6937388.672589453\\n\",\n      \"60771524771.883606\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"# Getting expected farm power and AEP weights each turbine by its own wind rose\\n\",\n    \"print(fmodel.get_expected_farm_power())\\n\",\n    \"print(fmodel.get_farm_AEP())\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 29,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Using point 0 at (0.0, 0.0) as reference location\\n\"\n     ]\n    },\n    {\n     \"data\": {\n      \"image/png\": \"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zQ0SiQS7du0qc5vjx4+jdevWUCgU8Pb2RlBQkMb7KpUKn376Kby8vGBubo4GDRrgyy+/hCAIVXMQRERUbYyt5uCMT0RERERERERElbBu3bpS3z9+/LjGcpcuXXDjxo1Stxk2bBiGDRtW5r7feustvPXWW2XGERGR/mDeICKiisrIyECLFi0wbtw4DBo0qMz48PBw9O3bF++88w42b96MI0eOYMKECXB1dUVAQAAAYNGiRVi9ejU2bNiAJk2a4NKlSxg7dixsbW3xv//9r6oPiYiIqpCx1Rwc+EREREREREREREREREREpKcCAwMRGBhY7vg1a9bAy8tLfMyQr68vTp8+jWXLlokDn86ePYsBAwagb9++AIB69eph69atuHDhgvYPgIiIqApx4BMRVas0lRmUqsp99GSplFrqDRER6TvmDSIiIiIiIiIiqqlSU1M1lhUKBRQKRaXbDQ4ORo8ePTTWBQQEYNq0aeJyhw4dsHbtWty5cweNGjXCP//8g9OnT2Pp0qWV3j8REVF14sAnIiIiIiIiIiIiIiIiIqJySFFZIE8lq1QbmSoVAMDDw0Nj/WeffYbPP/+8Um0DQExMDJydnTXWOTs7IzU1FVlZWTA3N8dHH32E1NRU+Pj4QCaTQaVSYcGCBRg5cmSl909ERFSdOPCJiIiIiIiIiIiIiIiIiKiaPXz4EDY2NuKyNmZ7Kq9t27Zh8+bN2LJlC5o0aYKQkBBMmzYNbm5uGD16dLX1g4iIqLI48ImIiIiIiIiIiIiIiIiIqJrZ2NhoDHzSFhcXF8TGxmqsi42NhY2NDczNzQEAM2fOxEcffYThw4cDAJo1a4YHDx5g4cKFHPhEREQGRarrDhARERERERERERERERERkXb4+/vjyJEjGusOHToEf39/cTkzMxNSqealYplMBrVaXS19JCIi0hbO+EREREREREREREREREREpKfS09Nx7949cTk8PBwhISGwt7dH3bp1MXv2bERFReGXX34BALzzzjv4/vvvMWvWLIwbNw5Hjx7Ftm3bsHfvXrGNfv36YcGCBahbty6aNGmCq1evYunSpRg3bly1Hx8REVFlcOATEREREREREREREREREZGeunTpErp16yYuz5gxAwAwevRoBAUFITo6GpGRkeL7Xl5e2Lt3L6ZPn47ly5fD3d0dP/30EwICAsSYFStW4NNPP8W7776LuLg4uLm54e2338bcuXOr78CIiIi0gAOfiIiIiIiIiIiIiIiIiIj0VNeuXSEIQonvBwUFFbvN1atXS9zG2toa3333Hb777jst9JCIiEh3pGWHEBERERERERERERERERERERER6RfO+ERE1SpdrYBSLa9UG9nqPC31hoiI9B3zBhEREREREREREREREZWEMz4REREREREREREREREREREREZHB4YxPRERERERERERERERERETlkC6YQaWu3CXWLEGppd4QERERZ3wiIiIiIiIiIiIiIiIiIiIiIiKDw4FPRERERERERERERERERERERERkcDjwiYiIiIiIiIiIiIiIiIiIiIiIDA4HPhERERERERERERERERERERERkcHhwCciIiIiIiIiIiIiIiIiIiIiIjI4HPhEREREREREREREREREREREREQGx0TXHSAi45KqtECOUl6pNnKUeVrqDRER6TvmDSIiIiIiIiIiIiIiIioJZ3wiIiIiIiIiIiIiIiIiIiIiIiKDo9OBTwsXLkTbtm1hbW0NJycnDBw4ELdv39aIyc7OxuTJk1G7dm1YWVlh8ODBiI2N1YiJjIxE3759YWFhAScnJ8ycORNKpVIj5vjx42jdujUUCgW8vb0RFBRU1YdHRERaxrxBREQVxdxBREQVwbxBREQVxdxBZHxSVBZIruQrRWWh68MgHWLuICLSLp0OfDpx4gQmT56Mc+fO4dChQ8jLy0OvXr2QkZEhxkyfPh1//fUXtm/fjhMnTuDx48cYNGiQ+L5KpULfvn2Rm5uLs2fPYsOGDQgKCsLcuXPFmPDwcPTt2xfdunVDSEgIpk2bhgkTJuDgwYPVcpypqakIDw9HampqteyP6Fn8GaSawljyBsDfW9It/vxRTcLcQVQ9+PNHNQXzBlH14c8g1RTMHUTVgz9/VJMYS+7g7y3pGn8GjYdEEARB150oEB8fDycnJ5w4cQKdO3dGSkoKHB0dsWXLFgwZMgQAcOvWLfj6+iI4OBjt27fH/v378corr+Dx48dwdnYGAKxZswYffvgh4uPjYWpqig8//BB79+7F9evXxX0NHz4cycnJOHDgQJn9Sk1Nha2tLVJSUmBjY1OhY7py5Qr++usvcblPnz5o27YtAEAQBOTl5ZW4rVQqhYmJSYVjASA3N1crsRKJBHK5/Lli8/LyUNKPV1XFAoCp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69X/+3//T71791ZqaqpycnK0ZMmSsDZfffWVJk+erJ49eyotLU3nn3++3nnnnbA2lZWVuuGGG5SZmalWrVrp0ksv1datW495vdLSUn3nO99R69at5fF49O1vf1s1NTXN88YBAI1GdgAAWsL3v/999ejRQ6mpqeratauuu+467d69+6TP2b59u37wgx+oc+fO8ng8uvLKK1VZWRnWZv369brkkkvUrl07dezYUbfccosOHjwYeryoqEiGYRz3tnfv3hZ5rwCA5kF2AABWrlypMWPGKDMzU4ZhaPHixfU+Z8WKFRoyZIhSUlLUp08fFRUVHdMmkvEvAED8cnrNwcQnAHHv2WefVUFBgWbMmKH169crJydH+fn5J/yynD59uv785z/rT3/6kz744ANNnDhRP/jBD7Rhw4ZQmwkTJqikpER//etf9f7772vkyJHKy8vTrl27JEmWZWns2LH6+OOP9dJLL2nDhg3q2bOn8vLyVF1dHdpPaWmpLr30Uo0cOVJr1qzRO++8o0mTJsk0+XoGADuRHQCAljJixAgtWrRIW7Zs0QsvvKDt27frRz/60QnbV1dXa+TIkTIMQ8uXL9ebb76puro6jRkzRoFAQJK0e/du5eXlqU+fPlq9erWWLFmiTZs26YYbbgjt56qrrtKePXvCbvn5+brooovUpUuXln7bAIAmIDsAANXV1crJydGCBQsa1L68vFyjR4/WiBEjVFZWpsmTJ2vChAlaunRpqE2k418AgPjl9JrDsCzLavS7TxBVVVVq27atDhw4II/HY3d3gKhrjt+B4D6G6zIlGe4m9cdnebVCLzW4P8OGDdM555yj+fPnS5ICgYCysrL005/+VNOmTTumfWZmpu666y7dfvvtoW2XX3650tLS9L//+7+qqalRmzZt9NJLL2n06NGhNkOHDtWoUaP029/+Vh999JH69u2rjRs3auDAgaHXzcjI0L333qsJEyZIks477zxdcskl+s1vftOkzwSxh+xAInN6bkhkB+xBdiCRxUN2NNY//vEPjR07VrW1tXK7j+33a6+9plGjRumLL74I9eXAgQNq3769XnvtNeXl5ekvf/mLfv3rX2vPnj2hibDvv/++Bg0apK1bt6pPnz7H7Hffvn3q1q2bHn/8cV133XUt+h7RMsgNJLqm/g44NTcksgONR3YgkTVnzTHC9cNmyY5/+f/e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zUc7OMrGpxb022+/RU1NTZ0XT0REUVFRVFZWttGo2o/S0tJYunRpvP3227Fw4cKoqKiIyy+/PKqrq6OysjLy8/OjsLCwzj3/XrvKysp61/boua7k6Hwb+12rrKyM008/vc757t27x6mnnmpNoR3RjobpRvPRDeg8dKNx2tF8tAM6D+1omG40L+2AzkE3GqcdzUc3oPPQjobpRvPSDo7q3tYDoOuaMmVK7v8XXnhhlJaWxtChQ2PZsmXRq1evNhwZAO2RbgCQlXYAkIVuAJCVdgCQhW5Ay/DFpxY0YMCAOOmkk2L37t11ju/evTuKi4vbaFTtV2FhYYwYMSK2b98excXFcejQoaiqqqpzzb/Xrri4uN61PXquKzk638Z+14qLi2PPnj11zh85ciT++OMPawrtiHYcP904cboBnYduZKMdJ047oPPQjuOnG02jHdA56EY22nHidAM6D+04frrRNNrBUTY+taD8/PwYO3ZsvPfee7ljtbW18d5778X48ePbcGTt019//RXff/99DBw4MMaOHRs9evSos3bbtm2LnTt35tZu/Pjx8fXXX9d5Ua1atSr69esXo0aNavXxt6Xhw4dHcXFxnfXat29frF+/vs56VVVVxcaNG3PXvP/++1FbWxulpaW5a1avXh2HDx/OXbNq1aoYOXJk9O/fv5VmA12bdhw/3ThxugGdh25kox0nTjug89CO46cbTaMd0DnoRjbaceJ0AzoP7Th+utE02kFOokWVl5ennj17pqVLl6atW7em2267LRUWFqbKysq2Hlqbu//++9OHH36YKioq0ieffJImTpyYBgwYkPbs2ZNSSumOO+5IQ4YMSe+//376/PPP0/jx49P48eNz9x85ciSdf/75adKkSemLL75Ib7/9djrttNPS3Llz22pKLaq6ujpt2rQpbdq0KUVEevLJJ9OmTZvSjh07UkoplZWVpcLCwvTaa6+lr776Kl177bVp+PDh6cCBA7lnXHXVVWnMmDFp/fr16eOPP07nnHNOmj59eu58VVVVKioqSjNnzkybN29O5eXlqaCgID333HOtPl/oyrSjfrqRjW5A16EbDdOObLQDug7tqJ9uZKcd0DXoRsO0IxvdgK5DO+qnG9lpB8fDxqdW8Mwzz6QhQ4ak/Pz8VFJSkj799NO2HlK7MG3atDRw4MCUn5+fBg8enKZNm5a2b9+e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\",\n      \"text/plain\": [\n       \"<Figure size 3000x500 with 12 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Use the get_heterogeneous_map method to generate a WindRose that represents\\n\",\n    \"# the information in the WindRoseWRG, rather than a set of WindRose objects\\n\",\n    \"# but as a  single WindRose object (for one location) and a HeterogeneousMap\\n\",\n    \"# the describes the speed up information per direction across the domain\\n\",\n    \"# This will allow running the optimization for a single wind speed while still\\n\",\n    \"# accounting for the difference in wind speeds in location by direction\\n\",\n    \"wind_rose_het = wind_rose_wrg.get_heterogeneous_wind_rose(\\n\",\n    \"    fmodel=fmodel,\\n\",\n    \"    x_loc=0.0,\\n\",\n    \"    y_loc=0.0,\\n\",\n    \"    representative_wind_speed=10.0,\\n\",\n    \")\\n\",\n    \"\\n\",\n    \"# Pull out the heterogeneous plot to show the underlying speedups\\n\",\n    \"het_map = wind_rose_het.heterogeneous_map\\n\",\n    \"wind_direction_to_plot = [0.0, 10.0, 45.0, 75.0, 90.0, 180.0]\\n\",\n    \"\\n\",\n    \"# Show the het_map for a few wind directions\\n\",\n    \"fig, axarr = plt.subplots(1, len(wind_direction_to_plot), figsize=(30, 5))\\n\",\n    \"axarr = axarr.flatten()\\n\",\n    \"for i, wd in enumerate(wind_direction_to_plot):\\n\",\n    \"    het_map.plot_single_speed_multiplier(\\n\",\n    \"        wind_direction=wd,\\n\",\n    \"        wind_speed=8.0,\\n\",\n    \"        ax=axarr[i],\\n\",\n    \"        show_colorbar=True,\\n\",\n    \"    )\\n\",\n    \"\\n\",\n    \"    axarr[i].set_title(f\\\"Wind Direction: {wd}\\\")\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"floris\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.11.9\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 4\n}\n"
  },
  {
    "path": "examples/001_opening_floris_computing_power.py",
    "content": "\"\"\"Example 1: Opening FLORIS and Computing Power\n\nThis example illustrates several of the key concepts in FLORIS. It demonstrates:\n\n  1) Initializing a FLORIS model\n  2) Changing the wind farm layout\n  3) Changing the incoming wind speed, wind direction and turbulence intensity\n  4) Running the FLORIS simulation\n  5) Getting the power output of the turbines\n\nMain concept is introduce FLORIS and illustrate essential structure of most-used FLORIS calls\n\"\"\"\n\n\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\n# The FlorisModel class is the entry point for most usage.\n# Initialize using an input yaml file\nfmodel = FlorisModel(\"inputs/gch.yaml\")\n\n# Changing the wind farm layout uses FLORIS' set method to a two-turbine layout\nfmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n\n# Changing wind speed, wind direction, and turbulence intensity uses the set method\n# as well. Note that the wind_speeds, wind_directions, and turbulence_intensities\n# are all specified as arrays of the same length.\nfmodel.set(\n    wind_directions=np.array([270.0]), wind_speeds=[8.0], turbulence_intensities=np.array([0.06])\n)\n\n# Note that typically all 3, wind_directions, wind_speeds and turbulence_intensities\n# must be supplied to set.  However, the exception is if not changing the length\n# of the arrays, then only one or two may be supplied.\nfmodel.set(turbulence_intensities=np.array([0.07]))\n\n# The number of elements in the wind_speeds, wind_directions, and turbulence_intensities\n# corresponds to the number of conditions to be simulated.  In FLORIS, each of these are\n# tracked by a simple index called a findex.  There is no requirement that the values\n# be unique.  Internally in FLORIS, most data structures will have the findex as their\n# 0th dimension.  The value n_findex is the total number of conditions to be simulated.\n# This command would simulate 4 conditions (n_findex = 4).\nfmodel.set(\n    wind_directions=np.array([270.0, 270.0, 270.0, 270.0]),\n    wind_speeds=[8.0, 8.0, 10.0, 10.0],\n    turbulence_intensities=np.array([0.06, 0.06, 0.06, 0.06]),\n)\n\n# After the set method, the run method is called to perform the simulation\nfmodel.run()\n\n# There are functions to get either the power of each turbine, or the farm power\nturbine_powers = fmodel.get_turbine_powers() / 1000.0\nfarm_power = fmodel.get_farm_power() / 1000.0\n\nprint(\"The turbine power matrix should be of dimensions 4 (n_findex) X 2 (n_turbines)\")\nprint(turbine_powers)\nprint(\"Shape: \", turbine_powers.shape)\n\nprint(\"The farm power should be a 1D array of length 4 (n_findex)\")\nprint(farm_power)\nprint(\"Shape: \", farm_power.shape)\n"
  },
  {
    "path": "examples/002_visualizations.py",
    "content": "\"\"\"Example 2: Visualizations\n\nThis example demonstrates the use of the flow and layout visualizations in FLORIS.\nFirst, an example wind farm layout is plotted, with the turbine names and the directions\nand distances between turbines shown in different configurations by subplot.\nNext, the horizontal flow field at hub height is plotted for a single wind condition.\n\nFLORIS includes two modules for visualization:\n  1) flow_visualization: for visualizing the flow field\n  2) layout_visualization: for visualizing the layout of the wind farm\nThe two modules can be used together to visualize the flow field and the layout\nof the wind farm.\n\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\n\nimport floris.layout_visualization as layoutviz\nfrom floris import FlorisModel\nfrom floris.flow_visualization import visualize_cut_plane\n\n\nfmodel = FlorisModel(\"inputs/gch.yaml\")\n\n# Set the farm layout to have 8 turbines irregularly placed\nlayout_x = [0, 500, 0, 128, 1000, 900, 1500, 1250]\nlayout_y = [0, 300, 750, 1400, 0, 567, 888, 1450]\nfmodel.set(layout_x=layout_x, layout_y=layout_y)\n\n\n# Layout visualization contains the functions for visualizing the layout:\n# plot_turbine_points\n# plot_turbine_labels\n# plot_turbine_rotors\n# plot_waking_directions\n# Each of which can be overlaid to provide further information about the layout\n# This series of 4 subplots shows the different ways to visualize the layout\n\n# Create the plotting objects using matplotlib\nfig, axarr = plt.subplots(2, 2, figsize=(15, 10), sharex=False)\naxarr = axarr.flatten()\n\nax = axarr[0]\nlayoutviz.plot_turbine_points(fmodel, ax=ax)\nax.set_title(\"Turbine Points\")\n\nax = axarr[1]\nlayoutviz.plot_turbine_points(fmodel, ax=ax)\nlayoutviz.plot_turbine_labels(fmodel, ax=ax)\nax.set_title(\"Turbine Points and Labels\")\n\nax = axarr[2]\nlayoutviz.plot_turbine_points(fmodel, ax=ax)\nlayoutviz.plot_turbine_labels(fmodel, ax=ax)\nlayoutviz.plot_waking_directions(fmodel, ax=ax, limit_num=2)\nax.set_title(\"Turbine Points, Labels, and Waking Directions\")\n\n# In the final subplot, use provided turbine names in place of the t_index\nax = axarr[3]\nturbine_names = [\"T1\", \"T2\", \"T3\", \"T4\", \"T9\", \"T10\", \"T75\", \"T78\"]\nlayoutviz.plot_turbine_points(fmodel, ax=ax)\nlayoutviz.plot_turbine_labels(fmodel, ax=ax, turbine_names=turbine_names)\nlayoutviz.plot_waking_directions(fmodel, ax=ax, limit_num=2)\nax.set_title(\"Use Provided Turbine Names\")\n\n\n# Visualizations of the flow field are made by using calculate plane methods.  In this example\n# we show the horizontal plane at hub height, further examples are provided within\n# the examples_visualizations folder\n\n# For flow visualizations, the FlorisModel may be set to run a single condition\n# (n_findex = 1). Otherwise, the user may set multiple conditions and then use\n# the findex_for_viz keyword argument to calculate_horizontal_plane to specify which\n# flow condition to visualize.\nfmodel.set(wind_speeds=[8.0], wind_directions=[290.0], turbulence_intensities=[0.06])\nhorizontal_plane = fmodel.calculate_horizontal_plane(\n    x_resolution=200,\n    y_resolution=100,\n    height=90.0,\n)\n\n# Plot the flow field with rotors\nfig, ax = plt.subplots()\nvisualize_cut_plane(\n    horizontal_plane,\n    ax=ax,\n    label_contours=False,\n    title=\"Horizontal Flow with Turbine Rotors and labels\",\n)\n\n# Plot the turbine rotors\nlayoutviz.plot_turbine_rotors(fmodel, ax=ax)\nlayoutviz.plot_turbine_labels(fmodel, ax=ax, turbine_names=turbine_names)\n\nplt.show()\n"
  },
  {
    "path": "examples/003_wind_data_objects.py",
    "content": "\"\"\"Example 3: Wind Data Objects\n\nThis example demonstrates the use of wind data objects in FLORIS:\n TimeSeries, WindRose, and WindTIRose.\n\n For each of the WindData objects, examples are shown of:\n\n    1) Initializing the object\n    2) Broadcasting values\n    3) Converting between objects\n    4) Setting TI and value\n    5) Plotting\n    6) Setting the FLORIS model using the object\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n    WindTIRose,\n)\n\n\n##################################################\n# Initializing\n##################################################\n\n# FLORIS provides a set of wind data objects to hold the ambient wind conditions in a\n# convenient classes that include capabilities and methods to manipulate and visualize\n# the data.\n\n# The TimeSeries class is used to hold time series data, such as wind speed, wind direction,\n# and turbulence intensity.\n\n# There is also a \"value\" wind data variable, which represents the value of the power\n# generated at each time step or wind condition (e.g., the price of electricity). This can\n# then be used in later optimization methods to optimize for quantities besides AEP.\n\n# Generate wind speeds, directions, turbulence intensities, and values via random signals\nN = 100\nrng = np.random.default_rng(0)\nwind_speeds = 8 + 2 * rng.standard_normal(N)\nwind_directions = 270 + 30 * rng.standard_normal(N)\nturbulence_intensities = 0.06 + 0.02 * rng.standard_normal(N)\nvalues = 25 + 10 * rng.standard_normal(N)\n\ntime_series = TimeSeries(\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    turbulence_intensities=turbulence_intensities,\n    values=values,\n)\n\n# The WindRose class is used to hold wind rose data, such as wind speed, wind direction,\n# and frequency.  TI and value are represented as bin averages per wind direction and\n# speed bin.\nwind_directions = np.arange(0, 360, 3.0)\nwind_speeds = np.arange(4, 20, 2.0)\n\n# Make TI table 6% TI for all wind directions and speeds\nti_table = 0.06 * np.ones((len(wind_directions), len(wind_speeds)))\n\n# Make value table 25 for all wind directions and speeds\nvalue_table = 25 * np.ones((len(wind_directions), len(wind_speeds)))\n\n# Uniform frequency\nfreq_table = np.ones((len(wind_directions), len(wind_speeds)))\nfreq_table = freq_table / np.sum(freq_table)\n\nwind_rose = WindRose(\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    ti_table=ti_table,\n    freq_table=freq_table,\n    value_table=value_table,\n)\n\n# The WindTIRose class is similar to the WindRose table except that TI is also binned\n# making the frequency table a 3D array.\nturbulence_intensities = np.arange(0.05, 0.15, 0.01)\n\n# Uniform frequency\nfreq_table = np.ones((len(wind_directions), len(wind_speeds), len(turbulence_intensities)))\n\n# Uniform value\nvalue_table = 25 * np.ones((len(wind_directions), len(wind_speeds), len(turbulence_intensities)))\n\nwind_ti_rose = WindTIRose(\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    turbulence_intensities=turbulence_intensities,\n    freq_table=freq_table,\n    value_table=value_table,\n)\n\n##################################################\n# Broadcasting\n##################################################\n\n# A convenience method of the wind data objects is that, unlike the lower-level\n# FlorisModel.set() method, the wind data objects can broadcast upward data provided\n# as a scalar to the full array.  This is useful for setting the same wind conditions\n# for all turbines in a wind farm.\n\n# For TimeSeries, as long as one condition is given as an array, the other 2\n# conditions can be given as scalars.  The TimeSeries object will broadcast the\n# scalars to the full array (uniform)\nwind_directions = 270 + 30 * rng.standard_normal(N)\ntime_series = TimeSeries(\n    wind_directions=wind_directions, wind_speeds=8.0, turbulence_intensities=0.06\n)\n\n\n# For WindRose, wind directions and wind speeds must be given as arrays, but the\n# ti_table can be supplied as a scalar which will apply uniformly to all wind\n# directions and speeds.  Not supplying a freq table will similarly generate\n# a uniform frequency table.\nwind_directions = np.arange(0, 360, 3.0)\nwind_speeds = np.arange(4, 20, 2.0)\nwind_rose = WindRose(wind_directions=wind_directions, wind_speeds=wind_speeds, ti_table=0.06)\n\n\n##################################################\n# Wind Rose from Time Series\n##################################################\n\n# The TimeSeries class has a method to generate a wind rose from a time series based on binning\nwind_rose = time_series.to_WindRose(wd_edges=np.arange(0, 360, 3.0), ws_edges=np.arange(2, 20, 2.0))\n\n##################################################\n# Wind Rose from long CSV FILE\n##################################################\n\n# The WindRose class can also be initialized from a long CSV file.  By long what is meant is\n# that the file has a column for each wind direction, wind speed combination.  The file can\n# also specify the mean TI per bin and the frequency of each bin as seperate columns.\n\n# If the TI is not provided, can specify a fixed TI for all bins using the ti_col_or_value\n# input\nwind_rose_from_csv = WindRose.read_csv_long(\n    \"inputs/wind_rose.csv\", wd_col=\"wd\", ws_col=\"ws\", freq_col=\"freq_val\", ti_col_or_value=0.06\n)\n\n##################################################\n# Aggregating and Resampling the Wind Rose\n##################################################\n\n# The downsample function allows for aggregation of the wind rose data into\n# fewer wind direction and wind speed bins.\n# Note it will throw an error if the step sizes passed in are smaller than the\n# step sizes of the original data.\nwind_rose_aggregate = wind_rose.downsample(wd_step=10, ws_step=2)\n\n# For upsampling, the upsample function can be used to interpolate\n# the wind rose data to a finer grid.  It can use either linear or nearest neighbor\nwind_rose_resample = wind_rose.upsample(wd_step=0.5, ws_step=0.25)\n\n##################################################\n# Setting turbulence intensity\n##################################################\n\n# Each of the wind data objects also has the ability to set the turbulence intensity\n# according to a function of wind speed and direction.  This can be done using a custom\n# function by using the assign_ti_using_wd_ws_function method. There is also a method\n# called assign_ti_using_IEC_method which assigns TI based on the IEC 61400-1 standard.\nwind_rose.assign_ti_using_IEC_method()  # Assign using default settings for Iref and offset\n\n##################################################\n# Setting value\n##################################################\n\n# Similarly, each of the wind data objects also has the ability to set the value according to\n# a function of wind speed and direction.  This can be done using a custom function by using\n# the assign_value_using_wd_ws_function method. There is also a method called\n# assign_value_piecewise_linear which assigns value based on a linear piecewise function of\n# wind speed.\n\n# Assign value using default settings. This produces a value vs. wind speed that approximates\n# the normalized mean electricity price vs. wind speed curve for the SPP market in the U.S.\n# for years 2018-2020 from figure 7 in \"The value of wake steering wind farm flow control in\n# US energy markets,\" Wind Energy Science, 2024. https://doi.org/10.5194/wes-9-219-2024.\nwind_rose.assign_value_piecewise_linear()\n\n##################################################\n# Plotting Wind Data Objects\n##################################################\n\n# Certain plotting methods are included to enable visualization of the wind data objects\n# Plotting a wind rose\nwind_rose.plot()\n\n# Plot a wind rose with the wind directions aggregated into 10-deg bins\nwind_rose.plot(wd_step=10)\n\n# Showing TI over wind speed for a WindRose\nwind_rose.plot_ti_over_ws()\n\n# Showing value over wind speed for a WindRose\nwind_rose.plot_value_over_ws()\n\n##################################################\n# Setting the FLORIS model via wind data\n##################################################\n\n# Each of the wind data objects can be used to set the FLORIS model by passing\n# them in as is to the set method.  The FLORIS model will then use the member functions\n# of the wind data to extract the wind conditions for the simulation.  Frequency tables\n# are also extracted for expected power and AEP-like calculations.\n# Similarly the value data is extracted and maintained.\n\nfmodel = FlorisModel(\"inputs/gch.yaml\")\n\n# Set the wind conditions using the TimeSeries object\nfmodel.set(wind_data=time_series)\n\n# Set the wind conditions using the WindRose object\nfmodel.set(wind_data=wind_rose)\n\n# Note that in the case of the wind_rose, under the default settings, wind direction and wind speed\n# bins for which frequency is zero are not simulated.  This can be changed by setting the\n# compute_zero_freq_occurrence parameter to True.\nwind_directions = np.array([200.0, 300.0])\nwind_speeds = np.array([5.0, 10.0])\nfreq_table = np.array([[0.5, 0], [0.5, 0]])\nwind_rose = WindRose(\n    wind_directions=wind_directions, wind_speeds=wind_speeds, ti_table=0.06, freq_table=freq_table\n)\nfmodel.set(wind_data=wind_rose)\n\nprint(\n    f\"Number of conditions to simulate with compute_zero_freq_occurrence = False: \"\n    f\"{fmodel.n_findex}\"\n)\n\nwind_rose = WindRose(\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    ti_table=0.06,\n    freq_table=freq_table,\n    compute_zero_freq_occurrence=True,\n)\nfmodel.set(wind_data=wind_rose)\n\nprint(\n    f\"Number of conditions to simulate with compute_zero_freq_occurrence = \"\n    f\"True: {fmodel.n_findex}\"\n)\n\n# Set the wind conditions using the WindTIRose object\nfmodel.set(wind_data=wind_ti_rose)\n\nplt.show()\n"
  },
  {
    "path": "examples/004_set.py",
    "content": "\"\"\"Example 4: Set\n\nThis example illustrates the use of the set method.  The set method is used to\nchange the wind conditions, the wind farm layout, the turbine type,\nand the controls settings.\n\nThis example demonstrates setting each of the following:\n    1) Wind conditions\n    2) Wind farm layout\n    3) Controls settings\n\n\"\"\"\n\n\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n)\n\n\nfmodel = FlorisModel(\"inputs/gch.yaml\")\n\n######################################################\n# Atmospheric Conditions\n######################################################\n\n\n# Change the wind directions, wind speeds, and turbulence intensities using numpy arrays\nfmodel.set(\n    wind_directions=np.array([270.0, 270.0, 270.0]),\n    wind_speeds=[8.0, 9.0, 10.0],\n    turbulence_intensities=np.array([0.06, 0.06, 0.06]),\n)\n\n# Set the wind conditions as above using the TimeSeries object\nfmodel.set(\n    wind_data=TimeSeries(\n        wind_directions=270.0, wind_speeds=np.array([8.0, 9.0, 10.0]), turbulence_intensities=0.06\n    )\n)\n\n# Set the wind conditions as above using the WindRose object\nfmodel.set(\n    wind_data=WindRose(\n        wind_directions=np.array([270.0]),\n        wind_speeds=np.array([8.0, 9.0, 10.0]),\n        ti_table=0.06,\n    )\n)\n\n# Set the wind shear\nfmodel.set(wind_shear=0.2)\n\n\n# Set the air density\nfmodel.set(air_density=1.1)\n\n# Set the reference wind height (which is the height at which the wind speed is given)\nfmodel.set(reference_wind_height=92.0)\n\n\n######################################################\n# Array Settings\n######################################################\n\n# Changing the wind farm layout uses FLORIS' set method to a two-turbine layout\nfmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n\n######################################################\n# Controls Settings\n######################################################\n\n# Changes to controls settings can be made using the set method\n# Note the dimension must match (n_findex, n_turbines) or (number of conditions, number of turbines)\n# Above we n_findex = 3 and n_turbines = 2 so the matrix of yaw angles must be 3x2\nyaw_angles = np.array([[0.0, 0.0], [25.0, 0.0], [0.0, 0.0]])\nfmodel.set(yaw_angles=yaw_angles)\n\n# By default for the turbines in the turbine_library, the power\n# thrust model is set to \"cosine-loss\" which adjusts\n# power and thrust according to cos^cosine_loss_exponent(yaw | tilt)\n# where the default exponent is 1.88.  For other\n# control capabilities, the power thrust model can be set to \"mixed\"\n#  which provides the same cosine loss model, and\n# additionally methods for specifying derating levels for power and disabling turbines.\n\n# Use the reset operation method to clear out control signals\nfmodel.reset_operation()\n\n# Change to the mixed model turbine\nfmodel.set_operation_model(\"mixed\")\n\n# Shut down the front turbine for the first two findex\ndisable_turbines = np.array([[True, False], [True, False], [False, False]])\nfmodel.set(disable_turbines=disable_turbines)\n\n# Derate the front turbine for the first two findex\nRATED_POWER = 5e6  # 5MW (Anything above true rated power will still result in rated power)\npower_setpoints = np.array(\n    [[RATED_POWER * 0.3, RATED_POWER], [RATED_POWER * 0.3, RATED_POWER], [RATED_POWER, RATED_POWER]]\n)\nfmodel.set(power_setpoints=power_setpoints)\n"
  },
  {
    "path": "examples/005_getting_power.py",
    "content": "\"\"\"Example 5: Getting Turbine and Farm Power\n\nAfter setting the FlorisModel and running, the next step is typically to get the power output\nof the turbines.  FLORIS has several methods for getting power:\n\n1. `get_turbine_powers()`: Returns the power output of each turbine in the farm for each findex\n    (n_findex, n_turbines)\n2. `get_farm_power()`: Returns the total power output of the farm for each findex (n_findex)\n3. `get_expected_farm_power()`: Returns the combination of the farm power over each findex\n    with the frequency of each findex to get the expected farm power\n4. `get_farm_AEP()`: Multiplies the expected farm power by the number of hours in a year to get\n    the expected annual energy production (AEP) of the farm\n\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n)\n\n\nfmodel = FlorisModel(\"inputs/gch.yaml\")\n\n# Set to a 3-turbine layout\nfmodel.set(layout_x=[0, 126 * 5, 126 * 10], layout_y=[0, 0, 0])\n\n######################################################\n# Using TimeSeries\n######################################################\n\n# Set up a time series in which the wind speed and TI are constant but the wind direction\n# sweeps the range from 250 to 290 degrees\nwind_directions = np.arange(250, 290, 1.0)\ntime_series = TimeSeries(\n    wind_directions=wind_directions, wind_speeds=9.9, turbulence_intensities=0.06\n)\nfmodel.set(wind_data=time_series)\n\n# Run the model\nfmodel.run()\n\n# Get the turbine powers\nturbine_powers = fmodel.get_turbine_powers()\n\n# Turbines powers will have shape (n_findex, n_turbines) where n_findex is the number of unique\n# wind conditions and n_turbines is the number of turbines in the farm\nprint(f\"Turbine power has shape {turbine_powers.shape}\")\n\n# It is also possible to get the farm power directly\nfarm_power = fmodel.get_farm_power()\n\n# Farm power has length n_findex, and is the sum of the turbine powers\nprint(f\"Farm power has shape {farm_power.shape}\")\n\n# It's possible to get these powers with wake losses disabled, this can be useful\n# for computing total wake losses\nfmodel.run_no_wake()\nfarm_power_no_wake = fmodel.get_farm_power()\n\n# Plot the results\nfig, axarr = plt.subplots(1, 3, figsize=(15, 5))\n\n# Plot the turbine powers\nax = axarr[0]\nfor i in range(turbine_powers.shape[1]):\n    ax.plot(wind_directions, turbine_powers[:, i] / 1e3, label=f\"Turbine {i+1}  \")\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Power (kW)\")\nax.grid(True)\nax.legend()\nax.set_title(\"Turbine Powers\")\n\n# Plot the farm power\nax = axarr[1]\nax.plot(wind_directions, farm_power / 1e3, label=\"Farm Power With Wakes\", color=\"k\")\nax.plot(wind_directions, farm_power_no_wake / 1e3, label=\"Farm Power No Wakes\", color=\"r\")\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Power (kW)\")\nax.grid(True)\nax.legend()\nax.set_title(\"Farm Power\")\n\n# Plot the percent wake losses\nax = axarr[2]\npercent_wake_losses = 100 * (farm_power_no_wake - farm_power) / farm_power_no_wake\nax.plot(wind_directions, percent_wake_losses, label=\"Percent Wake Losses\", color=\"k\")\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Percent Wake Losses\")\nax.grid(True)\nax.legend()\nax.set_title(\"Percent Wake Losses\")\n\n\n######################################################\n# Using WindRose\n######################################################\n\n# When running FLORIS using a wind rose, that is when a WindRose or WindTIRose object is\n# passed into the set function.  The functions get_expected_farm_power and get_farm_AEP\n# will operate the same as above, however the functions get_turbine_powers and get_farm_power\n# will be reshaped from (n_findex, n_turbines) and\n# (n_findex) to (n_wind_dir, n_wind_speed, n_turbines)\n# and (n_wind_dir, n_wind_speed) respectively.  This is make the powers align more easily with the\n# provided wind rose.\n\n# Declare a WindRose object of 2 wind directions and 3 wind speeds and constant turbulence intensity\nwind_rose = WindRose(\n    wind_directions=np.array([270.0, 280.0]), wind_speeds=np.array([8.0, 9.0, 10.0]), ti_table=0.06\n)\n\nfmodel.set(wind_data=wind_rose)\n\nprint(\"==========Wind Rose==========\")\nprint(f\"Number of conditions to simulate (2 x 3): {fmodel.n_findex}\")\n\nfmodel.run()\n\nturbine_powers = fmodel.get_turbine_powers()\n\nprint(f\"Shape of turbine powers: {turbine_powers.shape}\")\n\nfarm_power = fmodel.get_farm_power()\n\nprint(f\"Shape of farm power: {farm_power.shape}\")\n\n\n# Plot the farm power\nfig, ax = plt.subplots()\n\nfor w_idx, wd in enumerate(wind_rose.wind_directions):\n    ax.plot(wind_rose.wind_speeds, farm_power[w_idx, :] / 1e3, label=f\"WD: {wd}\")\n\nax.set_xlabel(\"Wind Speed (m/s)\")\nax.set_ylabel(\"Power (kW)\")\nax.grid(True)\nax.legend()\nax.set_title(\"Farm Power (from Wind Rose)\")\n\nplt.show()\n"
  },
  {
    "path": "examples/006_get_farm_aep.py",
    "content": "\"\"\"Example 6: Getting Expected Power and AEP\n\nThe expected power of a farm is computed by multiplying the power output of the farm by the\nfrequency of each findex.  This is done by the `get_expected_farm_power` method.  The expected\nAEP is annual energy production is computed by multiplying the expected power by the number of\nhours in a year.\n\nIf a wind_data object is provided to the model, the expected power and AEP\n can be computed directly by the`get_farm_AEP_with_wind_data` using the frequency table\n of the wind data object.  If not, a frequency table must be passed into these functions\n\n\n\"\"\"\n\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n)\n\n\nfmodel = FlorisModel(\"inputs/gch.yaml\")\n\n\n# Set to a 3-turbine layout\nD = 126.0\nfmodel.set(layout_x=[0.0, 5 * D, 10 * D], layout_y=[0.0, 0.0, 0.0])\n\n# Using TimeSeries\n\n# Randomly generated a time series with time steps = 365 * 24\nN = 365 * 24\nrng = np.random.default_rng(0)\nwind_directions = rng.uniform(0, 360, N)\nwind_speeds = rng.uniform(5, 25, N)\n\n# Set up a time series\ntime_series = TimeSeries(\n    wind_directions=wind_directions, wind_speeds=wind_speeds, turbulence_intensities=0.06\n)\n\n# Set the wind data\nfmodel.set(wind_data=time_series)\n\n# Run the model\nfmodel.run()\n\nexpected_farm_power = fmodel.get_expected_farm_power()\naep = fmodel.get_farm_AEP()\n\n# Note this is equivalent to the following\naep_b = fmodel.get_farm_AEP(freq=time_series.unpack_freq())\n\nprint(f\"AEP from time series: {aep}, and re-computed AEP: {aep_b}\")\n\n# Using WindRose==============================================\n\n# Load the wind rose from csv as in example 003\nwind_rose = WindRose.read_csv_long(\n    \"inputs/wind_rose.csv\", wd_col=\"wd\", ws_col=\"ws\", freq_col=\"freq_val\", ti_col_or_value=0.06\n)\n\n\n# Store some values\nn_wd = len(wind_rose.wind_directions)\nn_ws = len(wind_rose.wind_speeds)\n\n# Store the number of elements of the freq_table which are 0\nn_zeros = np.sum(wind_rose.freq_table == 0)\n\n# Set the wind rose\nfmodel.set(wind_data=wind_rose)\n\n# Run the model\nfmodel.run()\n\n# Note that the frequency table contains 0 frequency for some wind directions and wind speeds\n# and we've not selected to compute 0 frequency bins, therefore the n_findex will be less than\n# the total number of wind directions and wind speed combinations\nprint(f\"Total number of wind direction and wind speed combination: {n_wd * n_ws}\")\nprint(f\"Number of 0 frequency bins: {n_zeros}\")\nprint(f\"n_findex: {fmodel.n_findex}\")\n\n# Get the AEP\naep = fmodel.get_farm_AEP()\n\n# Print the AEP\nprint(f\"AEP from wind rose: {aep/1E9:.3f} (GWh)\")\n\n# Run the model again, without wakes, and use the result to compute the wake losses\nfmodel.run_no_wake()\n\n# Get the AEP without wake\naep_no_wake = fmodel.get_farm_AEP()\n\n# Compute the wake losses\nwake_losses = 100 * (aep_no_wake - aep) / aep_no_wake\n\n# Print the wake losses\nprint(f\"Wake losses: {wake_losses:.2f}%\")\n"
  },
  {
    "path": "examples/007_sweeping_variables.py",
    "content": "\"\"\"Example 7: Sweeping Variables\n\nDemonstrate methods for sweeping across variables.  Wind directions, wind speeds,\nturbulence intensities, as well as control inputs are passed to set() as arrays\nand so can be swept and run in one call to run().\n\nThe example includes demonstrations of sweeping:\n\n    1) Wind speeds\n    2) Wind directions\n    3) Turbulence intensities\n    4) Yaw angles\n    5) Power setpoints\n    6) Disabling turbines\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n)\n\n\nfmodel = FlorisModel(\"inputs/gch.yaml\")\n\n# Set to a 2 turbine layout\nfmodel.set(layout_x=[0.0, 126 * 5], layout_y=[0.0, 0.0])\n\n# Start a figure for the results\nfig, axarr = plt.subplots(2, 3, figsize=(15, 10), sharey=True)\naxarr = axarr.flatten()\n\n######################################################\n# Sweep wind speeds\n######################################################\n\n\n# The TimeSeries object is the most convenient for sweeping\n# wind speeds while keeping the wind direction and turbulence\n# intensity constant\nwind_speeds = np.arange(5, 10, 0.1)\nfmodel.set(\n    wind_data=TimeSeries(\n        wind_speeds=wind_speeds, wind_directions=270.0, turbulence_intensities=0.06\n    )\n)\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers() / 1e3\n\n# Plot the results\nax = axarr[0]\nax.plot(wind_speeds, turbine_powers[:, 0], label=\"Upstream Turbine\", color=\"k\")\nax.plot(wind_speeds, turbine_powers[:, 1], label=\"Downstream Turbine\", color=\"r\")\nax.set_ylabel(\"Power (kW)\")\nax.set_xlabel(\"Wind Speed (m/s)\")\nax.legend()\n\n######################################################\n# Sweep wind directions\n######################################################\n\n\nwind_directions = np.arange(250, 290, 1.0)\nfmodel.set(\n    wind_data=TimeSeries(\n        wind_speeds=8.0, wind_directions=wind_directions, turbulence_intensities=0.06\n    )\n)\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers() / 1e3\n\n# Plot the results\nax = axarr[1]\nax.plot(wind_directions, turbine_powers[:, 0], label=\"Upstream Turbine\", color=\"k\")\nax.plot(wind_directions, turbine_powers[:, 1], label=\"Downstream Turbine\", color=\"r\")\nax.set_xlabel(\"Wind Direction (deg)\")\n\n######################################################\n# Sweep turbulence intensities\n######################################################\n\nturbulence_intensities = np.arange(0.03, 0.2, 0.01)\nfmodel.set(\n    wind_data=TimeSeries(\n        wind_speeds=8.0, wind_directions=270.0, turbulence_intensities=turbulence_intensities\n    )\n)\nfmodel.run()\n\nturbine_powers = fmodel.get_turbine_powers() / 1e3\n\n# Plot the results\nax = axarr[2]\nax.plot(turbulence_intensities, turbine_powers[:, 0], label=\"Upstream Turbine\", color=\"k\")\nax.plot(turbulence_intensities, turbine_powers[:, 1], label=\"Downstream Turbine\", color=\"r\")\nax.set_xlabel(\"Turbulence Intensity\")\n\n######################################################\n# Sweep the upstream yaw angle\n######################################################\n\n# First set the conditions to uniform for N yaw_angles\nn_yaw = 100\nwind_directions = np.ones(n_yaw) * 270.0\nfmodel.set(\n    wind_data=TimeSeries(\n        wind_speeds=8.0, wind_directions=wind_directions, turbulence_intensities=0.06\n    )\n)\n\nyaw_angles_upstream = np.linspace(-30, 30, n_yaw)\nyaw_angles = np.zeros((n_yaw, 2))\nyaw_angles[:, 0] = yaw_angles_upstream\n\nfmodel.set(yaw_angles=yaw_angles)\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers() / 1e3\n\n# Plot the results\nax = axarr[3]\nax.plot(yaw_angles_upstream, turbine_powers[:, 0], label=\"Upstream Turbine\", color=\"k\")\nax.plot(yaw_angles_upstream, turbine_powers[:, 1], label=\"Downstream Turbine\", color=\"r\")\nax.set_xlabel(\"Upstream Yaw Angle (deg)\")\nax.set_ylabel(\"Power (kW)\")\n\n######################################################\n# Sweep the upstream power rating\n######################################################\n\n# Since we're changing control modes, need to reset the operation\nfmodel.reset_operation()\n\n# To the de-rating need to change the power_thrust_mode to mixed or simple de-rating\nfmodel.set_operation_model(\"simple-derating\")\n\n# Sweep the de-rating levels\nRATED_POWER = 5e6  # For NREL 5MW\nn_derating_levels = 150\nupstream_power_setpoint = np.linspace(0.0, RATED_POWER * 0.5, n_derating_levels)\npower_setpoints = np.ones((n_derating_levels, 2)) * RATED_POWER\npower_setpoints[:, 0] = upstream_power_setpoint\n\n# Set the wind conditions to fixed\nwind_directions = np.ones(n_derating_levels) * 270.0\nfmodel.set(\n    wind_data=TimeSeries(\n        wind_speeds=8.0, wind_directions=wind_directions, turbulence_intensities=0.06\n    )\n)\n\n# Set the de-rating levels\nfmodel.set(power_setpoints=power_setpoints)\nfmodel.run()\n\n# Get the turbine powers\nturbine_powers = fmodel.get_turbine_powers() / 1e3\n\n# Plot the results\nax = axarr[4]\nax.plot(upstream_power_setpoint / 1e3, turbine_powers[:, 0], label=\"Upstream Turbine\", color=\"k\")\nax.plot(upstream_power_setpoint / 1e3, turbine_powers[:, 1], label=\"Downstream Turbine\", color=\"r\")\nax.plot(\n    upstream_power_setpoint / 1e3,\n    upstream_power_setpoint / 1e3,\n    label=\"De-Rating Level\",\n    color=\"b\",\n    linestyle=\"--\",\n)\nax.set_xlabel(\"Upstream Power Setpoint (kW)\")\nax.legend()\n\n######################################################\n# Sweep through disabling turbine combinations\n######################################################\n\n# Reset the control settings\nfmodel.reset_operation()\n\n# Make a list of possible turbine disable combinations\ndisable_combinations = np.array([[False, False], [True, False], [False, True], [True, True]])\nn_combinations = disable_combinations.shape[0]\n\n# Make a list of strings representing the combinations\ndisable_combination_strings = [\"None\", \"T0\", \"T1\", \"T0 & T1\"]\n\n# Set the wind conditions to fixed\nwind_directions = np.ones(n_combinations) * 270.0\nfmodel.set(\n    wind_data=TimeSeries(\n        wind_speeds=8.0, wind_directions=wind_directions, turbulence_intensities=0.06\n    )\n)\n\n# Assign the disable settings\nfmodel.set(disable_turbines=disable_combinations)\n\n# Run the model\nfmodel.run()\n\n# Get the turbine powers\nturbine_powers = fmodel.get_turbine_powers() / 1e3\n\n# Plot the results\nax = axarr[5]\nax.plot(disable_combination_strings, turbine_powers[:, 0], \"ks-\", label=\"Upstream Turbine\")\nax.plot(disable_combination_strings, turbine_powers[:, 1], \"ro-\", label=\"Downstream Turbine\")\nax.set_xlabel(\"Turbine Disable Combination\")\n\n\nfor ax in axarr:\n    ax.grid(True)\n\n\nplt.show()\n"
  },
  {
    "path": "examples/008_uncertain_models.py",
    "content": "\"\"\"Example 8: Uncertain Models\n\nUncertainFlorisModel is a class that adds uncertainty to the inflow wind direction\non the FlorisModel class. The UncertainFlorisModel class is interacted with in the\nsame manner as the FlorisModel class is. This example demonstrates how the\nwind farm power production is calculated with and without uncertainty.\nOther use cases of UncertainFlorisModel are, e.g., comparing FLORIS to\nhistorical SCADA data and robust optimization.\n\nFor more details on using uncertain models, see further examples within the\nexamples_uncertain directory.\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    UncertainFlorisModel,\n)\n\n\n# Instantiate FLORIS FLORIS and UncertainFLORIS models\nfmodel = FlorisModel(\"inputs/gch.yaml\")  # GCH model\n\n# The instantiation of the UncertainFlorisModel class is similar to the FlorisModel class\n# with the addition of the wind direction standard deviation (wd_std) parameter\n# and certain resolution parameters.  Internally, the UncertainFlorisModel class\n# expands the wind direction time series to include the uncertainty but then\n# only runs the unique cases.  The final result is computed via a gaussian weighting\n# of the cases according to wd_std.  Here we use the default resolution parameters.\n# wd_resolution=1.0,  # Degree\n# ws_resolution=1.0,  # m/s\n# ti_resolution=0.01,\n\nufmodel_3 = UncertainFlorisModel(\"inputs/gch.yaml\", wd_std=3)\nufmodel_5 = UncertainFlorisModel(\"inputs/gch.yaml\", wd_std=5)\n\n# Define an inflow where wind direction is swept while\n# wind speed and turbulence intensity are held constant\nwind_directions = np.arange(240.0, 300.0, 1.0)\ntime_series = TimeSeries(\n    wind_directions=wind_directions,\n    wind_speeds=8.0,\n    turbulence_intensities=0.06,\n)\n\n# Define a two turbine farm and apply the inflow\nD = 126.0\nlayout_x = np.array([0, D * 6])\nlayout_y = [0, 0]\n\nfmodel.set(\n    layout_x=layout_x,\n    layout_y=layout_y,\n    wind_data=time_series,\n)\nufmodel_3.set(\n    layout_x=layout_x,\n    layout_y=layout_y,\n    wind_data=time_series,\n)\nufmodel_5.set(\n    layout_x=layout_x,\n    layout_y=layout_y,\n    wind_data=time_series,\n)\n\n\n# Run both models\nfmodel.run()\nufmodel_3.run()\nufmodel_5.run()\n\n# Collect the nominal and uncertain farm power\nturbine_powers_nom = fmodel.get_turbine_powers() / 1e3\nturbine_powers_unc_3 = ufmodel_3.get_turbine_powers() / 1e3\nturbine_powers_unc_5 = ufmodel_5.get_turbine_powers() / 1e3\nfarm_powers_nom = fmodel.get_farm_power() / 1e3\nfarm_powers_unc_3 = ufmodel_3.get_farm_power() / 1e3\nfarm_powers_unc_5 = ufmodel_5.get_farm_power() / 1e3\n\n# Plot results\nfig, axarr = plt.subplots(1, 3, figsize=(15, 5))\nax = axarr[0]\nax.plot(wind_directions, turbine_powers_nom[:, 0].flatten(), color=\"k\", label=\"Nominal power\")\nax.plot(\n    wind_directions,\n    turbine_powers_unc_3[:, 0].flatten(),\n    color=\"r\",\n    label=\"Power with uncertainty = 3 deg\",\n)\nax.plot(\n    wind_directions,\n    turbine_powers_unc_5[:, 0].flatten(),\n    color=\"m\",\n    label=\"Power with uncertainty = 5deg\",\n)\nax.grid(True)\nax.legend()\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Power (kW)\")\nax.set_title(\"Upstream Turbine\")\n\nax = axarr[1]\nax.plot(wind_directions, turbine_powers_nom[:, 1].flatten(), color=\"k\", label=\"Nominal power\")\nax.plot(\n    wind_directions,\n    turbine_powers_unc_3[:, 1].flatten(),\n    color=\"r\",\n    label=\"Power with uncertainty = 3 deg\",\n)\nax.plot(\n    wind_directions,\n    turbine_powers_unc_5[:, 1].flatten(),\n    color=\"m\",\n    label=\"Power with uncertainty = 5 deg\",\n)\nax.set_title(\"Downstream Turbine\")\nax.grid(True)\nax.legend()\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Power (kW)\")\n\nax = axarr[2]\nax.plot(wind_directions, farm_powers_nom.flatten(), color=\"k\", label=\"Nominal farm power\")\nax.plot(\n    wind_directions,\n    farm_powers_unc_3.flatten(),\n    color=\"r\",\n    label=\"Farm power with uncertainty = 3 deg\",\n)\nax.plot(\n    wind_directions,\n    farm_powers_unc_5.flatten(),\n    color=\"m\",\n    label=\"Farm power with uncertainty = 5 deg\",\n)\nax.set_title(\"Farm Power\")\nax.grid(True)\nax.legend()\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Power (kW)\")\n\n# Compare the AEP calculation\nfreq = np.ones_like(wind_directions)\nfreq = freq / freq.sum()\n\naep_nom = fmodel.get_farm_AEP(freq=freq)\naep_unc_3 = ufmodel_3.get_farm_AEP(freq=freq)\naep_unc_5 = ufmodel_5.get_farm_AEP(freq=freq)\n\nprint(f\"AEP without uncertainty {aep_nom}\")\nprint(f\"AEP without uncertainty (3 deg) {aep_unc_3} ({100*aep_unc_3/aep_nom:.2f}%)\")\nprint(f\"AEP without uncertainty (5 deg) {aep_unc_5} ({100*aep_unc_5/aep_nom:.2f}%)\")\n\n\nplt.show()\n"
  },
  {
    "path": "examples/009_parallel_models.py",
    "content": "\"\"\"Example 9: Parallel Models\n\nThis example demonstrates how to use the ParFlorisModel class to parallelize the\ncalculation of the FLORIS model. ParFlorisModel inherits from the FlorisModel\nand so can be used in the same way with a consistent interface. ParFlorisModel\nreplaces the ParallelFlorisModel, which will be deprecated in a future release.\n\n\"\"\"\n\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    ParFlorisModel,\n    TimeSeries,\n    UncertainFlorisModel,\n)\n\n\n# When using parallel optimization it is important the \"root\" script include this\n# if __name__ == \"__main__\": block to avoid problems\nif __name__ == \"__main__\":\n    # Instantiate the FlorisModel\n    fmodel = FlorisModel(\"inputs/gch.yaml\")\n\n    # The ParFlorisModel can be instantiated either from a FlorisModel or from\n    # the input file.\n    pfmodel_1 = ParFlorisModel(\"inputs/gch.yaml\")  # Via input file\n    pfmodel_2 = ParFlorisModel(fmodel)  # Via FlorisModel\n\n    # The ParFlorisModel has additional inputs which define the parallelization\n    # but don't affect the output.\n    pfmodel_3 = ParFlorisModel(\n        fmodel,\n        interface=\"multiprocessing\",  # Default\n        max_workers=2,  # Defaults to num_cpu\n        n_wind_condition_splits=2,  # Defaults to max_workers\n    )\n\n    # Define a simple inflow\n    time_series = TimeSeries(\n        wind_speeds=np.arange(1, 25, 0.5), wind_directions=270.0, turbulence_intensities=0.06\n    )\n\n    # Demonstrate that interface and results are the same\n    fmodel.set(wind_data=time_series)\n    pfmodel_1.set(wind_data=time_series)\n    pfmodel_2.set(wind_data=time_series)\n    pfmodel_3.set(wind_data=time_series)\n\n    fmodel.run()\n    pfmodel_1.run()\n    pfmodel_2.run()\n    pfmodel_3.run()\n\n    # Compare the results\n    powers_fmodel = fmodel.get_turbine_powers()\n    powers_pfmodel_1 = pfmodel_1.get_turbine_powers()\n    powers_pfmodel_2 = pfmodel_2.get_turbine_powers()\n    powers_pfmodel_3 = pfmodel_3.get_turbine_powers()\n\n    print(\n        f\"Testing if outputs of fmodel and pfmodel_1 are \"\n        f\"close: {np.allclose(powers_fmodel, powers_pfmodel_1)}\"\n    )\n    print(\n        f\"Testing if outputs of fmodel and pfmodel_2 are \"\n        f\"close: {np.allclose(powers_fmodel, powers_pfmodel_2)}\"\n    )\n    print(\n        f\"Testing if outputs of fmodel and pfmodel_3 are \"\n        f\"close: {np.allclose(powers_fmodel, powers_pfmodel_3)}\"\n    )\n\n    # Because ParFlorisModel is a subclass of FlorisModel, it can also be used as\n    # an input to the UncertainFlorisModel class. This allows for parallelization of\n    # the uncertainty calculations.\n    ufmodel = UncertainFlorisModel(fmodel)\n    pufmodel = UncertainFlorisModel(pfmodel_1)\n\n    # Demonstrate matched results\n    ufmodel.set(wind_data=time_series)\n    pufmodel.set(wind_data=time_series)\n\n    ufmodel.run()\n    pufmodel.run()\n\n    powers_ufmodel = ufmodel.get_turbine_powers()\n    powers_pufmodel = pufmodel.get_turbine_powers()\n\n    print(\"--------------------\")\n    print(\n        f\"Testing if outputs of ufmodel and pufmodel are \"\n        f\"close: {np.allclose(powers_ufmodel, powers_pufmodel)}\"\n    )\n"
  },
  {
    "path": "examples/010_compare_farm_power_with_neighbor.py",
    "content": "\"\"\"Example 10: Compare farm power with neighboring farm\n\nThis example demonstrates how to use turbine_weights to define a set of turbines belonging\nto a neighboring farm which impacts the power production of the farm under consideration\nvia wake losses, but whose own power production is not considered in farm power / aep production\n\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\n# Instantiate FLORIS using either the GCH or CC model\nfmodel = FlorisModel(\"inputs/gch.yaml\")  # GCH model matched to the default \"legacy_gauss\" of V2\n\n# Define a 4 turbine farm turbine farm\nD = 126.0\nlayout_x = np.array([0, D * 6, 0, D * 6])\nlayout_y = [0, 0, D * 3, D * 3]\nfmodel.set(layout_x=layout_x, layout_y=layout_y)\n\n# Define a simple inflow with just 1 wind speed\nwd_array = np.arange(0, 360, 4.0)\nws_array = 8.0 * np.ones_like(wd_array)\nturbulence_intensities = 0.06 * np.ones_like(wd_array)\nfmodel.set(\n    wind_directions=wd_array, wind_speeds=ws_array, turbulence_intensities=turbulence_intensities\n)\n\n\n# Calculate\nfmodel.run()\n\n# Collect the farm power\nfarm_power_base = fmodel.get_farm_power() / 1e3  # In kW\n\n# Add a neighbor to the east\nlayout_x = np.array([0, D * 6, 0, D * 6, D * 12, D * 15, D * 12, D * 15])\nlayout_y = np.array([0, 0, D * 3, D * 3, 0, 0, D * 3, D * 3])\nfmodel.set(layout_x=layout_x, layout_y=layout_y)\n\n# Define the weights to exclude the neighboring farm from calculations of power\nturbine_weights = np.zeros(len(layout_x), dtype=int)\nturbine_weights[0:4] = 1.0\n\n# Calculate\nfmodel.run()\n\n# Collect the farm power with the neighbor\nfarm_power_neighbor = fmodel.get_farm_power(turbine_weights=turbine_weights) / 1e3  # In kW\n\n# Show the farms\nfig, ax = plt.subplots()\nax.scatter(\n    layout_x[turbine_weights == 1], layout_y[turbine_weights == 1], color=\"k\", label=\"Base Farm\"\n)\nax.scatter(\n    layout_x[turbine_weights == 0],\n    layout_y[turbine_weights == 0],\n    color=\"r\",\n    label=\"Neighboring Farm\",\n)\nax.legend()\n\n# Plot the power difference\nfig, ax = plt.subplots()\nax.plot(wd_array, farm_power_base, color=\"k\", label=\"Farm Power (no neighbor)\")\nax.plot(wd_array, farm_power_neighbor, color=\"r\", label=\"Farm Power (neighboring farm due east)\")\nax.grid(True)\nax.legend()\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Power (kW)\")\nplt.show()\n"
  },
  {
    "path": "examples/_convert_examples_to_notebooks.py",
    "content": "\"\"\"\nUtility script to convert all Python scripts in the current directory to\n Jupyter notebooks.\n\n\"\"\"\n\nimport os\n\nimport nbformat as nbf\n\n\ndef script_to_notebook(script_path, notebook_path):\n    # Read Python script\n    with open(script_path, \"r\") as f:\n        python_code = f.read()\n\n    # Clear out leading whitespace\n    python_code = python_code.strip()\n\n    # Append to the bottom of the code suppression of warnings\n    python_code += \"\"\"\nimport warnings\nwarnings.filterwarnings('ignore')\n\"\"\"\n\n    # Create a new Jupyter notebook\n    nb = nbf.v4.new_notebook()\n\n    # The first line of code it the title, copy it, remove and\n    # leading quotes or comments and make it a markdown cell with one hash\n    title = python_code.split(\"\\n\")[0].strip().strip(\"#\").strip().strip('\"').strip().strip(\"'\")\n    nb[\"cells\"].append(nbf.v4.new_markdown_cell(f\"# {title}\"))\n\n    # # Every code block starts with a comment block surrounded by \"\"\" and ends with \"\"\"\n    # # Find that block and place it in markdown cell\n    # code_comments = python_code.split('\"\"\"')[1]\n\n    # # Remove the top line\n    # code_comments = code_comments.split(\"\\n\")[1:]\n\n    # # Add the code comments\n    # nb[\"cells\"].append(nbf.v4.new_markdown_cell(code_comments))\n\n    # # Add Python code to the notebook\n\n    # # Remove the top commented block (\"\"\"...\"\"\") but keep everything after it\n    # python_code = python_code.split('\"\"\"')[2]\n\n    # Strip any leading white space\n    python_code = python_code.strip()\n\n    nb[\"cells\"].append(nbf.v4.new_code_cell(python_code))\n\n    # Write the notebook to a file\n    with open(notebook_path, \"w\") as f:\n        nbf.write(nb, f)\n\n\n# Traverse the current directory and subdirectories to find\n# all python scripts that start with a number\n# and end with .py and make a list of all such scripts including relative path\nscripts = sorted(\n    [\n        os.path.join(dp, f)\n        for dp, dn, filenames in os.walk(\".\")\n        for f in filenames\n        if f.endswith(\".py\") and f[0].isdigit()\n    ]\n)\n\n\n# For each Python script, convert it to a Jupyter notebook\nnotebook_directories = []\nnotebook_filenames = []\nfor script_path in scripts:\n    print(f\"Converting {script_path} to Notebook...\")\n\n    notebook_path = script_path.replace(\".py\", \".ipynb\")\n    notebook_directories.append(os.path.dirname(notebook_path))\n    notebook_filenames.append(os.path.basename(notebook_path))\n\n    script_to_notebook(script_path, notebook_path)\n\n\n# Make a dictionary of all the notebooks, whose keys are\n# unique entries in the notebook_directories list\n# and values are lists of notebook filenames in that directory\nnotebooks = {k: [] for k in notebook_directories}\nfor i, directory in enumerate(notebook_directories):\n    notebooks[directory].append(notebook_filenames[i])\n\nprint(notebooks)\n\n# Now read in the _toc.yaml file one level up and add each of the note books to a new chapter\n# called examples and re-write the _toc.yaml file\ntoc_path = \"../_toc.yml\"\n\n# Load the toc file as a file\nwith open(toc_path, \"r\") as f:\n    toc = f.read()\n\n# Append a blank line and then \"  - caption: Developer Reference\" to the toc\ntoc += \"\\n  - caption: Examples\\n    chapters:\\n\"\n\n# For each entry in the '.' directory, add it to the toc as a file\nfor nb in notebooks[\".\"]:\n    toc += f\"    - file: examples/{nb}\\n\"\n\n# For the remaining keys in the notebooks dictionary, first add a section for the directory\n# and then add the notebooks in that directory as a file\nfor directory in notebooks:\n    if directory == \".\":\n        continue\n    dir_without_dot_slash = directory[2:]\n    dir_without_examples_ = dir_without_dot_slash.replace(\"examples_\", \"\")\n    dir_without_examples_ = dir_without_examples_.replace(\"_\", \" \").capitalize()\n    toc += f\"\\n  - caption: Examples - {dir_without_examples_}\\n    chapters:\\n\"\n    for nb in notebooks[directory]:\n        toc += f\"    - file: examples/{dir_without_dot_slash}/{nb}\\n\"\n\n# Print the toc\nprint(\"\\n\\nTOC: FILE:\\n\")\nprint(toc)\n\n# Save the toc\nwith open(toc_path, \"w\") as f:\n    f.write(toc)\n"
  },
  {
    "path": "examples/examples_control_optimization/001_opt_yaw_single_ws.py",
    "content": "\n\"\"\"Example: Optimize yaw for a single wind speed and multiple wind directions\n\nUse the serial-refine method to optimize the yaw angles for a 3-turbine wind farm\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nimport floris.flow_visualization as flowviz\nimport floris.layout_visualization as layoutviz\nfrom floris import FlorisModel, TimeSeries\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\n# Load the default example floris object\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Define an inflow that\n# keeps wind speed and TI constant while sweeping the wind directions\nwind_directions = np.arange(0.0, 360.0, 3.0)\ntime_series = TimeSeries(\n    wind_directions=wind_directions,\n    wind_speeds=8.0,\n    turbulence_intensities=0.06,\n)\n\n# Reinitialize as a 3-turbine using the above inflow\nD = 126.0 # Rotor diameter for the NREL 5 MW\nfmodel.set(\n    layout_x=[0.0, 5 * D, 10 * D],\n    layout_y=[0.0, 0.0, 0.0],\n    wind_data=time_series,\n)\n\n# Initialize optimizer object and run optimization using the Serial-Refine method\nyaw_opt = YawOptimizationSR(fmodel)\ndf_opt = yaw_opt.optimize()\n\nprint(\"Optimization results:\")\nprint(df_opt)\n\n# Split out the turbine results\nfor t in range(3):\n    df_opt['t%d' % t] = df_opt.yaw_angles_opt.apply(lambda x: x[t])\n\n# Show the results\nfig, axarr = plt.subplots(2,1,sharex=True,sharey=False,figsize=(8,8))\n\n# Yaw results\nax = axarr[0]\nfor t in range(3):\n    ax.plot(df_opt.wind_direction,df_opt['t%d' % t],label='t%d' % t)\nax.set_ylabel('Yaw Offset (deg')\nax.legend()\nax.grid(True)\n\n# Power results\nax = axarr[1]\nax.plot(df_opt.wind_direction,df_opt.farm_power_baseline,color='k',label='Baseline Farm Power')\nax.plot(df_opt.wind_direction,df_opt.farm_power_opt,color='r',label='Optimized Farm Power')\nax.set_ylabel('Power (W)')\nax.set_xlabel('Wind Direction (deg)')\nax.legend()\nax.grid(True)\n\n# Visualize results for a single wind direction (270 deg) and wind speed (8 m/s)\nfig, axarr = plt.subplots(2, 1, figsize=(10, 5), sharex=False)\nax = axarr[0] # Baseline aligned operation\nfmodel.reset_operation()\nfmodel.set(wind_directions=[270.0], wind_speeds=[8.0], turbulence_intensities=[0.06])\nfmodel.run()\nhorizontal_plane = fmodel.calculate_horizontal_plane(height=90.0)\nflowviz.visualize_cut_plane(horizontal_plane, ax=ax)\nlayoutviz.plot_turbine_rotors(fmodel, ax=ax)\nax.set_title(\"Turbines aligned\")\n\nax = axarr[1] # Optimized yaw angles\noptimal_yaw_angles = (\n    df_opt[(df_opt[\"wind_direction\"] == 270.0) & (df_opt[\"wind_speed\"] == 8.0)]\n    .yaw_angles_opt.values[0]\n).reshape(1,-1)\nfmodel.set(yaw_angles=optimal_yaw_angles)\nfmodel.run()\nhorizontal_plane = fmodel.calculate_horizontal_plane(height=90.0)\nflowviz.visualize_cut_plane(horizontal_plane, ax=ax)\nlayoutviz.plot_turbine_rotors(fmodel, ax=ax, yaw_angles=optimal_yaw_angles)\nax.set_title(\"Optimized yaw angles\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_control_optimization/002_opt_yaw_single_ws_uncertain.py",
    "content": "\"\"\"Example: Optimize yaw for a single wind speed and multiple wind directions.\nCompare certain and uncertain results.\n\nUse the serial-refine method to optimize the yaw angles for a 3-turbine wind farm.  In one\ncase use the FlorisModel without uncertainty and in the other use the UncertainFlorisModel\nwith a wind direction standard deviation of 3 degrees.  Compare the results.\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    UncertainFlorisModel,\n)\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\n# Load the  floris model and uncertain floris model\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\nufmodel = UncertainFlorisModel(\"../inputs/gch.yaml\", wd_std=3)\n\n\n# Define an inflow that\n# keeps wind speed and TI constant while sweeping the wind directions\nwind_directions = np.arange(250, 290.0, 1.0)\ntime_series = TimeSeries(\n    wind_directions=wind_directions,\n    wind_speeds=8.0,\n    turbulence_intensities=0.06,\n)\n\n# Reinitialize as a 3-turbine using the above inflow\nD = 126.0  # Rotor diameter for the NREL 5 MW\nfmodel.set(\n    layout_x=[0.0, 5 * D, 10 * D],\n    layout_y=[0.0, 0.0, 0.0],\n    wind_data=time_series,\n)\nufmodel.set(\n    layout_x=[0.0, 5 * D, 10 * D],\n    layout_y=[0.0, 0.0, 0.0],\n    wind_data=time_series,\n)\n\n# Initialize optimizer object and run optimization using the Serial-Refine method\nprint(\"++++++++++CERTAIN++++++++++++\")\nyaw_opt = YawOptimizationSR(fmodel)\ndf_opt = yaw_opt.optimize()\n\n# Repeat with uncertain model\nprint(\"++++++++++UNCERTAIN++++++++++++\")\nyaw_opt_u = YawOptimizationSR(ufmodel)\ndf_opt_uncertain = yaw_opt_u.optimize()\n\n# Split out the turbine results\nfor t in range(3):\n    df_opt[\"t%d\" % t] = df_opt.yaw_angles_opt.apply(lambda x: x[t])\n    df_opt_uncertain[\"t%d\" % t] = df_opt_uncertain.yaw_angles_opt.apply(lambda x: x[t])\n\n# Show the yaw and turbine results\nfig, axarr = plt.subplots(3, sharex=True, sharey=False, figsize=(15, 8))\n\n# Yaw results\nfor tindex in range(3):\n    ax = axarr[tindex]\n    ax.plot(\n        df_opt.wind_direction, df_opt[\"t%d\" % tindex], label=\"FlorisModel\", color=\"k\", marker=\"o\"\n    )\n    ax.plot(\n        df_opt_uncertain.wind_direction,\n        df_opt_uncertain[\"t%d\" % tindex],\n        label=\"UncertainFlorisModel\",\n        color=\"r\",\n        marker=\"x\",\n    )\n    ax.set_ylabel(\"Yaw Offset T{0:03d} (deg)\".format(tindex))\n    ax.legend()\n    ax.grid(True)\n\n\n# Power results\nfig, axarr = plt.subplots(1, 2, figsize=(15, 5), sharex=True, sharey=True)\nax = axarr[0]\nax.plot(df_opt.wind_direction, df_opt.farm_power_baseline, color=\"k\", label=\"Baseline Farm Power\")\nax.plot(df_opt.wind_direction, df_opt.farm_power_opt, color=\"r\", label=\"Optimized Farm Power\")\nax.set_ylabel(\"Power (W)\")\nax.set_xlabel(\"Wind Direction (deg)\")\nax.legend()\nax.grid(True)\nax.set_title(\"Certain\")\nax = axarr[1]\nax.plot(\n    df_opt_uncertain.wind_direction,\n    df_opt_uncertain.farm_power_baseline,\n    color=\"k\",\n    label=\"Baseline Farm Power\",\n)\nax.plot(\n    df_opt_uncertain.wind_direction,\n    df_opt_uncertain.farm_power_opt,\n    color=\"r\",\n    label=\"Optimized Farm Power\",\n)\nax.set_xlabel(\"Wind Direction (deg)\")\nax.grid(True)\nax.set_title(\"Uncertain\")\n\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_control_optimization/003_opt_yaw_multiple_ws.py",
    "content": "\n\"\"\"Example: Optimize yaw for multiple wind directions and multiple wind speeds.\nThis example demonstrates how to perform a yaw optimization for multiple wind directions\nand multiple wind speeds using the WindRose object\n\nFirst, we initialize our Floris Interface, and then generate a 3 turbine wind farm.\nNext, we create the yaw optimization object `yaw_opt` and perform the optimization using\nthe SerialRefine method. Finally, we plot the results.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, WindRose\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\n# Load the default example floris object\nfmodel = FlorisModel(\"../inputs/gch.yaml\") # GCH model matched to the default \"legacy_gauss\" of V2\n# fmodel = FlorisModel(\"inputs/cc.yaml\") # New CumulativeCurl model\n\n# Define a WindRose object with uniform TI and frequency table\nwind_rose = WindRose(\n    wind_directions=np.arange(0.0, 360.0, 3.0),\n    wind_speeds=np.arange(2.0, 18.0, 1.0),\n    ti_table=0.06,\n)\n\n\n\n# Reinitialize as a 3-turbine farm with range of WDs and WSs\nD = 126.0 # Rotor diameter for the NREL 5 MW\nfmodel.set(\n    layout_x=[0.0, 5 * D, 10 * D],\n    layout_y=[0.0, 0.0, 0.0],\n    wind_data=wind_rose,\n)\n\n# Initialize optimizer object and run optimization using the Serial-Refine method\n# Now, we enable the verify_convergence option. This function is useful to prevent\n# yaw misalignment that increases the wind farm power production by a negligible\n# amount. For example, at high wind speeds (e.g., 16 m/s), a turbine might yaw\n# by a substantial amount to increase the power production by less than 1 W. This\n# is typically the result of numerical imprecision of the power coefficient curve,\n# which slightly differs for different above-rated wind speeds. The option\n# verify_convergence therefore refines and validates the yaw angle choices\n# but has no effect on the predicted power uplift from wake steering.\n# Hence, it should mostly be used when actually synthesizing a practicable\n# wind farm controller.\nyaw_opt = YawOptimizationSR(fmodel)\ndf_opt = yaw_opt.optimize()\n\nprint(\"Optimization results:\")\nprint(df_opt)\n\n# Split out the turbine results\nfor t in range(3):\n    df_opt['t%d' % t] = df_opt.yaw_angles_opt.apply(lambda x: x[t])\n\n# Show the results: optimal yaw angles\nfig, axarr = plt.subplots(\n    nrows=4,\n    ncols=4,\n    sharex=True,\n    sharey=True,\n    figsize=(10, 8)\n)\njj = 0\nfor ii, ws in enumerate(np.unique(fmodel.wind_speeds)):\n    xi = np.remainder(ii, 4)\n    if ((ii > 0) & (xi == 0)):\n        jj += 1\n    ax = axarr[np.remainder(ii, 4)][jj]\n    ids = (df_opt.wind_speed == ws)\n    wd = df_opt.loc[ids, \"wind_direction\"]\n    for t in range(3):\n        yaw_opt = df_opt.loc[ids, \"t{:d}\".format(t)]\n        ax.plot(wd, yaw_opt, label='Turbine {:d}'.format(t))\n    ax.set_title(\"Wind speed = {:.1f} m/s\".format(ws), size=10)\n    if ((ii == 0) & (jj == 0)):\n        ax.legend()\n    ax.grid(True)\n    if jj == 0:\n        ax.set_ylabel('Yaw angle (deg)', size=10)\n    if xi == 3:\n        axarr[xi][jj].set_xlabel('Wind Direction (deg)', size=10)\n\n    plt.tight_layout()\n\n# Show the results: baseline and optimized farm power\nfig, axarr = plt.subplots(\n    nrows=4,\n    ncols=4,\n    sharex=True,\n    sharey=True,\n    figsize=(10, 8)\n)\njj = 0\nfor ii, ws in enumerate(np.unique(fmodel.wind_speeds)):\n    xi = np.remainder(ii, 4)\n    if ((ii > 0) & (xi == 0)):\n        jj += 1\n    ax = axarr[np.remainder(ii, 4)][jj]\n    ids = (df_opt.wind_speed == ws)\n    wd = df_opt.loc[ids, \"wind_direction\"]\n    power_baseline = df_opt.loc[ids, \"farm_power_baseline\"]\n    power_opt = df_opt.loc[ids, \"farm_power_opt\"]\n    ax.plot(wd, power_baseline / 1e6, color='k', label='Baseline')\n    ax.plot(wd, power_opt / 1e6, color='r', label='Optimized')\n    ax.set_title(\"Wind speed = {:.1f} m/s\".format(ws), size=10)\n    ax.set_ylim([0.0, 16.0])\n    if ((ii == 0) & (jj == 0)):\n        ax.legend()\n    ax.grid(True)\n    if jj == 0:\n        ax.set_ylabel('Farm Power (MW)', size=10)\n    if xi == 3:\n        axarr[xi][jj].set_xlabel('Wind Direction (deg)', size=10)\n\n    plt.tight_layout()\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_control_optimization/004_optimize_yaw_aep.py",
    "content": "\"\"\"Example: Optimize yaw and compare AEP\n\nThis example demonstrates how to perform a yaw optimization and evaluate the performance\nover a full wind rose.\n\nThe script performs the following steps:\n    1. Load a wind rose from a csv file\n    2. Calculates the optimal yaw angles for a wind speed of 8 m/s across the directions\n    3. Applies the optimal yaw angles to the wind rose and calculates the AEP\n\n\"\"\"\n\nfrom time import perf_counter as timerpc\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n)\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\n# Load the wind rose from csv\nwind_rose = WindRose.read_csv_long(\n    \"../inputs/wind_rose.csv\", wd_col=\"wd\", ws_col=\"ws\", freq_col=\"freq_val\", ti_col_or_value=0.06\n)\n\n# Load FLORIS\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Specify wind farm layout and update in the floris object\nN = 2  # number of turbines per row and per column\nX, Y = np.meshgrid(\n    5.0 * fmodel.core.farm.rotor_diameters_sorted[0][0] * np.arange(0, N, 1),\n    5.0 * fmodel.core.farm.rotor_diameters_sorted[0][0] * np.arange(0, N, 1),\n)\nfmodel.set(layout_x=X.flatten(), layout_y=Y.flatten())\n\n# Get the number of turbines\nn_turbines = len(fmodel.layout_x)\n\n# Optimize the yaw angles.  This could be done for every wind direction and wind speed\n# but in practice it is much faster to optimize only for one speed and infer the rest\n# using a rule of thumb\ntime_series = TimeSeries(\n    wind_directions=wind_rose.wind_directions, wind_speeds=8.0, turbulence_intensities=0.06\n)\nfmodel.set(wind_data=time_series)\n\n# Get the optimal angles\nstart_time = timerpc()\nyaw_opt = YawOptimizationSR(\n    fmodel=fmodel,\n    minimum_yaw_angle=0.0,  # Allowable yaw angles lower bound\n    maximum_yaw_angle=20.0,  # Allowable yaw angles upper bound\n    Ny_passes=[5, 4],\n    exclude_downstream_turbines=True,\n)\ndf_opt = yaw_opt.optimize()\nend_time = timerpc()\nt_tot = end_time - start_time\nprint(f\"Optimization finished in {t_tot:.2f} seconds.\")\n\n\n# Calculate the AEP in the baseline case\nfmodel.set(wind_data=wind_rose)\nfmodel.run()\nfarm_power_baseline = fmodel.get_farm_power()\naep_baseline = fmodel.get_farm_AEP()\n\n\n# Now need to apply the optimal yaw angles to the wind rose to get the optimized AEP\n# do this by applying a rule of thumb where the optimal yaw is applied between 6 and 12 m/s\n# and ramped down to 0 above and below this range\n\n# Grab wind speeds and wind directions from the fmodel.  Note that we do this because the\n# yaw angles will need to be n_findex long, and accounting for the fact that some wind\n# directions and wind speeds may not be present in the wind rose (0 frequency) and aren't\n# included in the fmodel\nwind_directions = fmodel.wind_directions\nwind_speeds = fmodel.wind_speeds\nn_findex = fmodel.n_findex\n\n\n# Now define how the optimal yaw angles for 8 m/s are applied over the other wind speeds\nyaw_angles_opt = np.vstack(df_opt[\"yaw_angles_opt\"])\nyaw_angles_wind_rose = np.zeros((n_findex, n_turbines))\nfor i in range(n_findex):\n    wind_speed = wind_speeds[i]\n    wind_direction = wind_directions[i]\n\n    # Interpolate the optimal yaw angles for this wind direction from df_opt\n    id_opt = df_opt[\"wind_direction\"] == wind_direction\n    yaw_opt_full = np.array(df_opt.loc[id_opt, \"yaw_angles_opt\"])[0]\n\n    # Now decide what to do for different wind speeds\n    wind_speed_low_no_steer = 4.0\n    wind_speed_high_no_steer = 14.0\n    wind_speed_low_steer = 6.0\n    wind_speed_high_steer = 12.0\n    if (wind_speed < wind_speed_low_no_steer) | (wind_speed > wind_speed_high_no_steer):\n        yaw_opt = np.zeros(n_turbines)  # do nothing for very low/high speeds\n    elif wind_speed < wind_speed_low_steer:\n        yaw_opt = (\n            yaw_opt_full\n            * (wind_speed_low_steer - wind_speed)\n            / (wind_speed_low_steer - wind_speed_low_no_steer)\n        )  # Linear ramp up\n    elif wind_speed > wind_speed_high_steer:\n        yaw_opt = (\n            yaw_opt_full\n            * (wind_speed_high_no_steer - wind_speed)\n            / (wind_speed_high_no_steer - wind_speed_high_steer)\n        )  # Linear ramp down\n    else:\n        yaw_opt = yaw_opt_full  # Apply full offsets between 6.0 and 12.0 m/s\n\n    # Save to collective array\n    yaw_angles_wind_rose[i, :] = yaw_opt\n\n\n# Now apply the optimal yaw angles and get the AEP\nfmodel.set(yaw_angles=yaw_angles_wind_rose)\nfmodel.run()\naep_opt = fmodel.get_farm_AEP()\naep_uplift = 100.0 * (aep_opt / aep_baseline - 1)\nfarm_power_opt = fmodel.get_farm_power()\n\nprint(f\"Baseline AEP: {aep_baseline / 1e9:.2f} GWh.\")\nprint(f\"Optimal AEP: {aep_opt / 1e9:.2f} GWh.\")\nprint(f\"Relative AEP uplift by wake steering: {aep_uplift:.3f} %.\")\n\n# Use farm_power_baseline, farm_power_opt and wind_data to make a heat map of uplift by\n# wind direction and wind speed\nwind_directions = wind_rose.wind_directions\nwind_speeds = wind_rose.wind_speeds\nrelative_gain = farm_power_opt - farm_power_baseline\n\n# Plot the heatmap with wind speeds on x, wind directions on y and relative gain as the color\nfig, ax = plt.subplots(figsize=(10, 12))\ncax = ax.imshow(relative_gain, cmap=\"viridis\", aspect=\"auto\")\nfig.colorbar(cax, ax=ax, label=\"Relative gain (%)\")\n\nax.set_yticks(np.arange(len(wind_directions)))\nax.set_yticklabels(wind_directions)\nax.set_xticks(np.arange(len(wind_speeds)))\nax.set_xticklabels(wind_speeds)\nax.set_ylabel(\"Wind direction (deg)\")\nax.set_xlabel(\"Wind speed (m/s)\")\n\n# Reduce x and y tick font size\nfor tick in ax.yaxis.get_major_ticks():\n    tick.label1.set_fontsize(8)\n\nfor tick in ax.xaxis.get_major_ticks():\n    tick.label1.set_fontsize(8)\n\n# Set y ticks to be horizontal\nfor tick in ax.get_yticklabels():\n    tick.set_rotation(0)\n\nax.set_title(\"Uplift in farm power by wind direction and wind speed\", fontsize=12)\n\nplt.tight_layout()\nplt.show()\n"
  },
  {
    "path": "examples/examples_control_optimization/005_optimize_yaw_aep_parallel.py",
    "content": "\"\"\"Example: Optimize yaw and compare AEP in parallel\n\nThis example demonstrates how to perform a yaw optimization and evaluate the performance\nover a full wind rose.  The example repeats the steps in 04 except using parallel\noptimization and evaluation.\n\nNote that constraints on parallelized operations mean that some syntax is different and\nnot all operations are possible.  Also, rather passing the ParallelFlorisModel\nobject to a YawOptimizationSR object, the optimization is performed\ndirectly by member functions\n\n\"\"\"\n\nfrom time import perf_counter as timerpc\n\nimport numpy as np\n\nfrom floris import (\n    ParFlorisModel,\n    TimeSeries,\n    WindRose,\n)\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\n# When using parallel optimization it is important the \"root\" script include this\n# if __name__ == \"__main__\": block to avoid problems\nif __name__ == \"__main__\":\n\n    # Load the wind rose from csv\n    wind_rose = WindRose.read_csv_long(\n        \"../inputs/wind_rose.csv\", wd_col=\"wd\", ws_col=\"ws\", freq_col=\"freq_val\",\n        ti_col_or_value=0.06\n    )\n\n    # Load FLORIS as a parallel model\n    max_workers = 16\n    pfmodel = ParFlorisModel(\n        \"../inputs/gch.yaml\",\n        max_workers=max_workers,\n        n_wind_condition_splits=max_workers,\n        interface=\"pathos\",\n        print_timings=True,\n    )\n\n    # Specify wind farm layout and update in the floris object\n    N = 2  # number of turbines per row and per column\n    X, Y = np.meshgrid(\n        5.0 * pfmodel.core.farm.rotor_diameters_sorted[0][0] * np.arange(0, N, 1),\n        5.0 * pfmodel.core.farm.rotor_diameters_sorted[0][0] * np.arange(0, N, 1),\n    )\n    pfmodel.set(layout_x=X.flatten(), layout_y=Y.flatten())\n\n    # Get the number of turbines\n    n_turbines = len(pfmodel.layout_x)\n\n    # Optimize the yaw angles.  This could be done for every wind direction and wind speed\n    # but in practice it is much faster to optimize only for one speed and infer the rest\n    # using a rule of thumb\n    time_series = TimeSeries(\n        wind_directions=wind_rose.wind_directions, wind_speeds=8.0, turbulence_intensities=0.06\n    )\n    pfmodel.set(wind_data=time_series)\n\n    start_time = timerpc()\n    yaw_opt = YawOptimizationSR(\n        fmodel=pfmodel,\n        minimum_yaw_angle=0.0,  # Allowable yaw angles lower bound\n        maximum_yaw_angle=20.0,  # Allowable yaw angles upper bound\n        Ny_passes=[5, 4],\n        exclude_downstream_turbines=True,\n    )\n    df_opt = yaw_opt.optimize()\n    end_time = timerpc()\n    t_tot = end_time - start_time\n    print(\"Optimization finished in {:.2f} seconds.\".format(t_tot))\n\n    # Calculate the AEP in the baseline case, using the parallel interface\n    pfmodel.set(wind_data=wind_rose)\n    pfmodel.run()\n    aep_baseline = pfmodel.get_farm_AEP()\n\n    # Now need to apply the optimal yaw angles to the wind rose to get the optimized AEP\n    # do this by applying a rule of thumb where the optimal yaw is applied between 6 and 12 m/s\n    # and ramped down to 0 above and below this range\n\n    # Grab wind speeds and wind directions from the fmodel.  Note that we do this because the\n    # yaw angles will need to be n_findex long, and accounting for the fact that some wind\n    # directions and wind speeds may not be present in the wind rose (0 frequency) and aren't\n    # included in the fmodel\n    # TODO: add operation wind rose to example, once built\n    wind_directions = pfmodel.wind_directions\n    wind_speeds = pfmodel.wind_speeds\n    n_findex = pfmodel.n_findex\n\n\n    # Now define how the optimal yaw angles for 8 m/s are applied over the other wind speeds\n    yaw_angles_opt = np.vstack(df_opt[\"yaw_angles_opt\"])\n    yaw_angles_wind_rose = np.zeros((n_findex, n_turbines))\n    for i in range(n_findex):\n        wind_speed = wind_speeds[i]\n        wind_direction = wind_directions[i]\n\n        # Interpolate the optimal yaw angles for this wind direction from df_opt\n        id_opt = df_opt[\"wind_direction\"] == wind_direction\n        yaw_opt_full = np.array(df_opt.loc[id_opt, \"yaw_angles_opt\"])[0]\n\n        # Now decide what to do for different wind speeds\n        if (wind_speed < 4.0) | (wind_speed > 14.0):\n            yaw_opt = np.zeros(n_turbines)  # do nothing for very low/high speeds\n        elif wind_speed < 6.0:\n            yaw_opt = yaw_opt_full * (6.0 - wind_speed) / 2.0  # Linear ramp up\n        elif wind_speed > 12.0:\n            yaw_opt = yaw_opt_full * (14.0 - wind_speed) / 2.0  # Linear ramp down\n        else:\n            yaw_opt = yaw_opt_full  # Apply full offsets between 6.0 and 12.0 m/s\n\n        # Save to collective array\n        yaw_angles_wind_rose[i, :] = yaw_opt\n\n\n    # Now apply the optimal yaw angles and get the AEP\n    pfmodel.set(yaw_angles=yaw_angles_wind_rose)\n    pfmodel.run()\n    aep_opt = pfmodel.get_farm_AEP()\n    aep_uplift = 100.0 * (aep_opt / aep_baseline - 1)\n\n    print(\"Baseline AEP: {:.2f} GWh.\".format(aep_baseline/1E9))\n    print(\"Optimal AEP: {:.2f} GWh.\".format(aep_opt/1E9))\n    print(\"Relative AEP uplift by wake steering: {:.3f} %.\".format(aep_uplift))\n"
  },
  {
    "path": "examples/examples_control_optimization/006_compare_yaw_optimizers.py",
    "content": "\n\"\"\"Example: Compare yaw optimizers\nThis example compares the SciPy-based yaw optimizer with the Serial-Refine optimizer\nand geometric optimizer.\n\nFirst, we initialize Floris, and then generate a 3 turbine wind farm.\nNext, we create two yaw optimization objects, `yaw_opt_sr` and `yaw_opt_scipy` for the\nSerial-Refine and SciPy methods, respectively.\nWe then perform the optimization using both methods.\nFinally, we compare the time it took to find the optimal angles and plot the optimal yaw angles\nand resulting wind farm powers.\n\nThe example now also compares the Geometric Yaw optimizer, which is fast\na method to find approximately optimal yaw angles based on the wind farm geometry. Its\nmain use case is for coupled layout and yaw optimization.\nsee floris.optimization.yaw_optimization.yaw_optimizer_geometric.py and the paper online\nat https://wes.copernicus.org/preprints/wes-2023-1/. See also example 16c.\n\n\"\"\"\n\nfrom time import perf_counter as timerpc\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom floris.optimization.yaw_optimization.yaw_optimizer_geometric import (\n    YawOptimizationGeometric,\n)\nfrom floris.optimization.yaw_optimization.yaw_optimizer_scipy import YawOptimizationScipy\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\n# Load the default example floris object\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Reinitialize as a 3-turbine farm with range of WDs and 1 WS\nD = 126.0 # Rotor diameter for the NREL 5 MW\nwd_array = np.arange(0.0, 360.0, 3.0)\nws_array = 8.0 * np.ones_like(wd_array)\nturbulence_intensities = 0.06 * np.ones_like(wd_array)\nfmodel.set(\n    layout_x=[0.0, 5 * D, 10 * D],\n    layout_y=[0.0, 0.0, 0.0],\n    wind_directions=wd_array,\n    wind_speeds=ws_array,\n    turbulence_intensities=turbulence_intensities,\n)\n\nprint(\"Performing optimizations with SciPy...\")\nstart_time = timerpc()\nyaw_opt_scipy = YawOptimizationScipy(fmodel)\ndf_opt_scipy = yaw_opt_scipy.optimize()\ntime_scipy = timerpc() - start_time\n\nprint(\"Performing optimizations with Serial Refine...\")\nstart_time = timerpc()\nyaw_opt_sr = YawOptimizationSR(fmodel)\ndf_opt_sr = yaw_opt_sr.optimize()\ntime_sr = timerpc() - start_time\n\nprint(\"Performing optimizations with Geometric Yaw...\")\nstart_time = timerpc()\nyaw_opt_geo = YawOptimizationGeometric(fmodel)\ndf_opt_geo = yaw_opt_geo.optimize()\ntime_geo = timerpc() - start_time\n\n\n\n# Print time spent\nprint(\"\\n Time spent, Geometric Yaw: {:.2f} s.\".format(time_geo))\nprint(\" Time spent, Serial Refine: {:.2f} s.\".format(time_sr))\nprint(\" Time spent, SciPy (SLSQP): {:.2f} s.\\n\".format(time_scipy))\n\n# Split out the turbine results\nyaw_angles_opt_geo = np.vstack(df_opt_geo.yaw_angles_opt)\nyaw_angles_opt_sr = np.vstack(df_opt_sr.yaw_angles_opt)\nyaw_angles_opt_scipy = np.vstack(df_opt_scipy.yaw_angles_opt)\n\n\n# Yaw results\nfor t in range(3):\n    fig, ax = plt.subplots()\n    ax.plot(df_opt_geo.wind_direction, yaw_angles_opt_geo[:, t],color='m',label='Geometric')\n    ax.plot(df_opt_sr.wind_direction, yaw_angles_opt_sr[:, t],color='r',label='Serial Refine')\n    ax.plot(df_opt_scipy.wind_direction, yaw_angles_opt_scipy[:, t],'--', color='g', label='SciPy')\n    ax.grid(True)\n    ax.set_ylabel('Yaw Offset (deg')\n    ax.legend()\n    ax.grid(True)\n    ax.set_title(\"Turbine {:d}\".format(t))\n\n# Power results ==============\n\n# Before plotting results, need to compute values for GEOOPT since it doesn't compute\n# power within the optimization\nfmodel.set(yaw_angles=yaw_angles_opt_geo)\nfmodel.run()\ngeo_farm_power = fmodel.get_farm_power().squeeze()\n\n\nfig, ax = plt.subplots()\nax.plot(\n    df_opt_sr.wind_direction,\n    df_opt_sr.farm_power_baseline,\n    color='k',\n    label='Baseline'\n)\nax.plot(\n    df_opt_geo.wind_direction,\n    geo_farm_power,\n    color='m',\n    label='Optimized, Gemoetric'\n)\nax.plot(\n    df_opt_sr.wind_direction,\n    df_opt_sr.farm_power_opt,\n    color='r',\n    label='Optimized, Serial Refine'\n)\nax.plot(\n    df_opt_scipy.wind_direction,\n    df_opt_scipy.farm_power_opt,\n    '--',\n    color='g',\n    label='Optimized, SciPy'\n)\nax.set_ylabel('Wind Farm Power (W)')\nax.set_xlabel('Wind Direction (deg)')\nax.legend()\nax.grid(True)\n\n# Finally, compare the overall the power gains\n\nfig, ax = plt.subplots()\n\nax.plot(\n    df_opt_geo.wind_direction,\n    geo_farm_power - df_opt_sr.farm_power_baseline,\n    color='m',\n    label='Optimized, Gemoetric'\n)\nax.plot(\n    df_opt_sr.wind_direction,\n    df_opt_sr.farm_power_opt - df_opt_sr.farm_power_baseline,\n    color='r',\n    label='Optimized, Serial Refine'\n)\nax.plot(\n    df_opt_scipy.wind_direction,\n    df_opt_scipy.farm_power_opt - df_opt_scipy.farm_power_baseline,\n    '--',\n    color='g',\n    label='Optimized, SciPy'\n)\nax.set_ylabel('Increase in Wind Farm Power (W)')\nax.set_xlabel('Wind Direction (deg)')\nax.legend()\nax.grid(True)\n\n\n# Finally, make a quick bar plot comparing nomimal power and nomimal uplift\ntotal_power_uplift_geo = np.sum(geo_farm_power - df_opt_sr.farm_power_baseline)\ntotal_power_uplift_sr = np.sum(df_opt_sr.farm_power_opt - df_opt_sr.farm_power_baseline)\ntotal_power_uplift_scipy = np.sum(df_opt_scipy.farm_power_opt - df_opt_scipy.farm_power_baseline)\n\n# Plot on the left subplot a barplot comparing the uplift normalized to scipy and on the right\n# subplot a barplot of total time normalzed to scipy\nfig, axarr = plt.subplots(1,2,figsize=(10,5))\n\nax = axarr[0]\nax.bar(\n    [0, 1, 2],\n    [\n        total_power_uplift_geo / total_power_uplift_scipy,\n        total_power_uplift_sr / total_power_uplift_scipy,\n        1.0,\n    ],\n    color=['m', 'r', 'g'],\n)\nax.set_xticks([0, 1, 2])\nax.set_xticklabels(['Geometric', 'Serial Refine', 'SciPy'])\nax.set_ylabel('Normalized Power Gain')\nax.grid(True)\n\nax = axarr[1]\nax.bar(\n    [0, 1, 2],\n    [\n        time_geo / time_scipy,\n        time_sr / time_scipy,\n        1.0,\n    ],\n    color=['m', 'r', 'g'],\n)\nax.set_xticks([0, 1, 2])\nax.set_xticklabels(['Geometric', 'Serial Refine', 'SciPy'])\nax.set_ylabel('Normalized Computation Time')\nax.grid(True)\n\n# Change to semi-logy\naxarr[1].set_yscale('log')\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_control_optimization/007_optimize_yaw_with_neighbor_farms.py",
    "content": "\"\"\"Example: Optimize yaw with neighbor farm\n\nThis example demonstrates how to optimize the yaw angles of a subset of turbines\nin order to maximize the annual energy production (AEP) of a wind farm.  In this\ncase, the wind farm is part of a larger collection of turbines, some of which are\npart of a neighboring farm.  The optimization is performed in two ways: first by\naccounting for the wakes of the neighboring farm (while not including those turbines)\nin the optimization as a target of yaw angle changes or including their power\nin the objective function.  In the second method the neighboring farms are removed\nfrom FLORIS for the optimization.  The AEP is then calculated for the optimized\nyaw angles (accounting for and not accounting for the neighboring farm) and compared\nto the baseline AEP.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n)\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\n# Load the wind rose from csv\nwind_rose = WindRose.read_csv_long(\n    \"../inputs/wind_rose.csv\", wd_col=\"wd\", ws_col=\"ws\", freq_col=\"freq_val\", ti_col_or_value=0.06\n)\n\n# Load FLORIS\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Specify a layout of turbines in which only the first 10 turbines are part\n# of the farm to be optimized, while the others belong to a neighboring farm\nX = (\n    np.array(\n        [\n            0.0,\n            756.0,\n            1512.0,\n            2268.0,\n            3024.0,\n            0.0,\n            756.0,\n            1512.0,\n            2268.0,\n            3024.0,\n            0.0,\n            756.0,\n            1512.0,\n            2268.0,\n            3024.0,\n            0.0,\n            756.0,\n            1512.0,\n            2268.0,\n            3024.0,\n            4500.0,\n            5264.0,\n            6028.0,\n            4878.0,\n            0.0,\n            756.0,\n            1512.0,\n            2268.0,\n            3024.0,\n        ]\n    )\n    / 1.5\n)\nY = (\n    np.array(\n        [\n            0.0,\n            0.0,\n            0.0,\n            0.0,\n            0.0,\n            504.0,\n            504.0,\n            504.0,\n            504.0,\n            504.0,\n            1008.0,\n            1008.0,\n            1008.0,\n            1008.0,\n            1008.0,\n            1512.0,\n            1512.0,\n            1512.0,\n            1512.0,\n            1512.0,\n            4500.0,\n            4059.0,\n            3618.0,\n            5155.0,\n            -504.0,\n            -504.0,\n            -504.0,\n            -504.0,\n            -504.0,\n        ]\n    )\n    / 1.5\n)\n\n# Turbine weights: we want to only optimize for the first 10 turbines\nturbine_weights = np.zeros(len(X), dtype=int)\nturbine_weights[0:10] = 1.0\n\n# Now reinitialize FLORIS layout\nfmodel.set(layout_x=X, layout_y=Y)\n\n# And visualize the floris layout\nfig, ax = plt.subplots()\nax.plot(X[turbine_weights == 0], Y[turbine_weights == 0], \"ro\", label=\"Neighboring farms\")\nax.plot(X[turbine_weights == 1], Y[turbine_weights == 1], \"go\", label=\"Farm subset\")\nax.grid(True)\nax.set_xlabel(\"x coordinate (m)\")\nax.set_ylabel(\"y coordinate (m)\")\nax.legend()\n\n# Indicate turbine 0 in the plot above with an annotation arrow\nax.annotate(\n    \"Turbine 0\",\n    (X[0], Y[0]),\n    xytext=(X[0] + 100, Y[0] + 100),\n    arrowprops={\"facecolor\": \"black\", \"shrink\": 0.05},\n)\n\n# Optimize the yaw angles.  This could be done for every wind direction and wind speed\n# but in practice it is much faster to optimize only for one speed and infer the rest\n# using a rule of thumb\ntime_series = TimeSeries(\n    wind_directions=wind_rose.wind_directions, wind_speeds=8.0, turbulence_intensities=0.06\n)\nfmodel.set(wind_data=time_series)\n\n# CASE 1: Optimize the yaw angles of the included farm while accounting for the\n# wake effects of the neighboring farm by using turbine weights\n\n# It's important here to do two things:\n# 1. Exclude the downstream turbines from the power optimization goal via\n#    turbine_weights\n# 2. Prevent the optimizer from changing the yaw angles of the turbines in the\n#    neighboring farm by limiting the yaw angles min max both to 0\n\n# Set the yaw angles max min according to point(2) above\nminimum_yaw_angle = np.zeros(\n    (\n        fmodel.n_findex,\n        fmodel.n_turbines,\n    )\n)\nmaximum_yaw_angle = np.zeros(\n    (\n        fmodel.n_findex,\n        fmodel.n_turbines,\n    )\n)\nmaximum_yaw_angle[:, :10] = 30.0\n\n\nyaw_opt = YawOptimizationSR(\n    fmodel=fmodel,\n    minimum_yaw_angle=minimum_yaw_angle,  # Allowable yaw angles lower bound\n    maximum_yaw_angle=maximum_yaw_angle,  # Allowable yaw angles upper bound\n    Ny_passes=[5, 4],\n    exclude_downstream_turbines=True,\n    turbine_weights=turbine_weights,\n)\ndf_opt_with_neighbor = yaw_opt.optimize()\n\n# CASE 2: Repeat the optimization, this time ignoring the wakes of the neighboring farm\n# by limiting the FLORIS model to only the turbines in the farm to be optimized\nf_model_subset = fmodel.copy()\nf_model_subset.set(\n    layout_x=X[:10],\n    layout_y=Y[:10],\n)\nyaw_opt = YawOptimizationSR(\n    fmodel=f_model_subset,\n    minimum_yaw_angle=0,  # Allowable yaw angles lower bound\n    maximum_yaw_angle=30,  # Allowable yaw angles upper bound\n    Ny_passes=[5, 4],\n    exclude_downstream_turbines=True,\n)\ndf_opt_without_neighbor = yaw_opt.optimize()\n\n\n# Calculate the AEP in the baseline case\n# Use turbine weights again to only consider the first 10 turbines power\nfmodel.set(wind_data=wind_rose)\nfmodel.run()\nfarm_power_baseline = fmodel.get_farm_power(turbine_weights=turbine_weights)\naep_baseline = fmodel.get_farm_AEP(turbine_weights=turbine_weights)\n\n\n# Now need to apply the optimal yaw angles to the wind rose to get the optimized AEP\n# do this by applying a rule of thumb where the optimal yaw is applied between 6 and 12 m/s\n# and ramped down to 0 above and below this range\n\n# Grab wind speeds and wind directions from the fmodel.  Note that we do this because the\n# yaw angles will need to be n_findex long, and accounting for the fact that some wind\n# directions and wind speeds may not be present in the wind rose (0 frequency) and aren't\n# included in the fmodel\nwind_directions = fmodel.wind_directions\nwind_speeds = fmodel.wind_speeds\nn_findex = fmodel.n_findex\n\nyaw_angles_wind_rose_with_neighbor = np.zeros((n_findex, fmodel.n_turbines))\nyaw_angles_wind_rose_without_neighbor = np.zeros((n_findex, fmodel.n_turbines))\nfor i in range(n_findex):\n    wind_speed = wind_speeds[i]\n    wind_direction = wind_directions[i]\n\n    # Interpolate the optimal yaw angles for this wind direction from df_opt\n    id_opt_with_neighbor = df_opt_with_neighbor[\"wind_direction\"] == wind_direction\n    id_opt_without_neighbor = df_opt_without_neighbor[\"wind_direction\"] == wind_direction\n\n    # Get the yaw angles for this wind direction\n    yaw_opt_full_with_neighbor = np.array(\n        df_opt_with_neighbor.loc[id_opt_with_neighbor, \"yaw_angles_opt\"]\n    )[0]\n    yaw_opt_full_without_neighbor = np.array(\n        df_opt_without_neighbor.loc[id_opt_without_neighbor, \"yaw_angles_opt\"]\n    )[0]\n\n    # Extend the yaw angles from 10 turbine to n_turbine by filling with 0s\n    # in the case of the removed neighboring farms\n    yaw_opt_full_without_neighbor = np.concatenate(\n        (yaw_opt_full_without_neighbor, np.zeros(fmodel.n_turbines - 10))\n    )\n\n    # Now decide what to do for different wind speeds\n    wind_speed_low_no_steer = 4.0\n    wind_speed_high_no_steer = 14.0\n    wind_speed_low_steer = 6.0\n    wind_speed_high_steer = 12.0\n    if (wind_speed < wind_speed_low_no_steer) | (wind_speed > wind_speed_high_no_steer):\n        yaw_opt_with_neighbor = np.zeros(fmodel.n_turbines)  # do nothing for very low/high speeds\n        yaw_opt_without_neighbor = np.zeros(\n            fmodel.n_turbines\n        )  # do nothing for very low/high speeds\n    elif wind_speed < wind_speed_low_steer:\n        yaw_opt_with_neighbor = (\n            yaw_opt_full_with_neighbor\n            * (wind_speed_low_steer - wind_speed)\n            / (wind_speed_low_steer - wind_speed_low_no_steer)\n        )  # Linear ramp up\n        yaw_opt_without_neighbor = (\n            yaw_opt_full_without_neighbor\n            * (wind_speed_low_steer - wind_speed)\n            / (wind_speed_low_steer - wind_speed_low_no_steer)\n        )  # Linear ramp up\n    elif wind_speed > wind_speed_high_steer:\n        yaw_opt_with_neighbor = (\n            yaw_opt_full_with_neighbor\n            * (wind_speed_high_no_steer - wind_speed)\n            / (wind_speed_high_no_steer - wind_speed_high_steer)\n        )  # Linear ramp down\n        yaw_opt_without_neighbor = (\n            yaw_opt_full_without_neighbor\n            * (wind_speed_high_no_steer - wind_speed)\n            / (wind_speed_high_no_steer - wind_speed_high_steer)\n        )  # Linear ramp down\n    else:\n        yaw_opt_with_neighbor = (\n            yaw_opt_full_with_neighbor  # Apply full offsets between 6.0 and 12.0 m/s\n        )\n        yaw_opt_without_neighbor = (\n            yaw_opt_full_without_neighbor  # Apply full offsets between 6.0 and 12.0 m/s\n        )\n\n    # Save to collective array\n    yaw_angles_wind_rose_with_neighbor[i, :] = yaw_opt_with_neighbor\n    yaw_angles_wind_rose_without_neighbor[i, :] = yaw_opt_without_neighbor\n\n\n# Now apply the optimal yaw angles and get the AEP, first accounting for the neighboring farm\nfmodel.set(yaw_angles=yaw_angles_wind_rose_with_neighbor)\nfmodel.run()\naep_opt_with_neighbor = fmodel.get_farm_AEP(turbine_weights=turbine_weights)\naep_uplift_with_neighbor = 100.0 * (aep_opt_with_neighbor / aep_baseline - 1)\nfarm_power_opt_with_neighbor = fmodel.get_farm_power(turbine_weights=turbine_weights)\n\n# Repeat without accounting for neighboring farm\nfmodel.set(yaw_angles=yaw_angles_wind_rose_without_neighbor)\nfmodel.run()\naep_opt_without_neighbor = fmodel.get_farm_AEP(turbine_weights=turbine_weights)\naep_uplift_without_neighbor = 100.0 * (aep_opt_without_neighbor / aep_baseline - 1)\nfarm_power_opt_without_neighbor = fmodel.get_farm_power(turbine_weights=turbine_weights)\n\nprint(f\"Baseline AEP: {aep_baseline / 1e9:.2f} GWh.\")\nprint(\n    f\"Optimal AEP (Not accounting for neighboring farm): {aep_opt_without_neighbor / 1e9:.2f} GWh.\"\n)\nprint(f\"Optimal AEP (Accounting for neighboring farm): {aep_opt_with_neighbor / 1e9:.2f} GWh.\")\n\n# Plot the optimal yaw angles for turbine 0 with and without accounting for the neighboring farm\nyaw_angles_0_with_neighbor = np.vstack(df_opt_with_neighbor[\"yaw_angles_opt\"])[:, 0]\nyaw_angles_0_without_neighbor = np.vstack(df_opt_without_neighbor[\"yaw_angles_opt\"])[:, 0]\n\nfig, ax = plt.subplots()\nax.plot(\n    df_opt_with_neighbor[\"wind_direction\"],\n    yaw_angles_0_with_neighbor,\n    label=\"Accounting for neighboring farm\",\n)\nax.plot(\n    df_opt_without_neighbor[\"wind_direction\"],\n    yaw_angles_0_without_neighbor,\n    label=\"Not accounting for neighboring farm\",\n)\nax.set_xlabel(\"Wind direction (deg)\")\nax.set_ylabel(\"Yaw angle (deg)\")\nax.legend()\nax.grid(True)\nax.set_title(\"Optimal yaw angles for turbine 0\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_control_optimization/008_optimize_yaw_with_disabled_turbines.py",
    "content": "\"\"\"Example: Optimizing yaw angles with disabled turbines\n\nThis example demonstrates how to optimize yaw angles in FLORIS, when some turbines are disabled.\nThe example optimization is run using both YawOptimizerSR and YawOptimizerGeometric, the two\nyaw optimizers that support disabling turbines.\n\"\"\"\n\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom floris.optimization.yaw_optimization.yaw_optimizer_geometric import YawOptimizationGeometric\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\n# Load a 3-turbine model\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Set wind conditions to be the same for two cases\nfmodel.set(wind_directions=[270.]*2, wind_speeds=[8.]*2, turbulence_intensities=[.06]*2)\n\n# First run the case where all turbines are active and print results\nyaw_opt = YawOptimizationSR(fmodel)\ndf_opt = yaw_opt.optimize()\nprint(\"Serial Refine optimized yaw angles (all turbines active) [deg]:\\n\", df_opt.yaw_angles_opt)\n\nyaw_opt = YawOptimizationGeometric(fmodel)\ndf_opt = yaw_opt.optimize()\nprint(\"\\nGeometric optimized yaw angles (all turbines active) [deg]:\\n\", df_opt.yaw_angles_opt)\n\n# Disable turbines (different pattern for each of the two cases)\n# First case: disable the middle turbine\n# Second case: disable the front turbine\nfmodel.set_operation_model('mixed')\nfmodel.set(disable_turbines=np.array([[False, True, False], [True, False, False]]))\n\n# Rerun optimizations and print results\nyaw_opt = YawOptimizationSR(fmodel)\ndf_opt = yaw_opt.optimize()\nprint(\n    \"\\nSerial Refine optimized yaw angles (some turbines disabled) [deg]:\\n\",\n    df_opt.yaw_angles_opt\n)\n# Note that disabled turbines are assigned a zero yaw angle, but their yaw angle is arbitrary as it\n# does not affect the total power output.\n\nyaw_opt = YawOptimizationGeometric(fmodel)\ndf_opt = yaw_opt.optimize()\nprint(\"\\nGeometric optimized yaw angles (some turbines disabled) [deg]:\\n\", df_opt.yaw_angles_opt)\n"
  },
  {
    "path": "examples/examples_control_types/001_derating_control.py",
    "content": "\"\"\"Example of using the simple-derating control model in FLORIS.\n\nThis example demonstrates how to use the simple-derating control model in FLORIS.\nThe simple-derating control model allows the user to specify a power setpoint for each turbine\nin the farm. The power setpoint is used to derate the turbine power output to be at most the\npower setpoint.\n\nIn this example:\n\n1. A simple two-turbine layout is created.\n2. The wind conditions are set to be constant.\n3. The power setpoint is varied, and set the same for each turbine\n4. The power produced by each turbine is computed and plotted\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Change to the simple-derating model turbine\n# (Note this could also be done with the mixed model)\nfmodel.set_operation_model(\"simple-derating\")\n\n# Convert to a simple two turbine layout with derating turbines\nfmodel.set(layout_x=[0, 1000.0], layout_y=[0.0, 0.0])\n\n# For reference, load the turbine type\nturbine_type = fmodel.core.farm.turbine_definitions[0]\n\n# Set the wind directions and speeds to be constant over n_findex = N time steps\nN = 50\nfmodel.set(\n    wind_directions=270 * np.ones(N),\n    wind_speeds=10.0 * np.ones(N),\n    turbulence_intensities=0.06 * np.ones(N),\n)\nfmodel.run()\nturbine_powers_orig = fmodel.get_turbine_powers()\n\n# Add derating level to both turbines\npower_setpoints = np.tile(np.linspace(1, 6e6, N), 2).reshape(2, N).T\nfmodel.set(power_setpoints=power_setpoints)\nfmodel.run()\nturbine_powers_derated = fmodel.get_turbine_powers()\n\n# Compute available power at downstream turbine\npower_setpoints_2 = np.array([np.linspace(1, 6e6, N), np.full(N, None)]).T\nfmodel.set(power_setpoints=power_setpoints_2)\nfmodel.run()\nturbine_powers_avail_ds = fmodel.get_turbine_powers()[:, 1]\n\n# Plot the results\nfig, ax = plt.subplots(1, 1)\nax.plot(\n    power_setpoints[:, 0] / 1000, turbine_powers_derated[:, 0] / 1000, color=\"C0\", label=\"Upstream\"\n)\nax.plot(\n    power_setpoints[:, 1] / 1000,\n    turbine_powers_derated[:, 1] / 1000,\n    color=\"C1\",\n    label=\"Downstream\",\n)\nax.plot(\n    power_setpoints[:, 0] / 1000,\n    turbine_powers_orig[:, 0] / 1000,\n    color=\"C0\",\n    linestyle=\"dotted\",\n    label=\"Upstream available\",\n)\nax.plot(\n    power_setpoints[:, 1] / 1000,\n    turbine_powers_avail_ds / 1000,\n    color=\"C1\",\n    linestyle=\"dotted\",\n    label=\"Downstream available\",\n)\nax.plot(\n    power_setpoints[:, 1] / 1000,\n    np.ones(N) * np.max(turbine_type[\"power_thrust_table\"][\"power\"]),\n    color=\"k\",\n    linestyle=\"dashed\",\n    label=\"Rated power\",\n)\nax.grid()\nax.legend()\nax.set_xlim([0, 6e3])\nax.set_xlabel(\"Power setpoint (kW) [Applied to both turbines]\")\nax.set_ylabel(\"Power produced (kW)\")\n\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_control_types/002_disable_turbines.py",
    "content": "\"\"\"Example: Disabling turbines\n\nThis example is adapted from https://github.com/NatLabRockies/floris/pull/693\ncontributed by Elie Kadoche.\n\nThis example demonstrates the ability of FLORIS to shut down some turbines\nduring a simulation.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\n# Initialize FLORIS\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Change to the mixed model turbine\n# (Note this could also be done with the simple-derating model)\nfmodel.set_operation_model(\"mixed\")\n\n# Consider a wind farm of 3 aligned wind turbines\nlayout = np.array([[0.0, 0.0], [500.0, 0.0], [1000.0, 0.0]])\n\n# Run the computations for 2 identical wind data\n# (n_findex = 2)\nwind_directions = np.array([270.0, 270.0])\nwind_speeds = np.array([8.0, 8.0])\nturbulence_intensities = np.array([0.06, 0.06])\n\n# Shut down the first 2 turbines for the second findex\n# 2 findex x 3 turbines\ndisable_turbines = np.array([[False, False, False], [True, True, False]])\n\n# Simulation\n# ------------------------------------------\n\n# Reinitialize flow field\nfmodel.set(\n    layout_x=layout[:, 0],\n    layout_y=layout[:, 1],\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    turbulence_intensities=turbulence_intensities,\n    disable_turbines=disable_turbines,\n)\n\n# # Compute wakes\nfmodel.run()\n\n# Results\n# ------------------------------------------\n\n# Get powers and effective wind speeds\nturbine_powers = fmodel.get_turbine_powers()\nturbine_powers = np.round(turbine_powers * 1e-3, decimals=2)\neffective_wind_speeds = fmodel.turbine_average_velocities\n\n\n# Plot the results\nfig, axarr = plt.subplots(2, 1, sharex=True)\n\n# Plot the power\nax = axarr[0]\nax.plot([\"T0\", \"T1\", \"T2\"], turbine_powers[0, :], \"ks-\", label=\"All on\")\nax.plot([\"T0\", \"T1\", \"T2\"], turbine_powers[1, :], \"ro-\", label=\"T0 & T1 disabled\")\nax.set_ylabel(\"Power (kW)\")\nax.grid(True)\nax.legend()\n\nax = axarr[1]\nax.plot([\"T0\", \"T1\", \"T2\"], effective_wind_speeds[0, :], \"ks-\", label=\"All on\")\nax.plot([\"T0\", \"T1\", \"T2\"], effective_wind_speeds[1, :], \"ro-\", label=\"T0 & T1 disabled\")\nax.set_ylabel(\"Effective wind speeds (m/s)\")\nax.grid(True)\nax.legend()\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_control_types/003_setting_yaw_and_disabling.py",
    "content": "\"\"\"Example: Setting yaw angles and disabling turbine\n\nThis example demonstrates how to set yaw angles and disable turbines in FLORIS.\nThe yaw angles are set to sweep from -20 to 20 degrees for the upstream-most turbine\nand to 0 degrees for the downstream-most turbine(s).  A two-turbine case is compared\nto a three-turbine case where the middle turbine is disabled making the two cases\nfunctionally equivalent.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, TimeSeries\n\n\n# Initialize 2 FLORIS models, a two-turbine layout\n# and three-turbine layout\nfmodel_2 = FlorisModel(\"../inputs/gch.yaml\")\nfmodel_3 = FlorisModel(\"../inputs/gch.yaml\")\n\n# Change to the mixed model turbine\n# This example sets both yaw angle and power setpoints\nfmodel_2.set_operation_model(\"mixed\")\nfmodel_3.set_operation_model(\"mixed\")\n\n# Set the layouts, f_model_3 has an extra turbine in-between the two\n# turbines of f_model_2\nfmodel_2.set(layout_x=[0, 1000.0], layout_y=[0.0, 0.0])\nfmodel_3.set(layout_x=[0, 500.0, 1000.0], layout_y=[0.0, 0.0, 0.0])\n\n# Set bo\n\n# Set both to have constant wind conditions\nN = 50\ntime_series = TimeSeries(\n    wind_directions=270.0 * np.ones(N),\n    wind_speeds = 8.,\n    turbulence_intensities=0.06\n    )\nfmodel_2.set(wind_data=time_series)\nfmodel_3.set(wind_data=time_series)\n\n# In both cases, set the yaw angles of the upstream-most turbine\n# to sweep from -20 to 20 degrees, while other turbines are set to 0\nupstream_yaw_angles = np.linspace(-20, 20, N)\nyaw_angles_2 = np.array([upstream_yaw_angles, np.zeros(N)]).T\nyaw_angles_3 = np.array([upstream_yaw_angles, np.zeros(N), np.zeros(N)]).T\n\n# In the three turbine case, also disable the middle turbine\n# Declare a np array of booleans that is Nx3 and whose middle column is True\ndisable_turbines = np.array([np.zeros(N), np.ones(N), np.zeros(N)]).T.astype(bool)\n\n# Set the yaw angles for both and disable the middle turbine for the\n# three turbine case\nfmodel_2.set(yaw_angles=yaw_angles_2)\nfmodel_3.set(yaw_angles=yaw_angles_3, disable_turbines=disable_turbines)\n\n# Run both models\nfmodel_2.run()\nfmodel_3.run()\n\n# Collect the turbine powers from both\nturbine_powers_2 = fmodel_2.get_turbine_powers()\nturbine_powers_3 = fmodel_3.get_turbine_powers()\n\n# Make a 2-panel plot of the turbine powers.  For the three-turbine case,\n# only plot the first and last turbine\nfig, axarr = plt.subplots(2, 1, sharex=True)\naxarr[0].plot(upstream_yaw_angles, turbine_powers_2[:, 0] / 1000, label=\"Two-Turbine\", marker='s')\naxarr[0].plot(upstream_yaw_angles, turbine_powers_3[:, 0] / 1000, label=\"Three-Turbine\", marker='.')\naxarr[0].set_ylabel(\"Power (kW)\")\naxarr[0].legend()\naxarr[0].grid(True)\naxarr[0].set_title(\"Upstream Turbine\")\n\naxarr[1].plot(upstream_yaw_angles, turbine_powers_2[:, 1] / 1000, label=\"Two-Turbine\", marker='s')\naxarr[1].plot(upstream_yaw_angles, turbine_powers_3[:, 2] / 1000, label=\"Three-Turbine\", marker='.')\naxarr[1].set_ylabel(\"Power (kW)\")\naxarr[1].legend()\naxarr[1].grid(True)\naxarr[1].set_title(\"Downstream-most Turbine\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_control_types/004_helix_active_wake_mixing.py",
    "content": "\"\"\"Example: Helix active wake mixing\n\nExample to test out using helix wake mixing of upstream turbines.\nHelix wake mixing is turned on at turbine 1, off at turbines 2 to 4;\nTurbine 2 is in wake turbine 1, turbine 4 in wake of turbine 3.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport yaml\n\nimport floris.flow_visualization as flowviz\nfrom floris import FlorisModel\n\n\n# Grab model of FLORIS and update to awc-enabled turbines\nfmodel = FlorisModel(\"../inputs/emgauss_helix.yaml\")\nfmodel.set_operation_model(\"awc\")\n\n# Set the wind directions and speeds to be constant over N different helix amplitudes\nN = 1\nawc_modes = np.array([\"helix\", \"baseline\", \"baseline\", \"baseline\"]).reshape(4, N).T\nawc_amplitudes = np.array([2.5, 0, 0, 0]).reshape(4, N).T\n\n# Create 4 WT WF layout with lateral offset of 3D and streamwise offset of 4D\nD = 240\nfmodel.set(\n    layout_x=[0.0, 4*D, 0.0, 4*D],\n    layout_y=[0.0, 0.0, -3*D, -3*D],\n    wind_directions=270 * np.ones(N),\n    wind_speeds=8.0 * np.ones(N),\n    turbulence_intensities=0.06*np.ones(N),\n    awc_modes=awc_modes,\n    awc_amplitudes=awc_amplitudes\n)\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers()\n\n# Plot the flow fields for T1 awc_amplitude = 2.5\nhorizontal_plane = fmodel.calculate_horizontal_plane(\n    x_resolution=200,\n    y_resolution=100,\n    height=150.0,\n)\n\ny_plane_baseline = fmodel.calculate_y_plane(\n    x_resolution=200,\n    z_resolution=100,\n    crossstream_dist=0.0,\n)\ny_plane_helix = fmodel.calculate_y_plane(\n    x_resolution=200,\n    z_resolution=100,\n    crossstream_dist=-3*D,\n)\n\ncross_plane = fmodel.calculate_cross_plane(\n    y_resolution=100,\n    z_resolution=100,\n    downstream_dist=720.0,\n)\n\n# Create the plots\nfig, ax_list = plt.subplots(2, 2, figsize=(10, 8), tight_layout=True)\nax_list = ax_list.flatten()\nflowviz.visualize_cut_plane(\n    horizontal_plane,\n    ax=ax_list[0],\n    label_contours=True,\n    title=\"Horizontal\"\n)\nflowviz.visualize_cut_plane(\n    cross_plane,\n    ax=ax_list[2],\n    label_contours=True,\n    title=\"Spanwise profile at 3D\"\n)\n\n# fig2, ax_list2 = plt.subplots(2, 1, figsize=(10, 8), tight_layout=True)\n# ax_list2 = ax_list2.flatten()\nflowviz.visualize_cut_plane(\n    y_plane_baseline,\n    ax=ax_list[1],\n    label_contours=True,\n    title=\"Streamwise profile, helix\"\n)\nflowviz.visualize_cut_plane(\n    y_plane_helix,\n    ax=ax_list[3],\n    label_contours=True,\n    title=\"Streamwise profile, baseline\"\n)\n\n# Calculate the effect of changing awc_amplitudes\nN = 50\nawc_amplitudes = np.array([\n    np.linspace(0, 5, N),\n    np.zeros(N), np.zeros(N), np.zeros(N)\n    ]).reshape(4, N).T\nawc_modes = np.tile(awc_modes, (N,1)) # Repeat over N findices\n\n# Reset FlorisModel for different helix amplitudes\nfmodel.set(\n    wind_directions=270 * np.ones(N),\n    wind_speeds=8 * np.ones(N),\n    turbulence_intensities=0.06*np.ones(N),\n    awc_modes=awc_modes,\n    awc_amplitudes=awc_amplitudes\n    )\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers()\n\n# Plot the power as a function of helix amplitude\nfig_power, ax_power = plt.subplots()\nax_power.fill_between(\n    awc_amplitudes[:, 0],\n    0,\n    turbine_powers[:, 0]/1000,\n    color='C0',\n    label='Turbine 1'\n    )\nax_power.fill_between(\n    awc_amplitudes[:, 0],\n    turbine_powers[:, 0]/1000,\n    turbine_powers[:, :2].sum(axis=1)/1000,\n    color='C1',\n    label='Turbine 2'\n    )\nax_power.plot(\n    awc_amplitudes[:, 0],\n    turbine_powers[:,:2].sum(axis=1)/1000,\n    color='k',\n    label='Farm'\n    )\n\nax_power.set_xlabel(\"Upstream turbine helix amplitude [deg]\")\nax_power.set_ylabel(\"Power [kW]\")\nax_power.legend()\n\nflowviz.show()\n"
  },
  {
    "path": "examples/examples_control_types/005_peak_shaving.py",
    "content": "\"\"\"Example of using the peak-shaving turbine operation model.\n\nThis example demonstrates how to use the peak-shaving operation model in FLORIS.\nThe peak-shaving operation model allows the user to a thrust reduction near rated wind speed to\nreduce loads on the turbine. The power is reduced accordingly, and wind turbine wakes\nare shallower due to the reduced thrust.\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, TimeSeries\n\n\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\nfmodel.set(layout_x=[0, 1000.0], layout_y=[0.0, 0.0])\nwind_speeds = np.linspace(0, 30, 100)\nfmodel.set(\n    wind_data=TimeSeries(\n        wind_directions=270 * np.ones_like(wind_speeds),\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.10, # High enough to engage peak shaving\n    )\n)\n\n# Start with \"normal\" operation under the simple turbine operation model\nfmodel.set_operation_model(\"simple\")\nfmodel.run()\npowers_base = fmodel.get_turbine_powers()/1000\nthrust_coefficients_base = fmodel.get_turbine_thrust_coefficients()\n\n# Switch to the peak-shaving operation model\nfmodel.set_operation_model(\"peak-shaving\")\nfmodel.run()\npowers_peak_shaving = fmodel.get_turbine_powers()/1000\nthrust_coefficients_peak_shaving = fmodel.get_turbine_thrust_coefficients()\n\n# Compare the power and thrust coefficients of the upstream turbine\nfig, ax = plt.subplots(2,1,sharex=True)\nax[0].plot(\n    wind_speeds,\n    thrust_coefficients_base[:,0],\n    label=\"Without peak shaving\",\n    color=\"black\"\n)\nax[0].plot(\n    wind_speeds,\n    thrust_coefficients_peak_shaving[:,0],\n    label=\"With peak shaving\",\n    color=\"C0\"\n)\nax[1].plot(\n    wind_speeds,\n    powers_base[:,0],\n    label=\"Without peak shaving\",\n    color=\"black\"\n)\nax[1].plot(\n    wind_speeds,\n    powers_peak_shaving[:,0],\n    label=\"With peak shaving\",\n    color=\"C0\"\n)\nax[1].grid()\nax[0].grid()\nax[0].legend()\nax[0].set_ylabel(\"Thrust coefficient [-]\")\nax[1].set_xlabel(\"Wind speed [m/s]\")\nax[1].set_ylabel(\"Power [kW]\")\n\n# Look at the total power across the two turbines for each case\nfig, ax = plt.subplots(2,1,sharex=True,sharey=True)\nax[0].fill_between(\n    wind_speeds,\n    0,\n    powers_base[:, 0]/1e6,\n    color='C0',\n    label='Turbine 1'\n)\nax[0].fill_between(\n    wind_speeds,\n    powers_base[:, 0]/1e6,\n    powers_base[:, :2].sum(axis=1)/1e6,\n    color='C1',\n    label='Turbine 2'\n    )\nax[0].plot(\n    wind_speeds,\n    powers_base[:,:2].sum(axis=1)/1e6,\n    color='k',\n    label='Farm'\n)\nax[1].fill_between(\n    wind_speeds,\n    0,\n    powers_peak_shaving[:, 0]/1e6,\n    color='C0',\n    label='Turbine 1'\n)\nax[1].fill_between(\n    wind_speeds,\n    powers_peak_shaving[:, 0]/1e6,\n    powers_peak_shaving[:, :2].sum(axis=1)/1e6,\n    color='C1',\n    label='Turbine 2'\n    )\nax[1].plot(\n    wind_speeds,\n    powers_peak_shaving[:,:2].sum(axis=1)/1e6,\n    color='k',\n    label='Farm'\n)\nax[0].legend()\nax[0].set_title(\"Without peak shaving\")\nax[1].set_title(\"With peak shaving\")\nax[0].set_ylabel(\"Power [MW]\")\nax[1].set_ylabel(\"Power [MW]\")\nax[0].grid()\nax[1].grid()\n\nax[1].set_xlabel(\"Free stream wind speed [m/s]\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_emgauss/001_empirical_gauss_velocity_deficit_parameters.py",
    "content": "\"\"\"Example: Empirical Gaussian velocity deficit parameters\nThis example illustrates the main parameters of the Empirical Gaussian\nvelocity deficit model and their effects on the wind turbine wake.\n\"\"\"\n\nimport copy\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom floris.flow_visualization import visualize_cut_plane\n\n\n# Options\nshow_flow_cuts = True\nnum_in_row = 5\n\n# Define function for visualizing wakes\ndef generate_wake_visualization(fmodel: FlorisModel, title=None):\n    # Using the FlorisModel functions, get 2D slices.\n    x_bounds = [-500, 3000]\n    y_bounds = [-250, 250]\n    z_bounds = [0.001, 500]\n    cross_plane_locations = [10, 1200, 2500]\n    horizontal_plane_location = 90.0\n    streamwise_plane_location = 0.0\n    # Contour plot colors\n    min_ws = 4\n    max_ws = 10\n\n    horizontal_plane = fmodel.calculate_horizontal_plane(\n        x_resolution=200,\n        y_resolution=100,\n        height=horizontal_plane_location,\n        x_bounds=x_bounds,\n        y_bounds=y_bounds,\n    )\n    y_plane = fmodel.calculate_y_plane(\n        x_resolution=200,\n        z_resolution=100,\n        crossstream_dist=streamwise_plane_location,\n        x_bounds=x_bounds,\n        z_bounds=z_bounds,\n    )\n    cross_planes = [\n        fmodel.calculate_cross_plane(y_resolution=100, z_resolution=100, downstream_dist=x)\n        for x in cross_plane_locations\n    ]\n\n    # Create the plots\n    # Cutplane settings\n    cp_ls = \"solid\"  # line style\n    cp_lw = 0.5  # line width\n    cp_clr = \"black\"  # line color\n    fig = plt.figure()\n    fig.set_size_inches(12, 12)\n    # Horizontal profile\n    ax = fig.add_subplot(311)\n    visualize_cut_plane(\n        horizontal_plane, ax=ax, title=\"Top-down profile\", min_speed=min_ws, max_speed=max_ws\n    )\n    ax.plot(\n        x_bounds, [streamwise_plane_location] * 2, color=cp_clr, linewidth=cp_lw, linestyle=cp_ls\n    )\n    for cpl in cross_plane_locations:\n        ax.plot([cpl] * 2, y_bounds, color=cp_clr, linewidth=cp_lw, linestyle=cp_ls)\n\n    ax = fig.add_subplot(312)\n    visualize_cut_plane(\n        y_plane, ax=ax, title=\"Streamwise profile\", min_speed=min_ws, max_speed=max_ws\n    )\n    ax.plot(\n        x_bounds, [horizontal_plane_location] * 2, color=cp_clr, linewidth=cp_lw, linestyle=cp_ls\n    )\n    for cpl in cross_plane_locations:\n        ax.plot([cpl, cpl], z_bounds, color=cp_clr, linewidth=cp_lw, linestyle=cp_ls)\n\n    # Spanwise profiles\n    for i, (cp, cpl) in enumerate(zip(cross_planes, cross_plane_locations)):\n        visualize_cut_plane(\n            cp,\n            ax=fig.add_subplot(3, len(cross_planes), i + 7),\n            title=\"Loc: {:.0f}m\".format(cpl),\n            min_speed=min_ws,\n            max_speed=max_ws,\n        )\n\n    # Add overall figure title\n    if title is not None:\n        fig.suptitle(title, fontsize=16)\n\n\n## Main script\n\n# Load input yaml and define farm layout\nfmodel = FlorisModel(\"../inputs/emgauss.yaml\")\nD = fmodel.core.farm.rotor_diameters[0]\nfmodel.set(\n    layout_x=[x * 5.0 * D for x in range(num_in_row)],\n    layout_y=[0.0] * num_in_row,\n    wind_speeds=[8.0],\n    wind_directions=[270.0],\n)\n\n# Save dictionary to modify later\nfmodel_dict = fmodel.core.as_dict()\n\n# Run wake calculation\nfmodel.run()\n\n# Look at the powers of each turbine\nturbine_powers = fmodel.get_turbine_powers().flatten() / 1e6\n\nfig0, ax0 = plt.subplots(1, 1)\nwidth = 0.1\nnw = -2\nx = np.array(range(num_in_row)) + width * nw\nnw += 1\n\ntitle = \"Original\"\nax0.bar(x, turbine_powers, width=width, label=title)\nax0.legend()\n\n# Visualize wakes\nif show_flow_cuts:\n    generate_wake_visualization(fmodel, title)\n\n# Increase the base recovery rate\nfmodel_dict_mod = copy.deepcopy(fmodel_dict)\nfmodel_dict_mod[\"wake\"][\"wake_velocity_parameters\"][\"empirical_gauss\"][\"wake_expansion_rates\"] = [\n    0.03,\n    0.015,\n]\nfmodel = FlorisModel(fmodel_dict_mod)\nfmodel.set(wind_speeds=[8.0], wind_directions=[270.0])\n\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers().flatten() / 1e6\n\nx = np.array(range(num_in_row)) + width * nw\nnw += 1\n\ntitle = \"Increase base recovery\"\nax0.bar(x, turbine_powers, width=width, label=title)\n\nif show_flow_cuts:\n    generate_wake_visualization(fmodel, title)\n\n# Add new expansion rate\nfmodel_dict_mod = copy.deepcopy(fmodel_dict)\nfmodel_dict_mod[\"wake\"][\"wake_velocity_parameters\"][\"empirical_gauss\"][\"wake_expansion_rates\"] = (\n    fmodel_dict[\"wake\"][\"wake_velocity_parameters\"][\"empirical_gauss\"][\"wake_expansion_rates\"]\n    + [0.0]\n)\nfmodel_dict_mod[\"wake\"][\"wake_velocity_parameters\"][\"empirical_gauss\"][\"breakpoints_D\"] = [5, 10]\n\nfmodel = FlorisModel(fmodel_dict_mod)\nfmodel.set(wind_speeds=[8.0], wind_directions=[270.0])\n\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers().flatten() / 1e6\n\nx = np.array(range(num_in_row)) + width * nw\nnw += 1\n\ntitle = \"Add rate, change breakpoints\"\nax0.bar(x, turbine_powers, width=width, label=title)\n\nif show_flow_cuts:\n    generate_wake_visualization(fmodel, title)\n\n# Increase the wake-induced mixing gain\nfmodel_dict_mod = copy.deepcopy(fmodel_dict)\nfmodel_dict_mod[\"wake\"][\"wake_velocity_parameters\"][\"empirical_gauss\"][\"mixing_gain_velocity\"] = 3.0\nfmodel = FlorisModel(fmodel_dict_mod)\nfmodel.set(wind_speeds=[8.0], wind_directions=[270.0])\n\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers().flatten() / 1e6\n\nx = np.array(range(num_in_row)) + width * nw\nnw += 1\n\ntitle = \"Increase mixing gain\"\nax0.bar(x, turbine_powers, width=width, label=title)\n\nif show_flow_cuts:\n    generate_wake_visualization(fmodel, title)\n\n# Power plot aesthetics\nax0.set_xticks(range(num_in_row))\nax0.set_xticklabels([\"T{0}\".format(t) for t in range(num_in_row)])\nax0.legend()\nax0.set_xlabel(\"Turbine\")\nax0.set_ylabel(\"Power [MW]\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_emgauss/002_empirical_gauss_deflection_parameters.py",
    "content": "\"\"\"Example: Empirical Gaussian deflection parameters\n\nThis example illustrates the main parameters of the Empirical Gaussian\ndeflection model and their effects on the wind turbine wake.\n\"\"\"\n\nimport copy\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom floris.flow_visualization import visualize_cut_plane\n\n\n# Initialize FLORIS with the given input file.\n# For basic usage, FlorisModel provides a simplified and expressive\n# entry point to the simulation routines.\n\n# Options\nshow_flow_cuts = True\nnum_in_row = 5  # Should be at least 3\nfirst_three_yaw_angles = [20.0, 20.0, 10.0]\n\nyaw_angles = np.array(first_three_yaw_angles + [0.0] * (num_in_row - 3))[None, :]\n\nprint(\"Turbine yaw angles (degrees): \", yaw_angles[0])\n\n\n# Define function for visualizing wakes\ndef generate_wake_visualization(fmodel: FlorisModel, title=None):\n    # Using the FlorisModel functions, get 2D slices.\n    x_bounds = [-500, 3000]\n    y_bounds = [-250, 250]\n    z_bounds = [0.001, 500]\n    cross_plane_locations = [10, 1200, 2500]\n    horizontal_plane_location = 90.0\n    streamwise_plane_location = 0.0\n    # Contour plot colors\n    min_ws = 4\n    max_ws = 10\n\n    horizontal_plane = fmodel.calculate_horizontal_plane(\n        x_resolution=200,\n        y_resolution=100,\n        height=horizontal_plane_location,\n        x_bounds=x_bounds,\n        y_bounds=y_bounds,\n    )\n    y_plane = fmodel.calculate_y_plane(\n        x_resolution=200,\n        z_resolution=100,\n        crossstream_dist=streamwise_plane_location,\n        x_bounds=x_bounds,\n        z_bounds=z_bounds,\n    )\n    cross_planes = [\n        fmodel.calculate_cross_plane(y_resolution=100, z_resolution=100, downstream_dist=x)\n        for x in cross_plane_locations\n    ]\n\n    # Create the plots\n    # Cutplane settings\n    cp_ls = \"solid\"  # line style\n    cp_lw = 0.5  # line width\n    cp_clr = \"black\"  # line color\n    fig = plt.figure()\n    fig.set_size_inches(12, 12)\n    # Horizontal profile\n    ax = fig.add_subplot(311)\n    visualize_cut_plane(\n        horizontal_plane, ax=ax, title=\"Top-down profile\", min_speed=min_ws, max_speed=max_ws\n    )\n    ax.plot(\n        x_bounds, [streamwise_plane_location] * 2, color=cp_clr, linewidth=cp_lw, linestyle=cp_ls\n    )\n    for cpl in cross_plane_locations:\n        ax.plot([cpl] * 2, y_bounds, color=cp_clr, linewidth=cp_lw, linestyle=cp_ls)\n\n    ax = fig.add_subplot(312)\n    visualize_cut_plane(\n        y_plane, ax=ax, title=\"Streamwise profile\", min_speed=min_ws, max_speed=max_ws\n    )\n    ax.plot(\n        x_bounds, [horizontal_plane_location] * 2, color=cp_clr, linewidth=cp_lw, linestyle=cp_ls\n    )\n    for cpl in cross_plane_locations:\n        ax.plot([cpl, cpl], z_bounds, color=cp_clr, linewidth=cp_lw, linestyle=cp_ls)\n\n    # Spanwise profiles\n    for i, (cp, cpl) in enumerate(zip(cross_planes, cross_plane_locations, strict=False)):\n        visualize_cut_plane(\n            cp,\n            ax=fig.add_subplot(3, len(cross_planes), i + 7),\n            title=f\"Loc: {cpl:.0f}m\",\n            min_speed=min_ws,\n            max_speed=max_ws,\n        )\n\n    # Add overall figure title\n    if title is not None:\n        fig.suptitle(title, fontsize=16)\n\n\n## Main script\n\n# Load input yaml and define farm layout\nfmodel = FlorisModel(\"../inputs/emgauss.yaml\")\nD = fmodel.core.farm.rotor_diameters[0]\nfmodel.set(\n    layout_x=[x * 5.0 * D for x in range(num_in_row)],\n    layout_y=[0.0] * num_in_row,\n    wind_speeds=[8.0],\n    wind_directions=[270.0],\n    yaw_angles=yaw_angles,\n)\n\n# Save dictionary to modify later\nfmodel_dict = fmodel.core.as_dict()\n\n# Run wake calculation\nfmodel.run()\n\n# Look at the powers of each turbine\nturbine_powers = fmodel.get_turbine_powers().flatten() / 1e6\n\nfig0, ax0 = plt.subplots(1, 1)\nwidth = 0.1\nnw = -2\nx = np.array(range(num_in_row)) + width * nw\nnw += 1\n\ntitle = \"Original\"\nax0.bar(x, turbine_powers, width=width, label=title)\nax0.legend()\n\n# Visualize wakes\nif show_flow_cuts:\n    generate_wake_visualization(fmodel, title)\n\n# Increase the maximum deflection attained\nfmodel_dict_mod = copy.deepcopy(fmodel_dict)\n\nfmodel_dict_mod[\"wake\"][\"wake_deflection_parameters\"][\"empirical_gauss\"][\n    \"horizontal_deflection_gain_D\"\n] = 5.0\n\nfmodel = FlorisModel(fmodel_dict_mod)\nfmodel.set(\n    wind_speeds=[8.0],\n    wind_directions=[270.0],\n    yaw_angles=yaw_angles,\n)\n\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers().flatten() / 1e6\n\nx = np.array(range(num_in_row)) + width * nw\nnw += 1\n\ntitle = \"Increase max deflection\"\nax0.bar(x, turbine_powers, width=width, label=title)\n\nif show_flow_cuts:\n    generate_wake_visualization(fmodel, title)\n\n# Add (increase) influence of wake added mixing\nfmodel_dict_mod = copy.deepcopy(fmodel_dict)\nfmodel_dict_mod[\"wake\"][\"wake_deflection_parameters\"][\"empirical_gauss\"][\n    \"mixing_gain_deflection\"\n] = 100.0\n\nfmodel = FlorisModel(fmodel_dict_mod)\nfmodel.set(\n    wind_speeds=[8.0],\n    wind_directions=[270.0],\n    yaw_angles=yaw_angles,\n)\n\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers().flatten() / 1e6\n\nx = np.array(range(num_in_row)) + width * nw\nnw += 1\n\ntitle = \"Increase mixing gain\"\nax0.bar(x, turbine_powers, width=width, label=title)\n\nif show_flow_cuts:\n    generate_wake_visualization(fmodel, title)\n\n# Add (increase) the yaw-added mixing contribution\nfmodel_dict_mod = copy.deepcopy(fmodel_dict)\n# Include a WIM gain so that YAM is reflected in deflection as well\n# as deficit\nfmodel_dict_mod[\"wake\"][\"wake_deflection_parameters\"][\"empirical_gauss\"][\n    \"mixing_gain_deflection\"\n] = 100.0\nfmodel_dict_mod[\"wake\"][\"wake_deflection_parameters\"][\"empirical_gauss\"][\n    \"yaw_added_mixing_gain\"\n] = 1.0\nfmodel = FlorisModel(fmodel_dict_mod)\nfmodel.set(\n    wind_speeds=[8.0],\n    wind_directions=[270.0],\n    yaw_angles=yaw_angles,\n)\n\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers().flatten() / 1e6\n\nx = np.array(range(num_in_row)) + width * nw\nnw += 1\n\ntitle = \"Increase yaw-added mixing\"\nax0.bar(x, turbine_powers, width=width, label=title)\n\nif show_flow_cuts:\n    generate_wake_visualization(fmodel, title)\n\n# Power plot aesthetics\nax0.set_xticks(range(num_in_row))\nax0.set_xticklabels([f\"T{t}\" for t in range(num_in_row)])\nax0.legend()\nax0.set_xlabel(\"Turbine\")\nax0.set_ylabel(\"Power [MW]\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_floating/001_floating_turbine_models.py",
    "content": "\"\"\"Example: Floating turbines\nThis example demonstrates the impact of floating on turbine power and thrust (not wake behavior).\nA floating turbine in FLORIS is defined by including a `floating_tilt_table` in the turbine\ninput yaml which sets the steady tilt angle of the turbine based on wind speed.  This tilt angle\nis computed for each turbine based on effective velocity.  This tilt angle is then passed on\nto the respective wake model.\n\nThe value of the parameter ref_tilt is the value of tilt at which the ct/cp curves\nhave been defined.\n\nIf `correct_cp_ct_for_tilt` is True, then the difference between the current tilt as\ninterpolated from the floating tilt table is used to scale the turbine power and thrust.\n\nIf `correct_cp_ct_for_tilt` is False, then it is assumed that the power/thrust coefficient tables\nprovided already account for the variation in tilt with wind speed (for example they were computed\nfrom a turbine simulator with tilt degree-of-freedom enabled and the floating platform simulated),\nand no correction is made.\n\nIn the example below, three single-turbine simulations are run to show the different behaviors.\n\nfmodel_fixed: Fixed bottom turbine (no tilt variation with wind speed)\nfmodel_floating: Floating turbine (tilt varies with wind speed)\nfmodel_floating_defined_floating: Floating turbine (tilt varies with wind speed, but\n    tilt does not scale power/thrust coefficient)\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, TimeSeries\n\n\n# Create the Floris instances\nfmodel_fixed = FlorisModel(\"../inputs_floating/gch_fixed.yaml\")\nfmodel_floating = FlorisModel(\"../inputs_floating/gch_floating.yaml\")\nfmodel_floating_defined_floating = FlorisModel(\n    \"../inputs_floating/gch_floating_defined_floating.yaml\"\n)\n\n# Calculate across wind speeds, while holding win directions constant\nws_array = np.arange(3.0, 25.0, 1.0)\ntime_series = TimeSeries(wind_directions=270.0, wind_speeds=ws_array, turbulence_intensities=0.06)\nfmodel_fixed.set(wind_data=time_series)\nfmodel_floating.set(wind_data=time_series)\nfmodel_floating_defined_floating.set(wind_data=time_series)\n\nfmodel_fixed.run()\nfmodel_floating.run()\nfmodel_floating_defined_floating.run()\n\n# Grab power\npower_fixed = fmodel_fixed.get_turbine_powers().flatten() / 1000.0\npower_floating = fmodel_floating.get_turbine_powers().flatten() / 1000.0\npower_floating_defined_floating = (\n    fmodel_floating_defined_floating.get_turbine_powers().flatten() / 1000.0\n)\n\n# Grab Ct\nct_fixed = fmodel_fixed.get_turbine_thrust_coefficients().flatten()\nct_floating = fmodel_floating.get_turbine_thrust_coefficients().flatten()\nct_floating_defined_floating = (\n    fmodel_floating_defined_floating.get_turbine_thrust_coefficients().flatten()\n)\n\n# Grab turbine tilt angles\neff_vels = fmodel_fixed.turbine_average_velocities\ntilt_angles_fixed = np.squeeze(fmodel_fixed.core.farm.calculate_tilt_for_eff_velocities(eff_vels))\n\neff_vels = fmodel_floating.turbine_average_velocities\ntilt_angles_floating = np.squeeze(\n    fmodel_floating.core.farm.calculate_tilt_for_eff_velocities(eff_vels)\n)\n\neff_vels = fmodel_floating_defined_floating.turbine_average_velocities\ntilt_angles_floating_defined_floating = np.squeeze(\n    fmodel_floating_defined_floating.core.farm.calculate_tilt_for_eff_velocities(eff_vels)\n)\n\n# Plot results\n\nfig, axarr = plt.subplots(4, 1, figsize=(8, 10), sharex=True)\n\nax = axarr[0]\nax.plot(ws_array, tilt_angles_fixed, color=\"k\", lw=2, label=\"Fixed Bottom\")\nax.plot(ws_array, tilt_angles_floating, color=\"b\", label=\"Floating\")\nax.plot(\n    ws_array,\n    tilt_angles_floating_defined_floating,\n    color=\"m\",\n    ls=\"--\",\n    label=\"Floating (power/thrust coefficient not scaled by tilt)\",\n)\nax.grid(True)\nax.legend()\nax.set_title(\"Tilt angle (deg)\")\nax.set_ylabel(\"Tlit (deg)\")\n\nax = axarr[1]\nax.plot(ws_array, power_fixed, color=\"k\", lw=2, label=\"Fixed Bottom\")\nax.plot(ws_array, power_floating, color=\"b\", label=\"Floating\")\nax.plot(\n    ws_array,\n    power_floating_defined_floating,\n    color=\"m\",\n    ls=\"--\",\n    label=\"Floating (power/thrust coefficient not scaled by tilt)\",\n)\nax.grid(True)\nax.legend()\nax.set_title(\"Power\")\nax.set_ylabel(\"Power (kW)\")\n\nax = axarr[2]\n# ax.plot(ws_array, power_fixed, color='k',label='Fixed Bottom')\nax.plot(ws_array, power_floating - power_fixed, color=\"b\", label=\"Floating\")\nax.plot(\n    ws_array,\n    power_floating_defined_floating - power_fixed,\n    color=\"m\",\n    ls=\"--\",\n    label=\"Floating (power/thrust coefficient not scaled by tilt)\",\n)\nax.grid(True)\nax.legend()\nax.set_title(\"Difference from fixed bottom power\")\nax.set_ylabel(\"Power (kW)\")\n\nax = axarr[3]\nax.plot(ws_array, ct_fixed, color=\"k\", lw=2, label=\"Fixed Bottom\")\nax.plot(ws_array, ct_floating, color=\"b\", label=\"Floating\")\nax.plot(\n    ws_array,\n    ct_floating_defined_floating,\n    color=\"m\",\n    ls=\"--\",\n    label=\"Floating (power/thrust coefficient not scaled by tilt)\",\n)\nax.grid(True)\nax.legend()\nax.set_title(\"Coefficient of thrust\")\nax.set_ylabel(\"Ct (-)\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_floating/002_floating_vs_fixedbottom_farm.py",
    "content": "\"\"\"Example: Floating vs fixed-bottom farm\nThis example demonstrates the impact of floating on turbine power and thrust\nand wake behavior. A floating turbine in FLORIS is defined by including a\n`floating_tilt_table` in the turbine input yaml which sets the steady tilt\nangle of the turbine based on wind speed.  This tilt angle is computed for each\nturbine based on effective velocity.  This tilt angle is then passed on\nto the respective wake model.\n\nThe value of the parameter ref_tilt is the value of tilt at which the\nct/cp curves have been defined.\n\nWith `correct_cp_ct_for_tilt` True, the difference between the current\ntilt as interpolated from the floating tilt table is used to scale the turbine\npower and thrust.\n\nIn the example below, a 20-turbine, gridded wind farm is simulated using\nthe Empirical Gaussian wake model to show the effects of floating turbines on\nboth turbine power and wake development.\n\nfmodel_fixed: Fixed bottom turbine (no tilt variation with wind speed)\nfmodel_floating: Floating turbine (tilt varies with wind speed)\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom scipy.interpolate import NearestNDInterpolator\n\nimport floris.flow_visualization as flowviz\nfrom floris import FlorisModel, WindRose\n\n\n# Declare the Floris Interface for fixed bottom, provide layout\nfmodel_fixed = FlorisModel(\"../inputs_floating/emgauss_fixed.yaml\")\nfmodel_floating = FlorisModel(\"../inputs_floating/emgauss_floating.yaml\")\nx, y = np.meshgrid(np.linspace(0, 4*630., 5), np.linspace(0, 3*630., 4))\nx = x.flatten()\ny = y.flatten()\nfor fmodel in [fmodel_fixed, fmodel_floating]:\n    fmodel.set(layout_x=x, layout_y=y)\n\n# Compute a single wind speed and direction, power and wakes\nfor fmodel in [fmodel_fixed, fmodel_floating]:\n    fmodel.set(\n        layout_x=x,\n        layout_y=y,\n        wind_speeds=[10],\n        wind_directions=[270],\n        turbulence_intensities=[0.06],\n    )\n    fmodel.run()\n\npowers_fixed = fmodel_fixed.get_turbine_powers()\npowers_floating = fmodel_floating.get_turbine_powers()\npower_difference = powers_floating - powers_fixed\n\n# Show the power differences\nfig, ax = plt.subplots()\nax.set_aspect('equal', adjustable='box')\nsc = ax.scatter(\n    x,\n    y,\n    c=power_difference.flatten()/1000,\n    cmap=\"PuOr\",\n    vmin=-30,\n    vmax=30,\n    s=200,\n)\nax.set_xlabel(\"x coordinate [m]\")\nax.set_ylabel(\"y coordinate [m]\")\nax.set_title(\"Power increase due to floating for each turbine.\")\nplt.colorbar(sc, label=\"Increase (kW)\")\n\nprint(\"Power increase from floating over farm (10m/s, 270deg winds): {0:.2f} kW\".\\\n    format(power_difference.sum()/1000))\n\n# Visualize flows (see also 02_visualizations.py)\nhorizontal_planes = []\ny_planes = []\nfor fmodel in [fmodel_fixed, fmodel_floating]:\n    horizontal_planes.append(\n        fmodel.calculate_horizontal_plane(\n            x_resolution=200,\n            y_resolution=100,\n            height=90.0,\n        )\n    )\n    y_planes.append(\n        fmodel.calculate_y_plane(\n            x_resolution=200,\n            z_resolution=100,\n            crossstream_dist=0.0,\n        )\n    )\n\n# Create the plots\nfig, ax_list = plt.subplots(2, 1, figsize=(10, 8))\nax_list = ax_list.flatten()\nflowviz.visualize_cut_plane(horizontal_planes[0], ax=ax_list[0], title=\"Horizontal\")\nflowviz.visualize_cut_plane(y_planes[0], ax=ax_list[1], title=\"Streamwise profile\")\nfig.suptitle(\"Fixed-bottom farm\")\n\nfig, ax_list = plt.subplots(2, 1, figsize=(10, 8))\nax_list = ax_list.flatten()\nflowviz.visualize_cut_plane(horizontal_planes[1], ax=ax_list[0], title=\"Horizontal\")\nflowviz.visualize_cut_plane(y_planes[1], ax=ax_list[1], title=\"Streamwise profile\")\nfig.suptitle(\"Floating farm\")\n\n# Compute AEP\n# Load the wind rose from csv as in example 003\nwind_rose = WindRose.read_csv_long(\n    \"../inputs/wind_rose.csv\", wd_col=\"wd\", ws_col=\"ws\", freq_col=\"freq_val\", ti_col_or_value=0.06\n)\n\n\nfor fmodel in [fmodel_fixed, fmodel_floating]:\n    fmodel.set(\n        wind_data=wind_rose,\n    )\n    fmodel.run()\n\n# Compute the AEP\naep_fixed = fmodel_fixed.get_farm_AEP()\naep_floating = fmodel_floating.get_farm_AEP()\nprint(\"Farm AEP (fixed bottom): {:.3f} GWh\".format(aep_fixed / 1.0e9))\nprint(\"Farm AEP (floating): {:.3f} GWh\".format(aep_floating / 1.0e9))\nprint(\n    \"Floating AEP increase: {0:.3f} GWh ({1:.2f}%)\".\\\n    format((aep_floating - aep_fixed) / 1.0e9, (aep_floating - aep_fixed)/aep_fixed*100)\n)\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_floating/003_tilt_driven_vertical_wake_deflection.py",
    "content": "\"\"\"Example: Tilt-driven vertical wake deflection\nThis example demonstrates vertical wake deflections due to the tilt angle when running\nwith the Empirical Gauss model. Note that only the Empirical Gauss model implements\nvertical deflections at this time. Also be aware that this example uses a potentially\nunrealistic tilt angle, 15 degrees, to highlight the wake deflection. Moreover, the magnitude\nof vertical deflections due to tilt has not been validated.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom floris.flow_visualization import visualize_cut_plane\n\n\n# Initialize two FLORIS objects: one with 5 degrees of tilt (fixed across all\n# wind speeds) and one with 15 degrees of tilt (fixed across all wind speeds).\n\nfmodel_5 = FlorisModel(\"../inputs_floating/emgauss_floating_fixedtilt5.yaml\")\nfmodel_15 = FlorisModel(\"../inputs_floating/emgauss_floating_fixedtilt15.yaml\")\n\nD = fmodel_5.core.farm.rotor_diameters[0]\n\nnum_in_row = 5\n\n# Figure settings\nx_bounds = [-500, 3000]\ny_bounds = [-250, 250]\nz_bounds = [0.001, 500]\n\ncross_plane_locations = [10, 1200, 2500]\nhorizontal_plane_location = 90.0\nstreamwise_plane_location = 0.0\n\n# Create the plots\n# Cutplane settings\ncp_ls = \"solid\"  # line style\ncp_lw = 0.5  # line width\ncp_clr = \"black\"  # line color\nmin_ws = 4\nmax_ws = 10\nfig = plt.figure()\nfig.set_size_inches(12, 6)\n\npowers = np.zeros((2, num_in_row))\n\n# Calculate wakes, powers, plot\nfor i, (fmodel, tilt) in enumerate(zip([fmodel_5, fmodel_15], [5, 15])):\n    # Farm layout and wind conditions\n    fmodel.set(\n        layout_x=[x * 5.0 * D for x in range(num_in_row)],\n        layout_y=[0.0] * num_in_row,\n        wind_speeds=[8.0],\n        wind_directions=[270.0],\n    )\n\n    # Flow solve and power computation\n    fmodel.run()\n    powers[i, :] = fmodel.get_turbine_powers().flatten()\n\n    # Compute flow slices\n    y_plane = fmodel.calculate_y_plane(\n        x_resolution=200,\n        z_resolution=100,\n        crossstream_dist=streamwise_plane_location,\n        x_bounds=x_bounds,\n        z_bounds=z_bounds,\n    )\n\n    # Horizontal profile\n    ax = fig.add_subplot(2, 1, i + 1)\n    visualize_cut_plane(y_plane, ax=ax, min_speed=min_ws, max_speed=max_ws)\n    ax.plot(\n        x_bounds, [horizontal_plane_location] * 2, color=cp_clr, linewidth=cp_lw, linestyle=cp_ls\n    )\n    ax.set_title(\"Tilt angle: {0} degrees\".format(tilt))\n\nfig = plt.figure()\nfig.set_size_inches(6, 4)\nax = fig.add_subplot(1, 1, 1)\nx_locs = np.arange(num_in_row)\nwidth = 0.25\nax.bar(x_locs - width / 2, powers[0, :] / 1000, width=width, label=\"5 degree tilt\")\nax.bar(x_locs + width / 2, powers[1, :] / 1000, width=width, label=\"15 degree tilt\")\nax.set_xticks(x_locs)\nax.set_xticklabels([\"T{0}\".format(i) for i in range(num_in_row)])\nax.set_xlabel(\"Turbine number in row\")\nax.set_ylabel(\"Power [kW]\")\nax.legend()\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_get_flow/001_extract_wind_speed_at_turbines.py",
    "content": "\"\"\"Example: Extract wind speed at turbines\n\nThis example demonstrates how to extract the wind speed at the turbine points\nfrom the FLORIS model.  Both the u velocities and the turbine average\nvelocities are grabbed from the model, then the turbine average is\nrecalculated from the u velocities to show that they are equivalent.\n\"\"\"\n\n\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\n# Initialize the FLORIS model\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Create a 4-turbine layouts\nfmodel.set(layout_x=[0, 0.0, 500.0, 500.0], layout_y=[0.0, 300.0, 0.0, 300.0])\n\n# Calculate wake\nfmodel.run()\n\n# Collect the wind speed at all the turbine points\nu_points = fmodel.core.flow_field.u\n\nprint(\"U points is 1 findex x 4 turbines x 3 x 3 points (turbine_grid_points=3)\")\nprint(u_points.shape)\n\nprint(\"turbine_average_velocities is 1 findex x 4 turbines\")\nprint(fmodel.turbine_average_velocities)\n\n# Show that one is equivalent to the other following averaging\nprint(\n    \"turbine_average_velocities is determined by taking the cube root of mean \"\n    \"of the cubed value across the points \"\n)\nprint(f\"turbine_average_velocities: {fmodel.turbine_average_velocities}\")\nprint(f\"Recomputed:       {np.cbrt(np.mean(u_points**3, axis=(2,3)))}\")\n"
  },
  {
    "path": "examples/examples_get_flow/002_extract_wind_speed_at_points.py",
    "content": "\"\"\"Example: Extract wind speed at points\nThis example demonstrates the use of the sample_flow_at_points method of\nFlorisModel. sample_flow_at_points extracts the wind speed\ninformation at user-specified locations in the flow.\n\nSpecifically, this example returns the wind speed at a single x, y\nlocation and four different heights over a sweep of wind directions.\nThis mimics the wind speed measurements of a met mast across all\nwind directions (at a fixed free stream wind speed).\n\nTry different values for met_mast_option to vary the location of the\nmet mast within the two-turbine farm.\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\n# User options\n# FLORIS model to use (legacy Turbopark not available)\nfloris_model = \"gch\"  # Try \"gch\", \"cc\", \"jensen\", \"emgauss\", \"turboparkgauss\"\n# Option to try different met mast locations\nmet_mast_option = 0  # Try 0, 1, 2, 3\n\n# Instantiate FLORIS model\nfmodel = FlorisModel(\"../inputs/\" + floris_model + \".yaml\")\n\n# Set up a two-turbine farm\nD = 126\nfmodel.set(layout_x=[0, 3 * D], layout_y=[0, 3 * D])\n\nfig, ax = plt.subplots(1, 2)\nfig.set_size_inches(10, 4)\nax[0].scatter(fmodel.layout_x, fmodel.layout_y, color=\"black\", label=\"Turbine\")\n\n# Set the wind direction to run 360 degrees\nwd_array = np.arange(0, 360, 1)\nws_array = 8.0 * np.ones_like(wd_array)\nti_array = 0.06 * np.ones_like(wd_array)\nfmodel.set(wind_directions=wd_array, wind_speeds=ws_array, turbulence_intensities=ti_array)\n\n# Simulate a met mast in between the turbines\nif met_mast_option == 0:\n    points_x = 4 * [3 * D]\n    points_y = 4 * [0]\nelif met_mast_option == 1:\n    points_x = 4 * [200.0]\n    points_y = 4 * [200.0]\nelif met_mast_option == 2:\n    points_x = 4 * [20.0]\n    points_y = 4 * [20.0]\nelif met_mast_option == 3:\n    points_x = 4 * [305.0]\n    points_y = 4 * [158.0]\n\npoints_z = [30, 90, 150, 250]\n\n# Collect the points\nu_at_points = fmodel.sample_flow_at_points(points_x, points_y, points_z)\n\nax[0].scatter(points_x, points_y, color=\"red\", marker=\"x\", label=\"Met mast\")\nax[0].grid()\nax[0].set_xlabel(\"x [m]\")\nax[0].set_ylabel(\"y [m]\")\nax[0].legend()\n\n# Plot the velocities\nfor z_idx, z in enumerate(points_z):\n    ax[1].plot(wd_array, u_at_points[:, z_idx].flatten(), label=f\"Speed at z={z} m\")\nax[1].grid()\nax[1].legend()\nax[1].set_xlabel(\"Wind Direction (deg)\")\nax[1].set_ylabel(\"Wind Speed (m/s)\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_get_flow/003_extract_turbulence_intensity_at_points.py",
    "content": "\"\"\"Example: Extract turbulence intensity at points\nThis example demonstrates the use of the sample_ti_at_points method of\nFlorisModel. sample_ti_at_points extracts the turbulence intensity (TI)\ninformation at user-specified locations in the flow.\n\nSpecifically, this example returns the TI at a single x, y\nlocation and four different heights over a sweep of wind directions.\nThis mimics the TI measurements of a met mast across all\nwind directions (at a fixed free stream wind speed).\n\nTry different values for met_mast_option to vary the location of the\nmet mast within the two-turbine farm.\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\n# User options\n# FLORIS model to use. Note that legacy \"turbopark\" is not available,\n# \"turboparkgauss\" is configured with none turbulence model by default,\n# and \"emgauss\" does not contain an explicit turbulence model.\nfloris_model = \"gch\"  # Try \"gch\", \"cc\", \"jensen\"\n# Option to try different met mast locations\nmet_mast_option = 0  # Try 0, 1, 2, 3\n\n# Instantiate FLORIS model\nfmodel = FlorisModel(\"../inputs/\" + floris_model + \".yaml\")\n\n# Set up a two-turbine farm\nD = 126\nfmodel.set(layout_x=[0, 3 * D], layout_y=[0, 3 * D])\n\nfig, ax = plt.subplots(1, 2)\nfig.set_size_inches(10, 4)\nax[0].scatter(fmodel.layout_x, fmodel.layout_y, color=\"black\", label=\"Turbine\")\n\n# Set the wind direction to run 360 degrees\nwd_array = np.arange(0, 360, 1)\nws_array = 8.0 * np.ones_like(wd_array)\nti_array = 0.06 * np.ones_like(wd_array)\nfmodel.set(wind_directions=wd_array, wind_speeds=ws_array, turbulence_intensities=ti_array)\n\n# Simulate a met mast in between the turbines\nif met_mast_option == 0:\n    points_x = 4 * [3 * D]\n    points_y = 4 * [0]\nelif met_mast_option == 1:\n    points_x = 4 * [200.0]\n    points_y = 4 * [200.0]\nelif met_mast_option == 2:\n    points_x = 4 * [20.0]\n    points_y = 4 * [20.0]\nelif met_mast_option == 3:\n    points_x = 4 * [305.0]\n    points_y = 4 * [158.0]\n\npoints_z = [30, 90, 150, 250]\n\n# Collect the points\nti_at_points = fmodel.sample_ti_at_points(points_x, points_y, points_z)\n\nax[0].scatter(points_x, points_y, color=\"red\", marker=\"x\", label=\"Met mast\")\nax[0].grid()\nax[0].set_xlabel(\"x [m]\")\nax[0].set_ylabel(\"y [m]\")\nax[0].legend()\n\n# Plot the turbulence intensities\nfor z_idx, z in enumerate(points_z):\n    ax[1].plot(wd_array, ti_at_points[:, z_idx].flatten(), label=f\"TI at z={z} m\")\nax[1].grid()\nax[1].legend()\nax[1].set_xlabel(\"Wind Direction (deg)\")\nax[1].set_ylabel(\"Turbulence Intensity (-)\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_get_flow/004_plot_velocity_deficit_profiles.py",
    "content": "\"\"\"Example: Plot velocity deficit profiles\n\nThis example illustrates how to plot velocity deficit profiles at several locations\ndownstream of a turbine. Here we use the following definition:\n    velocity_deficit = (homogeneous_wind_speed - u) / homogeneous_wind_speed\n        , where u is the wake velocity obtained when the incoming wind speed is the\n        same at all heights and equal to `homogeneous_wind_speed`.\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib import ticker\n\nimport floris.flow_visualization as flowviz\nfrom floris import FlorisModel\nfrom floris.flow_visualization import VelocityProfilesFigure\nfrom floris.utilities import reverse_rotate_coordinates_rel_west\n\n\n# The first two functions are just used to plot the coordinate system in which the\n# profiles are sampled. Please go to the main function to begin the example.\ndef plot_coordinate_system(x_origin, y_origin, wind_direction):\n    quiver_length = 1.4 * D\n    plt.quiver(\n        [x_origin, x_origin],\n        [y_origin, y_origin],\n        [quiver_length, quiver_length],\n        [0, 0],\n        angles=[270 - wind_direction, 360 - wind_direction],\n        scale_units=\"x\",\n        scale=1,\n    )\n    annotate_coordinate_system(x_origin, y_origin, quiver_length)\n\n\ndef annotate_coordinate_system(x_origin, y_origin, quiver_length):\n    x1 = np.array([quiver_length + 0.35 * D, 0.0])\n    x2 = np.array([0.0, quiver_length + 0.35 * D])\n    x3 = np.array([90.0, 90.0])\n    x, y, _ = reverse_rotate_coordinates_rel_west(\n        fmodel.wind_directions,\n        x1[None, :],\n        x2[None, :],\n        x3[None, :],\n        x_center_of_rotation=0.0,\n        y_center_of_rotation=0.0,\n    )\n    x = np.squeeze(x, axis=0) + x_origin\n    y = np.squeeze(y, axis=0) + y_origin\n    plt.text(x[0], y[0], \"$x_1$\", bbox={\"facecolor\": \"white\"})\n    plt.text(x[1], y[1], \"$x_2$\", bbox={\"facecolor\": \"white\"})\n\n\nif __name__ == \"__main__\":\n    D = 125.88  # Turbine diameter\n    hub_height = 90.0\n    homogeneous_wind_speed = 8.0\n\n    fmodel = FlorisModel(\"../inputs/gch.yaml\")\n    fmodel.set(layout_x=[0.0], layout_y=[0.0])\n\n    # ------------------------------ Single-turbine layout ------------------------------\n    # We first show how to sample and plot velocity deficit profiles on a single-turbine layout.\n    # Lines are drawn on a horizontal plane to indicate were the velocity is sampled.\n    downstream_dists = D * np.array([3, 5, 7])\n    # Sample three profiles along three corresponding lines that are all parallel to the y-axis\n    # (cross-stream direction). The streamwise location of each line is given in `downstream_dists`.\n    profiles = fmodel.sample_velocity_deficit_profiles(\n        direction=\"cross-stream\",\n        downstream_dists=downstream_dists,\n        homogeneous_wind_speed=homogeneous_wind_speed,\n    )\n\n    horizontal_plane = fmodel.calculate_horizontal_plane(height=hub_height)\n    fig, ax = plt.subplots(figsize=(6.4, 3))\n    flowviz.visualize_cut_plane(horizontal_plane, ax)\n    colors = [\"b\", \"g\", \"c\"]\n    for i, profile in enumerate(profiles):\n        # Plot profile coordinates on the horizontal plane\n        ax.plot(profile[\"x\"], profile[\"y\"], colors[i], label=f\"x/D={downstream_dists[i] / D:.1f}\")\n    ax.set_xlabel(\"x [m]\")\n    ax.set_ylabel(\"y [m]\")\n    ax.set_title(\"Streamwise velocity in a horizontal plane: gauss velocity model\")\n    fig.tight_layout(rect=[0, 0, 0.82, 1])\n    ax.legend(bbox_to_anchor=[1.29, 1.04])\n\n    # Initialize a VelocityProfilesFigure. The workflow is similar to a matplotlib Figure:\n    # Initialize it, plot data, and then customize it further if needed.\n    profiles_fig = VelocityProfilesFigure(\n        downstream_dists_D=downstream_dists / D,\n        layout=[\"cross-stream\"],\n        coordinate_labels=[\"x/D\", \"y/D\"],\n    )\n    # Add profiles to the VelocityProfilesFigure. This method automatically matches the supplied\n    # profiles to the initialized axes in the figure.\n    profiles_fig.add_profiles(profiles, color=\"k\")\n\n    # Change velocity model to jensen, get the velocity deficit profiles,\n    # and add them to the figure.\n    floris_dict = fmodel.core.as_dict()\n    floris_dict[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"jensen\"\n    fmodel = FlorisModel(floris_dict)\n    profiles = fmodel.sample_velocity_deficit_profiles(\n        direction=\"cross-stream\",\n        downstream_dists=downstream_dists,\n        homogeneous_wind_speed=homogeneous_wind_speed,\n        resolution=400,\n    )\n    profiles_fig.add_profiles(profiles, color=\"r\")\n\n    # The dashed reference lines show the extent of the rotor\n    profiles_fig.add_ref_lines_x2([-0.5, 0.5])\n    for ax in profiles_fig.axs[0]:\n        ax.xaxis.set_major_locator(ticker.MultipleLocator(0.2))\n\n    profiles_fig.axs[0, 0].legend([\"gauss\", \"jensen\"], fontsize=11)\n    profiles_fig.fig.suptitle(\n        \"Velocity deficit profiles from different velocity models\",\n        fontsize=14,\n    )\n\n    # -------------------------------- Two-turbine layout --------------------------------\n    # This is a two-turbine case where the wind direction is north-west. Velocity profiles\n    # are sampled behind the second turbine. This illustrates the need for a\n    # sampling-coordinate-system (x1, x2, x3) that is rotated such that x1 is always in the\n    # streamwise direction. The user may define the origin of this coordinate system\n    # (i.e. where to start sampling the profiles).\n    wind_direction = 315.0  # Try to change this\n    downstream_dists = D * np.array([3, 5])\n    floris_dict = fmodel.core.as_dict()\n    floris_dict[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"gauss\"\n    fmodel = FlorisModel(floris_dict)\n    # Let (x_t1, y_t1) be the location of the second turbine\n    x_t1 = 2 * D\n    y_t1 = -2 * D\n    fmodel.set(wind_directions=[wind_direction], layout_x=[0.0, x_t1], layout_y=[0.0, y_t1])\n\n    # Extract profiles at a set of downstream distances from the starting point (x_start, y_start)\n    cross_profiles = fmodel.sample_velocity_deficit_profiles(\n        direction=\"cross-stream\",\n        downstream_dists=downstream_dists,\n        homogeneous_wind_speed=homogeneous_wind_speed,\n        x_start=x_t1,\n        y_start=y_t1,\n    )\n\n    horizontal_plane = fmodel.calculate_horizontal_plane(\n        height=hub_height, x_bounds=[-2 * D, 9 * D]\n    )\n    ax = flowviz.visualize_cut_plane(horizontal_plane)\n    colors = [\"b\", \"g\", \"c\"]\n    for i, profile in enumerate(cross_profiles):\n        ax.plot(\n            profile[\"x\"],\n            profile[\"y\"],\n            colors[i],\n            label=f\"$x_1/D={downstream_dists[i] / D:.1f}$\",\n        )\n    ax.set_xlabel(\"x [m]\")\n    ax.set_ylabel(\"y [m]\")\n    ax.set_title(\"Streamwise velocity in a horizontal plane\")\n    ax.legend()\n    plot_coordinate_system(x_origin=x_t1, y_origin=y_t1, wind_direction=wind_direction)\n\n    # Sample velocity deficit profiles in the vertical direction at the same downstream\n    # locations as before. We stay directly downstream of the turbine (i.e. x2 = 0). These\n    # profiles are almost identical to the cross-stream profiles. However, we now explicitly\n    # set the profile range. The default range is [-2 * D, 2 * D].\n    vertical_profiles = fmodel.sample_velocity_deficit_profiles(\n        direction=\"vertical\",\n        profile_range=[-1.5 * D, 1.5 * D],\n        downstream_dists=downstream_dists,\n        homogeneous_wind_speed=homogeneous_wind_speed,\n        x_start=x_t1,\n        y_start=y_t1,\n    )\n\n    profiles_fig = VelocityProfilesFigure(\n        downstream_dists_D=downstream_dists / D,\n        layout=[\"cross-stream\", \"vertical\"],\n    )\n    profiles_fig.add_profiles(cross_profiles + vertical_profiles, color=\"k\")\n\n    profiles_fig.set_xlim([-0.05, 0.85])\n    profiles_fig.axs[1, 0].set_ylim([-2.2, 2.2])\n    for ax in profiles_fig.axs[0]:\n        ax.xaxis.set_major_locator(ticker.MultipleLocator(0.4))\n\n    profiles_fig.fig.suptitle(\n        \"Cross-stream profiles at hub-height, and\\nvertical profiles at $x_2 = 0$\",\n        fontsize=14,\n    )\n\n    plt.show()\n"
  },
  {
    "path": "examples/examples_heterogeneous/001_heterogeneous_inflow_single.py",
    "content": "\"\"\"Example: Heterogeneous Inflow for single case\n\nThis example illustrates how to set up a heterogeneous inflow condition in FLORIS.  It:\n\n    1) Initializes FLORIS\n    2) Changes the wind farm layout\n    3) Changes the incoming wind speed, wind direction and turbulence intensity\n        to a single condition\n    4) Sets up a heterogeneous inflow condition for that single condition\n    5) Runs the FLORIS simulation\n    6) Gets the power output of the turbines\n    7) Visualizes the horizontal plane at hub height\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, TimeSeries\nfrom floris.flow_visualization import visualize_heterogeneous_cut_plane\nfrom floris.layout_visualization import plot_turbine_labels\n\n\n# Initialize FlorisModel\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Change the layout to a 4 turbine layout in a box\nfmodel.set(layout_x=[0, 0, 500.0, 500.0], layout_y=[0, 500.0, 0, 500.0])\n\n# Set FLORIS to run for a single condition\nfmodel.set(wind_speeds=[8.0], wind_directions=[270.0], turbulence_intensities=[0.06])\n\n# Define the speed-ups of the heterogeneous inflow, and their locations.\n# Note that heterogeneity is only applied within the bounds of the points defined in the\n# heterogeneous_inflow_config dictionary.  In this case, set the inflow to be 1.25x the ambient\n# wind speed for the upper turbines at y = 500m.\nspeed_ups = [[1.0, 1.25, 1.0, 1.25]]  # Note speed-ups has dimensions of n_findex X n_points\nx_locs = [-500.0, -500.0, 1000.0, 1000.0]\ny_locs = [-500.0, 1000.0, -500.0, 1000.0]\n\n# Create the configuration dictionary to be used for the heterogeneous inflow.\nheterogeneous_inflow_config = {\n    \"speed_multipliers\": speed_ups,\n    \"x\": x_locs,\n    \"y\": y_locs,\n}\n\n# Set the heterogeneous inflow configuration\nfmodel.set(heterogeneous_inflow_config=heterogeneous_inflow_config)\n\n# Run the FLORIS simulation\nfmodel.run()\n\n# Get the power output of the turbines\nturbine_powers = fmodel.get_turbine_powers() / 1000.0\n\n# Print the turbine powers\nprint(f\"Turbine 0 power = {turbine_powers[0, 0]:.1f} kW\")\nprint(f\"Turbine 1 power = {turbine_powers[0, 1]:.1f} kW\")\nprint(f\"Turbine 2 power = {turbine_powers[0, 2]:.1f} kW\")\nprint(f\"Turbine 3 power = {turbine_powers[0, 3]:.1f} kW\")\n\n# Extract the horizontal plane at hub height\nhorizontal_plane = fmodel.calculate_horizontal_plane(\n    x_resolution=200, y_resolution=100, height=90.0\n)\n\n# Plot the horizontal plane using the visualize_heterogeneous_cut_plane.\n# Note that this function is not very different than the standard\n# visualize_cut_plane except that it accepts the fmodel object in order to\n# visualize the boundary of the heterogeneous inflow region.\nfig, ax = plt.subplots()\nvisualize_heterogeneous_cut_plane(\n    horizontal_plane,\n    fmodel=fmodel,\n    ax=ax,\n    title=\"Horizontal plane at hub height\",\n    color_bar=True,\n    label_contours=True,\n)\nplot_turbine_labels(fmodel, ax)\nax.legend()\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_heterogeneous/002_heterogeneous_using_wind_data.py",
    "content": "\"\"\"Example: Heterogeneous Inflow using wind data\n\nWhen multiple cases are considered, the heterogeneous inflow conditions can be defined in two ways:\n\n  1. Passing heterogeneous_inflow_config to the set method, with P points,\n        and speed_multipliers of size n_findex X P\n  2. More conveniently, building a HeterogeneousMap object that defines the speed_multipliers as a\n        function of wind direction and/or wind speed and passing that to a WindData object.  When\n        the WindData object is passed to the set method, the heterogeneous_inflow_config is\n        automatically generated for each findex by finding the nearest wind direction and/or wind\n        speed in the HeterogeneousMap object.\n\nThis example:\n\n    1) Implements heterogeneous inflow for a 4 turbine layout using both of the above methods\n    2) Compares the results of the two methods and shows that they are equivalent\n\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    HeterogeneousMap,\n    TimeSeries,\n)\n\n\n# Initialize FlorisModel\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Change the layout to a 4 turbine layout in a box\nfmodel.set(layout_x=[0, 0, 500.0, 500.0], layout_y=[0, 500.0, 0, 500.0])\n\n# Define a TimeSeries object with 4 wind directions and constant wind speed\n# and turbulence intensity\ntime_series = TimeSeries(\n    wind_directions=np.array([269.0, 270.0, 271.0, 282.0]),\n    wind_speeds=8.0,\n    turbulence_intensities=0.06,\n)\n\n# Apply the time series to the FlorisModel\nfmodel.set(wind_data=time_series)\n\n# Define the x_locs to be used in the heterogeneous inflow configuration that form\n# a box around the turbines\nx_locs = [-500.0, -500.0, 1000.0, 1000.0]\ny_locs = [-500.0, 1000.0, -500.0, 1000.0]\n\n# Assume the speed-ups are defined such that they are the same 265-275 degrees and 275-285 degrees\n\n# If defining heterogeneous_inflow_config directly, then the speed_multipliers are of size\n# n_findex x P, where the first 3 rows are identical and the last row is different\nspeed_multipliers = [\n    [1.0, 1.25, 1.0, 1.25],\n    [1.0, 1.25, 1.0, 1.25],\n    [1.0, 1.25, 1.0, 1.25],\n    [1.0, 1.35, 1.0, 1.35],\n]\n\nheterogeneous_inflow_config = {\n    \"speed_multipliers\": speed_multipliers,\n    \"x\": x_locs,\n    \"y\": y_locs,\n}\n\n# Set the heterogeneous inflow configuration\nfmodel.set(heterogeneous_inflow_config=heterogeneous_inflow_config)\n\n# Run the FLORIS simulation\nfmodel.run()\n\n# Get the power output of the turbines\nturbine_powers = fmodel.get_turbine_powers() / 1000.0\n\n# Now repeat using the wind_data object and HeterogeneousMap object\n# First, create the speed multipliers for the two wind directions\nspeed_multipliers = [[1.0, 1.25, 1.0, 1.25], [1.0, 1.35, 1.0, 1.35]]\n\n# Now define the HeterogeneousMap object\nheterogeneous_map = HeterogeneousMap(\n    x=x_locs,\n    y=y_locs,\n    speed_multipliers=speed_multipliers,\n    wind_directions=[270.0, 280.0],\n)\n\n# Print the HeterogeneousMap object\nprint(heterogeneous_map)\n\n# Now create a new TimeSeries object including the heterogeneous_inflow_config_by_wd\ntime_series = TimeSeries(\n    wind_directions=np.array([269.0, 270.0, 271.0, 282.0]),\n    wind_speeds=8.0,\n    turbulence_intensities=0.06,\n    heterogeneous_map=heterogeneous_map,\n)\n\n# Note that previously, the a heterogeneous_inflow_config_by_wd, which only only\n# specification by wind direction was defined, and for backwards compatibility,\n# this is still accepted.  However, the HeterogeneousMap object is more flexible.\n# The following code produces the same results as the previous code block.\nheterogeneous_inflow_config_by_wd = {\n    \"speed_multipliers\": speed_multipliers,\n    \"x\": x_locs,\n    \"y\": y_locs,\n    \"wind_directions\": [270.0, 280.0],\n}\n\ntime_series = TimeSeries(\n    wind_directions=np.array([269.0, 270.0, 271.0, 282.0]),\n    wind_speeds=8.0,\n    turbulence_intensities=0.06,\n    heterogeneous_inflow_config_by_wd=heterogeneous_inflow_config_by_wd,\n)\n\n\n# Apply the time series to the FlorisModel\nfmodel.set(wind_data=time_series)\n\n# Run the FLORIS simulation\nfmodel.run()\n\n# Get the power output of the turbines\nturbine_powers_by_wd = fmodel.get_turbine_powers() / 1000.0\n\n# Plot the results\nwind_directions = fmodel.wind_directions\nfig, axarr = plt.subplots(2, 2, sharex=True, sharey=True, figsize=(10, 10))\naxarr = axarr.flatten()\n\nfor tindex in range(4):\n    ax = axarr[tindex]\n    ax.plot(wind_directions, turbine_powers[:, tindex], \"ks-\", label=\"Heterogeneous Inflow\")\n    ax.plot(\n        wind_directions, turbine_powers_by_wd[:, tindex], \".--\", label=\"Heterogeneous Inflow by WD\"\n    )\n    ax.set_title(f\"Turbine {tindex}\")\n    ax.set_xlabel(\"Wind Direction (deg)\")\n    ax.set_ylabel(\"Power (kW)\")\n    ax.legend()\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_heterogeneous/003_heterogeneous_speedup_by_wd_and_ws.py",
    "content": "\"\"\"Example: Heterogeneous Speedup by Wind Direction and Wind Speed\n\nThe HeterogeneousMap object is a flexible way to define speedups as a function of wind direction\nand/or wind speed.  It also contains methods to plot the speedup map for a given wind direction\nand wind speed.\n\nThis example:\n\n    1) Instantiates a HeterogeneousMap object with speedups defined for two wind directions\n        and two wind speeds\n    2) Visualizes the speedups for two particular combinations of wind direction and wind speed\n    3) Runs a FLORIS simulation using the HeterogeneousMap and visualizes the results\n\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    HeterogeneousMap,\n    TimeSeries,\n)\nfrom floris.flow_visualization import visualize_heterogeneous_cut_plane\n\n\n# Define a HeterogeneousMap object with speedups defined for two wind directions\n# and two wind speeds.  The speedups imply no heterogeneity for the first wind direction\n# (0 degrees) with heterogeneity for the second wind direction (180 degrees) with the\n# specific speedups for this direction depending on the wind speed.\nheterogeneous_map = HeterogeneousMap(\n    x=np.array([0.0, 0.0, 250.0, 500.0, 500.0]),\n    y=np.array([0.0, 500.0, 250.0, 0.0, 500.0]),\n    speed_multipliers=np.array(\n        [\n            [1.0, 1.0, 1.0, 1.0, 1.0],\n            [1.0, 1.0, 1.0, 1.0, 1.0],\n            [1.5, 1.0, 1.25, 1.5, 1.0],\n            [1.0, 1.5, 1.25, 1.0, 1.5],\n        ]\n    ),\n    wind_directions=np.array([270.0, 270.0, 90.0, 90.0]),\n    wind_speeds=np.array([5.0, 10.0, 5.0, 10.0]),\n)\n\n# Use the HeterogeneousMap object to plot the speedup map for 3 wd/ws combinations\nfig, axarr = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(15, 5))\n\n\nax = axarr[0]\nheterogeneous_map.plot_single_speed_multiplier(\n    wind_direction=60.0, wind_speed=8.5, ax=ax, vmin=1.0, vmax=1.2\n)\nax.set_title(\"Wind Direction = 60.0\\nWind Speed = 8.5\")\n\nax = axarr[1]\nheterogeneous_map.plot_single_speed_multiplier(\n    wind_direction=130.0, wind_speed=4.0, ax=ax, vmin=1.0, vmax=1.2\n)\nax.set_title(\"Wind Direction = 130.0\\nWind Speed = 4.0\")\n\nax = axarr[2]\nheterogeneous_map.plot_single_speed_multiplier(\n    wind_direction=280.0, wind_speed=16.0, ax=ax, vmin=1.0, vmax=1.2\n)\nax.set_title(\"Wind Direction = 280.0\\nWind Speed = 16.0\")\nfig.suptitle(\"Heterogeneous speedup map for several directions and wind speeds\")\n\n\n# Initialize FlorisModel\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Change the layout to a 2 turbine layout within the heterogeneous domain\nfmodel.set(layout_x=[200, 200.0], layout_y=[50, 450.0])\n\n# Define a TimeSeries object with 3 wind directions and wind speeds\n# and turbulence intensity and using the above HeterogeneousMap object\ntime_series = TimeSeries(\n    wind_directions=np.array([275.0, 95.0, 75.0]),\n    wind_speeds=np.array([7.0, 6.2, 8.0]),\n    turbulence_intensities=0.06,\n    heterogeneous_map=heterogeneous_map,\n)\n\n# Apply the time series to the FlorisModel\nfmodel.set(wind_data=time_series)\n\n# Run the FLORIS simulation\nfmodel.run()\n\n# Visualize each of the findices\nfig, axarr = plt.subplots(3, 1, sharex=True, sharey=True, figsize=(10, 10))\n\nfor findex in range(3):\n    ax = axarr[findex]\n\n    horizontal_plane = fmodel.calculate_horizontal_plane(\n        x_resolution=200, y_resolution=100, height=90.0, findex_for_viz=findex\n    )\n\n    visualize_heterogeneous_cut_plane(\n        cut_plane=horizontal_plane,\n        fmodel=fmodel,\n        ax=ax,\n        title=(\n            f\"Wind Direction = {time_series.wind_directions[findex]}\\n\"\n            f\"Wind Speed = {time_series.wind_speeds[findex]}\"\n        ),\n    )\n\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_heterogeneous/004_heterogeneous_2d_and_3d.py",
    "content": "\"\"\"Example: Heterogeneous Inflow in 2D and 3D\n\nThis example showcases the heterogeneous inflow capabilities of FLORIS.\nHeterogeneous flow can be defined in either 2- or 3-dimensions for a single\ncondition.\n\nFor the 2-dimensional case, it can be seen that the freestream velocity\nonly varies in the x direction. For the 3-dimensional case, it can be\nseen that the freestream velocity only varies in the z direction. This\nis because of how the speed ups for each case were defined. More complex\ninflow conditions can be defined.\n\nFor each case, we are plotting three slices of the resulting flow field:\n1. Horizontal slice parallel to the ground and located at the hub height\n2. Vertical slice parallel with the direction of the wind\n3. Vertical slice parallel to to the turbine disc plane\n\nSince the intention is for plotting, only a single condition is run and in\nthis case the heterogeneous_inflow_config is more convenient to use than\nheterogeneous_inflow_config_by_wd. However, the latter is more convenient\nwhen running multiple conditions.\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\n\nfrom floris import FlorisModel\nfrom floris.flow_visualization import visualize_cut_plane\n\n\n# Initialize FLORIS with the given input file via FlorisModel.\n# Note that the heterogeneous flow is defined in the input file. The heterogeneous_inflow_config\n# dictionary is defined as below. The speed ups are multipliers of the ambient wind speed,\n# and the x and y are the locations of the speed ups.\n#\n# heterogeneous_inflow_config = {\n#     'speed_multipliers': [[2.0, 1.0, 2.0, 1.0]],\n#     'x': [-300.0, -300.0, 2600.0, 2600.0],\n#     'y': [ -300.0, 300.0, -300.0, 300.0],\n# }\n\n\nfmodel_2d = FlorisModel(\"../inputs/gch_heterogeneous_inflow.yaml\")\n\n# Set shear to 0.0 to highlight the heterogeneous inflow\nfmodel_2d.set(wind_shear=0.0)\n\n# Using the FlorisModel functions for generating plots, run FLORIS\n# and extract 2D planes of data.\nhorizontal_plane_2d = fmodel_2d.calculate_horizontal_plane(\n    x_resolution=200, y_resolution=100, height=90.0\n)\ny_plane_2d = fmodel_2d.calculate_y_plane(x_resolution=200, z_resolution=100, crossstream_dist=0.0)\ncross_plane_2d = fmodel_2d.calculate_cross_plane(\n    y_resolution=100, z_resolution=100, downstream_dist=500.0\n)\n\n# Create the plots\nfig, ax_list = plt.subplots(3, 1, figsize=(10, 8))\nax_list = ax_list.flatten()\nvisualize_cut_plane(\n    horizontal_plane_2d, ax=ax_list[0], title=\"Horizontal\", color_bar=True, label_contours=True\n)\nax_list[0].set_xlabel(\"x\")\nax_list[0].set_ylabel(\"y\")\nvisualize_cut_plane(\n    y_plane_2d, ax=ax_list[1], title=\"Streamwise profile\", color_bar=True, label_contours=True\n)\nax_list[1].set_xlabel(\"x\")\nax_list[1].set_ylabel(\"z\")\nvisualize_cut_plane(\n    cross_plane_2d,\n    ax=ax_list[2],\n    title=\"Spanwise profile at 500m downstream\",\n    color_bar=True,\n    label_contours=True,\n)\nax_list[2].set_xlabel(\"y\")\nax_list[2].set_ylabel(\"z\")\n\n\n# Define the speed ups of the heterogeneous inflow, and their locations.\n# For the 3-dimensional case, this requires x, y, and z locations.\n# The speed ups are multipliers of the ambient wind speed.\nspeed_multipliers = [[1.0, 1.0, 2.0, 2.0, 1.0, 1.0, 2.0, 2.0]]\nx_locs = [-300.0, -300.0, -300.0, -300.0, 2600.0, 2600.0, 2600.0, 2600.0]\ny_locs = [-300.0, 300.0, -300.0, 300.0, -300.0, 300.0, -300.0, 300.0]\nz_locs = [540.0, 540.0, 0.0, 0.0, 540.0, 540.0, 0.0, 0.0]\n\n# Create the configuration dictionary to be used for the heterogeneous inflow.\nheterogeneous_inflow_config = {\n    \"speed_multipliers\": speed_multipliers,\n    \"x\": x_locs,\n    \"y\": y_locs,\n    \"z\": z_locs,\n}\n\n# Initialize FLORIS with the given input file.\n# Note that we initialize FLORIS with a homogenous flow input file, but\n# then configure the heterogeneous inflow via the reinitialize method.\nfmodel_3d = FlorisModel(\"../inputs/gch.yaml\")\n\n# Set shear to 0.0 to highlight the heterogeneous inflow\nfmodel_3d.set(wind_shear=0.0)\n\n# Apply the heterogeneous inflow configuration\nfmodel_3d.set(heterogeneous_inflow_config=heterogeneous_inflow_config)\n\n# Using the FlorisModel functions for generating plots, run FLORIS\n# and extract 2D planes of data.\nhorizontal_plane_3d = fmodel_3d.calculate_horizontal_plane(\n    x_resolution=200, y_resolution=100, height=90.0\n)\ny_plane_3d = fmodel_3d.calculate_y_plane(x_resolution=200, z_resolution=100, crossstream_dist=0.0)\ncross_plane_3d = fmodel_3d.calculate_cross_plane(\n    y_resolution=100, z_resolution=100, downstream_dist=500.0\n)\n\n# Create the plots\nfig, ax_list = plt.subplots(3, 1, figsize=(10, 8))\nax_list = ax_list.flatten()\nvisualize_cut_plane(\n    horizontal_plane_3d, ax=ax_list[0], title=\"Horizontal\", color_bar=True, label_contours=True\n)\nax_list[0].set_xlabel(\"x\")\nax_list[0].set_ylabel(\"y\")\nvisualize_cut_plane(\n    y_plane_3d, ax=ax_list[1], title=\"Streamwise profile\", color_bar=True, label_contours=True\n)\nax_list[1].set_xlabel(\"x\")\nax_list[1].set_ylabel(\"z\")\nvisualize_cut_plane(\n    cross_plane_3d,\n    ax=ax_list[2],\n    title=\"Spanwise profile at 500m downstream\",\n    color_bar=True,\n    label_contours=True,\n)\nax_list[2].set_xlabel(\"y\")\nax_list[2].set_ylabel(\"z\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_layout_optimization/001_optimize_layout.py",
    "content": "\n\"\"\"Example: Optimize Layout\nThis example shows a simple layout optimization using the python module Scipy, optimizing for both\nannual energy production (AEP) and annual value production (AVP).\n\nFirst, a 4 turbine array is optimized such that the layout of the turbine produces the\nhighest AEP based on the given wind resource. The turbines\nare constrained to a square boundary and a random wind resource is supplied. The results\nof the optimization show that the turbines are pushed to near the outer corners of the boundary,\nwhich, given the generally uniform wind rose, makes sense in order to maximize the energy\nproduction by minimizing wake interactions.\n\nNext, with the same boundary, the same 4 turbine array is optimized to maximize AVP instead of AEP,\nusing the value table defined in the WindRose object, where value represents the value of the\nenergy produced for a given wind condition (e.g., the price of electricity). In this example, value\nis defined to be significantly higher for northerly and southerly wind directions, and zero when\nthe wind is from the east or west. Because the value is much higher when the wind is from the north\nor south, the turbines are spaced apart roughly evenly in the x direction while being relatively\nclose in the y direction to avoid wake interactions for northerly and southerly winds. Although the\nlayout results in large wake losses when the wind is from the east or west, these losses do not\nsignificantly impact the objective function because of the low value for those wind directions.\n\"\"\"\n\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, WindRose\nfrom floris.optimization.layout_optimization.layout_optimization_scipy import (\n    LayoutOptimizationScipy,\n)\n\n\n# Define scipy optimization parameters\nopt_options = {\n    \"maxiter\": 20,\n    \"disp\": True,\n    \"iprint\": 2,\n    \"ftol\": 1e-12,\n    \"eps\": 0.05,\n}\n\n# Initialize the FLORIS interface fi\nfmodel = FlorisModel('../inputs/gch.yaml')\n\n# Setup 72 wind directions with a 1 wind speed and frequency distribution\nwind_directions = np.arange(0, 360.0, 5.0)\nwind_speeds = np.array([8.0])\n\n# Shape random frequency distribution to match number of wind directions and wind speeds\nfreq_table = np.zeros((len(wind_directions), len(wind_speeds)))\nnp.random.seed(1)\nfreq_table[:,0] = (np.abs(np.sort(np.random.randn(len(wind_directions)))))\nfreq_table = freq_table / freq_table.sum()\n\n# Define the value table such that the value of the energy produced is\n# significantly higher when the wind direction is close to the north or\n# south, and zero when the wind is from the east or west. Here, value is\n# given a mean value of 25 USD/MWh.\nvalue_table = (0.5 + 0.5*np.cos(2*np.radians(wind_directions)))**10\nvalue_table = 25*value_table/np.mean(value_table)\nvalue_table = value_table.reshape((len(wind_directions),1))\n\n# Establish a WindRose object\nwind_rose = WindRose(\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    freq_table=freq_table,\n    ti_table=0.06,\n    value_table=value_table\n)\n\nfmodel.set(wind_data=wind_rose)\n\n# The boundaries for the turbines, specified as vertices\nboundaries = [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)]\n\n# Set turbine locations to 4 turbines in a rectangle\nD = 126.0 # rotor diameter for the NREL 5MW\nlayout_x = [0, 0, 6 * D, 6 * D]\nlayout_y = [0, 4 * D, 0, 4 * D]\nfmodel.set(layout_x=layout_x, layout_y=layout_y)\n\n# Setup the optimization problem to maximize AEP instead of value\nlayout_opt = LayoutOptimizationScipy(fmodel, boundaries, optOptions=opt_options)\n\n# Run the optimization\nsol = layout_opt.optimize()\n\n# Get the resulting improvement in AEP\nprint('... calculating improvement in AEP')\nfmodel.run()\nbase_aep = fmodel.get_farm_AEP() / 1e6\nfmodel.set(layout_x=sol[0], layout_y=sol[1])\nfmodel.run()\nopt_aep = fmodel.get_farm_AEP() / 1e6\n\npercent_gain = 100 * (opt_aep - base_aep) / base_aep\n\n# Print and plot the results\nprint(f'Optimal layout: {sol}')\nprint(\n    f'Optimal layout improves AEP by {percent_gain:.1f}% '\n    f'from {base_aep:.1f} MWh to {opt_aep:.1f} MWh'\n)\nlayout_opt.plot_layout_opt_results()\n\n# reset to the original layout\nfmodel.set(layout_x=layout_x, layout_y=layout_y)\n\n# Now set up the optimization problem to maximize annual value production (AVP)\n# using the value table provided in the WindRose object.\nlayout_opt = LayoutOptimizationScipy(fmodel, boundaries, optOptions=opt_options, use_value=True)\n\n# Run the optimization\nsol = layout_opt.optimize()\n\n# Get the resulting improvement in AVP\nprint('... calculating improvement in annual value production (AVP)')\nfmodel.run()\nbase_avp = fmodel.get_farm_AVP() / 1e6\nfmodel.set(layout_x=sol[0], layout_y=sol[1])\nfmodel.run()\nopt_avp = fmodel.get_farm_AVP() / 1e6\n\npercent_gain = 100 * (opt_avp - base_avp) / base_avp\n\n# Print and plot the results\nprint(f'Optimal layout: {sol}')\nprint(\n    f'Optimal layout improves AVP by {percent_gain:.1f}% '\n    f'from {base_avp:.1f} dollars to {opt_avp:.1f} dollars'\n)\nlayout_opt.plot_layout_opt_results()\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_layout_optimization/002_optimize_layout_with_heterogeneity.py",
    "content": "\"\"\"Example: Layout optimization with heterogeneous inflow\nThis example shows a layout optimization using the geometric yaw option. It\ncombines elements of layout optimization and heterogeneous\ninflow for demonstrative purposes.\n\nHeterogeneity in the inflow provides the necessary driver for coupled yaw\nand layout optimization to be worthwhile. First, a layout optimization is\nrun without coupled yaw optimization; then a coupled optimization is run to\nshow the benefits of coupled optimization when flows are heterogeneous.\n\"\"\"\n\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, WindRose\nfrom floris.optimization.layout_optimization.layout_optimization_scipy import (\n    LayoutOptimizationScipy,\n)\n\n\n# Initialize FLORIS\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Setup 2 wind directions (due east and due west)\n# and 1 wind speed with uniform probability\nwind_directions = np.array([90.0, 270.0])\nn_wds = len(wind_directions)\nwind_speeds = np.array([8.0])\n\n# Shape frequency distribution to match number of wind directions and wind speeds\nfreq_table = np.ones((len(wind_directions), len(wind_speeds)))\nfreq_table = freq_table / freq_table.sum()\n\n\n# The boundaries for the turbines, specified as vertices\nD = 126.0  # rotor diameter for the NREL 5MW\nsize_D = 12\nboundaries = [(0.0, 0.0), (size_D * D, 0.0), (size_D * D, 0.1), (0.0, 0.1), (0.0, 0.0)]\n\n# Set turbine locations to 4 turbines at corners of the rectangle\n# (optimal without flow heterogeneity)\nlayout_x = [0.1, 0.3 * size_D * D, 0.6 * size_D * D]\nlayout_y = [0, 0, 0]\n\n# Generate exaggerated heterogeneous inflow (same for all wind directions)\nspeed_multipliers = np.repeat(np.array([0.5, 1.0, 0.5, 1.0])[None, :], n_wds, axis=0)\nx_locs = [0, size_D * D, 0, size_D * D]\ny_locs = [-D, -D, D, D]\n\n# Create the configuration dictionary to be used for the heterogeneous inflow.\nheterogeneous_inflow_config_by_wd = {\n    \"speed_multipliers\": speed_multipliers,\n    \"wind_directions\": wind_directions,\n    \"x\": x_locs,\n    \"y\": y_locs,\n}\n\n# Establish a WindRose object\nwind_rose = WindRose(\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    freq_table=freq_table,\n    ti_table=0.06,\n    heterogeneous_inflow_config_by_wd=heterogeneous_inflow_config_by_wd,\n)\n\n\nfmodel.set(\n    layout_x=layout_x,\n    layout_y=layout_y,\n    wind_data=wind_rose,\n)\n\n# Setup and solve the layout optimization problem without heterogeneity\nmaxiter = 100\nlayout_opt = LayoutOptimizationScipy(\n    fmodel, boundaries, min_dist=2 * D, optOptions={\"maxiter\": maxiter}\n)\n\n# Run the optimization\nnp.random.seed(0)\nsol = layout_opt.optimize()\n\n# Get the resulting improvement in AEP\nprint(\"... calcuating improvement in AEP\")\n\nfmodel.run()\nbase_aep = fmodel.get_farm_AEP() / 1e6\nfmodel.set(layout_x=sol[0], layout_y=sol[1])\nfmodel.run()\nopt_aep = fmodel.get_farm_AEP() / 1e6\n\npercent_gain = 100 * (opt_aep - base_aep) / base_aep\n\n# Print and plot the results\nprint(f\"Optimal layout: {sol}\")\nprint(\n    f\"Optimal layout improves AEP by {percent_gain:.1f}% \"\n    f\"from {base_aep:.1f} MWh to {opt_aep:.1f} MWh\"\n)\nlayout_opt.plot_layout_opt_results()\nax = plt.gca()\nfig = plt.gcf()\nsm = ax.tricontourf(x_locs, y_locs, speed_multipliers[0], cmap=\"coolwarm\")\nfig.colorbar(sm, ax=ax, label=\"Speed multiplier\")\nax.legend([\"_Optimization boundary\", \"Initial layout\", \"Optimized layout\" ])\nax.set_title(\"Geometric yaw disabled\")\n\n\n# Rerun the layout optimization with geometric yaw enabled\nprint(\"\\nReoptimizing with geometric yaw enabled.\")\nfmodel.set(layout_x=layout_x, layout_y=layout_y)\nlayout_opt = LayoutOptimizationScipy(\n    fmodel, boundaries, min_dist=2 * D, enable_geometric_yaw=True, optOptions={\"maxiter\": maxiter}\n)\n\n# Run the optimization\nnp.random.seed(0)\nsol = layout_opt.optimize()\n\n# Get the resulting improvement in AEP\nprint(\"... calcuating improvement in AEP\")\n\nfmodel.set(yaw_angles=np.zeros_like(layout_opt.yaw_angles))\nfmodel.run()\nbase_aep = fmodel.get_farm_AEP() / 1e6\nfmodel.set(layout_x=sol[0], layout_y=sol[1], yaw_angles=layout_opt.yaw_angles)\nfmodel.run()\nopt_aep = fmodel.get_farm_AEP() / 1e6\n\npercent_gain = 100 * (opt_aep - base_aep) / base_aep\n\n# Print and plot the results\nprint(f\"Optimal layout: {sol}\")\nprint(\n    f\"Optimal layout improves AEP by {percent_gain:.1f}% \"\n    f\"from {base_aep:.1f} MWh to {opt_aep:.1f} MWh\"\n)\nlayout_opt.plot_layout_opt_results()\nax = plt.gca()\nfig = plt.gcf()\nsm = ax.tricontourf(x_locs, y_locs, speed_multipliers[0], cmap=\"coolwarm\")\nfig.colorbar(sm, ax=ax, label=\"Speed multiplier\")\nax.legend([\"_Optimization boundary\", \"Initial layout\", \"Optimized layout\"])\nax.set_title(\"Geometric yaw enabled\")\n\nprint(\n    \"Turbine geometric yaw angles for wind direction {0:.2f}\".format(wind_directions[1])\n    + \" and wind speed {0:.2f} m/s:\".format(wind_speeds[0]),\n    f\"{layout_opt.yaw_angles[1, :]}\",\n)\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_layout_optimization/003_genetic_random_search.py",
    "content": "\"\"\"Example: Layout optimization with genetic random search\nThis example shows a layout optimization using the genetic random search\nalgorithm. It provides options for the users to try different distance\nprobability mass functions for the random search perturbations.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.stats import gamma\n\nfrom floris import FlorisModel, WindRose\nfrom floris.optimization.layout_optimization.layout_optimization_random_search import (\n    LayoutOptimizationRandomSearch,\n)\n\n\nif __name__ == '__main__':\n    # Set up FLORIS\n    fmodel = FlorisModel('../inputs/gch.yaml')\n\n\n    # Setup 72 wind directions with a random wind speed and frequency distribution\n    wind_directions = np.arange(0, 360.0, 5.0)\n    np.random.seed(1)\n    wind_speeds = 8.0 + np.random.randn(1) * 0.0\n    # Shape frequency distribution to match number of wind directions and wind speeds\n    freq = (\n        np.abs(\n            np.sort(\n                np.random.randn(len(wind_directions))\n            )\n        )\n        .reshape( ( len(wind_directions), len(wind_speeds) ) )\n    )\n    freq = freq / freq.sum()\n    fmodel.set(\n        wind_data=WindRose(\n            wind_directions=wind_directions,\n            wind_speeds=wind_speeds,\n            freq_table=freq,\n            ti_table=0.06\n        )\n    )\n\n    # Set the boundaries\n    # The boundaries for the turbines, specified as vertices\n    boundaries = [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)]\n\n    # Set turbine locations to 4 turbines in a rectangle\n    D = 126.0 # rotor diameter for the NREL 5MW\n    layout_x = [0, 0, 6 * D, 6 * D]\n    layout_y = [0, 4 * D, 0, 4 * D]\n    fmodel.set(layout_x=layout_x, layout_y=layout_y)\n\n    # Perform the optimization\n    distance_pmf = None\n\n    # Other options that users can try\n    # 1.\n    # distance_pmf = {\"d\": [100, 1000], \"p\": [0.8, 0.2]}\n    # 2.\n    # p = gamma.pdf(np.linspace(0, 900, 91), 15, scale=20); p = p/p.sum()\n    # distance_pmf = {\"d\": np.linspace(100, 1000, 91), \"p\": p}\n\n    layout_opt = LayoutOptimizationRandomSearch(\n        fmodel,\n        boundaries,\n        min_dist_D=5.,\n        seconds_per_iteration=10,\n        total_optimization_seconds=60.,\n        distance_pmf=distance_pmf\n    )\n    layout_opt.describe()\n    layout_opt.plot_distance_pmf()\n\n    layout_opt.optimize()\n\n    layout_opt.plot_layout_opt_results()\n\n    layout_opt.plot_progress()\n\n    plt.show()\n"
  },
  {
    "path": "examples/examples_layout_optimization/004_generate_gridded_layout.py",
    "content": "\"\"\"Example: Gridded layout design\nThis example shows a layout optimization that places as many turbines as\npossible into a given boundary using a gridded layout pattern.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, WindRose\nfrom floris.optimization.layout_optimization.layout_optimization_gridded import (\n    LayoutOptimizationGridded,\n)\n\n\nif __name__ == '__main__':\n    # Load the Floris model\n    fmodel = FlorisModel('../inputs/gch.yaml')\n\n    # Set the boundaries\n    # The boundaries for the turbines, specified as vertices\n    boundaries = [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)]\n\n    # Set up the optimization object with 5D spacing\n    layout_opt = LayoutOptimizationGridded(\n        fmodel,\n        boundaries,\n        min_dist_D=5., # results in spacing of 5*125.88 = 629.4 m\n        min_dist=None, # Alternatively, can specify spacing directly in meters\n    )\n\n    layout_opt.optimize()\n\n    # Note that the \"initial\" layout that is provided with the fmodel is\n    # not used by the layout optimization.\n    layout_opt.plot_layout_opt_results()\n\n    plt.show()\n"
  },
  {
    "path": "examples/examples_layout_optimization/005_layout_optimization_complex_boundary.py",
    "content": "\"\"\"Example: Separated boundaries layout optimization\nDemonstrates the capabilities of LayoutOptimizationGridded and\nLayoutOptimizationRandomSearch to optimize turbine layouts with complex\nboundaries.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, WindRose\nfrom floris.optimization.layout_optimization.layout_optimization_gridded import (\n    LayoutOptimizationGridded,\n)\nfrom floris.optimization.layout_optimization.layout_optimization_random_search import (\n    LayoutOptimizationRandomSearch,\n)\n\n\nif __name__ == '__main__':\n    # Load the Floris model\n    fmodel = FlorisModel('../inputs/gch.yaml')\n\n    # Set the boundaries\n    # The boundaries for the turbines, specified as vertices\n    boundaries = [\n        [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)],\n        [(1500.0, 0.0), (1500.0, 1000.0), (2500.0, 0.0), (1500.0, 0.0)],\n    ]\n\n    # Set up the wind data information\n    wind_directions = np.arange(0, 360.0, 5.0)\n    np.random.seed(1)\n    wind_speeds = 8.0 + np.random.randn(1) * 0.0\n    # Shape frequency distribution to match number of wind directions and wind speeds\n    freq = (\n        np.abs(\n            np.sort(\n                np.random.randn(len(wind_directions))\n            )\n        )\n        .reshape( ( len(wind_directions), len(wind_speeds) ) )\n    )\n    freq = freq / freq.sum()\n    # Set wind data in the FlorisModel\n    fmodel.set(\n        wind_data=WindRose(\n            wind_directions=wind_directions,\n            wind_speeds=wind_speeds,\n            freq_table=freq,\n            ti_table=0.06\n        )\n    )\n\n    # Begin by placing as many turbines as possible using a gridded layout at 6D spacing\n    layout_opt_gridded = LayoutOptimizationGridded(\n        fmodel,\n        boundaries,\n        min_dist_D=6.,\n        min_dist=None,\n    )\n    layout_opt_gridded.optimize()\n    print(\"Gridded layout complete.\")\n\n    # Set the layout on the fmodel\n    fmodel.set(layout_x=layout_opt_gridded.x_opt, layout_y=layout_opt_gridded.y_opt)\n\n    # Update the layout using a random search optimization with 5D minimum spacing\n    layout_opt_rs = LayoutOptimizationRandomSearch(\n        fmodel,\n        boundaries,\n        min_dist_D=5.,\n        seconds_per_iteration=10,\n        total_optimization_seconds=60.,\n        use_dist_based_init=False,\n    )\n    layout_opt_rs.optimize()\n\n    layout_opt_rs.plot_layout_opt_results(\n        initial_locs_plotting_dict={\"label\": \"Gridded initial layout\"},\n        final_locs_plotting_dict={\"label\": \"Random search optimized layout\"},\n    )\n\n    plt.show()\n"
  },
  {
    "path": "examples/examples_load_optimization/001_lti_and_voc.py",
    "content": "\"\"\"Example: LTI and VOC Behavior with Changing Wind Direction and Power Setpoints\n\nDemonstrate the behavior of the load turbulence intensity model and\nvariable operating cost (VOC) model with respect\nto changing wind direction (which changes wake interactions) and\nchanging power setpoints (which changes wake strength).\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, TimeSeries\nfrom floris.core.turbine.operation_models import (\n    POWER_SETPOINT_DEFAULT,\n    POWER_SETPOINT_DISABLED,\n)\nfrom floris.optimization.load_optimization.load_optimization import (\n    compute_lti,\n    compute_turbine_voc,\n)\n\n\n# Declare a floris model with default configuration\nfmodel = FlorisModel(configuration=\"defaults\")\nfmodel.set_operation_model(\"simple-derating\")\n\n## Wind direction sweep\nwind_directions = np.arange(0, 360, 1.0)\n\n# Assume uniform load ambient turbulence intensities\nambient_lti = 0.1 * np.ones_like(wind_directions)\n\n# Declare a time series representing the wind direction sweep\ntime_series = TimeSeries(\n    wind_directions=wind_directions, wind_speeds=8.0, turbulence_intensities=0.06\n)\n\n# Set the turbine layout to be a simple two turbine layout using the\n# time series object\nD = fmodel.core.farm.rotor_diameters[0]\nfmodel.set(layout_x=[0, D * 7], layout_y=[0.0, 0.0], wind_data=time_series)\nfmodel.run()\n\n# Compute the load turbulence intensity and VOC\nload_ti = compute_lti(fmodel, ambient_lti)\nvoc = compute_turbine_voc(fmodel, A=2e-5, ambient_lti=ambient_lti)\n\n# Plot the TI and VOC for each turbine\nfig, ax = plt.subplots(2, 1, sharex=True)\nfor t in range(fmodel.n_turbines):\n    ax[0].plot(wind_directions, load_ti[:, t], label=f\"Turbine {t}\")\n    ax[1].plot(wind_directions, voc[:, t], label=f\"Turbine {t}\")\nax[0].set_ylabel(\"LTI [-]\")\nax[1].set_ylabel(\"VOC [$]\")\nax[1].set_xlabel(\"Wind Direction [deg]\")\nax[1].legend(loc=\"lower right\")\nax[0].grid()\nax[1].grid()\nax[0].set_title(\n    \"LTI and VOC vs Wind Direction\\n\"\n    \"X, Y Turbine Coordinates: T0: (0, 0), T1: (7D, 0)\"\n)\n\n## Power setpoint sweep\nN = 50\ntime_series = TimeSeries(\n    wind_directions=np.ones(N) * 270.0, # Single wind direction\n    wind_speeds=8.0,\n    turbulence_intensities=0.06,\n)\npower_setpoints = np.column_stack([\n    np.linspace(5e6, POWER_SETPOINT_DISABLED, N),\n    np.ones(N)*POWER_SETPOINT_DEFAULT\n])\nambient_lti = np.ones(N) * 0.1\nfmodel.set(\n    layout_x=[0, D * 7],\n    layout_y=[0.0, 0.0],\n    wind_data=time_series,\n    power_setpoints=power_setpoints,\n)\nfmodel.run()\n\n# Compute the load turbulence intensity and VOC\nload_ti = compute_lti(fmodel, ambient_lti)\nvoc = compute_turbine_voc(fmodel, A=2e-5, ambient_lti=ambient_lti)\n\n# Plot the TI and VOC for each turbine\nfig, ax = plt.subplots(2, 1, sharex=True)\nfor t in range(fmodel.n_turbines):\n    ax[0].plot(power_setpoints[:,0], load_ti[:, t], label=f\"Turbine {t}\")\n    ax[1].plot(power_setpoints[:,0], voc[:, t], label=f\"Turbine {t}\")\nax[0].set_ylabel(\"LTI [-]\")\nax[1].set_ylabel(\"VOC [$]\")\nax[1].set_xlabel(\"Power Setpoint (T0) [W]\")\nax[1].legend(loc=\"lower right\")\nax[0].grid()\nax[1].grid()\nax[0].set_title(\n    \"LTI and VOC vs T0 Power Setpoint\\n\"\n    \"Wind Direction = 270\\u00B0, Wind Speed = 8 m/s\"\n)\n\n## Load ambient TI sweep\nambient_lti = np.linspace(0.05, 0.25, N)\npower_setpoints = POWER_SETPOINT_DEFAULT * np.ones((N, 2))\nfmodel.set(power_setpoints=power_setpoints)\nfmodel.run()\n\n# Compute the load turbulence intensity and VOC\nload_ti = compute_lti(fmodel, ambient_lti)\nvoc = compute_turbine_voc(fmodel, A=2e-5, ambient_lti=ambient_lti)\n\n# Plot the TI and VOC for each turbine\nfig, ax = plt.subplots(2, 1, sharex=True)\nfor t in range(fmodel.n_turbines):\n    ax[0].plot(ambient_lti, load_ti[:, t], label=f\"Turbine {t}\")\n    ax[1].plot(ambient_lti, voc[:, t], label=f\"Turbine {t}\")\nax[0].set_ylabel(\"LTI [-]\")\nax[1].set_ylabel(\"VOC [$]\")\nax[1].set_xlabel(\"Load Ambient TI [-]\")\nax[1].legend(loc=\"lower right\")\nax[0].grid()\nax[1].grid()\nax[0].set_title(\n    \"LTI and VOC vs Load Ambient TI\\n\"\n    \"Wind Direction = 270\\u00B0, Wind Speed = 8 m/s\"\n)\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_load_optimization/002_row_opt_example.py",
    "content": "\"\"\"Example: Optimize a row of turbines\n\nThis example optimizes the derating of a row of three turbines to maximize net revenue for a\nvariety of combinations of wind direction, ambient \"load TI\" (LTI), and electricity values.\nThe row is aligned when the wind direction is 270 degrees.\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\n\nfrom floris import FlorisModel, TimeSeries\nfrom floris.core.turbine.operation_models import (\n    POWER_SETPOINT_DEFAULT,\n    POWER_SETPOINT_DISABLED,\n)\nfrom floris.optimization.load_optimization.load_optimization import (\n    compute_farm_revenue,\n    compute_farm_voc,\n    compute_net_revenue,\n    optimize_power_setpoints,\n)\n\n\n# Parameters\nD = 126.0\nd_spacing = 7.0\npower_setpoint_levels = np.linspace(POWER_SETPOINT_DEFAULT, POWER_SETPOINT_DISABLED, 10)\nn_turbines = 3\nA = 4e-6  # Selected to demonstrate variation in derating selection\n\n# Declare a floris model with default configuration\nfmodel = FlorisModel(configuration=\"defaults\")\n\n\n# Set up a row of turbines\nfmodel.set(\n    layout_x=[i * D * d_spacing for i in range(n_turbines)],\n    layout_y=[0.0 for i in range(n_turbines)],\n)\n\n# Set operation to simple derating\nfmodel.set_operation_model(\"simple-derating\")\n\n\n# Set up input conditions\nwind_directions = []\nvalues = []\nambient_lti = []\n\nfor w_i in [240.0, 270.0]:\n    for t_i in [0.1, 0.25]:\n        for v_i in [1e-5, 1e-6]:\n            wind_directions.append(w_i)\n            values.append(v_i)\n            ambient_lti.append(t_i)\nwind_directions = np.array(wind_directions)\nvalues = np.array(values)\nambient_lti = np.array(ambient_lti)\nN = len(wind_directions)\n\ntime_series = TimeSeries(\n    wind_directions=wind_directions, wind_speeds=8.0, turbulence_intensities=0.06, values=values\n)\n\n# Run the FLORIS model\nfmodel.set(wind_data=time_series)\nfmodel.run()\n\n# Set the initial power setpoints as no derating\ninitial_power_setpoint = np.ones((N, n_turbines)) * 5e6\n\n# Set these initial power setpoints\nfmodel.set(power_setpoints=initial_power_setpoint)\nfmodel.run()\nnet_revenue_initial = compute_net_revenue(fmodel, A, ambient_lti)\nfarm_voc_initial = compute_farm_voc(fmodel, A, ambient_lti)\nfarm_revenue_initial = compute_farm_revenue(fmodel)\n\n\n# Compute the optimal derating levels given A_initial\nopt_power_setpoints, opt_net_revenue = optimize_power_setpoints(\n    fmodel,\n    A,\n    ambient_lti,\n    power_setpoint_initial=initial_power_setpoint,\n    power_setpoint_levels=power_setpoint_levels,\n)\n\n# Compute final values\nfmodel.set(power_setpoints=opt_power_setpoints)\nfmodel.run()\nnet_revenue_opt = compute_net_revenue(fmodel, A, ambient_lti)\nfarm_voc_opt = compute_farm_voc(fmodel, A, ambient_lti)\nfarm_revenue_opt = compute_farm_revenue(fmodel)\n\n\n# Show the results\nfig, axarr = plt.subplots(7, 1, sharex=True, figsize=(10, 9))\n\n# Plot the wind direction\nax = axarr[0]\nax.plot(wind_directions, color=\"k\")\nax.set_ylabel(\"Wind\\n Direction (deg)\", fontsize=7)\nax.set_title(\"X, Y Turbine Coordinates: T0: (0, 0), T1: (7D, 0), T2: (14D, 0); Wind Speed = 8 m/s\")\n\n# Plot the load TI\nax = axarr[1]\nax.plot(ambient_lti, color=\"k\")\nax.set_ylabel(\"LTI (-)\", fontsize=7)\n\n# Plot the values\nax = axarr[2]\nax.plot(1e6 * values, color=\"k\")\nax.set_ylabel(\"Value of\\n Electricity ($/MWh)\", fontsize=7)\n\n# Plot the initial and final farm revenue\nax = axarr[3]\nax.plot(farm_revenue_initial, label=\"Initial\", color=\"k\")\nax.plot(farm_revenue_opt, label=\"Optimized\", color=\"r\")\nax.set_ylabel(\"Farm\\n Revenue ($)\", fontsize=7)\nax.legend()\n\n# Plot the initial and final farm VOC\nax = axarr[4]\nax.plot(farm_voc_initial, label=\"Initial\", color=\"k\")\nax.plot(farm_voc_opt, label=\"Optimized\", color=\"r\")\nax.set_ylabel(\"Farm VOC ($)\", fontsize=7)\nax.legend()\n\n# Plot the initial and final farm net revenue\nax = axarr[5]\nax.plot(net_revenue_initial, label=\"Initial\", color=\"k\")\nax.plot(net_revenue_opt, label=\"Optimized\", color=\"r\")\nax.set_ylabel(\"Farm Net\\nRevenue ($)\", fontsize=7)\nax.legend()\n\n# Plot the turbine deratings\nax = axarr[6]\nfor i in range(n_turbines):\n    ax.plot(opt_power_setpoints[:, i] / 1000.0, label=f\"Turbine {i}\", lw=3 * n_turbines / (i + 1))\nax.set_ylabel(\"Power\\n Setpoint (kW)\", fontsize=7)\nax.set_xlabel(\"Wind Condition and Electricity Value Combination\")\nax.legend()\n\nfor ax in axarr:\n    ax.grid(True)\n\n\n# Produce a heat-map to illustrate the chosen derating configurations by condition\n\n# Make a list of strings whose value is \"waked\" when wind_directions is at its maximum\nwake_status = [\"waked\" if wd == wind_directions.max() else \"unwaked\" for wd in wind_directions]\n\n# Make a list of strings whose value is \"high_ambient_ti\"\n# when ambient_lti is at its maximum, otherwise \"low_ambient_ti\"\nambient_status = [\n    \"high_ambient_ti\" if ti == ambient_lti.max() else \"low_ambient_ti\" for ti in ambient_lti\n]\n\n# Make a list of strings whose value is \"high_value\" when values is at its maximum,\n#  otherwise \"low_value\"\nvalue_status = [\"high_value\" if v == values.max() else \"low_value\" for v in values]\n\n# Cat the elements of each of these strings together\nstatus = [f\"{w} {a} {v}\" for w, a, v in zip(wake_status, ambient_status, value_status)]\n\n# Combine into a dataframe\ndf = pd.DataFrame(\n    {\n        \"status\": status,\n        \"Turbine 0\": opt_power_setpoints[:, 0],\n        \"Turbine 1\": opt_power_setpoints[:, 1],\n        \"Turbine 2\": opt_power_setpoints[:, 2],\n    }\n)\n\ndf = df.set_index(\"status\")\n\n\n# Assuming your dataframe df is already set up as in your example\nfig, ax = plt.subplots(figsize=(10, 5))\n\n# Get the data values as a numpy array\ndata = df.values\n\n# Create the heatmap\nim = ax.imshow(data, cmap=\"coolwarm_r\", aspect=\"auto\")\n\n# Add the annotations to the cells\nfor i in range(len(df.index)):\n    for j in range(len(df.columns)):\n        text = ax.text(j, i, f\"{data[i, j]:.3f}\", ha=\"center\", va=\"center\", color=\"w\")\n\n# Set title\nax.set_title(\"Optimized Power Setpoints (W)\")\n\n# Set x and y tick labels\nax.set_xticks(np.arange(len(df.columns)))\nax.set_yticks(np.arange(len(df.index)))\nax.set_xticklabels(df.columns)\nax.set_yticklabels(df.index)\n\n# Rotate the x tick labels\nplt.setp(ax.get_xticklabels(), rotation=45, ha=\"right\", rotation_mode=\"anchor\")\n\nplt.tight_layout()\nplt.show()\n"
  },
  {
    "path": "examples/examples_multidim/001_multi_dimensional_cp_ct.py",
    "content": "\"\"\"Example: Multi-dimensional power/thrust coefficient data\nThis example creates a FLORIS instance and:\n1) Makes a two-turbine layout\n2) Demonstrates single ws/wd simulations\n3) Demonstrates multiple ws/wd simulations\n\nwith the modification of using a turbine definition that has a multi-dimensional\npower/thrust coefficient table.\n\nIn the input file `gch_multi_dim_cp_ct.yaml`, the turbine_type points to a turbine definition,\niea_15MW_floating_multi_dim_cp_ct.yaml located in the turbine_library,\nthat supplies a multi-dimensional power/thrust coefficient data file in the form of a .csv file.\nThis .csv file contains two additional conditions to define power and thrust coefficient values for:\nTp for wave period, and Hs for wave height. For every combination of Tp and Hs defined, a\npower/thrust coefficient/Wind speed table of values is also defined. It is required for this .csv\nfile to have the last 3 columns be ws, power, and thrust coefficient. In order\nfor this table to be used, the flag 'multi_dimensional_cp_ct' must be present and set to true in\nthe turbine definition. With this flag enabled, the solver will down-select to use the\ninterpolant defined at the closest conditions. The user must supply these conditions in the\nmain input file under the 'flow_field' section, e.g.:\n\nNOTE: The multi-dimensional power/thrust coefficient data used in this example is fictional for the\npurposes of facilitating this example. The power/thrust coefficient values for the different wave\nconditions are scaled values of the original power/thrust coefficient data for the IEA 15MW turbine.\n\nflow_field:\n  multidim_conditions:\n    Tp: 2.5\n    Hs: 3.01\n\nThe solver will then use the nearest-neighbor interpolant. These conditions are currently global\nand used to select the interpolant at each turbine.\n\nAlso note in the example below that there is a specific method for computing powers when\nusing turbines with multi-dimensional power/thrust coefficient data under FlorisModel, called\n'get_turbine_powers_multidim'. The normal 'get_turbine_powers' method will not work.\n\"\"\"\n\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\n# Initialize FLORIS with the given input file.\nfmodel = FlorisModel(\"../inputs/gch_multi_dim_cp_ct.yaml\")\n\n# Convert to a simple two turbine layout\nfmodel.set(layout_x=[0.0, 500.0], layout_y=[0.0, 0.0])\n\n# Single wind speed and wind direction\nprint(\"\\n========================= Single Wind Direction and Wind Speed =========================\")\n\n# Get the turbine powers assuming 1 wind speed and 1 wind direction\nfmodel.set(wind_directions=[270.0], wind_speeds=[8.0], turbulence_intensities=[0.06])\n\n# Set the yaw angles to 0\nyaw_angles = np.zeros([1, 2])  # 1 wind direction and wind speed, 2 turbines\nfmodel.set(yaw_angles=yaw_angles)\n\n# Calculate\nfmodel.run()\n\n# Get the turbine powers\nturbine_powers = fmodel.get_turbine_powers() / 1000.0\nprint(\"The turbine power matrix should be of dimensions 1 findex X 2 Turbines\")\nprint(turbine_powers)\nprint(\"Shape: \", turbine_powers.shape)\n\n# Single wind speed and multiple wind directions\nprint(\"\\n========================= Single Wind Direction and Multiple Wind Speeds ===============\")\n\nwind_speeds = np.array([8.0, 9.0, 10.0])\nwind_directions = np.array([270.0, 270.0, 270.0])\nturbulence_intensities = np.array([0.06, 0.06, 0.06])\n\nyaw_angles = np.zeros([3, 2])  # 3 wind directions/ speeds, 2 turbines\nfmodel.set(\n    wind_speeds=wind_speeds,\n    wind_directions=wind_directions,\n    turbulence_intensities=turbulence_intensities,\n    yaw_angles=yaw_angles,\n)\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers() / 1000.0\nprint(\"The turbine power matrix should be of dimensions 3 findex X 2 Turbines\")\nprint(turbine_powers)\nprint(\"Shape: \", turbine_powers.shape)\n\n# Multiple wind speeds and multiple wind directions\nprint(\"\\n========================= Multiple Wind Directions and Multiple Wind Speeds ============\")\n\nwind_speeds = np.tile([8.0, 9.0, 10.0], 3)\nwind_directions = np.repeat([260.0, 270.0, 280.0], 3)\nturbulence_intensities = 0.06 * np.ones_like(wind_speeds)\n\nyaw_angles = np.zeros([9, 2])  # 9 wind directions/ speeds, 2 turbines\nfmodel.set(\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    turbulence_intensities=turbulence_intensities,\n    yaw_angles=yaw_angles,\n)\nfmodel.run()\nturbine_powers = fmodel.get_turbine_powers() / 1000.0\nprint(\"The turbine power matrix should be of dimensions 9 WD/WS X 2 Turbines\")\nprint(turbine_powers)\nprint(\"Shape: \", turbine_powers.shape)\n"
  },
  {
    "path": "examples/examples_multidim/002_multi_dimensional_cp_ct_2Hs.py",
    "content": "\"\"\"Example: Multi-dimensional power/thrust coefficient with 2 Hs values\nThis example follows the previous example but shows the effect of changing the Hs setting.\n\nUpdated in FLORIS v4.6 to use new array-based multidimensional functionality, where a different\nmultidimensional condition can be specified for each findex. Prior to v4.6, when only scalar\nmultidimensional conditions were supported, this example used two separate FLORIS runs to compute\nthe two Hs cases.\n\nNOTE: The multi-dimensional power/thrust coefficient data used in this example is fictional for the\npurposes of facilitating this example. The power/thrust coefficient values for the different wave\nconditions are scaled values of the original power/thrust coefficient data for the IEA 15MW turbine.\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, TimeSeries\n\n\n# Initialize FLORIS with the given input file.\nfmodel = FlorisModel(\"../inputs/gch_multi_dim_cp_ct.yaml\")\nfmodel.set(layout_x=[0.0, 500.0, 1000.0], layout_y=[0.0, 0.0, 0.0])\n\n# Conditions to evaluate\nn_wind_speeds = 16\nwind_speeds = np.tile(np.linspace(5, 20, n_wind_speeds), 2) # Sweep wind speeds\nmultidim_conditions = {\n    \"Tp\": np.array([2.5]*n_wind_speeds*2),\n    \"Hs\": np.array([3.1]*n_wind_speeds + [1.0]*n_wind_speeds),\n}\ntime_series = TimeSeries(\n    wind_directions=270.0,\n    wind_speeds=wind_speeds,\n    turbulence_intensities=0.06,\n    multidim_conditions=multidim_conditions\n)\n\n# Set wind, multidim conditios onto the FlorisModel\nfmodel.set(wind_data=time_series)\n\n# Calculate wakes\nfmodel.run()\n\n# Collect the turbine powers in kW\nturbine_powers = fmodel.get_turbine_powers() / 1000.0\n\n# Plot the power in each case and the difference in power\nfig, axarr = plt.subplots(1, 3, sharex=True, figsize=(12, 4))\n\nfor t_idx in range(3):\n    ax = axarr[t_idx]\n    ax.plot(\n        wind_speeds[:n_wind_speeds],\n        turbine_powers[:n_wind_speeds, t_idx],\n        color=\"k\",\n        label=\"Hs=3.1 (5)\"\n    )\n    ax.plot(\n        wind_speeds[n_wind_speeds:],\n        turbine_powers[n_wind_speeds:, t_idx],\n        color=\"r\",\n        label=\"Hs=1.0\"\n    )\n    ax.grid(True)\n    ax.set_xlabel(\"Wind Speed (m/s)\")\n    ax.set_title(f\"Turbine {t_idx}\")\n\naxarr[0].set_ylabel(\"Power (kW)\")\naxarr[0].legend()\nfig.suptitle(\"Power of each turbine\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_multidim/003_multi_dimensional_cp_ct_TI.py",
    "content": "\"\"\"Example: Multi-dimensional power/thrust coefficients with turbulence intensity\nThis example follows the previous example, but demonstrating how a multidimensional turbine can be\nused to model the effect of turbulence intensity on power and thrust coefficient.\n\nUpdated in FLORIS v4.6 to demonstrate new array-based multidimensional functionality. In the updated\nversion, setting loop_over_ti to True will run a single scalar multidimensional condition at a time\nand call fmodel.run() multiple times, similar to the behavior prior to v4.6. Alternatively, users\nmay set loop_over_ti to False to use the new (and improved!) functionality and run all TI values in\na single call to fmodel.run().\n\nNOTE: The multi-dimensional power/thrust coefficient data used in this example is fictional for the\npurposes of facilitating this example and the power values shown should not be taken as\nrepresentative of the actual effect of turbulence intensity on power/thrust coefficient.\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel, TimeSeries\n\n\n# Initialize FLORIS with the given input file.\nfmodel = FlorisModel(\"../inputs/gch_multi_dim_cp_ct_TI.yaml\")\n\n# Set both cases to 3 turbine layout\nfmodel.set(layout_x=[0.0, 500.0, 1000.0], layout_y=[0.0, 0.0, 0.0])\n\nloop_over_ti = True # Otherwise, will set all TIs at once.\n\n# Use a sweep of wind speeds\nwind_speeds = np.arange(5, 20, 0.1)\n\nif loop_over_ti:\n    # In this case, we will run() the fmodel multiple times, one for each turbulence intensity.\n    # We set a scalar multidim_conditions, which is broadcast over the wind speeds.\n    time_series = TimeSeries(\n        wind_directions=270.0, wind_speeds=wind_speeds, turbulence_intensities=0.06\n    )\n    fmodel.set(wind_data=time_series)\n\n    # Loop over different turbulence intensities using set()\n    # When running with TI=0.10, the multidimensional data handler will find the nearest defined\n    # value of 0.08 and use that data.\n    fig, axarr = plt.subplots(1, 3, sharex=True, figsize=(12, 4))\n    for ti, col in zip([0.06, 0.10], [\"k\", \"r\"]):\n        fmodel.set(multidim_conditions={\"TI\": ti})\n        fmodel.run()\n        turbine_powers = fmodel.get_turbine_powers() / 1000.0\n\n        for t_idx in range(3):\n            ax = axarr[t_idx]\n            ax.plot(wind_speeds, turbine_powers[:, t_idx], color=col, label=\"TI={0:.2f}\".format(ti))\nelse:\n    # Set all conditions to evaluate at once, and call fmodel.run() only once.\n    # We set multidim_conditions to be arrays matching the number of findices of the fmodel.\n\n    # Note that turbulence_intensities on the TimeSeries object is _not_ linked to the\n    # multidim_conditions\n    time_series = TimeSeries(\n        wind_directions=270.0,\n        wind_speeds=np.tile(wind_speeds, 2),\n        turbulence_intensities=0.06, # This value will be used for wake calculations only\n        multidim_conditions={\"TI\": np.array([0.06]*len(wind_speeds) + [0.10]*len(wind_speeds))},\n    )\n    fmodel.set(wind_data=time_series)\n    fmodel.run()\n    turbine_powers = fmodel.get_turbine_powers() / 1000.0\n\n    fig, axarr = plt.subplots(1, 3, sharex=True, figsize=(12, 4))\n    for t_idx in range(3):\n        ax = axarr[t_idx]\n        ax.plot(wind_speeds, turbine_powers[:len(wind_speeds), t_idx], color=\"k\", label=\"TI=0.06\")\n        ax.plot(wind_speeds, turbine_powers[len(wind_speeds):, t_idx], color=\"r\", label=\"TI=0.10\")\n\n# Plot aesthetics\nfor t_idx in range(3):\n    axarr[t_idx].grid(True)\n    axarr[t_idx].set_xlabel(\"Wind Speed (m/s)\")\n    axarr[t_idx].set_title(f\"Turbine {t_idx}\")\naxarr[0].legend()\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_operation_models/001_compare_yaw_loss.py",
    "content": "\"\"\"Example: Compare yaw loss under different operation models\n\nThis example shows demonstrates how the Controller-dependent operation model (developed at TUM)\nand Unified Momentum Model (developed at MIT) alter how a turbine loses power to yaw compared\nto the standard cosine loss model.\n\"\"\"\n\nimport itertools\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\n# Parameters\nN  = 101 # How many steps to cover yaw range in\nyaw_max = 30 # Maximum yaw to test\n\n# Set up the yaw angle sweep\nyaw_angles = np.zeros((N,1))\nyaw_angles[:,0] = np.linspace(-yaw_max, yaw_max, N)\n\n# Create the FLORIS model\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\nfmodel.set(\n    layout_x=[0.0],\n    layout_y=[0.0],\n    wind_directions=np.ones(N) * 270.0,\n    wind_speeds=1.0*np.ones(N), # Will be replaced\n    turbulence_intensities=0.06 * np.ones(N),\n    yaw_angles=yaw_angles,\n)\n\n# Define a function to evaluate the power under various yaw angles\ndef evaluate_yawed_power(wsp: float, op_model: str) -> float:\n    print(f\"Evaluating model: {op_model}   wind speed: {wsp} m/s\")\n    fmodel.set(wind_speeds=wsp * np.ones(N))\n    fmodel.set_operation_model(op_model)\n    fmodel.run()\n\n    return fmodel.get_turbine_powers()[:, 0]\n\n# Loop over the operational models and wind speeds to compare\nop_models = [\"simple\", \"cosine-loss\", \"controller-dependent\", \"unified-momentum\"]\nwind_speeds = [8.0, 11.5, 15.0]\nresults = {}\nfor op_model, wsp in itertools.product(op_models, wind_speeds):\n    results[(op_model, wsp)] = evaluate_yawed_power(wsp, op_model)\n\n# Plot the results\nfig, axes = plt.subplots(1, len(wind_speeds), sharey=True, figsize=(10, 5))\n\ncolors = [\"k\", \"k\", \"C0\", \"C1\"]\nlinestyles = [\"dashed\", \"solid\", \"dashed\", \"dotted\"]\nfor wsp, ax in zip(wind_speeds, axes):\n    ax.set_title(f\"Wind speed: {wsp} m/s\")\n    ax.set_xlabel(\"Yaw angle [deg]\")\n    ax.grid(True)\n    for op_model, c, ls in zip(op_models, colors, linestyles):\n\n        upstream_yaw_angle = yaw_angles[:, 0]\n        central_power = results[(op_model, wsp)][upstream_yaw_angle == 0]\n        ax.plot(\n            upstream_yaw_angle,\n            results[(op_model, wsp)] / central_power,\n            label=op_model,\n            color=c,\n            linestyle=ls,\n        )\n\nax.grid(True)\nax.legend()\naxes[0].set_xlabel(\"Yaw angle [deg]\")\naxes[0].set_ylabel(\"Normalized turbine power [-]\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_turbine/001_reference_turbines.py",
    "content": "\"\"\"Example: Reference turbines\n\nFor each reference wind turbine in the turbine library, make a small figure\nshowing its power and thrust coefficient curves and demonstrate its power loss\nto yaw.\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\n\n\nws_array = np.arange(0.1, 30, 0.2)\nwd_array = 270.0 * np.ones_like(ws_array)\nturbulence_intensities = 0.06 * np.ones_like(ws_array)\nyaw_angles = np.linspace(-30, 30, 60)\nwind_speed_to_test_yaw = 11\n\n# Grab the gch model\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Make one turbine simulation\nfmodel.set(layout_x=[0], layout_y=[0])\n\n# Apply wind directions and wind speeds\nfmodel.set(\n    wind_speeds=ws_array, wind_directions=wd_array, turbulence_intensities=turbulence_intensities\n)\n\n# Get a list of available turbine models provided through FLORIS, and remove\n# multi-dimensional power/thrust coefficient turbine definitions as they require different handling\nturbines = [\n    t.stem\n    for t in fmodel.core.farm.internal_turbine_library.iterdir()\n    if t.suffix == \".yaml\" and (\"multi_dim\" not in t.stem)\n]\n\n# Declare a set of figures for comparing cp and ct across models\nfig_pow_ct, axarr_pow_ct = plt.subplots(2, 1, sharex=True, figsize=(10, 10))\n\n# For each turbine model available plot the basic info\nfor t in turbines:\n    # Set t as the turbine\n    fmodel.set(turbine_type=[t])\n    fmodel.reset_operation() # Remove any previously applied yaw angles\n\n    # Since we are changing the turbine type, make a matching change to the reference wind height\n    fmodel.assign_hub_height_to_ref_height()\n\n    # Plot power and ct onto the fig_pow_ct plot\n    axarr_pow_ct[0].plot(\n        fmodel.core.farm.turbine_map[0].power_thrust_table[\"wind_speed\"],\n        fmodel.core.farm.turbine_map[0].power_thrust_table[\"power\"],\n        label=t,\n    )\n    axarr_pow_ct[0].grid(True)\n    axarr_pow_ct[0].legend()\n    axarr_pow_ct[0].set_ylabel(\"Power (kW)\")\n    axarr_pow_ct[1].plot(\n        fmodel.core.farm.turbine_map[0].power_thrust_table[\"wind_speed\"],\n        fmodel.core.farm.turbine_map[0].power_thrust_table[\"thrust_coefficient\"],\n        label=t,\n    )\n    axarr_pow_ct[1].grid(True)\n    axarr_pow_ct[1].legend()\n    axarr_pow_ct[1].set_ylabel(\"Ct (-)\")\n    axarr_pow_ct[1].set_xlabel(\"Wind Speed (m/s)\")\n\n    # Create a figure\n    fig, axarr = plt.subplots(1, 2, figsize=(10, 5))\n\n    # Try a few density\n    for density in [1.15, 1.225, 1.3]:\n        fmodel.set(air_density=density)\n\n        # POWER CURVE\n        ax = axarr[0]\n        fmodel.set(\n            wind_speeds=ws_array,\n            wind_directions=wd_array,\n            turbulence_intensities=turbulence_intensities,\n        )\n        fmodel.reset_operation() # Remove any previously applied yaw angles\n        fmodel.run()\n        turbine_powers = fmodel.get_turbine_powers().flatten() / 1e3\n        if density == 1.225:\n            ax.plot(ws_array, turbine_powers, label=\"Air Density = %.3f\" % density, lw=2, color=\"k\")\n        else:\n            ax.plot(ws_array, turbine_powers, label=\"Air Density = %.3f\" % density, lw=1)\n        ax.grid(True)\n        ax.legend()\n        ax.set_xlabel(\"Wind Speed (m/s)\")\n        ax.set_ylabel(\"Power (kW)\")\n\n        # Power loss to yaw, try a range of yaw angles\n        ax = axarr[1]\n\n        fmodel.set(\n            wind_speeds=[wind_speed_to_test_yaw],\n            wind_directions=[270.0],\n            turbulence_intensities=[0.06],\n        )\n        yaw_result = []\n        for yaw in yaw_angles:\n            fmodel.set(yaw_angles=np.array([[yaw]]))\n            fmodel.run()\n            turbine_powers = fmodel.get_turbine_powers().flatten() / 1e3\n            yaw_result.append(turbine_powers[0])\n        if density == 1.225:\n            ax.plot(yaw_angles, yaw_result, label=\"Air Density = %.3f\" % density, lw=2, color=\"k\")\n        else:\n            ax.plot(yaw_angles, yaw_result, label=\"Air Density = %.3f\" % density, lw=1)\n        # ax.plot(yaw_angles,yaw_result,label='Air Density = %.3f' % density)\n        ax.grid(True)\n        ax.legend()\n        ax.set_xlabel(\"Yaw Error (deg)\")\n        ax.set_ylabel(\"Power (kW)\")\n        ax.set_title(\"Wind Speed = %.1f\" % wind_speed_to_test_yaw)\n\n    # Give a suptitle\n    fig.suptitle(t)\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_turbine/002_multiple_turbine_types.py",
    "content": "\"\"\"Example: Multiple turbine types\n\nThis example uses an input file where multiple turbine types are defined.\nThe first two turbines are the NREL 5MW, and the third turbine is the IEA 10MW.\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\n\nimport floris.flow_visualization as flowviz\nfrom floris import FlorisModel\n\n\n# Initialize FLORIS with the given input file.\n# For basic usage, FlorisModel provides a simplified and expressive\n# entry point to the simulation routines.\nfmodel = FlorisModel(\"../inputs/gch_multiple_turbine_types.yaml\")\n\n# Using the FlorisModel functions for generating plots, run FLORIS\n# and extract 2D planes of data.\nhorizontal_plane = fmodel.calculate_horizontal_plane(x_resolution=200, y_resolution=100, height=90)\ny_plane = fmodel.calculate_y_plane(x_resolution=200, z_resolution=100, crossstream_dist=0.0)\ncross_plane = fmodel.calculate_cross_plane(\n    y_resolution=100, z_resolution=100, downstream_dist=500.0\n)\n\n# Create the plots\nfig, ax_list = plt.subplots(3, 1, figsize=(10, 8))\nax_list = ax_list.flatten()\nflowviz.visualize_cut_plane(horizontal_plane, ax=ax_list[0], title=\"Horizontal\")\nflowviz.visualize_cut_plane(y_plane, ax=ax_list[1], title=\"Streamwise profile\")\nflowviz.visualize_cut_plane(cross_plane, ax=ax_list[2], title=\"Spanwise profile\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_turbine/003_specify_turbine_power_curve.py",
    "content": "\"\"\"Example: Specify turbine power curve\n\nThis example demonstrates how to specify a turbine model based on a power\nand thrust curve for the wind turbine, as well as possible physical parameters\n(which default to the parameters of the NREL 5MW reference turbine).\n\nNote that it is also possible to have a .yaml created, if the file_path\nargument to build_turbine_dict is set.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom floris.turbine_library import build_cosine_loss_turbine_dict\n\n\n# Generate an example turbine power and thrust curve for use in the FLORIS model\npowers_orig = np.array([0, 30, 200, 500, 1000, 2000, 4000, 4000, 4000, 4000, 4000])\nwind_speeds = np.array([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20])\npower_coeffs = powers_orig[1:] / (0.5 * 126.0**2 * np.pi / 4 * 1.225 * wind_speeds[1:] ** 3)\nturbine_data_dict = {\n    \"wind_speed\": list(wind_speeds),\n    \"power_coefficient\": [0] + list(power_coeffs),\n    \"thrust_coefficient\": [0, 0.9, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.25, 0.2],\n}\n\nturbine_dict = build_cosine_loss_turbine_dict(\n    turbine_data_dict,\n    \"example_turbine\",\n    file_name=None,\n    generator_efficiency=1,\n    hub_height=90,\n    cosine_loss_exponent_yaw=1.88,\n    cosine_loss_exponent_tilt=1.88,\n    rotor_diameter=126,\n    TSR=8,\n    ref_air_density=1.225,\n    ref_tilt=5,\n)\n\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\nwind_speeds = np.linspace(1, 15, 100)\nwind_directions = 270 * np.ones_like(wind_speeds)\nturbulence_intensities = 0.06 * np.ones_like(wind_speeds)\n# Replace the turbine(s) in the FLORIS model with the created one\nfmodel.set(\n    layout_x=[0],\n    layout_y=[0],\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    turbulence_intensities=turbulence_intensities,\n    turbine_type=[turbine_dict],\n    reference_wind_height=fmodel.reference_wind_height\n)\nfmodel.run()\n\npowers = fmodel.get_farm_power()\n\nspecified_powers = (\n    np.array(turbine_data_dict[\"power_coefficient\"])\n    * 0.5\n    * turbine_dict[\"power_thrust_table\"][\"ref_air_density\"]\n    * turbine_dict[\"rotor_diameter\"] ** 2\n    * np.pi\n    / 4\n    * np.array(turbine_data_dict[\"wind_speed\"]) ** 3\n) / 1000\n\nfig, ax = plt.subplots(1, 1, sharex=True)\n\nax.scatter(wind_speeds, powers / 1000, color=\"C0\", s=5, label=\"Test points\")\nax.scatter(\n    turbine_data_dict[\"wind_speed\"], specified_powers, color=\"red\", s=20, label=\"Specified points\"\n)\n\nax.grid()\nax.set_xlabel(\"Wind speed [m/s]\")\nax.set_ylabel(\"Power [kW]\")\nax.legend()\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_turbopark/001_compare_turbopark_implementations.py",
    "content": "\"\"\"Example: Compare TurbOPark model implementations\nThis example demonstrates a new implementation of the TurbOPark model that is\nmore faithful to the original description provided by Pedersen et al and uses\nthe sequential_solver, and compares it to the existing implementation in\nFloris.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\n\nimport floris.flow_visualization as flowviz\nfrom floris import FlorisModel, TimeSeries\nfrom floris.turbine_library import build_cosine_loss_turbine_dict\n\n\n# Note: \"new\" is used to refer to the new implementation of TurbOPark, which is\n# more faithful to the description provided by Pedersen et al. (2022). \"orig\"\n# is used to refer to the existing TurbOPark implementation in Floris (which\n# was based on Ørsted's Matlab code, originally from Nygaard et al. (2020).\n\n### Build a constant CT turbine model for use in comparisons (not realistic)\nconst_CT_turb = build_cosine_loss_turbine_dict(\n    turbine_data_dict={\n        \"wind_speed\":[0.0, 30.0],\n        \"power\":[0.0, 1.0], # Not realistic but won't be used here\n        \"thrust_coefficient\":[0.75, 0.75]\n    },\n    turbine_name=\"ConstantCT\",\n    rotor_diameter=120.0,\n    hub_height=100.0,\n    ref_tilt=0.0,\n)\n\n### Start by visualizing a single turbine in and its wake with the new model\n# Load the new TurboPark implementation and switch to constant CT turbine\nfmodel_new = FlorisModel(\"../inputs/turboparkgauss_cubature.yaml\")\nfmodel_new.set(\n    turbine_type=[const_CT_turb],\n    reference_wind_height=fmodel_new.reference_wind_height\n)\nfmodel_new.run()\nu0 = fmodel_new.wind_speeds[0]\n\ncol_orig = \"C0\"\ncol_new = \"C1\"\n\n# Get plane of points for visualization\nrotor_diameter = 120.0\nx_resolution=1501\ny_resolution=201\nz_resolution=100\nx_bounds = [-5*rotor_diameter, 25*rotor_diameter]\n\nhorizontal_plane = fmodel_new.calculate_horizontal_plane(\n    x_resolution=x_resolution,\n    y_resolution=y_resolution,\n    height=100.0,\n    x_bounds=x_bounds\n)\n\n# Visualize the flows with a horizontal slice\nfig, ax = plt.subplots(3,1)\nfig.set_size_inches(7, 10)\nflowviz.visualize_cut_plane(\n    horizontal_plane,\n    ax=ax[0],\n    label_contours=True,\n    title=\"Horizontal plane\"\n)\nax[0].set_xlabel(\"x [m]\")\nax[0].set_ylabel(\"y [m]\")\n\n# Get points and velocities, normalized by rotor diameter and freestream velocity\nx_locs_norm = horizontal_plane.df.x1[:x_resolution]/rotor_diameter\ny_locs_norm = horizontal_plane.df.x2[::x_resolution]/rotor_diameter\nu_norm = horizontal_plane.df.u[150100:151601]/u0\n\n# Plot downstream velocities\nax[1].plot(x_locs_norm, u_norm, color=col_new)\nax[1].set_xlabel(\"Downstream distance [D]\")\nax[1].set_ylabel(\"Normalized velocity [-]\")\nax[1].grid()\nax[1].set_xlim([x/rotor_diameter for x in x_bounds])\n\n# Plot axial velocities at various downstream distances\nfor loc in np.append(251, np.linspace(350,750,5)):  #range(200,1200,200):\n    u_norm = horizontal_plane.df.u[int(loc)::x_resolution]/u0\n    alpha = 1.0 - (loc-250)/1000\n    ax[2].plot(y_locs_norm, u_norm, label=str((loc-250)/50)+\"D downstream\", alpha=alpha, c=col_new)\nax[2].legend()\nax[2].set_xlabel(\"Radial distance [D]\")\nax[2].set_ylabel(\"Normalized velocity [-]\")\nax[2].grid()\nax[2].set_xlim([-2, 2])\n\n### Look at the wake profile at a single downstream distance for a range of wind directions\n# Load the original TurboPark implementation and switch to constant CT turbine\nfmodel_orig = FlorisModel(\"../inputs/turbopark_cubature.yaml\")\nfmodel_orig.set(\n    turbine_type=[const_CT_turb],\n    reference_wind_height=fmodel_orig.reference_wind_height\n)\n\n# Set up and solve flows\nwd_array = np.arange(225,315,0.1)\nwind_data_wd_sweep = TimeSeries(\n    wind_speeds=8.0,\n    wind_directions=wd_array,\n    turbulence_intensities=0.06\n)\nfmodel_orig.set(\n    layout_x = [0.0, 600.0],\n    layout_y = [0.0, 0.0],\n    wind_data=wind_data_wd_sweep\n)\nfmodel_orig.run()\n\n# Extract output velocities at downstream turbine\norig_vels_ds = fmodel_orig.turbine_average_velocities[:,1]\nu0 = fmodel_orig.wind_speeds[0] # Get freestream wind speed for normalization\n\n# Set up and solve flows; extract velocities at downstream turbine\nfmodel_new.set(\n    layout_x = [0.0, 600.0],\n    layout_y = [0.0, 0.0],\n    wind_data=wind_data_wd_sweep\n)\nfmodel_new.run()\nnew_vels_ds = fmodel_new.turbine_average_velocities[:,1]\n\n# Load comparison data (generated by running Ørsted's Matlab code\n# https://github.com/OrstedRD/TurbOPark)\ndf_twinpark = pd.read_csv(\"comparison_data/WindDirection_Sweep_Orsted.csv\")\n\n# Plot the data and compare\nfig, ax = plt.subplots(2, 1)\nfig.set_size_inches(7, 10)\nax[0].plot(wd_array, orig_vels_ds/u0, label=\"Floris - TurbOPark\", c=col_orig)\nax[0].plot(wd_array, new_vels_ds/u0, label=\"Floris - TurbOPark-Gauss\", c=col_new)\ndf_twinpark.plot(\"wd\", \"wws\", ax=ax[0], linestyle=\"--\", color=\"k\", label=\"Orsted - TurbOPark\")\n\nax[0].set_xlabel(\"Wind direction [deg]\")\nax[0].set_ylabel(\"Normalized rotor averaged waked wind speed [-]\")\nax[0].set_xlim(240,300)\nax[0].set_ylim(0.65,1.05)\nax[0].legend()\nax[0].grid()\n\n### Now, look at velocities along a row of ten turbines aligned with the flow\nlayout_x = np.linspace(0.0, 5400.0, 10)\nlayout_y = np.zeros_like(layout_x)\nturbines = range(len(layout_x))\nwind_data_row = TimeSeries(\n    wind_speeds=np.array([8.0]),\n    wind_directions=270.0,\n    turbulence_intensities=0.06\n)\nfmodel_orig.set(\n    layout_x=layout_x,\n    layout_y=layout_y,\n    wind_data=wind_data_row\n)\nfmodel_new.set(\n    layout_x=layout_x,\n    layout_y=layout_y,\n    wind_data=wind_data_row\n)\n\n# Run and extract flow velocities at the turbines\nfmodel_orig.run()\norig_vels_row = fmodel_orig.turbine_average_velocities\nfmodel_new.run()\nnew_vels_row = fmodel_new.turbine_average_velocities\nu0 = fmodel_orig.wind_speeds[0] # Get freestream wind speed for normalization\n\n# Load comparison data\ndf_rowpark = pd.read_csv(\"comparison_data/Rowpark_Orsted.csv\")\n\n# Plot the data and compare\nax[1].scatter(\n    turbines, df_rowpark[\"wws\"], s=80, marker=\"o\", c=\"k\", label=\"Orsted - TurbOPark\"\n)\nax[1].scatter(\n    turbines, orig_vels_row/u0, s=20, marker=\"o\", c=col_orig, label=\"Floris - TurbOPark\"\n)\nax[1].scatter(\n    turbines, new_vels_row/u0, s=20, marker=\"o\", c=col_new, label=\"Floris - TurbOPark_Gauss\"\n)\nax[1].set_xlabel(\"Turbine number\")\nax[1].set_ylabel(\"Normalized rotor averaged wind speed [-]\")\nax[1].set_ylim(0.25, 1.05)\nax[1].legend()\nax[1].grid()\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_turbopark/comparison_data/Rowpark_Orsted.csv",
    "content": "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\n7,0.430238792036599\r\n8,0.402137593655074\r\n9,0.377783142608699\r\n10,0.356429516711137\r\n"
  },
  {
    "path": "examples/examples_turbopark/comparison_data/WindDirection_Sweep_Orsted.csv",
    "content": "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\n241.3,1\r\n241.4,1\r\n241.5,1\r\n241.6,1\r\n241.7,1\r\n241.8,1\r\n241.9,1\r\n242,1\r\n242.1,1\r\n242.2,1\r\n242.3,1\r\n242.4,1\r\n242.5,1\r\n242.6,1\r\n242.7,1\r\n242.8,1\r\n242.9,1\r\n243,1\r\n243.1,1\r\n243.2,1\r\n243.3,1\r\n243.4,1\r\n243.5,1\r\n243.6,1\r\n243.7,1\r\n243.8,1\r\n243.9,1\r\n244,1\r\n244.1,1\r\n244.2,1\r\n244.3,1\r\n244.4,1\r\n244.5,1\r\n244.6,1\r\n244.7,1\r\n244.8,1\r\n244.9,1\r\n245,1\r\n245.1,1\r\n245.2,1\r\n245.3,1\r\n245.4,1\r\n245.5,1\r\n245.6,1\r\n245.7,1\r\n245.8,1\r\n245.9,1\r\n246,1\r\n246.1,1\r\n246.2,1\r\n246.3,1\r\n246.4,1\r\n246.5,1\r\n246.6,1\r\n246.7,1\r\n246.8,1\r\n246.9,1\r\n247,1\r\n247.1,1\r\n247.2,1\r\n247.3,1\r\n247.4,1\r\n247.5,1\r\n247.6,1\r\n247.7,1\r\n247.8,1\r\n247.9,1\r\n248,1\r\n248.1,1\r\n248.2,1\r\n248.3,1\r\n248.4,1\r\n248.5,1\r\n248.6,1\r\n248.7,1\r\n248.8,1\r\n248.9,1\r\n249,1\r\n249.1,1\r\n249.2,1\r\n249.3,1\r\n249.4,1\r\n249.5,1\r\n249.6,1\r\n249.7,1\r\n249.8,1\r\n249.9,1\r\n250,1\r\n250.1,1\r\n250.2,1\r\n250.3,1\r\n250.4,1\r\n250.5,1\r\n250.6,1\r\n250.7,1\r\n250.8,1\r\n250.9,1\r\n251,1\r\n251.1,1\r\n251.2,1\r\n251.3,1\r\n251.4,1\r\n251.5,1\r\n251.6,1\r\n251.7,1\r\n251.8,1\r\n251.9,1\r\n252,1\r\n252.1,1\r\n252.2,1\r\n252.3,1\r\n252.4,1\r\n252.5,1\r\n252.6,1\r\n252.7,1\r\n252.8,1\r\n252.9,1\r\n253,1\r\n253.1,1\r\n253.2,1\r\n253.3,1\r\n253.4,1\r\n253.5,1\r\n253.6,1\r\n253.7,1\r\n253.8,1\r\n253.9,1\r\n254,1\r\n254.1,1\r\n254.2,1\r\n254.3,1\r\n254.4,1\r\n254.5,1\r\n254.6,1\r\n254.7,1\r\n254.8,1\r\n254.9,1\r\n255,1\r\n255.1,1\r\n255.2,1\r\n255.3,1\r\n255.4,1\r\n255.5,1\r\n255.6,1\r\n255.7,1\r\n255.8,0.993538664077203\r\n255.9,0.993163657321804\r\n256,0.992770495327025\r\n256.1,0.992358313847786\r\n256.2,0.991925610053336\r\n256.3,0.991472642429319\r\n256.4,0.990998649684299\r\n256.5,0.990501674053008\r\n256.6,0.98998221270739\r\n256.7,0.989439530053926\r\n256.8,0.988871463143701\r\n256.9,0.98827850586591\r\n257,0.987659983170125\r\n257.1,0.987013702153042\r\n257.2,0.986339994876325\r\n257.3,0.985638312213906\r\n257.4,0.984906427366052\r\n257.5,0.984144540999792\r\n257.6,0.983352231745704\r\n257.7,0.982527231179693\r\n257.8,0.981669653228834\r\n257.9,0.980779200463236\r\n258,0.979853551280177\r\n258.1,0.978892787644138\r\n258.2,0.977896729926102\r\n258.3,0.976862989104334\r\n258.4,0.975791697415342\r\n258.5,0.97468276936836\r\n258.6,0.973533728520613\r\n258.7,0.972344839286829\r\n258.8,0.971116091762022\r\n258.9,0.96984490254454\r\n259,0.968531765562319\r\n259.1,0.96717671860786\r\n259.2,0.965777049935718\r\n259.3,0.96433358834902\r\n259.4,0.962846386758057\r\n259.5,0.961312584298864\r\n259.6,0.959733454176337\r\n259.7,0.958109028463984\r\n259.8,0.956436278914363\r\n259.9,0.954717032094708\r\n260,0.952951261644229\r\n260.1,0.951135758385933\r\n260.2,0.949273005115791\r\n260.3,0.9473627123794\r\n260.4,0.945401986275212\r\n260.5,0.943393553818119\r\n260.6,0.941336847389892\r\n260.7,0.939229736935285\r\n260.8,0.937074820137102\r\n260.9,0.934871338387179\r\n261,0.932618039295836\r\n261.1,0.930317338994172\r\n261.2,0.927968281561089\r\n261.3,0.925570580132477\r\n261.4,0.923126425330613\r\n261.5,0.92063467246435\r\n261.6,0.918096054594981\r\n261.7,0.915512504495281\r\n261.8,0.912882714836796\r\n261.9,0.910208452415198\r\n262,0.90749137471691\r\n262.1,0.904730057903725\r\n262.2,0.901927269278807\r\n262.3,0.899084382259158\r\n262.4,0.896199952561399\r\n262.5,0.893277634297122\r\n262.6,0.890318154571413\r\n262.7,0.887321318579717\r\n262.8,0.884290346375519\r\n262.9,0.881225831351371\r\n263,0.878128716993821\r\n263.1,0.875001814308954\r\n263.2,0.871845680663186\r\n263.3,0.86866222402995\r\n263.4,0.865453897868534\r\n263.5,0.862221346668234\r\n263.6,0.858967205627504\r\n263.7,0.855693649591388\r\n263.8,0.852401558002709\r\n263.9,0.84909399374919\r\n264,0.845772832335429\r\n264.1,0.842439740485255\r\n264.2,0.839097468583526\r\n264.3,0.835747987758945\r\n264.4,0.832393539537496\r\n264.5,0.829036552890671\r\n264.6,0.825679322258521\r\n264.7,0.822324260240938\r\n264.8,0.818973626984464\r\n264.9,0.815630241610804\r\n265,0.812296234810439\r\n265.1,0.808973964717588\r\n265.2,0.805666720853472\r\n265.3,0.802376128951174\r\n265.4,0.799105063046563\r\n265.5,0.795856576665548\r\n265.6,0.792632199808558\r\n265.7,0.789435477805356\r\n265.8,0.786268700366033\r\n265.9,0.783133519200963\r\n266,0.780034380951238\r\n266.1,0.776972265521718\r\n266.2,0.773949449942233\r\n266.3,0.770970689004856\r\n266.4,0.76803592392432\r\n266.5,0.7651486501479\r\n266.6,0.762312258910748\r\n266.7,0.759527003855557\r\n266.8,0.756797459385703\r\n266.9,0.754125094991387\r\n267,0.751510723346101\r\n267.1,0.748960214180543\r\n267.2,0.746472579043332\r\n267.3,0.744050181507681\r\n267.4,0.741698131597992\r\n267.5,0.739414734981526\r\n267.6,0.737204041555762\r\n267.7,0.735068602520699\r\n267.8,0.733007537734214\r\n267.9,0.731026342177643\r\n268,0.729124534970449\r\n268.1,0.727302277422094\r\n268.2,0.725566656688728\r\n268.3,0.723913754893217\r\n268.4,0.722346595328026\r\n268.5,0.720869110121062\r\n268.6,0.719478470489897\r\n268.7,0.718179259631063\r\n268.8,0.716971888690611\r\n268.9,0.715854804612834\r\n269,0.714834246915094\r\n269.1,0.713906819981133\r\n269.2,0.713073268024026\r\n269.3,0.712338934517223\r\n269.4,0.711699026367391\r\n269.5,0.71115682475977\r\n269.6,0.710713804599393\r\n269.7,0.710366653964001\r\n269.8,0.710120302126759\r\n269.9,0.709972224114491\r\n270,0.709920677983239\r\n270.1,0.709972224114491\r\n270.2,0.710120302126759\r\n270.3,0.710366653964001\r\n270.4,0.710713804599393\r\n270.5,0.71115682475977\r\n270.6,0.711699026367391\r\n270.7,0.712338934517223\r\n270.8,0.713073268024026\r\n270.9,0.713906819981133\r\n271,0.714834246915094\r\n271.1,0.715854804612834\r\n271.2,0.716971888690611\r\n271.3,0.718179259631063\r\n271.4,0.719478470489897\r\n271.5,0.720869110121062\r\n271.6,0.722346595328026\r\n271.7,0.723913754893217\r\n271.8,0.725566656688728\r\n271.9,0.727302277422094\r\n272,0.729124534970449\r\n272.1,0.731026342177643\r\n272.2,0.733007537734214\r\n272.3,0.735068602520699\r\n272.4,0.737204041555762\r\n272.5,0.739414734981526\r\n272.6,0.741698131597992\r\n272.7,0.744050181507681\r\n272.8,0.746472579043332\r\n272.9,0.748960214180543\r\n273,0.751510723346101\r\n273.1,0.754125094991387\r\n273.2,0.756797459385703\r\n273.3,0.759527003855557\r\n273.4,0.762312258910748\r\n273.5,0.7651486501479\r\n273.6,0.76803592392432\r\n273.7,0.770970689004856\r\n273.8,0.773949449942233\r\n273.9,0.776972265521718\r\n274,0.780034380951238\r\n274.1,0.783133519200963\r\n274.2,0.786268700366033\r\n274.3,0.789435477805356\r\n274.4,0.792632199808558\r\n274.5,0.795856576665548\r\n274.6,0.799105063046563\r\n274.7,0.802376128951174\r\n274.8,0.805666720853472\r\n274.9,0.808973964717588\r\n275,0.812296234810439\r\n275.1,0.815630241610804\r\n275.2,0.818973626984464\r\n275.3,0.822324260240938\r\n275.4,0.825679322258521\r\n275.5,0.829036552890671\r\n275.6,0.832393539537496\r\n275.7,0.835747987758945\r\n275.8,0.839097468583526\r\n275.9,0.842439740485255\r\n276,0.845772832335429\r\n276.1,0.84909399374919\r\n276.2,0.852401558002709\r\n276.3,0.855693649591388\r\n276.4,0.858967205627504\r\n276.5,0.862221346668234\r\n276.6,0.865453897868534\r\n276.7,0.86866222402995\r\n276.8,0.871845680663186\r\n276.9,0.875001814308954\r\n277,0.878128716993821\r\n277.1,0.881225831351371\r\n277.2,0.884290346375519\r\n277.3,0.887321318579717\r\n277.4,0.890318154571413\r\n277.5,0.893277634297122\r\n277.6,0.896199952561399\r\n277.7,0.899084382259158\r\n277.8,0.901927269278807\r\n277.9,0.904730057903725\r\n278,0.90749137471691\r\n278.1,0.910208452415198\r\n278.2,0.912882714836796\r\n278.3,0.915512504495281\r\n278.4,0.918096054594981\r\n278.5,0.92063467246435\r\n278.6,0.923126425330613\r\n278.7,0.925570580132477\r\n278.8,0.927968281561089\r\n278.9,0.930317338994172\r\n279,0.932618039295836\r\n279.1,0.934871338387179\r\n279.2,0.937074820137102\r\n279.3,0.939229736935285\r\n279.4,0.941336847389892\r\n279.5,0.943393553818119\r\n279.6,0.945401986275212\r\n279.7,0.9473627123794\r\n279.8,0.949273005115791\r\n279.9,0.951135758385933\r\n280,0.952951261644229\r\n280.1,0.954717032094708\r\n280.2,0.956436278914363\r\n280.3,0.958109028463984\r\n280.4,0.959733454176337\r\n280.5,0.961312584298864\r\n280.6,0.962846386758057\r\n280.7,0.96433358834902\r\n280.8,0.965777049935718\r\n280.9,0.96717671860786\r\n281,0.968531765562319\r\n281.1,0.96984490254454\r\n281.2,0.971116091762022\r\n281.3,0.972344839286829\r\n281.4,0.973533728520613\r\n281.5,0.97468276936836\r\n281.6,0.975791697415342\r\n281.7,0.976862989104334\r\n281.8,0.977896729926102\r\n281.9,0.978892787644138\r\n282,0.979853551280177\r\n282.1,0.980779200463236\r\n282.2,0.981669653228834\r\n282.3,0.982527231179693\r\n282.4,0.983352231745704\r\n282.5,0.984144540999792\r\n282.6,0.984906427366052\r\n282.7,0.985638312213906\r\n282.8,0.986339994876325\r\n282.9,0.987013702153042\r\n283,0.987659983170125\r\n283.1,0.98827850586591\r\n283.2,0.988871463143701\r\n283.3,0.989439530053926\r\n283.4,0.98998221270739\r\n283.5,0.990501674053008\r\n283.6,0.990998649684299\r\n283.7,0.991472642429319\r\n283.8,0.991925610053336\r\n283.9,0.992358313847786\r\n284,0.992770495327025\r\n284.1,0.993163657321804\r\n284.2,0.993538664077203\r\n284.3,1\r\n284.4,1\r\n284.5,1\r\n284.6,1\r\n284.7,1\r\n284.8,1\r\n284.9,1\r\n285,1\r\n285.1,1\r\n285.2,1\r\n285.3,1\r\n285.4,1\r\n285.5,1\r\n285.6,1\r\n285.7,1\r\n285.8,1\r\n285.9,1\r\n286,1\r\n286.1,1\r\n286.2,1\r\n286.3,1\r\n286.4,1\r\n286.5,1\r\n286.6,1\r\n286.7,1\r\n286.8,1\r\n286.9,1\r\n287,1\r\n287.1,1\r\n287.2,1\r\n287.3,1\r\n287.4,1\r\n287.5,1\r\n287.6,1\r\n287.7,1\r\n287.8,1\r\n287.9,1\r\n288,1\r\n288.1,1\r\n288.2,1\r\n288.3,1\r\n288.4,1\r\n288.5,1\r\n288.6,1\r\n288.7,1\r\n288.8,1\r\n288.9,1\r\n289,1\r\n289.1,1\r\n289.2,1\r\n289.3,1\r\n289.4,1\r\n289.5,1\r\n289.6,1\r\n289.7,1\r\n289.8,1\r\n289.9,1\r\n290,1\r\n290.1,1\r\n290.2,1\r\n290.3,1\r\n290.4,1\r\n290.5,1\r\n290.6,1\r\n290.7,1\r\n290.8,1\r\n290.9,1\r\n291,1\r\n291.1,1\r\n291.2,1\r\n291.3,1\r\n291.4,1\r\n291.5,1\r\n291.6,1\r\n291.7,1\r\n291.8,1\r\n291.9,1\r\n292,1\r\n292.1,1\r\n292.2,1\r\n292.3,1\r\n292.4,1\r\n292.5,1\r\n292.6,1\r\n292.7,1\r\n292.8,1\r\n292.9,1\r\n293,1\r\n293.1,1\r\n293.2,1\r\n293.3,1\r\n293.4,1\r\n293.5,1\r\n293.6,1\r\n293.7,1\r\n293.8,1\r\n293.9,1\r\n294,1\r\n294.1,1\r\n294.2,1\r\n294.3,1\r\n294.4,1\r\n294.5,1\r\n294.6,1\r\n294.7,1\r\n294.8,1\r\n294.9,1\r\n295,1\r\n295.1,1\r\n295.2,1\r\n295.3,1\r\n295.4,1\r\n295.5,1\r\n295.6,1\r\n295.7,1\r\n295.8,1\r\n295.9,1\r\n296,1\r\n296.1,1\r\n296.2,1\r\n296.3,1\r\n296.4,1\r\n296.5,1\r\n296.6,1\r\n296.7,1\r\n296.8,1\r\n296.9,1\r\n297,1\r\n297.1,1\r\n297.2,1\r\n297.3,1\r\n297.4,1\r\n297.5,1\r\n297.6,1\r\n297.7,1\r\n297.8,1\r\n297.9,1\r\n298,1\r\n298.1,1\r\n298.2,1\r\n298.3,1\r\n298.4,1\r\n298.5,1\r\n298.6,1\r\n298.7,1\r\n298.8,1\r\n298.9,1\r\n299,1\r\n299.1,1\r\n299.2,1\r\n299.3,1\r\n299.4,1\r\n299.5,1\r\n299.6,1\r\n299.7,1\r\n299.8,1\r\n299.9,1\r\n300,1\r\n300.1,1\r\n300.2,1\r\n300.3,1\r\n300.4,1\r\n300.5,1\r\n300.6,1\r\n300.7,1\r\n300.8,1\r\n300.9,1\r\n301,1\r\n301.1,1\r\n301.2,1\r\n301.3,1\r\n301.4,1\r\n301.5,1\r\n301.6,1\r\n301.7,1\r\n301.8,1\r\n301.9,1\r\n302,1\r\n302.1,1\r\n302.2,1\r\n302.3,1\r\n302.4,1\r\n302.5,1\r\n302.6,1\r\n302.7,1\r\n302.8,1\r\n302.9,1\r\n303,1\r\n303.1,1\r\n303.2,1\r\n303.3,1\r\n303.4,1\r\n303.5,1\r\n303.6,1\r\n303.7,1\r\n303.8,1\r\n303.9,1\r\n304,1\r\n304.1,1\r\n304.2,1\r\n304.3,1\r\n304.4,1\r\n304.5,1\r\n304.6,1\r\n304.7,1\r\n304.8,1\r\n304.9,1\r\n305,1\r\n305.1,1\r\n305.2,1\r\n305.3,1\r\n305.4,1\r\n305.5,1\r\n305.6,1\r\n305.7,1\r\n305.8,1\r\n305.9,1\r\n306,1\r\n306.1,1\r\n306.2,1\r\n306.3,1\r\n306.4,1\r\n306.5,1\r\n306.6,1\r\n306.7,1\r\n306.8,1\r\n306.9,1\r\n307,1\r\n307.1,1\r\n307.2,1\r\n307.3,1\r\n307.4,1\r\n307.5,1\r\n307.6,1\r\n307.7,1\r\n307.8,1\r\n307.9,1\r\n308,1\r\n308.1,1\r\n308.2,1\r\n308.3,1\r\n308.4,1\r\n308.5,1\r\n308.6,1\r\n308.7,1\r\n308.8,1\r\n308.9,1\r\n309,1\r\n309.1,1\r\n309.2,1\r\n309.3,1\r\n309.4,1\r\n309.5,1\r\n309.6,1\r\n309.7,1\r\n309.8,1\r\n309.9,1\r\n310,1\r\n"
  },
  {
    "path": "examples/examples_uncertain/001_uncertain_model_params.py",
    "content": "\"\"\"Example: Uncertain Model Parameters\n\nThis example demonstrates how to use the UncertainFlorisModel class to\nanalyze the impact of uncertain wind direction on power results.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    UncertainFlorisModel,\n)\n\n\n# Instantiate FlorisModel for comparison\nfmodel = FlorisModel(\"../inputs/gch.yaml\")  # GCH model\n\n################################################\n# Resolution parameters\n################################################\n\n# The resolution parameters are used to define the precision of the wind direction,\n# wind speed, and turbulence intensity and control parameters.  All the inputs\n# passed into the UncertainFlorisModel class are rounded to this resolution.  Then\n# following expansion, non-unique cases are removed.  Here we apply the default\n# resolution parameters.\nwd_resolution = 1.0  # Degree\nws_resolution = 1.0  # m/s\nti_resolution = 0.01  # Decimal fraction\nyaw_resolution = 1.0  # Degree\npower_setpoint_resolution = 100.0  # kW\n\n################################################\n# wd_sample_points\n################################################\n\n# The wind direction sample points (wd_sample_points) parameter is used to define\n# the number of points to sample the wind direction uncertainty.  For example,\n# if the the single condition to analyze is 270 degrees, and the wd_sample_points\n# is [-2, -1, 0, 1 ,2], then the cases to be run and weighted\n#  will be 268, 269, 270, 271, 272.  If not supplied default is\n# [-2 * wd_std, -1 * wd_std, 0, wd_std, 2 * wd_std]\nwd_sample_points = [-6, -3, 0, 3, 6]\n\n\n################################################\n# WT_STD\n################################################\n\n# The wind direction standard deviation (wd_std) parameter is the primary input\n# to the UncertainFlorisModel class.  This parameter is used to weight the points\n# following expansion by the wd_sample_points.  The smaller the value, the closer\n# the weighting will be to the nominal case.\nwd_std = 3 # Default is 3 degrees\n\n################################################\n# Verbosity\n################################################\n\n# Setting verbose = True will print out the sizes of teh cases run\nverbose = True\n\n################################################\n# Define the UncertainFlorisModel\n################################################\nprint('*** Instantiating UncertainFlorisModel ***')\nufmodel = UncertainFlorisModel(\n    \"../inputs/gch.yaml\",\n    wd_resolution=wd_resolution,\n    ws_resolution=ws_resolution,\n    ti_resolution=ti_resolution,\n    yaw_resolution=yaw_resolution,\n    power_setpoint_resolution=power_setpoint_resolution,\n    wd_std=wd_std,\n    wd_sample_points=wd_sample_points,\n    verbose=verbose,\n)\n\n\n################################################\n# Run the models\n################################################\n\n# Define an inflow where wind direction is swept while\n# wind speed and turbulence intensity are held constant\nwind_directions = np.arange(240.0, 300.0, 1.0)\ntime_series = TimeSeries(\n    wind_directions=wind_directions,\n    wind_speeds=8.0,\n    turbulence_intensities=0.06,\n)\n\n# Define a two turbine farm and apply the inflow\nD = 126.0\nlayout_x = np.array([0, D * 6])\nlayout_y = [0, 0]\n\nfmodel.set(\n    layout_x=layout_x,\n    layout_y=layout_y,\n    wind_data=time_series,\n)\nprint('*** Setting UncertainFlorisModel to 60 Wind Direction Inflow ***')\nufmodel.set(\n    layout_x=layout_x,\n    layout_y=layout_y,\n    wind_data=time_series,\n)\n\n# Run both models\nfmodel.run()\nufmodel.run()\n\n\n# Collect the nominal and uncertain farm power\nturbine_powers_nom = fmodel.get_turbine_powers() / 1e3\nturbine_powers_unc = ufmodel.get_turbine_powers() / 1e3\n\nfarm_powers_nom = fmodel.get_farm_power() / 1e3\nfarm_powers_unc_3 = ufmodel.get_farm_power() / 1e3\n\n\n# Plot results\nfig, axarr = plt.subplots(1, 3, figsize=(15, 5))\nax = axarr[0]\nax.plot(wind_directions, turbine_powers_nom[:, 0].flatten(), color=\"k\", label=\"Nominal power\")\nax.plot(\n    wind_directions,\n    turbine_powers_unc[:, 0].flatten(),\n    color=\"r\",\n    label=\"Power with uncertainty\",\n)\nax.set_ylim(bottom=0)\n\nax.grid(True)\nax.legend()\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Power (kW)\")\nax.set_title(\"Upstream Turbine\")\n\nax = axarr[1]\nax.plot(wind_directions, turbine_powers_nom[:, 1].flatten(), color=\"k\", label=\"Nominal power\")\nax.plot(\n    wind_directions,\n    turbine_powers_unc[:, 1].flatten(),\n    color=\"r\",\n    label=\"Power with uncertainty\",\n)\nax.set_ylim(bottom=0)\n\nax.set_title(\"Downstream Turbine\")\nax.grid(True)\nax.legend()\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Power (kW)\")\n\nax = axarr[2]\nax.plot(wind_directions, farm_powers_nom.flatten(), color=\"k\", label=\"Nominal farm power\")\nax.plot(\n    wind_directions,\n    farm_powers_unc_3.flatten(),\n    color=\"r\",\n    label=\"Farm power with uncertainty\",\n)\nax.set_ylim(bottom=0)\n\nax.set_title(\"Farm Power\")\nax.grid(True)\nax.legend()\nax.set_xlabel(\"Wind Direction (deg)\")\nax.set_ylabel(\"Power (kW)\")\n\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_uncertain/002_approx_floris_model.py",
    "content": "\"\"\"Example: Approximate Model Parameters\n\nThis example demonstrates how to use the UncertainFlorisModel class to\nanalyze the impact of uncertain wind direction on power results.\n\"\"\"\n\nfrom time import perf_counter as timerpc\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    ApproxFlorisModel,\n    FlorisModel,\n    TimeSeries,\n)\n\n\n# Generate time series data using a random walk on wind speeds with constant wind direction\nN = 5000\nn_turbines = 25\n\n# Random walk on wind speed with values between 5 and 20 m/s\nws = np.ones(N) * 10\nrng = np.random.default_rng(0)\nws_ll = 5\nws_ul = 20\nfor i in range(1, N):\n    ws[i] = ws[i - 1] + rng.normal(0, 0.25)\n    if ws[i] < ws_ll:\n        ws[i] = ws_ll\n    if ws[i] > ws_ul:\n        ws[i] = ws_ul\n\ntime_series = TimeSeries(wind_directions=270.0, wind_speeds=ws, turbulence_intensities=0.06)\n\n# Instantiate a FlorisModel and an ApproxFlorisModel\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\nafmodel = ApproxFlorisModel(\"../inputs/gch.yaml\", ws_resolution=0.5)\n\n\n# Set both models to an n_turbine layout and use the above time series\nlayout_x = np.array([i*500 for i in range(n_turbines)])\nlayout_y = np.zeros(n_turbines)\nfmodel.set(layout_x=layout_x, layout_y=layout_y, wind_data=time_series)\nafmodel.set(layout_x=layout_x, layout_y=layout_y, wind_data=time_series)\n\n# Now time both runs to show the speedup from approximating the wind speed\nstart = timerpc()\nfmodel.run()\nend = timerpc()\nprint(f\"FlorisModel run time: {end - start} s\")\n\nstart = timerpc()\nafmodel.run()\nend = timerpc()\nprint(f\"ApproxFlorisModel run time: {end - start} s\")\n\n# Plot the power output from both models\nfig, ax = plt.subplots()\nax.plot(fmodel.get_farm_power(), label=\"FlorisModel\")\nax.plot(afmodel.get_farm_power(), label=\"ApproxFlorisModel\")\nax.set_xlabel(\"Time Step\")\nax.set_ylabel(\"Farm Power [W]\")\nax.legend()\nax.grid(True)\n\n\n# Compare the expected power results\nprint(f\"Expected power from FlorisModel: {fmodel.get_expected_farm_power()/1E6:0.2f} MW\")\nprint(f\"Expected power from ApproxFlorisModel: {afmodel.get_expected_farm_power()/1E6:0.2f} MW\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_uncertain/003_uncertain_model_with_parallelization.py",
    "content": "\"\"\"Example: Uncertain Model With Parallelization\n\nThis example demonstrates how to combined the parallelized model with the uncertain model\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    UncertainFlorisModel,\n)\nfrom floris.par_floris_model import ParFlorisModel\n\n\nif __name__ == \"__main__\":\n    # Following the refactoring of ParFlorisModel, the UncertainFlorisModel can be\n    # parallelized by passing the ParFlorisModel as the model to be run.  This example\n    # demonstrates the usage and shows that the result obtained from the UncertainFlorisModel\n    # with and without parallelization is the same.  The results are compared to the nominal\n    # results.\n\n    # Instantiate a FlorisModel and ParallelFlorisModel using the GCH model\n    fmodel = FlorisModel(\"../inputs/gch.yaml\")\n    pfmodel = ParFlorisModel(\"../inputs/gch.yaml\")\n\n    # Use the above model to declare a serial and parallel UncertainFlorisModel\n    ufmodel = UncertainFlorisModel(fmodel)\n    pufmodel = UncertainFlorisModel(pfmodel)\n\n\n    # Define an inflow where wind direction is swept while\n    # wind speed and turbulence intensity are held constant\n    wind_directions = np.arange(240.0, 300.0, 1.0)\n    time_series = TimeSeries(\n        wind_directions=wind_directions,\n        wind_speeds=8.0,\n        turbulence_intensities=0.06,\n    )\n\n    # Define a two turbine farm and apply the inflow\n    D = 126.0\n    layout_x = np.array([0, D * 6])\n    layout_y = [0, 0]\n\n    # Apply to fmodel, ufmodel, and pufmodel\n    fmodel.set(\n        layout_x=layout_x,\n        layout_y=layout_y,\n        wind_data=time_series,\n    )\n\n    ufmodel.set(\n        layout_x=layout_x,\n        layout_y=layout_y,\n        wind_data=time_series,\n    )\n\n    pufmodel.set(\n        layout_x=layout_x,\n        layout_y=layout_y,\n        wind_data=time_series,\n    )\n\n    # Run the models\n    fmodel.run()\n    ufmodel.run()\n    pufmodel.run()\n\n    # Collect the farm power results from each model\n    farm_powers_nom = fmodel.get_farm_power() / 1e3\n    farm_powers_unc = ufmodel.get_farm_power() / 1e3\n    farm_powers_punc = pufmodel.get_farm_power() / 1e3\n\n    # Compare the results\n    fig, ax = plt.subplots()\n    ax.plot(wind_directions, farm_powers_nom.flatten(), 'k-', label=\"Nominal power\")\n    ax.plot(wind_directions, farm_powers_unc.flatten(), 'bs-', label=\"Uncertain power\")\n    ax.plot(wind_directions, farm_powers_punc.flatten(), 'r.--', label=\"Parallel uncertain power\")\n    ax.grid(True)\n    ax.legend()\n    ax.set_xlabel(\"Wind Direction (deg)\")\n    ax.set_ylabel(\"Power (kW)\")\n\n    plt.show()\n"
  },
  {
    "path": "examples/examples_visualizations/001_layout_visualizations.py",
    "content": "\"\"\"Example: Layout Visualizations\n\nDemonstrate the use of all the functions within the layout_visualization module\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nimport floris.layout_visualization as layoutviz\nfrom floris import FlorisModel\nfrom floris.flow_visualization import visualize_cut_plane\n\n\n# Create the plotting objects using matplotlib\nfig, axarr = plt.subplots(3, 3, figsize=(16, 10), sharex=False)\naxarr = axarr.flatten()\n\nMIN_WS = 1.0\nMAX_WS = 8.0\n\n# Initialize FLORIS with the given input file.\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Change to 5-turbine layout with a wind direction from northwest\nfmodel.set(\n    layout_x=[0, 0, 1000, 1000, 1000], layout_y=[0, 500, 0, 500, 1000], wind_directions=[300]\n)\n\n# Plot 1: Visualize the flow\nax = axarr[0]\n# Plot a horizatonal slice of the initial configuration\nhorizontal_plane = fmodel.calculate_horizontal_plane(height=90.0)\nvisualize_cut_plane(\n    horizontal_plane,\n    ax=ax,\n    min_speed=MIN_WS,\n    max_speed=MAX_WS,\n)\n# Plot the turbine points, setting the color to white\nlayoutviz.plot_turbine_points(fmodel, ax=ax, plotting_dict={\"color\": \"w\"})\nax.set_title(\"Flow visualization and turbine points\")\n\n# Plot 2: Show a particular flow case\nax = axarr[1]\nturbine_names = [f\"T{i}\" for i in [10, 11, 12, 13, 22]]\nlayoutviz.plot_turbine_points(fmodel, ax=ax)\nlayoutviz.plot_turbine_labels(\n    fmodel, ax=ax, turbine_names=turbine_names, show_bbox=True, bbox_dict={\"facecolor\": \"r\"}\n)\nax.set_title(\"Show turbine names with a red bounding box\")\n\n\n# Plot 2: Show turbine rotors on flow\nax = axarr[2]\nfmodel.set(yaw_angles=np.array([[0., 30., 0., 0., 0.]]))\nhorizontal_plane = fmodel.calculate_horizontal_plane(height=90.0)\nvisualize_cut_plane(horizontal_plane, ax=ax, min_speed=MIN_WS, max_speed=MAX_WS)\nlayoutviz.plot_turbine_rotors(fmodel, ax=ax, yaw_angles=np.array([[0.0, 30.0, 0.0, 0.0, 0.0]]))\nax.set_title(\"Flow visualization with yawed turbine\")\n\n# Plot 3: Show the layout, including wake directions\nax = axarr[3]\nlayoutviz.plot_turbine_points(fmodel, ax=ax)\nlayoutviz.plot_turbine_labels(fmodel, ax=ax, turbine_names=turbine_names)\nlayoutviz.plot_waking_directions(fmodel, ax=ax)\nax.set_title(\"Show turbine names and wake direction\")\n\n# Plot 4: Plot a subset of the layout, and limit directions less than 7D\nax = axarr[4]\nlayoutviz.plot_turbine_points(fmodel, ax=ax, turbine_indices=[0, 1, 2, 3])\nlayoutviz.plot_turbine_labels(\n    fmodel, ax=ax, turbine_names=turbine_names, turbine_indices=[0, 1, 2, 3]\n)\nlayoutviz.plot_waking_directions(fmodel, ax=ax, turbine_indices=[0, 1, 2, 3], limit_dist_D=7)\nax.set_title(\"Plot a subset and limit wake line distance\")\n\n# Plot with a shaded region\nax = axarr[5]\nlayoutviz.plot_turbine_points(fmodel, ax=ax)\nlayoutviz.shade_region(np.array([[0, 0], [300, 0], [300, 1000], [0, 700]]), ax=ax)\nax.set_title(\"Plot with a shaded region\")\n\n# Change hub heights and plot as a proxy for terrain\nax = axarr[6]\nfmodel.core.farm.hub_heights = np.array([110, 90, 100, 100, 95])\nlayoutviz.plot_farm_terrain(fmodel, ax=ax)\n\nplt.tight_layout()\nplt.show()\n"
  },
  {
    "path": "examples/examples_visualizations/002_visualize_y_cut_plane.py",
    "content": "\"\"\"Example: Visualize y cut plane\n\nDemonstrate visualizing a plane cut vertically through the flow field along the wind direction.\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\n\nfrom floris import FlorisModel\nfrom floris.flow_visualization import visualize_cut_plane\n\n\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Set a 3 turbine layout with wind direction along the row\nfmodel.set(\n    layout_x=[0, 500, 1000],\n    layout_y=[0, 0, 0],\n    wind_directions=[270],\n    wind_speeds=[8],\n    turbulence_intensities=[0.06],\n)\n\n# Collect the yplane\ny_plane = fmodel.calculate_y_plane(x_resolution=200, z_resolution=100, crossstream_dist=0.0)\n\n# Plot the flow field\nfig, ax = plt.subplots(figsize=(10, 4))\nvisualize_cut_plane(\n    y_plane, ax=ax, min_speed=3, max_speed=9, label_contours=True, title=\"Y Cut Plane\"\n)\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_visualizations/003_visualize_cross_plane.py",
    "content": "\"\"\"Example: Visualize cross plane\n\nDemonstrate visualizing a plane cut vertically through the flow field across the wind direction.\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\n\nfrom floris import FlorisModel\nfrom floris.flow_visualization import visualize_cut_plane\n\n\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Set a 1 turbine layout\nfmodel.set(\n    layout_x=[0],\n    layout_y=[0],\n    wind_directions=[270],\n    wind_speeds=[8],\n    turbulence_intensities=[0.06],\n)\n\n# Collect the cross plane downstream of the turbine\ncross_plane = fmodel.calculate_cross_plane(\n    y_resolution=100,\n    z_resolution=100,\n    downstream_dist=500.0,\n)\n\n# Plot the flow field\nfig, ax = plt.subplots(figsize=(4, 6))\nvisualize_cut_plane(\n    cross_plane, ax=ax, min_speed=3, max_speed=9, label_contours=True, title=\"Cross Plane\"\n)\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_visualizations/004_visualize_rotor_values.py",
    "content": "\"\"\"Example: Visualize rotor velocities\n\nDemonstrate visualizing the flow velocities at the rotor using plot_rotor_values\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\n\nimport floris.flow_visualization as flowviz\nfrom floris import FlorisModel\n\n\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# Set a 2 turbine layout\nfmodel.set(\n    layout_x=[0, 500],\n    layout_y=[0, 0],\n    wind_directions=[270],\n    wind_speeds=[8],\n    turbulence_intensities=[0.06],\n)\n\n# Run the model\nfmodel.run()\n\n# Plot the values at each rotor\nfig, axes, _, _ = flowviz.plot_rotor_values(\n    fmodel.core.flow_field.u, findex=0, n_rows=1, n_cols=2, return_fig_objects=True\n)\nfig.suptitle(\"Rotor Plane Visualization, Original Resolution\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_visualizations/005_visualize_flow_by_sweeping_turbines.py",
    "content": "\"\"\"Example: Visualize flow by sweeping turbines\n\nDemonstrate the use calculate_horizontal_plane_with_turbines\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\n\nimport floris.flow_visualization as flowviz\nfrom floris import FlorisModel\n\n\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n# # Some wake models may not yet have a visualization method included, for these cases can use\n# # a slower version which scans a turbine model to produce the horizontal flow\n\n\n# Set a 2 turbine layout\nfmodel.set(\n    layout_x=[0, 500],\n    layout_y=[0, 0],\n    wind_directions=[270],\n    wind_speeds=[8],\n    turbulence_intensities=[0.06],\n)\n\nhorizontal_plane_scan_turbine = flowviz.calculate_horizontal_plane_with_turbines(\n    fmodel,\n    x_resolution=20,\n    y_resolution=10,\n)\n\nfig, ax = plt.subplots(figsize=(10, 4))\nflowviz.visualize_cut_plane(\n    horizontal_plane_scan_turbine,\n    ax=ax,\n    label_contours=True,\n    title=\"Horizontal (coarse turbine scan method)\",\n)\n\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_wind_data/001_wind_data_comparisons.py",
    "content": "\"\"\"Example: Wind Data Comparisons\n\nIn this example, a random time series of wind speeds, wind directions, turbulence\nintensities, and values is generated. Value represents the value of the power\ngenerated at each time step or wind condition (e.g., the price of electricity). This\ncan then be used in later optimization methods to optimize for total value instead of\nenergy. This time series is then used to instantiate a TimeSeries object. The TimeSeries\nobject is then used to instantiate a WindRose object and WindTIRose object based on the\nsame data. The three objects are then each used to drive a FLORIS model of a simple\ntwo-turbine wind farm. The annual energy production (AEP) and annual value production\n(AVP) outputs are then compared and printed to the console.\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n)\nfrom floris.utilities import wrap_360\n\n\n# Generate a random time series of wind speeds, wind directions, turbulence\n# intensities, and values. In this case let's treat value as the dollars per MWh.\nN = 500\nrng = np.random.default_rng(0)\nwd_array = wrap_360(270 * np.ones(N) + rng.standard_normal(N) * 20)\nws_array = np.clip(8 * np.ones(N) + rng.standard_normal(N) * 8, 3, 50)\nti_array = np.clip(0.1 * np.ones(N) + rng.standard_normal(N) * 0.05, 0, 0.25)\nvalue_array = np.clip(25 * np.ones(N) + rng.standard_normal(N) * 10, 0, 100)\n\nfig, axarr = plt.subplots(4, 1, sharex=True, figsize=(7, 6))\nax = axarr[0]\nax.plot(wd_array, marker=\".\", ls=\"None\")\nax.set_ylabel(\"Wind Direction\")\nax = axarr[1]\nax.plot(ws_array, marker=\".\", ls=\"None\")\nax.set_ylabel(\"Wind Speed\")\nax = axarr[2]\nax.plot(ti_array, marker=\".\", ls=\"None\")\nax.set_ylabel(\"Turbulence Intensity\")\nax = axarr[3]\nax.plot(value_array, marker=\".\", ls=\"None\")\nax.set_ylabel(\"Value\")\n\n# Build the time series\ntime_series = TimeSeries(wd_array, ws_array, turbulence_intensities=ti_array, values=value_array)\n\n# Now build the wind rose\nwind_rose = time_series.to_WindRose()\n\n# Plot the wind rose\nfig, ax = plt.subplots(subplot_kw={\"polar\": True})\nwind_rose.plot(ax=ax, legend_kwargs={\"label\": \"WS\"})\nfig.suptitle(\"WindRose Plot\")\n# Now build a wind rose with turbulence intensity\nwind_ti_rose = time_series.to_WindTIRose()\n\n# Plot the wind rose with TI\nfig, axs = plt.subplots(2, 1, figsize=(6, 8), subplot_kw={\"polar\": True})\nwind_ti_rose.plot(ax=axs[0], wind_rose_var=\"ws\", legend_kwargs={\"label\": \"WS\"})\naxs[0].set_title(\"Wind Direction and Wind Speed Frequencies\")\nwind_ti_rose.plot(ax=axs[1], wind_rose_var=\"ti\", legend_kwargs={\"label\": \"TI\"})\naxs[1].set_title(\"Wind Direction and Turbulence Intensity Frequencies\")\nfig.suptitle(\"WindTIRose Plots\")\nplt.tight_layout()\n\n# Now set up a FLORIS model and initialize it using the time series and wind rose\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\nfmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n\nfmodel_time_series = fmodel.copy()\nfmodel_wind_rose = fmodel.copy()\nfmodel_wind_ti_rose = fmodel.copy()\n\nfmodel_time_series.set(wind_data=time_series)\nfmodel_wind_rose.set(wind_data=wind_rose)\nfmodel_wind_ti_rose.set(wind_data=wind_ti_rose)\n\nfmodel_time_series.run()\nfmodel_wind_rose.run()\nfmodel_wind_ti_rose.run()\n\n# Now, compute AEP using the FLORIS models initialized with the three types of\n# WindData objects. The AEP values are very similar but not exactly the same\n# because of the effects of binning in the wind roses.\n\ntime_series_aep = fmodel_time_series.get_farm_AEP()\nwind_rose_aep = fmodel_wind_rose.get_farm_AEP()\nwind_ti_rose_aep = fmodel_wind_ti_rose.get_farm_AEP()\n\nprint(f\"AEP from TimeSeries {time_series_aep / 1e9:.2f} GWh\")\nprint(f\"AEP from WindRose {wind_rose_aep / 1e9:.2f} GWh\")\nprint(f\"AEP from WindTIRose {wind_ti_rose_aep / 1e9:.2f} GWh\")\n\n# Now, compute annual value production (AVP) using the FLORIS models initialized\n# with the three types of WindData objects. The AVP values are very similar but\n# not exactly the same because of the effects of binning in the wind roses.\n\ntime_series_avp = fmodel_time_series.get_farm_AVP()\nwind_rose_avp = fmodel_wind_rose.get_farm_AVP()\nwind_ti_rose_avp = fmodel_wind_ti_rose.get_farm_AVP()\n\nprint(f\"Annual Value Production (AVP) from TimeSeries {time_series_avp / 1e6:.2f} dollars\")\nprint(f\"AVP from WindRose {wind_rose_avp / 1e6:.2f} dollars\")\nprint(f\"AVP from WindTIRose {wind_ti_rose_avp / 1e6:.2f} dollars\")\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_wind_data/002_generate_ti.py",
    "content": "\"\"\"Example: Generate TI\n\nDemonstrate usage of TI generating and plotting functionality in the WindRose\nand TimeSeries classes\n\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    TimeSeries,\n    WindRose,\n)\n\n\n# Generate a random time series of wind speeds, wind directions and turbulence intensities\nwind_directions = np.array([250, 260, 270])\nwind_speeds = np.array([5, 6, 7, 8, 9, 10])\nti_table = 0.06\n\n# Declare a WindRose object\nwind_rose = WindRose(wind_directions=wind_directions, wind_speeds=wind_speeds, ti_table=ti_table)\n\n\n# Define a custom function where TI = 1 / wind_speed\ndef custom_ti_func(wind_directions, wind_speeds):\n    return 1 / wind_speeds\n\n\nwind_rose.assign_ti_using_wd_ws_function(custom_ti_func)\n\nfig, ax = plt.subplots()\nwind_rose.plot_ti_over_ws(ax)\nax.set_title(\"Turbulence Intensity defined by custom function\")\n\n# Now use the normal turbulence model approach from the IEC 61400-1 standard,\n# wherein TI is defined as a function of wind speed:\n# Iref is defined as the TI value at 15 m/s. Note that Iref = 0.07 is lower\n# than the values of Iref used in the IEC standard, but produces TI values more\n# in line with those typically used in FLORIS (TI=8.6% at 8 m/s).\nIref = 0.07\nwind_rose.assign_ti_using_IEC_method(Iref)\nfig, ax = plt.subplots()\nwind_rose.plot_ti_over_ws(ax)\nax.set_title(f\"Turbulence Intensity defined by Iref = {Iref:0.2}\")\n\n\n# Demonstrate equivalent usage in time series\nN = 100\nwind_directions = 270 * np.ones(N)\nwind_speeds = np.linspace(5, 15, N)\nturbulence_intensities =  0.06 * np.ones(N)\ntime_series = TimeSeries(\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    turbulence_intensities=turbulence_intensities\n)\ntime_series.assign_ti_using_IEC_method(Iref=Iref)\n\nfig, axarr = plt.subplots(2, 1, sharex=True, figsize=(7, 8))\nax = axarr[0]\nax.plot(wind_speeds)\nax.set_ylabel(\"Wind Speeds (m/s)\")\nax.grid(True)\nax = axarr[1]\nax.plot(time_series.turbulence_intensities)\nax.set_ylabel(\"Turbulence Intensity (-)\")\nax.grid(True)\nfig.suptitle(\"Generating TI in TimeSeries\")\n\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_wind_data/003_generate_value.py",
    "content": "\"\"\"Example: Generate value\n\nDemonstrate usage of value generating and plotting functionality in the WindRose\nand TimeSeries classes. Value represents the value of the power or energy generated\nat each time step or wind condition (e.g., the price of electricity in dollars/MWh).\nThis can then be used to compute the annual value production (AVP) instead of AEP,\nor in later optimization methods to optimize for total value instead of energy.\n\n\"\"\"\n\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    TimeSeries,\n    WindRose,\n)\n\n\n# Generate a random time series of wind speeds, wind directions and turbulence intensities\nwind_directions = np.array([250, 260, 270])\nwind_speeds = np.arange(3.0, 11.0, 1.0)\nti_table = 0.06\n\n# Declare a WindRose object\nwind_rose = WindRose(wind_directions=wind_directions, wind_speeds=wind_speeds, ti_table=ti_table)\n\n\n# Define a custom function where value = 100 / wind_speed\ndef custom_value_func(wind_directions, wind_speeds):\n    return 100 / wind_speeds\n\n\nwind_rose.assign_value_using_wd_ws_function(custom_value_func)\n\nfig, ax = plt.subplots()\nwind_rose.plot_value_over_ws(ax)\nax.set_title(\"Value defined by custom function\")\n\n# Now assign value using the provided assign_value_piecewise_linear method with the default\n# settings. This method assigns value based on a linear piecewise function of wind speed\n# (with two line segments). The default arguments produce a value vs. wind speed that\n# approximates the normalized mean electricity price vs. wind speed curve for the SPP market\n# in the U.S. for years 2018-2020 from figure 7 in \"The value of wake steering wind farm flow\n# control in US energy markets,\" Wind Energy Science, 2024. https://doi.org/10.5194/wes-9-219-2024.\nwind_rose.assign_value_piecewise_linear(\n    value_zero_ws=1.425,\n    ws_knee=4.5,\n    slope_1=0.0,\n    slope_2=-0.135\n)\nfig, ax = plt.subplots()\nwind_rose.plot_value_over_ws(ax)\nax.set_title(\"Value defined by default piecewise linear function\")\n\n# Demonstrate equivalent usage in time series\nN = 100\nwind_directions = 270 * np.ones(N)\nwind_speeds = np.linspace(3, 15, N)\nturbulence_intensities =  0.06 * np.ones(N)\ntime_series = TimeSeries(\n    wind_directions=wind_directions,\n    wind_speeds=wind_speeds,\n    turbulence_intensities=turbulence_intensities\n)\ntime_series.assign_value_piecewise_linear()\n\nfig, axarr = plt.subplots(2, 1, sharex=True, figsize=(7, 8))\nax = axarr[0]\nax.plot(wind_speeds)\nax.set_ylabel(\"Wind Speeds (m/s)\")\nax.grid(True)\nax = axarr[1]\nax.plot(time_series.values)\nax.set_ylabel(\"Value (normalized price/MWh)\")\nax.grid(True)\nfig.suptitle(\"Generating value in TimeSeries\")\n\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_wind_resource_grid/000_generate_example_wrg.py",
    "content": "\"\"\"Example: Generate Example WRG File\n\nThis first example demonstrates the content and structure of a\nWind Resource Grid (WRG) file.\n\nWRG files are Wind Resource Grid files, and their structure is\ndefined here:\nhttps://backend.orbit.dtu.dk/ws/portalfiles/portal/116352660/WAsP_10_Help_Facility.pdf\n\nIn the script, a synthetic WRG file is derived using the WindRose class.\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.optimize import curve_fit\n\nfrom floris import WindRose\n\n\n# Define a function given the distribution of wind speeds in one sector,\n#  compute the A and k parameters of the Weibull distribution\ndef weibull_func(U, A, k):\n    return (k / A) * (U / A) ** (k - 1) * np.exp(-((U / A) ** k))\n\n\ndef estimate_weibull(U, freq):\n    # Normalize the frequency\n    freq = freq / freq.sum()\n\n    # Fit the Weibull distribution\n    popt, _ = curve_fit(weibull_func, U, freq, p0=(6.0, 2.0))\n    A_fit, k_fit = popt\n\n    return A_fit, k_fit\n\n\n##################################################\n# Parameters\n##################################################\n# Top line parameters\nNx = 2  # Number of grid points in x\nNy = 3  # Number of grid points in y\nXmin = 0.0  # Minimum value of x (m)\nYmin = 0.0  # Minimum value of y (m)\ncell_size = 1000.0  # Grid spacing (m)\n\n# Other fixed parameters\nz_coord = 0.0  # z-coordinate of the grid\nheight_above_ground_level = 90.0  # Height above ground level\nnum_sectors = 12  # Number of direction sectors\n\n\n\n##################################################\n# Generating data\n##################################################\n# The above parameters define a 3x3 grid of points.  Let's start\n# by assuming the point at (0,0) has the wind rose as\n# defined in inputs/wind_rose.csv\nwind_rose_base = WindRose.read_csv_long(\n    \"../inputs/wind_rose.csv\", wd_col=\"wd\", ws_col=\"ws\", freq_col=\"freq_val\", ti_col_or_value=0.06\n)\n\n# Resample to number of sectors\nwind_rose_base = wind_rose_base.aggregate(wd_step=360 / num_sectors)\n\n## Generate the other wind roses\n# Assume that the wind roses at other points are generated by increasing\n# the north winds with increasing y and east winds with increasing x\nx_list = []\ny_list = []\nwind_rose_list = []\n\nfor xi in range(Nx):\n    for yi in range(Ny):\n        # Get the x and y locations for this point\n        x = Xmin + xi * cell_size\n        y = Ymin + yi * cell_size\n        x_list.append(x)\n        y_list.append(y)\n\n        # Instantiate the wind rose object\n        wind_rose = WindRose.read_csv_long(\n            \"../inputs/wind_rose.csv\",\n            wd_col=\"wd\",\n            ws_col=\"ws\",\n            freq_col=\"freq_val\",\n            ti_col_or_value=0.06,\n        )\n\n        # Resample to number of sectors\n        wind_rose = wind_rose.aggregate(wd_step=360 / num_sectors)\n\n        # Copy the frequency table\n        freq_table = wind_rose.freq_table.copy()\n\n        # How much to shift the wind rose for this location\n        percent_x = xi / (Nx - 1)\n        percent_y = yi / (Ny - 1)\n\n        # East frequency scaling\n        east_row = freq_table[3, :]\n        shift_amount = percent_x * east_row[:5] * .9\n        east_row[:5] = east_row[:5] - shift_amount\n        east_row[5:10] = east_row[5:10] + shift_amount\n        freq_table[3, :] = east_row\n\n        # North frequency scaling\n        north_row = freq_table[0, :]\n        shift_amount = percent_y * north_row[:6] * .9\n        north_row[:6] = north_row[:6] - shift_amount\n        north_row[6:12] = north_row[6:12] + shift_amount\n        freq_table[0, :] = north_row\n\n        # Add to list\n        wind_rose_list.append(\n            WindRose(\n                wind_directions=wind_rose.wind_directions,\n                wind_speeds=wind_rose.wind_speeds,\n                ti_table=wind_rose.ti_table,\n                freq_table=freq_table,\n            )\n        )\n\n##################################################\n# Show the wind roses in a grid\n##################################################\n\nfig, axarr = plt.subplots(Nx, Ny, figsize=(12, 12), subplot_kw={\"polar\": True})\naxarr = axarr.flatten()\n\nfor i, wind_rose in enumerate(wind_rose_list):\n    wind_rose.plot(ax=axarr[i], ws_step=5)\n    axarr[i].set_title(f\"({x_list[i]}, {y_list[i]})\")\n\nfig.suptitle(\"Wind Roses at Grid Points\")\n\n\n##################################################\n# Demonstrate fitting the Weibull distribution\n##################################################\n\nfreq_test = wind_rose_list[0].freq_table[0, :] / wind_rose_list[0].freq_table[0, :].sum()\na_test, k_test = estimate_weibull(wind_rose_list[0].wind_speeds, freq_test)\nprint(f\"A: {a_test}, k: {k_test}\")\n\nfig, ax = plt.subplots(1, 1, figsize=(6, 3))\nax.plot(wind_rose_list[0].wind_speeds, freq_test, label=\"Original\")\nax.plot(\n    wind_rose_list[0].wind_speeds,\n    weibull_func(wind_rose_list[0].wind_speeds, a_test, k_test),\n    label=\"Fitted\",\n)\nax.legend()\nax.set_xlabel(\"Wind speed (m/s)\")\nax.set_ylabel(\"Frequency\")\nax.grid(True)\n\n\n##################################################\n# Write out the WRG file\n##################################################\n\n# Open the file\nwith open(\"wrg_example.wrg\", \"w\") as f:\n    # Write the top line of the file\n    f.write(f\"{Nx} {Ny} {Xmin} {Ymin} {cell_size}\\n\")\n\n    # Now loop over the points\n    for i in range(Nx * Ny):\n        # Initiate the line to write as 10 blank spaces\n        line = \"          \"\n\n        # Add the x-coodinate as a 10 character fixed width integer\n        line = line + f\"{int(x_list[i]):10d}\"\n\n        # Add the y-coodinate as a 10 character fixed width integer\n        line = line + f\"{int(y_list[i]):10d}\"\n\n        # Add the z-coodinate as a 10 character fixed width integer\n        line = line + f\"{int(z_coord):8d}\"\n\n        # Add the height above ground level as a 10 character fixed width integer\n        line = line + f\"{int(height_above_ground_level):5d}\"\n\n        # Get the wind rose for this point\n        wind_rose = wind_rose_list[i]\n\n        # Get the frequency matrix and wind speed\n        freq_table = wind_rose.freq_table\n        wind_speeds = wind_rose.wind_speeds\n        wind_directions = wind_rose.wind_directions\n\n        # Get the A and k parameters across all sectors\n        freq_table_ws = freq_table.sum(axis=0)\n        A, k = estimate_weibull(wind_speeds, freq_table_ws)\n\n        # Write the A and k parameters\n        line = line + f\"{A:5.1f}{k:6.2f}\"\n\n        # Add place holder 0 for the power density\n        line = line + f\"{0:15d}\"\n\n        # Write the number of sectors\n        line = line + f\"{num_sectors:3d}\"\n\n        # Get the frequency table across wind directions\n        freq_table_wd = freq_table.sum(axis=1)\n\n        # Step through the sectors\n        for wd_idx in range(num_sectors):\n            # Write the probability for this sector\n            line = line + f\"{int(1000*freq_table_wd[wd_idx]):4d}\"\n\n            # Get the A and k parameters for this sector\n            A, k = estimate_weibull(wind_speeds, freq_table[wd_idx, :])\n\n            # Write the A and k parameters\n            line = line + f\"{int(A*10):4d}{int(k*100):5d}\"\n\n        # Write the line to the file\n        f.write(line + \"\\n\")\n\n\n# Show the plots\nplt.show()\n"
  },
  {
    "path": "examples/examples_wind_resource_grid/001_wind_rose_wrg.py",
    "content": "\"\"\"Example: WindRoseWRG\n\n`WindRoseWRG` is a type of WindData object, like `WindRose` and `TimeSeries`, that\nis used to store wind data in a format that can be used by the FLORIS model.  `WindRoseWRG`\nis different that `WindRose` however because the internal data holds the information\nof the WRG file and then a `WindRose` object is created for each turbine in a provided\nlayout.\n\nIn this example the WRG file generated in the previous example is read in\nusing the `WindRoseWRG` object, and wind roses as points on the WRG grid, as will\nas in-between interpolated points have wind roses calculated using the `get_wind_rose_at_point`\nmethod.  Finally, the wind roses are upsampled to 5 degree wind direction bins and plotted.\n\n\"\"\"\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import WindRoseWRG\n\n\n# Read the WRG file\nwind_rose_wrg = WindRoseWRG(\"wrg_example.wrg\")\n\n# Print some basic information\nprint(wind_rose_wrg)\n\n# The wind roses were set to have a higher concentration of faster north winds for\n# increasing y, show that this is contained within the wind roses, even those interpolated\n# between grid points\ny_points_to_test = np.array([0, 500, 1000, 1500, 2000])\n\nfig, axarr = plt.subplots(1, 5, figsize=(16, 5), subplot_kw={\"polar\": True})\n\nfor i in range(5):\n    wind_rose = wind_rose_wrg.get_wind_rose_at_point(0, y_points_to_test[i])\n    wind_rose.plot(ax=axarr[i], ws_step=5)\n    if i %2 == 0:\n        axarr[i].set_title(f\"y = {y_points_to_test[i]}\")\n    else:\n        axarr[i].set_title(f\"y = {y_points_to_test[i]}\\n(Interpolated)\")\n\n# Go through the axarr and delete the legends except for the middle\nfor ax in [axarr[0], axarr[1], axarr[3], axarr[4]]:\n    ax.legend().set_visible(False)\n\n\n# Draw a horizontal line on each axis indicating the level of the lower wind speed\n# bucket for the north wind from the first wind rose\nfor i in range(5):\n    axarr[i].axhline(y=0.036, color=\"red\", alpha=0.5)\n\nfig.suptitle(\"Wind Roses at locations with increasing y.  Note the location where the 5 m/s bin \\\ntransitions to 10 m/s for north wind at y = 0 is \\nindicated by the red line to show \\\nthe increase in wind speed to the north as y increases.\")\n\n# Since wind directions was not specified, the wind directions implied by the number of sectors\n# in the WRG was used, however the wind directions can be set using the set_wind_directions method\n# or passed in at initialization.  Here we upsample from 12, 30-deg sectors, to 72 5-deg sectors\nwind_rose_wrg.set_wd_step(5.0)\n\nfig, axarr = plt.subplots(1, 5, figsize=(16, 5), subplot_kw={\"polar\": True})\n\nfor i in range(5):\n    wind_rose = wind_rose_wrg.get_wind_rose_at_point(0, y_points_to_test[i])\n    wind_rose.plot(ax=axarr[i], ws_step=5)\n    if i %2 == 0:\n        axarr[i].set_title(f\"y = {y_points_to_test[i]}\")\n    else:\n        axarr[i].set_title(f\"y = {y_points_to_test[i]}\\n(Interpolated)\")\n\n# Go through the axarr and delete all the legends except for the middle\nfor ax in axarr:\n    ax.legend().set_visible(False)\n\nfig.suptitle('Wind roses with upsampling to 5-deg bins')\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_wind_resource_grid/002_set_floris_with_wrg.py",
    "content": "\"\"\"Example: Setting FLORIS with WindRoseWRG\n\nThis example shows how to set a FLORIS model with a WindRoseWRG object.  When a WindRoseWRG object\nis set as the wind data in a FLORIS model, the wind roses for each turbine in the layout are\ngenerated and stored in the WindRoseWRG object.  The wind roses are then used to calculate the\nexpected turbine powers and farm power.\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    WindRoseWRG,\n)\n\n\n# Read the WRG file into a WindRoseWRG object\nwind_rose_wrg = WindRoseWRG(\"wrg_example.wrg\")\n\n# Print out some information about the\nprint(wind_rose_wrg)\nprint(\"=====================================\")\n\n# Since we didn't specify the wind speeds or fixed ti, the default values are used\n# and displayed in the above printout.  Note the wrg file itself, does not specify\n# turbulence intensity, or the wind speed bins FLORIS should use.  These can be chosen\n# at initialization of the WindRoseWRG object, or set later.  We can update these values\n# using the following methods\nwind_rose_wrg.set_wind_speeds(np.arange(0, 26, 2.0))  # Use 2m/s steps\nwind_rose_wrg.set_ti_table(0.07)  # Use a fixed ti of 7% for all wind directions and wind speeds\n\n\n# Select a turbine layout\n# The original grid in example 000 was defined by having the wind rose rotate with increasing y\n# and move to higher speeds with increasing x.  Here we will define a turbine layout that\n# has a line of turbine along the diagonals of the grid.\nlayout_x = np.array([0, 500, 1000])\nlayout_y = np.array([0, 1000, 2000])\n\n# Set the turbine layout in the WindRoseWRG object, note that until this is done, the\n# wind_rose_wrg object contains no WindRose objects.\n# Note that if the wind_rose_wrg is applied to a FlorisModel, the layout_x and layout_y\n# will be set in the FlorisModel and the wind roses will be generated for each turbine\nwind_rose_wrg.set_layout(layout_x, layout_y)\n\n# Plot the wind roses in the first figure\nfig, axarr = plt.subplots(1, 3, figsize=(16, 5), subplot_kw={\"polar\": True})\nwind_rose_wrg.plot_wind_roses(axarr=axarr, ws_step=5)\n\n# Apply the wind_rose_wrg to a FlorisModel\n\n# Load the FLORIS model and set that layout\nfmodel = FlorisModel(\"../inputs/gch.yaml\")\nfmodel.set(layout_x=layout_x, layout_y=layout_y)\n\n# Set the wind data as the wind_rose_wrg\nfmodel.set(wind_data=wind_rose_wrg)\n\n# Run the model and get the expected turbine powers and farm power\nfmodel.run()\nexpected_turbine_powers = fmodel.get_expected_turbine_powers()\nexpected_farm_power = fmodel.get_expected_farm_power()\n\n# Print the expected turbine powers, farm power, and the sum of the expected turbine powers\nprint(\"=====================================\")\nprint(\"Expected turbine powers:\", expected_turbine_powers)\nprint(\"Expected farm power:\", expected_farm_power)\nprint(\"Sum of expected turbine powers:\", expected_turbine_powers.sum())\nprint(\"=====================================\")\n\n# Now re-run using one of the turbine wind roses alone\n\n# Compare with the result if just using the first wind rose or the last wind rose\nfmodel.set(wind_data=wind_rose_wrg.wind_roses[0])\nfmodel.run()\nexpected_turbine_powers_first = fmodel.get_expected_turbine_powers()\n\nfmodel.set(wind_data=wind_rose_wrg.wind_roses[-1])\nfmodel.run()\nexpected_turbine_powers_last = fmodel.get_expected_turbine_powers()\n\n# Print the results to show match of first and last turbine when using their respective wind roses\nprint(\"Expected turbine powers:\")\nprint(\"All wind roses:\", expected_turbine_powers)\nprint(\n    \"First wind rose (1st power matches): (\"\n    + str(expected_turbine_powers_first[0])\n    + \"), \"\n    + str(expected_turbine_powers_first[1])\n    + \", \"\n    + str(expected_turbine_powers_first[2])\n    + \")\"\n)\nprint(\n    \"Last wind rose (Last power matches): \"\n    + str(expected_turbine_powers_last[0])\n    + \", \"\n    + str(expected_turbine_powers_last[1])\n    + \", (\"\n    + str(expected_turbine_powers_last[2])\n    + \")\"\n)\n\n\nplt.show()\n"
  },
  {
    "path": "examples/examples_wind_resource_grid/003_wrg_compar_layout_optimization.py",
    "content": "\"\"\"Example: Layout optimization with WindRoseWRG comparison\n\nThis example compares a layout optimization using a WindRoseWRG.  In the example, two\nturbine positions are optimized within a square grid.  The optimization is run 3 times:\n\n1. Using a WindRoseWRG object generated using the example wrg file\n2. Using a WindRose object created from the WindRoseWRG object\n3. Using a WindRose object created from the WindRoseWRG object, but with the HeterogeneousMap\n   also generated by the WindRoseWRG object\n\n\nBecause the WRG file includes a speed-up for northern winds, optimizaitions (1) and (3) place both\nturbines near the northern boundary of the grid, while optimization (2) places the turbines in the\nfurthest corners of the grid.  The optimization illustrates that using the full WindRoseWRG object\nproduces a similar result to the WindRose object with the HeterogeneousMap, since they both\ncan represent the difference in resource for different locations.  The HeterogeneousMap may have\nadvantage for larger cases since it is running with only 1 wind speed.  For this example the results\nand performance are similar.\n\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom floris import (\n    FlorisModel,\n    WindRoseWRG,\n)\nfrom floris.optimization.layout_optimization.layout_optimization_random_search import (\n    LayoutOptimizationRandomSearch,\n)\n\n\nif __name__ == \"__main__\":\n\n    # Parameters of layout optimization\n    seconds_per_iteration = 30.0\n    total_optimization_seconds = 120.0\n    min_dist_D = 3.0\n    use_dist_based_init = False\n\n    # Initialize the WindRoseWRG object with wind speeds every 2 m/s and fixed ti of 6%.  Specify\n    # a wd_step of 4 degrees, which implies upsampling from wrg's 90 degree sectors to 12\n    # degree sectors\n    wind_rose_wrg = WindRoseWRG(\n        \"wrg_example.wrg\",\n        wd_step=2.0,\n        wind_speeds=np.arange(0, 21, 1.0),  # Use a sparser range of speeds\n        ti_table=0.06,\n    )\n\n    # Define an optimization boundary within the grid that is a square with a\n    # buffer to avoid the outer limits of the heterogeneous area\n    buffer = 100.0\n    boundaries = [\n        (buffer, buffer),\n        (1000 - buffer, buffer),\n        (1000 - buffer, 2000 - buffer),\n        (buffer, 2000 - buffer),\n        (buffer, buffer),\n    ]\n\n    # Select and initial layout in the corners of the boundary\n    layout_x = np.array([500, 1000 - buffer])\n    layout_y = np.array([900, 2000 - buffer])\n\n    ##########################\n    # Set up the FlorisModel\n    fmodel = FlorisModel(\"../inputs/gch.yaml\")\n\n    ##########################\n    # Use the get_heterogeneous_map method to generate a WindRose that represents\n    # the information in the WindRoseWRG, rather than a set of WindRose objects\n    # but as a  single WindRose object (for one location) and a HeterogeneousMap\n    # the describes the speed up information per direction across the domain\n    # This will allow running the optimization for a single wind speed while still\n    # accounting for the difference in wind speeds in location by direction\n    wind_rose_het = wind_rose_wrg.get_heterogeneous_wind_rose(\n        fmodel=fmodel,\n        x_loc=0.0,\n        y_loc=0.0,\n        representative_wind_speed=9.0,\n    )\n\n    # Pull out the heterogeneous plot to show the underlying speedups\n    het_map = wind_rose_het.heterogeneous_map\n    wind_direction_to_plot = [0.0, 10.0, 45.0, 75.0, 90.0, 180.0]\n\n    # Show the het_map for a few wind directions\n    fig, axarr = plt.subplots(1, len(wind_direction_to_plot), figsize=(16, 5))\n    axarr = axarr.flatten()\n    for i, wd in enumerate(wind_direction_to_plot):\n        het_map.plot_single_speed_multiplier(\n            wind_direction=wd,\n            wind_speed=8.0,\n            ax=axarr[i],\n            show_colorbar=True,\n        )\n\n        axarr[i].set_title(f\"Wind Direction: {wd}\")\n\n    # ##########################\n    # Run the optimization with the full WindRoseWRG first\n    fmodel.set(layout_x=layout_x, layout_y=layout_y, wind_data=wind_rose_wrg)\n\n    # Set the layout optimization\n    layout_opt = LayoutOptimizationRandomSearch(\n        fmodel,\n        boundaries,\n        min_dist_D=min_dist_D,\n        seconds_per_iteration=seconds_per_iteration,\n        total_optimization_seconds=total_optimization_seconds,\n        use_dist_based_init=use_dist_based_init,\n    )\n\n    layout_opt.optimize()\n    x_initial, y_initial, x_opt_wrg, y_opt_wrg = layout_opt._get_initial_and_final_locs()\n\n    # Grab the log array\n    objective_log_array_wrg = np.array(layout_opt.objective_candidate_log)\n\n    # Normalize\n    objective_log_array_wrg = objective_log_array_wrg / np.max(objective_log_array_wrg)\n\n    print(\"=====================================\")\n    print(\"Objective log array (WRG):\")\n    print(objective_log_array_wrg.shape)\n    print(objective_log_array_wrg)\n\n    # ##########################\n    # Repeat using wind_rose_het\n    fmodel.set(layout_x=layout_x, layout_y=layout_y, wind_data=wind_rose_het)\n\n    # Set the layout optimization\n    layout_opt = LayoutOptimizationRandomSearch(\n        fmodel,\n        boundaries,\n        min_dist_D=min_dist_D,\n        seconds_per_iteration=seconds_per_iteration,\n        total_optimization_seconds=total_optimization_seconds,\n        use_dist_based_init=use_dist_based_init,\n    )\n\n    layout_opt.optimize()\n    _, _, x_opt_het, y_opt_het = layout_opt._get_initial_and_final_locs()\n\n    # Grab the log array\n    objective_log_array_het = np.array(layout_opt.objective_candidate_log)\n\n    # Normalize\n    objective_log_array_het = objective_log_array_het / np.max(objective_log_array_het)\n\n    # ##########################\n    # Repeat using single wind rose (without het)\n    wind_rose = wind_rose_wrg.get_wind_rose_at_point(0, 0)\n    fmodel = FlorisModel(\"../inputs/gch.yaml\")\n    fmodel.set(layout_x=layout_x, layout_y=layout_y, wind_data=wind_rose)\n\n    # Set the layout optimization\n    layout_opt = LayoutOptimizationRandomSearch(\n        fmodel,\n        boundaries,\n        min_dist_D=min_dist_D,\n        seconds_per_iteration=seconds_per_iteration,\n        total_optimization_seconds=total_optimization_seconds,\n        use_dist_based_init=use_dist_based_init,\n    )\n\n    layout_opt.optimize()\n    _, _, x_opt_wr, y_opt_wr = layout_opt._get_initial_and_final_locs()\n\n    # Grab the log array\n    objective_log_array_wr = np.array(layout_opt.objective_candidate_log)\n\n    # Normalize\n    objective_log_array_wr = objective_log_array_wr / np.max(objective_log_array_wr)\n\n    fig, ax = plt.subplots(1, 1, figsize=(8, 8))\n    layout_opt.plot_layout_opt_boundary(ax=ax)\n    ax.scatter(x_initial, y_initial, label=\"Initial Layout\", s=80, color=\"k\", marker=\"s\")\n    ax.scatter(\n        x_opt_wr, y_opt_wr, label=\"Optimized Layout (Single Wind Rose)\", s=60, color=\"b\", marker=\"^\"\n    )\n    ax.scatter(x_opt_wrg, y_opt_wrg, label=\"Optimized Layout (WRG)\", s=40, color=\"r\", marker=\"o\")\n    ax.scatter(\n        x_opt_het,\n        y_opt_het,\n        label=\"Optimized Layout (Single Wind Rose + Het)\",\n        s=20,\n        color=\"g\",\n        marker=\"h\",\n    )\n    ax.set_aspect('equal')\n    ax.legend()\n\n    print(\"=====================================\")\n    print(\"Objective log array (HET):\")\n    print(objective_log_array_het.shape)\n    print(objective_log_array_het)\n\n    fig, ax = plt.subplots(1, 1, figsize=(8, 8))\n    for objective_log_array, label, color in zip(\n        [objective_log_array_wr, objective_log_array_wrg, objective_log_array_het],\n        [\"WR\", \"WRG\", \"Het\"],\n        [\"b\", \"r\", \"g\"],\n    ):\n        ax.plot(\n            np.arange(len(objective_log_array)),\n            np.log10(objective_log_array * 100.0),\n            label=label,\n            color=color,\n        )\n        ax.set_xlabel(\"Iteration\")\n        ax.set_ylabel(\"Objective\")\n        ax.legend()\n\n    plt.show()\n"
  },
  {
    "path": "examples/examples_wind_resource_grid/wrg_example.wrg",
    "content": "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  61  76  220  54  74  220  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                   0      1000       0   90  9.6  2.31              0 12 116 107  341  86  93  228  61  76  220  54  74  220  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                   0      2000       0   90  9.7  2.36              0 12 116 106  409  86  93  228  61  76  220  54  74  220  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                1000         0       0   90  9.6  2.34              0 12 116 106  273  86  93  228  61  76  220  54  82  407  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                1000      1000       0   90  9.6  2.40              0 12 116 107  341  86  93  228  61  76  220  54  82  407  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                1000      2000       0   90  9.7  2.46              0 12 116 106  409  86  93  228  61  76  220  54  82  407  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n"
  },
  {
    "path": "examples/inputs/cc.yaml",
    "content": "\nname: CC\ndescription: Three turbines using Cumulative Gauss Curl model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - nrel_5MW\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: cc\n\n  enable_secondary_steering: true\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: true\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.01\n      constant: 0.9\n      ai: 0.83\n      downstream: -0.25\n"
  },
  {
    "path": "examples/inputs/emgauss.yaml",
    "content": "\nname: Emperical Gaussian\ndescription: Three turbines using emperical Gaussian model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - nrel_5MW\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: empirical_gauss\n    turbulence_model: wake_induced_mixing\n    velocity_model: empirical_gauss\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: true\n  enable_active_wake_mixing: false\n  enable_transverse_velocities: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n    empirical_gauss:\n      horizontal_deflection_gain_D: 3.0\n      vertical_deflection_gain_D: -1\n      deflection_rate: 22\n      mixing_gain_deflection: 0.0\n      yaw_added_mixing_gain: 0.0\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    empirical_gauss:\n      wake_expansion_rates:\n      - 0.023\n      - 0.008\n      breakpoints_D:\n      - 10\n      sigma_0_D: 0.28\n      smoothing_length_D: 2.0\n      mixing_gain_velocity: 2.0\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n    wake_induced_mixing:\n      atmospheric_ti_gain: 0.0\n"
  },
  {
    "path": "examples/inputs/emgauss_helix.yaml",
    "content": "\nname: Emperical Gaussian\ndescription: Three turbines using empirical Gaussian model\nfloris_version: v4.0\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - iea_15MW\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: empirical_gauss\n    turbulence_model: wake_induced_mixing\n    velocity_model: empirical_gauss\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: false\n  enable_active_wake_mixing: true\n  enable_transverse_velocities: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n    empirical_gauss:\n      horizontal_deflection_gain_D: 3.0\n      vertical_deflection_gain_D: -1\n      deflection_rate: 30\n      mixing_gain_deflection: 0.0\n      yaw_added_mixing_gain: 0.0\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    empirical_gauss:\n      wake_expansion_rates:\n      - 0.023\n      - 0.008\n      breakpoints_D:\n      - 10\n      sigma_0_D: 0.28\n      smoothing_length_D: 2.0\n      mixing_gain_velocity: 2.0\n      awc_wake_exp: 1.2\n      awc_wake_denominator: 400\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n    wake_induced_mixing:\n      atmospheric_ti_gain: 0.0\n"
  },
  {
    "path": "examples/inputs/gch.yaml",
    "content": "\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: GCH\n\n###\n# Description of the contents of this input file.\n# This is not used by FLORIS and is simply for the user's reference.\n# String type.\ndescription: Three turbines using Gauss Curl Hybrid model\n\n###\n# The FLORIS version that the file is defined for.\n# This is not used by FLORIS and is simply for the user's reference.\n# String type.\nfloris_version: v4\n\n###\n# Upper-level group of options for configuring logging.\nlogging:\n\n  ###\n  # Group of settings for logging to the console (i.e. terminal).\n  console:\n\n    ###\n    # Flag to enable console logging. Boolean type.\n    enable: true\n\n    ###\n    # Severity to show output in console. Messages at this level or higher will be shown.\n    # String type. Can be one of \"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\".\n    level: WARNING\n\n  ###\n  # Group of settings for logging to a file.\n  file:\n\n    ###\n    # Flag to enable file logging. Boolean type.\n    enable: false\n\n    ###\n    # Severity to show output in file. Messages at this level or higher will be shown.\n    # String type. Can be one of \"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\".\n    level: WARNING\n\n###\n# Upper-level group of options for configuring solution grid.\nsolver:\n\n  ###\n  # Grid type for solving flow values at the turbines.\n  # String type. Can be one of: \"turbine_grid\", \"turbine_cubature_grid\".\n  type: turbine_grid\n\n  ###\n  # Number of grid points per turbine for solve. For turbine_grid type solve, represents the number\n  # of points along each of the two axes. For turbine_cubature_grid type solve, represents the\n  # total number of points used in the cubature solve. Integer type.\n  turbine_grid_points: 3\n\n###\n# Group for setting the wind farm configuration.\nfarm:\n\n  ###\n  # x-coordinates for the turbine locations, with the x axis corresponding to the\n  # \"west to east\" direction. The order of the coordinates corresponds to the index of the\n  # turbine in the primary data structures.\n  # List of float type.\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n\n  ###\n  # y-coordinates for the turbine locations, with the y axis corresponding to the\n  # \"south to north\" direction. The order of the coordinates corresponds to the index of the\n  # turbine in the primary data structures.\n  # List of float type.\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n\n  ###\n  # Listing of turbine types for placement at the x and y coordinates.\n  # The list length must be 1 or the same as ``layout_x`` and ``layout_y``. If it is a\n  # single value, all turbines are of the same type. Otherwise, the turbine type\n  # is mapped to the location at the same index in ``layout_x`` and ``layout_y``.\n  # The types can be either a string for a turbine included in the turbine_library,\n  # a string beginning with !include for a path to the user's turbine; or a full\n  # definition of a wind turbine (as a nested dictionary).\n  turbine_type:\n  - nrel_5MW\n\n###\n# Group for defining the atmospheric conditions.\nflow_field:\n\n  ###\n  # Air density. Float type.\n  air_density: 1.225\n\n  ###\n  # The height in meters to consider the \"center\" of the vertical wind speed profile\n  # due to shear. With a shear exponent not 1, the wind speed at this height\n  # will be the value given in ``wind_speeds``. Above and below this height,\n  # the wind speed will change according to the shear profile; see\n  # :py:meth:`.FlowField.initialize_velocity_field`.\n  # For farms consisting of one wind turbine type, use ``reference_wind_height: -1``\n  # to use the hub height of the wind turbine definition. For multiple wind turbine\n  # types, the reference wind height must be given explicitly. Float type (or -1).\n  reference_wind_height: -1\n\n  ###\n  # Turbulence intensities for the simulation, specified as a decimal value. Type list of floats.\n  turbulence_intensities:\n  - 0.06\n\n  ###\n  # Wind directions for the simulation, specified in degrees according to compass directions\n  # (0 is northerly, 90 is easterly, etc). Type list of floats.\n  wind_directions:\n  - 270.0\n\n  ###\n  # The exponent used to model the wind shear profile; see\n  # :py:meth:`.FlowField.initialize_velocity_field`. Float type.\n  wind_shear: 0.12\n\n  ###\n  # The wind speeds for the simulation, specified in m/s at the ``reference_wind_height``.\n  # Type list of floats.\n  wind_speeds:\n  - 8.0\n\n  ###\n  # The wind veer (in degrees) as a constant value for all points in the grid. Only used in\n  # certain models. Float type.\n  wind_veer: 0.0\n\n  ###\n  # Conditions that are specified for use with the multi-dimensional power/thrust capability.\n  # These conditions are external to FLORIS and specified by the user. They are used internally\n  # through a nearest-neighbor selection process to choose the correct Cp/Ct interpolants\n  # to use. Type dictionary of string:float pairs.\n  multidim_conditions:\n    Tp: 2.5\n    Hs: 3.01\n\n###\n# Group for defining the wake model parameters.\nwake:\n\n  ###\n  # Group for selecting the model elements for the simulation.\n  # See :py:mod:`~.wake` for a list of available models and their descriptions.\n  model_strings:\n\n    ###\n    # Wake combination model. String type..\n    combination_model: sosfs\n\n    ###\n    # Wake deflection model. String type.\n    deflection_model: gauss\n\n    ###\n    # Wake turbulence model. String type..\n    turbulence_model: crespo_hernandez\n\n    ###\n    # Wake velocity deficit model. String type.\n    velocity_model: gauss\n\n  ###\n  # Flag to include secondary steering effects. Only used in some models. Boolean type.\n  enable_secondary_steering: true\n\n  ###\n  # Flag to include yaw added recovery effects. Only used in some models. Boolean type.\n  enable_yaw_added_recovery: true\n\n  ###\n  # Flag to include active wake mixing effects. Only used in Empirical Guassian model. Boolean type.\n  enable_active_wake_mixing: false\n\n  ###\n  # Flag to compute transverse velocities across turbine rotors. Only used in some models.\n  # Boolean type.\n  enable_transverse_velocities: true\n\n  ###\n  # Parameters for the wake deflection model. See model descriptions and implementations for\n  # details of each parameter and its use.\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  ###\n  # Parameters for the wake velocity deficit model. See model descriptions and implementations for\n  # details of each parameter and its use.\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n\n  ###\n  # Parameters for the wake turbulence model. See model descriptions and implementations for\n  # details of each parameter and its use.\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n"
  },
  {
    "path": "examples/inputs/gch_heterogeneous_inflow.yaml",
    "content": "name: GCH\ndescription: Three turbines using Gauss Curl Hybrid model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 1\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - nrel_5MW\n\nflow_field:\n  air_density: 1.225\n  heterogeneous_inflow_config:\n    speed_multipliers:\n      - - 2.0\n        - 1.0\n        - 2.0\n        - 1.0\n    x:\n      - -300.\n      - -300.\n      - 2600.\n      - 2600.\n    y:\n      - -300.\n      - 300.\n      - -300.\n      - 300.\n  reference_wind_height: -1\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: gauss\n  enable_secondary_steering: true\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: true\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n"
  },
  {
    "path": "examples/inputs/gch_multi_dim_cp_ct.yaml",
    "content": "\nname: GCH multi dimensional power/thrust coefficient\ndescription: Three turbines using GCH model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - iea_15MW_floating_multi_dim_cp_ct\n\nflow_field:\n  multidim_conditions:\n    Tp: 2.5\n    Hs: 3.01\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: gauss\n\n  enable_secondary_steering: true\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: true\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n    empirical_gauss:\n      horizontal_deflection_gain_D: 3.0\n      vertical_deflection_gain_D: -1\n      deflection_rate: 22\n      mixing_gain_deflection: 0.0\n      yaw_added_mixing_gain: 0.0\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    turbopark:\n      A: 0.04\n      sigma_max_rel: 4.0\n    empirical_gauss:\n      wake_expansion_rates:\n      - 0.023\n      - 0.008\n      breakpoints_D:\n      - 10\n      sigma_0_D: 0.28\n      smoothing_length_D: 2.0\n      mixing_gain_velocity: 2.0\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.01\n      constant: 0.9\n      ai: 0.83\n      downstream: -0.25\n    wake_induced_mixing:\n      atmospheric_ti_gain: 0.0\n"
  },
  {
    "path": "examples/inputs/gch_multi_dim_cp_ct_TI.yaml",
    "content": "\nname: GCH multi dimensional power/thrust coefficient\ndescription: Three turbines using GCH model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - iea_15MW_multi_dim_TI.yaml\n  turbine_library_path: ../inputs/turbine_files/\n\nflow_field:\n  multidim_conditions:\n    TI: 0.06\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: gauss\n\n  enable_secondary_steering: true\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: true\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n    empirical_gauss:\n      horizontal_deflection_gain_D: 3.0\n      vertical_deflection_gain_D: -1\n      deflection_rate: 22\n      mixing_gain_deflection: 0.0\n      yaw_added_mixing_gain: 0.0\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    turbopark:\n      A: 0.04\n      sigma_max_rel: 4.0\n    empirical_gauss:\n      wake_expansion_rates:\n      - 0.023\n      - 0.008\n      breakpoints_D:\n      - 10\n      sigma_0_D: 0.28\n      smoothing_length_D: 2.0\n      mixing_gain_velocity: 2.0\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.01\n      constant: 0.9\n      ai: 0.83\n      downstream: -0.25\n    wake_induced_mixing:\n      atmospheric_ti_gain: 0.0\n"
  },
  {
    "path": "examples/inputs/gch_multiple_turbine_types.yaml",
    "content": "\nname: GCH\ndescription: Three turbines using Gauss Curl Hybrid model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  layout_y:\n  - 0.0\n  - 0.0\n  turbine_type:\n  - nrel_5MW\n  - iea_10MW\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: 90.0 # Since multiple defined turbines, must specify explicitly the reference wind height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: gauss\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: false\n  enable_transverse_velocities: false\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n"
  },
  {
    "path": "examples/inputs/jensen.yaml",
    "content": "\nname: Jensen-Jimenez\ndescription: Three turbines using Jensen / Jimenez models\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - nrel_5MW\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: jimenez\n    turbulence_model: crespo_hernandez\n    velocity_model: jensen\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: false\n  enable_transverse_velocities: false\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n"
  },
  {
    "path": "examples/inputs/turbine_files/iea_15MW_multi_dim_TI.csv",
    "content": "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.585981,0.784655297\n0.06,4.067900771,607.966543,0.781771245\n0.06,4.553906848,981.097693,0.785377072\n0.06,5.006427063,1401.98084,0.788045584\n0.06,5.424415288,1858.67086,0.789922119\n0.06,5.806905228,2337.575997,0.790464625\n0.06,6.153012649,2824.097302,0.789868339\n0.06,6.461937428,3303.06456,0.788727582\n0.06,6.732965398,3759.432328,0.787359348\n0.06,6.965470002,4178.637714,0.785895402\n0.06,7.158913742,4547.19121,0.778275899\n0.06,7.312849418,4855.342682,0.778275899\n0.06,7.426921164,5091.537139,0.778275899\n0.06,7.500865272,5248.453137,0.778275899\n0.06,7.534510799,5320.793207,0.778275899\n0.06,7.541241633,5335.345498,0.778275899\n0.06,7.58833327,5437.90563,0.778275899\n0.06,7.675676842,5631.253025,0.778275899\n0.06,7.803070431,5920.980626,0.778275899\n0.06,7.970219531,6315.115602,0.778275899\n0.06,8.176737731,6824.470067,0.778275899\n0.06,8.422147605,7462.846389,0.778275899\n0.06,8.70588182,8238.359448,0.778275899\n0.06,9.027284445,9167.96703,0.778275899\n0.06,9.385612468,10285.211,0.778275899\n0.06,9.780037514,11617.23699,0.778275899\n0.06,10.20964776,13194.41511,0.778275899\n0.06,10.67345004,15000.0,0.77176172\n0.06,10.86770694,15000.0,0.747149663\n0.06,11.17037214,15000.0,0.562338457\n0.06,11.6992653,15000.0,0.463477777\n0.06,12.25890683,15000.0,0.389083718\n0.06,12.84800295,15000.0,0.329822385\n0.06,13.46519181,15000.0,0.281465071\n0.06,14.10904661,15000.0,0.241494345\n0.06,14.77807889,15000.0,0.208180574\n0.06,15.470742,15000.0,0.180257568\n0.06,16.18543466,15000.0,0.156747535\n0.06,16.92050464,15000.0,0.136877529\n0.06,17.67425264,15000.0,0.120026379\n0.06,18.44493615,15000.0,0.105689427\n0.06,19.23077353,15000.0,0.093453742\n0.06,20.02994808,15000.0,0.082979637\n0.06,20.8406123,15000.0,0.073986457\n0.06,21.66089211,15000.0,0.066241166\n0.06,22.4888912,15000.0,0.059552107\n0.06,23.32269542,15000.0,0.053756866\n0.06,24.1603772,15000.0,0.048721662\n0.06,25.0,15000.0,0.044334197\n0.06,25.02,0.0,0.0\n0.06,50.0,0.0,0.0\n0.08,0.0,0.0,0.0\n0.08,2.9,0.0,0.0\n0.08,3.0,47.0066432,0.80742173\n0.08,3.54953237,321.84457910000003,0.784655297\n0.08,4.067900771,668.7631973,0.781771245\n0.08,4.553906848,1079.2074623,0.785377072\n0.08,5.006427063,1542.178924,0.788045584\n0.08,5.424415288,2044.5379460000001,0.789922119\n0.08,5.806905228,2571.3335967000003,0.790464625\n0.08,6.153012649,3106.5070322000006,0.789868339\n0.08,6.461937428,3633.371016,0.788727582\n0.08,6.732965398,4135.3755608,0.787359348\n0.08,6.965470002,4596.501485400001,0.785895402\n0.08,7.158913742,5001.910331,0.778275899\n0.08,7.312849418,5340.8769502000005,0.778275899\n0.08,7.426921164,5600.6908529,0.778275899\n0.08,7.500865272,5773.298450700001,0.778275899\n0.08,7.534510799,5852.8725277,0.778275899\n0.08,7.541241633,5868.8800478,0.778275899\n0.08,7.58833327,5981.696193000001,0.778275899\n0.08,7.675676842,6194.3783275000005,0.778275899\n0.08,7.803070431,6513.0786886,0.778275899\n0.08,7.970219531,6946.6271622,0.778275899\n0.08,8.176737731,7506.9170737,0.778275899\n0.08,8.422147605,8209.1310279,0.778275899\n0.08,8.70588182,9062.1953928,0.778275899\n0.08,9.027284445,10084.763733,0.778275899\n0.08,9.385612468,11313.732100000001,0.778275899\n0.08,9.780037514,12778.960689,0.778275899\n0.08,10.20964776,14513.856621,0.778275899\n0.08,10.67345004,15000.0,0.77176172\n0.08,10.86770694,15000.0,0.747149663\n0.08,11.17037214,15000.0,0.562338457\n0.08,11.6992653,15000.0,0.463477777\n0.08,12.25890683,15000.0,0.389083718\n0.08,12.84800295,15000.0,0.329822385\n0.08,13.46519181,15000.0,0.281465071\n0.08,14.10904661,15000.0,0.241494345\n0.08,14.77807889,15000.0,0.208180574\n0.08,15.470742,15000.0,0.180257568\n0.08,16.18543466,15000.0,0.156747535\n0.08,16.92050464,15000.0,0.136877529\n0.08,17.67425264,15000.0,0.120026379\n0.08,18.44493615,15000.0,0.105689427\n0.08,19.23077353,15000.0,0.093453742\n0.08,20.02994808,15000.0,0.082979637\n0.08,20.8406123,15000.0,0.073986457\n0.08,21.66089211,15000.0,0.066241166\n0.08,22.4888912,15000.0,0.059552107\n0.08,23.32269542,15000.0,0.053756866\n0.08,24.1603772,15000.0,0.048721662\n0.08,25.0,15000.0,0.044334197\n0.08,25.02,0.0,0.0\n0.08,50.0,0.0,0.0\n"
  },
  {
    "path": "examples/inputs/turbine_files/iea_15MW_multi_dim_TI.yaml",
    "content": "turbine_type: 'iea_15MW_floating'\nhub_height: 150.0\nrotor_diameter: 242.24\nTSR: 8.0\nmulti_dimensional_cp_ct: True\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 6.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  # Note that the multidimensional data provided here is fictional and does not represent a real\n  # wind turbine.\n  power_thrust_data_file: './iea_15MW_multi_dim_TI.csv'\n"
  },
  {
    "path": "examples/inputs/turbopark.yaml",
    "content": "\nname: TurbOPark\ndescription: Three turbines using TurbOPark model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: false\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 1\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - nrel_5MW\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: 90.0\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: fls\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: turbopark\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: false\n  enable_transverse_velocities: false\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    turbopark:\n      A: 0.04\n      sigma_max_rel: 4.0\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n"
  },
  {
    "path": "examples/inputs/turbopark_cubature.yaml",
    "content": "name: Case TwinPark FLORIS v4.0\ndescription: Two aligned wind turbines with 5D spacing as currently implemented in v4.0\n\nfloris_version: v4.0\n\nlogging:\n  console:\n    enable: true\n    # Can be one of \"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\".\n    level: WARNING\n  file:\n    enable: false\n    # Can be one of \"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\".\n    level: WARNING\n\nsolver:\n  type: turbine_cubature_grid # turbine_grid\n  turbine_grid_points: 6\n\nfarm:\n  layout_x:\n    - 0.0\n  layout_y:\n    - 0.0\n  turbine_type: # Constant CT turbine (TODO: implement in script?)\n    - nrel_5MW # Will be replaced in script\n\n# Configure the atmospheric conditions.\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1\n  turbulence_intensities:\n    - 0.06\n  wind_directions:\n    - 270.0\n  wind_speeds:\n    - 8.0\n  wind_shear: 0.0 # Needed to reproduce Pedersen et al's results with new model\n  wind_veer: 0.0\n\n# Configure the wake model.\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: none\n    turbulence_model: none\n    velocity_model: turbopark # current TurboPark model in FLORIS\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: false\n  enable_active_wake_mixing: false\n  enable_transverse_velocities: false\n  wake_velocity_parameters: # Parameters for the wake velocity deficit model\n    turbopark:\n      A: 0.04\n      sigma_max_rel: 4.0\n  wake_deflection_parameters:\n    none:\n  wake_turbulence_parameters:\n    none:\n"
  },
  {
    "path": "examples/inputs/turboparkgauss.yaml",
    "content": "\nname: TurbOParkGauss\ndescription: Three turbines using TurbOParkGauss model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: false\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_cubature_grid # turboparkgauss does not work with type: turbine_grid\n  turbine_grid_points: 4      # 4 is sufficient in nearly all cases\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - nrel_5MW\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: none\n    turbulence_model: none\n    velocity_model: turboparkgauss\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: false\n  enable_transverse_velocities: false\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    none:\n\n  wake_velocity_parameters:\n    turboparkgauss:\n      A: 0.04\n      include_mirror_wake: true\n\n  wake_turbulence_parameters:\n    none:\n"
  },
  {
    "path": "examples/inputs/turboparkgauss_cubature.yaml",
    "content": "name: Case TwinPark new implementation\ndescription: Two aligned wind turbines with 5D spacing under the new implementation\n\nfloris_version: v4.0\n\nlogging:\n  console:\n    enable: true\n    # Can be one of \"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\".\n    level: WARNING\n  file:\n    enable: false\n    # Can be one of \"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\".\n    level: WARNING\n\nsolver:\n  type: turbine_cubature_grid # turboparkgauss does not work with type: turbine_grid\n  turbine_grid_points: 6      # 4 is sufficient in nearly all cases\n\nfarm:\n  layout_x:\n    - 0.0\n  layout_y:\n    - 0.0\n  turbine_type: # Constant CT turbine (TODO: implement in script?)\n    - nrel_5MW # Will be replaced in script\n\n# Configure the atmospheric conditions.\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1\n  turbulence_intensities:\n    - 0.06\n  wind_directions:\n    - 270.0\n  wind_speeds:\n    - 8.0\n  wind_shear: 0.0 # Needed to reproduce Pedersen et al's results\n  wind_veer: 0.0\n\n# Configure the wake model.\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: none\n    turbulence_model: none\n    velocity_model: turboparkgauss # New model\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: false\n  enable_active_wake_mixing: false\n  enable_transverse_velocities: false\n  wake_velocity_parameters: # Parameters for the wake velocity deficit model\n    turboparkgauss:\n      A: 0.04\n      include_mirror_wake: true\n  wake_deflection_parameters:\n    none:\n  wake_turbulence_parameters:\n    none:\n"
  },
  {
    "path": "examples/inputs/wind_rose.csv",
    "content": "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.259027506192152e-05\n0.0,20.0,6.518055012384304e-05\n0.0,25.0,6.518055012384304e-05\n0.0,30.0,1.629513753096076e-05\n0.0,35.0,0.0\n0.0,40.0,3.259027506192152e-05\n0.0,45.0,4.888541259288228e-05\n0.0,50.0,0.0\n0.0,55.0,0.0\n0.0,60.0,4.888541259288228e-05\n0.0,65.0,1.629513753096076e-05\n0.0,70.0,3.259027506192152e-05\n0.0,75.0,1.629513753096076e-05\n0.0,80.0,3.259027506192152e-05\n0.0,85.0,4.888541259288228e-05\n0.0,90.0,4.888541259288228e-05\n0.0,95.0,4.888541259288228e-05\n0.0,100.0,4.888541259288228e-05\n0.0,105.0,6.518055012384304e-05\n0.0,110.0,4.888541259288228e-05\n0.0,115.0,4.888541259288228e-05\n0.0,120.0,0.0\n0.0,125.0,1.629513753096076e-05\n0.0,130.0,1.629513753096076e-05\n0.0,135.0,1.629513753096076e-05\n0.0,140.0,3.259027506192152e-05\n0.0,145.0,4.888541259288228e-05\n0.0,150.0,1.629513753096076e-05\n0.0,155.0,1.629513753096076e-05\n0.0,160.0,0.0\n0.0,165.0,1.629513753096076e-05\n0.0,170.0,1.629513753096076e-05\n0.0,175.0,3.259027506192152e-05\n0.0,180.0,0.0\n0.0,185.0,1.629513753096076e-05\n0.0,190.0,1.629513753096076e-05\n0.0,195.0,1.629513753096076e-05\n0.0,200.0,1.629513753096076e-05\n0.0,205.0,3.259027506192152e-05\n0.0,210.0,1.629513753096076e-05\n0.0,215.0,3.259027506192152e-05\n0.0,220.0,4.888541259288228e-05\n0.0,225.0,4.888541259288228e-05\n0.0,230.0,4.888541259288228e-05\n0.0,235.0,4.888541259288228e-05\n0.0,240.0,4.888541259288228e-05\n0.0,245.0,1.629513753096076e-05\n0.0,250.0,8.14756876548038e-05\n0.0,255.0,1.629513753096076e-05\n0.0,260.0,1.629513753096076e-05\n0.0,265.0,1.629513753096076e-05\n0.0,270.0,1.629513753096076e-05\n0.0,275.0,1.629513753096076e-05\n0.0,280.0,3.259027506192152e-05\n0.0,285.0,1.629513753096076e-05\n0.0,290.0,4.888541259288228e-05\n0.0,295.0,0.0\n0.0,300.0,0.0\n0.0,305.0,1.629513753096076e-05\n0.0,310.0,1.629513753096076e-05\n0.0,315.0,0.0\n0.0,320.0,9.777082518576456e-05\n0.0,325.0,0.0\n0.0,330.0,0.0\n0.0,335.0,0.0\n0.0,340.0,1.629513753096076e-05\n0.0,345.0,3.259027506192152e-05\n0.0,350.0,4.888541259288228e-05\n0.0,355.0,6.518055012384304e-05\n1.0,0.0,0.00019554165037152912\n1.0,5.0,0.00022813192543345064\n1.0,10.0,0.00026072220049537216\n1.0,15.0,0.00014665623777864684\n1.0,20.0,0.00017924651284056836\n1.0,25.0,0.00026072220049537216\n1.0,30.0,0.00024442706296441143\n1.0,35.0,0.00024442706296441143\n1.0,40.0,0.00019554165037152912\n1.0,45.0,0.0001629513753096076\n1.0,50.0,0.0002118367879024899\n1.0,55.0,0.00026072220049537216\n1.0,60.0,0.00014665623777864684\n1.0,65.0,0.00021183678790248988\n1.0,70.0,0.00030960761308825447\n1.0,75.0,0.00030960761308825447\n1.0,80.0,0.0003259027506192152\n1.0,85.0,0.00029331247555729374\n1.0,90.0,0.0001629513753096076\n1.0,95.0,0.00017924651284056836\n1.0,100.0,0.0001629513753096076\n1.0,105.0,0.00021183678790248988\n1.0,110.0,0.00024442706296441143\n1.0,115.0,0.00024442706296441143\n1.0,120.0,0.0002933124755572937\n1.0,125.0,0.00024442706296441143\n1.0,130.0,0.0002770173380263329\n1.0,135.0,0.00024442706296441143\n1.0,140.0,0.00026072220049537216\n1.0,145.0,0.0003259027506192152\n1.0,150.0,0.00022813192543345064\n1.0,155.0,0.0002933124755572937\n1.0,160.0,0.00024442706296441143\n1.0,165.0,0.0001629513753096076\n1.0,170.0,0.00021183678790248988\n1.0,175.0,0.00017924651284056836\n1.0,180.0,0.00019554165037152912\n1.0,185.0,0.0001629513753096076\n1.0,190.0,0.0002933124755572937\n1.0,195.0,0.00022813192543345064\n1.0,200.0,0.0002933124755572937\n1.0,205.0,0.00021183678790248988\n1.0,210.0,0.0002933124755572937\n1.0,215.0,0.00021183678790248988\n1.0,220.0,0.00026072220049537216\n1.0,225.0,0.0003259027506192152\n1.0,230.0,0.00021183678790248988\n1.0,235.0,0.00030960761308825447\n1.0,240.0,0.000342197888150176\n1.0,245.0,0.00026072220049537216\n1.0,250.0,0.00021183678790248988\n1.0,255.0,0.00017924651284056836\n1.0,260.0,0.0003259027506192152\n1.0,265.0,0.00021183678790248988\n1.0,270.0,0.0003259027506192152\n1.0,275.0,0.00019554165037152912\n1.0,280.0,9.777082518576456e-05\n1.0,285.0,0.0002770173380263329\n1.0,290.0,0.00019554165037152912\n1.0,295.0,0.00026072220049537216\n1.0,300.0,0.00022813192543345064\n1.0,305.0,0.00019554165037152912\n1.0,310.0,0.00021183678790248988\n1.0,315.0,0.00026072220049537216\n1.0,320.0,0.00021183678790248988\n1.0,325.0,0.00019554165037152912\n1.0,330.0,0.0002770173380263329\n1.0,335.0,0.00022813192543345064\n1.0,340.0,0.00013036110024768608\n1.0,345.0,0.00022813192543345064\n1.0,350.0,0.0001629513753096076\n1.0,355.0,0.00026072220049537216\n2.0,0.0,0.0006029200886455481\n2.0,5.0,0.000407378438274019\n2.0,10.0,0.0005214444009907443\n2.0,15.0,0.000407378438274019\n2.0,20.0,0.0005540346760526659\n2.0,25.0,0.00040737843827401903\n2.0,30.0,0.0004888541259288228\n2.0,35.0,0.0005051492634597836\n2.0,40.0,0.0005866249511145874\n2.0,45.0,0.0005051492634597836\n2.0,50.0,0.0005540346760526658\n2.0,55.0,0.0005866249511145874\n2.0,60.0,0.0006029200886455481\n2.0,65.0,0.0007006909138313127\n2.0,70.0,0.0005540346760526659\n2.0,75.0,0.0004888541259288229\n2.0,80.0,0.00043996871333594055\n2.0,85.0,0.0005377395385217051\n2.0,90.0,0.0002770173380263329\n2.0,95.0,0.0004562638508669013\n2.0,100.0,0.0005540346760526658\n2.0,105.0,0.0004888541259288229\n2.0,110.0,0.0005051492634597836\n2.0,115.0,0.0005051492634597836\n2.0,120.0,0.000342197888150176\n2.0,125.0,0.0004562638508669013\n2.0,130.0,0.0005214444009907443\n2.0,135.0,0.00042367357580497977\n2.0,140.0,0.0007332811888932343\n2.0,145.0,0.000472558988397862\n2.0,150.0,0.0005214444009907442\n2.0,155.0,0.000749576326424195\n2.0,160.0,0.0008473471516099595\n2.0,165.0,0.0005377395385217051\n2.0,170.0,0.0005214444009907443\n2.0,175.0,0.000749576326424195\n2.0,180.0,0.0006192152261765088\n2.0,185.0,0.0005214444009907443\n2.0,190.0,0.0006029200886455481\n2.0,195.0,0.0005703298135836265\n2.0,200.0,0.0005866249511145874\n2.0,205.0,0.0006192152261765089\n2.0,210.0,0.0006843957763003519\n2.0,215.0,0.0006843957763003519\n2.0,220.0,0.0007821666014861165\n2.0,225.0,0.0007006909138313126\n2.0,230.0,0.0006029200886455482\n2.0,235.0,0.0004399687133359405\n2.0,240.0,0.0005866249511145874\n2.0,245.0,0.0006192152261765088\n2.0,250.0,0.0003910833007430583\n2.0,255.0,0.0004399687133359405\n2.0,260.0,0.0005051492634597836\n2.0,265.0,0.00034219788815017594\n2.0,270.0,0.00034219788815017594\n2.0,275.0,0.0005214444009907443\n2.0,280.0,0.0003584930256811367\n2.0,285.0,0.0004236735758049798\n2.0,290.0,0.00039108330074305825\n2.0,295.0,0.00026072220049537216\n2.0,300.0,0.00022813192543345064\n2.0,305.0,0.000342197888150176\n2.0,310.0,0.00030960761308825447\n2.0,315.0,0.0004888541259288229\n2.0,320.0,0.0002933124755572937\n2.0,325.0,0.0004888541259288229\n2.0,330.0,0.0005051492634597836\n2.0,335.0,0.00022813192543345064\n2.0,340.0,0.00030960761308825447\n2.0,345.0,0.0004888541259288229\n2.0,350.0,0.00043996871333594055\n2.0,355.0,0.00043996871333594055\n3.0,0.0,0.0006681006387693913\n3.0,5.0,0.0007332811888932342\n3.0,10.0,0.0007332811888932342\n3.0,15.0,0.0007332811888932343\n3.0,20.0,0.0007332811888932343\n3.0,25.0,0.0007169860513622735\n3.0,30.0,0.0008310520140789988\n3.0,35.0,0.000749576326424195\n3.0,40.0,0.0007984617390170772\n3.0,45.0,0.0009125277017338027\n3.0,50.0,0.0008636422891409204\n3.0,55.0,0.0005540346760526658\n3.0,60.0,0.0008636422891409204\n3.0,65.0,0.0009940033893886065\n3.0,70.0,0.0007984617390170773\n3.0,75.0,0.0008962325642028417\n3.0,80.0,0.0008799374266718811\n3.0,85.0,0.0008636422891409204\n3.0,90.0,0.0008799374266718811\n3.0,95.0,0.0007006909138313127\n3.0,100.0,0.0008310520140789987\n3.0,105.0,0.0008310520140789988\n3.0,110.0,0.0008799374266718811\n3.0,115.0,0.0007169860513622735\n3.0,120.0,0.000879937426671881\n3.0,125.0,0.0008310520140789988\n3.0,130.0,0.0008799374266718811\n3.0,135.0,0.0008310520140789987\n3.0,140.0,0.0010428888019814887\n3.0,145.0,0.0011243644896362925\n3.0,150.0,0.000945117976795724\n3.0,155.0,0.001026593664450528\n3.0,160.0,0.0011406596271672533\n3.0,165.0,0.0009940033893886062\n3.0,170.0,0.001433972102724547\n3.0,175.0,0.0012710207274149394\n3.0,180.0,0.0012384304523530179\n3.0,185.0,0.001026593664450528\n3.0,190.0,0.0011243644896362925\n3.0,195.0,0.0009614131143266848\n3.0,200.0,0.0009940033893886065\n3.0,205.0,0.0011243644896362925\n3.0,210.0,0.0009940033893886065\n3.0,215.0,0.0007984617390170772\n3.0,220.0,0.0007006909138313126\n3.0,225.0,0.0007821666014861165\n3.0,230.0,0.0008473471516099595\n3.0,235.0,0.0006843957763003519\n3.0,240.0,0.0009940033893886065\n3.0,245.0,0.0006355103637074697\n3.0,250.0,0.0007006909138313127\n3.0,255.0,0.0006681006387693911\n3.0,260.0,0.000684395776300352\n3.0,265.0,0.0005866249511145873\n3.0,270.0,0.0008473471516099595\n3.0,275.0,0.00043996871333594055\n3.0,280.0,0.0005540346760526658\n3.0,285.0,0.0006681006387693911\n3.0,290.0,0.0006192152261765089\n3.0,295.0,0.0006029200886455481\n3.0,300.0,0.0006029200886455481\n3.0,305.0,0.0004725589883978621\n3.0,310.0,0.0006355103637074697\n3.0,315.0,0.0006681006387693911\n3.0,320.0,0.0006192152261765089\n3.0,325.0,0.0005051492634597836\n3.0,330.0,0.0007006909138313126\n3.0,335.0,0.0006681006387693911\n3.0,340.0,0.0009125277017338026\n3.0,345.0,0.0007658714639551558\n3.0,350.0,0.0006518055012384304\n3.0,355.0,0.0007169860513622733\n4.0,0.0,0.0008310520140789988\n4.0,5.0,0.0009125277017338026\n4.0,10.0,0.000749576326424195\n4.0,15.0,0.00149915265284839\n4.0,20.0,0.0013199061400078218\n4.0,25.0,0.0008962325642028418\n4.0,30.0,0.001352496415069743\n4.0,35.0,0.0012547255898839786\n4.0,40.0,0.0011080693521053318\n4.0,45.0,0.0010102985269195672\n4.0,50.0,0.0011243644896362925\n4.0,55.0,0.0010754790770434101\n4.0,60.0,0.0011243644896362925\n4.0,65.0,0.0013036110024768608\n4.0,70.0,0.0010265936644505277\n4.0,75.0,0.001482857515317429\n4.0,80.0,0.0008636422891409203\n4.0,85.0,0.000896232564202842\n4.0,90.0,0.0010102985269195672\n4.0,95.0,0.0008962325642028418\n4.0,100.0,0.0008636422891409203\n4.0,105.0,0.0008799374266718811\n4.0,110.0,0.0009451179767957243\n4.0,115.0,0.0014502672402555079\n4.0,120.0,0.0012710207274149394\n4.0,125.0,0.001222135314822057\n4.0,130.0,0.001222135314822057\n4.0,135.0,0.0010102985269195672\n4.0,140.0,0.0014013818276626254\n4.0,145.0,0.0012384304523530179\n4.0,150.0,0.0012384304523530179\n4.0,155.0,0.0013362012775387823\n4.0,160.0,0.001482857515317429\n4.0,165.0,0.002167253291617781\n4.0,170.0,0.0015480380654412723\n4.0,175.0,0.0014176769651935864\n4.0,180.0,0.0014176769651935862\n4.0,185.0,0.0014665623777864686\n4.0,190.0,0.0012058401772910964\n4.0,195.0,0.001156954764698214\n4.0,200.0,0.0011569547646982138\n4.0,205.0,0.0013362012775387825\n4.0,210.0,0.0010102985269195672\n4.0,215.0,0.001156954764698214\n4.0,220.0,0.0007984617390170772\n4.0,225.0,0.0009940033893886065\n4.0,230.0,0.000749576326424195\n4.0,235.0,0.0009777082518576457\n4.0,240.0,0.0006681006387693911\n4.0,245.0,0.0007658714639551558\n4.0,250.0,0.0007006909138313126\n4.0,255.0,0.0008799374266718811\n4.0,260.0,0.0007169860513622733\n4.0,265.0,0.0007332811888932342\n4.0,270.0,0.000945117976795724\n4.0,275.0,0.000684395776300352\n4.0,280.0,0.0004888541259288229\n4.0,285.0,0.0005866249511145874\n4.0,290.0,0.0004562638508669013\n4.0,295.0,0.0005051492634597835\n4.0,300.0,0.0008473471516099595\n4.0,305.0,0.0005866249511145875\n4.0,310.0,0.0006518055012384304\n4.0,315.0,0.0007658714639551558\n4.0,320.0,0.0006029200886455481\n4.0,325.0,0.0009125277017338026\n4.0,330.0,0.0010754790770434101\n4.0,335.0,0.0008310520140789988\n4.0,340.0,0.0010428888019814887\n4.0,345.0,0.0007658714639551558\n4.0,350.0,0.0011243644896362925\n4.0,355.0,0.0008799374266718811\n5.0,0.0,0.0011080693521053318\n5.0,5.0,0.0012547255898839784\n5.0,10.0,0.001433972102724547\n5.0,15.0,0.0012710207274149394\n5.0,20.0,0.0013036110024768608\n5.0,25.0,0.0014502672402555076\n5.0,30.0,0.0012058401772910962\n5.0,35.0,0.0013362012775387823\n5.0,40.0,0.001368791552600704\n5.0,45.0,0.0011080693521053318\n5.0,50.0,0.0013524964150697432\n5.0,55.0,0.001091774214574371\n5.0,60.0,0.0013199061400078216\n5.0,65.0,0.0014502672402555076\n5.0,70.0,0.0010102985269195672\n5.0,75.0,0.001368791552600704\n5.0,80.0,0.0012873158649459\n5.0,85.0,0.001222135314822057\n5.0,90.0,0.000945117976795724\n5.0,95.0,0.0011406596271672533\n5.0,100.0,0.0011732499022291747\n5.0,105.0,0.001368791552600704\n5.0,110.0,0.0011895450397601355\n5.0,115.0,0.0013524964150697432\n5.0,120.0,0.0011732499022291747\n5.0,125.0,0.0014339721027245471\n5.0,130.0,0.0014013818276626254\n5.0,135.0,0.001482857515317429\n5.0,140.0,0.0014502672402555079\n5.0,145.0,0.0014502672402555079\n5.0,150.0,0.0019554165037152915\n5.0,155.0,0.0017272845782818405\n5.0,160.0,0.001776169990874723\n5.0,165.0,0.0019554165037152915\n5.0,170.0,0.0022976143918654675\n5.0,175.0,0.0018413505409985659\n5.0,180.0,0.0017435797158128017\n5.0,185.0,0.0018739408160604876\n5.0,190.0,0.0015643332029722332\n5.0,195.0,0.0017924651284056837\n5.0,200.0,0.0014502672402555076\n5.0,205.0,0.0014176769651935862\n5.0,210.0,0.0012547255898839786\n5.0,215.0,0.0009940033893886062\n5.0,220.0,0.0010591839395124494\n5.0,225.0,0.0009777082518576457\n5.0,230.0,0.000945117976795724\n5.0,235.0,0.000961413114326685\n5.0,240.0,0.000814756876548038\n5.0,245.0,0.000814756876548038\n5.0,250.0,0.0006192152261765089\n5.0,255.0,0.0006518055012384304\n5.0,260.0,0.0005866249511145875\n5.0,265.0,0.00043996871333594055\n5.0,270.0,0.0007332811888932343\n5.0,275.0,0.0006192152261765089\n5.0,280.0,0.000749576326424195\n5.0,285.0,0.000749576326424195\n5.0,290.0,0.0006192152261765089\n5.0,295.0,0.0007658714639551557\n5.0,300.0,0.0007169860513622735\n5.0,305.0,0.0007984617390170772\n5.0,310.0,0.0006681006387693911\n5.0,315.0,0.0007658714639551558\n5.0,320.0,0.0006843957763003519\n5.0,325.0,0.0010102985269195672\n5.0,330.0,0.0009125277017338026\n5.0,335.0,0.0009451179767957242\n5.0,340.0,0.0009451179767957243\n5.0,345.0,0.0012547255898839786\n5.0,350.0,0.0010754790770434101\n5.0,355.0,0.0012384304523530177\n6.0,0.0,0.001352496415069743\n6.0,5.0,0.00149915265284839\n6.0,10.0,0.0015480380654412723\n6.0,15.0,0.0014828575153174295\n6.0,20.0,0.0012873158649458999\n6.0,25.0,0.0011243644896362925\n6.0,30.0,0.0012710207274149394\n6.0,35.0,0.0014665623777864684\n6.0,40.0,0.0009777082518576457\n6.0,45.0,0.0012384304523530177\n6.0,50.0,0.0010754790770434101\n6.0,55.0,0.0011732499022291747\n6.0,60.0,0.0013036110024768608\n6.0,65.0,0.0010591839395124494\n6.0,70.0,0.0011243644896362925\n6.0,75.0,0.0010428888019814887\n6.0,80.0,0.0013036110024768608\n6.0,85.0,0.0008636422891409203\n6.0,90.0,0.0009777082518576457\n6.0,95.0,0.0007821666014861164\n6.0,100.0,0.0010917742145743709\n6.0,105.0,0.0010102985269195672\n6.0,110.0,0.0013362012775387823\n6.0,115.0,0.0009777082518576457\n6.0,120.0,0.0012873158649459\n6.0,125.0,0.0012547255898839786\n6.0,130.0,0.0012058401772910964\n6.0,135.0,0.0016295137530960761\n6.0,140.0,0.0016783991656889583\n6.0,145.0,0.0014176769651935862\n6.0,150.0,0.001825055403467605\n6.0,155.0,0.0018087602659366446\n6.0,160.0,0.0024931560422369967\n6.0,165.0,0.002721287967670447\n6.0,170.0,0.002656107417546604\n6.0,175.0,0.0021998435666797027\n6.0,180.0,0.0021020727414939383\n6.0,185.0,0.0020368921913700953\n6.0,190.0,0.0018413505409985659\n6.0,195.0,0.0015154477903793506\n6.0,200.0,0.0017598748533437622\n6.0,205.0,0.0013199061400078218\n6.0,210.0,0.0015480380654412723\n6.0,215.0,0.0011243644896362925\n6.0,220.0,0.0009614131143266849\n6.0,225.0,0.001368791552600704\n6.0,230.0,0.0011243644896362925\n6.0,235.0,0.0009451179767957242\n6.0,240.0,0.0007006909138313127\n6.0,245.0,0.0007006909138313127\n6.0,250.0,0.000749576326424195\n6.0,255.0,0.0005051492634597836\n6.0,260.0,0.000602920088645548\n6.0,265.0,0.0005051492634597836\n6.0,270.0,0.0005866249511145874\n6.0,275.0,0.0007332811888932342\n6.0,280.0,0.0006681006387693911\n6.0,285.0,0.0005377395385217051\n6.0,290.0,0.0007495763264241949\n6.0,295.0,0.000749576326424195\n6.0,300.0,0.0006355103637074697\n6.0,305.0,0.0006681006387693913\n6.0,310.0,0.001026593664450528\n6.0,315.0,0.000749576326424195\n6.0,320.0,0.0011243644896362925\n6.0,325.0,0.0010754790770434103\n6.0,330.0,0.0011080693521053318\n6.0,335.0,0.0014828575153174293\n6.0,340.0,0.0011406596271672533\n6.0,345.0,0.0014502672402555079\n6.0,350.0,0.0012547255898839786\n6.0,355.0,0.0013524964150697432\n7.0,0.0,0.0014665623777864686\n7.0,5.0,0.0015806283405031937\n7.0,10.0,0.0020205970538391344\n7.0,15.0,0.00149915265284839\n7.0,20.0,0.0014339721027245471\n7.0,25.0,0.0012873158649459\n7.0,30.0,0.0012547255898839786\n7.0,35.0,0.0011080693521053318\n7.0,40.0,0.001026593664450528\n7.0,45.0,0.0010754790770434103\n7.0,50.0,0.0010102985269195672\n7.0,55.0,0.0010102985269195672\n7.0,60.0,0.0013362012775387823\n7.0,65.0,0.0013850866901316647\n7.0,70.0,0.0012710207274149394\n7.0,75.0,0.001156954764698214\n7.0,80.0,0.0012058401772910964\n7.0,85.0,0.0010428888019814887\n7.0,90.0,0.0008636422891409203\n7.0,95.0,0.0007984617390170772\n7.0,100.0,0.0011895450397601355\n7.0,105.0,0.0008473471516099595\n7.0,110.0,0.0012221353148220572\n7.0,115.0,0.0011895450397601355\n7.0,120.0,0.0014665623777864686\n7.0,125.0,0.0013850866901316647\n7.0,130.0,0.0013362012775387823\n7.0,135.0,0.0016621040281579976\n7.0,140.0,0.001906531091122409\n7.0,145.0,0.0020205970538391344\n7.0,150.0,0.0016295137530960761\n7.0,155.0,0.0019554165037152915\n7.0,160.0,0.0024279754921131534\n7.0,165.0,0.002607222004953722\n7.0,170.0,0.0025583365923608397\n7.0,175.0,0.0024442706296441143\n7.0,180.0,0.0019391213661843305\n7.0,185.0,0.0019554165037152915\n7.0,190.0,0.002265024116803546\n7.0,195.0,0.0019554165037152915\n7.0,200.0,0.0011895450397601355\n7.0,205.0,0.0012221353148220572\n7.0,210.0,0.0011406596271672533\n7.0,215.0,0.0012058401772910962\n7.0,220.0,0.0012547255898839786\n7.0,225.0,0.0009451179767957242\n7.0,230.0,0.0006192152261765089\n7.0,235.0,0.0005703298135836266\n7.0,240.0,0.0005866249511145875\n7.0,245.0,0.0007332811888932342\n7.0,250.0,0.0005214444009907443\n7.0,255.0,0.0005540346760526659\n7.0,260.0,0.0006192152261765088\n7.0,265.0,0.0006192152261765089\n7.0,270.0,0.0004725589883978621\n7.0,275.0,0.0004725589883978621\n7.0,280.0,0.0006355103637074697\n7.0,285.0,0.0006843957763003519\n7.0,290.0,0.0005051492634597836\n7.0,295.0,0.0005051492634597836\n7.0,300.0,0.0007984617390170773\n7.0,305.0,0.000814756876548038\n7.0,310.0,0.0006192152261765088\n7.0,315.0,0.0006681006387693911\n7.0,320.0,0.0008636422891409204\n7.0,325.0,0.0012384304523530179\n7.0,330.0,0.0016783991656889583\n7.0,335.0,0.0011895450397601355\n7.0,340.0,0.0011569547646982142\n7.0,345.0,0.001156954764698214\n7.0,350.0,0.0016132186155651154\n7.0,355.0,0.0015480380654412723\n8.0,0.0,0.0020857776039629773\n8.0,5.0,0.0018250554034676054\n8.0,10.0,0.0019391213661843305\n8.0,15.0,0.001433972102724547\n8.0,20.0,0.0012058401772910964\n8.0,25.0,0.0012873158649459003\n8.0,30.0,0.001482857515317429\n8.0,35.0,0.0012710207274149396\n8.0,40.0,0.0011243644896362925\n8.0,45.0,0.0010917742145743709\n8.0,50.0,0.0012384304523530179\n8.0,55.0,0.0009451179767957242\n8.0,60.0,0.001156954764698214\n8.0,65.0,0.0010917742145743709\n8.0,70.0,0.0010591839395124496\n8.0,75.0,0.0008799374266718811\n8.0,80.0,0.0007658714639551558\n8.0,85.0,0.0008310520140789988\n8.0,90.0,0.0007332811888932343\n8.0,95.0,0.0008636422891409204\n8.0,100.0,0.0007658714639551558\n8.0,105.0,0.000945117976795724\n8.0,110.0,0.0009125277017338026\n8.0,115.0,0.0009125277017338026\n8.0,120.0,0.0010591839395124494\n8.0,125.0,0.0009940033893886065\n8.0,130.0,0.0014502672402555076\n8.0,135.0,0.00149915265284839\n8.0,140.0,0.0017435797158128013\n8.0,145.0,0.0018087602659366446\n8.0,150.0,0.002053187328901056\n8.0,155.0,0.0022813192543345065\n8.0,160.0,0.0025583365923608397\n8.0,165.0,0.0024279754921131534\n8.0,170.0,0.002672402555077565\n8.0,175.0,0.0025746317298918\n8.0,180.0,0.0027212879676704474\n8.0,185.0,0.0023464998044583495\n8.0,190.0,0.0029168296180419762\n8.0,195.0,0.0017109894407508798\n8.0,200.0,0.0014502672402555079\n8.0,205.0,0.0016132186155651152\n8.0,210.0,0.0013362012775387823\n8.0,215.0,0.0010591839395124494\n8.0,220.0,0.0011406596271672533\n8.0,225.0,0.0006029200886455482\n8.0,230.0,0.0006192152261765089\n8.0,235.0,0.0004236735758049798\n8.0,240.0,0.0006192152261765089\n8.0,245.0,0.0006518055012384304\n8.0,250.0,0.0004888541259288229\n8.0,255.0,0.0007169860513622736\n8.0,260.0,0.0005377395385217052\n8.0,265.0,0.0005866249511145874\n8.0,270.0,0.0003096076130882544\n8.0,275.0,0.0003747881632120975\n8.0,280.0,0.0005051492634597836\n8.0,285.0,0.00047255898839786213\n8.0,290.0,0.000684395776300352\n8.0,295.0,0.0007495763264241949\n8.0,300.0,0.0005703298135836266\n8.0,305.0,0.0006029200886455482\n8.0,310.0,0.0008473471516099594\n8.0,315.0,0.000749576326424195\n8.0,320.0,0.0009288228392647633\n8.0,325.0,0.0012384304523530177\n8.0,330.0,0.0011895450397601355\n8.0,335.0,0.0012873158649459\n8.0,340.0,0.0016132186155651152\n8.0,345.0,0.0014991526528483898\n8.0,350.0,0.0018739408160604876\n8.0,355.0,0.0017761699908747227\n9.0,0.0,0.0019228262286533698\n9.0,5.0,0.001857645678529527\n9.0,10.0,0.0018250554034676052\n9.0,15.0,0.001694694303219919\n9.0,20.0,0.0014339721027245471\n9.0,25.0,0.0015154477903793506\n9.0,30.0,0.0011406596271672533\n9.0,35.0,0.0012710207274149394\n9.0,40.0,0.0010102985269195672\n9.0,45.0,0.0009777082518576457\n9.0,50.0,0.0010428888019814887\n9.0,55.0,0.0006029200886455481\n9.0,60.0,0.0008636422891409203\n9.0,65.0,0.0006843957763003519\n9.0,70.0,0.0006355103637074697\n9.0,75.0,0.0008962325642028418\n9.0,80.0,0.0010917742145743709\n9.0,85.0,0.0008310520140789989\n9.0,90.0,0.0007006909138313127\n9.0,95.0,0.0006518055012384304\n9.0,100.0,0.0006681006387693911\n9.0,105.0,0.0007332811888932342\n9.0,110.0,0.0008310520140789988\n9.0,115.0,0.0009288228392647633\n9.0,120.0,0.0008636422891409203\n9.0,125.0,0.0012221353148220572\n9.0,130.0,0.001091774214574371\n9.0,135.0,0.0014013818276626257\n9.0,140.0,0.0014991526528483898\n9.0,145.0,0.0017761699908747232\n9.0,150.0,0.0017272845782818408\n9.0,155.0,0.0022976143918654675\n9.0,160.0,0.002395385217051232\n9.0,165.0,0.002753878242732369\n9.0,170.0,0.0025909268674227616\n9.0,175.0,0.0030308955807587016\n9.0,180.0,0.002395385217051232\n9.0,185.0,0.002167253291617781\n9.0,190.0,0.0025257463172989178\n9.0,195.0,0.0022324338417416246\n9.0,200.0,0.001564333202972233\n9.0,205.0,0.0012547255898839786\n9.0,210.0,0.001156954764698214\n9.0,215.0,0.0010428888019814887\n9.0,220.0,0.0008799374266718811\n9.0,225.0,0.0008310520140789988\n9.0,230.0,0.0004888541259288229\n9.0,235.0,0.0005214444009907443\n9.0,240.0,0.00026072220049537216\n9.0,245.0,0.0006029200886455481\n9.0,250.0,0.0005377395385217051\n9.0,255.0,0.0004725589883978621\n9.0,260.0,0.0004236735758049798\n9.0,265.0,0.00043996871333594055\n9.0,270.0,0.00030960761308825447\n9.0,275.0,0.0003747881632120975\n9.0,280.0,0.0004725589883978621\n9.0,285.0,0.0005866249511145874\n9.0,290.0,0.00030960761308825447\n9.0,295.0,0.0007821666014861165\n9.0,300.0,0.0007006909138313126\n9.0,305.0,0.0007332811888932343\n9.0,310.0,0.0006843957763003519\n9.0,315.0,0.001026593664450528\n9.0,320.0,0.001515447790379351\n9.0,325.0,0.0017598748533437622\n9.0,330.0,0.0016458088906270369\n9.0,335.0,0.0016458088906270369\n9.0,340.0,0.0015154477903793508\n9.0,345.0,0.001971711641246252\n9.0,350.0,0.0021509581540868207\n9.0,355.0,0.002183548429148742\n10.0,0.0,0.0021020727414939383\n10.0,5.0,0.002053187328901056\n10.0,10.0,0.0016783991656889586\n10.0,15.0,0.0019065310911224093\n10.0,20.0,0.001580628340503194\n10.0,25.0,0.0012384304523530179\n10.0,30.0,0.0015480380654412723\n10.0,35.0,0.0011080693521053318\n10.0,40.0,0.0008310520140789988\n10.0,45.0,0.0008473471516099595\n10.0,50.0,0.0005540346760526658\n10.0,55.0,0.0007332811888932343\n10.0,60.0,0.0009940033893886062\n10.0,65.0,0.0006518055012384304\n10.0,70.0,0.0005540346760526659\n10.0,75.0,0.0006843957763003519\n10.0,80.0,0.0006192152261765089\n10.0,85.0,0.0008147568765480381\n10.0,90.0,0.0004236735758049797\n10.0,95.0,0.0007821666014861165\n10.0,100.0,0.0005377395385217052\n10.0,105.0,0.0005703298135836266\n10.0,110.0,0.0009940033893886062\n10.0,115.0,0.000684395776300352\n10.0,120.0,0.0007332811888932342\n10.0,125.0,0.000945117976795724\n10.0,130.0,0.0010428888019814887\n10.0,135.0,0.00149915265284839\n10.0,140.0,0.0014339721027245467\n10.0,145.0,0.0017435797158128015\n10.0,150.0,0.001482857515317429\n10.0,155.0,0.0017598748533437622\n10.0,160.0,0.002460565767175075\n10.0,165.0,0.0027701733802633294\n10.0,170.0,0.003275322643723113\n10.0,175.0,0.003047190718289662\n10.0,180.0,0.003128666405944466\n10.0,185.0,0.002933124755572937\n10.0,190.0,0.0024768609047060358\n10.0,195.0,0.0017109894407508798\n10.0,200.0,0.0014339721027245471\n10.0,205.0,0.0012058401772910962\n10.0,210.0,0.0010591839395124494\n10.0,215.0,0.0012058401772910964\n10.0,220.0,0.0006518055012384304\n10.0,225.0,0.00043996871333594055\n10.0,230.0,0.00047255898839786213\n10.0,235.0,0.0004725589883978621\n10.0,240.0,0.0003584930256811367\n10.0,245.0,0.0003584930256811368\n10.0,250.0,0.0004073784382740191\n10.0,255.0,0.0005540346760526658\n10.0,260.0,0.0004236735758049798\n10.0,265.0,0.00034219788815017594\n10.0,270.0,0.00029331247555729374\n10.0,275.0,0.0005866249511145874\n10.0,280.0,0.0007821666014861165\n10.0,285.0,0.00043996871333594045\n10.0,290.0,0.0006355103637074697\n10.0,295.0,0.0006192152261765089\n10.0,300.0,0.0005703298135836266\n10.0,305.0,0.0006681006387693913\n10.0,310.0,0.0008310520140789988\n10.0,315.0,0.0010102985269195672\n10.0,320.0,0.0012873158649459\n10.0,325.0,0.001368791552600704\n10.0,330.0,0.0018250554034676052\n10.0,335.0,0.002167253291617781\n10.0,340.0,0.0020205970538391344\n10.0,345.0,0.0019228262286533698\n10.0,350.0,0.0021346630165558597\n10.0,355.0,0.0020857776039629778\n11.0,0.0,0.0017598748533437622\n11.0,5.0,0.002053187328901056\n11.0,10.0,0.0016783991656889583\n11.0,15.0,0.0014013818276626252\n11.0,20.0,0.001303611002476861\n11.0,25.0,0.0011080693521053318\n11.0,30.0,0.0012058401772910962\n11.0,35.0,0.0009777082518576457\n11.0,40.0,0.0009777082518576457\n11.0,45.0,0.0007658714639551558\n11.0,50.0,0.0006518055012384304\n11.0,55.0,0.0005540346760526659\n11.0,60.0,0.00047255898839786213\n11.0,65.0,0.0004888541259288228\n11.0,70.0,0.00030960761308825447\n11.0,75.0,0.00045626385086690123\n11.0,80.0,0.00030960761308825447\n11.0,85.0,0.00043996871333594055\n11.0,90.0,0.00043996871333594055\n11.0,95.0,0.0003584930256811367\n11.0,100.0,0.00030960761308825447\n11.0,105.0,0.0006518055012384304\n11.0,110.0,0.0005866249511145874\n11.0,115.0,0.0003747881632120975\n11.0,120.0,0.0007006909138313127\n11.0,125.0,0.0007006909138313127\n11.0,130.0,0.0009288228392647634\n11.0,135.0,0.0011732499022291747\n11.0,140.0,0.0014013818276626254\n11.0,145.0,0.0014339721027245471\n11.0,150.0,0.0015154477903793508\n11.0,155.0,0.0020043019163081734\n11.0,160.0,0.0028027636553252513\n11.0,165.0,0.00299830530569678\n11.0,170.0,0.003731586494590014\n11.0,175.0,0.0034382740190327206\n11.0,180.0,0.0029494198931038977\n11.0,185.0,0.0026398122800156435\n11.0,190.0,0.002248728979272585\n11.0,195.0,0.0018087602659366444\n11.0,200.0,0.0019717116412462524\n11.0,205.0,0.001776169990874723\n11.0,210.0,0.000945117976795724\n11.0,215.0,0.0009451179767957242\n11.0,220.0,0.0005540346760526659\n11.0,225.0,0.00043996871333594055\n11.0,230.0,0.00026072220049537216\n11.0,235.0,0.00034219788815017594\n11.0,240.0,0.0003584930256811368\n11.0,245.0,0.00021183678790248988\n11.0,250.0,0.0002770173380263329\n11.0,255.0,0.00034219788815017594\n11.0,260.0,0.00021183678790248988\n11.0,265.0,0.0002770173380263329\n11.0,270.0,0.00022813192543345064\n11.0,275.0,0.00042367357580497977\n11.0,280.0,0.0005051492634597836\n11.0,285.0,0.0005866249511145874\n11.0,290.0,0.0007006909138313127\n11.0,295.0,0.0007169860513622735\n11.0,300.0,0.0005540346760526658\n11.0,305.0,0.0009288228392647633\n11.0,310.0,0.0007821666014861166\n11.0,315.0,0.0012547255898839786\n11.0,320.0,0.0012873158649459\n11.0,325.0,0.0014502672402555076\n11.0,330.0,0.0019554165037152915\n11.0,335.0,0.0020368921913700953\n11.0,340.0,0.001988006778777213\n11.0,345.0,0.0019391213661843307\n11.0,350.0,0.0017761699908747227\n11.0,355.0,0.0020043019163081734\n12.0,0.0,0.0016458088906270369\n12.0,5.0,0.0015969234780341547\n12.0,10.0,0.0013036110024768608\n12.0,15.0,0.00149915265284839\n12.0,20.0,0.0013524964150697432\n12.0,25.0,0.0009125277017338027\n12.0,30.0,0.0007821666014861165\n12.0,35.0,0.0005540346760526659\n12.0,40.0,0.0006355103637074697\n12.0,45.0,0.0006355103637074697\n12.0,50.0,0.00037478816321209746\n12.0,55.0,0.0004725589883978621\n12.0,60.0,0.0003096076130882544\n12.0,65.0,0.0003584930256811367\n12.0,70.0,0.0002933124755572937\n12.0,75.0,0.00017924651284056836\n12.0,80.0,0.00030960761308825447\n12.0,85.0,0.00029331247555729374\n12.0,90.0,0.00026072220049537216\n12.0,95.0,0.00024442706296441143\n12.0,100.0,0.00039108330074305825\n12.0,105.0,0.0004562638508669013\n12.0,110.0,0.0003584930256811368\n12.0,115.0,0.00043996871333594055\n12.0,120.0,0.00039108330074305825\n12.0,125.0,0.0005866249511145874\n12.0,130.0,0.0007169860513622736\n12.0,135.0,0.0007984617390170773\n12.0,140.0,0.001156954764698214\n12.0,145.0,0.001580628340503194\n12.0,150.0,0.0018250554034676054\n12.0,155.0,0.0023627949419893104\n12.0,160.0,0.0025420414548298787\n12.0,165.0,0.003340503193846956\n12.0,170.0,0.003275322643723113\n12.0,175.0,0.00321014209359927\n12.0,180.0,0.0027701733802633294\n12.0,185.0,0.0026398122800156435\n12.0,190.0,0.0022976143918654675\n12.0,195.0,0.0020205970538391344\n12.0,200.0,0.0014828575153174293\n12.0,205.0,0.0010754790770434101\n12.0,210.0,0.0009125277017338027\n12.0,215.0,0.0003910833007430583\n12.0,220.0,0.0003096076130882544\n12.0,225.0,0.00030960761308825447\n12.0,230.0,0.00022813192543345064\n12.0,235.0,0.00030960761308825447\n12.0,240.0,0.00014665623777864684\n12.0,245.0,0.00019554165037152912\n12.0,250.0,0.00022813192543345064\n12.0,255.0,0.00022813192543345064\n12.0,260.0,0.00014665623777864684\n12.0,265.0,0.00024442706296441143\n12.0,270.0,0.00019554165037152912\n12.0,275.0,0.0002770173380263329\n12.0,280.0,0.0003584930256811368\n12.0,285.0,0.0004562638508669013\n12.0,290.0,0.0005703298135836266\n12.0,295.0,0.0005214444009907443\n12.0,300.0,0.0005540346760526658\n12.0,305.0,0.0009288228392647633\n12.0,310.0,0.0010102985269195672\n12.0,315.0,0.001091774214574371\n12.0,320.0,0.0010102985269195672\n12.0,325.0,0.0015969234780341545\n12.0,330.0,0.001433972102724547\n12.0,335.0,0.0018087602659366444\n12.0,340.0,0.0016132186155651154\n12.0,345.0,0.0018739408160604876\n12.0,350.0,0.0018250554034676052\n12.0,355.0,0.0016783991656889583\n13.0,0.0,0.0012873158649459003\n13.0,5.0,0.0013036110024768608\n13.0,10.0,0.0012710207274149394\n13.0,15.0,0.0012873158649459003\n13.0,20.0,0.0009940033893886065\n13.0,25.0,0.0009125277017338026\n13.0,30.0,0.0004236735758049798\n13.0,35.0,0.000472558988397862\n13.0,40.0,0.0003747881632120975\n13.0,45.0,0.00030960761308825447\n13.0,50.0,0.00026072220049537216\n13.0,55.0,0.00026072220049537216\n13.0,60.0,0.0003584930256811368\n13.0,65.0,0.00013036110024768608\n13.0,70.0,0.00014665623777864684\n13.0,75.0,0.00022813192543345064\n13.0,80.0,0.00013036110024768608\n13.0,85.0,9.777082518576456e-05\n13.0,90.0,0.00013036110024768608\n13.0,95.0,0.00011406596271672532\n13.0,100.0,0.00026072220049537216\n13.0,105.0,0.00017924651284056836\n13.0,110.0,0.00030960761308825447\n13.0,115.0,0.00039108330074305825\n13.0,120.0,0.0002770173380263329\n13.0,125.0,0.000342197888150176\n13.0,130.0,0.00039108330074305825\n13.0,135.0,0.0007169860513622736\n13.0,140.0,0.0009288228392647633\n13.0,145.0,0.0010754790770434103\n13.0,150.0,0.0016132186155651154\n13.0,155.0,0.0020205970538391344\n13.0,160.0,0.0021346630165558593\n13.0,165.0,0.0030471907182896625\n13.0,170.0,0.003079780993351584\n13.0,175.0,0.0031123712684135055\n13.0,180.0,0.00236279494198931\n13.0,185.0,0.002167253291617781\n13.0,190.0,0.0017761699908747232\n13.0,195.0,0.0012221353148220572\n13.0,200.0,0.0005214444009907443\n13.0,205.0,0.000407378438274019\n13.0,210.0,0.0003259027506192152\n13.0,215.0,0.00030960761308825447\n13.0,220.0,0.00011406596271672532\n13.0,225.0,0.00014665623777864684\n13.0,230.0,0.00021183678790248988\n13.0,235.0,0.00013036110024768608\n13.0,240.0,0.00017924651284056836\n13.0,245.0,0.00019554165037152912\n13.0,250.0,6.518055012384304e-05\n13.0,255.0,9.777082518576456e-05\n13.0,260.0,0.00014665623777864684\n13.0,265.0,8.14756876548038e-05\n13.0,270.0,0.00013036110024768608\n13.0,275.0,0.00014665623777864684\n13.0,280.0,0.00030960761308825447\n13.0,285.0,0.0003259027506192152\n13.0,290.0,0.0005214444009907443\n13.0,295.0,0.0006843957763003519\n13.0,300.0,0.0006518055012384305\n13.0,305.0,0.0007821666014861166\n13.0,310.0,0.0009125277017338026\n13.0,315.0,0.0008473471516099595\n13.0,320.0,0.0009288228392647634\n13.0,325.0,0.0013850866901316647\n13.0,330.0,0.0014828575153174293\n13.0,335.0,0.0016783991656889586\n13.0,340.0,0.0013850866901316647\n13.0,345.0,0.001433972102724547\n13.0,350.0,0.0013850866901316647\n13.0,355.0,0.0014013818276626257\n14.0,0.0,0.0006192152261765089\n14.0,5.0,0.0007658714639551558\n14.0,10.0,0.0007984617390170772\n14.0,15.0,0.0006843957763003519\n14.0,20.0,0.0007169860513622736\n14.0,25.0,0.0004562638508669013\n14.0,30.0,0.0003259027506192152\n14.0,35.0,0.0003259027506192152\n14.0,40.0,0.00027701733802633295\n14.0,45.0,0.00017924651284056836\n14.0,50.0,9.777082518576456e-05\n14.0,55.0,6.518055012384304e-05\n14.0,60.0,0.00013036110024768608\n14.0,65.0,3.259027506192152e-05\n14.0,70.0,4.888541259288228e-05\n14.0,75.0,8.14756876548038e-05\n14.0,80.0,4.888541259288228e-05\n14.0,85.0,3.259027506192152e-05\n14.0,90.0,3.259027506192152e-05\n14.0,95.0,8.14756876548038e-05\n14.0,100.0,8.14756876548038e-05\n14.0,105.0,0.00014665623777864684\n14.0,110.0,8.14756876548038e-05\n14.0,115.0,0.00013036110024768608\n14.0,120.0,8.14756876548038e-05\n14.0,125.0,0.00017924651284056836\n14.0,130.0,0.00039108330074305825\n14.0,135.0,0.00034219788815017594\n14.0,140.0,0.0004888541259288229\n14.0,145.0,0.0005540346760526659\n14.0,150.0,0.0005540346760526659\n14.0,155.0,0.0009614131143266848\n14.0,160.0,0.0017435797158128013\n14.0,165.0,0.001792465128405684\n14.0,170.0,0.0023627949419893104\n14.0,175.0,0.0018739408160604876\n14.0,180.0,0.0017109894407508798\n14.0,185.0,0.0010428888019814887\n14.0,190.0,0.0006681006387693913\n14.0,195.0,0.0002770173380263329\n14.0,200.0,0.00021183678790248988\n14.0,205.0,0.00017924651284056836\n14.0,210.0,0.00017924651284056836\n14.0,215.0,9.777082518576456e-05\n14.0,220.0,4.888541259288228e-05\n14.0,225.0,1.629513753096076e-05\n14.0,230.0,0.0\n14.0,235.0,0.0\n14.0,240.0,3.259027506192152e-05\n14.0,245.0,0.00013036110024768608\n14.0,250.0,3.259027506192152e-05\n14.0,255.0,4.888541259288228e-05\n14.0,260.0,4.888541259288228e-05\n14.0,265.0,4.888541259288228e-05\n14.0,270.0,1.629513753096076e-05\n14.0,275.0,0.00013036110024768608\n14.0,280.0,9.777082518576456e-05\n14.0,285.0,0.00024442706296441143\n14.0,290.0,0.00014665623777864684\n14.0,295.0,0.0003910833007430583\n14.0,300.0,0.000472558988397862\n14.0,305.0,0.0006192152261765089\n14.0,310.0,0.0005377395385217051\n14.0,315.0,0.0005866249511145874\n14.0,320.0,0.0007658714639551557\n14.0,325.0,0.0010591839395124494\n14.0,330.0,0.0012384304523530179\n14.0,335.0,0.0010754790770434103\n14.0,340.0,0.0008147568765480381\n14.0,345.0,0.0008473471516099596\n14.0,350.0,0.0008310520140789988\n14.0,355.0,0.0009777082518576457\n15.0,0.0,0.000472558988397862\n15.0,5.0,0.000342197888150176\n15.0,10.0,0.0004888541259288229\n15.0,15.0,0.0002770173380263329\n15.0,20.0,0.00027701733802633295\n15.0,25.0,0.00030960761308825447\n15.0,30.0,0.00019554165037152912\n15.0,35.0,9.777082518576456e-05\n15.0,40.0,6.518055012384304e-05\n15.0,45.0,9.777082518576456e-05\n15.0,50.0,6.518055012384304e-05\n15.0,55.0,4.888541259288228e-05\n15.0,60.0,1.629513753096076e-05\n15.0,65.0,3.259027506192152e-05\n15.0,70.0,4.888541259288228e-05\n15.0,75.0,1.629513753096076e-05\n15.0,80.0,8.14756876548038e-05\n15.0,85.0,6.518055012384304e-05\n15.0,90.0,1.629513753096076e-05\n15.0,95.0,3.259027506192152e-05\n15.0,100.0,0.0\n15.0,105.0,8.14756876548038e-05\n15.0,110.0,1.629513753096076e-05\n15.0,115.0,8.14756876548038e-05\n15.0,120.0,4.888541259288228e-05\n15.0,125.0,1.629513753096076e-05\n15.0,130.0,0.00027701733802633295\n15.0,135.0,0.00014665623777864684\n15.0,140.0,0.00024442706296441143\n15.0,145.0,0.0001629513753096076\n15.0,150.0,0.00027701733802633295\n15.0,155.0,0.00034219788815017594\n15.0,160.0,0.0007169860513622733\n15.0,165.0,0.0009288228392647633\n15.0,170.0,0.0012873158649459003\n15.0,175.0,0.0008636422891409203\n15.0,180.0,0.0007006909138313127\n15.0,185.0,0.00040737843827401903\n15.0,190.0,0.00024442706296441143\n15.0,195.0,8.14756876548038e-05\n15.0,200.0,4.888541259288228e-05\n15.0,205.0,1.629513753096076e-05\n15.0,210.0,3.259027506192152e-05\n15.0,215.0,1.629513753096076e-05\n15.0,220.0,0.0\n15.0,225.0,4.888541259288228e-05\n15.0,230.0,3.259027506192152e-05\n15.0,235.0,1.629513753096076e-05\n15.0,240.0,0.0\n15.0,245.0,1.629513753096076e-05\n15.0,250.0,0.0\n15.0,255.0,0.0\n15.0,260.0,1.629513753096076e-05\n15.0,265.0,3.259027506192152e-05\n15.0,270.0,0.0\n15.0,275.0,1.629513753096076e-05\n15.0,280.0,4.888541259288228e-05\n15.0,285.0,6.518055012384304e-05\n15.0,290.0,0.00013036110024768608\n15.0,295.0,0.00022813192543345064\n15.0,300.0,0.00035849302568113667\n15.0,305.0,0.0005377395385217051\n15.0,310.0,0.00042367357580497977\n15.0,315.0,0.0005377395385217051\n15.0,320.0,0.0005703298135836265\n15.0,325.0,0.0007495763264241949\n15.0,330.0,0.0006843957763003519\n15.0,335.0,0.0008147568765480381\n15.0,340.0,0.0006192152261765089\n15.0,345.0,0.0006681006387693913\n15.0,350.0,0.0007495763264241949\n15.0,355.0,0.0007006909138313128\n16.0,0.0,0.0004236735758049798\n16.0,5.0,0.00027701733802633295\n16.0,10.0,0.000342197888150176\n16.0,15.0,0.00021183678790248988\n16.0,20.0,0.000342197888150176\n16.0,25.0,0.0001629513753096076\n16.0,30.0,4.888541259288228e-05\n16.0,35.0,8.14756876548038e-05\n16.0,40.0,1.629513753096076e-05\n16.0,45.0,3.259027506192152e-05\n16.0,50.0,0.0\n16.0,55.0,1.629513753096076e-05\n16.0,60.0,1.629513753096076e-05\n16.0,65.0,0.0\n16.0,70.0,1.629513753096076e-05\n16.0,75.0,0.0\n16.0,80.0,0.0\n16.0,85.0,0.0\n16.0,90.0,0.0\n16.0,95.0,1.629513753096076e-05\n16.0,100.0,3.259027506192152e-05\n16.0,105.0,1.629513753096076e-05\n16.0,110.0,1.629513753096076e-05\n16.0,115.0,3.259027506192152e-05\n16.0,120.0,4.888541259288228e-05\n16.0,125.0,1.629513753096076e-05\n16.0,130.0,3.259027506192152e-05\n16.0,135.0,6.518055012384304e-05\n16.0,140.0,8.14756876548038e-05\n16.0,145.0,9.777082518576456e-05\n16.0,150.0,0.00013036110024768608\n16.0,155.0,0.00017924651284056836\n16.0,160.0,0.0003259027506192152\n16.0,165.0,0.0005214444009907443\n16.0,170.0,0.0006029200886455482\n16.0,175.0,0.00039108330074305825\n16.0,180.0,0.00021183678790248988\n16.0,185.0,0.00014665623777864684\n16.0,190.0,0.00014665623777864684\n16.0,195.0,6.518055012384304e-05\n16.0,200.0,1.629513753096076e-05\n16.0,205.0,0.0\n16.0,210.0,0.0\n16.0,215.0,0.0\n16.0,220.0,0.0\n16.0,225.0,0.0\n16.0,230.0,0.0\n16.0,235.0,1.629513753096076e-05\n16.0,240.0,3.259027506192152e-05\n16.0,245.0,0.0\n16.0,250.0,0.0\n16.0,255.0,3.259027506192152e-05\n16.0,260.0,1.629513753096076e-05\n16.0,265.0,1.629513753096076e-05\n16.0,270.0,3.259027506192152e-05\n16.0,275.0,0.0\n16.0,280.0,1.629513753096076e-05\n16.0,285.0,3.259027506192152e-05\n16.0,290.0,0.00011406596271672532\n16.0,295.0,0.00014665623777864684\n16.0,300.0,0.0001629513753096076\n16.0,305.0,0.0003259027506192152\n16.0,310.0,0.00019554165037152912\n16.0,315.0,0.00026072220049537216\n16.0,320.0,0.0002933124755572937\n16.0,325.0,0.00039108330074305825\n16.0,330.0,0.0005540346760526659\n16.0,335.0,0.0005051492634597836\n16.0,340.0,0.0005377395385217051\n16.0,345.0,0.00039108330074305825\n16.0,350.0,0.00042367357580497977\n16.0,355.0,0.0005540346760526659\n17.0,0.0,0.0002770173380263329\n17.0,5.0,0.00019554165037152912\n17.0,10.0,8.14756876548038e-05\n17.0,15.0,9.777082518576456e-05\n17.0,20.0,8.14756876548038e-05\n17.0,25.0,3.259027506192152e-05\n17.0,30.0,4.888541259288228e-05\n17.0,35.0,3.259027506192152e-05\n17.0,40.0,1.629513753096076e-05\n17.0,45.0,0.0\n17.0,50.0,0.0\n17.0,55.0,0.0\n17.0,60.0,0.0\n17.0,65.0,0.0\n17.0,70.0,0.0\n17.0,75.0,3.259027506192152e-05\n17.0,80.0,0.0\n17.0,85.0,0.0\n17.0,90.0,0.0\n17.0,95.0,1.629513753096076e-05\n17.0,100.0,1.629513753096076e-05\n17.0,105.0,0.0\n17.0,110.0,0.0\n17.0,115.0,4.888541259288228e-05\n17.0,120.0,0.0\n17.0,125.0,0.0\n17.0,130.0,1.629513753096076e-05\n17.0,135.0,0.0\n17.0,140.0,0.0\n17.0,145.0,0.0\n17.0,150.0,0.0\n17.0,155.0,1.629513753096076e-05\n17.0,160.0,0.00014665623777864684\n17.0,165.0,0.00022813192543345064\n17.0,170.0,0.00030960761308825447\n17.0,175.0,0.0001629513753096076\n17.0,180.0,0.00017924651284056836\n17.0,185.0,8.14756876548038e-05\n17.0,190.0,8.14756876548038e-05\n17.0,195.0,0.0\n17.0,200.0,3.259027506192152e-05\n17.0,205.0,0.0\n17.0,210.0,0.0\n17.0,215.0,0.0\n17.0,220.0,1.629513753096076e-05\n17.0,225.0,0.0\n17.0,230.0,1.629513753096076e-05\n17.0,235.0,0.0\n17.0,240.0,0.0\n17.0,245.0,0.0\n17.0,250.0,0.0\n17.0,255.0,0.0\n17.0,260.0,0.0\n17.0,265.0,0.0\n17.0,270.0,0.0\n17.0,275.0,1.629513753096076e-05\n17.0,280.0,0.0\n17.0,285.0,0.0\n17.0,290.0,3.259027506192152e-05\n17.0,295.0,0.00011406596271672532\n17.0,300.0,4.888541259288228e-05\n17.0,305.0,8.14756876548038e-05\n17.0,310.0,0.00013036110024768608\n17.0,315.0,0.00022813192543345064\n17.0,320.0,4.888541259288228e-05\n17.0,325.0,0.00017924651284056836\n17.0,330.0,0.0002770173380263329\n17.0,335.0,0.00019554165037152912\n17.0,340.0,0.00034219788815017594\n17.0,345.0,0.000472558988397862\n17.0,350.0,0.00030960761308825447\n17.0,355.0,0.00019554165037152912\n18.0,0.0,6.518055012384304e-05\n18.0,5.0,9.777082518576456e-05\n18.0,10.0,1.629513753096076e-05\n18.0,15.0,1.629513753096076e-05\n18.0,20.0,1.629513753096076e-05\n18.0,25.0,4.888541259288228e-05\n18.0,30.0,3.259027506192152e-05\n18.0,35.0,3.259027506192152e-05\n18.0,40.0,0.0\n18.0,45.0,0.0\n18.0,50.0,0.0\n18.0,55.0,0.0\n18.0,60.0,1.629513753096076e-05\n18.0,65.0,1.629513753096076e-05\n18.0,70.0,0.0\n18.0,75.0,0.0\n18.0,80.0,1.629513753096076e-05\n18.0,85.0,0.0\n18.0,90.0,0.0\n18.0,95.0,0.0\n18.0,100.0,0.0\n18.0,105.0,1.629513753096076e-05\n18.0,110.0,0.0\n18.0,115.0,0.0\n18.0,120.0,0.0\n18.0,125.0,0.0\n18.0,130.0,0.0\n18.0,135.0,0.0\n18.0,140.0,1.629513753096076e-05\n18.0,145.0,0.0\n18.0,150.0,0.0\n18.0,155.0,6.518055012384304e-05\n18.0,160.0,4.888541259288228e-05\n18.0,165.0,6.518055012384304e-05\n18.0,170.0,8.14756876548038e-05\n18.0,175.0,0.00013036110024768608\n18.0,180.0,0.00014665623777864684\n18.0,185.0,4.888541259288228e-05\n18.0,190.0,1.629513753096076e-05\n18.0,195.0,0.0\n18.0,200.0,0.0\n18.0,205.0,0.0\n18.0,210.0,1.629513753096076e-05\n18.0,215.0,0.0\n18.0,220.0,0.0\n18.0,225.0,0.0\n18.0,230.0,0.0\n18.0,235.0,0.0\n18.0,240.0,0.0\n18.0,245.0,0.0\n18.0,250.0,0.0\n18.0,255.0,0.0\n18.0,260.0,0.0\n18.0,265.0,0.0\n18.0,270.0,0.0\n18.0,275.0,0.0\n18.0,280.0,0.0\n18.0,285.0,0.0\n18.0,290.0,3.259027506192152e-05\n18.0,295.0,9.777082518576456e-05\n18.0,300.0,6.518055012384304e-05\n18.0,305.0,4.888541259288228e-05\n18.0,310.0,3.259027506192152e-05\n18.0,315.0,9.777082518576456e-05\n18.0,320.0,8.14756876548038e-05\n18.0,325.0,6.518055012384304e-05\n18.0,330.0,0.00013036110024768608\n18.0,335.0,9.777082518576456e-05\n18.0,340.0,0.00013036110024768608\n18.0,345.0,0.00017924651284056836\n18.0,350.0,0.00017924651284056836\n18.0,355.0,8.14756876548038e-05\n19.0,0.0,4.888541259288228e-05\n19.0,5.0,6.518055012384304e-05\n19.0,10.0,1.629513753096076e-05\n19.0,15.0,0.0\n19.0,20.0,0.0\n19.0,25.0,1.629513753096076e-05\n19.0,30.0,3.259027506192152e-05\n19.0,35.0,0.0\n19.0,40.0,0.0\n19.0,45.0,0.0\n19.0,50.0,0.0\n19.0,55.0,0.0\n19.0,60.0,0.0\n19.0,65.0,0.0\n19.0,70.0,0.0\n19.0,75.0,0.0\n19.0,80.0,0.0\n19.0,85.0,0.0\n19.0,90.0,0.0\n19.0,95.0,0.0\n19.0,100.0,0.0\n19.0,105.0,0.0\n19.0,110.0,0.0\n19.0,115.0,0.0\n19.0,120.0,0.0\n19.0,125.0,0.0\n19.0,130.0,0.0\n19.0,135.0,0.0\n19.0,140.0,1.629513753096076e-05\n19.0,145.0,0.0\n19.0,150.0,0.0\n19.0,155.0,0.0\n19.0,160.0,0.0\n19.0,165.0,0.0\n19.0,170.0,3.259027506192152e-05\n19.0,175.0,6.518055012384304e-05\n19.0,180.0,4.888541259288228e-05\n19.0,185.0,1.629513753096076e-05\n19.0,190.0,0.0\n19.0,195.0,1.629513753096076e-05\n19.0,200.0,0.0\n19.0,205.0,0.0\n19.0,210.0,0.0\n19.0,215.0,1.629513753096076e-05\n19.0,220.0,0.0\n19.0,225.0,0.0\n19.0,230.0,0.0\n19.0,235.0,0.0\n19.0,240.0,0.0\n19.0,245.0,0.0\n19.0,250.0,0.0\n19.0,255.0,1.629513753096076e-05\n19.0,260.0,0.0\n19.0,265.0,0.0\n19.0,270.0,0.0\n19.0,275.0,0.0\n19.0,280.0,0.0\n19.0,285.0,3.259027506192152e-05\n19.0,290.0,0.0\n19.0,295.0,1.629513753096076e-05\n19.0,300.0,4.888541259288228e-05\n19.0,305.0,0.0\n19.0,310.0,1.629513753096076e-05\n19.0,315.0,0.0\n19.0,320.0,0.0\n19.0,325.0,9.777082518576456e-05\n19.0,330.0,4.888541259288228e-05\n19.0,335.0,4.888541259288228e-05\n19.0,340.0,0.00014665623777864684\n19.0,345.0,8.14756876548038e-05\n19.0,350.0,0.00011406596271672532\n19.0,355.0,4.888541259288228e-05\n20.0,0.0,4.888541259288228e-05\n20.0,5.0,0.0\n20.0,10.0,0.0\n20.0,15.0,1.629513753096076e-05\n20.0,20.0,0.0\n20.0,25.0,0.0\n20.0,30.0,0.0\n20.0,35.0,1.629513753096076e-05\n20.0,40.0,0.0\n20.0,45.0,0.0\n20.0,50.0,0.0\n20.0,55.0,0.0\n20.0,60.0,0.0\n20.0,65.0,0.0\n20.0,70.0,0.0\n20.0,75.0,0.0\n20.0,80.0,0.0\n20.0,85.0,0.0\n20.0,90.0,0.0\n20.0,95.0,0.0\n20.0,100.0,0.0\n20.0,105.0,0.0\n20.0,110.0,1.629513753096076e-05\n20.0,115.0,0.0\n20.0,120.0,0.0\n20.0,125.0,0.0\n20.0,130.0,0.0\n20.0,135.0,0.0\n20.0,140.0,0.0\n20.0,145.0,0.0\n20.0,150.0,0.0\n20.0,155.0,0.0\n20.0,160.0,0.0\n20.0,165.0,1.629513753096076e-05\n20.0,170.0,1.629513753096076e-05\n20.0,175.0,3.259027506192152e-05\n20.0,180.0,1.629513753096076e-05\n20.0,185.0,1.629513753096076e-05\n20.0,190.0,0.0\n20.0,195.0,0.0\n20.0,200.0,0.0\n20.0,205.0,0.0\n20.0,210.0,0.0\n20.0,215.0,0.0\n20.0,220.0,0.0\n20.0,225.0,0.0\n20.0,230.0,0.0\n20.0,235.0,0.0\n20.0,240.0,1.629513753096076e-05\n20.0,245.0,0.0\n20.0,250.0,0.0\n20.0,255.0,0.0\n20.0,260.0,0.0\n20.0,265.0,0.0\n20.0,270.0,0.0\n20.0,275.0,0.0\n20.0,280.0,0.0\n20.0,285.0,1.629513753096076e-05\n20.0,290.0,0.0\n20.0,295.0,0.0\n20.0,300.0,0.0\n20.0,305.0,3.259027506192152e-05\n20.0,310.0,6.518055012384304e-05\n20.0,315.0,3.259027506192152e-05\n20.0,320.0,0.0\n20.0,325.0,0.0\n20.0,330.0,3.259027506192152e-05\n20.0,335.0,0.0\n20.0,340.0,1.629513753096076e-05\n20.0,345.0,9.777082518576456e-05\n20.0,350.0,4.888541259288228e-05\n20.0,355.0,1.629513753096076e-05\n21.0,0.0,0.0\n21.0,5.0,1.629513753096076e-05\n21.0,10.0,0.0\n21.0,15.0,0.0\n21.0,20.0,0.0\n21.0,25.0,0.0\n21.0,30.0,0.0\n21.0,35.0,0.0\n21.0,40.0,0.0\n21.0,45.0,0.0\n21.0,50.0,0.0\n21.0,55.0,0.0\n21.0,60.0,0.0\n21.0,65.0,0.0\n21.0,70.0,0.0\n21.0,75.0,0.0\n21.0,80.0,0.0\n21.0,85.0,0.0\n21.0,90.0,0.0\n21.0,95.0,0.0\n21.0,100.0,0.0\n21.0,105.0,0.0\n21.0,110.0,0.0\n21.0,115.0,0.0\n21.0,120.0,0.0\n21.0,125.0,0.0\n21.0,130.0,0.0\n21.0,135.0,0.0\n21.0,140.0,0.0\n21.0,145.0,0.0\n21.0,150.0,0.0\n21.0,155.0,0.0\n21.0,160.0,0.0\n21.0,165.0,0.0\n21.0,170.0,0.0\n21.0,175.0,1.629513753096076e-05\n21.0,180.0,0.0\n21.0,185.0,0.0\n21.0,190.0,0.0\n21.0,195.0,0.0\n21.0,200.0,0.0\n21.0,205.0,0.0\n21.0,210.0,1.629513753096076e-05\n21.0,215.0,0.0\n21.0,220.0,0.0\n21.0,225.0,0.0\n21.0,230.0,0.0\n21.0,235.0,0.0\n21.0,240.0,0.0\n21.0,245.0,0.0\n21.0,250.0,0.0\n21.0,255.0,0.0\n21.0,260.0,0.0\n21.0,265.0,1.629513753096076e-05\n21.0,270.0,0.0\n21.0,275.0,0.0\n21.0,280.0,0.0\n21.0,285.0,0.0\n21.0,290.0,0.0\n21.0,295.0,0.0\n21.0,300.0,0.0\n21.0,305.0,0.0\n21.0,310.0,0.0\n21.0,315.0,0.0\n21.0,320.0,0.0\n21.0,325.0,0.0\n21.0,330.0,1.629513753096076e-05\n21.0,335.0,6.518055012384304e-05\n21.0,340.0,3.259027506192152e-05\n21.0,345.0,1.629513753096076e-05\n21.0,350.0,0.0\n21.0,355.0,0.0\n22.0,0.0,0.0\n22.0,5.0,0.0\n22.0,10.0,0.0\n22.0,15.0,0.0\n22.0,20.0,0.0\n22.0,25.0,0.0\n22.0,30.0,0.0\n22.0,35.0,0.0\n22.0,40.0,0.0\n22.0,45.0,0.0\n22.0,50.0,0.0\n22.0,55.0,0.0\n22.0,60.0,0.0\n22.0,65.0,0.0\n22.0,70.0,0.0\n22.0,75.0,0.0\n22.0,80.0,0.0\n22.0,85.0,0.0\n22.0,90.0,0.0\n22.0,95.0,0.0\n22.0,100.0,0.0\n22.0,105.0,0.0\n22.0,110.0,0.0\n22.0,115.0,0.0\n22.0,120.0,0.0\n22.0,125.0,0.0\n22.0,130.0,0.0\n22.0,135.0,0.0\n22.0,140.0,0.0\n22.0,145.0,0.0\n22.0,150.0,0.0\n22.0,155.0,0.0\n22.0,160.0,0.0\n22.0,165.0,1.629513753096076e-05\n22.0,170.0,0.0\n22.0,175.0,0.0\n22.0,180.0,0.0\n22.0,185.0,0.0\n22.0,190.0,0.0\n22.0,195.0,0.0\n22.0,200.0,0.0\n22.0,205.0,1.629513753096076e-05\n22.0,210.0,0.0\n22.0,215.0,0.0\n22.0,220.0,0.0\n22.0,225.0,0.0\n22.0,230.0,0.0\n22.0,235.0,0.0\n22.0,240.0,0.0\n22.0,245.0,0.0\n22.0,250.0,0.0\n22.0,255.0,0.0\n22.0,260.0,0.0\n22.0,265.0,0.0\n22.0,270.0,0.0\n22.0,275.0,0.0\n22.0,280.0,0.0\n22.0,285.0,0.0\n22.0,290.0,1.629513753096076e-05\n22.0,295.0,0.0\n22.0,300.0,0.0\n22.0,305.0,0.0\n22.0,310.0,0.0\n22.0,315.0,0.0\n22.0,320.0,1.629513753096076e-05\n22.0,325.0,0.0\n22.0,330.0,0.0\n22.0,335.0,0.0\n22.0,340.0,0.0\n22.0,345.0,0.0\n22.0,350.0,0.0\n22.0,355.0,0.0\n23.0,0.0,0.0\n23.0,5.0,0.0\n23.0,10.0,0.0\n23.0,15.0,0.0\n23.0,20.0,0.0\n23.0,25.0,0.0\n23.0,30.0,0.0\n23.0,35.0,0.0\n23.0,40.0,0.0\n23.0,45.0,0.0\n23.0,50.0,0.0\n23.0,55.0,0.0\n23.0,60.0,0.0\n23.0,65.0,0.0\n23.0,70.0,0.0\n23.0,75.0,0.0\n23.0,80.0,0.0\n23.0,85.0,0.0\n23.0,90.0,0.0\n23.0,95.0,0.0\n23.0,100.0,0.0\n23.0,105.0,0.0\n23.0,110.0,0.0\n23.0,115.0,0.0\n23.0,120.0,0.0\n23.0,125.0,0.0\n23.0,130.0,0.0\n23.0,135.0,0.0\n23.0,140.0,0.0\n23.0,145.0,0.0\n23.0,150.0,0.0\n23.0,155.0,0.0\n23.0,160.0,0.0\n23.0,165.0,0.0\n23.0,170.0,0.0\n23.0,175.0,0.0\n23.0,180.0,0.0\n23.0,185.0,0.0\n23.0,190.0,0.0\n23.0,195.0,0.0\n23.0,200.0,0.0\n23.0,205.0,0.0\n23.0,210.0,0.0\n23.0,215.0,0.0\n23.0,220.0,0.0\n23.0,225.0,0.0\n23.0,230.0,0.0\n23.0,235.0,0.0\n23.0,240.0,0.0\n23.0,245.0,0.0\n23.0,250.0,0.0\n23.0,255.0,0.0\n23.0,260.0,0.0\n23.0,265.0,0.0\n23.0,270.0,0.0\n23.0,275.0,0.0\n23.0,280.0,0.0\n23.0,285.0,0.0\n23.0,290.0,0.0\n23.0,295.0,0.0\n23.0,300.0,0.0\n23.0,305.0,1.629513753096076e-05\n23.0,310.0,0.0\n23.0,315.0,0.0\n23.0,320.0,0.0\n23.0,325.0,1.629513753096076e-05\n23.0,330.0,0.0\n23.0,335.0,3.259027506192152e-05\n23.0,340.0,0.0\n23.0,345.0,0.0\n23.0,350.0,0.0\n23.0,355.0,0.0\n24.0,0.0,1.629513753096076e-05\n24.0,5.0,0.0\n24.0,10.0,0.0\n24.0,15.0,0.0\n24.0,20.0,0.0\n24.0,25.0,0.0\n24.0,30.0,0.0\n24.0,35.0,0.0\n24.0,40.0,0.0\n24.0,45.0,0.0\n24.0,50.0,0.0\n24.0,55.0,0.0\n24.0,60.0,0.0\n24.0,65.0,0.0\n24.0,70.0,0.0\n24.0,75.0,0.0\n24.0,80.0,0.0\n24.0,85.0,0.0\n24.0,90.0,0.0\n24.0,95.0,0.0\n24.0,100.0,0.0\n24.0,105.0,0.0\n24.0,110.0,0.0\n24.0,115.0,0.0\n24.0,120.0,0.0\n24.0,125.0,0.0\n24.0,130.0,0.0\n24.0,135.0,0.0\n24.0,140.0,0.0\n24.0,145.0,0.0\n24.0,150.0,0.0\n24.0,155.0,0.0\n24.0,160.0,0.0\n24.0,165.0,0.0\n24.0,170.0,0.0\n24.0,175.0,0.0\n24.0,180.0,0.0\n24.0,185.0,0.0\n24.0,190.0,0.0\n24.0,195.0,0.0\n24.0,200.0,0.0\n24.0,205.0,0.0\n24.0,210.0,0.0\n24.0,215.0,0.0\n24.0,220.0,0.0\n24.0,225.0,0.0\n24.0,230.0,0.0\n24.0,235.0,0.0\n24.0,240.0,0.0\n24.0,245.0,0.0\n24.0,250.0,0.0\n24.0,255.0,0.0\n24.0,260.0,0.0\n24.0,265.0,0.0\n24.0,270.0,0.0\n24.0,275.0,0.0\n24.0,280.0,0.0\n24.0,285.0,0.0\n24.0,290.0,0.0\n24.0,295.0,0.0\n24.0,300.0,0.0\n24.0,305.0,0.0\n24.0,310.0,0.0\n24.0,315.0,0.0\n24.0,320.0,0.0\n24.0,325.0,0.0\n24.0,330.0,0.0\n24.0,335.0,0.0\n24.0,340.0,0.0\n24.0,345.0,0.0\n24.0,350.0,1.629513753096076e-05\n24.0,355.0,0.0\n25.0,0.0,0.0\n25.0,5.0,0.0\n25.0,10.0,0.0\n25.0,15.0,0.0\n25.0,20.0,0.0\n25.0,25.0,0.0\n25.0,30.0,0.0\n25.0,35.0,0.0\n25.0,40.0,0.0\n25.0,45.0,0.0\n25.0,50.0,0.0\n25.0,55.0,0.0\n25.0,60.0,0.0\n25.0,65.0,0.0\n25.0,70.0,0.0\n25.0,75.0,0.0\n25.0,80.0,0.0\n25.0,85.0,0.0\n25.0,90.0,0.0\n25.0,95.0,0.0\n25.0,100.0,0.0\n25.0,105.0,0.0\n25.0,110.0,0.0\n25.0,115.0,0.0\n25.0,120.0,0.0\n25.0,125.0,0.0\n25.0,130.0,0.0\n25.0,135.0,0.0\n25.0,140.0,0.0\n25.0,145.0,0.0\n25.0,150.0,0.0\n25.0,155.0,0.0\n25.0,160.0,0.0\n25.0,165.0,0.0\n25.0,170.0,0.0\n25.0,175.0,0.0\n25.0,180.0,0.0\n25.0,185.0,0.0\n25.0,190.0,0.0\n25.0,195.0,0.0\n25.0,200.0,0.0\n25.0,205.0,0.0\n25.0,210.0,0.0\n25.0,215.0,0.0\n25.0,220.0,0.0\n25.0,225.0,1.629513753096076e-05\n25.0,230.0,0.0\n25.0,235.0,0.0\n25.0,240.0,0.0\n25.0,245.0,0.0\n25.0,250.0,0.0\n25.0,255.0,0.0\n25.0,260.0,0.0\n25.0,265.0,0.0\n25.0,270.0,1.629513753096076e-05\n25.0,275.0,0.0\n25.0,280.0,0.0\n25.0,285.0,0.0\n25.0,290.0,0.0\n25.0,295.0,0.0\n25.0,300.0,0.0\n25.0,305.0,0.0\n25.0,310.0,0.0\n25.0,315.0,0.0\n25.0,320.0,0.0\n25.0,325.0,0.0\n25.0,330.0,0.0\n25.0,335.0,0.0\n25.0,340.0,0.0\n25.0,345.0,0.0\n25.0,350.0,0.0\n25.0,355.0,0.0\n"
  },
  {
    "path": "examples/inputs_floating/emgauss_fixed.yaml",
    "content": "\nname: Emperical Gaussian\ndescription: Example of single fixed-bottom turbine\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - !include turbine_files/nrel_5MW_fixed.yaml\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: empirical_gauss\n    turbulence_model: wake_induced_mixing\n    velocity_model: empirical_gauss\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: false\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n    empirical_gauss:\n      horizontal_deflection_gain_D: 3.0\n      vertical_deflection_gain_D: -1\n      deflection_rate: 22\n      mixing_gain_deflection: 0.0\n      yaw_added_mixing_gain: 0.0\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    empirical_gauss:\n      wake_expansion_rates:\n      - 0.023\n      - 0.008\n      breakpoints_D:\n      - 10\n      sigma_0_D: 0.28\n      smoothing_length_D: 2.0\n      mixing_gain_velocity: 2.0\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n    wake_induced_mixing:\n      atmospheric_ti_gain: 0.0\n"
  },
  {
    "path": "examples/inputs_floating/emgauss_floating.yaml",
    "content": "\nname: Emperical Gaussian\ndescription: Example of single floating turbine\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  - 630.0\n  - 1260.0\n  layout_y:\n  - 0.0\n  - 0.0\n  - 0.0\n  turbine_type:\n  - !include turbine_files/nrel_5MW_floating.yaml\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: empirical_gauss\n    turbulence_model: wake_induced_mixing\n    velocity_model: empirical_gauss\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: false\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n    empirical_gauss:\n      horizontal_deflection_gain_D: 3.0\n      vertical_deflection_gain_D: -1\n      deflection_rate: 22\n      mixing_gain_deflection: 0.0\n      yaw_added_mixing_gain: 0.0\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    empirical_gauss:\n      wake_expansion_rates:\n      - 0.023\n      - 0.008\n      breakpoints_D:\n      - 10\n      sigma_0_D: 0.28\n      smoothing_length_D: 2.0\n      mixing_gain_velocity: 2.0\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n    wake_induced_mixing:\n      atmospheric_ti_gain: 0.0\n"
  },
  {
    "path": "examples/inputs_floating/emgauss_floating_fixedtilt15.yaml",
    "content": "\nname: Emperical Gaussian floating\ndescription: Single turbine using emperical Gaussian model for floating\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  layout_y:\n  - 0.0\n  turbine_type:\n  - !include turbine_files/nrel_5MW_floating_fixedtilt15.yaml\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: empirical_gauss\n    turbulence_model: wake_induced_mixing\n    velocity_model: empirical_gauss\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: false\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n    empirical_gauss:\n      horizontal_deflection_gain_D: 3.0\n      vertical_deflection_gain_D: -1\n      deflection_rate: 22\n      mixing_gain_deflection: 0.0\n      yaw_added_mixing_gain: 0.0\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    empirical_gauss:\n      wake_expansion_rates:\n      - 0.023\n      - 0.008\n      breakpoints_D:\n      - 10\n      sigma_0_D: 0.28\n      smoothing_length_D: 2.0\n      mixing_gain_velocity: 2.0\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n    wake_induced_mixing:\n      atmospheric_ti_gain: 0.0\n"
  },
  {
    "path": "examples/inputs_floating/emgauss_floating_fixedtilt5.yaml",
    "content": "\nname: Emperical Gaussian floating\ndescription: Single turbine using emperical Gaussian model for floating\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  layout_y:\n  - 0.0\n  turbine_type:\n  - !include turbine_files/nrel_5MW_floating_fixedtilt5.yaml\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1 # -1 is code for use the hub height\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: empirical_gauss\n    turbulence_model: wake_induced_mixing\n    velocity_model: empirical_gauss\n\n  enable_secondary_steering: false\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: false\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n    empirical_gauss:\n      horizontal_deflection_gain_D: 3.0\n      vertical_deflection_gain_D: -1\n      deflection_rate: 22\n      mixing_gain_deflection: 0.0\n      yaw_added_mixing_gain: 0.0\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    empirical_gauss:\n      wake_expansion_rates:\n      - 0.023\n      - 0.008\n      breakpoints_D:\n      - 10\n      sigma_0_D: 0.28\n      smoothing_length_D: 2.0\n      mixing_gain_velocity: 2.0\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n    wake_induced_mixing:\n      atmospheric_ti_gain: 0.0\n"
  },
  {
    "path": "examples/inputs_floating/gch_fixed.yaml",
    "content": "\nname: GCH\ndescription: Example of single fixed-bottom turbine\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  layout_y:\n  - 0.0\n  turbine_type:\n  - !include turbine_files/nrel_5MW_fixed.yaml\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: gauss\n\n  enable_secondary_steering: true\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: true\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n"
  },
  {
    "path": "examples/inputs_floating/gch_floating.yaml",
    "content": "\n\nname: GCH\ndescription: Example of single floating turbine\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  layout_y:\n  - 0.0\n  turbine_type:\n  - !include turbine_files/nrel_5MW_floating.yaml\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: gauss\n\n  enable_secondary_steering: true\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: true\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n"
  },
  {
    "path": "examples/inputs_floating/gch_floating_defined_floating.yaml",
    "content": "\nname: GCH\ndescription: Example of single floating turbine where the cp/ct is calculated with floating tilt included\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  layout_y:\n  - 0.0\n  turbine_type:\n  - !include turbine_files/nrel_5MW_floating_defined_floating.yaml\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: gauss\n\n  enable_secondary_steering: true\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: true\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n"
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_fixed.yaml",
    "content": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: True # Apply tilt correction to cp/ct\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 5.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  power:\n    - 0.0\n    - 0.0\n    - 40.518011517569214\n    - 177.67162506419703\n    - 403.900880943964\n    - 737.5889584824021\n    - 1187.1774030611875\n    - 1239.245945375778\n    - 1292.5184293723503\n    - 1347.3213147477102\n    - 1403.2573725578948\n    - 1460.7011898730707\n    - 1519.6419125979983\n    - 1580.174365096404\n    - 1642.1103166918167\n    - 1705.758292831\n    - 1771.1659528893977\n    - 2518.553107505315\n    - 3448.381605840943\n    - 3552.140809000129\n    - 3657.9545431794127\n    - 3765.121299313842\n    - 3873.928844315059\n    - 3984.4800226955504\n    - 4096.582833096852\n    - 4210.721306623712\n    - 4326.154305853405\n    - 4443.395565353604\n    - 4562.497934188341\n    - 4683.419890251577\n    - 4806.164748311019\n    - 4929.931918769215\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 0.0\n    - 0.0\n  thrust_coefficient:\n    - 0.0\n    - 0.0\n    - 1.132034888\n    - 0.999470963\n    - 0.917697381\n    - 0.860849503\n    - 0.815371198\n    - 0.811614904\n    - 0.807939328\n    - 0.80443352\n    - 0.800993851\n    - 0.79768116\n    - 0.794529244\n    - 0.791495834\n    - 0.788560434\n    - 0.787217182\n    - 0.787127977\n    - 0.785839257\n    - 0.783812219\n    - 0.783568108\n    - 0.783328285\n    - 0.781194418\n    - 0.777292539\n    - 0.773464375\n    - 0.769690236\n    - 0.766001924\n    - 0.762348072\n    - 0.758760824\n    - 0.755242872\n    - 0.751792927\n    - 0.748434131\n    - 0.745113997\n    - 0.717806682\n    - 0.672204789\n    - 0.63831272\n    - 0.610176496\n    - 0.585456847\n    - 0.563222111\n    - 0.542912273\n    - 0.399312061\n    - 0.310517829\n    - 0.248633226\n    - 0.203543725\n    - 0.169616419\n    - 0.143478955\n    - 0.122938861\n    - 0.106515296\n    - 0.093026095\n    - 0.081648606\n    - 0.072197368\n    - 0.064388275\n    - 0.057782745\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.0\n    - 2.9\n    - 3.0\n    - 4.0\n    - 5.0\n    - 6.0\n    - 7.0\n    - 7.1\n    - 7.2\n    - 7.3\n    - 7.4\n    - 7.5\n    - 7.6\n    - 7.7\n    - 7.8\n    - 7.9\n    - 8.0\n    - 9.0\n    - 10.0\n    - 10.1\n    - 10.2\n    - 10.3\n    - 10.4\n    - 10.5\n    - 10.6\n    - 10.7\n    - 10.8\n    - 10.9\n    - 11.0\n    - 11.1\n    - 11.2\n    - 11.3\n    - 11.4\n    - 11.5\n    - 11.6\n    - 11.7\n    - 11.8\n    - 11.9\n    - 12.0\n    - 13.0\n    - 14.0\n    - 15.0\n    - 16.0\n    - 17.0\n    - 18.0\n    - 19.0\n    - 20.0\n    - 21.0\n    - 22.0\n    - 23.0\n    - 24.0\n    - 25.0\n    - 25.1\n    - 50.0\nfloating_tilt_table:\n  tilt:\n    - 5.0\n    - 5.0\n    - 5.0\n    - 5.0\n    - 5.0\n  wind_speed:\n    - 0.0\n    - 4.0\n    - 11.0\n    - 25.0\n    - 50.0\n"
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_floating.yaml",
    "content": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: True # Apply tilt correction to cp/ct\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 5.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  power:\n    - 0.0\n    - 0.0\n    - 40.518011517569214\n    - 177.67162506419703\n    - 403.900880943964\n    - 737.5889584824021\n    - 1187.1774030611875\n    - 1239.245945375778\n    - 1292.5184293723503\n    - 1347.3213147477102\n    - 1403.2573725578948\n    - 1460.7011898730707\n    - 1519.6419125979983\n    - 1580.174365096404\n    - 1642.1103166918167\n    - 1705.758292831\n    - 1771.1659528893977\n    - 2518.553107505315\n    - 3448.381605840943\n    - 3552.140809000129\n    - 3657.9545431794127\n    - 3765.121299313842\n    - 3873.928844315059\n    - 3984.4800226955504\n    - 4096.582833096852\n    - 4210.721306623712\n    - 4326.154305853405\n    - 4443.395565353604\n    - 4562.497934188341\n    - 4683.419890251577\n    - 4806.164748311019\n    - 4929.931918769215\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 0.0\n    - 0.0\n  thrust_coefficient:\n    - 0.0\n    - 0.0\n    - 1.132034888\n    - 0.999470963\n    - 0.917697381\n    - 0.860849503\n    - 0.815371198\n    - 0.811614904\n    - 0.807939328\n    - 0.80443352\n    - 0.800993851\n    - 0.79768116\n    - 0.794529244\n    - 0.791495834\n    - 0.788560434\n    - 0.787217182\n    - 0.787127977\n    - 0.785839257\n    - 0.783812219\n    - 0.783568108\n    - 0.783328285\n    - 0.781194418\n    - 0.777292539\n    - 0.773464375\n    - 0.769690236\n    - 0.766001924\n    - 0.762348072\n    - 0.758760824\n    - 0.755242872\n    - 0.751792927\n    - 0.748434131\n    - 0.745113997\n    - 0.717806682\n    - 0.672204789\n    - 0.63831272\n    - 0.610176496\n    - 0.585456847\n    - 0.563222111\n    - 0.542912273\n    - 0.399312061\n    - 0.310517829\n    - 0.248633226\n    - 0.203543725\n    - 0.169616419\n    - 0.143478955\n    - 0.122938861\n    - 0.106515296\n    - 0.093026095\n    - 0.081648606\n    - 0.072197368\n    - 0.064388275\n    - 0.057782745\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.0\n    - 2.9\n    - 3.0\n    - 4.0\n    - 5.0\n    - 6.0\n    - 7.0\n    - 7.1\n    - 7.2\n    - 7.3\n    - 7.4\n    - 7.5\n    - 7.6\n    - 7.7\n    - 7.8\n    - 7.9\n    - 8.0\n    - 9.0\n    - 10.0\n    - 10.1\n    - 10.2\n    - 10.3\n    - 10.4\n    - 10.5\n    - 10.6\n    - 10.7\n    - 10.8\n    - 10.9\n    - 11.0\n    - 11.1\n    - 11.2\n    - 11.3\n    - 11.4\n    - 11.5\n    - 11.6\n    - 11.7\n    - 11.8\n    - 11.9\n    - 12.0\n    - 13.0\n    - 14.0\n    - 15.0\n    - 16.0\n    - 17.0\n    - 18.0\n    - 19.0\n    - 20.0\n    - 21.0\n    - 22.0\n    - 23.0\n    - 24.0\n    - 25.0\n    - 25.1\n    - 50.0\nfloating_tilt_table:\n  tilt:\n    - 5.0\n    - 5.0\n    - 9.0\n    - 5.0\n    - 5.0\n  wind_speed:\n    - 0.0\n    - 4.0\n    - 11.0\n    - 25.0\n    - 50.0\n"
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_floating_defined_floating.yaml",
    "content": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: False # Do not apply tilt correction to cp/ct\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 5.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  power:\n    - 0.0\n    - 0.0\n    - 40.518011517569214\n    - 177.67162506419703\n    - 403.900880943964\n    - 737.5889584824021\n    - 1187.1774030611875\n    - 1239.245945375778\n    - 1292.5184293723503\n    - 1347.3213147477102\n    - 1403.2573725578948\n    - 1460.7011898730707\n    - 1519.6419125979983\n    - 1580.174365096404\n    - 1642.1103166918167\n    - 1705.758292831\n    - 1771.1659528893977\n    - 2518.553107505315\n    - 3448.381605840943\n    - 3552.140809000129\n    - 3657.9545431794127\n    - 3765.121299313842\n    - 3873.928844315059\n    - 3984.4800226955504\n    - 4096.582833096852\n    - 4210.721306623712\n    - 4326.154305853405\n    - 4443.395565353604\n    - 4562.497934188341\n    - 4683.419890251577\n    - 4806.164748311019\n    - 4929.931918769215\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 0.0\n    - 0.0\n  thrust_coefficient:\n    - 0.0\n    - 0.0\n    - 1.132034888\n    - 0.999470963\n    - 0.917697381\n    - 0.860849503\n    - 0.815371198\n    - 0.811614904\n    - 0.807939328\n    - 0.80443352\n    - 0.800993851\n    - 0.79768116\n    - 0.794529244\n    - 0.791495834\n    - 0.788560434\n    - 0.787217182\n    - 0.787127977\n    - 0.785839257\n    - 0.783812219\n    - 0.783568108\n    - 0.783328285\n    - 0.781194418\n    - 0.777292539\n    - 0.773464375\n    - 0.769690236\n    - 0.766001924\n    - 0.762348072\n    - 0.758760824\n    - 0.755242872\n    - 0.751792927\n    - 0.748434131\n    - 0.745113997\n    - 0.717806682\n    - 0.672204789\n    - 0.63831272\n    - 0.610176496\n    - 0.585456847\n    - 0.563222111\n    - 0.542912273\n    - 0.399312061\n    - 0.310517829\n    - 0.248633226\n    - 0.203543725\n    - 0.169616419\n    - 0.143478955\n    - 0.122938861\n    - 0.106515296\n    - 0.093026095\n    - 0.081648606\n    - 0.072197368\n    - 0.064388275\n    - 0.057782745\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.0\n    - 2.9\n    - 3.0\n    - 4.0\n    - 5.0\n    - 6.0\n    - 7.0\n    - 7.1\n    - 7.2\n    - 7.3\n    - 7.4\n    - 7.5\n    - 7.6\n    - 7.7\n    - 7.8\n    - 7.9\n    - 8.0\n    - 9.0\n    - 10.0\n    - 10.1\n    - 10.2\n    - 10.3\n    - 10.4\n    - 10.5\n    - 10.6\n    - 10.7\n    - 10.8\n    - 10.9\n    - 11.0\n    - 11.1\n    - 11.2\n    - 11.3\n    - 11.4\n    - 11.5\n    - 11.6\n    - 11.7\n    - 11.8\n    - 11.9\n    - 12.0\n    - 13.0\n    - 14.0\n    - 15.0\n    - 16.0\n    - 17.0\n    - 18.0\n    - 19.0\n    - 20.0\n    - 21.0\n    - 22.0\n    - 23.0\n    - 24.0\n    - 25.0\n    - 25.1\n    - 50.0\nfloating_tilt_table:\n  tilt:\n    - 5.0\n    - 5.0\n    - 9.0\n    - 5.0\n    - 5.0\n  wind_speed:\n    - 0.0\n    - 4.0\n    - 11.0\n    - 25.0\n    - 50.0\n"
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_floating_fixedtilt15.yaml",
    "content": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: True # Apply tilt correction to cp/ct\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 5.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  power:\n    - 0.0\n    - 0.0\n    - 40.518011517569214\n    - 177.67162506419703\n    - 403.900880943964\n    - 737.5889584824021\n    - 1187.1774030611875\n    - 1239.245945375778\n    - 1292.5184293723503\n    - 1347.3213147477102\n    - 1403.2573725578948\n    - 1460.7011898730707\n    - 1519.6419125979983\n    - 1580.174365096404\n    - 1642.1103166918167\n    - 1705.758292831\n    - 1771.1659528893977\n    - 2518.553107505315\n    - 3448.381605840943\n    - 3552.140809000129\n    - 3657.9545431794127\n    - 3765.121299313842\n    - 3873.928844315059\n    - 3984.4800226955504\n    - 4096.582833096852\n    - 4210.721306623712\n    - 4326.154305853405\n    - 4443.395565353604\n    - 4562.497934188341\n    - 4683.419890251577\n    - 4806.164748311019\n    - 4929.931918769215\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 0.0\n    - 0.0\n  thrust_coefficient:\n    - 0.0\n    - 0.0\n    - 1.132034888\n    - 0.999470963\n    - 0.917697381\n    - 0.860849503\n    - 0.815371198\n    - 0.811614904\n    - 0.807939328\n    - 0.80443352\n    - 0.800993851\n    - 0.79768116\n    - 0.794529244\n    - 0.791495834\n    - 0.788560434\n    - 0.787217182\n    - 0.787127977\n    - 0.785839257\n    - 0.783812219\n    - 0.783568108\n    - 0.783328285\n    - 0.781194418\n    - 0.777292539\n    - 0.773464375\n    - 0.769690236\n    - 0.766001924\n    - 0.762348072\n    - 0.758760824\n    - 0.755242872\n    - 0.751792927\n    - 0.748434131\n    - 0.745113997\n    - 0.717806682\n    - 0.672204789\n    - 0.63831272\n    - 0.610176496\n    - 0.585456847\n    - 0.563222111\n    - 0.542912273\n    - 0.399312061\n    - 0.310517829\n    - 0.248633226\n    - 0.203543725\n    - 0.169616419\n    - 0.143478955\n    - 0.122938861\n    - 0.106515296\n    - 0.093026095\n    - 0.081648606\n    - 0.072197368\n    - 0.064388275\n    - 0.057782745\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.0\n    - 2.9\n    - 3.0\n    - 4.0\n    - 5.0\n    - 6.0\n    - 7.0\n    - 7.1\n    - 7.2\n    - 7.3\n    - 7.4\n    - 7.5\n    - 7.6\n    - 7.7\n    - 7.8\n    - 7.9\n    - 8.0\n    - 9.0\n    - 10.0\n    - 10.1\n    - 10.2\n    - 10.3\n    - 10.4\n    - 10.5\n    - 10.6\n    - 10.7\n    - 10.8\n    - 10.9\n    - 11.0\n    - 11.1\n    - 11.2\n    - 11.3\n    - 11.4\n    - 11.5\n    - 11.6\n    - 11.7\n    - 11.8\n    - 11.9\n    - 12.0\n    - 13.0\n    - 14.0\n    - 15.0\n    - 16.0\n    - 17.0\n    - 18.0\n    - 19.0\n    - 20.0\n    - 21.0\n    - 22.0\n    - 23.0\n    - 24.0\n    - 25.0\n    - 25.1\n    - 50.0\nfloating_tilt_table:\n  tilt:\n    - 15.0\n    - 15.0\n    - 15.0\n    - 15.0\n    - 15.0\n  wind_speed:\n    - 0.0\n    - 4.0\n    - 11.0\n    - 25.0\n    - 50.0\n"
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_floating_fixedtilt5.yaml",
    "content": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: True # Apply tilt correction to cp/ct\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 5.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  power:\n    - 0.0\n    - 0.0\n    - 40.518011517569214\n    - 177.67162506419703\n    - 403.900880943964\n    - 737.5889584824021\n    - 1187.1774030611875\n    - 1239.245945375778\n    - 1292.5184293723503\n    - 1347.3213147477102\n    - 1403.2573725578948\n    - 1460.7011898730707\n    - 1519.6419125979983\n    - 1580.174365096404\n    - 1642.1103166918167\n    - 1705.758292831\n    - 1771.1659528893977\n    - 2518.553107505315\n    - 3448.381605840943\n    - 3552.140809000129\n    - 3657.9545431794127\n    - 3765.121299313842\n    - 3873.928844315059\n    - 3984.4800226955504\n    - 4096.582833096852\n    - 4210.721306623712\n    - 4326.154305853405\n    - 4443.395565353604\n    - 4562.497934188341\n    - 4683.419890251577\n    - 4806.164748311019\n    - 4929.931918769215\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 0.0\n    - 0.0\n  thrust_coefficient:\n    - 0.0\n    - 0.0\n    - 1.132034888\n    - 0.999470963\n    - 0.917697381\n    - 0.860849503\n    - 0.815371198\n    - 0.811614904\n    - 0.807939328\n    - 0.80443352\n    - 0.800993851\n    - 0.79768116\n    - 0.794529244\n    - 0.791495834\n    - 0.788560434\n    - 0.787217182\n    - 0.787127977\n    - 0.785839257\n    - 0.783812219\n    - 0.783568108\n    - 0.783328285\n    - 0.781194418\n    - 0.777292539\n    - 0.773464375\n    - 0.769690236\n    - 0.766001924\n    - 0.762348072\n    - 0.758760824\n    - 0.755242872\n    - 0.751792927\n    - 0.748434131\n    - 0.745113997\n    - 0.717806682\n    - 0.672204789\n    - 0.63831272\n    - 0.610176496\n    - 0.585456847\n    - 0.563222111\n    - 0.542912273\n    - 0.399312061\n    - 0.310517829\n    - 0.248633226\n    - 0.203543725\n    - 0.169616419\n    - 0.143478955\n    - 0.122938861\n    - 0.106515296\n    - 0.093026095\n    - 0.081648606\n    - 0.072197368\n    - 0.064388275\n    - 0.057782745\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.0\n    - 2.9\n    - 3.0\n    - 4.0\n    - 5.0\n    - 6.0\n    - 7.0\n    - 7.1\n    - 7.2\n    - 7.3\n    - 7.4\n    - 7.5\n    - 7.6\n    - 7.7\n    - 7.8\n    - 7.9\n    - 8.0\n    - 9.0\n    - 10.0\n    - 10.1\n    - 10.2\n    - 10.3\n    - 10.4\n    - 10.5\n    - 10.6\n    - 10.7\n    - 10.8\n    - 10.9\n    - 11.0\n    - 11.1\n    - 11.2\n    - 11.3\n    - 11.4\n    - 11.5\n    - 11.6\n    - 11.7\n    - 11.8\n    - 11.9\n    - 12.0\n    - 13.0\n    - 14.0\n    - 15.0\n    - 16.0\n    - 17.0\n    - 18.0\n    - 19.0\n    - 20.0\n    - 21.0\n    - 22.0\n    - 23.0\n    - 24.0\n    - 25.0\n    - 25.1\n    - 50.0\nfloating_tilt_table:\n  tilt:\n    - 5.0\n    - 5.0\n    - 5.0\n    - 5.0\n    - 5.0\n  wind_speed:\n    - 0.0\n    - 4.0\n    - 11.0\n    - 25.0\n    - 50.0\n"
  },
  {
    "path": "floris/__init__.py",
    "content": "\nfrom importlib.metadata import version\nfrom pathlib import Path\n\n\n__version__ = version(\"floris\")\n\n\nfrom .floris_model import FlorisModel\nfrom .flow_visualization import (\n    plot_rotor_values,\n    visualize_cut_plane,\n    visualize_quiver,\n)\nfrom .heterogeneous_map import HeterogeneousMap\nfrom .par_floris_model import ParFlorisModel\nfrom .parallel_floris_model import ParallelFlorisModel\nfrom .uncertain_floris_model import ApproxFlorisModel, UncertainFlorisModel\nfrom .wind_data import (\n    TimeSeries,\n    WindRose,\n    WindRoseWRG,\n    WindTIRose,\n)\n"
  },
  {
    "path": "floris/convert_floris_input_v3_to_v4.py",
    "content": "import sys\nfrom pathlib import Path\n\nimport yaml\n\n\n\"\"\"\nThis script is intended to be called with an argument and converts a floris input\nyaml file specified for FLORIS v3 to one specified for FLORIS v4.\n\nUsage:\npython convert_floris_input_v3_to_v4.py <path/to/floris_input>.yaml\n\nThe resulting floris input file is placed in the same directory as the original yaml,\nand is appended _v4.\n\"\"\"\n\n\ndef ignore_include(loader, node):\n    # Parrot back the !include tag\n    return node.tag + \" \" + node.value\n\n\nif __name__ == \"__main__\":\n    if len(sys.argv) != 2:\n        raise Exception(\n            \"Usage: python convert_floris_input_v3_to_v4.py <path/to/floris_input>.yaml\"\n        )\n\n    # Set the yaml loader to ignore the !include tag\n    yaml.SafeLoader.add_constructor(\"!include\", ignore_include)\n\n    input_yaml = sys.argv[1]\n\n    # Handling the path and new filename\n    input_path = Path(input_yaml)\n    split_input = input_path.parts\n    [filename_v3, extension] = split_input[-1].split(\".\")\n    filename_v4 = filename_v3 + \"_v4\"\n    split_output = list(split_input[:-1]) + [filename_v4 + \".\" + extension]\n    output_path = Path(*split_output)\n\n    # Load existing v3 model\n    with open(input_yaml, \"r\") as file:\n        v3_floris_input_dict = yaml.safe_load(file)\n    v4_floris_input_dict = v3_floris_input_dict.copy()\n\n    # Change turbulence_intensity field to turbulence_intensities as list\n    if \"turbulence_intensities\" in v3_floris_input_dict[\"flow_field\"]:\n        if \"turbulence_intensity\" in v3_floris_input_dict[\"flow_field\"]:\n            del v4_floris_input_dict[\"flow_field\"][\"turbulence_intensity\"]\n    elif \"turbulence_intensity\" in v3_floris_input_dict[\"flow_field\"]:\n        v4_floris_input_dict[\"flow_field\"][\"turbulence_intensities\"] = [\n            v3_floris_input_dict[\"flow_field\"][\"turbulence_intensity\"]\n        ]\n        del v4_floris_input_dict[\"flow_field\"][\"turbulence_intensity\"]\n\n    # Change multidim_cp_ct velocity model to gauss\n    if v3_floris_input_dict[\"wake\"][\"model_strings\"][\"velocity_model\"] == \"multidim_cp_ct\":\n        print(\n            \"multidim_cp_ct velocity model specified. Changing to gauss, \"\n            + \"but note that other velocity models are also compatible with multidimensional \"\n            + \"turbines in FLORIS v4. \"\n            + \"You will also need to convert your multidimensional turbine yaml files and their \"\n            + \"corresponding power/thrust csv files to be compatible with FLORIS v4 and to reflect \"\n            + \" the absolute power curve, rather than the power coefficient curve.\"\n        )\n        v4_floris_input_dict[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"gauss\"\n\n    # Add enable_active_wake_mixing field\n    v4_floris_input_dict[\"wake\"][\"enable_active_wake_mixing\"] = False\n\n    # Write the new v4 model to a new file, note that the in order to ignore the !include tag\n    # it is wrapped in single quotes by the ignore include/load/dump sequence and these will\n    # need to be removed in the next block of code\n    yaml.dump(v4_floris_input_dict, open(output_path, \"w\"), sort_keys=False)\n\n    # Open the output file and loop through line by line\n    # if a line contains the substring !include, then strip all\n    # occurrences of ' from the line to remove the extra single quotes\n    # added by the ignore include/load/dump sequence\n    temp_output_path = output_path.with_name(\"temp.yaml\")\n    with open(temp_output_path, \"w\") as file:\n        with open(output_path, \"r\") as f:\n            for line in f:\n                if \"!include\" in line:\n                    line = line.replace(\"'\", \"\")\n                file.write(line)\n\n    # Move the temp file to the output file\n    temp_output_path.replace(output_path)\n\n    print(output_path, \"created.\")\n"
  },
  {
    "path": "floris/convert_turbine_v3_to_v4.py",
    "content": "\nimport sys\nfrom pathlib import Path\n\nfrom floris.turbine_library import build_cosine_loss_turbine_dict, check_smooth_power_curve\nfrom floris.utilities import load_yaml\n\n\n\"\"\"\nThis script is intended to be called with an argument and converts a turbine\nyaml file specified for FLORIS v3 to one specified for FLORIS v4.\n\nUsage:\npython convert_turbine_v3_to_v4.py <path/to/turbine>.yaml\n\nThe resulting turbine is placed in the same directory as the original yaml,\nand is appended _v4.\n\"\"\"\n\n\nif __name__ == \"__main__\":\n    if len(sys.argv) != 2:\n        raise Exception(\"Usage: python convert_turbine_v3_to_v4.py <path/to/turbine>.yaml\")\n\n    input_yaml = sys.argv[1]\n\n    # Handling the path and new filename\n    input_path = Path(input_yaml)\n    split_input = input_path.parts\n    [filename_v3, extension] = split_input[-1].split(\".\")\n    filename_v4 = filename_v3 + \"_v4\"\n    split_output = list(split_input[:-1]) + [filename_v4+\".\"+extension]\n    output_path = Path(*split_output)\n\n    # Load existing v3 model\n    v3_turbine_dict = load_yaml(input_yaml)\n\n    # Split into components expected by build_turbine_dict\n    power_thrust_table = v3_turbine_dict[\"power_thrust_table\"]\n    if \"power_thrust_data_file\" in power_thrust_table:\n        raise ValueError(\n            \"Cannot convert multidimensional turbine model. Please manually update your \"\n            + \"turbine yaml. Note that the power_thrust_data_file csv needs to be updated to \"\n            + \"reflect the absolute power curve, rather than the power coefficient curve,\"\n            + \"and that `thrust` has been replaced by `thrust_coefficient`.\"\n        )\n    power_thrust_table[\"power_coefficient\"] = power_thrust_table[\"power\"]\n    power_thrust_table[\"thrust_coefficient\"] = power_thrust_table[\"thrust\"]\n    power_thrust_table.pop(\"power\")\n    power_thrust_table.pop(\"thrust\")\n\n    valid_properties = [\n        \"generator_efficiency\",\n        \"hub_height\",\n        \"cosine_loss_exponent_yaw\",\n        \"cosine_loss_exponent_tilt\",\n        \"rotor_diameter\",\n        \"TSR\",\n        \"ref_air_density\",\n        \"ref_tilt\"\n    ]\n\n    turbine_properties = {k:v for k,v in v3_turbine_dict.items() if k in valid_properties}\n    turbine_properties[\"ref_air_density\"] = v3_turbine_dict[\"ref_density_cp_ct\"]\n    turbine_properties[\"cosine_loss_exponent_yaw\"] = v3_turbine_dict[\"pP\"]\n    if \"ref_tilt_cp_ct\" in v3_turbine_dict:\n        turbine_properties[\"ref_tilt\"] = v3_turbine_dict[\"ref_tilt_cp_ct\"]\n    if \"pT\" in v3_turbine_dict:\n        turbine_properties[\"cosine_loss_exponent_tilt\"] = v3_turbine_dict[\"pT\"]\n\n    # Convert to v4 and print new yaml\n    v4_turbine_dict = build_cosine_loss_turbine_dict(\n        power_thrust_table,\n        v3_turbine_dict[\"turbine_type\"],\n        output_path,\n        **turbine_properties\n    )\n\n    if not check_smooth_power_curve(\n        v4_turbine_dict[\"power_thrust_table\"][\"power\"],\n        tolerance=0.001\n    ):\n        print(\n            \"Non-smoothness detected in output power curve. \",\n            \"Check above-rated power in generated v4 yaml file.\"\n        )\n"
  },
  {
    "path": "floris/core/__init__.py",
    "content": "\n\"\"\"\nThe :py:obj:`floris` package contains :py:obj:`floris.utilities` module\nand the modules that make up the FLORIS software. The floris simulation\nmodules are used to complete a wake simulation for a given wind farm\nand turbine configuration.\n\nAll modules and package can be imported with\n\n    >>> import floris\n\nThe ``__init__.py`` file enables the import of all modules in this\npackage so any additional modules should be included there.\n\nisort:skip_file\n\"\"\"\n\n# Provide full-path imports here for all modules\n# that should be included in the simulation package.\n# Since some of these depend on each other, the order\n# that they are listed here does matter.\n\nimport floris.logging_manager\n\nfrom .base import BaseClass, BaseModel, State\nfrom .turbine.turbine import (\n    axial_induction,\n    power,\n    thrust_coefficient,\n    Turbine\n)\nfrom .rotor_velocity import (\n    average_velocity,\n    rotor_effective_velocity,\n    compute_tilt_angles_for_floating_turbines,\n)\nfrom .farm import Farm\nfrom .grid import (\n    FlowFieldGrid,\n    FlowFieldPlanarGrid,\n    Grid,\n    PointsGrid,\n    TurbineGrid,\n    TurbineCubatureGrid\n)\nfrom .flow_field import FlowField\nfrom .wake import WakeModelManager\nfrom .solver import (\n    cc_solver,\n    empirical_gauss_solver,\n    full_flow_cc_solver,\n    full_flow_empirical_gauss_solver,\n    full_flow_sequential_solver,\n    full_flow_turbopark_solver,\n    sequential_solver,\n    turbopark_solver,\n)\nfrom .core import Core\n\n# initialize the logger\nfloris.logging_manager._setup_logger()\n"
  },
  {
    "path": "floris/core/base.py",
    "content": "\nfrom abc import abstractmethod\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Dict,\n    Final,\n)\n\nfrom attrs import (\n    Attribute,\n    define,\n    field,\n    fields,\n    setters,\n)\n\nfrom floris.logging_manager import LoggingManager\nfrom floris.type_dec import FromDictMixin\n\n\n\"\"\"\nDefines the BaseClass parent class for all models to be based upon.\n\"\"\"\n\n\nclass State(Enum):\n    UNINITIALIZED = 0\n    INITIALIZED = 1\n    USED = 2\n\n\n@define\nclass BaseClass(FromDictMixin):\n    \"\"\"\n    BaseClass object class. This class does the logging and MixIn class inheritance.\n    \"\"\"\n\n    # Initialize `state` and ensure it is treated as an attribute rather than a constant parameter.\n    # See https://www.attrs.org/en/stable/api-attr.html#attr.ib\n    state = field(init=False, default=State.UNINITIALIZED)\n    _logging_manager: LoggingManager = field(init=False, default=LoggingManager())\n\n    @property\n    def logger(self):\n        \"\"\"Returns the logger manager object.\"\"\"\n        return self._logging_manager.logger\n\n@define\nclass BaseModel(BaseClass):\n    \"\"\"\n    BaseModel is the generic class for any wake models. It defines the API required to\n    create a valid model.\n    \"\"\"\n\n    # This is a numerical epsilon to prevent divide by zeros\n    NUM_EPS: Final[float] = field(init=False, default=0.001, on_setattr=setters.frozen)\n\n    @abstractmethod\n    def prepare_function() -> dict:\n        raise NotImplementedError(\"BaseModel.prepare_function\")\n\n    @abstractmethod\n    def function() -> None:\n        raise NotImplementedError(\"BaseModel.function\")\n"
  },
  {
    "path": "floris/core/core.py",
    "content": "from __future__ import annotations\n\nfrom pathlib import Path\n\nimport numpy as np\nimport pandas as pd\nimport yaml\nfrom attrs import define, field\n\nfrom floris import logging_manager\nfrom floris.core import (\n    BaseClass,\n    cc_solver,\n    empirical_gauss_solver,\n    Farm,\n    FlowField,\n    FlowFieldGrid,\n    FlowFieldPlanarGrid,\n    full_flow_cc_solver,\n    full_flow_empirical_gauss_solver,\n    full_flow_sequential_solver,\n    full_flow_turbopark_solver,\n    Grid,\n    PointsGrid,\n    sequential_solver,\n    State,\n    TurbineCubatureGrid,\n    TurbineGrid,\n    turbopark_solver,\n    WakeModelManager,\n)\nfrom floris.type_dec import NDArrayFloat\nfrom floris.utilities import (\n    load_yaml,\n    reverse_rotate_coordinates_rel_west,\n)\n\n\n@define\nclass Core(BaseClass):\n    \"\"\"\n    Top-level class that describes a Floris model and initializes the\n    simulation. Use the :py:class:`~.simulation.farm.Farm` attribute to\n    access other objects within the model.\n    \"\"\"\n\n    logging: dict = field(converter=dict)\n    solver: dict = field(converter=dict)\n    wake: WakeModelManager = field(converter=WakeModelManager.from_dict)\n    farm: Farm = field(converter=Farm.from_dict)\n    flow_field: FlowField = field(converter=FlowField.from_dict)\n\n    # These fields are included to appease the requirement that all inputs must\n    # be mapped to a field in the class. They are not used in FLORIS.\n    name: str  = field(converter=str)\n    description: str = field(converter=str)\n    floris_version: str = field(converter=str)\n\n    grid: Grid = field(init=False)\n\n    def __attrs_post_init__(self) -> None:\n\n        # Configure logging\n        logging_manager.configure_console_log(\n            self.logging[\"console\"][\"enable\"],\n            self.logging[\"console\"][\"level\"],\n        )\n        logging_manager.configure_file_log(\n            self.logging[\"file\"][\"enable\"],\n            self.logging[\"file\"][\"level\"],\n        )\n\n        # Initialize farm quantities that depend on other objects\n        self.farm.construct_turbine_map()\n        self.farm.construct_turbine_thrust_coefficient_functions()\n        self.farm.construct_turbine_axial_induction_functions()\n        self.farm.construct_turbine_power_functions()\n        self.farm.construct_turbine_power_thrust_tables()\n        self.farm.construct_hub_heights()\n        self.farm.construct_rotor_diameters()\n        self.farm.construct_turbine_TSRs()\n        self.farm.construct_turbine_ref_tilts()\n        self.farm.construct_turbine_tilt_interps()\n        self.farm.construct_turbine_correct_cp_ct_for_tilt()\n        self.farm.set_yaw_angles_to_ref_yaw(self.flow_field.n_findex)\n        self.farm.set_tilt_to_ref_tilt(self.flow_field.n_findex)\n        self.farm.set_power_setpoints_to_ref_power(self.flow_field.n_findex)\n        self.farm.set_awc_modes_to_ref_mode(self.flow_field.n_findex)\n        self.farm.set_awc_amplitudes_to_ref_amp(self.flow_field.n_findex)\n        self.farm.set_awc_frequencies_to_ref_freq(self.flow_field.n_findex)\n\n        if self.solver[\"type\"] == \"turbine_grid\":\n            self.grid = TurbineGrid(\n                turbine_coordinates=self.farm.coordinates,\n                turbine_diameters=self.farm.rotor_diameters,\n                wind_directions=self.flow_field.wind_directions,\n                grid_resolution=self.solver[\"turbine_grid_points\"],\n            )\n        elif self.solver[\"type\"] == \"turbine_cubature_grid\":\n            self.grid = TurbineCubatureGrid(\n                turbine_coordinates=self.farm.coordinates,\n                turbine_diameters=self.farm.rotor_diameters,\n                wind_directions=self.flow_field.wind_directions,\n                grid_resolution=self.solver[\"turbine_grid_points\"],\n            )\n        elif self.solver[\"type\"] == \"flow_field_grid\":\n            self.grid = FlowFieldGrid(\n                turbine_coordinates=self.farm.coordinates,\n                turbine_diameters=self.farm.rotor_diameters,\n                wind_directions=self.flow_field.wind_directions,\n                grid_resolution=self.solver[\"flow_field_grid_points\"],\n            )\n        elif self.solver[\"type\"] == \"flow_field_planar_grid\":\n            self.grid = FlowFieldPlanarGrid(\n                turbine_coordinates=self.farm.coordinates,\n                turbine_diameters=self.farm.rotor_diameters,\n                wind_directions=self.flow_field.wind_directions,\n                normal_vector=self.solver[\"normal_vector\"],\n                planar_coordinate=self.solver[\"planar_coordinate\"],\n                grid_resolution=self.solver[\"flow_field_grid_points\"],\n                x1_bounds=self.solver[\"flow_field_bounds\"][0],\n                x2_bounds=self.solver[\"flow_field_bounds\"][1],\n            )\n        else:\n            raise ValueError(\n                \"Supported solver types are \"\n                \"[turbine_grid, turbine_cubature_grid, flow_field_grid, flow_field_planar_grid], \"\n                f\"but type given was {self.solver['type']}\"\n            )\n\n        if isinstance(self.grid, (TurbineGrid, TurbineCubatureGrid)):\n            self.farm.expand_farm_properties(\n                self.flow_field.n_findex,\n                self.grid.sorted_coord_indices\n            )\n\n    def initialize_domain(self):\n        \"\"\"Initialize solution space prior to wake calculations\"\"\"\n\n        # Initialize field quantities; doing this immediately prior to doing\n        # the calculation step allows for manipulating inputs in a script\n        # without changing the data structures\n        self.flow_field.initialize_velocity_field(self.grid)\n\n        # Initialize farm quantities\n        self.farm.initialize(self.grid.sorted_indices)\n\n        self.state.INITIALIZED\n\n    def steady_state_atmospheric_condition(self):\n        \"\"\"Perform the steady-state wind farm wake calculations. Note that\n        initialize_domain() is required to be called before this function.\"\"\"\n\n        vel_model = self.wake.model_strings[\"velocity_model\"]\n\n        if vel_model not in [\"empirical_gauss\"] and \\\n            self.farm.correct_cp_ct_for_tilt.any():\n            self.logger.warning(\n                \"The current model does not account for vertical wake deflection due to \" +\n                \"tilt. Corrections to power and thrust coefficient can be included, but no \" +\n                \"vertical wake deflection will occur.\"\n            )\n\n        operation_model_awc = False\n        for td in self.farm.turbine_definitions:\n            if \"operation_model\" in td and td[\"operation_model\"] == \"awc\":\n                operation_model_awc = True\n        if vel_model != \"empirical_gauss\" and operation_model_awc:\n            self.logger.warning(\n                f\"The current model `{vel_model}` does not account for additional wake mixing \" +\n                \"due to active wake control. Corrections to power and thrust coefficient can \" +\n                \"be included, but no enhanced wake recovery will occur.\"\n            )\n\n        if vel_model==\"cc\":\n            cc_solver(\n                self.farm,\n                self.flow_field,\n                self.grid,\n                self.wake\n            )\n        elif vel_model==\"turbopark\":\n            self.logger.warning(\n                \"The turbopark model has been superseded by the turboparkgauss model. We \" +\n                \"recommend using `velocity_model: turboparkgauss` instead.\"\n            )\n            turbopark_solver(\n                self.farm,\n                self.flow_field,\n                self.grid,\n                self.wake\n            )\n        elif vel_model==\"empirical_gauss\":\n            empirical_gauss_solver(\n                self.farm,\n                self.flow_field,\n                self.grid,\n                self.wake\n            )\n        else:\n            sequential_solver(\n                self.farm,\n                self.flow_field,\n                self.grid,\n                self.wake\n            )\n\n        self.finalize()\n\n    def solve_for_viz(self):\n        # Do the calculation with the TurbineGrid for a single wind speed\n        # and wind direction and 1 point on the grid. Then, use the result\n        # to construct the full flow field grid.\n        # This function call should be for a single wind direction and wind speed\n        # since the memory consumption is very large.\n\n        self.flow_field.initialize_velocity_field(self.grid)\n\n        vel_model = self.wake.model_strings[\"velocity_model\"]\n\n        if vel_model==\"cc\":\n            full_flow_cc_solver(self.farm, self.flow_field, self.grid, self.wake)\n        elif vel_model==\"turbopark\":\n            full_flow_turbopark_solver(self.farm, self.flow_field, self.grid, self.wake)\n        elif vel_model==\"empirical_gauss\":\n            full_flow_empirical_gauss_solver(self.farm, self.flow_field, self.grid, self.wake)\n        else:\n            full_flow_sequential_solver(self.farm, self.flow_field, self.grid, self.wake)\n\n    def solve_for_points(self, x, y, z):\n        # Do the calculation with the TurbineGrid for a single wind speed\n        # and wind direction and a 3x3 rotor grid. Then, use the result\n        # to construct the full flow field grid.\n        # This function call should be for a single wind direction and wind speed\n        # since the memory consumption is very large.\n\n        # Instantiate the flow_grid\n        field_grid = PointsGrid(\n            points_x=x,\n            points_y=y,\n            points_z=z,\n            turbine_coordinates=self.farm.coordinates,\n            turbine_diameters=self.farm.rotor_diameters,\n            wind_directions=self.flow_field.wind_directions,\n            grid_resolution=1,\n            x_center_of_rotation=self.grid.x_center_of_rotation,\n            y_center_of_rotation=self.grid.y_center_of_rotation\n        )\n\n        self.flow_field.initialize_velocity_field(field_grid)\n\n        vel_model = self.wake.model_strings[\"velocity_model\"]\n\n        if vel_model == \"turbopark\":\n            raise NotImplementedError(\n                \"solve_for_points is not available for the legacy \\'turbopark\\' model. \"\n                \"However, it is available for \\'turboparkgauss\\'.\"\n            )\n        elif vel_model == \"empirical_gauss\":\n            full_flow_empirical_gauss_solver(self.farm, self.flow_field, field_grid, self.wake)\n        elif vel_model == \"cc\":\n            full_flow_cc_solver(self.farm, self.flow_field, field_grid, self.wake)\n        else:\n            full_flow_sequential_solver(self.farm, self.flow_field, field_grid, self.wake)\n\n        return self.flow_field.u_sorted[:,:,0,0] # Remove turbine grid dimensions\n\n    def solve_for_velocity_deficit_profiles(\n        self,\n        direction: str,\n        downstream_dists: NDArrayFloat | list,\n        profile_range: NDArrayFloat | list,\n        resolution: int,\n        homogeneous_wind_speed: float,\n        ref_rotor_diameter: float,\n        x_start: float,\n        y_start: float,\n        reference_height: float,\n    ) -> list[pd.DataFrame]:\n        \"\"\"\n        Extract velocity deficit profiles. See\n        :py:meth:`~floris.floris_model.FlorisModel.sample_velocity_deficit_profiles`\n        for more details.\n        \"\"\"\n\n        # Create a grid that contains coordinates for all the sample points in all profiles.\n        # Effectively, this is a grid of parallel lines.\n        n_lines = len(downstream_dists)\n\n        # Coordinate system (x1, x2, x3) is used to define the sample points. The origin is at\n        # (x_start, y_start, reference_height) and x1 is in the streamwise direction.\n        # The x1-coordinate is fixed for every line (every row in  `x1`).\n        x1 = np.atleast_2d(downstream_dists).T * np.ones((n_lines, resolution))\n\n        if resolution == 1:\n            single_line = [0.0]\n        else:\n            single_line = np.linspace(profile_range[0], profile_range[1], resolution)\n\n        if direction == 'cross-stream':\n            x2 = single_line * np.ones((n_lines, resolution))\n            x3 = np.zeros((n_lines, resolution))\n        elif direction == 'vertical':\n            x3 = single_line * np.ones((n_lines, resolution))\n            x2 = np.zeros((n_lines, resolution))\n\n        # Find the coordinates of the sample points in the inertial frame (x, y, z). This is done\n        # through one rotation and one translation.\n        x, y, z = reverse_rotate_coordinates_rel_west(\n            self.flow_field.wind_directions,\n            x1[None, :, :],\n            x2[None, :, :],\n            x3[None, :, :],\n            x_center_of_rotation=0.0,\n            y_center_of_rotation=0.0,\n        )\n        x = np.squeeze(x, axis=0) + x_start\n        y = np.squeeze(y, axis=0) + y_start\n        z = np.squeeze(z, axis=0) + reference_height\n\n        u = self.solve_for_points(x.flatten(), y.flatten(), z.flatten())\n        u = np.reshape(u[0, :], (n_lines, resolution))\n        velocity_deficit = (homogeneous_wind_speed - u) / homogeneous_wind_speed\n\n        velocity_deficit_profiles = []\n\n        for i in range(n_lines):\n            df = pd.DataFrame(\n                {\n                    'x': x[i],\n                    'y': y[i],\n                    'z': z[i],\n                    'x1/D': x1[i]/ref_rotor_diameter,\n                    'x2/D': x2[i]/ref_rotor_diameter,\n                    'x3/D': x3[i]/ref_rotor_diameter,\n                    'velocity_deficit': velocity_deficit[i],\n                }\n            )\n            velocity_deficit_profiles.append(df)\n\n        return velocity_deficit_profiles\n\n    def finalize(self):\n        # Once the wake calculation is finished, unsort the values to match\n        # the user-supplied order of things.\n        self.flow_field.finalize(self.grid.unsorted_indices)\n        self.farm.finalize(self.grid.unsorted_indices)\n        self.state = State.USED\n\n    ## I/O\n\n    @classmethod\n    def from_file(cls, input_file_path: str | Path) -> Core:\n        \"\"\"Creates a `Floris` instance from an input file. Must be filetype YAML.\n\n        Args:\n            input_file_path (str): The relative or absolute file path and name to the\n                input file.\n\n        Returns:\n            Floris: The class object instance.\n        \"\"\"\n        input_dict = load_yaml(Path(input_file_path).resolve())\n        check_input_file_for_v3_keys(input_dict)\n        return Core.from_dict(input_dict)\n\n    def to_file(self, output_file_path: str) -> None:\n        \"\"\"Converts the `Floris` object to an input-ready YAML file at `output_file_path`.\n\n        Args:\n            output_file_path (str): The full path and filename for where to save the file.\n        \"\"\"\n        with open(output_file_path, \"w+\") as f:\n            yaml.dump(\n                self.as_dict(),\n                f,\n                sort_keys=False,\n                default_flow_style=False\n            )\n\ndef check_input_file_for_v3_keys(input_dict) -> None:\n    \"\"\"\n    Checks if any FLORIS v3 keys are present in the input file and raises special errors if\n    the extra keys belong to a v3 definition of the input_dct.\n    and raises special errors if the extra arguments belong to a v3 definition of the class.\n\n    Args:\n        input_dict (dict): The input dictionary to be checked for v3 keys.\n    \"\"\"\n    v3_deprecation_msg = (\n        \"Consider using the convert_floris_input_v3_to_v4.py utility in floris/tools \"\n        \"to convert from a FLORIS v3 input file to FLORIS v4. \"\n        \"See https://natlabrockies.github.io/floris/upgrade_guides/v3_to_v4.html \"\n        \"for more information.\"\n    )\n    if \"turbulence_intensity\" in input_dict[\"flow_field\"]:\n        raise AttributeError(\n            \"turbulence_intensity has been updated to turbulence_intensities in FLORIS v4. \"\n            + v3_deprecation_msg\n        )\n    elif not hasattr(input_dict[\"flow_field\"][\"turbulence_intensities\"], \"__len__\"):\n        raise AttributeError(\n            \"turbulence_intensities must be a list of floats in FLORIS v4. \"\n            + v3_deprecation_msg\n        )\n\n    if input_dict[\"wake\"][\"model_strings\"][\"velocity_model\"] == \"multidim_cp_ct\":\n        raise AttributeError(\n            \"Dedicated 'multidim_cp_ct' velocity model has been removed in FLORIS v4 in favor of \"\n            + \"supporting all available wake models. To recover previous operation, set \"\n            + \"velocity_model to gauss. \"\n            + v3_deprecation_msg\n        )\n"
  },
  {
    "path": "floris/core/farm.py",
    "content": "import copy\nfrom collections.abc import Callable\nfrom pathlib import Path\nfrom typing import (\n    Any,\n    Dict,\n    List,\n)\n\nimport attrs\nimport numpy as np\nfrom attrs import define, field\nfrom scipy.interpolate import interp1d\n\nfrom floris.core import (\n    BaseClass,\n    State,\n    Turbine,\n)\nfrom floris.core.rotor_velocity import compute_tilt_angles_for_floating_turbines_map\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT\nfrom floris.type_dec import (\n    convert_to_path,\n    floris_array_converter,\n    iter_validator,\n    NDArrayFloat,\n    NDArrayObject,\n    NDArrayStr,\n)\nfrom floris.utilities import load_yaml\n\n\ndefault_turbine_library_path = Path(__file__).parents[1] / \"turbine_library\"\n\n\n@define\nclass Farm(BaseClass):\n    \"\"\"Farm is where wind power plants should be instantiated from a YAML configuration\n    file. The Farm will create a heterogeneous set of turbines that compose a wind farm,\n    validate the inputs, and then create a vectorized representation of the the turbine\n    data.\n\n    Farm is the container class of the FLORIS package. It brings\n    together all of the component objects after input (i.e., Turbine,\n    Wake, FlowField) and packages everything into the appropriate data\n    type. Farm should also be used as an entry point to probe objects\n    for generating output.\n\n    Args:\n        layout_x (NDArrayFloat): A sequence of x-axis locations for the turbines that can be\n            converted to a 1-D :py:obj:`numpy.ndarray`.\n        layout_y (NDArrayFloat): A sequence of y-axis locations for the turbines that can be\n            converted to a 1-D :py:obj:`numpy.ndarray`.\n        turbine_type (list[dict | str]): A list of turbine definition dictionaries, or string\n            references to the filename of the turbine type in either the FLORIS-provided turbine\n            library (.../floris/turbine_library/), or a user-provided\n            :py:attr:`turbine_library_path`.\n        turbine_library_path (:obj:`str`): Either an absolute file path to the turbine library, or a\n            path relative to the file that is running the analysis.\n    \"\"\"\n\n    layout_x: NDArrayFloat = field(converter=floris_array_converter)\n    layout_y: NDArrayFloat = field(converter=floris_array_converter)\n    # TODO: turbine_type should be immutable\n    turbine_type: List = field(validator=iter_validator(list, (dict, str)))\n    turbine_library_path: Path = field(\n        default=default_turbine_library_path, converter=convert_to_path\n    )\n\n    turbine_definitions: list = field(init=False, validator=iter_validator(list, dict))\n\n    turbine_thrust_coefficient_functions: Dict[str, Callable] = field(init=False, factory=list)\n    turbine_axial_induction_functions: Dict[str, Callable] = field(init=False, factory=list)\n\n    turbine_tilt_interps: dict[str, interp1d] = field(init=False, factory=dict)\n\n    yaw_angles: NDArrayFloat = field(init=False)\n    yaw_angles_sorted: NDArrayFloat = field(init=False)\n\n    tilt_angles: NDArrayFloat = field(init=False)\n    tilt_angles_sorted: NDArrayFloat = field(init=False)\n\n    power_setpoints: NDArrayFloat = field(init=False)\n    power_setpoints_sorted: NDArrayFloat = field(init=False)\n\n    awc_modes: NDArrayStr = field(init=False)\n    awc_modes_sorted: NDArrayStr = field(init=False)\n\n    awc_amplitudes: NDArrayFloat = field(init=False)\n    awc_amplitudes_sorted: NDArrayFloat = field(init=False)\n\n    awc_frequencies: NDArrayFloat = field(init=False)\n    awc_frequencies_sorted: NDArrayFloat = field(init=False)\n\n    hub_heights: NDArrayFloat = field(init=False)\n    hub_heights_sorted: NDArrayFloat = field(init=False, factory=list)\n\n    turbine_map: List[Turbine] = field(init=False, factory=list)\n\n    turbine_type_map: NDArrayObject = field(init=False, factory=list)\n    turbine_type_map_sorted: NDArrayObject = field(init=False, factory=list)\n\n    turbine_power_functions: Dict[str, Callable] = field(init=False, factory=list)\n    turbine_power_thrust_tables: Dict[str, dict] = field(init=False, factory=list)\n\n    rotor_diameters: NDArrayFloat = field(init=False, factory=list)\n    rotor_diameters_sorted: NDArrayFloat = field(init=False, factory=list)\n\n    TSRs: NDArrayFloat = field(init=False, factory=list)\n    TSRs_sorted: NDArrayFloat = field(init=False, factory=list)\n\n    ref_tilts: NDArrayFloat = field(init=False, factory=list)\n    ref_tilts_sorted: NDArrayFloat = field(init=False, factory=list)\n\n    correct_cp_ct_for_tilt: NDArrayFloat = field(init=False, factory=list)\n    correct_cp_ct_for_tilt_sorted: NDArrayFloat = field(init=False, factory=list)\n\n    internal_turbine_library: Path = field(init=False, default=default_turbine_library_path)\n\n    # Private attributes\n    _turbine_types: List = field(init=False, validator=iter_validator(list, str), factory=list)\n    _turbine_definition_cache: dict = field(init=False, factory=dict)\n\n    def __attrs_post_init__(self) -> None:\n        # Turbine definitions can be supplied in three ways:\n        # - A string selecting a turbine in the floris turbine library\n        # - A Python dict representation of a turbine definition\n        #   - There's an option to use the yaml keyword \"!include\" which results in the yaml\n        #     library preprocessing the inputs and loading the specified file directly into\n        #     the main input file. The result is that floris sees the turbine definition as a dict.\n        # - A string selecting an turbine that exists in an external turbine library\n        #   specified in `turbine_library_path`\n\n        # Load all the turbine types into a cache to be mapped to specific turbine indices later.\n        # This allows to read the yaml input files once rather than every time they're given.\n        # In other words, if the turbine type is already in the cache, skip that iteration of\n        # the for-loop.\n\n        for t in self.turbine_type:\n            # If a turbine type is a dict, then it was either preprocessed by the yaml\n            # library to resolve the \"!include\" or it was set in a script as a dict. In either case,\n            # add an entry to the cache\n            if isinstance(t, dict):\n                if t[\"turbine_type\"] in self._turbine_definition_cache:\n                    if self._turbine_definition_cache[t[\"turbine_type\"]] == t:\n                        continue # Skip t if already loaded\n                    else:\n                        raise ValueError(\n                            \"Two different turbine definitions have the same name: \"\\\n                            f\"'{t['turbine_type']}'. \"\\\n                            \"Please specify a unique 'turbine_type' for each turbine definition.\"\n                        )\n                self._turbine_definition_cache[t[\"turbine_type\"]] = t\n                self._turbine_definition_cache[t[\"turbine_type\"]][\"turbine_library_path\"] = (\n                    self.turbine_library_path\n                )\n\n            # If a turbine type is a string, then it is expected in the internal or external\n            # turbine library\n            if isinstance(t, str):\n                if t in self._turbine_definition_cache:\n                    continue # Skip t if already loaded\n\n                # Check if the file exists in the internal and/or external library\n                internal_fn = (self.internal_turbine_library / t).with_suffix(\".yaml\")\n                external_fn = (self.turbine_library_path / t).with_suffix(\".yaml\")\n                in_internal = internal_fn.exists()\n                in_external = external_fn.exists()\n\n                # If an external library is used and there's a duplicate of an internal\n                # definition, then raise an error\n                is_unique_path = self.turbine_library_path != default_turbine_library_path\n                if is_unique_path and in_external and in_internal:\n                    raise ValueError(\n                        f\"The turbine type: {t} exists in both the internal and external\"\n                        \" turbine library.\"\n                    )\n\n                if in_internal:\n                    full_path = internal_fn\n                elif in_external:\n                    full_path = external_fn\n                else:\n                    raise FileNotFoundError(\n                        f\"The turbine type: {t} does not exist in either the internal or\"\n                        \" external turbine library.\"\n                    )\n                self._turbine_definition_cache[t] = load_yaml(full_path)\n                self._turbine_definition_cache[t][\"turbine_library_path\"] = (\n                    self.turbine_library_path\n                )\n\n        # Convert any dict entries in the turbine_type list to the type string. Since the\n        # definition is saved above, we can make the whole list consistent now to use it\n        # for mapping turbines later.\n        # We use a private variable here instead of self.turbine_type because self.turbine_type\n        # should always retain the input data. When this class is exported as_dict, the input\n        # types must be used. If we modify that directly and change its shape, recreating this\n        # class with a different layout but not a new self.turbine_type could cause the data\n        # to be out of sync.\n        self._turbine_types = [\n            copy.deepcopy(t[\"turbine_type\"]) if isinstance(t, dict) else t\n            for t in self.turbine_type\n        ]\n\n        # If 1 turbine definition is given, expand to N turbines; this covers a 1-turbine\n        # farm and 1 definition for multiple turbines\n        if len(self._turbine_types) == 1:\n            self._turbine_types *= self.n_turbines\n\n        # Check that turbine definitions contain any v3 keys\n        for _, v in self._turbine_definition_cache.items():\n            check_turbine_definition_for_v3_keys(v)\n\n        # Map each turbine definition to its index in this list\n        self.turbine_definitions = [\n            copy.deepcopy(self._turbine_definition_cache[t]) for t in self._turbine_types\n        ]\n\n    @layout_x.validator\n    def check_x(self, attribute: attrs.Attribute, value: Any) -> None:\n        if len(value) != len(self.layout_y):\n            raise ValueError(\"layout_x and layout_y must have the same number of entries.\")\n\n    @layout_y.validator\n    def check_y(self, attribute: attrs.Attribute, value: Any) -> None:\n        if len(value) != len(self.layout_x):\n            raise ValueError(\"layout_x and layout_y must have the same number of entries.\")\n\n    @turbine_type.validator\n    def check_turbine_type(self, attribute: attrs.Attribute, value: Any) -> None:\n        # Check that the list of turbines is either of length 1 or N turbines\n        if len(value) != 1 and len(value) != self.n_turbines:\n            raise ValueError(\n                \"turbine_type must have the same number of entries as layout_x/layout_y or have \"\n                \"a single turbine_type value. This error can arise if you set the turbine_type or \"\n                \"alter the operation model before setting the layout.\"\n            )\n\n    @turbine_library_path.validator\n    def check_library_path(self, attribute: attrs.Attribute, value: Path) -> None:\n        \"\"\"Ensures that the input to `library_path` exists and is a directory.\"\"\"\n        if not value.is_dir():\n            raise FileExistsError(f\"The input file path: {str(value)} is not a valid directory.\")\n\n    def initialize(self, sorted_indices):\n        # Sort yaw angles from most upstream to most downstream wind turbine\n        self.yaw_angles_sorted = np.take_along_axis(\n            self.yaw_angles,\n            sorted_indices[:, :, 0, 0],\n            axis=1,\n        )\n        self.tilt_angles_sorted = np.take_along_axis(\n            self.tilt_angles,\n            sorted_indices[:, :, 0, 0],\n            axis=1,\n        )\n        self.power_setpoints_sorted = np.take_along_axis(\n            self.power_setpoints,\n            sorted_indices[:, :, 0, 0],\n            axis=1,\n        )\n        self.awc_modes_sorted = np.take_along_axis(\n            self.awc_modes,\n            sorted_indices[:, :, 0, 0],\n            axis=1,\n        )\n        self.awc_amplitudes_sorted = np.take_along_axis(\n            self.awc_amplitudes,\n            sorted_indices[:, :, 0, 0],\n            axis=1,\n        )\n        self.awc_frequencies_sorted = np.take_along_axis(\n            self.awc_frequencies,\n            sorted_indices[:, :, 0, 0],\n            axis=1,\n        )\n        self.state = State.INITIALIZED\n\n    def construct_hub_heights(self):\n        self.hub_heights = np.array([turb['hub_height'] for turb in self.turbine_definitions])\n\n    def construct_rotor_diameters(self):\n        self.rotor_diameters = np.array([\n            turb['rotor_diameter'] for turb in self.turbine_definitions\n        ])\n\n    def construct_turbine_TSRs(self):\n        self.TSRs = np.array([turb['TSR'] for turb in self.turbine_definitions])\n\n    def construct_turbine_ref_tilts(self):\n        self.ref_tilts = np.array(\n            [turb['power_thrust_table']['ref_tilt'] for turb in self.turbine_definitions]\n        )\n\n    def construct_turbine_correct_cp_ct_for_tilt(self):\n        self.correct_cp_ct_for_tilt = np.array(\n            [turb.correct_cp_ct_for_tilt for turb in self.turbine_map]\n        )\n\n    def construct_turbine_map(self):\n        turbine_map_unique = {\n            k: Turbine.from_dict(v) for k, v in self._turbine_definition_cache.items()\n        }\n        self.turbine_map = [turbine_map_unique[k] for k in self._turbine_types]\n\n    def construct_turbine_thrust_coefficient_functions(self):\n        self.turbine_thrust_coefficient_functions = {\n            turb.turbine_type: turb.thrust_coefficient_function for turb in self.turbine_map\n        }\n\n    def construct_turbine_axial_induction_functions(self):\n        self.turbine_axial_induction_functions = {\n            turb.turbine_type: turb.axial_induction_function for turb in self.turbine_map\n        }\n\n    def construct_turbine_tilt_interps(self):\n        self.turbine_tilt_interps = {\n            turb.turbine_type: turb.tilt_interp for turb in self.turbine_map\n        }\n\n    def construct_turbine_power_functions(self):\n        self.turbine_power_functions = {\n            turb.turbine_type: turb.power_function for turb in self.turbine_map\n        }\n\n    def construct_turbine_power_thrust_tables(self):\n        self.turbine_power_thrust_tables = {\n            turb.turbine_type: turb.power_thrust_table for turb in self.turbine_map\n        }\n\n    def expand_farm_properties(self, n_findex: int, sorted_coord_indices):\n        template_shape = np.ones_like(sorted_coord_indices)\n        self.hub_heights_sorted = np.take_along_axis(\n            self.hub_heights * template_shape,\n            sorted_coord_indices,\n            axis=1\n        )\n        self.rotor_diameters_sorted = np.take_along_axis(\n            self.rotor_diameters * template_shape,\n            sorted_coord_indices,\n            axis=1\n        )\n        self.TSRs_sorted = np.take_along_axis(\n            self.TSRs * template_shape,\n            sorted_coord_indices,\n            axis=1\n        )\n        self.ref_tilts_sorted = np.take_along_axis(\n            self.ref_tilts * template_shape,\n            sorted_coord_indices,\n            axis=1\n        )\n        self.correct_cp_ct_for_tilt_sorted = np.take_along_axis(\n            self.correct_cp_ct_for_tilt * template_shape,\n            sorted_coord_indices,\n            axis=1\n        )\n\n        # NOTE: Tilt angles are sorted twice - here and in initialize()\n        self.tilt_angles_sorted = np.take_along_axis(\n            self.tilt_angles * template_shape,\n            sorted_coord_indices,\n            axis=1\n        )\n        self.turbine_type_map_sorted = np.take_along_axis(\n            np.reshape(\n                [turb[\"turbine_type\"] for turb in self.turbine_definitions] * n_findex,\n                np.shape(sorted_coord_indices)\n            ),\n            sorted_coord_indices,\n            axis=1\n        )\n\n    def set_yaw_angles(self, yaw_angles: NDArrayFloat | list[float]):\n        self.yaw_angles = np.array(yaw_angles)\n\n    def set_yaw_angles_to_ref_yaw(self, n_findex: int):\n        yaw_angles = np.zeros((n_findex, self.n_turbines))\n        self.set_yaw_angles(yaw_angles)\n        self.yaw_angles_sorted = np.zeros((n_findex, self.n_turbines))\n\n    def set_tilt_to_ref_tilt(self, n_findex: int):\n        self.tilt_angles = (\n            np.ones((n_findex, self.n_turbines))\n            * self.ref_tilts\n        )\n        self.tilt_angles_sorted = (\n            np.ones((n_findex, self.n_turbines))\n            * self.ref_tilts\n        )\n\n    def set_power_setpoints(self, power_setpoints: NDArrayFloat):\n        self.power_setpoints = np.array(power_setpoints)\n\n    def set_power_setpoints_to_ref_power(self, n_findex: int):\n        power_setpoints = POWER_SETPOINT_DEFAULT * np.ones((n_findex, self.n_turbines))\n        self.set_power_setpoints(power_setpoints)\n        self.power_setpoints_sorted = POWER_SETPOINT_DEFAULT * np.ones((n_findex, self.n_turbines))\n\n    def set_awc_modes(self, awc_modes: NDArrayStr):\n        self.awc_modes = np.array(awc_modes)\n\n    def set_awc_modes_to_ref_mode(self, n_findex: int):\n        # awc_modes = np.empty((n_findex, self.n_turbines))\\\n        awc_modes = np.array([[\"baseline\"]*self.n_turbines]*n_findex)\n        self.set_awc_modes(awc_modes)\n        # self.awc_modes_sorted = np.empty((n_findex, self.n_turbines))\n        self.awc_modes_sorted = np.array([[\"baseline\"]*self.n_turbines]*n_findex)\n\n    def set_awc_amplitudes(self, awc_amplitudes: NDArrayFloat):\n        self.awc_amplitudes = np.array(awc_amplitudes)\n\n    def set_awc_amplitudes_to_ref_amp(self, n_findex: int):\n        awc_amplitudes = np.zeros((n_findex, self.n_turbines))\n        self.set_awc_amplitudes(awc_amplitudes)\n        self.awc_amplitudes_sorted = np.zeros((n_findex, self.n_turbines))\n\n    def set_awc_frequencies(self, awc_frequencies: NDArrayFloat):\n        self.awc_frequencies = np.array(awc_frequencies)\n\n    def set_awc_frequencies_to_ref_freq(self, n_findex: int):\n        awc_frequencies = np.zeros((n_findex, self.n_turbines))\n        self.set_awc_frequencies(awc_frequencies)\n        self.awc_frequencies_sorted = np.zeros((n_findex, self.n_turbines))\n\n    def calculate_tilt_for_eff_velocities(self, rotor_effective_velocities):\n        tilt_angles = compute_tilt_angles_for_floating_turbines_map(\n            self.turbine_type_map_sorted,\n            self.tilt_angles_sorted,\n            self.turbine_tilt_interps,\n            rotor_effective_velocities,\n        )\n        return tilt_angles\n\n    def finalize(self, unsorted_indices):\n        self.yaw_angles = np.take_along_axis(\n            self.yaw_angles_sorted,\n            unsorted_indices[:,:,0,0],\n            axis=1\n        )\n        self.tilt_angles = np.take_along_axis(\n            self.tilt_angles_sorted,\n            unsorted_indices[:,:,0,0],\n            axis=1\n        )\n        self.hub_heights = np.take_along_axis(\n            self.hub_heights_sorted,\n            unsorted_indices[:,:,0,0],\n            axis=1\n        )\n        self.rotor_diameters = np.take_along_axis(\n            self.rotor_diameters_sorted,\n            unsorted_indices[:,:,0,0],\n            axis=1\n        )\n        self.TSRs = np.take_along_axis(\n            self.TSRs_sorted,\n            unsorted_indices[:,:,0,0],\n            axis=1\n        )\n        self.ref_tilts = np.take_along_axis(\n            self.ref_tilts_sorted,\n            unsorted_indices[:,:,0,0],\n            axis=1\n        )\n        self.correct_cp_ct_for_tilt = np.take_along_axis(\n            self.correct_cp_ct_for_tilt_sorted,\n            unsorted_indices[:,:,0,0],\n            axis=1\n        )\n        self.turbine_type_map = np.take_along_axis(\n            self.turbine_type_map_sorted,\n            unsorted_indices[:,:,0,0],\n            axis=1\n        )\n        self.state.USED\n\n    @property\n    def coordinates(self):\n        return np.array([\n            np.array([x, y, z]) for x, y, z in zip(\n                self.layout_x,\n                self.layout_y,\n                self.hub_heights if len(self.hub_heights.shape) == 1 else self.hub_heights[0]\n            )\n        ])\n\n    @property\n    def n_turbines(self):\n        return len(self.layout_x)\n\ndef check_turbine_definition_for_v3_keys(turbine_definition: dict):\n    \"\"\"Check that the turbine definition does not contain any v3 keys.\"\"\"\n    v3_deprecation_msg = (\n        \"Consider using the convert_turbine_v3_to_v4.py utility in floris/tools \"\n        + \"to convert from a FLORIS v3 turbine definition to FLORIS v4. \"\n        + \"See https://natlabrockies.github.io/floris/v3_to_v4.html for more information.\"\n    )\n    if \"generator_efficiency\" in turbine_definition:\n        raise ValueError(\n            \"generator_efficiency is no longer supported as power is specified in absolute terms \"\n            + \"in FLORIS v4. \"\n            + v3_deprecation_msg\n        )\n\n    v3_renamed_keys = [\"pP\", \"pT\", \"ref_density_cp_ct\", \"ref_tilt_cp_ct\"]\n    if any(k in turbine_definition for k in v3_renamed_keys):\n        v3_list_keys = \", \".join(map(str,v3_renamed_keys[:-1]))+\", and \"+v3_renamed_keys[-1]\n        v4_versions = (\n            \"cosine_loss_exponent_yaw, cosine_loss_exponent_tilt, ref_air_density, and ref_tilt\"\n        )\n        raise ValueError(\n            v3_list_keys\n            + \" have been renamed to \"\n            + v4_versions\n            + \", respectively, and placed under the power_thrust_table field in FLORIS v4. \"\n            + v3_deprecation_msg\n        )\n\n    if \"thrust\" in turbine_definition[\"power_thrust_table\"]:\n        raise ValueError(\n            \"thrust has been renamed thrust_coefficient in FLORIS v4 (and power is now specified \"\n            \"in absolute terms with units kW, rather than as a coefficient). \"\n            + v3_deprecation_msg\n        )\n"
  },
  {
    "path": "floris/core/flow_field.py",
    "content": "import copy\n\nimport attrs\nimport matplotlib.path as mpltPath\nimport numpy as np\nfrom attrs import define, field\nfrom scipy.interpolate import LinearNDInterpolator, NearestNDInterpolator\nfrom scipy.spatial import ConvexHull\nfrom shapely.geometry import Polygon\n\nfrom floris.core import (\n    BaseClass,\n    Grid,\n    PointsGrid,\n)\nfrom floris.type_dec import (\n    floris_array_converter,\n    NDArrayFloat,\n    NDArrayObject,\n)\n\n\n@define\nclass FlowField(BaseClass):\n    wind_speeds: NDArrayFloat = field(converter=floris_array_converter)\n    wind_directions: NDArrayFloat = field(converter=floris_array_converter)\n    wind_veer: float = field(converter=float)\n    wind_shear: float = field(converter=float)\n    air_density: float = field(converter=float)\n    turbulence_intensities: NDArrayFloat = field(converter=floris_array_converter)\n    reference_wind_height: float = field(converter=float)\n    heterogeneous_inflow_config: dict = field(default=None)\n    multidim_conditions: dict = field(default=None)\n\n    n_findex: int = field(init=False)\n    u_initial_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    v_initial_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    w_initial_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    u_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    v_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    w_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    u: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    v: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    w: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    het_map: NDArrayObject = field(init=False, default=None)\n    dudz_initial_sorted: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n\n    turbulence_intensity_field: NDArrayFloat = field(init=False, factory=lambda: np.array([]))\n    turbulence_intensity_field_sorted: NDArrayFloat = field(\n        init=False, factory=lambda: np.array([])\n    )\n    turbulence_intensity_field_sorted_avg: NDArrayFloat = field(\n        init=False, factory=lambda: np.array([])\n    )\n\n    @turbulence_intensities.validator\n    def turbulence_intensities_validator(\n        self, instance: attrs.Attribute, value: NDArrayFloat\n    ) -> None:\n\n        # Check that the array is 1-dimensional\n        if value.ndim != 1:\n            raise ValueError(\n                \"turbulence_intensities must have 1-dimension\"\n            )\n\n        # Check the turbulence intensity is length n_findex\n        if len(value) != self.n_findex:\n            raise ValueError(\"turbulence_intensities must be length n_findex\")\n\n\n\n    @wind_directions.validator\n    def wind_directions_validator(self, instance: attrs.Attribute, value: NDArrayFloat) -> None:\n        # Check that the array is 1-dimensional\n        if self.wind_directions.ndim != 1:\n            raise ValueError(\n                \"wind_directions must have 1-dimension\"\n            )\n\n        \"\"\"Using the validator method to keep the `n_findex` attribute up to date.\"\"\"\n        self.n_findex = value.size\n\n    @wind_speeds.validator\n    def wind_speeds_validator(self, instance: attrs.Attribute, value: NDArrayFloat) -> None:\n\n        # Check that the array is 1-dimensional\n        if self.wind_speeds.ndim != 1:\n            raise ValueError(\n                \"wind_speeds must have 1-dimension\"\n            )\n\n        \"\"\"Confirm wind speeds and wind directions have the same length\"\"\"\n        if len(self.wind_directions) != len(self.wind_speeds):\n            raise ValueError(\n                f\"wind_directions (length = {len(self.wind_directions)}) and \"\n                f\"wind_speeds (length = {len(self.wind_speeds)}) must have the same length\"\n            )\n\n    @heterogeneous_inflow_config.validator\n    def heterogeneous_config_validator(self, instance: attrs.Attribute, value: dict | None) -> None:\n        \"\"\"Using the validator method to check that the heterogeneous_inflow_config dictionary has\n        the correct key-value pairs.\n        \"\"\"\n        if value is None:\n            return\n\n        # Check that the correct keys are supplied for the heterogeneous_inflow_config dict\n        for k in [\"speed_multipliers\", \"x\", \"y\"]:\n            if k not in value.keys():\n                raise ValueError(\n                    \"heterogeneous_inflow_config must contain entries for 'speed_multipliers',\"\n                    f\"'x', and 'y', with 'z' optional. Missing '{k}'.\"\n                )\n        if \"z\" not in value:\n            # If only a 2D case, add \"None\" for the z locations\n            value[\"z\"] = None\n\n        if \"interp_method\" not in value:\n            # If no interpolation method is specified, default to linear\n            value[\"interp_method\"] = \"linear\"\n\n    @het_map.validator\n    def het_map_validator(self, instance: attrs.Attribute, value: list | None) -> None:\n        \"\"\"Using this validator to make sure that the het_map has an interpolant defined for\n        each findex.\n        \"\"\"\n        if value is None:\n            return\n\n        if self.n_findex != np.array(value).shape[0]:\n            raise ValueError(\n                \"The het_map's first dimension not equal to the FLORIS first dimension.\"\n            )\n\n\n    def __attrs_post_init__(self) -> None:\n        if self.heterogeneous_inflow_config is not None:\n            self.generate_heterogeneous_wind_map()\n\n\n    def initialize_velocity_field(self, grid: Grid) -> None:\n\n        # Create an initial wind profile as a function of height. The values here will\n        # be multiplied with the wind speeds to give the initial wind field.\n        # Since we use grid.z, this is a vertical plane for each turbine\n        # Here, the profile is of shape (# turbines, N grid points, M grid points)\n        # This velocity profile is 1.0 at the reference wind height and then follows wind\n        # shear as an exponent.\n        # NOTE: the convention of which dimension on the TurbineGrid is vertical and horizontal is\n        # determined by this line. Since the right-most dimension on grid.z is storing the values\n        # for height, using it here to apply the shear law makes that dimension store the vertical\n        # wind profile.\n\n        # Extract relevant x,y,z locations from the grid object\n        if isinstance(grid, PointsGrid):\n            x = np.tile(grid.points_x[None, :, None, None], (self.n_findex, 1, 1, 1))\n            y = np.tile(grid.points_y[None, :, None, None], (self.n_findex, 1, 1, 1))\n            z = grid.z_sorted\n        else:\n            x = grid.x_sorted_inertial_frame\n            y = grid.y_sorted_inertial_frame\n            z = grid.z_sorted\n\n        wind_profile_plane = (z / self.reference_wind_height) ** self.wind_shear\n        dwind_profile_plane = (\n            self.wind_shear\n            * (1 / self.reference_wind_height) ** self.wind_shear\n            * np.power(\n                z,\n                (self.wind_shear - 1),\n                where=z != 0.0\n            )\n        )\n        # If no heterogeneous inflow defined, then set all speeds ups to 1.0\n        if self.het_map is None:\n            speed_ups = 1.0\n\n        # If heterogeneous flow data is given, the speed ups at the defined\n        # grid locations are determined in either 2 or 3 dimensions.\n        else:\n            if isinstance(self.het_map[0], NearestNDInterpolator):\n                # Do not check for being inside of bounds for nearest neighbor interpolation.\n                pass\n            else:\n                # Create a convex hull around the user-defined heterogeneous inflow bounds\n                # to check if the calculated flow field is within the bounds.\n                bounds = np.array(list(zip(\n                    self.heterogeneous_inflow_config['x'],\n                    self.heterogeneous_inflow_config['y']\n                )))\n                hull = ConvexHull(bounds)\n                polygon = Polygon(bounds[hull.vertices])\n                path = mpltPath.Path(polygon.boundary.coords)\n                inside = path.contains_points(np.column_stack((x.flatten(), y.flatten())))\n                if not np.all(inside):\n                    self.logger.warning(\n                        \"The calculated flow field contains points outside of the the user-defined \"\n                        \"heterogeneous inflow bounds. For these points, the interpolated value has \"\n                        \"been filled with the freestream wind speed. If this is not the desired \"\n                        \"behavior, the user will need to expand the heterogeneous inflow bounds to \"\n                        \"fully cover the calculated flow field area.\"\n                    )\n\n            if len(self.het_map[0].points[0]) == 2:\n                speed_ups = self.calculate_speed_ups(self.het_map, x, y)\n            elif len(self.het_map[0].points[0]) == 3:\n                speed_ups = self.calculate_speed_ups(self.het_map, x, y, z)\n\n        # Create the sheer-law wind profile\n        # This array is of shape (# wind directions, # wind speeds, grid.template_array)\n        # Since generally grid.template_array may be many different shapes, we use transposes\n        # here to do broadcasting from left to right (transposed), and then transpose back.\n        # The result is an array the wind speed and wind direction dimensions on the left side\n        # of the shape and the grid.template array on the right\n        self.u_initial_sorted = (self.wind_speeds.T * wind_profile_plane.T).T * speed_ups\n        self.dudz_initial_sorted = (self.wind_speeds.T * dwind_profile_plane.T).T * speed_ups\n\n        self.v_initial_sorted = np.zeros(\n            np.shape(self.u_initial_sorted),\n            dtype=self.u_initial_sorted.dtype\n        )\n        self.w_initial_sorted = np.zeros(\n            np.shape(self.u_initial_sorted),\n            dtype=self.u_initial_sorted.dtype\n        )\n\n        self.u_sorted = self.u_initial_sorted.copy()\n        self.v_sorted = self.v_initial_sorted.copy()\n        self.w_sorted = self.w_initial_sorted.copy()\n\n        self.turbulence_intensity_field = self.turbulence_intensities[:, None, None, None]\n        self.turbulence_intensity_field = np.repeat(\n            self.turbulence_intensity_field,\n            grid.n_turbines,\n            axis=1\n        )\n\n        self.turbulence_intensity_field_sorted = self.turbulence_intensity_field.copy()\n\n    def finalize(self, unsorted_indices):\n        self.u = np.take_along_axis(self.u_sorted, unsorted_indices, axis=1)\n        self.v = np.take_along_axis(self.v_sorted, unsorted_indices, axis=1)\n        self.w = np.take_along_axis(self.w_sorted, unsorted_indices, axis=1)\n\n        self.turbulence_intensity_field = np.mean(\n            np.take_along_axis(\n                self.turbulence_intensity_field_sorted,\n                unsorted_indices,\n                axis=1\n            ),\n            axis=(2,3)\n        )\n\n    def calculate_speed_ups(self, het_map, x, y, z=None):\n        if z is not None:\n            # Calculate the 3-dimensional speed ups; squeeze is needed as the generator\n            # adds an extra dimension\n            speed_ups = np.squeeze(\n                [het_map[i](x[i:i+1], y[i:i+1], z[i:i+1]) for i in range( len(het_map))],\n                axis=1,\n            )\n\n        else:\n            # Calculate the 2-dimensional speed ups; squeeze is needed as the generator\n            # adds an extra dimension\n            speed_ups = np.squeeze(\n                [het_map[i](x[i:i+1], y[i:i+1]) for i in range(len(het_map))],\n                axis=1,\n            )\n\n        return speed_ups\n\n    def generate_heterogeneous_wind_map(self):\n        \"\"\"This function creates the heterogeneous interpolant used to calculate heterogeneous\n        inflows. The interpolant is for computing wind speed based on an x and y location in the\n        flow field. This is computed using SciPy's LinearNDInterpolator and uses a fill value\n        equal to the freestream for interpolated values outside of the user-defined heterogeneous\n        map bounds.\n\n        Args:\n            heterogeneous_inflow_config (dict): The heterogeneous inflow configuration dictionary.\n            The configuration should have the following inputs specified.\n                - **speed_multipliers** (list): A list of speed up factors that will multiply\n                    the specified freestream wind speed. This 2-dimensional array should have an\n                    array of multiplicative factors defined for each wind direction.\n                - **x** (list): A list of x locations at which the speed up factors are defined.\n                - **y**: A list of y locations at which the speed up factors are defined.\n                - **z** (optional): A list of z locations at which the speed up factors are defined.\n        \"\"\"\n        speed_multipliers = np.array(self.heterogeneous_inflow_config[\"speed_multipliers\"])\n        x = self.heterogeneous_inflow_config[\"x\"]\n        y = self.heterogeneous_inflow_config[\"y\"]\n        z = self.heterogeneous_inflow_config[\"z\"]\n\n        if \"interp_method\" in self.heterogeneous_inflow_config.keys():\n            interp_method = self.heterogeneous_inflow_config[\"interp_method\"]\n        else:\n            interp_method = \"linear\"\n\n        # Declare an empty list to store interpolants by findex\n        interps_f = np.empty(self.n_findex, dtype=object)\n\n        if z is not None:\n            # Compute the 3-dimensional interpolants for each wind direction\n            # Linear interpolation is used for points within the user-defined area of values,\n            # while the freestream wind speed is used for points outside that region.\n\n            # Because the (x,y,z) points are the same for each findex, we create the triangulation\n            # once and then overwrite the values for each findex.\n\n            # Create triangulation using zeroth findex\n            interp_3d = self.interpolate_multiplier_xyz(\n                x,\n                y,\n                z,\n                speed_multipliers[0],\n                fill_value=1.0,\n                interp_method=interp_method,\n            )\n            interp_shape = interp_3d.values.shape\n            # Copy the interpolant for each findex and overwrite the values\n            for findex in range(self.n_findex):\n                interp_3d.values = speed_multipliers[findex, :].reshape(interp_shape)\n                interps_f[findex] = copy.deepcopy(interp_3d)\n\n        else:\n            # Compute the 2-dimensional interpolants for each wind direction\n            # Linear interpolation is used for points within the user-defined area of values,\n            # while the freestream wind speed is used for points outside that region\n\n            # Because the (x,y) points are the same for each findex, we create the triangulation\n            # once and then overwrite the values for each findex.\n\n            # Create triangulation using zeroth findex\n            interp_2d = self.interpolate_multiplier_xy(\n                x, y, speed_multipliers[0], fill_value=1.0, interp_method=interp_method\n            )\n            # Copy the interpolant for each findex and overwrite the values\n            for findex in range(self.n_findex):\n                if interp_method == \"linear\":\n                    interp_2d.values = speed_multipliers[findex, :].reshape(-1, 1)\n                else:\n                    interp_2d.values = speed_multipliers[findex, :]\n                interps_f[findex] = copy.deepcopy(interp_2d)\n\n        self.het_map = interps_f\n\n    @staticmethod\n    def interpolate_multiplier_xy(\n        x: NDArrayFloat,\n        y: NDArrayFloat,\n        multiplier: NDArrayFloat,\n        fill_value: float = 1.0,\n        interp_method: str = \"linear\",\n    ):\n        \"\"\"Return an interpolant for a 2D multiplier field.\n\n        Args:\n            x (NDArrayFloat): x locations\n            y (NDArrayFloat): y locations\n            multiplier (NDArrayFloat): multipliers\n            fill_value (float): fill value for points outside the region\n            interp_method (str): interpolation method, either \"linear\" or \"nearest\".\n                Default is \"linear\".\n\n        Returns:\n            LinearNDInterpolator: interpolant\n        \"\"\"\n        if interp_method == \"linear\":\n            return LinearNDInterpolator(list(zip(x, y)), multiplier, fill_value=fill_value)\n        elif interp_method == \"nearest\":\n            return NearestNDInterpolator(list(zip(x, y)), multiplier)\n        else:\n            raise UserWarning(\"Incompatible interpolation method specified.\")\n\n    @staticmethod\n    def interpolate_multiplier_xyz(\n        x: NDArrayFloat,\n        y: NDArrayFloat,\n        z: NDArrayFloat,\n        multiplier: NDArrayFloat,\n        fill_value: float = 1.0,\n        interp_method: str = \"linear\",\n    ):\n        \"\"\"Return an interpolant for a 3D multiplier field.\n\n        Args:\n            x (NDArrayFloat): x locations\n            y (NDArrayFloat): y locations\n            z (NDArrayFloat): z locations\n            multiplier (NDArrayFloat): multipliers\n            fill_value (float): fill value for points outside the region\n            interp_method (str): interpolation method, either \"linear\" or \"nearest\".\n                Default is \"linear\".\n\n        Returns:\n            LinearNDInterpolator: interpolant\n        \"\"\"\n\n        if interp_method == \"linear\":\n            return LinearNDInterpolator(list(zip(x, y, z)), multiplier, fill_value=fill_value)\n        elif interp_method == \"nearest\":\n            return NearestNDInterpolator(list(zip(x, y, z)), multiplier)\n        else:\n            raise UserWarning(\"Incompatible interpolation method specified.\")\n"
  },
  {
    "path": "floris/core/grid.py",
    "content": "from abc import ABC, abstractmethod\nfrom typing import Iterable\n\nimport attrs\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import BaseClass\nfrom floris.type_dec import (\n    floris_array_converter,\n    floris_float_type,\n    NDArrayFloat,\n    NDArrayInt,\n)\nfrom floris.utilities import (\n    reverse_rotate_coordinates_rel_west,\n    rotate_coordinates_rel_west,\n)\n\n\n@define\nclass Grid(ABC, BaseClass):\n    \"\"\"\n    Grid should establish domain bounds based on given criteria,\n    and develop three arrays to contain components of the grid\n    locations in space. This could be generalized to any number\n    of dimensions to be used by perhaps a turbulence field.\n\n    The grid will have to be reestablished for each wind direction since the planform\n    area of the farm will be different.\n\n    x are the locations in space in the primary direction (typically the direction of the wind)\n    y are the locations in space in the lateral direction\n    z are the locations in space in the vertical direction\n    u are the velocity components at each point in space\n    v are the velocity components at each point in space\n    w are the velocity components at each point in space\n    all of these arrays are the same size\n\n    Args:\n        turbine_coordinates (:py:obj:`NDArrayFloat`): The arrays of turbine coordinates as Numpy\n            arrays with shape (N coordinates, 3).\n        turbine_diameters (:py:obj:`NDArrayFloat`): The rotor diameters of each turbine.\n        wind_directions (:py:obj:`NDArrayFloat`): Wind directions supplied by the user.\n        grid_resolution (:py:obj:`int` | :py:obj:`Iterable(int,)`): Grid resolution with values\n            specific to each grid type.\n    \"\"\"\n    turbine_coordinates: NDArrayFloat = field(converter=floris_array_converter)\n    turbine_diameters: NDArrayFloat = field(converter=floris_array_converter)\n    wind_directions: NDArrayFloat = field(converter=floris_array_converter)\n    grid_resolution: int | Iterable = field()\n\n    n_turbines: int = field(init=False)\n    n_findex: int = field(init=False)\n    x_sorted: NDArrayFloat = field(init=False)\n    y_sorted: NDArrayFloat = field(init=False)\n    z_sorted: NDArrayFloat = field(init=False)\n    x_sorted_inertial_frame: NDArrayFloat = field(init=False)\n    y_sorted_inertial_frame: NDArrayFloat = field(init=False)\n    z_sorted_inertial_frame: NDArrayFloat = field(init=False)\n    cubature_weights: NDArrayFloat = field(init=False, default=None)\n\n    @turbine_coordinates.validator\n    def check_coordinates(self, instance: attrs.Attribute, value: np.ndarray) -> None:\n        \"\"\"\n        Ensures all elements are Numpy arrays and keeps the `n_turbines`\n        attribute up to date.\n        \"\"\"\n        types = np.unique([isinstance(c, np.ndarray) for c in value])\n        if not all(types):\n            raise TypeError(\n                \"'turbine_coordinates' must be `np.array` objects \"\n                \"with three components of type `float`.\"\n            )\n\n        self.n_turbines = len(value)\n\n    @wind_directions.validator\n    def wind_directions_validator(self, instance: attrs.Attribute, value: NDArrayFloat) -> None:\n        \"\"\"Using the validator method to keep the `n_findex` attribute up to date.\"\"\"\n        self.n_findex = value.size\n\n    @grid_resolution.validator\n    def grid_resolution_validator(self, instance: attrs.Attribute, value: int | Iterable) -> None:\n        # TODO move this to the grid types and off of the base class\n        \"\"\"Check that grid resolution is given as appropriate for the chosen Grid-type.\"\"\"\n        if isinstance(value, int) and \\\n            isinstance(self, (TurbineGrid, TurbineCubatureGrid, PointsGrid)):\n            return\n        elif isinstance(value, Iterable) and isinstance(self, FlowFieldPlanarGrid):\n            assert type(value[0]) is int\n            assert type(value[1]) is int\n        elif isinstance(value, Iterable) and isinstance(self, FlowFieldGrid):\n            assert type(value[0]) is int\n            assert type(value[1]) is int\n            assert type(value[2]) is int\n        else:\n            raise TypeError(\"`grid_resolution` must be of type int or Iterable(int,)\")\n\n    @abstractmethod\n    def set_grid(self) -> None:\n        raise NotImplementedError(\"Grid.set_grid\")\n\n@define\nclass TurbineGrid(Grid):\n    \"\"\"See `Grid` for more details.\n\n    Args:\n        turbine_coordinates (:py:obj:`NDArrayFloat`): The arrays of turbine coordinates as Numpy\n            arrays with shape (N coordinates, 3).\n        turbine_diameters (:py:obj:`NDArrayFloat`): The rotor diameters of each turbine.\n        wind_directions (:py:obj:`NDArrayFloat`): Wind directions supplied by the user.\n        grid_resolution (:py:obj:`int`): The number of points in each\n            direction of the square grid on the rotor plane. For example, grid_resolution=3\n            creates a 3x3 grid within the rotor swept area.\n    \"\"\"\n    # TODO: describe these and the differences between `sorted_indices` and `sorted_coord_indices`\n    sorted_indices: NDArrayInt = field(init=False)\n    sorted_coord_indices: NDArrayInt = field(init=False)\n    unsorted_indices: NDArrayInt = field(init=False)\n    x_center_of_rotation: NDArrayFloat = field(init=False)\n    y_center_of_rotation: NDArrayFloat = field(init=False)\n    average_method = \"cubic-mean\"\n\n    def __attrs_post_init__(self) -> None:\n        self.set_grid()\n\n    def set_grid(self) -> None:\n        \"\"\"\n        Create grid points at each turbine for each wind direction and wind speed in the simulation.\n        This creates the underlying data structure for the calculation.\n\n        arrays have shape\n        (n wind directions, n wind speeds, n turbines, m grid spanwise, m grid vertically)\n        - dimension 1: each wind direction\n        - dimension 2: each wind speed\n        - dimension 3: each turbine\n        - dimension 4: number of points in the spanwise direction (ngrid)\n        - dimension 5: number of points in the vertical dimension (ngrid)\n\n        For example\n        - x is [\n            n wind direction,\n            n wind speeds,\n            n turbines,\n            x-component of the points in the spanwise direction,\n            x-component of the points in the vertical direction\n        ]\n        - y is [\n            n wind direction,\n            n wind speeds,\n            n turbines,\n            y-component of the points in the spanwise direction,\n            y-component of the points in the vertical direction\n        ]\n\n        The x,y,z arrays contain the actual locations in that direction.\n\n        # -   **self.grid_resolution** (*int*, optional): The square root of the number\n        #             of points to use on the turbine grid. This number will be\n        #             squared so that the points can be evenly distributed.\n        #             Defaults to 5.\n\n        If the grid conforms to the sequential solver interface,\n        it must be sorted from upstream to downstream\n\n        In a y-z plane on the rotor swept area, the -2 dimension is a column of\n        points and the -1 dimension is the row number.\n        So the following line prints the 0'th column of the the 0'th turbine's grid:\n        print(grid.y_sorted[0,0,0,0,:])\n        print(grid.z_sorted[0,0,0,0,:])\n        And this line prints a single point\n        print(grid.y_sorted[0,0,0,0,0])\n        print(grid.z_sorted[0,0,0,0,0])\n        Note that the x coordinates are all the same for the rotor plane.\n\n        \"\"\"\n        # TODO: Where should we locate the coordinate system? Currently, its at\n        # the foot of the turbine where the tower meets the ground.\n\n        # These are the rotated coordinates of the wind turbines based on the wind direction\n        x, y, z, self.x_center_of_rotation, self.y_center_of_rotation = rotate_coordinates_rel_west(\n            self.wind_directions,\n            self.turbine_coordinates,\n        )\n\n        # -   **rloc** (*float, optional): A value, from 0 to 1, that determines\n        #         the width/height of the grid of points on the rotor as a ratio of\n        #         the rotor radius.\n        #         Defaults to 0.5.\n\n        # Create the data for the turbine grids\n        radius_ratio = 0.5\n        disc_area_radius = radius_ratio * self.turbine_diameters / 2\n        template_grid = np.ones(\n            (\n                self.n_findex,\n                self.n_turbines,\n                self.grid_resolution,\n                self.grid_resolution,\n            ),\n            dtype=floris_float_type\n        )\n        # Calculate the radial distance from the center of the turbine rotor.\n        # If a grid resolution of 1 is selected, create a disc_grid of zeros, as\n        # np.linspace would just return the starting value of -1 * disc_area_radius\n        # which would place the point below the center of the rotor.\n        if self.grid_resolution == 1:\n            disc_grid = np.zeros((np.shape(disc_area_radius)[0], 1 ),dtype=floris_float_type)\n        else:\n            disc_grid = np.linspace(\n                -1 * disc_area_radius,\n                disc_area_radius,\n                self.grid_resolution,\n                dtype=floris_float_type,\n                axis=1\n            )\n        # Construct the turbine grids\n        # Here, they are already rotated to the correct orientation for each wind direction\n        _x = x[:, :, None, None] * template_grid\n\n        ones_grid = np.ones(\n            (self.n_turbines, self.grid_resolution, self.grid_resolution),\n            dtype=floris_float_type\n        )\n        _y = y[:, :, None, None] + template_grid * ( disc_grid[None, :, :, None])\n        _z = z[:, :, None, None] + template_grid * ( disc_grid[:, None, :] * ones_grid )\n\n        # Sort the turbines at each wind direction\n\n        # Get the sorted indices for the x coordinates. These are the indices\n        # to sort the turbines from upstream to downstream for all wind directions.\n        # Also, store the indices to sort them back for when the calculation finishes.\n        self.sorted_indices = _x.argsort(axis=1)\n        self.sorted_coord_indices = x.argsort(axis=1)\n        self.unsorted_indices = self.sorted_indices.argsort(axis=1)\n\n        # Put the turbine coordinates into the final arrays in their sorted order\n        # These are the coordinates that should be used within the internal calculations\n        # such as the wake models and the solvers.\n        self.x_sorted = np.take_along_axis(_x, self.sorted_indices, axis=1)\n        self.y_sorted = np.take_along_axis(_y, self.sorted_indices, axis=1)\n        self.z_sorted = np.take_along_axis(_z, self.sorted_indices, axis=1)\n\n        # Now calculate grid coordinates in original frame (from 270 deg perspective)\n        self.x_sorted_inertial_frame, self.y_sorted_inertial_frame, self.z_sorted_inertial_frame = \\\n            reverse_rotate_coordinates_rel_west(\n                wind_directions=self.wind_directions,\n                grid_x=self.x_sorted,\n                grid_y=self.y_sorted,\n                grid_z=self.z_sorted,\n                x_center_of_rotation=self.x_center_of_rotation,\n                y_center_of_rotation=self.y_center_of_rotation,\n            )\n\n@define\nclass TurbineCubatureGrid(Grid):\n    \"\"\"\n    This grid type arranges points throughout the swept area of the rotor based on the cubature\n    of a unit circle. The number of points is set by the user, and then the location of the\n    points and their weighting in integration is automatically set. This type of grid\n    enables a better approximation of the total incoming velocities on the rotor and therefore\n    a more accurate average velocity, thrust coefficient, and axial induction.\n\n    Args:\n        turbine_coordinates (:py:obj:`NDArrayFloat`): The arrays of turbine coordinates as Numpy\n            arrays with shape (N coordinates, 3).\n        turbine_diameters (:py:obj:`NDArrayFloat`): The rotor diameters of each turbine.\n        wind_directions (:py:obj:`NDArrayFloat`): Wind directions supplied by the user.\n        grid_resolution (:py:obj:`int`): The number of points to\n            include in the cubature method. This value must be in the range [1, 10], and the\n            corresponding cubature weights are set automatically.\n    \"\"\"\n    sorted_indices: NDArrayInt = field(init=False)\n    sorted_coord_indices: NDArrayInt = field(init=False)\n    unsorted_indices: NDArrayInt = field(init=False)\n    x_center_of_rotation: NDArrayFloat = field(init=False)\n    y_center_of_rotation: NDArrayFloat = field(init=False)\n    average_method = \"simple-cubature\"\n\n    def __attrs_post_init__(self) -> None:\n        self.set_grid()\n\n    def set_grid(self) -> None:\n        \"\"\"\n        \"\"\"\n        # These are the rotated coordinates of the wind turbines based on the wind direction\n        x, y, z, self.x_center_of_rotation, self.y_center_of_rotation = rotate_coordinates_rel_west(\n            self.wind_directions,\n            self.turbine_coordinates\n        )\n\n        # Coefficients\n        cubature_coefficients = TurbineCubatureGrid.get_cubature_coefficients(self.grid_resolution)\n\n        # Generate grid points\n        yv = np.kron(cubature_coefficients[\"r\"], cubature_coefficients[\"q\"])\n        zv = np.kron(cubature_coefficients[\"r\"], cubature_coefficients[\"t\"])\n\n        # Calculate weighting terms for the grid points\n        self.cubature_weights = (\n            np.kron(cubature_coefficients[\"A\"], np.ones((1, self.grid_resolution)))\n            * cubature_coefficients[\"B\"] / np.pi\n        )\n\n        # Here, the coordinates are already rotated to the correct orientation for each\n        # wind direction\n        template_grid = np.ones(\n            (\n                self.n_findex,\n                self.n_turbines,\n                len(yv),  # Number of coordinates\n                1,\n            ),\n            dtype=floris_float_type\n        )\n        _x = x[:, :, None, None] * template_grid\n        _y = y[:, :, None, None] * template_grid\n        _z = z[:, :, None, None] * template_grid\n\n        n_coordinates = len(yv)\n        yv = np.broadcast_to(yv, (self.n_findex, self.n_turbines, n_coordinates))\n        yv = np.expand_dims(yv, axis=-1)\n        zv = np.broadcast_to(zv, (self.n_findex, self.n_turbines, n_coordinates))\n        zv = np.expand_dims(zv, axis=-1)\n\n        for ti in range(self.n_turbines):\n            _y[:, ti, :, :] += yv[:, ti] * self.turbine_diameters[ti] / 2.0\n            _z[:, ti, :, :] += zv[:, ti] * self.turbine_diameters[ti] / 2.0\n\n        # Sort the turbines at each wind direction\n\n        # Get the sorted indices for the x coordinates. These are the indices\n        # to sort the turbines from upstream to downstream for all wind directions.\n        # Also, store the indices to sort them back for when the calculation finishes.\n        self.sorted_indices = _x.argsort(axis=1)\n        self.sorted_coord_indices = x.argsort(axis=1)\n        self.unsorted_indices = self.sorted_indices.argsort(axis=1)\n\n        # Put the turbine coordinates into the final arrays in their sorted order\n        # These are the coordinates that should be used within the internal calculations\n        # such as the wake models and the solvers.\n        self.x_sorted = np.take_along_axis(_x, self.sorted_indices, axis=1)\n        self.y_sorted = np.take_along_axis(_y, self.sorted_indices, axis=1)\n        self.z_sorted = np.take_along_axis(_z, self.sorted_indices, axis=1)\n\n        # Now calculate grid coordinates in original frame (from 270 deg perspective)\n        self.x_sorted_inertial_frame, self.y_sorted_inertial_frame, self.z_sorted_inertial_frame = \\\n            reverse_rotate_coordinates_rel_west(\n                wind_directions=self.wind_directions,\n                grid_x=self.x_sorted,\n                grid_y=self.y_sorted,\n                grid_z=self.z_sorted,\n                x_center_of_rotation=self.x_center_of_rotation,\n                y_center_of_rotation=self.y_center_of_rotation,\n            )\n\n    @classmethod\n    def get_cubature_coefficients(cls, N: int):\n        \"\"\"\n        Retrieve cubature integration coefficients. This is a class-method, and therefore\n        the coefficients can be accessed without creating an instance of the class.\n\n        Args:\n            N (int): Order of the cubature integration. The total\n            number of rotor points will be N^2. Must be an integer in the range [1, 10].\n\n        Returns:\n            cubature_coefficients (dict): A dictionary containing the cubature\n            integration coefficients, \"r\", \"t\", \"q\", \"A\" and \"B\".\n        \"\"\"\n\n        if N < 1 or N > 10:\n            raise ValueError(\n                f\"Order of cubature integration must be between '1' and '10', given {N}.\"\n            )\n\n        elif N == 1:\n            r = [0.0000000000000000000000000]\n            t = [0.0000000000000000000000000]\n            q = [1.0000000000000000000000000]\n            A = [1.0000000000000000000000000]\n        elif N == 2:\n            r = [-0.7071067811865475244008444, 0.7071067811865475244008444]\n            t = [-0.7071067811865475244008444, 0.7071067811865475244008444]\n            q = [ 0.7071067811865475244008444, 0.7071067811865475244008444]\n            A = [ 0.5000000000000000000000000, 0.5000000000000000000000000]\n        elif N == 3:\n            r = [-0.8164965809277260327324280, 0.0000000000000000000000000, 0.8164965809277260327324280]  # noqa: E501\n            t = [-0.8660254037844386467637232, 0.0000000000000000000000000, 0.8660254037844386467637232]  # noqa: E501\n            q = [ 0.5000000000000000000000000, 1.0000000000000000000000000, 0.5000000000000000000000000]  # noqa: E501\n            A = [ 0.3750000000000000000000000, 0.2500000000000000000000000, 0.3750000000000000000000000]  # noqa: E501\n        elif N == 4:\n            r = [-0.8880738339771152621607646,-0.4597008433809830609776340, 0.4597008433809830609776340, 0.8880738339771152621607646]  # noqa: E501\n            t = [-0.9238795325112867561281832,-0.3826834323650897717284600, 0.3826834323650897717284600, 0.9238795325112867561281832]  # noqa: E501\n            q = [ 0.3826834323650897717284600, 0.9238795325112867561281832, 0.9238795325112867561281832, 0.3826834323650897717284600]  # noqa: E501\n            A = [ 0.2500000000000000000000000, 0.2500000000000000000000000, 0.2500000000000000000000000, 0.2500000000000000000000000]  # noqa: E501\n        elif N == 5:\n            r = [-0.9192110607898045793726291,-0.5958615826865180525340234, 0.0000000000000000000000000, 0.5958615826865180525340234, 0.9192110607898045793726291]  # noqa: E501\n            t = [-0.9510565162951535721164393,-0.5877852522924731291687060, 0.0000000000000000000000000, 0.5877852522924731291687060, 0.9510565162951535721164393]  # noqa: E501\n            q = [ 0.3090169943749474241022934, 0.8090169943749474241022934, 1.0000000000000000000000000, 0.8090169943749474241022934, 0.3090169943749474241022934]  # noqa: E501\n            A = [ 0.1882015313502336375250377, 0.2562429130942108069194067, 0.1111111111111111111111111, 0.2562429130942108069194067, 0.1882015313502336375250377]  # noqa: E501\n        elif N == 6:\n            r = [-0.9419651451198933233901941,-0.7071067811865475244008444,-0.3357106870197288066698994, 0.3357106870197288066698994, 0.7071067811865475244008444, 0.9419651451198933233901941]  # noqa: E501\n            t = [-0.9659258262890682867497432,-0.7071067811865475244008444,-0.2588190451025207623488988, 0.2588190451025207623488988, 0.7071067811865475244008444, 0.9659258262890682867497432]  # noqa: E501\n            q = [ 0.2588190451025207623488988, 0.7071067811865475244008444, 0.9659258262890682867497432, 0.9659258262890682867497432, 0.7071067811865475244008444, 0.2588190451025207623488988]  # noqa: E501\n            A = [ 0.1388888888888888888888889, 0.2222222222222222222222222, 0.1388888888888888888888889, 0.1388888888888888888888889, 0.2222222222222222222222222, 0.1388888888888888888888889]  # noqa: E501\n        elif N == 7:\n            r = [-0.9546790248493448767148503,-0.7684615381131740734708478,-0.4608042298407784190147371, 0.0000000000000000000000000, 0.4608042298407784190147371, 0.7684615381131740734708478, 0.9546790248493448767148503]  # noqa: E501\n            t = [-0.9749279121818236070181317,-0.7818314824680298087084445,-0.4338837391175581204757683, 0.0000000000000000000000000, 0.4338837391175581204757683, 0.7818314824680298087084445, 0.9749279121818236070181317]  # noqa: E501\n            q = [ 0.2225209339563144042889026, 0.6234898018587335305250049, 0.9009688679024191262361023, 1.0000000000000000000000000, 0.9009688679024191262361023, 0.6234898018587335305250049, 0.2225209339563144042889026]  # noqa: E501\n            A = [ 0.1102311055883841876377392, 0.1940967344215859403901162, 0.1644221599900298719721446, 0.0625000000000000000000000, 0.1644221599900298719721446, 0.1940967344215859403901162, 0.1102311055883841876377392]  # noqa: E501\n        elif N == 8:\n            r = [-0.9646596061808674528345806,-0.8185294874300058668603761,-0.5744645143153507855310459,-0.2634992299855422962484895, 0.2634992299855422962484895, 0.5744645143153507855310459, 0.8185294874300058668603761, 0.9646596061808674528345806]  # noqa: E501\n            t = [-0.9807852804032304491261822,-0.8314696123025452370787884,-0.5555702330196022247428308,-0.1950903220161282678482849, 0.1950903220161282678482849, 0.5555702330196022247428308, 0.8314696123025452370787884, 0.9807852804032304491261822]  # noqa: E501\n            q = [ 0.1950903220161282678482849, 0.5555702330196022247428308, 0.8314696123025452370787884, 0.9807852804032304491261822, 0.9807852804032304491261822, 0.8314696123025452370787884, 0.5555702330196022247428308, 0.1950903220161282678482849]  # noqa: E501\n            A = [ 0.0869637112843634643432660, 0.1630362887156365356567340, 0.1630362887156365356567340, 0.0869637112843634643432660, 0.0869637112843634643432660, 0.1630362887156365356567340, 0.1630362887156365356567340, 0.0869637112843634643432660]  # noqa: E501\n        elif N == 9:\n            r = [-0.9710282199223060261836893,-0.8503863747508400503582112,-0.6452980455813291706201889,-0.3738447061866471744516959, 0.0000000000000000000000000, 0.3738447061866471744516959, 0.6452980455813291706201889, 0.8503863747508400503582112, 0.9710282199223060261836893]  # noqa: E501\n            t = [-0.9848077530122080593667430,-0.8660254037844386467637232,-0.6427876096865393263226434,-0.3420201433256687330440996, 0.0000000000000000000000000, 0.3420201433256687330440996, 0.6427876096865393263226434, 0.8660254037844386467637232, 0.9848077530122080593667430]  # noqa: E501\n            q = [ 0.1736481776669303488517166, 0.5000000000000000000000000, 0.7660444431189780352023927, 0.9396926207859083840541093, 1.0000000000000000000000000, 0.9396926207859083840541093, 0.7660444431189780352023927, 0.5000000000000000000000000, 0.1736481776669303488517166]  # noqa: E501\n            A = [ 0.0718567803956129706617061, 0.1406780075747310300960863, 0.1559132614878706270409275, 0.1115519505417853722012801, 0.0400000000000000000000000, 0.1115519505417853722012801, 0.1559132614878706270409275, 0.1406780075747310300960863, 0.0718567803956129706617061]  # noqa: E501\n        elif N == 10:\n            r = [-0.9762632447087885713212574,-0.8770602345636481685478274,-0.7071067811865475244008444,-0.4803804169063914437972190,-0.2165873427295972057980989, 0.2165873427295972057980989, 0.4803804169063914437972190, 0.7071067811865475244008444, 0.8770602345636481685478274, 0.9762632447087885713212574]  # noqa: E501\n            t = [-0.9876883405951377261900402,-0.8910065241883678623597096,-0.7071067811865475244008444,-0.4539904997395467915604084,-0.1564344650402308690101053, 0.1564344650402308690101053, 0.4539904997395467915604084, 0.7071067811865475244008444, 0.8910065241883678623597096, 0.9876883405951377261900402]  # noqa: E501\n            q = [ 0.1564344650402308690101053, 0.4539904997395467915604084, 0.7071067811865475244008444, 0.8910065241883678623597096, 0.9876883405951377261900402, 0.9876883405951377261900402, 0.8910065241883678623597096, 0.7071067811865475244008444, 0.4539904997395467915604084, 0.1564344650402308690101053]  # noqa: E501\n            A = [ 0.0592317212640472718785660, 0.1196571676248416170103229, 0.1422222222222222222222222, 0.1196571676248416170103229, 0.0592317212640472718785660, 0.0592317212640472718785660, 0.1196571676248416170103229, 0.1422222222222222222222222, 0.1196571676248416170103229, 0.0592317212640472718785660]  # noqa: E501\n\n        return {\n            \"r\": np.array(r, dtype=float),\n            \"t\": np.array(t, dtype=float),\n            \"q\": np.array(q, dtype=float),\n            \"A\": np.array(A, dtype=float),\n            \"B\": np.pi/N,\n        }\n\n@define\nclass FlowFieldGrid(Grid):\n    \"\"\"\n    Args:\n        turbine_coordinates (:py:obj:`NDArrayFloat`): The arrays of turbine coordinates as Numpy\n            arrays with shape (N coordinates, 3).\n        turbine_diameters (:py:obj:`NDArrayFloat`): The rotor diameters of each turbine.\n        wind_directions (:py:obj:`NDArrayFloat`): Wind directions supplied by the user.\n        grid_resolution (:py:obj:`Iterable(int,)`): The number of grid points to create in each\n            planar direction. Must be 3 components for resolution in the x, y, and z directions.\n    \"\"\"\n    x_center_of_rotation: NDArrayFloat = field(init=False)\n    y_center_of_rotation: NDArrayFloat = field(init=False)\n\n    def __attrs_post_init__(self) -> None:\n        self.set_grid()\n\n    def set_grid(self) -> None:\n        \"\"\"\n        Create a structured grid for the entire flow field domain.\n\n        Calculates the domain bounds for the current wake model. The bounds\n        are calculated based on preset extents from the\n        given layout. The bounds consist of the minimum and maximum values\n        in the x-, y-, and z-directions.\n\n        If the Curl model is used, the predefined bounds are always set.\n\n        First, sort the turbines so that we know the bounds in the correct orientation.\n        Then, create the grid based on this wind-from-left orientation\n        \"\"\"\n\n        # These are the rotated coordinates of the wind turbines based on the wind direction\n        x, y, z, self.x_center_of_rotation, self.y_center_of_rotation = rotate_coordinates_rel_west(\n            self.wind_directions,\n            self.turbine_coordinates\n        )\n\n        # Construct the arrays storing the grid points\n        eps = 0.01\n        xmin = min(x[0,0]) - 2 * self.turbine_diameters\n        xmax = max(x[0,0]) + 10 * self.turbine_diameters\n        ymin = min(y[0,0]) - 2 * self.turbine_diameters\n        ymax = max(y[0,0]) + 2 * self.turbine_diameters\n        zmin = 0 + eps\n        zmax = 6 * max(z[0,0])\n\n        x_points, y_points, z_points = np.meshgrid(\n            np.linspace(xmin, xmax, int(self.grid_resolution[0])),\n            np.linspace(ymin, ymax, int(self.grid_resolution[1])),\n            np.linspace(zmin, zmax, int(self.grid_resolution[2])),\n            indexing=\"ij\"\n        )\n\n        self.x_sorted = x_points[None, None, :, :, :]\n        self.y_sorted = y_points[None, None, :, :, :]\n        self.z_sorted = z_points[None, None, :, :, :]\n\n        # Now calculate grid coordinates in original frame (from 270 deg perspective)\n        self.x_sorted_inertial_frame, self.y_sorted_inertial_frame, self.z_sorted_inertial_frame = \\\n            reverse_rotate_coordinates_rel_west(\n                wind_directions=self.wind_directions,\n                grid_x=self.x_sorted,\n                grid_y=self.y_sorted,\n                grid_z=self.z_sorted,\n                x_center_of_rotation=self.x_center_of_rotation,\n                y_center_of_rotation=self.y_center_of_rotation,\n            )\n\n@define\nclass FlowFieldPlanarGrid(Grid):\n    \"\"\"\n    Args:\n        turbine_coordinates (:py:obj:`NDArrayFloat`): The arrays of turbine coordinates as Numpy\n            arrays with shape (N coordinates, 3).\n        turbine_diameters (:py:obj:`NDArrayFloat`): The rotor diameters of each turbine.\n        wind_directions (:py:obj:`NDArrayFloat`): Wind directions supplied by the user.\n        grid_resolution (:py:obj:`Iterable(int,)`): The number of grid points to create in each\n            planar direction. Must be 2 components for resolution in the x and y directions.\n            The z direction is set to 3 planes at -10.0, 0.0, and +10.0 relative to the\n            `planar_coordinate`.\n    \"\"\"\n    normal_vector: str = field()\n    planar_coordinate: float = field()\n    x1_bounds: tuple = field(default=None)\n    x2_bounds: tuple = field(default=None)\n    x_center_of_rotation: NDArrayFloat = field(init=False)\n    y_center_of_rotation: NDArrayFloat = field(init=False)\n    sorted_indices: NDArrayInt = field(init=False)\n    unsorted_indices: NDArrayInt = field(init=False)\n\n    def __attrs_post_init__(self) -> None:\n        self.set_grid()\n\n    def set_grid(self) -> None:\n        \"\"\"\n        Create a structured grid for the entire flow field domain.\n\n        Calculates the domain bounds for the current wake model. The bounds\n        are calculated based on preset extents from the\n        given layout. The bounds consist of the minimum and maximum values\n        in the x-, y-, and z-directions.\n\n        First, sort the turbines so that we know the bounds in the correct orientation.\n        Then, create the grid based on this wind-from-left orientation\n        \"\"\"\n        # These are the rotated coordinates of the wind turbines based on the wind direction\n        x, y, z, self.x_center_of_rotation, self.y_center_of_rotation = rotate_coordinates_rel_west(\n            self.wind_directions,\n            self.turbine_coordinates\n        )\n        max_diameter = np.max(self.turbine_diameters)\n\n        if self.normal_vector == \"z\":  # Rules of thumb for horizontal plane\n            if self.x1_bounds is None:\n                self.x1_bounds = (np.min(x) - 2 * max_diameter, np.max(x) + 10 * max_diameter)\n\n            if self.x2_bounds is None:\n                self.x2_bounds = (np.min(y) - 2 * max_diameter, np.max(y) + 2 * max_diameter)\n\n            # TODO figure out proper z spacing for GCH, currently set to +/- 10.0\n            x_points, y_points, z_points = np.meshgrid(\n                np.linspace(self.x1_bounds[0], self.x1_bounds[1], int(self.grid_resolution[0])),\n                np.linspace(self.x2_bounds[0], self.x2_bounds[1], int(self.grid_resolution[1])),\n                np.array([\n                    float(self.planar_coordinate) - 10.0,\n                    float(self.planar_coordinate),\n                    float(self.planar_coordinate) + 10.0\n                ]),\n                indexing=\"ij\"\n            )\n\n            self.x_sorted = x_points[None, :, :, :]\n            self.y_sorted = y_points[None, :, :, :]\n            self.z_sorted = z_points[None, :, :, :]\n\n        elif self.normal_vector == \"x\":  # Rules of thumb for cross plane\n            if self.x1_bounds is None:\n                self.x1_bounds = (np.min(y) - 2 * max_diameter, np.max(y) + 2 * max_diameter)\n\n            if self.x2_bounds is None:\n                self.x2_bounds = (0.001, 6 * np.max(z))\n\n            x_points, y_points, z_points = np.meshgrid(\n                np.array([float(self.planar_coordinate)]),\n                np.linspace(self.x1_bounds[0], self.x1_bounds[1], int(self.grid_resolution[0])),\n                np.linspace(self.x2_bounds[0], self.x2_bounds[1], int(self.grid_resolution[1])),\n                indexing=\"ij\"\n            )\n\n            self.x_sorted = x_points[None, :, :, :]\n            self.y_sorted = y_points[None, :, :, :]\n            self.z_sorted = z_points[None, :, :, :]\n\n        elif self.normal_vector == \"y\":  # Rules of thumb for y plane\n            if self.x1_bounds is None:\n                self.x1_bounds = (np.min(x) - 2 * max_diameter, np.max(x) + 10 * max_diameter)\n\n            if self.x2_bounds is None:\n                self.x2_bounds = (0.001, 6 * np.max(z))\n\n            x_points, y_points, z_points = np.meshgrid(\n                np.linspace(self.x1_bounds[0], self.x1_bounds[1], int(self.grid_resolution[0])),\n                np.array([float(self.planar_coordinate)]),\n                np.linspace(self.x2_bounds[0], self.x2_bounds[1], int(self.grid_resolution[1])),\n                indexing=\"ij\"\n            )\n\n            self.x_sorted = x_points[None, :, :, :]\n            self.y_sorted = y_points[None, :, :, :]\n            self.z_sorted = z_points[None, :, :, :]\n\n        # Now calculate grid coordinates in original frame (from 270 deg perspective)\n        self.x_sorted_inertial_frame, self.y_sorted_inertial_frame, self.z_sorted_inertial_frame = \\\n            reverse_rotate_coordinates_rel_west(\n                wind_directions=self.wind_directions,\n                grid_x=self.x_sorted,\n                grid_y=self.y_sorted,\n                grid_z=self.z_sorted,\n                x_center_of_rotation=self.x_center_of_rotation,\n                y_center_of_rotation=self.y_center_of_rotation,\n            )\n\n@define\nclass PointsGrid(Grid):\n    \"\"\"\n    Args:\n        turbine_coordinates (:py:obj:`NDArrayFloat`): Not used for PointsGrid, but\n            required for the `Grid` super-class.\n        turbine_diameters (:py:obj:`NDArrayFloat`):  Not used for PointsGrid, but\n            required for the `Grid` super-class.\n        wind_directions (:py:obj:`NDArrayFloat`): Wind directions supplied by the user.\n        grid_resolution (:py:obj:`int` | :py:obj:`Iterable(int,)`): Not used for PointsGrid, but\n            required for the `Grid` super-class.\n\n        points_x (:py:obj:`NDArrayFloat`): Array of x-components for the points in the grid.\n        points_y (:py:obj:`NDArrayFloat`): Array of y-components for the points in the grid.\n        points_z (:py:obj:`NDArrayFloat`): Array of z-components for the points in the grid.\n        x_center_of_rotation (:py:obj:`float`, optional): Component of the centroid of the\n            farm or area of interest. The PointsGrid will be rotated around this center\n            of rotation to account for wind direction changes. If not supplied, the center\n            of rotation will be the centroid of the points in the PointsGrid.\n        y_center_of_rotation (:py:obj:`float`, optional): Component of the centroid of the\n            farm or area of interest. The PointsGrid will be rotated around this center\n            of rotation to account for wind direction changes. If not supplied, the center\n            of rotation will be the centroid of the points in the PointsGrid.\n    \"\"\"\n    points_x: NDArrayFloat = field(converter=floris_array_converter)\n    points_y: NDArrayFloat = field(converter=floris_array_converter)\n    points_z: NDArrayFloat = field(converter=floris_array_converter)\n    x_center_of_rotation: float | None = field(default=None)\n    y_center_of_rotation: float | None = field(default=None)\n\n    def __attrs_post_init__(self) -> None:\n        self.set_grid()\n\n    def set_grid(self) -> None:\n        \"\"\"\n        Set points for calculation based on a series of user-supplied coordinates.\n        \"\"\"\n        point_coordinates = np.array(list(zip(self.points_x, self.points_y, self.points_z)))\n\n        # These are the rotated coordinates of the wind turbines based on the wind direction\n        x, y, z, _, _ = rotate_coordinates_rel_west(\n            self.wind_directions,\n            point_coordinates,\n            x_center_of_rotation=self.x_center_of_rotation,\n            y_center_of_rotation=self.y_center_of_rotation\n        )\n        self.x_sorted = x[:,:,None,None]\n        self.y_sorted = y[:,:,None,None]\n        self.z_sorted = z[:,:,None,None]\n"
  },
  {
    "path": "floris/core/rotor_velocity.py",
    "content": "import copy\nfrom collections.abc import Iterable\n\nimport numpy as np\nfrom scipy.interpolate import interp1d\n\nfrom floris.type_dec import (\n    NDArrayBool,\n    NDArrayFilter,\n    NDArrayFloat,\n    NDArrayInt,\n    NDArrayObject,\n)\nfrom floris.utilities import cosd\n\n\ndef rotor_velocity_yaw_cosine_correction(\n    cosine_loss_exponent_yaw: float,\n    yaw_angles: NDArrayFloat,\n    rotor_effective_velocities: NDArrayFloat,\n) -> NDArrayFloat:\n    # Compute the rotor effective velocity adjusting for yaw settings\n    pW = cosine_loss_exponent_yaw / 3.0  # Convert from cosine_loss_exponent_yaw to w\n    rotor_effective_velocities = rotor_effective_velocities * cosd(yaw_angles) ** pW\n\n    return rotor_effective_velocities\n\ndef rotor_velocity_tilt_cosine_correction(\n    tilt_angles: NDArrayFloat,\n    ref_tilt: NDArrayFloat,\n    cosine_loss_exponent_tilt: float,\n    tilt_interp: NDArrayObject,\n    correct_cp_ct_for_tilt: NDArrayBool,\n    rotor_effective_velocities: NDArrayFloat,\n) -> NDArrayFloat:\n    # Compute the tilt, if using floating turbines\n    old_tilt_angle = copy.deepcopy(tilt_angles)\n    tilt_angles = compute_tilt_angles_for_floating_turbines(\n        tilt_angles,\n        tilt_interp,\n        rotor_effective_velocities,\n    )\n    # Only update tilt angle if requested (if the tilt isn't accounted for in the Cp curve)\n    tilt_angles = np.where(correct_cp_ct_for_tilt, tilt_angles, old_tilt_angle)\n\n    # Compute the rotor effective velocity adjusting for tilt\n    rotor_effective_velocities = (\n        rotor_effective_velocities\n        * (cosd(tilt_angles) / cosd(ref_tilt)) ** (cosine_loss_exponent_tilt / 3.0)\n    )\n\n    return rotor_effective_velocities\n\ndef simple_mean(array, axis=0):\n    return np.mean(array, axis=axis)\n\ndef cubic_mean(array, axis=0):\n    return np.cbrt(np.mean(array ** 3.0, axis=axis))\n\ndef simple_cubature(array, cubature_weights, axis=0):\n    weights = cubature_weights.flatten()\n    weights = weights * len(weights) / np.sum(weights)\n    product = (array * weights[None, None, :, None])\n    return simple_mean(product, axis)\n\ndef cubic_cubature(array, cubature_weights, axis=0):\n    weights = cubature_weights.flatten()\n    weights = weights * len(weights) / np.sum(weights)\n    return np.cbrt(np.mean((array**3.0 * weights[None, None, :, None]), axis=axis))\n\ndef average_velocity(\n    velocities: NDArrayFloat,\n    ix_filter: NDArrayFilter | Iterable[int] | None = None,\n    method: str = \"cubic-mean\",\n    cubature_weights: NDArrayFloat | None = None\n) -> NDArrayFloat:\n    \"\"\"This property calculates and returns the average of the velocity field\n    in turbine's rotor swept area. The average is calculated using the\n    user-specified method. This is a vectorized function, so it can be used\n    to calculate the average velocity for multiple turbines at once or\n    a single turbine.\n\n    **Note:** The velocity is scaled to an effective velocity by the yaw.\n\n    Args:\n        velocities (NDArrayFloat): The velocity field at each turbine; should be shape:\n            (number of turbines, ngrid, ngrid), or (ngrid, ngrid) for a single turbine.\n        ix_filter (NDArrayFilter | Iterable[int] | None], optional): The boolean array, or\n            integer indices (as an iterable or array) to filter out before calculation.\n            Defaults to None.\n        method (str, optional): The method to use for averaging. Options are:\n            - \"simple-mean\": The simple mean of the velocities\n            - \"cubic-mean\": The cubic mean of the velocities\n            - \"simple-cubature\": A cubature integration of the velocities\n            - \"cubic-cubature\": A cubature integration of the cube of the velocities\n            Defaults to \"cubic-mean\".\n        cubature_weights (NDArrayFloat, optional): The cubature weights to use for the\n            cubature integration methods. Defaults to None.\n\n    Returns:\n        NDArrayFloat: The average velocity across the rotor(s).\n    \"\"\"\n\n    # The input velocities are expected to be a 4 dimensional array with shape:\n    # (# findex, # turbines, grid resolution, grid resolution)\n\n    if ix_filter is not None:\n        velocities = velocities[:, ix_filter]\n\n    axis = tuple([2 + i for i in range(velocities.ndim - 2)])\n    if method == \"simple-mean\":\n        return simple_mean(velocities, axis)\n\n    elif method == \"cubic-mean\":\n        return cubic_mean(velocities, axis)\n\n    elif method == \"simple-cubature\":\n        if cubature_weights is None:\n            raise ValueError(\"cubature_weights is required for 'simple-cubature' method.\")\n        return simple_cubature(velocities, cubature_weights, axis)\n\n    elif method == \"cubic-cubature\":\n        if cubature_weights is None:\n            raise ValueError(\"cubature_weights is required for 'cubic-cubature' method.\")\n        return cubic_cubature(velocities, cubature_weights, axis)\n\n    else:\n        raise ValueError(\"Incorrect method given.\")\n\ndef compute_tilt_angles_for_floating_turbines_map(\n    turbine_type_map: NDArrayObject,\n    tilt_angles: NDArrayFloat,\n    tilt_interps: dict[str, interp1d],\n    rotor_effective_velocities: NDArrayFloat,\n) -> NDArrayFloat:\n    # Loop over each turbine type given to get tilt angles for all turbines\n    old_tilt_angles = copy.deepcopy(tilt_angles)\n    tilt_angles = np.zeros(np.shape(rotor_effective_velocities))\n    turb_types = np.unique(turbine_type_map)\n    for turb_type in turb_types:\n        # If no tilt interpolation is specified, assume no modification to tilt\n        if tilt_interps[turb_type] is None: # Use passed tilt angles\n            tilt_angles += old_tilt_angles * (turbine_type_map == turb_type)\n        else: # Apply interpolated tilt angle\n            tilt_angles += compute_tilt_angles_for_floating_turbines(\n                tilt_angles,\n                tilt_interps[turb_type],\n                rotor_effective_velocities\n            ) * (turbine_type_map == turb_type)\n\n    return tilt_angles\n\ndef compute_tilt_angles_for_floating_turbines(\n    tilt_angles: NDArrayFloat,\n    tilt_interp: dict[str, interp1d],\n    rotor_effective_velocities: NDArrayFloat,\n) -> NDArrayFloat:\n    # Loop over each turbine type given to get tilt angles for all turbines\n    # If no tilt interpolation is specified, assume no modification to tilt\n    if tilt_interp is None:\n        # TODO should this be break? Should it be continue? Do we want to support mixed\n        # fixed-bottom and floating? Or non-tilting floating?\n        pass\n    # Using a masked array, apply the tilt angle for all turbines of the current\n    # type to the main tilt angle array\n    else:\n        tilt_angles = tilt_interp(rotor_effective_velocities)\n\n    return tilt_angles\n\ndef rotor_effective_velocity(\n    air_density: float,\n    ref_air_density: float,\n    velocities: NDArrayFloat,\n    yaw_angle: NDArrayFloat,\n    tilt_angle: NDArrayFloat,\n    ref_tilt: NDArrayFloat,\n    cosine_loss_exponent_yaw: float,\n    cosine_loss_exponent_tilt: float,\n    tilt_interp: NDArrayObject,\n    correct_cp_ct_for_tilt: NDArrayBool,\n    turbine_type_map: NDArrayObject,\n    ix_filter: NDArrayInt | Iterable[int] | None = None,\n    average_method: str = \"cubic-mean\",\n    cubature_weights: NDArrayFloat | None = None\n) -> NDArrayFloat:\n\n    if isinstance(yaw_angle, list):\n        yaw_angle = np.array(yaw_angle)\n    if isinstance(tilt_angle, list):\n        tilt_angle = np.array(tilt_angle)\n\n    # Down-select inputs if ix_filter is given\n    if ix_filter is not None:\n        velocities = velocities[:, ix_filter]\n        yaw_angle = yaw_angle[:, ix_filter]\n        tilt_angle = tilt_angle[:, ix_filter]\n        ref_tilt = ref_tilt[:, ix_filter]\n        cosine_loss_exponent_yaw = cosine_loss_exponent_yaw[:, ix_filter]\n        cosine_loss_exponent_tilt = cosine_loss_exponent_tilt[:, ix_filter]\n        turbine_type_map = turbine_type_map[:, ix_filter]\n\n    # Compute the rotor effective velocity adjusting for air density\n    average_velocities = average_velocity(\n        velocities,\n        method=average_method,\n        cubature_weights=cubature_weights\n    )\n    rotor_effective_velocities = (air_density/ref_air_density)**(1/3) * average_velocities\n\n    # Compute the rotor effective velocity adjusting for yaw settings\n    rotor_effective_velocities = rotor_velocity_yaw_cosine_correction(\n        cosine_loss_exponent_yaw,\n        yaw_angle,\n        rotor_effective_velocities\n    )\n\n    # Compute the tilt, if using floating turbines\n    rotor_effective_velocities = rotor_velocity_tilt_cosine_correction(\n        turbine_type_map,\n        tilt_angle,\n        ref_tilt,\n        cosine_loss_exponent_tilt,\n        tilt_interp,\n        correct_cp_ct_for_tilt,\n        rotor_effective_velocities,\n    )\n\n    return rotor_effective_velocities\n\ndef rotor_velocity_air_density_correction(\n    velocities: NDArrayFloat,\n    air_density: float,\n    ref_air_density: float,\n) -> NDArrayFloat:\n    # Produce equivalent velocities at the reference air density\n\n    return (air_density/ref_air_density)**(1/3) * velocities\n"
  },
  {
    "path": "floris/core/solver.py",
    "content": "import copy\n\nimport numpy as np\n\nfrom floris.core import (\n    axial_induction,\n    Farm,\n    FlowField,\n    FlowFieldGrid,\n    FlowFieldPlanarGrid,\n    PointsGrid,\n    thrust_coefficient,\n    TurbineGrid,\n)\nfrom floris.core.rotor_velocity import average_velocity\nfrom floris.core.wake import WakeModelManager\nfrom floris.core.wake_deflection.empirical_gauss import yaw_added_wake_mixing\nfrom floris.core.wake_deflection.gauss import (\n    calculate_transverse_velocity,\n    wake_added_yaw,\n    yaw_added_turbulence_mixing,\n)\nfrom floris.core.wake_velocity.empirical_gauss import awc_added_wake_mixing\nfrom floris.type_dec import NDArrayFloat\nfrom floris.utilities import cosd\n\n\ndef calculate_area_overlap(wake_velocities, freestream_velocities, y_ngrid, z_ngrid):\n    \"\"\"\n    compute wake overlap based on the number of points that are not freestream\n    velocity, i.e. affected by the wake\n    \"\"\"\n    # Count all of the rotor points with a negligible difference from freestream\n    # count = np.sum(freestream_velocities - wake_velocities <= 0.05, axis=(3, 4))\n    # return (y_ngrid * z_ngrid - count) / (y_ngrid * z_ngrid)\n    # return 1 - count / (y_ngrid * z_ngrid)\n\n    # Find the points on the rotor grids with a difference from freestream of greater\n    # than some tolerance. These are all the points in the wake. The ratio of\n    # these points to the total points is the portion of wake overlap.\n    return np.sum(freestream_velocities - wake_velocities > 0.05, axis=(3, 4)) / (y_ngrid * z_ngrid)\n\n\n# @profile\ndef sequential_solver(\n    farm: Farm,\n    flow_field: FlowField,\n    grid: TurbineGrid,\n    model_manager: WakeModelManager\n) -> None:\n    # Algorithm\n    # For each turbine, calculate its effect on every downstream turbine.\n    # For the current turbine, we are calculating the deficit that it adds to downstream turbines.\n    # Integrate this into the main data structure.\n    # Move on to the next turbine.\n\n    # <<interface>>\n    deflection_model_args = model_manager.deflection_model.prepare_function(grid, flow_field)\n    deficit_model_args = model_manager.velocity_model.prepare_function(grid, flow_field)\n\n    # This is u_wake\n    wake_field = np.zeros_like(flow_field.u_initial_sorted)\n    v_wake = np.zeros_like(flow_field.v_initial_sorted)\n    w_wake = np.zeros_like(flow_field.w_initial_sorted)\n\n    # Expand input turbulence intensity to 4d for (n_turbines, grid, grid)\n    turbine_turbulence_intensity = flow_field.turbulence_intensities[:, None, None, None]\n    turbine_turbulence_intensity = np.repeat(turbine_turbulence_intensity, farm.n_turbines, axis=1)\n\n    # Ambient turbulent intensity should be a copy of n_findex-long turbulence_intensity\n    # with dimensions expanded for (n_turbines, grid, grid)\n    ambient_turbulence_intensities = flow_field.turbulence_intensities.copy()\n    ambient_turbulence_intensities = ambient_turbulence_intensities[:, None, None, None]\n\n    # Calculate the velocity deficit sequentially from upstream to downstream turbines\n    for i in range(grid.n_turbines):\n\n        # Get the current turbine quantities\n        x_i = np.mean(grid.x_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        y_i = np.mean(grid.y_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        z_i = np.mean(grid.z_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n\n        u_i = flow_field.u_sorted[:, i:i+1]\n        v_i = flow_field.v_sorted[:, i:i+1]\n\n        ct_i = thrust_coefficient(\n            velocities=flow_field.u_sorted,\n            turbulence_intensities=flow_field.turbulence_intensity_field_sorted,\n            air_density=flow_field.air_density,\n            yaw_angles=farm.yaw_angles_sorted,\n            tilt_angles=farm.tilt_angles_sorted,\n            power_setpoints=farm.power_setpoints_sorted,\n            awc_modes=farm.awc_modes_sorted,\n            awc_amplitudes=farm.awc_amplitudes_sorted,\n            thrust_coefficient_functions=farm.turbine_thrust_coefficient_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions\n        )\n        # Since we are filtering for the i'th turbine in the thrust coefficient function,\n        # get the first index here (0:1)\n        ct_i = ct_i[:, 0:1, None, None]\n        axial_induction_i = axial_induction(\n            velocities=flow_field.u_sorted,\n            turbulence_intensities=flow_field.turbulence_intensity_field_sorted,\n            air_density=flow_field.air_density,\n            yaw_angles=farm.yaw_angles_sorted,\n            tilt_angles=farm.tilt_angles_sorted,\n            power_setpoints=farm.power_setpoints_sorted,\n            awc_modes=farm.awc_modes_sorted,\n            awc_amplitudes=farm.awc_amplitudes_sorted,\n            axial_induction_functions=farm.turbine_axial_induction_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions\n        )\n        # Since we are filtering for the i'th turbine in the axial induction function,\n        # get the first index here (0:1)\n        axial_induction_i = axial_induction_i[:, 0:1, None, None]\n        turbulence_intensity_i = turbine_turbulence_intensity[:, i:i+1]\n        yaw_angle_i = farm.yaw_angles_sorted[:, i:i+1, None, None]\n        hub_height_i = farm.hub_heights_sorted[:, i:i+1, None, None]\n        rotor_diameter_i = farm.rotor_diameters_sorted[:, i:i+1, None, None]\n        TSR_i = farm.TSRs_sorted[:, i:i+1, None, None]\n\n        effective_yaw_i = np.zeros_like(yaw_angle_i)\n        effective_yaw_i += yaw_angle_i\n\n        if model_manager.enable_secondary_steering:\n            added_yaw = wake_added_yaw(\n                u_i,\n                v_i,\n                flow_field.u_initial_sorted,\n                grid.y_sorted[:, i:i+1] - y_i,\n                grid.z_sorted[:, i:i+1],\n                rotor_diameter_i,\n                hub_height_i,\n                ct_i,\n                TSR_i,\n                axial_induction_i,\n                flow_field.wind_shear,\n            )\n            effective_yaw_i += added_yaw\n\n        # Model calculations\n        # NOTE: exponential\n        deflection_field = model_manager.deflection_model.function(\n            x_i,\n            y_i,\n            effective_yaw_i,\n            turbulence_intensity_i,\n            ct_i,\n            rotor_diameter_i,\n            **deflection_model_args,\n        )\n\n        if model_manager.enable_transverse_velocities:\n            v_wake, w_wake = calculate_transverse_velocity(\n                u_i,\n                flow_field.u_initial_sorted,\n                flow_field.dudz_initial_sorted,\n                grid.x_sorted - x_i,\n                grid.y_sorted - y_i,\n                grid.z_sorted,\n                rotor_diameter_i,\n                hub_height_i,\n                yaw_angle_i,\n                ct_i,\n                TSR_i,\n                axial_induction_i,\n                flow_field.wind_shear,\n            )\n\n        if model_manager.enable_yaw_added_recovery:\n            I_mixing = yaw_added_turbulence_mixing(\n                u_i,\n                turbulence_intensity_i,\n                v_i,\n                flow_field.w_sorted[:, i:i+1],\n                v_wake[:, i:i+1],\n                w_wake[:, i:i+1],\n            )\n            gch_gain = 2\n            turbine_turbulence_intensity[:, i:i+1] = turbulence_intensity_i + gch_gain * I_mixing\n\n        # NOTE: exponential\n        velocity_deficit = model_manager.velocity_model.function(\n            x_i,\n            y_i,\n            z_i,\n            axial_induction_i,\n            deflection_field,\n            yaw_angle_i,\n            turbulence_intensity_i,\n            ct_i,\n            hub_height_i,\n            rotor_diameter_i,\n            **deficit_model_args,\n        )\n\n        wake_field = model_manager.combination_model.function(\n            wake_field,\n            velocity_deficit * flow_field.u_initial_sorted\n        )\n\n        wake_added_turbulence_intensity = model_manager.turbulence_model.function(\n            ambient_turbulence_intensities,\n            grid.x_sorted,\n            x_i,\n            rotor_diameter_i,\n            axial_induction_i,\n        )\n\n        # Calculate wake overlap for wake-added turbulence (WAT)\n        area_overlap = (\n            np.sum(velocity_deficit * flow_field.u_initial_sorted > 0.05, axis=(2, 3))\n            / (grid.grid_resolution * grid.grid_resolution)\n        )\n        area_overlap = area_overlap[:, :, None, None]\n\n        # Modify wake added turbulence by wake area overlap\n        downstream_influence_length = 15 * rotor_diameter_i\n        ti_added = (\n            area_overlap\n            * np.nan_to_num(wake_added_turbulence_intensity, posinf=0.0)\n            * (grid.x_sorted > x_i)\n            * (np.abs(y_i - grid.y_sorted) < 2 * rotor_diameter_i)\n            * (grid.x_sorted <= downstream_influence_length + x_i)\n        )\n\n        # Combine turbine TIs with WAT\n        turbine_turbulence_intensity = np.maximum(\n            np.sqrt(ti_added**2 + ambient_turbulence_intensities**2), turbine_turbulence_intensity\n        )\n\n        flow_field.u_sorted = flow_field.u_initial_sorted - wake_field\n        flow_field.v_sorted += v_wake\n        flow_field.w_sorted += w_wake\n\n    flow_field.turbulence_intensity_field_sorted = turbine_turbulence_intensity\n    flow_field.turbulence_intensity_field_sorted_avg = np.mean(\n        turbine_turbulence_intensity,\n        axis=(2,3),\n        keepdims=True\n    )\n\n\ndef full_flow_sequential_solver(\n    farm: Farm,\n    flow_field: FlowField,\n    flow_field_grid: FlowFieldGrid | FlowFieldPlanarGrid | PointsGrid,\n    model_manager: WakeModelManager\n) -> None:\n\n    # Get the flow quantities and turbine performance\n    turbine_grid_farm = copy.deepcopy(farm)\n    turbine_grid_flow_field = copy.deepcopy(flow_field)\n\n    turbine_grid_farm.construct_turbine_map()\n    turbine_grid_farm.construct_turbine_thrust_coefficient_functions()\n    turbine_grid_farm.construct_turbine_axial_induction_functions()\n    turbine_grid_farm.construct_turbine_power_functions()\n    turbine_grid_farm.construct_hub_heights()\n    turbine_grid_farm.construct_rotor_diameters()\n    turbine_grid_farm.construct_turbine_TSRs()\n    turbine_grid_farm.construct_turbine_ref_tilts()\n    turbine_grid_farm.construct_turbine_tilt_interps()\n    turbine_grid_farm.construct_turbine_correct_cp_ct_for_tilt()\n    turbine_grid_farm.set_tilt_to_ref_tilt(flow_field.n_findex)\n\n    turbine_grid = TurbineGrid(\n        turbine_coordinates=turbine_grid_farm.coordinates,\n        turbine_diameters=turbine_grid_farm.rotor_diameters,\n        wind_directions=turbine_grid_flow_field.wind_directions,\n        grid_resolution=3,\n    )\n    turbine_grid_farm.expand_farm_properties(\n        turbine_grid_flow_field.n_findex,\n        turbine_grid.sorted_coord_indices,\n    )\n    turbine_grid_flow_field.initialize_velocity_field(turbine_grid)\n    turbine_grid_farm.initialize(turbine_grid.sorted_indices)\n    sequential_solver(turbine_grid_farm, turbine_grid_flow_field, turbine_grid, model_manager)\n\n    ### Referring to the quantities from above, calculate the wake in the full grid\n\n    # Use full flow_field here to use the full grid in the wake models\n    deflection_model_args = model_manager.deflection_model.prepare_function(\n        flow_field_grid,\n        flow_field\n    )\n    deficit_model_args = model_manager.velocity_model.prepare_function(\n        flow_field_grid,\n        flow_field\n    )\n\n    wake_field = np.zeros_like(flow_field.u_initial_sorted)\n    v_wake = np.zeros_like(flow_field.v_initial_sorted)\n    w_wake = np.zeros_like(flow_field.w_initial_sorted)\n\n    # Initialize the turbulence intensity field over the entire flow field grid\n    n_points = flow_field_grid.x_sorted.shape[1]\n    ambient_turbulence_intensities = flow_field.turbulence_intensities[:, None, None, None]\n    ambient_turbulence_intensities = np.repeat(ambient_turbulence_intensities, n_points, axis=1)\n    turbulence_intensity_field = ambient_turbulence_intensities.copy()\n\n    # Calculate the velocity deficit sequentially from upstream to downstream turbines\n    for i in range(flow_field_grid.n_turbines):\n\n        # Get the current turbine quantities\n        x_i = np.mean(turbine_grid.x_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        y_i = np.mean(turbine_grid.y_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        z_i = np.mean(turbine_grid.z_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n\n        u_i = turbine_grid_flow_field.u_sorted[:, i:i+1]\n        v_i = turbine_grid_flow_field.v_sorted[:, i:i+1]\n\n        ct_i = thrust_coefficient(\n            velocities=turbine_grid_flow_field.u_sorted,\n            turbulence_intensities=turbine_grid_flow_field.turbulence_intensity_field_sorted,\n            air_density=turbine_grid_flow_field.air_density,\n            yaw_angles=turbine_grid_farm.yaw_angles_sorted,\n            tilt_angles=turbine_grid_farm.tilt_angles_sorted,\n            power_setpoints=turbine_grid_farm.power_setpoints_sorted,\n            awc_modes=turbine_grid_farm.awc_modes_sorted,\n            awc_amplitudes=turbine_grid_farm.awc_amplitudes_sorted,\n            thrust_coefficient_functions=turbine_grid_farm.turbine_thrust_coefficient_functions,\n            tilt_interps=turbine_grid_farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=turbine_grid_farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=turbine_grid_farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=turbine_grid_farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=turbine_grid.average_method,\n            cubature_weights=turbine_grid.cubature_weights,\n            multidim_condition=turbine_grid_flow_field.multidim_conditions,\n        )\n        # Since we are filtering for the i'th turbine in the thrust_coefficient function,\n        # get the first index here (0:1)\n        ct_i = ct_i[:, 0:1, None, None]\n        axial_induction_i = axial_induction(\n            velocities=turbine_grid_flow_field.u_sorted,\n            turbulence_intensities=turbine_grid_flow_field.turbulence_intensity_field_sorted,\n            air_density=turbine_grid_flow_field.air_density,\n            yaw_angles=turbine_grid_farm.yaw_angles_sorted,\n            tilt_angles=turbine_grid_farm.tilt_angles_sorted,\n            power_setpoints=turbine_grid_farm.power_setpoints_sorted,\n            awc_modes=turbine_grid_farm.awc_modes_sorted,\n            awc_amplitudes=turbine_grid_farm.awc_amplitudes_sorted,\n            axial_induction_functions=turbine_grid_farm.turbine_axial_induction_functions,\n            tilt_interps=turbine_grid_farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=turbine_grid_farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=turbine_grid_farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=turbine_grid_farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=turbine_grid.average_method,\n            cubature_weights=turbine_grid.cubature_weights,\n            multidim_condition=turbine_grid_flow_field.multidim_conditions,\n        )\n        # Since we are filtering for the i'th turbine in the axial induction function,\n        # get the first index here (0:1)\n        axial_induction_i = axial_induction_i[:, 0:1, None, None]\n        turbulence_intensity_i = \\\n            turbine_grid_flow_field.turbulence_intensity_field_sorted_avg[:, i:i+1]\n        yaw_angle_i = turbine_grid_farm.yaw_angles_sorted[:, i:i+1, None, None]\n        hub_height_i = turbine_grid_farm.hub_heights_sorted[:, i:i+1, None, None]\n        rotor_diameter_i = turbine_grid_farm.rotor_diameters_sorted[:, i:i+1, None, None]\n        TSR_i = turbine_grid_farm.TSRs_sorted[:, i:i+1, None, None]\n\n        effective_yaw_i = np.zeros_like(yaw_angle_i)\n        effective_yaw_i += yaw_angle_i\n\n        if model_manager.enable_secondary_steering:\n            added_yaw = wake_added_yaw(\n                u_i,\n                v_i,\n                turbine_grid_flow_field.u_initial_sorted,\n                turbine_grid.y_sorted[:, i:i+1] - y_i,\n                turbine_grid.z_sorted[:, i:i+1],\n                rotor_diameter_i,\n                hub_height_i,\n                ct_i,\n                TSR_i,\n                axial_induction_i,\n                flow_field.wind_shear,\n            )\n            effective_yaw_i += added_yaw\n\n        # Model calculations\n        # NOTE: exponential\n        deflection_field = model_manager.deflection_model.function(\n            x_i,\n            y_i,\n            effective_yaw_i,\n            turbulence_intensity_i,\n            ct_i,\n            rotor_diameter_i,\n            **deflection_model_args,\n        )\n\n        if model_manager.enable_transverse_velocities:\n            v_wake, w_wake = calculate_transverse_velocity(\n                u_i,\n                flow_field.u_initial_sorted,\n                flow_field.dudz_initial_sorted,\n                flow_field_grid.x_sorted - x_i,\n                flow_field_grid.y_sorted - y_i,\n                flow_field_grid.z_sorted,\n                rotor_diameter_i,\n                hub_height_i,\n                yaw_angle_i,\n                ct_i,\n                TSR_i,\n                axial_induction_i,\n                flow_field.wind_shear,\n            )\n\n        # NOTE: exponential\n        velocity_deficit = model_manager.velocity_model.function(\n            x_i,\n            y_i,\n            z_i,\n            axial_induction_i,\n            deflection_field,\n            yaw_angle_i,\n            turbulence_intensity_i,\n            ct_i,\n            hub_height_i,\n            rotor_diameter_i,\n            **deficit_model_args,\n        )\n\n        wake_field = model_manager.combination_model.function(\n            wake_field,\n            velocity_deficit * flow_field.u_initial_sorted\n        )\n\n        wake_added_ti = model_manager.turbulence_model.function(\n            ambient_turbulence_intensities,\n            flow_field_grid.x_sorted,\n            x_i,\n            rotor_diameter_i,\n            axial_induction_i,\n        )\n\n        # Calculate locations where wake-added turbulence (WAT) applies\n        area_overlap = np.where(velocity_deficit * flow_field.u_initial_sorted > 0.05, 1, 0)\n\n        # Modify wake added turbulence by wake area overlap\n        downstream_influence_length = 15 * rotor_diameter_i\n        ti_added = (\n            area_overlap\n            * np.nan_to_num(wake_added_ti, posinf=0.0)\n            * (flow_field_grid.x_sorted > x_i)\n            * (np.abs(y_i - flow_field_grid.y_sorted) < 2 * rotor_diameter_i)\n            * (flow_field_grid.x_sorted <= downstream_influence_length + x_i)\n        )\n        # Combine turbine TIs with WAT\n        turbulence_intensity_field = np.maximum(\n            np.sqrt(ti_added**2 + ambient_turbulence_intensities**2), turbulence_intensity_field\n        )\n\n        flow_field.u_sorted = flow_field.u_initial_sorted - wake_field\n        flow_field.v_sorted += v_wake\n        flow_field.w_sorted += w_wake\n\n    flow_field.turbulence_intensity_field_sorted = turbulence_intensity_field\n\n\ndef cc_solver(\n    farm: Farm,\n    flow_field: FlowField,\n    grid: TurbineGrid,\n    model_manager: WakeModelManager\n) -> None:\n    # <<interface>>\n    deflection_model_args = model_manager.deflection_model.prepare_function(grid, flow_field)\n    deficit_model_args = model_manager.velocity_model.prepare_function(grid, flow_field)\n\n    # This is u_wake\n    v_wake = np.zeros_like(flow_field.v_initial_sorted)\n    w_wake = np.zeros_like(flow_field.w_initial_sorted)\n    turb_u_wake = np.zeros_like(flow_field.u_initial_sorted)\n    turb_inflow_field = copy.deepcopy(flow_field.u_initial_sorted)\n\n    # Set up turbulence arrays\n    turbine_turbulence_intensity = flow_field.turbulence_intensities[:, None, None, None]\n    turbine_turbulence_intensity = np.repeat(turbine_turbulence_intensity, farm.n_turbines, axis=1)\n\n    # Ambient turbulent intensity should be a copy of n_findex-long turbulence_intensities\n    # with extra dimension to reach 4d\n    ambient_turbulence_intensities = flow_field.turbulence_intensities.copy()\n    ambient_turbulence_intensities = ambient_turbulence_intensities[:, None, None, None]\n\n    shape = (farm.n_turbines,) + np.shape(flow_field.u_initial_sorted)\n    Ctmp = np.zeros((shape))\n    # Ctmp = np.zeros((len(x_coord), len(wd), len(ws), len(x_coord), y_ngrid, z_ngrid))\n\n    # sigma_i = np.zeros((shape))\n    # sigma_i = np.zeros((len(x_coord), len(wd), len(ws), len(x_coord), y_ngrid, z_ngrid))\n\n    # Calculate the velocity deficit sequentially from upstream to downstream turbines\n    for i in range(grid.n_turbines):\n\n        # Get the current turbine quantities\n        x_i = np.mean(grid.x_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        y_i = np.mean(grid.y_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        z_i = np.mean(grid.z_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n\n        rotor_diameter_i = farm.rotor_diameters_sorted[:, i:i+1, None, None]\n\n        mask2 = (\n            (grid.x_sorted < x_i + 0.01)\n            * (grid.x_sorted > x_i - 0.01)\n            * (grid.y_sorted < y_i + 0.51 * rotor_diameter_i)\n            * (grid.y_sorted > y_i - 0.51 * rotor_diameter_i)\n        )\n        turb_inflow_field = (\n            turb_inflow_field * ~mask2\n            + (flow_field.u_initial_sorted - turb_u_wake) * mask2\n        )\n\n        turb_avg_vels = average_velocity(turb_inflow_field)[:, :, None, None]\n        turb_Cts = thrust_coefficient(\n            turb_avg_vels,\n            flow_field.turbulence_intensity_field_sorted,\n            flow_field.air_density,\n            farm.yaw_angles_sorted,\n            farm.tilt_angles_sorted,\n            farm.power_setpoints_sorted,\n            farm.awc_modes_sorted,\n            farm.awc_amplitudes_sorted,\n            farm.turbine_thrust_coefficient_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions,\n        )\n        turb_Cts = turb_Cts[:, :, None, None]\n        turb_aIs = axial_induction(\n            turb_avg_vels,\n            flow_field.turbulence_intensity_field_sorted,\n            flow_field.air_density,\n            farm.yaw_angles_sorted,\n            farm.tilt_angles_sorted,\n            farm.power_setpoints_sorted,\n            farm.awc_modes_sorted,\n            farm.awc_amplitudes_sorted,\n            farm.turbine_axial_induction_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions,\n        )\n        turb_aIs = turb_aIs[:, :, None, None]\n\n        u_i = turb_inflow_field[:, i:i+1]\n        v_i = flow_field.v_sorted[:, i:i+1]\n\n        axial_induction_i = axial_induction(\n            velocities=flow_field.u_sorted,\n            turbulence_intensities=flow_field.turbulence_intensity_field_sorted,\n            air_density=flow_field.air_density,\n            yaw_angles=farm.yaw_angles_sorted,\n            tilt_angles=farm.tilt_angles_sorted,\n            power_setpoints=farm.power_setpoints_sorted,\n            awc_modes=farm.awc_modes_sorted,\n            awc_amplitudes=farm.awc_amplitudes_sorted,\n            axial_induction_functions=farm.turbine_axial_induction_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions,\n        )\n\n        axial_induction_i = axial_induction_i[:, :, None, None]\n\n        turbulence_intensity_i = turbine_turbulence_intensity[:, i:i+1]\n        yaw_angle_i = farm.yaw_angles_sorted[:, i:i+1, None, None]\n        hub_height_i = farm.hub_heights_sorted[:, i:i+1, None, None]\n        TSR_i = farm.TSRs_sorted[:, i:i+1, None, None]\n\n        effective_yaw_i = np.zeros_like(yaw_angle_i)\n        effective_yaw_i += yaw_angle_i\n\n        if model_manager.enable_secondary_steering:\n            added_yaw = wake_added_yaw(\n                u_i,\n                v_i,\n                flow_field.u_initial_sorted,\n                grid.y_sorted[:, i:i+1] - y_i,\n                grid.z_sorted[:, i:i+1],\n                rotor_diameter_i,\n                hub_height_i,\n                turb_Cts[:, i:i+1],\n                TSR_i,\n                axial_induction_i,\n                flow_field.wind_shear,\n                scale=2.0,\n            )\n            effective_yaw_i += added_yaw\n\n        # Model calculations\n        # NOTE: exponential\n        deflection_field = model_manager.deflection_model.function(\n            x_i,\n            y_i,\n            effective_yaw_i,\n            turbulence_intensity_i,\n            turb_Cts[:, i:i+1],\n            rotor_diameter_i,\n            **deflection_model_args,\n        )\n\n        if model_manager.enable_transverse_velocities:\n            v_wake, w_wake = calculate_transverse_velocity(\n                u_i,\n                flow_field.u_initial_sorted,\n                flow_field.dudz_initial_sorted,\n                grid.x_sorted - x_i,\n                grid.y_sorted - y_i,\n                grid.z_sorted,\n                rotor_diameter_i,\n                hub_height_i,\n                yaw_angle_i,\n                turb_Cts[:, i:i+1],\n                TSR_i,\n                axial_induction_i,\n                flow_field.wind_shear,\n                scale=2.0,\n            )\n\n        if model_manager.enable_yaw_added_recovery:\n            I_mixing = yaw_added_turbulence_mixing(\n                u_i,\n                turbulence_intensity_i,\n                v_i,\n                flow_field.w_sorted[:, i:i+1],\n                v_wake[:, i:i+1],\n                w_wake[:, i:i+1],\n            )\n            gch_gain = 1.0\n            turbine_turbulence_intensity[:, i:i+1] = turbulence_intensity_i + gch_gain * I_mixing\n\n        turb_u_wake, Ctmp = model_manager.velocity_model.function(\n            i,\n            x_i,\n            y_i,\n            z_i,\n            u_i,\n            deflection_field,\n            yaw_angle_i,\n            turbine_turbulence_intensity,\n            turb_Cts,\n            farm.rotor_diameters_sorted[:, :, None, None],\n            turb_u_wake,\n            Ctmp,\n            **deficit_model_args,\n        )\n\n        wake_added_turbulence_intensity = model_manager.turbulence_model.function(\n            ambient_turbulence_intensities,\n            grid.x_sorted,\n            x_i,\n            rotor_diameter_i,\n            turb_aIs\n        )\n\n        # Calculate wake overlap for wake-added turbulence (WAT)\n        area_overlap = 1 - (\n            np.sum(turb_u_wake <= 0.05, axis=(2, 3), keepdims=True)\n            / (grid.grid_resolution * grid.grid_resolution)\n        )\n\n        # Modify wake added turbulence by wake area overlap\n        downstream_influence_length = 15 * rotor_diameter_i\n        ti_added = (\n            area_overlap\n            * np.nan_to_num(wake_added_turbulence_intensity, posinf=0.0)\n            * (grid.x_sorted > x_i)\n            * (np.abs(y_i - grid.y_sorted) < 2 * rotor_diameter_i)\n            * (grid.x_sorted <= downstream_influence_length + x_i)\n        )\n\n        # Combine turbine TIs with WAT\n        turbine_turbulence_intensity = np.maximum(\n            np.sqrt(ti_added**2 + ambient_turbulence_intensities**2), turbine_turbulence_intensity\n        )\n\n        flow_field.v_sorted += v_wake\n        flow_field.w_sorted += w_wake\n    flow_field.u_sorted = turb_inflow_field\n\n    flow_field.turbulence_intensity_field_sorted = turbine_turbulence_intensity\n    flow_field.turbulence_intensity_field_sorted_avg = np.mean(\n        turbine_turbulence_intensity,\n        axis=(2,3),\n        keepdims=True\n    )\n\n\ndef full_flow_cc_solver(\n    farm: Farm,\n    flow_field: FlowField,\n    flow_field_grid: FlowFieldGrid | FlowFieldPlanarGrid | PointsGrid,\n    model_manager: WakeModelManager,\n) -> None:\n    # Get the flow quantities and turbine performance\n    turbine_grid_farm = copy.deepcopy(farm)\n    turbine_grid_flow_field = copy.deepcopy(flow_field)\n\n    turbine_grid_farm.construct_turbine_map()\n    turbine_grid_farm.construct_turbine_thrust_coefficient_functions()\n    turbine_grid_farm.construct_turbine_axial_induction_functions()\n    turbine_grid_farm.construct_turbine_power_functions()\n    turbine_grid_farm.construct_hub_heights()\n    turbine_grid_farm.construct_rotor_diameters()\n    turbine_grid_farm.construct_turbine_TSRs()\n    turbine_grid_farm.construct_turbine_ref_tilts()\n    turbine_grid_farm.construct_turbine_tilt_interps()\n    turbine_grid_farm.construct_turbine_correct_cp_ct_for_tilt()\n    turbine_grid_farm.set_tilt_to_ref_tilt(flow_field.n_findex)\n\n    turbine_grid = TurbineGrid(\n        turbine_coordinates=turbine_grid_farm.coordinates,\n        turbine_diameters=turbine_grid_farm.rotor_diameters,\n        wind_directions=turbine_grid_flow_field.wind_directions,\n        grid_resolution=3,\n    )\n    turbine_grid_farm.expand_farm_properties(\n        turbine_grid_flow_field.n_findex,\n        turbine_grid.sorted_coord_indices,\n    )\n    turbine_grid_flow_field.initialize_velocity_field(turbine_grid)\n    turbine_grid_farm.initialize(turbine_grid.sorted_indices)\n    cc_solver(turbine_grid_farm, turbine_grid_flow_field, turbine_grid, model_manager)\n\n    ### Referring to the quantities from above, calculate the wake in the full grid\n\n    # Use full flow_field here to use the full grid in the wake models\n    deflection_model_args = model_manager.deflection_model.prepare_function(\n        flow_field_grid,\n        flow_field\n    )\n    deficit_model_args = model_manager.velocity_model.prepare_function(\n        flow_field_grid,\n        flow_field\n    )\n\n    v_wake = np.zeros_like(flow_field.v_initial_sorted)\n    w_wake = np.zeros_like(flow_field.w_initial_sorted)\n    turb_u_wake = np.zeros_like(flow_field.u_initial_sorted)\n\n    # Initialize the turbulence intensity field over the entire flow field grid\n    n_points = flow_field_grid.x_sorted.shape[1]\n    ambient_turbulence_intensities = flow_field.turbulence_intensities[:, None, None, None]\n    ambient_turbulence_intensities = np.repeat(ambient_turbulence_intensities, n_points, axis=1)\n    turbulence_intensity_field = ambient_turbulence_intensities.copy()\n\n    shape = (farm.n_turbines,) + np.shape(flow_field.u_initial_sorted)\n    Ctmp = np.zeros((shape))\n\n    # Calculate the velocity deficit sequentially from upstream to downstream turbines\n    for i in range(flow_field_grid.n_turbines):\n\n        # Get the current turbine quantities\n        x_i = np.mean(turbine_grid.x_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        y_i = np.mean(turbine_grid.y_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        z_i = np.mean(turbine_grid.z_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n\n        u_i = turbine_grid_flow_field.u_sorted[:, i:i+1]\n        v_i = turbine_grid_flow_field.v_sorted[:, i:i+1]\n\n        turb_avg_vels = average_velocity(turbine_grid_flow_field.u_sorted)\n        turb_Cts = thrust_coefficient(\n            velocities=turb_avg_vels,\n            turbulence_intensities=turbine_grid_flow_field.turbulence_intensity_field_sorted,\n            air_density=turbine_grid_flow_field.air_density,\n            yaw_angles=turbine_grid_farm.yaw_angles_sorted,\n            tilt_angles=turbine_grid_farm.tilt_angles_sorted,\n            power_setpoints=turbine_grid_farm.power_setpoints_sorted,\n            awc_modes=turbine_grid_farm.awc_modes_sorted,\n            awc_amplitudes=turbine_grid_farm.awc_amplitudes_sorted,\n            thrust_coefficient_functions=turbine_grid_farm.turbine_thrust_coefficient_functions,\n            tilt_interps=turbine_grid_farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=turbine_grid_farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=turbine_grid_farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=turbine_grid_farm.turbine_power_thrust_tables,\n            average_method=turbine_grid.average_method,\n            cubature_weights=turbine_grid.cubature_weights,\n            multidim_condition=turbine_grid_flow_field.multidim_conditions,\n        )\n        turb_Cts = turb_Cts[:, :, None, None]\n\n        axial_induction_i = axial_induction(\n            velocities=turbine_grid_flow_field.u_sorted,\n            turbulence_intensities=turbine_grid_flow_field.turbulence_intensity_field_sorted,\n            air_density=turbine_grid_flow_field.air_density,\n            yaw_angles=turbine_grid_farm.yaw_angles_sorted,\n            tilt_angles=turbine_grid_farm.tilt_angles_sorted,\n            power_setpoints=turbine_grid_farm.power_setpoints_sorted,\n            awc_modes=turbine_grid_farm.awc_modes_sorted,\n            awc_amplitudes=turbine_grid_farm.awc_amplitudes_sorted,\n            axial_induction_functions=turbine_grid_farm.turbine_axial_induction_functions,\n            tilt_interps=turbine_grid_farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=turbine_grid_farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=turbine_grid_farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=turbine_grid_farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=turbine_grid.average_method,\n            cubature_weights=turbine_grid.cubature_weights,\n            multidim_condition=turbine_grid_flow_field.multidim_conditions,\n        )\n        axial_induction_i = axial_induction_i[:, :, None, None]\n\n        turbulence_intensity_i = \\\n            turbine_grid_flow_field.turbulence_intensity_field_sorted_avg[:, i:i+1]\n        yaw_angle_i = turbine_grid_farm.yaw_angles_sorted[:, i:i+1, None, None]\n        hub_height_i = turbine_grid_farm.hub_heights_sorted[:, i:i+1, None, None]\n        rotor_diameter_i = turbine_grid_farm.rotor_diameters_sorted[:, i:i+1, None, None]\n        TSR_i = turbine_grid_farm.TSRs_sorted[:, i:i+1, None, None]\n\n        effective_yaw_i = np.zeros_like(yaw_angle_i)\n        effective_yaw_i += yaw_angle_i\n\n        if model_manager.enable_secondary_steering:\n            added_yaw = wake_added_yaw(\n                u_i,\n                v_i,\n                turbine_grid_flow_field.u_initial_sorted,\n                turbine_grid.y_sorted[:, i:i+1] - y_i,\n                turbine_grid.z_sorted[:, i:i+1],\n                rotor_diameter_i,\n                hub_height_i,\n                turb_Cts[:, i:i+1],\n                TSR_i,\n                axial_induction_i,\n                flow_field.wind_shear,\n                scale=2.0,\n            )\n            effective_yaw_i += added_yaw\n\n        # Model calculations\n        # NOTE: exponential\n        deflection_field = model_manager.deflection_model.function(\n            x_i,\n            y_i,\n            effective_yaw_i,\n            turbulence_intensity_i,\n            turb_Cts[:, i:i+1],\n            rotor_diameter_i,\n            **deflection_model_args,\n        )\n\n        if model_manager.enable_transverse_velocities:\n            v_wake, w_wake = calculate_transverse_velocity(\n                u_i,\n                flow_field.u_initial_sorted,\n                flow_field.dudz_initial_sorted,\n                flow_field_grid.x_sorted - x_i,\n                flow_field_grid.y_sorted - y_i,\n                flow_field_grid.z_sorted,\n                rotor_diameter_i,\n                hub_height_i,\n                yaw_angle_i,\n                turb_Cts[:, i:i+1],\n                TSR_i,\n                axial_induction_i,\n                flow_field.wind_shear,\n                scale=2.0,\n            )\n\n        # NOTE: exponential\n        turb_u_wake, Ctmp = model_manager.velocity_model.function(\n            i,\n            x_i,\n            y_i,\n            z_i,\n            u_i,\n            deflection_field,\n            yaw_angle_i,\n            turbine_grid_flow_field.turbulence_intensity_field_sorted_avg,\n            turb_Cts,\n            turbine_grid_farm.rotor_diameters_sorted[:, :, None, None],\n            turb_u_wake,\n            Ctmp,\n            **deficit_model_args,\n        )\n\n        wake_added_turbulence_intensity = model_manager.turbulence_model.function(\n            ambient_turbulence_intensities,\n            flow_field_grid.x_sorted,\n            x_i,\n            rotor_diameter_i,\n            axial_induction_i\n        )\n\n        # Calculate wake overlap for wake-added turbulence (WAT)\n        area_overlap = np.where(turb_u_wake > 0.05, 1, 0)\n\n        # Modify wake added turbulence by wake area overlap\n        downstream_influence_length = 15 * rotor_diameter_i\n        ti_added = (\n            area_overlap\n            * np.nan_to_num(wake_added_turbulence_intensity, posinf=0.0)\n            * (flow_field_grid.x_sorted > x_i)\n            * (np.abs(y_i - flow_field_grid.y_sorted) < 2 * rotor_diameter_i)\n            * (flow_field_grid.x_sorted <= downstream_influence_length + x_i)\n        )\n\n        # Combine turbine TIs with WAT\n        turbulence_intensity_field = np.maximum(\n            np.sqrt(ti_added**2 + ambient_turbulence_intensities**2), turbulence_intensity_field\n        )\n\n        flow_field.v_sorted += v_wake\n        flow_field.w_sorted += w_wake\n\n    flow_field.u_sorted = flow_field.u_initial_sorted - turb_u_wake\n    flow_field.turbulence_intensity_field_sorted = turbulence_intensity_field\n\n\ndef turbopark_solver(\n    farm: Farm,\n    flow_field: FlowField,\n    grid: TurbineGrid,\n    model_manager: WakeModelManager\n) -> None:\n    # Algorithm\n    # For each turbine, calculate its effect on every downstream turbine.\n    # For the current turbine, we are calculating the deficit that it adds to downstream turbines.\n    # Integrate this into the main data structure.\n    # Move on to the next turbine.\n\n    # <<interface>>\n    deflection_model_args = model_manager.deflection_model.prepare_function(grid, flow_field)\n    deficit_model_args = model_manager.velocity_model.prepare_function(grid, flow_field)\n\n    # This is u_wake\n    wake_field = np.zeros_like(flow_field.u_initial_sorted)\n    v_wake = np.zeros_like(flow_field.v_initial_sorted)\n    w_wake = np.zeros_like(flow_field.w_initial_sorted)\n    shape = (farm.n_turbines,) + np.shape(flow_field.u_initial_sorted)\n    velocity_deficit = np.zeros(shape)\n    deflection_field = np.zeros_like(flow_field.u_initial_sorted)\n\n    # Set up turbulence arrays\n    turbine_turbulence_intensity = flow_field.turbulence_intensities[:, None, None, None]\n    turbine_turbulence_intensity = np.repeat(turbine_turbulence_intensity, farm.n_turbines, axis=1)\n\n    # Ambient turbulent intensity should be a copy of n_findex-long turbulence_intensities\n    # with extra dimension to reach 4d\n    ambient_turbulence_intensities = flow_field.turbulence_intensities.copy()\n    ambient_turbulence_intensities = ambient_turbulence_intensities[:, None, None, None]\n\n    # Calculate the velocity deficit sequentially from upstream to downstream turbines\n    for i in range(grid.n_turbines):\n        # Get the current turbine quantities\n        x_i = np.mean(grid.x_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        y_i = np.mean(grid.y_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        z_i = np.mean(grid.z_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n\n        Cts = thrust_coefficient(\n            velocities=flow_field.u_sorted,\n            turbulence_intensities=flow_field.turbulence_intensity_field_sorted,\n            air_density=flow_field.air_density,\n            yaw_angles=farm.yaw_angles_sorted,\n            tilt_angles=farm.tilt_angles_sorted,\n            power_setpoints=farm.power_setpoints_sorted,\n            awc_modes=farm.awc_modes_sorted,\n            awc_amplitudes=farm.awc_amplitudes_sorted,\n            thrust_coefficient_functions=farm.turbine_thrust_coefficient_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions,\n        )\n\n        ct_i = thrust_coefficient(\n            velocities=flow_field.u_sorted,\n            turbulence_intensities=flow_field.turbulence_intensity_field_sorted,\n            air_density=flow_field.air_density,\n            yaw_angles=farm.yaw_angles_sorted,\n            tilt_angles=farm.tilt_angles_sorted,\n            power_setpoints=farm.power_setpoints_sorted,\n            awc_modes=farm.awc_modes_sorted,\n            awc_amplitudes=farm.awc_amplitudes_sorted,\n            thrust_coefficient_functions=farm.turbine_thrust_coefficient_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions,\n        )\n        # Since we are filtering for the i'th turbine in the thrust coefficient function,\n        # get the first index here (0:1)\n        ct_i = ct_i[:, 0:1, None, None]\n        axial_induction_i = axial_induction(\n            velocities=flow_field.u_sorted,\n            turbulence_intensities=flow_field.turbulence_intensity_field_sorted,\n            air_density=flow_field.air_density,\n            yaw_angles=farm.yaw_angles_sorted,\n            tilt_angles=farm.tilt_angles_sorted,\n            power_setpoints=farm.power_setpoints_sorted,\n            awc_modes=farm.awc_modes_sorted,\n            awc_amplitudes=farm.awc_amplitudes_sorted,\n            axial_induction_functions=farm.turbine_axial_induction_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions,\n        )\n        # Since we are filtering for the i'th turbine in the axial induction function,\n        # get the first index here (0:1)\n        axial_induction_i = axial_induction_i[:, 0:1, None, None]\n        yaw_angle_i = farm.yaw_angles_sorted[:, i:i+1, None, None]\n        rotor_diameter_i = farm.rotor_diameters_sorted[:, i:i+1, None, None]\n\n        effective_yaw_i = np.zeros_like(yaw_angle_i)\n        effective_yaw_i += yaw_angle_i\n\n\n        if model_manager.enable_secondary_steering:\n            raise NotImplementedError(\n                \"Secondary steering not available for this model.\")\n\n        # Model calculations\n        # NOTE: exponential\n        if np.any(farm.yaw_angles_sorted):\n            model_manager.deflection_model.logger.warning(\n                \"WARNING: Deflection with the TurbOPark model has not been fully validated. \"\n                \"This is an initial implementation, and we advise you use at your own risk \"\n                \"and perform a thorough examination of the results.\"\n            )\n            for ii in range(i):\n                x_ii = np.mean(grid.x_sorted[:, ii:ii+1], axis=(2, 3), keepdims=True)\n                y_ii = np.mean(grid.y_sorted[:, ii:ii+1], axis=(2, 3), keepdims=True)\n\n                yaw_ii = farm.yaw_angles_sorted[:, ii:ii+1, None, None]\n                turbulence_intensity_ii = turbine_turbulence_intensity[:, ii:ii+1]\n                ct_ii = thrust_coefficient(\n                    velocities=flow_field.u_sorted,\n                    turbulence_intensities=flow_field.turbulence_intensity_field_sorted,\n                    air_density=flow_field.air_density,\n                    yaw_angles=farm.yaw_angles_sorted,\n                    tilt_angles=farm.tilt_angles_sorted,\n                    power_setpoints=farm.power_setpoints_sorted,\n                    awc_modes=farm.awc_modes_sorted,\n                    awc_amplitudes=farm.awc_amplitudes_sorted,\n                    thrust_coefficient_functions=farm.turbine_thrust_coefficient_functions,\n                    tilt_interps=farm.turbine_tilt_interps,\n                    correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n                    turbine_type_map=farm.turbine_type_map_sorted,\n                    turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n                    ix_filter=[ii],\n                    average_method=grid.average_method,\n                    cubature_weights=grid.cubature_weights,\n                    multidim_condition=flow_field.multidim_conditions,\n                )\n                ct_ii = ct_ii[:, 0:1, None, None]\n                rotor_diameter_ii = farm.rotor_diameters_sorted[:, ii:ii+1, None, None]\n\n                deflection_field_ii = model_manager.deflection_model.function(\n                    x_ii,\n                    y_ii,\n                    yaw_ii,\n                    turbulence_intensity_ii,\n                    ct_ii,\n                    rotor_diameter_ii,\n                    **deflection_model_args,\n                )\n\n                deflection_field[:, ii:ii+1, :, :] = deflection_field_ii[:, i:i+1, :, :]\n\n        if model_manager.enable_transverse_velocities:\n            raise NotImplementedError(\n                \"Transverse velocities not used in this model.\")\n\n        if model_manager.enable_yaw_added_recovery:\n            raise NotImplementedError(\n                \"Yaw added recovery not used in this model.\")\n\n        # NOTE: exponential\n        velocity_deficit = model_manager.velocity_model.function(\n            x_i,\n            y_i,\n            z_i,\n            turbine_turbulence_intensity,\n            Cts[:, :, None, None],\n            rotor_diameter_i,\n            farm.rotor_diameters_sorted[:, :, None, None],\n            i,\n            deflection_field,\n            **deficit_model_args,\n        )\n\n        wake_field = model_manager.combination_model.function(\n            wake_field,\n            velocity_deficit * flow_field.u_initial_sorted\n        )\n\n        wake_added_turbulence_intensity = model_manager.turbulence_model.function(\n            ambient_turbulence_intensities,\n            grid.x_sorted,\n            x_i,\n            rotor_diameter_i,\n            axial_induction_i\n        )\n\n        # TODO: leaving this in for GCH quantities; will need to find another way to\n        # compute area_overlap as the current wake deficit is solved for only upstream\n        # turbines; could use WAT_upstream\n        # Calculate wake overlap for wake-added turbulence (WAT)\n        area_overlap = (\n            np.sum(\n                velocity_deficit * flow_field.u_initial_sorted > 0.05,\n                axis=(2, 3),\n                keepdims=True\n            )\n            / (grid.grid_resolution * grid.grid_resolution)\n        )\n\n        # Modify wake added turbulence by wake area overlap\n        downstream_influence_length = 15 * rotor_diameter_i\n        ti_added = (\n            area_overlap\n            * np.nan_to_num(wake_added_turbulence_intensity, posinf=0.0)\n            * (grid.x_sorted > x_i)\n            * (np.abs(y_i - grid.y_sorted) < 2 * rotor_diameter_i)\n            * (grid.x_sorted <= downstream_influence_length + x_i)\n        )\n\n        # Combine turbine TIs with WAT\n        turbine_turbulence_intensity = np.maximum(\n            np.sqrt(ti_added**2 + ambient_turbulence_intensities**2), turbine_turbulence_intensity\n        )\n\n        flow_field.u_sorted = flow_field.u_initial_sorted - wake_field\n        flow_field.v_sorted += v_wake\n        flow_field.w_sorted += w_wake\n\n    flow_field.turbulence_intensity_field_sorted = turbine_turbulence_intensity\n    flow_field.turbulence_intensity_field_sorted_avg = np.mean(\n        turbine_turbulence_intensity,\n        axis=(2, 3),\n        keepdims=True\n    )\n\n\ndef full_flow_turbopark_solver(\n    farm: Farm,\n    flow_field: FlowField,\n    flow_field_grid: FlowFieldGrid,\n    model_manager: WakeModelManager\n) -> None:\n    raise NotImplementedError(\"Plotting for the TurbOPark model is not currently implemented.\")\n\n\ndef empirical_gauss_solver(\n    farm: Farm,\n    flow_field: FlowField,\n    grid: TurbineGrid,\n    model_manager: WakeModelManager\n) -> NDArrayFloat:\n    \"\"\"\n    Algorithm:\n    For each turbine, calculate its effect on every downstream turbine.\n    For the current turbine, we are calculating the deficit that it adds to downstream turbines.\n    Integrate this into the main data structure.\n    Move on to the next turbine.\n\n    Args:\n        farm (Farm)\n        flow_field (FlowField)\n        grid (TurbineGrid)\n        model_manager (WakeModelManager)\n\n    Raises:\n        NotImplementedError: Raised if secondary steering is enabled with the EmGauss model.\n        NotImplementedError: Raised if transverse velocities is enabled with the EmGauss model.\n\n    Returns:\n        NDArrayFloat: wake induced mixing field primarily for use in the full-flow EmGauss solver\n    \"\"\"\n\n\n    # <<interface>>\n    deflection_model_args = model_manager.deflection_model.prepare_function(grid, flow_field)\n    deficit_model_args = model_manager.velocity_model.prepare_function(grid, flow_field)\n\n    # This is u_wake\n    wake_field = np.zeros_like(flow_field.u_initial_sorted)\n    v_wake = np.zeros_like(flow_field.v_initial_sorted)\n    w_wake = np.zeros_like(flow_field.w_initial_sorted)\n\n    x_locs = np.mean(grid.x_sorted, axis=(2, 3))[:,:,None]\n    downstream_distance_D = x_locs - np.transpose(x_locs, axes=(0,2,1))\n    downstream_distance_D = downstream_distance_D / \\\n        np.repeat(farm.rotor_diameters_sorted[:,:,None], grid.n_turbines, axis=-1)\n    downstream_distance_D = np.maximum(downstream_distance_D, 0.1) # For ease\n    # Initialize the mixing factor model using TI if specified\n    initial_mixing_factor = model_manager.turbulence_model.atmospheric_ti_gain * np.eye(\n        grid.n_turbines\n    )\n    mixing_factor = np.repeat(\n        initial_mixing_factor[None, :, :],\n        flow_field.n_findex,\n        axis=0\n    )\n    mixing_factor = mixing_factor * flow_field.turbulence_intensities[:, None, None]\n\n    # Calculate the velocity deficit sequentially from upstream to downstream turbines\n    for i in range(grid.n_turbines):\n\n        # Get the current turbine quantities\n        x_i = np.mean(grid.x_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        y_i = np.mean(grid.y_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n        z_i = np.mean(grid.z_sorted[:, i:i+1], axis=(2, 3), keepdims=True)\n\n        ct_i = thrust_coefficient(\n            velocities=flow_field.u_sorted,\n            turbulence_intensities=flow_field.turbulence_intensity_field_sorted,\n            air_density=flow_field.air_density,\n            yaw_angles=farm.yaw_angles_sorted,\n            tilt_angles=farm.tilt_angles_sorted,\n            power_setpoints=farm.power_setpoints_sorted,\n            awc_modes=farm.awc_modes_sorted,\n            awc_amplitudes=farm.awc_amplitudes_sorted,\n            thrust_coefficient_functions=farm.turbine_thrust_coefficient_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions,\n        )\n        # Since we are filtering for the i'th turbine in the thrust coefficient function,\n        # get the first index here (0:1)\n        ct_i = ct_i[:, 0:1, None, None]\n        axial_induction_i = axial_induction(\n            velocities=flow_field.u_sorted,\n            turbulence_intensities=flow_field.turbulence_intensity_field_sorted,\n            air_density=flow_field.air_density,\n            yaw_angles=farm.yaw_angles_sorted,\n            tilt_angles=farm.tilt_angles_sorted,\n            power_setpoints=farm.power_setpoints_sorted,\n            awc_modes=farm.awc_modes_sorted,\n            awc_amplitudes=farm.awc_amplitudes_sorted,\n            axial_induction_functions=farm.turbine_axial_induction_functions,\n            tilt_interps=farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=grid.average_method,\n            cubature_weights=grid.cubature_weights,\n            multidim_condition=flow_field.multidim_conditions,\n        )\n        # Since we are filtering for the i'th turbine in the axial induction function,\n        # get the first index here (0:1)\n        axial_induction_i = axial_induction_i[:, 0:1, None, None]\n        yaw_angle_i = farm.yaw_angles_sorted[:, i:i+1, None, None]\n        awc_mode_i = farm.awc_modes_sorted[:, i:i+1, None, None]\n        awc_amplitude_i = farm.awc_amplitudes_sorted[:, i:i+1, None, None]\n        awc_frequency_i = farm.awc_frequencies_sorted[:, i:i+1, None, None]\n        hub_height_i = farm.hub_heights_sorted[:, i:i+1, None, None]\n        rotor_diameter_i = farm.rotor_diameters_sorted[:, i:i+1, None, None]\n\n        # Secondary steering not currently implemented in EmGauss model\n        # effective_yaw_i = np.zeros_like(yaw_angle_i)\n        # effective_yaw_i += yaw_angle_i\n\n        average_velocities = average_velocity(\n            flow_field.u_sorted,\n            method=grid.average_method,\n            cubature_weights=grid.cubature_weights\n        )\n        tilt_angle_i = farm.calculate_tilt_for_eff_velocities(average_velocities)\n        tilt_angle_i = tilt_angle_i[:, i:i+1, None, None]\n\n        if model_manager.enable_secondary_steering:\n            raise NotImplementedError(\n                \"Secondary steering not available for this model.\")\n\n        if model_manager.enable_transverse_velocities:\n            raise NotImplementedError(\n                \"Transverse velocities not used in this model.\")\n\n        if model_manager.enable_yaw_added_recovery:\n            # Influence of yawing on turbine's own wake\n            mixing_factor[:, i:i+1, i] += \\\n                yaw_added_wake_mixing(\n                    axial_induction_i,\n                    yaw_angle_i,\n                    1,\n                    model_manager.deflection_model.yaw_added_mixing_gain\n                )\n\n        if model_manager.enable_active_wake_mixing:\n            # Influence of awc on turbine's own wake\n            mixing_factor[:, i:i+1, i] += \\\n                awc_added_wake_mixing(\n                    awc_mode_i,\n                    awc_amplitude_i,\n                    awc_frequency_i,\n                    model_manager.velocity_model.awc_wake_exp,\n                    model_manager.velocity_model.awc_wake_denominator\n                )\n\n        # Extract total wake induced mixing for turbine i\n        mixing_i = np.linalg.norm(\n            mixing_factor[:, i:i+1, :, None],\n            ord=2, axis=2, keepdims=True\n        )\n\n        # Model calculations\n        # NOTE: exponential\n        deflection_field_y, deflection_field_z = model_manager.deflection_model.function(\n            x_i,\n            y_i,\n            yaw_angle_i,\n            tilt_angle_i,\n            mixing_i,\n            ct_i,\n            rotor_diameter_i,\n            **deflection_model_args\n        )\n\n        # NOTE: exponential\n        velocity_deficit = model_manager.velocity_model.function(\n            x_i,\n            y_i,\n            z_i,\n            axial_induction_i,\n            deflection_field_y,\n            deflection_field_z,\n            yaw_angle_i,\n            tilt_angle_i,\n            mixing_i,\n            ct_i,\n            hub_height_i,\n            rotor_diameter_i,\n            **deficit_model_args\n        )\n\n        wake_field = model_manager.combination_model.function(\n            wake_field,\n            velocity_deficit * flow_field.u_initial_sorted\n        )\n\n        # Calculate wake overlap for wake-added turbulence (WAT)\n        area_overlap = np.sum(velocity_deficit * flow_field.u_initial_sorted > 0.05, axis=(2, 3))\\\n            / (grid.grid_resolution * grid.grid_resolution)\n\n        # Compute wake induced mixing factor\n        mixing_factor[:,:,i] += \\\n            area_overlap * model_manager.turbulence_model.function(\n                axial_induction_i, downstream_distance_D[:,:,i]\n            )\n        if model_manager.enable_yaw_added_recovery:\n            mixing_factor[:,:,i] += \\\n                area_overlap * yaw_added_wake_mixing(\n                axial_induction_i,\n                yaw_angle_i,\n                downstream_distance_D[:,:,i],\n                model_manager.deflection_model.yaw_added_mixing_gain\n            )\n\n        flow_field.u_sorted = flow_field.u_initial_sorted - wake_field\n        flow_field.v_sorted += v_wake\n        flow_field.w_sorted += w_wake\n\n    return mixing_factor\n\n\ndef full_flow_empirical_gauss_solver(\n    farm: Farm,\n    flow_field: FlowField,\n    flow_field_grid: FlowFieldGrid,\n    model_manager: WakeModelManager\n) -> None:\n\n    # Get the flow quantities and turbine performance\n    turbine_grid_farm = copy.deepcopy(farm)\n    turbine_grid_flow_field = copy.deepcopy(flow_field)\n\n    turbine_grid_farm.construct_turbine_map()\n    turbine_grid_farm.construct_turbine_thrust_coefficient_functions()\n    turbine_grid_farm.construct_turbine_axial_induction_functions()\n    turbine_grid_farm.construct_turbine_power_functions()\n    turbine_grid_farm.construct_hub_heights()\n    turbine_grid_farm.construct_rotor_diameters()\n    turbine_grid_farm.construct_turbine_TSRs()\n    turbine_grid_farm.construct_turbine_ref_tilts()\n    turbine_grid_farm.construct_turbine_tilt_interps()\n    turbine_grid_farm.construct_turbine_correct_cp_ct_for_tilt()\n    turbine_grid_farm.set_tilt_to_ref_tilt(flow_field.n_findex)\n\n    turbine_grid = TurbineGrid(\n        turbine_coordinates=turbine_grid_farm.coordinates,\n        turbine_diameters=turbine_grid_farm.rotor_diameters,\n        wind_directions=turbine_grid_flow_field.wind_directions,\n        grid_resolution=3,\n    )\n    turbine_grid_farm.expand_farm_properties(\n        turbine_grid_flow_field.n_findex,\n        turbine_grid.sorted_coord_indices\n    )\n    turbine_grid_flow_field.initialize_velocity_field(turbine_grid)\n    turbine_grid_farm.initialize(turbine_grid.sorted_indices)\n    wim_field = empirical_gauss_solver(\n        turbine_grid_farm,\n        turbine_grid_flow_field,\n        turbine_grid,\n        model_manager\n    )\n\n    # Create placeholder for TI, which is not currently used in the EmG model\n    n_points = flow_field_grid.x_sorted.shape[1]\n    ambient_turbulence_intensities = flow_field.turbulence_intensities[:, None, None, None]\n    ambient_turbulence_intensities = np.repeat(ambient_turbulence_intensities, n_points, axis=1)\n    turbulence_intensity_field = ambient_turbulence_intensities.copy()\n\n    ### Referring to the quantities from above, calculate the wake in the full grid\n\n    # Use full flow_field here to use the full grid in the wake models\n    deflection_model_args = model_manager.deflection_model.prepare_function(\n        flow_field_grid, flow_field\n    )\n    deficit_model_args = model_manager.velocity_model.prepare_function(flow_field_grid, flow_field)\n\n    wake_field = np.zeros_like(flow_field.u_initial_sorted)\n    v_wake = np.zeros_like(flow_field.v_initial_sorted)\n    w_wake = np.zeros_like(flow_field.w_initial_sorted)\n\n    # Calculate the velocity deficit sequentially from upstream to downstream turbines\n    for i in range(flow_field_grid.n_turbines):\n\n        # Get the current turbine quantities\n        x_i = np.mean(turbine_grid.x_sorted[:, i:i+1], axis=(2,3), keepdims=True)\n        y_i = np.mean(turbine_grid.y_sorted[:, i:i+1], axis=(2,3), keepdims=True)\n        z_i = np.mean(turbine_grid.z_sorted[:, i:i+1], axis=(2,3), keepdims=True)\n\n        ct_i = thrust_coefficient(\n            velocities=turbine_grid_flow_field.u_sorted,\n            turbulence_intensities=turbine_grid_flow_field.turbulence_intensity_field_sorted,\n            air_density=turbine_grid_flow_field.air_density,\n            yaw_angles=turbine_grid_farm.yaw_angles_sorted,\n            tilt_angles=turbine_grid_farm.tilt_angles_sorted,\n            power_setpoints=turbine_grid_farm.power_setpoints_sorted,\n            awc_modes=turbine_grid_farm.awc_modes_sorted,\n            awc_amplitudes=turbine_grid_farm.awc_amplitudes_sorted,\n            thrust_coefficient_functions=turbine_grid_farm.turbine_thrust_coefficient_functions,\n            tilt_interps=turbine_grid_farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=turbine_grid_farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=turbine_grid_farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=turbine_grid_farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=turbine_grid.average_method,\n            cubature_weights=turbine_grid.cubature_weights,\n            multidim_condition=turbine_grid_flow_field.multidim_conditions,\n        )\n        # Since we are filtering for the i'th turbine in the thrust coefficient function,\n        # get the first index here (0:1)\n        ct_i = ct_i[:, 0:1, None, None]\n        axial_induction_i = axial_induction(\n            velocities=turbine_grid_flow_field.u_sorted,\n            turbulence_intensities=turbine_grid_flow_field.turbulence_intensity_field_sorted,\n            air_density=turbine_grid_flow_field.air_density,\n            yaw_angles=turbine_grid_farm.yaw_angles_sorted,\n            tilt_angles=turbine_grid_farm.tilt_angles_sorted,\n            power_setpoints=turbine_grid_farm.power_setpoints_sorted,\n            awc_modes=turbine_grid_farm.awc_modes_sorted,\n            awc_amplitudes=turbine_grid_farm.awc_amplitudes_sorted,\n            axial_induction_functions=turbine_grid_farm.turbine_axial_induction_functions,\n            tilt_interps=turbine_grid_farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=turbine_grid_farm.correct_cp_ct_for_tilt_sorted,\n            turbine_type_map=turbine_grid_farm.turbine_type_map_sorted,\n            turbine_power_thrust_tables=turbine_grid_farm.turbine_power_thrust_tables,\n            ix_filter=[i],\n            average_method=turbine_grid.average_method,\n            cubature_weights=turbine_grid.cubature_weights,\n            multidim_condition=turbine_grid_flow_field.multidim_conditions,\n        )\n        # Since we are filtering for the i'th turbine in the axial induction function,\n        # get the first index here (0:1)\n        axial_induction_i = axial_induction_i[:, 0:1, None, None]\n        yaw_angle_i = turbine_grid_farm.yaw_angles_sorted[:, i:i+1, None, None]\n        hub_height_i = turbine_grid_farm.hub_heights_sorted[:, i:i+1, None, None]\n        rotor_diameter_i = turbine_grid_farm.rotor_diameters_sorted[:, i:i+1, None, None]\n        wake_induced_mixing_i = wim_field[:, i:i+1, :, None].sum(axis=2, keepdims=1)\n        effective_yaw_i = np.zeros_like(yaw_angle_i)\n        effective_yaw_i += yaw_angle_i\n\n        average_velocities = average_velocity(\n            turbine_grid_flow_field.u_sorted,\n            method=turbine_grid.average_method,\n            cubature_weights=turbine_grid.cubature_weights\n        )\n        tilt_angle_i = turbine_grid_farm.calculate_tilt_for_eff_velocities(average_velocities)\n        tilt_angle_i = tilt_angle_i[:, i:i+1, None, None]\n\n        if model_manager.enable_secondary_steering:\n            raise NotImplementedError(\n                \"Secondary steering not available for this model.\")\n\n        if model_manager.enable_transverse_velocities:\n            raise NotImplementedError(\n                \"Transverse velocities not used in this model.\")\n\n        # Model calculations\n        # NOTE: exponential\n        deflection_field_y, deflection_field_z = model_manager.deflection_model.function(\n            x_i,\n            y_i,\n            effective_yaw_i,\n            tilt_angle_i,\n            wake_induced_mixing_i,\n            ct_i,\n            rotor_diameter_i,\n            **deflection_model_args\n        )\n\n        # NOTE: exponential\n        velocity_deficit = model_manager.velocity_model.function(\n            x_i,\n            y_i,\n            z_i,\n            axial_induction_i,\n            deflection_field_y,\n            deflection_field_z,\n            yaw_angle_i,\n            tilt_angle_i,\n            wake_induced_mixing_i,\n            ct_i,\n            hub_height_i,\n            rotor_diameter_i,\n            **deficit_model_args\n        )\n\n        wake_field = model_manager.combination_model.function(\n            wake_field,\n            velocity_deficit * flow_field.u_initial_sorted\n        )\n\n        flow_field.u_sorted = flow_field.u_initial_sorted - wake_field\n        flow_field.v_sorted += v_wake\n        flow_field.w_sorted += w_wake\n        flow_field.turbulence_intensity_field_sorted = turbulence_intensity_field\n"
  },
  {
    "path": "floris/core/turbine/__init__.py",
    "content": "\nfrom floris.core.turbine.controller_dependent_operation_model import ControllerDependentTurbine\nfrom floris.core.turbine.operation_models import (\n    AWCTurbine,\n    CosineLossTurbine,\n    MixedOperationTurbine,\n    PeakShavingTurbine,\n    SimpleDeratingTurbine,\n    SimpleTurbine,\n)\nfrom floris.core.turbine.unified_momentum_model import UnifiedMomentumModelTurbine\n"
  },
  {
    "path": "floris/core/turbine/controller_dependent_operation_model.py",
    "content": "import copy\n\nimport numpy as np\nfrom attrs import define\nfrom scipy.interpolate import RegularGridInterpolator\nfrom scipy.optimize import fsolve\n\nfrom floris.core.rotor_velocity import (\n    average_velocity,\n    compute_tilt_angles_for_floating_turbines,\n    rotor_velocity_air_density_correction,\n)\nfrom floris.core.turbine.operation_models import BaseOperationModel\nfrom floris.type_dec import (\n    NDArrayFloat,\n    NDArrayObject,\n)\nfrom floris.utilities import cosd, sind\n\n\n@define\nclass ControllerDependentTurbine(BaseOperationModel):\n    \"\"\"\n    Static class defining a wind turbine model that may be misaligned with the flow.\n    Nonzero tilt and yaw angles are handled via the model presented in\n    https://doi.org/10.5194/wes-2023-133 .\n\n    The method requires C_P, C_T look-up tables as functions of tip speed ratio and blade pitch\n    angle, available here:\n    \"floris/turbine_library/iea_15MW_demo_cp_ct_surface.npz\" for the IEA 15MW reference turbine.\n    As with all turbine submodules, implements only static power() and thrust_coefficient() methods,\n    which are called by power() and thrust_coefficient() on turbine.py, respectively.\n    There are also two new functions, i.e. compute_local_vertical_shear() and control_trajectory().\n    These are called by thrust_coefficient() and power() to compute the vertical shear and predict\n    the turbine status in terms of tip speed ratio and pitch angle.\n    This class is not intended to be instantiated; it simply defines a library of static methods.\n\n    Developed and implemented by Simone Tamaro, Filippo Campagnolo, and Carlo L. Bottasso\n    at Technische Universität München (TUM).\n    email: simone.tamaro@tum.de\n    \"\"\"\n\n    @staticmethod\n    def power(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        yaw_angles: NDArrayFloat,\n        tilt_angles: NDArrayFloat,\n        power_setpoints: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_,  # <- Allows other models to accept other keyword arguments\n    ):\n        # Sign convention: in the TUM model, negative tilt creates tower clearance\n        tilt_angles = -tilt_angles\n\n        # Compute the power-effective wind speed across the rotor\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        rotor_effective_velocities = rotor_velocity_air_density_correction(\n            velocities=rotor_average_velocities,\n            air_density=air_density,\n            ref_air_density=power_thrust_table[\"ref_air_density\"],\n        )\n\n        # Compute power\n        n_findex, n_turbines = tilt_angles.shape\n\n        shear = ControllerDependentTurbine.compute_local_vertical_shear(velocities)\n\n        beta = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"beta\"]\n        cd = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cd\"]\n        cl_alfa = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cl_alfa\"]\n\n        sigma = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"rotor_solidity\"]\n        R = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"rotor_diameter\"] / 2\n\n        air_density = power_thrust_table[\"ref_air_density\"]\n\n        pitch_out, tsr_out = ControllerDependentTurbine.control_trajectory(\n            rotor_effective_velocities,\n            yaw_angles,\n            tilt_angles,\n            air_density,\n            R,\n            shear,\n            power_setpoints,\n            power_thrust_table,\n        )\n\n        tsr_array = tsr_out\n        theta_array = np.deg2rad(pitch_out + beta)\n        x0 = 0.2\n\n        ### Solve for the power in yawed conditions\n        # Compute overall misalignment (eq. (1) in Tamaro et al.)\n        MU = np.arccos(cosd(yaw_angles) * cosd(tilt_angles))\n        cosMu = np.cos(MU)\n        sinMu = np.sin(MU)\n        p = np.zeros_like(average_velocity(velocities))\n        # Need to loop over findices to use fsolve\n        for i in np.arange(n_findex):\n            for j in np.arange(n_turbines):\n                # Create data tuple for fsolve\n                data = (\n                    sigma,\n                    cd,\n                    cl_alfa,\n                    yaw_angles[i, j],\n                    tilt_angles[i, j],\n                    shear[i, j],\n                    cosMu[i, j],\n                    sinMu[i, j],\n                    (tsr_array[i, j]),\n                    (theta_array[i, j]),\n                    MU[i, j],\n                )\n                ct, info, ier, msg = fsolve(\n                    ControllerDependentTurbine.get_ct,\n                    x0,\n                    args=data,\n                    full_output=True\n                )\n                if ier == 1:\n                    p[i, j] = np.squeeze(\n                        ControllerDependentTurbine.find_cp(\n                            sigma,\n                            cd,\n                            cl_alfa,\n                            yaw_angles[i, j],\n                            tilt_angles[i, j],\n                            shear[i, j],\n                            cosMu[i, j],\n                            sinMu[i, j],\n                            (tsr_array[i, j]),\n                            (theta_array[i, j]),\n                            MU[i, j],\n                            ct,\n                        )\n                    )\n                else:\n                    p[i, j] = -1e3\n\n        ### Solve for the power in non-yawed conditions\n        yaw_angles = np.zeros_like(yaw_angles)\n        # Compute overall misalignment (eq. (1) in Tamaro et al.)\n        MU = np.arccos(cosd(yaw_angles) * cosd(tilt_angles))\n        cosMu = np.cos(MU)\n        sinMu = np.sin(MU)\n\n        p0 = np.zeros_like((average_velocity(velocities)))\n\n        for i in np.arange(n_findex):\n            for j in np.arange(n_turbines):\n                data = (\n                    sigma,\n                    cd,\n                    cl_alfa,\n                    yaw_angles[i, j],\n                    tilt_angles[i, j],\n                    shear[i, j],\n                    cosMu[i, j],\n                    sinMu[i, j],\n                    (tsr_array[i, j]),\n                    (theta_array[i, j]),\n                    MU[i, j],\n                )\n                ct, info, ier, msg = fsolve(\n                    ControllerDependentTurbine.get_ct,\n                    x0,\n                    args=data,\n                    full_output=True\n                )\n                if ier == 1:\n                    p0[i, j] = np.squeeze(\n                        ControllerDependentTurbine.find_cp(\n                            sigma,\n                            cd,\n                            cl_alfa,\n                            yaw_angles[i, j],\n                            tilt_angles[i, j],\n                            shear[i, j],\n                            cosMu[i, j],\n                            sinMu[i, j],\n                            (tsr_array[i, j]),\n                            (theta_array[i, j]),\n                            MU[i, j],\n                            ct,\n                        )\n                    )\n                else:\n                    p0[i, j] = -1e3\n\n        # ratio of yawed to unyawed thrust coefficients\n        ratio = p / p0\n\n        # Extract data from lookup table and construct interpolator\n        cp_ct_data = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"]\n        cp_i = np.array(cp_ct_data[\"cp_lut\"])\n        pitch_i = np.array(cp_ct_data[\"pitch_lut\"])\n        tsr_i = np.array(cp_ct_data[\"tsr_lut\"])\n        interp_lut = RegularGridInterpolator(\n            (tsr_i, pitch_i), cp_i, bounds_error=False, fill_value=None\n        )\n\n        power_coefficient = np.zeros_like(average_velocity(velocities))\n        cp_interp = interp_lut(\n            np.concatenate((tsr_array[:,:,None], pitch_out[:,:,None]), axis=2), method=\"cubic\"\n        )\n        power_coefficient = cp_interp * ratio\n\n        power = (\n            0.5\n            * air_density\n            * (rotor_effective_velocities)**3\n            * np.pi\n            * R**2\n            * power_coefficient\n            * power_thrust_table[\"controller_dependent_turbine_parameters\"][\"generator_efficiency\"]\n        )\n\n        if power.max() > (power_thrust_table[\"controller_dependent_turbine_parameters\"]\n                                            [\"rated_power\"] * 1e3 * 1.01):\n            print(\"Powers more than 1% above rated detected. Consider checking Cp-Ct data.\")\n        power = np.clip(\n            power,\n            0,\n            power_thrust_table[\"controller_dependent_turbine_parameters\"][\"rated_power\"] * 1e3\n        )\n        return power\n\n    @staticmethod\n    def thrust_coefficient(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        yaw_angles: NDArrayFloat,\n        tilt_angles: NDArrayFloat,\n        power_setpoints: NDArrayFloat,\n        tilt_interp: NDArrayObject,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        correct_cp_ct_for_tilt: bool = False,\n        **_,  # <- Allows other models to accept other keyword arguments\n    ):\n        # sign convention. in the TUM model, negative tilt creates tower clearance\n        tilt_angles = -tilt_angles\n\n        # Compute the effective wind speed across the rotor\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        # Apply tilt and yaw corrections\n        # Compute the tilt, if using floating turbines\n        old_tilt_angles = copy.deepcopy(tilt_angles)\n        tilt_angles = compute_tilt_angles_for_floating_turbines(\n            tilt_angles=tilt_angles,\n            tilt_interp=tilt_interp,\n            rotor_effective_velocities=rotor_average_velocities,\n        )\n        # Only update tilt angle if requested (if the tilt isn't accounted for in the Ct curve)\n        tilt_angles = np.where(correct_cp_ct_for_tilt, tilt_angles, old_tilt_angles)\n\n        beta = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"beta\"]\n        cd = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cd\"]\n        cl_alfa = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cl_alfa\"]\n\n        sigma = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"rotor_solidity\"]\n        R = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"rotor_diameter\"] / 2\n\n        shear = ControllerDependentTurbine.compute_local_vertical_shear(velocities)\n\n        air_density = power_thrust_table[\"ref_air_density\"]  # CHANGE\n\n        rotor_effective_velocities = rotor_velocity_air_density_correction(\n            velocities=rotor_average_velocities,\n            air_density=air_density,\n            ref_air_density=power_thrust_table[\"ref_air_density\"],\n        )\n\n        # Apply standard control trajectory to determine pitch and TSR\n        pitch_out, tsr_out = ControllerDependentTurbine.control_trajectory(\n            rotor_effective_velocities,\n            yaw_angles,\n            tilt_angles,\n            air_density,\n            R,\n            shear,\n            power_setpoints,\n            power_thrust_table,\n        )\n\n        n_findex, n_turbines = tilt_angles.shape\n\n        # u = np.squeeze(u)\n        theta_array = np.deg2rad(pitch_out + beta)\n        tsr_array = tsr_out\n        x0 = 0.2 # Initial guess for the thrust coefficient solve\n\n        ### Solve for the thrust coefficient in yawed conditions\n        # Compute overall misalignment (eq. (1) in Tamaro et al.)\n        MU = np.arccos(cosd(yaw_angles) * cosd(tilt_angles))\n        cosMu = np.cos(MU)\n        sinMu = np.sin(MU)\n        thrust_coefficient1 = np.zeros_like(average_velocity(velocities))\n        # Need to loop over n_findex and n_turbines here to use fsolve\n        for i in np.arange(n_findex):\n            for j in np.arange(n_turbines):\n                data = (\n                    sigma,\n                    cd,\n                    cl_alfa,\n                    yaw_angles[i, j],\n                    tilt_angles[i, j],\n                    shear[i, j],\n                    cosMu[i, j],\n                    sinMu[i, j],\n                    (tsr_array[i, j]),\n                    (theta_array[i, j]),\n                    MU[i, j],\n                )\n                ct = fsolve(ControllerDependentTurbine.get_ct, x0, args=data) # Solves eq. (25)\n                thrust_coefficient1[i, j] = np.squeeze(np.clip(ct, 0.0001, 0.9999))\n\n        ### Resolve thrust coefficient in non-yawed conditions\n        yaw_angles = np.zeros_like(yaw_angles)\n        MU = np.arccos(cosd(yaw_angles) * cosd(tilt_angles))\n        cosMu = np.cos(MU)\n        sinMu = np.sin(MU)\n\n        thrust_coefficient0 = np.zeros_like(average_velocity(velocities))\n        # Need to loop over n_findex and n_turbines here to use fsolve\n        for i in np.arange(n_findex):\n            for j in np.arange(n_turbines):\n                data = (\n                    sigma,\n                    cd,\n                    cl_alfa,\n                    yaw_angles[i, j],\n                    tilt_angles[i, j],\n                    shear[i, j],\n                    cosMu[i, j],\n                    sinMu[i, j],\n                    (tsr_array[i, j]),\n                    (theta_array[i, j]),\n                    MU[i, j],\n                )\n                ct = fsolve(ControllerDependentTurbine.get_ct, x0, args=data) # Solves eq. (25)\n                thrust_coefficient0[i, j] = np.squeeze(ct)  # np.clip(ct, 0.0001, 0.9999)\n\n        # Compute ratio of yawed to unyawed thrust coefficients\n        ratio = thrust_coefficient1 / thrust_coefficient0 # See above eq. (29)\n\n        # Extract data from lookup table and construct interpolator\n        cp_ct_data = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"]\n        ct_i = np.array(cp_ct_data[\"ct_lut\"])\n        pitch_i = np.array(cp_ct_data[\"pitch_lut\"])\n        tsr_i = np.array(cp_ct_data[\"tsr_lut\"])\n        interp_lut = RegularGridInterpolator(\n            (tsr_i, pitch_i), ct_i, bounds_error=False, fill_value=None\n        )  # *0.9722085500886761)\n\n        # Interpolate and apply ratio to determine thrust coefficient\n        ct_interp = interp_lut(\n            np.concatenate((tsr_array[:,:,None], pitch_out[:,:,None]), axis=2), method=\"cubic\"\n        )\n        thrust_coefficient = ct_interp * ratio\n\n        return thrust_coefficient\n\n    @staticmethod\n    def axial_induction(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        yaw_angles: NDArrayFloat,\n        tilt_angles: NDArrayFloat,\n        power_setpoints: NDArrayFloat,\n        tilt_interp: NDArrayObject,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        correct_cp_ct_for_tilt: bool = False,\n        **_,  # <- Allows other models to accept other keyword arguments\n    ):\n        thrust_coefficients = ControllerDependentTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            yaw_angles=yaw_angles,\n            tilt_angles=tilt_angles,\n            power_setpoints=power_setpoints,\n            tilt_interp=tilt_interp,\n            average_method=average_method,\n            cubature_weights=cubature_weights,\n            correct_cp_ct_for_tilt=correct_cp_ct_for_tilt,\n        )\n\n        # TODO: should the axial induction calculation be based on MU for zero yaw (as it is\n        # currently) or should this be the actual yaw angle?\n        yaw_angles = np.zeros_like(yaw_angles)\n        MU = np.arccos(cosd(yaw_angles) * cosd(tilt_angles))\n        sinMu = np.sin(MU) # all the same in this case anyway (since yaw zero)\n\n        # Eq. (25a) from Tamaro et al.\n        a = 1 - (\n            (1 + np.sqrt(1 - thrust_coefficients - 1 / 16 * thrust_coefficients**2 * sinMu ** 2))\n            / (2 * (1 + 1 / 16 * thrust_coefficients * sinMu ** 2))\n        )\n        axial_induction = np.clip(a, 0.0001, 0.9999)\n\n        return axial_induction\n\n    @staticmethod\n    def compute_local_vertical_shear(velocities):\n        \"\"\"\n        Called to evaluate the vertical (linear) shear that each rotor experience, based on the\n        inflow velocity. This allows to make the power curve asymmetric w.r.t. yaw misalignment.\n        \"\"\"\n        # Check that there is a vertical profile to compute a shear profile for. If not,\n        # raise an error.\n        if velocities.shape[3] == 1:\n            raise ValueError((\n                \"The ControllerDependentTurbine computes a local shear based on inflow wind speeds \"\n                \"across the rotor. The provided velocities does not contain a vertical profile. \"\n                \"This can occur if n_grid is set to 1 in the FLORIS input yaml.\"\n            ))\n        n_findex, n_turbines = velocities.shape[:2]\n        shear = np.zeros((n_findex, n_turbines))\n        for i in np.arange(n_findex):\n            for j in np.arange(n_turbines):\n                mean_speed = np.mean(velocities[i, j, :, :], axis=0)\n                if len(mean_speed) % 2 != 0:  # odd number\n                    u_u_hh = mean_speed / mean_speed[int(np.floor(len(mean_speed) / 2))]\n                else:\n                    u_u_hh = (\n                        mean_speed\n                        / (\n                            mean_speed[int((len(mean_speed) / 2))]\n                            + mean_speed[int((len(mean_speed) / 2)) - 1]\n                        )\n                        / 2\n                    )\n                zg_R = np.linspace(-1, 1, len(mean_speed) + 2)\n                polifit_k = np.polyfit(zg_R[1:-1], 1 - u_u_hh, 1)\n                shear[i, j] = -polifit_k[0]\n        return shear\n\n    @staticmethod\n    def control_trajectory(\n        rotor_average_velocities,\n        yaw_angles,\n        tilt_angles,\n        air_density,\n        R,\n        shear,\n        power_setpoints,\n        power_thrust_table,\n    ):\n        \"\"\"\n        Determines the tip-speed-ratio and pitch angles that occur in operation. This routine\n        assumes a standard region 2 control approach (i.e. k*rpm^2) and a region 3. Also\n        region 2-1/2 is considered. In the future, different control strategies could be included,\n        even user-defined.\n        \"\"\"\n        # Unpack parameters from power_thrust_table\n        beta = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"beta\"]\n        cd = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cd\"]\n        cl_alfa = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cl_alfa\"]\n        sigma = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"rotor_solidity\"]\n\n        # Compute power demanded\n        if power_setpoints is None:\n            power_demanded = (\n                np.ones_like(tilt_angles)\n                * power_thrust_table[\"controller_dependent_turbine_parameters\"][\"rated_power\"]\n                * 1000\n                / power_thrust_table[\"controller_dependent_turbine_parameters\"]\n                                    [\"generator_efficiency\"]\n            )\n        else:\n            power_demanded = (\n                power_setpoints / power_thrust_table[\"controller_dependent_turbine_parameters\"]\n                                                    [\"generator_efficiency\"]\n            )\n\n        ## Define function to get tip speed ratio\n        def get_tsr(x, *data):\n            (\n                air_density,\n                R,\n                sigma,\n                shear,\n                cd,\n                cl_alfa,\n                beta,\n                gamma,\n                tilt,\n                u,\n                pitch_in,\n                omega_lut_pow,\n                torque_lut_omega,\n                cp_i,\n                pitch_i,\n                tsr_i,\n            ) = data\n\n            omega_lut_torque = omega_lut_pow * np.pi / 30\n\n            omega = x * u / R\n            omega_rpm = omega * 30 / np.pi\n\n            torque_nm = np.interp(omega, omega_lut_torque, torque_lut_omega)\n\n            # Yawed case\n            mu = np.arccos(cosd(gamma) * cosd(tilt))\n            data = (\n                sigma,\n                cd,\n                cl_alfa,\n                gamma,\n                tilt,\n                shear,\n                np.cos(mu),\n                np.sin(mu),\n                x,\n                np.deg2rad(pitch_in) + np.deg2rad(beta),\n                mu,\n            )\n            x0 = 0.1\n            [ct, infodict, ier, mesg] = fsolve(\n                ControllerDependentTurbine.get_ct, x0, args=data, full_output=True, factor=0.1\n            )\n            cp = ControllerDependentTurbine.find_cp(\n                sigma,\n                cd,\n                cl_alfa,\n                gamma,\n                tilt,\n                shear,\n                np.cos(mu),\n                np.sin(mu),\n                x,\n                np.deg2rad(pitch_in) + np.deg2rad(beta),\n                mu,\n                ct,\n            )\n\n            # Unyawed case\n            mu = np.arccos(cosd(0) * cosd(tilt))\n            data = (\n                sigma,\n                cd,\n                cl_alfa,\n                0,\n                tilt,\n                shear,\n                np.cos(mu),\n                np.sin(mu),\n                x,\n                np.deg2rad(pitch_in) + np.deg2rad(beta),\n                mu,\n            )\n            x0 = 0.1\n            [ct, infodict, ier, mesg] = fsolve(\n                ControllerDependentTurbine.get_ct, x0, args=data, full_output=True, factor=0.1\n            )\n            cp0 = ControllerDependentTurbine.find_cp(\n                sigma,\n                cd,\n                cl_alfa,\n                0,\n                tilt,\n                shear,\n                np.cos(mu),\n                np.sin(mu),\n                x,\n                np.deg2rad(pitch_in) + np.deg2rad(beta),\n                mu,\n                ct,\n            )\n\n            # Ratio\n            eta_p = cp / cp0\n\n            interp = RegularGridInterpolator(\n                (np.squeeze((tsr_i)), np.squeeze((pitch_i))),\n                cp_i,\n                bounds_error=False,\n                fill_value=None,\n            )\n\n            Cp_now = interp((x, pitch_in), method=\"cubic\")\n            cp_g1 = Cp_now * eta_p\n            aero_pow = 0.5 * air_density * (np.pi * R**2) * (u)**3 * cp_g1\n            electric_pow = torque_nm * (omega_rpm * np.pi / 30)\n\n            y = aero_pow - electric_pow\n            return y\n\n        ## Define function to get pitch angle\n        def get_pitch(x, *data):\n            (\n                air_density,\n                R,\n                sigma,\n                shear,\n                cd,\n                cl_alfa,\n                beta,\n                gamma,\n                tilt,\n                u,\n                omega_rated,\n                omega_lut_torque,\n                torque_lut_omega,\n                cp_i,\n                pitch_i,\n                tsr_i,\n            ) = data\n\n            omega_rpm = omega_rated * 30 / np.pi\n            tsr = omega_rated * R / (u)\n\n            pitch_in = np.deg2rad(x)\n            torque_nm = np.interp(\n                omega_rpm, omega_lut_torque * 30 / np.pi, torque_lut_omega\n            )\n\n            # Yawed case\n            mu = np.arccos(cosd(gamma) * cosd(tilt))\n            data = (\n                sigma,\n                cd,\n                cl_alfa,\n                gamma,\n                tilt,\n                shear,\n                np.cos(mu),\n                np.sin(mu),\n                tsr,\n                (pitch_in) + np.deg2rad(beta),\n                mu,\n            )\n            x0 = 0.1\n            [ct, infodict, ier, mesg] = fsolve(\n                ControllerDependentTurbine.get_ct, x0, args=data, full_output=True, factor=0.1\n            )\n            cp = ControllerDependentTurbine.find_cp(\n                sigma,\n                cd,\n                cl_alfa,\n                gamma,\n                tilt,\n                shear,\n                np.cos(mu),\n                np.sin(mu),\n                tsr,\n                (pitch_in) + np.deg2rad(beta),\n                mu,\n                ct,\n            )\n\n            # Unyawed case\n            mu = np.arccos(cosd(0) * cosd(tilt))\n            data = (\n                sigma,\n                cd,\n                cl_alfa,\n                0,\n                tilt,\n                shear,\n                np.cos(mu),\n                np.sin(mu),\n                tsr,\n                (pitch_in) + np.deg2rad(beta),\n                mu,\n            )\n            x0 = 0.1\n            [ct, infodict, ier, mesg] = fsolve(\n                ControllerDependentTurbine.get_ct, x0, args=data, full_output=True, factor=0.1\n            )\n            cp0 = ControllerDependentTurbine.find_cp(\n                sigma,\n                cd,\n                cl_alfa,\n                0,\n                tilt,\n                shear,\n                np.cos(mu),\n                np.sin(mu),\n                tsr,\n                (pitch_in) + np.deg2rad(beta),\n                mu,\n                ct,\n            )\n\n            # Ratio yawed / unyawed\n            eta_p = cp / cp0\n\n            interp = RegularGridInterpolator(\n                (np.squeeze((tsr_i)), np.squeeze((pitch_i))),\n                cp_i,\n                bounds_error=False,\n                fill_value=None,\n            )\n\n            Cp_now = interp((tsr, x), method=\"cubic\")\n            cp_g1 = Cp_now * eta_p\n            aero_pow = 0.5 * air_density * (np.pi * R**2) * (u)**3 * cp_g1\n            electric_pow = torque_nm * (omega_rpm * np.pi / 30)\n\n            y = aero_pow - electric_pow\n            return y\n\n        # Extract data from lookup table\n        cp_ct_data = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"]\n        cp_i = np.array(cp_ct_data[\"cp_lut\"])\n        pitch_i = np.array(cp_ct_data[\"pitch_lut\"])\n        tsr_i = np.array(cp_ct_data[\"tsr_lut\"])\n        idx = np.squeeze(np.where(cp_i == np.max(cp_i)))\n\n        tsr_opt = tsr_i[idx[0]]\n        pitch_opt = pitch_i[idx[1]]\n        max_cp = cp_i[idx[0], idx[1]]\n\n        omega_cut_in = 0  # RPM\n        omega_max = power_thrust_table[\"controller_dependent_turbine_parameters\"][\"rated_rpm\"]\n        rated_power_aero = (\n            power_thrust_table[\"controller_dependent_turbine_parameters\"][\"rated_power\"]\n            / power_thrust_table[\"controller_dependent_turbine_parameters\"][\"generator_efficiency\"]\n        ) * 1000\n\n        # Compute torque-rpm relation and check for region 2-and-a-half\n        Region2andAhalf = False\n\n        omega_array = np.linspace(omega_cut_in, omega_max, 161) * np.pi / 30  # rad/s\n        Q = (0.5 * air_density * omega_array**2 * R**5 * np.pi * max_cp) / tsr_opt**3\n\n        Paero_array = Q * omega_array\n\n        if Paero_array[-1] < rated_power_aero:  # then we have region 2-and-a-half\n            Region2andAhalf = True\n            Q_extra = rated_power_aero / (omega_max * np.pi / 30)\n            Q = np.append(Q, Q_extra)\n            # TODO: Expression below is not assigned to anything. Should this be removed?\n            (Paero_array[-1] / (0.5 * air_density * np.pi * R**2 * max_cp)) ** (1 / 3)\n            omega_array = np.append(omega_array, omega_array[-1])\n            Paero_array = np.append(Paero_array, rated_power_aero)\n        else:  # limit aero_power to the last Q*omega_max\n            rated_power_aero = Paero_array[-1]\n\n        u_rated = (rated_power_aero / (0.5 * air_density * np.pi * R**2 * max_cp)) ** (\n            1 / 3\n        )\n        u_array = np.linspace(3, 25, 45)\n        idx = np.argmin(np.abs(u_array - u_rated))\n        if u_rated > u_array[idx]:\n            u_array = np.insert(u_array, idx + 1, u_rated)\n        else:\n            u_array = np.insert(u_array, idx, u_rated)\n\n        pow_lut_omega = Paero_array\n        omega_lut_pow = omega_array * 30 / np.pi\n        torque_lut_omega = Q\n        omega_lut_torque = omega_lut_pow\n\n        n_findex, n_turbines = tilt_angles.shape\n\n        omega_rated = np.interp(power_demanded, pow_lut_omega, omega_lut_pow) * np.pi / 30  # rad/s\n        u_rated = (power_demanded / (0.5 * air_density * np.pi * R**2 * max_cp)) ** (1 / 3)\n\n        pitch_out = np.zeros_like(rotor_average_velocities)\n        tsr_out = np.zeros_like(rotor_average_velocities)\n\n        # Must loop to use fsolve\n        for i in np.arange(n_findex):\n            for j in np.arange(n_turbines):\n                u_v = rotor_average_velocities[i, j]\n                if u_v > u_rated[i, j]:\n                    tsr_v = (\n                        omega_rated[i, j] * R / u_v * cosd(yaw_angles[i, j]) ** 0.5\n                    )\n                else:\n                    tsr_v = tsr_opt * cosd(yaw_angles[i, j])\n                if Region2andAhalf:  # fix for interpolation\n                    omega_lut_torque[-1] = omega_lut_torque[-1] + 1e-2\n                    omega_lut_pow[-1] = omega_lut_pow[-1] + 1e-2\n\n                data = (\n                    air_density,\n                    R,\n                    sigma,\n                    shear[i, j],\n                    cd,\n                    cl_alfa,\n                    beta,\n                    yaw_angles[i, j],\n                    tilt_angles[i, j],\n                    u_v,\n                    pitch_opt,\n                    omega_lut_pow,\n                    torque_lut_omega,\n                    cp_i,\n                    pitch_i,\n                    tsr_i,\n                )\n                [tsr_out_soluzione, infodict, ier, mesg] = fsolve(\n                    get_tsr, tsr_v, args=data, full_output=True\n                )\n                # check if solution was possible. If not, we are in region 3\n                if np.abs(infodict[\"fvec\"]) > 10 or tsr_out_soluzione < 4:\n                    tsr_out_soluzione = 1000\n\n                # save solution\n                tsr_outO = tsr_out_soluzione\n                omega = tsr_outO * u_v / R\n\n                # check if we are in region 2 or 3\n                if omega < omega_rated[i, j]:  # region 2\n                    # Define optimum pitch\n                    pitch_out0 = pitch_opt\n\n                else:  # region 3\n                    tsr_outO = omega_rated[i, j] * R / u_v\n                    data = (\n                        air_density,\n                        R,\n                        sigma,\n                        shear[i, j],\n                        cd,\n                        cl_alfa,\n                        beta,\n                        yaw_angles[i, j],\n                        tilt_angles[i, j],\n                        u_v,\n                        omega_rated[i, j],\n                        omega_array,\n                        Q,\n                        cp_i,\n                        pitch_i,\n                        tsr_i,\n                    )\n                    # solve aero-electrical power balance with TSR from rated omega\n                    [pitch_out_soluzione, infodict, ier, mesg] = fsolve(\n                        get_pitch,\n                        u_v,\n                        args=data,\n                        factor=0.1,\n                        full_output=True,\n                        xtol=1e-10,\n                        maxfev=2000,\n                    )\n                    if pitch_out_soluzione < pitch_opt:\n                        pitch_out_soluzione = pitch_opt\n                    pitch_out0 = pitch_out_soluzione\n\n                # pitch and tsr will be used to compute Cp and Ct\n                pitch_out[i, j] = np.squeeze(pitch_out0)\n                tsr_out[i, j] = np.squeeze(tsr_outO)\n\n        return pitch_out, tsr_out\n\n    @staticmethod\n    def find_cp(sigma, cd, cl_alfa, gamma, delta, k, cosMu, sinMu, tsr, theta, MU, ct):\n        # add a small misalignment in case MU = 0 to avoid division by 0\n        if MU == 0:\n            MU = 1e-6\n            sinMu = np.sin(MU)\n            cosMu = np.cos(MU)\n        a = 1 - (\n            (1 + np.sqrt(1 - ct - 1 / 16 * sinMu**2 * ct**2))\n            / (2 * (1 + 1 / 16 * ct * sinMu**2))\n        )\n        SG = sind(gamma)\n        CG = cosd(gamma)\n        SD = sind(delta)\n        CD = cosd(delta)\n        k_1s = -1 * (15 * np.pi / 32 * np.tan((MU + sinMu * (ct / 2)) / 2))\n\n        p = sigma * (\n            (\n                np.pi\n                * cosMu**2\n                * tsr\n                * cl_alfa\n                * (a - 1) ** 2\n                - (\n                    tsr\n                    * cd\n                    * np.pi\n                    * (\n                        CD**2 * CG**2 * SD**2 * k**2\n                        + 3 * CD**2 * SG**2 * k**2\n                        - 8 * CD * tsr * SG * k\n                        + 8 * tsr**2\n                    )\n                )\n                / 16\n                - (np.pi * tsr * sinMu**2 * cd) / 2\n                - (2 * np.pi * cosMu * tsr**2 * cl_alfa * theta) / 3\n                + (np.pi * cosMu**2 * k_1s**2 * tsr * a**2 * cl_alfa) / 4\n                + (2 * np.pi * cosMu * tsr**2 * a * cl_alfa * theta) / 3\n                + (2 * np.pi * CD * cosMu * tsr * SG * cl_alfa * k * theta) / 3\n                + (\n                    (\n                        CD**2 * cosMu**2 * tsr * cl_alfa * k**2 * np.pi * (a - 1)**2\n                        * (CG**2 * SD**2 + SG**2)\n                    )\n                    / (4 * sinMu**2)\n                )\n                - (2 * np.pi * CD * cosMu * tsr * SG * a * cl_alfa * k * theta) / 3\n                + (\n                    (\n                        CD**2 * cosMu**2 * k_1s**2 * tsr * a**2 * cl_alfa * k**2 * np.pi\n                        * (3 * CG**2 * SD**2 + SG**2)\n                    )\n                    / (24 * sinMu**2)\n                )\n                - (np.pi * CD * CG * cosMu**2 * k_1s * tsr * SD * a * cl_alfa * k) / sinMu\n                + (np.pi * CD * CG * cosMu**2 * k_1s * tsr * SD * a**2 * cl_alfa * k)\n                / sinMu\n                + (np.pi * CD * CG * cosMu * k_1s * tsr**2 * SD * a * cl_alfa * k * theta)\n                / (5 * sinMu)\n                - (np.pi * CD**2 * CG * cosMu * k_1s * tsr * SD * SG * a * cl_alfa * k**2 * theta)\n                / (10 * sinMu)\n            )\n            / (2 * np.pi)\n        )\n        return p\n\n    @staticmethod\n    def get_ct(x, *data):\n        \"\"\"\n        System of equations for Ct, as represented in Eq. (25) of Tamaro et al.\n        x is a stand-in variable for Ct, which a numerical solver will solve for.\n        data is a tuple of input parameters to the system of equations to solve.\n        \"\"\"\n        sigma, cd, cl_alfa, gamma, delta, k, cosMu, sinMu, tsr, theta, MU = data\n        # Add a small misalignment in case MU = 0 to avoid division by 0\n        if MU == 0:\n            MU = 1e-6\n            sinMu = np.sin(MU)\n            cosMu = np.cos(MU)\n        CD = cosd(delta)\n        CG = cosd(gamma)\n        SD = sind(delta)\n        SG = sind(gamma)\n\n        # Axial induction\n        a = 1 - (\n            (1 + np.sqrt(1 - x - 1 / 16 * x**2 * sinMu**2))\n            / (2 * (1 + 1 / 16 * x * sinMu**2))\n        )\n\n        k_1s = -1 * (15 * np.pi / 32 * np.tan((MU + sinMu * (x / 2)) / 2))\n\n        I1 = -(\n            np.pi\n            * cosMu\n            * (tsr - CD * SG * k)\n            * (a - 1)\n            + (CD * CG * cosMu * k_1s * SD * a * k * np.pi * (2 * tsr - CD * SG * k))\n            / (8 * sinMu)\n        ) / (2 * np.pi)\n\n        I2 = (\n            np.pi\n            * sinMu**2\n            + (\n                np.pi\n                * (\n                    CD**2 * CG**2 * SD**2 * k**2\n                    + 3 * CD**2 * SG**2 * k**2\n                    - 8 * CD * tsr * SG * k\n                    + 8 * tsr**2\n                )\n            )\n            / 12\n        ) / (2 * np.pi)\n\n        return (sigma * (cd + cl_alfa) * (I1) - sigma * cl_alfa * theta * (I2)) - x\n"
  },
  {
    "path": "floris/core/turbine/operation_models.py",
    "content": "import copy\nfrom abc import abstractmethod\nfrom typing import (\n    Any,\n    Dict,\n    Final,\n)\n\nimport numpy as np\nfrom attrs import define, field\nfrom scipy.interpolate import interp1d\n\nfrom floris.core import BaseClass\nfrom floris.core.rotor_velocity import (\n    average_velocity,\n    compute_tilt_angles_for_floating_turbines,\n    rotor_velocity_air_density_correction,\n    rotor_velocity_tilt_cosine_correction,\n    rotor_velocity_yaw_cosine_correction,\n)\nfrom floris.type_dec import (\n    NDArrayFloat,\n    NDArrayObject,\n)\nfrom floris.utilities import cosd\n\n\nPOWER_SETPOINT_DEFAULT = 1e12\nPOWER_SETPOINT_DISABLED = 0.001\n\n\n@define\nclass BaseOperationModel(BaseClass):\n    \"\"\"\n    Base class for turbine operation models. All turbine operation models must implement static\n    power(), thrust_coefficient(), and axial_induction() methods, which are called by power() and\n    thrust_coefficient() through the interface in the turbine.py module.\n\n    Args:\n        BaseClass (_type_): _description_\n\n    Raises:\n        NotImplementedError: _description_\n        NotImplementedError: _description_\n    \"\"\"\n    @staticmethod\n    @abstractmethod\n    def power() -> None:\n        raise NotImplementedError(\"BaseOperationModel.power\")\n\n    @staticmethod\n    @abstractmethod\n    def thrust_coefficient() -> None:\n        raise NotImplementedError(\"BaseOperationModel.thrust_coefficient\")\n\n    @staticmethod\n    @abstractmethod\n    def axial_induction() -> None:\n        # TODO: Consider whether we can make a generic axial_induction method\n        # based purely on thrust_coefficient so that we don't need to implement\n        # axial_induciton() in individual operation models.\n        raise NotImplementedError(\"BaseOperationModel.axial_induction\")\n\n@define\nclass SimpleTurbine(BaseOperationModel):\n    \"\"\"\n    Static class defining an actuator disk turbine model that is fully aligned with the flow. No\n    handling for yaw or tilt angles.\n\n    As with all turbine submodules, implements only static power() and thrust_coefficient() methods,\n    which are called by power() and thrust_coefficient() on turbine.py, respectively. This class is\n    not intended to be instantiated; it simply defines a library of static methods.\n    \"\"\"\n\n    def power(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        # Construct power interpolant\n        power_interpolator = interp1d(\n            power_thrust_table[\"wind_speed\"],\n            power_thrust_table[\"power\"],\n            fill_value=0.0,\n            bounds_error=False,\n        )\n\n        # Compute the power-effective wind speed across the rotor\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        rotor_effective_velocities = rotor_velocity_air_density_correction(\n            velocities=rotor_average_velocities,\n            air_density=air_density,\n            ref_air_density=power_thrust_table[\"ref_air_density\"]\n        )\n\n        # Compute power\n        power = power_interpolator(rotor_effective_velocities) * 1e3 # Convert to W\n\n        return power\n\n    def thrust_coefficient(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        # Construct thrust coefficient interpolant\n        thrust_coefficient_interpolator = interp1d(\n            power_thrust_table[\"wind_speed\"],\n            power_thrust_table[\"thrust_coefficient\"],\n            fill_value=0.0001,\n            bounds_error=False,\n        )\n\n        # Compute the effective wind speed across the rotor\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        # TODO: Do we need an air density correction here?\n\n        thrust_coefficient = thrust_coefficient_interpolator(rotor_average_velocities)\n        thrust_coefficient = np.clip(thrust_coefficient, 0.0001, 0.9999)\n\n        return thrust_coefficient\n\n    def axial_induction(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n\n        thrust_coefficient = SimpleTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            average_method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        return (1 - np.sqrt(1 - thrust_coefficient))/2\n\n\n@define\nclass CosineLossTurbine(BaseOperationModel):\n    \"\"\"\n    Static class defining an actuator disk turbine model that may be misaligned with the flow.\n    Nonzero tilt and yaw angles are handled via cosine relationships, with the power lost to yawing\n    defined by the cosine of the yaw misalignment raised to the power of cosine_loss_exponent_yaw.\n    This turbine submodel is the default, and matches the turbine model in FLORIS v3.\n\n    As with all turbine submodules, implements only static power() and thrust_coefficient() methods,\n    which are called by power() and thrust_coefficient() on turbine.py, respectively. This class is\n    not intended to be instantiated; it simply defines a library of static methods.\n    \"\"\"\n\n    def power(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        yaw_angles: NDArrayFloat,\n        tilt_angles: NDArrayFloat,\n        tilt_interp: NDArrayObject,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        correct_cp_ct_for_tilt: bool = False,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        # Construct power interpolant\n        power_interpolator = interp1d(\n            power_thrust_table[\"wind_speed\"],\n            power_thrust_table[\"power\"],\n            fill_value=0.0,\n            bounds_error=False,\n        )\n\n        # Compute the power-effective wind speed across the rotor\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        rotor_effective_velocities = rotor_velocity_air_density_correction(\n            velocities=rotor_average_velocities,\n            air_density=air_density,\n            ref_air_density=power_thrust_table[\"ref_air_density\"]\n        )\n\n        rotor_effective_velocities = rotor_velocity_yaw_cosine_correction(\n            cosine_loss_exponent_yaw=power_thrust_table[\"cosine_loss_exponent_yaw\"],\n            yaw_angles=yaw_angles,\n            rotor_effective_velocities=rotor_effective_velocities,\n        )\n\n        rotor_effective_velocities = rotor_velocity_tilt_cosine_correction(\n            tilt_angles=tilt_angles,\n            ref_tilt=power_thrust_table[\"ref_tilt\"],\n            cosine_loss_exponent_tilt=power_thrust_table[\"cosine_loss_exponent_tilt\"],\n            tilt_interp=tilt_interp,\n            correct_cp_ct_for_tilt=correct_cp_ct_for_tilt,\n            rotor_effective_velocities=rotor_effective_velocities,\n        )\n\n        # Compute power\n        power = power_interpolator(rotor_effective_velocities) * 1e3 # Convert to W\n\n        return power\n\n    def thrust_coefficient(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        yaw_angles: NDArrayFloat,\n        tilt_angles: NDArrayFloat,\n        tilt_interp: NDArrayObject,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        correct_cp_ct_for_tilt: bool = False,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        # Construct thrust coefficient interpolant\n        thrust_coefficient_interpolator = interp1d(\n            power_thrust_table[\"wind_speed\"],\n            power_thrust_table[\"thrust_coefficient\"],\n            fill_value=0.0001,\n            bounds_error=False,\n        )\n\n        # Compute the effective wind speed across the rotor\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        # TODO: Do we need an air density correction here?\n        thrust_coefficient = thrust_coefficient_interpolator(rotor_average_velocities)\n        thrust_coefficient = np.clip(thrust_coefficient, 0.0001, 0.9999)\n\n        # Apply tilt and yaw corrections\n        # Compute the tilt, if using floating turbines\n        old_tilt_angles = copy.deepcopy(tilt_angles)\n        tilt_angles = compute_tilt_angles_for_floating_turbines(\n            tilt_angles=tilt_angles,\n            tilt_interp=tilt_interp,\n            rotor_effective_velocities=rotor_average_velocities,\n        )\n        # Only update tilt angle if requested (if the tilt isn't accounted for in the Ct curve)\n        tilt_angles = np.where(correct_cp_ct_for_tilt, tilt_angles, old_tilt_angles)\n\n        thrust_coefficient = (\n            thrust_coefficient\n            * cosd(yaw_angles)\n            * cosd(tilt_angles)\n            / cosd(power_thrust_table[\"ref_tilt\"])\n        )\n\n        return thrust_coefficient\n\n    def axial_induction(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        yaw_angles: NDArrayFloat,\n        tilt_angles: NDArrayFloat,\n        tilt_interp: NDArrayObject,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        correct_cp_ct_for_tilt: bool = False,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n\n        thrust_coefficient = CosineLossTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            yaw_angles=yaw_angles,\n            tilt_angles=tilt_angles,\n            tilt_interp=tilt_interp,\n            average_method=average_method,\n            cubature_weights=cubature_weights,\n            correct_cp_ct_for_tilt=correct_cp_ct_for_tilt\n        )\n\n        misalignment_loss = (\n            cosd(yaw_angles) * cosd(tilt_angles) / cosd(power_thrust_table[\"ref_tilt\"])\n        )\n        return 0.5 / misalignment_loss * (1 - np.sqrt(1 - thrust_coefficient * misalignment_loss))\n\n@define\nclass SimpleDeratingTurbine(BaseOperationModel):\n    \"\"\"\n    power_thrust_table is a dictionary (normally defined on the turbine input yaml)\n    that contains the parameters necessary to evaluate power(), thrust(), and axial_induction().\n    Any specific parameters for derating can be placed here. (they can be added to the turbine\n    yaml). For this operation model to receive those arguements, they'll need to be\n    added to the kwargs dictionaries in the respective functions on turbine.py. They won't affect\n    the other operation models.\n    \"\"\"\n    def power(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        power_setpoints: NDArrayFloat | None,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        base_powers = SimpleTurbine.power(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            air_density=air_density,\n            average_method=average_method,\n            cubature_weights=cubature_weights\n        )\n        if power_setpoints is None:\n            return base_powers\n        else:\n            return np.minimum(base_powers, power_setpoints)\n\n        # TODO: would we like special handling of zero power setpoints\n        # (mixed with non-zero values) to speed up computation in that case?\n\n    def thrust_coefficient(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        power_setpoints: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        base_thrust_coefficients = SimpleTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            average_method=average_method,\n            cubature_weights=cubature_weights\n        )\n        if power_setpoints is None:\n            return base_thrust_coefficients\n        else:\n            # Assume thrust coefficient scales directly with power\n            base_powers = SimpleTurbine.power(\n                power_thrust_table=power_thrust_table,\n                velocities=velocities,\n                air_density=air_density\n            )\n            power_fractions = power_setpoints / base_powers\n            thrust_coefficients = power_fractions * base_thrust_coefficients\n            return np.minimum(base_thrust_coefficients, thrust_coefficients)\n\n    def axial_induction(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        power_setpoints: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        thrust_coefficient = SimpleDeratingTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            air_density=air_density,\n            power_setpoints=power_setpoints,\n            average_method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        return (1 - np.sqrt(1 - thrust_coefficient))/2\n\n@define\nclass MixedOperationTurbine(BaseOperationModel):\n\n    @staticmethod\n    def power(\n        yaw_angles: NDArrayFloat,\n        power_setpoints: NDArrayFloat,\n        **kwargs\n    ):\n        (\n            yaw_angles,\n            power_setpoints,\n            yaw_angles_mask,\n            power_setpoints_mask,\n            neither_mask\n        ) = MixedOperationTurbine._handle_mixed_operation_setpoints(\n            yaw_angles=yaw_angles,\n            power_setpoints=power_setpoints\n        )\n\n        powers = np.zeros_like(power_setpoints)\n        powers[yaw_angles_mask] += CosineLossTurbine.power(\n            yaw_angles=yaw_angles,\n            **kwargs\n        )[yaw_angles_mask]\n        powers[power_setpoints_mask] += SimpleDeratingTurbine.power(\n            power_setpoints=power_setpoints,\n            **kwargs\n        )[power_setpoints_mask]\n        powers[neither_mask] += SimpleTurbine.power(\n            **kwargs\n        )[neither_mask]\n\n        return powers\n\n    @staticmethod\n    def thrust_coefficient(\n        yaw_angles: NDArrayFloat,\n        power_setpoints: NDArrayFloat,\n        **kwargs\n    ):\n        (\n            yaw_angles,\n            power_setpoints,\n            yaw_angles_mask,\n            power_setpoints_mask,\n            neither_mask\n        ) = MixedOperationTurbine._handle_mixed_operation_setpoints(\n            yaw_angles=yaw_angles,\n            power_setpoints=power_setpoints\n        )\n\n        thrust_coefficients = np.zeros_like(power_setpoints)\n        thrust_coefficients[yaw_angles_mask] += CosineLossTurbine.thrust_coefficient(\n            yaw_angles=yaw_angles,\n            **kwargs\n        )[yaw_angles_mask]\n        thrust_coefficients[power_setpoints_mask] += SimpleDeratingTurbine.thrust_coefficient(\n            power_setpoints=power_setpoints,\n            **kwargs\n        )[power_setpoints_mask]\n        thrust_coefficients[neither_mask] += SimpleTurbine.thrust_coefficient(\n            **kwargs\n        )[neither_mask]\n\n        return thrust_coefficients\n\n    @staticmethod\n    def axial_induction(\n        yaw_angles: NDArrayFloat,\n        power_setpoints: NDArrayFloat,\n        **kwargs\n    ):\n        (\n            yaw_angles,\n            power_setpoints,\n            yaw_angles_mask,\n            power_setpoints_mask,\n            neither_mask\n        ) = MixedOperationTurbine._handle_mixed_operation_setpoints(\n            yaw_angles=yaw_angles,\n            power_setpoints=power_setpoints\n        )\n\n        axial_inductions = np.zeros_like(power_setpoints)\n        axial_inductions[yaw_angles_mask] += CosineLossTurbine.axial_induction(\n            yaw_angles=yaw_angles,\n            **kwargs\n        )[yaw_angles_mask]\n        axial_inductions[power_setpoints_mask] += SimpleDeratingTurbine.axial_induction(\n            power_setpoints=power_setpoints,\n            **kwargs\n        )[power_setpoints_mask]\n        axial_inductions[neither_mask] += SimpleTurbine.axial_induction(\n            **kwargs\n        )[neither_mask]\n\n        return axial_inductions\n\n    @staticmethod\n    def _handle_mixed_operation_setpoints(\n        yaw_angles: NDArrayFloat,\n        power_setpoints: NDArrayFloat,\n    ):\n        \"\"\"\n        Check for incompatible yaw angles and power setpoints and raise an error if found.\n        Return masks and updated setpoints.\n        \"\"\"\n        # If any turbines are disabled, set their yaw angles to zero\n        yaw_angles[power_setpoints <= POWER_SETPOINT_DISABLED] = 0.0\n\n        # Create masks for whether yaw angles and power setpoints are set\n        yaw_angles_mask = yaw_angles != 0.0\n        power_setpoints_mask = power_setpoints < POWER_SETPOINT_DEFAULT\n        neither_mask = np.logical_not(yaw_angles_mask) & np.logical_not(power_setpoints_mask)\n\n        # Check for incompatibility and raise error if found.\n        if (power_setpoints_mask & yaw_angles_mask).any():\n            raise ValueError((\n                \"Power setpoints and yaw angles are incompatible.\"\n                \"If yaw_angles entry is nonzero, power_setpoints must be greater than\"\n                \" or equal to {0}.\".format(POWER_SETPOINT_DEFAULT)\n            ))\n\n        # Return updated setpoints as well as masks\n        return yaw_angles, power_setpoints, yaw_angles_mask, power_setpoints_mask, neither_mask\n\n@define\nclass AWCTurbine(BaseOperationModel):\n    \"\"\"\n    power_thrust_table is a dictionary (normally defined on the turbine input yaml)\n    that contains the parameters necessary to evaluate power(), thrust(), and axial_induction().\n\n    Feel free to put any Helix tuning parameters into here (they can be added to the turbine yaml).\n    Also, feel free to add any commanded inputs to power(), thrust_coefficient(), or\n    axial_induction(). For this operation model to receive those arguments, they'll need to be\n    added to the kwargs dictionaries in the respective functions on turbine.py. They won't affect\n    the other operation models.\n    \"\"\"\n\n    def AWC_model(a, b, c, base_values, awc_amplitudes):\n            return base_values * (1 - (b + c*base_values)*awc_amplitudes**a)\n\n    def power(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        awc_modes: str,\n        awc_amplitudes: NDArrayFloat | None,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        base_powers = SimpleTurbine.power(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            air_density=air_density,\n            average_method=average_method,\n            cubature_weights=cubature_weights\n        )\n\n        valid_entries = ['helix', 'baseline']\n        if not np.all(np.isin(awc_modes, valid_entries)):\n            raise UserWarning(\n                'Active wake mixing strategies other than the `helix` strategy '\n                'have not yet been implemented in FLORIS. Returning baseline power.'\n            )\n\n        # Create a copy of the base power to modify according to different AWC modes\n        powers = base_powers.copy()\n\n        helix_mask = (awc_modes == 'helix')\n        if np.any(np.isclose(base_powers[helix_mask]/1000,np.max(power_thrust_table['power']))):\n            raise UserWarning(\n                'The selected wind speed is above or near rated wind speed. '\n                '`AWCTurbine` operation model is not designed '\n                'or verified for above-rated conditions.'\n            )\n\n        awc_powers = AWCTurbine.AWC_model(\n            power_thrust_table['helix_a'],\n            power_thrust_table['helix_power_b'],\n            power_thrust_table['helix_power_c'],\n            base_powers[helix_mask],\n            awc_amplitudes[helix_mask]\n        )\n        powers[helix_mask] = awc_powers\n\n        return powers\n\n\n    def thrust_coefficient(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        awc_modes: str,\n        awc_amplitudes: NDArrayFloat | None,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        base_thrust_coefficients = SimpleTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            average_method=average_method,\n            cubature_weights=cubature_weights\n        )\n\n        # Create a copy of the base thrust coefficients to modify according to different AWC modes\n        thrust_coefficients = base_thrust_coefficients.copy()\n\n        helix_mask = (awc_modes == 'helix')\n\n        awc_thrust_coefficients = AWCTurbine.AWC_model(\n            power_thrust_table['helix_a'],\n            power_thrust_table['helix_thrust_b'],\n            power_thrust_table['helix_thrust_c'],\n            base_thrust_coefficients[helix_mask],\n            awc_amplitudes[helix_mask]\n        )\n        thrust_coefficients[helix_mask] = awc_thrust_coefficients\n\n        return thrust_coefficients\n\n    def axial_induction(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        awc_modes: str,\n        awc_amplitudes: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        thrust_coefficient = AWCTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            awc_modes=awc_modes,\n            awc_amplitudes=awc_amplitudes,\n            average_method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        return (1 - np.sqrt(1 - thrust_coefficient))/2\n\n@define\nclass PeakShavingTurbine():\n\n    def power(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        turbulence_intensities: NDArrayFloat,\n        air_density: float,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        base_powers = SimpleTurbine.power(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            air_density=air_density,\n            average_method=average_method,\n            cubature_weights=cubature_weights\n        )\n\n        # Get fraction by thrust\n        base_thrust_coefficients = SimpleTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            average_method=average_method,\n            cubature_weights=cubature_weights\n        )\n        peak_shaving_thrust_coefficients = PeakShavingTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            turbulence_intensities=turbulence_intensities,\n            average_method=average_method,\n            cubature_weights=cubature_weights\n        )\n\n        # Compute equivalent axial inductions\n        base_ais = (1 - np.sqrt(1 - base_thrust_coefficients))/2\n        peak_shaving_ais = (1 - np.sqrt(1 - peak_shaving_thrust_coefficients))/2\n\n        # Power proportion\n        power_fractions = (\n            (peak_shaving_thrust_coefficients * (1-peak_shaving_ais))\n            / (base_thrust_coefficients * (1-base_ais))\n        )\n\n        # Apply fraction to power and return\n        powers = power_fractions * base_powers\n\n        return powers\n\n    def thrust_coefficient(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        turbulence_intensities: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n        base_thrust_coefficients = SimpleTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            average_method=average_method,\n            cubature_weights=cubature_weights\n        )\n\n        peak_normal_thrust_prime = np.max(\n            np.array(power_thrust_table[\"wind_speed\"])**2\n            * np.array(power_thrust_table[\"thrust_coefficient\"])\n        )\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n        # Replace zeros with small values to avoid division by zero\n        rotor_average_velocities = np.maximum(rotor_average_velocities, 0.01)\n        max_allowable_thrust_coefficient = (\n            (1-power_thrust_table[\"peak_shaving_fraction\"])\n            * peak_normal_thrust_prime\n            / rotor_average_velocities**2\n        )\n\n        # Apply TI mask\n        max_allowable_thrust_coefficient = np.where(\n            (\n                turbulence_intensities.mean(\n                    axis=tuple([2 + i for i in range(turbulence_intensities.ndim - 2)])\n                )\n                >= power_thrust_table[\"peak_shaving_TI_threshold\"]\n            ),\n            max_allowable_thrust_coefficient,\n            base_thrust_coefficients\n        )\n\n        thrust_coefficient = np.minimum(base_thrust_coefficients, max_allowable_thrust_coefficient)\n\n        return thrust_coefficient\n\n    def axial_induction(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        turbulence_intensities: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **_ # <- Allows other models to accept other keyword arguments\n    ):\n\n        thrust_coefficient = PeakShavingTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=velocities,\n            turbulence_intensities=turbulence_intensities,\n            average_method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        return (1 - np.sqrt(1 - thrust_coefficient))/2\n"
  },
  {
    "path": "floris/core/turbine/turbine.py",
    "content": "import copy\nimport logging\nimport os\nfrom collections.abc import Callable, Iterable\nfrom pathlib import Path\n\nimport attrs\nimport numpy as np\nimport pandas as pd\nfrom attrs import define, field\nfrom scipy.interpolate import interp1d\n\nfrom floris.core import BaseClass\nfrom floris.core.turbine import (\n    AWCTurbine,\n    ControllerDependentTurbine,\n    CosineLossTurbine,\n    MixedOperationTurbine,\n    PeakShavingTurbine,\n    SimpleDeratingTurbine,\n    SimpleTurbine,\n    UnifiedMomentumModelTurbine,\n)\nfrom floris.type_dec import (\n    convert_to_path,\n    floris_numeric_dict_converter,\n    NDArrayBool,\n    NDArrayFilter,\n    NDArrayFloat,\n    NDArrayInt,\n    NDArrayObject,\n    NDArrayStr,\n)\nfrom floris.utilities import cosd\n\n\nTURBINE_MODEL_MAP = {\n    \"operation_model\": {\n        \"simple\": SimpleTurbine,\n        \"cosine-loss\": CosineLossTurbine,\n        \"controller-dependent\": ControllerDependentTurbine,\n        \"simple-derating\": SimpleDeratingTurbine,\n        \"mixed\": MixedOperationTurbine,\n        \"awc\": AWCTurbine,\n        \"peak-shaving\": PeakShavingTurbine,\n        \"unified-momentum\": UnifiedMomentumModelTurbine,\n    },\n}\n\n\ndef _select_multidim_condition(\n    condition: dict,\n    specified_conditions: Iterable[tuple],\n    condition_keys: list[str],\n    n_findex: int,\n) -> tuple:\n    \"\"\"\n    Convert condition to the type expected by power_thrust_table and select\n    nearest specified condition\n    \"\"\"\n    if type(condition) is dict:\n        # Check valid keys\n        if set(condition.keys()) != set(condition_keys):\n            raise ValueError(\n                f\"The provided condition keys {list(condition.keys())} do not match the \"\n                f\"expected keys {condition_keys}. A single value should be provided for \"\n                \"each dimension of the multidimensional power/thrust_coefficient table.\"\n            )\n        # Create a tuple of the condition values in the correct order\n        if isinstance(condition[condition_keys[0]], list) or isinstance(\n            condition[condition_keys[0]], np.ndarray\n        ):\n            # Assume multiple specified conditions\n            n_conds = len(condition[condition_keys[0]])\n            if n_conds != n_findex:\n                raise ValueError(\n                    \"When providing multiple specified conditions, the number of conditions \"\n                    \"must match the number of findices.\"\n                )\n            for k in condition_keys:\n                if len(condition[k]) != n_conds:\n                    raise ValueError(\n                        \"All condition values must have the same length when providing \"\n                        \"multiple specified conditions.\"\n                    )\n            condition = [tuple(condition[k][i] for k in condition_keys) for i in range(n_conds)]\n        else:\n            n_conds = 1\n            condition = [tuple(condition[k] for k in condition_keys)]\n    elif condition is None:\n        raise ValueError(\n            \"multidim_condition must be provided if using multidimensional \"\n            \"power/thrust_coefficient.\"\n        )\n    else:\n        raise TypeError(\"condition should be of type dict.\")\n\n    # Find the nearest key to the specified conditions.\n    specified_conditions = np.array(specified_conditions)\n    if specified_conditions.ndim == 1: # Single specified condition\n        specified_conditions = specified_conditions.reshape(-1, 1)\n\n    # Find the nearest key to the specified conditions.\n    nearest_conditions = np.zeros((n_conds, specified_conditions.shape[1]))\n    for f, cond in enumerate(condition): # Loop over findices\n        for i, c in enumerate(cond):\n            nearest_conditions[f, i] = (\n                specified_conditions[:, i][np.absolute(specified_conditions[:, i] - c).argmin()]\n            )\n\n    nearest_conditions, md_map = np.unique(nearest_conditions, axis=0, return_inverse=True)\n\n    # Update map if only a single condition was provided\n    if n_conds == 1:\n        md_map = np.repeat(md_map, n_findex, axis=0)\n\n    return nearest_conditions, md_map\n\n\ndef power(\n    velocities: NDArrayFloat,\n    turbulence_intensities: NDArrayFloat,\n    air_density: float,\n    power_functions: dict[str, Callable],\n    yaw_angles: NDArrayFloat,\n    tilt_angles: NDArrayFloat,\n    power_setpoints: NDArrayFloat,\n    awc_modes: NDArrayStr,\n    awc_amplitudes: NDArrayFloat,\n    tilt_interps: dict[str, interp1d],\n    turbine_type_map: NDArrayObject,\n    turbine_power_thrust_tables: dict,\n    ix_filter: NDArrayInt | Iterable[int] | None = None,\n    average_method: str = \"cubic-mean\",\n    cubature_weights: NDArrayFloat | None = None,\n    correct_cp_ct_for_tilt: bool = False,\n    multidim_condition: dict | None = None,\n) -> NDArrayFloat:\n    \"\"\"Power produced by a turbine adjusted for yaw and tilt. Value\n    given in Watts.\n\n    Args:\n        velocities (NDArrayFloat[n_findex, n_turbines, n_grid, n_grid]): The velocities at a\n            turbine.\n        turbulence_intensities (NDArrayFloat[findex, turbines]): The turbulence intensity at\n            each turbine.\n        air_density (float): air density for simulation [kg/m^3]\n        power_functions (dict[str, Callable]): A dictionary of power functions for\n            each turbine type. Keys are the turbine type and values are the callable functions.\n        yaw_angles (NDArrayFloat[findex, turbines]): The yaw angle for each turbine.\n        tilt_angles (NDArrayFloat[findex, turbines]): The tilt angle for each turbine.\n        power_setpoints: (NDArrayFloat[findex, turbines]): Maximum power setpoint for each\n            turbine [W].\n        awc_modes: (NDArrayStr[findex, turbines]): awc excitation mode (currently, only \"baseline\"\n            and \"helix\" are implemented).\n        awc_modes: (NDArrayStr[findex, turbines]): awc excitation mode (currently, only \"baseline\"\n            and \"helix\" are implemented).\n        awc_amplitudes: (NDArrayFloat[findex, turbines]): awc excitation amplitude for each\n            turbine [deg].\n        tilt_interps (Iterable[tuple]): The tilt interpolation functions for each\n            turbine.\n        turbine_type_map: (NDArrayObject[wd, ws, turbines]): The Turbine type definition for\n            each turbine.\n        turbine_power_thrust_tables: Reference data for the power and thrust representation\n        ix_filter (NDArrayInt, optional): The boolean array, or\n            integer indices to filter out before calculation. Defaults to None.\n        average_method (str, optional): The method for averaging over turbine rotor points\n            to determine a rotor-average wind speed. Defaults to \"cubic-mean\".\n        cubature_weights (NDArrayFloat | None): Weights for cubature averaging methods. Defaults to\n            None.\n        multidim_condition (dict | None): The condition dictionary used to select the appropriate\n            thrust coefficient relationship for multidimensional power/thrust tables. Defaults to\n            None.\n\n    Returns:\n        NDArrayFloat: The power, in Watts, for each turbine after adjusting for yaw and tilt.\n    \"\"\"\n\n    # Down-select inputs if ix_filter is given\n    if ix_filter is not None:\n        velocities = velocities[:, ix_filter]\n        turbulence_intensities = turbulence_intensities[:, ix_filter]\n        yaw_angles = yaw_angles[:, ix_filter]\n        tilt_angles = tilt_angles[:, ix_filter]\n        power_setpoints = power_setpoints[:, ix_filter]\n        awc_modes = awc_modes[:, ix_filter]\n        awc_amplitudes = awc_amplitudes[:, ix_filter]\n        turbine_type_map = turbine_type_map[:, ix_filter]\n        if type(correct_cp_ct_for_tilt) is bool:\n            pass\n        else:\n            correct_cp_ct_for_tilt = correct_cp_ct_for_tilt[:, ix_filter]\n\n    # Establish the main set of keyword arguments for power()\n    power_model_kwargs = {\n        \"power_thrust_table\": None, # Will be filled below\n        \"velocities\": velocities,\n        \"turbulence_intensities\": turbulence_intensities,\n        \"air_density\": air_density,\n        \"yaw_angles\": yaw_angles,\n        \"tilt_angles\": tilt_angles,\n        \"power_setpoints\": power_setpoints,\n        \"awc_modes\": awc_modes,\n        \"awc_amplitudes\": awc_amplitudes,\n        \"tilt_interp\": None, # Will be filled below\n        \"average_method\": average_method,\n        \"cubature_weights\": cubature_weights,\n        \"correct_cp_ct_for_tilt\": correct_cp_ct_for_tilt,\n    }\n\n    # Loop over each turbine type given to get power for all turbines\n    p = np.zeros(np.shape(velocities)[0:2])\n    turb_types = np.unique(turbine_type_map)\n    for turb_type in turb_types:\n        if \"power\" in turbine_power_thrust_tables[turb_type]:  # Not multidimensional\n            power_thrust_table = turbine_power_thrust_tables[turb_type]\n\n            power_model_kwargs[\"power_thrust_table\"] = power_thrust_table\n            power_model_kwargs[\"tilt_interp\"] = tilt_interps[turb_type]\n\n            p += (\n                power_functions[turb_type](**power_model_kwargs)\n                * (turbine_type_map == turb_type)\n            )\n        else: # Multidimensional\n            md_conditions, md_conditions_map = _select_multidim_condition(\n                multidim_condition,\n                [k for k in turbine_power_thrust_tables[turb_type].keys() if k != \"condition_keys\"],\n                turbine_power_thrust_tables[turb_type][\"condition_keys\"],\n                velocities.shape[0],\n            )\n\n            # Loop over conditions and mask onto power\n            for i, md_cond in enumerate(md_conditions):\n                power_thrust_table = turbine_power_thrust_tables[turb_type][tuple(md_cond)]\n\n                power_model_kwargs[\"power_thrust_table\"] = power_thrust_table\n                power_model_kwargs[\"tilt_interp\"] = tilt_interps[turb_type]\n\n                p += (\n                    power_functions[turb_type](**power_model_kwargs)\n                    * (turbine_type_map == turb_type)\n                    * (md_conditions_map[:, None] == i)\n                )\n\n    return p\n\n\ndef thrust_coefficient(\n    velocities: NDArrayFloat,\n    turbulence_intensities: NDArrayFloat,\n    air_density: float,\n    yaw_angles: NDArrayFloat,\n    tilt_angles: NDArrayFloat,\n    power_setpoints: NDArrayFloat,\n    awc_modes: NDArrayStr,\n    awc_amplitudes: NDArrayFloat,\n    thrust_coefficient_functions: dict[str, Callable],\n    tilt_interps: dict[str, interp1d],\n    correct_cp_ct_for_tilt: NDArrayBool,\n    turbine_type_map: NDArrayObject,\n    turbine_power_thrust_tables: dict,\n    ix_filter: NDArrayFilter | Iterable[int] | None = None,\n    average_method: str = \"cubic-mean\",\n    cubature_weights: NDArrayFloat | None = None,\n    multidim_condition: dict | None = None,\n) -> NDArrayFloat:\n\n    \"\"\"Thrust coefficient of a turbine.\n    The value is obtained from the coefficient of thrust specified by the callables specified\n    in the thrust_coefficient_functions.\n\n    Args:\n        velocities (NDArrayFloat[findex, turbines, grid1, grid2]): The velocity field at\n            a turbine.\n        turbulence_intensities (NDArrayFloat[findex, turbines]): The turbulence intensity at\n            each turbine.\n        air_density (float): air density for simulation [kg/m^3]\n        yaw_angles (NDArrayFloat[findex, turbines]): The yaw angle for each turbine.\n        tilt_angles (NDArrayFloat[findex, turbines]): The tilt angle for each turbine.\n        power_setpoints: (NDArrayFloat[findex, turbines]): Maximum power setpoint for each\n            turbine [W].\n        awc_modes: (NDArrayStr[findex, turbines]): awc excitation mode (currently, only \"baseline\"\n            and \"helix\" are implemented).\n        awc_amplitudes: (NDArrayFloat[findex, turbines]): awc excitation amplitude for each\n            turbine [deg].\n        thrust_coefficient_functions (dict): The thrust coefficient functions for each turbine. Keys\n            are the turbine type string and values are the callable functions.\n        tilt_interps (Iterable[tuple]): The tilt interpolation functions for each\n            turbine.\n        correct_cp_ct_for_tilt (NDArrayBool[findex, turbines]): Boolean for determining if the\n            turbines Cp and Ct should be corrected for tilt.\n        turbine_type_map: (NDArrayObject[findex, turbines]): The Turbine type definition\n            for each turbine.\n        ix_filter (NDArrayFilter | Iterable[int] | None, optional): The boolean array, or\n            integer indices as an iterable of array to filter out before calculation.\n            Defaults to None.\n        average_method (str, optional): The method for averaging over turbine rotor points\n            to determine a rotor-average wind speed. Defaults to \"cubic-mean\".\n        cubature_weights (NDArrayFloat | None): Weights for cubature averaging methods. Defaults to\n            None.\n        multidim_condition (dict | None): The condition dictionary used to select the appropriate\n            thrust coefficient relationship for multidimensional power/thrust tables. Defaults to\n            None.\n\n    Returns:\n        NDArrayFloat: Coefficient of thrust for each requested turbine.\n    \"\"\"\n\n    # Down-select inputs if ix_filter is given\n    if ix_filter is not None:\n        velocities = velocities[:, ix_filter]\n        turbulence_intensities = turbulence_intensities[:, ix_filter]\n        yaw_angles = yaw_angles[:, ix_filter]\n        tilt_angles = tilt_angles[:, ix_filter]\n        power_setpoints = power_setpoints[:, ix_filter]\n        awc_modes = awc_modes[:, ix_filter]\n        awc_amplitudes = awc_amplitudes[:, ix_filter]\n        turbine_type_map = turbine_type_map[:, ix_filter]\n        if type(correct_cp_ct_for_tilt) is bool:\n            pass\n        else:\n            correct_cp_ct_for_tilt = correct_cp_ct_for_tilt[:, ix_filter]\n\n    # Establish the main set of keyword arguments for thrust_coefficient()\n    thrust_model_kwargs = {\n        \"power_thrust_table\": None, # Will be filled below\n        \"velocities\": velocities,\n        \"turbulence_intensities\": turbulence_intensities,\n        \"air_density\": air_density,\n        \"yaw_angles\": yaw_angles,\n        \"tilt_angles\": tilt_angles,\n        \"power_setpoints\": power_setpoints,\n        \"awc_modes\": awc_modes,\n        \"awc_amplitudes\": awc_amplitudes,\n        \"tilt_interp\": None, # Will be filled below\n        \"average_method\": average_method,\n        \"cubature_weights\": cubature_weights,\n        \"correct_cp_ct_for_tilt\": correct_cp_ct_for_tilt,\n    }\n\n    # Loop over each turbine type given to get thrust coefficient for all turbines\n    thrust_coefficient = np.zeros(np.shape(velocities)[0:2])\n    turb_types = np.unique(turbine_type_map)\n    for turb_type in turb_types:\n        if \"thrust_coefficient\" in turbine_power_thrust_tables[turb_type]:  # Not multidimensional\n            power_thrust_table = turbine_power_thrust_tables[turb_type]\n\n            thrust_model_kwargs[\"power_thrust_table\"] = power_thrust_table\n            thrust_model_kwargs[\"tilt_interp\"] = tilt_interps[turb_type]\n\n            thrust_coefficient += (\n                thrust_coefficient_functions[turb_type](**thrust_model_kwargs)\n                * (turbine_type_map == turb_type)\n            )\n        else: # Multidimensional\n            md_conditions, md_conditions_map = _select_multidim_condition(\n                multidim_condition,\n                [k for k in turbine_power_thrust_tables[turb_type].keys() if k != \"condition_keys\"],\n                turbine_power_thrust_tables[turb_type][\"condition_keys\"],\n                velocities.shape[0],\n            )\n\n            # Loop over conditions and mask onto thrust_coefficient\n            for i, md_cond in enumerate(md_conditions):\n                power_thrust_table = turbine_power_thrust_tables[turb_type][tuple(md_cond)]\n\n                thrust_model_kwargs[\"power_thrust_table\"] = power_thrust_table\n                thrust_model_kwargs[\"tilt_interp\"] = tilt_interps[turb_type]\n\n                thrust_coefficient += (\n                    thrust_coefficient_functions[turb_type](**thrust_model_kwargs)\n                    * (turbine_type_map == turb_type)\n                    * (md_conditions_map[:, None] == i)\n                )\n\n    return thrust_coefficient\n\n\ndef axial_induction(\n    velocities: NDArrayFloat,\n    turbulence_intensities: NDArrayFloat,\n    air_density: float,\n    yaw_angles: NDArrayFloat,\n    tilt_angles: NDArrayFloat,\n    power_setpoints: NDArrayFloat,\n    awc_modes: NDArrayStr,\n    awc_amplitudes: NDArrayFloat,\n    axial_induction_functions: dict,\n    tilt_interps: NDArrayObject,\n    correct_cp_ct_for_tilt: NDArrayBool,\n    turbine_type_map: NDArrayObject,\n    turbine_power_thrust_tables: dict,\n    ix_filter: NDArrayFilter | Iterable[int] | None = None,\n    average_method: str = \"cubic-mean\",\n    cubature_weights: NDArrayFloat | None = None,\n    multidim_condition: dict | None = None,\n) -> NDArrayFloat:\n    \"\"\"Axial induction factor of the turbine incorporating\n    the thrust coefficient and yaw angle.\n\n    Args:\n        velocities (NDArrayFloat): The velocity field at each turbine; should be shape:\n            (number of turbines, ngrid, ngrid), or (ngrid, ngrid) for a single turbine.\n        turbulence_intensities (NDArrayFloat[findex, turbines]): The turbulence intensity at\n            each turbine.\n        air_density (float): air density for simulation [kg/m^3]\n        yaw_angles (NDArrayFloat[findex, turbines]): The yaw angle for each turbine.\n        tilt_angles (NDArrayFloat[findex, turbines]): The tilt angle for each turbine.\n        power_setpoints: (NDArrayFloat[findex, turbines]): Maximum power setpoint for each\n            turbine [W].\n        awc_amplitudes: (NDArrayFloat[findex, turbines]): awc excitation amplitude for each\n            turbine [deg].\n        axial_induction_functions (dict): The axial induction functions for each turbine. Keys are\n            the turbine type string and values are the callable functions.\n        tilt_interps (Iterable[tuple]): The tilt interpolation functions for each\n            turbine.\n        correct_cp_ct_for_tilt (NDArrayBool[findex, turbines]): Boolean for determining if the\n            turbines Cp and Ct should be corrected for tilt.\n        turbine_type_map: (NDArrayObject[findex, turbines]): The Turbine type definition\n            for each turbine.\n        ix_filter (NDArrayFilter | Iterable[int] | None, optional): The boolean array, or\n            integer indices (as an array or iterable) to filter out before calculation.\n            Defaults to None.\n        average_method (str, optional): The method for averaging over turbine rotor points\n            to determine a rotor-average wind speed. Defaults to \"cubic-mean\".\n        cubature_weights (NDArrayFloat | None): Weights for cubature averaging methods. Defaults to\n            None.\n        multidim_condition (dict | None): The condition dictionary used to select the appropriate\n            thrust coefficient relationship for multidimensional power/thrust tables. Defaults to\n            None.\n\n    Returns:\n        Union[float, NDArrayFloat]: [description]\n    \"\"\"\n\n    # Down-select inputs if ix_filter is given\n    if ix_filter is not None:\n        velocities = velocities[:, ix_filter]\n        turbulence_intensities = turbulence_intensities[:, ix_filter]\n        yaw_angles = yaw_angles[:, ix_filter]\n        tilt_angles = tilt_angles[:, ix_filter]\n        power_setpoints = power_setpoints[:, ix_filter]\n        awc_modes = awc_modes[:, ix_filter]\n        awc_amplitudes = awc_amplitudes[:, ix_filter]\n        turbine_type_map = turbine_type_map[:, ix_filter]\n        if type(correct_cp_ct_for_tilt) is bool:\n            pass\n        else:\n            correct_cp_ct_for_tilt = correct_cp_ct_for_tilt[:, ix_filter]\n\n    # Establish the main set of keyword arguments for axial_induction()\n    axial_induction_model_kwargs = {\n        \"power_thrust_table\": None, # Will be filled below\n        \"velocities\": velocities,\n        \"turbulence_intensities\": turbulence_intensities,\n        \"air_density\": air_density,\n        \"yaw_angles\": yaw_angles,\n        \"tilt_angles\": tilt_angles,\n        \"power_setpoints\": power_setpoints,\n        \"awc_modes\": awc_modes,\n        \"awc_amplitudes\": awc_amplitudes,\n        \"tilt_interp\": None, # Will be filled below\n        \"average_method\": average_method,\n        \"cubature_weights\": cubature_weights,\n        \"correct_cp_ct_for_tilt\": correct_cp_ct_for_tilt,\n    }\n\n    # Loop over each turbine type given to get axial induction for all turbines\n    axial_induction = np.zeros(np.shape(velocities)[0:2])\n    turb_types = np.unique(turbine_type_map)\n    for turb_type in turb_types:\n        if \"thrust_coefficient\" in turbine_power_thrust_tables[turb_type]:  # Not multidimensional\n            power_thrust_table = turbine_power_thrust_tables[turb_type]\n\n            axial_induction_model_kwargs[\"power_thrust_table\"] = power_thrust_table\n            axial_induction_model_kwargs[\"tilt_interp\"] = tilt_interps[turb_type]\n\n            axial_induction += (\n                axial_induction_functions[turb_type](**axial_induction_model_kwargs)\n                * (turbine_type_map == turb_type)\n            )\n        else: # Multidimensional\n            md_conditions, md_conditions_map = _select_multidim_condition(\n                multidim_condition,\n                [k for k in turbine_power_thrust_tables[turb_type].keys() if k != \"condition_keys\"],\n                turbine_power_thrust_tables[turb_type][\"condition_keys\"],\n                velocities.shape[0],\n            )\n\n            # Loop over conditions and mask onto axial_induction\n            for i, md_cond in enumerate(md_conditions):\n                power_thrust_table = turbine_power_thrust_tables[turb_type][tuple(md_cond)]\n\n                axial_induction_model_kwargs[\"power_thrust_table\"] = power_thrust_table\n                axial_induction_model_kwargs[\"tilt_interp\"] = tilt_interps[turb_type]\n\n                axial_induction += (\n                    axial_induction_functions[turb_type](**axial_induction_model_kwargs)\n                    * (turbine_type_map == turb_type)\n                    * (md_conditions_map[:, None] == i)\n                )\n\n    return axial_induction\n\n\n@define\nclass Turbine(BaseClass):\n    \"\"\"\n    A class containing the parameters and infrastructure to model a wind turbine's performance\n    for a particular atmospheric condition.\n\n    Args:\n        turbine_type (str): An identifier for this type of turbine such as \"NREL_5MW\".\n        rotor_diameter (float): The rotor diameter in meters.\n        hub_height (float): The hub height in meters.\n        TSR (float): The Tip Speed Ratio of the turbine.\n        power_thrust_table (dict[str, float]): Contains power coefficient and thrust coefficient\n            values at a series of wind speeds to define the turbine performance.\n            The dictionary must have the following three keys with equal length values:\n                {\n                    \"wind_speeds\": List[float],\n                    \"power\": List[float],\n                    \"thrust\": List[float],\n                }\n            or, contain a key \"power_thrust_data_file\" pointing to the power/thrust data.\n            Optionally, power_thrust_table may include parameters for use in the turbine submodel,\n            for example:\n                cosine_loss_exponent_yaw (float): The cosine exponent relating the yaw misalignment\n                    angle to turbine power.\n                cosine_loss_exponent_tilt (float): The cosine exponent relating the rotor tilt angle\n                    to turbine power.\n                ref_air_density (float): The density at which the provided Cp and Ct curves are\n                    defined.\n                ref_tilt (float): The implicit tilt of the turbine for which the Cp and Ct\n                    curves are defined. This is typically the nacelle tilt.\n        correct_cp_ct_for_tilt (bool): A flag to indicate whether to correct Cp and Ct for tilt\n            usually for a floating turbine.\n            Optional, defaults to False.\n        floating_tilt_table (dict[str, float]): Look up table of tilt angles at a series of\n            wind speeds. The dictionary must have the following keys with equal length values:\n                {\n                    \"wind_speeds\": List[float],\n                    \"tilt\": List[float],\n                }\n            Required if `correct_cp_ct_for_tilt = True`. Defaults to None.\n        multi_dimensional_cp_ct (bool): Use a multidimensional power_thrust_table. Defaults to\n            False.\n    \"\"\"\n    turbine_type: str = field()\n    rotor_diameter: float = field()\n    hub_height: float = field()\n    TSR: float = field()\n    power_thrust_table: dict = field(default={}) # conversion to numpy in __post_init__\n    operation_model: str = field(default=\"cosine-loss\")\n\n    correct_cp_ct_for_tilt: bool = field(default=False)\n    floating_tilt_table: dict[str, NDArrayFloat] | None = field(default=None)\n\n    multi_dimensional_cp_ct: bool = field(default=False)\n\n    # Initialized in the post_init function\n    rotor_radius: float = field(init=False)\n    rotor_area: float = field(init=False)\n    thrust_coefficient_function: Callable = field(init=False)\n    axial_induction_function: Callable = field(init=False)\n    power_function: Callable = field(init=False)\n    tilt_interp: interp1d = field(init=False, default=None)\n    power_thrust_data_file: str = field(default=None)\n\n    # Only used by mutlidimensional turbines\n    turbine_library_path: Path = field(\n        default=Path(__file__).parents[2] / \"turbine_library\",\n        converter=convert_to_path,\n        validator=attrs.validators.instance_of(Path)\n    )\n\n    # Not to be provided by the user\n    condition_keys: list[str] = field(init=False, factory=list)\n\n    def __attrs_post_init__(self) -> None:\n        self._initialize_power_thrust_functions()\n        self.__post_init__()\n\n    def __post_init__(self) -> None:\n        self._initialize_tilt_interpolation()\n\n        bypass_numeric_converter = False\n        if self.multi_dimensional_cp_ct:\n            self._initialize_multidim_power_thrust_table()\n            bypass_numeric_converter = True\n\n        # Check for whether a cp_ct_data_file is specified, and load it if so.\n        if \"controller_dependent_turbine_parameters\" in self.power_thrust_table:\n            floris_root = Path(__file__).resolve().parents[2]\n            file_path = (\n                floris_root / \"turbine_library\" /\n                self.power_thrust_table[\"controller_dependent_turbine_parameters\"]\n                                       [\"cp_ct_data_file\"]\n            )\n            npz_data = dict(np.load(file_path))\n            self.power_thrust_table[\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"] = {\n                k: v.tolist() for k, v in npz_data.items()\n            }\n            bypass_numeric_converter = True\n\n        # Raise warning if \"demo\" in the cp_ct data file name\n        if (\n            self.operation_model in [\"controller-dependent\"]\n            and \"demo\" in self.power_thrust_table[\"controller_dependent_turbine_parameters\"]\n                                                 [\"cp_ct_data_file\"]\n        ):\n            self.logger.warning(\n                \"Cp/Ct data provided with FLORIS is for demonstration purposes only,\"\n                \" and may not accurately reflect the actual Cp/Ct surfaces of reference wind\"\n                \" turbines.\"\n            )\n\n        if not bypass_numeric_converter:\n            self.power_thrust_table = floris_numeric_dict_converter(self.power_thrust_table)\n\n    def _initialize_power_thrust_functions(self) -> None:\n        turbine_function_model = TURBINE_MODEL_MAP[\"operation_model\"][self.operation_model]\n        self.thrust_coefficient_function = turbine_function_model.thrust_coefficient\n        self.axial_induction_function = turbine_function_model.axial_induction\n        self.power_function = turbine_function_model.power\n\n\n    def _initialize_tilt_interpolation(self) -> None:\n        # TODO:\n        # Remove any duplicate wind speed entries\n        # _, duplicate_filter = np.unique(self.wind_speeds, return_index=True)\n        # self.tilt = self.tilt[duplicate_filter]\n        # self.wind_speeds = self.wind_speeds[duplicate_filter]\n\n        if self.floating_tilt_table is not None:\n            self.floating_tilt_table = floris_numeric_dict_converter(self.floating_tilt_table)\n\n        # If defined, create a tilt interpolation function for floating turbines.\n        # fill_value currently set to apply the min or max tilt angles if outside\n        # of the interpolation range.\n        if self.correct_cp_ct_for_tilt:\n            self.tilt_interp = interp1d(\n                self.floating_tilt_table[\"wind_speed\"],\n                self.floating_tilt_table[\"tilt\"],\n                fill_value=(0.0, self.floating_tilt_table[\"tilt\"][-1]),\n                bounds_error=False,\n            )\n\n    def _initialize_multidim_power_thrust_table(self):\n        # Collect reference information\n        power_thrust_table_ref = copy.deepcopy(self.power_thrust_table)\n        self.power_thrust_data_file = power_thrust_table_ref.pop(\"power_thrust_data_file\")\n\n        # Solidify the data file path and name\n        self.power_thrust_data_file = self.turbine_library_path / self.power_thrust_data_file\n\n        # Read in the multi-dimensional data supplied by the user.\n        df = pd.read_csv(self.power_thrust_data_file)\n\n        # Down-select the DataFrame to have just the ws, Cp, and Ct values\n        index_col = df.columns.values[:-3]\n        self.condition_keys = index_col.tolist()\n        df2 = df.set_index(index_col.tolist())\n\n        # Loop over the multi-dimensional keys to get the correct ws/Cp/Ct data to make\n        # the thrust_coefficient and power interpolants.\n        power_thrust_table_ = {} # Reset\n        for key in df2.index.unique():\n            # Select the correct ws/Cp/Ct data\n            data = df2.loc[key]\n            if type(key) is not tuple:\n                key = (key,)\n\n            # Build the interpolants\n            power_thrust_table_.update(\n                {\n                    key: {\n                        \"wind_speed\": data['ws'].values,\n                        \"power\": data['power'].values,\n                        \"thrust_coefficient\": data['thrust_coefficient'].values,\n                        **power_thrust_table_ref\n                    },\n                }\n            )\n            # Add reference information at the lower level\n\n        # Save names of dimensions and set on-object version\n        power_thrust_table_.update({\"condition_keys\": self.condition_keys})\n        self.power_thrust_table = power_thrust_table_\n\n    @power_thrust_table.validator\n    def check_power_thrust_table(self, instance: attrs.Attribute, value: dict) -> None:\n        \"\"\"\n        Verify that the power and thrust tables are given with arrays of equal length\n        to the wind speed array.\n        \"\"\"\n\n        if self.multi_dimensional_cp_ct:\n            if \"power_thrust_data_file\" in value.keys():\n                return None\n            else:\n                key_types = [type(k) for k in value.keys()]\n                if key_types[0] in (tuple, float, int):\n                    value = list(value.values())[0] # Check the first entry of multidim\n                else:\n                    raise ValueError(\n                        \"power_thrust_data_file must be defined if multi_dimensional_cp_ct is True.\"\n                    )\n\n        if not {\"wind_speed\", \"power\", \"thrust_coefficient\"} <= set(value.keys()):\n            raise ValueError(\n                \"\"\"\n                power_thrust_table dictionary must contain:\n                    {\n                        \"wind_speed\": List[float],\n                        \"power\": List[float],\n                        \"thrust_coefficient\": List[float],\n                    }\n                \"\"\"\n            )\n\n    @rotor_diameter.validator\n    def reset_rotor_diameter_dependencies(self, instance: attrs.Attribute, value: float) -> None:\n        \"\"\"Resets the `rotor_radius` and `rotor_area` attributes.\"\"\"\n        # Temporarily turn off validators to avoid infinite recursion\n        with attrs.validators.disabled():\n            # Reset the values\n            self.rotor_radius = value / 2.0\n            self.rotor_area = np.pi * self.rotor_radius ** 2.0\n\n    @rotor_radius.validator\n    def reset_rotor_radius(self, instance: attrs.Attribute, value: float) -> None:\n        \"\"\"\n        Resets the `rotor_diameter` value to trigger the recalculation of\n        `rotor_diameter`, `rotor_radius` and `rotor_area`.\n        \"\"\"\n        self.rotor_diameter = value * 2.0\n\n    @rotor_area.validator\n    def reset_rotor_area(self, instance: attrs.Attribute, value: float) -> None:\n        \"\"\"\n        Resets the `rotor_radius` value to trigger the recalculation of\n        `rotor_diameter`, `rotor_radius` and `rotor_area`.\n        \"\"\"\n        self.rotor_radius = (value / np.pi) ** 0.5\n\n    @floating_tilt_table.validator\n    def check_floating_tilt_table(self, instance: attrs.Attribute, value: dict | None) -> None:\n        \"\"\"\n        If the tilt / wind_speed table is defined, verify that the tilt and\n        wind_speed arrays are the same length.\n        \"\"\"\n        if value is None:\n            return\n\n        if len(value.keys()) != 2 or set(value.keys()) != {\"wind_speed\", \"tilt\"}:\n            raise ValueError(\n                \"\"\"\n                floating_tilt_table dictionary must have the form:\n                    {\n                        \"wind_speed\": List[float],\n                        \"tilt\": List[float],\n                    }\n                \"\"\"\n            )\n\n        if any(len(np.shape(e)) > 1 for e in (value[\"tilt\"], value[\"wind_speed\"])):\n            raise ValueError(\"tilt and wind_speed inputs must be 1-D.\")\n\n        if len( {len(value[\"tilt\"]), len(value[\"wind_speed\"])} ) > 1:\n            raise ValueError(\"tilt and wind_speed inputs must be the same size.\")\n\n    @correct_cp_ct_for_tilt.validator\n    def check_for_cp_ct_correct_flag_if_floating(\n        self,\n        instance: attrs.Attribute,\n        value: bool\n    ) -> None:\n        \"\"\"\n        Check that the boolean flag exists for correcting Cp/Ct for tilt\n        if a tile/wind_speed table is also defined.\n        \"\"\"\n        if self.correct_cp_ct_for_tilt and self.floating_tilt_table is None:\n            raise ValueError(\n                \"To enable the Cp and Ct tilt correction, a tilt table must be given.\"\n            )\n"
  },
  {
    "path": "floris/core/turbine/unified_momentum_model.py",
    "content": "from dataclasses import dataclass\nfrom typing import (\n    Any,\n    Callable,\n    List,\n    Optional,\n    Protocol,\n    Tuple,\n    Union,\n)\n\nimport numpy as np\nfrom numpy.typing import ArrayLike\nfrom scipy.interpolate import interp1d\n\nfrom floris.core.rotor_velocity import (\n    average_velocity,\n    rotor_velocity_air_density_correction,\n)\nfrom floris.core.turbine.operation_models import BaseOperationModel\nfrom floris.type_dec import NDArrayFloat\n\n\n## Turbine operation model functions\n# These are called by FLORIS through the UnifiedMomentumModelTurbine class to ultimately compute\n# the power, thrust coefficient, and axial induction of the turbine.\n\ndef UMM_rotor_axial_induction(Cts: NDArrayFloat, yaw_angles: NDArrayFloat)-> NDArrayFloat:\n    \"\"\"\n    Computes the axial induction of a yawed rotor given the yaw-aligned thrust\n    coefficient and yaw angles using the yawed actuator disk model developed at\n    MIT as described in Heck et al. 2023. Assumes the modified thrust\n    coefficient, C_T', is invariant to yaw misalignment angle.\n\n    Uses form of C_T' from Eq. (19) of Calaf et al., 2010, https://doi.org/10.1063/1.3291077\n\n    Args\n        Cts (NDArrayFloat): Yaw-aligned thrust coefficient(s).\n        yaw_angles (NDArrayFloat): Rotor yaw angle(s) in degrees.\n\n    Returns: NDArrayFloat: Axial induction factor(s) of the yawed rotor.\n    \"\"\"\n    ai_yawaligned = 0.5*(1 - np.sqrt(1 - Cts)) # Actuator disc theory\n    Ctprime = Cts / (1-ai_yawaligned)**2 # Eq. (19) of Calaf et al., 2010\n    sol = Heck()(Ctprime, np.deg2rad(yaw_angles))\n\n    return sol.an\n\ndef UMM_rotor_velocity_yaw_correction(\n    Cts: NDArrayFloat,\n    yaw_angles: NDArrayFloat,\n    axial_inductions: NDArrayFloat,\n    rotor_effective_velocities: NDArrayFloat,\n) -> NDArrayFloat:\n    \"\"\"\n    Computes adjusted rotor wind speeds given the yaw-aligned thrust\n    coefficient, yaw angles, and axial induction values using the yawed actuator\n    disk model developed at MIT as described in Heck et al. 2023. Assumes the\n    modified thrust coefficient, C_T', is invariant to yaw misalignment angle.\n\n    Args\n        Cts (NDArrayFloat): Yaw-aligned thrust coefficient(s).\n        yaw_angles (NDArrayFloat): Rotor yaw angle(s) in degrees.\n        axial_induction (NDArrayFloat): Rotor axial induction(s); this should follow the MIT model\n        yaw dependent derivation and probably gotten from `UMM_rotor_axial_induction`.\n        rotor_effective_velocities (NDArrayFloat) rotor effective wind speed(s) at the rotor.\n\n    Returns: NDArrayFloat: corrected rotor effective wind speed(s) of the yawed rotor.\n    \"\"\"\n    ai_yawaligned = 0.5*(1 - np.sqrt(1 - Cts)) # Actuator disc theory\n    Ctprime = Cts / (1-ai_yawaligned)**2 # Eq. (19) of Calaf et al., 2010\n\n    u_d_yawed = (1 - axial_inductions) * np.cos(np.deg2rad(yaw_angles)) # Eq. 2.3 of Heck et al.\n    u_d_aligned = (1 - (Ctprime)/(Ctprime + 4)) # From eq. D1 of Heck et al.\n\n    # Ratio of yaw-adjusted rotor wind speeds to yaw-aligned rotor wind speeds\n    ratio = u_d_yawed / u_d_aligned\n\n    return ratio * rotor_effective_velocities\n\n\n## Iterative solver functions\n\nclass FixedPointIterationCompatible(Protocol):\n    def residual(self, *args, **kwargs) -> Tuple[ArrayLike]: ...\n\n    def initial_guess(self, *args, **kwargs) -> Tuple[ArrayLike]: ...\n\n@dataclass\nclass FixedPointIterationResult:\n    converged: bool\n    niter: int\n    relax: float\n    max_resid: float\n    x: ArrayLike\n\ndef _fixedpointiteration(\n    f: Callable[[ArrayLike, Any], np.ndarray],\n    x0: np.ndarray,\n    args=(),\n    kwargs={},\n    eps=0.00001,\n    maxiter=100,\n    relax=0,\n    callback=None,\n) -> FixedPointIterationResult:\n    \"\"\"\n    Performs fixed-point iteration on function f until residuals converge or max\n    iterations is reached.\n\n    Args:\n        f (Callable): residual function of form f(x, *args, **kwargs) -> np.ndarray\n        x0 (np.ndarray): Initial guess\n        args (tuple): arguments to pass to residual function. Defaults to ().\n        kwargs (dict): keyword arguments to pass to residual function. Defaults to {}.\n        eps (float): Convergence tolerance. Defaults to 0.000001.\n        maxiter (int): Maximum number of iterations. Defaults to 100.\n        relax (float): Relaxation factor between 0 and 1. Defaults to 0.\n        callback (Callable): optional callback function at each iteration of the form f(x0) -> None\n\n    Returns:\n        FixedPointIterationResult: Solution to residual function.\n    \"\"\"\n\n    for c in range(maxiter):\n        residuals = f(x0, *args, **kwargs)\n\n        x0 = [_x0 + (1 - relax) * _r for _x0, _r in zip(x0, residuals)]\n        max_resid = [np.nanmax(np.abs(_r)) for _r in residuals]\n\n        if callback:\n            callback(x0)\n\n        if all(_r < eps for _r in max_resid):\n            converged = True\n            break\n    else:\n        converged = False\n\n    if maxiter == 0:\n        return FixedPointIterationResult(False, 0, np.nan, np.nan, x0)\n    return FixedPointIterationResult(converged, c, relax, max_resid, x0)\n\ndef fixedpointiteration(\n    max_iter: int = 100,\n    tolerance: float = 1e-6,\n    relaxation: float = 0.0\n) -> FixedPointIterationCompatible:\n    \"\"\"\n    Class decorator which adds a __call__ method to the class which performs\n    fixed-point iteration.\n\n    Args:\n        max_iter (int): Maximum number of iterations (default: 100)\n        tolerance (float): Convergence criteria (default: 1e-6)\n        relaxation (float): Relaxation factor between 0 and 1 (default: 0.0)\n\n    The class must contain 2 mandatory methods and 3\n    optional method:\n\n    mandatory:\n    initial_guess(self, *args, **kwargs)\n    residual(self, x, *args, **kwargs)\n\n    optional:\n    pre_process(self, *args, **kwargs) # Optional\n    post_process(self, result:FixedPointIterationResult) # Optional\n    callback(self, x) # Optional\n    \"\"\"\n\n    def decorator(cls: FixedPointIterationCompatible) -> Callable:\n        def call(self, *args, **kwargs):\n            if hasattr(self, \"pre_process\"):\n                self.pre_process(*args, **kwargs)\n\n            callback = self.callback if hasattr(self, \"callback\") else None\n\n            x0 = self.initial_guess(*args, **kwargs)\n            result = _fixedpointiteration(\n                self.residual,\n                x0,\n                args=args,\n                kwargs=kwargs,\n                eps=tolerance,\n                maxiter=max_iter,\n                relax=relaxation,\n                callback=callback,\n            )\n\n            if hasattr(self, \"post_process\"):\n                return self.post_process(result, *args, **kwargs)\n            else:\n                return result\n\n        setattr(cls, \"__call__\", call)\n        return cls\n\n    return decorator\n\ndef adaptivefixedpointiteration(\n    max_iter: int = 100,\n    tolerance: float = 1e-6,\n    relaxations: List[float] = [0.0]\n) -> Callable:\n    \"\"\"\n    Class decorator which adds a __call__ method to the class which performs\n    fixed-point iteration. Same as `fixedpointiteration`, but takes a list of\n    relaxation factors, and iterates over all of them in order until convergence\n    is reached.\n    \"\"\"\n\n    def decorator(cls: FixedPointIterationCompatible) -> Callable:\n        def call(self, *args, **kwargs):\n            if hasattr(self, \"pre_process\"):\n                self.pre_process(*args, **kwargs)\n            callback = self.callback if hasattr(self, \"callback\") else None\n\n            for relaxation in relaxations:\n                x0 = self.initial_guess(*args, **kwargs)\n                result = _fixedpointiteration(\n                    self.residual,\n                    x0,\n                    args=args,\n                    kwargs=kwargs,\n                    eps=tolerance,\n                    maxiter=max_iter,\n                    relax=relaxation,\n                    callback=callback,\n                )\n                if result.converged:\n                    break\n\n            if hasattr(self, \"post_process\"):\n                return self.post_process(result, *args, **kwargs)\n            else:\n                return result\n\n        setattr(cls, \"__call__\", call)\n        return cls\n\n    return decorator\n\n## The operation model class to interface with FLORIS.\n# This uses the iterative solve functions above.\n\nclass UnifiedMomentumModelTurbine(BaseOperationModel):\n    \"\"\"\n    Turbine operation model as described by Heck et al. (2023).\n    \"\"\"\n\n    def power(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        yaw_angles: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **kwargs,\n    ) -> None:\n\n        # Construct thrust coefficient interpolant\n        thrust_coefficient_interpolator = interp1d(\n            power_thrust_table[\"wind_speed\"],\n            power_thrust_table[\"thrust_coefficient\"],\n            fill_value=0.0001,\n            bounds_error=False,\n        )\n\n        # Compute the power-effective wind speed across the rotor\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        rotor_effective_velocities = rotor_velocity_air_density_correction(\n            velocities=rotor_average_velocities,\n            air_density=air_density,\n            ref_air_density=power_thrust_table[\"ref_air_density\"]\n        )\n\n        thrust_coefficients = thrust_coefficient_interpolator(rotor_effective_velocities)\n\n        axial_inductions = UMM_rotor_axial_induction(thrust_coefficients, yaw_angles)\n\n        corrected_rotor_effective_velocities = UMM_rotor_velocity_yaw_correction(\n            thrust_coefficients,\n            yaw_angles,\n            axial_inductions,\n            rotor_effective_velocities\n        )\n\n        # TODO: Tilt correction?\n\n        # Construct power interpolant\n        power_interpolator = interp1d(\n            power_thrust_table[\"wind_speed\"],\n            power_thrust_table[\"power\"],\n            fill_value=0.0,\n            bounds_error=False,\n        )\n\n        # Compute power\n        power = power_interpolator(corrected_rotor_effective_velocities) * 1e3 # Convert to W\n\n        return power\n\n    def thrust_coefficient(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        yaw_angles: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **kwargs,\n    ) -> None:\n\n        # Construct thrust coefficient interpolant\n        thrust_coefficient_interpolator = interp1d(\n            power_thrust_table[\"wind_speed\"],\n            power_thrust_table[\"thrust_coefficient\"],\n            fill_value=0.0001,\n            bounds_error=False,\n        )\n\n        # Compute the power-effective wind speed across the rotor\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        rotor_effective_velocities = rotor_velocity_air_density_correction(\n            velocities=rotor_average_velocities,\n            air_density=air_density,\n            ref_air_density=power_thrust_table[\"ref_air_density\"]\n        )\n\n        thrust_coefficients = thrust_coefficient_interpolator(rotor_effective_velocities)\n\n        axial_inductions = UMM_rotor_axial_induction(thrust_coefficients, yaw_angles)\n\n        corrected_rotor_effective_velocities = UMM_rotor_velocity_yaw_correction(\n            thrust_coefficients,\n            yaw_angles,\n            axial_inductions,\n            rotor_effective_velocities\n        )\n\n        # TODO: Tilt correction?\n\n        # Compute thrust coefficient\n        yawed_thrust_coefficients = thrust_coefficient_interpolator(\n            corrected_rotor_effective_velocities\n        )\n\n        return yawed_thrust_coefficients\n\n    def axial_induction(\n        power_thrust_table: dict,\n        velocities: NDArrayFloat,\n        air_density: float,\n        yaw_angles: NDArrayFloat,\n        average_method: str = \"cubic-mean\",\n        cubature_weights: NDArrayFloat | None = None,\n        **kwargs,\n    ):\n\n        # Construct thrust coefficient interpolant\n        thrust_coefficient_interpolator = interp1d(\n            power_thrust_table[\"wind_speed\"],\n            power_thrust_table[\"thrust_coefficient\"],\n            fill_value=0.0001,\n            bounds_error=False,\n        )\n\n        # Compute the power-effective wind speed across the rotor\n        rotor_average_velocities = average_velocity(\n            velocities=velocities,\n            method=average_method,\n            cubature_weights=cubature_weights,\n        )\n\n        rotor_effective_velocities = rotor_velocity_air_density_correction(\n            velocities=rotor_average_velocities,\n            air_density=air_density,\n            ref_air_density=power_thrust_table[\"ref_air_density\"]\n        )\n\n        thrust_coefficients = thrust_coefficient_interpolator(rotor_effective_velocities)\n\n        axial_inductions = UMM_rotor_axial_induction(thrust_coefficients, yaw_angles)\n\n        return axial_inductions\n\n\n## Below is the implementation of the model as described in the paper.\n\n@dataclass\nclass MomentumSolution:\n    \"\"\"Stores the results of the Unified Momentum model solution.\"\"\"\n\n    Ctprime: float\n    yaw: float\n    an: Union[float, NDArrayFloat]\n    u4: Union[float, NDArrayFloat]\n    v4: Union[float, NDArrayFloat]\n    x0: Union[float, NDArrayFloat]\n    dp: Union[float, NDArrayFloat]\n    dp_NL: Optional[Union[float, NDArrayFloat]] = 0.0\n    niter: Optional[int] = 1\n    converged: Optional[bool] = True\n    beta: Optional[float] = 0.0\n\n    @property\n    def Ct(self):\n        \"\"\"Returns the thrust coefficient Ct.\"\"\"\n        return self.Ctprime * (1 - self.an) ** 2 * np.cos(self.yaw) ** 2\n\n    @property\n    def Cp(self):\n        \"\"\"Returns the power coefficient Cp.\"\"\"\n        return self.Ctprime * ((1 - self.an) * np.cos(self.yaw)) ** 3\n\nclass LimitedHeck():\n    \"\"\"\n    Solves the limiting case when v_4 << u_4. (Eq. 2.19, 2.20). Also takes Numpy\n    array arguments.\n    \"\"\"\n\n    def __call__(self, Ctprime: float, yaw: float, **kwargs) -> MomentumSolution:\n        \"\"\"\n        Args:\n            Ctprime (float): Rotor thrust coefficient.\n            yaw (float): Rotor yaw angle (radians).\n\n        Returns:\n            Tuple[float, float, float]: induction and outlet velocities.\n        \"\"\"\n\n        a = Ctprime * np.cos(yaw) ** 2 / (4 + Ctprime * np.cos(yaw) ** 2)\n        u4 = (4 - Ctprime * np.cos(yaw) ** 2) / (4 + Ctprime * np.cos(yaw) ** 2)\n        v4 = (\n            -(4 * Ctprime * np.sin(yaw) * np.cos(yaw) ** 2)\n            / (4 + Ctprime * np.cos(yaw) ** 2) ** 2\n        )\n        dp = np.zeros_like(a)\n        x0 = np.inf * np.ones_like(a)\n        return MomentumSolution(Ctprime, yaw, a, u4, v4, x0, dp)\n\n@fixedpointiteration(max_iter=500, tolerance=0.00001, relaxation=0.1)\nclass Heck():\n    \"\"\"\n    Solves the iterative momentum equation for an actuator disk model.\n    \"\"\"\n\n    def __init__(self, v4_correction: float = 1.0):\n        \"\"\"\n        Initialize the HeckModel instance.\n\n        Args:\n            v4_correction (float, optional): The premultiplier of v4 in the Heck\n            model. A correction factor applied to v4, with a default value of\n            1.0, indicating no correction. Lu (2023) suggests an empirical correction\n            of 1.5.\n\n        Example:\n            >>> model = HeckModel(v4_correction=1.5)\n        \"\"\"\n        self.v4_correction = v4_correction\n\n    def initial_guess(self, Ctprime, yaw):\n        sol = LimitedHeck()(Ctprime, yaw)\n        return sol.an, sol.u4, sol.v4\n\n    def residual(self, x: np.ndarray, Ctprime: float, yaw: float) -> np.ndarray:\n        \"\"\"\n        Residual function of yawed-actuator disk model in Eq. 2.15.\n\n        Args:\n            x (np.ndarray): (a, u4, v4)\n            Ctprime (float): Rotor thrust coefficient.\n            yaw (float): Rotor yaw angle (radians).\n\n        Returns:\n            np.ndarray: residuals of induction and outlet velocities.\n        \"\"\"\n\n        a, u4, v4 = x\n        e_a = 1 - np.sqrt(1 - u4**2 - v4**2) / (np.sqrt(Ctprime) * np.cos(yaw)) - a\n\n        e_u4 = (1 - 0.5 * Ctprime * (1 - a) * np.cos(yaw) ** 2) - u4\n\n        e_v4 = (\n            -self.v4_correction\n            * 0.25\n            * Ctprime\n            * (1 - a) ** 2\n            * np.sin(yaw)\n            * np.cos(yaw) ** 2\n            - v4\n        )\n\n        return np.array([e_a, e_u4, e_v4])\n\n    def post_process(self, result, Ctprime: float, yaw: float):\n        if result.converged:\n            a, u4, v4 = result.x\n        else:\n            a, u4, v4 = np.nan * np.zeros_like([Ctprime, Ctprime, Ctprime])\n        dp = np.zeros_like(a)\n        x0 = np.inf * np.ones_like(a)\n        return MomentumSolution(\n            Ctprime,\n            yaw,\n            a,\n            u4,\n            v4,\n            x0,\n            dp,\n            niter=result.niter,\n            converged=result.converged,\n        )\n"
  },
  {
    "path": "floris/core/wake.py",
    "content": "\nimport attrs\nfrom attrs import define, field\n\nfrom floris.core import BaseClass, BaseModel\nfrom floris.core.wake_combination import (\n    FLS,\n    MAX,\n    SOSFS,\n)\nfrom floris.core.wake_deflection import (\n    EmpiricalGaussVelocityDeflection,\n    GaussVelocityDeflection,\n    JimenezVelocityDeflection,\n    NoneVelocityDeflection,\n)\nfrom floris.core.wake_turbulence import (\n    CrespoHernandez,\n    NoneWakeTurbulence,\n    WakeInducedMixing,\n)\nfrom floris.core.wake_velocity import (\n    CumulativeGaussCurlVelocityDeficit,\n    EmpiricalGaussVelocityDeficit,\n    GaussVelocityDeficit,\n    JensenVelocityDeficit,\n    NoneVelocityDeficit,\n    TurboparkgaussVelocityDeficit,\n    TurbOParkVelocityDeficit,\n)\n\n\nMODEL_MAP = {\n    \"combination_model\": {\n        \"fls\": FLS,\n        \"max\": MAX,\n        \"sosfs\": SOSFS\n    },\n    \"deflection_model\": {\n        \"jimenez\": JimenezVelocityDeflection,\n        \"gauss\": GaussVelocityDeflection,\n        \"none\": NoneVelocityDeflection,\n        \"empirical_gauss\": EmpiricalGaussVelocityDeflection\n    },\n    \"turbulence_model\": {\n        \"none\": NoneWakeTurbulence,\n        \"crespo_hernandez\": CrespoHernandez,\n        \"wake_induced_mixing\": WakeInducedMixing\n    },\n    \"velocity_model\": {\n        \"none\": NoneVelocityDeficit,\n        \"cc\": CumulativeGaussCurlVelocityDeficit,\n        \"gauss\": GaussVelocityDeficit,\n        \"jensen\": JensenVelocityDeficit,\n        \"turbopark\": TurbOParkVelocityDeficit,\n        \"empirical_gauss\": EmpiricalGaussVelocityDeficit,\n        \"turboparkgauss\": TurboparkgaussVelocityDeficit,\n    },\n}\n\n\n@define\nclass WakeModelManager(BaseClass):\n    \"\"\"\n    WakeModelManager is a container class for the wake velocity, deflection,\n    turbulence, and combination models.\n\n    Args:\n        wake (:obj:`dict`): The wake's properties input dictionary\n            - velocity_model (str): The name of the velocity model to be instantiated.\n            - turbulence_model (str): The name of the turbulence model to be instantiated.\n            - deflection_model (str): The name of the deflection model to be instantiated.\n            - combination_model (str): The name of the combination model to be instantiated.\n    \"\"\"\n    model_strings: dict = field(converter=dict)\n    enable_secondary_steering: bool = field(converter=bool)\n    enable_yaw_added_recovery: bool = field(converter=bool)\n    enable_active_wake_mixing: bool = field(converter=bool)\n    enable_transverse_velocities: bool = field(converter=bool)\n\n    wake_deflection_parameters: dict = field(converter=dict)\n    wake_turbulence_parameters: dict = field(converter=dict)\n    wake_velocity_parameters: dict = field(converter=dict, factory=dict)\n\n    combination_model: BaseModel = field(init=False)\n    deflection_model: BaseModel = field(init=False)\n    turbulence_model: BaseModel = field(init=False)\n    velocity_model: BaseModel = field(init=False)\n\n    def __attrs_post_init__(self) -> None:\n        velocity_model_string = self.model_strings[\"velocity_model\"].lower()\n        model: BaseModel = MODEL_MAP[\"velocity_model\"][velocity_model_string]\n        if velocity_model_string == \"none\":\n            model_parameters = None\n        else:\n            model_parameters = self.wake_velocity_parameters[velocity_model_string]\n        if model_parameters is None:\n            # Use model defaults\n            self.velocity_model = model()\n        else:\n            self.velocity_model = model.from_dict(model_parameters)\n\n        deflection_model_string = self.model_strings[\"deflection_model\"].lower()\n        model: BaseModel = MODEL_MAP[\"deflection_model\"][deflection_model_string]\n        if deflection_model_string == \"none\":\n            model_parameters = None\n        else:\n            model_parameters = self.wake_deflection_parameters[deflection_model_string]\n        if model_parameters is None:\n            self.deflection_model = model()\n        else:\n            self.deflection_model = model.from_dict(model_parameters)\n\n        turbulence_model_string = self.model_strings[\"turbulence_model\"].lower()\n        model: BaseModel = MODEL_MAP[\"turbulence_model\"][turbulence_model_string]\n        if turbulence_model_string == \"none\":\n            model_parameters = None\n        else:\n            model_parameters = self.wake_turbulence_parameters[turbulence_model_string]\n        if model_parameters is None:\n            self.turbulence_model = model()\n        else:\n            self.turbulence_model = model.from_dict(model_parameters)\n\n        combination_model_string = self.model_strings[\"combination_model\"].lower()\n        model: BaseModel = MODEL_MAP[\"combination_model\"][combination_model_string]\n        self.combination_model = model()\n\n    @model_strings.validator\n    def validate_model_strings(self, instance: attrs.Attribute, value: dict) -> None:\n        required_strings = [\n            \"velocity_model\",\n            \"deflection_model\",\n            \"combination_model\",\n            \"turbulence_model\"\n        ]\n        # Check that all required strings are given\n        for s in required_strings:\n            if s not in value.keys():\n                raise KeyError(f\"Wake: '{s}' not provided in the input but it is required.\")\n\n        # Check that no other strings are given\n        for k in value.keys():\n            if k not in required_strings:\n                raise KeyError((\n                    f\"Wake: '{k}' was given as input but it is not a valid option.\"\n                    f\"Required inputs are: {', '.join(required_strings)}\"\n                ))\n\n    @property\n    def deflection_function(self):\n        return self.deflection_model.function\n\n    @property\n    def velocity_function(self):\n        return self.velocity_model.function\n\n    @property\n    def turbulence_function(self):\n        return self.turbulence_model.function\n\n    @property\n    def combination_function(self):\n        return self.combination_model.function\n"
  },
  {
    "path": "floris/core/wake_combination/__init__.py",
    "content": "\nfrom floris.core.wake_combination.fls import FLS\nfrom floris.core.wake_combination.max import MAX\nfrom floris.core.wake_combination.sosfs import SOSFS\n"
  },
  {
    "path": "floris/core/wake_combination/fls.py",
    "content": "\nimport numpy as np\nfrom attrs import define\n\nfrom floris.core import BaseModel\n\n\n@define\nclass FLS(BaseModel):\n    \"\"\"\n    FLS uses freestream linear superposition to apply the wake velocity\n    deficits to the freestream flow field.\n    \"\"\"\n\n    def prepare_function(self) -> dict:\n        pass\n\n    def function(self, wake_field: np.ndarray, velocity_field: np.ndarray):\n        \"\"\"\n        Combines the base flow field with the velocity deficits\n        using freestream linear superposition. In other words, the wake\n        field and base fields are simply added together.\n\n        Args:\n            u_field (np.array): The base flow field.\n            u_wake (np.array): The wake to apply to the base flow field.\n\n        Returns:\n            np.array: The resulting flow field after applying the wake to the\n                base.\n        \"\"\"\n        return wake_field + velocity_field\n"
  },
  {
    "path": "floris/core/wake_combination/max.py",
    "content": "\nimport numpy as np\nfrom attrs import define\n\nfrom floris.core import BaseModel\n\n\n@define\nclass MAX(BaseModel):\n    \"\"\"\n    MAX uses the maximum wake velocity deficit to add to the\n    base flow field. For more information, refer to\n    :cite:`max-gunn2016limitations`.\n\n    References:\n        .. bibliography:: /references.bib\n            :style: unsrt\n            :filter: docname in docnames\n            :keyprefix: max-\n    \"\"\"\n\n    def prepare_function(self) -> dict:\n        pass\n\n    def function(self, wake_field: np.ndarray, velocity_field: np.ndarray):\n        \"\"\"\n        Incorporates the velocity deficits into the base flow field by\n        selecting the maximum of the two for each point.\n\n        Args:\n            u_field (np.array): The base flow field.\n            u_wake (np.array): The wake to apply to the base flow field.\n\n        Returns:\n            np.array: The resulting flow field after applying the wake to the\n                base.\n        \"\"\"\n        return np.maximum(wake_field, velocity_field)\n"
  },
  {
    "path": "floris/core/wake_combination/sosfs.py",
    "content": "\nimport numpy as np\nfrom attrs import define\n\nfrom floris.core import BaseModel\n\n\n@define\nclass SOSFS(BaseModel):\n    \"\"\"\n    SOSFS uses sum of squares freestream superposition to combine the\n    wake velocity deficits to the base flow field.\n\n    For more information, refer to :cite:`katic_sos_1986`.\n    \"\"\"\n\n    def prepare_function(self) -> dict:\n        pass\n\n    def function(self, wake_field: np.ndarray, velocity_field: np.ndarray):\n        \"\"\"\n        Combines the base flow field with the velocity deficits\n        using sum of squares.\n\n        Args:\n            u_field (np.array): The base flow field.\n            u_wake (np.array): The wake to apply to the base flow field.\n\n        Returns:\n            np.array: The resulting flow field after applying the wake to the\n                base.\n        \"\"\"\n        return np.hypot(wake_field, velocity_field)\n"
  },
  {
    "path": "floris/core/wake_deflection/__init__.py",
    "content": "\nfrom floris.core.wake_deflection.empirical_gauss import EmpiricalGaussVelocityDeflection\nfrom floris.core.wake_deflection.gauss import GaussVelocityDeflection\nfrom floris.core.wake_deflection.jimenez import JimenezVelocityDeflection\nfrom floris.core.wake_deflection.none import NoneVelocityDeflection\n"
  },
  {
    "path": "floris/core/wake_deflection/empirical_gauss.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.utilities import cosd, sind\n\n\n@define\nclass EmpiricalGaussVelocityDeflection(BaseModel):\n    \"\"\"\n    The Empirical Gauss deflection model is based on the form of previous the\n    Gauss deflection model (see :cite:`bastankhah2016experimental` and\n    :cite:`King2019Controls`) but simplifies the formulation for simpler\n    tuning and more independence from the velocity deficit model.\n\n    parameter_dictionary (dict): Model-specific parameters.\n        Default values are used when a parameter is not included\n        in `parameter_dictionary`. Possible key-value pairs include:\n\n            -   **horizontal_deflection_gain_D** (*float*): Gain for the\n                maximum (y-direction) deflection achieved far downstream\n                of a yawed turbine.\n            -   **vertical_deflection_gain_D** (*float*): Gain for the\n                maximum vertical (z-direction) deflection achieved at a\n                far downstream location due to rotor tilt. Specifying as\n                -1 will mean that vertical deflections due to tilt match\n                horizontal deflections due to yaw.\n            -   **deflection_rate** (*float*): Rate at which the\n                deflected wake center approaches its maximum deflection.\n            -   **mixing_gain_deflection** (*float*): Gain to set the\n                reduction in deflection due to wake-induced mixing.\n            -   **yaw_added_mixing_gain** (*float*): Sets the\n                contribution of turbine yaw misalignment to the mixing\n                in that turbine's wake (similar to yaw-added recovery).\n\n    References:\n        .. bibliography:: /references.bib\n            :style: unsrt\n            :filter: docname in docnames\n    \"\"\"\n    horizontal_deflection_gain_D: float = field(default=3.0)\n    vertical_deflection_gain_D: float = field(default=-1)\n    deflection_rate: float = field(default=22)\n    mixing_gain_deflection: float = field(default=0.0)\n    yaw_added_mixing_gain: float = field(default=0.0)\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n\n        kwargs = {\n            \"x\": grid.x_sorted,\n        }\n        return kwargs\n\n    # @profile\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        yaw_i: np.ndarray,\n        tilt_i: np.ndarray,\n        mixing_i: np.ndarray,\n        ct_i: np.ndarray,\n        rotor_diameter_i: float,\n        *,\n        x: np.ndarray,\n    ):\n        \"\"\"\n        Calculates the deflection field of the wake.\n\n        Args:\n            x_i (np.array): Streamwise direction grid coordinates of\n                the ith turbine (m).\n            y_i (np.array): Cross stream direction grid coordinates of\n                the ith turbine (m) [not used].\n            yaw_i (np.array): Yaw angle of the ith turbine (deg).\n            tilt_i (np.array): Tilt angle of the ith turbine (deg).\n            mixing_i (np.array): The wake-induced mixing term for the\n                ith turbine.\n            ct_i (np.array): Thrust coefficient for the ith turbine (-).\n            rotor_diameter_i (np.array): Rotor diameter for the ith\n                turbine (m).\n\n            x (np.array): Streamwise direction grid coordinates of the\n                flow field domain (m).\n\n        Returns:\n            np.array: Deflection field for the wake.\n        \"\"\"\n        # ==============================================================\n\n        deflection_gain_y = self.horizontal_deflection_gain_D * rotor_diameter_i\n        if self.vertical_deflection_gain_D == -1:\n            deflection_gain_z = deflection_gain_y\n        else:\n            deflection_gain_z = self.vertical_deflection_gain_D * rotor_diameter_i\n\n        # Convert to radians, CW yaw for consistency with other models\n        yaw_r = np.pi/180 * -yaw_i\n        tilt_r = np.pi/180 * tilt_i\n\n        A_y = (deflection_gain_y * ct_i * yaw_r) / (1 + self.mixing_gain_deflection * mixing_i)\n        A_z = (deflection_gain_z * ct_i * tilt_r) / (1 + self.mixing_gain_deflection * mixing_i)\n\n        # Apply downstream mask in the process\n        x_normalized = (x - x_i) * (x > x_i + 0.1) / rotor_diameter_i\n\n        log_term = np.log(\n            (x_normalized - self.deflection_rate) / (x_normalized + self.deflection_rate)\n            + 2\n        )\n\n        deflection_y = A_y * log_term\n        deflection_z = A_z * log_term\n\n        return deflection_y, deflection_z\n\ndef yaw_added_wake_mixing(\n    axial_induction_i,\n    yaw_angle_i,\n    downstream_distance_D_i,\n    yaw_added_mixing_gain\n):\n    return (\n        axial_induction_i[:,:,0,0]\n        * yaw_added_mixing_gain\n        * (1 - cosd(yaw_angle_i[:,:,0,0]))\n        / downstream_distance_D_i**2\n    )\n"
  },
  {
    "path": "floris/core/wake_deflection/gauss.py",
    "content": "from typing import Any\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import (\n    define,\n    field,\n    fields,\n)\nfrom numpy import pi\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.utilities import cosd, sind\n\n\nNUM_EPS = fields(BaseModel).NUM_EPS.default\n\n@define\nclass GaussVelocityDeflection(BaseModel):\n    \"\"\"\n    The Gauss deflection model is a blend of the models described in\n    :cite:`gdm-bastankhah2016experimental` and :cite:`gdm-King2019Controls` for\n    calculating the deflection field in turbine wakes.\n\n    parameter_dictionary (dict): Model-specific parameters.\n        Default values are used when a parameter is not included\n        in `parameter_dictionary`. Possible key-value pairs include:\n\n            -   **ka** (*float*): Parameter used to determine the linear\n                relationship between the turbulence intensity and the\n                width of the Gaussian wake shape.\n            -   **kb** (*float*): Parameter used to determine the linear\n                relationship between the turbulence intensity and the\n                width of the Gaussian wake shape.\n            -   **alpha** (*float*): Parameter that determines the\n                dependence of the downstream boundary between the near\n                wake and far wake region on the turbulence intensity.\n            -   **beta** (*float*): Parameter that determines the\n                dependence of the downstream boundary between the near\n                wake and far wake region on the turbine's induction\n                factor.\n            -   **ad** (*float*): Additional tuning parameter to modify\n                the wake deflection with a lateral offset.\n                Defaults to 0.\n            -   **bd** (*float*): Additional tuning parameter to modify\n                the wake deflection with a lateral offset.\n                Defaults to 0.\n            -   **dm** (*float*): Additional tuning parameter to scale\n                the amount of wake deflection. Defaults to 1.0\n            -   **use_secondary_steering** (*bool*): Flag to use\n                secondary steering on the wake velocity using methods\n                developed in [2].\n            -   **eps_gain** (*float*): Tuning value for calculating\n                the V- and W-component velocities using methods\n                developed in [7].\n                TODO: Believe this should be removed, need to verify.\n                See property on super-class for more details.\n\n    References:\n        .. bibliography:: /references.bib\n            :style: unsrt\n            :filter: docname in docnames\n            :keyprefix: gdm-\n    \"\"\"\n\n    ad: float = field(converter=float, default=0.0)\n    bd: float = field(converter=float, default=0.0)\n    alpha: float = field(converter=float, default=0.58)\n    beta: float = field(converter=float, default=0.077)\n    ka: float = field(converter=float, default=0.38)\n    kb: float = field(converter=float, default=0.004)\n    dm: float = field(converter=float, default=1.0)\n    eps_gain: float = field(converter=float, default=0.2)\n    use_secondary_steering: bool = field(converter=bool, default=True)\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> dict[str, Any]:\n\n        kwargs = {\n            \"x\": grid.x_sorted,\n            \"y\": grid.y_sorted,\n            \"z\": grid.z_sorted,\n            \"freestream_velocity\": flow_field.u_initial_sorted,\n            \"wind_veer\": flow_field.wind_veer,\n        }\n        return kwargs\n\n    # @profile\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        yaw_i: np.ndarray,\n        turbulence_intensity_i: np.ndarray,\n        ct_i: np.ndarray,\n        rotor_diameter_i: float,\n        *,\n        x: np.ndarray,\n        y: np.ndarray,\n        z: np.ndarray,\n        freestream_velocity: np.ndarray,\n        wind_veer: float,\n    ):\n        \"\"\"\n        Calculates the deflection field of the wake. See\n        :cite:`gdm-bastankhah2016experimental` and :cite:`gdm-King2019Controls`\n        for details on the methods used.\n\n        Args:\n            x_i (np.array): x-coordinates of turbine i.\n            y_i (np.array): y-coordinates of turbine i.\n            yaw_i (np.array): Yaw angle of turbine i.\n            turbulence_intensity_i (np.array): Turbulence intensity at turbine i.\n            ct_i (np.array): Thrust coefficient of turbine i.\n            rotor_diameter_i (float): Rotor diameter of turbine i.\n\n        Returns:\n            np.array: Deflection field for the wake.\n        \"\"\"\n        # ==============================================================\n\n        # Opposite sign convention in this model\n        yaw_i *= -1\n\n        # TODO: connect support for tilt\n        tilt = 0.0  # turbine.tilt_angle\n\n        # initial velocity deficits\n        uR = (\n            freestream_velocity\n            * ct_i\n            * cosd(tilt)\n            * cosd(yaw_i)\n            / (2.0 * (1 - np.sqrt(1 - (ct_i * cosd(tilt) * cosd(yaw_i)))))\n        )\n        u0 = freestream_velocity * np.sqrt(1 - ct_i)\n\n        # length of near wake\n        x0 = (\n            rotor_diameter_i\n            * (cosd(yaw_i) * (1 + np.sqrt(1 - ct_i * cosd(yaw_i))))\n            / (np.sqrt(2) * (\n                4 * self.alpha * turbulence_intensity_i + 2 * self.beta * (1 - np.sqrt(1 - ct_i))\n            )) + x_i\n        )\n\n        # wake expansion parameters\n        ky = self.ka * turbulence_intensity_i + self.kb\n        kz = self.ka * turbulence_intensity_i + self.kb\n\n        C0 = 1 - u0 / freestream_velocity\n        M0 = C0 * (2 - C0)\n        E0 = ne.evaluate(\"C0 ** 2 - 3 * exp(1.0 / 12.0) * C0 + 3 * exp(1.0 / 3.0)\")\n\n        # initial Gaussian wake expansion\n        sigma_z0 = ne.evaluate(\"rotor_diameter_i * 0.5 * sqrt(uR / (freestream_velocity + u0))\")\n        sigma_y0 = sigma_z0 * cosd(yaw_i) * cosd(wind_veer)\n\n        # yR = y - y_i\n        xR = x_i # yR * tand(yaw) + x_i\n\n        # yaw parameters (skew angle and distance from centerline)\n        # skew angle in radians\n        theta_c0 = self.dm * (0.3 * np.radians(yaw_i) / cosd(yaw_i))\n        theta_c0 *= (1 - np.sqrt(1 - ct_i * cosd(yaw_i)))\n        delta0 = np.tan(theta_c0) * (x0 - x_i)  # initial wake deflection;\n        # NOTE: use np.tan here since theta_c0 is radians\n\n        # deflection in the near wake\n        delta_near_wake = ((x - xR) / (x0 - xR)) * delta0 + (self.ad + self.bd * (x - x_i))\n        delta_near_wake *= (x >= xR) & (x <= x0)\n\n        # deflection in the far wake\n        sigma_y = ky * (x - x0) + sigma_y0\n        sigma_z = kz * (x - x0) + sigma_z0\n        sigma_y = sigma_y * (x >= x0) + sigma_y0 * (x < x0)\n        sigma_z = sigma_z * (x >= x0) + sigma_z0 * (x < x0)\n\n        M0_sqrt = np.sqrt(M0)\n        middle_term = np.sqrt(sigma_y * sigma_z / (sigma_y0 * sigma_z0))\n        ln_deltaNum = (1.6 + M0_sqrt) * (1.6 * middle_term - M0_sqrt)\n        ln_deltaDen = (1.6 - M0_sqrt) * (1.6 * middle_term + M0_sqrt)\n\n        middle_term = ne.evaluate(\n            \"theta_c0\"\n            \" * E0\"\n            \" / 5.2\"\n            \" * sqrt(sigma_y0 * sigma_z0 / (ky * kz * M0))\"\n            \" * log(ln_deltaNum / ln_deltaDen)\"\n        )\n        delta_far_wake = delta0 + middle_term + (self.ad + self.bd * (x - x_i))\n\n        delta_far_wake = delta_far_wake * (x > x0)\n        deflection = delta_near_wake + delta_far_wake\n\n        return deflection\n\n## GCH components\n\ndef gamma(\n    D,\n    velocity,\n    Uinf,\n    Ct,\n    scale=1.0,\n):\n    \"\"\"\n    Vortex circulation strength. Units of XXX TODO\n\n    Args:\n        D (float): Rotor diameter of the current turbine\n        velocity (np.array(float)): Velocities at the current turbine\n        Uinf (float): Free-stream velocity\n        Ct (float): Thrust coefficient at the current turbine\n\n    Returns:\n        [type]: [description]\n    \"\"\"\n    # NOTE the cos commented below is included in Ct\n    return scale * (pi / 8) * D * velocity * Uinf * Ct # * cosd(yaw)\n\n\ndef wake_added_yaw(\n    u_i,\n    v_i,\n    u_initial,\n    delta_y,\n    z_i,\n    rotor_diameter,\n    hub_height,\n    ct_i,\n    tip_speed_ratio,\n    axial_induction_i,\n    wind_shear,\n    scale=1.0,\n):\n    \"\"\"\n    what yaw angle would have produced that same average spanwise velocity\n\n    These calculations focus around the current turbine. The formulation could\n    remove the dimension for n-turbines, but for consistency with other\n    similar equations it is left. However, the turbine dimension should\n    always have length 1.\n    \"\"\"\n\n    # turbine parameters\n    D = rotor_diameter              # scalar\n    HH = hub_height                 # scalar\n    Ct = ct_i                       # (findex, 1, 1, 1) for the current turbine\n    TSR = tip_speed_ratio           # scalar\n    aI = axial_induction_i          # (findex, 1, 1, 1) for the current turbine\n    avg_v = np.mean(v_i, axis=(2,3))  # (findex, 1, grid, grid)\n\n    # flow parameters\n    Uinf = np.mean(u_initial, axis=(1, 2, 3))\n    Uinf = Uinf[:, None, None, None]\n\n    # TODO: Allow user input for eps gain\n    eps_gain = 0.2\n    eps = eps_gain * D  # Use set value\n\n    vel_top = ((HH + D / 2) / HH) ** wind_shear * np.ones((1, 1, 1, 1))\n    Gamma_top = gamma(\n        D,\n        vel_top,\n        Uinf,\n        Ct,\n        scale,\n    )\n\n    vel_bottom = ((HH - D / 2) / HH) ** wind_shear * np.ones((1, 1, 1, 1))\n    Gamma_bottom = -1 * gamma(\n        D,\n        vel_bottom,\n        Uinf,\n        Ct,\n        scale,\n    )\n\n    turbine_average_velocity = np.cbrt(np.mean(u_i ** 3, axis=(2, 3), keepdims=True))\n    Gamma_wake_rotation = 0.25 * 2 * pi * D * (aI - aI ** 2) * turbine_average_velocity / TSR\n\n    ### compute the spanwise and vertical velocities induced by yaw\n\n    # decay = eps ** 2 / (4 * nu * delta_x / Uinf + eps ** 2)   # This is the decay downstream\n    yLocs = delta_y + NUM_EPS\n\n    # top vortex\n    # NOTE: this is the top of the grid, not the top of the rotor\n    zT = z_i - (HH + D / 2) + NUM_EPS  # distance from the top of the grid\n    # NOTE: This is (-) in the paper, but (+) is consistent with the\n    # Martínez-Tossas et al. (2019) source.\n    rT_squared = ne.evaluate(\"yLocs ** 2 + zT ** 2\")\n    # This looks like spanwise decay;\n    # it defines the vortex profile in the spanwise directions\n    core_shape = ne.evaluate(\"1 - exp(-rT_squared / (eps ** 2))\")\n    v_top = ne.evaluate(\"(Gamma_top * zT) / (2 * pi * rT_squared) * core_shape\")\n    v_top = np.mean( v_top, axis=(2,3) )\n    # w_top = (-1 * Gamma_top * yLocs) / (2 * pi * rT) * core_shape * decay\n\n    # bottom vortex\n    zB = z_i - (HH - D / 2) + NUM_EPS\n    rB_squared = ne.evaluate(\"yLocs ** 2 + zB ** 2\")\n    core_shape = ne.evaluate(\"1 - exp(-rB_squared / (eps ** 2))\")\n    v_bottom = ne.evaluate(\"(Gamma_bottom * zB) / (2 * pi * rB_squared) * core_shape\")\n    v_bottom = np.mean( v_bottom, axis=(2,3) )\n    # w_bottom = (-1 * Gamma_bottom * yLocs) / (2 * pi * rB) * core_shape * decay\n\n    # wake rotation vortex\n    zC = z_i - HH + NUM_EPS\n    rC_squared = ne.evaluate(\"yLocs ** 2 + zC ** 2\")\n    core_shape = ne.evaluate(\"1 - exp(-rC_squared / (eps ** 2))\")\n    v_core = ne.evaluate(\"(Gamma_wake_rotation * zC) / (2 * pi * rC_squared) * core_shape\")\n    v_core = np.mean( v_core, axis=(2,3) )\n    # w_core = (-1 * Gamma_wake_rotation * yLocs) / (2 * pi * rC_squared) * core_shape * decay\n\n    # Cap the effective yaw values between -45 and 45 degrees\n    val = 2 * (avg_v - v_core) / (v_top + v_bottom)\n    val = np.where(val < -1.0, -1.0, val)\n    val = np.where(val > 1.0, 1.0, val)\n    y = np.degrees(0.5 * np.arcsin(val))\n\n    return y[:, :, None, None]\n\ndef calculate_transverse_velocity(\n    u_i,\n    u_initial,\n    dudz_initial,\n    delta_x,\n    delta_y,\n    z,\n    rotor_diameter,\n    hub_height,\n    yaw,\n    ct_i,\n    tsr_i,\n    axial_induction_i,\n    wind_shear,\n    scale=1.0,\n):\n    \"\"\"\n    Calculate transverse velocity components for all downstream turbines\n    given the vortices at the current turbine.\n    \"\"\"\n\n    # turbine parameters\n    D = rotor_diameter\n    HH = hub_height\n    Ct = ct_i\n    TSR = tsr_i\n    aI = axial_induction_i\n\n    # flow parameters\n    Uinf = np.mean(u_initial, axis=(1, 2, 3))\n    Uinf = Uinf[:, None, None, None]\n\n    eps_gain = 0.2\n    eps = eps_gain * D  # Use set value\n\n    vel_top = ((HH + D / 2) / HH) ** wind_shear * np.ones((1, 1, 1, 1))\n    Gamma_top = sind(yaw) * cosd(yaw) * gamma(\n        D,\n        vel_top,\n        Uinf,\n        Ct,\n        scale,\n    )\n\n    vel_bottom = ((HH - D / 2) / HH) ** wind_shear * np.ones((1, 1, 1, 1))\n    Gamma_bottom = -1 * sind(yaw) * cosd(yaw) * gamma(\n        D,\n        vel_bottom,\n        Uinf,\n        Ct,\n        scale,\n    )\n    turbine_average_velocity = np.cbrt(np.mean(u_i ** 3, axis=(2,3), keepdims=True))\n    Gamma_wake_rotation = 0.25 * 2 * pi * D * (aI - aI ** 2) * turbine_average_velocity / TSR\n\n    ### compute the spanwise and vertical velocities induced by yaw\n\n    # decay the vortices as they move downstream - using mixing length\n    lmda = D / 8\n    kappa = 0.41\n    lm = kappa * z / (1 + kappa * z / lmda)\n    nu = lm ** 2 * np.abs(dudz_initial)\n\n    # This is the decay downstream\n    decay = ne.evaluate(\"eps ** 2 / (4 * nu * delta_x / Uinf + eps ** 2)\")\n    yLocs = delta_y + NUM_EPS\n\n    # top vortex\n    zT = z - (HH + D / 2) + NUM_EPS\n    # NOTE: This is (-) in the paper, but (+) is consistent with the\n    # Martínez-Tossas et al. (2019) source.\n    rT_squared = ne.evaluate(\"yLocs ** 2 + zT ** 2\")\n    # This looks like spanwise decay;\n    # it defines the vortex profile in the spanwise directions\n    core_shape = ne.evaluate(\"1 - exp(-rT_squared / (eps ** 2))\")\n    V1 = ne.evaluate(\"(Gamma_top * zT) / (2 * pi * rT_squared) * core_shape * decay\")\n    W1 = ne.evaluate(\"(-1 * Gamma_top * yLocs) / (2 * pi * rT_squared) * core_shape * decay\")\n\n    # bottom vortex\n    zB = z - (HH - D / 2) + NUM_EPS\n    rB_squared = ne.evaluate(\"yLocs ** 2 + zB ** 2\")\n    core_shape = ne.evaluate(\"1 - exp(-rB_squared / (eps ** 2))\")\n    V2 = ne.evaluate(\"(Gamma_bottom * zB) / (2 * pi * rB_squared) * core_shape * decay\")\n    W2 = ne.evaluate(\"(-1 * Gamma_bottom * yLocs) / (2 * pi * rB_squared) * core_shape * decay\")\n\n    # wake rotation vortex\n    zC = z - HH + NUM_EPS\n    rC_squared = ne.evaluate(\"yLocs ** 2 + zC ** 2\")\n    core_shape = ne.evaluate(\"1 - exp(-rC_squared / (eps ** 2))\")\n    V5 = ne.evaluate(\"(Gamma_wake_rotation * zC) / (2 * pi * rC_squared) * core_shape * decay\")\n    W5 = ne.evaluate(\n        \"(-1 * Gamma_wake_rotation * yLocs) / (2 * pi * rC_squared) * core_shape * decay\"\n    )\n\n    ### Boundary condition - ground mirror vortex\n\n    # top vortex - ground\n    zTb = z + (HH + D / 2) + NUM_EPS\n    rTb_squared = ne.evaluate(\"yLocs ** 2 + zTb ** 2\")\n    # This looks like spanwise decay;\n    # it defines the vortex profile in the spanwise directions\n    core_shape = ne.evaluate(\"1 - exp(-rTb_squared / (eps ** 2))\")\n    V3 = ne.evaluate(\"(-1 * Gamma_top * zTb) / (2 * pi * rTb_squared) * core_shape * decay\")\n    W3 = ne.evaluate(\"(Gamma_top * yLocs) / (2 * pi * rTb_squared) * core_shape * decay\")\n\n    # bottom vortex - ground\n    zBb = z + (HH - D / 2) + NUM_EPS\n    rBb_squared = ne.evaluate(\"yLocs ** 2 + zBb ** 2\")\n    core_shape = ne.evaluate(\"1 - exp(-rBb_squared / (eps ** 2))\")\n    V4 = ne.evaluate(\"(-1 * Gamma_bottom * zBb) / (2 * pi * rBb_squared) * core_shape * decay\")\n    W4 = ne.evaluate(\"(Gamma_bottom * yLocs) / (2 * pi * rBb_squared) * core_shape * decay\")\n\n    # wake rotation vortex - ground effect\n    zCb = z + HH + NUM_EPS\n    rCb_squared = ne.evaluate(\"yLocs ** 2 + zCb ** 2\")\n    core_shape = ne.evaluate(\"1 - exp(-rCb_squared / (eps ** 2))\")\n    V6 = ne.evaluate(\n        \"(-1 * Gamma_wake_rotation * zCb) / (2 * pi * rCb_squared) * core_shape * decay\"\n    )\n    W6 = ne.evaluate(\n        \"(Gamma_wake_rotation * yLocs) / (2 * pi * rCb_squared) * core_shape * decay\"\n    )\n\n    # total spanwise velocity\n    V = V1 + V2 + V3 + V4 + V5 + V6\n    W = W1 + W2 + W3 + W4 + W5 + W6\n\n    # No spanwise and vertical velocity upstream of the turbine\n    ### Original v3 implementation\n    # V[delta_x < -1] = 0.0  # Subtract by 1 to avoid numerical issues on rotation\n    # W[delta_x < -1] = 0.0  # Subtract by 1 to avoid numerical issues on rotation\n    # TODO Should this be <= ? Shouldn't be adding V and W on the current turbine?\n    ### Then we changed it to this\n    # V[delta_x < 0.0] = 0.0  # Subtract by 1 to avoid numerical issues on rotation\n    # W[delta_x < 0.0] = 0.0  # Subtract by 1 to avoid numerical issues on rotation\n    ### Currently, here\n    V = np.where(delta_x >= 0.0, V, 0.0)\n    W = np.where(delta_x >= 0.0, W, 0.0)\n\n    # TODO: Why would the say W cannot be negative?\n    W = np.where(W >= 0, W, 0.0)\n\n    return V, W\n\ndef yaw_added_turbulence_mixing(\n    u_i,\n    I_i,\n    v_i,\n    w_i,\n    turb_v_i,\n    turb_w_i\n):\n    # Since turbulence mixing is constant for the turbine,\n    # use the left two dimensions only here and expand\n    # before returning. Dimensions are (wd, ws).\n\n    I_i = I_i[:, 0, 0, 0]\n\n    average_u_i = np.cbrt(np.mean(u_i ** 3, axis=(1, 2, 3)))\n\n    # Convert ambient turbulence intensity to TKE (eq 24)\n    k = (average_u_i * I_i) ** 2 / (2 / 3)\n\n    u_term = np.sqrt(2 * k)\n    v_term = np.mean(v_i + turb_v_i, axis=(1, 2, 3))\n    w_term = np.mean(w_i + turb_w_i, axis=(1, 2, 3))\n\n    # Compute the new TKE (eq 23)\n    k_total = 0.5 * (u_term ** 2 + v_term ** 2 + w_term ** 2)\n\n    # Convert TKE back to TI\n    I_total = np.sqrt((2 / 3) * k_total) / average_u_i\n\n    # Remove ambient from total TI leaving only the TI due to mixing\n    I_mixing = I_total - I_i\n\n    return I_mixing[:, None, None, None]\n"
  },
  {
    "path": "floris/core/wake_deflection/jimenez.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.utilities import cosd, sind\n\n\n@define\nclass JimenezVelocityDeflection(BaseModel):\n    \"\"\"\n    Jiménez wake deflection model, derived from\n    :cite:`jdm-jimenez2010application`.\n\n    References:\n        .. bibliography:: /references.bib\n            :style: unsrt\n            :filter: docname in docnames\n            :keyprefix: jdm-\n    \"\"\"\n\n    kd: float = field(default=0.05)\n    ad: float = field(default=0.0)\n    bd: float = field(default=0.0)\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n\n        kwargs = {\n            \"x\": grid.x_sorted,\n        }\n        return kwargs\n\n    # @profile\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        yaw_i: np.ndarray,\n        turbulence_intensity_i: np.ndarray,\n        ct_i: np.ndarray,\n        rotor_diameter_i: np.ndarray,\n        *,\n        x: np.ndarray,\n    ):\n        \"\"\"\n        Calculates the deflection field of the wake in relation to the yaw of\n        the turbine. This is coded as defined in [1].\n\n        Args:\n            x_locations (np.array): streamwise locations in wake\n            y_locations (np.array): spanwise locations in wake\n            z_locations (np.array): vertical locations in wake\n                (not used in Jiménez)\n            turbine (:py:class:`floris.core.turbine.Turbine`):\n                Turbine object\n            coord\n                (:py:meth:`floris.core.turbine_map.TurbineMap.coords`):\n                Spatial coordinates of wind turbine.\n            flow_field\n                (:py:class:`floris.core.flow_field.FlowField`):\n                Flow field object.\n\n        Returns:\n            deflection (np.array): Deflected wake centerline.\n\n\n        This function calculates the deflection of the entire flow field\n        given the yaw angle and Ct of the current turbine\n        \"\"\"\n\n        # NOTE: Its important to remember the rules of broadcasting here.\n        # An operation between two np.arrays of different sizes involves\n        # broadcasting. First, the rank and then the dimensions are compared.\n        # If the ranks are different, new dimensions of size 1 are added to\n        # the missing dimensions. Then, arrays can be combined (arithmetic)\n        # if corresponding dimensions are either the same size or 1.\n        # https://numpy.org/doc/stable/user/basics.broadcasting.html\n        # Here, many dimensions are 1, but these are essentially treated\n        # as a scalar value for that dimension.\n\n        # angle of deflection\n        xi_init = cosd(yaw_i) * sind(yaw_i) * ct_i / 2.0\n\n        \"\"\"\n        delta_x = x - x_i\n\n        # yaw displacement\n        A = 15 * (2 * self.kd * delta_x / rotor_diameter_i + 1) ** 4.0 + xi_init ** 2.0\n        B = (30 * self.kd / rotor_diameter_i)\n        B *= ( 2 * self.kd * delta_x / rotor_diameter_i + 1 ) ** 5.0\n        C = xi_init * rotor_diameter_i * (15 + xi_init ** 2.0)\n        D = 30 * self.kd\n\n        yYaw_init = (xi_init * A / B) - (C / D)\n\n        # corrected yaw displacement with lateral offset\n        # This has the same shape as the grid\n\n        deflection = yYaw_init + self.ad + self.bd * delta_x\n        \"\"\"\n\n        # Numexpr - do not change below without corresponding changes above.\n        kd = self.kd\n        ad = self.ad\n        bd = self.bd\n\n        delta_x = ne.evaluate(\"x - x_i\")\n        A = ne.evaluate(\"15 * (2 * kd * delta_x / rotor_diameter_i + 1) ** 4.0 + xi_init ** 2.0\")\n        B = ne.evaluate(\"(30 * kd / rotor_diameter_i)\")\n        B = ne.evaluate(\"B * ( 2 * kd * delta_x / rotor_diameter_i + 1 ) ** 5.0\")\n        C = ne.evaluate(\"xi_init * rotor_diameter_i * (15 + xi_init ** 2.0)\")\n        D = ne.evaluate(\"30 * kd\")\n\n        yYaw_init = ne.evaluate(\"(xi_init * A / B) - (C / D)\")\n        deflection = ne.evaluate(\"yYaw_init + ad + bd * delta_x\")\n\n        return deflection\n"
  },
  {
    "path": "floris/core/wake_deflection/none.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define\n\nfrom floris.core import (\n    BaseModel,\n    FlowField,\n    Grid,\n)\n\n\n@define\nclass NoneVelocityDeflection(BaseModel):\n    \"\"\"\n    The None deflection model is a placeholder code that simple ignores any\n    deflection and returns an array of zeroes.\n    \"\"\"\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n\n        kwargs = {\n            \"freestream_velocity\": flow_field.u_initial_sorted,\n        }\n        return kwargs\n\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        yaw_i: np.ndarray,\n        turbulence_intensity_i: np.ndarray,\n        ct_i: np.ndarray,\n        rotor_diameter_i: float,\n        *,\n        freestream_velocity: np.ndarray,\n    ):\n        \"\"\"Skip all deflection calculations and returns zeros array.\"\"\"\n        self.logger.info(\n            \"The wake deflection model is set to 'none'. Deflection modeling disabled.\"\n        )\n        if np.any(np.abs(yaw_i) > 0.001):\n            raise ValueError(\n                \"The deflection model is disabled yet not all effective yaw angles are zero. \" +\n                \"To resolve this error, please ensure secondary steering is disabled in your \" +\n                \"input file and ensure no nonzero yaw angles are passed to the floris object.\"\n            )\n\n        return np.zeros_like(freestream_velocity)\n"
  },
  {
    "path": "floris/core/wake_turbulence/__init__.py",
    "content": "\nfrom floris.core.wake_turbulence.crespo_hernandez import CrespoHernandez\nfrom floris.core.wake_turbulence.none import NoneWakeTurbulence\nfrom floris.core.wake_turbulence.wake_induced_mixing import WakeInducedMixing\n"
  },
  {
    "path": "floris/core/wake_turbulence/crespo_hernandez.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.utilities import cosd, sind\n\n\n@define\nclass CrespoHernandez(BaseModel):\n    \"\"\"\n    CrespoHernandez is a wake-turbulence model that is used to compute\n    additional variability introduced to the flow field by operation of a wind\n    turbine. Implementation of the model follows the original formulation and\n    limitations outlined in :cite:`cht-crespo1996turbulence`.\n\n    Note: The values for default parameters provided here differ from those in\n    :cite:`cht-crespo1996turbulence. Following their recommendations, the\n    default parameters would instead be:\n        - initial: -0.0325*\n        - constant: 0.73\n        - ai: 0.8325\n        - downstream: -0.32\n    * The \"initial\" parameter is given as -0.0325 in :cite:`cht-crespo1996turbulence`,\n    but the negative exponent is not clear in the scans of the paper found on the internet,\n    and several subsequent paper cite the exponent as positive (0.0325). This discrepancy\n    is noted in :cite:`zehtabiyan_rezaie_CH_2023`. Moreover, :cite:`zehtabiyan_rezaie_CH_2023`\n    argues that positive values for this exponent are not representative of the physical\n    phenomena occurring. For more details, see https://github.com/NREL/floris/issues/773.\n    Nonetheless, the default value here is set to 0.1 for consistency with previous\n    FLORIS versions. The default value may be updated in a future release.\n\n    Args:\n        parameter_dictionary (dict): Model-specific parameters.\n            Default values are used when a parameter is not included\n            in `parameter_dictionary`. Possible key-value pairs include:\n\n            -   **initial** (*float*): The exponent on the initial ambient\n                turbulence intensity.\n            -   **constant** (*float*): The constant used to scale the\n                wake-added turbulence intensity.\n            -   **ai** (*float*): The axial induction factor exponent used\n                in in the calculation of wake-added turbulence.\n            -   **downstream** (*float*): The exponent applied to the\n                distance downstream of an upstream turbine normalized by\n                the rotor diameter used in the calculation of wake-added\n                turbulence.\n\n    References:\n        .. bibliography:: /references.bib\n            :style: unsrt\n            :filter: docname in docnames\n            :keyprefix: cht-\n    \"\"\"\n\n    initial: float = field(converter=float, default=0.1)\n    constant: float = field(converter=float, default=0.9)\n    ai: float = field(converter=float, default=0.8)\n    downstream: float = field(converter=float, default=-0.32)\n\n    def prepare_function(self) -> dict:\n        pass\n\n    def function(\n        self,\n        ambient_TI: float,\n        x: np.ndarray,\n        x_i: np.ndarray,\n        rotor_diameter: float,\n        axial_induction: np.ndarray,\n    ) -> None:\n        # Replace zeros and negatives with 1 to prevent nans/infs\n        delta_x = x - x_i\n\n        # TODO: ensure that these fudge factors are needed for different rotations\n        upstream_mask = delta_x <= 0.1\n        downstream_mask = delta_x > -0.1\n\n        #        Keep downstream components          Set upstream to 1.0\n        delta_x = delta_x * downstream_mask + np.ones_like(delta_x) * upstream_mask\n\n        # turbulence intensity calculation based on Crespo et. al.\n        constant = self.constant\n        ai = self.ai\n        initial = self.initial\n        downstream = self.downstream\n        ti = ne.evaluate(\n            \"constant\"\n            \" * axial_induction ** ai\"\n            \" * ambient_TI ** initial\"\n            \" * (delta_x / rotor_diameter) ** downstream\"\n        )\n        # Mask the 1 values from above with zeros\n        return ti * downstream_mask\n"
  },
  {
    "path": "floris/core/wake_turbulence/none.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import BaseModel\n\n\n@define\nclass NoneWakeTurbulence(BaseModel):\n    \"\"\"\n    The None wake turbulence model is a placeholder code that simple ignores\n    any wake turbulence and just returns an array of the ambient TIs.\n    \"\"\"\n\n    def prepare_function(self) -> dict:\n        pass\n\n    def function(\n        self,\n        ambient_TI: float,\n        x: np.ndarray,\n        x_i: np.ndarray,\n        rotor_diameter: float,\n        axial_induction: np.ndarray,\n    ) -> None:\n        \"\"\"Return unchanged field of turbulence intensities\"\"\"\n        self.logger.info(\n            \"The wake-turbulence model is set to 'none'. Turbulence model disabled.\"\n        )\n        return np.zeros_like(x)\n"
  },
  {
    "path": "floris/core/wake_turbulence/wake_induced_mixing.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.utilities import cosd, sind\n\n\n@define\nclass WakeInducedMixing(BaseModel):\n    \"\"\"\n    WakeInducedMixing is a model used to generalize wake-added turbulence\n    in the Empirical Gaussian wake model. It computes the contribution of each\n    turbine to a \"wake-induced mixing\" term that in turn is used in the\n    velocity deficit and deflection models.\n\n    Args:\n        parameter_dictionary (dict): Model-specific parameters.\n            Default values are used when a parameter is not included\n            in `parameter_dictionary`. Possible key-value pairs include:\n\n            -   **atmospheric_ti_gain** (*float*): The contribution of ambient\n                turbulent intensity to the wake-induced mixing term. Currently\n                throws a warning if nonzero.\n\n    References:\n        .. bibliography:: /references.bib\n            :style: unsrt\n            :filter: docname in docnames\n    \"\"\"\n    atmospheric_ti_gain: float = field(converter=float, default=0.0)\n\n    def __attrs_post_init__(self) -> None:\n        if self.atmospheric_ti_gain != 0.0:\n            nonzero_err_msg = \\\n                \"Running wake_induced_mixing model with mixing contributions\"+\\\n                \" from the atmospheric turbulence intensity has not been\"+\\\n                \" vetted. To avoid this warning, set atmospheric_ti_gain=0.\"+\\\n                \" in the FLORIS input yaml.\"\n            self.logger.warning(nonzero_err_msg, stack_info=True)\n\n    def prepare_function(self) -> dict:\n        pass\n\n    def function(\n        self,\n        axial_induction_i: np.ndarray,\n        downstream_distance_D_i: np.ndarray,\n    ) -> None:\n        \"\"\"\n        Calculates the contribution of turbine i to all other turbines'\n        mixing terms.\n\n        Args:\n            axial_induction_i (np.array): Axial induction factor of\n                the ith turbine (-).\n            downstream_distance_D_i (np.array): The distance downstream\n                from turbine i to all other turbines (specified in terms\n                of multiples of turbine i's rotor diameter) (D).\n\n        Returns:\n            np.array: Components of the wake-induced mixing term due to\n                the ith turbine.\n        \"\"\"\n\n        wake_induced_mixing = axial_induction_i[:,:,0,0] / downstream_distance_D_i**2\n\n        return wake_induced_mixing\n"
  },
  {
    "path": "floris/core/wake_velocity/__init__.py",
    "content": "\nfrom floris.core.wake_velocity.cumulative_gauss_curl import CumulativeGaussCurlVelocityDeficit\nfrom floris.core.wake_velocity.empirical_gauss import EmpiricalGaussVelocityDeficit\nfrom floris.core.wake_velocity.gauss import GaussVelocityDeficit\nfrom floris.core.wake_velocity.jensen import JensenVelocityDeficit\nfrom floris.core.wake_velocity.none import NoneVelocityDeficit\nfrom floris.core.wake_velocity.turbopark import TurbOParkVelocityDeficit\nfrom floris.core.wake_velocity.turboparkgauss import TurboparkgaussVelocityDeficit\n"
  },
  {
    "path": "floris/core/wake_velocity/cumulative_gauss_curl.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\nfrom scipy.special import gamma\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.utilities import (\n    cosd,\n    sind,\n    tand,\n)\n\n\n@define\nclass CumulativeGaussCurlVelocityDeficit(BaseModel):\n    \"\"\"\n    The cumulative curl model is an implementation of the model described in\n    :cite:`cc-bay_2022`, which itself is based on the cumulative model of\n    :cite:`cc-bastankhah_2021`.\n\n    References:\n        .. bibliography:: /references.bib\n            :style: unsrt\n            :filter: docname in docnames\n            :keyprefix: cc-\n    \"\"\"\n\n    a_s: float = field(default=0.179367259)\n    b_s: float = field(default=0.0118889215)\n    c_s1: float = field(default=0.0563691592)\n    c_s2: float = field(default=0.13290157)\n    a_f: float = field(default=3.11)\n    b_f: float = field(default=-0.68)\n    c_f: float = field(default=2.41)\n    alpha_mod: float = field(default=1.0)\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n\n        kwargs = {\n            \"x\": grid.x_sorted,\n            \"y\": grid.y_sorted,\n            \"z\": grid.z_sorted,\n            \"u_initial\": flow_field.u_initial_sorted,\n        }\n        return kwargs\n\n    def function(\n        self,\n        ii: int,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        z_i: np.ndarray,\n        u_i: np.ndarray,\n        deflection_field: np.ndarray,\n        yaw_i: np.ndarray,\n        turbulence_intensity: np.ndarray,\n        ct: np.ndarray,\n        turbine_diameter: np.ndarray,\n        turb_u_wake: np.ndarray,\n        Ctmp: np.ndarray,\n        # enforces the use of the below as keyword arguments and adherence to the\n        # unpacking of the results from prepare_function()\n        *,\n        x: np.ndarray,\n        y: np.ndarray,\n        z: np.ndarray,\n        u_initial: np.ndarray,\n    ) -> None:\n\n        turbine_Ct = ct\n        turbine_ti = turbulence_intensity\n        turbine_yaw = yaw_i\n\n        # TODO Should this be cbrt? This is done to match v2\n        turb_avg_vels = np.cbrt(np.mean(u_i ** 3, axis=(2, 3), keepdims=True))\n\n        delta_x = x - x_i\n\n        sigma_n = wake_expansion(\n            delta_x,\n            turbine_Ct[:, ii:ii+1],\n            turbine_ti[:, ii:ii+1],\n            turbine_diameter[:, ii:ii+1],\n            self.a_s,\n            self.b_s,\n            self.c_s1,\n            self.c_s2,\n        )\n\n        y_i_loc = np.mean(y_i, axis=(2, 3), keepdims=True)\n        z_i_loc = np.mean(z_i, axis=(2, 3), keepdims=True)\n\n        x_coord = np.mean(x, axis=(2, 3), keepdims=True)\n\n        y_loc = y\n        y_coord = np.mean(y, axis=(2, 3), keepdims=True)\n\n        z_loc = z  # np.mean(z, axis=(3,4))\n        z_coord = np.mean(z, axis=(2, 3), keepdims=True)\n\n        sum_lbda = np.zeros_like(u_initial)\n\n        for m in range(0, ii - 1):\n            x_coord_m = x_coord[:, m:m+1]\n            y_coord_m = y_coord[:, m:m+1]\n            z_coord_m = z_coord[:, m:m+1]\n\n            # For computing cross planes, we don't need to compute downstream\n            # turbines from out cross plane position.\n            if x_coord[:, m:m+1].size == 0:\n                break\n\n            delta_x_m = x - x_coord_m\n\n            sigma_i = wake_expansion(\n                delta_x_m,\n                turbine_Ct[:, m:m+1],\n                turbine_ti[:, m:m+1],\n                turbine_diameter[:, m:m+1],\n                self.a_s,\n                self.b_s,\n                self.c_s1,\n                self.c_s2,\n            )\n\n            S_i = sigma_n ** 2 + sigma_i ** 2\n\n            Y_i = (y_i_loc - y_coord_m - deflection_field) ** 2 / (2 * S_i)\n            Z_i = (z_i_loc - z_coord_m) ** 2 / (2 * S_i)\n\n            lbda = 1.0 * sigma_i ** 2 / S_i * np.exp(-Y_i) * np.exp(-Z_i)\n\n            sum_lbda = sum_lbda + lbda * (Ctmp[m] / u_initial)\n\n        # Vectorized version of sum_lbda calc; has issues with y_coord (needs to be\n        # down-selected appropriately. Prelim. timings show vectorized form takes\n        # longer than for loop.)\n        # if ii >= 2:\n        #     S = sigma_n ** 2 + sigma_i[0:ii-1, :, :, :, :, :] ** 2\n        #     Y = (y_i_loc - y_coord - deflection_field) ** 2 / (2 * S)\n        #     Z = (z_i_loc - z_coord) ** 2 / (2 * S)\n\n        #     lbda = self.alpha_mod * sigma_i[0:ii-1, :, :, :, :, :] ** 2\n        #     lbda /= S * np.exp(-Y) * np.exp(-Z)\n        #     sum_lbda = np.sum(lbda * (Ctmp[0:ii-1, :, :, :, :, :] / u_initial), axis=0)\n        # else:\n        #     sum_lbda = 0.0\n\n        # sigma_i[ii] = sigma_n\n\n        # blondel\n        # super gaussian\n        # b_f = self.b_f1 * np.exp(self.b_f2 * TI) + self.b_f3\n        x_tilde = np.abs(delta_x) / turbine_diameter[:,ii:ii+1]\n        r_tilde = np.sqrt( (y_loc - y_i_loc - deflection_field) ** 2 + (z_loc - z_i_loc) ** 2 )\n        r_tilde /= turbine_diameter[:,ii:ii+1]\n\n        n = self.a_f * np.exp(self.b_f * x_tilde) + self.c_f\n        a1 = 2 ** (2 / n - 1)\n        a2 = 2 ** (4 / n - 2)\n\n        # based on Blondel model, modified to include cumulative effects\n        tmp = a2 - (\n            (n * turbine_Ct[:, ii:ii+1])\n            * cosd(turbine_yaw)\n            / (\n                16.0\n                * gamma(2 / n)\n                * np.sign(sigma_n)\n                * (np.abs(sigma_n) ** (4 / n))\n                * (1 - sum_lbda) ** 2\n            )\n        )\n\n        # for some low wind speeds, tmp can become slightly negative, which causes NANs,\n        # so replace the slightly negative values with zeros\n        tmp = tmp * (tmp >= 0)\n\n        C = a1 - np.sqrt(tmp)\n\n        C = C * (1 - sum_lbda)\n\n        Ctmp[ii] = C\n\n        yR = y_loc - y_i_loc\n        xR = yR * tand(turbine_yaw) + x_i\n\n        # add turbines together\n        velDef = C * np.exp((-1 * r_tilde ** n) / (2 * sigma_n ** 2))\n\n        velDef = velDef * (x - xR >= 0.1)\n\n        turb_u_wake = turb_u_wake + turb_avg_vels * velDef\n        return (turb_u_wake, Ctmp)\n\n\ndef wake_expansion(\n    delta_x,\n    ct_i,\n    turbulence_intensity_i,\n    rotor_diameter,\n    a_s,\n    b_s,\n    c_s1,\n    c_s2,\n):\n    # Calculate Beta (Eq 10, pp 5 of ref. [1] and table 4 of ref. [2] in docstring)\n    beta = 0.5 * (1.0 + np.sqrt(1.0 - ct_i)) / np.sqrt(1.0 - ct_i)\n    k = a_s * turbulence_intensity_i + b_s\n    eps = (c_s1 * ct_i + c_s2) * np.sqrt(beta)\n\n    # Calculate sigma_tilde (Eq 9, pp 5 of ref. [1] and table 4 of ref. [2] in docstring)\n    x_tilde = np.abs(delta_x) / rotor_diameter\n    sigma_y = k * x_tilde + eps\n\n    # [added dimension to get upstream values, empty, wd, ws, x, y, z  ]\n    # return sigma_y[na, :, :, :, :, :, :]\n    # Do this ^^ in the main function\n\n    return sigma_y\n"
  },
  {
    "path": "floris/core/wake_velocity/empirical_gauss.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.core.wake_velocity.gauss import gaussian_function\nfrom floris.type_dec import floris_float_type\nfrom floris.utilities import (\n    cosd,\n    sind,\n    tand,\n)\n\n\n@define\nclass EmpiricalGaussVelocityDeficit(BaseModel):\n    \"\"\"\n    The Empirical Gauss velocity model has a Gaussian profile\n    (see :cite:`bastankhah2016experimental` and\n    :cite:`King2019Controls`) throughout and expands in a (smoothed)\n    piecewise linear fashion.\n\n    parameter_dictionary (dict): Model-specific parameters.\n        Default values are used when a parameter is not included\n        in `parameter_dictionary`. Possible key-value pairs include:\n\n            -   **wake_expansion_rates** (*list*): List of expansion\n                rates for the Gaussian wake width. Must be of length 1\n                or greater.\n            -   **breakpoints_D** (*list*): List of downstream\n                locations, specified in terms of rotor diameters, where\n                the expansion rates go into effect. Must be one element\n                shorter than wake_expansion_rates. May be empty.\n            -   **sigma_0_D** (*float*): Initial width of the Gaussian\n                wake at the turbine location, specified as a multiplier\n                of the rotor diameter.\n            -   **smoothing_length_D** (*float*): Distance over which\n                the corners in the piece-wise linear wake expansion rate\n                are smoothed (specified as a multiplier of the rotor\n                diameter).\n            -   **mixing_gain_deflection** (*float*): Gain to set the\n                increase in wake expansion due to wake-induced mixing.\n\n    References:\n        .. bibliography:: /references.bib\n            :style: unsrt\n            :filter: docname in docnames\n    \"\"\"\n    wake_expansion_rates: list = field(factory=lambda: [0.023, 0.008])\n    breakpoints_D: list = field(factory=lambda: [10])\n    sigma_0_D: float = field(default=0.28)\n    smoothing_length_D: float = field(default=2.0)\n    mixing_gain_velocity: float = field(default=2.0)\n    awc_mode: str = field(default=\"baseline\")\n    awc_wake_exp: float = field(default=1.2)\n    awc_wake_denominator: float = field(default=400)\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n\n        kwargs = {\n            \"x\": grid.x_sorted,\n            \"y\": grid.y_sorted,\n            \"z\": grid.z_sorted,\n            \"wind_veer\": flow_field.wind_veer\n        }\n        return kwargs\n\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        z_i: np.ndarray,\n        axial_induction_i: np.ndarray,\n        deflection_field_y_i: np.ndarray,\n        deflection_field_z_i: np.ndarray,\n        yaw_angle_i: np.ndarray,\n        tilt_angle_i: np.ndarray,\n        mixing_i: np.ndarray,\n        ct_i: np.ndarray,\n        hub_height_i: float,\n        rotor_diameter_i: np.ndarray,\n        # enforces the use of the below as keyword arguments and adherence to the\n        # unpacking of the results from prepare_function()\n        *,\n        x: np.ndarray,\n        y: np.ndarray,\n        z: np.ndarray,\n        wind_veer: float\n    ) -> None:\n        \"\"\"\n        Calculates the velocity deficits in the wake.\n\n        Args:\n            x_i (np.array): Streamwise direction grid coordinates of\n                the ith turbine (m).\n            y_i (np.array): Cross stream direction grid coordinates of\n                the ith turbine (m).\n            z_i (np.array): Vertical direction grid coordinates of\n                the ith turbine (m) [not used].\n            axial_induction_i (np.array): Axial induction factor of the\n                ith turbine (-) [not used].\n            deflection_field_y_i (np.array): Horizontal wake deflections\n                due to the ith turbine's yaw misalignment (m).\n            deflection_field_z_i (np.array): Vertical wake deflections\n                due to the ith turbine's tilt angle (m).\n            yaw_angle_i (np.array): Yaw angle of the ith turbine (deg).\n            tilt_angle_i (np.array): Tilt angle of the ith turbine\n                (deg).\n            mixing_i (np.array): The wake-induced mixing term for the\n                ith turbine.\n            ct_i (np.array): Thrust coefficient for the ith turbine (-).\n            hub_height_i (float): Hub height for the ith turbine (m).\n            rotor_diameter_i (np.array): Rotor diameter for the ith\n                turbine (m).\n\n            x (np.array): Streamwise direction grid coordinates of the\n                flow field domain (m).\n            y (np.array): Cross stream direction grid coordinates of the\n                flow field domain (m).\n            z (np.array): Vertical direction grid coordinates of the\n                flow field domain (m).\n            wind_veer (np.array): Wind veer (deg).\n\n        Returns:\n            np.array: Velocity deficits (-).\n        \"\"\"\n\n        include_mirror_wake = True # Could add this as a user preference.\n\n        # Only symmetric terms using yaw, but keep for consistency\n        yaw_angle = -1 * yaw_angle_i\n\n        # Initial wake widths\n        sigma_y0 = self.sigma_0_D * rotor_diameter_i * cosd(yaw_angle)\n        sigma_z0 = self.sigma_0_D * rotor_diameter_i * cosd(tilt_angle_i)\n\n        # No specific near, far wakes in this model\n        downstream_mask = (x > x_i + 0.1)\n        upstream_mask = (x < x_i - 0.1)\n\n        # Wake expansion in the lateral (y) and the vertical (z)\n        # TODO: could compute shared components in sigma_z, sigma_y\n        # with one function call.\n        sigma_y = empirical_gauss_model_wake_width(\n            x - x_i,\n            self.wake_expansion_rates,\n            [b * rotor_diameter_i for b in self.breakpoints_D], # .flatten()[0]\n            sigma_y0,\n            self.smoothing_length_D * rotor_diameter_i,\n            self.mixing_gain_velocity * mixing_i,\n        )\n        sigma_y[upstream_mask] = \\\n            np.tile(sigma_y0, np.shape(sigma_y)[1:])[upstream_mask]\n\n        sigma_z = empirical_gauss_model_wake_width(\n            x - x_i,\n            self.wake_expansion_rates,\n            [b * rotor_diameter_i for b in self.breakpoints_D], # .flatten()[0]\n            sigma_z0,\n            self.smoothing_length_D * rotor_diameter_i,\n            self.mixing_gain_velocity * mixing_i,\n        )\n        sigma_z[upstream_mask] = \\\n            np.tile(sigma_z0, np.shape(sigma_z)[1:])[upstream_mask]\n\n        # 'Standard' wake component\n        r, C = rCalt(\n            wind_veer,\n            sigma_y,\n            sigma_z,\n            y,\n            y_i,\n            deflection_field_y_i,\n            deflection_field_z_i,\n            z,\n            hub_height_i,\n            ct_i,\n            yaw_angle,\n            tilt_angle_i,\n            rotor_diameter_i,\n            sigma_y0,\n            sigma_z0\n        )\n        # Normalize to match end of actuator disk model tube\n        C = C / (8 * self.sigma_0_D**2 )\n\n        wake_deficit = gaussian_function(C, r, 1, np.sqrt(0.5))\n\n        if include_mirror_wake:\n            # TODO: speed up this option by calculating various elements in\n            #       rCalt only once.\n            # Mirror component\n            r_mirr, C_mirr = rCalt(\n                wind_veer, # TODO: Is veer OK with mirror wakes?\n                sigma_y,\n                sigma_z,\n                y,\n                y_i,\n                deflection_field_y_i,\n                deflection_field_z_i,\n                z,\n                -hub_height_i, # Turbine at negative hub height location\n                ct_i,\n                yaw_angle,\n                tilt_angle_i,\n                rotor_diameter_i,\n                sigma_y0,\n                sigma_z0\n            )\n            # Normalize to match end of actuator disk model tube\n            C_mirr = C_mirr / (8 * self.sigma_0_D**2)\n\n            # ASSUME sum-of-squares superposition for the real and mirror wakes\n            wake_deficit = np.sqrt(\n                wake_deficit**2 +\n                gaussian_function(C_mirr, r_mirr, 1, np.sqrt(0.5))**2\n            )\n\n        velocity_deficit = wake_deficit * downstream_mask\n\n        return velocity_deficit\n\ndef rCalt(wind_veer, sigma_y, sigma_z, y, y_i, delta_y, delta_z, z, HH, Ct,\n    yaw, tilt, D, sigma_y0, sigma_z0):\n\n    ## Numexpr\n    wind_veer = np.deg2rad(wind_veer)\n    a = ne.evaluate(\n        \"cos(wind_veer) ** 2 / (2 * sigma_y ** 2) + sin(wind_veer) ** 2 / (2 * sigma_z ** 2)\"\n    )\n    b = ne.evaluate(\n        \"-sin(2 * wind_veer) / (4 * sigma_y ** 2) + sin(2 * wind_veer) / (4 * sigma_z ** 2)\"\n    )\n    c = ne.evaluate(\n        \"sin(wind_veer) ** 2 / (2 * sigma_y ** 2) + cos(wind_veer) ** 2 / (2 * sigma_z ** 2)\"\n    )\n    r = ne.evaluate(\n        \"a * ( (y - y_i - delta_y) ** 2) - \"+\\\n        \"2 * b * (y - y_i - delta_y) * (z - HH - delta_z) + \"+\\\n        \"c * ((z - HH - delta_z) ** 2)\"\n    )\n    d = 1 - Ct * (sigma_y0 * sigma_z0)/(sigma_y * sigma_z) * cosd(yaw) * cosd(tilt)\n    C = ne.evaluate(\"1 - sqrt(d)\")\n    return r, C\n\ndef sigmoid_integral(x, center=0, width=1):\n    y = np.zeros_like(x)\n    # TODO: Can this be made faster?\n    above_smoothing_zone = (x-center) > width/2\n    y[above_smoothing_zone] = (x-center)[above_smoothing_zone]\n    in_smoothing_zone = ((x-center) >= -width/2) & ((x-center) <= width/2)\n    z = ((x-center)/width + 0.5)[in_smoothing_zone]\n    if width.shape[0] > 1: # multiple turbine sizes\n        width = np.broadcast_to(width, x.shape)[in_smoothing_zone]\n    y[in_smoothing_zone] = (width*(z**6 - 3*z**5 + 5/2*z**4)).flatten()\n    return y\n\ndef empirical_gauss_model_wake_width(\n    x,\n    wake_expansion_rates,\n    breakpoints,\n    sigma_0,\n    smoothing_length,\n    mixing_final,\n    ):\n    assert len(wake_expansion_rates) == len(breakpoints) + 1, \\\n        \"Invalid combination of wake_expansion_rates and breakpoints.\"\n\n    sigma = (wake_expansion_rates[0] + mixing_final) * x + sigma_0\n    for ib, b in enumerate(breakpoints):\n        sigma += (wake_expansion_rates[ib+1] - wake_expansion_rates[ib]) * \\\n            sigmoid_integral(x, center=b, width=smoothing_length)\n\n    return sigma\n\ndef awc_added_wake_mixing(\n    awc_mode_i,\n    awc_amplitude_i,\n    awc_frequency_i,\n    awc_wake_exp,\n    awc_wake_denominator\n):\n    # Drop surplus (grid) dimensions\n    awc_amplitude_i = awc_amplitude_i[:,:,0,0]\n    awc_mode_i = awc_mode_i[:,:,0,0]\n\n    # TODO: Add TI in the mix, finetune amplitude/freq effect\n    awc_mixing_factor = np.zeros_like(awc_amplitude_i, dtype=floris_float_type)\n    helix_mask = awc_mode_i == 'helix'\n\n    awc_mixing_factor[helix_mask] = (\n        awc_amplitude_i[helix_mask]**awc_wake_exp/awc_wake_denominator\n    )\n\n    return awc_mixing_factor\n"
  },
  {
    "path": "floris/core/wake_velocity/gauss.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.utilities import (\n    cosd,\n    sind,\n    tand,\n)\n\n\n@define\nclass GaussVelocityDeficit(BaseModel):\n\n    alpha: float = field(default=0.58)\n    beta: float = field(default=0.077)\n    ka: float = field(default=0.38)\n    kb: float = field(default=0.004)\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n\n        kwargs = {\n            \"x\": grid.x_sorted,\n            \"y\": grid.y_sorted,\n            \"z\": grid.z_sorted,\n            \"u_initial\": flow_field.u_initial_sorted,\n            \"wind_veer\": flow_field.wind_veer\n        }\n        return kwargs\n\n    # @profile\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        z_i: np.ndarray,\n        axial_induction_i: np.ndarray,\n        deflection_field_i: np.ndarray,\n        yaw_angle_i: np.ndarray,\n        turbulence_intensity_i: np.ndarray,\n        ct_i: np.ndarray,\n        hub_height_i: float,\n        rotor_diameter_i: np.ndarray,\n        # enforces the use of the below as keyword arguments and adherence to the\n        # unpacking of the results from prepare_function()\n        *,\n        x: np.ndarray,\n        y: np.ndarray,\n        z: np.ndarray,\n        u_initial: np.ndarray,\n        wind_veer: float,\n    ) -> None:\n\n        # yaw_angle is all turbine yaw angles for each wind speed\n        # Extract and broadcast only the current turbine yaw setting\n        # for all wind speeds\n\n        # Opposite sign convention in this model\n        yaw_angle = -1 * yaw_angle_i\n\n        # Initialize the velocity deficit\n        uR = u_initial * ct_i / (2.0 * (1 - np.sqrt(1 - ct_i)))\n        u0 = u_initial * np.sqrt(1 - ct_i)\n\n        # Initial lateral bounds\n        sigma_z0 = rotor_diameter_i * 0.5 * np.sqrt(uR / (u_initial + u0))\n        sigma_y0 = sigma_z0 * cosd(yaw_angle) * cosd(wind_veer)\n\n        # Compute the bounds of the near and far wake regions and a mask\n\n        # Start of the near wake\n        xR = x_i\n\n        # Start of the far wake\n        x0 = np.ones_like(u_initial)\n        x0 *= rotor_diameter_i * cosd(yaw_angle) * (1 + np.sqrt(1 - ct_i) )\n        x0 /= np.sqrt(2) * (\n            4 * self.alpha * turbulence_intensity_i + 2 * self.beta * (1 - np.sqrt(1 - ct_i) )\n        )\n        x0 += x_i\n\n        # Initialize the velocity deficit array\n        velocity_deficit = np.zeros_like(u_initial)\n\n        # Masks\n        # When we have only an inequality, the current turbine may be applied its own\n        # wake in cases where numerical precision cause in incorrect comparison. We've\n        # applied a small bump to avoid this. \"0.1\" is arbitrary but it is a small, non\n        # zero value.\n\n        # This mask defines the near wake; keeps the areas downstream of xR and upstream of x0\n        near_wake_mask = (x > xR + 0.1) * (x < x0)\n        far_wake_mask = (x >= x0)\n\n        # Compute the velocity deficit in the NEAR WAKE region\n        # ONLY If there are points within the near wake boundary\n        # TODO: for the TurbineGrid, do we need to do this near wake calculation at all?\n        #       same question for any grid with a resolution larger than the near wake region\n        if np.sum(near_wake_mask):\n\n            # Calculate the wake expansion\n\n            # This is a linear ramp from 0 to 1 from the start of the near wake to the start\n            # of the far wake.\n            near_wake_ramp_up = (x - xR) / (x0 - xR)\n            # Another linear ramp, but positive upstream of the far wake and negative in the\n            # far wake; 0 at the start of the far wake\n            near_wake_ramp_down = (x0 - x) / (x0 - xR)\n            # near_wake_ramp_down = -1 * (near_wake_ramp_up - 1)  # : this is equivalent, right?\n\n            sigma_y = near_wake_ramp_down * 0.501 * rotor_diameter_i * np.sqrt(ct_i / 2.0)\n            sigma_y += near_wake_ramp_up * sigma_y0\n            sigma_y *= (x >= xR)\n            sigma_y += np.ones_like(sigma_y) * (x < xR) * 0.5 * rotor_diameter_i\n\n            sigma_z = near_wake_ramp_down * 0.501 * rotor_diameter_i * np.sqrt(ct_i / 2.0)\n            sigma_z += near_wake_ramp_up * sigma_z0\n            sigma_z *= (x >= xR)\n            sigma_z += np.ones_like(sigma_z) * (x < xR) * 0.5 * rotor_diameter_i\n\n            r_squared, C = rC(\n                wind_veer,\n                sigma_y,\n                sigma_z,\n                y,\n                y_i,\n                deflection_field_i,\n                z,\n                hub_height_i,\n                ct_i,\n                yaw_angle,\n                rotor_diameter_i,\n            )\n\n            near_wake_deficit = gaussian_function(C, r_squared, 1, np.sqrt(0.5))\n            near_wake_deficit *= near_wake_mask\n\n            velocity_deficit += near_wake_deficit\n\n        # Compute the velocity deficit in the FAR WAKE region\n        if np.sum(far_wake_mask):\n\n            # Wake expansion in the lateral (y) and the vertical (z)\n            ky = self.ka * turbulence_intensity_i + self.kb  # wake expansion parameters\n            kz = self.ka * turbulence_intensity_i + self.kb  # wake expansion parameters\n            sigma_y = (ky * (x - x0) + sigma_y0) * far_wake_mask + sigma_y0 * (x < x0)\n            sigma_z = (kz * (x - x0) + sigma_z0) * far_wake_mask + sigma_z0 * (x < x0)\n\n            r_squared, C = rC(\n                wind_veer,\n                sigma_y,\n                sigma_z,\n                y,\n                y_i,\n                deflection_field_i,\n                z,\n                hub_height_i,\n                ct_i,\n                yaw_angle,\n                rotor_diameter_i,\n            )\n\n            far_wake_deficit = gaussian_function(C, r_squared, 1, np.sqrt(0.5))\n            far_wake_deficit *= far_wake_mask\n\n            velocity_deficit += far_wake_deficit\n\n        return velocity_deficit\n\n\n# @profile\ndef rC(wind_veer, sigma_y, sigma_z, y, y_i, delta, z, HH, Ct, yaw, D):\n\n    ## original\n    # a = cosd(wind_veer) ** 2 / (2 * sigma_y ** 2) + sind(wind_veer) ** 2 / (2 * sigma_z ** 2)\n    # b = -sind(2 * wind_veer) / (4 * sigma_y ** 2) + sind(2 * wind_veer) / (4 * sigma_z ** 2)\n    # c = sind(wind_veer) ** 2 / (2 * sigma_y ** 2) + cosd(wind_veer) ** 2 / (2 * sigma_z ** 2)\n    # r_squared = (\n    #     a * (y - y_i - delta) ** 2\n    #     - 2 * b * (y - y_i - delta) * (z - HH)\n    #     + c * (z - HH) ** 2\n    # )\n    # C = 1 - np.sqrt(np.clip(1 - (Ct * cosd(yaw) / (8.0 * sigma_y * sigma_z / D ** 2)), 0.0, 1.0))\n\n    ## Precalculate some parts\n    # twox_sigmay_2 = 2 * sigma_y ** 2\n    # twox_sigmaz_2 = 2 * sigma_z ** 2\n    # a = cosd(wind_veer) ** 2 / (twox_sigmay_2) + sind(wind_veer) ** 2 / (twox_sigmaz_2)\n    # b = -sind(2 * wind_veer) / (2 * twox_sigmay_2) + sind(2 * wind_veer) / (2 * twox_sigmaz_2)\n    # c = sind(wind_veer) ** 2 / (twox_sigmay_2) + cosd(wind_veer) ** 2 / (twox_sigmaz_2)\n    # delta_y = y - y_i - delta\n    # delta_z = z - HH\n    # r_squared = (a * (delta_y ** 2) - 2 * b * (delta_y) * (delta_z) + c * (delta_z ** 2))\n    # C = 1 - np.sqrt(np.clip(1 - (Ct * cosd(yaw) / (8.0 * sigma_y * sigma_z / (D * D))), 0.0, 1.0))\n\n    ## Numexpr\n    wind_veer = np.deg2rad(wind_veer)\n    a = ne.evaluate(\n        \"cos(wind_veer) ** 2 / (2 * sigma_y ** 2) + sin(wind_veer) ** 2 / (2 * sigma_z ** 2)\"\n    )\n    b = ne.evaluate(\n        \"-sin(2 * wind_veer) / (4 * sigma_y ** 2) + sin(2 * wind_veer) / (4 * sigma_z ** 2)\"\n    )\n    c = ne.evaluate(\n        \"sin(wind_veer) ** 2 / (2 * sigma_y ** 2) + cos(wind_veer) ** 2 / (2 * sigma_z ** 2)\"\n    )\n    r_squared = ne.evaluate(\n        \"a * ((y - y_i - delta) ** 2) - 2 * b * (y - y_i - delta) * (z - HH) + c * ((z - HH) ** 2)\"\n    )\n    d = np.clip(1 - (Ct * cosd(yaw) / ( 8.0 * sigma_y * sigma_z / (D * D) )), 0.0, 1.0)\n    C = ne.evaluate(\"1 - sqrt(d)\")\n    return r_squared, C\n\n\ndef mask_upstream_wake(mesh_y_rotated, x_coord_rotated, y_coord_rotated, turbine_yaw):\n    yR = mesh_y_rotated - y_coord_rotated\n    xR = yR * tand(turbine_yaw) + x_coord_rotated\n    return xR, yR\n\n\ndef gaussian_function(C, r_squared, n, sigma):\n    result = ne.evaluate(\"C * exp(-1 * r_squared ** n / (2 * sigma ** 2))\")\n    return result\n"
  },
  {
    "path": "floris/core/wake_velocity/jensen.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import (\n    define,\n    field,\n    fields,\n)\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\n\n\nNUM_EPS = fields(BaseModel).NUM_EPS.default\n\n@define\nclass JensenVelocityDeficit(BaseModel):\n    \"\"\"\n    The Jensen model computes the wake velocity deficit based on the classic\n    Jensen/Park model :cite:`jvm-jensen1983note`.\n\n    -   **we** (*float*): The linear wake decay constant that\n        defines the cone boundary for the wake as well as the\n        velocity deficit. D/2 +/- we*x is the cone boundary for the\n        wake.\n\n    References:\n        .. bibliography:: /references.bib\n            :style: unsrt\n            :filter: docname in docnames\n            :keyprefix: jvm-\n    \"\"\"\n\n    we: float = field(converter=float, default=0.05)\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n        \"\"\"\n        This function prepares the inputs from the various FLORIS data structures\n        for use in the Jensen model. This should only be used to 'initialize'\n        the inputs. For any data that should be updated successively,\n        do not use this function and instead pass that data directly to\n        the model function.\n        \"\"\"\n        kwargs = {\n            \"x\": grid.x_sorted,\n            \"y\": grid.y_sorted,\n            \"z\": grid.z_sorted,\n        }\n        return kwargs\n\n    # @profile\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        z_i: np.ndarray,\n        axial_induction_i: np.ndarray,\n        deflection_field_i: np.ndarray,\n        yaw_angle_i: np.ndarray,\n        turbulence_intensity_i: np.ndarray,\n        ct_i: np.ndarray,\n        hub_height_i,\n        rotor_diameter_i,\n        # enforces the use of the below as keyword arguments and adherence to the\n        # unpacking of the results from prepare_function()\n        *,\n        x: np.ndarray,\n        y: np.ndarray,\n        z: np.ndarray,\n    ) -> None:\n\n        # u is 4-dimensional (n wind speeds, n turbines, grid res 1, grid res 2)\n        # velocities is 3-dimensional (n turbines, grid res 1, grid res 2)\n\n        # TODO: check the rotations with multiple directions or non-0/270\n        # grid.rotate_fields(flow_field.wind_directions)\n\n        # Calculate and apply wake mask\n        # x = grid.x_sorted # mesh_x_rotated - x_coord_rotated\n\n        # This is the velocity deficit seen by the i'th turbine due to wake effects\n        # from upstream turbines.\n        # Indeces of velocity_deficit corresponding to unwaked turbines will have 0's\n        # velocity_deficit = np.zeros(np.shape(flow_field.u_initial))\n\n        rotor_radius = rotor_diameter_i / 2.0\n\n        # Numexpr - do not change below without corresponding changes above.\n        dx = ne.evaluate(\"x - x_i\")\n        dy = ne.evaluate(\"y - y_i - deflection_field_i\")\n        dz = ne.evaluate(\"z - z_i\")\n\n        we = self.we\n\n        # Construct a boolean mask to include all points downstream of the turbine\n        downstream_mask = ne.evaluate(\"dx > 0 + NUM_EPS\")\n\n        # Construct a boolean mask to include all points within the wake boundary\n        # as defined by the Jensen model. This is a linear wake expansion that makes\n        # a shape like a cone and starts at the turbine disc.\n        # The left side of the inequality below evaluates the distance from the wake centerline\n        # for all points including positive and negative values. The inequality compares distance\n        # from the centerline and it must be below the line defined by the wake\n        # expansion parameter, \"we\".\n        boundary_mask = ne.evaluate(\"sqrt(dy ** 2 + dz ** 2) < we * dx + rotor_radius\")\n\n        # Calculate C for points within the mask and fill points outside with 0\n        c = np.where(\n            np.logical_and(downstream_mask, boundary_mask),\n            ne.evaluate(\"(rotor_radius / (rotor_radius + we * dx + NUM_EPS)) ** 2\"),  # This is \"C\"\n            0.0,\n        )\n\n        velocity_deficit = ne.evaluate(\"2 * axial_induction_i * c\")\n\n        return velocity_deficit\n"
  },
  {
    "path": "floris/core/wake_velocity/none.py",
    "content": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseModel,\n    FlowField,\n    Grid,\n)\n\n\n@define\nclass NoneVelocityDeficit(BaseModel):\n    \"\"\"\n    The None deficit model is a placeholder code that simple ignores any\n    wake wind speed deficits and returns an array of zeroes.\n    \"\"\"\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n\n        kwargs = {\n            \"u_initial\": flow_field.u_initial_sorted,\n        }\n        return kwargs\n\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        z_i: np.ndarray,\n        axial_induction_i: np.ndarray,\n        deflection_field_i: np.ndarray,\n        yaw_angle_i: np.ndarray,\n        turbulence_intensity_i: np.ndarray,\n        ct_i: np.ndarray,\n        hub_height_i: float,\n        rotor_diameter_i: np.ndarray,\n        # enforces the use of the below as keyword arguments and adherence to the\n        # unpacking of the results from prepare_function()\n        *,\n        u_initial: np.ndarray,\n    ) -> None:\n        self.logger.warning(\"The wake deficit model is set to 'none'. Wake modeling disabled.\")\n        return np.zeros_like(u_initial)\n"
  },
  {
    "path": "floris/core/wake_velocity/turbopark.py",
    "content": "\n\nfrom pathlib import Path\nfrom typing import Any, Dict\n\nimport numpy as np\nimport scipy.io\nfrom attrs import define, field\nfrom scipy import integrate\nfrom scipy.interpolate import RegularGridInterpolator\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.utilities import (\n    cosd,\n    sind,\n    tand,\n)\n\n\n@define\nclass TurbOParkVelocityDeficit(BaseModel):\n    \"\"\"\n    Model based on the TurbOPark model. For model details see\n    https://github.com/OrstedRD/TurbOPark,\n    https://github.com/OrstedRD/TurbOPark/blob/main/TurbOPark%20description.pdf, and\n    Nygaard, Nicolai Gayle, et al. \"Modelling cluster wakes and wind farm blockage.\"\n    Journal of Physics: Conference Series. Vol. 1618. No. 6. IOP Publishing, 2020.\n    \"\"\"\n\n    A: float = field(default=0.04)\n    sigma_max_rel: float = field(default=4.0)\n    overlap_gauss_interp: RegularGridInterpolator = field(init=False)\n\n    def __attrs_post_init__(self) -> None:\n        lookup_table_matlab_file = Path(__file__).parent / \"turbopark_lookup_table.mat\"\n        lookup_table_file = scipy.io.loadmat(lookup_table_matlab_file)\n        dist = lookup_table_file['overlap_lookup_table'][0][0][0][0]\n        radius_down = lookup_table_file['overlap_lookup_table'][0][0][1][0]\n        overlap_gauss = lookup_table_file['overlap_lookup_table'][0][0][2]\n        self.overlap_gauss_interp = RegularGridInterpolator(\n            (dist, radius_down),\n            overlap_gauss,\n            method='linear',\n            bounds_error=False\n        )\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n\n        kwargs = {\n            \"x\": grid.x_sorted,\n            \"y\": grid.y_sorted,\n            \"z\": grid.z_sorted,\n            \"u_initial\": flow_field.u_initial_sorted,\n        }\n        return kwargs\n\n    # @profile\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        z_i: np.ndarray,\n        ambient_turbulence_intensities: np.ndarray,\n        Cts: np.ndarray,\n        rotor_diameter_i: np.ndarray,\n        rotor_diameters: np.ndarray,\n        i: int,\n        deflection_field: np.ndarray,\n        # enforces the use of the below as keyword arguments and adherence to the\n        # unpacking of the results from prepare_function()\n        *,\n        x: np.ndarray,\n        y: np.ndarray,\n        z: np.ndarray,\n        u_initial: np.ndarray,\n    ) -> None:\n        delta_total = np.zeros_like(u_initial)\n\n        # Normalized distances along x between the turbine i and all other turbines\n        # The downstream_mask is used to avoid negative numbers in the sqrt and the\n        # subsequent runtime warnings.\n        # Here self.NUM_EPS is to avoid precision issues with masking, and is slightly\n        # larger than 0.0\n        downstream_mask = (x_i - x >= self.NUM_EPS)\n        x_dist = (x_i - x) * downstream_mask / rotor_diameters\n\n        # Radial distance between turbine i and the center lines of wakes from all\n        # real/image turbines\n        r_dist = np.sqrt((y_i - (y + deflection_field)) ** 2 + (z_i - z) ** 2)\n        r_dist_image = np.sqrt((y_i - (y + deflection_field)) ** 2 + (z_i - (-z)) ** 2)\n\n        Cts[:, i:, :, :] = 0.00001\n\n        # Characteristic wake widths from all turbines relative to turbine i\n        dw = characteristic_wake_width(x_dist, ambient_turbulence_intensities, Cts, self.A)\n        epsilon = 0.25 * np.sqrt(\n            np.min( 0.5 * (1 + np.sqrt(1 - Cts)) / np.sqrt(1 - Cts), 3, keepdims=True )\n        )\n        sigma = rotor_diameters * (epsilon + dw)\n\n        # Peak wake deficits\n        val = 1 - Cts / (8 * (sigma / rotor_diameters) ** 2)\n        C = 1 - np.sqrt(val)\n\n        # Compute deficit for all turbines and mask to keep upstream and overlapping turbines\n        # NOTE self.sigma_max_rel * sigma is an effective wake width\n        is_overlapping = (self.sigma_max_rel * sigma) / 2 + rotor_diameter_i / 2 > r_dist\n        wtg_overlapping = (x_dist > 0) * is_overlapping\n\n        delta_real = np.empty(np.shape(u_initial)) * np.nan\n        delta_image = np.empty(np.shape(u_initial)) * np.nan\n\n        # Compute deficits for real turbines and for mirrored (image) turbines\n        delta_real = C * wtg_overlapping * self.overlap_gauss_interp(\n            (r_dist / sigma, rotor_diameter_i / 2 / sigma)\n        )\n        delta_image = C * wtg_overlapping * self.overlap_gauss_interp(\n            (r_dist_image / sigma, rotor_diameter_i / 2 / sigma)\n        )\n        delta = np.concatenate((delta_real, delta_image), axis=1)\n\n        delta_total[:, i, :, :] = np.sqrt(np.sum(np.nan_to_num(delta) ** 2, axis=1))\n\n        return delta_total\n\n\ndef precalculate_overlap():\n    # TODO: first implementation to generate wake overlap lookup table\n    # (currently supplied by turbopark_lookup_table.mat.)\n    # However, the result of this function doesn't generate the same\n    # interpolant as the .mat file, so if used, needs to be corrected.\n    dist = np.arange(0, 10, 1.0)\n    radius_down = np.arange(0, 20, 1.0)\n    overlap_gauss = np.zeros((len(dist), len(radius_down)))\n\n    for i in range(len(dist)):\n        for j in range(len(radius_down)):\n            if radius_down[j] > 0:\n                def fun(r, theta):\n                    return r * np.exp(\n                        -1 * (r ** 2 + dist[i] ** 2 - 2 * dist[i] * r * np.cos(theta)) / 2\n                    )\n                out = integrate.dblquad(fun, 0, radius_down[j], lambda x: 0, lambda x: 2 * np.pi)[0]\n                out = out / (np.pi * radius_down[j] ** 2)\n            else:\n                out = np.exp(-(dist[i] ** 2) / 2)\n            overlap_gauss[i, j] = out\n\n    return dist, radius_down, overlap_gauss\n\n\ndef characteristic_wake_width(x_dist, TI, Cts, A):\n    # Parameter values taken from S. T. Frandsen, “Risø-R-1188(EN) Turbulence\n    # and turbulence generated structural loading in wind turbine clusters”\n    # Risø, Roskilde, Denmark, 2007.\n    c1 = 1.5\n    c2 = 0.8\n\n    alpha = TI * c1\n    beta = c2 * TI / np.sqrt(Cts)\n\n    dw = A * TI / beta * (\n        np.sqrt((alpha + beta * x_dist) ** 2 + 1)\n        - np.sqrt(1 + alpha ** 2)\n        - np.log(\n            ((np.sqrt((alpha + beta * x_dist) ** 2 + 1) + 1) * alpha)\n            / ((np.sqrt(1 + alpha ** 2) + 1) * (alpha + beta * x_dist))\n        )\n    )\n\n    return dw\n"
  },
  {
    "path": "floris/core/wake_velocity/turboparkgauss.py",
    "content": "from typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseModel,\n    Farm,\n    FlowField,\n    Grid,\n    Turbine,\n)\nfrom floris.core.wake_velocity.gauss import gaussian_function\nfrom floris.utilities import (\n    cosd,\n    sind,\n    tand,\n)\n\n\n@define\nclass TurboparkgaussVelocityDeficit(BaseModel):\n    \"\"\"\n    Model based on the TurbOPark model with Gaussian wake profile.\n    For model details see:\n    Pedersen J G, Svensen E, Poulsen L, and Nygaard N G. \"Turbulence Optimized\n    Park model with Gaussian wake profile.\" Journal of Physics: Conference\n    Series. Vol. 2265. No. 022063. IOP Publishing, 2020.\n    doi:10.1088/1742-6596/2265/2/022063\n    \"\"\"\n\n    A: float = field(default=0.04)\n    include_mirror_wake: bool = field(default=True)\n\n    def prepare_function(\n        self,\n        grid: Grid,\n        flow_field: FlowField,\n    ) -> Dict[str, Any]:\n\n        kwargs = {\n            \"x\": grid.x_sorted,\n            \"y\": grid.y_sorted,\n            \"z\": grid.z_sorted,\n            \"u_initial\": flow_field.u_initial_sorted,\n            \"wind_veer\": flow_field.wind_veer\n        }\n        return kwargs\n\n    # @profile\n    def function(\n        self,\n        x_i: np.ndarray,\n        y_i: np.ndarray,\n        z_i: np.ndarray,\n        axial_induction_i: np.ndarray,\n        deflection_field_i: np.ndarray,\n        yaw_angle_i: np.ndarray,\n        turbulence_intensity_i: np.ndarray,\n        ct_i: np.ndarray,\n        hub_height_i: float,\n        rotor_diameter_i: np.ndarray,\n        # enforces the use of the below as keyword arguments and adherence to the\n        # unpacking of the results from prepare_function()\n        *,\n        x: np.ndarray,\n        y: np.ndarray,\n        z: np.ndarray,\n        u_initial: np.ndarray,\n        wind_veer: float,\n    ) -> None:\n\n        # Initialize the velocity deficit array\n        velocity_deficit = np.zeros_like(u_initial)\n\n        downstream_mask = (x - x_i >= self.NUM_EPS)\n        x_dist = (x - x_i) * downstream_mask / rotor_diameter_i\n\n        # Characteristic wake widths from all turbines relative to turbine i\n        sigma = characteristic_wake_width(\n            x_dist, turbulence_intensity_i, ct_i, self.A\n        ) * rotor_diameter_i\n\n        # Peak wake deficits\n        C = 1 - np.sqrt(np.clip(1 - ct_i / (8 * (sigma / rotor_diameter_i) ** 2), 0.0, 1.0))\n\n        r_dist = np.sqrt((y - y_i) ** 2 + (z - z_i) ** 2)\n\n        # Compute deficits for real turbines and for mirrored (image) turbines\n        delta_real  = (x_dist > 0) * gaussian_function(C, r_dist, 2, sigma)\n        if self.include_mirror_wake:\n            r_dist_image = np.sqrt((y - y_i) ** 2 + (z - 3*z_i) ** 2)\n            delta_image = (x_dist > 0) * gaussian_function(C, r_dist_image, 2, sigma)\n            delta = np.hypot(delta_real, delta_image)\n        else: # No mirror wakes\n            delta = delta_real\n\n        velocity_deficit = np.nan_to_num(delta)\n\n        return velocity_deficit\n\n\ndef characteristic_wake_width(x_D, ambient_TI, Cts, A):\n    # Parameter values taken from S. T. Frandsen, “Risø-R-1188(EN) Turbulence\n    # and turbulence generated structural loading in wind turbine clusters”\n    # Risø, Roskilde, Denmark, 2007.\n    c1 = 1.5\n    c2 = 0.8\n\n    alpha = ambient_TI * c1\n    beta = c2 * ambient_TI / np.sqrt(Cts)\n\n    # Term for the initial width at the turbine location (denoted epsilon in Pedersen et al.)\n    # Saturate term in initial width to 3.0, as is done in Orsted Matlab code.\n    initial_width = 0.25 * np.sqrt(np.minimum(0.5 * (1 + np.sqrt(1 - Cts)) / np.sqrt(1 - Cts), 3.0))\n\n    # Term for the added width downstream of the turbine\n    added_width = A * ambient_TI / beta * (\n        np.sqrt((alpha + beta * x_D) ** 2 + 1)\n        - np.sqrt(1 + alpha ** 2)\n        - np.log(\n            ((np.sqrt((alpha + beta * x_D) ** 2 + 1) + 1) * alpha)\n            / ((np.sqrt(1 + alpha ** 2) + 1) * (alpha + beta * x_D))\n        )\n    )\n\n    sigma_w_D = initial_width + added_width\n\n    return sigma_w_D\n"
  },
  {
    "path": "floris/cut_plane.py",
    "content": "\nimport copy\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom scipy.interpolate import griddata\n\n\ndef nudge_outward(x):\n    \"\"\"\n    Avoid numerical issue in grid data by slightly expanding input x.\n    TODO: expand this description\n    - What numerical issues?\n    - Whats the scenario when I would need this?\n\n    Args:\n        x (np.array): Vector of values.\n\n    Returns:\n        np.array: Expanded vector.\n    \"\"\"\n    nudge_val = 0.001\n    min_x = np.min(x)\n    max_x = np.max(x)\n    x = np.where(x == min_x, min_x - nudge_val, x)\n    x = np.where(x == max_x, max_x + nudge_val, x)\n    return x\n\n\ndef get_plane_from_flow_data(flow_data, normal_vector=\"z\", x3_value=100):\n    \"\"\"\n    Get a plane of data, in form of DataFrame, from a :py:class:`~.FlowData`\n    object. This is used to get planes from SOWFA results and FLORIS\n    simulations with fixed grids, i.e. curl.\n\n    Args:\n        flow_data (np.array): 3D vector field of velocity data. #TODO: is this\n            supposed to be a :py:class:`~.FlowData` object?\n        normal_vector (string, optional): Vector normal to plane.\n            Defaults to z.\n        x3_value (float, optional): Value of normal vector to slice through.\n            Defaults to 100.\n\n    Returns:\n        pandas.DataFrame: Extracted data.\n    \"\"\"\n    order = \"f\"\n    if normal_vector == \"z\":\n        x1_array = flow_data.x.flatten(order=order)\n        x2_array = flow_data.y.flatten(order=order)\n        x3_array = flow_data.z.flatten(order=order)\n\n    if normal_vector == \"x\":\n        x3_array = flow_data.x.flatten(order=order)\n        x1_array = flow_data.y.flatten(order=order)\n        x2_array = flow_data.z.flatten(order=order)\n\n    if normal_vector == \"y\":\n        x3_array = flow_data.y.flatten(order=order)\n        x1_array = flow_data.x.flatten(order=order)\n        x2_array = flow_data.z.flatten(order=order)\n\n    u = flow_data.u.flatten(order=order)\n    v = flow_data.v.flatten(order=order)\n    w = flow_data.w.flatten(order=order)\n\n    search_values = np.array(sorted(np.unique(x3_array)))\n    nearest_idx = (np.abs(search_values - x3_value)).argmin()\n    nearest_value = search_values[nearest_idx]\n    print(\"Nearest value to %.2f is %.2f\" % (x3_value, nearest_value))\n\n    # Select down the data\n    x3_select_mask = x3_array == nearest_value\n\n    # Store the un-interpolated input arrays at this slice\n    x1 = x1_array[x3_select_mask]\n    x2 = x2_array[x3_select_mask]\n    x3 = np.ones_like(x1) * x3_value\n    u = u[x3_select_mask]\n    v = v[x3_select_mask]\n    w = w[x3_select_mask]\n\n    df = pd.DataFrame({\"x1\": x1, \"x2\": x2, \"x3\": x3, \"u\": u, \"v\": v, \"w\": w})\n    return df\n\n\nclass CutPlane:\n    \"\"\"\n    A CutPlane object represents a 2D slice through the flow of a\n    FLORIS simulation, or other such as SOWFA result.\n    \"\"\"\n\n    def __init__(self, df, x1_resolution, x2_resolution, normal_vector):\n        \"\"\"\n        Initialize CutPlane object, storing the DataFrame and resolution.\n\n        Args:\n            df (pandas.DataFrame): Pandas DataFrame of data with\n                columns x1, x2, u, v, w.\n        \"\"\"\n        self.df: pd.DataFrame = df\n        self.normal_vector: str = normal_vector\n        self.resolution = (x1_resolution, x2_resolution)\n        self.df.set_index([\"x1\", \"x2\"])\n\n    def __sub__(self, other):\n\n        if self.normal_vector != other.normal_vector:\n            raise ValueError(\"Operands must have consistent normal vectors.\")\n\n        # if self.normal_vector.df.\n        # DF must be of the same size\n        # resolution must be of the same size\n\n        df: pd.DataFrame = self.df.copy()\n        other_df: pd.DataFrame = other.df.copy()\n\n        df['u'] = self.df['u'] - other_df['u']\n        df['v'] = self.df['v'] - other_df['v']\n        df['w'] = self.df['w'] - other_df['w']\n\n        return CutPlane(\n            df,\n            self.resolution[0],\n            self.resolution[1],\n            self.normal_vector\n        )\n\n\n# Modification functions\ndef set_origin(cut_plane, center_x1=0.0, center_x2=0.0):\n    \"\"\"\n    Establish the origin of a CutPlane object.\n\n    Args:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            Plane of data.\n        center_x1 (float, optional): x1-coordinate of origin.\n            Defaults to 0.0.\n        center_x2 (float, optional): x2-coordinate of origin.\n            Defaults to 0.0.\n\n    Returns:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            Updated plane of data.\n    \"\"\"\n    # Store the un-interpolated input arrays at this slice\n    cut_plane.df.x1 = cut_plane.df.x1 - center_x1\n    cut_plane.df.x2 = cut_plane.df.x2 - center_x2\n\n    return cut_plane\n\n\ndef change_resolution(cut_plane, resolution=(100, 100)):\n    \"\"\"\n    Modify default resolution of a CutPlane object.\n\n    Args:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            Plane of data.\n        resolution (tuple, optional): Desired resolution in x1 and x2.\n            Defaults to (100, 100).\n\n    Returns:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            Updated plane of data.\n    \"\"\"\n\n    # Linearize the data\n    x1_lin = np.linspace(min(cut_plane.df.x1), max(cut_plane.df.x1), resolution[0])\n    x2_lin = np.linspace(min(cut_plane.df.x2), max(cut_plane.df.x2), resolution[1])\n    # x3 = np.ones_like(x1) * cut_plane.df.x3[0]\n\n    # Mesh the data\n    x1_mesh, x2_mesh = np.meshgrid(x1_lin, x2_lin)\n    x3_mesh = np.ones_like(x1_mesh) * cut_plane.df.x3[0]\n\n    # Interpolate u,v,w\n    u_mesh = griddata(\n        np.column_stack(\n            [nudge_outward(cut_plane.df.x1), nudge_outward(cut_plane.df.x2)]\n        ),\n        cut_plane.df.u.values,\n        (x1_mesh.flatten(), x2_mesh.flatten()),\n        method=\"cubic\",\n    )\n    v_mesh = griddata(\n        np.column_stack(\n            [nudge_outward(cut_plane.df.x1), nudge_outward(cut_plane.df.x2)]\n        ),\n        cut_plane.df.v.values,\n        (x1_mesh.flatten(), x2_mesh.flatten()),\n        method=\"cubic\",\n    )\n\n    w_mesh = griddata(\n        np.column_stack(\n            [nudge_outward(cut_plane.df.x1), nudge_outward(cut_plane.df.x2)]\n        ),\n        cut_plane.df.w.values,\n        (x1_mesh.flatten(), x2_mesh.flatten()),\n        method=\"cubic\",\n    )\n\n    # Assign back to df\n    cut_plane.df = pd.DataFrame(\n        {\n            \"x1\": x1_mesh.flatten(),\n            \"x2\": x2_mesh.flatten(),\n            \"x3\": x3_mesh.flatten(),\n            \"u\": u_mesh.flatten(),\n            \"v\": v_mesh.flatten(),\n            \"w\": w_mesh.flatten(),\n        }\n    )\n\n    # Save the resolution\n    cut_plane.resolution = resolution\n\n    # Return the cutplane\n    return cut_plane\n\n\ndef interpolate_onto_array(cut_plane_in, x1_array, x2_array):\n    \"\"\"\n    Interpolate a CutPlane object onto specified coordinate arrays.\n\n    Args:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            Plane of data.\n        x1_array (np.array): Specified x1-coordinate.\n        x2_array (np.array): Specified x2-coordinate.\n\n    Returns:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            Updated plane of data.\n    \"\"\"\n    cut_plane = copy.deepcopy(cut_plane_in)\n\n    # Linearize the data\n    x1_lin = x1_array\n    x2_lin = x2_array\n\n    # Save the new resolution\n    cut_plane.resolution = (len(np.unique(x1_lin)), len(np.unique(x2_lin)))\n\n    # Mesh the data\n    x1_mesh, x2_mesh = np.meshgrid(x1_lin, x2_lin)\n    x3_mesh = np.ones_like(x1_mesh) * cut_plane.df.x3.iloc[0]\n\n    # Interpolate u,v,w\n    u_mesh = griddata(\n        np.column_stack(\n            [nudge_outward(cut_plane.df.x1), nudge_outward(cut_plane.df.x2)]\n        ),\n        cut_plane.df.u.values,\n        (x1_mesh.flatten(), x2_mesh.flatten()),\n        method=\"cubic\",\n    )\n    v_mesh = griddata(\n        np.column_stack(\n            [nudge_outward(cut_plane.df.x1), nudge_outward(cut_plane.df.x2)]\n        ),\n        cut_plane.df.v.values,\n        (x1_mesh.flatten(), x2_mesh.flatten()),\n        method=\"cubic\",\n    )\n\n    w_mesh = griddata(\n        np.column_stack(\n            [nudge_outward(cut_plane.df.x1), nudge_outward(cut_plane.df.x2)]\n        ),\n        cut_plane.df.w.values,\n        (x1_mesh.flatten(), x2_mesh.flatten()),\n        method=\"cubic\",\n    )\n\n    # Assign back to df\n    cut_plane.df = pd.DataFrame(\n        {\n            \"x1\": x1_mesh.flatten(),\n            \"x2\": x2_mesh.flatten(),\n            \"x3\": x3_mesh.flatten(),\n            \"u\": u_mesh.flatten(),\n            \"v\": v_mesh.flatten(),\n            \"w\": w_mesh.flatten(),\n        }\n    )\n\n    # Return the cutplane\n    return cut_plane\n\n\ndef rescale_axis(cut_plane, x1_factor=1.0, x2_factor=1.0):\n    \"\"\"\n    Stretch or compress CutPlane coordinates.\n\n    Args:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            Plane of data.\n        x1_factor (float): Scaling factor for x1-coordinate.\n        x2_factor (float): Scaling factor for x2-coordinate.\n\n    Returns:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            Updated plane of data.\n    \"\"\"\n    # Store the un-interpolated input arrays at this slice\n    cut_plane.df.x1 = cut_plane.df.x1 / x1_factor\n    cut_plane.df.x2 = cut_plane.df.x2 / x2_factor\n\n    return cut_plane\n\n\ndef project_onto(cut_plane_a, cut_plane_b):\n    \"\"\"\n    Project cut_plane_a onto the x1, x2 of cut_plane_b\n\n    Args:\n        cut_plane_a (:py:class:`~.tools.cut_plane.CutPlane`):\n            Plane of data to project from.\n        cut_plane_b (:py:class:`~.tools.cut_plane.CutPlane`):\n            Plane of data to project onto.\n\n    Returns:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            Cut_plane_a projected onto cut_plane_b's axis.\n    \"\"\"\n\n    return interpolate_onto_array(\n        cut_plane_a, cut_plane_b.df.x1.unique(), cut_plane_b.df.x2.unique()\n    )\n\n\ndef calculate_wind_speed(cross_plane, x1_loc, x2_loc, R):\n    \"\"\"\n    Calculate effective wind speed within specified range of a point.\n\n    Args:\n        cross_plane (:py:class:`floris.cut_plane.CrossPlane`):\n            plane of data.\n        x1_loc (float): x1-coordinate of point of interest.\n        x2_loc (float): x2-coordinate of point of interest.\n        R (float): radius from point of interest to consider\n\n    Returns:\n        (float): effective wind speed\n    \"\"\"\n\n    # Temp local copy\n    df = cross_plane.df.copy()\n\n    # Make a distance column\n    df[\"distance\"] = np.sqrt((df.x1 - x1_loc) ** 2 + (df.x2 - x2_loc) ** 2)\n\n    # Return the cube-mean wind speed\n    return np.cbrt(np.mean(df[df.distance < R].u ** 3))\n\n\ndef wind_speed_profile(cross_plane, R, x2_loc, resolution=100, x1_locs=None):\n\n    if x1_locs is None:\n        x1_locs = np.linspace(\n            min(cross_plane.df.x1), max(cross_plane.df.x1), resolution\n        )\n    v_array = np.array(\n        [calculate_wind_speed(cross_plane, x1_loc, x2_loc, R) for x1_loc in x1_locs]\n    )\n    return x1_locs, v_array\n\n\ndef calculate_power(\n    cross_plane, x1_loc, x2_loc, R, ws_array, cp_array, air_density=1.225\n):\n    \"\"\"\n    Calculate maximum power available in a given cross plane.\n\n    Args:\n        cross_plane (:py:class:`floris.cut_plane.CrossPlane`):\n            plane of data.\n        x1_loc (float): x1-coordinate of point of interest.\n        x2_loc (float): x2-coordinate of point of interest.\n        R (float): Radius of wind turbine rotor.\n        ws_array (np.array): reference wind speed for cp curve.\n        cp_array (np.array): cp curve at reference wind speeds.\n        air_density (float, optional): air density. Defaults to 1.225.\n\n    Returns:\n        float: Power!\n    \"\"\"\n    # Compute the ws\n    ws = calculate_wind_speed(cross_plane, x1_loc, x2_loc, R)\n\n    # Compute the cp\n    cp_value = np.interp(ws, ws_array, cp_array)\n\n    # Return the power\n    return 0.5 * air_density * (np.pi * R ** 2) * cp_value * ws ** 3\n\n\ndef get_power_profile(\n    cross_plane,\n    x2_loc,\n    ws_array,\n    cp_array,\n    R,\n    air_density=1.225,\n    resolution=100,\n    x1_locs=None,\n):\n\n    if x1_locs is None:\n        x1_locs = np.linspace(\n            min(cross_plane.df.x1), max(cross_plane.df.x1), resolution\n        )\n    p_array = np.array(\n        [\n            calculate_power(\n                cross_plane,\n                x1_loc,\n                x2_loc,\n                R,\n                ws_array,\n                cp_array,\n                air_density=air_density,\n            )\n            for x1_loc in x1_locs\n        ]\n    )\n    return x1_locs, p_array\n\n\n# # Define horizontal subclass\n# class HorPlane(_CutPlane):\n#     \"\"\"\n#     Subclass of _CutPlane. Shortcut to extracting a horizontal plane.\n#     \"\"\"\n\n#     def __init__(self, df):\n#         \"\"\"\n#         Initialize horizontal CutPlane\n\n#         Args:\n#             flow_data (np.array): 3D vector field of velocity data\n#             z_value (float): vertical position through which to slice\n#         \"\"\"\n#         # Set up call super\n#         super().__init__(df)\n\n\n# # Define cross plane subclass\n# class CrossPlane(_CutPlane):\n#     \"\"\"\n#     Subclass of _CutPlane. Shortcut to extracting a cross-stream plane.\n#     \"\"\"\n\n#     def __init__(self, df):\n#         \"\"\"\n#         Initialize cross-stream CutPlane\n\n#         Args:\n#             flow_data (np.array): 3D vector field of velocity data\n#             x_value (float): streamwise position through which to slice\n#         \"\"\"\n#         # Set up call super\n#         super().__init__(df)\n\n\n# # Define cross plane subclass\n# class VertPlane(_CutPlane):\n#     \"\"\"\n#     Subclass of _CutPlane. Shortcut to extracting a streamwise-vertical plane.\n#     \"\"\"\n\n#     def __init__(self, df):\n#         \"\"\"\n#         Initialize streamwise-vertical  CutPlane\n\n#         Args:\n#             flow_data (np.array): 3D vector field of velocity data\n#             y_value (float): spanwise position through which to slice\n#         \"\"\"\n#         # Set up call super\n#         super().__init__(df)\n"
  },
  {
    "path": "floris/default_inputs.yaml",
    "content": "\nname: GCH\ndescription: \"Default initialization: Gauss-Curl hybrid model (GCH)\"\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  layout_y:\n  - 0.0\n  turbine_type:\n  - nrel_5MW\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: -1\n  turbulence_intensities: []\n  wind_directions: []\n  wind_shear: 0.12\n  wind_speeds: []\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: gauss\n\n  enable_secondary_steering: true\n  enable_yaw_added_recovery: true\n  enable_transverse_velocities: true\n  enable_active_wake_mixing: false\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n    empirical_gauss:\n      horizontal_deflection_gain_D: 3.0\n      vertical_deflection_gain_D: -1\n      deflection_rate: 22\n      mixing_gain_deflection: 0.0\n      yaw_added_mixing_gain: 0.0\n\n  wake_velocity_parameters:\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    turbopark:\n      A: 0.04\n      sigma_max_rel: 4.0\n    turboparkgauss:\n      A: 0.04\n      include_mirror_wake: True\n    empirical_gauss:\n      wake_expansion_rates: [0.023, 0.008]\n      breakpoints_D: [10]\n      sigma_0_D: 0.28\n      smoothing_length_D: 2.0\n      mixing_gain_velocity: 2.0\n      awc_wake_exp: 1.2\n      awc_wake_denominator: 400\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n    wake_induced_mixing:\n      atmospheric_ti_gain: 0.0\n"
  },
  {
    "path": "floris/floris_model.py",
    "content": "import copy\nimport inspect\nfrom pathlib import Path\nfrom typing import (\n    Any,\n    List,\n    Optional,\n)\n\nimport numpy as np\nimport pandas as pd\n\nfrom floris.core import Core, State\nfrom floris.core.rotor_velocity import average_velocity\nfrom floris.core.turbine.operation_models import (\n    POWER_SETPOINT_DEFAULT,\n    POWER_SETPOINT_DISABLED,\n)\nfrom floris.core.turbine.turbine import (\n    axial_induction,\n    power,\n    thrust_coefficient,\n)\nfrom floris.cut_plane import CutPlane\nfrom floris.logging_manager import LoggingManager\nfrom floris.type_dec import (\n    floris_array_converter,\n    NDArrayBool,\n    NDArrayFloat,\n    NDArrayStr,\n)\nfrom floris.utilities import (\n    load_yaml,\n    nested_get,\n    nested_set,\n    print_nested_dict,\n)\nfrom floris.wind_data import (\n    TimeSeries,\n    WindDataBase,\n    WindRose,\n    WindRoseWRG,\n    WindTIRose,\n)\n\n\nclass FlorisModel(LoggingManager):\n    \"\"\"\n    FlorisModel provides a high-level user interface to many of the\n    underlying methods within the FLORIS framework. It is meant to act as a\n    single entry-point for the majority of users, simplifying the calls to\n    methods on objects within FLORIS.\n    \"\"\"\n\n    @staticmethod\n    def get_defaults() -> dict:\n        \"\"\"\n        Load the default FLORIS configuration dictionary.\n\n        Returns:\n            dict: The default FLORIS configuration dictionary.\n        \"\"\"\n        return copy.deepcopy(load_yaml(Path(__file__).parent / \"default_inputs.yaml\"))\n\n    def __init__(self, configuration: dict | str | Path):\n        \"\"\"\n        Initialize the FlorisModel object.\n\n        Args:\n            configuration: The Floris configuration dictionary or path to the input YAML file.\n                See floris.default_inputs.yaml for an example of the configuration dictionary\n                or visit https://nrel.github.io/floris/input_reference_main.html.\n        \"\"\"\n\n        if configuration == \"defaults\":\n            configuration = FlorisModel.get_defaults()\n\n        self.configuration = configuration\n\n        if isinstance(self.configuration, (str, Path)):\n            try:\n                self.core = Core.from_file(self.configuration)\n            except FileNotFoundError:\n                # If the file cannot be found, then attempt the configuration path relative to the\n                # file location from which FlorisModel was attempted to be run. If successful,\n                # update self.configuration to an absolute, working file path and name.\n                base_fn = Path(inspect.stack()[-1].filename).resolve().parent\n                config = (base_fn / self.configuration).resolve()\n                self.core = Core.from_file(config)\n                self.configuration = config\n\n        elif isinstance(self.configuration, dict):\n            self.core = Core.from_dict(self.configuration)\n\n        else:\n            raise TypeError(\"The Floris `configuration` must be of type 'dict', 'str', or 'Path'.\")\n\n        # If ref height is -1, assign the hub height\n        if np.abs(self.core.flow_field.reference_wind_height + 1.0) < 1.0e-6:\n            self.assign_hub_height_to_ref_height()\n\n        # Make a check on reference height and provide a helpful warning\n        unique_heights = np.unique(np.round(self.core.farm.hub_heights, decimals=6))\n        if ((\n            len(unique_heights) == 1) and\n            (np.abs(self.core.flow_field.reference_wind_height - unique_heights[0]) > 1.0e-6\n        )):\n            err_msg = (\n                \"The only unique hub-height is not equal to the specified reference \"\n                \"wind height. If this was unintended use -1 as the reference hub height to \"\n                \"indicate use of hub-height as reference wind height.\"\n            )\n            self.logger.warning(err_msg, stack_info=True)\n\n        # Check the turbine_grid_points is reasonable\n        if self.core.solver[\"type\"] == \"turbine_grid\":\n            if self.core.solver[\"turbine_grid_points\"] > 3:\n                self.logger.error(\n                    f\"turbine_grid_points value is {self.core.solver['turbine_grid_points']} \"\n                    \"which is larger than the recommended value of less than or equal to 3. \"\n                    \"High amounts of turbine grid points reduce the computational performance \"\n                    \"but have a small change on accuracy.\"\n                )\n                raise ValueError(\"turbine_grid_points must be less than or equal to 3.\")\n\n        # Initialize stored wind_data object to None\n        self._wind_data = None\n\n    ### Methods for setting and running the FlorisModel\n\n    def _reinitialize(\n        self,\n        wind_speeds: list[float] | NDArrayFloat | None = None,\n        wind_directions: list[float] | NDArrayFloat | None = None,\n        wind_shear: float | None = None,\n        wind_veer: float | None = None,\n        reference_wind_height: float | None = None,\n        turbulence_intensities: list[float] | NDArrayFloat | None = None,\n        air_density: float | None = None,\n        layout_x: list[float] | NDArrayFloat | None = None,\n        layout_y: list[float] | NDArrayFloat | None = None,\n        turbine_type: list | None = None,\n        turbine_library_path: str | Path | None = None,\n        solver_settings: dict | None = None,\n        heterogeneous_inflow_config: dict | None = None,\n        wind_data: type[WindDataBase] | None = None,\n        multidim_conditions: dict | None = None,\n    ):\n        \"\"\"\n        Instantiate a new Floris object with updated conditions set by arguments. Any parameters\n        in Floris that aren't changed by arguments to this function retain their values.\n        Note that, although it's name is similar to the reinitialize() method from Floris v3,\n        this function is not meant to be called directly by the user---users should instead call\n        the set() method.\n\n        Args:\n            wind_speeds (NDArrayFloat | list[float] | None, optional): Wind speeds at each findex.\n                Defaults to None.\n            wind_directions (NDArrayFloat | list[float] | None, optional): Wind directions at each\n                findex. Defaults to None.\n            wind_shear (float | None, optional): Wind shear exponent. Defaults to None.\n            wind_veer (float | None, optional): Wind veer. Defaults to None.\n            reference_wind_height (float | None, optional): Reference wind height. Defaults to None.\n            turbulence_intensities (NDArrayFloat | list[float] | None, optional): Turbulence\n                intensities at each findex. Defaults to None.\n            air_density (float | None, optional): Air density. Defaults to None.\n            layout_x (NDArrayFloat | list[float] | None, optional): X-coordinates of the turbines.\n                Defaults to None.\n            layout_y (NDArrayFloat | list[float] | None, optional): Y-coordinates of the turbines.\n                Defaults to None.\n            turbine_type (list | None, optional): Turbine type. Defaults to None.\n            turbine_library_path (str | Path | None, optional): Path to the turbine library.\n                Defaults to None.\n            solver_settings (dict | None, optional): Solver settings. Defaults to None.\n            heterogeneous_inflow_config (dict | None, optional): heterogeneous inflow configuration.\n                Defaults to None.\n            wind_data (type[WindDataBase] | None, optional): Wind data. Defaults to None.\n        \"\"\"\n        # Export the floris object recursively as a dictionary\n        floris_dict = self.core.as_dict()\n        flow_field_dict = floris_dict[\"flow_field\"]\n        farm_dict = floris_dict[\"farm\"]\n\n        ## Farm\n        if layout_x is not None:\n            farm_dict[\"layout_x\"] = layout_x\n        if layout_y is not None:\n            farm_dict[\"layout_y\"] = layout_y\n        if turbine_type is not None:\n            if reference_wind_height is None:\n                self.logger.warning(\n                    \"turbine_type has been changed without specifying a new \"\n                    +\"reference_wind_height. reference_wind_height remains {0:.2f} m.\".format(\n                        flow_field_dict[\"reference_wind_height\"]\n                    )\n                    +f\" Consider calling `{self.__class__.__name__}.\"\n                    +\"assign_hub_height_to_ref_height` to update the reference wind height to the \"\n                    +\"turbine hub height.\"\n                )\n            farm_dict[\"turbine_type\"] = turbine_type\n        if turbine_library_path is not None:\n            farm_dict[\"turbine_library_path\"] = turbine_library_path\n\n        ## If layout is changed and self._wind_data is not None, update the layout in wind_data\n        if (layout_x is not None) or (layout_y is not None):\n            if self._wind_data is not None:\n                self._wind_data.set_layout(farm_dict[\"layout_x\"], farm_dict[\"layout_y\"])\n\n        # Wind data\n        if (\n            (wind_directions is not None)\n            or (wind_speeds is not None)\n            or (turbulence_intensities is not None)\n            or (heterogeneous_inflow_config is not None)\n        ):\n            if wind_data is not None:\n                raise ValueError(\n                    \"If wind_data is passed to reinitialize, then do not pass wind_directions, \"\n                    \"wind_speeds, turbulence_intensities or \"\n                    \"heterogeneous_inflow_config as this is redundant\"\n                )\n            elif self.wind_data is not None:\n                self.logger.warning(\"Deleting stored wind_data information.\")\n                self._wind_data = None\n        if wind_data is not None:\n\n            # Set the wind data to the current layout\n            wind_data.set_layout(farm_dict[\"layout_x\"], farm_dict[\"layout_y\"])\n\n            # Unpack wind data for reinitialization and save wind_data for use in output\n            (\n                wind_directions,\n                wind_speeds,\n                turbulence_intensities,\n                heterogeneous_inflow_config,\n            ) = wind_data.unpack_for_reinitialize()\n\n            # For backwards compatibility, multidim_conditions are unpacked separately.\n            # multidim_conditions may be included in unpack_for_reinitialize in a future release.\n            if (multidim_conditions is not None\n                and wind_data.unpack_multidim_conditions() is not None):\n                self.logger.warning(\n                    \"multidim_conditions passed to reinitialize() and also found in \"\n                    \"wind_data. Using multidim_conditions from wind_data.\"\n                )\n                multidim_conditions = wind_data.unpack_multidim_conditions()\n            elif wind_data.unpack_multidim_conditions() is not None:\n                multidim_conditions = wind_data.unpack_multidim_conditions()\n\n            self._wind_data = wind_data\n\n        ## FlowField\n        if wind_speeds is not None:\n            flow_field_dict[\"wind_speeds\"] = wind_speeds\n        if wind_directions is not None:\n            flow_field_dict[\"wind_directions\"] = wind_directions\n        if wind_shear is not None:\n            flow_field_dict[\"wind_shear\"] = wind_shear\n        if wind_veer is not None:\n            flow_field_dict[\"wind_veer\"] = wind_veer\n        if reference_wind_height is not None:\n            flow_field_dict[\"reference_wind_height\"] = reference_wind_height\n        if turbulence_intensities is not None:\n            flow_field_dict[\"turbulence_intensities\"] = turbulence_intensities\n        if air_density is not None:\n            flow_field_dict[\"air_density\"] = air_density\n        if heterogeneous_inflow_config is not None:\n            if (\n                \"z\" in heterogeneous_inflow_config\n                and flow_field_dict[\"wind_shear\"] != 0.0\n                and heterogeneous_inflow_config['z'] is not None\n            ):\n                raise ValueError(\n                    \"Heterogeneous inflow configuration contains a z term, and \"\n                    \"flow_field_dict['wind_shear'] is not 0.0. Combining both options \"\n                    \"is not currently allowed in FLORIS.  If using a z term in the \"\n                    \" heterogeneous inflow configuration, set flow_field_dict['wind_shear'] \"\n                    \"to 0.0.\"\n                )\n\n            flow_field_dict[\"heterogeneous_inflow_config\"] = heterogeneous_inflow_config\n\n        if multidim_conditions is not None:\n            flow_field_dict[\"multidim_conditions\"] = multidim_conditions\n\n\n        if solver_settings is not None:\n            floris_dict[\"solver\"] = solver_settings\n\n        floris_dict[\"flow_field\"] = flow_field_dict\n        floris_dict[\"farm\"] = farm_dict\n\n        # Create a new instance of floris and attach to self\n        self.core = Core.from_dict(floris_dict)\n\n    def set_operation(\n        self,\n        yaw_angles: NDArrayFloat | list[float] | None = None,\n        power_setpoints: NDArrayFloat | list[float] | list[float, None] | None = None,\n        awc_modes: NDArrayStr | list[str] | list[str, None] | None = None,\n        awc_amplitudes: NDArrayFloat | list[float] | list[float, None] | None = None,\n        awc_frequencies: NDArrayFloat | list[float] | list[float, None] | None = None,\n        disable_turbines: NDArrayBool | list[bool] | None = None,\n    ):\n        \"\"\"\n        Apply operating setpoints to the floris object.\n\n        This function is not meant to be called directly by most users---users should instead call\n        the set() method.\n\n        Args:\n            yaw_angles (NDArrayFloat | list[float] | None, optional): Turbine yaw angles. Defaults\n                to None.\n            power_setpoints (NDArrayFloat | list[float] | list[float, None] | None, optional):\n                Turbine power setpoints. Defaults to None.\n            disable_turbines (NDArrayBool | list[bool] | None, optional): Boolean array on whether\n                to disable turbines. Defaults to None.\n        \"\"\"\n        # Add operating conditions to the floris object\n        if yaw_angles is not None:\n            if np.array(yaw_angles).shape[1] != self.core.farm.n_turbines:\n                raise ValueError(\n                    f\"yaw_angles has a size of {np.array(yaw_angles).shape[1]} in the 1st \"\n                    f\"dimension, must be equal to n_turbines={self.core.farm.n_turbines}\"\n                )\n            self.core.farm.set_yaw_angles(yaw_angles)\n\n        if power_setpoints is not None:\n            if np.array(power_setpoints).shape[1] != self.core.farm.n_turbines:\n                raise ValueError(\n                    f\"power_setpoints has a size of {np.array(power_setpoints).shape[1]} in the 1st\"\n                    f\" dimension, must be equal to n_turbines={self.core.farm.n_turbines}\"\n                )\n            power_setpoints = np.array(power_setpoints)\n\n            # Convert any None values to the default power setpoint\n            power_setpoints[\n                power_setpoints == np.full(power_setpoints.shape, None)\n            ] = POWER_SETPOINT_DEFAULT\n            power_setpoints = floris_array_converter(power_setpoints)\n\n            self.core.farm.set_power_setpoints(power_setpoints)\n\n        if awc_modes is None:\n            awc_modes = np.array(\n                [[\"baseline\"]\n                *self.core.farm.n_turbines]\n                *self.core.flow_field.n_findex\n            )\n        self.core.farm.awc_modes = awc_modes\n\n        if awc_amplitudes is None:\n            awc_amplitudes = np.zeros(\n                (\n                    self.core.flow_field.n_findex,\n                    self.core.farm.n_turbines,\n                )\n            )\n        self.core.farm.awc_amplitudes = awc_amplitudes\n\n        if awc_frequencies is None:\n            awc_frequencies = np.zeros(\n                (\n                    self.core.flow_field.n_findex,\n                    self.core.farm.n_turbines,\n                )\n            )\n        self.core.farm.awc_frequencies = awc_frequencies\n\n        # Check for turbines to disable\n        if disable_turbines is not None:\n\n            # Force to numpy array\n            disable_turbines = np.array(disable_turbines)\n\n            # Must have first dimension = n_findex\n            if disable_turbines.shape[0] != self.core.flow_field.n_findex:\n                raise ValueError(\n                    f\"disable_turbines has a size of {disable_turbines.shape[0]} \"\n                    f\"in the 0th dimension, must be equal to \"\n                    f\"n_findex={self.core.flow_field.n_findex}\"\n                )\n\n            # Must have first dimension = n_turbines\n            if disable_turbines.shape[1] != self.core.farm.n_turbines:\n                raise ValueError(\n                    f\"disable_turbines has a size of {disable_turbines.shape[1]} \"\n                    f\"in the 1th dimension, must be equal to \"\n                    f\"n_turbines={self.core.farm.n_turbines}\"\n                )\n\n            # Set power setpoints to small value (non zero to avoid numerical issues) and\n            # yaw_angles to 0 in all locations where disable_turbines is True\n            self.core.farm.yaw_angles[disable_turbines] = 0.0\n            self.core.farm.power_setpoints[disable_turbines] = POWER_SETPOINT_DISABLED\n\n        if any([yaw_angles is not None, power_setpoints is not None, disable_turbines is not None]):\n            self.core.state = State.UNINITIALIZED\n\n    def set(\n        self,\n        wind_speeds: list[float] | NDArrayFloat | None = None,\n        wind_directions: list[float] | NDArrayFloat | None = None,\n        wind_shear: float | None = None,\n        wind_veer: float | None = None,\n        reference_wind_height: float | None = None,\n        turbulence_intensities: list[float] | NDArrayFloat | None = None,\n        air_density: float | None = None,\n        layout_x: list[float] | NDArrayFloat | None = None,\n        layout_y: list[float] | NDArrayFloat | None = None,\n        turbine_type: list | None = None,\n        turbine_library_path: str | Path | None = None,\n        solver_settings: dict | None = None,\n        heterogeneous_inflow_config: dict | None = None,\n        wind_data: type[WindDataBase] | None = None,\n        yaw_angles: NDArrayFloat | list[float] | None = None,\n        power_setpoints: NDArrayFloat | list[float] | list[float, None] | None = None,\n        awc_modes: NDArrayStr | list[str] | list[str, None] | None = None,\n        awc_amplitudes: NDArrayFloat | list[float] | list[float, None] | None = None,\n        awc_frequencies: NDArrayFloat | list[float] | list[float, None] | None = None,\n        disable_turbines: NDArrayBool | list[bool] | None = None,\n        multidim_conditions: dict | None = None,\n    ):\n        \"\"\"\n        Set the wind conditions and operation setpoints for the wind farm.\n\n        Args:\n            wind_speeds (NDArrayFloat | list[float] | None, optional): Wind speeds at each findex.\n                Defaults to None.\n            wind_directions (NDArrayFloat | list[float] | None, optional): Wind directions at each\n                findex. Defaults to None.\n            wind_shear (float | None, optional): Wind shear exponent. Defaults to None.\n            wind_veer (float | None, optional): Wind veer. Defaults to None.\n            reference_wind_height (float | None, optional): Reference wind height. Defaults to None.\n            turbulence_intensities (NDArrayFloat | list[float] | None, optional): Turbulence\n                intensities at each findex. Defaults to None.\n            air_density (float | None, optional): Air density. Defaults to None.\n            layout_x (NDArrayFloat | list[float] | None, optional): X-coordinates of the turbines.\n                Defaults to None.\n            layout_y (NDArrayFloat | list[float] | None, optional): Y-coordinates of the turbines.\n                Defaults to None.\n            turbine_type (list | None, optional): Turbine type. Defaults to None.\n            turbine_library_path (str | Path | None, optional): Path to the turbine library.\n                Defaults to None.\n            solver_settings (dict | None, optional): Solver settings. Defaults to None.\n            heterogeneous_inflow_config (dict | None, optional): heterogeneous inflow configuration.\n                Defaults to None.\n            wind_data (type[WindDataBase] | None, optional): Wind data. Defaults to None.\n            yaw_angles (NDArrayFloat | list[float] | None, optional): Turbine yaw angles.\n                Defaults to None.\n            power_setpoints (NDArrayFloat | list[float] | list[float, None] | None, optional):\n                Turbine power setpoints.\n            disable_turbines (NDArrayBool | list[bool] | None, optional): NDArray with dimensions\n                n_findex x n_turbines. True values indicate the turbine is disabled at that findex\n                and the power setpoint at that position is set to 0. Defaults to None.\n        \"\"\"\n        # Initialize a new Floris object after saving the setpoints\n        _yaw_angles = self.core.farm.yaw_angles\n        _power_setpoints = self.core.farm.power_setpoints\n        _awc_modes = self.core.farm.awc_modes\n        _awc_amplitudes = self.core.farm.awc_amplitudes\n        _awc_frequencies = self.core.farm.awc_frequencies\n        self._reinitialize(\n            wind_speeds=wind_speeds,\n            wind_directions=wind_directions,\n            wind_shear=wind_shear,\n            wind_veer=wind_veer,\n            reference_wind_height=reference_wind_height,\n            turbulence_intensities=turbulence_intensities,\n            air_density=air_density,\n            layout_x=layout_x,\n            layout_y=layout_y,\n            turbine_type=turbine_type,\n            turbine_library_path=turbine_library_path,\n            solver_settings=solver_settings,\n            heterogeneous_inflow_config=heterogeneous_inflow_config,\n            wind_data=wind_data,\n            multidim_conditions=multidim_conditions,\n        )\n\n        # If the yaw angles or power setpoints are not the default, set them back to the\n        # previous setting\n        if not (_yaw_angles == 0).all():\n            self.core.farm.set_yaw_angles(_yaw_angles)\n        if not (_power_setpoints == POWER_SETPOINT_DEFAULT).all():\n            self.core.farm.set_power_setpoints(_power_setpoints)\n        if _awc_modes is not None:\n            self.core.farm.set_awc_modes(_awc_modes)\n        if not (_awc_amplitudes == 0).all():\n            self.core.farm.set_awc_amplitudes(_awc_amplitudes)\n        if not (_awc_frequencies == 0).all():\n            self.core.farm.set_awc_frequencies(_awc_frequencies)\n\n        # Set the operation\n        self.set_operation(\n            yaw_angles=yaw_angles,\n            power_setpoints=power_setpoints,\n            awc_modes=awc_modes,\n            awc_amplitudes=awc_amplitudes,\n            awc_frequencies=awc_frequencies,\n            disable_turbines=disable_turbines,\n        )\n\n    def reset_operation(self):\n        \"\"\"\n        Instantiate a new Floris object to set all operation setpoints to their default values.\n        \"\"\"\n        self._reinitialize()\n\n    def run(self) -> None:\n        \"\"\"\n        Run the FLORIS solve to compute the velocity field and wake effects.\n        \"\"\"\n\n        # Initialize solution space\n        self.core.initialize_domain()\n\n        # Perform the wake calculations\n        self.core.steady_state_atmospheric_condition()\n\n    def run_no_wake(self) -> None:\n        \"\"\"\n        This function is similar to `run()` except that it does not apply a wake model. That is,\n        the wind farm is modeled as if there is no wake in the flow. Operation settings may\n        reduce the power and thrust of the turbine to where they're applied.\n        \"\"\"\n\n        # Initialize solution space\n        self.core.initialize_domain()\n\n        # Finalize values to user-supplied order\n        self.core.finalize()\n\n\n    ### Methods for extracting turbine performance after running\n\n    def _get_turbine_powers(self) -> NDArrayFloat:\n        \"\"\"Calculates the power at each turbine in the wind farm.\n\n        Returns:\n            NDArrayFloat: Powers at each turbine.\n        \"\"\"\n\n        # Confirm calculate wake has been run\n        if self.core.state is not State.USED:\n            raise RuntimeError(\n                \"Can't compute turbine powers without first running `FlorisModel.run()`.\"\n            )\n        # Check for negative velocities, which could indicate bad model\n        # parameters or turbines very closely spaced.\n        if (self.core.flow_field.u < 0.0).any():\n            self.logger.warning(\"Some velocities at the rotor are negative.\")\n\n        turbine_powers = power(\n            velocities=self.core.flow_field.u,\n            turbulence_intensities=self.core.flow_field.turbulence_intensity_field[:,:,None,None],\n            air_density=self.core.flow_field.air_density,\n            power_functions=self.core.farm.turbine_power_functions,\n            yaw_angles=self.core.farm.yaw_angles,\n            tilt_angles=self.core.farm.tilt_angles,\n            power_setpoints=self.core.farm.power_setpoints,\n            awc_modes = self.core.farm.awc_modes,\n            awc_amplitudes=self.core.farm.awc_amplitudes,\n            tilt_interps=self.core.farm.turbine_tilt_interps,\n            turbine_type_map=self.core.farm.turbine_type_map,\n            turbine_power_thrust_tables=self.core.farm.turbine_power_thrust_tables,\n            correct_cp_ct_for_tilt=self.core.farm.correct_cp_ct_for_tilt,\n            multidim_condition=self.core.flow_field.multidim_conditions,\n        )\n        return turbine_powers\n\n\n    def get_turbine_powers(self):\n        \"\"\"\n        Calculates the power at each turbine in the wind farm.\n\n        Returns:\n            NDArrayFloat: Powers at each turbine.\n        \"\"\"\n        turbine_powers = self._get_turbine_powers()\n\n        if self.wind_data is not None:\n            if isinstance(self.wind_data, (WindRose, WindRoseWRG)):\n                turbine_powers_rose = np.full(\n                    (len(self.wind_data.wd_flat), self.core.farm.n_turbines),\n                    np.nan\n                )\n                turbine_powers_rose[self.wind_data.non_zero_freq_mask, :] = turbine_powers\n                turbine_powers = turbine_powers_rose.reshape(\n                    len(self.wind_data.wind_directions),\n                    len(self.wind_data.wind_speeds),\n                    self.core.farm.n_turbines\n                )\n            elif type(self.wind_data) is WindTIRose:\n                turbine_powers_rose = np.full(\n                    (len(self.wind_data.wd_flat), self.core.farm.n_turbines),\n                    np.nan\n                )\n                turbine_powers_rose[self.wind_data.non_zero_freq_mask, :] = turbine_powers\n                turbine_powers = turbine_powers_rose.reshape(\n                    len(self.wind_data.wind_directions),\n                    len(self.wind_data.wind_speeds),\n                    len(self.wind_data.turbulence_intensities),\n                    self.core.farm.n_turbines\n                )\n\n        return turbine_powers\n\n    def get_expected_turbine_powers(self, freq=None):\n        \"\"\"\n        Compute the expected (mean) power of each turbine.\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape\n                with the frequencies of each wind direction and\n                wind speed combination.  freq is either a 1D array,\n                in which case the same frequencies are used for all\n                turbines, or a 2D array with shape equal to\n                (n_findex, n_turbines), in which case each turbine has a unique\n                set of frequencies (this is the case for example using\n                WindRoseByTurbine).\n\n                    These frequencies should typically sum across rows\n                up to 1.0 and are used to weigh the wind farm power for every\n                condition in calculating the wind farm's AEP. Defaults to None.\n                If None and a WindData object was supplied, the WindData object's\n                frequencies will be used. Otherwise, uniform frequencies are assumed\n                (i.e., a simple mean over the findices is computed).\n        \"\"\"\n\n        turbine_powers = self._get_turbine_powers()\n\n        if freq is None:\n            if self.wind_data is None:\n                freq = np.array([1.0/self.core.flow_field.n_findex])\n            else:\n                freq = self.wind_data.unpack_freq()\n\n        # If freq is 2d, then use the per turbine frequencies\n        if len(np.shape(freq)) == 2:\n            return np.nansum(np.multiply(freq, turbine_powers), axis=0)\n        else:\n            return np.nansum(np.multiply(freq.reshape(-1, 1), turbine_powers), axis=0)\n\n    def _get_weighted_turbine_powers(\n        self,\n        turbine_weights=None,\n        use_turbulence_correction=False,\n    ):\n        if use_turbulence_correction:\n            raise NotImplementedError(\n                \"Turbulence correction is not yet implemented in the power calculation.\"\n            )\n\n        # Confirm run() has been run\n        if self.core.state is not State.USED:\n            raise RuntimeError(\n                f\"Can't run function `{self.__class__.__name__}.get_farm_power` without \"\n                f\"first running `{self.__class__.__name__}.run`.\"\n            )\n\n        if turbine_weights is None:\n            # Default to equal weighing of all turbines when turbine_weights is None\n            turbine_weights = np.ones(\n                (\n                    self.core.flow_field.n_findex,\n                    self.core.farm.n_turbines,\n                )\n            )\n        elif len(np.shape(turbine_weights)) == 1:\n            # Deal with situation when 1D array is provided\n            turbine_weights = np.tile(\n                turbine_weights,\n                (self.core.flow_field.n_findex, 1),\n            )\n\n        # Calculate all turbine powers and apply weights\n        turbine_powers = self._get_turbine_powers()\n        turbine_powers = np.multiply(turbine_weights, turbine_powers)\n\n        return turbine_powers\n\n    def _get_farm_power(\n        self,\n        turbine_weights=None,\n        use_turbulence_correction=False,\n    ):\n        \"\"\"\n        Report wind plant power from instance of floris. Optionally includes\n        uncertainty in wind direction and yaw position when determining power.\n        Uncertainty is included by computing the mean wind farm power for a\n        distribution of wind direction and yaw position deviations from the\n        original wind direction and yaw angles.\n\n        Args:\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the power production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                objective function. If None, this  is an array with all values\n                1.0 and with shape equal to (n_findex, n_turbines).\n                Defaults to None.\n            use_turbulence_correction: (bool, optional): When True uses a\n                turbulence parameter to adjust power output calculations.\n                Defaults to False. Not currently implemented.\n\n        Returns:\n            float: Sum of wind turbine powers in W.\n        \"\"\"\n\n\n        turbine_powers = self._get_weighted_turbine_powers(\n            turbine_weights=turbine_weights,\n            use_turbulence_correction=use_turbulence_correction\n        )\n\n        return np.sum(turbine_powers, axis=1)\n\n    def get_farm_power(\n        self,\n        turbine_weights=None,\n        use_turbulence_correction=False,\n    ):\n        \"\"\"\n        Report wind plant power from instance of floris. Optionally includes\n        uncertainty in wind direction and yaw position when determining power.\n        Uncertainty is included by computing the mean wind farm power for a\n        distribution of wind direction and yaw position deviations from the\n        original wind direction and yaw angles.\n\n        Args:\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the power production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                objective function. If None, this  is an array with all values\n                1.0 and with shape equal to (n_findex, n_turbines).\n                Defaults to None.\n            use_turbulence_correction: (bool, optional): When True uses a\n                turbulence parameter to adjust power output calculations.\n                Defaults to False. Not currently implemented.\n\n        Returns:\n            float: Sum of wind turbine powers in W.\n        \"\"\"\n        farm_power = self._get_farm_power(turbine_weights, use_turbulence_correction)\n\n        if self.wind_data is not None:\n            if isinstance(self.wind_data, (WindRose, WindRoseWRG)):\n                farm_power_rose = np.full(len(self.wind_data.wd_flat), np.nan)\n                farm_power_rose[self.wind_data.non_zero_freq_mask] = farm_power\n                farm_power = farm_power_rose.reshape(\n                    len(self.wind_data.wind_directions),\n                    len(self.wind_data.wind_speeds)\n                )\n            elif type(self.wind_data) is WindTIRose:\n                farm_power_rose = np.full(len(self.wind_data.wd_flat), np.nan)\n                farm_power_rose[self.wind_data.non_zero_freq_mask] = farm_power\n                farm_power = farm_power_rose.reshape(\n                    len(self.wind_data.wind_directions),\n                    len(self.wind_data.wind_speeds),\n                    len(self.wind_data.turbulence_intensities)\n                )\n\n        return farm_power\n\n    def get_expected_farm_power(\n            self,\n            freq=None,\n            turbine_weights=None,\n    ) -> float:\n        \"\"\"\n        Compute the expected (mean) power of the wind farm.\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape (n_findex)\n                with the frequencies of each wind direction and\n                wind speed combination. These frequencies should typically sum\n                up to 1.0 and are used to weigh the wind farm power for every\n                condition in calculating the wind farm's AEP. Defaults to None.\n                If None and a WindData object was supplied, the WindData object's\n                frequencies will be used. Otherwise, uniform frequencies are assumed\n                (i.e., a simple mean over the findices is computed).\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the power production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                objective function. If None, this  is an array with all values\n                1.0 and with shape equal to (n_findex,\n                n_turbines). Defaults to None.\n        \"\"\"\n\n        if freq is None:\n            if self.wind_data is None:\n                freq = np.array([1.0/self.core.flow_field.n_findex])\n            else:\n                freq = self.wind_data.unpack_freq()\n\n        # If freq is 1d\n        if len(np.shape(freq)) == 1:\n            farm_power = self._get_farm_power(turbine_weights=turbine_weights)\n            return np.nansum(np.multiply(freq, farm_power))\n        else:\n            weighted_turbine_powers = self._get_weighted_turbine_powers(\n                turbine_weights=turbine_weights,\n            )\n            return np.nansum(np.multiply(freq, weighted_turbine_powers))\n\n    def get_farm_AEP(\n        self,\n        freq=None,\n        turbine_weights=None,\n        hours_per_year=8760,\n    ) -> float:\n        \"\"\"\n        Estimate annual energy production (AEP) for distributions of wind speed, wind\n        direction, frequency of occurrence, and yaw offset.\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape (n_findex)\n                with the frequencies of each wind direction and\n                wind speed combination. These frequencies should typically sum\n                up to 1.0 and are used to weigh the wind farm power for every\n                condition in calculating the wind farm's AEP. Defaults to None.\n                If None and a WindData object was supplied, the WindData object's\n                frequencies will be used. Otherwise, uniform frequencies are assumed.\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the power production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                objective function. If None, this  is an array with all values\n                1.0 and with shape equal to (n_findex,\n                n_turbines). Defaults to None.\n            hours_per_year (float, optional): Number of hours in a year. Defaults to 365 * 24.\n\n        Returns:\n            float:\n                The Annual Energy Production (AEP) for the wind farm in\n                watt-hours.\n        \"\"\"\n        if freq is None and not isinstance(self.wind_data, (WindRose, WindRoseWRG, WindTIRose)):\n            self.logger.warning(\n                \"Computing AEP with uniform frequencies. Results results may not reflect annual \"\n                \"operation.\"\n            )\n\n        return self.get_expected_farm_power(\n            freq=freq,\n            turbine_weights=turbine_weights\n        ) * hours_per_year\n\n    def get_expected_farm_value(\n            self,\n            freq=None,\n            values=None,\n            turbine_weights=None,\n    ) -> float:\n        \"\"\"\n        Compute the expected (mean) value produced by the wind farm. This is\n        computed by multiplying the wind farm power for each wind condition by\n        the corresponding value of the power generated (e.g., electricity\n        market price per unit of energy), then weighting by frequency and\n        summing over all conditions.\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape (n_findex)\n                with the frequencies of each wind condition combination.\n                These frequencies should typically sum up to 1.0 and are used\n                to weigh the wind farm value for every condition in calculating\n                the wind farm's expected value. Defaults to None. If None and a\n                WindData object is supplied, the WindData object's frequencies\n                will be used. Otherwise, uniform frequencies are assumed (i.e.,\n                a simple mean over the findices is computed).\n            values (NDArrayFloat): NumPy array with shape (n_findex)\n                with the values corresponding to the power generated for each\n                wind condition combination. The wind farm power is multiplied\n                by the value for every condition in calculating the wind farm's\n                expected value. Defaults to None. If None and a WindData object\n                is supplied, the WindData object's values will be used.\n                Otherwise, a value of 1 for all conditions is assumed (i.e.,\n                the expected farm value will be equivalent to the expected farm\n                power).\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the value production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                expected value. If None, this is an array with all values 1.0\n                and with shape equal to (n_findex, n_turbines). Defaults to None.\n\n        Returns:\n            float:\n                The expected value produced by the wind farm in units of value.\n        \"\"\"\n        if freq is None:\n            if self.wind_data is None:\n                freq = np.array([1.0/self.core.flow_field.n_findex])\n            else:\n                freq = self.wind_data.unpack_freq()\n        # If freq is 1d\n        if len(np.shape(freq)) == 1:\n            farm_power = self._get_farm_power(turbine_weights=turbine_weights)\n            farm_power = np.multiply(freq, farm_power)\n        else:\n            weighted_turbine_powers = self._get_weighted_turbine_powers(\n                turbine_weights=turbine_weights\n            )\n            farm_power = np.nansum(np.multiply(freq, weighted_turbine_powers), axis=1)\n        if values is None:\n            if self.wind_data is None:\n                values = np.array([1.0])\n            else:\n                values = self.wind_data.unpack_value()\n        return np.nansum(np.multiply(values, farm_power))\n\n    def get_farm_AVP(\n        self,\n        freq=None,\n        values=None,\n        turbine_weights=None,\n        hours_per_year=8760,\n    ) -> float:\n        \"\"\"\n        Estimate annual value production (AVP) for distribution of wind\n        conditions, frequencies of occurrence, and corresponding values of\n        power generated (e.g., electricity price per unit of energy).\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape (n_findex)\n                with the frequencies of each wind condition combination.\n                These frequencies should typically sum up to 1.0 and are used\n                to weigh the wind farm value for every condition in calculating\n                the wind farm's AVP. Defaults to None. If None and a\n                WindData object is supplied, the WindData object's frequencies\n                will be used. Otherwise, uniform frequencies are assumed (i.e.,\n                a simple mean over the findices is computed).\n            values (NDArrayFloat): NumPy array with shape (n_findex)\n                with the values corresponding to the power generated for each\n                wind condition combination. The wind farm power is multiplied\n                by the value for every condition in calculating the wind farm's\n                AVP. Defaults to None. If None and a WindData object is\n                supplied, the WindData object's values will be used. Otherwise,\n                a value of 1 for all conditions is assumed (i.e., the AVP will\n                be equivalent to the AEP).\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the value production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris is\n                multiplied with this array in the calculation of the AVP. If\n                None, this is an array with all values 1.0 and with shape equal\n                to (n_findex, n_turbines). Defaults to None.\n            hours_per_year (float, optional): Number of hours in a year.\n                Defaults to 365 * 24.\n\n        Returns:\n            float:\n                The Annual Value Production (AVP) for the wind farm in units\n                of value.\n        \"\"\"\n        if (\n            freq is None\n            and not isinstance(self.wind_data, WindRose)\n            and not isinstance(self.wind_data, WindRoseWRG)\n            and not isinstance(self.wind_data, WindTIRose)\n        ):\n            self.logger.warning(\n                \"Computing AVP with uniform frequencies. Results results may not reflect annual \"\n                \"operation.\"\n            )\n\n        if values is None and self.wind_data is None:\n            self.logger.warning(\n                \"Computing AVP with uniform value equal to 1. Results will be equivalent to \"\n                \"annual energy production.\"\n            )\n\n        return self.get_expected_farm_value(\n            freq=freq,\n            values=values,\n            turbine_weights=turbine_weights\n        ) * hours_per_year\n\n    def get_turbine_ais(self) -> NDArrayFloat:\n        turbine_ais = axial_induction(\n            velocities=self.core.flow_field.u,\n            turbulence_intensities=self.core.flow_field.turbulence_intensity_field[:,:,None,None],\n            air_density=self.core.flow_field.air_density,\n            yaw_angles=self.core.farm.yaw_angles,\n            tilt_angles=self.core.farm.tilt_angles,\n            power_setpoints=self.core.farm.power_setpoints,\n            awc_modes = self.core.farm.awc_modes,\n            awc_amplitudes=self.core.farm.awc_amplitudes,\n            axial_induction_functions=self.core.farm.turbine_axial_induction_functions,\n            tilt_interps=self.core.farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=self.core.farm.correct_cp_ct_for_tilt,\n            turbine_type_map=self.core.farm.turbine_type_map,\n            turbine_power_thrust_tables=self.core.farm.turbine_power_thrust_tables,\n            average_method=self.core.grid.average_method,\n            cubature_weights=self.core.grid.cubature_weights,\n            multidim_condition=self.core.flow_field.multidim_conditions,\n        )\n        return turbine_ais\n\n    def get_turbine_thrust_coefficients(self) -> NDArrayFloat:\n        turbine_thrust_coefficients = thrust_coefficient(\n            velocities=self.core.flow_field.u,\n            turbulence_intensities=self.core.flow_field.turbulence_intensity_field[:,:,None,None],\n            air_density=self.core.flow_field.air_density,\n            yaw_angles=self.core.farm.yaw_angles,\n            tilt_angles=self.core.farm.tilt_angles,\n            power_setpoints=self.core.farm.power_setpoints,\n            awc_modes = self.core.farm.awc_modes,\n            awc_amplitudes=self.core.farm.awc_amplitudes,\n            thrust_coefficient_functions=self.core.farm.turbine_thrust_coefficient_functions,\n            tilt_interps=self.core.farm.turbine_tilt_interps,\n            correct_cp_ct_for_tilt=self.core.farm.correct_cp_ct_for_tilt,\n            turbine_type_map=self.core.farm.turbine_type_map,\n            turbine_power_thrust_tables=self.core.farm.turbine_power_thrust_tables,\n            average_method=self.core.grid.average_method,\n            cubature_weights=self.core.grid.cubature_weights,\n            multidim_condition=self.core.flow_field.multidim_conditions,\n        )\n        return turbine_thrust_coefficients\n\n    def get_turbine_TIs(self) -> NDArrayFloat:\n        return self.core.flow_field.turbulence_intensity_field\n\n\n    ### Methods for sampling and visualization\n\n    def set_for_viz(self, findex: int, solver_settings: dict) -> None:\n        \"\"\"\n        Set the floris object to a single findex for visualization.\n\n        Args:\n            findex (int): The findex to set the floris object to.\n            solver_settings (dict): The solver settings to use for visualization.\n        \"\"\"\n\n        # If not None, set the heterogeneous inflow configuration\n        if self.core.flow_field.heterogeneous_inflow_config is not None:\n            heterogeneous_inflow_config = {\n                'x': self.core.flow_field.heterogeneous_inflow_config['x'],\n                'y': self.core.flow_field.heterogeneous_inflow_config['y'],\n                'speed_multipliers':\n                    self.core.flow_field.heterogeneous_inflow_config['speed_multipliers'][findex:findex+1],\n                'interp_method': self.core.flow_field.heterogeneous_inflow_config['interp_method'],\n            }\n            if 'z' in self.core.flow_field.heterogeneous_inflow_config:\n                heterogeneous_inflow_config['z'] = (\n                    self.core.flow_field.heterogeneous_inflow_config['z']\n                )\n        else:\n            heterogeneous_inflow_config = None\n\n        self.set(\n            wind_speeds=self.wind_speeds[findex:findex+1],\n            wind_directions=self.wind_directions[findex:findex+1],\n            turbulence_intensities=self.turbulence_intensities[findex:findex+1],\n            yaw_angles=self.core.farm.yaw_angles[findex:findex+1,:],\n            power_setpoints=self.core.farm.power_setpoints[findex:findex+1,:],\n            awc_modes=self.core.farm.awc_modes[findex:findex+1,:],\n            awc_amplitudes=self.core.farm.awc_amplitudes[findex:findex+1,:],\n            heterogeneous_inflow_config = heterogeneous_inflow_config,\n            solver_settings=solver_settings,\n        )\n\n    def calculate_cross_plane(\n        self,\n        downstream_dist,\n        y_resolution=200,\n        z_resolution=200,\n        y_bounds=None,\n        z_bounds=None,\n        findex_for_viz=None,\n    ):\n        \"\"\"\n        Shortcut method to instantiate a :py:class:`~.tools.cut_plane.CutPlane`\n        object containing the velocity field in a vertical plane cut through\n        the simulation domain at a specific downstream (x) distance.\n\n        Args:\n            downstream_dist (float): Distance downstream to compute.\n            y_resolution (float, optional): Output array resolution.\n                Defaults to 200 points.\n            z_resolution (float, optional): Output array resolution.\n                Defaults to 200 points.\n            y_bounds (tuple, optional): Limits of output array (in m).\n                Defaults to None.\n            z_bounds (tuple, optional): Limits of output array (in m).\n                Defaults to None.\n            finder_for_viz (int, optional): Index of the condition to visualize.\n        Returns:\n            :py:class:`~.tools.cut_plane.CutPlane`: containing values\n            of y, z, u, v, w\n        \"\"\"\n        if self.n_findex > 1 and findex_for_viz is None:\n            self.logger.warning(\n                \"Multiple findices detected. Using first findex for visualization.\"\n            )\n        if findex_for_viz is None:\n            findex_for_viz = 0\n\n        # Store the current state for reinitialization\n        fmodel_viz = copy.deepcopy(self)\n\n        # Set the solver to a flow field planar grid\n        solver_settings = {\n            \"type\": \"flow_field_planar_grid\",\n            \"normal_vector\": \"x\",\n            \"planar_coordinate\": downstream_dist,\n            \"flow_field_grid_points\": [y_resolution, z_resolution],\n            \"flow_field_bounds\": [y_bounds, z_bounds],\n        }\n        fmodel_viz.set_for_viz(findex_for_viz, solver_settings)\n\n        # Calculate wake\n        fmodel_viz.core.solve_for_viz()\n\n        # Get the points of data in a dataframe\n        # TODO this just seems to be flattening and storing the data in a df; is this necessary?\n        # It seems the biggest dependency is on CutPlane and the subsequent visualization tools.\n        df = fmodel_viz.get_plane_of_points(\n            normal_vector=\"x\",\n            planar_coordinate=downstream_dist,\n        )\n\n        # Compute the cutplane\n        cross_plane = CutPlane(df, y_resolution, z_resolution, \"x\")\n\n        return cross_plane\n\n    def calculate_horizontal_plane(\n        self,\n        height,\n        x_resolution=200,\n        y_resolution=200,\n        x_bounds=None,\n        y_bounds=None,\n        findex_for_viz=None,\n    ):\n        \"\"\"\n        Shortcut method to instantiate a :py:class:`~.tools.cut_plane.CutPlane`\n        object containing the velocity field in a horizontal plane cut through\n        the simulation domain at a specific height.\n\n        Args:\n            height (float): Height of cut plane. Defaults to Hub-height.\n            x_resolution (float, optional): Output array resolution.\n                Defaults to 200 points.\n            y_resolution (float, optional): Output array resolution.\n                Defaults to 200 points.\n            x_bounds (tuple, optional): Limits of output array (in m).\n                Defaults to None.\n            y_bounds (tuple, optional): Limits of output array (in m).\n                Defaults to None.\n            findex_for_viz (int, optional): Index of the condition to visualize.\n\n        Returns:\n            :py:class:`~.tools.cut_plane.CutPlane`: containing values\n            of x, y, u, v, w\n        \"\"\"\n        if self.n_findex > 1 and findex_for_viz is None:\n            self.logger.warning(\n                \"Multiple findices detected. Using first findex for visualization.\"\n            )\n        if findex_for_viz is None:\n            findex_for_viz = 0\n\n        # Store the current state for reinitialization\n        fmodel_viz = copy.deepcopy(self)\n\n        # Set the solver to a flow field planar grid\n        solver_settings = {\n            \"type\": \"flow_field_planar_grid\",\n            \"normal_vector\": \"z\",\n            \"planar_coordinate\": height,\n            \"flow_field_grid_points\": [x_resolution, y_resolution],\n            \"flow_field_bounds\": [x_bounds, y_bounds],\n        }\n        fmodel_viz.set_for_viz(findex_for_viz, solver_settings)\n\n        # Calculate wake\n        fmodel_viz.core.solve_for_viz()\n\n        # Get the points of data in a dataframe\n        # TODO this just seems to be flattening and storing the data in a df; is this necessary?\n        # It seems the biggest depenedcy is on CutPlane and the subsequent visualization tools.\n        df = fmodel_viz.get_plane_of_points(\n            normal_vector=\"z\",\n            planar_coordinate=height,\n        )\n\n        # Compute the cutplane\n        horizontal_plane = CutPlane(\n            df,\n            fmodel_viz.core.grid.grid_resolution[0],\n            fmodel_viz.core.grid.grid_resolution[1],\n            \"z\",\n        )\n\n        return horizontal_plane\n\n    def calculate_y_plane(\n        self,\n        crossstream_dist,\n        x_resolution=200,\n        z_resolution=200,\n        x_bounds=None,\n        z_bounds=None,\n        findex_for_viz=None,\n    ):\n        \"\"\"\n        Shortcut method to instantiate a :py:class:`~.tools.cut_plane.CutPlane`\n        object containing the velocity field in a vertical plane cut through\n        the simulation domain at a specific cross-stream (y) distance.\n\n        Args:\n            crossstream_dist (float): Cross-stream distance to compute.\n            x_resolution (float, optional): Output array resolution.\n                Defaults to 200 points.\n            z_resolution (float, optional): Output array resolution.\n                Defaults to 200 points.\n            x_bounds (tuple, optional): Limits of output array (in m).\n                Defaults to None.\n            z_bounds (tuple, optional): Limits of output array (in m).\n                Defaults to None.\n            findex_for_viz (int, optional): Index of the condition to visualize.\n                Defaults to 0.\n\n        Returns:\n            :py:class:`~.tools.cut_plane.CutPlane`: containing values\n            of x, z, u, v, w\n        \"\"\"\n        if self.n_findex > 1 and findex_for_viz is None:\n            self.logger.warning(\n                \"Multiple findices detected. Using first findex for visualization.\"\n            )\n        if findex_for_viz is None:\n            findex_for_viz = 0\n\n        # Store the current state for reinitialization\n        fmodel_viz = copy.deepcopy(self)\n\n        # Set the solver to a flow field planar grid\n        solver_settings = {\n            \"type\": \"flow_field_planar_grid\",\n            \"normal_vector\": \"y\",\n            \"planar_coordinate\": crossstream_dist,\n            \"flow_field_grid_points\": [x_resolution, z_resolution],\n            \"flow_field_bounds\": [x_bounds, z_bounds],\n        }\n        fmodel_viz.set_for_viz(findex_for_viz, solver_settings)\n\n        # Calculate wake\n        fmodel_viz.core.solve_for_viz()\n\n        # Get the points of data in a dataframe\n        # TODO this just seems to be flattening and storing the data in a df; is this necessary?\n        # It seems the biggest dependency is on CutPlane and the subsequent visualization tools.\n        df = fmodel_viz.get_plane_of_points(\n            normal_vector=\"y\",\n            planar_coordinate=crossstream_dist,\n        )\n\n        # Compute the cutplane\n        y_plane = CutPlane(df, x_resolution, z_resolution, \"y\")\n\n        return y_plane\n\n    def get_plane_of_points(\n        self,\n        normal_vector=\"z\",\n        planar_coordinate=None,\n    ):\n        \"\"\"\n        Calculates velocity values through the\n        :py:meth:`FlorisModel.calculate_wake` method at points in plane\n        specified by inputs.\n\n        Args:\n            normal_vector (string, optional): Vector normal to plane.\n                Defaults to z.\n            planar_coordinate (float, optional): Value of normal vector\n                to slice through. Defaults to None.\n\n        Returns:\n            :py:class:`pandas.DataFrame`: containing values of x1, x2, x3, u, v, w\n        \"\"\"\n        # Get results vectors\n        if normal_vector == \"z\":\n            x_flat = self.core.grid.x_sorted_inertial_frame[0].flatten()\n            y_flat = self.core.grid.y_sorted_inertial_frame[0].flatten()\n            z_flat = self.core.grid.z_sorted_inertial_frame[0].flatten()\n        else:\n            x_flat = self.core.grid.x_sorted[0].flatten()\n            y_flat = self.core.grid.y_sorted[0].flatten()\n            z_flat = self.core.grid.z_sorted[0].flatten()\n        u_flat = self.core.flow_field.u_sorted[0].flatten()\n        v_flat = self.core.flow_field.v_sorted[0].flatten()\n        w_flat = self.core.flow_field.w_sorted[0].flatten()\n\n        # Create a df of these\n        if normal_vector == \"z\":\n            df = pd.DataFrame(\n                {\n                    \"x1\": x_flat,\n                    \"x2\": y_flat,\n                    \"x3\": z_flat,\n                    \"u\": u_flat,\n                    \"v\": v_flat,\n                    \"w\": w_flat,\n                }\n            )\n        if normal_vector == \"x\":\n            df = pd.DataFrame(\n                {\n                    \"x1\": y_flat,\n                    \"x2\": z_flat,\n                    \"x3\": x_flat,\n                    \"u\": u_flat,\n                    \"v\": v_flat,\n                    \"w\": w_flat,\n                }\n            )\n        if normal_vector == \"y\":\n            df = pd.DataFrame(\n                {\n                    \"x1\": x_flat,\n                    \"x2\": z_flat,\n                    \"x3\": y_flat,\n                    \"u\": u_flat,\n                    \"v\": v_flat,\n                    \"w\": w_flat,\n                }\n            )\n\n        # Subset to plane\n        # TODO: Seems sloppy as need more than one plane in the z-direction for GCH\n        if planar_coordinate is not None:\n            df = df[np.isclose(df.x3, planar_coordinate)]  # , atol=0.1, rtol=0.0)]\n\n        # Drop duplicates\n        # TODO is this still needed now that we setup a grid for just this plane?\n        df = df.drop_duplicates()\n\n        # Sort values of df to make sure plotting is acceptable\n        df = df.sort_values([\"x2\", \"x1\"]).reset_index(drop=True)\n\n        return df\n\n    def sample_flow_at_points(self, x: NDArrayFloat, y: NDArrayFloat, z: NDArrayFloat):\n        \"\"\"\n        Extract the wind speed at points in the flow.\n\n        Args:\n            x (1DArrayFloat | list): x-locations of points where flow is desired.\n            y (1DArrayFloat | list): y-locations of points where flow is desired.\n            z (1DArrayFloat | list): z-locations of points where flow is desired.\n\n        Returns:\n            3DArrayFloat containing wind speed with dimensions\n            (# of findex, # of sample points)\n        \"\"\"\n\n        # Check that x, y, z are all the same length\n        if not len(x) == len(y) == len(z):\n            raise ValueError(\"x, y, and z must be the same size\")\n\n        return self.core.solve_for_points(x, y, z)\n\n    def sample_ti_at_points(self, x: NDArrayFloat, y: NDArrayFloat, z: NDArrayFloat):\n        \"\"\"\n        Extract the turbulence intensity at points in the flow.\n\n        Args:\n            x (1DArrayFloat | list): x-locations of points where TI is desired.\n            y (1DArrayFloat | list): y-locations of points where TI is desired.\n            z (1DArrayFloat | list): z-locations of points where TI is desired.\n\n        Returns:\n            3DArrayFloat containing turbulence intensity with dimensions\n            (# of findex, # of sample points)\n        \"\"\"\n\n        self.sample_flow_at_points(x, y, z) # Solve, but ignore returned velocities\n\n        # Remove grid dimensions and return sorted TI field\n        return self.core.flow_field.turbulence_intensity_field_sorted[:, :, 0, 0]\n\n    def sample_velocity_deficit_profiles(\n        self,\n        direction: str = \"cross-stream\",\n        downstream_dists: NDArrayFloat | list = None,\n        profile_range: NDArrayFloat | list = None,\n        resolution: int = 100,\n        wind_direction: float = None,\n        homogeneous_wind_speed: float = None,\n        ref_rotor_diameter: float = None,\n        x_start: float = 0.0,\n        y_start: float = 0.0,\n        reference_height: float = None,\n    ) -> list[pd.DataFrame]:\n        \"\"\"\n        Extract velocity deficit profiles at a set of downstream distances from a starting point\n        (usually a turbine location). For each downstream distance, a profile is sampled along\n        a line in either the cross-stream direction (x2) or the vertical direction (x3).\n        Velocity deficit is here defined as (homogeneous_wind_speed - u)/homogeneous_wind_speed,\n        where u is the wake velocity obtained when wind_shear = 0.0.\n\n        Args:\n            direction: At each downstream location, this is the direction in which to sample the\n                profile. Either `cross-stream` or `vertical`.\n            downstream_dists: A list/array of streamwise locations for where to sample the profiles.\n                Default starting point is (0.0, 0.0, reference_height).\n            profile_range: Determines the extent of the line along which the profiles are sampled.\n                The range is defined about a point which lies some distance directly downstream of\n                the starting point.\n            resolution: Number of sample points in each profile.\n            wind_direction: A single wind direction.\n            homogeneous_wind_speed: A single wind speed. It is called homogeneous since 'wind_shear'\n                is temporarily set to 0.0 in this method.\n            ref_rotor_diameter: A reference rotor diameter which is used to normalize the\n                coordinates.\n            x_start: x-coordinate of starting point.\n            y_start: y-coordinate of starting point.\n            reference_height: If `direction` is cross-stream, then `reference_height` defines the\n                height of the horizontal plane in which the velocity profiles are sampled.\n                If `direction` is vertical, then the velocity is sampled along the vertical\n                direction with the `profile_range` being relative to the `reference_height`.\n        Returns:\n            A list of pandas DataFrame objects where each DataFrame represents one velocity deficit\n            profile.\n        \"\"\"\n\n        if direction not in [\"cross-stream\", \"vertical\"]:\n            raise ValueError(\"`direction` must be either `cross-stream` or `vertical`.\")\n\n        if ref_rotor_diameter is None:\n            unique_rotor_diameters = np.unique(self.core.farm.rotor_diameters)\n            if len(unique_rotor_diameters) == 1:\n                ref_rotor_diameter = unique_rotor_diameters[0]\n            else:\n                raise ValueError(\n                    \"Please provide a `ref_rotor_diameter`. This is needed to normalize the \"\n                    \"coordinates. Could not select a value automatically since the number of \"\n                    \"unique rotor diameters in the turbine layout is not 1. \"\n                    f\"Found the following rotor diameters: {unique_rotor_diameters}.\"\n                )\n\n        if downstream_dists is None:\n            downstream_dists = ref_rotor_diameter * np.array([3, 5, 7, 9])\n\n        if profile_range is None:\n            profile_range = ref_rotor_diameter * np.array([-2, 2])\n\n        wind_directions_copy = np.array(self.core.flow_field.wind_directions, copy=True)\n        wind_speeds_copy = np.array(self.core.flow_field.wind_speeds, copy=True)\n        wind_shear_copy = self.core.flow_field.wind_shear\n\n        if wind_direction is None:\n            if len(wind_directions_copy) == 1:\n                wind_direction = wind_directions_copy[0]\n            else:\n                raise ValueError(\n                    \"Could not determine a wind direction for which to sample the velocity \"\n                    \"profiles. Either provide a single `wind_direction` as an argument to this \"\n                    \"method, or initialize the Floris object with a single wind direction.\"\n                )\n\n        if homogeneous_wind_speed is None:\n            if len(wind_speeds_copy) == 1:\n                homogeneous_wind_speed = wind_speeds_copy[0]\n                self.logger.warning(\n                    \"`homogeneous_wind_speed` not provided. Setting it to the following wind speed \"\n                    f\"found in the current flow field: {wind_speeds_copy[0]} m/s. Note that the \"\n                    \"inflow is always homogeneous when calculating the velocity deficit profiles. \"\n                    \"This is done by temporarily setting `wind_shear` to 0.0\"\n                )\n            else:\n                raise ValueError(\n                    \"Could not determine a wind speed for which to sample the velocity \"\n                    \"profiles. Provide a single `homogeneous_wind_speed` to this method.\"\n                )\n\n        if reference_height is None:\n            reference_height = self.core.flow_field.reference_wind_height\n\n        self.set(\n            wind_directions=[wind_direction],\n            wind_speeds=[homogeneous_wind_speed],\n            wind_shear=0.0,\n        )\n\n        velocity_deficit_profiles = self.core.solve_for_velocity_deficit_profiles(\n            direction,\n            downstream_dists,\n            profile_range,\n            resolution,\n            homogeneous_wind_speed,\n            ref_rotor_diameter,\n            x_start,\n            y_start,\n            reference_height,\n        )\n\n        self.set(\n            wind_directions=wind_directions_copy,\n            wind_speeds=wind_speeds_copy,\n            wind_shear=wind_shear_copy,\n        )\n\n        return velocity_deficit_profiles\n\n\n    ### Utility methods\n\n    def assign_hub_height_to_ref_height(self):\n\n        # Confirm can do this operation\n        unique_heights = np.unique(self.core.farm.hub_heights)\n        if len(unique_heights) > 1:\n            raise ValueError(\n                \"To assign hub heights to reference height, can not have more than one \"\n                \"specified height. \"\n                f\"Current length is {unique_heights}.\"\n            )\n\n        self.core.flow_field.reference_wind_height = unique_heights[0]\n\n    def get_operation_model(self) -> str:\n        \"\"\"Get the operation model of a FlorisModel.\n\n        Returns:\n            str: The operation_model.\n        \"\"\"\n        operation_models = [\n            self.core.farm.turbine_definitions[tindex][\"operation_model\"]\n            for tindex in range(self.core.farm.n_turbines)\n        ]\n        if len(set(operation_models)) == 1:\n            return operation_models[0]\n        else:\n            return operation_models\n\n    def set_operation_model(self, operation_model: str | List[str]):\n        \"\"\"Set the turbine operation model(s).\n\n        Args:\n            operation_model (str): The operation model to set.\n        \"\"\"\n        if isinstance(operation_model, str):\n            if len(self.core.farm.turbine_type) == 1:\n                # Set a single one here, then, and return\n                turbine_type = self.core.farm.turbine_definitions[0]\n                turbine_type[\"operation_model\"] = operation_model\n                self.set(\n                    turbine_type=[turbine_type],\n                    reference_wind_height=self.reference_wind_height\n                )\n                return\n            else:\n                operation_model = [operation_model]*self.core.farm.n_turbines\n\n        if len(operation_model) != self.core.farm.n_turbines:\n            raise ValueError(\n                    \"The length of the operation_model list must be \"\n                    \"equal to the number of turbines.\"\n                )\n\n        turbine_type_list = self.core.farm.turbine_definitions\n\n        for tindex in range(self.core.farm.n_turbines):\n            turbine_type_list[tindex][\"turbine_type\"] = (\n                turbine_type_list[tindex][\"turbine_type\"]+\"_\"+operation_model[tindex]\n            )\n            turbine_type_list[tindex][\"operation_model\"] = operation_model[tindex]\n\n        self.set(\n            turbine_type=turbine_type_list,\n            reference_wind_height=self.reference_wind_height\n        )\n\n    def copy(self):\n        \"\"\"Create an independent copy of the current FlorisModel object\n\n        When creating the copy, this method uses self.__class__(), rather than FlorisModel()\n        directly, so that subclasses of FlorisModel can inherit this method and return\n        instantiations of their own class, rather than the FlorisModel class.\n        \"\"\"\n        return self.__class__(self.core.as_dict(), **self.secondary_init_kwargs)\n\n    def get_param(\n        self,\n        param: List[str],\n        param_idx: Optional[int] = None\n    ) -> Any:\n        \"\"\"Get a parameter from a FlorisModel object.\n\n        Args:\n            param (List[str]): A list of keys to traverse the FlorisModel dictionary.\n            param_idx (Optional[int], optional): The index to get the value at. Defaults to None.\n                If None, the entire parameter is returned.\n\n        Returns:\n            Any: The value of the parameter.\n        \"\"\"\n        fm_dict = self.core.as_dict()\n\n        if param_idx is None:\n            return nested_get(fm_dict, param)\n        else:\n            return nested_get(fm_dict, param)[param_idx]\n\n    def set_param(\n        self,\n        param: List[str],\n        value: Any,\n        param_idx: Optional[int] = None\n    ):\n        \"\"\"Set a parameter in a FlorisModel object.\n\n        Args:\n            param (List[str]): A list of keys to traverse the FlorisModel dictionary.\n            value (Any): The value to set.\n            param_idx (Optional[int], optional): The index to set the value at. Defaults to None.\n        \"\"\"\n        fm_dict_mod = self.core.as_dict()\n        nested_set(fm_dict_mod, param, value, param_idx)\n        self.__init__(fm_dict_mod, **self.secondary_init_kwargs)\n\n    def get_turbine_layout(self, z=False):\n        \"\"\"\n        Get turbine layout\n\n        Args:\n            z (bool): When *True*, return lists of x, y, and z coords,\n            otherwise, return x and y only. Defaults to *False*.\n\n        Returns:\n            np.array: lists of x, y, and (optionally) z coordinates of\n                each turbine\n        \"\"\"\n        xcoords, ycoords, zcoords = self.core.farm.coordinates.T\n        if z:\n            return xcoords, ycoords, zcoords\n        else:\n            return xcoords, ycoords\n\n    def show_config(self, full=False) -> None:\n        \"\"\"Print the FlorisModel dictionary.\n        \"\"\"\n        config_dict = self.core.as_dict()\n        if not full:\n            del config_dict[\"logging\"]\n            del config_dict[\"wake\"][\"enable_secondary_steering\"]\n            del config_dict[\"wake\"][\"enable_yaw_added_recovery\"]\n            del config_dict[\"wake\"][\"enable_transverse_velocities\"]\n            del config_dict[\"wake\"][\"enable_active_wake_mixing\"]\n            del config_dict[\"wake\"][\"wake_deflection_parameters\"]\n            del config_dict[\"wake\"][\"wake_velocity_parameters\"]\n            del config_dict[\"wake\"][\"wake_turbulence_parameters\"]\n        print_nested_dict(config_dict)\n\n    def print_dict(self) -> None:\n        \"\"\"Print the FlorisModel dictionary.\n        \"\"\"\n        self.logger.warning(\n            \"The print_dict() method has been deprecated.\"\n            \" Please use the show_config() method instead.\"\n        )\n        self.show_config(full=True)\n\n    ### Properties\n\n    @property\n    def secondary_init_kwargs(self):\n        \"\"\"\n        FlorisModel takes only the configuration argument. This method is a placeholder for\n        subclasses of FlorisModel.\n        \"\"\"\n        return {}\n\n    @property\n    def layout_x(self):\n        \"\"\"\n        Wind turbine coordinate information.\n\n        Returns:\n            np.array: Wind turbine x-coordinate.\n        \"\"\"\n        return self.core.farm.layout_x\n\n    @property\n    def layout_y(self):\n        \"\"\"\n        Wind turbine coordinate information.\n\n        Returns:\n            np.array: Wind turbine y-coordinate.\n        \"\"\"\n        return self.core.farm.layout_y\n\n    @property\n    def wind_directions(self):\n        \"\"\"\n        Wind direction information.\n\n        Returns:\n            np.array: Wind direction.\n        \"\"\"\n        return self.core.flow_field.wind_directions\n\n    @property\n    def wind_speeds(self):\n        \"\"\"\n        Wind speed information.\n\n        Returns:\n            np.array: Wind speed.\n        \"\"\"\n        return self.core.flow_field.wind_speeds\n\n    @property\n    def turbulence_intensities(self):\n        \"\"\"\n        Turbulence intensity information.\n\n        Returns:\n            np.array: Turbulence intensity.\n        \"\"\"\n        return self.core.flow_field.turbulence_intensities\n\n    @property\n    def n_findex(self):\n        \"\"\"\n        Number of floris indices (findex).\n\n        Returns:\n            int: Number of flow indices.\n        \"\"\"\n        return self.core.flow_field.n_findex\n\n    @property\n    def n_turbines(self):\n        \"\"\"\n        Number of turbines.\n\n        Returns:\n            int: Number of turbines.\n        \"\"\"\n        return self.core.farm.n_turbines\n\n    @property\n    def reference_wind_height(self):\n        \"\"\"\n        Reference wind height.\n\n        Returns:\n            float: Reference wind height.\n        \"\"\"\n        return self.core.flow_field.reference_wind_height\n\n    @property\n    def turbine_average_velocities(self) -> NDArrayFloat:\n        return average_velocity(\n            velocities=self.core.flow_field.u,\n            method=self.core.grid.average_method,\n            cubature_weights=self.core.grid.cubature_weights,\n        )\n\n    @property\n    def wind_data(self):\n        return self._wind_data\n\n\n    ### v3 functions that are removed - raise an error if used\n\n    def calculate_wake(self, **_):\n        raise NotImplementedError(\n            \"The calculate_wake method has been removed. Please use the run method. \"\n            \"See https://natlabrockies.github.io/floris/v3_to_v4.html for more information.\"\n        )\n\n    def reinitialize(self, **_):\n        raise NotImplementedError(\n            \"The reinitialize method has been removed. Please use the set method. \"\n            \"See https://natlabrockies.github.io/floris/v3_to_v4.html for more information.\"\n        )\n\n\n    @staticmethod\n    def merge_floris_models(fmodel_list, reference_wind_height=None):\n        \"\"\"Merge a list of FlorisModel objects into a single FlorisModel object.\n        Note that it uses the first object specified in fmodel_list to build upon,\n        so it uses those wake model parameters, air density, and so on.\n        Currently, this function supports merging the following components of the FLORIS inputs:\n            - farm\n                - layout_x\n                - layout_y\n                - turbine_type\n            - flow_field\n                - reference_wind_height\n\n        Args:\n            fmodel_list (list): Array-like of FlorisModel objects.\n            reference_wind_height (float, optional): Height in meters\n                at which the reference wind speed is assigned. If None, will assume\n                this value is equal to the reference wind height specified in the FlorisModel\n                objects. This only works if all objects have the same value\n                for their reference_wind_height.\n\n        Returns:\n            fmodel_merged (FlorisModel): The merged FlorisModel object,\n                merged in the same order as fmodel_list. The objects are merged\n                on the turbine locations and turbine types, but not on the wake parameters\n                or general solver settings.\n        \"\"\"\n\n        if not all( type(fm) is FlorisModel for fm in fmodel_list ):\n            raise TypeError(\n                \"Incompatible input specified. fmodel_list must be a list of FlorisModel objects.\"\n            )\n\n        # Get the turbine locations and specifications for each subset and save as a list\n        x_list = []\n        y_list = []\n        turbine_type_list = []\n        reference_wind_heights = []\n        for fmodel in fmodel_list:\n            # Remove any control setpoints that might be specified for the turbines on one fmodel\n            fmodel.reset_operation()\n\n            x_list.extend(fmodel.layout_x)\n            y_list.extend(fmodel.layout_y)\n\n            fmodel_turbine_type = fmodel.core.farm.turbine_type\n            if len(fmodel_turbine_type) == 1:\n                fmodel_turbine_type = fmodel_turbine_type * len(fmodel.layout_x)\n            elif not len(fmodel_turbine_type) == len(fmodel.layout_x):\n                raise ValueError(\"Incompatible format of turbine_type in fmodel.\")\n\n            turbine_type_list.extend(fmodel_turbine_type)\n            reference_wind_heights.append(fmodel.core.flow_field.reference_wind_height)\n\n        # Derive reference wind height, if unspecified by the user\n        if reference_wind_height is None:\n            reference_wind_height = np.mean(reference_wind_heights)\n            if np.any(np.abs(np.array(reference_wind_heights) - reference_wind_height) > 1.0e-3):\n                raise ValueError(\n                    \"Cannot automatically derive a fitting reference_wind_height since they \"\n                    \"substantially differ between FlorisModel objects. \"\n                    \"Please specify 'reference_wind_height' manually.\"\n                )\n\n        # Construct the merged FLORIS model based on the first entry in fmodel_list\n        fmodel_merged = fmodel_list[0].copy()\n        fmodel_merged.set(\n            layout_x=x_list,\n            layout_y=y_list,\n            turbine_type=turbine_type_list,\n            reference_wind_height=reference_wind_height,\n        )\n\n        return fmodel_merged\n"
  },
  {
    "path": "floris/flow_visualization.py",
    "content": "import copy\nimport warnings\nfrom typing import Union\n\nimport attrs\nimport matplotlib as mpl\nimport matplotlib.colors as mplcolors\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom attrs import define, field\nfrom matplotlib import rcParams\nfrom scipy.spatial import ConvexHull\n\nfrom floris import FlorisModel\nfrom floris.core import Core\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT\nfrom floris.cut_plane import CutPlane\nfrom floris.heterogeneous_map import HeterogeneousMap\nfrom floris.type_dec import (\n    floris_array_converter,\n    NDArrayFloat,\n)\nfrom floris.utilities import rotate_coordinates_rel_west, wind_delta\n\n\ndef show():\n    \"\"\"\n    Display all open figures.  This is a wrapper for `plt.show()`.\n    This function is useful if the user doesn't wish to import `matplotlib.pyplot`\n    \"\"\"\n    plt.show(\n    )\n\n\ndef line_contour_cut_plane(\n    cut_plane,\n    ax=None,\n    levels=None,\n    colors=None,\n    label_contours=False,\n    **kwargs):\n    \"\"\"\n    Visualize a cut_plane as a line contour plot.\n\n    Args:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`):\n            CutPlane Object.\n        ax (:py:class:`matplotlib.pyplot.axes`): Figure axes. Defaults\n            to None.\n        levels (np.array, optional): Contour levels for plot.\n            Defaults to None.\n        colors (list, optional): Strings of color specification info.\n            Defaults to None.\n        label_contours (Boolean, optional): Flag to include a numerical contour labels\n            on the plot. Defaults to False.\n        **kwargs: Additional parameters to pass to `ax.contour`.\n    \"\"\"\n\n    if not ax:\n        fig, ax = plt.subplots()\n\n    rcParams[\"contour.negative_linestyle\"] = \"solid\"\n\n    # Plot the cut-through\n    contours = ax.tricontour(\n        cut_plane.df.x1,\n        cut_plane.df.x2,\n        cut_plane.df.u,\n        levels=levels,\n        colors=colors,\n        extend=\"both\",\n        **kwargs,\n    )\n\n    if label_contours:\n        ax.clabel(contours, contours.levels, inline=True, fontsize=10, colors=\"black\")\n\n    # Make equal axis\n    ax.set_aspect(\"equal\")\n\n\ndef visualize_cut_plane(\n    cut_plane,\n    ax=None,\n    vel_component='u',\n    min_speed=None,\n    max_speed=None,\n    cmap=\"coolwarm\",\n    levels=None,\n    clevels=None,\n    color_bar=False,\n    label_contours=False,\n    title=\"\",\n    **kwargs\n):\n    \"\"\"\n    Generate pseudocolor mesh plot of the cut_plane.\n\n    Horizontal cut planes are plotted with \"North\" pointing up the page (assuming the\n    layout is defined with x pointing East and y pointing North).\n\n    y planes are plotted with flows coming from the left (that is, the layout is rotated\n    such that the wind is coming from the left).\n\n    Cross planes are plotted \"looking downstream\".\n\n    Args:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`): 2D\n            plane through wind plant.\n        ax (:py:class:`matplotlib.pyplot.axes`, optional): Figure axes. Defaults\n            to None.\n        vel_component (str, optional): The velocity component that the cut plane is\n            perpendicular to.\n        min_speed (float, optional): Minimum value of wind speed for\n            contours. Defaults to None.\n        max_speed (float, optional): Maximum value of wind speed for\n            contours. Defaults to None.\n        cmap (str, optional): Colormap specifier. Defaults to\n            'coolwarm'.\n        levels (np.array, optional): Contour levels for line contour plot.\n            Defaults to None.\n        clevels (np.array, optional): Contour levels for tricontourf plot.\n            Defaults to None.\n        color_bar (Boolean, optional): Flag to include a color bar on the plot.\n            Defaults to False.\n        label_contours (Boolean, optional): Flag to include a numerical contour labels\n            on the plot. Defaults to False.\n        title (str, optional): User-supplied title for the plot. Defaults to \"\".\n        **kwargs: Additional parameters to pass to line contour plot.\n\n    Returns:\n        ax (:py:class:`matplotlib.pyplot.axes`): Figure axes.\n    \"\"\"\n\n    if not ax:\n        fig, ax = plt.subplots()\n\n    if vel_component=='u':\n        # vel_mesh = cut_plane.df.u.values.reshape(cut_plane.resolution[1], cut_plane.resolution[0])\n        if min_speed is None:\n            min_speed = cut_plane.df.u.min()\n        if max_speed is None:\n            max_speed = cut_plane.df.u.max()\n    elif vel_component=='v':\n        # vel_mesh = cut_plane.df.v.values.reshape(cut_plane.resolution[1], cut_plane.resolution[0])\n        if min_speed is None:\n            min_speed = cut_plane.df.v.min()\n        if max_speed is None:\n            max_speed = cut_plane.df.v.max()\n    elif vel_component=='w':\n        # vel_mesh = cut_plane.df.w.values.reshape(cut_plane.resolution[1], cut_plane.resolution[0])\n        if min_speed is None:\n            min_speed = cut_plane.df.w.min()\n        if max_speed is None:\n            max_speed = cut_plane.df.w.max()\n\n    # Allow separate number of levels for tricontourf and for line_contour\n    if clevels is None:\n        clevels = levels\n\n    # Plot the cut-through\n    im = ax.tricontourf(\n        cut_plane.df.x1,\n        cut_plane.df.x2,\n        cut_plane.df.u,\n        vmin=min_speed,\n        vmax=max_speed,\n        levels=clevels,\n        cmap=cmap,\n        extend=\"both\",\n    )\n\n    # Add line contour\n    line_contour_cut_plane(\n        cut_plane,\n        ax=ax,\n        levels=levels,\n        colors=\"b\",\n        label_contours=label_contours,\n        linewidths=0.8,\n        alpha=0.3,\n        **kwargs\n    )\n\n    if cut_plane.normal_vector == \"x\":\n        ax.invert_xaxis()\n\n    if color_bar:\n        cbar = plt.colorbar(im, ax=ax)\n        cbar.set_label('m/s')\n\n    # Set the title\n    ax.set_title(title)\n\n    # Make equal axis\n    ax.set_aspect(\"equal\")\n\n    return ax\n\n\ndef visualize_heterogeneous_cut_plane(\n    cut_plane,\n    fmodel,\n    ax=None,\n    vel_component='u',\n    min_speed=None,\n    max_speed=None,\n    cmap=\"coolwarm\",\n    levels=None,\n    clevels=None,\n    color_bar=False,\n    label_contours=False,\n    title=\"\",\n    plot_het_bounds=True,\n    **kwargs\n):\n    \"\"\"\n    Generate pseudocolor mesh plot of the heterogeneous cut_plane.\n\n    Args:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`): 2D\n            plane through wind plant.\n        fmodel (:py:class:`~.floris_model.FlorisModel`): FlorisModel object.\n        ax (:py:class:`matplotlib.pyplot.axes`): Figure axes. Defaults\n            to None.\n        vel_component (str, optional): The velocity component that the cut plane is\n            perpendicular to.\n        min_speed (float, optional): Minimum value of wind speed for\n            contours. Defaults to None.\n        max_speed (float, optional): Maximum value of wind speed for\n            contours. Defaults to None.\n        cmap (str, optional): Colormap specifier. Defaults to\n            'coolwarm'.\n        levels (np.array, optional): Contour levels for line contour plot.\n            Defaults to None.\n        clevels (np.array, optional): Contour levels for tricontourf plot.\n            Defaults to None.\n        color_bar (Boolean, optional): Flag to include a color bar on the plot.\n            Defaults to False.\n        label_contours (Boolean, optional): Flag to include a numerical contour labels\n            on the plot. Defaults to False.\n        title (str, optional): User-supplied title for the plot. Defaults to \"\".\n        plot_het_bonds (boolean, optional): Flag to include the user-defined bounds of the\n            heterogeneous wind speed area. Defaults to True.\n        **kwargs: Additional parameters to pass to line contour plot.\n\n    Returns:\n        ax (:py:class:`matplotlib.pyplot.axes`): Figure axes.\n    \"\"\"\n\n    ax = visualize_cut_plane(\n        cut_plane=cut_plane,\n        ax=ax,\n        vel_component=vel_component,\n        min_speed=min_speed,\n        max_speed=max_speed,\n        cmap=cmap,\n        levels=levels,\n        clevels=clevels,\n        color_bar=color_bar,\n        label_contours=label_contours,\n        title=title,\n        **kwargs\n    )\n\n    if plot_het_bounds:\n        HeterogeneousMap.plot_heterogeneous_boundary(\n            fmodel.core.flow_field.heterogeneous_inflow_config['x'],\n            fmodel.core.flow_field.heterogeneous_inflow_config['y'],\n            ax=ax\n        )\n    return ax\n\n\ndef visualize_quiver(cut_plane, ax=None, min_speed=None, max_speed=None, downSamp=1, **kwargs):\n    \"\"\"\n    Visualize the in-plane flows in a cut_plane using quiver.\n\n    Args:\n        cut_plane (:py:class:`~.tools.cut_plane.CutPlane`): 2D\n            plane through wind plant.\n        ax (:py:class:`matplotlib.pyplot.axes`): Figure axes. Defaults\n            to None.\n        min_speed (float, optional): Minimum value of wind speed for\n            contours. Defaults to None.\n        max_speed (float, optional): Maximum value of wind speed for\n            contours. Defaults to None.\n        downSamp (int, optional): Down sample the number of quiver arrows\n            from underlying grid.\n        **kwargs: Additional parameters to pass to `ax.streamplot`.\n\n    Returns:\n        im (:py:class:`matplotlib.plt.pcolormesh`): Image handle.\n    \"\"\"\n    if not ax:\n        fig, ax = plt.subplots()\n\n    # Reshape UMesh internally\n    x1_mesh = cut_plane.df.x1.values.reshape(cut_plane.resolution[1], cut_plane.resolution[0])\n    x2_mesh = cut_plane.df.x2.values.reshape(cut_plane.resolution[1], cut_plane.resolution[0])\n    v_mesh = cut_plane.df.v.values.reshape(cut_plane.resolution[1], cut_plane.resolution[0])\n    w_mesh = cut_plane.df.w.values.reshape(cut_plane.resolution[1], cut_plane.resolution[0])\n\n    # plot the stream plot\n    ax.streamplot(\n        (x1_mesh[::downSamp, ::downSamp]),\n        (x2_mesh[::downSamp, ::downSamp]),\n        v_mesh[::downSamp, ::downSamp],\n        w_mesh[::downSamp, ::downSamp],\n        # scale=80.0,\n        # alpha=0.75,\n        # **kwargs\n    )\n\n    # ax.quiverkey(QV1, -.75, -0.4, 1, '1 m/s', coordinates='data')\n\n    # Make equal axis\n    # ax.set_aspect('equal')\n\n\ndef reverse_cut_plane_x_axis_in_plot(ax):\n    \"\"\"\n    Shortcut method to reverse direction of x-axis.\n\n    Args:\n        ax (:py:class:`matplotlib.pyplot.axes`): Figure axes.\n    \"\"\"\n    ax.invert_xaxis()\n\n\ndef plot_rotor_values(\n    values: np.ndarray,\n    findex: int,\n    n_rows: int,\n    n_cols: int,\n    t_range: range | None = None,\n    cmap: str = \"coolwarm\",\n    return_fig_objects: bool = False,\n    save_path: Union[str, None] = None,\n    show: bool = False\n) -> Union[None, tuple[plt.figure, plt.axes, plt.axis, plt.colorbar]]:\n    \"\"\"\n    Plots the gridded turbine rotor values. This is intended to be used for\n    understanding the differences between two sets of values, so each subplot can be\n    used for inspection of what values are differing, and under what conditions.\n\n    Parameters:\n        values (np.ndarray): The 4-dimensional array of values to plot. Should be:\n            (N findex, N turbines, N rotor points, N rotor points).\n        findex (int): The index for the sample point to plot.\n        n_rows (int): The number of rows to include for subplots. With ncols, this should\n            generally add up to the number of turbines in the farm.\n        n_cols (int): The number of columns to include for subplots. With ncols, this should\n            generally add up to the number of turbines in the farm.\n        t_range (range | None): Optional. The turbine count used to create the title for each\n            subplot. If not provided, the size of the 2-th dimension of `values` is used.\n        cmap (str): Optional. The matplotlib colormap to be used, default \"coolwarm\".\n        return_fig_objects (bool): Optional. Flag to return the primary figure objects for\n            further editing, default False.\n        save_path (str | None): Optional. Where to save the figure, if a value is provided.\n        show (bool): Optional. Flag to run `plt.show()` to present all the plots\n            currently created with matplotlib.\n\n    Returns:\n        None | tuple[plt.figure, plt.axes, plt.axis, plt.colorbar]: If\n        `return_fig_objects` is `False, then `None` is returned`, otherwise the primary\n        figure objects are returned for custom editing.\n\n    Example:\n        from floris.visualization import plot_rotor_values\n        plot_rotor_values(floris.flow_field.u, findex=0, n_rows=1, ncols=4)\n        plot_rotor_values(floris.flow_field.v, findex=0, n_rows=1, ncols=4)\n        plot_rotor_values(floris.flow_field.w, findex=0, n_rows=1, ncols=4, show=True)\n    \"\"\"\n\n    cmap = plt.get_cmap(name=cmap)\n\n    if t_range is None:\n        t_range = range(values.shape[1])\n\n    fig = plt.figure()\n    axes = fig.subplots(n_rows, n_cols)\n\n    # For 1x1, fig.subplots returns an Axes object, but for more than 1x1 it returns a np.array.\n    # In this case, convert to an array so that the rest of this function can be simplified.\n    if n_rows == 1 and n_cols == 1:\n        axes = np.array([axes])\n\n    titles = np.array([f\"tindex: {i}\" for i in t_range])\n\n    for ax, t, i in zip(axes.flatten(), titles, t_range):\n\n        vmin = np.min(values[findex])\n        vmax = np.max(values[findex])\n\n        norm = mplcolors.Normalize(vmin, vmax)\n\n        ax.imshow(values[findex, i].T, cmap=cmap, norm=norm, origin=\"lower\")\n        ax.invert_xaxis()\n\n        ax.set_xticks([])\n        ax.set_yticks([])\n        ax.set_title(t)\n\n    fig.subplots_adjust(right=0.8)\n    cbar_ax = fig.add_axes([0.83, 0.25, 0.03, 0.5])\n    cb = fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap), cax=cbar_ax)\n\n    if save_path:\n        plt.savefig(save_path, bbox_inches=\"tight\")\n\n    if return_fig_objects:\n        return fig, axes, cbar_ax, cb\n\n    if show:\n        plt.show()\n\ndef calculate_horizontal_plane_with_turbines(\n    fmodel,\n    x_resolution=200,\n    y_resolution=200,\n    x_bounds=None,\n    y_bounds=None,\n    findex_for_viz=None,\n) -> CutPlane:\n        \"\"\"\n        This function creates a :py:class:`~.tools.cut_plane.CutPlane` by\n        adding an additional turbine to the farm and moving it through every\n        a regular grid throughout the flow field. This method allows for\n        visualizing wake models that do not support the FullFlowGrid and\n        its associated solver. As the new turbine is moved around the flow\n        field, the velocities at its rotor are stored in local variables,\n        and the flow field is reset to its initial state for every new\n        location. Then, the local velocities are put into a DataFrame and\n        then into a CutPlane. This method is much slower than\n        `FlorisModel.calculate_horizontal_plane`, but it is helpful\n        for models where the visualization capability is not yet available.\n\n        Args:\n            fmodel (:py:class:`floris.floris_model.FlorisModel`):\n                Preinitialized FlorisModel object.\n            x_resolution (float, optional): Output array resolution. Defaults to 200 points.\n            y_resolution (float, optional): Output array resolution. Defaults to 200 points.\n            x_bounds (tuple, optional): Limits of output array (in m). Defaults to None.\n            y_bounds (tuple, optional): Limits of output array (in m). Defaults to None.\n            findex_for_viz (int, optional): Index of the condition to visualize.\n\n        Returns:\n            :py:class:`~.tools.cut_plane.CutPlane`: containing values of x, y, u, v, w\n        \"\"\"\n        if fmodel.core.flow_field.n_findex > 1 and findex_for_viz is None:\n            print(\n                \"Multiple findices detected. Using first findex for visualization.\"\n            )\n        if findex_for_viz is None:\n            findex_for_viz = 0\n\n        # Make a local copy of fmodel to avoid editing passed in fmodel\n        fmodel_viz = copy.deepcopy(fmodel)\n\n        # Set the ws and wd\n        fmodel_viz.set_for_viz(findex_for_viz, None)\n\n        yaw_angles = fmodel_viz.core.farm.yaw_angles\n        power_setpoints = fmodel_viz.core.farm.power_setpoints\n        awc_modes = fmodel_viz.core.farm.awc_modes\n        awc_amplitudes = fmodel_viz.core.farm.awc_amplitudes\n        awc_frequencies = fmodel_viz.core.farm.awc_frequencies\n\n        # Grab the turbine layout\n        layout_x = copy.deepcopy(fmodel_viz.layout_x)\n        layout_y = copy.deepcopy(fmodel_viz.layout_y)\n        turbine_types = copy.deepcopy(fmodel_viz.core.farm.turbine_type)\n        D = fmodel_viz.core.farm.rotor_diameters_sorted[0, 0]\n\n        # Declare a new layout array with an extra turbine\n        layout_x_test = np.append(layout_x,[0])\n        layout_y_test = np.append(layout_y,[0])\n\n        # Declare turbine types with an extra turbine in case of special one-type usage\n        if len(layout_x) > 1 and len(turbine_types) == 1:\n            # Convert to list length len(layout_x) + 1\n            turbine_types_test = [turbine_types[0] for i in range(len(layout_x))] + ['nrel_5MW']\n        else:\n            turbine_types_test = np.append(turbine_types, 'nrel_5MW').tolist()\n        yaw_angles = np.append(\n            yaw_angles,\n            np.zeros([fmodel_viz.core.flow_field.n_findex, 1]),\n            axis=1\n        )\n        power_setpoints = np.append(\n            power_setpoints,\n            POWER_SETPOINT_DEFAULT * np.ones([fmodel_viz.core.flow_field.n_findex, 1]),\n            axis=1\n        )\n        awc_modes = np.append(\n            awc_modes,\n            np.full((fmodel_viz.core.flow_field.n_findex, 1), \"baseline\"),\n            axis=1\n        )\n        awc_amplitudes = np.append(\n            awc_amplitudes,\n            np.zeros([fmodel_viz.core.flow_field.n_findex, 1]),\n            axis=1\n        )\n        awc_frequencies = np.append(\n            awc_frequencies,\n            np.zeros([fmodel_viz.core.flow_field.n_findex, 1]),\n            axis=1\n        )\n\n        # Get a grid of points test test\n        if x_bounds is None:\n            x_bounds = (np.min(layout_x) - 2 * D, np.max(layout_x) + 10 * D)\n\n        if y_bounds is None:\n            y_bounds = (np.min(layout_y) - 2 * D, np.max(layout_y) + 2 * D)\n\n        # Now generate a list of points\n        x_points = np.linspace(x_bounds[0], x_bounds[1], x_resolution)\n        y_points = np.linspace(y_bounds[0], y_bounds[1], y_resolution)\n        num_points = len(x_points) * len(y_points)\n\n        # Now loop over the points\n        x_results = np.zeros(num_points)\n        y_results = np.zeros(num_points)\n        z_results = np.zeros(num_points)\n        u_results = np.zeros(num_points)\n        v_results = np.zeros(num_points)\n        w_results = np.zeros(num_points)\n        idx = 0\n        for y in y_points:\n            for x in x_points:\n\n                # Save the x and y results\n                x_results[idx] = x\n                y_results[idx] = y\n\n                # Place the test turbine at this location and calculate wake\n                layout_x_test[-1] = x\n                layout_y_test[-1] = y\n                fmodel_viz.set(\n                    layout_x=layout_x_test,\n                    layout_y=layout_y_test,\n                    yaw_angles=yaw_angles,\n                    power_setpoints=power_setpoints,\n                    awc_modes=awc_modes,\n                    awc_amplitudes=awc_amplitudes,\n                    awc_frequencies=awc_frequencies,\n                    turbine_type=turbine_types_test,\n                    reference_wind_height=fmodel_viz.reference_wind_height\n                )\n                fmodel_viz.run()\n\n                # Get the velocity of that test turbines central point\n                center_point = int(np.floor(fmodel_viz.core.flow_field.u[0,-1].shape[0] / 2.0))\n                u_results[idx] = fmodel_viz.core.flow_field.u[0,-1,center_point,center_point]\n\n                # Increment index\n                idx = idx + 1\n\n        # Make a dataframe\n        df = pd.DataFrame({\n            'x1':x_results,\n            'x2':y_results,\n            'x3':z_results,\n            'u':u_results,\n            'v':v_results,\n            'w':w_results,\n        })\n\n        # Convert to a cut_plane\n        horizontal_plane = CutPlane(df, x_resolution, y_resolution, \"z\")\n\n        return horizontal_plane\n\n@define\nclass VelocityProfilesFigure():\n    \"\"\"\n    Create a figure which displays velocity deficit profiles at several downstream\n    locations of a turbine.\n\n    Args:\n        downstream_dists_D: A list/array of streamwise locations at which the velocity deficit\n            profiles have been sampled. The locations should be normalized by the turbine\n            diameter D.\n        layout: A one- or two-element list defining the direction of the profiles and in which\n            order the directions are plotted. For example, ['cross-stream', 'vertical'] initializes\n            a figure where cross-stream profiles are expected on the top row of Axes in the figure,\n            and vertical profiles are expected on the bottom row.\n        ax_width: Roughly the width of each Axes.\n        ax_height: Roughly the height of each Axes.\n        coordinate_labels: A list of labels for the normalized coordinates.\n\n    \"\"\"\n    downstream_dists_D: NDArrayFloat = field(converter=floris_array_converter)\n    layout: list[str] = field(default=['cross-stream'])\n    ax_width: float = field(default=2.07)\n    ax_height: float = field(default=3.0)\n    coordinate_labels: list[str] = field(default=['x_1/D', 'x_2/D', 'x_3/D'])\n\n    n_rows: int = field(init=False)\n    n_cols: int = field(init=False)\n    fig: plt.Figure = field(init=False)\n    axs: np.ndarray = field(init=False)\n    deficit_max: float = field(init=False, default=0.0)\n\n    def __attrs_post_init__(self) -> None:\n        self.n_rows = len(self.layout)\n        self.n_cols = len(self.downstream_dists_D)\n        figsize = [0.7 + self.ax_width * self.n_cols, 1.0 + self.ax_height * self.n_rows]\n        self.fig, self.axs = plt.subplots(\n            self.n_rows,\n            self.n_cols,\n            figsize=figsize,\n            layout='tight',\n            sharex='col',\n            sharey='row',\n            squeeze=False,\n        )\n\n        for ax in self.axs[-1]:\n            ax.set_xlabel(r'$\\Delta U / U_\\infty$', fontsize=14)\n            ax.tick_params('x', labelsize=14)\n\n        for ax, x1_D in zip(self.axs[0], self.downstream_dists_D):\n            ax.set_title(f'${self.coordinate_labels[0]} = {x1_D:.1f}$', fontsize=14)\n\n        for ax, profile_direction in zip(self.axs[:,0], self.layout):\n            if profile_direction == 'cross-stream':\n                ylabel = f'${self.coordinate_labels[1]}$'\n            elif profile_direction == 'vertical':\n                ylabel = f'${self.coordinate_labels[2]}$'\n            ax.set_ylabel(ylabel, fontsize=14)\n            ax.tick_params('y', labelsize=14)\n\n    @layout.validator\n    def layout_validator(self, instance : attrs.Attribute, value : list[str]) -> None:\n        allowed_layouts = [\n            ['cross-stream'],\n            ['vertical'],\n            ['cross-stream', 'vertical'],\n            ['vertical', 'cross-stream'],\n        ]\n        if value not in allowed_layouts:\n            raise ValueError(f\"'layout' must be one of the following: {allowed_layouts}.\")\n\n    def add_profiles(\n        self,\n        velocity_deficit_profiles: list[pd.DataFrame],\n        **kwargs\n    ) -> None:\n        \"\"\"\n        Add a list of velocity deficit profiles to the figure. Each profile is represented\n        as a pandas DataFrame. `kwargs` are passed to `ax.plot`.\n        \"\"\"\n        for df in velocity_deficit_profiles:\n            ax, profile_direction = self.match_profile_to_axes(df)\n            profile_direction_D = f'{profile_direction}/D'\n            ax.plot(df['velocity_deficit'], df[profile_direction_D], **kwargs)\n            self.deficit_max = max(self.deficit_max, df['velocity_deficit'].max())\n\n        margin = 0.05\n        self.set_xlim([0.0 - margin, self.deficit_max + margin])\n\n    def match_profile_to_axes(\n        self,\n        df: pd.DataFrame,\n    ) -> tuple[plt.Axes, str]:\n        x1_D = np.unique(df['x1/D'])\n        if len(x1_D) == 1:\n            x1_D = x1_D[0]\n        else:\n            raise ValueError(\n                \"The streamwise location x1/D must be constant for each velocity profile.\"\n            )\n\n        unique_x2 = np.unique(df['x2/D'])\n        unique_x3 = np.unique(df['x3/D'])\n        if len(unique_x2) == 1:\n            profile_direction = 'x3'\n            profile_direction_name = 'vertical'\n        elif len(unique_x3) == 1:\n            profile_direction = 'x2'\n            profile_direction_name = 'cross-stream'\n        else:\n            raise ValueError(\n                f\"Velocity deficit profile at x1/D = {x1_D} is neither in the cross-stream (x2) \"\n                \"nor the vertical (x3) direction.\"\n            )\n        row = self.layout.index(profile_direction_name)\n\n        col = None\n        for i in range(self.n_cols):\n            if np.abs(x1_D - self.downstream_dists_D[i]) < 0.001:\n                col = i\n                break\n        if col is None:\n            raise ValueError(\n                \"Could not add a velocity deficit profile at downstream distance \"\n                f\"x1/D = {x1_D}. The downstream distance must be one of the following \"\n                \"values with which this VelocityProfilesFigure object was initialized: \"\n                f\"{self.downstream_dists_D}.\"\n            )\n        return self.axs[row,col], profile_direction\n\n    def set_xlim(\n        self,\n        xlim: list[float] | NDArrayFloat,\n    ) -> None:\n        for ax in self.axs[-1]:\n            ax.set_xlim(xlim)\n\n    def add_ref_lines_x2(\n        self,\n        ref_lines_x2_D: list[float] | NDArrayFloat,\n        **kwargs\n    ) -> None:\n        \"\"\"\n        Add reference lines to the VelocityProfilesFigure which go along the XAxis.\n        Commonly used to show the extent of the turbine.\n        Args:\n            ref_lines_x2_D: A list of x2-coordinates normalized by the turbine diameter D.\n                One coordinate per reference line.\n            **kwargs: Additional parameters to pass to `ax.plot`.\n        \"\"\"\n        if 'cross-stream' not in self.layout:\n            raise Exception(\n                \"Could not add reference lines to cross-stream (x2) velocity profiles. No \"\n                \"such profiles exist in the figure.\"\n            )\n        row_x2 = self.layout.index('cross-stream')\n        self.add_ref_lines(ref_lines_x2_D, row_x2, **kwargs)\n\n    def add_ref_lines_x3(\n        self,\n        ref_lines_x3_D: list[float] | NDArrayFloat,\n        **kwargs\n    ) -> None:\n        \"\"\"\n        Add reference lines to the VelocityProfilesFigure which go along the XAxis.\n        Commonly used to show the extent of the turbine.\n        Args:\n            ref_lines_x3_D: A list of x3-coordinates normalized by the turbine diameter D.\n                One coordinate per reference line.\n            **kwargs: Additional parameters to pass to `ax.plot`.\n        \"\"\"\n        if 'vertical' not in self.layout:\n            raise Exception(\n                \"Could not add reference lines to vertical (x3) velocity profiles. No \"\n                \"such profiles exist in the figure.\"\n            )\n        row_x3 = self.layout.index('vertical')\n        self.add_ref_lines(ref_lines_x3_D, row_x3, **kwargs)\n\n    def add_ref_lines(\n        self,\n        ref_lines_D: list[float] | NDArrayFloat,\n        row: int,\n        **kwargs\n    ) -> None:\n        default_params = {\n                'linestyle': (0, (4, 2)),\n                'color': 'k',\n                'linewidth': 1.1\n        }\n        params = copy.deepcopy(default_params)\n        params.update(kwargs)\n\n        for ax in self.axs[row]:\n            for coordinate in ref_lines_D:\n                ax.plot([0.0, 1.0], [coordinate, coordinate], **params)\n"
  },
  {
    "path": "floris/heterogeneous_map.py",
    "content": "import matplotlib.cm as cm\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport scipy.spatial._qhull\nfrom scipy.interpolate import LinearNDInterpolator, NearestNDInterpolator\nfrom scipy.spatial import ConvexHull\n\nfrom floris.core.flow_field import FlowField\nfrom floris.logging_manager import LoggingManager\nfrom floris.type_dec import NDArrayFloat\n\n\nclass HeterogeneousMap(LoggingManager):\n    \"\"\"\n    Class for handling heterogeneous inflow configurations when defined by wind direction\n      and wind speed.\n    Args:\n        x (NDArrayFloat): A 1D NumPy array (size num_points) of x-coordinates (meters).\n        y (NDArrayFloat): A 1D NumPy array (size num_points) of y-coordinates (meters).\n        speed_multipliers (NDArrayFloat): A 2D NumPy array (size num_wd (or num_ws) x num_points)\n            of speed multipliers.  If neither wind_directions nor wind_speeds are defined, then\n            this should be a single row array\n        z (NDArrayFloat, optional): A 1D NumPy array (size num_points) of z-coordinates (meters).\n            Optional.\n        wind_directions (NDArrayFloat, optional): A 1D NumPy array (size num_wd) of wind directions\n            (degrees). Optional.\n        wind_speeds (NDArrayFloat, optional): A 1D NumPy array (size num_ws) of wind speeds (m/s).\n            Optional.\n        interp_method (str, optional): Interpolation method used to calculate the heterogeneous\n            wind speeds at various locations in the wind farm. Options are 'linear' and 'nearest',\n            representing linear interpolation and nearest-neighbor interpolation respectively.\n            Linear interpolation is accurate, nearest-neighbor interpolation is very fast but\n            inaccurate. Note also that in the default 'linear' setting, speed-ups at locations\n            outside the convex hull of points defined by `x`, `y` and `z` are 1.0 while in\n            the nearest case will be the value of the nearest point. Defaults to 'linear'. Optional.\n\n    Notes:\n        * If wind_directions and wind_speeds are both defined, then they must be the same length\n            and equal the length of the 0th dimension of 'speed_multipliers'.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        x: NDArrayFloat,\n        y: NDArrayFloat,\n        speed_multipliers: NDArrayFloat,\n        z: NDArrayFloat = None,\n        wind_directions: NDArrayFloat = None,\n        wind_speeds: NDArrayFloat = None,\n        interp_method: str = \"linear\",\n    ):\n        # Check that x, y and speed_multipliers are lists or numpy arrays\n        if not isinstance(x, (list, np.ndarray)):\n            raise TypeError(\"x must be a numpy array or list\")\n        if not isinstance(y, (list, np.ndarray)):\n            raise TypeError(\"y must be a numpy array or list\")\n        if not isinstance(speed_multipliers, (list, np.ndarray)):\n            raise TypeError(\"speed_multipliers must be a numpy array or list\")\n\n        # If z is provided, check that it is a list or numpy array\n        if (z is not None) and (not isinstance(z, (list, np.ndarray))):\n                raise TypeError(\"z must be a numpy array or list\")\n\n        # Save the values\n        self.x = np.array(x)\n        self.y = np.array(y)\n        self.speed_multipliers = np.array(speed_multipliers)\n        self.interp_method = str(interp_method)\n\n        # If z is provided, save it as an np array\n        if z is not None:\n            self.z = np.array(z)\n        else:\n            self.z = None\n\n        # Check that the length of the 1st dimension of speed_multipliers is the\n        # same as the length of both x and y\n        if (\n            len(self.x) != self.speed_multipliers.shape[1]\n            or len(self.y) != self.speed_multipliers.shape[1]\n        ):\n            raise ValueError(\n                \"The lengths of x and y must equal the 1th dimension of speed_multipliers \"\n            )\n\n        # If z is provided, check that it is the same length as the 1st\n        # dimension of speed_multipliers\n        if self.z is not None:\n            if len(self.z) != self.speed_multipliers.shape[1]:\n                raise ValueError(\n                    \"The length of z must equal the 1th dimension of speed_multipliers \"\n                )\n\n        # If wind_directions is note None, check that it is valid then save it\n        if wind_directions is not None:\n            if not isinstance(wind_directions, (list, np.ndarray)):\n                raise TypeError(\"wind_directions must be a numpy array or list\")\n\n            # Check that length of wind_directions is the same as the length of the 0th\n            # dimension of speed_multipliers\n            if len(wind_directions) != self.speed_multipliers.shape[0]:\n                raise ValueError(\n                    \"The length of wind_directions must equal \"\n                    \"the 0th dimension of speed_multipliers\"\n                    \"Within the heterogeneous_inflow_config_by_wd dictionary\"\n                )\n\n            self.wind_directions = np.array(wind_directions)\n\n        else:\n            self.wind_directions = None\n\n        # If wind_speeds is not None, check that it is valid then save it\n        if wind_speeds is not None:\n            if not isinstance(wind_speeds, (list, np.ndarray)):\n                raise TypeError(\"wind_speeds must be a numpy array or list\")\n\n            # Check that length of wind_speeds is the same as the length of the 0th\n            # dimension of speed_multipliers\n            if len(wind_speeds) != self.speed_multipliers.shape[0]:\n                raise ValueError(\n                    \"The length of wind_speeds must equal \"\n                    \"the 0th dimension of speed_multipliers\"\n                    \"Within the heterogeneous_inflow_config_by_wd dictionary\"\n                )\n\n            self.wind_speeds = np.array(wind_speeds)\n        else:\n            self.wind_speeds = None\n\n        # If both wind_directions and wind_speeds are None, then speed_multipliers should be\n        # length 1 in 0th dimension\n        if self.wind_speeds is None and self.wind_directions is None:\n            if self.speed_multipliers.shape[0] != 1:\n                raise ValueError(\n                    \"If both wind_speeds and wind_directions are None, then speed_multipliers \"\n                    \"should be length 1 in 0th dimension.\"\n                )\n\n        # If both wind_directions and wind_speeds are not None, then make sure each row\n        # of a matrix where wind directions and wind speeds are the columns is unique\n        if self.wind_speeds is not None and self.wind_directions is not None:\n            if len(\n                np.unique(np.column_stack((self.wind_directions, self.wind_speeds)), axis=0)\n            ) != len(self.wind_directions):\n                raise ValueError(\n                    \"Each row of a matrix where wind directions and wind speeds are the columns \"\n                    \"should be unique.\"\n                )\n\n    def __str__(self) -> str:\n        \"\"\"\n        Return a string representation of the HeterogeneousMap.\n        Returns:\n            str: A string representation of the HeterogeneousMap.\n        \"\"\"\n        if self.z is None:\n            num_dim = 2\n        else:\n            num_dim = 3\n\n        # Make a pandas dataframe of the data\n        df = pd.DataFrame(\n            data=self.speed_multipliers,\n            index=self.wind_directions,\n            columns=list(range(len(self.x)))\n        )\n\n        return (\n            f\"HeterogeneousMap with {num_dim} dimensions \"\n            f\"using interpolation method \\\"{self.interp_method}\\\".\\n\"\n            f\"Speed multipliers are defined for {len(self.x)} points and \"\n            f\"{self.speed_multipliers.shape[0]} wind conditions.\"\n            f\"\\n\\n{df}\"\n        )\n\n    def get_heterogeneous_inflow_config(\n        self,\n        wind_directions: NDArrayFloat | list[float],\n        wind_speeds: NDArrayFloat | list[float],\n    ):\n        \"\"\"\n        Get the heterogeneous inflow configuration for the given wind directions and wind speeds.\n        Args:\n            wind_directions (NDArrayFloat | list[float]): A 1D NumPy array or\n                list of wind directions (degrees).\n            wind_speeds (NDArrayFloat | list[float]): A 1D NumPy array or list of wind speeds (m/s).\n        Returns:\n            dict: A dictionary (heterogeneous_inflow_config) containing the x, y,\n            and speed_multipliers for the given wind directions and wind speeds.\n        \"\"\"\n        # Check the wind_directions and wind_speeds are either lists or numpy arrays,\n        # and are the same length\n        if not isinstance(wind_directions, (list, np.ndarray)):\n            raise TypeError(\"wind_directions must be a list or numpy array\")\n        if not isinstance(wind_speeds, (list, np.ndarray)):\n            raise TypeError(\"wind_speeds must be a list or numpy array\")\n        if len(wind_directions) != len(wind_speeds):\n            raise ValueError(\"wind_directions and wind_speeds must be the same length\")\n\n        # Select for wind direction first\n        if self.wind_directions is not None:\n            angle_diffs = np.abs(wind_directions[:, None] - self.wind_directions)\n            min_angle_diffs = np.minimum(angle_diffs, 360 - angle_diffs)\n\n            # If wind_speeds is none, can return the value in each case\n            if self.wind_speeds is None:\n                closest_wd_indices = np.argmin(min_angle_diffs, axis=1)\n\n                # Construct the output array using the calculated indices\n                speed_multipliers_by_findex = self.speed_multipliers[closest_wd_indices]\n\n            # Need to loop over cases and match by wind speed\n            else:\n                speed_diffs = np.abs(wind_speeds[:, None] - self.wind_speeds)\n\n                # Initialize the output array\n                speed_multipliers_by_findex = np.zeros((len(wind_directions), len(self.x)))\n\n                # Loop over each wind direction\n                for i in range(len(wind_directions)):\n                    # Find all the indices in the ith row of min_angle_diffs\n                    # that are equal to the minimum value\n                    closest_wd_indices = np.where(min_angle_diffs[i] == min_angle_diffs[i].min())[0]\n\n                    # Find the index of the minimum value in the ith row of speed_diffs\n                    # conditions on that index being in closest_wd_indices\n                    closest_ws_index = np.argmin(speed_diffs[i, closest_wd_indices])\n\n                    # Construct the output array using the calculated indices\n                    speed_multipliers_by_findex[i] = self.speed_multipliers[\n                        closest_wd_indices[closest_ws_index]\n                    ]\n\n        # If wind speeds are defined without wind direction\n        elif self.wind_speeds is not None:\n            speed_diffs = np.abs(wind_speeds[:, None] - self.wind_speeds)\n            closest_ws_indices = np.argmin(speed_diffs, axis=1)\n\n            # Construct the output array using the calculated indices\n            speed_multipliers_by_findex = self.speed_multipliers[closest_ws_indices]\n\n        # Else if both are None, then speed_multipliers should be length 1 in 0th\n        # dimension and so just 1 row\n        # repeat this row until length of wind_directions\n        else:\n            speed_multipliers_by_findex = np.repeat(\n                self.speed_multipliers, len(wind_directions), axis=0\n            )\n\n        # Return heterogeneous_inflow_config with only x and y is z is not defined\n        if self.z is None:\n            return {\n                \"x\": self.x,\n                \"y\": self.y,\n                \"speed_multipliers\": speed_multipliers_by_findex,\n                \"interp_method\": self.interp_method,\n            }\n        else:\n            return {\n                \"x\": self.x,\n                \"y\": self.y,\n                \"z\": self.z,\n                \"speed_multipliers\": speed_multipliers_by_findex,\n                \"interp_method\": self.interp_method,\n            }\n\n    def get_heterogeneous_map_2d(self, z: float):\n        \"\"\"\n        Return a HeterogeneousMap with only x and y coordinates and a constant z value.\n        Do this by selecting from x, y and speed_multipliers where z is nearest to the given value.\n        \"\"\"\n        if self.z is None:\n            raise ValueError(\"No z values defined in the HeterogeneousMap\")\n\n        # Find the value in self.z that is closest to the given z value\n        closest_z_index = np.argmin(np.abs(self.z - z))\n\n        # Get the indices of all the values in self.z that are equal to the closest value\n        closest_z_indices = np.where(self.z == self.z[closest_z_index])[0]\n\n        # Get versions of x, y and speed_multipliers that include only the closest z values\n        # by selecting the indices in closest_z_indices\n        x = self.x[closest_z_indices]\n        y = self.y[closest_z_indices]\n        speed_multipliers = self.speed_multipliers[:, closest_z_indices]\n\n        # Return a new HeterogeneousMap with the new x, y and speed_multipliers\n        return HeterogeneousMap(\n            x=x,\n            y=y,\n            speed_multipliers=speed_multipliers,\n            wind_directions=self.wind_directions,\n            wind_speeds=self.wind_speeds,\n            interp_method=self.interp_method,\n        )\n\n    @staticmethod\n    def plot_heterogeneous_boundary(x, y, ax=None):\n        \"\"\"\n        Plot the boundary of the heterogeneous inflow configuration.\n        Args:\n            x (NDArrayFloat): A 1D NumPy array of x-coordinates (meters).\n            y (NDArrayFloat): A 1D NumPy array of y-coordinates (meters).\n            ax (matplotlib.axes.Axes, optional): The axes on which to plot the boundary.\n                If None, a new figure and axes will be created.\n        \"\"\"\n\n        # If not provided create the axis\n        if ax is None:\n            _, ax = plt.subplots()\n\n        # Get the x and y coordinates of the het map\n        points = np.array(\n            list(\n                zip(\n                    x,\n                    y,\n                )\n            )\n        )\n\n        # Derive and plot the convex hull surrounding the points\n        hull = ConvexHull(points)\n        ax.plot(\n            points[np.append(hull.vertices, hull.vertices[0]), 0],\n            points[np.append(hull.vertices, hull.vertices[0]), 1],\n            \"--\",\n            color=\"gray\",\n            label=\"Heterogeneity Boundary\",\n        )\n\n    def plot_wind_direction(self, ax: plt.Axes, wind_direction: float):\n        \"\"\"\n        Plot the wind direction as an arrow on the plot.\n        Args:\n            ax (matplotlib.axes.Axes): The axes on which to plot the wind direction.\n            wind_direction (float): The wind direction to plot.\n        \"\"\"\n\n        # Get the x and y limits of the axis\n        xlim = ax.get_xlim()\n        ylim = ax.get_ylim()\n\n        # Find a point in the top-left corner of the plot\n        xm = xlim[0] + 0.2 * (xlim[1] - xlim[0])\n        ym = ylim[1] - 0.2 * (ylim[1] - ylim[0])\n\n        # Select a radius for the circle 5% the plot width\n        radius = 0.075 * (xlim[1] - xlim[0])\n\n        theta = np.linspace(0.0, 2 * np.pi, 100)\n        xcirc = np.cos(theta) * radius + xm\n        ycirc = np.sin(theta) * radius + ym\n        ax.scatter(xm, ym, color=\"k\", marker=\"o\")\n        ax.plot(xcirc, ycirc, color=\"w\", linewidth=2)\n        ax.arrow(\n            x=xm - np.cos(-(wind_direction - 270.0) * np.pi / 180.0) * radius,\n            y=ym - np.sin(-(wind_direction - 270.0) * np.pi / 180.0) * radius,\n            dx=1 * np.cos(-(wind_direction - 270.0) * np.pi / 180.0) * radius,\n            dy=1 * np.sin(-(wind_direction - 270.0) * np.pi / 180.0) * radius,\n            width=0.125 * radius,\n            head_width=0.3 * radius,\n            head_length=0.3 * radius,\n            length_includes_head=True,\n            color=\"w\",\n        )\n\n    def plot_single_speed_multiplier(\n        self,\n        wind_direction: float,\n        wind_speed: float,\n        z: float = None,\n        ax: plt.Axes = None,\n        vmin: float = None,\n        vmax: float = None,\n        cmap: cm = cm.viridis,\n        show_boundary: bool = True,\n        show_wind_direction: bool = True,\n        show_colorbar: bool = True,\n        show_points: bool = True,\n    ):\n        \"\"\"\n        Plot the speed multipliers as a heatmap.\n        Args:\n            wind_direction (float): The wind direction for which to plot the speed multipliers.\n            wind_speed (float): The wind speed for which to plot the speed multipliers.\n            z (float, optional): The z-coordinate for which to plot the speed multipliers.\n                If None, the z-coordinate is not used.  Only for when z is defined in the\n                HeterogeneousMap.\n            ax (matplotlib.axes.Axes, optional): The axes on which to plot the speed multipliers.\n                If None, a new figure and axes will be created.\n            vmin (float, optional): The minimum value for the colorbar. Default is the minimum\n                value of the speed multipliers.\n            vmax (float, optional): The maximum value for the colorbar. Default is the maximum\n                value of the speed multipliers.\n            cmap (matplotlib.colors.Colormap, optional): The colormap to use for the heatmap.\n                Default is matplotlib.cm.viridis.\n            show_boundary (bool, optional): Whether to show the boundary of the heterogeneous\n                inflow configuration. Default is True.\n            show_wind_direction (bool, optional): Whether to show the wind direction as an arrow.\n                Default is True.\n            show_colorbar (bool, optional): Whether to show the colorbar. Default is True.\n            show_points (bool, optional): Whether to show the points of the heterogeneous inflow\n                configuration. Default is True.\n\n        Returns:\n            matplotlib.axes.Axes: The axes on which the speed multipliers are plotted.\n        \"\"\"\n\n        # Confirm wind_direction and wind_speed are floats\n        if not isinstance(wind_direction, float):\n            raise TypeError(\"wind_direction must be a float\")\n        if not isinstance(wind_speed, float):\n            raise TypeError(\"wind_speed must be a float\")\n\n        # If self.z is None, then z should be None\n        if self.z is None and z is not None:\n            raise ValueError(\"No z values defined in the HeterogeneousMap\")\n\n        # If self.z is defined and has more than one unique value, then z should be defined\n        if self.z is not None and len(np.unique(self.z)) > 1 and z is None:\n            raise ValueError(\n                \"Multiple z values defined in the HeterogeneousMap. z must be provided\"\n            )\n\n        # Get the 2d version at height z if z is defined and get the speed multiplier from there\n        # as well as x and y\n        if z is not None:\n            hm_2d = self.get_heterogeneous_map_2d(z)\n            x = hm_2d.x\n            y = hm_2d.y\n            speed_multiplier_row = hm_2d.get_heterogeneous_inflow_config(\n                np.array([wind_direction]), np.array([wind_speed])\n            )[\"speed_multipliers\"][0]\n        else:\n            x = self.x\n            y = self.y\n            # Get the speed multipliers for the given wind direction and wind speed\n            speed_multiplier_row = self.get_heterogeneous_inflow_config(\n                np.array([wind_direction]), np.array([wind_speed])\n            )[\"speed_multipliers\"][0]\n\n        # If not provided create the axis\n        if ax is None:\n            fig, ax = plt.subplots()\n        else:\n            fig = ax.get_figure()\n\n        # Get some boundary info\n        min_x = np.min(x)\n        max_x = np.max(x)\n        min_y = np.min(y)\n        max_y = np.max(y)\n        delta_x = max_x - min_x\n        delta_y = max_y - min_y\n        plot_min_x = min_x - 0.1 * delta_x\n        plot_max_x = max_x + 0.1 * delta_x\n        plot_min_y = min_y - 0.1 * delta_y\n        plot_max_y = max_y + 0.1 * delta_y\n\n        # Fill in the plot area\n        x_plot, y_plot = np.meshgrid(\n            np.linspace(plot_min_x, plot_max_x, 100),\n            np.linspace(plot_min_y, plot_max_y, 100),\n            indexing=\"ij\",\n        )\n\n        try:\n            interpolant = FlowField.interpolate_multiplier_xy(\n                x,\n                y,\n                speed_multiplier_row,\n                fill_value=1.0,\n                interp_method=self.interp_method\n            )\n\n            het_map_mesh = interpolant(x_plot.flatten(), y_plot.flatten()).reshape(x_plot.shape)\n        except scipy.spatial._qhull.QhullError:\n            self.logger.warning(\n                \"QhullError occurred in computing visualize. Creating null visualization.\"\n            )\n            het_map_mesh = np.nan * np.ones_like(x_plot)\n\n        # If vmin is not provided, use a value rounded to the nearest 0.01 below the minimum\n        if vmin is None:\n            vmin = np.floor(het_map_mesh.min() * 100) / 100\n\n        # If vmax is not provided, use a value rounded to the nearest 0.01 above the maximum\n        if vmax is None:\n            vmax = np.ceil(het_map_mesh.max() * 100) / 100\n\n        # Produce color plot of the speed multipliers\n        im = ax.contourf(\n            x_plot,\n            y_plot,\n            het_map_mesh,\n            cmap=cmap,\n            vmin=vmin,\n            vmax=vmax,\n            levels=50,\n            zorder=-1,\n        )\n\n        # Plot the grid coordinates as a scatter plot\n        if show_points:\n            ax.scatter(x, y, color=\"gray\", marker=\".\", label=\"Heterogeneity Coordinates\")\n\n        # Show the boundary\n        if show_boundary:\n            self.plot_heterogeneous_boundary(self.x, self.y, ax)\n\n        # Add a colorbar\n        if show_colorbar:\n            fig.colorbar(im, ax=ax)\n\n        # Set the x and y limits\n        ax.set_xlim(plot_min_x, plot_max_x)\n        ax.set_ylim(plot_min_y, plot_max_y)\n\n        # Make equal axis\n        ax.set_aspect(\"equal\")\n\n        # Set the x and y labels\n        ax.set_xlabel(\"X (m)\")\n        ax.set_ylabel(\"Y (m)\")\n\n        # Add the wind direction arrow\n        if show_wind_direction:\n            self.plot_wind_direction(ax, wind_direction)\n\n        return ax\n"
  },
  {
    "path": "floris/layout_visualization.py",
    "content": "\nimport math\nfrom typing import (\n    Any,\n    Dict,\n    List,\n    Tuple,\n)\n\nimport matplotlib.lines\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom scipy.spatial.distance import pdist, squareform\n\nfrom floris import FlorisModel\nfrom floris.utilities import rotate_coordinates_rel_west, wind_delta\n\n\ndef plot_turbine_points(\n    fmodel: FlorisModel,\n    ax: plt.Axes = None,\n    turbine_indices: List[int] = None,\n    plotting_dict: Dict[str, Any] = {},\n) -> plt.Axes:\n    \"\"\"\n    Plots turbine layout from a FlorisModel object.\n\n    Args:\n        fmodel (FlorisModel): The FlorisModel object containing layout data.\n        ax (plt.Axes, optional): An existing axes object to plot on. If None,\n            a new figure and axes will be created. Defaults to None.\n        turbine_indices (List[int], optional): A list of turbine indices to plot.\n            If None, all turbines will be plotted. Defaults to None.\n        plotting_dict (Dict[str, Any], optional):  A dictionary to customize plot\n            appearance.  Valid keys include:\n                * 'color' (str): Turbine marker color. Defaults to 'black'.\n                * 'marker' (str):  Turbine marker style. Defaults to '.'.\n                * 'markersize' (int): Turbine marker size. Defaults to 10.\n                * 'label' (str): Label for the legend. Defaults to None.\n\n    Returns:\n        plt.Axes: The axes object used for the plot.\n\n    Raises:\n        IndexError: If any value in `turbine_indices` is an invalid turbine index.\n    \"\"\"\n\n    # Generate axis, if needed\n    if ax is None:\n        _, ax = plt.subplots()\n\n    # If turbine_indices is not none, make sure all elements correspond to real indices\n    if turbine_indices is not None:\n        try:\n            fmodel.layout_x[turbine_indices]\n        except IndexError:\n            raise IndexError(\"turbine_indices does not correspond to turbine indices in fi\")\n    else:\n        turbine_indices = list(range(len(fmodel.layout_x)))\n\n    # Generate plotting dictionary\n    default_plotting_dict = {\n        \"color\": \"black\",\n        \"marker\": \".\",\n        \"markersize\": 10,\n        \"label\": None,\n    }\n    plotting_dict = {**default_plotting_dict, **plotting_dict}\n\n    # Plot\n    ax.plot(\n        fmodel.layout_x[turbine_indices],\n        fmodel.layout_y[turbine_indices],\n        linestyle=\"None\",\n        **plotting_dict,\n    )\n\n    # Make sure axis set to equal\n    ax.axis(\"equal\")\n\n    return ax\n\n\ndef plot_turbine_labels(\n    fmodel: FlorisModel,\n    ax: plt.Axes = None,\n    turbine_names: List[str] = None,\n    turbine_indices: List[int] = None,\n    label_offset: float = None,\n    show_bbox: bool = False,\n    bbox_dict: Dict[str, Any] = {},\n    plotting_dict: Dict[str, Any] = {},\n) -> plt.Axes:\n    \"\"\"\n    Adds turbine labels to a turbine layout plot.\n\n    Args:\n        fmodel (FlorisModel): The FlorisModel object containing layout data.\n        ax (plt.Axes, optional): An existing axes object to plot on. If None,\n            a new figure and axes will be created. Defaults to None.\n        turbine_names (List[str], optional): Custom turbine labels. If None,\n            defaults to turbine indices (e.g., '000', '001'). Defaults to None.\n        turbine_indices (List[int], optional): Indices of turbines to label.\n            If None, all turbines will be labeled. Defaults to None.\n        label_offset (float, optional): Distance to offset labels from turbine\n            points (in meters). If None, defaults to rotor_diameter/8.\n            Defaults to None.\n        show_bbox (bool, optional): If True, adds a bounding box around each label.\n            Defaults to False.\n        bbox_dict (Dict[str, Any], optional): Dictionary to customize the appearance\n            of bounding boxes (if show_bbox is True). Valid keys include:\n                * 'facecolor' (str):  Box background color. Defaults to 'gray'.\n                * 'alpha' (float): Opacity of box. Defaults to 0.5.\n                * 'pad' (float): Padding around text. Defaults to 0.1.\n                * 'boxstyle' (str): Box style (e.g., 'round'). Defaults to 'round'.\n        plotting_dict (Dict[str, Any], optional): Dictionary to control text\n            appearance. Valid keys include:\n                * 'color' (str): Text color. Defaults to 'black'.\n\n    Returns:\n        plt.Axes: The axes object used for the plot.\n\n    Raises:\n        IndexError: If any value in `turbine_indices` is an invalid turbine index.\n        ValueError: If the length of `turbine_names` does not match the number of turbines.\n    \"\"\"\n\n    # Generate axis, if needed\n    if ax is None:\n        _, ax = plt.subplots()\n\n    # If turbine names not none, confirm has correct number of turbines\n    if turbine_names is not None:\n        if len(turbine_names) != len(fmodel.layout_x):\n            raise ValueError(\n                \"Length of turbine_names not equal to number turbines in fmodel object\"\n            )\n    else:\n        # Assign simple default numbering\n        turbine_names = [f\"{i:03d}\" for i in range(len(fmodel.layout_x))]\n\n    # If label_offset is None, use default value of r/8\n    if label_offset is None:\n        rotor_diameters = fmodel.core.farm.rotor_diameters.flatten()\n        r = rotor_diameters[0] / 2.0\n        label_offset = r / 8.0\n\n    # If turbine_indices is not none, make sure all elements correspond to real indices\n    if turbine_indices is not None:\n        try:\n            fmodel.layout_x[turbine_indices]\n        except IndexError:\n            raise IndexError(\"turbine_indices does not correspond to turbine indices in fi\")\n    else:\n        turbine_indices = list(range(len(fmodel.layout_x)))\n\n    # Generate plotting dictionary\n    default_plotting_dict = {\n        \"color\": \"black\",\n        \"label\": None,\n    }\n    plotting_dict = {**default_plotting_dict, **plotting_dict}\n\n    # If showing bbox is true, if bbox_dict is None, use a default\n    default_bbox_dict = {\"facecolor\": \"gray\", \"alpha\": 0.5, \"pad\": 0.1, \"boxstyle\": \"round\"}\n    bbox_dict = {**default_bbox_dict, **bbox_dict}\n\n    for ti in turbine_indices:\n        if not show_bbox:\n            ax.text(\n                fmodel.layout_x[ti] + label_offset,\n                fmodel.layout_y[ti] + label_offset,\n                turbine_names[ti],\n                **plotting_dict,\n            )\n        else:\n            ax.text(\n                fmodel.layout_x[ti] + label_offset,\n                fmodel.layout_y[ti] + label_offset,\n                turbine_names[ti],\n                bbox=bbox_dict,\n                **plotting_dict,\n            )\n\n    # Plot labels and aesthetics\n    ax.axis(\"equal\")\n\n    return ax\n\n\ndef plot_turbine_rotors(\n    fmodel: FlorisModel,\n    ax: plt.Axes = None,\n    color: str = \"k\",\n    wd: float = None,\n    yaw_angles: np.ndarray = None,\n) -> plt.Axes:\n    \"\"\"\n    Plots wind turbine rotors on an existing axes, visually representing their yaw angles.\n\n    Args:\n        fmodel (FlorisModel): The FlorisModel object containing layout and turbine data.\n        ax (plt.Axes, optional): An existing axes object to plot on. If None,\n            a new figure and axes will be created. Defaults to None.\n        color (str, optional): Color of the turbine rotor lines. Defaults to 'k' (black).\n        wd (float, optional): Wind direction (in degrees) relative to global reference.\n            If None, the first wind direction in `fmodel.core.flow_field.wind_directions` is used.\n            Defaults to None.\n        yaw_angles (np.ndarray, optional): Array of turbine yaw angles (in degrees). If None,\n            the values from `fmodel.core.farm.yaw_angles` are used. Defaults to None.\n\n    Returns:\n        plt.Axes: The axes object used for the plot.\n    \"\"\"\n    if not ax:\n        _, ax = plt.subplots()\n    if yaw_angles is None:\n        yaw_angles = fmodel.core.farm.yaw_angles\n    if wd is None:\n        wd = fmodel.core.flow_field.wind_directions[0]\n\n    # Rotate yaw angles to inertial frame for plotting turbines relative to wind direction\n    yaw_angles = yaw_angles - wind_delta(np.array(wd))\n\n    if color is None:\n        color = \"k\"\n\n    # If yaw angles is not 1D, assume we want first findex\n    yaw_angles = np.array(yaw_angles)\n    if yaw_angles.ndim == 2:\n        yaw_angles = yaw_angles[0, :]\n\n    rotor_diameters = fmodel.core.farm.rotor_diameters.flatten()\n    for x, y, yaw, d in zip(fmodel.layout_x, fmodel.layout_y, yaw_angles, rotor_diameters):\n        R = d / 2.0\n        x_0 = x + np.sin(np.deg2rad(yaw)) * R\n        x_1 = x - np.sin(np.deg2rad(yaw)) * R\n        y_0 = y - np.cos(np.deg2rad(yaw)) * R\n        y_1 = y + np.cos(np.deg2rad(yaw)) * R\n        ax.plot([x_0, x_1], [y_0, y_1], color=color)\n\n    return ax\n\n\ndef get_wake_direction(x_i: float, y_i: float, x_j: float, y_j: float) -> float:\n    \"\"\"\n    Calculates the wind direction at which the wake of turbine i would impact turbine j.\n\n    Args:\n        x_i (float): X-coordinate of turbine i (the upstream turbine).\n        y_i (float): Y-coordinate of turbine i.\n        x_j (float): X-coordinate of turbine j (the downstream turbine).\n        y_j (float): Y-coordinate of turbine j.\n\n    Returns:\n        float: Wind direction in degrees (0-360) where 0 degrees represents wind\n               blowing from the north, and the angle increases clockwise.\n    \"\"\"\n\n    dx = x_j - x_i\n    dy = y_j - y_i\n\n    angle_rad = np.arctan2(dy, dx)\n\n\n    # Adjust for \"from\" direction (add 180 degrees) and wrap within 0-360\n    angle_deg = 270 - np.rad2deg(angle_rad)\n    wind_direction = angle_deg % 360\n\n    return wind_direction\n\n\ndef label_line(\n    line: matplotlib.lines.Line2D,\n    label_text: str,\n    ax: plt.Axes,\n    near_i: int = None,\n    near_x: float = None,\n    near_y: float = None,\n    rotation_offset: float = 0.0,\n    offset: Tuple[float, float] = (0, 0),\n    size: int = 7,\n) -> None:\n    \"\"\"\n    Adds a text label to a matplotlib line, with options to specify label placement.\n\n    Args:\n        line (matplotlib.lines.Line2D): The line object to label.\n        label_text (str): The text of the label.\n        ax (plt.Axes): The axes object where the line is plotted.\n        near_i (int, optional): Index near which to place the label. Defaults to None.\n        near_x (float, optional): X-coordinate near which to place the label. Defaults to None.\n        near_y (float, optional): Y-coordinate near which to place the label. Defaults to None.\n        rotation_offset (float, optional): Additional rotation for the label (in degrees).\n            Defaults to 0.0.\n        offset (Tuple[float, float], optional):  X and Y offset from the label position.\n            Defaults to (0, 0).\n        size (int, optional): Font size of the label. Defaults to 7.\n\n    Raises:\n        ValueError: If none of `near_i`, `near_x`, or `near_y`\n            are provided to determine label placement.\n    \"\"\"\n\n    def put_label(i: int) -> None:\n        \"\"\"\n        Adds a label to a line segment within a plot (used internally by the 'label_line' function).\n\n        Args:\n            i (int): The index of the line segment where the label should be placed.\n                    The label will be positioned between points i and i+1.\n        \"\"\"\n        i = min(i, len(x) - 2)\n        dx = sx[i + 1] - sx[i]\n        dy = sy[i + 1] - sy[i]\n        rotation = np.rad2deg(np.arctan2(dy, dx)) + rotation_offset\n        pos = [(x[i] + x[i + 1]) / 2.0 + offset[0], (y[i] + y[i + 1]) / 2 + offset[1]]\n        ax.text(\n            pos[0],\n            pos[1],\n            label_text,\n            size=size,\n            rotation=rotation,\n            color=line.get_color(),\n            ha=\"center\",\n            va=\"center\",\n            bbox={\"ec\": \"1\", \"fc\": \"1\", \"alpha\": 0.8},\n        )\n\n    # extract line data\n    x = line.get_xdata()\n    y = line.get_ydata()\n\n    # define screen spacing\n    if ax.get_xscale() == \"log\":\n        sx = np.log10(x)\n    else:\n        sx = x\n    if ax.get_yscale() == \"log\":\n        sy = np.log10(y)\n    else:\n        sy = y\n\n    # find index\n    if near_i is not None:\n        i = near_i\n        if i < 0:  # sanitize negative i\n            i = len(x) + i\n        put_label(i)\n    elif near_x is not None:\n        for i in range(len(x) - 2):\n            if (x[i] < near_x and x[i + 1] >= near_x) or (x[i + 1] < near_x and x[i] >= near_x):\n                put_label(i)\n    elif near_y is not None:\n        for i in range(len(y) - 2):\n            if (y[i] < near_y and y[i + 1] >= near_y) or (y[i + 1] < near_y and y[i] >= near_y):\n                put_label(i)\n    else:\n        raise ValueError(\"Need one of near_i, near_x, near_y\")\n\n\ndef plot_waking_directions(\n    fmodel: FlorisModel,\n    ax: plt.Axes = None,\n    turbine_indices: List[int] = None,\n    wake_plotting_dict: Dict[str, Any] = {},\n    D: float = None,\n    limit_dist_D: float = None,\n    limit_dist_m: float = None,\n    limit_num: int = None,\n    wake_label_size: int = 7,\n) -> plt.Axes:\n    \"\"\"\n    Plots lines representing potential waking directions between wind turbines in a layout.\n\n    Args:\n        fmodel (FlorisModel): Instantiated FlorisModel object containing layout data.\n        ax (plt.Axes, optional): An existing axes object to plot on. If None, a new\n            figure and axes will be created. Defaults to None.\n        turbine_indices (List[int], optional):  Indices of turbines to include in the plot.\n            If None, all turbines are plotted. Defaults to None.\n        wake_plotting_dict (Dict[str, Any], optional): Dictionary to customize the appearance\n            of waking direction lines. Valid keys include:\n                * 'color' (str): Line color. Defaults to 'black'.\n                * 'linestyle' (str): Line style (e.g., 'solid', 'dashed'). Defaults to 'solid'.\n                * 'linewidth' (float): Line width. Defaults to 0.5.\n        D (float, optional):  Rotor diameter. Used for distance calculations if `limit_dist_D`\n            is provided. If None, defaults to the first turbine's rotor diameter.\n        limit_dist_D (float, optional): Maximum distance between turbines (in rotor diameters)\n            to plot waking lines. Defaults to None (no limit).\n        limit_dist_m (float, optional): Maximum distance (in meters) between turbines to plot\n            waking lines. Overrides `limit_dist_D` if provided. Defaults to None (no limit).\n        limit_num (int, optional):  Limits the number of waking lines plotted from each turbine\n            to the `limit_num` closest neighbors. Defaults to None (no limit).\n        wake_label_size (int, optional): Font size for labels showing wake distance and direction.\n            Defaults to 7.\n\n    Returns:\n        plt.Axes: The axes object used for the plot.\n\n    Raises:\n        IndexError: If any value in `turbine_indices` is an invalid turbine index.\n\n    \"\"\"\n\n    if not ax:\n        _, ax = plt.subplots()\n\n    # If turbine_indices is not none, make sure all elements correspond to real indices\n    if turbine_indices is not None:\n        try:\n            fmodel.layout_x[turbine_indices]\n        except IndexError:\n            raise IndexError(\"turbine_indices does not correspond to turbine indices in fi\")\n    else:\n        turbine_indices = list(range(len(fmodel.layout_x)))\n\n    layout_x = fmodel.layout_x[turbine_indices]\n    layout_y = fmodel.layout_y[turbine_indices]\n    N_turbs = len(layout_x)\n\n    # Combine default plotting options\n    def_wake_plotting_dict = {\n        \"color\": \"black\",\n        \"linestyle\": \"solid\",\n        \"linewidth\": 0.5,\n    }\n    wake_plotting_dict = {**def_wake_plotting_dict, **wake_plotting_dict}\n\n    # N_turbs = len(fmodel.core.farm.turbine_definitions)\n\n    if D is None:\n        D = fmodel.core.farm.turbine_definitions[0][\"rotor_diameter\"]\n        # TODO: build out capability to use multiple diameters, if of interest.\n        # D = np.array([turb['rotor_diameter'] for turb in\n        #      fmodel.core.farm.turbine_definitions])\n    # else:\n    # D = D*np.ones(N_turbs)\n\n    dists_m = np.zeros((N_turbs, N_turbs))\n    angles_d = np.zeros((N_turbs, N_turbs))\n\n    for i in range(N_turbs):\n        for j in range(N_turbs):\n            dists_m[i, j] = np.linalg.norm([layout_x[i] - layout_x[j], layout_y[i] - layout_y[j]])\n            angles_d[i, j] = get_wake_direction(layout_x[i], layout_y[i], layout_x[j], layout_y[j])\n\n    # Mask based on the limit distance (assumed to be in measurement D)\n    if limit_dist_D is not None and limit_dist_m is None:\n        limit_dist_m = limit_dist_D * D\n    if limit_dist_m is not None:\n        mask = dists_m > limit_dist_m\n        dists_m[mask] = np.nan\n        angles_d[mask] = np.nan\n\n    # Handle default limit number case\n    if limit_num is None:\n        limit_num = -1\n\n    # Loop over pairs, plot\n    label_exists = np.full((N_turbs, N_turbs), False)\n    for i in range(N_turbs):\n        for j in range(N_turbs):\n            # import ipdb; ipdb.set_trace()\n            if (\n                ~np.isnan(dists_m[i, j])\n                and dists_m[i, j] != 0.0\n                and ~(dists_m[i, j] > np.sort(dists_m[i, :])[limit_num])\n                # and i in layout_plotting_dict[\"turbine_indices\"]\n                # and j in layout_plotting_dict[\"turbine_indices\"]\n            ):\n                (h,) = ax.plot(\n                    layout_x[[i, j]],\n                    layout_y[[i, j]],\n                    **wake_plotting_dict\n                )\n\n                # Only label in one direction\n                if ~label_exists[i, j]:\n                    linetext = \"{0:.1f} D --- {1:.0f}/{2:.0f}\".format(\n                        dists_m[i, j] / D,\n                        angles_d[i, j],\n                        angles_d[j, i],\n                    )\n\n                    label_line(\n                        h,\n                        linetext,\n                        ax,\n                        near_i=1,\n                        near_x=None,\n                        near_y=None,\n                        rotation_offset=0,\n                        size=wake_label_size,\n                    )\n\n                    label_exists[i, j] = True\n                    label_exists[j, i] = True\n\n    return ax\n\n\ndef plot_farm_terrain(fmodel: FlorisModel, ax: plt.Axes = None) -> None:\n    \"\"\"\n    Creates a filled contour plot visualizing terrain-corrected wind turbine hub heights.\n\n    Args:\n        fmodel (FlorisModel): The FlorisModel object containing layout data.\n        ax (plt.Axes, optional): An existing axes object to plot on. If None, a new\n            figure and axes will be created. Defaults to None.\n    \"\"\"\n    if not ax:\n        _, ax = plt.subplots()\n\n    hub_heights = fmodel.core.farm.hub_heights.flatten()\n    cntr = ax.tricontourf(fmodel.layout_x, fmodel.layout_y, hub_heights, levels=14, cmap=\"RdBu_r\")\n\n    ax.get_figure().colorbar(\n        cntr,\n        ax=ax,\n        label=\"Terrain-corrected hub height (m)\",\n        ticks=np.linspace(\n            np.min(hub_heights) - 10.0,\n            np.max(hub_heights) + 10.0,\n            15,\n        ),\n    )\n\n    return ax\n\n\ndef shade_region(\n    points: np.ndarray,\n    show_points: bool = False,\n    plotting_dict_region: Dict[str, Any] = {},\n    plotting_dict_points: Dict[str, Any] = {},\n    ax: plt.Axes = None,\n) -> plt.Axes:\n    \"\"\"\n    Shades a region defined by a set of vertices and optionally plots the vertices.\n\n    Args:\n        points (np.ndarray): A 2D array where each row represents (x, y) coordinates of a vertex.\n        show_points (bool, optional): If True, plots markers at the specified vertices.\n            Defaults to False.\n        plotting_dict_region (Dict[str, Any], optional): Customization options for shaded region.\n            Valid keys include:\n                * 'color' (str): Fill color. Defaults to 'black'.\n                * 'edgecolor' (str): Edge color. Defaults to None (no edge).\n                * 'alpha' (float): Opacity (transparency) of the fill. Defaults to 0.3.\n                * 'label' (str): Optional label for legend.\n        plotting_dict_points (Dict[str, Any], optional): Customization options for vertex markers.\n            Valid keys include:\n                * 'color' (str): Marker color. Defaults to 'black'.\n                * 'marker' (str): Marker style (e.g., '.', 'o', 'x'). Defaults to None (no marker).\n                * 's' (float): Marker size. Defaults to 10.\n                * 'label' (str): Optional label for legend.\n        ax (plt.Axes, optional): An existing axes object for plotting. If None, creates a new figure\n            and axes. Defaults to None.\n\n    Returns:\n        plt.Axes: The axes object used for the plot.\n    \"\"\"\n\n    # Generate axis, if needed\n    if ax is None:\n        fig = plt.figure(figsize=(8, 8))\n        ax = fig.add_subplot(111)\n\n    # Generate plotting dictionary\n    default_plotting_dict_region = {\n        \"color\": \"black\",\n        \"edgecolor\": None,\n        \"alpha\": 0.3,\n        \"label\": None,\n    }\n    plotting_dict_region = {**default_plotting_dict_region, **plotting_dict_region}\n\n    ax.fill(points[:, 0], points[:, 1], **plotting_dict_region)\n\n    if show_points:\n        default_plotting_dict_points = {\"color\": \"black\", \"marker\": \".\", \"s\": 10, \"label\": None}\n        plotting_dict_points = {**default_plotting_dict_points, **plotting_dict_points}\n\n        ax.scatter(points[:, 0], points[:, 1], **plotting_dict_points)\n\n    # Plot labels and aesthetics\n    ax.axis(\"equal\")\n\n    return ax\n"
  },
  {
    "path": "floris/logging_manager.py",
    "content": "\nimport logging\nfrom datetime import datetime\n\nimport coloredlogs\n\n\n# Global variables for logging\nLOG_TO_CONSOLE = True\nCONSOLE_LEVEL = \"INFO\"\nLOG_TO_FILE = False\nFILE_LEVEL = \"INFO\"\n\n\ndef configure_console_log(enabled=True, level=\"INFO\"):\n    \"\"\"\n    Sets whether the log statements are displayed in the console logging, and,\n    if enabled, the log level to use. If not explicitly configured, console\n    logging is ON at the INFO level.\n\n    Args:\n        enabled (bool, optional): Whether to enable console logging.\n            Defaults to True.\n        level (str, optional): If `enabled` is True, sets the level that the\n            logging module displays. This level is the minimum and all\n            messages at a higher level are included. Valid values are\n\n                - CRITICAL\n                - ERROR\n                - WARNING\n                - INFO\n                - DEBUG\n\n            Defaults to \"INFO\".\n    \"\"\"\n    global LOG_TO_CONSOLE\n    global CONSOLE_LEVEL\n    LOG_TO_CONSOLE = enabled\n    CONSOLE_LEVEL = level\n    _setup_logger()\n\n\ndef configure_file_log(enabled=True, level=\"INFO\"):\n    \"\"\"\n    Sets whether the log statements are exported to a log file, and,\n    if enabled, the log level to use. If not explicitly configured, file\n    logging is OFF.\n\n    Args:\n        enabled (bool, optional): Whether to enable file logging.\n            This argument defaults to True.\n        level (str, optional): If `enabled` is True, sets the level that the\n            logging module displays. This level is the minimum and all\n            messages at a higher level are included. Valid values are\n\n                - CRITICAL\n                - ERROR\n                - WARNING\n                - INFO\n                - DEBUG\n\n            Defaults to \"INFO\".\n    \"\"\"\n    global LOG_TO_FILE\n    global FILE_LEVEL\n    LOG_TO_FILE = enabled\n    FILE_LEVEL = level\n    _setup_logger()\n\n\ndef _setup_logger():\n    \"\"\"\n    Configures the root logger based on the default or user-specified settings.\n    As needed, a StreamHandler is created for console logging or FileHandler\n    is created for file logging. Either or both are attached to the root\n    logger for use throughout FLORIS.\n\n    Returns:\n        logging.Logger: The root logger from the `logging` module.\n    \"\"\"\n    # Create a logger object for floris\n    logger = logging.getLogger(name=\"floris\")\n    logger.setLevel(logging.DEBUG)\n    # level_styles = {'warning': {'color': 'red', 'bold': False}}\n    fmt_console = \"%(name)s %(levelname)s %(message)s\"\n    fmt_file = \"%(asctime)s - %(name)s - %(levelname)s - %(message)s\"\n\n    file_name = \"floris_{:%Y-%m-%d-%H_%M_%S}.log\".format(datetime.now())\n\n    # Remove all existing handlers before adding new ones\n    for h in logger.handlers.copy():\n        logger.removeHandler(h)\n\n    # Configure and add the console handler\n    if LOG_TO_CONSOLE:\n        console_handler = logging.StreamHandler()\n        console_handler.setLevel(CONSOLE_LEVEL)\n        console_format = coloredlogs.ColoredFormatter(\n            # level_styles=level_styles,\n            fmt=fmt_console\n        )\n        console_handler.setFormatter(console_format)\n        console_handler.addFilter(TracebackInfoFilter(clear=True))\n        logger.addHandler(console_handler)\n\n    # Configure and add the file handler\n    if LOG_TO_FILE:\n        file_handler = logging.FileHandler(file_name)\n        file_handler.setLevel(FILE_LEVEL)\n        file_format = logging.Formatter(fmt_file)\n        file_handler.setFormatter(file_format)\n        file_handler.addFilter(TracebackInfoFilter(clear=False))\n        logger.addHandler(file_handler)\n\n    return logger\n\n\nclass TracebackInfoFilter(logging.Filter):\n    \"\"\"Clear or restore the exception on log records\"\"\"\n\n    def __init__(self, clear=True):\n        self.clear = clear\n\n    def filter(self, record):\n        if self.clear:\n            record._stack_info_hidden, record.stack_info = record.stack_info, None\n        elif hasattr(record, \"_stack_info_hidden\"):\n            record.stack_info = record._stack_info_hidden\n            del record._stack_info_hidden\n        return True\n\n\nclass LoggingManager:\n    \"\"\"\n    This class provide an easy access to the global logger.\n    The virtual property here allows a simple and dynamic method\n    for obtaining the correct logger for the calling class.\n    \"\"\"\n\n    @property\n    def logger(self):\n        return logging.getLogger(\n            \"{}.{}\".format(type(self).__module__, type(self).__name__)\n        )\n"
  },
  {
    "path": "floris/optimization/__init__.py",
    "content": "from . import (\n    layout_optimization,\n    other,\n    yaw_optimization,\n)\n"
  },
  {
    "path": "floris/optimization/layout_optimization/__init__.py",
    "content": ""
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_base.py",
    "content": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom shapely.geometry import MultiPolygon, Polygon\n\nfrom floris import TimeSeries\nfrom floris.optimization.yaw_optimization.yaw_optimizer_geometric import (\n    YawOptimizationGeometric,\n)\nfrom floris.wind_data import WindDataBase\n\nfrom ...logging_manager import LoggingManager\n\n\nclass LayoutOptimization(LoggingManager):\n    \"\"\"\n    Base class for layout optimization. This class should not be used directly\n    but should be subclassed by a specific optimization method.\n\n    Args:\n        fmodel (FlorisModel): A FlorisModel object.\n        boundaries (iterable(float, float)): Pairs of x- and y-coordinates\n            that represent the boundary's vertices (m).\n        min_dist (float, optional): The minimum distance to be maintained\n            between turbines during the optimization (m). If not specified,\n            initializes to 2 rotor diameters. Defaults to None.\n        enable_geometric_yaw (bool, optional): If True, enables geometric yaw\n            optimization. Defaults to False.\n        use_value (bool, optional): If True, the layout optimization objective\n            is to maximize annual value production using the value array in the\n            FLORIS model's WindData object. If False, the optimization\n            objective is to maximize AEP. Defaults to False.\n    \"\"\"\n    def __init__(\n        self,\n        fmodel,\n        boundaries,\n        min_dist=None,\n        enable_geometric_yaw=False,\n        use_value=False,\n    ):\n        self.fmodel = fmodel.copy() # Does not copy over the wind_data object\n        self.fmodel.set(wind_data=fmodel.wind_data)\n        self.boundaries = boundaries\n        self.enable_geometric_yaw = enable_geometric_yaw\n        self.use_value = use_value\n\n        # Allow boundaries to be set either as a list of corners or as a\n        # nested list of corners (for seperable regions)\n        self.boundaries = boundaries\n        b_depth = list_depth(boundaries)\n\n        boundary_specification_error_msg = (\n            \"boundaries should be a list of coordinates (specified as (x,y) \"+\\\n            \"tuples) or as a list of list of tuples (for separable regions).\"\n        )\n\n        if b_depth == 1:\n            self._boundary_polygon = MultiPolygon([Polygon(self.boundaries)])\n            self._boundary_line = self._boundary_polygon.boundary\n        elif b_depth == 2:\n            if not isinstance(self.boundaries[0][0], tuple):\n                raise TypeError(boundary_specification_error_msg)\n            self._boundary_polygon = MultiPolygon([Polygon(p) for p in self.boundaries])\n            self._boundary_line = self._boundary_polygon.boundary\n        else:\n            raise TypeError(boundary_specification_error_msg)\n\n        self.xmin, self.ymin, self.xmax, self.ymax = self._boundary_polygon.bounds\n\n        # If no minimum distance is provided, assume a value of 2 rotor diameters\n        if min_dist is None:\n            self.min_dist = 2 * self.rotor_diameter\n        else:\n            self.min_dist = min_dist\n\n        # Check that wind_data is a WindDataBase object\n        if (not isinstance(self.fmodel.wind_data, WindDataBase)):\n            # NOTE: it is no longer strictly necessary that fmodel use\n            # a WindData object, but it is still recommended.\n            self.logger.warning(\n                \"Running layout optimization without a WindData object (e.g. TimeSeries, WindRose, \"\n                \"WindTIRose). We suggest that the user set the wind conditions (and if applicable, \"\n                \"frequencies and values) on the FlorisModel using the wind_data keyword argument \"\n                \"for layout optimizations to capture frequencies and the value of the energy \"\n                \"production accurately. If a WindData object is not defined, uniform frequencies \"\n                \"will be assumed. If use_value is True and a WindData object is not defined, a \"\n                \"value of 1 will be used for each wind condition and layout optimization will \"\n                \"simply be performed to maximize AEP.\"\n            )\n\n        # Establish geometric yaw class\n        if self.enable_geometric_yaw:\n            self.yaw_opt = YawOptimizationGeometric(\n                fmodel,\n                minimum_yaw_angle=-30.0,\n                maximum_yaw_angle=30.0,\n            )\n        fmodel.run()\n\n        if self.use_value:\n            self.initial_AEP_or_AVP = fmodel.get_farm_AVP()\n        else:\n            self.initial_AEP_or_AVP = fmodel.get_farm_AEP()\n\n    def __str__(self):\n        return \"layout\"\n\n    def _norm(self, val, x1, x2):\n            return (val - x1) / (x2 - x1)\n\n    def _unnorm(self, val, x1, x2):\n        return np.array(val) * (x2 - x1) + x1\n\n    def _get_geoyaw_angles(self):\n        # NOTE: requires that child class saves x and y locations\n        # as self.x and self.y and updates them during optimization.\n        if self.enable_geometric_yaw:\n            self.yaw_opt.fmodel_subset.set(layout_x=self.x, layout_y=self.y)\n            df_opt = self.yaw_opt.optimize()\n            self.yaw_angles = np.vstack(df_opt['yaw_angles_opt'])[:, :]\n        else:\n            self.yaw_angles = None\n\n        return self.yaw_angles\n\n    # Public methods\n\n    def optimize(self):\n        sol = self._optimize()\n        return sol\n\n    def plot_layout_opt_results(\n            self,\n            plot_boundary_dict={},\n            initial_locs_plotting_dict={},\n            final_locs_plotting_dict={},\n            ax=None,\n            fontsize=16\n        ):\n\n        x_initial, y_initial, x_opt, y_opt = self._get_initial_and_final_locs()\n\n        # Generate axis, if needed\n        if ax is None:\n            fig = plt.figure(figsize=(9,6))\n            ax = fig.add_subplot(111)\n            ax.set_aspect(\"equal\")\n\n        # Handle default boundary plotting\n        default_plot_boundary_dict = {\n            \"color\":\"None\",\n            \"alpha\":1,\n            \"edgecolor\":\"b\",\n            \"linewidth\":2\n        }\n        plot_boundary_dict = {**default_plot_boundary_dict, **plot_boundary_dict}\n\n        # Handle default initial location plotting\n        default_initial_locs_plotting_dict = {\n            \"marker\":\"o\",\n            \"color\":\"b\",\n            \"linestyle\":\"None\",\n            \"label\":\"Initial locations\",\n        }\n        initial_locs_plotting_dict = {\n            **default_initial_locs_plotting_dict,\n            **initial_locs_plotting_dict\n        }\n\n        # Handle default final location plotting\n        default_final_locs_plotting_dict = {\n            \"marker\":\"o\",\n            \"color\":\"r\",\n            \"linestyle\":\"None\",\n            \"label\":\"New locations\",\n        }\n        final_locs_plotting_dict = {**default_final_locs_plotting_dict, **final_locs_plotting_dict}\n\n        self.plot_layout_opt_boundary(plot_boundary_dict, ax=ax)\n        ax.plot(x_initial, y_initial, **initial_locs_plotting_dict)\n        ax.plot(x_opt, y_opt, **final_locs_plotting_dict)\n        ax.set_xlabel(\"x (m)\", fontsize=fontsize)\n        ax.set_ylabel(\"y (m)\", fontsize=fontsize)\n        ax.grid(True)\n        ax.tick_params(which=\"both\", labelsize=fontsize)\n        ax.legend(\n            loc=\"lower center\",\n            bbox_to_anchor=(0.5, 1.01),\n            ncol=2,\n            fontsize=fontsize,\n        )\n\n        return ax\n\n    def plot_layout_opt_boundary(self, plot_boundary_dict={}, ax=None):\n\n        # Generate axis, if needed\n        if ax is None:\n            fig = plt.figure(figsize=(9,6))\n            ax = fig.add_subplot(111)\n            ax.set_aspect(\"equal\")\n\n        default_plot_boundary_dict = {\n            \"color\":\"k\",\n            \"alpha\":0.1,\n            \"edgecolor\":None\n        }\n\n        plot_boundary_dict = {**default_plot_boundary_dict, **plot_boundary_dict}\n\n        for line in self._boundary_line.geoms:\n            xy = np.array(line.coords)\n            ax.fill(xy[:,0], xy[:,1], **plot_boundary_dict)\n        ax.grid(True)\n\n        return ax\n\n    def plot_progress(self, ax=None):\n\n        if not hasattr(self, \"objective_candidate_log\"):\n            raise NotImplementedError(\n                \"plot_progress not yet configured for \"+self.__class__.__name__\n            )\n\n        if ax is None:\n            _, ax = plt.subplots(1,1)\n\n        objective_log_array = np.array(self.objective_candidate_log)\n\n        if len(objective_log_array.shape) == 1: # Just one AEP candidate per step\n            ax.plot(np.arange(len(objective_log_array)), objective_log_array, color=\"k\")\n        elif len(objective_log_array.shape) == 2: # Multiple AEP candidates per step\n            for i in range(objective_log_array.shape[1]):\n                ax.plot(\n                    np.arange(len(objective_log_array)),\n                    objective_log_array[:,i],\n                    color=\"lightgray\"\n                )\n\n        ax.scatter(\n            np.zeros(objective_log_array.shape[1]),\n            objective_log_array[0,:],\n            color=\"b\",\n            label=\"Initial\"\n        )\n        ax.scatter(\n            objective_log_array.shape[0]-1,\n            objective_log_array[-1,:].max(),\n            color=\"r\",\n            label=\"Final\"\n        )\n\n        # Plot aesthetics\n        ax.grid(True)\n        ax.set_xlabel(\"Optimization step [-]\")\n        ax.set_ylabel(\"Objective function\")\n        ax.legend()\n\n        return ax\n\n\n    ###########################################################################\n    # Properties\n    ###########################################################################\n\n    @property\n    def nturbs(self):\n        \"\"\"\n        This property returns the number of turbines in the FLORIS\n        object.\n\n        Returns:\n            nturbs (int): The number of turbines in the FLORIS object.\n        \"\"\"\n        self._nturbs = self.fmodel.core.farm.n_turbines\n        return self._nturbs\n\n    @property\n    def rotor_diameter(self):\n        return self.fmodel.core.farm.rotor_diameters_sorted[0][0]\n\n# Helper functions\n\ndef list_depth(x):\n    if isinstance(x, list) and len(x) > 0:\n        return 1 + max(list_depth(item) for item in x)\n    else:\n        return 0\n"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_boundary_grid.py",
    "content": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.spatial.distance import cdist\nfrom shapely.geometry import (\n    LineString,\n    Point,\n    Polygon,\n)\n\nfrom .layout_optimization_base import LayoutOptimization\n\n\nclass LayoutOptimizationBoundaryGrid(LayoutOptimization):\n    def __init__(\n        self,\n        fmodel,\n        boundaries,\n        start,\n        x_spacing,\n        y_spacing,\n        shear,\n        rotation,\n        center_x,\n        center_y,\n        boundary_setback,\n        n_boundary_turbines=None,\n        boundary_spacing=None,\n    ):\n        self.fmodel = fmodel\n\n        self.boundary_x = np.array([val[0] for val in boundaries])\n        self.boundary_y = np.array([val[1] for val in boundaries])\n        boundary = np.zeros((len(self.boundary_x), 2))\n        boundary[:, 0] = self.boundary_x[:]\n        boundary[:, 1] = self.boundary_y[:]\n        self._boundary_polygon = Polygon(boundary)\n\n        self.start = start\n        self.x_spacing = x_spacing\n        self.y_spacing = y_spacing\n        self.shear = shear\n        self.rotation = rotation\n        self.center_x = center_x\n        self.center_y = center_y\n        self.boundary_setback = boundary_setback\n        self.n_boundary_turbines = n_boundary_turbines\n        self.boundary_spacing = boundary_spacing\n\n    def _discontinuous_grid(\n        self,\n        nrows,\n        ncols,\n        farm_width,\n        farm_height,\n        shear,\n        rotation,\n        center_x,\n        center_y,\n        shrink_boundary,\n        boundary_x,\n        boundary_y,\n        eps=1e-3,\n    ):\n        \"\"\"\n        Map from grid design variables to turbine x and y locations.\n        Includes integer design variables and the formulation\n        results in a discontinous design space.\n\n        TODO: shrink_boundary doesn't work well with concave boundaries,\n        or with boundary angles less than 90 deg\n\n        Args:\n            nrows (Int): number of rows in the grid.\n            ncols (Int): number of columns in the grid.\n            farm_width (Float): total grid width (before shear).\n            farm_height (Float): total grid height.\n            shear (Float): grid shear (rad).\n            rotation (Float): rotation about grid center (rad).\n            center_x (Float): location of grid x center.\n            center_y (Float): location of grid y center.\n            shrink_boundary (Float): how much to shrink the boundary that the grid can occupy.\n            boundary_x (Array(Float)): x boundary points.\n            boundary_y (Array(Float)): y boundary points.\n\n        Returns:\n            grid_x (Array(Float)): turbine x locations.\n            grid_y (Array(Float)): turbine y locations.\n        \"\"\"\n        # create grid\n        nrows = int(nrows)\n        ncols = int(ncols)\n        xlocs = np.linspace(0.0, farm_width, ncols)\n        ylocs = np.linspace(0.0, farm_height, nrows)\n        y_spacing = ylocs[1] - ylocs[0]\n        nturbs = nrows * ncols\n        grid_x = np.zeros(nturbs)\n        grid_y = np.zeros(nturbs)\n        turb = 0\n        for i in range(nrows):\n            for j in range(ncols):\n                grid_x[turb] = xlocs[j] + float(i) * y_spacing * np.tan(shear)\n                grid_y[turb] = ylocs[i]\n                turb += 1\n\n        # rotate\n        grid_x, grid_y = (\n            np.cos(rotation) * grid_x - np.sin(rotation) * grid_y,\n            np.sin(rotation) * grid_x + np.cos(rotation) * grid_y,\n        )\n\n        # move center of grid\n        grid_x = (grid_x - np.mean(grid_x)) + center_x\n        grid_y = (grid_y - np.mean(grid_y)) + center_y\n\n        # arrange the boundary\n\n        # boundary = np.zeros((len(boundary_x),2))\n        # boundary[:,0] = boundary_x[:]\n        # boundary[:,1] = boundary_y[:]\n        # poly = Polygon(boundary)\n        # centroid = poly.centroid\n\n        # boundary[:,0] = (boundary_x[:]-centroid.x)*boundary_mult + centroid.x\n        # boundary[:,1] = (boundary_y[:]-centroid.y)*boundary_mult + centroid.y\n        # poly = Polygon(boundary)\n\n        boundary = np.zeros((len(boundary_x), 2))\n        boundary[:, 0] = boundary_x[:]\n        boundary[:, 1] = boundary_y[:]\n        poly = Polygon(boundary)\n\n        if shrink_boundary != 0.0:\n            nBounds = len(boundary_x)\n            for i in range(nBounds):\n                point = Point(boundary_x[i] + eps, boundary_y[i])\n                if poly.contains(point) is True or poly.touches(point) is True:\n                    boundary[i, 0] = boundary_x[i] + shrink_boundary\n                else:\n                    boundary[i, 0] = boundary_x[i] - shrink_boundary\n\n                point = Point(boundary_x[i], boundary_y[i] + eps)\n                if poly.contains(point) is True or poly.touches(point) is True:\n                    boundary[i, 1] = boundary_y[i] + shrink_boundary\n                else:\n                    boundary[i, 1] = boundary_y[i] - shrink_boundary\n\n            poly = Polygon(boundary)\n\n        # get rid of points outside of boundary\n        index = 0\n        for i in range(len(grid_x)):\n            point = Point(grid_x[index], grid_y[index])\n            if poly.contains(point) is False and poly.touches(point) is False:\n                grid_x = np.delete(grid_x, index)\n                grid_y = np.delete(grid_y, index)\n            else:\n                index += 1\n\n        return grid_x, grid_y\n\n    def _discrete_grid(\n        self,\n        x_spacing,\n        y_spacing,\n        shear,\n        rotation,\n        center_x,\n        center_y,\n        boundary_setback,\n        boundary_poly\n    ):\n        \"\"\"\n        returns grid turbine layout. Assumes the turbines fill the entire plant area\n\n        Args:\n        x_spacing (Float): grid spacing in the unrotated x direction (m)\n        y_spacing (Float): grid spacing in the unrotated y direction (m)\n        shear (Float): grid shear (rad)\n        rotation (Float): grid rotation (rad)\n        center_x (Float): the x coordinate of the grid center (m)\n        center_y (Float): the y coordinate of the grid center (m)\n        boundary_poly (Polygon): a shapely Polygon of the wind plant boundary\n\n        Returns\n        return_x (Array(Float)): turbine x locations\n        return_y (Array(Float)): turbine y locations\n        \"\"\"\n\n        shrunk_poly = boundary_poly.buffer(-boundary_setback)\n        if shrunk_poly.area <= 0:\n            return np.array([]), np.array([])\n        # create grid\n        minx, miny, maxx, maxy = shrunk_poly.bounds\n        width = maxx-minx\n        height = maxy-miny\n\n        center_point = Point((center_x,center_y))\n        poly_to_center = center_point.distance(shrunk_poly.centroid)\n\n        width = np.max([width,poly_to_center])\n        height = np.max([height,poly_to_center])\n        nrows = int(np.max([width,height])/np.min([x_spacing,y_spacing]))*2 + 1\n        ncols = nrows\n\n        xlocs = np.arange(0,ncols)*x_spacing\n        ylocs = np.arange(0,nrows)*y_spacing\n        row_number = np.arange(0,nrows)\n\n        d = np.array([i for x in xlocs for i in row_number])\n        layout_x = np.array([x for x in xlocs for y in ylocs]) + d*y_spacing*np.tan(shear)\n        layout_y = np.array([y for x in xlocs for y in ylocs])\n\n        # rotate\n        rotate_x = np.cos(rotation)*layout_x - np.sin(rotation)*layout_y\n        rotate_y = np.sin(rotation)*layout_x + np.cos(rotation)*layout_y\n\n        # move center of grid\n        rotate_x = (rotate_x - np.mean(rotate_x)) + center_x\n        rotate_y = (rotate_y - np.mean(rotate_y)) + center_y\n\n        # get rid of points outside of boundary polygon\n        meets_constraints = np.zeros(len(rotate_x),dtype=bool)\n        for i in range(len(rotate_x)):\n            pt = Point(rotate_x[i],rotate_y[i])\n            if shrunk_poly.contains(pt) or shrunk_poly.touches(pt):\n                meets_constraints[i] = True\n\n        # arrange final x,y points\n        return_x = rotate_x[meets_constraints]\n        return_y = rotate_y[meets_constraints]\n\n        return return_x, return_y\n\n    def find_lengths(self, x, y, npoints):\n        length = np.zeros(len(x) - 1)\n        for i in range(npoints):\n            length[i] = np.sqrt((x[i + 1] - x[i]) ** 2 + (y[i + 1] - y[i]) ** 2)\n        return length\n\n    # def _place_boundary_turbines(self, n_boundary_turbs, start, boundary_x, boundary_y):\n    #     \"\"\"\n    #     Place turbines equally spaced traversing the perimiter if the wind farm along the boundary\n\n    #     Args:\n    #     n_boundary_turbs (Int): number of turbines to be placed on the boundary\n    #     start (Float): where the first turbine should be placed\n    #     boundary_x (Array(Float)): x boundary points\n    #     boundary_y (Array(Float)): y boundary points\n\n    #     Returns\n    #     layout_x (Array(Float)): turbine x locations\n    #     layout_y (Array(Float)): turbine y locations\n    #     \"\"\"\n\n    #     # check if the boundary is closed, correct if not\n    #     if boundary_x[-1] != boundary_x[0] or boundary_y[-1] != boundary_y[0]:\n    #         boundary_x = np.append(boundary_x, boundary_x[0])\n    #         boundary_y = np.append(boundary_y, boundary_y[0])\n\n    #     # make the boundary\n    #     boundary = np.zeros((len(boundary_x), 2))\n    #     boundary[:, 0] = boundary_x[:]\n    #     boundary[:, 1] = boundary_y[:]\n    #     poly = Polygon(boundary)\n    #     perimeter = poly.length\n\n    #     # get the flattened turbine locations\n    #     spacing = perimeter / float(n_boundary_turbs)\n    #     flattened_locs = np.linspace(start, perimeter + start - spacing, n_boundary_turbs)\n\n    #     # set all of the flattened values between 0 and the perimeter\n    #     for i in range(n_boundary_turbs):\n    #         while flattened_locs[i] < 0.0:\n    #             flattened_locs[i] += perimeter\n    #         if flattened_locs[i] > perimeter:\n    #             flattened_locs[i] = flattened_locs[i] % perimeter\n\n    #     # place the turbines around the perimeter\n    #     nBounds = len(boundary_x)\n    #     layout_x = np.zeros(n_boundary_turbs)\n    #     layout_y = np.zeros(n_boundary_turbs)\n\n    #     lenBound = np.zeros(nBounds - 1)\n    #     for i in range(nBounds - 1):\n    #         lenBound[i] = Point(boundary[i]).distance(Point(boundary[i + 1]))\n    #     for i in range(n_boundary_turbs):\n    #         for j in range(nBounds - 1):\n    #             if flattened_locs[i] < sum(lenBound[0 : j + 1]):\n    #                 layout_x[i] = (\n    #                     boundary_x[j]\n    #                     + (boundary_x[j + 1] - boundary_x[j])\n    #                     * (flattened_locs[i] - sum(lenBound[0:j]))\n    #                     / lenBound[j]\n    #                 )\n    #                 layout_y[i] = (\n    #                     boundary_y[j]\n    #                     + (boundary_y[j + 1] - boundary_y[j])\n    #                     * (flattened_locs[i] - sum(lenBound[0:j]))\n    #                     / lenBound[j]\n    #                 )\n    #                 break\n\n    #     return layout_x, layout_y\n\n    def _place_boundary_turbines(self, start, boundary_poly, nturbs=None, spacing=None):\n        xBounds, yBounds = boundary_poly.boundary.coords.xy\n\n        if xBounds[-1] != xBounds[0]:\n            xBounds = np.append(xBounds, xBounds[0])\n            yBounds = np.append(yBounds, yBounds[0])\n\n        nBounds = len(xBounds)\n        lenBound = self.find_lengths(xBounds, yBounds, len(xBounds) - 1)\n        circumference = sum(lenBound)\n\n        if nturbs is not None and spacing is None:\n            # When the number of boundary turbines is specified\n            nturbs = int(nturbs)\n            bound_loc = np.linspace(\n                start, start + circumference - circumference / float(nturbs), nturbs\n            )\n        elif spacing is not None and nturbs is None:\n            # When the spacing of boundary turbines is specified\n            nturbs = int(np.floor(circumference / spacing))\n            bound_loc = np.linspace(\n                start, start + circumference - circumference / float(nturbs), nturbs\n            )\n        else:\n            raise ValueError(\"Please specify either nturbs or spacing.\")\n\n        x = np.zeros(nturbs)\n        y = np.zeros(nturbs)\n\n        if spacing is None:\n            # When the number of boundary turbines is specified\n            for i in range(nturbs):\n                if bound_loc[i] > circumference:\n                    bound_loc[i] = bound_loc[i] % circumference\n                while bound_loc[i] < 0.0:\n                    bound_loc[i] += circumference\n            for i in range(nturbs):\n                done = False\n                for j in range(nBounds):\n                    if done is False:\n                        if bound_loc[i] < sum(lenBound[0:j+1]):\n                            point_x = (\n                                xBounds[j]\n                                + (xBounds[j+1] - xBounds[j])\n                                * (bound_loc[i] - sum(lenBound[0:j]))\n                                / lenBound[j]\n                            )\n                            point_y = (\n                                yBounds[j]\n                                + (yBounds[j+1] - yBounds[j])\n                                * (bound_loc[i] - sum(lenBound[0:j]))\n                                / lenBound[j]\n                            )\n                            done = True\n                            x[i] = point_x\n                            y[i] = point_y\n        else:\n            # When the spacing of boundary turbines is specified\n            additional_space = 0.0\n            end_loop = False\n            for i in range(nturbs):\n                done = False\n                for j in range(nBounds):\n                    while done is False:\n                        dist = start + i*spacing + additional_space\n                        if dist < sum(lenBound[0:j+1]):\n                            point_x = (\n                                xBounds[j]\n                                + (xBounds[j+1]-xBounds[j])\n                                * (dist -sum(lenBound[0:j]))\n                                / lenBound[j]\n                            )\n                            point_y = (\n                                yBounds[j]\n                                + (yBounds[j+1]-yBounds[j])\n                                * (dist -sum(lenBound[0:j]))\n                                / lenBound[j]\n                            )\n\n                            # Check if turbine is too close to previous turbine\n                            if i > 0:\n                                # Check if turbine just placed is to close to first turbine\n                                min_dist = cdist([(point_x, point_y)], [(x[0], y[0])])\n                                if min_dist < spacing:\n                                    # TODO: make this more robust;\n                                    # pass is needed if 2nd turbine is too close to the first\n                                    if i == 1:\n                                        pass\n                                    else:\n                                        end_loop = True\n                                        ii = i\n                                        break\n\n                                min_dist = cdist([(point_x, point_y)], [(x[i-1], y[i-1])])\n                                if min_dist < spacing:\n                                    additional_space += 1.0\n                                else:\n                                    done = True\n                                    x[i] = point_x\n                                    y[i] = point_y\n                            elif i == 0:\n                                # If first turbine, just add initial turbine point\n                                done = True\n                                x[i] = point_x\n                                y[i] = point_y\n                            else:\n                                pass\n                        else:\n                            break\n                    if end_loop is True:\n                        break\n                if end_loop is True:\n                    x = x[:ii]\n                    y = y[:ii]\n                    break\n        return x, y\n\n    def _place_boundary_turbines_with_specified_spacing(\n        self,\n        spacing,\n        start,\n        boundary_x,\n        boundary_y\n    ):\n        \"\"\"\n        Place turbines equally spaced traversing the perimiter if the wind farm along the boundary\n\n        Args:\n        n_boundary_turbs (Int): number of turbines to be placed on the boundary\n        start (Float): where the first turbine should be placed\n        boundary_x (Array(Float)): x boundary points\n        boundary_y (Array(Float)): y boundary points\n\n        Returns\n        layout_x (Array(Float)): turbine x locations\n        layout_y (Array(Float)): turbine y locations\n        \"\"\"\n\n        # check if the boundary is closed, correct if not\n        if boundary_x[-1] != boundary_x[0] or boundary_y[-1] != boundary_y[0]:\n            boundary_x = np.append(boundary_x, boundary_x[0])\n            boundary_y = np.append(boundary_y, boundary_y[0])\n\n        # make the boundary\n        boundary = np.zeros((len(boundary_x), 2))\n        boundary[:, 0] = boundary_x[:]\n        boundary[:, 1] = boundary_y[:]\n        poly = Polygon(boundary)\n        perimeter = poly.length\n\n        # get the flattened turbine locations\n        n_boundary_turbs = int(perimeter / float(spacing))\n        flattened_locs = np.linspace(start, perimeter + start - spacing, n_boundary_turbs)\n\n        # set all of the flattened values between 0 and the perimeter\n        for i in range(n_boundary_turbs):\n            while flattened_locs[i] < 0.0:\n                flattened_locs[i] += perimeter\n            if flattened_locs[i] > perimeter:\n                flattened_locs[i] = flattened_locs[i] % perimeter\n\n        # place the turbines around the perimeter\n        nBounds = len(boundary_x)\n        layout_x = np.zeros(n_boundary_turbs)\n        layout_y = np.zeros(n_boundary_turbs)\n\n        lenBound = np.zeros(nBounds - 1)\n        for i in range(nBounds - 1):\n            lenBound[i] = Point(boundary[i]).distance(Point(boundary[i + 1]))\n        for i in range(n_boundary_turbs):\n            for j in range(nBounds - 1):\n                if flattened_locs[i] < sum(lenBound[0 : j + 1]):\n                    layout_x[i] = (\n                        boundary_x[j]\n                        + (boundary_x[j + 1] - boundary_x[j])\n                        * (flattened_locs[i] - sum(lenBound[0:j]))\n                        / lenBound[j]\n                    )\n                    layout_y[i] = (\n                        boundary_y[j]\n                        + (boundary_y[j + 1] - boundary_y[j])\n                        * (flattened_locs[i] - sum(lenBound[0:j]))\n                        / lenBound[j]\n                    )\n                    break\n\n        return layout_x, layout_y\n\n    def boundary_grid(\n        self,\n        start,\n        x_spacing,\n        y_spacing,\n        shear,\n        rotation,\n        center_x,\n        center_y,\n        boundary_setback,\n        n_boundary_turbines=None,\n        boundary_spacing=None,\n    ):\n        \"\"\"\n        Place turbines equally spaced traversing the perimiter if the wind farm along the boundary\n\n        Args:\n        n_boundary_turbs,start: boundary variables\n        nrows,ncols,farm_width,farm_height,shear,\n            rotation,center_x,center_y,shrink_boundary,eps: grid variables\n        boundary_x,boundary_y: boundary points\n\n        Returns\n        layout_x (Array(Float)): turbine x locations\n        layout_y (Array(Float)): turbine y locations\n        \"\"\"\n\n        boundary_turbines_x, boundary_turbines_y = self._place_boundary_turbines(\n            start, self._boundary_polygon, nturbs=n_boundary_turbines, spacing=boundary_spacing\n        )\n        # ( boundary_turbines_x,\n        #  boundary_turbines_y ) = self._place_boundary_turbines_with_specified_spacing(\n        #     spacing, start, boundary_x, boundary_y\n        # )\n\n        # grid_turbines_x, grid_turbines_y = self._discontinuous_grid(\n        #     nrows,\n        #     ncols,\n        #     farm_width,\n        #     farm_height,\n        #     shear,\n        #     rotation,\n        #     center_x,\n        #     center_y,\n        #     shrink_boundary,\n        #     boundary_x,\n        #     boundary_y,\n        #     eps=eps,\n        # )\n\n        grid_turbines_x, grid_turbines_y = self._discrete_grid(\n            x_spacing,\n            y_spacing,\n            shear,\n            rotation,\n            center_x,\n            center_y,\n            boundary_setback,\n            self._boundary_polygon,\n        )\n\n        layout_x = np.append(boundary_turbines_x, grid_turbines_x)\n        layout_y = np.append(boundary_turbines_y, grid_turbines_y)\n\n        return layout_x, layout_y\n\n    def reinitialize_bg(\n        self,\n        n_boundary_turbines=None,\n        start=None,\n        x_spacing=None,\n        y_spacing=None,\n        shear=None,\n        rotation=None,\n        center_x=None,\n        center_y=None,\n        boundary_setback=None,\n        boundary_x=None,\n        boundary_y=None,\n        boundary_spacing=None,\n    ):\n\n        if n_boundary_turbines is not None:\n            self.n_boundary_turbines = n_boundary_turbines\n        if start is not None:\n            self.start = start\n        if x_spacing is not None:\n            self.x_spacing = x_spacing\n        if y_spacing is not None:\n            self.y_spacing = y_spacing\n        if shear is not None:\n            self.shear = shear\n        if rotation is not None:\n            self.rotation = rotation\n        if center_x is not None:\n            self.center_x = center_x\n        if center_y is not None:\n            self.center_y = center_y\n        if boundary_setback is not None:\n            self.boundary_setback = boundary_setback\n        if boundary_x is not None:\n            self.boundary_x = boundary_x\n        if boundary_y is not None:\n            self.boundary_y = boundary_y\n        if boundary_spacing is not None:\n            self.boundary_spacing = boundary_spacing\n\n    def reinitialize_xy(self):\n        layout_x, layout_y = self.boundary_grid(\n            self.start,\n            self.x_spacing,\n            self.y_spacing,\n            self.shear,\n            self.rotation,\n            self.center_x,\n            self.center_y,\n            self.boundary_setback,\n            self.n_boundary_turbines,\n            self.boundary_spacing,\n        )\n\n        self.fmodel.set(layout=(layout_x, layout_y))\n\n    def plot_layout(self):\n        plt.figure(figsize=(9, 6))\n        fontsize = 16\n\n        plt.plot(self.fmodel.layout_x, self.fmodel.layout_y, \"ob\")\n        # plt.plot(locsx, locsy, \"or\")\n\n        plt.xlabel(\"x (m)\", fontsize=fontsize)\n        plt.ylabel(\"y (m)\", fontsize=fontsize)\n        plt.axis(\"equal\")\n        plt.grid()\n        plt.tick_params(which=\"both\", labelsize=fontsize)\n\n    def space_constraint(self, x, y, min_dist, rho=500):\n        # Calculate distances between turbines\n        locs = np.vstack((x, y)).T\n        distances = cdist(locs, locs)\n        arange = np.arange(distances.shape[0])\n        distances[arange, arange] = 1e10\n        dist = np.min(distances, axis=0)\n\n        g = 1 - np.array(dist) / min_dist\n\n        # Following code copied from OpenMDAO KSComp().\n        # Constraint is satisfied when KS_constraint <= 0\n        g_max = np.max(np.atleast_2d(g), axis=-1)[:, np.newaxis]\n        g_diff = g - g_max\n        exponents = np.exp(rho * g_diff)\n        summation = np.sum(exponents, axis=-1)[:, np.newaxis]\n        KS_constraint = g_max + 1.0 / rho * np.log(summation)\n\n        return KS_constraint[0][0], dist\n"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_gridded.py",
    "content": "import numpy as np\n\nfrom floris import FlorisModel\n\nfrom .layout_optimization_base import LayoutOptimization\nfrom .layout_optimization_random_search import test_point_in_bounds\n\n\nclass LayoutOptimizationGridded(LayoutOptimization):\n    \"\"\"\n    Generates layouts that fit the most turbines arranged in a gridded\n    pattern into the given boundaries. The grid can be square (default)\n    or hexagonal. The layout is optimized by rotating and translating\n    the grid to maximize the number of turbines that fit within the\n    boundaries. Note that no wake or AEP calculations are performed in\n    determining the maximum number of turbines that fit within the\n    boundary.\n    \"\"\"\n    def __init__(\n        self,\n        fmodel: FlorisModel,\n        boundaries: list[tuple[float, float] | list[tuple[float, float]]],\n        min_dist: float | None = None,\n        min_dist_D: float | None = -1,\n        rotation_step: float = 5.0,\n        rotation_range: tuple[float, float] = (0.0, 360.0),\n        translation_step: float | None = None,\n        translation_step_D: float | None = -1,\n        translation_range: tuple[float, float] | None = None,\n        hexagonal_packing: bool = False,\n    ):\n        \"\"\"\n        Initialize the LayoutOptimizationGridded object.\n\n        Args:\n            fmodel: FlorisModel, mostly used to obtain rotor diameter for spacing\n            boundaries: List of boundary vertices. Specified as a list of two-tuples (x,y),\n                or a list of lists of two-tuples if there are multiple separate boundary areas.\n            min_dist: Minimum distance between turbines in meters. Defaults to None, which results\n                in 5D spacing if min_dist_D is not defined.\n            min_dist_D: Minimum distance between turbines in terms of rotor diameters. If specified\n                as a negative number, will result in 5D spacing using the first turbine diameter\n                found on the fmodel. Defaults to -1, which results in 5D spacing if min_dist is not\n                defined.\n            rotation_step: Step size for grid rotations in degrees. Defaults to 5.0.\n            rotation_range: Range of possible rotation in degrees. Defaults to (0.0, 360.0).\n            translation_step: Step size for translation in meters. Defaults to None, which results\n                in 1D translations if translation_step_D is not defined.\n            translation_step_D: Step size for translation in terms of rotor diameters. If specified\n                as a negative number, will result in 1D translation steps using the first turbine\n                diameter found on the fmodel. Defaults to -1, which results in 1D steps if\n                translation_step is not defined.\n            translation_range: Range of translation in meters. Defaults to None, which results in\n                a range of (0, min_dist).\n            hexagonal_packing: Use hexagonal packing instead of square grid. Defaults to False.\n        \"\"\"\n\n        # Handle spacing information\n        if min_dist is not None and min_dist_D is not None and min_dist_D >= 0:\n            raise ValueError(\"Only one of min_dist and min_dist_D can be defined.\")\n        if min_dist is None and min_dist_D is None:\n            raise ValueError(\"Either min_dist or min_dist_D must be defined.\")\n        if min_dist_D is not None and min_dist is None:\n            if min_dist_D < 0: # Default to 5D\n                min_dist_D = 5.0\n            min_dist = min_dist_D * fmodel.core.farm.rotor_diameters.flat[0]\n            if len(np.unique(fmodel.core.farm.rotor_diameters)) > 1:\n                self.logger.warning((\n                    \"Found multiple turbine diameters. Using diameter of first turbine to set\"\n                    f\" min_dist to {min_dist}m ({min_dist_D} diameters).\"\n                ))\n\n        # Similar for translation step\n        if (translation_step is not None\n            and translation_step_D is not None\n            and translation_step_D >= 0\n           ):\n            raise ValueError(\"Only one of translation_step and translation_step_D can be defined.\")\n        if translation_step is None and translation_step_D is None:\n            raise ValueError(\"Either translation_step or translation_step_D must be defined.\")\n        if translation_step_D is not None and translation_step is None:\n            if translation_step_D < 0: # Default to 1D\n                translation_step_D = 1.0\n            translation_step = translation_step_D * fmodel.core.farm.rotor_diameters.flat[0]\n            if len(np.unique(fmodel.core.farm.rotor_diameters)) > 1:\n                self.logger.warning((\n                    \"Found multiple turbine diameters. Using diameter of first turbine to set\"\n                    f\" translation step to {translation_step}m ({translation_step_D} diameters).\"\n                ))\n\n        # Initialize the base class\n        super().__init__(\n            fmodel,\n            boundaries,\n            min_dist=min_dist,\n            enable_geometric_yaw=False,\n            use_value=False,\n        )\n\n        # Initial locations not used for optimization, but may be useful\n        # for comparison\n        self.x0 = fmodel.layout_x\n        self.y0 = fmodel.layout_y\n\n        # Create the default grid\n\n        # use min_dist, hexagonal packing, and boundaries to create a grid.\n        d = 1.1 * np.sqrt((self.xmax - self.xmin)**2 + (self.ymax - self.ymin)**2)\n        grid_1D = np.arange(0, d+min_dist, min_dist)\n        if hexagonal_packing:\n            x_locs = np.tile(grid_1D.reshape(1,-1), (len(grid_1D), 1))\n            x_locs[np.arange(1, len(grid_1D), 2), :] += 0.5 * min_dist\n            y_locs = np.tile(np.sqrt(3) / 2 * grid_1D.reshape(-1,1), (1, len(grid_1D)))\n        else:\n            x_locs, y_locs = np.meshgrid(grid_1D, grid_1D)\n        x_locs = x_locs.flatten() - np.mean(x_locs) + 0.5*(self.xmax + self.xmin)\n        y_locs = y_locs.flatten() - np.mean(y_locs) + 0.5*(self.ymax + self.ymin)\n\n        # Trim to a circle to avoid wasted computation\n        x_locs_grid, y_locs_grid = self.trim_to_circle(\n            x_locs,\n            y_locs,\n            (grid_1D.max()-grid_1D.min()+min_dist)/2\n        )\n        self.xy_grid = np.concatenate(\n            [x_locs_grid.reshape(-1,1), y_locs_grid.reshape(-1,1)],\n            axis=1\n        )\n\n        # Limit the rotation range if grid has symmetry\n        if hexagonal_packing:\n            # Hexagonal packing has 60 degree symmetry\n            rotation_range = (\n                rotation_range[0],\n                np.minimum(rotation_range[1], rotation_range[0]+60)\n            )\n        else:\n            # Square grid has 90 degree symmetry\n            rotation_range = (\n                rotation_range[0],\n                np.minimum(rotation_range[1], rotation_range[0]+90)\n            )\n\n        # Deal with None translation_range\n        if translation_range is None:\n            translation_range = (0.0, min_dist)\n\n        # Create test rotations and translations\n        self.rotations = np.arange(rotation_range[0], rotation_range[1], rotation_step)\n        self.translations = np.arange(translation_range[0], translation_range[1], translation_step)\n        self.translations = np.concatenate([-np.flip(self.translations), self.translations])\n\n    def optimize(self):\n\n        # Sweep over rotations and translations to find the best layout\n        n_rots = len(self.rotations)\n        n_trans = len(self.translations)\n        n_tot = n_rots * n_trans**2\n\n        # There are a total of n_rots x n_trans x n_trans layouts to test\n        rots_rad = np.radians(self.rotations)\n        rotation_matrices = np.array(\n            [\n                [np.cos(rots_rad), -np.sin(rots_rad)],\n                [np.sin(rots_rad), np.cos(rots_rad)]\n            ]\n        ).transpose(2,0,1)\n\n        translations_x, translations_y = np.meshgrid(self.translations, self.translations)\n        translation_matrices = np.concatenate(\n            [translations_x.reshape(-1,1), translations_y.reshape(-1,1)],\n            axis=1\n        )\n\n        rotations_all = np.tile(rotation_matrices, (n_trans**2, 1, 1))\n        translations_all = np.repeat(translation_matrices, n_rots, axis=0)[:,None,:]\n\n        # Create candidate layouts [(n_rots x n_trans x n_trans) x n_turbines x 2]\n        candidate_layouts = np.einsum('ijk,lk->ilj', rotations_all, self.xy_grid) + translations_all\n\n        # For each candidate layout, check how many turbines are in bounds\n        turbines_in_bounds = np.zeros(n_tot)\n        for i in range(n_tot):\n            turbines_in_bounds[i] = np.sum(\n                [test_point_in_bounds(xy[0], xy[1], self._boundary_polygon) for\n                 xy in candidate_layouts[i, :, :]]\n            )\n        idx_max = np.argmax(turbines_in_bounds) # First maximizing index returned\n\n        # Get the best layout\n        x_opt_all = candidate_layouts[idx_max, :, 0]\n        y_opt_all = candidate_layouts[idx_max, :, 1]\n        mask_in_bounds = [test_point_in_bounds(x, y, self._boundary_polygon) for\n                          x, y in zip(x_opt_all, y_opt_all)]\n\n        # Save best layout, along with the number of turbines in bounds, and return\n        self.n_turbines_max = round(turbines_in_bounds[idx_max])\n        self.x_opt = x_opt_all[mask_in_bounds]\n        self.y_opt = y_opt_all[mask_in_bounds]\n        return self.n_turbines_max, self.x_opt, self.y_opt\n\n    def _get_initial_and_final_locs(self):\n        return self.x0, self.y0, self.x_opt, self.y_opt\n\n    @staticmethod\n    def trim_to_circle(x_locs, y_locs, radius):\n        center = np.array([0.5*(x_locs.max() + x_locs.min()), 0.5*(y_locs.max() + y_locs.min())])\n        xy = np.concatenate([x_locs.reshape(-1,1), y_locs.reshape(-1,1)], axis=1)\n        mask = np.linalg.norm(xy - center, axis=1) <= radius\n        return x_locs[mask], y_locs[mask]\n"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_pyoptsparse.py",
    "content": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.spatial.distance import cdist\nfrom shapely.geometry import Point\n\nfrom .layout_optimization_base import LayoutOptimization, list_depth\n\n\nclass LayoutOptimizationPyOptSparse(LayoutOptimization):\n    \"\"\"\n    This class provides an interface for optimizing the layout of wind turbines\n    using the pyOptSparse optimization library.  The optimization objective is to\n    maximize annual energy production (AEP) or annual value production (AVP).\n\n    Args:\n        fmodel (FlorisModel): A FlorisModel object.\n        boundaries (iterable(float, float)): Pairs of x- and y-coordinates\n            that represent the boundary's vertices (m).\n        min_dist (float, optional): The minimum distance to be maintained\n            between turbines during the optimization (m). If not specified,\n            initializes to 2 rotor diameters. Defaults to None.\n        solver (str, optional): Sets the solver used by pyOptSparse. Defaults\n            to 'SLSQP'.\n        optOptions (dict, optional): Dictionary for setting the\n            optimization options. Defaults to None.\n        timeLimit (float, optional): Variable passed to pyOptSparse optimizer.\n            The maximum amount of time for optimizer to run (seconds). If None,\n            no time limit is imposed. Defaults to None.\n        storeHistory (str, optional): Variable passed to pyOptSparse optimizer.\n            File name of the history file into which the history of the\n            pyOptSparse optimization will be stored. Defaults to \"hist.hist\".\n        hotStart (str, optional): Variable passed to pyOptSparse optimizer.\n            File name of the history file to “replay” for the optimization.\n            If None, pyOptSparse initializes the optimization from scratch.\n            Defaults to None.\n        enable_geometric_yaw (bool, optional): If True, enables geometric yaw\n            optimization. Defaults to False.\n        use_value (bool, optional): If True, the layout optimization objective\n            is to maximize annual value production using the value array in the\n            FLORIS model's WindData object. If False, the optimization\n            objective is to maximize AEP. Defaults to False.\n    \"\"\"\n    def __init__(\n        self,\n        fmodel,\n        boundaries,\n        min_dist=None,\n        solver=None,\n        optOptions=None,\n        timeLimit=None,\n        storeHistory='hist.hist',\n        hotStart=None,\n        enable_geometric_yaw=False,\n        use_value=False,\n    ):\n        if list_depth(boundaries) > 1 and hasattr(boundaries[0][0], \"__len__\"):\n            raise NotImplementedError(\n                \"LayoutOptimizationPyOptSparse is not configured for multiple regions.\"\n            )\n\n        super().__init__(\n            fmodel,\n            boundaries,\n            min_dist=min_dist,\n            enable_geometric_yaw=enable_geometric_yaw,\n            use_value=use_value\n        )\n\n        self.x0 = self._norm(self.fmodel.layout_x, self.xmin, self.xmax)\n        self.y0 = self._norm(self.fmodel.layout_y, self.ymin, self.ymax)\n\n        self.storeHistory = storeHistory\n        self.timeLimit = timeLimit\n        self.hotStart = hotStart\n        self.enable_geometric_yaw = enable_geometric_yaw\n\n        try:\n            import pyoptsparse\n        except ImportError:\n            err_msg = (\n                \"It appears you do not have pyOptSparse installed. \"\n                + \"Please refer to https://pyoptsparse.readthedocs.io/ for \"\n                + \"guidance on how to properly install the module.\"\n            )\n            self.logger.error(err_msg, stack_info=True)\n            raise ImportError(err_msg)\n\n        # Instantiate pyOptSparse optimization object with name and objective function\n        self.optProb = pyoptsparse.Optimization('layout', self._obj_func)\n\n        self.optProb = self.add_var_group(self.optProb)\n        self.optProb = self.add_con_group(self.optProb)\n        self.optProb.addObj(\"obj\")\n\n        if solver is not None:\n            self.solver = solver\n            print(\"Setting up optimization with user's choice of solver: \", self.solver)\n        else:\n            self.solver = \"SLSQP\"\n            print(\"Setting up optimization with default solver: SLSQP.\")\n        if optOptions is not None:\n            self.optOptions = optOptions\n        else:\n            if self.solver == \"SNOPT\":\n                self.optOptions = {\"Major optimality tolerance\": 1e-7}\n            else:\n                self.optOptions = {}\n\n        exec(\"self.opt = pyoptsparse.\" + self.solver + \"(options=self.optOptions)\")\n\n    def _optimize(self):\n        if hasattr(self, \"_sens\"):\n            self.sol = self.opt(self.optProb, sens=self._sens)\n        else:\n            if self.timeLimit is not None:\n                self.sol = self.opt(\n                    self.optProb,\n                    sens=\"CDR\",\n                    storeHistory=self.storeHistory,\n                    timeLimit=self.timeLimit,\n                    hotStart=self.hotStart\n                )\n            else:\n                self.sol = self.opt(\n                    self.optProb,\n                    sens=\"CDR\",\n                    storeHistory=self.storeHistory,\n                    hotStart=self.hotStart\n                )\n        return self.sol\n\n    def _obj_func(self, varDict):\n        # Parse the variable dictionary\n        self.parse_opt_vars(varDict)\n\n        # Compute turbine yaw angles using PJ's geometric code (if enabled)\n        yaw_angles = self._get_geoyaw_angles()\n        # Update turbine map with turbine locations and yaw angles\n        self.fmodel.set(layout_x=self.x, layout_y=self.y, yaw_angles=yaw_angles)\n        self.fmodel.run()\n\n        # Compute the objective function\n        funcs = {}\n        if self.use_value:\n            funcs[\"obj\"] = -1 * self.fmodel.get_farm_AVP() / self.initial_AEP_or_AVP\n        else:\n            funcs[\"obj\"] = -1 * self.fmodel.get_farm_AEP() / self.initial_AEP_or_AVP\n\n        # Compute constraints, if any are defined for the optimization\n        funcs = self.compute_cons(funcs, self.x, self.y)\n\n        fail = False\n        return funcs, fail\n\n    # Optionally, the user can supply the optimization with gradients\n    # def _sens(self, varDict, funcs):\n    #     funcsSens = {}\n    #     fail = False\n    #     return funcsSens, fail\n\n    def parse_opt_vars(self, varDict):\n        self.x = self._unnorm(varDict[\"x\"], self.xmin, self.xmax)\n        self.y = self._unnorm(varDict[\"y\"], self.ymin, self.ymax)\n\n    def parse_sol_vars(self, sol):\n        self.x = list(self._unnorm(sol.getDVs()[\"x\"], self.xmin, self.xmax))[0]\n        self.y = list(self._unnorm(sol.getDVs()[\"y\"], self.ymin, self.ymax))[1]\n\n    def add_var_group(self, optProb):\n        optProb.addVarGroup(\n            \"x\", self.nturbs, varType=\"c\", lower=0.0, upper=1.0, value=self.x0\n        )\n        optProb.addVarGroup(\n            \"y\", self.nturbs, varType=\"c\", lower=0.0, upper=1.0, value=self.y0\n        )\n\n        return optProb\n\n    def add_con_group(self, optProb):\n        optProb.addConGroup(\"boundary_con\", self.nturbs, upper=0.0)\n        optProb.addConGroup(\"spacing_con\", 1, upper=0.0)\n\n        return optProb\n\n    def compute_cons(self, funcs, x, y):\n        funcs[\"boundary_con\"] = self.distance_from_boundaries(x, y)\n        funcs[\"spacing_con\"] = self.space_constraint(x, y)\n\n        return funcs\n\n    def space_constraint(self, x, y, rho=500):\n        # Calculate distances between turbines\n        locs = np.vstack((x, y)).T\n        distances = cdist(locs, locs)\n        arange = np.arange(distances.shape[0])\n        distances[arange, arange] = 1e10\n        dist = np.min(distances, axis=0)\n\n        g = 1 - np.array(dist) / self.min_dist\n\n        # Following code copied from OpenMDAO KSComp().\n        # Constraint is satisfied when KS_constraint <= 0\n        g_max = np.max(np.atleast_2d(g), axis=-1)[:, np.newaxis]\n        g_diff = g - g_max\n        exponents = np.exp(rho * g_diff)\n        summation = np.sum(exponents, axis=-1)[:, np.newaxis]\n        KS_constraint = g_max + 1.0 / rho * np.log(summation)\n\n        return KS_constraint[0][0]\n\n    def distance_from_boundaries(self, x, y):\n        boundary_con = np.zeros(self.nturbs)\n        for i in range(self.nturbs):\n            loc = Point(x[i], y[i])\n            boundary_con[i] = loc.distance(self._boundary_line)\n            if self._boundary_polygon.contains(loc) is True:\n                boundary_con[i] *= -1.0\n\n        return boundary_con\n\n    def _get_initial_and_final_locs(self):\n        x_initial = self._unnorm(self.x0, self.xmin, self.xmax)\n        y_initial = self._unnorm(self.y0, self.ymin, self.ymax)\n        x_opt, y_opt = self.get_optimized_locs()\n        return x_initial, y_initial, x_opt, y_opt\n\n    def get_optimized_locs(self):\n        x_opt = self._unnorm(self.sol.getDVs()[\"x\"], self.xmin, self.xmax)\n        y_opt = self._unnorm(self.sol.getDVs()[\"y\"], self.ymin, self.ymax)\n        return x_opt, y_opt\n"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_pyoptsparse_spread.py",
    "content": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.spatial.distance import cdist\nfrom shapely.geometry import Point\n\nfrom .layout_optimization_base import LayoutOptimization\n\n\nclass LayoutOptimizationPyOptSparse(LayoutOptimization):\n    def __init__(\n        self,\n        fmodel,\n        boundaries,\n        min_dist=None,\n        solver=None,\n        optOptions=None,\n        timeLimit=None,\n        storeHistory='hist.hist',\n        hotStart=None\n    ):\n        super().__init__(fmodel, boundaries, min_dist=min_dist)\n        self._reinitialize(solver=solver, optOptions=optOptions)\n\n        self.storeHistory = storeHistory\n        self.timeLimit = timeLimit\n        self.hotStart = hotStart\n\n    def _reinitialize(self, solver=None, optOptions=None):\n        try:\n            import pyoptsparse\n        except ImportError:\n            err_msg = (\n                \"It appears you do not have pyOptSparse installed. \"\n                + \"Please refer to https://pyoptsparse.readthedocs.io/ for \"\n                + \"guidance on how to properly install the module.\"\n            )\n            self.logger.error(err_msg, stack_info=True)\n            raise ImportError(err_msg)\n\n        # Insantiate ptOptSparse optimization object with name and objective function\n        self.optProb = pyoptsparse.Optimization('layout', self._obj_func)\n\n        self.optProb = self.add_var_group(self.optProb)\n        self.optProb = self.add_con_group(self.optProb)\n        self.optProb.addObj(\"obj\")\n\n        if solver is not None:\n            self.solver = solver\n            print(\"Setting up optimization with user's choice of solver: \", self.solver)\n        else:\n            self.solver = \"SLSQP\"\n            print(\"Setting up optimization with default solver: SLSQP.\")\n        if optOptions is not None:\n            self.optOptions = optOptions\n        else:\n            if self.solver == \"SNOPT\":\n                self.optOptions = {\"Major optimality tolerance\": 1e-7}\n            else:\n                self.optOptions = {}\n\n        exec(\"self.opt = pyoptsparse.\" + self.solver + \"(options=self.optOptions)\")\n\n    def _optimize(self):\n        if hasattr(self, \"_sens\"):\n            self.sol = self.opt(self.optProb, sens=self._sens)\n        else:\n            if self.timeLimit is not None:\n                self.sol = self.opt(\n                    self.optProb,\n                    sens=\"CDR\",\n                    storeHistory=self.storeHistory,\n                    timeLimit=self.timeLimit,\n                    hotStart=self.hotStart\n                )\n            else:\n                self.sol = self.opt(\n                    self.optProb,\n                    sens=\"CDR\",\n                    storeHistory=self.storeHistory,\n                    hotStart=self.hotStart\n                )\n        return self.sol\n\n    def _obj_func(self, varDict):\n        # Parse the variable dictionary\n        self.parse_opt_vars(varDict)\n\n        # Update turbine map with turbince locations\n        # self.fmodel.reinitialize(layout=[self.x, self.y])\n        # self.fmodel.calculate_wake()\n\n        # Compute the objective function\n        funcs = {}\n        funcs[\"obj\"] = (\n            -1 * self.mean_distance(self.x, self.y)\n        )\n\n        # Compute constraints, if any are defined for the optimization\n        funcs = self.compute_cons(funcs, self.x, self.y)\n\n        fail = False\n        return funcs, fail\n\n    # Optionally, the user can supply the optimization with gradients\n    # def _sens(self, varDict, funcs):\n    #     funcsSens = {}\n    #     fail = False\n    #     return funcsSens, fail\n\n    def parse_opt_vars(self, varDict):\n        self.x = self._unnorm(varDict[\"x\"], self.xmin, self.xmax)\n        self.y = self._unnorm(varDict[\"y\"], self.ymin, self.ymax)\n\n    def parse_sol_vars(self, sol):\n        self.x = list(self._unnorm(sol.getDVs()[\"x\"], self.xmin, self.xmax))[0]\n        self.y = list(self._unnorm(sol.getDVs()[\"y\"], self.ymin, self.ymax))[1]\n\n    def add_var_group(self, optProb):\n        optProb.addVarGroup(\n            \"x\", self.nturbs, type=\"c\", lower=0.0, upper=1.0, value=self.x0\n        )\n        optProb.addVarGroup(\n            \"y\", self.nturbs, type=\"c\", lower=0.0, upper=1.0, value=self.y0\n        )\n\n        return optProb\n\n    def add_con_group(self, optProb):\n        optProb.addConGroup(\"boundary_con\", self.nturbs, upper=0.0)\n        optProb.addConGroup(\"spacing_con\", 1, upper=0.0)\n\n        return optProb\n\n    def compute_cons(self, funcs, x, y):\n        funcs[\"boundary_con\"] = self.distance_from_boundaries(x, y)\n        funcs[\"spacing_con\"] = self.space_constraint(x, y)\n\n        return funcs\n\n    def mean_distance(self, x, y):\n\n        locs = np.vstack((x, y)).T\n        distances = cdist(locs, locs)\n        return np.mean(distances)\n\n\n    def space_constraint(self, x, y, rho=500):\n        # Calculate distances between turbines\n        locs = np.vstack((x, y)).T\n        distances = cdist(locs, locs)\n        arange = np.arange(distances.shape[0])\n        distances[arange, arange] = 1e10\n        dist = np.min(distances, axis=0)\n\n        g = 1 - np.array(dist) / self.min_dist\n\n        # Following code copied from OpenMDAO KSComp().\n        # Constraint is satisfied when KS_constraint <= 0\n        g_max = np.max(np.atleast_2d(g), axis=-1)[:, np.newaxis]\n        g_diff = g - g_max\n        exponents = np.exp(rho * g_diff)\n        summation = np.sum(exponents, axis=-1)[:, np.newaxis]\n        KS_constraint = g_max + 1.0 / rho * np.log(summation)\n\n        return KS_constraint[0][0]\n\n    def distance_from_boundaries(self, x, y):\n        boundary_con = np.zeros(self.nturbs)\n        for i in range(self.nturbs):\n            loc = Point(x[i], y[i])\n            boundary_con[i] = loc.distance(self.boundary_line)\n            if self.boundary_polygon.contains(loc) is True:\n                boundary_con[i] *= -1.0\n\n        return boundary_con\n\n    def plot_layout_opt_results(self):\n        \"\"\"\n        Method to plot the old and new locations of the layout opitimization.\n        \"\"\"\n        locsx = self._unnorm(self.sol.getDVs()[\"x\"], self.xmin, self.xmax)\n        locsy = self._unnorm(self.sol.getDVs()[\"y\"], self.ymin, self.ymax)\n        x0 = self._unnorm(self.x0, self.xmin, self.xmax)\n        y0 = self._unnorm(self.y0, self.ymin, self.ymax)\n\n        plt.figure(figsize=(9, 6))\n        fontsize = 16\n        plt.plot(x0, y0, \"ob\")\n        plt.plot(locsx, locsy, \"or\")\n        # plt.title('Layout Optimization Results', fontsize=fontsize)\n        plt.xlabel(\"x (m)\", fontsize=fontsize)\n        plt.ylabel(\"y (m)\", fontsize=fontsize)\n        plt.axis(\"equal\")\n        plt.grid()\n        plt.tick_params(which=\"both\", labelsize=fontsize)\n        plt.legend(\n            [\"Old locations\", \"New locations\"],\n            loc=\"lower center\",\n            bbox_to_anchor=(0.5, 1.01),\n            ncol=2,\n            fontsize=fontsize,\n        )\n\n        verts = self.boundaries\n        for i in range(len(verts)):\n            if i == len(verts) - 1:\n                plt.plot([verts[i][0], verts[0][0]], [verts[i][1], verts[0][1]], \"b\")\n            else:\n                plt.plot(\n                    [verts[i][0], verts[i + 1][0]], [verts[i][1], verts[i + 1][1]], \"b\"\n                )\n"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_random_search.py",
    "content": "from multiprocessing import Pool\nfrom time import perf_counter as timerpc\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.spatial.distance import cdist, pdist\nfrom shapely.geometry import Point, Polygon\n\nfrom floris import FlorisModel\nfrom floris.optimization.yaw_optimization.yaw_optimizer_geometric import (\n    YawOptimizationGeometric,\n)\n\nfrom .layout_optimization_base import LayoutOptimization\n\n\ndef _load_local_floris_object(\n    fmodel_dict,\n    wind_data=None,\n):\n    # Load local FLORIS object\n    fmodel = FlorisModel(fmodel_dict)\n    fmodel.set(wind_data=wind_data)\n    return fmodel\n\ndef test_min_dist(layout_x, layout_y, min_dist):\n    coords = np.array([layout_x,layout_y]).T\n    dist = pdist(coords)\n    return dist.min() >= min_dist\n\ndef test_point_in_bounds(test_x, test_y, poly_outer):\n    return poly_outer.contains(Point(test_x, test_y))\n\n# Return in MW\ndef _get_objective(\n        layout_x,\n        layout_y,\n        fmodel,\n        yaw_angles=None,\n        use_value=False\n):\n    fmodel.set(\n        layout_x=layout_x,\n        layout_y=layout_y,\n        yaw_angles=yaw_angles\n    )\n    fmodel.run()\n\n    return fmodel.get_farm_AVP() if use_value else fmodel.get_farm_AEP()\n\ndef _gen_dist_based_init(\n    N, # Number of turbins to place\n    step_size, #m, courseness of search grid\n    poly_outer, # Polygon of outer boundary\n    min_x,\n    max_x,\n    min_y,\n    max_y,\n    s\n):\n    \"\"\"\n    Generates an initial layout by randomly placing\n    the first turbine than placing the remaining turbines\n    as far as possible from the existing turbines.\n    \"\"\"\n\n    # Set random seed\n    np.random.seed(s)\n\n    # Choose the initial point randomly\n    init_x = float(np.random.randint(int(min_x),int(max_x)))\n    init_y = float(np.random.randint(int(min_y),int(max_y)))\n    while not (poly_outer.contains(Point([init_x,init_y]))):\n        init_x = float(np.random.randint(int(min_x),int(max_x)))\n        init_y = float(np.random.randint(int(min_y),int(max_y)))\n\n    # Intialize the layout arrays\n    layout_x = np.array([init_x])\n    layout_y = np.array([init_y])\n    layout = np.array([layout_x, layout_y]).T\n\n    # Now add the remaining points\n    for i in range(1,N):\n\n        print(\"Placing turbine {0} of {1}.\".format(i, N))\n        # Add a new turbine being as far as possible from current\n        max_dist = 0.\n        for x in np.arange(min_x, max_x,step_size):\n            for y in np.arange(min_y, max_y,step_size):\n                if poly_outer.contains(Point([x,y])):\n                    test_dist = cdist([[x,y]],layout)\n                    min_dist = np.min(test_dist)\n                    if min_dist > max_dist:\n                        max_dist = min_dist\n                        save_x = x\n                        save_y = y\n\n        # Add point to the layout\n        layout_x = np.append(layout_x,[save_x])\n        layout_y = np.append(layout_y,[save_y])\n        layout = np.array([layout_x, layout_y]).T\n\n    # Return the layout\n    return layout_x, layout_y\n\nclass LayoutOptimizationRandomSearch(LayoutOptimization):\n    def __init__(\n        self,\n        fmodel,\n        boundaries,\n        min_dist=None,\n        min_dist_D=None,\n        distance_pmf=None,\n        n_individuals=4,\n        seconds_per_iteration=60.,\n        total_optimization_seconds=600.,\n        interface=\"multiprocessing\",  # Options are 'multiprocessing', 'mpi4py', None\n        max_workers=None,\n        grid_step_size=100.,\n        relegation_number=1,\n        enable_geometric_yaw=False,\n        use_dist_based_init=True,\n        random_seed=None,\n        use_value=False,\n    ):\n        \"\"\"\n        Optimize layout using genetic random search algorithm. Details of the algorithm can be found\n        in Sinner and Fleming, 2024: https://dx.doi.org/10.1088/1742-6596/2767/3/032036\n\n        Args:\n            fmodel (_type_): _description_\n            boundaries (iterable(float, float)): Pairs of x- and y-coordinates\n                that represent the boundary's vertices (m).\n            min_dist (float, optional): The minimum distance to be maintained\n                between turbines during the optimization (m). If not specified,\n                initializes to 2 rotor diameters. Defaults to None.\n            min_dist_D (float, optional): The minimum distance to be maintained\n                between turbines during the optimization, specified as a multiple\n                of the rotor diameter.\n            distance_pmf (dict, optional): Probability mass function describing the\n                length of steps in the random search. Specified as a dictionary with\n                keys \"d\" (array of step distances, specified in meters) and \"p\"\n                (array of probability of occurrence, should sum to 1). Defaults to\n                uniform probability between 0.5D and 2D, with some extra mass\n                to encourage large changes.\n            n_individuals (int, optional): The number of individuals to use in the\n                optimization. Defaults to 4.\n            seconds_per_iteration (float, optional): The number of seconds to\n                run each step of the optimization for. Defaults to 60.\n            total_optimization_seconds (float, optional): The total number of\n                seconds to run the optimization for. Defaults to 600.\n            interface (str): Parallel computing interface to leverage. Recommended is 'concurrent'\n                or 'multiprocessing' for local (single-system) use, and 'mpi4py' for high\n                performance computing on multiple nodes. Defaults to 'multiprocessing'.\n            max_workers (int): Number of parallel workers, typically equal to the number of cores\n                you have on your system or HPC.  Defaults to None, which will use all\n                available cores.\n            grid_step_size (float): The coarseness of the grid used to generate the initial layout.\n                Defaults to 100.\n            relegation_number (int): The number of the lowest performing individuals to be replaced\n                with new individuals generated from the best performing individual.  Must\n                be less than n_individuals / 2.  Defaults to 1.\n            enable_geometric_yaw (bool): Use geometric yaw code to determine approximate wake\n                steering yaw angles during layout optimization routine. Defaults to False.\n            use_dist_based_init (bool): Generate initial layouts automatically by placing turbines\n                as far apart as possible.\n            random_seed (int or None): Random seed for reproducibility. Defaults to None.\n            use_value (bool, optional): If True, the layout optimization objective\n                is to maximize annual value production using the value array in the\n                FLORIS model's WindData object. If False, the optimization\n                objective is to maximize AEP. Defaults to False.\n        \"\"\"\n        # The parallel computing interface to use\n        if interface == \"mpi4py\":\n            import mpi4py.futures as mp\n            self._PoolExecutor = mp.MPIPoolExecutor\n        elif interface == \"multiprocessing\":\n            import multiprocessing as mp\n            self._PoolExecutor = mp.Pool\n            if max_workers is None:\n                max_workers = mp.cpu_count()\n        elif interface is None:\n            if n_individuals > 1 or (max_workers is not None and max_workers > 1):\n                print(\n                    \"Parallelization not possible with interface=None. \"\n                    +\"Reducing n_individuals to 1 and ignoring max_workers.\"\n                )\n                self._PoolExecutor = None\n                max_workers = None\n                n_individuals = 1\n\n        # elif interface == \"concurrent\":\n        #     from concurrent.futures import ProcessPoolExecutor\n        #     self._PoolExecutor = ProcessPoolExecutor\n        else:\n            raise ValueError(\n                f\"Interface '{interface}' not recognized. \"\n                \"Please use ' 'multiprocessing' or 'mpi4py'.\"\n            )\n\n        # Store the max_workers\n        self.max_workers = max_workers\n\n        # Store the interface\n        self.interface = interface\n\n        # Set and store the random seed\n        self.random_seed = random_seed\n\n        # Confirm the relegation_number is valid\n        if relegation_number > n_individuals / 2:\n            raise ValueError(\"relegation_number must be less than n_individuals / 2.\")\n        self.relegation_number = relegation_number\n\n        # Store the rotor diameter and number of turbines\n        self.D = fmodel.core.farm.rotor_diameters.max()\n        if not all(fmodel.core.farm.rotor_diameters == self.D):\n            self.logger.warning(\"Using largest rotor diameter for min_dist_D and distance_pmf.\")\n        self.N_turbines = fmodel.n_turbines\n\n        # Make sure not both min_dist and min_dist_D are defined\n        if min_dist is not None and min_dist_D is not None:\n            raise ValueError(\"Only one of min_dist and min_dist_D can be defined.\")\n\n        # If min_dist_D is defined, convert to min_dist\n        if min_dist_D is not None:\n            min_dist = min_dist_D * self.D\n\n        super().__init__(\n            fmodel,\n            boundaries,\n            min_dist=min_dist,\n            enable_geometric_yaw=enable_geometric_yaw,\n            use_value=use_value,\n        )\n        if use_value:\n            self._obj_name = \"value\"\n            self._obj_unit = \"\"\n        else:\n            self._obj_name = \"AEP\"\n            self._obj_unit = \"[GWh]\"\n\n        # Save min_dist_D\n        self.min_dist_D = self.min_dist / self.D\n\n        # Process and save the step distribution\n        self._process_dist_pmf(distance_pmf)\n\n        # Store the Core dictionary\n        self.fmodel_dict = self.fmodel.core.as_dict()\n\n        # Save the grid step size\n        self.grid_step_size = grid_step_size\n\n        # Save number of individuals\n        self.n_individuals = n_individuals\n\n        # Store the initial locations\n        self.x_initial = self.fmodel.layout_x\n        self.y_initial = self.fmodel.layout_y\n\n        # Store the total optimization seconds\n        self.total_optimization_seconds = total_optimization_seconds\n\n        # Store the seconds per iteration\n        self.seconds_per_iteration = seconds_per_iteration\n\n        # Get the initial objective value\n        self.x = self.x_initial # Required by _get_geoyaw_angles\n        self.y = self.y_initial # Required by _get_geoyaw_angles\n        self.objective_initial = _get_objective(\n            self.x_initial,\n            self.y_initial,\n            self.fmodel,\n            self._get_geoyaw_angles(),\n            self.use_value,\n        )\n\n        # Initialize the objective statistics\n        self.objective_mean = self.objective_initial\n        self.objective_median = self.objective_initial\n        self.objective_max = self.objective_initial\n        self.objective_min = self.objective_initial\n\n        # Initialize the numpy arrays which will hold the candidate layouts\n        # these will have dimensions n_individuals x N_turbines\n        self.x_candidate = np.zeros((self.n_individuals, self.N_turbines))\n        self.y_candidate = np.zeros((self.n_individuals, self.N_turbines))\n\n        # Initialize the array which will hold the objective function values for each candidate\n        self.objective_candidate = np.zeros(self.n_individuals)\n\n        # Initialize the iteration step\n        self.iteration_step = -1\n\n        # Initialize the optimization time\n        self.opt_time_start = timerpc()\n        self.opt_time = 0\n\n        # Generate the initial layouts\n        if use_dist_based_init:\n            self._generate_initial_layouts()\n        else:\n            print(f'Using supplied initial layout for {self.n_individuals} individuals.')\n            for i in range(self.n_individuals):\n                self.x_candidate[i, :] = self.x_initial\n                self.y_candidate[i, :] = self.y_initial\n                self.objective_candidate[i] = self.objective_initial\n\n        # Evaluate the initial optimization step\n        self._evaluate_opt_step()\n\n        # Delete stored x and y to avoid confusion\n        del self.x, self.y\n\n        # Set up to run in normal mode\n        self.debug = False\n\n    def describe(self):\n        print(\"Random Layout Optimization\")\n        print(f\"Number of turbines to optimize = {self.N_turbines}\")\n        print(f\"Minimum distance between turbines = {self.min_dist_D} [D], {self.min_dist} [m]\")\n        print(f\"Number of individuals = {self.n_individuals}\")\n        print(f\"Seconds per iteration = {self.seconds_per_iteration}\")\n        print(f\"Initial {self._obj_name} = {self.objective_initial/1e9:.1f} {self._obj_unit}\")\n\n    def _process_dist_pmf(self, dist_pmf):\n        \"\"\"\n        Check validity of pmf and assign default if none provided.\n        \"\"\"\n        if dist_pmf is None:\n            jump_dist = np.min([self.xmax-self.xmin, self.ymax-self.ymin])/2\n            jump_prob = 0.05\n\n            d = np.append(np.linspace(0.0, 2.0*self.D, 99), jump_dist)\n            p = np.append((1-jump_prob)/len(d)*np.ones(len(d)-1), jump_prob)\n            p = p / p.sum()\n            dist_pmf = {\"d\":d, \"p\":p}\n\n        # Check correct keys are provided\n        if not all(k in dist_pmf for k in (\"d\", \"p\")):\n            raise KeyError(\"distance_pmf must contains keys \\\"d\\\" (step distance)\"+\\\n                \" and \\\"p\\\" (probability of occurrence).\")\n\n        # Check entries are in the correct form\n        if not hasattr(dist_pmf[\"d\"], \"__len__\") or not hasattr(dist_pmf[\"d\"], \"__len__\")\\\n            or len(dist_pmf[\"d\"]) != len(dist_pmf[\"p\"]):\n            raise TypeError(\"distance_pmf entries should be numpy arrays or lists\"+\\\n                \" of equal length.\")\n\n        if not np.isclose(dist_pmf[\"p\"].sum(), 1):\n            print(\"Probability mass function does not sum to 1. Normalizing.\")\n            dist_pmf[\"p\"] = np.array(dist_pmf[\"p\"]) / np.array(dist_pmf[\"p\"]).sum()\n\n        self.distance_pmf = dist_pmf\n\n    def _evaluate_opt_step(self):\n\n        # Sort the candidate layouts by objective function value\n        sorted_indices = np.argsort(self.objective_candidate)[::-1] # Decreasing order\n        self.objective_candidate = self.objective_candidate[sorted_indices]\n        self.x_candidate = self.x_candidate[sorted_indices]\n        self.y_candidate = self.y_candidate[sorted_indices]\n\n        # Update the optimization time\n        self.opt_time = timerpc() - self.opt_time_start\n\n        # Update the optimizations step\n        self.iteration_step += 1\n\n        # Update the objective statistics\n        self.objective_mean = np.mean(self.objective_candidate)\n        self.objective_median = np.median(self.objective_candidate)\n        self.objective_max = np.max(self.objective_candidate)\n        self.objective_min = np.min(self.objective_candidate)\n\n        # Report the results\n        increase_mean = (\n            100 * (self.objective_mean - self.objective_initial) / self.objective_initial\n        )\n        increase_median = (\n            100 * (self.objective_median - self.objective_initial) / self.objective_initial\n        )\n        increase_max = 100 * (self.objective_max - self.objective_initial) / self.objective_initial\n        increase_min = 100 * (self.objective_min - self.objective_initial) / self.objective_initial\n        print(\"=======================================\")\n        print(f\"Optimization step {self.iteration_step:+.1f}\")\n        print(f\"Optimization time = {self.opt_time:+.1f} [s]\")\n        print(\n            f\"Mean {self._obj_name} = {self.objective_mean/1e9:.1f}\"\n            f\" {self._obj_unit} ({increase_mean:+.2f}%)\"\n        )\n        print(\n            f\"Median {self._obj_name} = {self.objective_median/1e9:.1f}\"\n            f\" {self._obj_unit} ({increase_median:+.2f}%)\"\n        )\n        print(\n            f\"Max {self._obj_name} = {self.objective_max/1e9:.1f}\"\n            f\" {self._obj_unit} ({increase_max:+.2f}%)\"\n        )\n        print(\n            f\"Min {self._obj_name} = {self.objective_min/1e9:.1f}\"\n            f\" {self._obj_unit} ({increase_min:+.2f}%)\"\n        )\n        print(\"=======================================\")\n\n        # Replace the relegation_number worst performing layouts with relegation_number\n        # best layouts\n        if self.relegation_number > 0:\n            self.objective_candidate[-self.relegation_number:] = (\n                self.objective_candidate[:self.relegation_number]\n            )\n            self.x_candidate[-self.relegation_number:] = self.x_candidate[:self.relegation_number]\n            self.y_candidate[-self.relegation_number:] = self.y_candidate[:self.relegation_number]\n\n\n    # Private methods\n    def _generate_initial_layouts(self):\n        \"\"\"\n        This method generates n_individuals initial layout of turbines. It does\n        this by calling the _generate_random_layout method within a multiprocessing\n        pool.\n        \"\"\"\n\n        # Set random seed for initial layout\n        if self.random_seed is None:\n            multi_random_seeds = [None]*self.n_individuals\n        else:\n            multi_random_seeds = [23 + i for i in range(self.n_individuals)]\n            # 23 is just an arbitrary choice to ensure different random seeds\n            # to the evaluation code\n\n        print(f'Generating {self.n_individuals} initial layouts...')\n        t1 = timerpc()\n        # Generate the multiargs for parallel execution\n        multiargs = [\n            (self.N_turbines,\n            self.grid_step_size,\n            self._boundary_polygon,\n            self.xmin,\n            self.xmax,\n            self.ymin,\n            self.ymax,\n            multi_random_seeds[i])\n            for i in range(self.n_individuals)\n        ]\n\n        if self._PoolExecutor: # Parallelized\n            with self._PoolExecutor(self.max_workers) as p:\n                # This code is not currently necessary, but leaving in case implement\n                # concurrent later, based on parallel_computing_interface.py\n                if (self.interface == \"mpi4py\") or (self.interface == \"multiprocessing\"):\n                        out = p.starmap(_gen_dist_based_init, multiargs)\n        else: # Parallelization not activated\n            out = [_gen_dist_based_init(*multiargs[0])]\n\n        # Unpack out into the candidate layouts\n        for i in range(self.n_individuals):\n            self.x_candidate[i, :] = out[i][0]\n            self.y_candidate[i, :] = out[i][1]\n\n        # Get the objective function values for each candidate layout\n        for i in range(self.n_individuals):\n            self.objective_candidate[i] = _get_objective(\n                self.x_candidate[i, :],\n                self.y_candidate[i, :],\n                self.fmodel,\n                self._get_geoyaw_angles(),\n                self.use_value,\n            )\n\n        t2 = timerpc()\n        print(f\"  Time to generate initial layouts: {t2-t1:.3f} s\")\n\n    def _get_initial_and_final_locs(self):\n        x_initial = self.x_initial\n        y_initial = self.y_initial\n        x_opt = self.x_opt\n        y_opt = self.y_opt\n        return x_initial, y_initial, x_opt, y_opt\n\n    def _initialize_optimization(self):\n        \"\"\"\n        Set up logs etc\n        \"\"\"\n        print(f'Optimizing using {self.n_individuals} individuals.')\n        self._opt_start_time = timerpc()\n        self._opt_stop_time = self._opt_start_time + self.total_optimization_seconds\n\n        self.objective_candidate_log = [self.objective_candidate.copy()]\n        self.num_objective_calls_log = []\n        self._num_objective_calls = [0]*self.n_individuals\n\n    def _run_optimization_generation(self):\n        \"\"\"\n        Run a generation of the outer genetic algorithm\n        \"\"\"\n        # Set random seed for the main loop\n        if self.random_seed is None:\n            multi_random_seeds = [None]*self.n_individuals\n        else:\n            multi_random_seeds = [55 + self.iteration_step + i\n                for i in range(self.n_individuals)]\n        # 55 is just an arbitrary choice to ensure different random seeds\n        # to the initialization code\n\n        # Update the optimization time\n        sim_time = timerpc() - self._opt_start_time\n        print(f'Optimization time: {sim_time:.1f} s / {self.total_optimization_seconds:.1f} s')\n\n\n        # Generate the multiargs for parallel execution of single individual optimization\n        multiargs = [\n            (self.seconds_per_iteration,\n                self.objective_candidate[i],\n                self.x_candidate[i, :],\n                self.y_candidate[i, :],\n                self.fmodel_dict,\n                self.fmodel.wind_data,\n                self.min_dist,\n                self._boundary_polygon,\n                self.distance_pmf,\n                self.enable_geometric_yaw,\n                multi_random_seeds[i],\n                self.use_value,\n                self.debug\n            )\n                for i in range(self.n_individuals)\n        ]\n\n        # Run the single individual optimization in parallel\n        if self._PoolExecutor: # Parallelized\n            with self._PoolExecutor(self.max_workers) as p:\n                out = p.starmap(_single_individual_opt, multiargs)\n        else: # Parallelization not activated\n            out = [_single_individual_opt(*multiargs[0])]\n\n        # Unpack the results\n        for i in range(self.n_individuals):\n            self.objective_candidate[i] = out[i][0]\n            self.x_candidate[i, :] = out[i][1]\n            self.y_candidate[i, :] = out[i][2]\n            self._num_objective_calls[i] = out[i][3]\n        self.objective_candidate_log.append(self.objective_candidate)\n        self.num_objective_calls_log.append(self._num_objective_calls)\n\n        # Evaluate the individuals for this step\n        self._evaluate_opt_step()\n\n    def _finalize_optimization(self):\n        \"\"\"\n        Package and print final results.\n        \"\"\"\n\n        # Finalize the result\n        self.objective_final = self.objective_candidate[0]\n        self.x_opt = self.x_candidate[0, :]\n        self.y_opt = self.y_candidate[0, :]\n\n        # Print the final result\n        increase = 100 * (self.objective_final - self.objective_initial) / self.objective_initial\n        print(\n            f\"Final {self._obj_name} = {self.objective_final/1e9:.1f}\"\n            f\" {self._obj_unit} ({increase:+.2f}%)\"\n        )\n\n    def _test_optimize(self):\n        \"\"\"\n        Perform a fixed number of iterations with a single worker for\n        debugging and testing purposes.\n        \"\"\"\n        # Set up a minimal problem to run on a single worker\n        print(\"Running test optimization on a single worker.\")\n        self._PoolExecutor = None\n        self.max_workers = None\n        self.n_individuals = 1\n        self.debug = True\n\n        self._initialize_optimization()\n\n        # Run 2 generations\n        for _ in range(2):\n            self._run_optimization_generation()\n\n        self._finalize_optimization()\n\n        return self.objective_final, self.x_opt, self.y_opt\n\n    # Public methods\n    def optimize(self):\n        \"\"\"\n        Perform the optimization\n        \"\"\"\n        self._initialize_optimization()\n\n        # Run generations until the overall stop time\n        while timerpc() < self._opt_stop_time:\n            self._run_optimization_generation()\n\n        self._finalize_optimization()\n\n        return self.objective_final, self.x_opt, self.y_opt\n\n    # Helpful visualizations\n    def plot_distance_pmf(self, ax=None):\n        \"\"\"\n        Tool to check the used distance pmf.\n        \"\"\"\n\n        if ax is None:\n            _, ax = plt.subplots(1,1)\n\n        ax.stem(self.distance_pmf[\"d\"], self.distance_pmf[\"p\"], linefmt=\"k-\")\n        ax.grid(True)\n        ax.set_xlabel(\"Step distance [m]\")\n        ax.set_ylabel(\"Probability\")\n\n        return ax\n\n\n\ndef _single_individual_opt(\n    seconds_per_iteration,\n    initial_objective,\n    layout_x,\n    layout_y,\n    fmodel_dict,\n    wind_data,\n    min_dist,\n    poly_outer,\n    dist_pmf,\n    enable_geometric_yaw,\n    s,\n    use_value,\n    debug\n):\n    # Set random seed\n    np.random.seed(s)\n\n    # Initialize the optimization time\n    single_opt_start_time = timerpc()\n    stop_time = single_opt_start_time + seconds_per_iteration\n\n    num_objective_calls = 0\n\n    # Get the fmodel\n    fmodel_ = _load_local_floris_object(fmodel_dict, wind_data)\n\n    # Initialize local variables\n    num_turbines = len(layout_x)\n    get_new_point = True # Will always be true, due to hardcoded use_momentum\n    current_objective = initial_objective\n\n    # Establish geometric yaw optimizer, if desired\n    if enable_geometric_yaw:\n        yaw_opt = YawOptimizationGeometric(\n            fmodel_,\n            minimum_yaw_angle=-30.0,\n            maximum_yaw_angle=30.0,\n        )\n    else: # yaw_angles will always be none\n        yaw_angles = None\n\n    # We have a beta feature to maintain momentum, i.e., if a move improves\n    # the objective, we try to keep moving in that direction. This is currently\n    # disabled.\n    use_momentum = False\n\n    # Special handling for debug mode\n    if debug:\n        debug_iterations = 100\n        stop_time = np.inf\n        dd = 0\n\n    # Loop as long as we've not hit the stop time\n    while timerpc() < stop_time:\n\n        if debug and dd >= debug_iterations:\n            break\n        elif debug:\n            dd += 1\n\n        if not use_momentum:\n            get_new_point = True\n\n        if get_new_point: #If the last test wasn't successful\n\n            # Randomly select a turbine to nudge\n            tr = np.random.randint(0,num_turbines)\n\n            # Randomly select a direction to nudge in (uniform direction)\n            rand_dir = np.random.uniform(low=0.0, high=2*np.pi)\n\n            # Randomly select a distance to travel according to pmf\n            rand_dist = np.random.choice(dist_pmf[\"d\"], p=dist_pmf[\"p\"])\n\n        # Get a new test point\n        test_x = layout_x[tr] + np.cos(rand_dir) * rand_dist\n        test_y = layout_y[tr] + np.sin(rand_dir) * rand_dist\n\n        # In bounds?\n        if not test_point_in_bounds(test_x, test_y, poly_outer):\n            get_new_point = True\n            continue\n\n        # Make a new layout\n        original_x = layout_x[tr]\n        original_y = layout_y[tr]\n        layout_x[tr] = test_x\n        layout_y[tr] = test_y\n\n        # Acceptable distances?\n        if not test_min_dist(layout_x, layout_y,min_dist):\n            # Revert and continue\n            layout_x[tr] = original_x\n            layout_y[tr] = original_y\n            get_new_point = True\n            continue\n\n        # Does it improve the objective?\n        if enable_geometric_yaw: # Select appropriate yaw angles\n            yaw_opt.fmodel_subset.set(layout_x=layout_x, layout_y=layout_y)\n            df_opt = yaw_opt.optimize()\n            yaw_angles = np.vstack(df_opt['yaw_angles_opt'])\n\n        num_objective_calls += 1\n        test_objective = _get_objective(layout_x, layout_y, fmodel_, yaw_angles, use_value)\n\n        if test_objective > current_objective:\n            # Accept the change\n            current_objective = test_objective\n\n            # If not a random point this cycle and it did improve things\n            # try not getting a new point\n            # Feature is currently disabled by use_momentum flag\n            get_new_point = False\n\n        else:\n            # Revert the change\n            layout_x[tr] = original_x\n            layout_y[tr] = original_y\n            get_new_point = True\n\n    # Return the best result from this individual\n    return current_objective, layout_x, layout_y, num_objective_calls\n"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_scipy.py",
    "content": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.optimize import minimize\nfrom scipy.spatial.distance import cdist\nfrom shapely.geometry import Point\n\nfrom .layout_optimization_base import LayoutOptimization, list_depth\n\n\nclass LayoutOptimizationScipy(LayoutOptimization):\n    \"\"\"\n    This class provides an interface for optimizing the layout of wind turbines\n    using the Scipy optimization library.  The optimization objective is to\n    maximize annual energy production (AEP) or annual value production (AVP).\n    \"\"\"\n    def __init__(\n        self,\n        fmodel,\n        boundaries,\n        bnds=None,\n        min_dist=None,\n        solver='SLSQP',\n        optOptions=None,\n        enable_geometric_yaw=False,\n        use_value=False,\n    ):\n        \"\"\"\n        Args:\n            fmodel (FlorisModel): A FlorisModel object.\n            boundaries (iterable(float, float)): Pairs of x- and y-coordinates\n                that represent the boundary's vertices (m).\n            bnds (iterable, optional): Bounds for the optimization\n                variables (pairs of min/max values for each variable (m)). If\n                none are specified, they are set to 0 and 1. Defaults to None.\n            min_dist (float, optional): The minimum distance to be maintained\n                between turbines during the optimization (m). If not specified,\n                initializes to 2 rotor diameters. Defaults to None.\n            solver (str, optional): Sets the solver used by Scipy. Defaults to 'SLSQP'.\n            optOptions (dict, optional): Dictionary for setting the\n                optimization options. Defaults to None.\n            enable_geometric_yaw (bool, optional): If True, enables geometric yaw\n                optimization. Defaults to False.\n            use_value (bool, optional): If True, the layout optimization objective\n                is to maximize annual value production using the value array in the\n                FLORIS model's WindData object. If False, the optimization\n                objective is to maximize AEP. Defaults to False.\n        \"\"\"\n        if list_depth(boundaries) > 1 and hasattr(boundaries[0][0], \"__len__\"):\n            raise NotImplementedError(\n                \"LayoutOptimizationScipy is not configured for multiple regions.\"\n            )\n\n        super().__init__(\n            fmodel,\n            boundaries,\n            min_dist=min_dist,\n            enable_geometric_yaw=enable_geometric_yaw,\n            use_value=use_value\n        )\n\n        self.boundaries_norm = [\n            [\n                self._norm(val[0], self.xmin, self.xmax),\n                self._norm(val[1], self.ymin, self.ymax),\n            ]\n            for val in self.boundaries\n        ]\n        self.x0 = [\n            self._norm(x, self.xmin, self.xmax)\n            for x in self.fmodel.layout_x\n        ] + [\n            self._norm(y, self.ymin, self.ymax)\n            for y in self.fmodel.layout_y\n        ]\n        if bnds is not None:\n            self.bnds = bnds\n        else:\n            self._set_opt_bounds()\n        if solver is not None:\n            self.solver = solver\n\n        default_optOptions = {\"maxiter\": 100, \"disp\": True, \"iprint\": 2, \"ftol\": 1e-9, \"eps\":0.01}\n        if optOptions is not None:\n            self.optOptions = {**default_optOptions, **optOptions}\n        else:\n            self.optOptions = default_optOptions\n\n        self._generate_constraints()\n\n\n    # Private methods\n\n    def _optimize(self):\n\n        self._num_aep_calls = 0\n        self._aep_record = []\n\n        self.residual_plant = minimize(\n            self._obj_func,\n            self.x0,\n            method=self.solver,\n            bounds=self.bnds,\n            constraints=self.cons,\n            options=self.optOptions,\n        )\n\n        return self.residual_plant.x\n\n    def _obj_func(self, locs):\n        locs_unnorm = [\n            self._unnorm(valx, self.xmin, self.xmax)\n            for valx in locs[0 : self.nturbs]\n        ] + [\n            self._unnorm(valy, self.ymin, self.ymax)\n            for valy in locs[self.nturbs : 2 * self.nturbs]\n        ]\n        self._change_coordinates(locs_unnorm)\n        # Compute turbine yaw angles using PJ's geometric code (if enabled)\n        yaw_angles = self._get_geoyaw_angles()\n        self.fmodel.set_operation(yaw_angles=yaw_angles)\n        self.fmodel.run()\n        self._num_aep_calls += 1\n\n        if self.use_value:\n            val = -1 * self.fmodel.get_farm_AVP() / self.initial_AEP_or_AVP\n            self._aep_record.append(val)\n            return val\n        else:\n            aep = -1 * self.fmodel.get_farm_AEP() / self.initial_AEP_or_AVP\n            self._aep_record.append(aep)\n            return aep\n\n\n    def _change_coordinates(self, locs):\n        # Parse the layout coordinates\n        layout_x = locs[0 : self.nturbs]\n        layout_y = locs[self.nturbs : 2 * self.nturbs]\n\n        # Store on object for use in geoyaw code\n        self.x = layout_x\n        self.y = layout_y\n\n        # Update the turbine map in floris\n        self.fmodel.set(layout_x=layout_x, layout_y=layout_y)\n\n    def _generate_constraints(self):\n        tmp1 = {\n            \"type\": \"ineq\",\n            \"fun\": lambda x, *args: self._space_constraint(x),\n        }\n        tmp2 = {\n            \"type\": \"ineq\",\n            \"fun\": lambda x: self._distance_from_boundaries(x),\n        }\n\n        self.cons = [tmp1, tmp2]\n\n    def _set_opt_bounds(self):\n        self.bnds = [(0.0, 1.0) for _ in range(2 * self.nturbs)]\n\n    def _space_constraint(self, x_in, rho=500):\n        x = [\n            self._unnorm(valx, self.xmin, self.xmax)\n            for valx in x_in[0 : self.nturbs]\n        ]\n        y =  [\n            self._unnorm(valy, self.ymin, self.ymax)\n            for valy in x_in[self.nturbs : 2 * self.nturbs]\n        ]\n\n        # Calculate distances between turbines\n        locs = np.vstack((x, y)).T\n        distances = cdist(locs, locs)\n        arange = np.arange(distances.shape[0])\n        distances[arange, arange] = 1e10\n        dist = np.min(distances, axis=0)\n\n        g = 1 - np.array(dist) / self.min_dist\n\n        # Following code copied from OpenMDAO KSComp().\n        # Constraint is satisfied when KS_constraint <= 0\n        g_max = np.max(np.atleast_2d(g), axis=-1)[:, np.newaxis]\n        g_diff = g - g_max\n        exponents = np.exp(rho * g_diff)\n        summation = np.sum(exponents, axis=-1)[:, np.newaxis]\n        KS_constraint = g_max + 1.0 / rho * np.log(summation)\n\n        return -1*KS_constraint[0][0]\n\n    def _distance_from_boundaries(self, x_in):\n        x = [\n            self._unnorm(valx, self.xmin, self.xmax)\n            for valx in x_in[0 : self.nturbs]\n        ]\n        y =  [\n            self._unnorm(valy, self.ymin, self.ymax)\n            for valy in x_in[self.nturbs : 2 * self.nturbs]\n        ]\n        boundary_con = np.zeros(self.nturbs)\n        for i in range(self.nturbs):\n            loc = Point(x[i], y[i])\n            boundary_con[i] = loc.distance(self._boundary_line)\n            if self._boundary_polygon.contains(loc) is True:\n                boundary_con[i] *= 1.0\n            else:\n                boundary_con[i] *= -1.0\n\n        return boundary_con\n\n    def _get_initial_and_final_locs(self):\n        x_initial = [\n            self._unnorm(valx, self.xmin, self.xmax)\n            for valx in self.x0[0 : self.nturbs]\n        ]\n        y_initial = [\n            self._unnorm(valy, self.ymin, self.ymax)\n            for valy in self.x0[self.nturbs : 2 * self.nturbs]\n        ]\n        x_opt = [\n            self._unnorm(valx, self.xmin, self.xmax)\n            for valx in self.residual_plant.x[0 : self.nturbs]\n        ]\n        y_opt = [\n            self._unnorm(valy, self.ymin, self.ymax)\n            for valy in self.residual_plant.x[self.nturbs : 2 * self.nturbs]\n        ]\n        return x_initial, y_initial, x_opt, y_opt\n\n\n    # Public methods\n\n    def optimize(self):\n        \"\"\"\n        This method finds the optimized layout of wind turbines for power\n        production given the provided frequencies of occurrence of wind\n        conditions (wind speed, direction).\n\n        Returns:\n            opt_locs (iterable): A list of the optimized locations of each\n            turbine (m).\n        \"\"\"\n        print(\"=====================================================\")\n        print(\"Optimizing turbine layout...\")\n        print(\"Number of parameters to optimize = \", len(self.x0))\n        print(\"=====================================================\")\n\n        opt_locs_norm = self._optimize()\n\n        print(\"Optimization complete.\")\n\n        opt_locs = [\n            [\n                self._unnorm(valx, self.xmin, self.xmax)\n                for valx in opt_locs_norm[0 : self.nturbs]\n            ],\n            [\n                self._unnorm(valy, self.ymin, self.ymax)\n                for valy in opt_locs_norm[self.nturbs : 2 * self.nturbs]\n            ],\n        ]\n\n        return opt_locs\n"
  },
  {
    "path": "floris/optimization/load_optimization/__init__.py",
    "content": ""
  },
  {
    "path": "floris/optimization/load_optimization/load_optimization.py",
    "content": "\"\"\"Module for the load optimization class and functions.\"\"\"\n\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom floris.core import State\nfrom floris.core.turbine.operation_models import (\n    POWER_SETPOINT_DEFAULT,\n    POWER_SETPOINT_DISABLED,\n)\n\n\ndef compute_lti(\n    fmodel: FlorisModel,\n    ambient_lti: np.array,\n    wake_slope: float = 0.3,\n    max_dist_D: float = 10.0,\n):\n    \"\"\"Compute the turbine 'load turbulence intensity' (lti) for the current layout.\n\n    LTI represents the turbulence intensity used in load calculations and follows the\n    method of computing wake added turbulence described in Annex E of the IEC 61400-1 Ed. 4\n    standard.  In principle this can be the same as the turbulence models used in the wake\n    velocity and deflection models within FLORIS, but for consistency with the IEC standard\n    is computed separately here.\n\n\n\n    Args:\n        fmodel (FlorisModel): FlorisModel object\n        ambient_lti (list or np.array): Ambient 'load' turbulence intensity (lti) for each findex\n        wake_slope (float, optional): Wake slope, defined as the lateral expansion of the wake on\n            each side per unit downstream distance along the axial direction. Defaults to 0.3.\n        max_dist_D (flat, optional): Maximum distance downstream of a turbine beyond which wake\n            added turbulence is assumed to be zero, in rotor diameters. Defaults to 10.0\n            (see IEC 61400-1 Ed. 4 Annex E).\n\n    Returns:\n        np.array: Array of load turbulence intensity for each findex and turbine\n    \"\"\"\n\n    if fmodel.core.state is not State.USED:\n        raise ValueError(\"FlorisModel must be run before computing load turbulence intensity\")\n\n    D = fmodel.core.farm.rotor_diameters.flatten()[0]\n\n    # Get the indices for sorting and unsorting\n    sorted_indices = fmodel.core.grid.sorted_indices[:, :, 0, 0]\n    unsorted_indices = fmodel.core.grid.unsorted_indices[:, :, 0, 0]\n\n    # Ensure ambient_lti is a list or np.array\n    if not isinstance(ambient_lti, (list, np.ndarray)):\n        raise ValueError(\"ambient_lti must be a list or np.array\")\n\n    # Ensure ambient_lti is  of length n_findex\n    if len(ambient_lti) != fmodel.n_findex:\n        raise ValueError(\n            (\n                \"ambient_lti must be a list or np.array of length n_findex\",\n                f\"FMODEL findex = {fmodel.n_findex}, ambient_lti = {len(ambient_lti)}\",\n            )\n        )\n\n    # Initialize the lti to the ambient_lti\n    # This should be n_findex x n_turbines\n    # Tile the ambient ti across the turbines\n    lti = np.tile(np.array(ambient_lti).reshape(-1, 1), (1, fmodel.n_turbines))\n\n    # Get the turbine thrust coefficients\n    # n_findex x n_turbines\n    cts = fmodel.get_turbine_thrust_coefficients()\n\n    # Get the ambient wind speeds\n    # n_findex\n    ambient_wind_speeds = fmodel.wind_speeds.reshape(-1, 1)\n\n    # Reshape the ambient ti for multiplication\n    ambient_lti_reshape = np.array(ambient_lti).reshape(-1, 1)\n\n    # Get the x-sorted locations\n    x_sorted = np.mean(fmodel.core.grid.x_sorted, axis=(2, 3))\n    y_sorted = np.mean(fmodel.core.grid.y_sorted, axis=(2, 3))\n\n    # Put ct into sorted frame\n    ct_sorted = np.take_along_axis(cts, sorted_indices, axis=1)\n\n    # 2. Iterate over turbines from front to back across findices\n    for t in range(fmodel.n_turbines):\n        # Get current turbine locations\n        x_t = x_sorted[:, t].reshape(-1, 1)\n        y_t = y_sorted[:, t].reshape(-1, 1)\n\n        # Get the current ct value\n        ct_t = ct_sorted[:, t].reshape(-1, 1)\n\n        # Get the differences\n        dx = x_sorted - x_t\n        dy = y_sorted - y_t  # Note no deflection\n\n        # Set the boundary mask\n        wake_cone_mask = np.abs(dy) < D + wake_slope * dx\n\n        # Set the downstream mask\n        downstream_mask = dx > 0\n\n        # Calculate total distance\n        distance = np.sqrt(dx**2 + dy**2)\n\n        # Set the minimum distance mask\n        max_dist_mask = distance < D * max_dist_D\n\n        # Compute the standard deviation of the wind speed owed to this wake following Annex E\n        # of the IEC 61400-1 Ed. 4 standard\n        ws_std_wake_add = np.where(\n            wake_cone_mask & downstream_mask & max_dist_mask,\n            ambient_wind_speeds / (1.5 + 0.8 * (distance / D) / np.sqrt(ct_t)),\n            0.0,\n        )\n\n        # Combine with ambient TI to get the total TI from this wake following Annex E\n        # of the IEC 61400-1 Ed. 4 standard\n        lti_update = (\n            np.sqrt(ws_std_wake_add**2 + (ambient_lti_reshape * ambient_wind_speeds) ** 2)\n            / ambient_wind_speeds\n        )\n\n        # Update the lti using maximum wake TI\n        lti = np.maximum(lti, lti_update)\n\n    # Re-sort lti to non-sorted frame\n    lti = np.take_along_axis(lti, unsorted_indices, axis=1)\n\n    return lti\n\n\ndef compute_turbine_voc(\n    fmodel: FlorisModel,\n    A: float,\n    ambient_lti: np.array,\n    wake_slope: float = 0.3,\n    max_dist_D: float = 10.0,\n    exp_ws_std: float = 1.0,\n    exp_thrust: float = 1.0,\n):\n    \"\"\"Compute the turbine Variable Operating Cost (VOC) for each findex and turbine.\n\n    Variable Operating Cost (VOC) is meant to represent the cost of operating a turbine\n    at a particular rating in particular conditions.  We envision in the future there\n    can be several possible functions to determine VOC for a turbine, but for now we\n    use a simple model that is proportional to the wind speed standard deviation and the\n    absolute thrust of the turbine.\n\n\n    Args:\n        fmodel (FlorisModel): FlorisModel object\n        A (float): Coefficient for the VOC calculation\n        ambient_lti (list or np.array): Ambient 'load' turbulence intensity for each findex.\n        wake_slope (float, optional): Wake slope, defined as the lateral expansion of the wake on\n            each side per unit downstream distance along the axial direction. Defaults to 0.3.\n        max_dist_D (flat, optional): Maximum distance downstream of a turbine beyond which wake\n            added turbulence is assumed to be zero, in rotor diameters. Defaults to 10.0\n            (see IEC 61400-1 Ed. 4 Annex E).\n        exp_ws_std (float, optional): Exponent for the wind speed standard deviation.\n            Defaults to 1.0.\n        exp_thrust (float, optional): Exponent for the thrust. Defaults to 1.0.\n\n    Returns:\n        np.array: Array of VOC for each findex and turbine\n    \"\"\"\n\n    # A should be a float and not a list or array\n    if not isinstance(A, (int, float)):\n        raise ValueError(\"A (coefficient of VOC) must be a float\")\n\n    # Get the ambient wind speed and apply to each turbine per findex\n    ambient_wind_speeds = fmodel.wind_speeds\n    ambient_wind_speeds = np.tile(ambient_wind_speeds[:, np.newaxis], (1, fmodel.n_turbines))\n\n    # Compute the rotor area\n    D = fmodel.core.farm.rotor_diameters.flatten()[0]\n    area = np.pi * (D / 2) ** 2\n\n    # Compute the thrust\n    cts = fmodel.get_turbine_thrust_coefficients()\n    thrust = 0.5 * fmodel.core.flow_field.air_density * area * cts * ambient_wind_speeds**2\n\n    # Compute the load_ti\n    load_ti = compute_lti(\n        fmodel=fmodel,\n        ambient_lti=ambient_lti,\n        wake_slope=wake_slope,\n        max_dist_D=max_dist_D,\n    )\n\n    # Compute wind speed standard deviation\n    ws_std = ambient_wind_speeds * load_ti\n\n    # Compute voc\n    return A * (ws_std**exp_ws_std) * (thrust**exp_thrust)\n\n\ndef compute_farm_voc(\n    fmodel: FlorisModel,\n    A: float,\n    ambient_lti: np.array,\n    wake_slope: float = 0.3,\n    max_dist_D: float = 10.0,\n    exp_ws_std: float = 1.0,\n    exp_thrust: float = 1.0,\n):\n    \"\"\"Compute the farm-total Variable Operating Cost (VOC) for each findex.\n\n    Variable Operating Cost (VOC) is meant to represent the cost of operating a turbine\n    at a particular rating in particular conditions.  We envision in the future there\n    can be several possible functions to determine VOC for a turbine, but for now we\n    use a simple model that is proportional to the wind speed standard deviation and the\n    absolute thrust of the turbine.  The farm-total VOC is the sum of the VOC for each\n    turbine in the farm.\n\n    Args:\n        fmodel (FlorisModel): FlorisModel object\n        A (float): Coefficient for the VOC calculation\n        ambient_lti (list or np.array): Ambient 'load' turbulence intensity for each findex,\n            expressed as fractions of mean wind speed\n        wake_slope (float, optional): Wake slope, defined as the lateral expansion of the wake on\n            each side per unit downstream distance along the axial direction. Defaults to 0.3.\n        max_dist_D (flat, optional): Maximum distance downstream of a turbine beyond which wake\n            added turbulence is assumed to be zero, in rotor diameters. Defaults to 10.0\n            (see IEC 61400-1 Ed. 4 Annex E).\n        exp_ws_std (float, optional): Exponent for the wind speed standard deviation.\n            Defaults to 1.0.\n        exp_thrust (float, optional): Exponent for the thrust. Defaults to 1.0.\n\n    Returns:\n        np.array: Array of farm VOC for each findex\n\n    \"\"\"\n    turbine_voc = compute_turbine_voc(\n        fmodel=fmodel,\n        A=A,\n        ambient_lti=ambient_lti,\n        wake_slope=wake_slope,\n        max_dist_D=max_dist_D,\n        exp_ws_std=exp_ws_std,\n        exp_thrust=exp_thrust,\n    )\n    return np.sum(turbine_voc, axis=1)\n\n\ndef compute_farm_revenue(\n    fmodel: FlorisModel,\n):\n    \"\"\"Compute the farm revenue of the FlorisModel object using the values from fmodel.wind_data.\n\n    Args:\n        fmodel (FlorisModel): FlorisModel object\n\n    Returns:\n        np.array: Array of farm revenue for each findex\n\n    \"\"\"\n\n    if fmodel.core.state is not State.USED:\n        raise ValueError(\"FlorisModel must be run before computing net revenue\")\n\n    # Make sure fmodel.wind_data is not None\n    if fmodel.wind_data is None:\n        raise ValueError(\"FlorisModel must have wind_data to compute net revenue\")\n\n    # Ensure that fmodel.wind_data.values is not None\n    if fmodel.wind_data.values is None:\n        raise ValueError(\"FlorisModel wind_data.values must be set to compute revenue\")\n\n    farm_power = fmodel.get_farm_power()\n    values = fmodel.wind_data.values\n    return farm_power * values\n\n\ndef compute_net_revenue(\n    fmodel: FlorisModel,\n    A: float,\n    ambient_lti: np.array,\n    wake_slope: float = 0.3,\n    max_dist_D: float = 10.0,\n    exp_ws_std: float = 1.0,\n    exp_thrust: float = 1.0,\n):\n    \"\"\"Compute the net revenue for the current layout as the difference between the farm revenue\n    the farm VOC for each index.\n\n    Args:\n        fmodel (FlorisModel): FlorisModel object\n        A (float): Coefficient for the VOC calculation\n        ambient_lti (list or np.array): Ambient 'load' turbulence intensity for each findex,\n            expressed as fractions of mean wind speed\n        wake_slope (float, optional): Wake slope, defined as the lateral expansion of the wake on\n            each side per unit downstream distance along the axial direction. Defaults to 0.3.\n        max_dist_D (flat, optional): Maximum distance downstream of a turbine beyond which wake\n            added turbulence is assumed to be zero, in rotor diameters. Defaults to 10.0\n            (see IEC 61400-1 Ed. 4 Annex E).\n        exp_ws_std (float, optional): Exponent for the wind speed standard deviation.\n            Defaults to 1.0.\n        exp_thrust (float, optional): Exponent for the thrust. Defaults to 1.0.\n\n    Returns:\n        np.array: Array of net revenue for each findex\n\n    \"\"\"\n\n    revenue = compute_farm_revenue(\n        fmodel=fmodel,\n    )\n\n    farm_voc = compute_farm_voc(\n        fmodel=fmodel,\n        A=A,\n        ambient_lti=ambient_lti,\n        wake_slope=wake_slope,\n        max_dist_D=max_dist_D,\n        exp_ws_std=exp_ws_std,\n        exp_thrust=exp_thrust,\n    )\n\n    return revenue - farm_voc\n\n\ndef find_A_to_satisfy_rev_voc_ratio(\n    fmodel: FlorisModel,\n    target_rev_voc_ratio: float,\n    ambient_lti: np.array,\n    wake_slope: float = 0.3,\n    max_dist_D: float = 10.0,\n    exp_ws_std: float = 1.0,\n    exp_thrust: float = 1.0,\n):\n    \"\"\"Find the value of A that satisfies the target ratio of total farm revenue over all findices\n    to total farm VOC over all findices.\n\n    Args:\n        fmodel (FlorisModel): FlorisModel object\n        target_rev_voc_ratio (float): Target revenue to VOC ratio\n        ambient_lti (list or np.array): Ambient 'load' turbulence intensity for each findex,\n            expressed as fractions of mean wind speed\n        wake_slope (float, optional): Wake slope, defined as the lateral expansion of the wake on\n            each side per unit downstream distance along the axial direction. Defaults to 0.3.\n        max_dist_D (flat, optional): Maximum distance downstream of a turbine beyond which wake\n            added turbulence is assumed to be zero, in rotor diameters. Defaults to 10.0\n            (see IEC 61400-1 Ed. 4 Annex E).\n        exp_ws_std (float, optional): Exponent for the wind speed standard deviation.\n            Defaults to 1.0.\n        exp_thrust (float, optional): Exponent for the thrust. Defaults to 1.\n\n    Returns:\n        float: Value of A that satisfies the target revenue to VOC ratio\n\n    \"\"\"\n\n    # Compute farm revenue\n    farm_revenue = compute_farm_revenue(\n        fmodel=fmodel,\n    )\n\n    # Compute farm VOC\n    farm_voc = compute_farm_voc(\n        fmodel=fmodel,\n        A=1.0,\n        ambient_lti=ambient_lti,\n        wake_slope=wake_slope,\n        max_dist_D=max_dist_D,\n        exp_ws_std=exp_ws_std,\n        exp_thrust=exp_thrust,\n    )\n\n    return (farm_revenue.sum() / farm_voc.sum()) / target_rev_voc_ratio\n\n\ndef find_A_to_satisfy_target_VOC_per_MW(\n    fmodel: FlorisModel,\n    target_VOC_per_MW_findex: float,\n    ambient_lti: np.array,\n    wake_slope: float = 0.3,\n    max_dist_D: float = 10.0,\n    exp_ws_std: float = 1.0,\n    exp_thrust: float = 1.0,\n):\n    \"\"\"Find the value of A that satisfies the target average cost per total farm power per findex\n    over all findices. Note that if each findex represents 1 hour of operation, this is equivalent\n    to the target average cost/MWh.\n\n    Args:\n        fmodel (FlorisModel): FlorisModel object\n        target_VOC_per_MW_findex (float): Target average cost per MW per findex\n        ambient_lti (list or np.array): Ambient 'load' turbulence intensity for each findex,\n            expressed as fractions of mean wind speed\n        wake_slope (float, optional): Wake slope, defined as the lateral expansion of the wake on\n            each side per unit downstream distance along the axial direction. Defaults to 0.3.\n        max_dist_D (flat, optional): Maximum distance downstream of a turbine beyond which wake\n            added turbulence is assumed to be zero, in rotor diameters. Defaults to 10.0\n            (see IEC 61400-1 Ed. 4 Annex E).\n        exp_ws_std (float, optional): Exponent for the wind speed standard deviation.\n            Defaults to 1.0.\n        exp_thrust (float, optional): Exponent for the thrust. Defaults to 1.\n\n    Returns:\n        float: Value of A that satisfies the target cost/MW/findex\n\n    \"\"\"\n\n    if fmodel.core.state is not State.USED:\n        raise ValueError(\"FlorisModel must be run before finding A for target cost/MW/findex\")\n\n    # Compute farm power\n    farm_power = fmodel.get_farm_power()\n\n    # Compute farm VOC\n    farm_voc = compute_farm_voc(\n        fmodel=fmodel,\n        A=1.0,\n        ambient_lti=ambient_lti,\n        wake_slope=wake_slope,\n        max_dist_D=max_dist_D,\n        exp_ws_std=exp_ws_std,\n        exp_thrust=exp_thrust,\n    )\n\n    return 1e-6 * target_VOC_per_MW_findex / (farm_voc.sum() / (farm_power.sum()))\n\n\ndef optimize_power_setpoints(\n    fmodel: FlorisModel,\n    A: float,\n    ambient_lti: np.array,\n    wake_slope: float = 0.3,\n    max_dist_D: float = 10.0,\n    exp_ws_std: float = 1.0,\n    exp_thrust: float = 1.0,\n    power_setpoint_initial: np.array = None,\n    power_setpoint_levels: np.array = np.linspace(\n        POWER_SETPOINT_DEFAULT, POWER_SETPOINT_DISABLED, 5\n    ),\n):\n    \"\"\"Optimize the derating of each turbine to maximize net revenue sequentially from upstream to\n    downstream.\n\n    Args:\n        fmodel (FlorisModel): FlorisModel object\n        A (float): Coefficient for the VOC calculation\n        ambient_lti (list or np.array): Ambient 'load' turbulence intensity for each findex,\n            expressed as fractions of mean wind speed\n        wake_slope (float, optional): Wake slope, defined as the lateral expansion of the wake on\n            each side per unit downstream distance along the axial direction. Defaults to 0.3.\n        max_dist_D (flat, optional): Maximum distance downstream of a turbine beyond which wake\n            added turbulence is assumed to be zero, in rotor diameters. Defaults to 10.0\n            (see IEC 61400-1 Ed. 4 Annex E).\n        exp_ws_std (float, optional): Exponent for the wind speed standard deviation.\n            Defaults to 1.0.\n        exp_thrust (float, optional): Exponent for the thrust. Defaults to 1.\n        power_setpoint_initial (np.array, optional): Initial power setpoint for each turbine.\n            If None, each turbine's rated power will be used. Defaults to None.\n        power_setpoint_levels (np.array, optional): Array of power setpoint levels to consider\n            in optimization in W.\n            Defaults to np.linspace(POWER_SETPOINT_DEFAULT, POWER_SETPOINT_DISABLED, 5).\n\n    \"\"\"\n\n    # Ensure we're in an operation model which includes derating\n    # presently this can be \"mixed\" or \"simple-derating\"\n    if fmodel.get_operation_model() not in [\"mixed\", \"simple-derating\"]:\n        raise ValueError(\n            \"Operation model must include derating (e.g., 'mixed' or 'simple-derating')\"\n        )\n\n    # Raise an error if there is more than one turbine type specified\n    if not np.array(\n        [\n            fmodel.core.farm.turbine_definitions[0] == td\n            for td in fmodel.core.farm.turbine_definitions\n        ]\n    ).all():\n        raise NotImplementedError(\"Only one turbine type is currently supported for optimization\")\n\n    # If initial set point not provided, set to rated (assumed max) power\n    if power_setpoint_initial is None:\n        max_power = fmodel.core.farm.turbine_map[0].power_thrust_table[\"power\"].max() * 1000.0\n        power_setpoint_initial = np.tile(max_power, (fmodel.n_findex, 1))\n\n    # Initialize the test power setpoints\n    power_setpoint_test = power_setpoint_initial.copy()\n    power_setpoint_opt = power_setpoint_initial.copy()\n\n    # Get the sorted coords\n    sorted_indices = fmodel.core.grid.sorted_indices[:, :, 0, 0]\n\n    # Initialize the net revenue using the initial setpoints\n    fmodel.set(power_setpoints=power_setpoint_initial)\n    fmodel.run()\n    net_revenue_opt = compute_net_revenue(\n        fmodel=fmodel,\n        A=A,\n        ambient_lti=ambient_lti,\n        wake_slope=wake_slope,\n        max_dist_D=max_dist_D,\n        exp_ws_std=exp_ws_std,\n        exp_thrust=exp_thrust,\n    )\n\n    # Now loop over turbines\n    for t in sorted_indices.T:\n        # Loop over derating levels\n        for d in power_setpoint_levels:\n            # Apply the proposed derating level to the test_power_setpoint matrix\n            power_setpoint_test[range(fmodel.n_findex), t] = d\n\n            # Apply the setpoint to fmodel\n            fmodel.set(power_setpoints=power_setpoint_test)\n\n            # Run\n            fmodel.run()\n\n            # Get the net revenue\n            test_net_revenue = compute_net_revenue(\n                fmodel=fmodel,\n                A=A,\n                ambient_lti=ambient_lti,\n                wake_slope=wake_slope,\n                max_dist_D=max_dist_D,\n            )\n\n            # Get a map of where test_net_revenue is greater than net_revenue\n            update_mask = test_net_revenue > net_revenue_opt\n\n            # Where update_mask is false, revert the test_power_setpoint to previous value\n            power_setpoint_test[~update_mask, :] = power_setpoint_opt[~update_mask, :]\n\n            # Update the final_power_setpoint\n            power_setpoint_opt[:, :] = power_setpoint_test[:, :]\n\n            # Update the net_revenue\n            net_revenue_opt[update_mask] = test_net_revenue[update_mask]\n\n    # Return the final power setpoint and optimized revenue\n    return power_setpoint_opt, net_revenue_opt\n"
  },
  {
    "path": "floris/optimization/other/__init__.py",
    "content": "from . import boundary_grid\n"
  },
  {
    "path": "floris/optimization/other/boundary_grid.py",
    "content": "\nimport numpy as np\nfrom shapely.geometry import Point, Polygon\n\n\ndef discontinuous_grid(\n    nrows,\n    ncols,\n    farm_width,\n    farm_height,\n    shear,\n    rotation,\n    center_x,\n    center_y,\n    shrink_boundary,\n    boundary_x,\n    boundary_y,\n    eps=1e-3,\n):\n    \"\"\"\n    Map from grid design variables to turbine x and y locations.\n    Includes integer design variables and the formulation\n    results in a discontinous design space.\n\n    TODO: shrink_boundary doesn't work well with concave boundaries,\n    or with boundary angles less than 90 deg\n\n    Args:\n        nrows (Int): number of rows in the grid.\n        ncols (Int): number of columns in the grid.\n        farm_width (Float): total grid width (before shear).\n        farm_height (Float): total grid height.\n        shear (Float): grid shear (rad).\n        rotation (Float): rotation about grid center (rad).\n        center_x (Float): location of grid x center.\n        center_y (Float): location of grid y center.\n        shrink_boundary (Float): how much to shrink the boundary that the grid can occupy.\n        boundary_x (Array(Float)): x boundary points.\n        boundary_y (Array(Float)): y boundary points.\n\n    Returns:\n        grid_x (Array(Float)): turbine x locations.\n        grid_y (Array(Float)): turbine y locations.\n    \"\"\"\n    # create grid\n    nrows = int(nrows)\n    ncols = int(ncols)\n    xlocs = np.linspace(0.0, farm_width, ncols)\n    ylocs = np.linspace(0.0, farm_height, nrows)\n    y_spacing = ylocs[1] - ylocs[0]\n    nturbs = nrows * ncols\n    grid_x = np.zeros(nturbs)\n    grid_y = np.zeros(nturbs)\n    turb = 0\n    for i in range(nrows):\n        for j in range(ncols):\n            grid_x[turb] = xlocs[j] + float(i) * y_spacing * np.tan(shear)\n            grid_y[turb] = ylocs[i]\n            turb += 1\n\n    # rotate\n    grid_x, grid_y = (\n        np.cos(rotation) * grid_x - np.sin(rotation) * grid_y,\n        np.sin(rotation) * grid_x + np.cos(rotation) * grid_y,\n    )\n\n    # move center of grid\n    grid_x = (grid_x - np.mean(grid_x)) + center_x\n    grid_y = (grid_y - np.mean(grid_y)) + center_y\n\n    # arrange the boundary\n\n    # boundary = np.zeros((len(boundary_x),2))\n    # boundary[:,0] = boundary_x[:]\n    # boundary[:,1] = boundary_y[:]\n    # poly = Polygon(boundary)\n    # centroid = poly.centroid\n\n    # boundary[:,0] = (boundary_x[:]-centroid.x)*boundary_mult + centroid.x\n    # boundary[:,1] = (boundary_y[:]-centroid.y)*boundary_mult + centroid.y\n    # poly = Polygon(boundary)\n\n    boundary = np.zeros((len(boundary_x), 2))\n    boundary[:, 0] = boundary_x[:]\n    boundary[:, 1] = boundary_y[:]\n    poly = Polygon(boundary)\n\n    if shrink_boundary != 0.0:\n        nBounds = len(boundary_x)\n        for i in range(nBounds):\n            point = Point(boundary_x[i] + eps, boundary_y[i])\n            if poly.contains(point) is True or poly.touches(point) is True:\n                boundary[i, 0] = boundary_x[i] + shrink_boundary\n            else:\n                boundary[i, 0] = boundary_x[i] - shrink_boundary\n\n            point = Point(boundary_x[i], boundary_y[i] + eps)\n            if poly.contains(point) is True or poly.touches(point) is True:\n                boundary[i, 1] = boundary_y[i] + shrink_boundary\n            else:\n                boundary[i, 1] = boundary_y[i] - shrink_boundary\n\n        poly = Polygon(boundary)\n\n    # get rid of points outside of boundary\n    index = 0\n    for i in range(len(grid_x)):\n        point = Point(grid_x[index], grid_y[index])\n        if poly.contains(point) is False and poly.touches(point) is False:\n            grid_x = np.delete(grid_x, index)\n            grid_y = np.delete(grid_y, index)\n        else:\n            index += 1\n\n    return grid_x, grid_y\n\n\ndef place_boundary_turbines(n_boundary_turbs, start, boundary_x, boundary_y):\n    \"\"\"\n    Place turbines equally spaced traversing the perimiter if the wind farm along the boundary\n\n    Args:\n    n_boundary_turbs (Int): number of turbines to be placed on the boundary\n    start (Float): where the first turbine should be placed\n    boundary_x (Array(Float)): x boundary points\n    boundary_y (Array(Float)): y boundary points\n\n    Returns\n    layout_x (Array(Float)): turbine x locations\n    layout_y (Array(Float)): turbine y locations\n    \"\"\"\n\n    # check if the boundary is closed, correct if not\n    if boundary_x[-1] != boundary_x[0] or boundary_y[-1] != boundary_y[0]:\n        boundary_x = np.append(boundary_x, boundary_x[0])\n        boundary_y = np.append(boundary_y, boundary_y[0])\n\n    # make the boundary\n    boundary = np.zeros((len(boundary_x), 2))\n    boundary[:, 0] = boundary_x[:]\n    boundary[:, 1] = boundary_y[:]\n    poly = Polygon(boundary)\n    perimeter = poly.length\n\n    # get the flattened turbine locations\n    spacing = perimeter / float(n_boundary_turbs)\n    flattened_locs = np.linspace(start, perimeter + start - spacing, n_boundary_turbs)\n\n    # set all of the flattened values between 0 and the perimeter\n    for i in range(n_boundary_turbs):\n        while flattened_locs[i] < 0.0:\n            flattened_locs[i] += perimeter\n        if flattened_locs[i] > perimeter:\n            flattened_locs[i] = flattened_locs[i] % perimeter\n\n    # place the turbines around the perimeter\n    nBounds = len(boundary_x)\n    layout_x = np.zeros(n_boundary_turbs)\n    layout_y = np.zeros(n_boundary_turbs)\n\n    lenBound = np.zeros(nBounds - 1)\n    for i in range(nBounds - 1):\n        lenBound[i] = Point(boundary[i]).distance(Point(boundary[i + 1]))\n    for i in range(n_boundary_turbs):\n        for j in range(nBounds - 1):\n            if flattened_locs[i] < sum(lenBound[0 : j + 1]):\n                layout_x[i] = (\n                    boundary_x[j]\n                    + (boundary_x[j + 1] - boundary_x[j])\n                    * (flattened_locs[i] - sum(lenBound[0:j]))\n                    / lenBound[j]\n                )\n                layout_y[i] = (\n                    boundary_y[j]\n                    + (boundary_y[j + 1] - boundary_y[j])\n                    * (flattened_locs[i] - sum(lenBound[0:j]))\n                    / lenBound[j]\n                )\n                break\n\n    return layout_x, layout_y\n\n\ndef boundary_grid(\n    n_boundary_turbs,\n    start,\n    nrows,\n    ncols,\n    farm_width,\n    farm_height,\n    shear,\n    rotation,\n    center_x,\n    center_y,\n    shrink_boundary,\n    boundary_x,\n    boundary_y,\n    eps=1e-3,\n):\n    \"\"\"\n    Place turbines equally spaced traversing the perimiter if the wind farm along the boundary\n\n    Args:\n    n_boundary_turbs,start: boundary variables\n    nrows,ncols,farm_width,farm_height,shear,\n        rotation,center_x,center_y,shrink_boundary,eps: grid variables\n    boundary_x,boundary_y: boundary points\n\n    Returns\n    layout_x (Array(Float)): turbine x locations\n    layout_y (Array(Float)): turbine y locations\n    \"\"\"\n\n    boundary_turbines_x, boundary_turbines_y = place_boundary_turbines(\n        n_boundary_turbs, start, boundary_x, boundary_y\n    )\n    grid_turbines_x, grid_turbines_y = discontinuous_grid(\n        nrows,\n        ncols,\n        farm_width,\n        farm_height,\n        shear,\n        rotation,\n        center_x,\n        center_y,\n        shrink_boundary,\n        boundary_x,\n        boundary_y,\n        eps=eps,\n    )\n\n    layout_x = np.append(boundary_turbines_x, grid_turbines_x)\n    layout_y = np.append(boundary_turbines_y, grid_turbines_y)\n\n    return layout_x, layout_y\n\n\nclass BoundaryGrid:\n    \"\"\"\n    Parameterize the wind farm layout with a grid or the boundary grid method\n    \"\"\"\n\n    def __init__(self, fi):\n        \"\"\"\n        Initializes a BoundaryGrid object by assigning a\n        FlorisModel object.\n\n        Args:\n            fmodel (FlorisModel): A FlorisModel object.\n        \"\"\"\n        self.fmodel = fi\n\n        self.n_boundary_turbs = 0\n        self.start = 0.0\n        self.nrows = 0\n        self.ncols = 0\n        self.farm_width = 0.0\n        self.farm_height = 0.0\n        self.shear = 0.0\n        self.rotation = 0.0\n        self.center_x = 0.0\n        self.center_y = 0.0\n        self.shrink_boundary = 0.0\n        self.boundary_x = np.array([])\n        self.boundary_y = np.array([])\n        self.eps = 1e-3\n\n    def reinitialize_bg(\n        self,\n        n_boundary_turbs=None,\n        start=None,\n        nrows=None,\n        ncols=None,\n        farm_width=None,\n        farm_height=None,\n        shear=None,\n        rotation=None,\n        center_x=None,\n        center_y=None,\n        shrink_boundary=None,\n        boundary_x=None,\n        boundary_y=None,\n        eps=None,\n    ):\n\n        if n_boundary_turbs is not None:\n            self.n_boundary_turbs = n_boundary_turbs\n        if start is not None:\n            self.start = start\n        if nrows is not None:\n            self.nrows = nrows\n        if ncols is not None:\n            self.ncols = ncols\n        if farm_width is not None:\n            self.farm_width = farm_width\n        if farm_height is not None:\n            self.farm_height = farm_height\n        if shear is not None:\n            self.shear = shear\n        if rotation is not None:\n            self.rotation = rotation\n        if center_x is not None:\n            self.center_x = center_x\n        if center_y is not None:\n            self.center_y = center_y\n        if shrink_boundary is not None:\n            self.shrink_boundary = shrink_boundary\n        if boundary_x is not None:\n            self.boundary_x = boundary_x\n        if boundary_y is not None:\n            self.boundary_y = boundary_y\n        if eps is not None:\n            self.eps = eps\n\n    def reinitialize_xy(self):\n\n        layout_x, layout_y = boundary_grid(\n            self.n_boundary_turbs,\n            self.start,\n            self.nrows,\n            self.ncols,\n            self.farm_width,\n            self.farm_height,\n            self.shear,\n            self.rotation,\n            self.center_x,\n            self.center_y,\n            self.shrink_boundary,\n            self.boundary_x,\n            self.boundary_y,\n            eps=self.eps,\n        )\n\n        self.fmodel.reinitialize_flow_field(layout_array=(layout_x, layout_y))\n\n\nif __name__ == \"__main__\":\n\n    nrows = 10\n    ncols = 10\n    farm_width = 600\n    farm_height = 600\n    shear = np.deg2rad(10)\n    rotation = np.deg2rad(30)\n    center_x = 250\n    center_y = 300\n    boundary_mult = 0.6\n    shrink_boundary = 10.0\n    # boundary_x = np.array([-300.0,-100.0,100.0,100.0,0.0]) + 2200.0\n    # boundary_y = np.array([-100.0,100.0,140.0,-100.0,0.0]) + 300.0\n    boundary_x = np.array(\n        [0.0, 100.0, 100.0, 200.0, 200.0, 300.0, 300.0, 400.0, 400.0, 500.0, 500.0, 0.0]\n    )\n    boundary_y = np.array(\n        [\n            500.0,\n            500.0,\n            400.0,\n            400.0,\n            300.0,\n            300.0,\n            200.0,\n            200.0,\n            100.0,\n            100.0,\n            600.0,\n            600.0,\n        ]\n    )\n    x, y = discontinuous_grid(\n        nrows,\n        ncols,\n        farm_width,\n        farm_height,\n        shear,\n        rotation,\n        center_x,\n        center_y,\n        shrink_boundary,\n        boundary_x,\n        boundary_y,\n    )\n\n    n_boundary_turbs = 25\n    start = 1000.0\n    layout_x, layout_y = place_boundary_turbines(\n        n_boundary_turbs, start, boundary_x, boundary_y\n    )\n\n    bx = np.append(boundary_x, boundary_x[0])\n    by = np.append(boundary_y, boundary_y[0])\n\n    boundary = np.zeros((len(bx), 2))\n    boundary[:, 0] = bx[:]\n    boundary[:, 1] = by[:]\n    poly = Polygon(boundary)\n\n    # centroid = poly.centroid\n    # new_bx = (bx[:]-centroid.x)*boundary_mult + centroid.x\n    # new_by = (by[:]-centroid.y)*boundary_mult + centroid.y\n\n    nBounds = len(bx)\n    new_bx = np.zeros(len(bx))\n    new_by = np.zeros(len(by))\n    eps = 1e-3\n    for i in range(nBounds):\n        point = Point(bx[i] + eps, by[i])\n        if poly.contains(point) is True or poly.touches(point) is True:\n            new_bx[i] = bx[i] + shrink_boundary\n        else:\n            new_bx[i] = bx[i] - shrink_boundary\n\n        point = Point(bx[i], by[i] + eps)\n        if poly.contains(point) is True or poly.touches(point) is True:\n            new_by[i] = by[i] + shrink_boundary\n        else:\n            new_by[i] = by[i] - shrink_boundary\n\n    import matplotlib.pyplot as plt\n\n    nx, ny = boundary_grid(\n        n_boundary_turbs,\n        start,\n        nrows,\n        ncols,\n        farm_width,\n        farm_height,\n        shear,\n        rotation,\n        center_x,\n        center_y,\n        shrink_boundary,\n        boundary_x,\n        boundary_y,\n    )\n\n    plt.plot(bx, by)\n    plt.plot(new_bx, new_by)\n    plt.plot(x, y, \"o\")\n    plt.plot(layout_x, layout_y, \"o\")\n    plt.axis(\"equal\")\n\n    plt.figure(2)\n    plt.plot(bx, by)\n    plt.plot(nx, ny, \"o\")\n    plt.axis(\"equal\")\n\n    plt.show()\n"
  },
  {
    "path": "floris/optimization/yaw_optimization/__init__.py",
    "content": ""
  },
  {
    "path": "floris/optimization/yaw_optimization/yaw_optimization_base.py",
    "content": "\nimport copy\nfrom time import perf_counter as timerpc\n\nimport numpy as np\nimport pandas as pd\n\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DISABLED\nfrom floris.logging_manager import LoggingManager\n\nfrom .yaw_optimization_tools import derive_downstream_turbines\n\n\nclass YawOptimization(LoggingManager):\n    \"\"\"\n    YawOptimization is a subclass of :py:class:`floris.optimization.scipy.\n    Optimization` that is used to optimize the yaw angles of all turbines in a Floris\n    Farm for a single set of inflow conditions using the SciPy optimize package.\n    \"\"\"\n\n    def __init__(\n        self,\n        fmodel,\n        minimum_yaw_angle=0.0,\n        maximum_yaw_angle=25.0,\n        yaw_angles_baseline=None,\n        x0=None,\n        turbine_weights=None,\n        normalize_control_variables=False,\n        calc_baseline_power=True,\n        exclude_downstream_turbines=True,\n        verify_convergence=False,\n    ):\n        \"\"\"\n        Instantiate YawOptimization object with a FlorisModel object\n        and assign parameter values.\n\n        Args:\n            fmodel (:py:class:`~.floris_model.FlorisModel`): A FlorisModel object.\n            minimum_yaw_angle (float or ndarray): Minimum constraint on yaw\n                angle (deg). If a single value specified, assumes this value\n                for all turbines. If a 1D array is specified, assumes these\n                limits for each turbine specifically, but uniformly across\n                all atmospheric conditions. If a 2D array, limits are specific\n                both to the turbine and to the atmospheric condition.\n                Defaults to 0.0.\n            maximum_yaw_angle (float or ndarray): Maximum constraint on yaw\n                angle (deg). If a single value specified, assumes this value\n                for all turbines. If a 1D array is specified, assumes these\n                limits for each turbine specifically, but uniformly across\n                all atmospheric conditions. If a 2D array, limits are specific\n                both to the turbine and to the atmospheric condition.\n                Defaults to 25.0.\n            yaw_angles_baseline (iterable, optional): The baseline yaw\n                angles used to calculate the initial and baseline power\n                production in the wind farm and used to normalize the cost\n                function. If none are specified, this variable is set equal\n                to the current yaw angles in floris. Note that this variable\n                need not meet the yaw constraints specified in self.bnds,\n                yet a warning is raised if it does to inform the user.\n                Defaults to None.\n            x0 (iterable, optional): The initial guess for the optimization\n                problem. These values must meet the constraints specified\n                in self.bnds. Note that, if exclude_downstream_turbines=True,\n                the initial guess for any downstream turbines are ignored\n                since they are not part of the optimization. Instead, the yaw\n                angles for those turbines are 0.0 if that meets the lower and\n                upper bound, or otherwise as close to 0.0 as feasible. If no\n                values for x0 are specified, x0 is set to be equal to zeros\n                wherever feasible (w.r.t. the bounds), and equal to the\n                average of its lower and upper bound for all non-downstream\n                turbines otherwise. Defaults to None.\n            turbine_weights (iterable, optional): weighing terms that allow\n                the user to emphasize power gains at particular turbines or\n                completely ignore power gains from other turbines. The array\n                of turbine powers from floris is multiplied with this array\n                in the calculation of the objective function. If None, this\n                is an array with all values 1.0 and length equal to the\n                number of turbines. Defaults to None.\n            calc_init_power (bool, optional): If True, calculates initial\n                wind farm power for each set of wind conditions. Defaults to\n                True.\n            exclude_downstream_turbines (bool, optional): If True,\n                automatically finds and excludes turbines that are most\n                downstream from the optimization problem. This significantly\n                reduces computation time at no loss in performance. The yaw\n                angles of these downstream turbines are fixed to 0.0 deg if\n                the yaw bounds specified in self.bnds allow that, or otherwise\n                are fixed to the lower or upper yaw bound, whichever is closer\n                to 0.0. Defaults to False.\n            verify_convergence (bool, optional): specifies whether the found\n                optimal yaw angles will be checked for accurately convergence.\n                With large farms, especially when using SciPy or other global\n                optimization methods, solutions do not always converge and\n                turbines that should have a 0.0 deg actually have a 1.0 deg\n                angle, for example. By enabling this function, the final yaw\n                angles are compared to their baseline values one-by-one for\n                the turbines to make sure no such convergence issues arise.\n                Defaults to False.\n        \"\"\"\n\n        # Save turbine object to self\n        self.fmodel = copy.deepcopy(fmodel)\n        self.nturbs = len(self.fmodel.layout_x)\n\n        # # Check floris options\n        # if self.fmodel.core.flow_field.n_wind_speeds > 1:\n        #     raise NotImplementedError(\n        #         \"Optimizer currently does not support more than one wind\" +\n        #         \" speed. Please assign FLORIS a single wind speed.\"\n        #     )\n\n        # Initialize optimizer\n        self.verify_convergence = verify_convergence\n        if yaw_angles_baseline is not None:\n            yaw_angles_baseline = self._unpack_variable(yaw_angles_baseline)\n            self.yaw_angles_baseline = yaw_angles_baseline\n        else:\n            b = self.fmodel.core.farm.yaw_angles\n            self.yaw_angles_baseline = self._unpack_variable(b)\n            if np.any(np.abs(b) > 0.0):\n                print(\n                    \"INFO: Baseline yaw angles were not specified and \"\n                    \"were derived from the floris object.\"\n                )\n                print(\n                    \"INFO: The inherent yaw angles in the floris object \"\n                    \"are not all 0.0 degrees.\"\n                )\n\n        # Set optimization bounds\n        self.minimum_yaw_angle = self._unpack_variable(minimum_yaw_angle)\n        self.maximum_yaw_angle = self._unpack_variable(maximum_yaw_angle)\n\n        # Limit yaw angles to zero for disabled turbines\n        active_turbines = fmodel.core.farm.power_setpoints > POWER_SETPOINT_DISABLED\n        self.minimum_yaw_angle[~active_turbines] = 0.0\n        self.maximum_yaw_angle[~active_turbines] = 0.0\n\n        # Set initial condition for optimization\n        if x0 is not None:\n            self.x0 = self._unpack_variable(x0)\n        else:\n            self.x0 = self._unpack_variable(0.0)\n            for ti in range(self.nturbs):\n                yaw_lb = self.minimum_yaw_angle[:, ti]\n                yaw_ub = self.maximum_yaw_angle[:, ti]\n                idx = (yaw_lb > 0.0) | (yaw_ub < 0.0)\n                self.x0[idx, ti] = (yaw_lb[idx] + yaw_ub[idx]) / 2.0\n\n        # Check inputs for consistency\n        if np.any(self.yaw_angles_baseline < self.minimum_yaw_angle):\n            print(\"INFO: yaw_angles_baseline exceed lower bound constraints.\")\n        if np.any(self.yaw_angles_baseline > self.maximum_yaw_angle):\n            print(\"INFO: yaw_angles_baseline exceed upper bound constraints.\")\n        if np.any(self.x0 < self.minimum_yaw_angle):\n            raise ValueError(\"Initial guess x0 exceeds lower bound constraints.\")\n        if np.any(self.x0 > self.maximum_yaw_angle):\n            raise ValueError(\"Initial guess x0 exceeds upper bound constraints.\")\n\n        # Define turbine weighing terms\n        if turbine_weights is None:\n            self.turbine_weights = self._unpack_variable(1.0)\n        else:\n            self.turbine_weights = self._unpack_variable(turbine_weights)\n\n        # Save remaining user options to self\n        self.normalize_variables = normalize_control_variables\n        self.calc_baseline_power = calc_baseline_power\n        self.exclude_downstream_turbines = exclude_downstream_turbines\n\n\n        # Prepare for optimization and calculate baseline powers (if applic.)\n        self._initialize()\n        self._calculate_baseline_farm_power()\n\n        # Initialize optimal yaw angles and cost function as baseline values\n        self._yaw_angles_opt_subset = copy.deepcopy(self._yaw_angles_baseline_subset)\n        self._farm_power_opt_subset = copy.deepcopy(self._farm_power_baseline_subset)\n        self._yaw_lbs = copy.deepcopy(self._minimum_yaw_angle_subset)\n        self._yaw_ubs = copy.deepcopy(self._maximum_yaw_angle_subset)\n\n    # Private methods\n\n    def _initialize(self):\n        # Reduce optimization problem as much as possible\n        self._reduce_control_problem()\n\n        # Normalize optimization variables\n        if self.normalize_variables:\n            self._normalize_control_problem()\n\n    def _unpack_variable(self, variable, subset=False):\n        \"\"\"Take a variable, can be either a float, a list equal in\n        length to the number of turbines, or an ndarray. It then\n        upsamples this value so that it always matches the dimensions\n        (self.nconds, self.nturbs).\n        \"\"\"\n        # Deal with full vs. subset dimensions\n        nturbs = self.nturbs\n        if subset:\n            nturbs = np.shape(self._x0_subset.shape[1])\n\n        # Then process maximum yaw angle\n        if isinstance(variable, (int, float)):\n            # If single value, copy over to all turbines\n            variable = np.tile(variable, (nturbs))\n\n        variable = np.array(variable, dtype=float)\n        if len(np.shape(variable)) == 1:\n            # If one-dimensional array, copy over to all atmos. conditions\n            variable = np.tile(\n                variable,\n                (self.fmodel.core.flow_field.n_findex, 1)\n            )\n\n\n        return variable\n\n    def _reduce_control_problem(self):\n        \"\"\"\n        This function reduces the control problem by eliminating turbines\n        of which the yaw angles need not be optimized, either because of a\n        user-specified set of bounds (where bounds[i][0] == bounds[i][1]),\n        or alternatively turbines that are far downstream in the wind farm\n        and of which the wake does not impinge other turbines, if\n        exclude_downstream_turbines == True.\n        \"\"\"\n        # Initialize which turbines to optimize for\n        self.turbs_to_opt = (self.maximum_yaw_angle - self.minimum_yaw_angle >= 0.001)\n\n        # Initialize subset variables as full set\n        self.fmodel_subset = copy.deepcopy(self.fmodel)\n        if hasattr(self.fmodel_subset, \"_wind_data\"): # Normal FlorisModel, ParFlorisModel\n            self.fmodel_subset._wind_data = None # Accessing private attribute!\n        elif hasattr(self.fmodel_subset, \"fmodel_expanded\"): # UncertainFlorisModel\n            self.fmodel_subset.fmodel_unexpanded._wind_data = None # Accessing private attribute!\n        n_findex_subset = copy.deepcopy(self.fmodel.core.flow_field.n_findex)\n        minimum_yaw_angle_subset = copy.deepcopy(self.minimum_yaw_angle)\n        maximum_yaw_angle_subset = copy.deepcopy(self.maximum_yaw_angle)\n        x0_subset = copy.deepcopy(self.x0)\n        turbs_to_opt_subset = copy.deepcopy(self.turbs_to_opt)\n        turbine_weights_subset = copy.deepcopy(self.turbine_weights)\n        yaw_angles_template_subset = self._unpack_variable(0.0)\n        yaw_angles_baseline_subset = copy.deepcopy(self.yaw_angles_baseline)\n\n        # Define which turbines to optimize for\n        if self.exclude_downstream_turbines:\n            for iw, wd in enumerate(self.fmodel.core.flow_field.wind_directions):\n                # Remove turbines from turbs_to_opt that are downstream\n                downstream_turbines = derive_downstream_turbines(self.fmodel, wd)\n                downstream_turbines = np.array(downstream_turbines, dtype=int)\n                self.turbs_to_opt[iw, downstream_turbines] = False\n                turbs_to_opt_subset = copy.deepcopy(self.turbs_to_opt)  # Update\n\n        # Set up a template yaw angles array with default solutions. The default\n        # solutions are either 0.0 or the allowable yaw angle closest to 0.0 deg.\n        # This solution addresses both downstream turbines, minimizing their abs.\n        # yaw offset, and additionally fixing equality-constrained turbines to\n        # their appropriate yaw angle.\n        idx = (minimum_yaw_angle_subset > 0.0) | (maximum_yaw_angle_subset < 0.0)\n        if np.any(idx):\n            # Find bounds closest to 0.0 deg\n            combined_bounds = np.concatenate(\n                (\n                    np.expand_dims(minimum_yaw_angle_subset, axis=2),\n                    np.expand_dims(maximum_yaw_angle_subset, axis=2)\n                ),\n                axis=2\n            )\n            # Overwrite all values that are not allowed to be 0.0 with bound value closest to zero\n            ids_closest = np.expand_dims(np.argmin(np.abs(combined_bounds), axis=2), axis=2)\n            yaw_mb = np.squeeze(np.take_along_axis(combined_bounds, ids_closest, axis=2), axis=2)\n            yaw_angles_template_subset[idx] = yaw_mb[idx]\n\n        # Save all subset variables to self\n        self._n_findex_subset = n_findex_subset\n        self._minimum_yaw_angle_subset = minimum_yaw_angle_subset\n        self._maximum_yaw_angle_subset = maximum_yaw_angle_subset\n        self._x0_subset = x0_subset\n        self._turbs_to_opt_subset = turbs_to_opt_subset\n        self._turbine_weights_subset = turbine_weights_subset\n        self._yaw_angles_template_subset = yaw_angles_template_subset\n        self._yaw_angles_baseline_subset = yaw_angles_baseline_subset\n\n    def _normalize_control_problem(self):\n        \"\"\"\n        This private function normalizes variables for the optimization\n        problem, specifically the initial condition x0 and the bounds.\n        Normalization can improve optimization performance when using common\n        optimization methods such as the SciPy Optimization Toolbox.\n        \"\"\"\n        lb = np.min(self._minimum_yaw_angle_subset)\n        ub = np.max(self._maximum_yaw_angle_subset)\n        self._normalization_length = (ub - lb)\n        self._x0_subset_norm = self._x0_subset / self._normalization_length\n        self._minimum_yaw_angle_subset_norm = (\n            self._minimum_yaw_angle_subset\n            / self._normalization_length\n        )\n        self._maximum_yaw_angle_subset_norm = (\n            self._maximum_yaw_angle_subset\n            / self._normalization_length\n        )\n\n    def _calculate_farm_power(\n            self,\n            yaw_angles=None,\n            wd_array=None,\n            ws_array=None,\n            ti_array=None,\n            turbine_weights=None,\n            heterogeneous_speed_multipliers=None,\n            power_setpoints=None,\n        ):\n        \"\"\"\n        Calculate the wind farm power production assuming the predefined\n        probability distribution (self.unc_options/unc_pmf), with the\n        appropriate weighing terms, and for a specific set of yaw angles.\n\n        Args:\n            yaw_angles (iterable, optional): Array or list of yaw angles in degrees.\n                Defaults to None.\n            wd_array (iterable, optional): Array or list of wind directions in degrees.\n                Defaults to None.\n            ws_array (iterable, optional): Array or list of wind speeds in m/s. Defaults to None.\n            ti_array (iterable, optional): Array or list of turbulence intensities.\n                Defaults to None.\n            turbine_weights (iterable, optional): Array or list of weights to apply to the turbine\n                powers. Defaults to None.\n            heterogeneous_speed_multipliers (iterable, optional): Array or list of speed up factors\n                for heterogeneous inflow. Defaults to None.\n\n\n        Returns:\n            farm_power (float): Weighted wind farm power.\n        \"\"\"\n        # Unpack all variables, whichever are defined.\n        fmodel_subset = copy.deepcopy(self.fmodel_subset)\n        if wd_array is None:\n            wd_array = fmodel_subset.core.flow_field.wind_directions\n        if ws_array is None:\n            ws_array = fmodel_subset.core.flow_field.wind_speeds\n        if ti_array is None:\n            ti_array = fmodel_subset.core.flow_field.turbulence_intensities\n        if yaw_angles is None:\n            yaw_angles = self._yaw_angles_baseline_subset\n        if turbine_weights is None:\n            turbine_weights = self._turbine_weights_subset\n        if heterogeneous_speed_multipliers is not None:\n            fmodel_subset.core.flow_field.\\\n                heterogeneous_inflow_config['speed_multipliers'] = heterogeneous_speed_multipliers\n\n        # Ensure format [incompatible with _subset notation]\n        yaw_angles = self._unpack_variable(yaw_angles, subset=True)\n\n        # # Correct wind direction definition: 270 deg is from left, cw positive\n        # wd_array = wrap_360(wd_array)\n\n        # Calculate solutions\n        turbine_power = np.zeros_like(self._minimum_yaw_angle_subset[:, :])\n        fmodel_subset.set(\n            wind_directions=wd_array,\n            wind_speeds=ws_array,\n            turbulence_intensities=ti_array,\n            yaw_angles=yaw_angles,\n            power_setpoints=power_setpoints,\n        )\n        fmodel_subset.run()\n        turbine_power = fmodel_subset.get_turbine_powers()\n\n        # Multiply with turbine weighing terms\n        turbine_power_weighted = np.multiply(turbine_weights, turbine_power)\n        farm_power_weighted = np.sum(turbine_power_weighted, axis=1)\n        return farm_power_weighted\n\n    def _calculate_baseline_farm_power(self):\n        \"\"\"\n        Calculate the weighted wind farm power under the baseline turbine yaw\n        angles.\n        \"\"\"\n        if self.calc_baseline_power:\n            P = self._calculate_farm_power(self._yaw_angles_baseline_subset)\n            self._farm_power_baseline_subset = P\n            self.farm_power_baseline = P\n        else:\n            self._farm_power_baseline_subset = None\n            self.farm_power_baseline = None\n\n    def _finalize(self, farm_power_opt_subset=None, yaw_angles_opt_subset=None):\n        # Process final solutions\n        if farm_power_opt_subset is None:\n            farm_power_opt_subset = self._farm_power_opt_subset\n        if yaw_angles_opt_subset is None:\n            yaw_angles_opt_subset = self._yaw_angles_opt_subset\n\n        # Now verify solutions for convergence, if necessary\n        if self.verify_convergence:\n            yaw_angles_opt_subset, farm_power_opt_subset = (\n                self._verify_solutions_for_convergence(\n                    farm_power_opt_subset,\n                    yaw_angles_opt_subset\n                )\n            )\n\n        # Finalization step for optimization: undo reduction step\n        self.farm_power_opt = farm_power_opt_subset\n        self.yaw_angles_opt = yaw_angles_opt_subset\n\n        # Produce output table\n        df_list = []\n        df_list.append(\n            pd.DataFrame(\n                {\n                    \"wind_direction\": self.fmodel.core.flow_field.wind_directions,\n                    \"wind_speed\": self.fmodel.core.flow_field.wind_speeds,\n                    \"turbulence_intensity\": self.fmodel.core.flow_field.turbulence_intensities,\n                    \"yaw_angles_opt\": list(self.yaw_angles_opt[:, :]),\n                    \"farm_power_opt\": None\n                    if self.farm_power_opt is None\n                    else self.farm_power_opt[:],\n                    \"farm_power_baseline\": None\n                    if self.farm_power_baseline is None\n                    else self.farm_power_baseline[:],\n                }\n            )\n        )\n        df_opt = pd.concat(df_list, axis=0)\n\n        return df_opt\n\n    def _verify_solutions_for_convergence(\n        self,\n        farm_power_opt_subset,\n        yaw_angles_opt_subset,\n        min_yaw_offset=0.01,\n        min_power_gain_for_yaw=0.02,\n        verbose=True,\n    ):\n        \"\"\"\n        This function verifies whether the found solutions (yaw_angles_opt)\n        have any nonzero yaw angles that are actually a result of incorrect\n        convergence. By evaluating the power production by setting each turbine's\n        yaw angle to 0.0 deg, one by one, we verify that the found\n        optimal values do in fact lead to a nonzero power production gain.\n\n        Args:\n            farm_power_opt_subset (iterable): Array with the optimal wind\n            farm power values (i.e., farm powers with yaw_angles_opt_subset).\n            yaw_angles_opt_subset (iterable): Array with the optimal yaw angles\n            for all turbines in the farm (or for all the to-be-optimized\n            turbines in the farm). The yaw angles in this array will be\n            verified.\n            min_yaw_offset (float, optional): Values that differ by less than\n            this amount compared to the baseline value will be assumed to be\n            too small to make any notable difference. Therefore, for practical\n            reasons, the value is overwritten by its baseline value (which\n            typically is 0.0 deg). Defaults to 0.01.\n            min_power_gain_for_yaw (float, optional): The minimum percentage\n            uplift a turbine must create in the farm power production for its\n            yaw offset to be considered non negligible. Set to 0.0 to ignore\n            this criteria. Defaults to 0.02 (implying 0.02%).\n            verbose (bool, optional): Print to console. Defaults to True.\n        Returns:\n            x_opt (iterable): Array with the optimal yaw angles, possibly\n            with certain values being set to 0.0 deg as they were found\n            to be a result of incorrect convergence. If the optimization\n            has perfectly converged, x_opt will be identical to the user-\n            provided input yaw_angles_opt.\n        \"\"\"\n\n        print(\"Verifying convergence of the found optimal yaw angles.\")\n\n        # Start timer\n        start_time = timerpc()\n\n        # Define variables locally\n        yaw_angles_opt_subset = np.array(yaw_angles_opt_subset, copy=True)\n        yaw_angles_baseline_subset = self._yaw_angles_baseline_subset\n        farm_power_baseline_subset = self._farm_power_baseline_subset\n        turbs_to_opt_subset = self._turbs_to_opt_subset\n\n        # Round small nonzero yaw angles to zero\n        ydiff = np.abs(yaw_angles_opt_subset - yaw_angles_baseline_subset)\n        ids = np.where((ydiff < min_yaw_offset) & (ydiff > 0.0))\n        if len(ids[0]) > 0:\n            if verbose:\n                print(f\"Rounding {len(ids)} insignificant yaw angles to their baseline value.\")\n            yaw_angles_opt_subset[ids] = yaw_angles_baseline_subset[ids]\n            ydiff[ids] = 0.0\n\n        # Turbines to test whether their angles sufficiently improve farm power\n        ids = np.where((turbs_to_opt_subset) & (ydiff > min_yaw_offset))\n\n        # Define situations that need to be calculated and find farm power.\n        # Each situation basically contains the exact same conditions as the\n        # baseline conditions and optimal yaw angles, besides for a single\n        # turbine for which its yaw angle was set to its baseline value (\n        # typically 0.0 deg). This way, we investigate whether the yaw offset\n        # of that turbine really adds significant uplift to the farm power\n        # production.\n\n        # For each turbine in the farm, reset its values to baseline. Thus,\n        # we copy the atmospheric conditions n_turbs times and for each\n        # copy of atmospheric conditions, we reset that turbine's yaw angle\n        # to its baseline value for all conditions.\n        n_turbs = len(self.fmodel.layout_x)\n        sp = (n_turbs, 1)  # Tile shape for matrix expansion\n        wd_array_nominal = self.fmodel_subset.core.flow_field.wind_directions\n        ws_array_nominal = self.fmodel_subset.core.flow_field.wind_speeds\n        ti_array_nominal = self.fmodel_subset.core.flow_field.turbulence_intensities\n        n_wind_directions = len(wd_array_nominal)\n        yaw_angles_verify = np.tile(yaw_angles_opt_subset, sp)\n        yaw_angles_bl_verify = np.tile(yaw_angles_baseline_subset, sp)\n        turbine_id_array = np.zeros(np.shape(yaw_angles_verify)[0], dtype=int)\n        for ti in range(n_turbs):\n            ids = ti * n_wind_directions + np.arange(n_wind_directions)\n            yaw_angles_verify[ids, ti] = yaw_angles_bl_verify[ids, ti]\n            turbine_id_array[ids] = ti\n\n        # Now evaluate all situations\n        farm_power_baseline_verify = np.tile(farm_power_baseline_subset, (n_turbs))\n        farm_power = self._calculate_farm_power(\n            yaw_angles=yaw_angles_verify,\n            wd_array=np.tile(wd_array_nominal, n_turbs),\n            ws_array=np.tile(ws_array_nominal, n_turbs),\n            ti_array=np.tile(ti_array_nominal, n_turbs),\n            turbine_weights=np.tile(self._turbs_to_opt_subset, sp)\n        )\n\n        # Calculate power uplift for optimal solutions\n        uplift_o = 100 * (\n            np.tile(farm_power_opt_subset, (n_turbs)) /\n            farm_power_baseline_verify - 1.0\n        )\n\n        # Calculate power uplift for all cases we evaluated\n        uplift_n = 100.0 * (farm_power / farm_power_baseline_verify - 1.0)\n\n        # Check difference in uplift, where each row represents a different\n        # situation (i.e., where one turbine was set to its baseline yaw angle\n        # instead of its optimal yaw angle).\n        dp = uplift_o - uplift_n\n        ids_to_simplify = np.where(dp < min_power_gain_for_yaw)\n        ids_to_simplify = (\n            np.remainder(ids_to_simplify[0], n_wind_directions),  # Wind direction identifier\n            turbine_id_array[ids_to_simplify[0]],  # Turbine identifier\n        )\n\n        # Overwrite yaw angles that insufficiently increased farm power with baseline values\n        yaw_angles_opt_subset[ids_to_simplify] = (\n            yaw_angles_baseline_subset[ids_to_simplify]\n        )\n\n        n = len(ids_to_simplify[0])\n        if n > 0:\n            # Yaw angles notably changed: recalculate farm powers\n            farm_power_opt_subset_new = (\n                self._calculate_farm_power(yaw_angles_opt_subset)\n            )\n\n            if verbose:\n                # Calculate old uplift for all conditions\n                dP_old = 100.0 * (\n                    farm_power_opt_subset /\n                    farm_power_baseline_subset\n                ) - 100.0\n\n                # Calculate new uplift for all conditions\n                dP_new = 100.0 * (\n                    farm_power_opt_subset_new /\n                    farm_power_baseline_subset\n                ) - 100.0\n\n                # Calculate differences in power uplift\n                diff_uplift = dP_old - dP_new\n                ids_max_loss = np.where(np.nanmax(diff_uplift) == diff_uplift)\n                jj = (ids_max_loss[0][0], ids_max_loss[1][0])\n                ws_array_nominal = self.fmodel_subset.core.flow_field.wind_speeds\n                print(\n                    \"Nullified the optimal yaw offset for {:d}\".format(n) +\n                    \" conditions and turbines.\"\n                )\n                print(\n                    \"Simplifying the yaw angles for these conditions lead \" +\n                    \"to a maximum change in wake-steering power uplift from \"\n                    + \"{:.5f}% to {:.5f}% at \".format(dP_old[jj], dP_new[jj])\n                    + \" WD = {:.1f} deg and WS = {:.1f} m/s.\".format(\n                        wd_array_nominal[jj[0]], ws_array_nominal[jj[1]],\n                    )\n                )\n\n                t = timerpc() - start_time\n                print(\n                    \"Time spent to verify the convergence of the optimal \" +\n                    \"yaw angles: {:.3f} s.\".format(t)\n                )\n\n            # Return optimal solutions to the user\n            farm_power_opt_subset = farm_power_opt_subset_new\n\n        return yaw_angles_opt_subset, farm_power_opt_subset\n\n    # Supporting functions\n    def _norm(self, val, x1, x2):\n        \"\"\"\n        Normalize a variable to a value range.\n\n        Args:\n            val ([float]): Value to normalize.\n            x1 ([float]): Normalization lower bound.\n            x2 ([float]): Normalization upper bound.\n\n        Returns:\n            val_norm: Normalized variable.\n        \"\"\"\n        return (val - x1) / (x2 - x1)\n\n    def _unnorm(self, val_norm, x1, x2):\n        \"\"\"\n        Unnormalize a variable to a value range.\n\n        Args:\n            val_norm ([float]): Normalized value.\n            x1 ([float]): Normalization lower bound.\n            x2 ([float]): Normalization upper bound.\n\n        Returns:\n            val: Unnormalized variable.\n        \"\"\"\n        return np.array(val_norm) * (x2 - x1) + x1\n"
  },
  {
    "path": "floris/optimization/yaw_optimization/yaw_optimization_tools.py",
    "content": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\n\n\ndef derive_downstream_turbines(fmodel, wind_direction, wake_slope=0.30, plot_lines=False):\n    \"\"\"Determine which turbines have no effect on other turbines in the\n    farm, i.e., which turbines have wakes that do not impact the other\n    turbines in the farm. This allows the user to exclude these turbines\n    from a control setpoint optimization, for example. This function\n    assumes a very simplified wake function where the wakes are assumed\n    to have a linearly diverging profile. In comparisons with the FLORIS\n    GCH model, the wake_slope matches well with the FLORIS' wake profiles\n    for a value of wake_slope = 0.5 * turbulence_intensity, where\n    turbulence_intensity is an input to the FLORIS model at the default\n    GCH parameterization. Note that does not include wind direction variability.\n    To be conservative, the user is recommended to use the rule of thumb:\n    `wake_slope = turbulence_intensity`. Hence, the default value for\n    `wake_slope=0.30` should be conservative for turbulence intensities up to\n    0.30 and is likely to provide valid estimates of which turbines are\n    downstream until a turbulence intensity of 0.50. This simple model saves\n    time compared to FLORIS.\n\n    Args:\n        fmodel (FlorisModel): A FlorisModel object.\n        wind_direction (float): The wind direction in the FLORIS frame\n        of reference for which the downstream turbines are to be determined.\n        wake_slope (float, optional): linear slope of the wake (dy/dx)\n        plot_lines (bool, optional): Enable plotting wakes/turbines.\n        Defaults to False.\n\n    Returns:\n        turbs_downstream (iterable): A list containing the turbine\n        numbers that have a wake that does not affect any other\n        turbine inside the farm.\n    \"\"\"\n\n    # Get farm layout\n    x = fmodel.layout_x\n    y = fmodel.layout_y\n    D = np.ones_like(x) * fmodel.core.farm.rotor_diameters_sorted[0][0]\n    n_turbs = len(x)\n\n    # Rotate farm and determine freestream/waked turbines\n    is_downstream = [False for _ in range(n_turbs)]\n    x_rot = (\n        np.cos((wind_direction - 270.0) * np.pi / 180.0) * x\n        - np.sin((wind_direction - 270.0) * np.pi / 180.0) * y\n    )\n    y_rot = (\n        np.sin((wind_direction - 270.0) * np.pi / 180.0) * x\n        + np.cos((wind_direction - 270.0) * np.pi / 180.0) * y\n    )\n\n    if plot_lines:\n        fig, ax = plt.subplots()\n        for ii in range(n_turbs):\n            ax.plot(\n                x_rot[ii] * np.ones(2),\n                [y_rot[ii] - D[ii] / 2, y_rot[ii] + D[ii] / 2],\n                \"k\",\n            )\n        for ii in range(n_turbs):\n            ax.text(x_rot[ii], y_rot[ii], \"T%03d\" % ii)\n        ax.axis(\"equal\")\n\n    srt = np.argsort(x_rot)\n    x_rot_srt = x_rot[srt]\n    y_rot_srt = y_rot[srt]\n    for ii in range(n_turbs):\n        x0 = x_rot_srt[ii]\n        y0 = y_rot_srt[ii]\n\n        def wake_profile_ub_turbii(x):\n            y = (y0 + D[ii]) + (x - x0) * wake_slope\n            if isinstance(y, (float, np.float64, np.float32)):\n                if x < (x0 + 0.01):\n                    y = -np.inf\n            else:\n                y[x < x0 + 0.01] = -np.inf\n            return y\n\n        def wake_profile_lb_turbii(x):\n            y = (y0 - D[ii]) - (x - x0) * wake_slope\n            if isinstance(y, (float, np.float64, np.float32)):\n                if x < (x0 + 0.01):\n                    y = -np.inf\n            else:\n                y[x < x0 + 0.01] = -np.inf\n            return y\n\n        def determine_if_in_wake(xt, yt):\n            return (yt < wake_profile_ub_turbii(xt)) & (yt > wake_profile_lb_turbii(xt))\n\n        is_downstream[ii] = not any(\n            determine_if_in_wake(x_rot_srt[iii], y_rot_srt[iii]) for iii in range(n_turbs)\n        )\n\n        if plot_lines:\n            x1 = np.max(x_rot_srt) + 500.0\n            ax.fill_between(\n                [x0, x1, x1, x0],\n                [\n                    wake_profile_ub_turbii(x0 + 0.02),\n                    wake_profile_ub_turbii(x1),\n                    wake_profile_lb_turbii(x1),\n                    wake_profile_lb_turbii(x0 + 0.02),\n                ],\n                alpha=0.1,\n                color=\"k\",\n                edgecolor=None,\n            )\n\n    usrt = np.argsort(srt)\n    is_downstream = [is_downstream[i] for i in usrt]\n    turbs_downstream = list(np.where(is_downstream)[0])\n\n    if plot_lines:\n        ax.set_title(\"wind_direction = %03d\" % wind_direction)\n        ax.set_xlim([np.min(x_rot) - 500.0, x1])\n        ax.set_ylim([np.min(y_rot) - 500.0, np.max(y_rot) + 500.0])\n        ax.plot(\n            x_rot[turbs_downstream],\n            y_rot[turbs_downstream],\n            \"o\",\n            color=\"green\",\n        )\n\n    return turbs_downstream\n"
  },
  {
    "path": "floris/optimization/yaw_optimization/yaw_optimizer_geometric.py",
    "content": "\nimport numpy as np\n\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DISABLED\nfrom floris.utilities import rotate_coordinates_rel_west\n\nfrom .yaw_optimization_base import YawOptimization\n\n\nclass YawOptimizationGeometric(YawOptimization):\n    \"\"\"\n    YawOptimizationGeometric is a subclass of\n    :py:class:`floris.optimization.general_library.YawOptimization` that is\n    used to provide a rough estimate of optimal yaw angles based purely on the\n    wind farm geometry. Main use case is for coupled layout and yaw optimization.\n\n    See Stanley et al. (2023) for details: https://wes.copernicus.org/articles/8/1341/2023/\n    \"\"\"\n\n    def __init__(\n        self,\n        fmodel,\n        minimum_yaw_angle=0.0,\n        maximum_yaw_angle=25.0,\n    ):\n        \"\"\"\n        Instantiate YawOptimizationGeometric object with a FlorisModel\n        object assign parameter values.\n        \"\"\"\n\n        super().__init__(\n            fmodel=fmodel,\n            minimum_yaw_angle=minimum_yaw_angle,\n            maximum_yaw_angle=maximum_yaw_angle,\n            calc_baseline_power=False\n        )\n\n    def optimize(self):\n        \"\"\"\n        Find rough yaw angles based on wind farm geometry.\n        Assumes all wind turbines have the same rotor diameter.\n\n        Returns:\n            opt_yaw_angles (np.array): Optimal yaw angles in degrees. This\n            array is equal in length to the number of turbines in the farm.\n        \"\"\"\n        # Loop through every WD individually. WS ignored!\n        wd_array = self.fmodel_subset.core.flow_field.wind_directions\n\n        active_turbines = self.fmodel_subset.core.farm.power_setpoints > POWER_SETPOINT_DISABLED\n        for nwdi, wd in enumerate(wd_array):\n            self._yaw_angles_opt_subset[nwdi, active_turbines[nwdi]] = geometric_yaw(\n                self.fmodel_subset.layout_x[active_turbines[nwdi]],\n                self.fmodel_subset.layout_y[active_turbines[nwdi]],\n                wd,\n                self.fmodel.core.farm.turbine_definitions[0][\"rotor_diameter\"],\n                top_left_yaw_upper=self.maximum_yaw_angle[0, 0],\n                bottom_left_yaw_upper=self.maximum_yaw_angle[0, 0],\n                top_left_yaw_lower=self.minimum_yaw_angle[0, 0],\n                bottom_left_yaw_lower=self.minimum_yaw_angle[0, 0],\n            )\n\n        # Finalize optimization, i.e., retrieve full solutions\n        df_opt = self._finalize()\n\n        # Otherwise, df_opt will just copy the farm_power_baseline in\n        return df_opt\n\ndef geometric_yaw(\n    turbine_x,\n    turbine_y,\n    wind_direction,\n    rotor_diameter,\n    left_x=0.0,\n    top_left_y=1.0,\n    right_x=25.0,\n    top_right_y=1.0,\n    top_left_yaw_upper=30.0,\n    top_right_yaw_upper=0.0,\n    bottom_left_yaw_upper=30.0,\n    bottom_right_yaw_upper=0.0,\n    top_left_yaw_lower=-30.0,\n    top_right_yaw_lower=0.0,\n    bottom_left_yaw_lower=-30.0,\n    bottom_right_yaw_lower=0.0,\n):\n    \"\"\"\n    Main function to compute geometric yaw angles based on wind farm layout for a single wind\n    direction.\n\n    Arguments:\n        turbine_x: unrotated x turbine coords\n        turbine_y: unrotated y turbine coords\n        wind_direction: float, degrees\n        rotor_diameter: float\n        left_x: where we start the trapezoid. Should be left as 0.\n        top_left_y: trapezoid top left coord\n        right_x: where to stop the trapezoid downstream.\n            Max coord after which the upstream turbine won't yaw.\n        top_right_y: trapezoid top right coord\n        top_left_yaw_upper: yaw angle associated with top left point (upper trapezoid)\n        top_right_yaw_upper: yaw angle associated with top right point\n        bottom_left_yaw_upper: yaw angle associated with bottom left point\n        bottom_right_yaw_upper: yaw angle associated with bottom right point\n        top_left_yaw_lower: yaw angle associated with top left point (lower trapezoid)\n        top_right_yaw_lower: yaw angle associated with top right point\n        bottom_left_yaw_lower: yaw angle associated with bottom left point\n        bottom_right_yaw_lower: yaw angle associated with bottom right point\n\n    Returns:\n        yaw_array: yaw angles for all turbines for the present wind direction.\n    \"\"\"\n\n    nturbs = len(turbine_x)\n    turbine_coordinates_array = np.zeros((nturbs,3))\n    turbine_coordinates_array[:,0] = turbine_x[:]\n    turbine_coordinates_array[:,1] = turbine_y[:]\n\n    rotated_x, rotated_y, _, _, _ = rotate_coordinates_rel_west(\n        np.array([wind_direction]),\n        turbine_coordinates_array\n    )\n    processed_x, processed_y = _process_layout(rotated_x[0], rotated_y[0], rotor_diameter)\n    yaw_array = np.zeros(nturbs)\n    for i in range(nturbs):\n        # TODO: fix shape of top left yaw etc?\n        yaw_array[i] = _get_yaw_angles(\n            processed_x[i],\n            processed_y[i],\n            left_x,\n            top_left_y,\n            right_x,\n            top_right_y,\n            top_left_yaw_upper,\n            top_right_yaw_upper,\n            bottom_left_yaw_upper,\n            bottom_right_yaw_upper,\n            top_left_yaw_lower,\n            top_right_yaw_lower,\n            bottom_left_yaw_lower,\n            bottom_right_yaw_lower,\n        )\n\n    return yaw_array\n\ndef _process_layout(\n    turbine_x,\n    turbine_y,\n    rotor_diameter,\n    spread=0.1\n):\n    \"\"\"\n    Returns the distance from each turbine to the nearest downstream waked turbine\n    normalized by the rotor diameter. Right now \"waked\" is determined by a Jensen-like\n    wake spread, but this could/should be modified to be the same as the trapezoid rule\n    used to determine the yaw angles.\n\n    Arguments:\n        turbine_x: turbine x coords (rotated)\n        turbine_y: turbine y coords (rotated)\n        rotor_diameter: turbine rotor diameter (float)\n        spread=0.1: Jensen alpha wake spread value\n\n    Returns:\n        dx: distance to nearest downstream turbine in rotor diameters for all turbines\n        dy: lateral distance to nearest downstream turbine in rotor diameters for all turbines\n    \"\"\"\n\n    # Compute distances\n    x_dists = turbine_x.reshape(-1,1).T - turbine_x.reshape(-1,1)\n    y_dists = turbine_y.reshape(-1,1).T - turbine_y.reshape(-1,1)\n\n    # Any turbines upstream or at the turbine location are ineligible\n    x_dists[x_dists <= 0.] = np.inf\n\n    # Check within Jensen model spread\n    in_Jensen_wake = (abs(y_dists) < spread * x_dists + rotor_diameter/2.0)\n    x_dists[~in_Jensen_wake] = np.inf\n\n    # Get minimums (and arguments to select the correct y values also)\n    dx = x_dists.min(axis=1)\n    dy = y_dists[range(len(turbine_x)), x_dists.argmin(axis=1)]\n\n    return dx/rotor_diameter, dy/rotor_diameter\n\n\ndef _get_yaw_angles(\n    x,\n    y,\n    left_x,\n    top_left_y,\n    right_x,\n    top_right_y,\n    top_left_yaw_upper,\n    top_right_yaw_upper,\n    bottom_left_yaw_upper,\n    bottom_right_yaw_upper,\n    top_left_yaw_lower,\n    top_right_yaw_lower,\n    bottom_left_yaw_lower,\n    bottom_right_yaw_lower\n):\n    \"\"\"\n    For a given turbine, return the geometric yaw angle based on its position relative to the\n    nearest downstream turbine.\n\n    Arguments:\n        x: downstream distance to the nearest downstream turbine in rotor diameters with\n        turbines rotated so wind is coming left to right\n        y: lateral distance to the nearest downstream turbine in rotor diameters with\n        turbines rotated so wind is coming left to right\n        left_x: where we start the trapezoid. Should be left as 0.\n        top_left_y: trapezoid top left coord\n        right_x: where to stop the trapezoid downstream.\n            Max coord after which the upstream turbine won't yaw.\n        top_right_y: trapezoid top right coord\n        top_left_yaw_upper: yaw angle associated with top left point (upper trapezoid)\n        top_right_yaw_upper: yaw angle associated with top right point\n        bottom_left_yaw_upper: yaw angle associated with bottom left point\n        bottom_right_yaw_upper: yaw angle associated with bottom right point\n        top_left_yaw_lower: yaw angle associated with top left point (lower trapezoid)\n        top_right_yaw_lower: yaw angle associated with top right point\n        bottom_left_yaw_lower: yaw angle associated with bottom left point\n        bottom_right_yaw_lower: yaw angle associated with bottom right point\n\n    Returns:\n        (yaw angle): float, geometric yaw angle for the given turbine\n    \"\"\"\n\n    dx = (x-left_x)/(right_x-left_x)\n    if dx >= 1.0:\n        return 0.0\n    edge_y = top_left_y + (top_right_y-top_left_y)*dx\n    if abs(y) > edge_y:\n        return 0.0\n    elif y >= -0.01: # Tolerance to handle numerical issues\n        top_yaw = top_left_yaw_upper + (top_right_yaw_upper-top_left_yaw_upper)*dx\n        bottom_yaw = bottom_left_yaw_upper + (bottom_right_yaw_upper-bottom_left_yaw_upper)*dx\n        return bottom_yaw + (top_yaw-bottom_yaw)*abs(y)/edge_y\n    elif y < -0.01:\n        top_yaw = top_left_yaw_lower + (top_right_yaw_lower-top_left_yaw_lower)*dx\n        bottom_yaw = bottom_left_yaw_lower + (bottom_right_yaw_lower-bottom_left_yaw_lower)*dx\n        return bottom_yaw + (top_yaw-bottom_yaw)*abs(y)/edge_y\n"
  },
  {
    "path": "floris/optimization/yaw_optimization/yaw_optimizer_scipy.py",
    "content": "\nimport numpy as np\nfrom scipy.optimize import minimize\n\nfrom .yaw_optimization_base import YawOptimization\n\n\nclass YawOptimizationScipy(YawOptimization):\n    \"\"\"\n    YawOptimizationScipy is a subclass of\n    :py:class:`floris.optimization.general_library.YawOptimization` that is\n    used to optimize the yaw angles of all turbines in a Floris Farm for a single\n    set of inflow conditions using the SciPy optimize package.\n    \"\"\"\n\n    def __init__(\n        self,\n        fmodel,\n        minimum_yaw_angle=0.0,\n        maximum_yaw_angle=25.0,\n        yaw_angles_baseline=None,\n        x0=None,\n        opt_method=\"SLSQP\",\n        opt_options=None,\n        turbine_weights=None,\n        exclude_downstream_turbines=True,\n        verify_convergence=False,\n    ):\n        \"\"\"\n        Instantiate YawOptimizationScipy object with a FlorisModel object\n        and assign parameter values.\n        \"\"\"\n        valid_op_models = [\"cosine-loss\"]\n        if fmodel.get_operation_model() not in valid_op_models:\n            raise ValueError(\n                \"YawOptimizationScipy is currently limited to the following operation models: \"\n                + \", \".join(valid_op_models)\n            )\n        if opt_options is None:\n            # Default SciPy parameters\n            opt_options = {\n                \"maxiter\": 100,\n                \"disp\": True,\n                \"iprint\": 2,\n                \"ftol\": 1e-12,\n                \"eps\": 0.1,\n            }\n\n        super().__init__(\n            fmodel=fmodel,\n            minimum_yaw_angle=minimum_yaw_angle,\n            maximum_yaw_angle=maximum_yaw_angle,\n            yaw_angles_baseline=yaw_angles_baseline,\n            x0=x0,\n            turbine_weights=turbine_weights,\n            normalize_control_variables=True,\n            calc_baseline_power=True,\n            exclude_downstream_turbines=exclude_downstream_turbines,\n            verify_convergence=verify_convergence,\n        )\n\n        self.opt_method = opt_method\n        self.opt_options = opt_options\n\n    def optimize(self):\n        \"\"\"\n        Find optimum setting of turbine yaw angles for a single turbine\n        cluster that maximizes the weighted wind farm power production\n        given fixed atmospheric conditions (wind speed, direction, etc.)\n        using the scipy.optimize.minimize function.\n\n        Returns:\n            opt_yaw_angles (np.array): Optimal yaw angles in degrees. This\n            array is equal in length to the number of turbines in the farm.\n        \"\"\"\n        # Loop through every wind condition individually\n        wd_array = self.fmodel_subset.core.flow_field.wind_directions\n        ws_array = self.fmodel_subset.core.flow_field.wind_speeds\n        ti_array = self.fmodel_subset.core.flow_field.turbulence_intensities\n        for i, (wd, ws, ti) in enumerate(zip(wd_array, ws_array, ti_array)):\n\n            self.fmodel_subset.set(\n                wind_directions=[wd],\n                wind_speeds=[ws],\n                turbulence_intensities=[ti]\n            )\n\n\n            # Find turbines to optimize\n            turbs_to_opt = self._turbs_to_opt_subset[i, :]\n            if not any(turbs_to_opt):\n                continue  # Nothing to do here: no turbines to optimize\n\n            # Extract current optimization problem variables (normalized)\n            yaw_lb = self._minimum_yaw_angle_subset_norm[i, turbs_to_opt]\n            yaw_ub = self._maximum_yaw_angle_subset_norm[i, turbs_to_opt]\n            bnds = [(a, b) for a, b in zip(yaw_lb, yaw_ub)]\n            x0 = self._x0_subset_norm[i, turbs_to_opt]\n\n            J0 = self._farm_power_baseline_subset[i]\n            yaw_template = self._yaw_angles_template_subset[i, :]\n            turbine_weights = self._turbine_weights_subset[i, :]\n            yaw_template = np.tile(yaw_template, (1, 1))\n            turbine_weights = np.tile(turbine_weights, (1, 1))\n\n            # Handle heterogeneous inflow, if there is one\n            if (hasattr(self.fmodel.core.flow_field, 'heterogeneous_inflow_config') and\n                self.fmodel.core.flow_field.heterogeneous_inflow_config is not None):\n                het_sm_orig = np.array(\n                    self.fmodel.core.flow_field.heterogeneous_inflow_config['speed_multipliers']\n                )\n                het_sm = het_sm_orig[i, :].reshape(1, -1)\n            else:\n                het_sm = None\n\n            # Define cost function\n            def cost(x):\n                x_full = np.array(yaw_template, copy=True)\n                x_full[0, turbs_to_opt] = x * self._normalization_length\n                return (\n                    - 1.0 * self._calculate_farm_power(\n                        yaw_angles=x_full,\n                        wd_array=[wd],\n                        ws_array=[ws],\n                        ti_array=[ti],\n                        turbine_weights=turbine_weights,\n                        heterogeneous_speed_multipliers=het_sm\n                    )[0] / J0\n                )\n\n            # Perform optimization\n            residual_plant = minimize(\n                fun=cost,\n                x0=x0,\n                bounds=bnds,\n                method=self.opt_method,\n                options=self.opt_options,\n            )\n\n            # Undo normalization/masks and save results to self\n            self._farm_power_opt_subset[i] = -residual_plant.fun * J0\n            self._yaw_angles_opt_subset[i, turbs_to_opt] = (\n                residual_plant.x * self._normalization_length\n            )\n\n        # Finalize optimization, i.e., retrieve full solutions\n        df_opt = self._finalize()\n        return df_opt\n"
  },
  {
    "path": "floris/optimization/yaw_optimization/yaw_optimizer_sr.py",
    "content": "\nimport copy\nimport warnings\nfrom time import perf_counter as timerpc\n\nimport numpy as np\nimport pandas as pd\n\nfrom floris.logging_manager import LoggingManager\n\n# from .yaw_optimizer_scipy import YawOptimizationScipy\nfrom .yaw_optimization_base import YawOptimization\n\n\nclass YawOptimizationSR(YawOptimization, LoggingManager):\n    \"\"\"\n    Optimize yaw angles using the Serial Refine (SR) optimization method.\n\n    See :cite:`fleming_sr_2022` for full details on the SR method.\n    \"\"\"\n    def __init__(\n        self,\n        fmodel,\n        minimum_yaw_angle=0.0,\n        maximum_yaw_angle=25.0,\n        yaw_angles_baseline=None,\n        x0=None,\n        Ny_passes=[5, 4],  # Optimization options\n        turbine_weights=None,\n        exclude_downstream_turbines=True,\n        verify_convergence=False,\n    ):\n        \"\"\"\n        Instantiate YawOptimizationSR object with a FlorisModel object\n        and assign parameter values.\n\n        Args:\n            fmodel: An instantiated FlorisModel object.\n            minimum_yaw_angle: Minimum yaw angle for all turbines [degrees]. Default is 0.0.\n            maximum_yaw_angle: Maximum yaw angle for all turbines [degrees]. Default is 25.0.\n            yaw_angles_baseline: Yaw angles to use as a baseline for comparison to optimized\n               yaw angles [degrees]. If None, defaults to 0.0 for all turbines.\n            x0: Not used in this optimizer. Included for compatibility with base class. Defaults to\n                None.\n            Ny_passes: List of integers defining the number of yaw angles to evaluate\n                per turbine in each pass of the SR algorithm. The length of the list\n                defines the number of passes. The first entry can be even or odd,\n                but all further entries must be even. Default is [5, 4].\n            turbine_weights: Weights for each turbine when calculating the\n                weighted power output during optimization. If None, all turbines\n                are weighted equally. Default is None.\n            exclude_downstream_turbines: Not used in this optimizer. Included for compatibility with\n                base class. Default is True.\n            verify_convergence: If True, the optimizer will perform additional checks to verify\n                that the optimal yaw angles have been found. See\n                YawOptimization._verify_solutions_for_convergence() for more details.\n        \"\"\"\n\n        # Warn if non-default values are provided for unused inputs\n        if x0 is not None:\n            warnings.warn(\n                \"The 'x0' argument is not used in the Serial Refine optimization method \"\n                \"and will be ignored.\",\n                UserWarning\n            )\n\n        # Initialize base class\n        super().__init__(\n            fmodel=fmodel,\n            minimum_yaw_angle=minimum_yaw_angle,\n            maximum_yaw_angle=maximum_yaw_angle,\n            yaw_angles_baseline=yaw_angles_baseline,\n            x0=x0,\n            turbine_weights=turbine_weights,\n            calc_baseline_power=True,\n            exclude_downstream_turbines=exclude_downstream_turbines,\n            verify_convergence=verify_convergence,\n        )\n\n        # Start a timer for FLORIS computations\n        self.time_spent_in_floris = 0\n\n        # Confirm that Ny_passes are integers and odd/even\n        for Nii, Ny in enumerate(Ny_passes):\n            if not isinstance(Ny, int):\n                raise ValueError(\"Ny_passes must contain exclusively integers\")\n            if Ny < 2:\n                raise ValueError(\"Each entry in Ny_passes must have a value of at least 2.\")\n            if (Nii > 0) & ((Ny + 1) % 2 == 0):\n                raise ValueError(\n                    \"The second and further entries of Ny_passes must be even numbers. \"\n                    \"This is to ensure the same yaw angles are not evaluated twice between passes.\"\n                )\n\n        # Save optimization choices to self\n        self.Ny_passes = Ny_passes\n\n        # For each wind direction, determine the order of turbines\n        self._get_turbine_orders()\n\n    def _get_turbine_orders(self):\n        layout_x = self.fmodel.layout_x\n        layout_y = self.fmodel.layout_y\n        turbines_ordered_array = []\n        for wd in self.fmodel_subset.core.flow_field.wind_directions:\n            layout_x_rot = (\n                np.cos((wd - 270.0) * np.pi / 180.0) * layout_x\n                - np.sin((wd - 270.0) * np.pi / 180.0) * layout_y\n            )\n            turbines_ordered = np.argsort(layout_x_rot)\n            turbines_ordered_array.append(turbines_ordered)\n        self.turbines_ordered_array_subset = np.vstack(turbines_ordered_array)\n\n\n    def _calc_powers_with_memory(self, yaw_angles_subset, use_memory=True):\n        # Define current optimal solutions and floris wind directions locally\n        yaw_angles_opt_subset = self._yaw_angles_opt_subset\n        farm_power_opt_subset = self._farm_power_opt_subset\n        wd_array_subset = self.fmodel_subset.core.flow_field.wind_directions\n        ws_array_subset = self.fmodel_subset.core.flow_field.wind_speeds\n        ti_array_subset = self.fmodel_subset.core.flow_field.turbulence_intensities\n        power_setpoints_subset = self.fmodel_subset.core.farm.power_setpoints\n        turbine_weights_subset = self._turbine_weights_subset\n\n        # Reformat yaw_angles_subset, if necessary\n        eval_multiple_passes = (len(np.shape(yaw_angles_subset)) == 3)\n        if eval_multiple_passes:\n            # Four-dimensional; format everything into three-dimensional\n            Ny = yaw_angles_subset.shape[0]  # Number of passes\n            yaw_angles_subset = np.vstack(\n                [yaw_angles_subset[iii, :, :] for iii in range(Ny)]\n            )\n            yaw_angles_opt_subset = np.tile(yaw_angles_opt_subset, (Ny, 1))\n            farm_power_opt_subset = np.tile(farm_power_opt_subset, (Ny))\n            wd_array_subset = np.tile(wd_array_subset, Ny)\n            ws_array_subset = np.tile(ws_array_subset, Ny)\n            ti_array_subset = np.tile(ti_array_subset, Ny)\n            power_setpoints_subset = np.tile(power_setpoints_subset, (Ny, 1))\n            turbine_weights_subset = np.tile(turbine_weights_subset, (Ny, 1))\n\n        # Initialize empty matrix for floris farm power outputs\n        farm_powers = np.zeros((yaw_angles_subset.shape[0]))\n\n        # Find indices of yaw angles that we previously already evaluated, and\n        # prevent redoing the same calculations\n        if use_memory:\n            idx = (np.abs(yaw_angles_opt_subset - yaw_angles_subset) < 0.01).all(axis=1)\n            farm_powers[idx] = farm_power_opt_subset[idx]\n            if self.print_progress:\n                self.logger.info(\n                    \"Skipping {:d}/{:d} calculations: already in memory.\".format(\n                        np.sum(idx), len(idx))\n                )\n        else:\n            idx = np.zeros(yaw_angles_subset.shape[0], dtype=bool)\n\n        if not np.all(idx):\n            # Now calculate farm powers for conditions we haven't yet evaluated previously\n            start_time = timerpc()\n            if (hasattr(self.fmodel.core.flow_field, 'heterogeneous_inflow_config') and\n                self.fmodel.core.flow_field.heterogeneous_inflow_config is not None):\n                het_sm_orig = np.array(\n                    self.fmodel.core.flow_field.heterogeneous_inflow_config['speed_multipliers']\n                )\n                het_sm = np.tile(het_sm_orig, (Ny, 1))[~idx, :]\n            else:\n                het_sm = None\n            farm_powers[~idx] = self._calculate_farm_power(\n                wd_array=wd_array_subset[~idx],\n                ws_array=ws_array_subset[~idx],\n                ti_array=ti_array_subset[~idx],\n                turbine_weights=turbine_weights_subset[~idx, :],\n                yaw_angles=yaw_angles_subset[~idx, :],\n                heterogeneous_speed_multipliers=het_sm,\n                power_setpoints=power_setpoints_subset[~idx, :],\n            )\n            self.time_spent_in_floris += (timerpc() - start_time)\n\n        # Finally format solutions back to original format, if necessary\n        if eval_multiple_passes:\n            farm_powers = np.reshape(\n                farm_powers,\n                (\n                    Ny,\n                    self.fmodel_subset.core.flow_field.n_findex\n                )\n            )\n\n        return farm_powers\n\n    def _generate_evaluation_grid(self, pass_depth, turbine_depth):\n        \"\"\"\n        Calculate the yaw angles for every iteration in the SR algorithm, for turbine,\n        for every wind direction, for every wind speed, for every TI. Basically, this\n        should yield a grid of yaw angle sets to evaluate the wind farm AEP with 'Ny'\n        times. Then, for each ambient condition set,\n        \"\"\"\n\n        # Initialize yaw angles to evaluate, 'Ny' times the wind rose\n        Ny = self.Ny_passes[pass_depth]\n        evaluation_grid = np.tile(self._yaw_angles_opt_subset, (Ny, 1, 1))\n\n        # Get a list of the turbines in order of x and sort front to back\n        for iw in range(self._n_findex_subset):\n            turbid = self.turbines_ordered_array_subset[iw, turbine_depth]  # Turbine to manipulate\n\n            # Grab yaw bounds from self\n            yaw_lb = self._yaw_lbs[iw, turbid]\n            yaw_ub = self._yaw_ubs[iw, turbid]\n\n            # Saturate to allowable yaw limits\n            yaw_lb = np.clip(\n                yaw_lb,\n                self.minimum_yaw_angle[iw, turbid],\n                self.maximum_yaw_angle[iw, turbid]\n            )\n            yaw_ub = np.clip(\n                yaw_ub,\n                self.minimum_yaw_angle[iw, turbid],\n                self.maximum_yaw_angle[iw, turbid]\n            )\n\n            if pass_depth == 0:\n                # Evaluate all possible coordinates\n                yaw_angles_subset = np.linspace(yaw_lb, yaw_ub, Ny)\n            else:\n                # Remove middle point: was evaluated in previous iteration\n                c = int(Ny / 2)  # Central point (to remove)\n                ids = [*list(range(0, c)), *list(range(c + 1, Ny + 1))]\n                yaw_angles_subset = np.linspace(yaw_lb, yaw_ub, Ny + 1)[ids]\n\n            evaluation_grid[:, iw, turbid] = yaw_angles_subset\n\n        self._yaw_evaluation_grid = evaluation_grid\n        return evaluation_grid\n\n    def _process_evaluation_grid(self):\n        # Evaluate the farm AEPs for the grid of possible yaw angles\n        evaluation_grid = self._yaw_evaluation_grid\n        farm_powers = self._calc_powers_with_memory(evaluation_grid)\n        return farm_powers\n\n    def optimize(self, print_progress=True):\n        \"\"\"\n        Find the yaw angles that maximize the power production for every wind direction,\n        wind speed and turbulence intensity using the SR optimization algorithm.\n        \"\"\"\n        self.print_progress = print_progress\n\n        # For each pass, from front to back\n        ii = 0\n        for Nii in range(len(self.Ny_passes)):\n            # Disturb yaw angles for one turbine at a time, from front to back\n            for turbine_depth in range(self.nturbs):\n                p = 100.0 * ii / (len(self.Ny_passes) * self.nturbs)\n                ii += 1\n                if self.print_progress:\n                    print(\n                        f\"[Serial Refine] Processing pass={Nii}, \"\n                        f\"turbine_depth={turbine_depth} ({p:.1f}%)\"\n                    )\n\n                # Create grid to evaluate yaw angles for one turbine == turbine_depth\n                evaluation_grid = self._generate_evaluation_grid(\n                    pass_depth=Nii,\n                    turbine_depth=turbine_depth\n                )\n\n                # Evaluate grid of yaw angles, get farm powers and find optimal solutions\n                farm_powers = self._process_evaluation_grid()\n\n                # If farm powers contains any nans, then issue a warning\n                if np.any(np.isnan(farm_powers)):\n                    err_msg = (\n                        \"NaNs found in farm powers during SerialRefine \"\n                        \"optimization routine. Proceeding to maximize over yaw \"\n                        \"settings that produce valid powers.\"\n                    )\n                    self.logger.warning(err_msg, stack_info=True)\n\n                # Find optimal solutions in new evaluation grid\n                args_opt = np.expand_dims(np.nanargmax(farm_powers, axis=0), axis=0)\n                farm_powers_opt_new = np.squeeze(\n                    np.take_along_axis(farm_powers, args_opt, axis=0),\n                    axis=0,\n                )\n                yaw_angles_opt_new = np.squeeze(\n                    np.take_along_axis(\n                        evaluation_grid,\n                        np.expand_dims(args_opt, axis=2),\n                        axis=0\n                    ),\n                    axis=0\n                )\n\n                farm_powers_opt_prev = self._farm_power_opt_subset\n                yaw_angles_opt_prev = self._yaw_angles_opt_subset\n\n                # Now update optimal farm powers if better than previous\n                ids_better = (farm_powers_opt_new > farm_powers_opt_prev)\n                farm_power_opt = farm_powers_opt_prev\n                farm_power_opt[ids_better] = farm_powers_opt_new[ids_better]\n\n                # Now update optimal yaw angles if better than previous\n                turbs_sorted = self.turbines_ordered_array_subset\n                turbids = turbs_sorted[np.where(ids_better)[0], turbine_depth]\n                ids = (*np.where(ids_better), turbids)\n                yaw_angles_opt = yaw_angles_opt_prev\n                yaw_angles_opt[ids] = yaw_angles_opt_new[ids]\n\n                # Update bounds for next iteration to close proximity of optimal solution\n                dx = (\n                    evaluation_grid[1, :, :] -\n                    evaluation_grid[0, :, :]\n                )[ids]\n                self._yaw_lbs[ids] = np.clip(\n                    yaw_angles_opt[ids] - 0.50 * dx,\n                    self._minimum_yaw_angle_subset[ids],\n                    self._maximum_yaw_angle_subset[ids]\n                )\n                self._yaw_ubs[ids] = np.clip(\n                    yaw_angles_opt[ids] + 0.50 * dx,\n                    self._minimum_yaw_angle_subset[ids],\n                    self._maximum_yaw_angle_subset[ids]\n                )\n\n                # Save results to self\n                self._farm_power_opt_subset = farm_power_opt\n                self._yaw_angles_opt_subset = yaw_angles_opt\n\n        # Finalize optimization, i.e., retrieve full solutions\n        df_opt = self._finalize()\n        return df_opt\n"
  },
  {
    "path": "floris/par_floris_model.py",
    "content": "import copy\nfrom pathlib import Path\nfrom time import perf_counter as timerpc\n\nimport numpy as np\n\nfrom floris.core import State\nfrom floris.floris_model import FlorisModel\nfrom floris.type_dec import (\n    NDArrayFloat,\n)\nfrom floris.utilities import is_all_scalar_dict\n\n\nclass ParFlorisModel(FlorisModel):\n    \"\"\"\n    This class mimics the FlorisModel, but enables parallelization of the main\n    computational effort.\n    \"\"\"\n\n    def __init__(\n        self,\n        configuration: dict | str | Path | FlorisModel,\n        interface: str | None = \"multiprocessing\",\n        max_workers: int = -1,\n        n_wind_condition_splits: int = -1,\n        return_turbine_powers_only: bool = False,\n        print_timings: bool = False\n    ):\n        \"\"\"\n        Initialize the ParFlorisModel object.\n\n        Args:\n            configuration (:py:obj:`dict`): The Floris configuration dictionary or YAML file.\n                See floris.default_inputs.yaml for an example of the configuration dictionary\n                or visit https://nrel.github.io/floris/input_reference_main.html.\n            interface: The parallelization interface to use. Options are \"multiprocessing\",\n               \"pathos\", and \"concurrent\", with possible future support for \"mpi4py\"\n            max_workers: The maximum number of workers to use. Defaults to -1, which then\n               takes the number of CPUs available.\n            n_wind_condition_splits: The number of wind conditions to split the simulation over.\n               Defaults to the same as max_workers.\n            return_turbine_powers_only: Whether to return only the turbine powers.\n            print_timings (bool): Print the computation time to the console. Defaults to False.\n        \"\"\"\n        # Instantiate the underlying FlorisModel\n        if isinstance(configuration, FlorisModel):\n            configuration_dict = configuration.core.as_dict()\n            super().__init__(configuration_dict)\n            # Copy over any control setpoints, wind data, if not already done.\n            self.set(\n                yaw_angles=configuration.core.farm.yaw_angles,\n                power_setpoints=configuration.core.farm.power_setpoints,\n                awc_modes=configuration.core.farm.awc_modes,\n                awc_amplitudes=configuration.core.farm.awc_amplitudes,\n                awc_frequencies=configuration.core.farm.awc_frequencies,\n                wind_data=configuration.wind_data,\n            )\n        else:\n            super().__init__(configuration)\n\n        # Save parallelization parameters\n        if interface == \"multiprocessing\":\n            import multiprocessing as mp\n            self._PoolExecutor = mp.Pool\n            if max_workers == -1:\n                max_workers = mp.cpu_count()\n            # TODO: test spinning up the worker pool at this point\n        elif interface == \"pathos\":\n            import pathos\n            if max_workers == -1:\n                max_workers = pathos.helpers.cpu_count()\n            self.pathos_pool = pathos.pools.ProcessPool(nodes=max_workers)\n        elif interface == \"concurrent\":\n            from concurrent.futures import ProcessPoolExecutor\n            if max_workers == -1:\n                from multiprocessing import cpu_count\n                max_workers = cpu_count()\n            self._PoolExecutor = ProcessPoolExecutor\n        elif interface in [\"mpi4py\"]:\n            raise NotImplementedError(\n                f\"Parallelization interface {interface} not yet supported.\"\n            )\n        elif interface is None:\n            self.logger.warning(\n                \"No parallelization interface specified. Running in serial mode.\"\n            )\n            if return_turbine_powers_only:\n                self.logger.warn(\n                    \"return_turbine_powers_only is not supported in serial mode.\"\n                )\n        else:\n            raise ValueError(\n                f\"Invalid parallelization interface {interface}. \"\n                \"Options are 'multiprocessing', 'pathos', or 'concurrent'.\"\n            )\n\n        self._interface = interface\n        self.max_workers = max_workers\n        if n_wind_condition_splits == -1:\n            self.n_wind_condition_splits = max_workers\n        else:\n            self.n_wind_condition_splits = n_wind_condition_splits\n        self.return_turbine_powers_only = return_turbine_powers_only\n        self.print_timings = print_timings\n\n    def run(self) -> None:\n        \"\"\"\n        Run the FLORIS model in parallel.\n        \"\"\"\n\n        if self.return_turbine_powers_only:\n            # TODO: code here that does not return flow fields\n            # Somehow, overload methods on FlorisModel that need flow field\n            # data.\n\n            # This version will call super().get_turbine_powers() on each of\n            # the splits, and return them somehow.\n            self._stored_turbine_powers = None # Temporary\n        if self.interface is None:\n            t0 = timerpc()\n            super().run()\n            t1 = timerpc()\n            self._print_timings(t0, t1, None, None)\n        else:\n            t0 = timerpc()\n            self.core.initialize_domain()\n            parallel_run_inputs = self._preprocessing()\n            t1 = timerpc()\n            if self.interface == \"multiprocessing\":\n                if self.return_turbine_powers_only:\n                    with self._PoolExecutor(self.max_workers) as p:\n                        self._turbine_powers_split = p.starmap(\n                            _parallel_run_powers_only,\n                            parallel_run_inputs\n                        )\n                else:\n                    with self._PoolExecutor(self.max_workers) as p:\n                        self._fmodels_split = p.starmap(_parallel_run, parallel_run_inputs)\n            elif self.interface == \"pathos\":\n                if self.return_turbine_powers_only:\n                    self._turbine_powers_split = self.pathos_pool.map(\n                        _parallel_run_powers_only_map,\n                        parallel_run_inputs\n                    )\n                else:\n                    self._fmodels_split = self.pathos_pool.map(\n                        _parallel_run_map,\n                        parallel_run_inputs\n                    )\n            elif self.interface == \"concurrent\":\n                if self.return_turbine_powers_only:\n                    with self._PoolExecutor(self.max_workers) as p:\n                        self._turbine_powers_split = p.map(\n                            _parallel_run_powers_only_map,\n                            parallel_run_inputs\n                        )\n                        self._turbine_powers_split = list(self._turbine_powers_split)\n                else:\n                    with self._PoolExecutor(self.max_workers) as p:\n                        self._fmodels_split = p.map(\n                            _parallel_run_map,\n                            parallel_run_inputs\n                        )\n                        self._fmodels_split = list(self._fmodels_split)\n            t2 = timerpc()\n            self._postprocessing()\n            self.core.farm.finalize(self.core.grid.unsorted_indices)\n            self.core.state = State.USED\n            t3 = timerpc()\n            self._print_timings(t0, t1, t2, t3)\n\n    def sample_flow_at_points(self, x: NDArrayFloat, y: NDArrayFloat, z: NDArrayFloat):\n        \"\"\"\n        Sample the flow field velocity at specified points.\n\n        Args:\n            x: The x-coordinates of the points.\n            y: The y-coordinates of the points.\n            z: The z-coordinates of the points.\n\n        Returns:\n            NDArrayFloat: The wind speeds at the specified points.\n        \"\"\"\n        return self._sample_value_at_points(x, y, z, value=\"velocity\")\n\n    def sample_ti_at_points(self, x: NDArrayFloat, y: NDArrayFloat, z: NDArrayFloat):\n        \"\"\"\n        Sample the turbulence intensity at specified points.\n\n        Args:\n            x: The x-coordinates of the points.\n            y: The y-coordinates of the points.\n            z: The z-coordinates of the points.\n\n        Returns:\n            NDArrayFloat: The turbulence intensity at the specified points.\n        \"\"\"\n        return self._sample_value_at_points(x, y, z, value=\"turbulence_intensity\")\n\n    def _sample_value_at_points(\n            self,\n            x: NDArrayFloat,\n            y: NDArrayFloat,\n            z: NDArrayFloat,\n            value: str\n        ):\n        \"\"\"\n        Underlying method for sample values at (x,y,z) points for ParFlorisModel.\n\n        Args:\n            x: The x-coordinates of the points.\n            y: The y-coordinates of the points.\n            z: The z-coordinates of the points.\n            value: The type of value to sample (\"velocity\" or \"turbulence_intensity\").\n\n        Returns:\n            NDArrayFloat: The values at the specified points.\n        \"\"\"\n        if self.return_turbine_powers_only:\n            raise NotImplementedError(\n                \"Sampling at points is not supported when \"\n                \"return_turbine_powers_only is set to True on ParFlorisModel.\"\n            )\n\n        valid_values = [\"velocity\", \"turbulence_intensity\"]\n        if value not in valid_values:\n            raise ValueError(\n                f\"Invalid value '{value}' for sampling. Must be one of {valid_values}.\"\n            )\n\n        if self.interface is None:\n            t0 = timerpc()\n            if value == \"velocity\":\n                output = super().sample_flow_at_points(x, y, z)\n            elif value == \"turbulence_intensity\":\n                output = super().sample_ti_at_points(x, y, z)\n            t1 = timerpc()\n            self._print_timings(t0, t1, None, None)\n        else:\n            t0 = timerpc()\n            self.core.initialize_domain()\n            parallel_run_inputs = self._preprocessing()\n            parallel_sample_flow_at_points_inputs = [\n                (fmodel_dict, set_args, x, y, z)\n                for fmodel_dict, set_args in parallel_run_inputs\n            ]\n            t1 = timerpc()\n            if value == \"velocity\":\n                _parallel_func = _parallel_sample_flow_at_points\n                _parallel_fmap = _parallel_sample_flow_at_points_map\n            elif value == \"turbulence_intensity\":\n                _parallel_func = _parallel_sample_ti_at_points\n                _parallel_fmap = _parallel_sample_ti_at_points_map\n\n            if self.interface == \"multiprocessing\":\n                with self._PoolExecutor(self.max_workers) as p:\n                    sampled_wind_speeds_p = p.starmap(\n                        _parallel_func,\n                        parallel_sample_flow_at_points_inputs\n                    )\n            elif self.interface == \"pathos\":\n                sampled_wind_speeds_p = self.pathos_pool.map(\n                    _parallel_fmap,\n                    parallel_sample_flow_at_points_inputs\n                )\n            elif self.interface == \"concurrent\":\n                with self._PoolExecutor(self.max_workers) as p:\n                    sampled_wind_speeds_p = p.map(\n                        _parallel_fmap,\n                        parallel_sample_flow_at_points_inputs\n                    )\n                    sampled_wind_speeds_p = list(sampled_wind_speeds_p)\n            t2 = timerpc()\n            output = np.concatenate(sampled_wind_speeds_p, axis=0)\n            t3 = timerpc()\n            self._print_timings(t0, t1, t2, t3)\n\n        return output\n\n    def _preprocessing(self):\n        \"\"\"\n        Prepare the input arguments for parallel execution.\n        \"\"\"\n\n        # Split over the wind conditions\n        n_wind_condition_splits = self.n_wind_condition_splits\n        n_wind_condition_splits = np.min(\n            [n_wind_condition_splits, self.core.flow_field.n_findex]\n        )\n\n        # Prepare the input arguments for parallel execution\n        fmodel_dict = self.core.as_dict()\n        wind_condition_id_splits = np.array_split(\n            np.arange(self.core.flow_field.n_findex),\n            n_wind_condition_splits,\n        )\n        multiargs = []\n        for wc_id_split in wind_condition_id_splits:\n            # for ws_id_split in wind_speed_id_splits:\n            fmodel_dict_split = copy.deepcopy(fmodel_dict)\n\n            # Extract and format all arguments that are per-findex\n            # (scalar arguments are already broadcast on fmodel_dict_split)\n            set_args_subset = {\n                \"wind_directions\": self.core.flow_field.wind_directions[wc_id_split],\n                \"wind_speeds\": self.core.flow_field.wind_speeds[wc_id_split],\n                \"turbulence_intensities\": self.core.flow_field.turbulence_intensities[wc_id_split],\n                \"yaw_angles\": self.core.farm.yaw_angles[wc_id_split, :],\n                \"power_setpoints\": self.core.farm.power_setpoints[wc_id_split, :],\n                \"awc_modes\": self.core.farm.awc_modes[wc_id_split, :],\n                \"awc_amplitudes\": self.core.farm.awc_amplitudes[wc_id_split, :],\n                \"awc_frequencies\": self.core.farm.awc_frequencies[wc_id_split, :],\n                # disable_turbines is not saved on core, but passed through power_setpoints\n            }\n\n            # Handle heterogeneous_inflow_config\n            if self.core.flow_field.heterogeneous_inflow_config is not None:\n                heterogeneous_inflow_config_subset = {\n                    \"x\": self.core.flow_field.heterogeneous_inflow_config[\"x\"],\n                    \"y\": self.core.flow_field.heterogeneous_inflow_config[\"y\"],\n                    \"speed_multipliers\": self.core.flow_field.heterogeneous_inflow_config\\\n                        [\"speed_multipliers\"][wc_id_split, :]\n                }\n                if \"z\" in self.core.flow_field.heterogeneous_inflow_config.keys():\n                    heterogeneous_inflow_config_subset[\"z\"] = \\\n                        self.core.flow_field.heterogeneous_inflow_config[\"z\"]\n                set_args_subset[\"heterogeneous_inflow_config\"] = heterogeneous_inflow_config_subset\n\n            # Handle multidim_conditions\n            if self.core.flow_field.multidim_conditions is not None:\n                if is_all_scalar_dict(self.core.flow_field.multidim_conditions):\n                    multidim_conditions_subset = self.core.flow_field.multidim_conditions\n                else:\n                    multidim_conditions_subset = {\n                        k: v[wc_id_split] for k, v in\n                        self.core.flow_field.multidim_conditions.items()\n                    }\n                set_args_subset[\"multidim_conditions\"] = multidim_conditions_subset\n\n            # Prepare lightweight data to pass along\n            multiargs.append((fmodel_dict_split, set_args_subset))\n\n        return multiargs\n\n    def _postprocessing(self):\n        # Append the remaining flow_fields\n        # Could consider adding a merge method to the FlowField class\n        # to make this easier\n\n        if self.return_turbine_powers_only:\n            self._stored_turbine_powers = np.vstack(self._turbine_powers_split)\n        else:\n            # Ensure fields to set have correct dimensions\n            self.core.flow_field.u = self._fmodels_split[0].core.flow_field.u\n            self.core.flow_field.v = self._fmodels_split[0].core.flow_field.v\n            self.core.flow_field.w = self._fmodels_split[0].core.flow_field.w\n            self.core.flow_field.turbulence_intensity_field = \\\n                self._fmodels_split[0].core.flow_field.turbulence_intensity_field\n\n            for fm in self._fmodels_split[1:]:\n                self.core.flow_field.u = np.append(\n                    self.core.flow_field.u,\n                    fm.core.flow_field.u,\n                    axis=0\n                )\n                self.core.flow_field.v = np.append(\n                    self.core.flow_field.v,\n                    fm.core.flow_field.v,\n                    axis=0\n                )\n                self.core.flow_field.w = np.append(\n                    self.core.flow_field.w,\n                    fm.core.flow_field.w,\n                    axis=0\n                )\n                self.core.flow_field.turbulence_intensity_field = np.append(\n                    self.core.flow_field.turbulence_intensity_field,\n                    fm.core.flow_field.turbulence_intensity_field,\n                    axis=0\n                )\n\n    def _print_timings(self, t0, t1, t2, t3):\n        \"\"\"\n        Print the timings for the parallel execution.\n        \"\"\"\n        if self.print_timings:\n            print(\"===============================================================================\")\n            if self.interface is None:\n                print(f\"Total time spent for serial calculation (interface=None): {t1 - t0:.3f} s\")\n            else:\n                print(\n                    \"Total time spent for parallel calculation \"\n                    f\"({self.max_workers} workers): {t3-t0:.3f} s\"\n                )\n                print(f\"  Time spent in parallel preprocessing: {t1-t0:.3f} s\")\n                print(f\"  Time spent in parallel loop execution: {t2-t1:.3f} s.\")\n                print(f\"  Time spent in parallel postprocessing: {t3-t2:.3f} s\")\n\n    def _get_turbine_powers(self):\n        \"\"\"\n        Calculates the power at each turbine in the wind farm.\n        This override will only be necessary if we want to be able to\n        use the return_turbine_powers_only option. Need to check if that\n        makes a significant speed difference.\n\n        Returns:\n            NDArrayFloat: Powers at each turbine.\n        \"\"\"\n        if self.core.state is not State.USED:\n            self.logger.warning(\n                f\"Please call `{self.__class__.__name__}.run` before computing\"\n                \" turbine powers. In future versions, an explicit run() call will\"\n                \"be required.\"\n            )\n            self.run()\n        if self.return_turbine_powers_only:\n            return self._stored_turbine_powers\n        else:\n            return super()._get_turbine_powers()\n\n    @property\n    def secondary_init_kwargs(self):\n        \"\"\"\n        ParFlorisModel secondary keyword arguments (after configuration).\n        \"\"\"\n        return {\n            \"interface\": self.interface,\n            \"max_workers\": self.max_workers,\n            \"n_wind_condition_splits\": self.n_wind_condition_splits,\n            \"return_turbine_powers_only\": self.return_turbine_powers_only,\n            \"print_timings\": self.print_timings\n        }\n\n    @property\n    def fmodel(self):\n        \"\"\"\n        Raise deprecation warning.\n        \"\"\"\n        self.logger.warning(\n            \"ParFlorisModel no longer contains `fmodel` as an attribute \"\n            \"and now directly inherits from FlorisModel. Please use the \"\n            \"attributes and methods of FlorisModel directly.\"\n        )\n\n    @property\n    def interface(self):\n        \"\"\"\n        The parallelization interface used.\n        \"\"\"\n        return self._interface\n\n    @interface.setter\n    def interface(self, value):\n        \"\"\"\n        Raise error regarding setting the interface.\n        \"\"\"\n        raise AttributeError(\n            \"The parallelization interface cannot be changed after instantiation.\"\n        )\n\ndef _parallel_run(fmodel_dict, set_kwargs) -> FlorisModel:\n    \"\"\"\n    Run the FLORIS model in parallel.\n\n    Args:\n        fmodel: The FLORIS model to run.\n        set_kwargs: Additional keyword arguments to pass to fmodel.set().\n    \"\"\"\n    fmodel = FlorisModel(fmodel_dict)\n    fmodel.set(**set_kwargs)\n    fmodel.run()\n    return fmodel\n\ndef _parallel_run_powers_only(fmodel_dict, set_kwargs) -> np.ndarray:\n    \"\"\"\n    Run the FLORIS model in parallel, returning only the turbine powers.\n\n    Args:\n        fmodel: The FLORIS model to run.\n        set_kwargs: Additional keyword arguments to pass to fmodel.set().\n    \"\"\"\n    fmodel = FlorisModel(fmodel_dict)\n    fmodel.set(**set_kwargs)\n    fmodel.run()\n    return fmodel.get_turbine_powers()\n\ndef _parallel_run_map(x):\n    \"\"\"\n    Wrapper for unpacking inputs to _parallel_run() for use with map().\n    \"\"\"\n    return _parallel_run(*x)\n\ndef _parallel_run_powers_only_map(x):\n    \"\"\"\n    Wrapper for unpacking inputs to _parallel_run_powers_only() for use with map().\n    \"\"\"\n    return _parallel_run_powers_only(*x)\n\ndef _parallel_sample_flow_at_points(fmodel_dict, set_kwargs, x, y, z):\n    fmodel = FlorisModel(fmodel_dict)\n    fmodel.set(**set_kwargs)\n    return fmodel.sample_flow_at_points(x, y, z)\n\ndef _parallel_sample_flow_at_points_map(x):\n    \"\"\"\n    Wrapper for unpacking inputs to _parallel_sample_flow_at_points() for use with map().\n    \"\"\"\n    return _parallel_sample_flow_at_points(*x)\n\ndef _parallel_sample_ti_at_points(fmodel_dict, set_kwargs, x, y, z):\n    fmodel = FlorisModel(fmodel_dict)\n    fmodel.set(**set_kwargs)\n    return fmodel.sample_ti_at_points(x, y, z)\n\ndef _parallel_sample_ti_at_points_map(x):\n    \"\"\"\n    Wrapper for unpacking inputs to _parallel_sample_ti_at_points() for use with map().\n    \"\"\"\n    return _parallel_sample_ti_at_points(*x)\n"
  },
  {
    "path": "floris/parallel_floris_model.py",
    "content": "# Copyright 2022 Shell\nimport copy\nimport warnings\nfrom time import perf_counter as timerpc\n\nimport numpy as np\nimport pandas as pd\n\nfrom floris.floris_model import FlorisModel\nfrom floris.logging_manager import LoggingManager\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\nfrom floris.uncertain_floris_model import map_turbine_values_uncertain, UncertainFlorisModel\n\n\ndef _get_turbine_powers_serial(fmodel_information, yaw_angles=None):\n    fmodel = FlorisModel(fmodel_information)\n    fmodel.set(yaw_angles=yaw_angles)\n    fmodel.run()\n    return (fmodel.get_turbine_powers(), fmodel.core.flow_field)\n\ndef _get_turbine_powers_serial_no_wake(fmodel_information, yaw_angles=None):\n    fmodel = FlorisModel(fmodel_information)\n    fmodel.set(yaw_angles=yaw_angles)\n    fmodel.run_no_wake()\n    return (fmodel.get_turbine_powers(), fmodel.core.flow_field)\n\n\ndef _optimize_yaw_angles_serial(\n    fmodel_information,\n    minimum_yaw_angle,\n    maximum_yaw_angle,\n    yaw_angles_baseline,\n    x0,\n    Ny_passes,\n    turbine_weights,\n    exclude_downstream_turbines,\n    verify_convergence,\n    print_progress,\n):\n    fmodel_opt = FlorisModel(fmodel_information)\n    yaw_opt = YawOptimizationSR(\n        fmodel=fmodel_opt,\n        minimum_yaw_angle=minimum_yaw_angle,\n        maximum_yaw_angle=maximum_yaw_angle,\n        yaw_angles_baseline=yaw_angles_baseline,\n        x0=x0,\n        Ny_passes=Ny_passes,\n        turbine_weights=turbine_weights,\n        exclude_downstream_turbines=exclude_downstream_turbines,\n        verify_convergence=verify_convergence,\n    )\n\n    # Perform optimization but silence print statements to avoid cluttering\n    df_opt = yaw_opt.optimize(print_progress=print_progress)\n    return df_opt\n\n\nclass ParallelFlorisModel(LoggingManager):\n    def __init__(\n        self,\n        fmodel,\n        max_workers,\n        n_wind_condition_splits,\n        interface=\"multiprocessing\",  # Options are 'multiprocessing', 'mpi4py' or 'concurrent'\n        use_mpi4py=None,\n        propagate_flowfield_from_workers=False,\n        print_timings=False\n    ):\n        \"\"\"A wrapper around the nominal floris_interface class that adds\n        parallel computing to common FlorisModel properties.\n\n        Args:\n        fmodel (FlorisModel object): Interactive FLORIS object used to\n            perform the wake and turbine calculations.\n        max_workers (int): Number of parallel workers, typically equal to the number of cores\n            you have on your system or HPC.\n        n_wind_condition_splits (int): Number of sectors to split the wind findex array over.\n            This is typically equal to max_workers, or a multiple of it.\n        interface (str): Parallel computing interface to leverage. Recommended is 'concurrent'\n            or 'multiprocessing' for local (single-system) use, and 'mpi4py' for high performance\n            computing on multiple nodes. Defaults to 'multiprocessing'.\n        use_mpi4py (bool): Deprecated option to enable/disable the usage of 'mpi4py'. This option\n            has been superseded by 'interface'.\n        propagate_flowfield_from_workers (bool): By enabling this, the flow field from every\n            floris object (one for each worker) is exported, combined and sent back to the main\n            module. This is slow so unless it's needed, it's recommended to be disabled. Defaults\n            to False.\n        print_timings (bool): Print the computation time to the console. Defaults to False.\n        \"\"\"\n\n        self.logger.warning((\n            \"ParallelFlorisModel is deprecated and will be removed in a future version. \"\n            \"Please switch to ParFlorisModel instead.\"\n        ))\n\n        # Set defaults for backward compatibility\n        if use_mpi4py is not None:\n            warnings.warn(\n                \"The option 'mpi4py' will be removed in a future version. \"\n                \"Please use the option 'interface'.\"\n            )\n            if use_mpi4py:\n                interface = \"mpi4py\"\n            else:\n                interface = \"multiprocessing\"\n\n        if interface == \"mpi4py\":\n            import mpi4py.futures as mp\n            self._PoolExecutor = mp.MPIPoolExecutor\n        elif interface == \"multiprocessing\":\n            import multiprocessing as mp\n            self._PoolExecutor = mp.Pool\n            if max_workers is None:\n                max_workers = mp.cpu_count()\n        elif interface == \"concurrent\":\n            from concurrent.futures import ProcessPoolExecutor\n            self._PoolExecutor = ProcessPoolExecutor\n        else:\n            raise ValueError(\n                f\"Interface '{interface}' not recognized. \"\n                \"Please use 'concurrent', 'multiprocessing' or 'mpi4py'.\"\n            )\n\n        # Raise error if uncertain model is passed in and refer to new parallel_floris_model_2\n        if isinstance(fmodel, UncertainFlorisModel):\n            raise ValueError(\n                \"UncertainFlorisModel is not supported in this version of ParallelFlorisModel. \"\n                \"Please use the new version ParFlorisModel (par_floris_model) \"\n                \"for UncertainFlorisModel compatibility.\"\n            )\n\n        # Initialize floris object and copy common properties\n        if isinstance(fmodel, FlorisModel):\n            self.fmodel = fmodel.copy()\n            self._is_uncertain = False\n        elif isinstance(fmodel, UncertainFlorisModel):\n            self.fmodel = fmodel.fmodel_expanded.copy()\n            self._is_uncertain = True\n            self._weights = fmodel.weights\n            self._n_unexpanded = fmodel.n_unexpanded\n            self._n_sample_points = fmodel.n_sample_points\n            self._map_to_expanded_inputs = fmodel.map_to_expanded_inputs\n        self.core = self.fmodel.core # Static copy as a placeholder\n\n        # Save to self\n        self._n_wind_condition_splits = n_wind_condition_splits  # Save initial user input\n        self._max_workers = max_workers  # Save initial user input\n\n        self.n_wind_condition_splits = int(\n            np.min([n_wind_condition_splits, self.fmodel.core.flow_field.n_findex])\n        )\n        self.max_workers = int(\n            np.min([max_workers, self.n_wind_condition_splits])\n        )\n        self.propagate_flowfield_from_workers = propagate_flowfield_from_workers\n        self.interface = interface\n        self.print_timings = print_timings\n\n    def copy(self):\n        # Make an independent copy\n        self_copy = copy.deepcopy(self)\n        self_copy.fmodel = self.fmodel.copy()\n        return self_copy\n\n    def set(\n        self,\n        wind_speeds=None,\n        wind_directions=None,\n        wind_shear=None,\n        wind_veer=None,\n        reference_wind_height=None,\n        turbulence_intensities=None,\n        air_density=None,\n        layout=None,\n        layout_x=None,\n        layout_y=None,\n        turbine_type=None,\n        turbine_library_path=None,\n        solver_settings=None,\n        heterogeneous_inflow_config=None,\n        wind_data=None,\n        yaw_angles=None,\n        power_setpoints=None,\n        awc_modes=None,\n        awc_amplitudes=None,\n        awc_frequencies=None,\n        disable_turbines=None,\n    ):\n        \"\"\"Pass to the FlorisModel set function. To allow users\n        to directly replace a FlorisModel object with this\n        UncertainFlorisModel object, this function is required\n\n        Args:\n            wind_speeds (NDArrayFloat | list[float] | None, optional): Wind speeds at each findex.\n                Defaults to None.\n            wind_directions (NDArrayFloat | list[float] | None, optional): Wind directions at each\n                findex. Defaults to None.\n            wind_shear (float | None, optional): Wind shear exponent. Defaults to None.\n            wind_veer (float | None, optional): Wind veer. Defaults to None.\n            reference_wind_height (float | None, optional): Reference wind height. Defaults to None.\n            turbulence_intensities (NDArrayFloat | list[float] | None, optional): Turbulence\n                intensities at each findex. Defaults to None.\n            air_density (float | None, optional): Air density. Defaults to None.\n            layout_x (NDArrayFloat | list[float] | None, optional): X-coordinates of the turbines.\n                Defaults to None.\n            layout_y (NDArrayFloat | list[float] | None, optional): Y-coordinates of the turbines.\n                Defaults to None.\n            turbine_type (list | None, optional): Turbine type. Defaults to None.\n            turbine_library_path (str | Path | None, optional): Path to the turbine library.\n                Defaults to None.\n            solver_settings (dict | None, optional): Solver settings. Defaults to None.\n            heterogeneous_inflow_config (None, optional): heterogeneous inflow configuration.\n                Defaults to None.\n            wind_data (type[WindDataBase] | None, optional): Wind data. Defaults to None.\n            yaw_angles (NDArrayFloat | list[float] | None, optional): Turbine yaw angles.\n                Defaults to None.\n            power_setpoints (NDArrayFloat | list[float] | list[float, None] | None, optional):\n                Turbine power setpoints.\n            disable_turbines (NDArrayBool | list[bool] | None, optional): NDArray with dimensions\n                n_findex x n_turbines. True values indicate the turbine is disabled at that findex\n                and the power setpoint at that position is set to 0. Defaults to None.\n\n        \"\"\"\n\n        if layout is not None:\n            msg = \"Use the `layout_x` and `layout_y` parameters in place of `layout` \"\n            msg += \"because the `layout` parameter will be deprecated in 3.3.\"\n            self.logger.warning(msg)\n            layout_x = layout[0]\n            layout_y = layout[1]\n\n        # Just passes arguments to the floris object\n        fmodel = self.fmodel.copy()\n        fmodel.set(\n            wind_speeds=wind_speeds,\n            wind_directions=wind_directions,\n            wind_shear=wind_shear,\n            wind_veer=wind_veer,\n            reference_wind_height=reference_wind_height,\n            turbulence_intensities=turbulence_intensities,\n            air_density=air_density,\n            layout_x=layout_x,\n            layout_y=layout_y,\n            turbine_type=turbine_type,\n            turbine_library_path=turbine_library_path,\n            solver_settings=solver_settings,\n            heterogeneous_inflow_config=heterogeneous_inflow_config,\n            wind_data=wind_data,\n            yaw_angles=yaw_angles,\n            power_setpoints=power_setpoints,\n            awc_modes=awc_modes,\n            awc_amplitudes=awc_amplitudes,\n            awc_frequencies=awc_frequencies,\n            disable_turbines=disable_turbines,\n        )\n\n        # Reinitialize settings\n        self.__init__(\n            fmodel=fmodel,\n            max_workers=self._max_workers,\n            n_wind_condition_splits=self._n_wind_condition_splits,\n            interface=self.interface,\n            propagate_flowfield_from_workers=self.propagate_flowfield_from_workers,\n            print_timings=self.print_timings,\n        )\n\n    def _preprocessing(self, yaw_angles=None):\n        # Format yaw angles\n        if yaw_angles is None:\n            yaw_angles = np.zeros((\n                self.fmodel.core.flow_field.n_findex,\n                self.fmodel.core.farm.n_turbines\n            ))\n\n        # Prepare settings\n        n_wind_condition_splits = self.n_wind_condition_splits\n        n_wind_condition_splits = np.min(\n            [n_wind_condition_splits, self.fmodel.core.flow_field.n_findex]\n        )\n\n        # Prepare the input arguments for parallel execution\n        fmodel_dict = self.fmodel.core.as_dict()\n        wind_condition_id_splits = np.array_split(\n            np.arange(self.fmodel.core.flow_field.n_findex),\n            n_wind_condition_splits,\n        )\n        multiargs = []\n        for wc_id_split in wind_condition_id_splits:\n            # for ws_id_split in wind_speed_id_splits:\n            fmodel_dict_split = copy.deepcopy(fmodel_dict)\n            wind_directions = self.fmodel.core.flow_field.wind_directions[wc_id_split]\n            wind_speeds = self.fmodel.core.flow_field.wind_speeds[wc_id_split]\n            turbulence_intensities = self.fmodel.core.flow_field.turbulence_intensities[wc_id_split]\n            yaw_angles_subset = yaw_angles[wc_id_split[0]:wc_id_split[-1]+1, :]\n            fmodel_dict_split[\"flow_field\"][\"wind_directions\"] = wind_directions\n            fmodel_dict_split[\"flow_field\"][\"wind_speeds\"] = wind_speeds\n            fmodel_dict_split[\"flow_field\"][\"turbulence_intensities\"] = turbulence_intensities\n\n            # Prepare lightweight data to pass along\n            multiargs.append((fmodel_dict_split, yaw_angles_subset))\n\n        return multiargs\n\n    # Function to merge subsets in dictionaries\n    def _merge_subsets(self, field, subset):\n        i, j, k = np.shape(subset)\n        subset_reshape = np.reshape(subset, (i*j, k))\n        return [eval(\"f.{:s}\".format(field) for f in subset_reshape)]\n\n    def _postprocessing(self, output):\n        # Split results\n        power_subsets = [p[0] for p in output]\n        flowfield_subsets = [p[1] for p in output]\n\n        # Retrieve and merge turbine power productions\n        turbine_powers = np.concatenate(power_subsets, axis=0)\n\n        # Optionally, also merge flow field dictionaries from individual floris solutions\n        if self.propagate_flowfield_from_workers:\n            self.core = self.fmodel.core  # Refresh static copy of underlying floris class\n            # self.core.flow_field.u_initial = self._merge_subsets(\"u_initial\", flowfield_subsets)\n            # self.core.flow_field.v_initial = self._merge_subsets(\"v_initial\", flowfield_subsets)\n            # self.core.flow_field.w_initial = self._merge_subsets(\"w_initial\", flowfield_subsets)\n            self.core.flow_field.u = self._merge_subsets(\"u\", flowfield_subsets)\n            self.core.flow_field.v = self._merge_subsets(\"v\", flowfield_subsets)\n            self.core.flow_field.w = self._merge_subsets(\"w\", flowfield_subsets)\n            self.core.flow_field.turbulence_intensity_field = self._merge_subsets(\n                \"turbulence_intensity_field\",\n                flowfield_subsets\n            )\n\n        return turbine_powers\n\n    def run(self):\n        raise UserWarning(\n            \"'run' not supported on ParallelFlorisModel. Please use \"\n            \"'get_turbine_powers' or 'get_farm_power' directly.\"\n        )\n\n    def get_turbine_powers(self, yaw_angles=None, no_wake=False):\n        # Retrieve multiargs: preprocessing\n        t0 = timerpc()\n        multiargs = self._preprocessing(yaw_angles)\n        t_preparation = timerpc() - t0\n\n        # Set the function based on whether wake is disabled\n        if not no_wake:\n            turbine_power_function = _get_turbine_powers_serial\n        else:\n            turbine_power_function = _get_turbine_powers_serial_no_wake\n\n        # Perform parallel calculation\n        t1 = timerpc()\n        with self._PoolExecutor(self.max_workers) as p:\n            if (self.interface == \"mpi4py\") or (self.interface == \"multiprocessing\"):\n                out = p.starmap(turbine_power_function, multiargs)\n            else:\n                out = p.map(\n                    turbine_power_function,\n                    [j[0] for j in multiargs],\n                    [j[1] for j in multiargs]\n                )\n                # out = list(out)\n        t_execution = timerpc() - t1\n\n        # Postprocessing: merge power production (and opt. flow field) from individual runs\n        t2 = timerpc()\n        turbine_powers = self._postprocessing(out)\n        if self._is_uncertain:\n            turbine_powers = map_turbine_values_uncertain(\n                unique_turbine_values=turbine_powers,\n                map_to_expanded_inputs=self._map_to_expanded_inputs,\n                weights=self._weights,\n                n_unexpanded=self._n_unexpanded,\n                n_sample_points=self._n_sample_points,\n                n_turbines=self.fmodel.core.farm.n_turbines,\n            )\n        t_postprocessing = timerpc() - t2\n        t_total = timerpc() - t0\n\n        if self.print_timings:\n            print(\"===============================================================================\")\n            print(\n                \"Total time spent for parallel calculation \"\n                f\"({self.max_workers} workers): {t_total:.3f} s\"\n            )\n            print(f\"  Time spent in parallel preprocessing: {t_preparation:.3f} s\")\n            print(f\"  Time spent in parallel loop execution: {t_execution:.3f} s.\")\n            print(f\"  Time spent in parallel postprocessing: {t_postprocessing:.3f} s\")\n\n        return turbine_powers\n\n    def get_farm_power(self, yaw_angles=None, turbine_weights=None, no_wake=False):\n        if turbine_weights is None:\n            # Default to equal weighing of all turbines when turbine_weights is None\n            turbine_weights = np.ones(\n                (\n                    (self._n_unexpanded if self._is_uncertain\n                     else self.fmodel.core.flow_field.n_findex),\n                    self.fmodel.core.farm.n_turbines\n                )\n            )\n        elif len(np.shape(turbine_weights)) == 1:\n            # Deal with situation when 1D array is provided\n            turbine_weights = np.tile(\n                turbine_weights,\n                (\n                    (self._n_unexpanded if self._is_uncertain\n                     else self.fmodel.core.flow_field.n_findex),\n                    1\n                )\n            )\n\n        # Calculate all turbine powers and apply weights\n        turbine_powers = self.get_turbine_powers(yaw_angles=yaw_angles, no_wake=no_wake)\n        turbine_powers = np.multiply(turbine_weights, turbine_powers)\n\n        return np.sum(turbine_powers, axis=1)\n\n    def get_farm_AEP(\n        self,\n        freq,\n        cut_in_wind_speed=None,\n        cut_out_wind_speed=None,\n        yaw_angles=None,\n        turbine_weights=None,\n        no_wake=False,\n    ) -> float:\n        \"\"\"\n        Estimate annual energy production (AEP) for distributions of wind speed, wind\n        direction, frequency of occurrence, and yaw offset.\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape (n_wind_directions,\n                n_wind_speeds) with the frequencies of each wind direction and\n                wind speed combination. These frequencies should typically sum\n                up to 1.0 and are used to weigh the wind farm power for every\n                condition in calculating the wind farm's AEP.\n            cut_in_wind_speed (float, optional): No longer supported.\n            cut_out_wind_speed (float, optional): No longer supported.\n            yaw_angles (NDArrayFloat | list[float] | None, optional):\n                The relative turbine yaw angles in degrees. If None is\n                specified, will assume that the turbine yaw angles are all\n                zero degrees for all conditions. Defaults to None.\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the power production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                objective function. If None, this  is an array with all values\n                1.0 and with shape equal to (n_wind_directions, n_wind_speeds,\n                n_turbines). Defaults to None.\n            no_wake: (bool, optional): When *True* updates the turbine\n                quantities without calculating the wake or adding the wake to\n                the flow field. This can be useful when quantifying the loss\n                in AEP due to wakes. Defaults to *False*.\n\n        Returns:\n            float:\n                The Annual Energy Production (AEP) for the wind farm in\n                watt-hours.\n        \"\"\"\n\n        # This code is out of date, let's just thread it through\n        # # If no_wake==True, ignore parallelization because it's fast enough\n        # if no_wake:\n        #     return self.fmodel.get_farm_AEP(\n        #         freq=freq,\n        #         cut_in_wind_speed=cut_in_wind_speed,\n        #         cut_out_wind_speed=cut_out_wind_speed,\n        #         yaw_angles=yaw_angles,\n        #         turbine_weights=turbine_weights,\n        #         no_wake=no_wake\n        #     )\n\n        # Verify dimensions of the variable \"freq\"\n        if ((self._is_uncertain and np.shape(freq)[0] != self._n_unexpanded) or\n            (not self._is_uncertain and np.shape(freq)[0] != self.fmodel.core.flow_field.n_findex)):\n            raise UserWarning(\n                \"'freq' should be a one-dimensional array with dimensions (n_findex). \"\n                f\"Given shape is {np.shape(freq)}\"\n            )\n\n        # Check if frequency vector sums to 1.0. If not, raise a warning\n        if np.abs(np.sum(freq) - 1.0) > 0.001:\n            self.logger.warning(\n                \"WARNING: The frequency array provided to get_farm_AEP() does not sum to 1.0.\"\n            )\n\n        # Copy the full wind speed array from the floris object and initialize\n        # the the farm_power variable as an empty array.\n        wind_speeds = np.array(self.fmodel.core.flow_field.wind_speeds, copy=True)\n        wind_directions = np.array(self.fmodel.core.flow_field.wind_directions, copy=True)\n        turbulence_intensities = np.array(\n            self.fmodel.core.flow_field.turbulence_intensities,\n            copy=True,\n        )\n        farm_power = np.zeros(\n            self._n_unexpanded if self._is_uncertain else self.core.flow_field.n_findex\n        )\n\n        # Determine which wind speeds we must evaluate in floris\n        if cut_in_wind_speed is not None or cut_out_wind_speed is not None:\n            raise NotImplementedError(\n                \"WARNING: The 'cut_in_wind_speed' and 'cut_out_wind_speed' \"\n                \"parameters are no longer supported in the 'ParallelFlorisModel.get_farm_AEP' \"\n                \"method.\"\n            )\n\n        farm_power = (\n            self.get_farm_power(yaw_angles=yaw_angles,\n                                turbine_weights=turbine_weights,\n                                  no_wake=no_wake)\n        )\n\n        # Finally, calculate AEP in GWh\n        aep = np.nansum(np.multiply(freq, farm_power) * 365 * 24)\n\n        # Reset the FLORIS object to the full wind speed array\n        self.fmodel.set(\n            wind_directions=wind_directions,\n            wind_speeds=wind_speeds,\n            turbulence_intensities=turbulence_intensities,\n        )\n\n        return aep\n\n    def optimize_yaw_angles(\n        self,\n        minimum_yaw_angle=-25.0,\n        maximum_yaw_angle=25.0,\n        yaw_angles_baseline=None,\n        x0=None,\n        Ny_passes=[5,4],\n        turbine_weights=None,\n        exclude_downstream_turbines=True,\n        verify_convergence=False,\n        print_worker_progress=False,  # Recommended disabled to avoid clutter. Useful for debugging\n    ):\n\n        # Prepare the inputs to each core for multiprocessing module\n        t0 = timerpc()\n        multiargs = self._preprocessing()\n        for ii in range(len(multiargs)):\n            multiargs[ii] = (\n                multiargs[ii][0],\n                minimum_yaw_angle,\n                maximum_yaw_angle,\n                yaw_angles_baseline,\n                x0,\n                Ny_passes,\n                turbine_weights,\n                exclude_downstream_turbines,\n                verify_convergence,\n                print_worker_progress,\n            )\n        t1 = timerpc()\n\n        # Optimize yaw angles using parallel processing\n        print(\"Optimizing yaw angles with {:d} workers.\".format(self.max_workers))\n        with self._PoolExecutor(self.max_workers) as p:\n            if (self.interface == \"mpi4py\") or (self.interface == \"multiprocessing\"):\n                df_opt_splits = p.starmap(_optimize_yaw_angles_serial, multiargs)\n            else:\n                df_opt_splits = p.map(\n                    _optimize_yaw_angles_serial,\n                    [j[0] for j in multiargs],\n                    [j[1] for j in multiargs],\n                    [j[2] for j in multiargs],\n                    [j[3] for j in multiargs],\n                    [j[4] for j in multiargs],\n                    [j[5] for j in multiargs],\n                    [j[6] for j in multiargs],\n                    [j[7] for j in multiargs],\n                    [j[8] for j in multiargs],\n                    [j[9] for j in multiargs],\n                )\n        t2 = timerpc()\n\n        # Combine all solutions from multiprocessing into single dataframe\n        df_opt = pd.concat(df_opt_splits, axis=0).reset_index(drop=True).sort_values(\n            by=[\"wind_direction\", \"wind_speed\", \"turbulence_intensity\"]\n        )\n        t3 = timerpc()\n\n        if self.print_timings:\n            print(\"===============================================================================\")\n            print(\n                \"Total time spent for parallel calculation \"\n                f\"({self.max_workers} workers): {t3 - t0:.3f} s\"\n            )\n            print(\"  Time spent in parallel preprocessing: {:.3f} s\".format(t1 - t0))\n            print(\"  Time spent in parallel loop execution: {:.3f} s.\".format(t2 - t1))\n            print(\"  Time spent in parallel postprocessing: {:.3f} s\".format(t3 - t2))\n\n        return df_opt\n\n    def get_operation_model(self):\n        \"\"\"Get the operation model of underlying fmodel.\n\n        Returns:\n            str: The operation_model.\n        \"\"\"\n        return self.fmodel.get_operation_model()\n\n    def set_operation_model(self, operation_model):\n        \"\"\"Set the operation model of underlying fmodel.\n\n        Args:\n            operation_model (str): The operation model to set.\n        \"\"\"\n        self.fmodel.set_operation_model(operation_model)\n\n        # Reinitialize settings\n        self.__init__(\n            fmodel=self.fmodel,\n            max_workers=self._max_workers,\n            n_wind_condition_splits=self._n_wind_condition_splits,\n            interface=self.interface,\n            propagate_flowfield_from_workers=self.propagate_flowfield_from_workers,\n            print_timings=self.print_timings,\n        )\n\n    def get_param(self, param, param_idx=None):\n        \"\"\"Get the parameter of underlying fmodel.\n\n        Args:\n            param (List[str]): A list of keys to traverse the FlorisModel dictionary.\n            param_idx (Optional[int], optional): The index to get the value at. Defaults to None.\n                If None, the entire parameter is returned.\n\n        Returns:\n            Any: The value of the parameter.\n        \"\"\"\n        return self.fmodel.get_param(param, param_idx)\n\n    def set_param(self, param, value, param_idx=None):\n        \"\"\"Set the parameter of underlying fmodel.\n\n        Args:\n            param (List[str]): A list of keys to traverse the FlorisModel dictionary.\n            value (Any): The value to set.\n            param_idx (Optional[int], optional): The index to set the value at. Defaults to None.\n        \"\"\"\n        self.fmodel.set_param(param, value, param_idx)\n\n        # Reinitialize settings\n        self.__init__(\n            fmodel=self.fmodel,\n            max_workers=self._max_workers,\n            n_wind_condition_splits=self._n_wind_condition_splits,\n            interface=self.interface,\n            propagate_flowfield_from_workers=self.propagate_flowfield_from_workers,\n            print_timings=self.print_timings,\n        )\n\n\n\n    @property\n    def layout_x(self):\n        return self.fmodel.layout_x\n\n    @property\n    def layout_y(self):\n        return self.fmodel.layout_y\n\n    @property\n    def wind_speeds(self):\n        return self.fmodel.wind_speeds\n\n    @property\n    def wind_directions(self):\n        return self.fmodel.wind_directions\n\n    @property\n    def turbulence_intensities(self):\n        return self.fmodel.turbulence_intensities\n\n    @property\n    def n_findex(self):\n        return self.fmodel.n_findex\n\n    @property\n    def n_turbines(self):\n        return self.fmodel.n_turbines\n"
  },
  {
    "path": "floris/turbine_library/__init__.py",
    "content": "from floris.turbine_library.turbine_previewer import TurbineInterface, TurbineLibrary\nfrom floris.turbine_library.turbine_utilities import (\n    build_cosine_loss_turbine_dict,\n    check_smooth_power_curve,\n)\n"
  },
  {
    "path": "floris/turbine_library/iea_10MW.yaml",
    "content": "# Data based on:\n# https://github.com/NREL/turbine-models/blob/master/Offshore/IEA_10MW_198_RWT.csv\n# Note: Generator efficiency of 94% used. Small power variations above rated removed.\nturbine_type: 'iea_10MW'\nhub_height: 119.0\nrotor_diameter: 198.0\nTSR: 8.0\noperation_model: cosine-loss\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 6.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  helix_a: 1.719\n  helix_power_b: 4.823e-03\n  helix_power_c: 2.314e-10\n  helix_thrust_b: 1.157e-03\n  helix_thrust_c: 1.167e-04\n  controller_dependent_turbine_parameters:\n    rotor_solidity: 0.03500415472147307\n    rated_rpm:  8.6\n    generator_efficiency: 0.944\n    rated_power: 10000.0\n    rotor_diameter: 198\n    beta: -3.8233819218614817\n    cd:  0.004612981322772105\n    cl_alfa: 4.602140680380394\n    cp_ct_data_file: \"demo_cp_ct_surfaces/iea_10MW_demo_cp_ct_surface.npz\"\n  power:\n    - 0.0\n    - 0.0\n    - 35.60156\n    - 414.0606\n    - 1009.90686\n    - 1855.02326\n    - 2963.01442\n    - 4440.26484\n    - 6330.82856\n    - 7392.13274\n    - 8514.32824\n    - 9691.10578\n    - 10000.00\n    - 10000.00\n    - 10000.00\n    - 10000.00\n    - 10000.00\n    - 10000.00\n    - 10000.00\n    - 10000.00\n    - 10000.00\n    - 10000.00\n    - 0.0\n    - 0.0\n  thrust_coefficient:\n    - 0.0\n    - 0.0\n    - 0.915\n    - 0.926\n    - 0.921\n    - 0.895\n    - 0.885\n    - 0.873\n    - 0.827\n    - 0.789\n    - 0.754\n    - 0.721\n    - 0.591\n    - 0.49\n    - 0.418\n    - 0.318\n    - 0.251\n    - 0.203\n    - 0.167\n    - 0.119\n    - 0.088\n    - 0.049\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.0000\n    - 2.9\n    - 3.0\n    - 4.0\n    - 5.0\n    - 6.0\n    - 7.0\n    - 8.0\n    - 9.0\n    - 9.5\n    - 10.0\n    - 10.5\n    - 11.0\n    - 11.5\n    - 12.0\n    - 13.0\n    - 14.0\n    - 15.0\n    - 16.0\n    - 18.0\n    - 20.0\n    - 25.0\n    - 25.01\n    - 50.0\n"
  },
  {
    "path": "floris/turbine_library/iea_15MW.yaml",
    "content": "# Data based on:\n# https://github.com/IEAWindTask37/IEA-15-240-RWT/blob/master/Documentation/\n# IEA-15-240-RWT_tabular.xlsx\n# Note: Small power variations above rated removed.\n# Generator efficiency of 100% used.\nturbine_type: 'iea_15MW'\nhub_height: 150.0\nrotor_diameter: 242.24\nTSR: 8.0\noperation_model: cosine-loss\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 6.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  helix_a: 1.809\n  helix_power_b: 4.828e-03\n  helix_power_c: 4.017e-11\n  helix_thrust_b: 1.390e-03\n  helix_thrust_c: 5.084e-04\n  controller_dependent_turbine_parameters:\n    rotor_solidity: 0.031018237027995298\n    rated_rpm: 7.55\n    generator_efficiency: 0.95756\n    rated_power: 15000.00\n    rotor_diameter: 242.24\n    beta: -3.098605491003358\n    cd:  0.004426686198054057\n    cl_alfa: 4.546410770937916\n    cp_ct_data_file: \"demo_cp_ct_surfaces/iea_15MW_demo_cp_ct_surface.npz\"\n  power:\n    - 0.000000\n    - 0.000000\n    - 42.733312\n    - 292.585981\n    - 607.966543\n    - 981.097693\n    - 1401.98084\n    - 1858.67086\n    - 2337.575997\n    - 2824.097302\n    - 3303.06456\n    - 3759.432328\n    - 4178.637714\n    - 4547.19121\n    - 4855.342682\n    - 5091.537139\n    - 5248.453137\n    - 5320.793207\n    - 5335.345498\n    - 5437.90563\n    - 5631.253025\n    - 5920.980626\n    - 6315.115602\n    - 6824.470067\n    - 7462.846389\n    - 8238.359448\n    - 9167.96703\n    - 10285.211\n    - 11617.23699\n    - 13194.41511\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 15000.00\n    - 0.0\n    - 0.0\n  thrust_coefficient:\n    - 0.000000\n    - 0.000000\n    - 0.80742173\n    - 0.784655297\n    - 0.781771245\n    - 0.785377072\n    - 0.788045584\n    - 0.789922119\n    - 0.790464625\n    - 0.789868339\n    - 0.788727582\n    - 0.787359348\n    - 0.785895402\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.778275899\n    - 0.77176172\n    - 0.747149663\n    - 0.562338457\n    - 0.463477777\n    - 0.389083718\n    - 0.329822385\n    - 0.281465071\n    - 0.241494345\n    - 0.208180574\n    - 0.180257568\n    - 0.156747535\n    - 0.136877529\n    - 0.120026379\n    - 0.105689427\n    - 0.093453742\n    - 0.082979637\n    - 0.073986457\n    - 0.066241166\n    - 0.059552107\n    - 0.053756866\n    - 0.048721662\n    - 0.044334197\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.000\n    - 2.9\n    - 3.0\n    - 3.54953237\n    - 4.067900771\n    - 4.553906848\n    - 5.006427063\n    - 5.424415288\n    - 5.806905228\n    - 6.153012649\n    - 6.461937428\n    - 6.732965398\n    - 6.965470002\n    - 7.158913742\n    - 7.312849418\n    - 7.426921164\n    - 7.500865272\n    - 7.534510799\n    - 7.541241633\n    - 7.58833327\n    - 7.675676842\n    - 7.803070431\n    - 7.970219531\n    - 8.176737731\n    - 8.422147605\n    - 8.70588182\n    - 9.027284445\n    - 9.385612468\n    - 9.780037514\n    - 10.20964776\n    - 10.67345004\n    - 10.86770694\n    - 11.17037214\n    - 11.6992653\n    - 12.25890683\n    - 12.84800295\n    - 13.46519181\n    - 14.10904661\n    - 14.77807889\n    - 15.470742\n    - 16.18543466\n    - 16.92050464\n    - 17.67425264\n    - 18.44493615\n    - 19.23077353\n    - 20.02994808\n    - 20.8406123\n    - 21.66089211\n    - 22.4888912\n    - 23.32269542\n    - 24.1603772\n    - 25\n    - 25.020\n    - 50.0\n"
  },
  {
    "path": "floris/turbine_library/iea_15MW_floating_multi_dim_cp_ct.yaml",
    "content": "turbine_type: 'iea_15MW_floating'\nhub_height: 150.0\nrotor_diameter: 242.24\nTSR: 8.0\nmulti_dimensional_cp_ct: True\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 6.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  # Note that the multidimensional data provided here is fictional and does not represent a real\n  # wind turbine.\n  power_thrust_data_file: 'iea_15MW_multi_dim_Tp_Hs.csv'\n# The floating_tilt_table describes the steady state tilt of the floating platform as a function of\n# wind speed. This is used to adjust the power and thrust coefficients when correct_cp_ct_for_tilt\n# is True. Updated values as of FLORIS v4.6, taken from\n# https://github.com/FLOWMAS-EERC/IEA15_FOWT/blob/main/iea_15MW_floating_power-from-fixed.yaml\n# generated using OpenFAST with the U-Maine floater by Sam Kaufman-Martin.\n# The floater model used to generate these values is the UMaine VolturnUS-S Reference Platform.\nfloating_tilt_table:\n  tilt:\n    - 5.406938261\n    - 5.889508311\n    - 6.566875672\n    - 7.339842075\n    - 8.189297064\n    - 9.175639814\n    - 10.20156799\n    - 10.42520318\n    - 9.954627435\n    - 9.266065643\n    - 8.833742574\n    - 8.514576732\n    - 8.268973572\n    - 8.076813462\n    - 7.924809783\n    - 7.803116564\n    - 7.70524892\n    - 7.626825229\n    - 7.564642136\n    - 7.516322963\n    - 7.48004717\n    - 7.45510389\n  wind_speed:\n    - 3.5\n    - 4.5\n    - 5.5\n    - 6.5\n    - 7.5\n    - 8.5\n    - 9.5\n    - 10.5\n    - 11.5\n    - 12.5\n    - 13.5\n    - 14.5\n    - 15.5\n    - 16.5\n    - 17.5\n    - 18.5\n    - 19.5\n    - 20.5\n    - 21.5\n    - 22.5\n    - 23.5\n    - 24.5\ncorrect_cp_ct_for_tilt: True\n"
  },
  {
    "path": "floris/turbine_library/iea_15MW_multi_dim_TI_u.csv",
    "content": "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.585981,0.784655297\n0.06,4.067900771,607.966543,0.781771245\n0.06,4.553906848,981.097693,0.785377072\n0.06,5.006427063,1401.98084,0.788045584\n0.06,5.424415288,1858.67086,0.789922119\n0.06,5.806905228,2337.575997,0.790464625\n0.06,6.153012649,2824.097302,0.789868339\n0.06,6.461937428,3303.06456,0.788727582\n0.06,6.732965398,3759.432328,0.787359348\n0.06,6.965470002,4178.637714,0.785895402\n0.06,7.158913742,4547.19121,0.778275899\n0.06,7.312849418,4855.342682,0.778275899\n0.06,7.426921164,5091.537139,0.778275899\n0.06,7.500865272,5248.453137,0.778275899\n0.06,7.534510799,5320.793207,0.778275899\n0.06,7.541241633,5335.345498,0.778275899\n0.06,7.58833327,5437.90563,0.778275899\n0.06,7.675676842,5631.253025,0.778275899\n0.06,7.803070431,5920.980626,0.778275899\n0.06,7.970219531,6315.115602,0.778275899\n0.06,8.176737731,6824.470067,0.778275899\n0.06,8.422147605,7462.846389,0.778275899\n0.06,8.70588182,8238.359448,0.778275899\n0.06,9.027284445,9167.96703,0.778275899\n0.06,9.385612468,10285.211,0.778275899\n0.06,9.780037514,11617.23699,0.778275899\n0.06,10.20964776,13194.41511,0.778275899\n0.06,10.67345004,15000.0,0.77176172\n0.06,10.86770694,15000.0,0.747149663\n0.06,11.17037214,15000.0,0.562338457\n0.06,11.6992653,15000.0,0.463477777\n0.06,12.25890683,15000.0,0.389083718\n0.06,12.84800295,15000.0,0.329822385\n0.06,13.46519181,15000.0,0.281465071\n0.06,14.10904661,15000.0,0.241494345\n0.06,14.77807889,15000.0,0.208180574\n0.06,15.470742,15000.0,0.180257568\n0.06,16.18543466,15000.0,0.156747535\n0.06,16.92050464,15000.0,0.136877529\n0.06,17.67425264,15000.0,0.120026379\n0.06,18.44493615,15000.0,0.105689427\n0.06,19.23077353,15000.0,0.093453742\n0.06,20.02994808,15000.0,0.082979637\n0.06,20.8406123,15000.0,0.073986457\n0.06,21.66089211,15000.0,0.066241166\n0.06,22.4888912,15000.0,0.059552107\n0.06,23.32269542,15000.0,0.053756866\n0.06,24.1603772,15000.0,0.048721662\n0.06,25.0,15000.0,0.044334197\n0.06,25.02,0.0,0.0\n0.06,50.0,0.0,0.0\n0.08,0.0,0.0,0.0\n0.08,2.9,0.0,0.0\n0.08,3.0,42.733312,0.80742173\n0.08,3.54953237,292.585981,0.784655297\n0.08,4.067900771,607.966543,0.781771245\n0.08,4.553906848,981.097693,0.785377072\n0.08,5.006427063,1401.98084,0.788045584\n0.08,5.424415288,1858.67086,0.789922119\n0.08,5.806905228,2337.575997,0.790464625\n0.08,6.153012649,2824.097302,0.789868339\n0.08,6.461937428,3303.06456,0.788727582\n0.08,6.732965398,3759.432328,0.787359348\n0.08,6.965470002,4178.637714,0.785895402\n0.08,7.158913742,4547.19121,0.778275899\n0.08,7.312849418,4855.342682,0.778275899\n0.08,7.426921164,5091.537139,0.778275899\n0.08,7.500865272,5248.453137,0.778275899\n0.08,7.534510799,5320.793207,0.778275899\n0.08,7.541241633,5335.345498,0.778275899\n0.08,7.58833327,5437.90563,0.778275899\n0.08,7.675676842,5631.253025,0.778275899\n0.08,7.803070431,5920.980626,0.778275899\n0.08,7.970219531,6315.115602,0.778275899\n0.08,8.176737731,6824.470067,0.778275899\n0.08,8.422147605,7462.846389,0.778275899\n0.08,8.70588182,8238.359448,0.778275899\n0.08,9.027284445,9167.96703,0.778275899\n0.08,9.385612468,10285.211,0.778275899\n0.08,9.780037514,11617.23699,0.778275899\n0.08,10.20964776,13194.41511,0.778275899\n0.08,10.67345004,15000.0,0.77176172\n0.08,10.86770694,15000.0,0.747149663\n0.08,11.17037214,15000.0,0.562338457\n0.08,11.6992653,15000.0,0.463477777\n0.08,12.25890683,15000.0,0.389083718\n0.08,12.84800295,15000.0,0.329822385\n0.08,13.46519181,15000.0,0.281465071\n0.08,14.10904661,15000.0,0.241494345\n0.08,14.77807889,15000.0,0.208180574\n0.08,15.470742,15000.0,0.180257568\n0.08,16.18543466,15000.0,0.156747535\n0.08,16.92050464,15000.0,0.136877529\n0.08,17.67425264,15000.0,0.120026379\n0.08,18.44493615,15000.0,0.105689427\n0.08,19.23077353,15000.0,0.093453742\n0.08,20.02994808,15000.0,0.082979637\n0.08,20.8406123,15000.0,0.073986457\n0.08,21.66089211,15000.0,0.066241166\n0.08,22.4888912,15000.0,0.059552107\n0.08,23.32269542,15000.0,0.053756866\n0.08,24.1603772,15000.0,0.048721662\n0.08,25.0,15000.0,0.044334197\n0.08,25.02,0.0,0.0\n0.08,50.0,0.0,0.0\n"
  },
  {
    "path": "floris/turbine_library/iea_15MW_multi_dim_Tp_Hs.csv",
    "content": "Tp,Hs,ws,power,thrust_coefficient\r\n2,1,0,0,0\r\n2,1,2.9,0,0\r\n2,1,3,42.733312,0.80742173\r\n2,1,3.54953237,292.585981,0.784655297\r\n2,1,4.067900771,607.966543,0.781771245\r\n2,1,4.553906848,981.097693,0.785377072\r\n2,1,5.006427063,1401.98084,0.788045584\r\n2,1,5.424415288,1858.67086,0.789922119\r\n2,1,5.806905228,2337.575997,0.790464625\r\n2,1,6.153012649,2824.097302,0.789868339\r\n2,1,6.461937428,3303.06456,0.788727582\r\n2,1,6.732965398,3759.432328,0.787359348\r\n2,1,6.965470002,4178.637714,0.785895402\r\n2,1,7.158913742,4547.19121,0.778275899\r\n2,1,7.312849418,4855.342682,0.778275899\r\n2,1,7.426921164,5091.537139,0.778275899\r\n2,1,7.500865272,5248.453137,0.778275899\r\n2,1,7.534510799,5320.793207,0.778275899\r\n2,1,7.541241633,5335.345498,0.778275899\r\n2,1,7.58833327,5437.90563,0.778275899\r\n2,1,7.675676842,5631.253025,0.778275899\r\n2,1,7.803070431,5920.980626,0.778275899\r\n2,1,7.970219531,6315.115602,0.778275899\r\n2,1,8.176737731,6824.470067,0.778275899\r\n2,1,8.422147605,7462.846389,0.778275899\r\n2,1,8.70588182,8238.359448,0.778275899\r\n2,1,9.027284445,9167.96703,0.778275899\r\n2,1,9.385612468,10285.211,0.778275899\r\n2,1,9.780037514,11617.23699,0.778275899\r\n2,1,10.20964776,13194.41511,0.778275899\r\n2,1,10.67345004,15000,0.77176172\r\n2,1,10.86770694,15000,0.747149663\r\n2,1,11.17037214,15000,0.562338457\r\n2,1,11.6992653,15000,0.463477777\r\n2,1,12.25890683,15000,0.389083718\r\n2,1,12.84800295,15000,0.329822385\r\n2,1,13.46519181,15000,0.281465071\r\n2,1,14.10904661,15000,0.241494345\r\n2,1,14.77807889,15000,0.208180574\r\n2,1,15.470742,15000,0.180257568\r\n2,1,16.18543466,15000,0.156747535\r\n2,1,16.92050464,15000,0.136877529\r\n2,1,17.67425264,15000,0.120026379\r\n2,1,18.44493615,15000,0.105689427\r\n2,1,19.23077353,15000,0.093453742\r\n2,1,20.02994808,15000,0.082979637\r\n2,1,20.8406123,15000,0.073986457\r\n2,1,21.66089211,15000,0.066241166\r\n2,1,22.4888912,15000,0.059552107\r\n2,1,23.32269542,15000,0.053756866\r\n2,1,24.1603772,15000,0.048721662\r\n2,1,25,15000,0.044334197\r\n2,1,25.02,0,0\r\n2,1,50,0,0\r\n2,5,0,0,0\r\n2,5,2.9,0,0\r\n2,5,3,21.366656,0.403710865\r\n2,5,3.54953237,146.2929905,0.392327649\r\n2,5,4.067900771,303.9832715,0.390885623\r\n2,5,4.553906848,490.5488465,0.392688536\r\n2,5,5.006427063,700.99042,0.394022792\r\n2,5,5.424415288,929.33543,0.39496106\r\n2,5,5.806905228,1168.787999,0.395232313\r\n2,5,6.153012649,1412.048651,0.39493417\r\n2,5,6.461937428,1651.53228,0.394363791\r\n2,5,6.732965398,1879.716164,0.393679674\r\n2,5,6.965470002,2089.318857,0.392947701\r\n2,5,7.158913742,2273.595605,0.38913795\r\n2,5,7.312849418,2427.671341,0.38913795\r\n2,5,7.426921164,2545.76857,0.38913795\r\n2,5,7.500865272,2624.226569,0.38913795\r\n2,5,7.534510799,2660.396604,0.38913795\r\n2,5,7.541241633,2667.672749,0.38913795\r\n2,5,7.58833327,2718.952815,0.38913795\r\n2,5,7.675676842,2815.626513,0.38913795\r\n2,5,7.803070431,2960.490313,0.38913795\r\n2,5,7.970219531,3157.557801,0.38913795\r\n2,5,8.176737731,3412.235034,0.38913795\r\n2,5,8.422147605,3731.423195,0.38913795\r\n2,5,8.70588182,4119.179724,0.38913795\r\n2,5,9.027284445,4583.983515,0.38913795\r\n2,5,9.385612468,5142.6055,0.38913795\r\n2,5,9.780037514,5808.618495,0.38913795\r\n2,5,10.20964776,6597.207555,0.38913795\r\n2,5,10.67345004,7500,0.38588086\r\n2,5,10.86770694,7500,0.373574832\r\n2,5,11.17037214,7500,0.281169229\r\n2,5,11.6992653,7500,0.231738889\r\n2,5,12.25890683,7500,0.194541859\r\n2,5,12.84800295,7500,0.164911193\r\n2,5,13.46519181,7500,0.140732536\r\n2,5,14.10904661,7500,0.120747173\r\n2,5,14.77807889,7500,0.104090287\r\n2,5,15.470742,7500,0.090128784\r\n2,5,16.18543466,7500,0.078373768\r\n2,5,16.92050464,7500,0.068438765\r\n2,5,17.67425264,7500,0.06001319\r\n2,5,18.44493615,7500,0.052844714\r\n2,5,19.23077353,7500,0.046726871\r\n2,5,20.02994808,7500,0.041489819\r\n2,5,20.8406123,7500,0.036993229\r\n2,5,21.66089211,7500,0.033120583\r\n2,5,22.4888912,7500,0.029776054\r\n2,5,23.32269542,7500,0.026878433\r\n2,5,24.1603772,7500,0.024360831\r\n2,5,25,7500,0.022167099\r\n2,5,25.02,0,0\r\n2,5,50,0,0\r\n4,1,0,0,0\r\n4,1,2.9,0,0\r\n4,1,3,10.683328,0.201855433\r\n4,1,3.54953237,73.14649525,0.196163824\r\n4,1,4.067900771,151.9916358,0.195442811\r\n4,1,4.553906848,245.2744233,0.196344268\r\n4,1,5.006427063,350.49521,0.197011396\r\n4,1,5.424415288,464.667715,0.19748053\r\n4,1,5.806905228,584.3939993,0.197616156\r\n4,1,6.153012649,706.0243255,0.197467085\r\n4,1,6.461937428,825.76614,0.197181896\r\n4,1,6.732965398,939.858082,0.196839837\r\n4,1,6.965470002,1044.659429,0.196473851\r\n4,1,7.158913742,1136.797803,0.194568975\r\n4,1,7.312849418,1213.835671,0.194568975\r\n4,1,7.426921164,1272.884285,0.194568975\r\n4,1,7.500865272,1312.113284,0.194568975\r\n4,1,7.534510799,1330.198302,0.194568975\r\n4,1,7.541241633,1333.836375,0.194568975\r\n4,1,7.58833327,1359.476408,0.194568975\r\n4,1,7.675676842,1407.813256,0.194568975\r\n4,1,7.803070431,1480.245157,0.194568975\r\n4,1,7.970219531,1578.778901,0.194568975\r\n4,1,8.176737731,1706.117517,0.194568975\r\n4,1,8.422147605,1865.711597,0.194568975\r\n4,1,8.70588182,2059.589862,0.194568975\r\n4,1,9.027284445,2291.991758,0.194568975\r\n4,1,9.385612468,2571.30275,0.194568975\r\n4,1,9.780037514,2904.309248,0.194568975\r\n4,1,10.20964776,3298.603778,0.194568975\r\n4,1,10.67345004,3750,0.19294043\r\n4,1,10.86770694,3750,0.186787416\r\n4,1,11.17037214,3750,0.140584614\r\n4,1,11.6992653,3750,0.115869444\r\n4,1,12.25890683,3750,0.09727093\r\n4,1,12.84800295,3750,0.082455596\r\n4,1,13.46519181,3750,0.070366268\r\n4,1,14.10904661,3750,0.060373586\r\n4,1,14.77807889,3750,0.052045144\r\n4,1,15.470742,3750,0.045064392\r\n4,1,16.18543466,3750,0.039186884\r\n4,1,16.92050464,3750,0.034219382\r\n4,1,17.67425264,3750,0.030006595\r\n4,1,18.44493615,3750,0.026422357\r\n4,1,19.23077353,3750,0.023363436\r\n4,1,20.02994808,3750,0.020744909\r\n4,1,20.8406123,3750,0.018496614\r\n4,1,21.66089211,3750,0.016560292\r\n4,1,22.4888912,3750,0.014888027\r\n4,1,23.32269542,3750,0.013439217\r\n4,1,24.1603772,3750,0.012180416\r\n4,1,25,3750,0.011083549\r\n4,1,25.02,0,0\r\n4,1,50,0,0\r\n4,5,0,0,0\r\n4,5,2.9,0,0\r\n4,5,3,5.341664,0.100927716\r\n4,5,3.54953237,36.57324763,0.098081912\r\n4,5,4.067900771,75.99581788,0.097721406\r\n4,5,4.553906848,122.6372116,0.098172134\r\n4,5,5.006427063,175.247605,0.098505698\r\n4,5,5.424415288,232.3338575,0.098740265\r\n4,5,5.806905228,292.1969996,0.098808078\r\n4,5,6.153012649,353.0121628,0.098733542\r\n4,5,6.461937428,412.88307,0.098590948\r\n4,5,6.732965398,469.929041,0.098419919\r\n4,5,6.965470002,522.3297143,0.098236925\r\n4,5,7.158913742,568.3989013,0.097284487\r\n4,5,7.312849418,606.9178353,0.097284487\r\n4,5,7.426921164,636.4421424,0.097284487\r\n4,5,7.500865272,656.0566421,0.097284487\r\n4,5,7.534510799,665.0991509,0.097284487\r\n4,5,7.541241633,666.9181873,0.097284487\r\n4,5,7.58833327,679.7382038,0.097284487\r\n4,5,7.675676842,703.9066281,0.097284487\r\n4,5,7.803070431,740.1225783,0.097284487\r\n4,5,7.970219531,789.3894503,0.097284487\r\n4,5,8.176737731,853.0587584,0.097284487\r\n4,5,8.422147605,932.8557986,0.097284487\r\n4,5,8.70588182,1029.794931,0.097284487\r\n4,5,9.027284445,1145.995879,0.097284487\r\n4,5,9.385612468,1285.651375,0.097284487\r\n4,5,9.780037514,1452.154624,0.097284487\r\n4,5,10.20964776,1649.301889,0.097284487\r\n4,5,10.67345004,1875,0.096470215\r\n4,5,10.86770694,1875,0.093393708\r\n4,5,11.17037214,1875,0.070292307\r\n4,5,11.6992653,1875,0.057934722\r\n4,5,12.25890683,1875,0.048635465\r\n4,5,12.84800295,1875,0.041227798\r\n4,5,13.46519181,1875,0.035183134\r\n4,5,14.10904661,1875,0.030186793\r\n4,5,14.77807889,1875,0.026022572\r\n4,5,15.470742,1875,0.022532196\r\n4,5,16.18543466,1875,0.019593442\r\n4,5,16.92050464,1875,0.017109691\r\n4,5,17.67425264,1875,0.015003297\r\n4,5,18.44493615,1875,0.013211178\r\n4,5,19.23077353,1875,0.011681718\r\n4,5,20.02994808,1875,0.010372455\r\n4,5,20.8406123,1875,0.009248307\r\n4,5,21.66089211,1875,0.008280146\r\n4,5,22.4888912,1875,0.007444013\r\n4,5,23.32269542,1875,0.006719608\r\n4,5,24.1603772,1875,0.006090208\r\n4,5,25,1875,0.005541775\r\n4,5,25.02,0,0\r\n4,5,50,0,0\r\n"
  },
  {
    "path": "floris/turbine_library/iea_15MW_multi_dim_cp_ct.yaml",
    "content": "turbine_type: 'iea_15MW_multi_dim_cp_ct'\nhub_height: 150.0\nrotor_diameter: 242.24\nTSR: 8.0\nmulti_dimensional_cp_ct: True\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 6.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  # Note that the multidimensional data provided here is fictional and does not represent a real\n  # wind turbine.\n  power_thrust_data_file: 'iea_15MW_multi_dim_Tp_Hs.csv'\n"
  },
  {
    "path": "floris/turbine_library/iea_22MW.yaml",
    "content": "# Data generated using OpenFAST v4.1.2 and ROSCO v2.10.2\nturbine_type: 'iea_22MW'\nhub_height: 170.0\nrotor_diameter: 284.0\nTSR: 9.15\noperation_model: cosine-loss\npower_thrust_table:\n  ref_air_density: 1.225\n  ref_tilt: 6.0\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  power:\n    - 0.000000\n    - 0.000000\n    - 470.42006956610055\n    - 1118.232780617167\n    - 2188.311980648143\n    - 3782.7306259417846\n    - 5997.190541701143\n    - 8910.135612999937\n    - 10648.827448063703\n    - 12596.925211817956\n    - 14685.013190976455\n    - 15726.690294207267\n    - 16756.8567719253\n    - 17769.676433679262\n    - 18801.041099221588\n    - 19827.767728789564\n    - 20848.709510875513\n    - 21864.885529798317\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 22000.0\n    - 0.0\n    - 0.0\n  thrust_coefficient:\n    - 0.000000\n    - 0.000000\n    - 0.8151028985050527\n    - 0.8186962341625531\n    - 0.8256090342400992\n    - 0.8302179769897181\n    - 0.828968333088208\n    - 0.8248223398544402\n    - 0.8212931067329768\n    - 0.8040275589649526\n    - 0.75721959807142\n    - 0.7326878124377916\n    - 0.7084846280602614\n    - 0.6843036442042609\n    - 0.663147304888859\n    - 0.6424161102200797\n    - 0.6221917507431868\n    - 0.6025783643621286\n    - 0.5539840778236028\n    - 0.5054754180818498\n    - 0.4648590217686185\n    - 0.42984915555590786\n    - 0.3991369663817839\n    - 0.3474807030632657\n    - 0.3055334704356\n    - 0.27077311601674536\n    - 0.21679726239514083\n    - 0.17717614488236633\n    - 0.14722553071482708\n    - 0.12404315188884445\n    - 0.10574107410244936\n    - 0.0791170545715597\n    - 0.06114076570325394\n    - 0.04852760403701628\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.0\n    - 2.9\n    - 3.0\n    - 4.0\n    - 5.0\n    - 6.0\n    - 7.0\n    - 8.0\n    - 8.5\n    - 9.0\n    - 9.5\n    - 9.75\n    - 10.0\n    - 10.25\n    - 10.5\n    - 10.75\n    - 11.0\n    - 11.25\n    - 11.5\n    - 11.75\n    - 12.0\n    - 12.25\n    - 12.5\n    - 13.0\n    - 13.5\n    - 14.0\n    - 15.0\n    - 16.0\n    - 17.0\n    - 18.0\n    - 19.0\n    - 21.0\n    - 23.0\n    - 25.0\n    - 25.1\n    - 50.0\n"
  },
  {
    "path": "floris/turbine_library/nrel_5MW.yaml",
    "content": "# NREL 5MW reference wind turbine.\n# Data based on:\n# https://github.com/NREL/turbine-models/blob/master/Offshore/NREL_5MW_126_RWT_corrected.csv\n# Note: Small power variations above rated removed. Rotor diameter includes coning angle.\n# Note: generator efficiency of 94.4% is assumed for the NREL 5MW turbine.\n\n###\n# An ID for this type of turbine definition.\n# This is used to uniquely identify different turbines in the simulation, so should be different\n# for each different turbine definition being used in the same simulation.\n# String type.\nturbine_type: 'nrel_5MW'\n\n###\n# Turbine hub height in meters. Float type.\nhub_height: 90.0\n\n###\n# Turbine rotor diameter in meters. Float type.\nrotor_diameter: 125.88\n\n###\n# Nominal wind turbine tip-speed ratio for below-rated operation. Only used in some wake models.\n# Float type.\nTSR: 8.0\n\n###\n# Model for power and thrust curve interpretation. See floris.core.turbine.operation_models for\n# details. String type.\noperation_model: 'cosine-loss'\n\n###\n# Group of parameters needed to evaluate the power and thrust produced by the turbine.\npower_thrust_table:\n  ###\n  # Air density at which the power and thrust_coefficient curves are defined (kg / m^3). Float type.\n  ref_air_density: 1.225\n  ###\n  # Tilt angle at which the power and thrust_coefficient curves are defined (degrees).\n  # Used to capture the effects of a floating platform on a turbine's power and wake.\n  # Float type.\n  ref_tilt: 5.0\n  ###\n  # Cosine exponent for power loss due to tilt. Float type.\n  cosine_loss_exponent_tilt: 1.88\n  ###\n  # Cosine exponent for power loss due to yaw misalignment. Float type.\n  cosine_loss_exponent_yaw: 1.88\n  ###\n  # Helix parameter a. See documentation for details. Float type.\n  helix_a: 1.802\n  ###\n  # Helix parameter b for power calculation. See documentation for details. Float type.\n  helix_power_b: 4.568e-03\n  ###\n  # Helix parameter c for power calculation. See documentation for details. Float type.\n  helix_power_c: 1.629e-10\n  ###\n  # Helix parameter b for thrust calculation. See documentation for details. Float type.\n  helix_thrust_b: 1.027e-03\n  ###\n  # Helix parameter c for thrust calculation. See documentation for details. Float type.\n  helix_thrust_c: 1.378e-06\n  ###\n  # Fraction of peak thrust by which to reduce (specified as a decimal). Float type.\n  peak_shaving_fraction: 0.2\n  ###\n  # Threshold turbulence intensity above which to apply peak shaving (specified as a decimal).\n  # Float tpe.\n  peak_shaving_TI_threshold: 0.1\n\n  ###\n  # Parameters for the 'controller-dependenter-dependent' operation model. See\n  # floris.core.turbine.controller_dependent_operation_model and documentation for details.\n  controller_dependent_turbine_parameters:\n    rated_rpm: 12.1\n    rotor_solidity: 0.05132\n    generator_efficiency: 0.944\n    rated_power: 5000.0\n    rotor_diameter: 126\n    beta: -0.45891\n    cd:  0.0040638\n    cl_alfa: 4.275049\n    cp_ct_data_file: \"demo_cp_ct_surfaces/nrel_5MW_demo_cp_ct_surface.npz\"\n\n  ###\n  # Wind speeds for look-up tables of power and thrust_coefficient. List of float type.\n  wind_speed:\n    - 0.0\n    - 2.9\n    - 3.0\n    - 4.0\n    - 5.0\n    - 6.0\n    - 7.0\n    - 7.1\n    - 7.2\n    - 7.3\n    - 7.4\n    - 7.5\n    - 7.6\n    - 7.7\n    - 7.8\n    - 7.9\n    - 8.0\n    - 9.0\n    - 10.0\n    - 10.1\n    - 10.2\n    - 10.3\n    - 10.4\n    - 10.5\n    - 10.6\n    - 10.7\n    - 10.8\n    - 10.9\n    - 11.0\n    - 11.1\n    - 11.2\n    - 11.3\n    - 11.4\n    - 11.5\n    - 11.6\n    - 11.7\n    - 11.8\n    - 11.9\n    - 12.0\n    - 13.0\n    - 14.0\n    - 15.0\n    - 16.0\n    - 17.0\n    - 18.0\n    - 19.0\n    - 20.0\n    - 21.0\n    - 22.0\n    - 23.0\n    - 24.0\n    - 25.0\n    - 25.1\n    - 50.0\n  ###\n  # Power values (specified in kW) for lookup by wind speed. List of float type.\n  power:\n    - 0.0\n    - 0.0\n    - 40.518011517569214\n    - 177.67162506419703\n    - 403.900880943964\n    - 737.5889584824021\n    - 1187.1774030611875\n    - 1239.245945375778\n    - 1292.5184293723503\n    - 1347.3213147477102\n    - 1403.2573725578948\n    - 1460.7011898730707\n    - 1519.6419125979983\n    - 1580.174365096404\n    - 1642.1103166918167\n    - 1705.758292831\n    - 1771.1659528893977\n    - 2518.553107505315\n    - 3448.381605840943\n    - 3552.140809000129\n    - 3657.9545431794127\n    - 3765.121299313842\n    - 3873.928844315059\n    - 3984.4800226955504\n    - 4096.582833096852\n    - 4210.721306623712\n    - 4326.154305853405\n    - 4443.395565353604\n    - 4562.497934188341\n    - 4683.419890251577\n    - 4806.164748311019\n    - 4929.931918769215\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 0.0\n    - 0.0\n  ###\n  # Thrust coefficient values (unitless) for lookup by wind speed. List of float type.\n  thrust_coefficient:\n    - 0.0\n    - 0.0\n    - 1.132034888\n    - 0.999470963\n    - 0.917697381\n    - 0.860849503\n    - 0.815371198\n    - 0.811614904\n    - 0.807939328\n    - 0.80443352\n    - 0.800993851\n    - 0.79768116\n    - 0.794529244\n    - 0.791495834\n    - 0.788560434\n    - 0.787217182\n    - 0.787127977\n    - 0.785839257\n    - 0.783812219\n    - 0.783568108\n    - 0.783328285\n    - 0.781194418\n    - 0.777292539\n    - 0.773464375\n    - 0.769690236\n    - 0.766001924\n    - 0.762348072\n    - 0.758760824\n    - 0.755242872\n    - 0.751792927\n    - 0.748434131\n    - 0.745113997\n    - 0.717806682\n    - 0.672204789\n    - 0.63831272\n    - 0.610176496\n    - 0.585456847\n    - 0.563222111\n    - 0.542912273\n    - 0.399312061\n    - 0.310517829\n    - 0.248633226\n    - 0.203543725\n    - 0.169616419\n    - 0.143478955\n    - 0.122938861\n    - 0.106515296\n    - 0.093026095\n    - 0.081648606\n    - 0.072197368\n    - 0.064388275\n    - 0.057782745\n    - 0.0\n    - 0.0\n\n###\n# Boolean flag used when the user wants FLORIS to use the user-supplied multi-dimensional\n# power/thrust coefficient information information. Boolean type.\nmulti_dimensional_cp_ct: False\n\n###\n# Path to the .csv file that contains the multi-dimensional power/thrust coefficient data.\n# The format of this file is such that any external conditions, such as wave height or wave period,\n# that the power/thrust data is dependent on come first, in column format. The last three columns\n# of the .csv file must be ``ws``, ``power``, and ``thrust_coefficient``, in that order. An example\n# of fictional data is given in ``floris/turbine_library/iea_15MW_multi_dim_Tp_Hs.csv``.\n# String type.\npower_thrust_data_file: '../floris/turbine_library/iea_15MW_multi_dim_Tp_Hs.csv'\n\n###\n# Group of parameters needed to evaluate the tilt angle of a floating turbine across wind speeds.\nfloating_tilt_table:\n  ###\n  # Wind speeds at which steady tilt angles are defined (m/s). List of float type.\n  wind_speed:\n    - 4.0\n    - 6.0\n    - 8.0\n    - 10.0\n    - 12.0\n    - 14.0\n    - 16.0\n  ###\n  # Tilt angle for each wind speed (degrees, positive \"tilted back\"). List of float type.\n  tilt:\n    - 5.0\n    - 5.0\n    - 5.0\n    - 5.0\n    - 5.0\n    - 5.0\n    - 5.0\n\n###\n# Flag for whether to apply the floating tilt table to correct turbine power and thrust curves.\n# Boolean type.\ncorrect_cp_ct_for_tilt: false\n"
  },
  {
    "path": "floris/turbine_library/turbine_previewer.py",
    "content": "from pathlib import Path\n\nimport attrs\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT\nfrom floris.core.turbine.turbine import (\n    power,\n    thrust_coefficient,\n    Turbine,\n)\nfrom floris.type_dec import convert_to_path, NDArrayFloat\nfrom floris.utilities import (\n    load_yaml,\n    round_nearest,\n    round_nearest_2_or_5,\n)\n\n\nINTERNAL_LIBRARY = Path(__file__).parent\nDEFAULT_WIND_SPEEDS = np.linspace(0, 40, 81)\n\nDEPRECATION_MESSAGE = (\n    \"The TurbineInterface and TurbineLibrary classes are now deprecated as will be removed in a\",\n    \" future FLORIS release.\"\n)\n\n\n@define(auto_attribs=True)\nclass TurbineInterface:\n    turbine: Turbine = field(validator=attrs.validators.instance_of(Turbine))\n\n    @classmethod\n    def from_library(cls, library_path: str | Path, file_name: str):\n        \"\"\"Loads the turbine definition from a YAML configuration file located in either the\n        internal turbine library ``floris/floris/turbine_library/``, or a user-specified location.\n\n        Args:\n            library_path (:obj:`str` | :obj:`pathlib.Path`): The location of the turbine library;\n                use \"internal\" to use the FLORIS-provided library.\n            file_name (:obj:`str` | :obj:`pathlib.Path`): The name of the configuration file.\n\n        Returns:\n            (TurbineInterface): Creates a new ``TurbineInterface`` object.\n        \"\"\"\n        print(DEPRECATION_MESSAGE)\n        # Use the pre-mapped internal turbine library or validate the user's library\n        if library_path == \"internal\":\n            library_path = INTERNAL_LIBRARY\n        else:\n            library_path = convert_to_path(library_path)\n\n        # Add in the library specification if needed, and load from dict\n        turb_dict = load_yaml(library_path / file_name)\n        return cls(turbine=Turbine.from_dict(turb_dict))\n\n    @classmethod\n    def from_yaml(cls, file_path: str | Path):\n        \"\"\"Loads the turbine definition from a YAML configuration file.\n\n        Args:\n            file_path : str | Path\n                The full path and file name of the turbine configuration file.\n\n        Returns:\n            (TurbineInterface): Creates a new ``TurbineInterface`` object.\n        \"\"\"\n        print(DEPRECATION_MESSAGE)\n        file_path = Path(file_path).resolve()\n\n        # Add in the library specification if needed, and load from dict\n        turb_dict = load_yaml(file_path)\n        return cls(turbine=Turbine.from_dict(turb_dict))\n\n    @classmethod\n    def from_turbine_dict(cls, config_dict: dict):\n        \"\"\"Loads the turbine definition from a dictionary.\n\n        Args:\n            config_dict : dict\n                The ``Turbine`` configuration dictionary.\n\n        Returns:\n            (`TurbineInterface`): Returns a ``TurbineInterface`` object.\n        \"\"\"\n        print(DEPRECATION_MESSAGE)\n        return cls(turbine=Turbine.from_dict(config_dict))\n\n    def power_curve(\n        self,\n        wind_speeds: NDArrayFloat = DEFAULT_WIND_SPEEDS,\n    ) -> tuple[NDArrayFloat, NDArrayFloat] | tuple[NDArrayFloat, dict[tuple, NDArrayFloat]]:\n        \"\"\"Produces a plot-ready power curve for the turbine for wind speed vs power (MW), assuming\n        no tilt or yaw effects.\n\n        Args:\n            wind_speeds (NDArrayFloat, optional): A 1-D array of wind speeds, in m/s. Defaults to\n                0 m/s -> 40 m/s, every 0.5 m/s.\n\n        Returns:\n            (tuple[NDArrayFloat, NDArrayFloat] | tuple[NDArrayFloat, dict[tuple, NDArrayFloat]]):\n                Returns the wind speed array and the power array, or the wind speed array and a\n                dictionary of the multidimensional parameters and their associated power arrays.\n        \"\"\"\n        shape = (wind_speeds.size, 1)\n        if self.turbine.multi_dimensional_cp_ct:\n            power_mw = {\n                k: power(\n                    velocities=wind_speeds.reshape(shape),\n                    turbulence_intensities=np.zeros(shape),\n                    air_density=np.full(shape, v[\"ref_air_density\"]),\n                    power_functions={self.turbine.turbine_type: self.turbine.power_function},\n                    yaw_angles=np.zeros(shape),\n                    tilt_angles=np.full(shape, v[\"ref_tilt\"]),\n                    power_setpoints=np.full(shape, POWER_SETPOINT_DEFAULT),\n                    awc_modes=np.full(shape, [\"baseline\"]),\n                    awc_amplitudes=np.zeros(shape),\n                    tilt_interps={self.turbine.turbine_type: self.turbine.tilt_interp},\n                    turbine_type_map=np.full(shape, self.turbine.turbine_type),\n                    turbine_power_thrust_tables={self.turbine.turbine_type: v},\n                ).flatten() / 1e6\n                for k,v in self.turbine.power_thrust_table.items()\n            }\n        else:\n            power_mw = power(\n                velocities=wind_speeds.reshape(shape),\n                turbulence_intensities=np.zeros(shape),\n                air_density=np.full(shape, self.turbine.power_thrust_table[\"ref_air_density\"]),\n                power_functions={self.turbine.turbine_type: self.turbine.power_function},\n                yaw_angles=np.zeros(shape),\n                tilt_angles=np.full(shape, self.turbine.power_thrust_table[\"ref_tilt\"]),\n                power_setpoints=np.full(shape, POWER_SETPOINT_DEFAULT),\n                awc_modes=np.full(shape, [\"baseline\"]),\n                awc_amplitudes=np.zeros(shape),\n                tilt_interps={self.turbine.turbine_type: self.turbine.tilt_interp},\n                turbine_type_map=np.full(shape, self.turbine.turbine_type),\n                turbine_power_thrust_tables={\n                    self.turbine.turbine_type: self.turbine.power_thrust_table\n                },\n            ).flatten() / 1e6\n        return wind_speeds, power_mw\n\n    def thrust_coefficient_curve(\n        self,\n        wind_speeds: NDArrayFloat = DEFAULT_WIND_SPEEDS,\n    ) -> tuple[NDArrayFloat, NDArrayFloat]:\n        \"\"\"Produces a plot-ready thrust curve for the turbine for wind speed vs thrust coefficient\n        assuming no tilt or yaw effects.\n\n        Args:\n            wind_speeds (NDArrayFloat, optional): A 1-D array of wind speeds, in m/s. Defaults to\n                0 m/s -> 40 m/s, every 0.5 m/s.\n\n        Returns:\n            tuple[NDArrayFloat, NDArrayFloat]\n                Returns the wind speed array and the thrust coefficient array.\n        \"\"\"\n        shape = (wind_speeds.size, 1)\n        if self.turbine.multi_dimensional_cp_ct:\n            ct_curve = {\n                k: thrust_coefficient(\n                    velocities=wind_speeds.reshape(shape),\n                    turbulence_intensities=np.zeros(shape),\n                    air_density=np.full(shape, v[\"ref_air_density\"]),\n                    yaw_angles=np.zeros(shape),\n                    tilt_angles=np.full(shape, v[\"ref_tilt\"]),\n                    power_setpoints=np.full(shape, POWER_SETPOINT_DEFAULT),\n                    awc_modes=np.full(shape, [\"baseline\"]),\n                    awc_amplitudes=np.zeros(shape),\n                    thrust_coefficient_functions={\n                        self.turbine.turbine_type: self.turbine.thrust_coefficient_function\n                    },\n                    tilt_interps={self.turbine.turbine_type: self.turbine.tilt_interp},\n                    correct_cp_ct_for_tilt=np.zeros(shape, dtype=bool),\n                    turbine_type_map=np.full(shape, self.turbine.turbine_type),\n                    turbine_power_thrust_tables={self.turbine.turbine_type: v},\n                ).flatten()\n                for k,v in self.turbine.power_thrust_table.items()\n            }\n        else:\n            ct_curve = thrust_coefficient(\n                velocities=wind_speeds.reshape(shape),\n                turbulence_intensities=np.zeros(shape),\n                air_density=np.full(shape, self.turbine.power_thrust_table[\"ref_air_density\"]),\n                yaw_angles=np.zeros(shape),\n                tilt_angles=np.full(shape, self.turbine.power_thrust_table[\"ref_tilt\"]),\n                power_setpoints=np.full(shape, POWER_SETPOINT_DEFAULT),\n                awc_modes=np.full(shape, [\"baseline\"]),\n                awc_amplitudes=np.zeros(shape),\n                thrust_coefficient_functions={\n                    self.turbine.turbine_type: self.turbine.thrust_coefficient_function\n                },\n                tilt_interps={self.turbine.turbine_type: self.turbine.tilt_interp},\n                correct_cp_ct_for_tilt=np.zeros(shape, dtype=bool),\n                turbine_type_map=np.full(shape, self.turbine.turbine_type),\n                turbine_power_thrust_tables={\n                    self.turbine.turbine_type: self.turbine.power_thrust_table\n                },\n            ).flatten()\n        return wind_speeds, ct_curve\n\n    def plot_power_curve(\n        self,\n        wind_speeds: NDArrayFloat = DEFAULT_WIND_SPEEDS,\n        fig_kwargs: dict | None =  None,\n        plot_kwargs: dict | None =  None,\n        legend_kwargs: dict | None =  None,\n        return_fig: bool = False\n    ) -> None | tuple[plt.Figure, plt.Axes]:\n        \"\"\"Plots the power curve for a given set of wind speeds.\n\n        Args:\n            wind_speeds (NDArrayFloat, optional): A 1-D array of wind speeds, in m/s.\n                Defaults to 0 m/s -> 40 m/s, every 0.5 m/s.\n            fig_kwargs (dict, optional): Any keywords arguments to be passed to ``plt.Figure()``.\n                Defaults to None.\n            plot_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.plot()``.\n                Defaults to None.\n            legend_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.legend()``.\n                Defaults to None.\n            return_fig (bool, optional): Indicator if the ``Figure`` and ``Axes`` objects should be\n                returned. Defaults to False.\n\n        Returns:\n            None | tuple[plt.Figure, plt.Axes]: None, if :py:attr:`return_fig` is False, otherwise\n                a tuple of the Figure and Axes objects are returned.\n        \"\"\"\n        wind_speeds, power_mw = self.power_curve(wind_speeds=wind_speeds)\n\n        # Initialize kwargs if None\n        fig_kwargs = {} if fig_kwargs is None else fig_kwargs\n        plot_kwargs = {} if plot_kwargs is None else plot_kwargs\n        legend_kwargs = {} if legend_kwargs is None else legend_kwargs\n\n        # Set the figure defaults if none are provided\n        fig_kwargs.setdefault(\"dpi\", 200)\n        fig_kwargs.setdefault(\"figsize\", (4, 3))\n\n        fig = plt.figure(**fig_kwargs)\n        ax = fig.add_subplot(111)\n\n        min_windspeed = 0\n        max_windspeed = max(wind_speeds)\n        min_power = 0\n        max_power = 0\n        if isinstance(power_mw, dict):\n            for key, _power_mw in power_mw.items():\n                max_power = max(max_power, *_power_mw)\n                _cond = \"; \".join((f\"{c}: {k}\" for c, k in zip(self.turbine.condition_keys, key)))\n                label = f\"{self.turbine.turbine_type} - {_cond}\"\n                ax.plot(wind_speeds, _power_mw, label=label, **plot_kwargs)\n        else:\n            max_power = max(power_mw)\n            ax.plot(wind_speeds, power_mw, label=self.turbine.turbine_type, **plot_kwargs)\n\n        ax.grid()\n        ax.set_axisbelow(True)\n        ax.legend(**legend_kwargs)\n\n        max_power = round_nearest_2_or_5(max_power)\n        ax.set_xlim(min_windspeed, max_windspeed)\n        ax.set_ylim(min_power, max_power)\n\n        ax.set_xlabel(\"Wind Speed (m/s)\")\n        ax.set_ylabel(\"Power (MW)\")\n\n        if return_fig:\n            return fig, ax\n\n        fig.tight_layout()\n\n    def plot_thrust_coefficient_curve(\n        self,\n        wind_speeds: NDArrayFloat = DEFAULT_WIND_SPEEDS,\n        fig_kwargs: dict | None =  None,\n        plot_kwargs: dict | None =  None,\n        legend_kwargs: dict | None =  None,\n        return_fig: bool = False\n    ) -> None | tuple[plt.Figure, plt.Axes]:\n        \"\"\"Plots the thrust coefficient curve for a given set of wind speeds.\n\n        Args:\n            wind_speeds (NDArrayFloat, optional): A 1-D array of wind speeds, in m/s. Defaults to\n                0 m/s -> 40 m/s, every 0.5 m/s.\n            fig_kwargs (dict, optional): Any keywords arguments to be passed to ``plt.Figure()``.\n                Defaults to None.\n            plot_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.plot()``.\n                Defaults to None.\n            legend_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.legend()``.\n                Defaults to None.\n            return_fig (bool, optional): Indicator if the ``Figure`` and ``Axes`` objects should be\n                returned. Defaults to False.\n\n        Returns:\n            None | tuple[plt.Figure, plt.Axes]: None, if :py:attr:`return_fig` is False, otherwise\n                a tuple of the Figure and Axes objects are returned.\n        \"\"\"\n        wind_speeds, thrust = self.thrust_coefficient_curve(wind_speeds=wind_speeds)\n\n        # Initialize kwargs if None\n        fig_kwargs = {} if fig_kwargs is None else fig_kwargs\n        plot_kwargs = {} if plot_kwargs is None else plot_kwargs\n        legend_kwargs = {} if legend_kwargs is None else legend_kwargs\n\n        # Set the figure defaults if none are provided\n        fig_kwargs.setdefault(\"dpi\", 200)\n        fig_kwargs.setdefault(\"figsize\", (4, 3))\n\n        fig = plt.figure(**fig_kwargs)\n        ax = fig.add_subplot(111)\n\n        min_windspeed = 0\n        max_thrust = 0\n        max_windspeed = max(wind_speeds)\n        if isinstance(thrust, dict):\n            for key, _thrust in thrust.items():\n                max_thrust = max(max_thrust, *_thrust)\n                _cond = \"; \".join((f\"{c}: {k}\" for c, k in zip(self.turbine.condition_keys, key)))\n                label = f\"{self.turbine.turbine_type} - {_cond}\"\n                ax.plot(wind_speeds, _thrust, label=label, **plot_kwargs)\n        else:\n            max_thrust = max(thrust)\n            ax.plot(wind_speeds, thrust, label=self.turbine.turbine_type, **plot_kwargs)\n\n        ax.grid()\n        ax.set_axisbelow(True)\n        ax.legend(**legend_kwargs)\n\n        ax.set_xlim(min_windspeed, max_windspeed)\n        ax.set_ylim(0, round_nearest(max_thrust * 100, base=10) / 100)\n\n        ax.set_xlabel(\"Wind Speed (m/s)\")\n        ax.set_ylabel(\"Thrust Coefficient\")\n\n        if return_fig:\n            return fig, ax\n\n        fig.tight_layout()\n\n\n@define(auto_attribs=True)\nclass TurbineLibrary:\n    turbine_map: dict[str: TurbineInterface] = field(factory=dict)\n    power_curves: dict[str, tuple[NDArrayFloat, NDArrayFloat]] = field(factory=dict)\n    thrust_coefficient_curves: dict[str, tuple[NDArrayFloat, NDArrayFloat]] = field(factory=dict)\n\n    def load_internal_library(self, which: list[str] = [], exclude: list[str] = []) -> None:\n        \"\"\"Loads all of the turbine configurations from ``floris/floris/turbine_libary``,\n        except any turbines defined in :py:attr:`exclude`.\n\n        Args:\n            which (list[str], optional): A list of which file names to include from loading.\n                Defaults to [].\n            exclude (list[str], optional): A list of file names to exclude from loading.\n                Defaults to [].\n        \"\"\"\n        print(DEPRECATION_MESSAGE)\n        include = [el for el in INTERNAL_LIBRARY.iterdir() if el.suffix in (\".yaml\", \".yml\")]\n        which = [INTERNAL_LIBRARY / el for el in which] if which != [] else include\n        exclude = [INTERNAL_LIBRARY / el for el in exclude]\n        include = set(which).intersection(include).difference(exclude)\n        for fn in include:\n            turbine_dict = load_yaml(fn)\n            self.turbine_map.update({\n                turbine_dict[\"turbine_type\"]: TurbineInterface.from_turbine_dict(turbine_dict)\n            })\n\n    def load_external_library(\n            self,\n            library_path: str | Path,\n            which: list[str] = [],\n            exclude: list[str] = [],\n        ) -> None:\n        \"\"\"Loads all the turbine configurations from :py:attr:`library_path`, except the file names\n        defined in :py:attr:`exclude`, and adds each to ``turbine_map`` via a dictionary\n        update.\n\n        Args:\n            library_path : str | Path\n                The external turbine library that should be used for loading the turbines.\n            which (list[str], optional): A list of which file names to include from loading.\n                Defaults to [].\n            exclude (list[str], optional): A list of file names to exclude from loading.\n                Defaults to [].\n        \"\"\"\n        print(DEPRECATION_MESSAGE)\n        library_path = Path(library_path).resolve()\n        include = [el for el in library_path.iterdir() if el.suffix in (\".yaml\", \".yml\")]\n        which = [library_path / el for el in which] if which != [] else include\n        exclude = [library_path / el for el in exclude]\n        include = set(which).intersection(include).difference(exclude)\n        for fn in include:\n            turbine_dict = load_yaml(fn)\n            self.turbine_map.update({\n                turbine_dict[\"turbine_type\"]: TurbineInterface.from_turbine_dict(turbine_dict)\n            })\n\n    def compute_power_curves(\n            self,\n            wind_speeds: NDArrayFloat = DEFAULT_WIND_SPEEDS,\n        ) -> None:\n        \"\"\"Computes the power curves for each turbine in ``turbine_map`` and sets the\n        ``power_curves`` attribute.\n\n        Args:\n            wind_speeds (NDArrayFloat, optional): A 1-D array of wind speeds, in m/s. Defaults to\n                0 m/s -> 40 m/s, every 0.5 m/s.\n        \"\"\"\n        self.power_curves = {\n            name: t.power_curve(wind_speeds) for name, t in self.turbine_map.items()\n        }\n\n    def compute_thrust_coefficient_curves(\n            self,\n            wind_speeds: NDArrayFloat = DEFAULT_WIND_SPEEDS,\n        ) -> None:\n        \"\"\"Computes the thrust curves for each turbine in ``turbine_map`` and sets the\n        ``thrust_coefficient_curves`` attribute.\n\n        Args:\n            wind_speeds (NDArrayFloat, optional): A 1-D array of wind speeds, in m/s. Defaults to\n                0 m/s -> 40 m/s, every 0.5 m/s.\n        \"\"\"\n        self.thrust_coefficient_curves = {\n            name: t.thrust_coefficient_curve(wind_speeds) for name, t in self.turbine_map.items()\n        }\n\n    def plot_power_curves(\n        self,\n        fig: plt.Figure | None = None,\n        ax: plt.Axes | None = None,\n        which: list[str] = [],\n        exclude: list[str] = [],\n        wind_speeds: NDArrayFloat = DEFAULT_WIND_SPEEDS,\n        fig_kwargs: dict | None = None,\n        plot_kwargs: dict | None = None,\n        legend_kwargs: dict | None = None,\n        return_fig: bool = False,\n        show: bool = False,\n    ) -> None | tuple[plt.Figure, plt.Axes]:\n        \"\"\"Plots each power curve in ``turbine_map`` in a single plot.\n\n        Args:\n            fig (plt.figure, optional): A pre-made figure where the plot should exist.\n            ax (plt.Axes, optional): A pre-initialized axes object that should be used for the plot.\n            which (list[str], optional): A list of which turbine types/names to include. Defaults to\n                [].\n            exclude (list[str], optional): A list of turbine types/names names to exclude. Defaults\n                to [].\n            wind_speeds (NDArrayFloat, optional): A 1-D array of wind speeds, in m/s. Defaults to\n                0 m/s -> 40 m/s, every 0.5 m/s.\n            fig_kwargs (dict, optional): Any keywords arguments to be passed to ``plt.Figure()``.\n                Defaults to None.\n            plot_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.plot()``.\n                Defaults to None.\n            legend_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.legend()``.\n                Defaults to None.\n            return_fig (bool, optional): Indicator if the ``Figure`` and ``Axes`` objects should be\n                returned. Defaults to False.\n            show (bool, optional): Indicator if the figure should be automatically displayed.\n                Defaults to False.\n\n        Returns:\n            None | tuple[plt.Figure, plt.Axes]: None, if :py:attr:`return_fig` is False, otherwise\n                a tuple of the Figure and Axes objects are returned.\n        \"\"\"\n        if self.power_curves == {} or wind_speeds is not None:\n            self.compute_power_curves(wind_speeds=wind_speeds)\n\n        which = [*self.turbine_map] if which == [] else which\n\n        # Initialize kwargs if None\n        fig_kwargs = {} if fig_kwargs is None else fig_kwargs\n        plot_kwargs = {} if plot_kwargs is None else plot_kwargs\n        legend_kwargs = {} if legend_kwargs is None else legend_kwargs\n\n        # Set the figure defaults if none are provided\n        if fig is None:\n            fig_kwargs.setdefault(\"dpi\", 200)\n            fig_kwargs.setdefault(\"figsize\", (4, 3))\n\n            fig = plt.figure(**fig_kwargs)\n        if ax is None:\n            ax = fig.add_subplot(111)\n\n        min_windspeed = 0\n        max_windspeed = 0\n        min_power = 0\n        max_power = 0\n        for name, (ws, p) in self.power_curves.items():\n            if name in exclude or name not in which:\n                continue\n            if isinstance(p, dict):\n                max_windspeed = max(ws.max(), max_windspeed)\n                for k, _p in p.items():\n                    max_power = max(_p.max(), max_power)\n                    label = f\"{name} - {k}\"\n                    ax.plot(ws, _p, label=label, linestyle=\"--\", **plot_kwargs)\n            else:\n                max_power = max(p.max(), max_power)\n                max_windspeed = max(ws.max(), max_windspeed)\n                ax.plot(ws, p, label=name, **plot_kwargs)\n\n        ax.grid()\n        ax.set_axisbelow(True)\n        ax.legend(**legend_kwargs)\n\n        max_power = round_nearest(max_power, base=5)\n        ax.set_xlim(min_windspeed, max_windspeed)\n        ax.set_ylim(min_power, max_power)\n\n        ax.set_xlabel(\"Wind Speed (m/s)\")\n        ax.set_ylabel(\"Power (MW)\")\n\n        if return_fig:\n            return fig, ax\n\n        if show:\n            fig.tight_layout()\n\n    def plot_thrust_coefficient_curves(\n        self,\n        fig: plt.Figure | None = None,\n        ax: plt.Axes | None = None,\n        which: list[str] = [],\n        exclude: list[str] = [],\n        wind_speeds: NDArrayFloat = DEFAULT_WIND_SPEEDS,\n        fig_kwargs: dict | None =  None,\n        plot_kwargs: dict | None =  None,\n        legend_kwargs: dict | None =  None,\n        return_fig: bool = False,\n        show: bool = False,\n    ) -> None | tuple[plt.Figure, plt.Axes]:\n        \"\"\"Plots each thrust coefficient curve in ``turbine_map`` in a single plot.\n\n        Args:\n            fig (plt.figure, optional): A pre-made figure where the plot should exist.\n            ax (plt.Axes, optional): A pre-initialized axes object that should be used for the plot.\n            which (list[str], optional): A list of which turbine types/names to include. Defaults to\n                [].\n            exclude (list[str], optional): A list of turbine types/names names to exclude. Defaults\n                to [].\n            wind_speeds (NDArrayFloat, optional): A 1-D array of wind speeds, in m/s. Defaults to\n                0 m/s -> 40 m/s, every 0.5 m/s.\n            fig_kwargs (dict, optional): Any keywords arguments to be passed to ``plt.Figure()``.\n                Defaults to None.\n            plot_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.plot()``.\n                Defaults to None.\n            plot_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.legend()``.\n                Defaults to None.\n            return_fig (bool, optional): Indicator if the ``Figure`` and ``Axes`` objects should be\n                returned. Defaults to False.\n            show (bool, optional): Indicator if the figure should be automatically displayed.\n                Defaults to False.\n\n        Returns:\n            None | tuple[plt.Figure, plt.Axes]: None, if :py:attr:`return_fig` is False, otherwise\n                a tuple of the Figure and Axes objects are returned.\n        \"\"\"\n        if self.thrust_coefficient_curves == {} or wind_speeds is None:\n            self.compute_thrust_coefficient_curves(wind_speeds=wind_speeds)\n\n        which = [*self.turbine_map] if which == [] else which\n\n        # Initialize kwargs if None\n        fig_kwargs = {} if fig_kwargs is None else fig_kwargs\n        plot_kwargs = {} if plot_kwargs is None else plot_kwargs\n        legend_kwargs = {} if legend_kwargs is None else legend_kwargs\n\n\n        # Set the figure defaults if none are provided\n        if fig is None:\n            fig_kwargs.setdefault(\"dpi\", 200)\n            fig_kwargs.setdefault(\"figsize\", (4, 3))\n\n            fig = plt.figure(**fig_kwargs)\n        if ax is None:\n            ax = fig.add_subplot(111)\n\n        min_windspeed = 0\n        max_windspeed = 0\n        max_thrust = 0\n        for name, (ws, t) in self.thrust_coefficient_curves.items():\n            if name in exclude or name not in which:\n                continue\n            if isinstance(t, dict):\n                max_windspeed = max(ws.max(), max_windspeed)\n                for k, _t in t.items():\n                    max_thrust = max(_t.max(), max_thrust)\n                    label = f\"{name} - {k}\"\n                    ax.plot(ws, _t, label=label, linestyle=\"--\", **plot_kwargs)\n            else:\n                max_windspeed = max(ws.max(), max_windspeed)\n                max_thrust = max(t.max(), max_thrust)\n                ax.plot(ws, t, label=name, **plot_kwargs)\n\n        ax.grid()\n        ax.set_axisbelow(True)\n        ax.legend(**legend_kwargs)\n\n        ax.set_xlim(min_windspeed, max_windspeed)\n        ax.set_ylim(0, round_nearest(max_thrust * 100, base=10) / 100)\n\n        ax.set_xlabel(\"Wind Speed (m/s)\")\n        ax.set_ylabel(\"Thrust Coefficient\")\n\n        if return_fig:\n            return fig, ax\n\n        if show:\n            fig.tight_layout()\n\n    def plot_rotor_diameters(\n        self,\n        fig: plt.Figure | None = None,\n        ax: plt.Axes | None = None,\n        which: list[str] = [],\n        exclude: list[str] = [],\n        fig_kwargs: dict | None =  None,\n        bar_kwargs: dict | None =  None,\n        return_fig: bool = False,\n        show: bool = False,\n    ) -> None | tuple[plt.Figure, plt.Axes]:\n        \"\"\"Plots a bar chart of rotor diameters for each turbine in ``turbine_map``.\n\n        Args:\n            fig (plt.figure, optional): A pre-made figure where the plot should exist.\n            ax (plt.Axes, optional): A pre-initialized axes object that should be used for the plot.\n            which (list[str], optional): A list of which turbine types/names to include. Defaults to\n                [].\n            exclude (list[str], optional): A list of turbine types/names names to exclude. Defaults\n                to [].\n            fig_kwargs (dict, optional): Any keywords arguments to be passed to ``plt.Figure()``.\n                Defaults to None.\n            bar_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.bar()``.\n                Defaults to None.\n            return_fig (bool, optional): Indicator if the ``Figure`` and ``Axes`` objects should be\n                returned. Defaults to False.\n            show (bool, optional): Indicator if the figure should be automatically displayed.\n                Defaults to False.\n\n        Returns:\n            None | tuple[plt.Figure, plt.Axes]: None, if :py:attr:`return_fig` is False, otherwise\n                a tuple of the Figure and Axes objects are returned.\n        \"\"\"\n        which = [*self.turbine_map] if which == [] else which\n\n        # Initialize kwargs if None\n        fig_kwargs = {} if fig_kwargs is None else fig_kwargs\n        bar_kwargs = {} if bar_kwargs is None else bar_kwargs\n\n        # Set the figure defaults if none are provided\n        if fig is None:\n            fig_kwargs.setdefault(\"dpi\", 200)\n            fig_kwargs.setdefault(\"figsize\", (4, 3))\n\n            fig = plt.figure(**fig_kwargs)\n        if ax is None:\n            ax = fig.add_subplot(111)\n\n        subset_map = {\n            name: t for name, t in self.turbine_map.items()\n            if name not in exclude or name in which\n        }\n        x = np.arange(len(subset_map))\n        y = [ti.turbine.rotor_diameter for ti in subset_map.values()]\n        ix_sort = np.argsort(y)\n        y_sorted = np.array(y)[ix_sort]\n        ax.bar(x, y_sorted, **bar_kwargs)\n\n        ax.grid(axis=\"y\")\n        ax.set_axisbelow(True)\n\n        ax.set_xlim(-0.5, len(x) - 0.5)\n        ax.set_ylim(0, round_nearest(max(y) / 10, base=5) * 10)\n\n        ax.set_xticks(x)\n        ax.set_xticklabels(np.array([*subset_map])[ix_sort], rotation=30, ha=\"right\")\n        ax.set_ylabel(\"Rotor Diameter (m)\")\n\n        if return_fig:\n            return fig, ax\n\n        if show:\n            fig.tight_layout()\n\n    def plot_hub_heights(\n        self,\n        fig: plt.Figure | None = None,\n        ax: plt.Axes | None = None,\n        which: list[str] = [],\n        exclude: list[str] = [],\n        fig_kwargs: dict | None =  None,\n        bar_kwargs: dict | None =  None,\n        return_fig: bool = False,\n        show: bool = False,\n    ) -> None | tuple[plt.Figure, plt.Axes]:\n        \"\"\"Plots a bar chart of hub heights for each turbine in ``turbine_map``.\n\n        Args:\n            fig (plt.figure, optional): A pre-made figure where the plot should exist.\n            ax (plt.Axes, optional): A pre-initialized axes object that should be used for the plot.\n            which (list[str], optional): A list of which turbine types/names to include. Defaults to\n                [].\n            exclude (list[str], optional): A list of turbine types/names names to exclude. Defaults\n                to [].\n            fig_kwargs (dict, optional): Any keywords arguments to be passed to ``plt.Figure()``.\n                Defaults to None.\n            bar_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.bar()``.\n                Defaults to None.\n            return_fig (bool, optional): Indicator if the ``Figure`` and ``Axes`` objects should be\n                returned. Defaults to False.\n            show (bool, optional): Indicator if the figure should be automatically displayed.\n                Defaults to False.\n\n        Returns:\n            None | tuple[plt.Figure, plt.Axes]: None, if :py:attr:`return_fig` is False, otherwise\n                a tuple of the Figure and Axes objects are returned.\n        \"\"\"\n        which = [*self.turbine_map] if which == [] else which\n\n        # Initialize kwargs if None\n        fig_kwargs = {} if fig_kwargs is None else fig_kwargs\n        bar_kwargs = {} if bar_kwargs is None else bar_kwargs\n\n        # Set the figure defaults if none are provided\n        if fig is None:\n            fig_kwargs.setdefault(\"dpi\", 200)\n            fig_kwargs.setdefault(\"figsize\", (4, 3))\n\n            fig = plt.figure(**fig_kwargs)\n        if ax is None:\n            ax = fig.add_subplot(111)\n\n        subset_map = {\n            name: t for name, t in self.turbine_map.items()\n            if name not in exclude or name in which\n        }\n        x = np.arange(len(subset_map))\n        y = [ti.turbine.hub_height for ti in subset_map.values()]\n        ix_sort = np.argsort(y)\n        y_sorted = np.array(y)[ix_sort]\n        ax.bar(x, y_sorted, **bar_kwargs)\n\n        ax.grid(axis=\"y\")\n        ax.set_axisbelow(True)\n\n        ax.set_xlim(-0.5, len(x) - 0.5)\n        ax.set_ylim(0, round_nearest(max(y) / 10, base=5) * 10)\n\n        ax.set_xticks(x)\n        ax.set_xticklabels(np.array([*subset_map])[ix_sort], rotation=30, ha=\"right\")\n        ax.set_ylabel(\"Hub Height (m)\")\n\n        if return_fig:\n            return fig, ax\n\n        if show:\n            fig.tight_layout()\n\n    def plot_comparison(\n        self,\n        which: list[str] = [],\n        exclude: list[str] = [],\n        wind_speeds: NDArrayFloat = DEFAULT_WIND_SPEEDS,\n        fig_kwargs: dict | None =  None,\n        plot_kwargs: dict | None =  None,\n        bar_kwargs: dict | None =  None,\n        legend_kwargs: dict | None =  None,\n        return_fig: bool = False\n    ) -> None | tuple[plt.Figure, list[plt.Axes]]:\n        \"\"\"Plots each thrust curve in ``turbine_map`` in a single plot.\n\n        Args:\n            which (list[str], optional): A list of which turbine types/names to include. Defaults to\n                [].\n            exclude (list[str], optional): A list of turbine types/names names to exclude. Defaults\n                to [].\n            wind_speeds (NDArrayFloat, optional): A 1-D array of wind speeds, in m/s. Defaults to\n                0 m/s -> 40 m/s, every 0.5 m/s.\n            fig_kwargs (dict, optional): Any keywords arguments to be passed to ``plt.Figure()``.\n                Defaults to None.\n            plot_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.plot()``.\n                Defaults to None.\n            bar_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.bar()``.\n                Defaults to None.\n            legend_kwargs (dict, optional): Any keyword arguments to be passed to ``plt.legend()``.\n                Defaults to None.\n            return_fig (bool, optional): Indicator if the ``Figure`` and ``Axes`` objects should be\n                returned. Defaults to False.\n\n        Returns:\n            None | tuple[plt.Figure, list[plt.Axes]]: None, if :py:attr:`return_fig` is False,\n                otherwise a tuple of the Figure and Axes objects are returned.\n        \"\"\"\n        # Initialize kwargs if None\n        fig_kwargs = {} if fig_kwargs is None else fig_kwargs\n        plot_kwargs = {} if plot_kwargs is None else plot_kwargs\n        bar_kwargs = {} if bar_kwargs is None else bar_kwargs\n        legend_kwargs = {} if legend_kwargs is None else legend_kwargs\n\n        # Set the figure defaults if none are provided\n        fig_kwargs.setdefault(\"dpi\", 200)\n        fig_kwargs.setdefault(\"figsize\", (6, 5))\n        legend_kwargs.setdefault(\"fontsize\", 6)\n\n        fig = plt.figure(**fig_kwargs)\n        ax1 = fig.add_subplot(321)\n        ax2 = fig.add_subplot(322)\n        ax3 = fig.add_subplot(323)\n        ax4 = fig.add_subplot(324)\n        ax_list = [ax1, ax2, ax3, ax4]\n\n        self.plot_power_curves(\n            fig,\n            ax1,\n            which=which,\n            exclude=exclude,\n            wind_speeds=wind_speeds,\n            plot_kwargs=plot_kwargs,\n        )\n        self.plot_thrust_coefficient_curves(\n            fig,\n            ax3,\n            which=which,\n            exclude=exclude,\n            wind_speeds=wind_speeds,\n            plot_kwargs=plot_kwargs,\n        )\n        self.plot_rotor_diameters(fig, ax2, which=which, exclude=exclude, bar_kwargs=bar_kwargs)\n        self.plot_hub_heights(fig, ax4, which=which, bar_kwargs=bar_kwargs)\n\n        for ax in ax_list:\n            ax.tick_params(axis='both', which='major', labelsize=7)\n            ax.xaxis.label.set_size(7)\n            ax.yaxis.label.set_size(8)\n\n        for ax in (ax1, ax3):\n            ax.legend(**legend_kwargs)\n\n        if return_fig:\n            return fig, ax_list\n\n        fig.tight_layout()\n"
  },
  {
    "path": "floris/turbine_library/turbine_utilities.py",
    "content": "from collections.abc import Iterable\n\nimport numpy as np\nimport yaml\n\n\ndef build_cosine_loss_turbine_dict(\n    turbine_data_dict,\n    turbine_name,\n    file_name=None,\n    generator_efficiency=None,\n    hub_height=90.0,\n    cosine_loss_exponent_yaw=1.88,\n    cosine_loss_exponent_tilt=1.88,\n    rotor_diameter=125.88,\n    TSR=8.0,\n    ref_air_density=1.225,\n    ref_tilt=5.0\n):\n    \"\"\"\n    Tool for formatting a full turbine dict from data formatted as a\n    dictionary.\n\n    Default value for turbine physical parameters are from the NREL 5MW reference\n    wind turbine.\n\n    Returns a turbine dictionary object as expected by FLORIS. Optionally,\n    prints the dictionary to a yaml to be included in a FLORIS wake model yaml.\n\n    turbine_data is a dictionary that contains keys specifying the\n    turbine power and thrust as a function of wind speed. The following keys\n    are possible:\n    - wind_speed [m/s]\n    - power [kW]\n    - power_coefficient [-]\n    - thrust [kN]\n    - thrust_coefficient [-]\n    Of these, wind_speed is required. One of power and power_coefficient\n    must be specified; and one of thrust and thrust_coefficient must be\n    specified. If both (absolute) and _coefficient versions are specified, the\n    (absolute) power will be used along with the thrust_coefficient, with the\n    other entries ignored.\n\n    Args:\n        turbine_data_dict (dict): Dictionary containing performance of the wind\n            turbine as a function of wind speed. Described in more detail above.\n        turbine_name (string): Name of the turbine, which will be used for the\n            turbine_type field as well as the filename.\n        file_name (): Name for the produced yaml, including possibly path.\n            Defaults to None, in which case no yaml is written.\n        generator_efficiency (float): Generator efficiency [-]. Unused if power is specified\n            in absolute terms in the turbine_data_dict. Must be specified if\n            power not specified and power_coefficient specified instead. Defaults to None.\n        hub_height (float): Hub height [m]. Defaults to 90.0.\n        cosine_loss_exponent_yaw (float): Cosine exponent for power loss to yaw [-].\n            Defaults to 1.88.\n        cosine_loss_exponent_tilt (float): Cosine exponent for thrust loss to yaw [-].\n            Defaults to 1.88.\n        rotor_diameter (float). Rotor diameter [m]. Defaults to 126.0.\n        TSR (float). Turbine optimal tip-speed ratio [-]. Defaults to 8.0.\n        ref_air_density (float). Air density used to specify power and thrust\n            curves [kg/m^3]. Defaults to 1.225.\n        ref_tilt (float). Rotor tilt (due to shaft tilt and/or platform\n            tilt) used when defining the power and thrust curves [deg]. Defaults\n            to 5.0.\n\n    Returns:\n        turbine_dict (dict): Formatted turbine dictionary as expected by FLORIS.\n    \"\"\"\n\n    # Check that necessary columns are specified\n    if \"wind_speed\" not in turbine_data_dict:\n        raise KeyError(\"wind_speed column must be specified.\")\n    u = np.array(turbine_data_dict[\"wind_speed\"])\n    A = np.pi * rotor_diameter**2/4\n\n    # Construct the Cp curve\n    if \"power\" in turbine_data_dict:\n        if \"power_coefficient\" in turbine_data_dict:\n            print(\n                \"Found both power and power_coefficient. \"\n                \"Ignoring power_coefficient.\"\n            )\n        p = np.array(turbine_data_dict[\"power\"])\n\n    elif \"power_coefficient\" in turbine_data_dict:\n        if generator_efficiency is None:\n            raise KeyError(\n                \"generator_efficiency must be specified to convert power_coefficient to power.\"\n            )\n        Cp = np.array(turbine_data_dict[\"power_coefficient\"])\n        if _find_nearest_value_for_wind_speed(Cp, u, 10) > 16.0/27.0 or \\\n           _find_nearest_value_for_wind_speed(Cp, u, 10) < 0.0:\n           print(\n               \"Unusual power coefficient detected. Check that power coefficients\"\n               \"are physical.\"\n           )\n\n        validity_mask = (Cp != 0) | (u != 0)\n        p = np.zeros_like(Cp, dtype=float)\n\n        p[validity_mask] = (\n            Cp[validity_mask]\n            * 0.5 * ref_air_density * A * generator_efficiency\n            * u[validity_mask]**3 / 1000\n        )\n\n    else:\n        raise KeyError(\n            \"Either power or power_coefficient must be specified.\"\n        )\n\n    # Construct Ct curve\n    if \"thrust_coefficient\" in turbine_data_dict:\n        if \"thrust\" in turbine_data_dict:\n            print(\n                \"Found both thrust and thrust_coefficient. \"\n                \"Ignoring thrust.\"\n            )\n        Ct = np.array(turbine_data_dict[\"thrust_coefficient\"])\n\n    elif \"thrust\" in turbine_data_dict:\n        T = np.array(turbine_data_dict[\"thrust\"])\n        if _find_nearest_value_for_wind_speed(T, u, 10) > 3000 or \\\n           _find_nearest_value_for_wind_speed(T, u, 10) < 100:\n           print(\n               \"Unusual thrust value detected. Please check that thrust\",\n               \"is specified in kN.\"\n           )\n\n        validity_mask = (T != 0) | (u != 0)\n        Ct = np.zeros_like(T)\n\n        Ct[validity_mask] = (T[validity_mask]*1000)/\\\n                            (0.5*ref_air_density*A*u[validity_mask]**2)\n\n    else:\n        raise KeyError(\n            \"Either thrust or thrust_coefficient must be specified.\"\n        )\n\n    # Build the turbine dict\n    power_thrust_dict = {\n        \"ref_air_density\": ref_air_density,\n        \"ref_tilt\": ref_tilt,\n        \"cosine_loss_exponent_yaw\": cosine_loss_exponent_yaw,\n        \"cosine_loss_exponent_tilt\": cosine_loss_exponent_tilt,\n        \"wind_speed\": u.tolist(),\n        \"power\": p.tolist(),\n        \"thrust_coefficient\": Ct.tolist()\n    }\n\n    turbine_dict = {\n        \"turbine_type\": turbine_name,\n        \"hub_height\": hub_height,\n        \"rotor_diameter\": rotor_diameter,\n        \"TSR\": TSR,\n        \"operation_model\": \"cosine-loss\",\n        \"power_thrust_table\": power_thrust_dict\n    }\n\n    # Create yaml file\n    if file_name is not None:\n        yaml.dump(\n            turbine_dict,\n            open(file_name, \"w\"),\n            sort_keys=False\n        )\n\n        print(file_name, \"created.\")\n\n    return turbine_dict\n\ndef _find_nearest_value_for_wind_speed(test_vals, ws_vals, ws):\n    errs = np.absolute(ws_vals-ws)\n    idx = errs.argmin()\n    return test_vals[idx]\n\ndef check_smooth_power_curve(power, tolerance=0.001):\n    \"\"\"\n    Check whether there are \"wiggles\" in the power signal.\n    \"\"\"\n\n    if power[-1] < 0.95*max(power): # Cut-out or shutdown included\n        expected_changes = 2\n    else: # Shutdown appears not to be included\n        expected_changes = 1\n\n    dirs = np.where(\n        np.abs(np.diff(power)) > tolerance,\n        np.sign(np.diff(power)),\n        np.zeros(len(power)-1)\n    )\n    dir_changes = np.sum(np.abs(np.diff(dirs)))\n    is_smooth = dir_changes <= expected_changes\n\n    return is_smooth\n"
  },
  {
    "path": "floris/type_dec.py",
    "content": "import copy\nimport inspect\nfrom pathlib import Path\nfrom typing import (\n    Any,\n    Callable,\n    Iterable,\n    Tuple,\n    Union,\n)\n\nimport attrs\nimport numpy as np\nimport numpy.typing as npt\nfrom attrs import Attribute, define\n\n\n### Define general data types used throughout\n\nfloris_float_type = np.float64\n\nNDArrayFloat = npt.NDArray[floris_float_type]\nNDArrayInt = npt.NDArray[np.int_]\nNDArrayFilter = Union[npt.NDArray[np.int_], npt.NDArray[np.bool_]]\nNDArrayObject = npt.NDArray[np.object_]\nNDArrayBool = npt.NDArray[np.bool_]\nNDArrayStr = npt.NDArray[np.str_]\n\n\n### Custom callables for attrs objects and functions\n\ndef floris_array_converter(data: Iterable) -> np.ndarray:\n    \"\"\"\n    For a given iterable, convert the data to a numpy array and cast to `floris_float_type`.\n    If the input is a scalar, np.array() creates a 0-dimensional array, and this is not supported\n    in FLORIS so this function raises an error.\n\n    Args:\n        data (Iterable): The input data to be converted to a Numpy array.\n\n    Raises:\n        TypeError: Raises if the input data is not iterable.\n        TypeError: Raises if the input data cannot be converted to a Numpy array.\n\n    Returns:\n        np.ndarray: data converted to a Numpy array and cast to `floris_float_type`.\n    \"\"\"\n    try:\n        iter(data)\n    except TypeError as e:\n        raise TypeError(e.args[0] + f\". Data given: {data}\")\n\n    try:\n        a = np.array(data, dtype=floris_float_type)\n    except (TypeError, ValueError) as e:\n        raise TypeError(e.args[0] + f\". Data given: {data}\")\n    return a\n\ndef floris_numeric_dict_converter(data: dict) -> dict:\n    \"\"\"\n    For the given dictionary, convert all the values to a numeric type. If a value is a scalar, it\n    will be converted to a float. If a value is an iterable, it will be converted to a Numpy\n    array and cast to `floris_float_type`. If a value is not a numeric type, a TypeError will be\n    raised.\n\n    Args:\n        data (dict): Dictionary of data to be converted to a numeric type.\n\n    Returns:\n        dict: Dictionary with the same keys and all values converted to a numeric type.\n    \"\"\"\n    converted_dict = copy.deepcopy(data)  # deepcopy -> data is a container and passed by reference\n    for k, v in data.items():\n        try:\n            iter(v)\n        except TypeError:\n            # Not iterable so try to cast to float\n            converted_dict[k] = float(v)\n        else:\n            # Iterable so convert to Numpy array\n            converted_dict[k] = floris_array_converter(v)\n    return converted_dict\n\n# def array_field(**kwargs) -> Callable:\n#     \"\"\"\n#     A wrapper for the :py:func:`attr.field` function that converts the input to a Numpy array,\n#     adds a comparison function specific to Numpy arrays, and passes through all additional\n#     keyword arguments.\n#     \"\"\"\n#     return field(\n#         converter=floris_array_converter,\n#         eq=cmp_using(eq=np.array_equal),\n#         **kwargs\n#     )\n\ndef _attr_serializer(inst: type, field: Attribute, value: Any):\n    if isinstance(value, np.ndarray):\n        return value.tolist()\n    return value\n\ndef _attr_floris_filter(inst: Attribute, value: Any) -> bool:\n    if inst.init is False:\n        return False\n    if value is None:\n        return False\n\n    # This is removed to support initializing FLORIS with default values:\n    # - defaults added in https://github.com/NatLabRockies/floris/pull/1040\n    # - bug fix in https://github.com/NatLabRockies/floris/pull/1061\n    # When Core is exported to a dict in _reinitialize, this filter removes empty arrays.\n    # For init with defaults, this results in FlowField losing the wind speed, wind direction and TI\n    # arrays if they weren't provided in the .set function.\n    # if isinstance(value, np.ndarray):\n    #     if value.size == 0:\n    #         return False\n    return True\n\ndef iter_validator(iter_type, item_types: Union[Any, Tuple[Any]]) -> Callable:\n    \"\"\"\n    Helper function to generate iterable validators that will reduce the amount of\n    boilerplate code.\n\n    Args:\n        iter_type (iterable): The type of iterable object that should be validated.\n        item_types (Union[Any, Tuple[Any]]): The type or types of acceptable item types.\n\n    Returns:\n        Callable: The attr.validators.deep_iterable iterable and instance validator.\n    \"\"\"\n    validator = attrs.validators.deep_iterable(\n        member_validator=attrs.validators.instance_of(item_types),\n        iterable_validator=attrs.validators.instance_of(iter_type),\n    )\n    return validator\n\ndef convert_to_path(fn: str | Path) -> Path:\n    \"\"\"\n    Converts an input string or ``pathlib.Path`` object to a fully resolved ``pathlib.Path``\n    object. If the input is a string, it is converted to a pathlib.Path object.\n    The function then checks if the path exists as an absolute path, a relative path from\n    the script, or a relative path from the system location. If the path does not exist in\n    any of these locations, a FileExistsError is raised.\n\n    Args:\n        fn (str | Path): The user input file path or file name.\n\n    Raises:\n        FileExistsError: Raised if :py:attr:`fn` is not able to be found as an absolute path, nor as\n            a relative path.\n        TypeError: Raised if :py:attr:`fn` is neither a :py:obj:`str`, nor a :py:obj:`pathlib.Path`.\n\n    Returns:\n        Path: A resolved pathlib.Path object.\n    \"\"\"\n    if isinstance(fn, str):\n        fn = Path(fn)\n\n    # Get the base path from where the analysis script was run to determine the relative\n    # path from which `fn` might be based. [1] is where a direct call to this function will be\n    # located (e.g., testing via pytest), and [-1] is where a direct call to the function via an\n    # analysis script will be located (e.g., running an example).\n    base_fn_script = Path(inspect.stack()[-1].filename).resolve().parent\n    base_fn_sys = Path(inspect.stack()[1].filename).resolve().parent\n\n    if isinstance(fn, Path):\n        absolute_fn = fn.resolve()\n        relative_fn_script = (base_fn_script / fn).resolve()\n        relative_fn_sys = (base_fn_sys / fn).resolve()\n        if absolute_fn.exists():\n            return absolute_fn\n        if relative_fn_script.exists():\n            return relative_fn_script\n        if relative_fn_sys.exists():\n            return relative_fn_sys\n        raise FileExistsError(\n            f\"{fn} could not be found as either a\\n\"\n            f\"  - relative file path from a script: {relative_fn_script}\\n\"\n            f\"  - relative file path from a system location: {relative_fn_sys}\\n\"\n            f\"  - or absolute file path: {absolute_fn}\"\n        )\n    raise TypeError(f\"The passed input: {fn} could not be converted to a pathlib.Path object\")\n\n\n@define\nclass FromDictMixin:\n    \"\"\"\n    A Mixin class to allow for kwargs overloading when a data class doesn't\n    have a specific parameter defined. This allows passing of larger dictionaries\n    to a data class without throwing an error.\n    \"\"\"\n\n    @classmethod\n    def from_dict(cls, data: dict):\n        \"\"\"Maps a data dictionary to an `attr`-defined class.\n\n        TODO: Add an error to ensure that either none or all the parameters are passed in\n\n        Args:\n            data : dict\n                The data dictionary to be mapped.\n        Returns:\n            cls\n                The `attr`-defined class.\n        \"\"\"\n        # Make a copy of the input dict to prevent any side effects\n        data = copy.deepcopy(data)\n\n        # Check for any inputs that aren't part of the class definition\n        class_attr_names = [a.name for a in cls.__attrs_attrs__]\n        extra_args = [d for d in data if d not in class_attr_names]\n        if len(extra_args):\n            raise AttributeError(\n                f\"The initialization for {cls.__name__} was given extraneous inputs: {extra_args}\"\n            )\n\n        kwargs = {a.name: data[a.name] for a in cls.__attrs_attrs__ if a.name in data and a.init}\n\n        # Map the inputs must be provided: 1) must be initialized, 2) no default value defined\n        required_inputs = [\n            a.name\n            for a in cls.__attrs_attrs__\n            if a.init and a.default is attrs.NOTHING\n        ]\n        undefined = sorted(set(required_inputs) - set(kwargs))\n\n        if undefined:\n            raise AttributeError(\n                f\"The class definition for {cls.__name__} \"\n                f\"is missing the following inputs: {undefined}\"\n            )\n        return cls(**kwargs)\n\n    def as_dict(self) -> dict:\n        \"\"\"Creates a YAML friendly dictionary that can be saved for future reloading.\n        This dictionary will contain only `Python` types that can later be converted to their\n        proper formats. See `_attr_floris_filter` for detail on which attributes are\n        removed from the export.\n\n        Returns:\n            dict: All key, value pairs required for class recreation.\n        \"\"\"\n        return attrs.asdict(self, filter=_attr_floris_filter, value_serializer=_attr_serializer)\n\n\n# Avoids constant redefinition of the same attr.ib properties for model attributes\n\n# from functools import partial, update_wrapper\n\n# def is_default(instance, attribute, value):\n#     if attribute.default != value:\n#         raise ValueError(f\"{attribute.name} should never be set manually.\")\n\n# model_attrib = partial(field, on_setattr=attrs.setters.frozen, validator=is_default)\n# update_wrapper(model_attrib, field)\n\n# float_attrib = partial(\n#     attr.ib,\n#     converter=float,\n#     on_setattr=(attr.setters.convert, attr.setters.validate),  # type: ignore\n#     kw_only=True,\n# )\n# update_wrapper(float_attrib, attr.ib)\n\n# bool_attrib = partial(\n#     attr.ib,\n#     converter=bool,\n#     on_setattr=(attr.setters.convert, attr.setters.validate),  # type: ignore\n#     kw_only=True,\n# )\n# update_wrapper(bool_attrib, attr.ib)\n\n# int_attrib = partial(\n#     attr.ib,\n#     converter=int,\n#     on_setattr=(attr.setters.convert, attr.setters.validate),  # type: ignore\n#     kw_only=True,\n# )\n# update_wrapper(int_attrib, attr.ib)\n"
  },
  {
    "path": "floris/uncertain_floris_model.py",
    "content": "from pathlib import Path\nfrom typing import (\n    Any,\n    List,\n    Optional,\n)\n\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom floris.core import average_velocity, State\nfrom floris.logging_manager import LoggingManager\nfrom floris.par_floris_model import ParFlorisModel\nfrom floris.type_dec import (\n    floris_array_converter,\n    NDArrayBool,\n    NDArrayFloat,\n)\nfrom floris.utilities import (\n    is_all_scalar_dict,\n    nested_get,\n    nested_set,\n    wrap_180,\n)\nfrom floris.wind_data import (\n    TimeSeries,\n    WindDataBase,\n    WindRose,\n    WindRoseWRG,\n    WindTIRose,\n)\n\n\nclass UncertainFlorisModel(LoggingManager):\n    \"\"\"\n    An interface for handling uncertainty in wind farm simulations.\n\n    This class contains a FlorisModel object and adds functionality to handle\n    uncertainty in wind direction.  It is designed to be used similarly to FlorisModel.\n    In the model, the turbine powers are computed for a set of expanded wind conditions,\n    given by wd_sample_points, and then the powers are computed as a gaussian blend\n    of these expanded conditions.\n\n    To reduce computational costs, the wind directions, wind speeds, turbulence intensities,\n    yaw angles, and power setpoints are rounded to specified resolutions.  Only unique\n    conditions from within the expanded set of conditions are run.\n\n    Args:\n        configuration (dict | str | Path | FlorisModel | ParFlorisModel):  The configuration\n            for the wind farm.  This can be a dictionary, a path to a yaml file, or a FlorisModel\n            or ParFlorisModel object.  If dict, str or Path, a new FlorisModel object is\n            created.  If a FlorisModel or ParFlorisModel object a copy of the object is made.\n        wd_resolution (float, optional): The resolution of wind direction for generating\n            gaussian blends, in degrees.  Defaults to 1.0.\n        ws_resolution (float, optional): The resolution of wind speed, in m/s. Defaults to 1.0.\n        ti_resolution (float, optional): The resolution of turbulence intensity.\n            Defaults to 0.01.\n        yaw_resolution (float, optional): The resolution of yaw angle, in degrees.\n            Defaults to 1.0.\n        power_setpoint_resolution (int, optional): The resolution of power setpoints, in kW.\n            Defaults to 100.\n        wd_std (float, optional): The standard deviation of wind direction. Defaults to 3.0.\n        wd_sample_points (list[float], optional): The sample points for wind direction.\n            If not provided, defaults to [-2 * wd_std, -1 * wd_std, 0, wd_std, 2 * wd_std].\n        fix_yaw_to_nominal_direction (bool, optional): Fix the yaw angle to the nominal\n            direction?   When False, the yaw misalignment is the same across the sampled wind\n            directions. When True, the turbine orientation is fixed to the nominal wind\n            direction such that the yaw misalignment changes depending on the sampled wind\n            direction.  Defaults to False.\n        verbose (bool, optional): Verbosity flag for printing messages. Defaults to False.\n    \"\"\"\n\n    def __init__(\n        self,\n        configuration: dict | str | Path | FlorisModel | ParFlorisModel,\n        wd_resolution=1.0,  # Degree\n        ws_resolution=1.0,  # m/s\n        ti_resolution=0.01,\n        yaw_resolution=1.0,  # Degree\n        power_setpoint_resolution=100,  # kW\n        awc_amplitude_resolution=0.1,  # Deg\n        wd_std=3.0,\n        wd_sample_points=None,\n        fix_yaw_to_nominal_direction=False,\n        verbose=False,\n    ):\n        # Check validity of inputs\n        if wd_std <= 0:\n            raise ValueError(\"wd_std must be strictly greater than 0.\")\n\n        # Save these inputs\n        self.wd_resolution = wd_resolution\n        self.ws_resolution = ws_resolution\n        self.ti_resolution = ti_resolution\n        self.yaw_resolution = yaw_resolution\n        self.power_setpoint_resolution = power_setpoint_resolution\n        self.awc_amplitude_resolution = awc_amplitude_resolution\n        self.wd_std = wd_std\n        self.fix_yaw_to_nominal_direction = fix_yaw_to_nominal_direction\n        self.verbose = verbose\n\n        # If wd_sample_points, default to 1 and 2 std\n        if wd_sample_points is None:\n            wd_sample_points = [-2 * wd_std, -1 * wd_std, 0, wd_std, 2 * wd_std]\n\n        self.wd_sample_points = wd_sample_points\n        self.n_sample_points = len(self.wd_sample_points)\n\n        # Get the weights\n        self.weights = self._get_weights(self.wd_std, self.wd_sample_points)\n\n        # Instantiate the un-expanded FlorisModel\n        if isinstance(configuration, (FlorisModel, ParFlorisModel)):\n            self.fmodel_unexpanded = configuration.copy()\n            # Copy over any control setpoints, wind data, if not already done.\n            self.fmodel_unexpanded.set(\n                yaw_angles=configuration.core.farm.yaw_angles,\n                power_setpoints=configuration.core.farm.power_setpoints,\n                awc_modes=configuration.core.farm.awc_modes,\n                awc_amplitudes=configuration.core.farm.awc_amplitudes,\n                awc_frequencies=configuration.core.farm.awc_frequencies,\n                wind_data=configuration.wind_data,\n            )\n        elif isinstance(configuration, (dict, str, Path)):\n            self.fmodel_unexpanded = FlorisModel(configuration)\n        else:\n            raise ValueError(\n                \"configuration must be a FlorisModel, ParFlorisModel, dict, str, or Path\"\n            )\n\n        # Call set at this point with no arguments so ready to run\n        self.set()\n\n\n    def set(\n        self,\n        **kwargs,\n    ):\n        \"\"\"\n        Set the wind farm conditions in the UncertainFlorisModel.\n\n        See FlorisModel.set() for details of the contents of kwargs.\n\n        Args:\n            **kwargs: The wind farm conditions to set.\n        \"\"\"\n        # Call the nominal set function\n        self.fmodel_unexpanded.set(**kwargs)\n\n        self._set_uncertain()\n\n    def _set_uncertain(\n        self,\n    ):\n        \"\"\"\n        Sets the underlying wind direction (wd), wind speed (ws), turbulence intensity (ti),\n          yaw angle, and power setpoint for unique conditions, accounting for uncertainties.\n\n        \"\"\"\n\n        # Grab the unexpanded values of all arrays\n        # These original dimensions are what is returned\n        self.wind_directions_unexpanded = self.fmodel_unexpanded.core.flow_field.wind_directions\n        self.wind_speeds_unexpanded = self.fmodel_unexpanded.core.flow_field.wind_speeds\n        self.turbulence_intensities_unexpanded = (\n            self.fmodel_unexpanded.core.flow_field.turbulence_intensities\n        )\n        self.yaw_angles_unexpanded = self.fmodel_unexpanded.core.farm.yaw_angles\n        self.power_setpoints_unexpanded = self.fmodel_unexpanded.core.farm.power_setpoints\n        self.awc_amplitudes_unexpanded = self.fmodel_unexpanded.core.farm.awc_amplitudes\n        self.n_unexpanded = len(self.wind_directions_unexpanded)\n\n        # Combine into the complete unexpanded_inputs\n        self.unexpanded_inputs = np.hstack(\n            (\n                self.wind_directions_unexpanded[:, np.newaxis],\n                self.wind_speeds_unexpanded[:, np.newaxis],\n                self.turbulence_intensities_unexpanded[:, np.newaxis],\n                self.yaw_angles_unexpanded,\n                self.power_setpoints_unexpanded,\n                self.awc_amplitudes_unexpanded,\n            )\n        )\n\n        # Get the rounded inputs\n        self.rounded_inputs = self._get_rounded_inputs(\n            self.unexpanded_inputs,\n            self.wd_resolution,\n            self.ws_resolution,\n            self.ti_resolution,\n            self.yaw_resolution,\n            self.power_setpoint_resolution,\n            self.awc_amplitude_resolution,\n        )\n\n        # Get the expanded inputs\n        self._expanded_wind_directions = self._expand_wind_directions(\n            self.rounded_inputs,\n            self.wd_sample_points,\n            self.fix_yaw_to_nominal_direction,\n            self.fmodel_unexpanded.core.farm.n_turbines,\n        )\n        self.n_expanded = self._expanded_wind_directions.shape[0]\n\n        # Get the unique inputs\n        self.unique_inputs, self.map_to_expanded_inputs = self._get_unique_inputs(\n            self._expanded_wind_directions\n        )\n        self.n_unique = self.unique_inputs.shape[0]\n\n        # Display info on sizes\n        if self.verbose:\n            print(f\"Original num rows: {self.n_unexpanded}\")\n            print(f\"Expanded num rows: {self.n_expanded}\")\n            print(f\"Unique num rows: {self.n_unique}\")\n\n        # Initiate the expanded FlorisModel\n        self.fmodel_expanded = self.fmodel_unexpanded.copy()\n\n        # Now set the underlying wd/ws/ti/yaw/setpoint to check only the unique conditions\n        self.fmodel_expanded.set(\n            wind_directions=self.unique_inputs[:, 0],\n            wind_speeds=self.unique_inputs[:, 1],\n            turbulence_intensities=self.unique_inputs[:, 2],\n            yaw_angles=self.unique_inputs[:, 3 : 3 + self.fmodel_unexpanded.core.farm.n_turbines],\n            power_setpoints=self.unique_inputs[\n                :,\n                3 + self.fmodel_unexpanded.core.farm.n_turbines : 3\n                + 2 * self.fmodel_unexpanded.core.farm.n_turbines,\n            ],\n            awc_amplitudes=self.unique_inputs[\n                :,\n                3 + 2 * self.fmodel_unexpanded.core.farm.n_turbines : 3\n                + 3 * self.fmodel_unexpanded.core.farm.n_turbines,\n            ],\n        )\n\n    def reset_operation(self):\n        \"\"\"\n        Reset the operation of the underlying FlorisModel object.\n        \"\"\"\n        self.fmodel_unexpanded.set(\n            wind_directions=self.wind_directions_unexpanded,\n            wind_speeds=self.wind_speeds_unexpanded,\n            turbulence_intensities=self.turbulence_intensities_unexpanded,\n        )\n        self.fmodel_unexpanded.reset_operation()\n\n        # Calling set_uncertain again to reset the expanded FlorisModel\n        self._set_uncertain()\n\n    def run(self):\n        \"\"\"\n        Run the simulation in the underlying FlorisModel object.\n        \"\"\"\n\n        self.fmodel_expanded.run()\n\n    def run_no_wake(self):\n        \"\"\"\n        Run the simulation in the underlying FlorisModel object without wakes.\n        \"\"\"\n\n        self.fmodel_expanded.run_no_wake()\n\n    def _get_turbine_powers(self):\n        \"\"\"Calculates the power at each turbine in the wind farm.\n\n        This method calculates the power at each turbine in the wind farm, considering\n        the underlying turbine powers and applying a weighted sum to handle uncertainty.\n\n        Returns:\n            NDArrayFloat: An array containing the powers at each turbine for each findex.\n\n        \"\"\"\n\n        # Pass to off-class function\n        result = map_turbine_values_uncertain(\n            unique_turbine_values=self.fmodel_expanded._get_turbine_powers(),\n            map_to_expanded_inputs=self.map_to_expanded_inputs,\n            weights=self.weights,\n            n_unexpanded=self.n_unexpanded,\n            n_sample_points=self.n_sample_points,\n            n_turbines=self.fmodel_unexpanded.core.farm.n_turbines,\n        )\n\n        return result\n\n    def get_turbine_powers(self):\n        \"\"\"\n        Calculate the power at each turbine in the wind farm.  If WindRose or\n           WindTIRose is passed in, result is reshaped to match\n\n        Returns:\n            NDArrayFloat: An array containing the powers at each turbine for each findex.\n        \"\"\"\n\n        turbine_powers = self._get_turbine_powers()\n\n        if self.fmodel_unexpanded.wind_data is not None:\n            if isinstance(self.fmodel_unexpanded.wind_data, (WindRose, WindRoseWRG)):\n                turbine_powers_rose = np.full(\n                    (\n                        len(self.fmodel_unexpanded.wind_data.wd_flat),\n                        self.fmodel_unexpanded.core.farm.n_turbines,\n                    ),\n                    np.nan,\n                )\n                turbine_powers_rose[self.fmodel_unexpanded.wind_data.non_zero_freq_mask, :] = (\n                    turbine_powers\n                )\n                turbine_powers = turbine_powers_rose.reshape(\n                    len(self.fmodel_unexpanded.wind_data.wind_directions),\n                    len(self.fmodel_unexpanded.wind_data.wind_speeds),\n                    self.fmodel_unexpanded.core.farm.n_turbines,\n                )\n            elif type(self.fmodel_unexpanded.wind_data) is WindTIRose:\n                turbine_powers_rose = np.full(\n                    (\n                        len(self.fmodel_unexpanded.wind_data.wd_flat),\n                        self.fmodel_unexpanded.core.farm.n_turbines,\n                    ),\n                    np.nan,\n                )\n                turbine_powers_rose[self.fmodel_unexpanded.wind_data.non_zero_freq_mask, :] = (\n                    turbine_powers\n                )\n                turbine_powers = turbine_powers_rose.reshape(\n                    len(self.fmodel_unexpanded.wind_data.wind_directions),\n                    len(self.fmodel_unexpanded.wind_data.wind_speeds),\n                    len(self.fmodel_unexpanded.wind_data.turbulence_intensities),\n                    self.fmodel_unexpanded.core.farm.n_turbines,\n                )\n\n        return turbine_powers\n\n    def get_expected_turbine_powers(self, freq=None):\n        \"\"\"\n        Compute the expected (mean) power of each turbine.\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape\n                with the frequencies of each wind direction and\n                wind speed combination.  freq is either a 1D array,\n                in which case the same frequencies are used for all\n                turbines, or a 2D array with shape equal to\n                (n_findex, n_turbines), in which case each turbine has a unique\n                set of frequencies (this is the case for example using\n                WindRoseByTurbine).\n\n                    These frequencies should typically sum across rows\n                up to 1.0 and are used to weigh the wind farm power for every\n                condition in calculating the wind farm's AEP. Defaults to None.\n                If None and a WindData object was supplied, the WindData object's\n                frequencies will be used. Otherwise, uniform frequencies are assumed\n                (i.e., a simple mean over the findices is computed).\n        \"\"\"\n\n        turbine_powers = self._get_turbine_powers()\n\n        if freq is None:\n            if self.fmodel_unexpanded.wind_data is None:\n                freq = np.array([1.0 / self.fmodel_unexpanded.core.flow_field.n_findex])\n            else:\n                freq = self.fmodel_unexpanded.wind_data.unpack_freq()\n\n        # If freq is 2d, then use the per turbine frequencies\n        if len(np.shape(freq)) == 2:\n            return np.nansum(np.multiply(freq, turbine_powers), axis=0)\n        else:\n            return np.nansum(np.multiply(freq.reshape(-1, 1), turbine_powers), axis=0)\n\n    def _get_weighted_turbine_powers(\n        self,\n        turbine_weights=None,\n        use_turbulence_correction=False,\n    ):\n        if use_turbulence_correction:\n            raise NotImplementedError(\n                \"Turbulence correction is not yet implemented in the power calculation.\"\n            )\n\n        # Confirm run() has been run on the expanded fmodel\n        if self.fmodel_expanded.core.state is not State.USED:\n            raise RuntimeError(\n                \"Can't run function `FlorisModel.get_farm_power` without \"\n                \"first running `FlorisModel.run`.\"\n            )\n\n        if turbine_weights is None:\n            # Default to equal weighing of all turbines when turbine_weights is None\n            turbine_weights = np.ones(\n                (\n                    self.fmodel_unexpanded.core.flow_field.n_findex,\n                    self.fmodel_unexpanded.core.farm.n_turbines,\n                )\n            )\n        elif len(np.shape(turbine_weights)) == 1:\n            # Deal with situation when 1D array is provided\n            turbine_weights = np.tile(\n                turbine_weights,\n                (self.fmodel_unexpanded.core.flow_field.n_findex, 1),\n            )\n\n        # Calculate all turbine powers and apply weights\n        turbine_powers = self._get_turbine_powers()\n        turbine_powers = np.multiply(turbine_weights, turbine_powers)\n\n        return turbine_powers\n\n    def _get_farm_power(\n        self,\n        turbine_weights=None,\n        use_turbulence_correction=False,\n    ):\n        \"\"\"\n        Report wind plant power from instance of floris with uncertainty.\n\n        Args:\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the power production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                objective function. If None, this  is an array with all values\n                1.0 and with shape equal to (n_findex, n_turbines).\n                Defaults to None.\n            use_turbulence_correction: (bool, optional): When True uses a\n                turbulence parameter to adjust power output calculations.\n                Defaults to False. Not currently implemented.\n\n        Returns:\n            float: Sum of wind turbine powers in W.\n        \"\"\"\n        turbine_powers = self._get_weighted_turbine_powers(\n            turbine_weights=turbine_weights, use_turbulence_correction=use_turbulence_correction\n        )\n\n        return np.sum(turbine_powers, axis=1)\n\n    def get_farm_power(\n        self,\n        turbine_weights=None,\n        use_turbulence_correction=False,\n    ):\n        \"\"\"\n        Report wind plant power from instance of floris. Optionally includes\n        uncertainty in wind direction and yaw position when determining power.\n        Uncertainty is included by computing the mean wind farm power for a\n        distribution of wind direction and yaw position deviations from the\n        original wind direction and yaw angles.\n\n        Args:\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the power production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                objective function. If None, this  is an array with all values\n                1.0 and with shape equal to (n_findex, n_turbines).\n                Defaults to None.\n            use_turbulence_correction: (bool, optional): When True uses a\n                turbulence parameter to adjust power output calculations.\n                Defaults to False. Not currently implemented.\n\n        Returns:\n            float: Sum of wind turbine powers in W.\n        \"\"\"\n        farm_power = self._get_farm_power(turbine_weights, use_turbulence_correction)\n\n        if self.fmodel_unexpanded.wind_data is not None:\n            if isinstance(self.fmodel_unexpanded.wind_data, (WindRose, WindRoseWRG)):\n                farm_power_rose = np.full(len(self.fmodel_unexpanded.wind_data.wd_flat), np.nan)\n                farm_power_rose[self.fmodel_unexpanded.wind_data.non_zero_freq_mask] = farm_power\n                farm_power = farm_power_rose.reshape(\n                    len(self.fmodel_unexpanded.wind_data.wind_directions),\n                    len(self.fmodel_unexpanded.wind_data.wind_speeds),\n                )\n            elif type(self.fmodel_unexpanded.wind_data) is WindTIRose:\n                farm_power_rose = np.full(len(self.fmodel_unexpanded.wind_data.wd_flat), np.nan)\n                farm_power_rose[self.fmodel_unexpanded.wind_data.non_zero_freq_mask] = farm_power\n                farm_power = farm_power_rose.reshape(\n                    len(self.fmodel_unexpanded.wind_data.wind_directions),\n                    len(self.fmodel_unexpanded.wind_data.wind_speeds),\n                    len(self.fmodel_unexpanded.wind_data.turbulence_intensities),\n                )\n\n        return farm_power\n\n    def get_expected_farm_power(\n        self,\n        freq=None,\n        turbine_weights=None,\n    ) -> float:\n        \"\"\"\n        Compute the expected (mean) power of the wind farm.\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape (n_findex)\n                with the frequencies of each wind direction and\n                wind speed combination. These frequencies should typically sum\n                up to 1.0 and are used to weigh the wind farm power for every\n                condition in calculating the wind farm's AEP. Defaults to None.\n                If None and a WindData object was supplied, the WindData object's\n                frequencies will be used. Otherwise, uniform frequencies are assumed\n                (i.e., a simple mean over the findices is computed).\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the power production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                objective function. If None, this  is an array with all values\n                1.0 and with shape equal to (n_findex,\n                n_turbines). Defaults to None.\n        \"\"\"\n\n        if freq is None:\n            if self.fmodel_unexpanded.wind_data is None:\n                freq = np.array([1.0 / self.fmodel_unexpanded.core.flow_field.n_findex])\n            else:\n                freq = self.fmodel_unexpanded.wind_data.unpack_freq()\n\n        farm_power = self._get_farm_power(turbine_weights=turbine_weights)\n\n        # If freq is 1d\n        if len(np.shape(freq)) == 1:\n            farm_power = self._get_farm_power(turbine_weights=turbine_weights)\n            return np.nansum(np.multiply(freq, farm_power))\n        else:\n            weighted_turbine_powers = self._get_weighted_turbine_powers(\n                turbine_weights=turbine_weights,\n            )\n            return np.nansum(np.multiply(freq, weighted_turbine_powers))\n\n    def get_farm_AEP(\n        self,\n        freq=None,\n        turbine_weights=None,\n        hours_per_year=8760,\n    ) -> float:\n        \"\"\"\n        Estimate annual energy production (AEP) for distributions of wind speed, wind\n        direction, frequency of occurrence, and yaw offset.\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape (n_findex)\n                with the frequencies of each wind direction and\n                wind speed combination. These frequencies should typically sum\n                up to 1.0 and are used to weigh the wind farm power for every\n                condition in calculating the wind farm's AEP. Defaults to None.\n                If None and a WindData object was supplied, the WindData object's\n                frequencies will be used. Otherwise, uniform frequencies are assumed.\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the power production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                objective function. If None, this  is an array with all values\n                1.0 and with shape equal to (n_findex,\n                n_turbines). Defaults to None.\n            hours_per_year (float, optional): Number of hours in a year. Defaults to 365 * 24.\n\n        Returns:\n            float:\n                The Annual Energy Production (AEP) for the wind farm in\n                watt-hours.\n        \"\"\"\n        if freq is None and not isinstance(\n            self.fmodel_unexpanded.wind_data, (WindRose, WindRoseWRG, WindTIRose)\n        ):\n            self.logger.warning(\n                \"Computing AEP with uniform frequencies. Results results may not reflect annual \"\n                \"operation.\"\n            )\n\n        return (\n            self.get_expected_farm_power(freq=freq, turbine_weights=turbine_weights)\n            * hours_per_year\n        )\n\n    def get_expected_farm_value(\n        self,\n        freq=None,\n        values=None,\n        turbine_weights=None,\n    ) -> float:\n        \"\"\"\n        Compute the expected (mean) value produced by the wind farm. This is\n        computed by multiplying the wind farm power for each wind condition by\n        the corresponding value of the power generated (e.g., electricity\n        market price per unit of energy), then weighting by frequency and\n        summing over all conditions.\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape (n_findex)\n                with the frequencies of each wind condition combination.\n                These frequencies should typically sum up to 1.0 and are used\n                to weigh the wind farm value for every condition in calculating\n                the wind farm's expected value. Defaults to None. If None and a\n                WindData object is supplied, the WindData object's frequencies\n                will be used. Otherwise, uniform frequencies are assumed (i.e.,\n                a simple mean over the findices is computed).\n            values (NDArrayFloat): NumPy array with shape (n_findex)\n                with the values corresponding to the power generated for each\n                wind condition combination. The wind farm power is multiplied\n                by the value for every condition in calculating the wind farm's\n                expected value. Defaults to None. If None and a WindData object\n                is supplied, the WindData object's values will be used.\n                Otherwise, a value of 1 for all conditions is assumed (i.e.,\n                the expected farm value will be equivalent to the expected farm\n                power).\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the value production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris\n                is multiplied with this array in the calculation of the\n                expected value. If None, this is an array with all values 1.0\n                and with shape equal to (n_findex, n_turbines). Defaults to None.\n\n        Returns:\n            float:\n                The expected value produced by the wind farm in units of value.\n        \"\"\"\n        if freq is None:\n            if self.fmodel_unexpanded.wind_data is None:\n                freq = np.array([1.0 / self.fmodel_unexpanded.core.flow_field.n_findex])\n            else:\n                freq = self.fmodel_unexpanded.wind_data.unpack_freq()\n        # If freq is 1d\n        if len(np.shape(freq)) == 1:\n            farm_power = self._get_farm_power(turbine_weights=turbine_weights)\n            farm_power = np.multiply(freq, farm_power)\n        else:\n            weighted_turbine_powers = self._get_weighted_turbine_powers(\n                turbine_weights=turbine_weights\n            )\n            farm_power = np.nansum(np.multiply(freq, weighted_turbine_powers), axis=1)\n        if values is None:\n            if self.fmodel_unexpanded.wind_data is None:\n                values = np.array([1.0])\n            else:\n                values = self.fmodel_unexpanded.wind_data.unpack_value()\n        return np.nansum(np.multiply(values, farm_power))\n\n    def get_farm_AVP(\n        self,\n        freq=None,\n        values=None,\n        turbine_weights=None,\n        hours_per_year=8760,\n    ) -> float:\n        \"\"\"\n        Estimate annual value production (AVP) for distribution of wind\n        conditions, frequencies of occurrence, and corresponding values of\n        power generated (e.g., electricity price per unit of energy).\n\n        Args:\n            freq (NDArrayFloat): NumPy array with shape (n_findex)\n                with the frequencies of each wind condition combination.\n                These frequencies should typically sum up to 1.0 and are used\n                to weigh the wind farm value for every condition in calculating\n                the wind farm's AVP. Defaults to None. If None and a\n                WindData object is supplied, the WindData object's frequencies\n                will be used. Otherwise, uniform frequencies are assumed (i.e.,\n                a simple mean over the findices is computed).\n            values (NDArrayFloat): NumPy array with shape (n_findex)\n                with the values corresponding to the power generated for each\n                wind condition combination. The wind farm power is multiplied\n                by the value for every condition in calculating the wind farm's\n                AVP. Defaults to None. If None and a WindData object is\n                supplied, the WindData object's values will be used. Otherwise,\n                a value of 1 for all conditions is assumed (i.e., the AVP will\n                be equivalent to the AEP).\n            turbine_weights (NDArrayFloat | list[float] | None, optional):\n                weighing terms that allow the user to emphasize power at\n                particular turbines and/or completely ignore the power\n                from other turbines. This is useful when, for example, you are\n                modeling multiple wind farms in a single floris object. If you\n                only want to calculate the value production for one of those\n                farms and include the wake effects of the neighboring farms,\n                you can set the turbine_weights for the neighboring farms'\n                turbines to 0.0. The array of turbine powers from floris is\n                multiplied with this array in the calculation of the AVP. If\n                None, this is an array with all values 1.0 and with shape equal\n                to (n_findex, n_turbines). Defaults to None.\n            hours_per_year (float, optional): Number of hours in a year.\n                Defaults to 365 * 24.\n\n        Returns:\n            float:\n                The Annual Value Production (AVP) for the wind farm in units\n                of value.\n        \"\"\"\n        if (\n            freq is None and not isinstance(\n                self.fmodel_unexpanded.wind_data,\n                (WindRose, WindRoseWRG, WindTIRose)\n            )\n        ):\n            self.logger.warning(\n                \"Computing AVP with uniform frequencies. Results results may not reflect annual \"\n                \"operation.\"\n            )\n\n        if values is None and self.fmodel_unexpanded.wind_data is None:\n            self.logger.warning(\n                \"Computing AVP with uniform value equal to 1. Results will be equivalent to \"\n                \"annual energy production.\"\n            )\n\n        return (\n            self.get_expected_farm_value(freq=freq, values=values, turbine_weights=turbine_weights)\n            * hours_per_year\n        )\n\n    def _get_rounded_inputs(\n        self,\n        input_array,\n        wd_resolution=1.0,  # Degree\n        ws_resolution=1.0,  # m/s\n        ti_resolution=0.025,\n        yaw_resolution=1.0,  # Degree\n        power_setpoint_resolution=100,  # kW\n        awc_amplitude_resolution=0.1,  # Deg\n    ):\n        \"\"\"\n        Round the input array  specified resolutions.\n\n        Parameters:\n            input_array (numpy.ndarray): An array of shape (n, 5)  with columns\n                                        for wind direction (wd), wind speed (ws),\n                                        turbulence intensity (tu),\n                                        yaw angle (yaw), and power setpoint.\n            wd_resolution (float): Resolution for rounding wind direction in degrees.\n                Default is 1.0 degree.\n            ws_resolution (float): Resolution for rounding wind speed in m/s. Default is 1.0 m/s.\n            ti_resolution (float): Resolution for rounding turbulence intensity. Default is 0.1.\n            yaw_resolution (float): Resolution for rounding yaw angle in degrees.\n                Default is 1.0 degree.\n            power_setpoint_resolution (int): Resolution for rounding power setpoint in kW.\n                Default is 100 kW.\n            awc_amplitude_resolution (float): Resolution for rounding amplitude of awc_amplitude\n\n        Returns:\n            numpy.ndarray: A rounded array of wind turbine parameters with\n                    the same shape as input_array,\n                    where each parameter is rounded to the specified resolution.\n        \"\"\"\n\n        # input_array is a nx5 numpy array whose columns are wd, ws, tu, yaw, power_setpoint\n        # round each column by the respective resolution\n        rounded_input_array = np.copy(input_array)\n        rounded_input_array[:, 0] = (\n            np.round(rounded_input_array[:, 0] / wd_resolution) * wd_resolution\n        )\n        rounded_input_array[:, 1] = (\n            np.round(rounded_input_array[:, 1] / ws_resolution) * ws_resolution\n        )\n        rounded_input_array[:, 2] = (\n            np.round(rounded_input_array[:, 2] / ti_resolution) * ti_resolution\n        )\n        rounded_input_array[:, 3 : 3 + self.fmodel_unexpanded.core.farm.n_turbines] = (\n            np.round(\n                rounded_input_array[:, 3 : 3 + self.fmodel_unexpanded.core.farm.n_turbines]\n                / yaw_resolution\n            )\n            * yaw_resolution\n        )\n        rounded_input_array[\n            :,\n            3 + self.fmodel_unexpanded.core.farm.n_turbines : 3\n            + 2 * self.fmodel_unexpanded.core.farm.n_turbines,\n        ] = (\n            np.round(\n                rounded_input_array[\n                    :,\n                    3 + self.fmodel_unexpanded.core.farm.n_turbines : 3\n                    + 2 * self.fmodel_unexpanded.core.farm.n_turbines,\n                ]\n                / power_setpoint_resolution\n            )\n            * power_setpoint_resolution\n        )\n\n        rounded_input_array[\n            :,\n            3 + 2 * self.fmodel_unexpanded.core.farm.n_turbines : 3\n            + 3 * self.fmodel_unexpanded.core.farm.n_turbines,\n        ] = (\n            np.round(\n                rounded_input_array[\n                    :,\n                    3 + 2 * self.fmodel_unexpanded.core.farm.n_turbines : 3\n                    + 3 * self.fmodel_unexpanded.core.farm.n_turbines,\n                ]\n                / awc_amplitude_resolution\n            )\n            * awc_amplitude_resolution\n        )\n\n        return rounded_input_array\n\n    def _expand_wind_directions(\n        self, input_array, wd_sample_points, fix_yaw_to_nominal_direction=False, n_turbines=None\n    ):\n        \"\"\"\n        Expand wind direction data.\n\n        Args:\n            input_array (numpy.ndarray): 2D numpy array of shape (m, n)\n            representing wind direction data,\n                where m is the number of data points and n is the number of features.\n                The first column\n                represents wind direction.\n            wd_sample_points (list): List of integers representing\n            wind direction sample points.\n            fix_yaw_to_nominal_direction (bool): Fix the yaw angle to the nominal\n                direction?   Defaults to False\n            n_turbines (int): The number of turbines in the wind farm.  Must be supplied\n                if fix_yaw_to_nominal_direction is True.\n\n        Returns:\n            numpy.ndarray: Expanded wind direction data as a 2D numpy array\n                of shape (m * p, n), where\n                p is the number of sample points.\n\n        Raises:\n            ValueError: If wd_sample_points does not have an odd length or\n                if the middle element is not 0.\n\n        This function takes wind direction data and expands it\n        by perturbing the wind direction column\n        based on a list of sample points. It vertically stacks\n        copies of the input array with the wind\n        direction column perturbed by each sample point, ensuring\n        the resultant values are within the range\n        of 0 to 360.\n        \"\"\"\n\n        # Check if wd_sample_points is odd-length and the middle element is 0\n        if len(wd_sample_points) % 2 != 1:\n            raise ValueError(\"wd_sample_points must have an odd length.\")\n        if wd_sample_points[len(wd_sample_points) // 2] != 0:\n            raise ValueError(\"The middle element of wd_sample_points must be 0.\")\n\n        # If fix_yaw_to_nominal_direction is True, n_turbines must be supplied\n        if fix_yaw_to_nominal_direction and n_turbines is None:\n            raise ValueError(\"The number of turbines in the wind farm must be supplied\")\n\n        num_samples = len(wd_sample_points)\n        num_rows = input_array.shape[0]\n\n        # Create an array to hold the expanded data\n        output_array = np.zeros((num_rows * num_samples, input_array.shape[1]))\n\n        # Repeat each row of input_array for each sample point\n        for i in range(num_samples):\n            start_idx = i * num_rows\n            end_idx = start_idx + num_rows\n            output_array[start_idx:end_idx, :] = input_array.copy()\n\n            # Perturb the wd column by the current sample point\n            output_array[start_idx:end_idx, 0] = (\n                output_array[start_idx:end_idx, 0] + wd_sample_points[i]\n            ) % 360\n\n            # If fix_yaw_to_nominal_direction is True, set the yaw angle to relative\n            # to the nominal wind direction\n            if fix_yaw_to_nominal_direction:\n                # Wrap between -180 and 180\n                output_array[start_idx:end_idx, 3 : 3 + n_turbines] = wrap_180(\n                    output_array[start_idx:end_idx, 3 : 3 + n_turbines] + wd_sample_points[i]\n                )\n\n        return output_array\n\n    def _get_unique_inputs(self, input_array):\n        \"\"\"\n        Finds unique rows in the input numpy array and constructs a mapping array\n        to reconstruct the input array from the unique rows.\n\n        Include an exception that if the underlying FlorisModel object (fmodel_unexpanded)\n        includes a multidim_conditions that includes non-scalar values, then force\n        unique_inputs and map_to_expanded_inputs to represent that all rows are unique.\n\n        Args:\n            input_array (numpy.ndarray): Input array of shape (m, n).\n\n        Returns:\n            tuple: A tuple containing:\n                numpy.ndarray: An array of unique rows found in the input_array, of shape (r, n),\n                            where r <= m.\n                numpy.ndarray: A 1D array of indices mapping each row of the input_array\n                            to the corresponding row in the unique_inputs array.\n                            It represents how to reconstruct the input_array from the unique rows.\n        \"\"\"\n\n        if (self.fmodel_unexpanded.core.flow_field.multidim_conditions is not None\n           and not is_all_scalar_dict(self.fmodel_unexpanded.core.flow_field.multidim_conditions)\n        ):\n            self.logger.warning(\"Given non-scalar multidim conditions. Forcing all unique values \"\n                                \"for the uncertainty model, which may be slower to run.\")\n            unique_inputs = input_array\n            map_to_expanded_inputs = np.arange(len(input_array))\n            return unique_inputs, map_to_expanded_inputs\n\n        unique_inputs, indices, map_to_expanded_inputs = np.unique(\n            input_array, axis=0, return_index=True, return_inverse=True\n        )\n\n        return unique_inputs, map_to_expanded_inputs\n\n    def _get_weights(self, wd_std, wd_sample_points):\n        \"\"\"Generates weights based on a Gaussian distribution sampled at specific x-locations.\n\n        Args:\n            wd_std (float): The standard deviation of the Gaussian distribution.\n            wd_sample_points (array-like): The x-locations where the Gaussian function is sampled.\n\n        Returns:\n            numpy.ndarray: An array of weights, generated using a Gaussian distribution with mean 0\n                and standard deviation wd_std, sampled at the specified x-locations.\n                The weights are normalized so that they sum to 1.\n\n        \"\"\"\n\n        # Calculate the Gaussian function values at sample points\n        gaussian_values = np.exp(-(np.array(wd_sample_points) ** 2) / (2 * wd_std**2))\n\n        # Normalize the Gaussian values to get the weights\n        weights = gaussian_values / np.sum(gaussian_values)\n\n        return weights\n\n    def get_operation_model(self) -> str:\n        \"\"\"Get the operation model of a FlorisModel.\n\n        Returns:\n            str: The operation_model.\n        \"\"\"\n        operation_models = [\n            self.fmodel_unexpanded.core.farm.turbine_definitions[tindex][\"operation_model\"]\n            for tindex in range(self.fmodel_unexpanded.core.farm.n_turbines)\n        ]\n        if len(set(operation_models)) == 1:\n            return operation_models[0]\n        else:\n            return operation_models\n\n    def set_operation_model(self, operation_model: str | List[str]):\n        \"\"\"Set the turbine operation model(s).\n\n        Args:\n            operation_model (str): The operation model to set.\n        \"\"\"\n        if isinstance(operation_model, str):\n            if len(self.fmodel_unexpanded.core.farm.turbine_type) == 1:\n                # Set a single one here, then, and return\n                turbine_type = self.fmodel_unexpanded.core.farm.turbine_definitions[0]\n                turbine_type[\"operation_model\"] = operation_model\n                self.set(\n                    turbine_type=[turbine_type],\n                    reference_wind_height=self.reference_wind_height\n                )\n                return\n            else:\n                operation_model = [operation_model] * self.fmodel_unexpanded.core.farm.n_turbines\n\n        if len(operation_model) != self.fmodel_unexpanded.core.farm.n_turbines:\n            raise ValueError(\n                \"The length of the operation_model list must be \" \"equal to the number of turbines.\"\n            )\n\n        turbine_type_list = self.fmodel_unexpanded.core.farm.turbine_definitions\n\n        for tindex in range(self.fmodel_unexpanded.core.farm.n_turbines):\n            turbine_type_list[tindex][\"turbine_type\"] = (\n                turbine_type_list[tindex][\"turbine_type\"] + \"_\" + operation_model[tindex]\n            )\n            turbine_type_list[tindex][\"operation_model\"] = operation_model[tindex]\n\n        self.set(\n            turbine_type=turbine_type_list,\n            reference_wind_height=self.reference_wind_height\n        )\n\n    def copy(self):\n        \"\"\"Create an independent copy of the current UncertainFlorisModel object\n\n        When creating the copy, this method uses self.__class__(), rather than\n        UncertainFlorisModel() directly, so that subclasses of UncertainFlorisModel can inherit this\n        method and return instantiations of their own class, rather than the UncertainFlorisModel\n        class.\n        \"\"\"\n        return self.__class__(self.fmodel_unexpanded.copy(), **self.secondary_init_kwargs)\n\n    def get_param(self, param: List[str], param_idx: Optional[int] = None) -> Any:\n        \"\"\"Get a parameter from a FlorisModel object.\n\n        Args:\n            param (List[str]): A list of keys to traverse the FlorisModel dictionary.\n            param_idx (Optional[int], optional): The index to get the value at. Defaults to None.\n                If None, the entire parameter is returned.\n\n        Returns:\n            Any: The value of the parameter.\n        \"\"\"\n        fm_dict = self.fmodel_unexpanded.core.as_dict()\n\n        if param_idx is None:\n            return nested_get(fm_dict, param)\n        else:\n            return nested_get(fm_dict, param)[param_idx]\n\n    def set_param(self, param: List[str], value: Any, param_idx: Optional[int] = None):\n        \"\"\"Set a parameter in a FlorisModel object.\n\n        Args:\n            param (List[str]): A list of keys to traverse the FlorisModel dictionary.\n            value (Any): The value to set.\n            param_idx (Optional[int], optional): The index to set the value at. Defaults to None.\n        \"\"\"\n        fm_dict_mod = self.fmodel_unexpanded.core.as_dict()\n        nested_set(fm_dict_mod, param, value, param_idx)\n        self.fmodel_unexpanded.__init__(fm_dict_mod, **self.fmodel_unexpanded.secondary_init_kwargs)\n        self.set()\n\n    @property\n    def secondary_init_kwargs(self):\n        \"\"\"\n        UncertainFlorisModel secondary keyword arguments (after configuration).\n        \"\"\"\n        return {\n            \"wd_resolution\": self.wd_resolution,\n            \"ws_resolution\": self.ws_resolution,\n            \"ti_resolution\": self.ti_resolution,\n            \"yaw_resolution\": self.yaw_resolution,\n            \"power_setpoint_resolution\": self.power_setpoint_resolution,\n            \"awc_amplitude_resolution\": self.awc_amplitude_resolution,\n            \"wd_std\": self.wd_std,\n            \"wd_sample_points\": self.wd_sample_points,\n            \"fix_yaw_to_nominal_direction\": self.fix_yaw_to_nominal_direction,\n            \"verbose\": self.verbose,\n        }\n\n    @property\n    def layout_x(self):\n        \"\"\"\n        Wind turbine coordinate information.\n\n        Returns:\n            np.array: Wind turbine x-coordinate.\n        \"\"\"\n        return self.fmodel_unexpanded.core.farm.layout_x\n\n    @property\n    def layout_y(self):\n        \"\"\"\n        Wind turbine coordinate information.\n\n        Returns:\n            np.array: Wind turbine y-coordinate.\n        \"\"\"\n        return self.fmodel_unexpanded.core.farm.layout_y\n\n    @property\n    def wind_directions(self):\n        \"\"\"\n        Wind direction information.\n\n        Returns:\n            np.array: Wind direction.\n        \"\"\"\n        return self.fmodel_unexpanded.core.flow_field.wind_directions\n\n    @property\n    def wind_speeds(self):\n        \"\"\"\n        Wind speed information.\n\n        Returns:\n            np.array: Wind speed.\n        \"\"\"\n        return self.fmodel_unexpanded.core.flow_field.wind_speeds\n\n    @property\n    def turbulence_intensities(self):\n        \"\"\"\n        Turbulence intensity information.\n\n        Returns:\n            np.array: Turbulence intensity.\n        \"\"\"\n        return self.fmodel_unexpanded.core.flow_field.turbulence_intensities\n\n    @property\n    def n_findex(self):\n        \"\"\"\n        Number of unique wind conditions.\n\n        Returns:\n            int: Number of unique wind conditions.\n        \"\"\"\n        return self.fmodel_unexpanded.core.flow_field.n_findex\n\n    @property\n    def n_turbines(self):\n        \"\"\"\n        Number of turbines in the wind farm.\n\n        Returns:\n            int: Number of turbines in the wind farm.\n        \"\"\"\n        return self.fmodel_unexpanded.core.farm.n_turbines\n\n    @property\n    def reference_wind_height(self):\n        \"\"\"\n        Reference wind height.\n\n        Returns:\n            float: Reference wind height.\n        \"\"\"\n        return self.fmodel_unexpanded.core.flow_field.reference_wind_height\n\n    @property\n    def core(self):\n        \"\"\"\n        Returns the core of the unexpanded model.\n\n        Returns:\n            Floris: The core of the unexpanded model.\n        \"\"\"\n        return self.fmodel_unexpanded.core\n\n    @property\n    def turbine_average_velocities(self) -> NDArrayFloat:\n        # Get the expanded velocities\n        expanded_velocities = average_velocity(\n            velocities=self.fmodel_expanded.core.flow_field.u,\n            method=self.fmodel_expanded.core.grid.average_method,\n            cubature_weights=self.fmodel_expanded.core.grid.cubature_weights,\n        )\n\n        # Pass to off-class function\n        result = map_turbine_values_uncertain(\n            unique_turbine_values=expanded_velocities,\n            map_to_expanded_inputs=self.map_to_expanded_inputs,\n            weights=self.weights,\n            n_unexpanded=self.n_unexpanded,\n            n_sample_points=self.n_sample_points,\n            n_turbines=self.fmodel_unexpanded.core.farm.n_turbines,\n        )\n\n        return result\n\n\ndef map_turbine_powers_uncertain(\n    unique_turbine_powers,\n    map_to_expanded_inputs,\n    weights,\n    n_unexpanded,\n    n_sample_points,\n    n_turbines,\n):\n    \"\"\"\n    Alias for map_turbine_values_uncertain.\n    \"\"\"\n    # Deprecation warning\n    print(\"map_turbine_powers_uncertain is deprecated, use map_turbine_values_uncertain instead.\")\n    return map_turbine_values_uncertain(\n        unique_turbine_values=unique_turbine_powers,\n        map_to_expanded_inputs=map_to_expanded_inputs,\n        weights=weights,\n        n_unexpanded=n_unexpanded,\n        n_sample_points=n_sample_points,\n        n_turbines=n_turbines,\n    )\n\ndef map_turbine_values_uncertain(\n    unique_turbine_values,\n    map_to_expanded_inputs,\n    weights,\n    n_unexpanded,\n    n_sample_points,\n    n_turbines,\n):\n    \"\"\"Calculates values at each turbine in the wind farm based on uncertainty weights.\n\n    This function calculates the values (e.g. power, velocity) at each turbine in the wind farm,\n    considering the underlying turbine values and applying a weighted sum to handle uncertainty.\n\n    Args:\n        unique_turbine_values (NDArrayFloat): An array of unique turbine powers, velocities, etc\n            from the underlying FlorisModel\n        map_to_expanded_inputs (NDArrayFloat): An array of indices mapping the unique values to\n            the expanded values\n        weights (NDArrayFloat): An array of weights for each wind direction sample point\n        n_unexpanded (int): The number of unexpanded conditions\n        n_sample_points (int): The number of wind direction sample points\n        n_turbines (int): The number of turbines in the wind farm\n\n    Returns:\n        NDArrayFloat: An array containing the values at each turbine for each findex.\n\n    \"\"\"\n\n    # Expand back to the expanded value\n    expanded_turbine_values = unique_turbine_values[map_to_expanded_inputs]\n\n    # Reshape the weights array to make it compatible with broadcasting\n    weights_reshaped = weights[:, np.newaxis]\n\n    # Reshape expanded_turbine_values into blocks\n    blocks = np.reshape(\n        expanded_turbine_values,\n        (n_unexpanded, n_sample_points, n_turbines),\n        order=\"F\",\n    )\n\n    # Multiply each block by the corresponding weight\n    weighted_blocks = blocks * weights_reshaped\n\n    # Sum the blocks along the second axis\n    result = np.sum(weighted_blocks, axis=1)\n\n    return result\n\n\nclass ApproxFlorisModel(UncertainFlorisModel):\n    \"\"\"\n    The ApproxFlorisModel overloads the UncertainFlorisModel with the special case that\n    the wd_sample_points = [0].  This is a special case where no uncertainty is added\n    but the resolution of the values wind direction, wind speed etc are still reduced\n    by the specified resolution.  This allows for cases to be reused and a faster approximate\n    result computed\n    \"\"\"\n\n    def __init__(\n        self,\n        configuration: dict | str | Path,\n        wd_resolution=1.0,  # Degree\n        ws_resolution=1.0,  # m/s\n        ti_resolution=0.01,\n        yaw_resolution=1.0,  # Degree\n        power_setpoint_resolution=100,  # kW\n        awc_amplitude_resolution=0.1,  # Deg\n        verbose=False,\n    ):\n        super().__init__(\n            configuration,\n            wd_resolution,\n            ws_resolution,\n            ti_resolution,\n            yaw_resolution,\n            power_setpoint_resolution,\n            awc_amplitude_resolution,\n            wd_std=1.0,  # Arbitrary nonzero value, not used since only one sample point\n            wd_sample_points=[0],\n            fix_yaw_to_nominal_direction=False,\n            verbose=verbose,\n        )\n\n        self.wd_resolution = wd_resolution\n        self.ws_resolution = ws_resolution\n        self.ti_resolution = ti_resolution\n        self.yaw_resolution = yaw_resolution\n        self.power_setpoint_resolution = power_setpoint_resolution\n        self.awc_amplitude_resolution = awc_amplitude_resolution\n\n    @property\n    def secondary_init_kwargs(self):\n        \"\"\"\n        ApproxFlorisModel secondary keyword arguments (after configuration).\n        \"\"\"\n        return {\n            \"wd_resolution\": self.wd_resolution,\n            \"ws_resolution\": self.ws_resolution,\n            \"ti_resolution\": self.ti_resolution,\n            \"yaw_resolution\": self.yaw_resolution,\n            \"power_setpoint_resolution\": self.power_setpoint_resolution,\n            \"awc_amplitude_resolution\": self.awc_amplitude_resolution,\n            \"verbose\": self.verbose,\n        }\n"
  },
  {
    "path": "floris/utilities.py",
    "content": "import os\nfrom math import ceil\nfrom typing import (\n    Any,\n    Dict,\n    List,\n    Optional,\n    Tuple,\n)\n\nimport numpy as np\nimport yaml\nfrom attrs import define, field\n\nfrom floris.type_dec import floris_float_type, NDArrayFloat\n\n\ndef pshape(array: np.ndarray, label: str = \"\"):\n    print(label, np.shape(array))\n\n\ndef cosd(angle):\n    \"\"\"\n    Cosine of an angle with the angle given in degrees.\n\n    Args:\n        angle (float): Angle in degrees.\n\n    Returns:\n        float\n    \"\"\"\n    return np.cos(np.radians(angle))\n\n\ndef sind(angle):\n    \"\"\"\n    Sine of an angle with the angle given in degrees.\n\n    Args:\n        angle (float): Angle in degrees.\n\n    Returns:\n        float\n    \"\"\"\n    return np.sin(np.radians(angle))\n\n\ndef tand(angle):\n    \"\"\"\n    Tangent of an angle with the angle given in degrees.\n\n    Args:\n        angle (float): Angle in degrees.\n\n    Returns:\n        float\n    \"\"\"\n    return np.tan(np.radians(angle))\n\n\ndef wrap_180(x):\n    \"\"\"\n    Shift the given values to within the range (-180, 180].\n\n    Args:\n        x (numeric or np.array): Scalar value or np.array of values to shift.\n\n    Returns:\n        np.ndarray | float | int: Shifted values.\n    \"\"\"\n\n    return ((x + 180.0) % 360.0) - 180.0\n\n\ndef wrap_360(x):\n    \"\"\"\n    Shift the given values to within the range (0, 360].\n\n    Args:\n        x (numeric or np.array): Scalar value or np.array of values to shift.\n\n    Returns:\n        np.ndarray | float | int: Shifted values.\n    \"\"\"\n\n    return x % 360.0\n\ndef check_and_identify_step_size(wind_directions):\n    \"\"\"\n    This function identifies the step size in a series of wind directions. The function will\n    return the step size if the wind directions are evenly spaced, otherwise it will raise an\n    error.\n\n    Args:\n        wind_directions (np.ndarray): Array of wind directions.\n\n    Returns:\n        float: The step size of the wind directions.\n    \"\"\"\n\n    if len(wind_directions) < 2:\n        raise ValueError(\"Array must contain at least 2 elements\")\n\n    # First compute the steps between each wind direction\n    steps = np.diff(wind_directions)\n\n    # Confirm that the steps are all positive\n    if not np.all(steps > 0):\n        raise ValueError(\"wind_directions must be monotonically increasing\")\n\n    # Check the step from the last to the first element\n    last_step = wind_directions[0] - wind_directions[-1] + 360\n\n    # If len(window_directions) == 2, then return whichever step is smaller\n    if len(wind_directions) == 2:\n        return min(steps[0], last_step)\n\n    # If len(window_directions) == 3 make some checks\n    elif len(wind_directions) == 3:\n        if np.all(steps == steps[0]):\n            return steps[0]\n        elif steps[0] == last_step:\n            return steps[0]\n        elif steps[1] == last_step:\n            return steps[1]\n        else:\n            raise ValueError(\"wind_directions must be evenly spaced\")\n\n    else:\n        if np.allclose(steps, steps[0]):\n            return steps[0]\n\n        # If all but one of the steps are the same\n        values, counts = np.unique(steps, return_counts=True)\n\n        # Check for the case where there are more than two different step sizes\n        if len(values) > 2:\n            raise ValueError(\"wind_directions must be evenly spaced\")\n\n        # In the case there are only two step sizes, ensure that one only happens once\n        if np.min(counts) > 1:\n            raise ValueError(\"wind_directions must be evenly spaced\")\n\n        # If the last step equals the most common step, return the most common step\n        if last_step == values[np.argmax(counts)]:\n            return values[np.argmax(counts)]\n\n        raise ValueError(\"wind_directions must be evenly spaced\")\n\ndef make_wind_directions_adjacent(wind_directions: NDArrayFloat) -> NDArrayFloat:\n    \"\"\"\n    This function reorders the wind directions so that they are adjacent. The function will\n    return the reordered wind directions if the wind directions are not adjacent, otherwise it\n    will return the input wind directions\n\n    Args:\n        wind_directions (NDArrayFloat): Array of wind directions.\n\n    Returns:\n        NDArrayFloat: The reordered wind directions to be adjacent.\n    \"\"\"\n\n    # Check the step size of the wind directions\n    step_size = check_and_identify_step_size(wind_directions)\n\n    # Get a list of steps\n    steps = np.diff(wind_directions)\n\n    # There will be at most one step with a size larger than the step size\n    # If there is one, find it\n    if np.any(steps > step_size):\n        idx = np.argmax(steps)\n\n        # Now change wind_directions such that for each direction after that index\n        # subtract 360 and move that block to the front\n        wind_directions = np.concatenate(\n            (wind_directions[idx+1:] - 360, wind_directions[:idx+1])\n        )\n\n        # Return the wind directions and indices to go from the original to the new\n        sort_indices = np.array(list(range(idx+1,len(wind_directions))) + list(range(idx+1)))\n\n        return wind_directions, sort_indices\n\n    else:\n\n        return wind_directions, np.arange(len(wind_directions))\n\n\ndef wind_delta(wind_directions: NDArrayFloat | float):\n    \"\"\"\n    This function calculates the deviation from West (270) for a given wind direction or series\n    of wind directions. First, 270 is subtracted from the input wind direction, and then the\n    remainder after dividing by 360 is retained (modulo). The table below lists examples of\n    results.\n\n    | Input | Result |\n    | ----- | ------ |\n    | 270.0 | 0.0    |\n    | 280.0 | 10.0   |\n    | 360.0 | 90.0   |\n    | 180.0 | 270.0  |\n    | -10.0 | 80.0   |\n    |-100.0 | 350.0  |\n\n    Args:\n        wind_directions (NDArrayFloat | float): A single or series of wind directions. They can be\n        any number, negative or positive, but it is typically between 0 and 360.\n\n    Returns:\n        NDArrayFloat | float: The delta between the given wind direction and 270 in positive\n        quantities between 0 and 360. The returned type is the same as wind_directions.\n    \"\"\"\n\n    return (wind_directions - 270) % 360\n\n\ndef rotate_coordinates_rel_west(\n    wind_directions,\n    coordinates,\n    x_center_of_rotation=None,\n    y_center_of_rotation=None\n):\n    \"\"\"\n    This function rotates the given coordinates so that they are aligned with West (270) rather\n    than North (0). The rotation happens about the centroid of the coordinates.\n\n    Args:\n        wind_directions (NDArrayFloat): Series of wind directions to base the rotation.\n        coordinates (NDArrayFloat): Series of coordinates to rotate with shape (N coordinates, 3)\n            so that each element of the array coordinates[i] yields a three-component coordinate.\n        x_center_of_rotation (float, optional): The x-coordinate for the rotation center of the\n            input coordinates. Defaults to None.\n        y_center_of_rotation (float, optional): The y-coordinate for the rotational center of the\n            input coordinates. Defaults to None.\n    \"\"\"\n\n    # Calculate the difference in given wind direction from 270 / West\n    wind_deviation_from_west = wind_delta(wind_directions)\n    wind_deviation_from_west = np.reshape(wind_deviation_from_west, (len(wind_directions), 1))\n\n    # Construct the arrays storing the turbine locations\n    x_coordinates, y_coordinates, z_coordinates = coordinates.T\n\n    # Find center of rotation - this is the center of box bounding all of the turbines\n    if x_center_of_rotation is None:\n        x_center_of_rotation = (np.min(x_coordinates) + np.max(x_coordinates)) / 2\n    if y_center_of_rotation is None:\n        y_center_of_rotation = (np.min(y_coordinates) + np.max(y_coordinates)) / 2\n\n    # Rotate turbine coordinates about the center\n    x_coord_offset = x_coordinates - x_center_of_rotation\n    y_coord_offset = y_coordinates - y_center_of_rotation\n    x_coord_rotated = (\n        x_coord_offset * cosd(wind_deviation_from_west)\n        - y_coord_offset * sind(wind_deviation_from_west)\n        + x_center_of_rotation\n    )\n    y_coord_rotated = (\n        x_coord_offset * sind(wind_deviation_from_west)\n        + y_coord_offset * cosd(wind_deviation_from_west)\n        + y_center_of_rotation\n    )\n    z_coord_rotated = np.ones_like(\n        wind_deviation_from_west,\n        dtype=floris_float_type\n    ) * z_coordinates\n    return x_coord_rotated, y_coord_rotated, z_coord_rotated, x_center_of_rotation, \\\n        y_center_of_rotation\n\n\ndef reverse_rotate_coordinates_rel_west(\n    wind_directions: NDArrayFloat,\n    grid_x: NDArrayFloat,\n    grid_y: NDArrayFloat,\n    grid_z: NDArrayFloat,\n    x_center_of_rotation: float,\n    y_center_of_rotation: float\n):\n    \"\"\"\n    This function reverses the rotation of the given grid so that the coordinates are aligned with\n    the original wind direction. The rotation happens about the centroid of the coordinates.\n\n    Args:\n        wind_directions (NDArrayFloat): Series of wind directions to base the rotation.\n        grid_x (NDArrayFloat): X-coordinates to be rotated.\n        grid_y (NDArrayFloat): Y-coordinates to be rotated.\n        grid_z (NDArrayFloat): Z-coordinates to be rotated.\n        x_center_of_rotation (float): The x-coordinate for the rotation center of the\n            input coordinates.\n        y_center_of_rotation (float): The y-coordinate for the rotational center of the\n            input coordinates.\n    \"\"\"\n    # Calculate the difference in given wind direction from 270 / West\n    # We are rotating in the other direction\n    wind_deviation_from_west = -1.0 * wind_delta(wind_directions)\n\n    # Construct the arrays storing the turbine locations\n    grid_x_reversed = np.zeros_like(grid_x)\n    grid_y_reversed = np.zeros_like(grid_x)\n    grid_z_reversed = np.zeros_like(grid_x)\n    for wii, angle_rotation in enumerate(wind_deviation_from_west):\n        x_rot = grid_x[wii]\n        y_rot = grid_y[wii]\n        z_rot = grid_z[wii]\n\n        # Rotate turbine coordinates about the center\n        x_rot_offset = x_rot - x_center_of_rotation\n        y_rot_offset = y_rot - y_center_of_rotation\n        x = (\n            x_rot_offset * cosd(angle_rotation)\n            - y_rot_offset * sind(angle_rotation)\n            + x_center_of_rotation\n        )\n        y = (\n            x_rot_offset * sind(angle_rotation)\n            + y_rot_offset * cosd(angle_rotation)\n            + y_center_of_rotation\n        )\n        z = z_rot  # Nothing changed in this rotation\n\n        grid_x_reversed[wii] = x\n        grid_y_reversed[wii] = y\n        grid_z_reversed[wii] = z\n\n    return grid_x_reversed, grid_y_reversed, grid_z_reversed\n\n\nclass Loader(yaml.SafeLoader):\n\n    def __init__(self, stream):\n\n        self._root = os.path.split(stream.name)[0]\n\n        super().__init__(stream)\n\n    def include(self, node):\n\n        filename = os.path.join(self._root, self.construct_scalar(node))\n\n        with open(filename, 'r') as f:\n            return yaml.load(f, self.__class__)\n\n\nLoader.add_constructor('!include', Loader.include)\n\ndef load_yaml(filename, loader=Loader):\n    with open(filename) as fid:\n        return yaml.load(fid, loader)\n\n\ndef round_nearest_2_or_5(x: int | float) -> int:\n    \"\"\"Rounds a number (with a 0.5 buffer) up to the nearest integer divisible by 2 or 5.\n\n    Args:\n        x (int | float): The number to be rounded.\n\n    Returns:\n        int: The rounded number.\n    \"\"\"\n    base_2 = 2\n    base_5 = 5\n    return min(base_2 * ceil((x + 0.5) / base_2), base_5 * ceil((x + 0.5) / base_5))\n\n\ndef round_nearest(x: int | float, base: int = 5) -> int:\n    \"\"\"Rounds a number (with a 0.5 buffer) up to the nearest integer divisible by 5.\n\n    Args:\n        x (int | float): The number to be rounded.\n\n    Returns:\n        int: The rounded number.\n    \"\"\"\n    return base * ceil((x + 0.5) / base)\n\n\ndef nested_get(\n    d: Dict[str, Any],\n    keys: List[str]\n) -> Any:\n    \"\"\"Get a value from a nested dictionary using a list of keys.\n    Based on:\n    https://stackoverflow.com/questions/14692690/access-nested-dictionary-items-via-a-list-of-keys\n\n    Args:\n        d (Dict[str, Any]): The dictionary to get the value from.\n        keys (List[str]): A list of keys to traverse the dictionary.\n\n    Returns:\n        Any: The value at the end of the key traversal.\n    \"\"\"\n    for key in keys:\n        d = d[key]\n    return d\n\ndef nested_set(\n    d: Dict[str, Any],\n    keys: List[str],\n    value: Any,\n    idx: Optional[int] = None\n) -> None:\n    \"\"\"Set a value in a nested dictionary using a list of keys.\n    Based on:\n    https://stackoverflow.com/questions/14692690/access-nested-dictionary-items-via-a-list-of-keys\n\n    Args:\n        dic (Dict[str, Any]): The dictionary to set the value in.\n        keys (List[str]): A list of keys to traverse the dictionary.\n        value (Any): The value to set.\n        idx (Optional[int], optional): If the value is an list, the index to change.\n            Defaults to None.\n    \"\"\"\n    d_in = d.copy()\n\n    for key in keys[:-1]:\n        d = d.setdefault(key, {})\n    if idx is None:\n        # Parameter is a scalar, set directly\n        d[keys[-1]] = value\n    else:\n        # Parameter is a list, need to first get the list, change the values at idx\n\n        # # Get the underlying list\n        par_list = nested_get(d_in, keys)\n        par_list[idx] = value\n        d[keys[-1]] = par_list\n\ndef print_nested_dict(dictionary: Dict[str, Any], indent: int = 0) -> None:\n    \"\"\"Print a nested dictionary with indentation.\n\n    Args:\n        dictionary (Dict[str, Any]): The dictionary to print.\n        indent (int, optional): The number of spaces to indent. Defaults to 0.\n    \"\"\"\n    for key, value in dictionary.items():\n        print(\" \" * indent + str(key))\n        if isinstance(value, dict):\n            print_nested_dict(value, indent + 4)\n        else:\n            print(\" \" * (indent + 4) + str(value))\n\ndef is_all_scalar_dict(dictionary: Dict[str, Any]) -> bool:\n    \"\"\"Check if all values in a dictionary are scalar.\n\n    A scalar is defined as a value that is not iterable (like int, float, str, bool)\n    or a numpy scalar (0-dimensional array).\n\n    Args:\n        dictionary (Dict[str, Any]): The dictionary to check.\n\n    Returns:\n        bool: True if all values are scalar, False otherwise.\n    \"\"\"\n    for value in dictionary.values():\n        if not np.isscalar(value):\n            return False\n\n    return True\n"
  },
  {
    "path": "floris/wind_data.py",
    "content": "from __future__ import annotations\n\nimport copy\nimport inspect\nfrom abc import abstractmethod\nfrom pathlib import Path\nfrom typing import List\n\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom pandas.api.types import CategoricalDtype\nfrom scipy.interpolate import (\n    LinearNDInterpolator,\n    NearestNDInterpolator,\n    RegularGridInterpolator,\n)\n\nfrom floris.heterogeneous_map import HeterogeneousMap\nfrom floris.type_dec import NDArrayFloat\nfrom floris.utilities import (\n    check_and_identify_step_size,\n    is_all_scalar_dict,\n    make_wind_directions_adjacent,\n)\n\n\nclass WindDataBase:\n    \"\"\"\n    Super class that WindRose and TimeSeries inherit from, enforcing the implementation of\n    unpack() on the child classes and providing the general functions unpack_for_reinitialize() and\n    unpack_freq().\n    \"\"\"\n\n    @abstractmethod\n    def unpack(self):\n        \"\"\"\n        Placeholder for child classes of WindDataBase, which each need to implement the unpack()\n        method.\n        \"\"\"\n        raise NotImplementedError(\"unpack() not implemented on {0}\".format(self.__class__.__name__))\n\n    def unpack_for_reinitialize(self):\n        \"\"\"\n        Return only the variables need for FlorisModel.reinitialize\n        \"\"\"\n        (\n            wind_directions_unpack,\n            wind_speeds_unpack,\n            ti_table_unpack,\n            _,\n            _,\n            heterogeneous_inflow_config,\n        ) = self.unpack()\n\n        return (\n            wind_directions_unpack,\n            wind_speeds_unpack,\n            ti_table_unpack,\n            heterogeneous_inflow_config,\n        )\n\n    def unpack_freq(self):\n        \"\"\"Unpack frequency weighting\"\"\"\n\n        return self.unpack()[3]\n\n    def unpack_value(self):\n        \"\"\"Unpack values of power generated\"\"\"\n\n        return self.unpack()[4]\n\n    def unpack_multidim_conditions(self):\n        \"\"\"Unpack multidimensional conditions\n\n        NOTE: This is a temporary method for backwards compatibility and will be removed in a\n        future release, when multidim_conditions are included in the unpack() method of child\n        classes.\n        \"\"\"\n\n        return getattr(self, \"multidim_conditions\", None)\n\n    def check_heterogeneous_inflow_config(self, heterogeneous_inflow_config):\n        \"\"\"\n        Check that the heterogeneous_inflow_config dictionary is properly formatted\n\n        Args:\n            heterogeneous_inflow_config (dict): A dictionary containing the following keys:\n                * 'speed_multipliers': A 2D NumPy array (size n_findex x num_points)\n                      of speed multipliers.\n                * 'x': A 1D NumPy array (size num_points) of x-coordinates (meters).\n                * 'y': A 1D NumPy array (size num_points) of y-coordinates (meters).\n        \"\"\"\n        if heterogeneous_inflow_config is not None:\n            if not isinstance(heterogeneous_inflow_config, dict):\n                raise TypeError(\"heterogeneous_inflow_config_by_wd must be a dictionary\")\n            if \"speed_multipliers\" not in heterogeneous_inflow_config:\n                raise ValueError(\n                    \"heterogeneous_inflow_config must contain a key 'speed_multipliers'\"\n                )\n            if \"x\" not in heterogeneous_inflow_config:\n                raise ValueError(\"heterogeneous_inflow_config must contain a key 'x'\")\n            if \"y\" not in heterogeneous_inflow_config:\n                raise ValueError(\"heterogeneous_inflow_config must contain a key 'y'\")\n\n    def set_layout(self, layout_x=None, layout_y=None):\n        \"\"\"\n        Default implementation the explicitly does nothing.  Only WindData objects that depend\n        on layout need to implement this method.\n\n        Included so that FlorisModel can call this method on the WindData object when the layout\n        is updated.\n\n        Args:\n            layout_x (list, optional): List of x-coordinates of the turbines. Defaults to None.\n            layout_y (list, optional): List of y-coordinates of the turbines. Defaults to None.\n        \"\"\"\n        # No operation performed\n        return None\n\n\nclass WindRose(WindDataBase):\n    \"\"\"\n    The WindRose class is used to drive FLORIS and optimization operations in\n    which the inflow is characterized by the frequency of binned wind speed and\n    wind direction values.  Turbulence intensities are defined as a function of\n    wind direction and wind speed.\n\n    Args:\n        wind_directions: NumPy array of wind directions (NDArrayFloat).  Must\n            be evenly spaced and monotonically increasing.\n        wind_speeds: NumPy array of wind speeds (NDArrayFloat).  Must be\n            evenly spaced and monotonically increasing.\n        ti_table: Turbulence intensity table for binned wind direction, wind\n            speed values (float, NDArrayFloat).  Can be an array with dimensions\n            (n_wind_directions, n_wind_speeds) or a single float value.  If a\n            single float value is provided, the turbulence intensity is assumed\n            to be constant across all wind directions and wind speeds.\n        freq_table: Frequency table for binned wind direction, wind speed\n            values (NDArrayFloat, optional).   Must have dimension\n            (n_wind_directions, n_wind_speeds).  Defaults to None in which case\n            uniform frequency of all bins is assumed.\n        value_table: Value table for binned wind direction, wind\n            speed values (NDArrayFloat, optional).  Must have dimension\n            (n_wind_directions, n_wind_speeds).  Defaults to None in which case\n            uniform values are assumed.  Value can be used to weight power in\n            each bin to compute the total value of the energy produced\n        compute_zero_freq_occurrence: Flag indicating whether to compute zero\n            frequency occurrences (bool, optional).  Defaults to False.\n        heterogeneous_map (HeterogeneousMap, optional): A HeterogeneousMap object to define\n            background heterogeneous inflow condition as a function\n            of wind direction and wind speed.  Alternatively, a dictionary can be\n            passed in to define a HeterogeneousMap object.  Defaults to None.\n        heterogeneous_inflow_config_by_wd (dict, optional): A dictionary containing the following\n            which can be used to define a heterogeneous_map object (note this parameter is kept\n            for backwards compatibility and is not recommended for use):\n            * 'x': A 1D NumPy array (size num_points) of x-coordinates (meters).\n            * 'y': A 1D NumPy array (size num_points) of y-coordinates (meters).\n            * 'speed_multipliers': A 2D NumPy array (size num_wd (or num_ws) x num_points)\n                of speed multipliers.  If neither wind_directions nor wind_speeds are\n                defined, then this should be a single row array\n            * 'wind_directions': A 1D NumPy array (size num_wd) of wind directions (degrees).\n                Optional.\n            * 'wind_speeds': A 1D NumPy array (size num_ws) of wind speeds (m/s). Optional.\n            Defaults to None.\n        multidim_conditions (dict, optional): A dictionary containing multidimensional inflow\n            conditions. Each key is the name of the condition, and each value is either a 2D NumPy\n            array of size n_wind_directions x n_wind_speeds containing the condition values,\n            or a scalar value that will be broadcast to size n_findex. Defaults to None.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        wind_directions: NDArrayFloat,\n        wind_speeds: NDArrayFloat,\n        ti_table: float | NDArrayFloat,\n        freq_table: NDArrayFloat | None = None,\n        value_table: NDArrayFloat | None = None,\n        compute_zero_freq_occurrence: bool = False,\n        heterogeneous_map: HeterogeneousMap | dict | None = None,\n        heterogeneous_inflow_config_by_wd: dict | None = None,\n        multidim_conditions: dict | None = None,\n    ):\n        if not isinstance(wind_directions, np.ndarray) or wind_directions.ndim != 1:\n            raise TypeError(\"wind_directions must be a 1D NumPy array\")\n\n        if not isinstance(wind_speeds, np.ndarray) or wind_speeds.ndim != 1:\n            raise TypeError(\"wind_speeds must be a 1D NumPy array\")\n\n        # Confirm that both wind_directions and wind_speeds are monitonically\n        # increasing and evenly spaced\n        _n_wd = len(wind_directions)\n        _n_ws = len(wind_speeds)\n\n        if _n_wd > 1:\n            # Check monotonically increasing\n            if not np.all(np.diff(wind_directions) > 0):\n                raise ValueError(\"wind_directions must be monotonically increasing\")\n\n            # Check evenly spaced (Function will raise error if not)\n            check_and_identify_step_size(wind_directions=wind_directions)\n\n        if _n_ws > 1:\n            # Check monotonically increasing\n            if not np.all(np.diff(wind_speeds) > 0):\n                raise ValueError(\"wind_speeds must be monotonically increasing\")\n\n            # Check evenly spaced\n            if not np.allclose(np.diff(wind_speeds), wind_speeds[1] - wind_speeds[0]):\n                raise ValueError(\"wind_speeds must be evenly spaced\")\n\n        # Save the wind speeds and directions\n        self.wind_directions = wind_directions\n        self.wind_speeds = wind_speeds\n\n        # Check ti_table is a float or a NumPy array\n        if not isinstance(ti_table, (float, np.ndarray)):\n            raise TypeError(\"ti_table must be a float or a NumPy array\")\n\n        # Check if ti_table is a single float value\n        if isinstance(ti_table, float):\n            self.ti_table = np.full((_n_wd, _n_ws), ti_table)\n\n        # Otherwise confirm the dimensions and then save it\n        else:\n            if not ti_table.shape[0] == _n_wd:\n                raise ValueError(\"ti_table first dimension must equal len(wind_directions)\")\n            if not ti_table.shape[1] == _n_ws:\n                raise ValueError(\"ti_table second dimension must equal len(wind_speeds)\")\n            self.ti_table = ti_table\n\n        # If freq_table is not None, confirm it has correct dimension,\n        # otherwise initialize to uniform probability\n        if freq_table is not None:\n            if not freq_table.shape[0] == _n_wd:\n                raise ValueError(\"freq_table first dimension must equal len(wind_directions)\")\n            if not freq_table.shape[1] == _n_ws:\n                raise ValueError(\"freq_table second dimension must equal len(wind_speeds)\")\n            self.freq_table = freq_table\n        else:\n            self.freq_table = np.ones((_n_wd, _n_ws))\n\n        # Normalize freq table\n        self.freq_table = self.freq_table / np.sum(self.freq_table)\n\n        # If value_table is not None, confirm it has correct dimension,\n        # otherwise initialize to all ones\n        if value_table is not None:\n            if not value_table.shape[0] == _n_wd:\n                raise ValueError(\"value_table first dimension must equal len(wind_directions)\")\n            if not value_table.shape[1] == _n_ws:\n                raise ValueError(\"value_table second dimension must equal len(wind_speeds)\")\n        self.value_table = value_table\n\n        # Save whether zero occurrence cases should be computed\n        # First check if the ti_table contains any nan values (which would occur for example\n        # if generated by the TimeSeries to WindRose conversion for wind speeds and directions\n        # that were not present in the original time series)  In this case, raise an error\n        if compute_zero_freq_occurrence:\n            if np.isnan(self.ti_table).any():\n                raise ValueError(\n                    \"ti_table contains nan values.  (This is likely the result of \"\n                    \" unsed wind speeds and directions in the original time series.)\"\n                    \"  Cannot compute zero frequency occurrences.\"\n                )\n        self.compute_zero_freq_occurrence = compute_zero_freq_occurrence\n\n        # Check that heterogeneous_map and heterogeneous_inflow_config_by_wd are not both defined\n        if heterogeneous_map is not None and heterogeneous_inflow_config_by_wd is not None:\n            raise ValueError(\n                \"Only one of heterogeneous_map and heterogeneous_inflow_config_by_wd can be\"\n                + \" defined.\"\n            )\n\n        # If heterogeneous_inflow_config_by_wd is not None, then create a HeterogeneousMap object\n        # using the dictionary\n        if heterogeneous_inflow_config_by_wd is not None:\n            # TODO: In future, add deprecation warning for this parameter here\n\n            self.heterogeneous_map = HeterogeneousMap(**heterogeneous_inflow_config_by_wd)\n\n        # Else if heterogeneous_map is not None\n        elif heterogeneous_map is not None:\n            # If heterogeneous_map is a dictionary, then create a HeterogeneousMap object\n            if isinstance(heterogeneous_map, dict):\n                self.heterogeneous_map = HeterogeneousMap(**heterogeneous_map)\n\n            # Else if heterogeneous_map is a HeterogeneousMap object, then save it\n            elif isinstance(heterogeneous_map, HeterogeneousMap):\n                self.heterogeneous_map = heterogeneous_map\n\n            # Else raise an error\n            else:\n                raise ValueError(\n                    \"heterogeneous_map must be a HeterogeneousMap object or a dictionary.\"\n                )\n\n        # Else if neither heterogeneous_map nor heterogeneous_inflow_config_by_wd are defined,\n        # then set heterogeneous_map to None\n        else:\n            self.heterogeneous_map = None\n\n        # Handle the multidim_conditions\n        if multidim_conditions is not None:\n            # Check that each value in the dictionary is either scalar or a correctly-sized array\n            if is_all_scalar_dict(multidim_conditions):\n                # Leave all scalar for performance purposes\n                pass\n            else:\n                for key, value in multidim_conditions.items():\n                    if isinstance(value, np.ndarray):\n                        if value.shape != (_n_wd, _n_ws):\n                            raise ValueError(\n                                f\"multidim_conditions[{key}] must be of size len(wind_directions) \"\n                                f\"x len(wind_speeds) [({_n_wd}, {_n_ws})] but currently has shape \"\n                                f\"{value.shape}.\"\n                            )\n                    else:\n                        raise ValueError(\n                            f\"multidim_conditions[{key}] must be a 2D NumPy array of size \"\n                            \"len(wind_directions) x len(wind_speeds) or a scalar value.\"\n                        )\n        self.multidim_conditions = multidim_conditions\n\n        # Build the gridded and flatten versions\n        self._build_gridded_and_flattened_version()\n\n    def _build_gridded_and_flattened_version(self):\n        \"\"\"\n        Given the wind direction and speed array, build the gridded versions\n        covering all combinations, and then flatten versions which put all\n        combinations into 1D array\n        \"\"\"\n        # Gridded wind speed and direction\n        self.wd_grid, self.ws_grid = np.meshgrid(\n            self.wind_directions, self.wind_speeds, indexing=\"ij\"\n        )\n\n        # Flat wind speed and direction\n        self.wd_flat = self.wd_grid.flatten()\n        self.ws_flat = self.ws_grid.flatten()\n\n        # Flat frequency table\n        self.freq_table_flat = self.freq_table.flatten()\n\n        # Flat TI table\n        self.ti_table_flat = self.ti_table.flatten()\n\n        # value table\n        if self.value_table is not None:\n            self.value_table_flat = self.value_table.flatten()\n        else:\n            self.value_table_flat = None\n\n        # Flatten multidim_conditions if defined\n        if self.multidim_conditions is not None:\n            if is_all_scalar_dict(self.multidim_conditions):\n                # Leave all scalar for performance purposes\n                self.multidim_conditions_flat = self.multidim_conditions\n            else:\n                self.multidim_conditions_flat = {\n                    k: v.flatten() for k, v in self.multidim_conditions.items()\n                }\n        else:\n            self.multidim_conditions_flat = None\n\n        # Set mask to non-zero frequency cases depending on compute_zero_freq_occurrence\n        if self.compute_zero_freq_occurrence:\n            # If computing zero freq occurrences, then this is all True\n            self.non_zero_freq_mask = [True for i in range(len(self.freq_table_flat))]\n        else:\n            self.non_zero_freq_mask = self.freq_table_flat > 0.0\n\n        # N_findex should only be the calculated cases\n        self.n_findex = np.sum(self.non_zero_freq_mask)\n\n    def unpack(self):\n        \"\"\"\n        Unpack the flattened versions of the matrices and return the values\n        accounting for the non_zero_freq_mask\n        \"\"\"\n\n        # The unpacked versions start as the flat version of each\n        wind_directions_unpack = self.wd_flat.copy()\n        wind_speeds_unpack = self.ws_flat.copy()\n        freq_table_unpack = self.freq_table_flat.copy()\n        ti_table_unpack = self.ti_table_flat.copy()\n\n        # Now mask thes values according to self.non_zero_freq_mask\n        wind_directions_unpack = wind_directions_unpack[self.non_zero_freq_mask]\n        wind_speeds_unpack = wind_speeds_unpack[self.non_zero_freq_mask]\n        freq_table_unpack = freq_table_unpack[self.non_zero_freq_mask]\n        ti_table_unpack = ti_table_unpack[self.non_zero_freq_mask]\n\n        # Now get unpacked value table\n        if self.value_table_flat is not None:\n            value_table_unpack = self.value_table_flat[self.non_zero_freq_mask].copy()\n        else:\n            value_table_unpack = None\n\n        # If heterogeneous_map is not None, then get the heterogeneous_inflow_config\n        if self.heterogeneous_map is not None:\n            heterogeneous_inflow_config = self.heterogeneous_map.get_heterogeneous_inflow_config(\n                wind_directions=wind_directions_unpack, wind_speeds=wind_speeds_unpack\n            )\n        else:\n            heterogeneous_inflow_config = None\n\n        return (\n            wind_directions_unpack,\n            wind_speeds_unpack,\n            ti_table_unpack,\n            freq_table_unpack,\n            value_table_unpack,\n            heterogeneous_inflow_config,\n        )\n\n    def unpack_multidim_conditions(self):\n        if self.multidim_conditions_flat is None:\n            return None\n        elif is_all_scalar_dict(self.multidim_conditions_flat):\n            return self.multidim_conditions_flat\n        else:\n            return {\n                k: v[self.non_zero_freq_mask] for k, v in self.multidim_conditions_flat.items()\n            }\n\n    def aggregate(self, wd_step=None, ws_step=None, inplace=False):\n        \"\"\"\n        Wrapper for downsample method for backwards compatibility\n        \"\"\"\n\n        return self.downsample(wd_step, ws_step, inplace)\n\n    def downsample(self, wd_step=None, ws_step=None, inplace=False):\n        \"\"\"\n        Aggregates the wind rose into fewer wind direction and wind speed bins.\n        It is necessary the wd_step and ws_step passed in are at least as\n        large as the current wind direction and wind speed steps.  If they are\n        not, the function will raise an error.\n\n        The function will return a new WindRose object with the aggregated\n        wind direction and wind speed bins.  If inplace is set to True, the\n        current WindRose object will be updated with the aggregated bins.\n\n        Args:\n            wd_step: Step size for wind direction resampling (float, optional).\n                If None, the current step size will be used. Defaults to None.\n            ws_step: Step size for wind speed resampling (float, optional). If\n                None, the current step size will be used. Defaults to None.\n            inplace: Flag indicating whether to update the current WindRose\n                object when True or return a new WindRose object when False\n                (bool, optional). Defaults to False.\n\n        Returns:\n            WindRose: Aggregated wind rose based on the provided or default step\n                sizes. Only returned if inplace = False.\n\n        Notes:\n            - Returns a aggregated version of the wind rose using new `ws_step` and `wd_step`.\n            - Uses the bin weights feature in TimeSeries to aggregated the wind rose.\n            - If `ws_step` or `wd_step` is not specified, it uses the current values.\n        \"\"\"\n\n        # If ws_step is passed in, confirm is it at least as large as the current step\n        if ws_step is not None:\n            if len(self.wind_speeds) >= 2:\n                current_ws_step = self.wind_speeds[1] - self.wind_speeds[0]\n                if ws_step < current_ws_step:\n                    raise ValueError(\n                        \"ws_step provided must be at least as large as the current ws_step \"\n                        f\"({current_ws_step} m/s)\"\n                    )\n\n        # If wd_step is passed in, confirm is it at least as large as the current step\n        if wd_step is not None:\n            if len(self.wind_directions) >= 2:\n                current_wd_step = check_and_identify_step_size(wind_directions=self.wind_directions)\n                if wd_step < current_wd_step:\n                    raise ValueError(\n                        \"wd_step provided must be at least as large as the current wd_step \"\n                        f\"({current_wd_step} degrees)\"\n                    )\n\n        # If either ws_step or wd_step is None, set it to the current step\n        if ws_step is None:\n            if len(self.wind_speeds) >= 2:\n                ws_step = self.wind_speeds[1] - self.wind_speeds[0]\n            else:  # wind rose will have only a single wind speed, and we assume a ws_step of 1\n                ws_step = 1.0\n        if wd_step is None:\n            if len(self.wind_directions) >= 2:\n                wd_step = check_and_identify_step_size(wind_directions=self.wind_directions)\n            else:  # wind rose will have only a single wind direction, and we assume a wd_step of 1\n                wd_step = 1.0\n\n        # Pass the flat versions of each quantity to build a TimeSeries model\n        time_series = TimeSeries(\n            self.wd_flat,\n            self.ws_flat,\n            self.ti_table_flat,\n            self.value_table_flat,\n            self.heterogeneous_map,\n        )\n\n        # Now build a new wind rose using the new steps\n        aggregated_wind_rose = time_series.to_WindRose(\n            wd_step=wd_step, ws_step=ws_step, bin_weights=self.freq_table_flat\n        )\n        if inplace:\n            self.__init__(\n                aggregated_wind_rose.wind_directions,\n                aggregated_wind_rose.wind_speeds,\n                aggregated_wind_rose.ti_table,\n                aggregated_wind_rose.freq_table,\n                aggregated_wind_rose.value_table,\n                aggregated_wind_rose.compute_zero_freq_occurrence,\n                aggregated_wind_rose.heterogeneous_map,\n            )\n        else:\n            return aggregated_wind_rose\n\n    def resample_by_interpolation(self, wd_step=None, ws_step=None, method=\"linear\", inplace=False):\n        \"\"\"\n        Wrapper to upsample method for backwards compatibility\n        \"\"\"\n\n        return self.upsample(wd_step, ws_step, method, inplace)\n\n    def upsample(self, wd_step=None, ws_step=None, method=\"linear\", inplace=False):\n        \"\"\"\n\n        Resample the wind rose using interpolation for upsampling.  The method can be either\n        'linear' or 'nearest'.  If inplace is set to True, the current WindRose\n        object will be updated with the resampled bins.\n\n        Args:\n            wd_step: Step size for wind direction resampling (float, optional).\n                If None, the current step size will be used. Defaults to None.\n            ws_step: Step size for wind speed resampling (float, optional).\n                If None, the current step size will be used. Defaults to None.\n            method: Interpolation method to use (str, optional).  Can be either\n                'linear' or 'nearest'. Defaults to \"linear\".\n            inplace: Flag indicating whether to update the current WindRose\n                object when True or return a new WindRose object when False\n                (bool, optional). Defaults to False.\n\n        Returns:\n            WindRose: Resampled wind rose based on the provided or default step\n                sizes. Only returned if inplace = False.\n\n        \"\"\"\n        if method == \"linear\":\n            interpolator = LinearNDInterpolator\n        elif method == \"nearest\":\n            interpolator = NearestNDInterpolator\n        else:\n            raise ValueError(\n                f\"Unknown interpolation method: '{method}'. \"\n                \"Available methods are 'linear' and 'nearest'\"\n            )\n\n        # First establish the current ws_step and wd_step\n        if len(self.wind_speeds) >= 2:\n            ws_step_current = self.wind_speeds[1] - self.wind_speeds[0]\n        else:  # wind rose will have only a single wind speed, and we assume a ws_step of 1\n            ws_step_current = 1.0\n\n        if len(self.wind_directions) >= 2:\n            # Identify the current step size\n            wd_step_current = check_and_identify_step_size(wind_directions=self.wind_directions)\n        else:  # wind rose will have only a single wind direction, and we assume a wd_step of 1\n            wd_step_current = 1.0\n\n        # If either ws_step or wd_step is None, set it to the current step\n        if ws_step is None:\n            ws_step = ws_step_current\n        if wd_step is None:\n            wd_step = wd_step_current\n\n        # Make sure upsampling is appropriate\n        if wd_step > wd_step_current:\n            raise ValueError(\n                f\"Provided wd_step ({wd_step}) is larger than the current \"\n                f\" wind direction step size.  ({wd_step_current} degrees)\"\n                \" Use the downsample method.\"\n            )\n\n        if ws_step > ws_step_current:\n            raise ValueError(\n                f\"Provided ws_step ({ws_step}) is larger than \"\n                f\"the current wind speed step size.  ({ws_step_current} m/s)\"\n                \" Use the downsample method.\"\n            )\n\n        # Get the current wind directions in adjacent from (ie 0, 2 358 -> -2, 0 ,2)\n        if len(self.wind_directions) >= 2:\n            current_wind_directions, adjacent_sort_index = make_wind_directions_adjacent(\n                self.wind_directions\n            )\n        else:\n            current_wind_directions = self.wind_directions\n            adjacent_sort_index = np.arange(len(current_wind_directions))\n\n        # Identify the covered range of wind directions\n        wd_range_min_current = np.min(current_wind_directions) - wd_step_current / 2.0\n        wd_range_max_current = np.max(current_wind_directions) + wd_step_current / 2.0\n\n        # Look for unlikely case where for example wind directions are 8, 28, ... 358\n        if wd_range_max_current > 360:\n            # TODO: Handle this case without an error\n            raise ValueError(\n                \"Cannot upsample wind rose for case when wind directions are defined\"\n                \" such that 0 degrees is included by bins to the left of 0 degrees. \"\n            )\n\n        # Identify the new minimum wind direction\n        wd_min_new = wd_range_min_current + wd_step / 2.0\n        wd_max_new = wd_range_max_current - wd_step / 2.0\n\n        new_wind_directions = np.arange(wd_min_new, wd_max_new + wd_step / 2.0, wd_step)\n\n        # Set up the new wind speeds\n        ws_range_min_current = np.min(self.wind_speeds) - ws_step_current / 2.0\n        ws_range_max_current = np.max(self.wind_speeds) + ws_step_current / 2.0\n        ws_min_new = ws_range_min_current + ws_step / 2.0\n        ws_max_new = ws_range_max_current - ws_step / 2.0\n\n        # Force the new ws_min to 0 if negative\n        if ws_min_new < 0:\n            ws_min_new = 0.0\n\n        new_wind_speeds = np.arange(ws_min_new, ws_max_new + ws_step / 2.0, ws_step)\n\n        # Set up for interpolation by copying the current values\n        # and making sure they are sorted according to the adjacent wind directions\n        wind_direction_column = current_wind_directions.copy()\n        wind_speed_column = self.wind_speeds.copy()\n        ti_matrix = self.ti_table.copy()[adjacent_sort_index, :]\n        freq_matrix = self.freq_table.copy()[adjacent_sort_index, :]\n        if self.value_table is not None:\n            value_matrix = self.value_table.copy()[adjacent_sort_index, :]\n        else:\n            value_matrix = None\n\n        # For padding wind directions, there are two cases to consider.  In the first,\n        # say that the wind directions are 30, 40, 50.  In this case it's important append\n        # 30 and 50 to 35 and 55 to ensure the interpolation covers the full range of data\n        # This is the case when wind directions doesn't cover the full range of possible\n        # degrees (0-360)\n        if np.abs((wd_range_min_current % 360.0) - (wd_range_max_current % 360.0)) > 1e-6:\n            wind_direction_column = np.concatenate((\n                np.array([wd_range_min_current]),\n                wind_direction_column,\n                np.array([wd_range_max_current])\n            ))\n            ti_matrix = ti_matrix = np.vstack((ti_matrix[0, :], ti_matrix, ti_matrix[-1,:]))\n            freq_matrix = np.vstack((freq_matrix[0, :], freq_matrix, freq_matrix[-1,:]))\n            if self.value_table is not None:\n                value_matrix = np.vstack((value_matrix[0, :], value_matrix, value_matrix[-1,:]))\n\n        # In the alternative case, where the wind directions cover the full range\n        # ie, 0, 10, 20 30, ...350, then need to place 0 at 360 and 350 at -10\n        # to cover all interpolations\n        else:\n            # Pad wind direction column with min_wd + 360\n            wind_direction_column = np.concatenate(\n                (\n                    [np.max(self.wind_directions) - 360.0],\n                    wind_direction_column,\n                    [np.min(self.wind_directions) + 360.0],\n                )\n            )\n\n            # Pad the remaining with the appropriate value\n            ti_matrix = ti_matrix = np.vstack((ti_matrix[-1, :], ti_matrix, ti_matrix[0, :]))\n            freq_matrix = np.vstack((freq_matrix[-1, :], freq_matrix, freq_matrix[0, :]))\n            if self.value_table is not None:\n                value_matrix = np.vstack((value_matrix[-1, :], value_matrix, value_matrix[0, :]))\n\n        # Pad out the wind speeds\n        wind_speed_column = np.concatenate(\n            (\n                np.array([ws_range_min_current]),\n                wind_speed_column,\n                np.array([ws_range_max_current])\n            )\n        )\n        ti_matrix = np.hstack(\n            (ti_matrix[:, 0].reshape((-1, 1)), ti_matrix, ti_matrix[:, -1].reshape((-1, 1)))\n        )\n        freq_matrix = np.hstack(\n            (freq_matrix[:, 0].reshape((-1, 1)), freq_matrix, freq_matrix[:, -1].reshape((-1, 1)))\n        )\n        if self.value_table is not None:\n            value_matrix = np.hstack(\n                (\n                    value_matrix[:, 0].reshape((-1, 1)),\n                    value_matrix,\n                    value_matrix[:, -1].reshape((-1, 1))\n                )\n            )\n\n        # Grid wind directions and wind speeds to match the ti_matrix and freq_matrix when flattened\n        wd_grid, ws_grid = np.meshgrid(wind_direction_column, wind_speed_column, indexing=\"ij\")\n\n        # Form wd_grid and ws_grid to a 2-column matrix\n        wd_ws_mat = np.array([wd_grid.flatten(), ws_grid.flatten()]).T\n\n        # Build the interpolator from wd_grid, ws_grid, to ti_matrix, freq_matrix and value_matrix\n        ti_interpolator = interpolator(wd_ws_mat, ti_matrix.flatten())\n        freq_interpolator = interpolator(wd_ws_mat, freq_matrix.flatten())\n        if self.value_table is not None:\n            value_interpolator = interpolator(wd_ws_mat, value_matrix.flatten())\n\n        # Grid the new wind directions and wind speeds\n        new_wd_grid, new_ws_grid = np.meshgrid(new_wind_directions, new_wind_speeds, indexing=\"ij\")\n        new_wd_ws_mat = np.array([new_wd_grid.flatten(), new_ws_grid.flatten()]).T\n\n        # Create the new ti_matrix and freq_matrix\n        new_ti_matrix = ti_interpolator(new_wd_ws_mat).reshape(\n            (len(new_wind_directions), len(new_wind_speeds))\n        )\n        new_freq_matrix = freq_interpolator(new_wd_ws_mat).reshape(\n            (len(new_wind_directions), len(new_wind_speeds))\n        )\n\n        if self.value_table is not None:\n            new_value_matrix = value_interpolator(new_wd_ws_mat).reshape(\n                (len(new_wind_directions), len(new_wind_speeds))\n            )\n        else:\n            new_value_matrix = None\n\n        # Wrap new_wind_directions to 0-360\n        new_wind_directions = new_wind_directions % 360\n\n        # Finally sort new_wind_directions, and re-order new_ti_matrix, new_freq_matrix\n        # and new_value_matrix accordingly\n        sort_indices = np.argsort(new_wind_directions)\n        new_wind_directions = new_wind_directions[sort_indices]\n        new_ti_matrix = new_ti_matrix[sort_indices, :]\n        new_freq_matrix = new_freq_matrix[sort_indices, :]\n        if self.value_table is not None:\n            new_value_matrix = new_value_matrix[sort_indices, :]\n\n        # Create the resampled wind rose\n        resampled_wind_rose = WindRose(\n            new_wind_directions,\n            new_wind_speeds,\n            new_ti_matrix,\n            new_freq_matrix,\n            new_value_matrix,\n            self.compute_zero_freq_occurrence,\n            self.heterogeneous_map,\n        )\n\n        if inplace:\n            self.__init__(\n                resampled_wind_rose.wind_directions,\n                resampled_wind_rose.wind_speeds,\n                resampled_wind_rose.ti_table,\n                resampled_wind_rose.freq_table,\n                resampled_wind_rose.value_table,\n                resampled_wind_rose.compute_zero_freq_occurrence,\n                resampled_wind_rose.heterogeneous_map,\n            )\n        else:\n            return resampled_wind_rose\n\n    def plot(\n        self,\n        ax=None,\n        color_map=\"viridis_r\",\n        wd_step=None,\n        ws_step=None,\n        legend_kwargs={\"label\": \"Wind speed [m/s]\"},\n    ):\n        \"\"\"\n        This method creates a wind rose plot showing the frequency of occurrence\n        of the specified wind direction and wind speed bins. If no axis is\n        provided, a new one is created.\n\n        **Note**: Based on code provided by Patrick Murphy from the University\n        of Colorado Boulder.\n\n        Args:\n            ax (:py:class:`matplotlib.pyplot.axes`, optional): The figure axes\n                on which the wind rose is plotted. Defaults to None.\n            color_map (str, optional): Colormap to use. Defaults to 'viridis_r'.\n            wd_step: Step size for wind direction (float, optional). If None,\n                the current step size will be used. Defaults to None.\n            ws_step: Step size for wind speed (float, optional).\n                the current step size will be used. Defaults to None.\n            legend_kwargs (dict, optional): Keyword arguments to be passed to\n                ax.legend(). Defaults to {\"label\": \"Wind speed [m/s]\"}.\n\n        Returns:\n            :py:class:`matplotlib.pyplot.axes`: A figure axes object containing\n            the plotted wind rose.\n        \"\"\"\n\n        # Get a aggregated (downsampled) wind_rose\n        wind_rose_aggregate = self.downsample(wd_step, ws_step, inplace=False)\n        wd_bins = wind_rose_aggregate.wind_directions\n        ws_bins = wind_rose_aggregate.wind_speeds\n        freq_table = wind_rose_aggregate.freq_table\n\n        # Set up figure\n        if ax is None:\n            _, ax = plt.subplots(subplot_kw={\"polar\": True})\n\n        # Get the wd_step\n        if wd_step is None:\n            if len(wd_bins) >= 2:\n                wd_step = wd_bins[1] - wd_bins[0]\n            else:\n                # This admittedly an odd edge case\n                wd_step = 360.0\n\n        # Get a color array\n        color_array = plt.get_cmap(color_map, len(ws_bins))\n        norm_ws = mpl.colors.Normalize(vmin=np.min(ws_bins), vmax=np.max(ws_bins))\n        sm_ws = mpl.cm.ScalarMappable(norm=norm_ws, cmap=color_array)\n\n        for wd_idx, wd in enumerate(wd_bins):\n            rects = []\n            freq_table_sub = freq_table[wd_idx, :].flatten()\n            for ws_idx, ws in reversed(list(enumerate(ws_bins))):\n                plot_val = freq_table_sub[: ws_idx + 1].sum()\n                rects.append(\n                    ax.bar(\n                        np.radians(wd),\n                        plot_val,\n                        width=0.9 * np.radians(wd_step),\n                        color=color_array(ws_idx),\n                        edgecolor=\"k\",\n                    )\n                )\n\n        # Configure the plot\n        try:\n           ax.figure.colorbar(sm_ws, ax=ax, **legend_kwargs)\n           ax.figure.tight_layout()\n        except TypeError:\n           ax.legend(reversed(rects), ws_bins, **legend_kwargs)\n           ax.figure.get_children()[-1].remove() # Remove the empty colorbar\n        ax.set_theta_direction(-1)\n        ax.set_theta_offset(np.pi / 2.0)\n        ax.set_theta_zero_location(\"N\")\n        ax.set_xticks(np.arange(0, 2 * np.pi, np.pi / 4))\n        ax.set_xticklabels([\"N\", \"NE\", \"E\", \"SE\", \"S\", \"SW\", \"W\", \"NW\"])\n\n        return ax\n\n    def assign_ti_using_wd_ws_function(self, func):\n        \"\"\"\n        Use the passed in function to assign new values to turbulence_intensities\n\n        Args:\n            func (function): Function which accepts wind_directions as its\n                first argument and wind_speeds as second argument and returns\n                turbulence_intensities\n        \"\"\"\n        self.ti_table = func(self.wd_grid, self.ws_grid)\n        self._build_gridded_and_flattened_version()\n\n    def assign_ti_using_IEC_method(self, Iref=0.07, offset=3.8):\n        \"\"\"\n        Define TI as a function of wind speed by specifying an Iref and offset\n        value as in the normal turbulence model in the IEC 61400-1 standard\n\n        Args:\n            Iref (float): Reference turbulence level, defined as the expected\n                value of TI at 15 m/s. Default = 0.07. Note this value is\n                lower than the values of Iref for turbulence classes A, B, and\n                C in the IEC standard (0.16, 0.14, and 0.12, respectively), but\n                produces TI values more in line with those typically used in\n                FLORIS. When the default Iref and offset are used, the TI at\n                8 m/s is 8.6%.\n            offset (float): Offset value to equation. Default = 3.8, as defined\n                in the IEC standard to give the expected value of TI for\n                each wind speed.\n        \"\"\"\n        if (Iref < 0) or (Iref > 1):\n            raise ValueError(\"Iref must be >= 0 and <=1\")\n\n        def iref_func(wind_directions, wind_speeds):\n            sigma_1 = Iref * (0.75 * wind_speeds + offset)\n            return sigma_1 / wind_speeds\n\n        self.assign_ti_using_wd_ws_function(iref_func)\n\n    def plot_ti_over_ws(\n        self,\n        ax=None,\n        marker=\".\",\n        ls=\"None\",\n        color=\"k\",\n    ):\n        \"\"\"\n        Scatter plot the turbulence_intensities against wind_speeds\n\n        Args:\n            ax (:py:class:`matplotlib.pyplot.axes`, optional): The figure axes\n                on which the turbulence intensity is plotted. Defaults to None.\n            marker (str, optional): Scatter plot marker style. Defaults to \".\".\n            ls (str, optional): Scatter plot line style. Defaults to \"None\".\n            color (str, optional): Scatter plot color. Defaults to \"k\".\n\n        Returns:\n            :py:class:`matplotlib.pyplot.axes`: A figure axes object containing\n            the plotted turbulence intensities as a function of wind speed.\n        \"\"\"\n\n        # TODO: Plot mean and std. devs. of TI in each ws bin in addition to\n        # individual points\n\n        # Set up figure\n        if ax is None:\n            _, ax = plt.subplots()\n\n        ax.plot(self.ws_flat, self.ti_table_flat * 100, marker=marker, ls=ls, color=color)\n        ax.set_xlabel(\"Wind Speed (m/s)\")\n        ax.set_ylabel(\"Turbulence Intensity (%)\")\n        ax.grid(True)\n\n    def assign_value_using_wd_ws_function(self, func, normalize=False):\n        \"\"\"\n        Use the passed in function to assign new values to the value table.\n\n        Args:\n            func (function): Function which accepts wind_directions as its\n                first argument and wind_speeds as second argument and returns\n                values.\n            normalize (bool, optional): If True, the value array will be\n                normalized by the mean value. Defaults to False.\n\n        \"\"\"\n        self.value_table = func(self.wd_grid, self.ws_grid)\n\n        if normalize:\n            self.value_table /= np.sum(self.freq_table * self.value_table)\n\n        self._build_gridded_and_flattened_version()\n\n    def assign_value_piecewise_linear(\n        self,\n        value_zero_ws=1.425,\n        ws_knee=4.5,\n        slope_1=0.0,\n        slope_2=-0.135,\n        limit_to_zero=False,\n        normalize=False,\n    ):\n        \"\"\"\n        Define value as a continuous piecewise linear function of wind speed\n        with two line segments. The default parameters yield a value function\n        that approximates the normalized mean electricity price vs. wind speed\n        curve for the SPP market in the U.S. for years 2018-2020 from figure 7\n        in Simley et al. \"The value of wake steering wind farm flow control in\n        US energy markets,\" Wind Energy Science, 2024.\n        https://doi.org/10.5194/wes-9-219-2024. This default value function is\n        constant at low wind speeds, then linearly decreases above 4.5 m/s.\n\n        Args:\n            value_zero_ws (float, optional): The value when wind speed is zero.\n                Defaults to 1.425.\n            ws_knee (float, optional): The wind speed separating line segments\n                1 and 2. Default = 4.5 m/s.\n            slope_1 (float, optional): The slope of the first line segment\n                (unit of value per m/s). Defaults to zero.\n            slope_2 (float, optional): The slope of the second line segment\n            (unit of value per m/s). Defaults to -0.135.\n            limit_to_zero (bool, optional): If True, negative values will be\n                set to zero. Defaults to False.\n            normalize (bool, optional): If True, the value array will be\n                normalized by the mean value. Defaults to False.\n        \"\"\"\n\n        def piecewise_linear_value_func(wind_directions, wind_speeds):\n            value = np.zeros_like(wind_speeds, dtype=float)\n            value[wind_speeds < ws_knee] = (\n                slope_1 * wind_speeds[wind_speeds < ws_knee] + value_zero_ws\n            )\n\n            offset_2 = (slope_1 - slope_2) * ws_knee + value_zero_ws\n\n            value[wind_speeds >= ws_knee] = slope_2 * wind_speeds[wind_speeds >= ws_knee] + offset_2\n\n            if limit_to_zero:\n                value[value < 0] = 0.0\n\n            return value\n\n        self.assign_value_using_wd_ws_function(piecewise_linear_value_func, normalize)\n\n    def plot_value_over_ws(\n        self,\n        ax=None,\n        marker=\".\",\n        ls=\"None\",\n        color=\"k\",\n    ):\n        \"\"\"\n        Scatter plot the value of the energy generated against wind speed.\n\n        Args:\n            ax (:py:class:`matplotlib.pyplot.axes`, optional): The figure axes\n                on which the value is plotted. Defaults to None.\n            marker (str, optional): Scatter plot marker style. Defaults to \".\".\n            ls (str, optional): Scatter plot line style. Defaults to \"None\".\n            color (str, optional): Scatter plot color. Defaults to \"k\".\n\n        Returns:\n            :py:class:`matplotlib.pyplot.axes`: A figure axes object containing\n            the plotted value as a function of wind speed.\n        \"\"\"\n\n        # TODO: Plot mean and std. devs. of value in each ws bin in addition to\n        # individual points\n\n        # Set up figure\n        if ax is None:\n            _, ax = plt.subplots()\n\n        ax.plot(self.ws_flat, self.value_table_flat, marker=marker, ls=ls, color=color)\n        ax.set_xlabel(\"Wind Speed (m/s)\")\n        ax.set_ylabel(\"Value\")\n        ax.grid(True)\n\n    @staticmethod\n    def read_csv_long(\n        file_path: str,\n        ws_col: str = \"wind_speeds\",\n        wd_col: str = \"wind_directions\",\n        ti_col_or_value: str | float = \"turbulence_intensities\",\n        freq_col: str | None = None,\n        sep: str = \",\",\n    ) -> WindRose:\n        \"\"\"\n        Read a long-formatted CSV file into the wind rose object. By long, what is meant\n        is that the wind speed, wind direction combination is given for each row in the\n        CSV file. The wind speed, wind direction, are\n        given in separate columns, and the frequency of occurrence of each combination\n        is given in a separate column. The frequency column is optional, and if not\n        provided, uniform frequency of all bins is assumed.\n\n        The value of ti_col_or_value can be either a string or a float. If it is a string,\n        it is assumed to be the name of the column in the CSV file that contains the\n        turbulence intensity values. If it is a float, it is assumed to be a constant\n        turbulence intensity value for all wind speed and direction combinations.\n\n        Args:\n            file_path (str): Path to the CSV file.\n            ws_col (str): Name of the column in the CSV file that contains the wind speed\n                values. Defaults to 'wind_speeds'.\n            wd_col (str): Name of the column in the CSV file that contains the wind direction\n                values. Defaults to 'wind_directions'.\n            ti_col_or_value (str or float): Name of the column in the CSV file that contains\n                the turbulence intensity values, or a constant turbulence intensity value.\n            freq_col (str): Name of the column in the CSV file that contains the frequency\n                values. Defaults to None in which case constant frequency assumed.\n            sep (str): Delimiter to use. Defaults to ','.\n\n        Returns:\n            WindRose: Wind rose object created from the CSV file.\n        \"\"\"\n\n        # Read in the CSV file\n        try:\n            df = pd.read_csv(file_path, sep=sep)\n        except FileNotFoundError:\n            # If the file cannot be found, then attempt the level above\n            base_fn = Path(inspect.stack()[-1].filename).resolve().parent\n            file_path = base_fn / file_path\n            df = pd.read_csv(file_path, sep=sep)\n\n        # Check that ti_col_or_value is a string or a float\n        if not isinstance(ti_col_or_value, (str, float)):\n            raise TypeError(\"ti_col_or_value must be a string or a float\")\n\n        # Check that the required columns are present\n        if ws_col not in df.columns:\n            raise ValueError(f\"Column {ws_col} not found in CSV file\")\n        if wd_col not in df.columns:\n            raise ValueError(f\"Column {wd_col} not found in CSV file\")\n        if ti_col_or_value not in df.columns and isinstance(ti_col_or_value, str):\n            raise ValueError(f\"Column {ti_col_or_value} not found in CSV file\")\n        if freq_col not in df.columns and freq_col is not None:\n            raise ValueError(f\"Column {freq_col} not found in CSV file\")\n\n        # Get the wind speed, wind direction, and turbulence intensity values\n        wind_directions = df[wd_col].values\n        wind_speeds = df[ws_col].values\n        if isinstance(ti_col_or_value, str):\n            turbulence_intensities = df[ti_col_or_value].values\n        else:\n            turbulence_intensities = ti_col_or_value * np.ones(len(wind_speeds))\n        if freq_col is not None:\n            freq_values = df[freq_col].values\n        else:\n            freq_values = np.ones(len(wind_speeds))\n\n        # Normalize freq_values\n        freq_values = freq_values / np.sum(freq_values)\n\n        # Get the unique values of wind directions and wind speeds\n        unique_wd = np.unique(wind_directions)\n        unique_ws = np.unique(wind_speeds)\n\n        # Get the step side for wind direction and wind speed\n        wd_step = unique_wd[1] - unique_wd[0]\n        ws_step = unique_ws[1] - unique_ws[0]\n\n        # Now use TimeSeries to create a wind rose\n        time_series = TimeSeries(wind_directions, wind_speeds, turbulence_intensities)\n\n        # Now build a new wind rose using the new steps\n        return time_series.to_WindRose(wd_step=wd_step, ws_step=ws_step, bin_weights=freq_values)\n\n\nclass WindTIRose(WindDataBase):\n    \"\"\"\n    WindTIRose is similar to the WindRose class, but contains turbulence\n    intensity as an additional wind rose dimension instead of being defined\n    as a function of wind direction and wind speed. The class is used to drive\n    FLORIS and optimization operations in which the inflow is characterized by\n    the frequency of binned wind speed, wind direction, and turbulence intensity\n    values.\n\n    Args:\n        wind_directions: NumPy array of wind directions (NDArrayFloat).\n        wind_speeds: NumPy array of wind speeds (NDArrayFloat).\n        turbulence_intensities: NumPy array of turbulence intensities (NDArrayFloat).\n        freq_table: Frequency table for binned wind direction, wind speed, and\n            turbulence intensity values (NDArrayFloat, optional). Must have\n            dimension (n_wind_directions, n_wind_speeds, n_turbulence_intensities).\n            Defaults to None in which case uniform frequency of all bins is\n            assumed.\n        value_table: Value table for binned wind direction, wind\n            speed, and turbulence intensity values (NDArrayFloat, optional).\n            Must have dimension (n_wind_directions, n_wind_speeds,\n            n_turbulence_intensities). Defaults to None in which case uniform\n            values are assumed. Value can be used to weight power in each bin\n            to compute the total value of the energy produced.\n        compute_zero_freq_occurrence: Flag indicating whether to compute zero\n            frequency occurrences (bool, optional).  Defaults to False.\n        heterogeneous_map (HeterogeneousMap, optional): A HeterogeneousMap object to define\n            background heterogeneous inflow condition as a function\n            of wind direction and wind speed.  Alternatively, a dictionary can be\n            passed in to define a HeterogeneousMap object.  Defaults to None.\n        heterogeneous_inflow_config_by_wd (dict, optional): A dictionary containing the following\n            which can be used to define a heterogeneous_map object (note this parameter is kept\n            for backwards compatibility and is not recommended for use):\n            * 'x': A 1D NumPy array (size num_points) of x-coordinates (meters).\n            * 'y': A 1D NumPy array (size num_points) of y-coordinates (meters).\n            * 'speed_multipliers': A 2D NumPy array (size num_wd (or num_ws) x num_points)\n                of speed multipliers.  If neither wind_directions nor wind_speeds are\n                defined, then this should be a single row array\n            * 'wind_directions': A 1D NumPy array (size num_wd) of wind directions (degrees).\n                Optional.\n            * 'wind_speeds': A 1D NumPy array (size num_ws) of wind speeds (m/s). Optional.\n            Defaults to None.\n        multidim_conditions (dict, optional): A dictionary containing multidimensional inflow\n            conditions. Each key is the name of the condition, and each value is either a 3D NumPy\n            array of shape (n_wind_speeds, n_wind_directions, n_turbulence_intensities) containing\n            the condition values, or a scalar value that will be broadcast to size n_findex.\n            Defaults to None.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        wind_directions: NDArrayFloat,\n        wind_speeds: NDArrayFloat,\n        turbulence_intensities: NDArrayFloat,\n        freq_table: NDArrayFloat | None = None,\n        value_table: NDArrayFloat | None = None,\n        compute_zero_freq_occurrence: bool = False,\n        heterogeneous_map: HeterogeneousMap | dict | None = None,\n        heterogeneous_inflow_config_by_wd: dict | None = None,\n        multidim_conditions: dict | None = None,\n    ):\n        if not isinstance(wind_directions, np.ndarray) or wind_directions.ndim != 1:\n            raise TypeError(\"wind_directions must be a 1D NumPy array\")\n\n        if not isinstance(wind_speeds, np.ndarray) or wind_speeds.ndim != 1:\n            raise TypeError(\"wind_speeds must be a 1D NumPy array\")\n\n        if not isinstance(turbulence_intensities, np.ndarray) or turbulence_intensities.ndim != 1:\n            raise TypeError(\"turbulence_intensities must be a 1D NumPy array\")\n\n        # Confirm that both wind_directions and wind_speeds\n        # and turbulence intensities are monotonically\n        # increasing and evenly spaced\n        _n_wd = len(wind_directions)\n        _n_ws = len(wind_speeds)\n        _n_ti = len(turbulence_intensities)\n\n        if _n_wd > 1:\n            # Check monotonically increasing\n            if not np.all(np.diff(wind_directions) > 0):\n                raise ValueError(\"wind_directions must be monotonically increasing\")\n\n            # Check evenly spaced (Function will raise error if not)\n            check_and_identify_step_size(wind_directions=wind_directions)\n\n        if _n_ws > 1:\n            # Check monotonically increasing\n            if not np.all(np.diff(wind_speeds) > 0):\n                raise ValueError(\"wind_speeds must be monotonically increasing\")\n\n            # Check evenly spaced\n            if not np.allclose(np.diff(wind_speeds), wind_speeds[1] - wind_speeds[0]):\n                raise ValueError(\"wind_speeds must be evenly spaced\")\n\n        if _n_ti > 1:\n            # Check monotonically increasing\n            if not np.all(np.diff(turbulence_intensities) > 0):\n                raise ValueError(\"turbulence_intensities must be monotonically increasing\")\n\n            # Check evenly spaced\n            if not np.allclose(\n                np.diff(turbulence_intensities),\n                turbulence_intensities[1] - turbulence_intensities[0],\n            ):\n                raise ValueError(\"turbulence_intensities must be evenly spaced\")\n\n        # Save the wind speeds and directions\n        self.wind_directions = wind_directions\n        self.wind_speeds = wind_speeds\n        self.turbulence_intensities = turbulence_intensities\n\n        # If freq_table is not None, confirm it has correct dimension,\n        # otherwise initialize to uniform probability\n        if freq_table is not None:\n            if not freq_table.shape[0] == _n_wd:\n                raise ValueError(\"freq_table first dimension must equal len(wind_directions)\")\n            if not freq_table.shape[1] == _n_ws:\n                raise ValueError(\"freq_table second dimension must equal len(wind_speeds)\")\n            if not freq_table.shape[2] == _n_ti:\n                raise ValueError(\n                    \"freq_table third dimension must equal len(turbulence_intensities)\"\n                )\n            self.freq_table = freq_table\n        else:\n            self.freq_table = np.ones((_n_wd, _n_ws, _n_ti))\n\n        # Normalize freq table\n        self.freq_table = self.freq_table / np.sum(self.freq_table)\n\n        # If value_table is not None, confirm it has correct dimension,\n        # otherwise initialize to all ones\n        if value_table is not None:\n            if not value_table.shape[0] == _n_wd:\n                raise ValueError(\"value_table first dimension must equal len(wind_directions)\")\n            if not value_table.shape[1] == _n_ws:\n                raise ValueError(\"value_table second dimension must equal len(wind_speeds)\")\n            if not value_table.shape[2] == _n_ti:\n                raise ValueError(\n                    \"value_table third dimension must equal len(turbulence_intensities)\"\n                )\n        self.value_table = value_table\n\n        # Save whether zero occurrence cases should be computed\n        self.compute_zero_freq_occurrence = compute_zero_freq_occurrence\n\n        # Check that heterogeneous_map and heterogeneous_inflow_config_by_wd are not both defined\n        if heterogeneous_map is not None and heterogeneous_inflow_config_by_wd is not None:\n            raise ValueError(\n                \"Only one of heterogeneous_map and heterogeneous_inflow_config_by_wd can be\"\n                + \" defined.\"\n            )\n\n        # If heterogeneous_inflow_config_by_wd is not None, then create a HeterogeneousMap object\n        # using the dictionary\n        if heterogeneous_inflow_config_by_wd is not None:\n            # TODO: In future, add deprectation warning for this parameter here\n\n            self.heterogeneous_map = HeterogeneousMap(**heterogeneous_inflow_config_by_wd)\n\n        # Else if heterogeneous_map is not None\n        elif heterogeneous_map is not None:\n            # If heterogeneous_map is a dictionary, then create a HeterogeneousMap object\n            if isinstance(heterogeneous_map, dict):\n                self.heterogeneous_map = HeterogeneousMap(**heterogeneous_map)\n\n            # Else if heterogeneous_map is a HeterogeneousMap object, then save it\n            elif isinstance(heterogeneous_map, HeterogeneousMap):\n                self.heterogeneous_map = heterogeneous_map\n\n            # Else raise an error\n            else:\n                raise ValueError(\n                    \"heterogeneous_map must be a HeterogeneousMap object or a dictionary.\"\n                )\n\n        # Else if neither heterogeneous_map nor heterogeneous_inflow_config_by_wd are defined,\n        # then set heterogeneous_map to None\n        else:\n            self.heterogeneous_map = None\n\n        # Handle the multidim_conditions\n        if multidim_conditions is not None:\n            # Check that each value in the dictionary is either scalar or a correctly-sized array\n            if is_all_scalar_dict(multidim_conditions):\n                # Leave all scalar for performance purposes\n                pass\n            else:\n                for key, value in multidim_conditions.items():\n                    if isinstance(value, np.ndarray):\n                        if value.shape != (_n_wd, _n_ws, _n_ti):\n                            raise ValueError(\n                                f\"multidim_conditions[{key}] must be of size len(wind_directions) \"\n                                \"x len(wind_speeds) x len(turbulence_intensities) \"\n                                f\"[({_n_wd}, {_n_ws}, {_n_ti})] but currently has shape \"\n                                f\"{value.shape}.\"\n                            )\n                    else:\n                        raise ValueError(\n                            f\"multidim_conditions[{key}] must be a 2D NumPy array of size \"\n                            \"len(wind_directions) x len(wind_speeds) x len(turbulence_intensities)\"\n                            \" or a scalar value.\"\n                        )\n        self.multidim_conditions = multidim_conditions\n\n        # Build the gridded and flatten versions\n        self._build_gridded_and_flattened_version()\n\n    def _build_gridded_and_flattened_version(self):\n        \"\"\"\n        Given the wind direction, wind speed, and turbulence intensity array,\n        build the gridded versions covering all combinations, and then flatten\n        versions which put all combinations into 1D array\n        \"\"\"\n        # Gridded wind speed and direction\n        self.wd_grid, self.ws_grid, self.ti_grid = np.meshgrid(\n            self.wind_directions, self.wind_speeds, self.turbulence_intensities, indexing=\"ij\"\n        )\n\n        # Flat wind direction, wind speed, and turbulence intensity\n        self.wd_flat = self.wd_grid.flatten()\n        self.ws_flat = self.ws_grid.flatten()\n        self.ti_flat = self.ti_grid.flatten()\n\n        # Flat frequency table\n        self.freq_table_flat = self.freq_table.flatten()\n\n        # value table\n        if self.value_table is not None:\n            self.value_table_flat = self.value_table.flatten()\n        else:\n            self.value_table_flat = None\n\n        # Flatten multidim_conditions if defined\n        if self.multidim_conditions is not None:\n            if is_all_scalar_dict(self.multidim_conditions):\n                # Leave all scalar for performance purposes\n                self.multidim_conditions_flat = self.multidim_conditions\n            else:\n                self.multidim_conditions_flat = {\n                    k: v.flatten() for k, v in self.multidim_conditions.items()\n                }\n        else:\n            self.multidim_conditions_flat = None\n\n        # Set mask to non-zero frequency cases depending on compute_zero_freq_occurrence\n        if self.compute_zero_freq_occurrence:\n            # If computing zero freq occurrences, then this is all True\n            self.non_zero_freq_mask = [True for i in range(len(self.freq_table_flat))]\n        else:\n            self.non_zero_freq_mask = self.freq_table_flat > 0.0\n\n        # N_findex should only be the calculated cases\n        self.n_findex = np.sum(self.non_zero_freq_mask)\n\n    def unpack(self):\n        \"\"\"\n        Unpack the flattened versions of the matrices and return the values\n        accounting for the non_zero_freq_mask\n        \"\"\"\n\n        # The unpacked versions start as the flat version of each\n        wind_directions_unpack = self.wd_flat.copy()\n        wind_speeds_unpack = self.ws_flat.copy()\n        turbulence_intensities_unpack = self.ti_flat.copy()\n        freq_table_unpack = self.freq_table_flat.copy()\n\n        # Now mask thes values according to self.non_zero_freq_mask\n        wind_directions_unpack = wind_directions_unpack[self.non_zero_freq_mask]\n        wind_speeds_unpack = wind_speeds_unpack[self.non_zero_freq_mask]\n        turbulence_intensities_unpack = turbulence_intensities_unpack[self.non_zero_freq_mask]\n        freq_table_unpack = freq_table_unpack[self.non_zero_freq_mask]\n\n        # Now get unpacked value table\n        if self.value_table_flat is not None:\n            value_table_unpack = self.value_table_flat[self.non_zero_freq_mask].copy()\n        else:\n            value_table_unpack = None\n\n        # If heterogeneous_map is not None, then get the heterogeneous_inflow_config\n        if self.heterogeneous_map is not None:\n            heterogeneous_inflow_config = self.heterogeneous_map.get_heterogeneous_inflow_config(\n                wind_directions=wind_directions_unpack, wind_speeds=wind_speeds_unpack\n            )\n        else:\n            heterogeneous_inflow_config = None\n\n        return (\n            wind_directions_unpack,\n            wind_speeds_unpack,\n            turbulence_intensities_unpack,\n            freq_table_unpack,\n            value_table_unpack,\n            heterogeneous_inflow_config,\n        )\n\n    def unpack_multidim_conditions(self):\n        if self.multidim_conditions_flat is None:\n            return None\n        elif is_all_scalar_dict(self.multidim_conditions_flat):\n            return self.multidim_conditions_flat\n        else:\n            return {\n                k: v[self.non_zero_freq_mask] for k, v in self.multidim_conditions_flat.items()\n            }\n\n    def aggregate(self, wd_step=None, ws_step=None, ti_step=None, inplace=False):\n        \"\"\"\n        Wrapper for downsample method for backwards compatibility\n        \"\"\"\n\n        return self.downsample(wd_step, ws_step, ti_step, inplace)\n\n    def downsample(self, wd_step=None, ws_step=None, ti_step=None, inplace=False):\n        \"\"\"\n        Aggregates the wind TI rose into fewer wind direction, wind speed and TI bins.\n        It is necessary the wd_step and ws_step ti_step passed in are at least as\n        large as the current wind direction and wind speed steps.  If they are\n        not, the function will raise an error.\n\n        The function will return a new WindTIRose object with the aggregated\n        wind direction, wind speed and TI bins.  If inplace is set to True, the\n        current WindTIRose object will be updated with the aggregated bins.\n\n        Args:\n            wd_step: Step size for wind direction resampling (float, optional).\n            ws_step: Step size for wind speed resampling (float, optional).\n            ti_step: Step size for turbulence intensity resampling (float, optional).\n            inplace: Flag indicating whether to update the current WindTIRose.\n                Defaults to False.\n\n        Returns:\n            WindTIRose: Aggregated wind TI rose based on the provided or default step sizes.\n\n        Notes:\n            - Returns an aggregated version of the wind TI rose using new `ws_step`,\n                `wd_step`, and `ti_step`.\n            - Uses the bin weights feature in TimeSeries to aggregate the wind rose.\n            - If `ws_step`, `wd_step`, or `ti_step` are not specified, it uses\n                the current values.\n        \"\"\"\n\n        # If ws_step is passed in, confirm is it at least as large as the current step\n        if ws_step is not None:\n            if len(self.wind_speeds) >= 2:\n                current_ws_step = self.wind_speeds[1] - self.wind_speeds[0]\n                if ws_step < current_ws_step:\n                    raise ValueError(\n                        \"ws_step provided must be at least as large as the current ws_step \"\n                        f\"({current_ws_step} m/s)\"\n                    )\n\n        # If wd_step is passed in, confirm is it at least as large as the current step\n        if wd_step is not None:\n            if len(self.wind_directions) >= 2:\n                current_wd_step = check_and_identify_step_size(wind_directions=self.wind_directions)\n                if wd_step < current_wd_step:\n                    raise ValueError(\n                        \"wd_step provided must be at least as large as the current wd_step \"\n                        f\"({current_wd_step} degrees)\"\n                    )\n\n        # If ti_step is passed in, confirm is it at least as large as the current step\n        if ti_step is not None:\n            if len(self.turbulence_intensities) >= 2:\n                current_ti_step = self.turbulence_intensities[1] - self.turbulence_intensities[0]\n                if ti_step < current_ti_step:\n                    raise ValueError(\n                        \"ti_step provided must be at least as large as the current ti_step \"\n                        f\"({current_ti_step})\"\n                    )\n\n        # If ws_step, wd_step or ti_step is none, set it to the current step\n        if ws_step is None:\n            if len(self.wind_speeds) >= 2:\n                ws_step = self.wind_speeds[1] - self.wind_speeds[0]\n            else:  # wind rose will have only a single wind speed, and we assume a ws_step of 1\n                ws_step = 1.0\n        if wd_step is None:\n            if len(self.wind_directions) >= 2:\n                wd_step = check_and_identify_step_size(wind_directions=self.wind_directions)\n            else:  # wind rose will have only a single wind direction, and we assume a wd_step of 1\n                wd_step = 1.0\n        if ti_step is None:\n            if len(self.turbulence_intensities) >= 2:\n                ti_step = self.turbulence_intensities[1] - self.turbulence_intensities[0]\n            else:  # wind rose will have only a single TI, and we assume a ti_step of 1\n                ti_step = 1.0\n\n        # Pass the flat versions of each quantity to build a TimeSeries model\n        time_series = TimeSeries(\n            self.wd_flat,\n            self.ws_flat,\n            self.ti_flat,\n            self.value_table_flat,\n            self.heterogeneous_map,\n        )\n\n        # Now build a new wind rose using the new steps\n        aggregated_wind_rose = time_series.to_WindTIRose(\n            wd_step=wd_step, ws_step=ws_step, ti_step=ti_step, bin_weights=self.freq_table_flat\n        )\n\n        if inplace:\n            self.__init__(\n                aggregated_wind_rose.wind_directions,\n                aggregated_wind_rose.wind_speeds,\n                aggregated_wind_rose.turbulence_intensities,\n                aggregated_wind_rose.freq_table,\n                aggregated_wind_rose.value_table,\n                aggregated_wind_rose.compute_zero_freq_occurrence,\n                aggregated_wind_rose.heterogeneous_map,\n            )\n        else:\n            return aggregated_wind_rose\n\n    def resample_by_interpolation(self, wd_step=None, ws_step=None, method=\"linear\", inplace=False):\n        \"\"\"\n        Wrapper to upsample method for backwards compatibility\n        \"\"\"\n\n        return self.upsample(wd_step, ws_step, method, inplace)\n\n    def upsample(self, wd_step=None, ws_step=None, ti_step=None, method=\"linear\", inplace=False):\n        \"\"\"\n\n        Resample the wind TI rose using interpolation.  The method can be either\n        'linear' or 'nearest'.  If inplace is set to True, the current WindTIRose\n        object will be updated with the resampled bins.\n\n        Args:\n            wd_step: Step size for wind direction resampling (float, optional).\n                If None, the current step size will be used. Defaults to None.\n            ws_step: Step size for wind speed resampling (float, optional).\n                If None, the current step size will be used. Defaults to None.\n            ti_step: Step size for turbulence intensity resampling (float, optional).\n                If None, the current step size will be used. Defaults to None.\n            method: Interpolation method to use (str, optional).  Can be either\n                'linear' or 'nearest'. Defaults to \"linear\".\n            inplace: Flag indicating whether to update the current WindRose\n                object when True or return a new WindRose object when False\n                (bool, optional). Defaults to False.\n\n        Returns:\n            WindRose: Resampled wind rose based on the provided or default step\n                sizes. Only returned if inplace = False.\n\n        \"\"\"\n        if method == \"linear\":\n            interpolator = LinearNDInterpolator\n        elif method == \"nearest\":\n            interpolator = NearestNDInterpolator\n        else:\n            raise ValueError(\n                f\"Unknown interpolation method: '{method}'. \"\n                \"Available methods are 'linear' and 'nearest'\"\n            )\n\n        # First establish the current ws_step and wd_step and ti_step\n        if len(self.wind_speeds) >= 2:\n            ws_step_current = self.wind_speeds[1] - self.wind_speeds[0]\n        else:  # wind rose will have only a single wind speed, and we assume a ws_step of 1\n            ws_step_current = 1.0\n\n        if len(self.wind_directions) >= 2:\n            wd_step_current = check_and_identify_step_size(wind_directions=self.wind_directions)\n        else:  # wind rose will have only a single wind direction, and we assume a wd_step of 1\n            wd_step_current = 1.0\n\n        if len(self.turbulence_intensities) >= 2:\n            ti_step_current = self.turbulence_intensities[1] - self.turbulence_intensities[0]\n        else:  # wind rose will have only a single turbulence intensity,\n            # and we assume a ti_step of 1\n            ti_step_current = 1.0\n\n        # If either ws_step or wd_step or ti_step is None, set it to the current step\n        if ws_step is None:\n            ws_step = ws_step_current\n        if wd_step is None:\n            wd_step = wd_step_current\n        if ti_step is None:\n            ti_step = ti_step_current\n\n        # Make sure upsampling is appropriate\n        if wd_step > wd_step_current:\n            raise ValueError(\n                f\"Provided wd_step ({wd_step}) is larger than the current \"\n                f\" wind direction step size.  ({wd_step_current} degrees)\"\n                \" Use the downsample method.\"\n            )\n\n        if ws_step > ws_step_current:\n            raise ValueError(\n                f\"Provided ws_step ({ws_step}) is larger than \"\n                f\"the current wind speed step size.  ({ws_step_current} m/s)\"\n                \" Use the downsample method.\"\n            )\n\n        if ti_step > ti_step_current:\n            raise ValueError(\n                f\"Provided ti_step ({ti_step}) is larger than \"\n                f\"the current turbulence intensity step size.  ({ti_step_current})\"\n                \" Use the downsample method.\"\n            )\n\n        # Get the current wind directions in adjacent from (ie 0, 2 358 -> -2, 0 ,2)\n        if len(self.wind_directions) >= 2:\n            current_wind_directions, adjacent_sort_index = make_wind_directions_adjacent(\n                self.wind_directions\n            )\n        else:\n            current_wind_directions = self.wind_directions\n            adjacent_sort_index = np.arange(len(current_wind_directions))\n\n        # Identify the covered range of wind directions\n        wd_range_min_current = np.min(current_wind_directions) - wd_step_current / 2.0\n        wd_range_max_current = np.max(current_wind_directions) + wd_step_current / 2.0\n\n        # Look for unlikely case where for example wind directions are 8, 28, ... 358\n        if wd_range_max_current > 360:\n            # TODO: Handle this case without an error\n            raise ValueError(\n                \"Cannot upsample wind rose for case when wind directions are defined\"\n                \" such that 0 degrees is included by bins to the left of 0 degrees. \"\n            )\n\n        # Identify the new minimum wind direction\n        wd_min_new = wd_range_min_current + wd_step / 2.0\n        wd_max_new = wd_range_max_current - wd_step / 2.0\n\n        new_wind_directions = np.arange(wd_min_new, wd_max_new + wd_step / 2.0, wd_step)\n\n        # Set up the new wind speeds\n        ws_range_min_current = np.min(self.wind_speeds) - ws_step_current / 2.0\n        ws_range_max_current = np.max(self.wind_speeds) + ws_step_current / 2.0\n        ws_min_new = ws_range_min_current + ws_step / 2.0\n        ws_max_new = ws_range_max_current - ws_step / 2.0\n\n        # Force the new ws_min to 0 if negative\n        if ws_min_new < 0:\n            ws_min_new = 0.0\n\n        new_wind_speeds = np.arange(ws_min_new, ws_max_new + ws_step / 2.0, ws_step)\n\n        # Set up the new turbulence intensities\n        ti_range_min_current = np.min(self.turbulence_intensities) - ti_step_current / 2.0\n        ti_range_max_current = np.max(self.turbulence_intensities) + ti_step_current / 2.0\n        ti_min_new = ti_range_min_current + ti_step / 2.0\n        ti_max_new = ti_range_max_current - ti_step / 2.0\n\n        # Force the new ti_min to 0 if negative\n        if ti_min_new < 0:\n            ti_min_new = 0.0\n\n        new_turbulence_intensities = np.arange(ti_min_new, ti_max_new + ti_step / 2.0, ti_step)\n\n        # Set up for interpolation by copying the current values\n        # and making sure they are sorted according to the adjacent wind directions\n        wind_direction_column = current_wind_directions.copy()\n        wind_speed_column = self.wind_speeds.copy()\n        turbulence_intensity_column = self.turbulence_intensities.copy()\n        freq_matrix = self.freq_table.copy()[adjacent_sort_index, :, :]\n        if self.value_table is not None:\n            value_matrix = self.value_table.copy()[adjacent_sort_index, :, :]\n        else:\n            value_matrix = None\n\n        # For padding wind directions, there are two cases to consider.  In the first,\n        # say that the wind directions are 30, 40, 50.  In this case it's important append\n        # 30 and 50 to 35 and 55 to ensure the interpolation covers the full range of data\n        # This is the case when wind directions doesn't cover the full range of possible\n        # degrees (0-360)\n        if np.abs((wd_range_min_current % 360.0) - (wd_range_max_current % 360.0)) > 1e-6:\n            wind_direction_column = np.concatenate(\n                (\n                    np.array([wd_range_min_current]),\n                    wind_direction_column,\n                    np.array([wd_range_max_current])\n                )\n            )\n            freq_matrix = np.concatenate(\n                (freq_matrix[0:1, :, :], freq_matrix, freq_matrix[-1:, :, :]),\n                axis=0\n            )\n            if self.value_table is not None:\n                value_matrix = np.concatenate(\n                    (value_matrix[0:1, :, :], value_matrix, value_matrix[-1:, :, :]),\n                    axis=0\n                )\n\n        # In the alternative case, where the wind directions cover the full range\n        # ie, 0, 10, 20 30, ...350, then need to place 0 at 360 and 350 at -10\n        # to cover all interpolations\n        else:\n            # Pad wind direction column with min_wd + 360\n            wind_direction_column = np.concatenate(\n                (\n                    [np.max(self.wind_directions) - 360.0],\n                    wind_direction_column,\n                    [np.min(self.wind_directions) + 360.0],\n                )\n            )\n\n            # Pad the remaining with the appropriate value\n            freq_matrix = np.vstack(\n                (freq_matrix[-1:, :, :], freq_matrix, freq_matrix[0:1, :, :])\n            )\n            if self.value_table is not None:\n                value_matrix = np.vstack(\n                    (value_matrix[-1:, :, :], value_matrix, value_matrix[0:1, :, :])\n                )\n\n        # Pad out the wind speeds\n        wind_speed_column = np.concatenate(\n            (\n                np.array([ws_range_min_current]),\n                wind_speed_column,\n                np.array([ws_range_max_current])\n            )\n        )\n        freq_matrix = np.concatenate(\n            (freq_matrix[:, 0, :][:, None, :], freq_matrix, freq_matrix[:, -1, :][:, None, :]),\n            axis=1\n        )\n        if self.value_table is not None:\n            value_matrix = np.concatenate(\n                (value_matrix[:, 0:1, :], value_matrix, value_matrix[:, -1:, :]),\n                axis=1\n            )\n\n        # Pad out the turbulence intensities\n        turbulence_intensity_column = np.concatenate(\n            (\n                np.array([ti_range_min_current]),\n                turbulence_intensity_column,\n                np.array([ti_range_max_current])\n            )\n        )\n        freq_matrix = np.concatenate(\n            (freq_matrix[:, :, 0:1], freq_matrix, freq_matrix[:, :, -1:]),\n            axis=2\n        )\n        if self.value_table is not None:\n            value_matrix = np.concatenate(\n                (value_matrix[:, :, 0:1], value_matrix, value_matrix[:, :, -1:]),\n                axis=2\n            )\n\n        # Grid wind directions, wind speeds and turbulence intensities to match the\n        # freq_matrix when flattened\n        wd_grid, ws_grid, ti_grid = np.meshgrid(\n            wind_direction_column, wind_speed_column, turbulence_intensity_column, indexing=\"ij\"\n        )\n\n        # Form wd_grid and ws_grid to a 2-column matrix\n        wd_ws_ti_mat = np.array([wd_grid.flatten(), ws_grid.flatten(), ti_grid.flatten()]).T\n\n        # Build the interpolator from wd_grid, ws_grid, to ti_matrix, freq_matrix and value_matrix\n        freq_interpolator = interpolator(wd_ws_ti_mat, freq_matrix.flatten())\n        if self.value_table is not None:\n            value_interpolator = interpolator(wd_ws_ti_mat, value_matrix.flatten())\n\n        # Grid the new wind directions and wind speeds\n        new_wd_grid, new_ws_grid, new_ti_grid = np.meshgrid(\n            new_wind_directions, new_wind_speeds, new_turbulence_intensities, indexing=\"ij\"\n        )\n        new_wd_ws_ti_mat = np.array(\n            [new_wd_grid.flatten(), new_ws_grid.flatten(), new_ti_grid.flatten()]\n        ).T\n\n        # Create the new freq_matrix and value_matrix\n        new_freq_matrix = freq_interpolator(new_wd_ws_ti_mat).reshape(\n            (len(new_wind_directions), len(new_wind_speeds), len(new_turbulence_intensities))\n        )\n\n        if self.value_table is not None:\n            new_value_matrix = value_interpolator(new_wd_ws_ti_mat).reshape(\n                (len(new_wind_directions), len(new_wind_speeds), len(new_turbulence_intensities))\n            )\n        else:\n            new_value_matrix = None\n\n        # Wrap new_wind_directions to 0-360\n        new_wind_directions = new_wind_directions % 360\n\n        # Finally sort new_wind_directions, and re-order new_ti_matrix, new_freq_matrix\n        # and new_value_matrix accordingly\n        sort_indices = np.argsort(new_wind_directions)\n        new_wind_directions = new_wind_directions[sort_indices]\n        new_freq_matrix = new_freq_matrix[sort_indices, :, :]\n        if self.value_table is not None:\n            new_value_matrix = new_value_matrix[sort_indices, :, :]\n\n        # Create the resampled wind rose\n        resampled_wind_rose = WindTIRose(\n            new_wind_directions,\n            new_wind_speeds,\n            new_turbulence_intensities,\n            new_freq_matrix,\n            new_value_matrix,\n            self.compute_zero_freq_occurrence,\n            self.heterogeneous_map,\n        )\n\n        if inplace:\n            self.__init__(\n                resampled_wind_rose.wind_directions,\n                resampled_wind_rose.wind_speeds,\n                resampled_wind_rose.turbulence_intensities,\n                resampled_wind_rose.freq_table,\n                resampled_wind_rose.value_table,\n                resampled_wind_rose.compute_zero_freq_occurrence,\n                resampled_wind_rose.heterogeneous_map,\n            )\n        else:\n            return resampled_wind_rose\n\n    def plot(\n        self,\n        ax=None,\n        wind_rose_var=\"ws\",\n        color_map=\"viridis_r\",\n        wd_step=15.0,\n        wind_rose_var_step=None,\n        legend_kwargs={\"label\": \"Wind speed [m/s]\"},\n    ):\n        \"\"\"\n        This method creates a wind rose plot showing the frequency of occurrence\n        of either the specified wind direction and wind speed bins or wind\n        direction and turbulence intensity bins. If no axis is provided, a new\n        one is created.\n\n        **Note**: Based on code provided by Patrick Murphy from the University\n        of Colorado Boulder.\n\n        Args:\n            ax (:py:class:`matplotlib.pyplot.axes`, optional): The figure axes\n                on which the wind rose is plotted. Defaults to None.\n            wind_rose_var (str, optional): The variable to display in the wind\n                rose plot in addition to wind direction. If\n                wind_rose_var = \"ws\", wind speed frequencies will be plotted.\n                If wind_rose_var = \"ti\", turbulence intensity frequencies will\n                be plotted. Defaults to \"ws\".\n            color_map (str, optional): Colormap to use. Defaults to 'viridis_r'.\n            wd_step (float, optional): Step size for wind direction. Defaults\n                to 15 degrees.\n            wind_rose_var_step (float, optional): Step size for other wind rose\n                variable. Defaults to None. If unspecified, a value of 5 m/s\n                will be used if wind_rose_var = \"ws\", and a value of 4% will be\n                used if wind_rose_var = \"ti\".\n            legend_kwargs (dict, optional): Keyword arguments to be passed to\n                ax.legend(). Defaults to {\"label\": \"Wind speed [m/s]\"}.\n\n        Returns:\n            :py:class:`matplotlib.pyplot.axes`: A figure axes object containing\n            the plotted wind rose.\n        \"\"\"\n\n        if wind_rose_var not in {\"ws\", \"ti\"}:\n            raise ValueError(\n                'wind_rose_var must be either \"ws\" or \"ti\" for wind speed or turbulence intensity.'\n            )\n\n        # Get a aggregated wind_rose\n        if wind_rose_var == \"ws\":\n            if wind_rose_var_step is None:\n                wind_rose_var_step = 5.0\n            wind_rose_aggregated = self.downsample(wd_step, ws_step=wind_rose_var_step)\n            var_bins = wind_rose_aggregated.wind_speeds\n            freq_table = wind_rose_aggregated.freq_table.sum(2)  # sum along TI dimension\n        else:  # wind_rose_var == \"ti\"\n            if wind_rose_var_step is None:\n                wind_rose_var_step = 0.04\n            wind_rose_aggregated = self.downsample(wd_step, ti_step=wind_rose_var_step)\n            var_bins = wind_rose_aggregated.turbulence_intensities\n            freq_table = wind_rose_aggregated.freq_table.sum(1)  # sum along wind speed dimension\n\n        wd_bins = wind_rose_aggregated.wind_directions\n\n        # Set up figure\n        if ax is None:\n            _, ax = plt.subplots(subplot_kw={\"polar\": True})\n\n        # Get a color array\n        color_array = plt.get_cmap(color_map, len(var_bins))\n        norm_wv = mpl.colors.Normalize(vmin=np.min(var_bins), vmax=np.max(var_bins))\n        sm_wv = mpl.cm.ScalarMappable(norm=norm_wv, cmap=color_array)\n\n        for wd_idx, wd in enumerate(wd_bins):\n            rects = []\n            freq_table_sub = freq_table[wd_idx, :].flatten()\n            for var_idx, ws in reversed(list(enumerate(var_bins))):\n                plot_val = freq_table_sub[: var_idx + 1].sum()\n                rects.append(\n                    ax.bar(\n                        np.radians(wd),\n                        plot_val,\n                        width=0.9 * np.radians(wd_step),\n                        color=color_array(var_idx),\n                        edgecolor=\"k\",\n                    )\n                )\n\n        # Configure the plot\n        try:\n            ax.figure.colorbar(sm_wv, ax=ax, **legend_kwargs)\n            ax.figure.tight_layout()\n        except TypeError:\n            ax.legend(reversed(rects), var_bins, **legend_kwargs)\n            ax.figure.get_children()[-1].remove() # Remove the empty colorbar\n        ax.set_theta_direction(-1)\n        ax.set_theta_offset(np.pi / 2.0)\n        ax.set_theta_zero_location(\"N\")\n        ax.set_xticks(np.arange(0, 2 * np.pi, np.pi / 4))\n        ax.set_xticklabels([\"N\", \"NE\", \"E\", \"SE\", \"S\", \"SW\", \"W\", \"NW\"])\n\n        return ax\n\n    def plot_ti_over_ws(\n        self,\n        ax=None,\n        marker=\".\",\n        ls=\"-\",\n        color=\"k\",\n    ):\n        \"\"\"\n        Plot the mean turbulence intensity against wind speed.\n\n        Args:\n            ax (:py:class:`matplotlib.pyplot.axes`, optional): The figure axes\n                on which the mean turbulence intensity is plotted. Defaults to None.\n            marker (str, optional): Scatter plot marker style. Defaults to \".\".\n            ls (str, optional): Scatter plot line style. Defaults to \"None\".\n            color (str, optional): Scatter plot color. Defaults to \"k\".\n\n        Returns:\n            :py:class:`matplotlib.pyplot.axes`: A figure axes object containing\n            the plotted mean turbulence intensities as a function of wind speed.\n        \"\"\"\n\n        # TODO: Plot individual points and std. devs. of TI in addition to mean\n        # values\n\n        # Set up figure\n        if ax is None:\n            _, ax = plt.subplots()\n\n        # get mean TI for each wind speed by averaging along wind direction and\n        # TI dimensions\n        mean_ti_values = (self.ti_grid * self.freq_table).sum((0, 2)) / self.freq_table.sum((0, 2))\n\n        ax.plot(self.wind_speeds, mean_ti_values * 100, marker=marker, ls=ls, color=color)\n        ax.set_xlabel(\"Wind Speed (m/s)\")\n        ax.set_ylabel(\"Mean Turbulence Intensity (%)\")\n        ax.grid(True)\n\n    def assign_value_using_wd_ws_ti_function(self, func, normalize=False):\n        \"\"\"\n        Use the passed in function to assign new values to the value table.\n\n        Args:\n            func (function): Function which accepts wind_directions as its\n                first argument, wind_speeds as its second argument, and\n                turbulence_intensities as its third argument and returns\n                values.\n            normalize (bool, optional): If True, the value array will be\n                normalized by the mean value. Defaults to False.\n\n        \"\"\"\n        self.value_table = func(self.wd_grid, self.ws_grid, self.ti_grid)\n\n        if normalize:\n            self.value_table /= np.sum(self.freq_table * self.value_table)\n\n        self._build_gridded_and_flattened_version()\n\n    def assign_value_piecewise_linear(\n        self,\n        value_zero_ws=1.425,\n        ws_knee=4.5,\n        slope_1=0.0,\n        slope_2=-0.135,\n        limit_to_zero=False,\n        normalize=False,\n    ):\n        \"\"\"\n        Define value as a continuous piecewise linear function of wind speed\n        with two line segments. The default parameters yield a value function\n        that approximates the normalized mean electricity price vs. wind speed\n        curve for the SPP market in the U.S. for years 2018-2020 from figure 7\n        in Simley et al. \"The value of wake steering wind farm flow control in\n        US energy markets,\" Wind Energy Science, 2024.\n        https://doi.org/10.5194/wes-9-219-2024. This default value function is\n        constant at low wind speeds, then linearly decreases above 4.5 m/s.\n\n        Args:\n            value_zero_ws (float, optional): The value when wind speed is zero.\n                Defaults to 1.425.\n            ws_knee (float, optional): The wind speed separating line segments\n                1 and 2. Default = 4.5 m/s.\n            slope_1 (float, optional): The slope of the first line segment\n                (unit of value per m/s). Defaults to zero.\n            slope_2 (float, optional): The slope of the second line segment\n            (unit of value per m/s). Defaults to -0.135.\n            limit_to_zero (bool, optional): If True, negative values will be\n                set to zero. Defaults to False.\n            normalize (bool, optional): If True, the value array will be\n                normalized by the mean value. Defaults to False.\n        \"\"\"\n\n        def piecewise_linear_value_func(wind_directions, wind_speeds, turbulence_intensities):\n            value = np.zeros_like(wind_speeds, dtype=float)\n            value[wind_speeds < ws_knee] = (\n                slope_1 * wind_speeds[wind_speeds < ws_knee] + value_zero_ws\n            )\n\n            offset_2 = (slope_1 - slope_2) * ws_knee + value_zero_ws\n\n            value[wind_speeds >= ws_knee] = slope_2 * wind_speeds[wind_speeds >= ws_knee] + offset_2\n\n            if limit_to_zero:\n                value[value < 0] = 0.0\n\n            return value\n\n        self.assign_value_using_wd_ws_ti_function(piecewise_linear_value_func, normalize)\n\n    def plot_value_over_ws(\n        self,\n        ax=None,\n        marker=\".\",\n        ls=\"None\",\n        color=\"k\",\n    ):\n        \"\"\"\n        Scatter plot the value of the energy generated against wind speed.\n\n        Args:\n            ax (:py:class:`matplotlib.pyplot.axes`, optional): The figure axes\n                on which the value is plotted. Defaults to None.\n            marker (str, optional): Scatter plot marker style. Defaults to \".\".\n            ls (str, optional): Scatter plot line style. Defaults to \"None\".\n            color (str, optional): Scatter plot color. Defaults to \"k\".\n\n        Returns:\n            :py:class:`matplotlib.pyplot.axes`: A figure axes object containing\n            the plotted value as a function of wind speed.\n        \"\"\"\n\n        # TODO: Plot mean and std. devs. of value in each ws bin in addition to\n        # individual points\n\n        # Set up figure\n        if ax is None:\n            _, ax = plt.subplots()\n\n        ax.plot(self.ws_flat, self.value_table_flat, marker=marker, ls=ls, color=color)\n        ax.set_xlabel(\"Wind Speed (m/s)\")\n        ax.set_ylabel(\"Value\")\n        ax.grid(True)\n\n    @staticmethod\n    def read_csv_long(\n        file_path: str,\n        ws_col: str = \"wind_speeds\",\n        wd_col: str = \"wind_directions\",\n        ti_col: str = \"turbulence_intensities\",\n        freq_col: str | None = None,\n        sep: str = \",\",\n    ) -> WindTIRose:\n        \"\"\"\n        Read a long-formatted CSV file into the WindTIRose object. By long, what is meant\n        is that the wind speed, wind direction  and turbulence intensities\n        combination is given for each row in the\n        CSV file. The wind speed, wind direction, and turbulence intensity are\n        given in separate columns, and the frequency of occurrence of each combination\n        is given in a separate column. The frequency column is optional, and if not\n        provided, uniform frequency of all bins is assumed.\n\n        Args:\n            file_path (str): Path to the CSV file.\n            ws_col (str): Name of the column in the CSV file that contains the wind speed\n                values. Defaults to 'wind_speeds'.\n            wd_col (str): Name of the column in the CSV file that contains the wind direction\n                values. Defaults to 'wind_directions'.\n            ti_col (str): Name of the column in the CSV file that contains\n                the turbulence intensity values.\n            freq_col (str): Name of the column in the CSV file that contains the frequency\n                values. Defaults to None in which case constant frequency assumed.\n            sep (str): Delimiter to use. Defaults to ','.\n\n        Returns:\n            WindRose: Wind rose object created from the CSV file.\n        \"\"\"\n\n        # Read in the CSV file\n        df = pd.read_csv(file_path, sep=sep)\n\n        # Check that the required columns are present\n        if ws_col not in df.columns:\n            raise ValueError(f\"Column {ws_col} not found in CSV file\")\n        if wd_col not in df.columns:\n            raise ValueError(f\"Column {wd_col} not found in CSV file\")\n        if ti_col not in df.columns:\n            raise ValueError(f\"Column {ti_col} not found in CSV file\")\n        if freq_col not in df.columns and freq_col is not None:\n            raise ValueError(f\"Column {freq_col} not found in CSV file\")\n\n        # Get the wind speed, wind direction, and turbulence intensity values\n        wind_directions = df[wd_col].values\n        wind_speeds = df[ws_col].values\n        turbulence_intensities = df[ti_col].values\n        if freq_col is not None:\n            freq_values = df[freq_col].values\n        else:\n            freq_values = np.ones(len(wind_speeds))\n\n        # Normalize freq_values\n        freq_values = freq_values / np.sum(freq_values)\n\n        # Get the unique values of wind directions and wind speeds\n        unique_wd = np.unique(wind_directions)\n        unique_ws = np.unique(wind_speeds)\n        unique_ti = np.unique(turbulence_intensities)\n\n        # Get the step side for wind direction and wind speed\n        wd_step = unique_wd[1] - unique_wd[0]\n        ws_step = unique_ws[1] - unique_ws[0]\n        ti_step = unique_ti[1] - unique_ti[0]\n\n        # Now use TimeSeries to create a wind rose\n        time_series = TimeSeries(wind_directions, wind_speeds, turbulence_intensities)\n\n        # Now build a new wind rose using the new steps\n        return time_series.to_WindTIRose(\n            wd_step=wd_step, ws_step=ws_step, ti_step=ti_step, bin_weights=freq_values\n        )\n\n\nclass TimeSeries(WindDataBase):\n    \"\"\"\n    The TimeSeries class is used to drive FLORIS and optimization operations in\n    which the inflow is by a sequence of wind direction, wind speed and\n    turbulence intensity values.  Each input of wind direction, wind speed, and\n    turbulence intensity can be assigned as an array of values or a single value.\n    At least one of wind_directions, wind_speeds, or turbulence_intensities must\n    be an array.  If arrays are provided, they must be the same length as the\n    other arrays or the single values.  If single values are provided, then an\n    array of the same length as the other arrays will be created with the single\n    value.\n\n    Args:\n        wind_directions (float, NDArrayFloat): Wind direction. Can be a single\n            value or an array of values.\n        wind_speeds (float, NDArrayFloat): Wind speed. Can be a single value or\n            an array of values.\n        turbulence_intensities (float, NDArrayFloat): Turbulence intensity. Can be\n            a single value or an array of values.\n        values (NDArrayFloat, optional): Values associated with each wind\n            direction, wind speed, and turbulence intensity. Defaults to None.\n        heterogeneous_map (HeterogeneousMap, optional): A HeterogeneousMap object to define\n            background heterogeneous inflow condition as a function\n            of wind direction and wind speed.  Alternatively, a dictionary can be\n            passed in to define a HeterogeneousMap object.  Defaults to None.\n        heterogeneous_inflow_config_by_wd (dict, optional): A dictionary containing the following\n            which can be used to define a heterogeneous_map object (note this parameter is kept\n            for backwards compatibility and is not recommended for use):\n            * 'x': A 1D NumPy array (size num_points) of x-coordinates (meters).\n            * 'y': A 1D NumPy array (size num_points) of y-coordinates (meters).\n            * 'speed_multipliers': A 2D NumPy array (size num_wd (or num_ws) x num_points)\n                of speed multipliers.  If neither wind_directions nor wind_speeds are\n                defined, then this should be a single row array\n            * 'wind_directions': A 1D NumPy array (size num_wd) of wind directions (degrees).\n                Optional.\n            * 'wind_speeds': A 1D NumPy array (size num_ws) of wind speeds (m/s). Optional.\n            Defaults to None.\n        heterogeneous_inflow_config (dict, optional): A dictionary containing the following keys.\n            Defaults to None.\n            * 'speed_multipliers': A 2D NumPy array (size n_findex x num_points)\n                    of speed multipliers.\n            * 'x': A 1D NumPy array (size num_points) of x-coordinates (meters).\n            * 'y': A 1D NumPy array (size num_points) of y-coordinates (meters).\n        multidim_conditions (dict, optional): A dictionary containing multidimensional inflow\n            conditions. Each key is the name of the condition, and each value is either a 1D NumPy\n            array of size n_findex containing the condition values, or a scalar value that will be\n            broadcast to size n_findex. Defaults to None.\n    \"\"\"\n\n    def __init__(\n        self,\n        wind_directions: float | NDArrayFloat,\n        wind_speeds: float | NDArrayFloat,\n        turbulence_intensities: float | NDArrayFloat,\n        values: NDArrayFloat | None = None,\n        heterogeneous_map: HeterogeneousMap | dict | None = None,\n        heterogeneous_inflow_config_by_wd: dict | None = None,\n        heterogeneous_inflow_config: dict | None = None,\n        multidim_conditions: dict | None = None,\n    ):\n        # Check that wind_directions, wind_speeds, and turbulence_intensities are either numpy array\n        # of floats\n        if not isinstance(wind_directions, (float, np.ndarray)):\n            raise TypeError(\"wind_directions must be a float or a NumPy array\")\n        if not isinstance(wind_speeds, (float, np.ndarray)):\n            raise TypeError(\"wind_speeds must be a float or a NumPy array\")\n        if not isinstance(turbulence_intensities, (float, np.ndarray)):\n            raise TypeError(\"turbulence_intensities must be a float or a NumPy array\")\n\n        # At least one of wind_directions, wind_speeds, or turbulence_intensities must be an array\n        if (\n            not isinstance(wind_directions, np.ndarray)\n            and not isinstance(wind_speeds, np.ndarray)\n            and not isinstance(turbulence_intensities, np.ndarray)\n        ):\n            raise TypeError(\n                \"At least one of wind_directions, wind_speeds, or \"\n                \" turbulence_intensities must be a NumPy array\"\n            )\n\n        # For each of wind_directions, wind_speeds, and turbulence_intensities provided as\n        # an array, confirm they are the same length\n        if isinstance(wind_directions, np.ndarray) and isinstance(wind_speeds, np.ndarray):\n            if len(wind_directions) != len(wind_speeds):\n                raise ValueError(\n                    \"wind_directions and wind_speeds must be the same length if provided as arrays\"\n                )\n\n        if isinstance(wind_directions, np.ndarray) and isinstance(\n            turbulence_intensities, np.ndarray\n        ):\n            if len(wind_directions) != len(turbulence_intensities):\n                raise ValueError(\n                    \"wind_directions and turbulence_intensities must be \"\n                    \"the same length if provided as arrays\"\n                )\n\n        if isinstance(wind_speeds, np.ndarray) and isinstance(turbulence_intensities, np.ndarray):\n            if len(wind_speeds) != len(turbulence_intensities):\n                raise ValueError(\n                    \"wind_speeds and turbulence_intensities must be the \"\n                    \"same length if provided as arrays\"\n                )\n\n        # For each of wind_directions, wind_speeds, and turbulence_intensities\n        # provided as a single value, set them\n        # to be the same length as those passed in as arrays\n        if isinstance(wind_directions, float):\n            if isinstance(wind_speeds, np.ndarray):\n                wind_directions = np.full(len(wind_speeds), wind_directions)\n            elif isinstance(turbulence_intensities, np.ndarray):\n                wind_directions = np.full(len(turbulence_intensities), wind_directions)\n\n        if isinstance(wind_speeds, float):\n            if isinstance(wind_directions, np.ndarray):\n                wind_speeds = np.full(len(wind_directions), wind_speeds)\n            elif isinstance(turbulence_intensities, np.ndarray):\n                wind_speeds = np.full(len(turbulence_intensities), wind_speeds)\n\n        if isinstance(turbulence_intensities, float):\n            if isinstance(wind_directions, np.ndarray):\n                turbulence_intensities = np.full(len(wind_directions), turbulence_intensities)\n            elif isinstance(wind_speeds, np.ndarray):\n                turbulence_intensities = np.full(len(wind_speeds), turbulence_intensities)\n\n        # Record findex\n        self.n_findex = len(wind_directions)\n\n        # If values is not None, must be same length as wind_directions/wind_speeds/\n        if values is not None:\n            if len(wind_directions) != len(values):\n                raise ValueError(\"wind_directions and values must be the same length\")\n\n        self.wind_directions = wind_directions\n        self.wind_speeds = wind_speeds\n        self.turbulence_intensities = turbulence_intensities\n        self.values = values\n\n        # Check that at most one of heterogeneous_inflow_config_by_wd,\n        # heterogeneous_map and heterogeneous_inflow_config is not None\n        if (\n            sum(\n                [\n                    heterogeneous_inflow_config_by_wd is not None,\n                    heterogeneous_map is not None,\n                    heterogeneous_inflow_config is not None,\n                ]\n            )\n            > 1\n        ):\n            raise ValueError(\n                \"Only one of heterogeneous_inflow_config_by_wd, \"\n                + \"heterogeneous_map, and heterogeneous_inflow_config can be not None.\"\n            )\n\n        # if heterogeneous_inflow_config is not None, then the speed_multipliers\n        # must be the same length as wind_directions\n        # in the 0th dimension\n        if heterogeneous_inflow_config is not None:\n            if len(heterogeneous_inflow_config[\"speed_multipliers\"]) != len(wind_directions):\n                raise ValueError(\"speed_multipliers must be the same length as wind_directions\")\n\n            # Check  heterogeneous_inflow_config and save\n            self.check_heterogeneous_inflow_config(heterogeneous_inflow_config)\n            self.heterogeneous_inflow_config = heterogeneous_inflow_config\n        else:\n            self.heterogeneous_inflow_config = None\n\n        # If heterogeneous_inflow_config_by_wd is not None, then create a HeterogeneousMap object\n        # using the dictionary\n        if heterogeneous_inflow_config_by_wd is not None:\n            # TODO: In future, add deprecation warning for this parameter here\n\n            self.heterogeneous_map = HeterogeneousMap(**heterogeneous_inflow_config_by_wd)\n\n        # Else if heterogeneous_map is not None\n        elif heterogeneous_map is not None:\n            # If heterogeneous_map is a dictionary, then create a HeterogeneousMap object\n            if isinstance(heterogeneous_map, dict):\n                self.heterogeneous_map = HeterogeneousMap(**heterogeneous_map)\n\n            # Else if heterogeneous_map is a HeterogeneousMap object, then save it\n            elif isinstance(heterogeneous_map, HeterogeneousMap):\n                self.heterogeneous_map = heterogeneous_map\n\n            # Else raise an error\n            else:\n                raise ValueError(\n                    \"heterogeneous_map must be a HeterogeneousMap object or a dictionary.\"\n                )\n\n        # Else if neither heterogeneous_map nor heterogeneous_inflow_config_by_wd are defined,\n        # then set heterogeneous_map to None\n        else:\n            self.heterogeneous_map = None\n\n        # Handle the multidim_conditions\n        if multidim_conditions is not None:\n            # Check that each value in the dictionary is either a 1D NumPy array of size n_findex\n            # or a scalar value\n            if is_all_scalar_dict(multidim_conditions):\n                # Leave all scalar for performance purposes\n                pass\n            else:\n                for key, value in multidim_conditions.items():\n                    if isinstance(value, np.ndarray):\n                        if value.shape != (self.n_findex,):\n                            raise ValueError(\n                                f\"multidim_conditions[{key}] must be of size n_findex\"\n                                f\"({self.n_findex})\"\n                            )\n                    else:\n                        raise ValueError(\n                            f\"multidim_conditions[{key}] must be a 1D NumPy array of size n_findex \"\n                            \"or a scalar value.\"\n                        )\n\n        self.multidim_conditions = multidim_conditions\n\n    def unpack(self):\n        \"\"\"\n        Unpack the time series data in a manner consistent with wind rose unpack\n        \"\"\"\n\n        # to match wind_rose, make a uniform frequency\n        uniform_frequency = np.ones_like(self.wind_directions)\n        uniform_frequency = uniform_frequency / uniform_frequency.sum()\n\n        # If heterogeneous_map is not None, then update\n        # heterogeneous_inflow_config to match wind_directions_unpack\n        if self.heterogeneous_map is not None:\n            heterogeneous_inflow_config = self.heterogeneous_map.get_heterogeneous_inflow_config(\n                wind_directions=self.wind_directions, wind_speeds=self.wind_speeds\n            )\n        else:\n            heterogeneous_inflow_config = self.heterogeneous_inflow_config\n\n        return (\n            self.wind_directions,\n            self.wind_speeds,\n            self.turbulence_intensities,\n            uniform_frequency,\n            self.values,\n            heterogeneous_inflow_config,\n        )\n\n    def _wrap_wind_directions_near_360(self, wind_directions, wd_step):\n        \"\"\"\n        Wraps the wind directions using `wd_step` to produce a wrapped version\n        where values between [360 - wd_step/2.0, 360] get mapped to negative numbers\n        for binning.\n\n        Args:\n            wind_directions (NDArrayFloat): NumPy array of wind directions.\n            wd_step (float): Step size for wind direction.\n\n        Returns:\n            NDArrayFloat: Wrapped version of wind directions.\n\n        \"\"\"\n        wind_directions_wrapped = wind_directions.copy()\n        mask = wind_directions_wrapped >= 360 - wd_step / 2.0\n        wind_directions_wrapped[mask] = wind_directions_wrapped[mask] - 360.0\n        return wind_directions_wrapped\n\n    def assign_ti_using_wd_ws_function(self, func):\n        \"\"\"\n        Use the passed in function to new assign values to turbulence_intensities\n\n        Args:\n            func (function): Function which accepts wind_directions as its\n                first argument and wind_speeds as second argument and returns\n                turbulence_intensities\n        \"\"\"\n        self.turbulence_intensities = func(self.wind_directions, self.wind_speeds)\n\n    def assign_ti_using_IEC_method(self, Iref=0.07, offset=3.8):\n        \"\"\"\n        Define TI as a function of wind speed by specifying an Iref and offset\n        value as in the normal turbulence model in the IEC 61400-1 standard\n\n        Args:\n            Iref (float): Reference turbulence level, defined as the expected\n                value of TI at 15 m/s. Default = 0.07. Note this value is\n                lower than the values of Iref for turbulence classes A, B, and\n                C in the IEC standard (0.16, 0.14, and 0.12, respectively), but\n                produces TI values more in line with those typically used in\n                FLORIS. When the default Iref and offset are used, the TI at\n                8 m/s is 8.6%.\n            offset (float): Offset value to equation. Default = 3.8, as defined\n                in the IEC standard to give the expected value of TI for\n                each wind speed.\n        \"\"\"\n        if (Iref < 0) or (Iref > 1):\n            raise ValueError(\"Iref must be >= 0 and <=1\")\n\n        def iref_func(wind_directions, wind_speeds):\n            sigma_1 = Iref * (0.75 * wind_speeds + offset)\n            return sigma_1 / wind_speeds\n\n        self.assign_ti_using_wd_ws_function(iref_func)\n\n    def assign_value_using_wd_ws_function(self, func, normalize=False):\n        \"\"\"\n        Use the passed in function to assign new values to the value table.\n\n        Args:\n            func (function): Function which accepts wind_directions as its\n                first argument and wind_speeds as second argument and returns\n                values.\n            normalize (bool, optional): If True, the value array will be\n                normalized by the mean value. Defaults to False.\n\n        \"\"\"\n        self.values = func(self.wind_directions, self.wind_speeds)\n\n        if normalize:\n            self.values /= np.mean(self.values)\n\n    def assign_value_piecewise_linear(\n        self,\n        value_zero_ws=1.425,\n        ws_knee=4.5,\n        slope_1=0.0,\n        slope_2=-0.135,\n        limit_to_zero=False,\n        normalize=False,\n    ):\n        \"\"\"\n        Define value as a continuous piecewise linear function of wind speed\n        with two line segments. The default parameters yield a value function\n        that approximates the normalized mean electricity price vs. wind speed\n        curve for the SPP market in the U.S. for years 2018-2020 from figure 7\n        in Simley et al. \"The value of wake steering wind farm flow control in\n        US energy markets,\" Wind Energy Science, 2024.\n        https://doi.org/10.5194/wes-9-219-2024. This default value function is\n        constant at low wind speeds, then linearly decreases above 4.5 m/s.\n\n        Args:\n            value_zero_ws (float, optional): The value when wind speed is zero.\n                Defaults to 1.425.\n            ws_knee (float, optional): The wind speed separating line segments\n                1 and 2. Default = 4.5 m/s.\n            slope_1 (float, optional): The slope of the first line segment\n                (unit of value per m/s). Defaults to zero.\n            slope_2 (float, optional): The slope of the second line segment\n            (unit of value per m/s). Defaults to -0.135.\n            limit_to_zero (bool, optional): If True, negative values will be\n                set to zero. Defaults to False.\n            normalize (bool, optional): If True, the value array will be\n                normalized by the mean value. Defaults to False.\n        \"\"\"\n\n        def piecewise_linear_value_func(wind_directions, wind_speeds):\n            value = np.zeros_like(wind_speeds, dtype=float)\n            value[wind_speeds < ws_knee] = (\n                slope_1 * wind_speeds[wind_speeds < ws_knee] + value_zero_ws\n            )\n\n            offset_2 = (slope_1 - slope_2) * ws_knee + value_zero_ws\n\n            value[wind_speeds >= ws_knee] = slope_2 * wind_speeds[wind_speeds >= ws_knee] + offset_2\n\n            if limit_to_zero:\n                value[value < 0] = 0.0\n\n            return value\n\n        self.assign_value_using_wd_ws_function(piecewise_linear_value_func, normalize)\n\n    def to_WindRose(self, wd_step=2.0, ws_step=1.0, wd_edges=None, ws_edges=None, bin_weights=None):\n        \"\"\"\n        Converts the TimeSeries data to a WindRose.\n\n        Args:\n            wd_step (float, optional): Step size for wind direction (default is 2.0).\n            ws_step (float, optional): Step size for wind speed (default is 1.0).\n            wd_edges (NDArrayFloat, optional): Custom wind direction edges. Defaults to None.\n            ws_edges (NDArrayFloat, optional): Custom wind speed edges. Defaults to None.\n            bin_weights (NDArrayFloat, optional): Bin weights for resampling.  Note these\n                are primarily used by the downsample() method.\n                Defaults to None.\n\n        Returns:\n            WindRose: A WindRose object based on the TimeSeries data.\n\n        Notes:\n            - If `wd_edges` is defined, it uses it to produce the bin centers.\n            - If `wd_edges` is not defined, it determines `wd_edges` from the step and data.\n            - If `ws_edges` is defined, it uses it for wind speed edges.\n            - If `ws_edges` is not defined, it determines `ws_edges` from the step and data.\n        \"\"\"\n\n        # If wd_edges is defined, then use it to produce the bin centers\n        if wd_edges is not None:\n            wd_step = wd_edges[1] - wd_edges[0]\n\n            # use wd_step to produce a wrapped version of wind_directions\n            wind_directions_wrapped = self._wrap_wind_directions_near_360(\n                self.wind_directions, wd_step\n            )\n\n        # Else, determine wd_edges from the step and data\n        else:\n            wd_edges = np.arange(0.0 - wd_step / 2.0, 360.0, wd_step)\n\n            # use wd_step to produce a wrapped version of wind_directions\n            wind_directions_wrapped = self._wrap_wind_directions_near_360(\n                self.wind_directions, wd_step\n            )\n\n            # Only keep the range with values in it\n            wd_edges = wd_edges[wd_edges + wd_step > wind_directions_wrapped.min()]\n            wd_edges = wd_edges[wd_edges - wd_step <= wind_directions_wrapped.max()]\n\n        # Define the centers from the edges\n        wd_centers = wd_edges[:-1] + wd_step / 2.0\n\n        # Repeat for wind speeds\n        if ws_edges is not None:\n            ws_step = ws_edges[1] - ws_edges[0]\n\n        else:\n            ws_edges = np.arange(0.0 - ws_step / 2.0, 50.0, ws_step)\n\n            # Only keep the range with values in it\n            ws_edges = ws_edges[ws_edges + ws_step > self.wind_speeds.min()]\n            ws_edges = ws_edges[ws_edges - ws_step <= self.wind_speeds.max()]\n\n        # Define the centers from the edges\n        ws_centers = ws_edges[:-1] + ws_step / 2.0\n\n        # Now use pandas to get the tables need for wind rose\n        df = pd.DataFrame(\n            {\n                \"wd\": wind_directions_wrapped,\n                \"ws\": self.wind_speeds,\n                \"freq_val\": np.ones(len(wind_directions_wrapped)),\n            }\n        )\n\n        # If bin_weights are passed in, apply these to the frequency\n        # this is mostly used when resampling the wind rose\n        if bin_weights is not None:\n            df = df.assign(freq_val=df[\"freq_val\"] * bin_weights)\n\n        # Add turbulence intensities to dataframe\n        df = df.assign(turbulence_intensities=self.turbulence_intensities)\n\n        # If values is not none, add to dataframe\n        if self.values is not None:\n            df = df.assign(values=self.values)\n\n        # Bin wind speed and wind direction and then group things up\n        df = (\n            df.assign(\n                wd_bin=pd.cut(\n                    df.wd, bins=wd_edges, labels=wd_centers, right=False, include_lowest=True\n                )\n            )\n            .assign(\n                ws_bin=pd.cut(\n                    df.ws, bins=ws_edges, labels=ws_centers, right=False, include_lowest=True\n                )\n            )\n            .drop([\"wd\", \"ws\"], axis=1)\n        )\n\n        # Convert wd_bin and ws_bin to categoricals to ensure all combinations\n        # are considered and then group\n        wd_cat = CategoricalDtype(categories=wd_centers, ordered=True)\n        ws_cat = CategoricalDtype(categories=ws_centers, ordered=True)\n\n        df = (\n            df.assign(wd_bin=df[\"wd_bin\"].astype(wd_cat))\n            .assign(ws_bin=df[\"ws_bin\"].astype(ws_cat))\n            .groupby([\"wd_bin\", \"ws_bin\"], observed=False)\n            .agg([\"sum\", \"mean\"])\n        )\n        # Flatten and combine levels using an underscore\n        df.columns = [\"_\".join(col) for col in df.columns]\n\n        # Collect the frequency table and reshape\n        freq_table = df[\"freq_val_sum\"].values.copy()\n        freq_table = freq_table / freq_table.sum()\n        freq_table = freq_table.reshape((len(wd_centers), len(ws_centers)))\n\n        # Compute the TI table\n        ti_table = df[\"turbulence_intensities_mean\"].values.copy()\n        ti_table = ti_table.reshape((len(wd_centers), len(ws_centers)))\n\n        # If values is not none, compute the table\n        if self.values is not None:\n            value_table = df[\"values_mean\"].values.copy()\n            value_table = value_table.reshape((len(wd_centers), len(ws_centers)))\n        else:\n            value_table = None\n\n        # Return a WindRose\n        return WindRose(\n            wd_centers,\n            ws_centers,\n            ti_table,\n            freq_table,\n            value_table,\n            self.heterogeneous_map,\n        )\n\n    def to_WindTIRose(\n        self,\n        wd_step=2.0,\n        ws_step=1.0,\n        ti_step=0.02,\n        wd_edges=None,\n        ws_edges=None,\n        ti_edges=None,\n        bin_weights=None,\n    ):\n        \"\"\"\n        Converts the TimeSeries data to a WindTIRose.\n\n        Args:\n            wd_step (float, optional): Step size for wind direction (default is 2.0).\n            ws_step (float, optional): Step size for wind speed (default is 1.0).\n            ti_step (float, optional): Step size for turbulence intensity (default is 0.02).\n            wd_edges (NDArrayFloat, optional): Custom wind direction edges. Defaults to None.\n            ws_edges (NDArrayFloat, optional): Custom wind speed edges. Defaults to None.\n            ti_edges (NDArrayFloat, optional): Custom turbulence intensity\n                edges. Defaults to None.\n            bin_weights (NDArrayFloat, optional): Bin weights for resampling.  Note these\n                are primarily used by the downsample() method.\n                Defaults to None.\n\n        Returns:\n            WindRose: A WindTIRose object based on the TimeSeries data.\n\n        Notes:\n            - If `wd_edges` is defined, it uses it to produce the wind direction bin edges.\n            - If `wd_edges` is not defined, it determines `wd_edges` from the step and data.\n            - If `ws_edges` is defined, it uses it for wind speed edges.\n            - If `ws_edges` is not defined, it determines `ws_edges` from the step and data.\n            - If `ti_edges` is defined, it uses it for turbulence intensity edges.\n            - If `ti_edges` is not defined, it determines `ti_edges` from the step and data.\n        \"\"\"\n\n        # If wd_edges is defined, then use it to produce the bin centers\n        if wd_edges is not None:\n            wd_step = wd_edges[1] - wd_edges[0]\n\n            # use wd_step to produce a wrapped version of wind_directions\n            wind_directions_wrapped = self._wrap_wind_directions_near_360(\n                self.wind_directions, wd_step\n            )\n\n        # Else, determine wd_edges from the step and data\n        else:\n            wd_edges = np.arange(0.0 - wd_step / 2.0, 360.0, wd_step)\n\n            # use wd_step to produce a wrapped version of wind_directions\n            wind_directions_wrapped = self._wrap_wind_directions_near_360(\n                self.wind_directions, wd_step\n            )\n\n            # Only keep the range with values in it\n            wd_edges = wd_edges[wd_edges + wd_step > wind_directions_wrapped.min()]\n            wd_edges = wd_edges[wd_edges - wd_step <= wind_directions_wrapped.max()]\n\n        # Define the centers from the edges\n        wd_centers = wd_edges[:-1] + wd_step / 2.0\n\n        # Repeat for wind speeds\n        if ws_edges is not None:\n            ws_step = ws_edges[1] - ws_edges[0]\n\n        else:\n            ws_edges = np.arange(0.0 - ws_step / 2.0, 50.0, ws_step)\n\n            # Only keep the range with values in it\n            ws_edges = ws_edges[ws_edges + ws_step > self.wind_speeds.min()]\n            ws_edges = ws_edges[ws_edges - ws_step <= self.wind_speeds.max()]\n\n        # Define the centers from the edges\n        ws_centers = ws_edges[:-1] + ws_step / 2.0\n\n        # Repeat for turbulence intensities\n        if ti_edges is not None:\n            ti_step = ti_edges[1] - ti_edges[0]\n\n        else:\n            ti_edges = np.arange(0.0 - ti_step / 2.0, 1.0, ti_step)\n\n            # Only keep the range with values in it\n            ti_edges = ti_edges[ti_edges + ti_step > self.turbulence_intensities.min()]\n            ti_edges = ti_edges[ti_edges - ti_step <= self.turbulence_intensities.max()]\n\n        # Define the centers from the edges\n        ti_centers = ti_edges[:-1] + ti_step / 2.0\n\n        # Now use pandas to get the tables need for wind rose\n        df = pd.DataFrame(\n            {\n                \"wd\": wind_directions_wrapped,\n                \"ws\": self.wind_speeds,\n                \"ti\": self.turbulence_intensities,\n                \"freq_val\": np.ones(len(wind_directions_wrapped)),\n            }\n        )\n\n        # If bin_weights are passed in, apply these to the frequency\n        # this is mostly used when resampling the wind rose\n        if bin_weights is not None:\n            df = df.assign(freq_val=df[\"freq_val\"] * bin_weights)\n\n        # If values is not none, add to dataframe\n        if self.values is not None:\n            df = df.assign(values=self.values)\n\n        # Bin wind speed, wind direction, and turbulence intensity and then group things up\n        df = (\n            df.assign(\n                wd_bin=pd.cut(\n                    df.wd, bins=wd_edges, labels=wd_centers, right=False, include_lowest=True\n                )\n            )\n            .assign(\n                ws_bin=pd.cut(\n                    df.ws, bins=ws_edges, labels=ws_centers, right=False, include_lowest=True\n                )\n            )\n            .assign(\n                ti_bin=pd.cut(\n                    df.ti, bins=ti_edges, labels=ti_centers, right=False, include_lowest=True\n                )\n            )\n            .drop([\"wd\", \"ws\", \"ti\"], axis=1)\n        )\n\n        # Convert wd_bin, ws_bin, and ti_bin to categoricals to ensure all\n        # combinations are considered and then group\n        wd_cat = CategoricalDtype(categories=wd_centers, ordered=True)\n        ws_cat = CategoricalDtype(categories=ws_centers, ordered=True)\n        ti_cat = CategoricalDtype(categories=ti_centers, ordered=True)\n\n        df = (\n            df.assign(wd_bin=df[\"wd_bin\"].astype(wd_cat))\n            .assign(ws_bin=df[\"ws_bin\"].astype(ws_cat))\n            .assign(ti_bin=df[\"ti_bin\"].astype(ti_cat))\n            .groupby([\"wd_bin\", \"ws_bin\", \"ti_bin\"], observed=False)\n            .agg([\"sum\", \"mean\"])\n        )\n        # Flatten and combine levels using an underscore\n        df.columns = [\"_\".join(col) for col in df.columns]\n\n        # Collect the frequency table and reshape\n        freq_table = df[\"freq_val_sum\"].values.copy()\n        freq_table = freq_table / freq_table.sum()\n        freq_table = freq_table.reshape((len(wd_centers), len(ws_centers), len(ti_centers)))\n\n        # If values is not none, compute the table\n        if self.values is not None:\n            value_table = df[\"values_mean\"].values.copy()\n            value_table = value_table.reshape((len(wd_centers), len(ws_centers), len(ti_centers)))\n        else:\n            value_table = None\n\n        # Return a WindTIRose\n        return WindTIRose(\n            wd_centers,\n            ws_centers,\n            ti_centers,\n            freq_table,\n            value_table,\n            self.heterogeneous_map,\n        )\n\n\nclass WindRoseWRG(WindDataBase):\n    \"\"\"\n    The WindRoseWRG class is a WindData object the represents a wind resource grid (WRG) file\n    to FLORIS.  As a WindData object it can be passed to the FlorisModel.set method.  A WRG file\n    represents a wind resource as a grid of points where each point has a separate wind rose define\n    by the frequency of each wind direction and the Weibull parameters for each wind direction.\n\n    WindRoseWRG objects are provided the layout of a wind farm and computes a wind rose at\n    each point in the layout.  The wind rose at each point is computed by interpolating the weibull\n    parameter in the WRG file to the point in the layout and using them to compute a WindRose\n    object.  Each WindRose object shares wind direction and wind speed, only the frequencies differ.\n\n    When running a FlorisModel with a WindRoseWRG object, most behaviors are the same\n    except functions which compute an expected value, use separate frequencies for each\n    turbine to weight the individual power bins.\n\n    Args:\n        filename (str): The name of the WRG file to read.\n        wd_step (float, optional): Step size to use resampling the wind directions given by the WRG\n            file. If None, wd_step and wind_directions are set by the number of\n            sectors in the WRG file.   Defaults to None.\n        wind_speeds (NDArrayFloat, optional): Wind speeds to use in the wind rose. Defaults to\n            np.arange(0.0, 26.0, 1.0).\n        ti_table (float, optional): Turbulence intensities table to use for each WindRose object.\n            As in the WindRose ti_table, this can be a single value or an array of values.  If an\n            array of values is provided, it must be (len(wind_directions) x len(wind_speeds)).\n            Defaults to 0.06.\n\n    \"\"\"\n\n    def __init__(\n        self, filename, wd_step=None, wind_speeds=np.arange(0.0, 26.0, 1.0), ti_table=0.06\n    ):\n        # Read in the WRG file\n        self.filename = filename\n        self.read_wrg_file(filename)\n\n        # If wd_step is None, then use the wind directions in the WRG file\n        if wd_step is None:\n            self.wind_directions = self._wind_directions_wrg_file\n            self.wd_step = self.wind_directions[1] - self.wind_directions[0]\n        else:\n            self.wind_directions = np.arange(0.0, 360.0, wd_step)\n            self.wd_step = wd_step\n\n        # Initialize the layouts which will need to be specified\n        self.layout_x = None\n        self.layout_y = None\n\n        # Save the wind speeds and ti_table\n        self.wind_speeds = wind_speeds\n        self.ti_table = ti_table\n\n        # Initialize the flat arrays, these will depend on the specified wind speeds\n        self.wd_flat = None\n        self.ws_flat = None\n        self.non_zero_freq_mask = None\n\n    def read_wrg_file(self, filename):\n        \"\"\"\n        Read the contents of a WRG file and store the data in the object.\n\n        Args:\n            filename (str): The name of the WRG file to read.\n\n        \"\"\"\n\n        # Read the file into data\n        with open(filename, \"r\") as f:\n            data = f.readlines()\n\n        # Read the header\n        header = data[0].split()\n        self.nx = int(header[0])\n        self.ny = int(header[1])\n        self.xmin = float(header[2])\n        self.ymin = float(header[3])\n        self.grid_size = float(header[4])\n\n        # The grid of points is implied by the values above\n        self.x_array = np.arange(self.nx) * self.grid_size + self.xmin\n        self.y_array = np.arange(self.ny) * self.grid_size + self.ymin\n\n        # The number of grid points (n_gid) is the product of the number of points in x and y\n        self.n_gid = self.nx * self.ny\n\n        # Finally get the number of sectors from the first line after the header\n        self.n_sectors = int(data[1][70:72])\n\n        # The wind directions are implied by the number of sectors\n        self._wind_directions_wrg_file = np.arange(0.0, 360.0, 360.0 / self.n_sectors)\n\n        # Initialize the data arrays which have the same number of\n        # elements as the number of grid points\n        x_gid = np.zeros(self.n_gid)\n        y_gid = np.zeros(self.n_gid)\n        z_gid = np.zeros(self.n_gid)\n        h_gid = np.zeros(self.n_gid)\n\n        # Initialize the data arrays which are n_gid x n_sectors\n        sector_freq_gid = np.zeros((self.n_gid, self.n_sectors))\n        weibull_A_gid = np.zeros((self.n_gid, self.n_sectors))\n        weibull_k_gid = np.zeros((self.n_gid, self.n_sectors))\n\n        # Loop through the data and extract the values\n        for gid in range(self.n_gid):\n            line = data[1 + gid]\n            x_gid[gid] = float(line[10:20])\n            y_gid[gid] = float(line[20:30])\n            z_gid[gid] = float(line[30:38])\n            h_gid[gid] = float(line[38:43])\n\n            for sector in range(self.n_sectors):\n                # The frequency of the wind in this sector is in probablility * 1000\n                sector_freq_gid[gid, sector] = (\n                    float(line[72 + sector * 13 : 76 + sector * 13]) / 1000.0\n                )\n\n                # The A and k parameters are in the next 10 characters, with A stored * 10\n                # and k stored * 100\n                weibull_A_gid[gid, sector] = float(line[76 + sector * 13 : 80 + sector * 13]) / 10.0\n                weibull_k_gid[gid, sector] = (\n                    float(line[80 + sector * 13 : 85 + sector * 13]) / 100.0\n                )\n        # Save the x_gid and y_gid form for iteration in het map\n        self.x_gid = x_gid\n        self.y_gid = y_gid\n        self.weibull_A_gid = weibull_A_gid\n        self.weibull_k_gid = weibull_k_gid\n\n        # Save a single value of z and h for the entire grid\n        self.z = z_gid[0]\n        self.h = h_gid[0]\n\n        # Index the by sector data by x and y\n        self.sector_freq = np.zeros((self.nx, self.ny, self.n_sectors))\n        self.weibull_A = np.zeros((self.nx, self.ny, self.n_sectors))\n        self.weibull_k = np.zeros((self.nx, self.ny, self.n_sectors))\n\n        for x_idx, x in enumerate(self.x_array):\n            for y_idx, y in enumerate(self.y_array):\n                # Find the indices when x_gid and y_gid are equal to x and y\n                idx = np.where((x_gid == x) & (y_gid == y))[0]\n\n                # Assign the data to the correct location\n                self.sector_freq[x_idx, y_idx, :] = sector_freq_gid[idx, :]\n                self.weibull_A[x_idx, y_idx, :] = weibull_A_gid[idx, :]\n                self.weibull_k[x_idx, y_idx, :] = weibull_k_gid[idx, :]\n\n        # Build the interpolant function lists\n        self.interpolant_sector_freq = self._build_interpolant_function_list(\n            self.x_array, self.y_array, self.n_sectors, self.sector_freq\n        )\n        self.interpolant_weibull_A = self._build_interpolant_function_list(\n            self.x_array, self.y_array, self.n_sectors, self.weibull_A\n        )\n        self.interpolant_weibull_k = self._build_interpolant_function_list(\n            self.x_array, self.y_array, self.n_sectors, self.weibull_k\n        )\n\n    def __str__(self) -> str:\n        \"\"\"\n        Return a string representation of the WindRose object\n        \"\"\"\n\n        return (\n            f\"WindResourceGrid with {self.nx} x {self.ny} grid points, \"\n            f\"min x: {self.xmin}, min y: {self.ymin}, grid size: {self.grid_size}, \"\n            f\"z: {self.z}, h: {self.h}, {self.n_sectors} sectors\\n\"\n            f\"Wind directions in file: {self._wind_directions_wrg_file}\\n\"\n            f\"Wind directions: {self.wind_directions}\\n\"\n            f\"Wind speeds: {self.wind_speeds}\\n\"\n            f\"ti_table: {self.ti_table}\"\n        )\n\n    def _build_interpolant_function_list(self, x, y, n_sectors, data):\n        \"\"\"\n        Build a list of interpolant functions for the data.  It is assumed that the function\n        should return a list of interpolant functions, length n_sectors.\n\n        Args:\n            x (np.array): The x values of the data, length nx.\n            y (np.array): The y values of the data, length ny.\n            n_sectors (int): The number of sectors.\n            data (np.array): The data to interpolate, shape (nx, ny, n_sectors).\n\n        Returns:\n            list: A list of interpolant functions, length n_sectors.\n        \"\"\"\n\n        function_list = []\n\n        for sector in range(n_sectors):\n            function_list.append(\n                RegularGridInterpolator(\n                    (x, y),\n                    data[:, :, sector],\n                    bounds_error=False,\n                    fill_value=None,\n                )\n            )\n\n        return function_list\n\n    def _interpolate_data(self, x, y, interpolant_function_list):\n        \"\"\"\n        Interpolate the data at a given x, y location using the interpolant function list.\n\n        Args:\n            x (float): The x location to interpolate.\n            y (float): The y location to interpolate.\n            interpolant_function_list (list): A list of interpolant functions.\n\n        Returns:\n            list: A list of interpolated data, length n_sectors.\n        \"\"\"\n\n        # Check if x and y are within the bounds of the self.x_array and self.y_array, if\n        # so use the nearest method, otherwise use the linear method of interpolation\n        if (\n            x < self.x_array[0]\n            or x > self.x_array[-1]\n            or y < self.y_array[0]\n            or y > self.y_array[-1]\n        ):\n            method = \"nearest\"\n        else:\n            method = \"linear\"\n\n        result = np.zeros(self.n_sectors)\n        for sector in range(self.n_sectors):\n            result[sector] = interpolant_function_list[sector]((x, y), method=method)\n\n        return result\n\n    def _weibull_cumulative(self, x, a, k):\n        \"\"\"\n        Calculate the Weibull cumulative distribution function.\n\n        Args:\n            x (np.array): The wind speed values.\n            a (np.array): The Weibull A parameter values.\n            k (np.array): The Weibull k parameter values.\n\n        Returns:\n            np.array: The cumulative distribution function values.\n        \"\"\"\n\n        exponent = -((x / a) ** k)\n        result = 1.0 - np.exp(exponent)\n\n        # Where x is less than 0, the result should be 0\n        result[x < 0] = 0.0\n\n        return result\n\n        # Original code from PJ Stanley\n        # if x >= 0.0:\n        #     exponent = -(x / a) ** k\n        #     return 1.0 - np.exp(exponent)\n        # else:\n        #     return 0.0\n\n    def _generate_wind_speed_frequencies_from_weibull(self, A, k, wind_speeds=None):\n        \"\"\"\n        Generate the wind speed frequencies from the Weibull parameters.  Use the\n        cumulative form of the function and calculate the probability of the wind speed\n        in a given bin via the difference in the cumulative function at the bin edges.\n        Args:\n\n            A (np.array): The Weibull A parameter.\n            k (np.array): The Weibull k parameter.\n            wind_speeds (np.array): The wind speeds to calculate the frequencies for.\n                If None, the frequencies are calculated for 0 to 25 m/s in 1 m/s increments.\n                Default is None.\n\n        Returns:\n            np.array: The wind speed frequencies.\n        \"\"\"\n\n        if wind_speeds is None:\n            wind_speeds = self.wind_speeds\n        ws_steps = np.diff(wind_speeds)\n        if not np.all(np.isclose(ws_steps, ws_steps[0])):\n           raise ValueError(\"wind_speeds must be equally spaced.\")\n        else:\n            ws_step = ws_steps[0]\n\n        # Define the wind speed edges (not half-open interval in np.arange)\n        wind_speed_edges = np.arange(\n            wind_speeds[0] - ws_step / 2, wind_speeds[-1] + ws_step, ws_step\n        )\n\n        # Get the cumulative distribution function at the edges\n        cdf_edges = self._weibull_cumulative(wind_speed_edges, A, k)\n\n        # The frequency is the difference in the cumulative distribution function\n        # at the edges\n        # NOTE: The probability mass associated to each discrete wind speed (ws) is taken as the\n        # cumulative mass under the continuous Weibull distribution from ws - ws_step/2 to\n        # ws + ws_step/2, where ws_step is the step between the provided wind_speeds.\n        freq = cdf_edges[1:] - cdf_edges[:-1]\n\n        # Normalize the frequency\n        freq = freq / freq.sum()\n\n        return wind_speeds, freq\n\n    def get_wind_rose_at_point(self, x, y, wind_directions=None, wind_speeds=None, ti_table=0.06):\n        \"\"\"\n        Get the wind rose at a given x, y location.  Interpolate the parameters to the point\n        and then generate the wind rose.\n\n        Args:\n            x (float): The x location to interpolate.\n            y (float): The y location to interpolate.\n            wind_directions (np.array): The wind directions to calculate the frequencies for.\n                If None, use self.wind_directions.  Default is None.\n            wind_speeds (np.array): The wind speeds to calculate the frequencies for.\n                If None, use self.wind_speeds.  Default is None.\n            ti_table (float): The ti_table to use in the wind rose.\n                Default is 0.06.\n        \"\"\"\n\n        if wind_speeds is None:\n            wind_speeds = self.wind_speeds\n\n        # If wind directions is None, use the values stored\n        if wind_directions is None:\n            wind_directions = self.wind_directions\n            wd_step = self.wd_step\n        else:\n            # Calculate wd_step for these directions\n            wd_step = wind_directions[1] - wind_directions[0]\n\n        # Get the interpolated data\n        sector_freq = self._interpolate_data(x, y, self.interpolant_sector_freq)\n        weibull_A = self._interpolate_data(x, y, self.interpolant_weibull_A)\n        weibull_k = self._interpolate_data(x, y, self.interpolant_weibull_k)\n\n        # Initialize the freq_table\n        freq_table = np.zeros((self.n_sectors, len(wind_speeds)))\n\n        # First fill in the rows of the table using the weibull distributions,\n        # weighted by the sector freq\n        for sector in range(self.n_sectors):\n            wind_speeds, freq = self._generate_wind_speed_frequencies_from_weibull(\n                weibull_A[sector], weibull_k[sector], wind_speeds=wind_speeds\n            )\n            freq_table[sector, :] = sector_freq[sector] * freq\n\n        # Normalize the table\n        freq_table = freq_table / freq_table.sum()\n\n        # First build the wind rose using the wind directions in the wrg file\n        wind_rose = WindRose(\n            wind_directions=self._wind_directions_wrg_file,\n            wind_speeds=wind_speeds,\n            freq_table=freq_table,\n            ti_table=ti_table,\n            compute_zero_freq_occurrence=True,\n        )\n\n        # Now upsample or downsample the wind rose to the specified wind directions\n        if wd_step == (self._wind_directions_wrg_file[1] - self._wind_directions_wrg_file[0]):\n            # If the wind directions are the same, return the wind rose\n            return wind_rose\n        elif wd_step < (self._wind_directions_wrg_file[1] - self._wind_directions_wrg_file[0]):\n            # If the wind directions are smaller, upsample\n            return wind_rose.upsample(wd_step)\n        else:\n            # If the wind directions are larger, downsample\n            return wind_rose.downsample(wd_step)\n\n    def set_wd_step(self, wd_step):\n        \"\"\"\n        Set the wind directions for the WindRoseWRG object.\n\n        Args:\n            wind_directions (np.array): The wind directions to use for the wind roses.\n        \"\"\"\n\n        self.wind_directions = np.arange(0.0, 360.0, wd_step)\n        self.wd_step = wd_step\n\n        # Update the wind roses if the layout has been set\n        if self.layout_x is not None:\n            self._update_wind_roses()\n\n    def set_wind_speeds(self, wind_speeds):\n        \"\"\"\n        Set the wind speeds for the WindRoseWRG object.\n\n        Args:\n            wind_speeds (np.array): The wind speeds to use for the wind roses.\n        \"\"\"\n\n        self.wind_speeds = wind_speeds\n\n        # Update the wind roses if the layout has been set\n        if self.layout_x is not None:\n            self._update_wind_roses()\n\n    def set_ti_table(self, ti_table):\n        \"\"\"\n        Set the fixed turbulence intensity value for the WindRoseWRG object.\n\n        Args:\n            ti_table (float): The ti_table value to use in the wind roses.\n        \"\"\"\n\n        self.ti_table = ti_table\n\n        # Update the wind roses if the layout has been set\n        if self.layout_x is not None:\n            self._update_wind_roses()\n\n    def set_layout(self, layout_x, layout_y):\n        \"\"\"\n        Set the layout for the WindRoseWRG object.\n\n        Args:\n            layout_x (np.array): The x coordinates of the layout.\n            layout_y (np.array): The y coordinates of the layout.\n        \"\"\"\n\n        # Confirm that layout_x, layout_y, and wind_roses are the same length\n        if len(layout_x) != len(layout_y):\n            raise ValueError(\"layout_x and layout_y must be the same length\")\n\n        # If the current layout is the same as the new layout, return\n        if self.layout_x is not None and self.layout_y is not None:\n            if np.allclose(np.array(layout_x), self.layout_x) and np.allclose(\n                np.array(layout_y), self.layout_y\n            ):\n                return\n\n        # Save the layouts\n        self.layout_x = np.array(layout_x)\n        self.layout_y = np.array(layout_y)\n\n        # Update the wind roses\n        self._update_wind_roses()\n\n    def _update_wind_roses(self):\n        # Initialize the list of wind roses\n        self.wind_roses = []\n\n        # Loop through the turbines and get the wind rose at each location\n        for i in range(len(self.layout_x)):\n            wind_rose = self.get_wind_rose_at_point(\n                self.layout_x[i],\n                self.layout_y[i],\n                wind_directions=self.wind_directions,\n                wind_speeds=self.wind_speeds,\n                ti_table=self.ti_table,\n            )\n            self.wind_roses.append(wind_rose)\n\n        # Save also the wd_flat and ws_flat from the first wind rose as this could be needed\n        # for unpacking and non_zero_freq_mask\n        self.wd_flat = self.wind_roses[0].wd_flat\n        self.ws_flat = self.wind_roses[0].ws_flat\n        self.non_zero_freq_mask = self.wind_roses[0].non_zero_freq_mask\n\n    def unpack(self):\n        \"\"\"\n        Implement the unpack method for WindRoseByTurbine by\n        calling the unpack method for each of the WindRose objects in wind_roses.\n        Mose of the variables can be passed as is but freq_table_unpack are combined\n        and stacked along the 1th axis\n\n        Returns:\n            Tuple: Tuple containing the unpacked wind rose data.\n        \"\"\"\n\n        if self.layout_x is None:\n            raise ValueError(\"WindRoseByTurbine must be initialized to a layout before unpacking\")\n\n        # Initialize freq_table_unpack\n        freq_table_unpack = np.zeros((len(self.wd_flat), len(self.layout_x)))\n\n        # Loop over remaining wind roses and stack freq_table_unpack\n        for i, wind_rose in enumerate(self.wind_roses):\n            (\n                wind_directions_unpack,\n                wind_speeds_unpack,\n                ti_table_unpack,\n                freq_table_unpack_0,\n                value_table_unpack,\n                heterogeneous_inflow_config,\n            ) = wind_rose.unpack()\n            freq_table_unpack[:, i] = freq_table_unpack_0\n\n        return (\n            wind_directions_unpack,\n            wind_speeds_unpack,\n            ti_table_unpack,\n            freq_table_unpack,\n            value_table_unpack,\n            heterogeneous_inflow_config,\n        )\n\n    def plot_wind_roses(\n        self,\n        axarr=None,\n        wd_step=None,\n        ws_step=None,\n    ):\n        \"\"\"\n        Plot the wind roses for each turbine in the WindRoseByTurbine object.\n\n        Args:\n            axarr (NDArrayAxes, optional): Array of axes to plot the wind roses on.\n                Defaults to None.  Must have length equal to the number of wind roses.\n            wd_step (float, optional): Step size for wind direction. Defaults to None.\n            ws_step (float, optional): Step size for wind speed. Defaults to None.\n        \"\"\"\n\n        if self.layout_x is None:\n            raise ValueError(\"WindRoseByTurbine must be initialized to a layout before plotting\")\n\n        # If axarr is not defined, create a new figure\n        if axarr is None:\n            _, axarr = plt.subplots(1, len(self.wind_roses), subplot_kw={\"polar\": True})\n\n        # Test that axarr is the correct length\n        if len(axarr) != len(self.wind_roses):\n            raise ValueError(\"axarr must have the same length as the number of wind roses\")\n\n        # Plot the wind roses for each turbine\n        for i, wind_rose in enumerate(self.wind_roses):\n            wind_rose.plot(ax=axarr[i], wd_step=wd_step, ws_step=ws_step)\n            axarr[i].set_title(f\"Turbine {i}\\n ({self.layout_x[i]:.1f}, {self.layout_y[i]:.1f})\")\n\n    def get_heterogeneous_wind_rose(\n        self,\n        fmodel,\n        wind_speeds=None,\n        x_loc=None,\n        y_loc=None,\n        representative_wind_speed=8.0,\n    ):\n        \"\"\"\n        Get the heterogeneous map at each location in the grid, with the speeds ups\n        defined relative the location indicated by gid_norm_index.\n\n        Args:\n            fmodel (FlorisModel): The FlorisModel object to use to generate the power curve.\n            wind_speeds (np.array): The wind speeds to calculate the frequencies for.\n                Default is np.arange(0.0, 25.0, 1.0).\n            gid_norm_index (int): The index of the turbine to normalize the speed ups to.\n                Default is 0.\n            representative_wind_speed (float): The representative wind speed to use\n                in the power curve.\n\n        Returns:\n            HeterogeneousMap: The heterogeneous map object.\n        \"\"\"\n        ############################\n        # Compute the power curve for combining the wind speeds\n        ############################\n\n        if wind_speeds is None:\n            wind_speeds = self.wind_speeds\n\n        # Get a local copy\n        fm = copy.deepcopy(fmodel)\n\n        # Get the power curve for the turbine\n        # TODO: Maybe the power curve could be directly extracted\n        fm.set(\n            layout_x=[0],\n            layout_y=[0],\n            wind_data=TimeSeries(\n                wind_speeds=wind_speeds,\n                wind_directions=270.0,\n                turbulence_intensities=0.06,\n            ),\n        )\n        fm.run()\n        turbine_power = fm.get_turbine_powers().flatten()\n\n        ############################\n        # Identify the point on the original wrg grid closest to the x_loc and y_loc\n        ############################\n\n        if x_loc is None or y_loc is None:\n            # Simply use the first point\n            gid_reference = 0\n\n        else:\n            # Find the closest point\n            gid_reference = np.argmin((self.x_gid - x_loc) ** 2 + (self.y_gid - y_loc) ** 2)\n\n        # Assign x_loc and y_loc to this point\n        x_loc = self.x_gid[gid_reference]\n        y_loc = self.y_gid[gid_reference]\n        print(f\"Using point {gid_reference} at ({x_loc}, {y_loc}) as reference location\")\n\n        ############################\n        # Get the wind rose at this point\n        ############################\n        wind_rose = self.get_wind_rose_at_point(\n            x=x_loc,\n            y=y_loc,\n        )\n\n        # Subset to the representative wind speed\n\n        # Check the represenative_wind_speed is valid\n        if representative_wind_speed in wind_rose.wind_speeds:\n            ws_idx = np.where(wind_rose.wind_speeds == representative_wind_speed)[0]\n        else:\n            raise ValueError(\"representative_wind_speed must be in original set\")\n\n        # Create a new wind rose with only the specified wind speeds\n        wind_rose = WindRose(\n            wind_rose.wind_directions,\n            wind_rose.wind_speeds[ws_idx],\n            wind_rose.ti_table[:, ws_idx],\n            wind_rose.freq_table[:, ws_idx],\n            wind_rose.value_table[:, ws_idx] if wind_rose.value_table is not None else None,\n            wind_rose.compute_zero_freq_occurrence,\n            wind_rose.heterogeneous_map,\n        )\n\n        ############################\n        # Calculate speed multipliers\n        ############################\n\n        speed_multipliers = np.zeros((self.n_sectors, self.n_gid))\n\n        for direction_sector in range(self.n_sectors):\n            for gid in range(self.n_gid):\n                _, freq = self._generate_wind_speed_frequencies_from_weibull(\n                    self.weibull_A_gid[gid, direction_sector],\n                    self.weibull_k_gid[gid, direction_sector],\n                    wind_speeds=wind_speeds,\n                )\n\n                # Record the expected power\n                speed_multipliers[direction_sector, gid] = np.sum(turbine_power * freq)\n\n            # Normalize the speed ups\n            speed_multipliers[direction_sector, :] = (\n                speed_multipliers[direction_sector, :]\n                / speed_multipliers[direction_sector, gid_reference]\n            )\n\n        # Take the cube root of the speed ups to place in the frame of wind speed ups\n        speed_multipliers = np.cbrt(speed_multipliers)\n\n        # Create the heterogeneous map\n        heterogeneous_map = HeterogeneousMap(\n            x=self.x_gid,\n            y=self.y_gid,\n            wind_directions=self._wind_directions_wrg_file,\n            speed_multipliers=speed_multipliers,\n        )\n\n        # Return the wind rose with the heterogeneous map\n        return WindRose(\n            wind_directions=wind_rose.wind_directions,\n            wind_speeds=wind_rose.wind_speeds,\n            freq_table=wind_rose.freq_table,\n            ti_table=wind_rose.ti_table,\n            heterogeneous_map=heterogeneous_map,\n        )\n"
  },
  {
    "path": "profiling/linux_perf.py",
    "content": "\nfrom contextlib import contextmanager\nfrom os import getpid\nfrom resource import getrusage, RUSAGE_SELF\nfrom signal import SIGINT\nfrom subprocess import Popen\nfrom time import (\n    perf_counter,\n    sleep,\n    time,\n)\n\n\n# Additional events described here:\n# https://www.brendangregg.com/perf.html#SoftwareEvents\nevents = [\n    \"instructions\",\n    \"cache-references\",\n    \"cache-misses\",\n    \"avx_insts.all\",\n]\n\n@contextmanager\ndef perf():\n    \"\"\"\n    Benchmark this process with Linux's perf util.\n\n    Example usage:\n\n        with perf():\n            x = run_some_code()\n            more_code(x)\n            all_this_code_will_be_measured()\n    \"\"\"\n    p = Popen([\n        # Run perf stat\n        \"perf\", \"stat\",\n        # for the current Python process\n        \"-p\", str(getpid()),\n        # record the list of events mentioned above\n        \"-e\", \",\".join(events)\n    ])\n\n    # Ensure perf has started before running more\n    # Python code. This will add ~0.1 to the elapsed\n    # time reported by perf, so we also track elapsed\n    # time separately.\n    sleep(0.1)\n    start = time()\n    try:\n        yield\n    finally:\n        print(f\"Elapsed (seconds): {time() - start}\")\n        print(\"Peak memory (MiB):\",\n            int(getrusage(RUSAGE_SELF).ru_maxrss / 1024))\n        p.send_signal(SIGINT)\n"
  },
  {
    "path": "profiling/profiling.py",
    "content": "\n# import re\n# import sys\n# import time\n# import cProfile\n# from copy import deepcopy\n\nimport copy\n\nfrom conftest import SampleInputs\n\nfrom floris.core import Core\n\n\ndef run_floris():\n    core = Core.from_file(\"examples/example_input.yaml\")\n    return core\n\nif __name__==\"__main__\":\n    # if len(sys.argv) > 1:\n    #     floris = Floris(sys.argv[1])\n    # else:\n    #     floris = Floris(\"example_input.yaml\")\n    # floris.farm.flow_field.calculate_wake()\n\n    # start = time.time()\n    # cProfile.run('re.compile(\"floris.steady_state_atmospheric_condition()\")')\n    # end = time.time()\n    # print(start, end, end - start)\n\n    sample_inputs = SampleInputs()\n\n    sample_inputs.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"gauss\"\n    sample_inputs.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = \"gauss\"\n    sample_inputs.core[\"wake\"][\"enable_secondary_steering\"] = True\n    sample_inputs.core[\"wake\"][\"enable_yaw_added_recovery\"] = True\n    sample_inputs.core[\"wake\"][\"enable_transverse_velocities\"] = True\n\n    N_TURBINES = 100\n    N_FINDEX = 72 * 25  # Size of a characteristic wind rose\n\n    TURBINE_DIAMETER = sample_inputs.core[\"farm\"][\"turbine_type\"][0][\"rotor_diameter\"]\n    sample_inputs.core[\"farm\"][\"layout_x\"] = [5 * TURBINE_DIAMETER * i for i in range(N_TURBINES)]\n    sample_inputs.core[\"farm\"][\"layout_y\"] = [0.0 for i in range(N_TURBINES)]\n\n    sample_inputs.core[\"flow_field\"][\"wind_directions\"] = N_FINDEX * [270.0]\n    sample_inputs.core[\"flow_field\"][\"wind_speeds\"] = N_FINDEX * [8.0]\n    sample_inputs.core[\"flow_field\"][\"turbulence_intensities\"] = N_FINDEX * [0.06]\n\n    N = 1\n    for i in range(N):\n        core = Core.from_dict(copy.deepcopy(sample_inputs.core))\n        core.initialize_domain()\n        core.steady_state_atmospheric_condition()\n"
  },
  {
    "path": "profiling/quality_metrics.py",
    "content": "\nimport copy\nimport time\nimport warnings\n\nimport numpy as np\nfrom linux_perf import perf\n\nfrom floris.core import Core\n\n\nwd_grid, ws_grid = np.meshgrid(\n    np.arange(0, 360.0, 5),     # wind directions\n    np.arange(8.0, 12.0, 0.2),  # wind speeds\n    indexing=\"ij\"\n)\nWIND_DIRECTIONS = wd_grid.flatten()\nWIND_SPEEDS = ws_grid.flatten()\nTURBULENCE_INTENSITIES = np.ones_like(WIND_DIRECTIONS) * 0.1\nN_FINDEX = len(WIND_DIRECTIONS)\n\nN_TURBINES = 3\nX_COORDS, Y_COORDS = np.meshgrid(\n    5.0 * 126.0 * np.arange(0, N_TURBINES, 1),\n    5.0 * 126.0 * np.arange(0, N_TURBINES, 1),\n)\nX_COORDS = X_COORDS.flatten()\nY_COORDS = Y_COORDS.flatten()\n\nN_ITERATIONS = 20\n\n\ndef run_floris(input_dict):\n    try:\n        start = time.perf_counter()\n        core = Core.from_dict(copy.deepcopy(input_dict.core))\n        core.initialize_domain()\n        core.steady_state_atmospheric_condition()\n        end = time.perf_counter()\n        return end - start\n    except KeyError:\n        # Catch the errors when an invalid wake model was given because the model\n        # was not yet implemented\n        return -1.0\n\n\ndef time_profile(input_dict):\n\n    # Run once to initialize Python and memory\n    run_floris(input_dict)\n\n    times = np.zeros(N_ITERATIONS)\n    for i in range(N_ITERATIONS):\n        times[i] = run_floris(input_dict)\n\n    return np.sum(times) / N_ITERATIONS\n\n\ndef test_time_jensen_jimenez(sample_inputs_fixture):\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"jensen\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = \"jimenez\"\n    return time_profile(sample_inputs_fixture)\n\n\ndef test_time_gauss(sample_inputs_fixture):\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"gauss\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = \"gauss\"\n    return time_profile(sample_inputs_fixture)\n\n\ndef test_time_gch(sample_inputs_fixture):\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"gauss\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = \"gauss\"\n    sample_inputs_fixture.core[\"wake\"][\"enable_transverse_velocities\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_secondary_steering\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_yaw_added_recovery\"] = True\n    return time_profile(sample_inputs_fixture)\n\n\ndef test_time_cumulative(sample_inputs_fixture):\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"cc\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = \"gauss\"\n    return time_profile(sample_inputs_fixture)\n\n\ndef memory_profile(input_dict):\n    # Run once to initialize Python and memory\n    core = Core.from_dict(copy.deepcopy(input_dict.core))\n    core.initialize_domain()\n    core.steady_state_atmospheric_condition()\n\n    with perf():\n        for i in range(N_ITERATIONS):\n            core = Core.from_dict(copy.deepcopy(input_dict.core))\n            core.initialize_domain()\n            core.steady_state_atmospheric_condition()\n\n    print(\n        \"Size of one data array: \"\n        f\"{64 * N_FINDEX * N_TURBINES * 25 / (1000 * 1000)} MB\"\n    )\n\n\ndef test_mem_jensen_jimenez(sample_inputs_fixture):\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"jensen\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = \"jimenez\"\n    memory_profile(sample_inputs_fixture)\n\n\nif __name__==\"__main__\":\n    warnings.filterwarnings('ignore')\n\n    from conftest import SampleInputs\n    sample_inputs = SampleInputs()\n\n    sample_inputs.core[\"farm\"][\"layout_x\"] = X_COORDS\n    sample_inputs.core[\"farm\"][\"layout_y\"] = Y_COORDS\n    sample_inputs.core[\"flow_field\"][\"wind_directions\"] = WIND_DIRECTIONS\n    sample_inputs.core[\"flow_field\"][\"wind_speeds\"] = WIND_SPEEDS\n    sample_inputs.core[\"flow_field\"][\"turbulence_intensities\"] = TURBULENCE_INTENSITIES\n\n    print()\n    print(\"### Memory profiling\")\n    test_mem_jensen_jimenez(sample_inputs)\n\n    print()\n    print(\"### Performance profiling\")\n    time_jensen = test_time_jensen_jimenez(sample_inputs)\n    time_gauss = test_time_gauss(sample_inputs)\n    time_gch = test_time_gch(sample_inputs)\n    # TODO: reenable this after the cc model is fixed with multiturbine\n    # time_cc = test_time_cumulative(sample_inputs)\n\n    # print(\"{:.4f} {:.4f} {:.4f} {:.4f}\".format(time_jensen, time_gauss, time_gch, time_cc))\n    print(\"{:.4f} {:.4f} {:.4f}\".format(time_jensen, time_gauss, time_gch))\n"
  },
  {
    "path": "profiling/serial_vectorize.py",
    "content": "\nimport copy\nimport time\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom conftest import SampleInputs\n\nfrom floris.simulation import Floris\n\n\ndef time_vec(input_dict):\n    start = time.time()\n    floris = Floris(input_dict=input_dict.core)\n    end = time.time()\n    init_time = end - start\n\n    start = time.time()\n    floris.steady_state_atmospheric_condition()\n    end = time.time()\n    calc_time = end - start\n\n    return init_time, calc_time\n\n\ndef time_serial(input_dict, wd, ws):\n    init_times = np.zeros(len(wd))\n    calc_times = np.zeros(len(wd))\n\n    for i, (d, s) in enumerate(zip(wd, ws)):\n\n        input_dict.core[\"flow_field\"][\"wind_directions\"] = [d]\n        input_dict.core[\"flow_field\"][\"wind_speeds\"] = [s]\n\n        start = time.time()\n        floris = Floris(input_dict=input_dict.core)\n        end = time.time()\n        init_times[i] = end - start\n\n        start = time.time()\n        floris.steady_state_atmospheric_condition()\n        end = time.time()\n        calc_times[i] = end - start\n\n    return np.sum(init_times), np.sum(calc_times)\n\nif __name__==\"__main__\":\n    plt.figure()\n\n    sample_inputs = SampleInputs()\n    sample_inputs.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n    sample_inputs.core[\"flow_field\"][\"wind_speeds\"] = [8.0]\n    TURBINE_DIAMETER = sample_inputs.core[\"turbine\"][\"rotor_diameter\"]\n\n    N = 5\n    simulation_size = np.arange(N)\n\n    # 1 turbine\n    vectorize_init, vectorize_calc = np.zeros(N), np.zeros(N)\n    for i in range(N):\n        vectorize_scaling_inputs = copy.deepcopy(sample_inputs)\n\n        factor = (i+1) * 50\n        vectorize_scaling_inputs.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n        vectorize_scaling_inputs.core[\"flow_field\"][\"wind_speeds\"] = factor * [8.0]\n\n        vectorize_init[i], vectorize_calc[i] = time_vec(copy.deepcopy(vectorize_scaling_inputs))\n        print(\"vectorize\", i, vectorize_calc[i])\n\n    serial_init, serial_calc = np.zeros(N), np.zeros(N)\n    for i in range(N):\n        serial_scaling_inputs = copy.deepcopy(sample_inputs)\n\n        factor = (i+1) * 50\n        wind_directions = [270.0]\n        wind_speeds = factor * [8.0]\n\n        serial_init[i], serial_calc[i] = time_serial(\n            copy.deepcopy(serial_scaling_inputs),\n            wind_directions,\n            wind_speeds\n        )\n        print(\"serial\", i, serial_calc[i])\n\n    plt.plot(simulation_size, vectorize_init, 'b--', label='vectorize init - 1 turbine')\n    plt.plot(simulation_size, vectorize_calc, 'bo-', label='vectorize calc - 1 turbine')\n    plt.plot(simulation_size, serial_init, 'g--', label='serial init - 1 turbine')\n    plt.plot(simulation_size, serial_calc, 'go-', label='serial calc - 1 turbine')\n\n\n    # More than 1 turbine\n    n_turbines = 10\n    sample_inputs.core[\"farm\"][\"layout_x\"] = [5 * TURBINE_DIAMETER * j for j in range(n_turbines)]\n    sample_inputs.core[\"farm\"][\"layout_y\"] = n_turbines * [0.0]\n\n    vectorize_init, vectorize_calc = np.zeros(N), np.zeros(N)\n    for i in range(N):\n        vectorize_scaling_inputs = copy.deepcopy(sample_inputs)\n\n        factor = (i+1) * 50\n        vectorize_scaling_inputs.core[\"flow_field\"][\"wind_speeds\"] = factor * [8.0]\n        vectorize_scaling_inputs.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n\n        vectorize_init[i], vectorize_calc[i] = time_vec(copy.deepcopy(vectorize_scaling_inputs))\n        print(\"vectorize\", i, vectorize_calc[i])\n\n    serial_init, serial_calc = np.zeros(N), np.zeros(N)\n    for i in range(N):\n        serial_scaling_inputs = copy.deepcopy(sample_inputs)\n\n        factor = (i+1) * 50\n        speeds = factor * [8.0]\n        wind_directions = [270.0]\n\n        serial_init[i], serial_calc[i] = time_serial(\n            copy.deepcopy(serial_scaling_inputs),\n            wind_directions,\n            speeds\n        )\n        print(\"serial\", i, serial_calc[i])\n\n    plt.plot(simulation_size, vectorize_init, 'c--', label='vectorize init - 10 turbine')\n    plt.plot(simulation_size, vectorize_calc, 'co-', label='vectorize calc - 10 turbine')\n    plt.plot(simulation_size, serial_init, 'y--', label='serial init - 10 turbine')\n    plt.plot(simulation_size, serial_calc, 'yo-', label='serial calc - 10 turbine')\n\n    ## Show plots\n    plt.legend(loc=\"upper left\")\n    plt.grid(True)\n    plt.show()\n"
  },
  {
    "path": "profiling/timing.py",
    "content": "\nimport copy\nimport time\n\nimport matplotlib.pyplot as plt\nimport memory_profiler\nimport numpy as np\nfrom conftest import SampleInputs\n\nfrom floris.simulation import Floris\n\n\ndef time_profile(input_dict):\n    floris = Floris.from_dict(input_dict.core)\n    start = time.perf_counter()\n    floris.steady_state_atmospheric_condition()\n    end = time.perf_counter()\n    return end - start\n\ndef internal_probe(input_dict):\n    floris = Floris(input_dict=input_dict.core)\n    internal_quantity = floris.steady_state_atmospheric_condition()\n    return internal_quantity\n\ndef memory_profile(input_dict):\n    floris = Floris(input_dict=input_dict.core)\n    mem_usage = memory_profiler.memory_usage(\n        (floris.steady_state_atmospheric_condition, (), {}),\n        max_usage=True\n    )\n    return mem_usage\n\nif __name__==\"__main__\":\n    sample_inputs = SampleInputs()\n    TURBINE_DIAMETER = sample_inputs.core[\"turbine\"][\"rotor_diameter\"]\n\n    # Use Gauss models\n    sample_inputs.core[\"wake\"][\"model_strings\"] = {\n        \"velocity_model\": \"gauss\",\n        \"deflection_model\": \"gauss\",\n        \"combination_model\": None,\n        \"turbulence_model\": None,\n    }\n\n    ### Time scaling\n\n    # N = 30\n\n    # wd_calc_time = np.zeros(N)\n    # wd_size = np.zeros(N)\n    # wind_direction_scaling_inputs = copy.deepcopy(sample_inputs)\n    # for i in range(N):\n    #     factor = (i+1) * 50\n    #     wind_direction_scaling_inputs.core[\"flow_field\"][\"wind_directions\"] = factor * [270.0]\n    #     wind_direction_scaling_inputs.core[\"flow_field\"][\"wind_speeds\"] = [8.0]\n\n    #     wd_calc_time[i] = time_profile(copy.deepcopy(wind_direction_scaling_inputs))\n    #     wd_size[i] = factor\n    #     print(\"wind direction\", i, wd_calc_time[i])\n\n\n    # ws_calc_time = np.zeros(N)\n    # ws_size = np.zeros(N)\n    # wind_speed_scaling_inputs = copy.deepcopy(sample_inputs)\n    # for i in range(N):\n    #     factor = (i+1) * 50\n    #     wind_speed_scaling_inputs.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n    #     wind_speed_scaling_inputs.core[\"flow_field\"][\"wind_speeds\"] = factor * [8.0]\n\n    #     ws_calc_time[i] = time_profile(copy.deepcopy(wind_speed_scaling_inputs))\n    #     ws_size[i] = factor\n    #     print(\"wind speed\", i, ws_calc_time[i])\n\n\n    # turb_calc_time = np.zeros(N)\n    # turb_size = np.zeros(N)\n    # turbine_scaling_inputs = copy.deepcopy(sample_inputs)\n    # for i in range(N):\n    #     factor = (i+1) * 3\n    #     turbine_scaling_inputs.core[\"farm\"][\"layout_x\"] = [\n    #         5 * TURBINE_DIAMETER * j\n    #         for j in range(factor)\n    #     ]\n    #     turbine_scaling_inputs.core[\"farm\"][\"layout_y\"] = factor * [0.0]\n\n    #     turb_calc_time[i] = time_profile(copy.deepcopy(turbine_scaling_inputs))\n    #     turb_size[i] = factor\n    #     print(\"n turbine\", i, turb_calc_time[i])\n\n\n    # internal_quantity = np.zeros(N)\n    # scaling_inputs = copy.deepcopy(sample_inputs)\n    # for i in range(5):\n    #     factor = (i+1) * 2\n    #     scaling_inputs.core[\"farm\"][\"layout_x\"] = [\n    #         5 * TURBINE_DIAMETER * j\n    #         for j in range(factor)\n    #     ]\n    #     scaling_inputs.core[\"farm\"][\"layout_y\"] = factor * [0.0]\n    #     factor = (i+1) * 20\n    #     scaling_inputs.core[\"flow_field\"][\"wind_directions\"] = factor * [270.0]\n    #     scaling_inputs.core[\"flow_field\"][\"wind_speeds\"] = factor * [8.0]\n\n    #     internal_quantity[i] = time_profile(scaling_inputs)\n    #     print(\"n turbine\", i, internal_quantity[i])\n\n    # plt.figure()\n    # plt.plot(wd_size, wd_calc_time, 'b+-', label='wind direction')\n    # plt.plot(ws_size, ws_calc_time, 'g+-', label='wind speed')\n    # plt.plot(turb_size, turb_calc_time, 'r+-', label='n turbine')\n    # # plt.plot(simulation_size, internal_quantity, 'b+-', label='internal quantity')\n    # plt.legend(loc=\"upper left\")\n    # plt.grid(True)\n\n\n    ### Timing larger sizes in each dimension\n\n    n_wind_directions = 1\n    n_wind_speeds = 1\n    n_turbines = 3\n    sample_inputs.core[\"wake\"][\"model_strings\"] = {\n        # \"velocity_model\": \"jensen\",\n        # \"deflection_model\": \"jimenez\",\n        \"velocity_model\": \"cc\",\n        \"deflection_model\": \"gauss\",\n        \"combination_model\": None,\n        \"turbulence_model\": None,\n    }\n    sample_inputs.core[\"solver\"] = {\n        \"type\": \"turbine_grid\",\n        \"turbine_grid_points\": 5\n    }\n\n    # sample_inputs.core[\"wake\"][\"enable_transverse_velocities\"] = False\n    # sample_inputs.core[\"wake\"][\"enable_secondary_steering\"] = False\n    # sample_inputs.core[\"wake\"][\"enable_yaw_added_recovery\"] = False\n    sample_inputs.core[\"flow_field\"][\"wind_directions\"] = n_wind_directions * [270.0]\n    sample_inputs.core[\"flow_field\"][\"wind_speeds\"] = n_wind_speeds * [8.0]\n    sample_inputs.core[\"farm\"][\"layout_x\"] = [5 * TURBINE_DIAMETER * j for j in range(n_turbines)]\n    sample_inputs.core[\"farm\"][\"layout_y\"] = n_turbines * [0.0]\n\n    N = 1\n    times = np.zeros(N)\n    for i in range(N):\n        print(f\"Iteration {i}\")\n        times[i] = time_profile(copy.deepcopy(sample_inputs))\n        print(f\"    {times[i]}\")\n\n    print(f\"Total time: {np.sum(times)}\")\n    print(f\"Average per iteration: { np.sum(times) / N }\")\n\n    ### Memory scaling\n\n    # N = 6\n    # simulation_size = np.arange(N)\n\n    # wd_space = np.zeros(N)\n    # wind_direction_scaling_inputs = copy.deepcopy(sample_inputs)\n    # for i in range(N):\n    #     factor = (i+1) * 50\n    #     wind_direction_scaling_inputs.core[\"farm\"][\"wind_directions\"] = factor * [270.0]\n    #     wind_direction_scaling_inputs.core[\"farm\"][\"wind_speeds\"] = [8.0]\n\n    #     wd_space[i] = memory_profile(wind_direction_scaling_inputs)\n    #     print(\"wind direction\", i, wd_space[i])\n\n\n    # ws_space = np.zeros(N)\n    # wind_speed_scaling_inputs = copy.deepcopy(sample_inputs)\n    # for i in range(N):\n    #     factor = (i+1) * 50\n    #     wind_speed_scaling_inputs.core[\"farm\"][\"wind_directions\"] = [270.0]\n    #     wind_speed_scaling_inputs.core[\"farm\"][\"wind_speeds\"] = factor * [8.0]\n\n    #     ws_space[i] = memory_profile(wind_speed_scaling_inputs)\n    #     print(\"wind speed\", i, ws_space[i])\n\n\n    # turb_space = np.zeros(N)\n    # turbine_scaling_inputs = copy.deepcopy(sample_inputs)\n    # for i in range(N):\n    #     factor = (i+1) * 50\n    #     turbine_scaling_inputs.core[\"farm\"][\"layout_x\"] = [\n    #         5 * TURBINE_DIAMETER * j\n    #         for j in range(factor)\n    #     ]\n    #     turbine_scaling_inputs.core[\"farm\"][\"layout_y\"] = factor * [0.0]\n\n    #     turb_space[i] = memory_profile(turbine_scaling_inputs)\n    #     print(\"n turbine\", turb_space[i])\n\n\n    # # Remove the min from each test so that each starts at 0\n    # wd_space = wd_space - min(wd_space)\n    # ws_space = ws_space - min(ws_space)\n    # turb_space = turb_space - min(turb_space)\n\n\n    # plt.figure()\n    # plt.plot(simulation_size, wd_space, 'b+-', label='wind direction')\n    # plt.plot(simulation_size, ws_space, 'g+-', label='wind speed')\n    # plt.plot(simulation_size, turb_space, 'r+-', label='n turbine')\n    # plt.legend(loc=\"upper left\")\n    # plt.grid(True)\n\n\n    ### Show plots\n    # plt.show()\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools >= 40.6.0\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"floris\"\nversion = \"4.6.4\"\ndescription = \"A controls-oriented engineering wake model.\"\nreadme = \"README.md\"\nrequires-python = \">=3.10, <3.15\"\nauthors = [\n    { name = \"Rafael Mudafort\", email = \"Rafael.Mudafort@nlr.gov\" },\n    { name = \"Paul Fleming\", email = \"Paul.Fleming@nlr.gov\" },\n    { name = \"Michael (Misha) Sinner\", email = \"Michael.Sinner@nlr.gov\" },\n    { name = \"Eric Simley\", email = \"Eric.Simley@nlr.gov\" },\n    { name = \"Christopher Bay\", email = \"Christopher.Bay@nlr.gov\" },\n]\nlicense = { file = \"LICENSE.txt\" }\nkeywords = [\"floris\"]\nclassifiers = [\n    \"License :: OSI Approved :: BSD License\",\n    \"Programming Language :: Python\",\n    \"Programming Language :: Python :: 3\",\n    \"Programming Language :: Python :: 3.9\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n    \"Programming Language :: Python :: 3.13\",\n    \"Programming Language :: Python :: Implementation :: CPython\",\n    \"Programming Language :: Python :: Implementation :: PyPy\"\n]\ndependencies = [\n    \"attrs\",\n    \"pyyaml~=6.0\",\n    \"numexpr~=2.0\",\n    \"numpy~=2.0\",\n    \"scipy~=1.1\",\n    \"matplotlib~=3.0\",\n    \"pandas~=2.0\",\n    \"shapely~=2.0\",\n    \"coloredlogs~=15.0\",\n    \"pathos~=0.3\",\n]\n\n[project.optional-dependencies]\ndocs = [\n    \"jupyter-book~=1.0\",\n    \"sphinx-book-theme~=1.0\",\n    \"sphinx-autodoc-typehints>=2,<4\",\n    \"sphinxcontrib-autoyaml~=1.0\",\n    \"sphinxcontrib.mermaid>=1,<3\",\n    \"bokeh~=3.7\",\n    \"ruamel.yaml~=0.18.0\",\n]\ndevelop = [\n    \"pytest>=8,<10\",\n    \"pytest-benchmark~=5.1\",\n    \"pre-commit~=4.0\",\n    \"ruff~=0.9\",\n    \"isort>=5,<8\"\n]\n\n[tool.setuptools.packages.find]\ninclude = [\"floris*\"]\n\n[tool.setuptools.package-data]\nfloris = [\n    \"turbine_library/*.yaml\",\n    \"turbine_library/*.csv\",\n    \"turbine_library/demo_cp_ct_surfaces/*.npz\",\n    \"core/wake_velocity/turbopark_lookup_table.mat\",\n    \"default_inputs.yaml\"\n]\n\n[project.urls]\nHomepage = \"https://github.com/NatLabRockies/floris\"\nDocumentation = \"https://natlabrockies.github.io/floris/\"\n\n[coverage.run]\n# Coverage.py configuration file\n# https://coverage.readthedocs.io/en/latest/config.html\nbranch = true\nsource = \"floris/*\"\nomit = [\n    \"tests/*\",\n    \"benchmarks/*\"\n]\n\n\n[tool.pytest.ini_options]\ntestpaths = \"tests\"\nfilterwarnings = [\n    \"ignore::DeprecationWarning:pandas.*:\"\n]\n\n\n\n## Pyflakes (F)\n## pycodestyle (E, W)\n# mccabe (C90)\n# isort (I)     # Use isort directly until more isort features are included in ruff\n# pep8-naming (N)\n# pydocstyle (D)\n# pyupgrade (UP)\n# flake8-2020 (YTT)\n# flake8-annotations (ANN)\n# flake8-bandit (S)\n# flake8-blind-except (BLE)\n# flake8-boolean-trap (FBT)\n# flake8-bugbear (B)\n# flake8-builtins (A)\n# flake8-commas (COM)\n# flake8-comprehensions (C4)\n# flake8-datetimez (DTZ)\n# flake8-debugger (T10)\n# flake8-errmsg (EM)\n# flake8-executable (EXE)\n# flake8-implicit-str-concat (ISC)\n# flake8-import-conventions (ICN)\n# flake8-logging-format (G)\n# flake8-no-pep420 (INP)\n# flake8-pie (PIE)\n# flake8-print (T20)\n# flake8-pytest-style (PT)\n# flake8-quotes (Q)\n# flake8-return (RET)\n# flake8-simplify (SIM)\n# flake8-tidy-imports (TID)\n# flake8-type-checking (TCH)\n# flake8-unused-arguments (ARG)\n# flake8-use-pathlib (PTH)\n# eradicate (ERA)\n# pandas-vet (PD)\n# pygrep-hooks (PGH)\n# Pylint (PL)\n# - Convention (PLC)\n# - Error (PLE)\n# - Refactor (PLR)\n# - Warning (PLW)\n# tryceratops (TRY)\n# flake8-raise (RSE)\n# flake8-self (SLF)\n# Ruff-specific rules (RUF)\n\n[tool.ruff]\nsrc = [\"floris\", \"tests\"]\nline-length = 100\ntarget-version = \"py313\"\n\n# See https://github.com/charliermarsh/ruff#supported-rules\n# for rules included and matching to prefix.\nlint.select = [\"F\", \"E\", \"W\", \"C4\", ] #\"T20\", \"I\"\n# I - isort is not fully implemented in ruff so there is not parity. Consider disabling I.\n\n# F401 unused-import: Ignore until all used isort flags are adopted in ruff\nlint.ignore = [\"F401\"]\n\n# Allow autofix for all enabled rules (when `--fix`) is provided.\n# fixable = [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\"]\nlint.fixable = [\"F\", \"E\", \"W\", \"C4\"] #\"T20\", \"I\"\nlint.unfixable = []\n\n# Exclude a variety of commonly ignored directories.\nexclude = [\n    \"floris/version.py\",\n    \".bzr\",\n    \".direnv\",\n    \".eggs\",\n    \".git\",\n    \".hg\",\n    \".mypy_cache\",\n    \".nox\",\n    \".pants.d\",\n    \".ruff_cache\",\n    \".svn\",\n    \".tox\",\n    \".venv\",\n    \"__pypackages__\",\n    \"_build\",\n    \"buck-out\",\n    \"build\",\n    \"dist\",\n    \"node_modules\",\n    \"venv\",\n    \"docs\",\n]\n\n# Allow unused variables when underscore-prefixed.\nlint.dummy-variable-rgx = \"^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$\"\n\n[tool.ruff.lint.per-file-ignores]\n# F841 unused-variable: ignore since this file uses numexpr and many variables look unused\n\"floris/core/wake_deflection/jimenez.py\" = [\"F841\"]\n\"floris/core/wake_turbulence/crespo_hernandez.py\" = [\"F841\"]\n\"floris/core/wake_deflection/gauss.py\" = [\"F841\"]\n\"floris/core/wake_velocity/jensen.py\" = [\"F841\"]\n\"floris/core/wake_velocity/gauss.py\" = [\"F841\"]\n\"floris/core/wake_velocity/empirical_gauss.py\" = [\"F841\"]\n# Ignore `F401` (import violations) in all `__init__.py` files, and in `path/to/file.py`.\n\"__init__.py\" = [\"F401\"]\n\n# I001 unsorted-imports: ignore because the import order is meaningful to navigate\n# import dependencies\n\"floris/core/__init__.py\" = [\"I001\"]\n\n[tool.ruff.lint.isort]\ncombine-as-imports = true\nknown-first-party = [\"floris\"]\norder-by-type = false\n# lines-after-imports = 2\n\n# [tool.ruff.mccabe]\n# # Unlike Flake8, default to a complexity level of 10.\n# max-complexity = 10\n\n\n[tool.isort]\nsections = [\n    \"FUTURE\",\n    \"STDLIB\",\n    \"THIRDPARTY\",\n    \"FIRSTPARTY\",\n    \"LOCALFOLDER\"\n]\nknown_first_party = [\n    \"floris\"\n]\nmulti_line_output = 3\ncombine_as_imports = true\nforce_grid_wrap = 3\ninclude_trailing_comma = true\nuse_parentheses = true\nlines_after_imports = 2\nline_length = 100\norder_by_type = false\nsplit_on_trailing_comma = true\n\n# length_sort = true\n# case_sensitive: False\n# force_sort_within_sections: True\n# reverse_relative: True\n# sort_relative_in_force_sorted_sections: True\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/base_unit_test.py",
    "content": "\nimport pytest\nfrom attr import define, field\nfrom attrs.exceptions import FrozenAttributeError\n\nfrom floris.core import BaseClass, BaseModel\n\n\n@define\nclass ClassTest(BaseModel):\n    x: int = field(default=1, converter=int)\n    a_string: str = field(default=\"abc\", converter=str)\n\n    def prepare_function() -> dict:\n        return {}\n\n    def function() -> None:\n        return None\n\n\ndef test_get_model_values():\n    \"\"\"\n    BaseClass and therefore BaseModel previously had a method `get_model_values` that\n    returned the values of the model parameters. This was removed because it was redundant\n    but this test was refactored to test the as_dict method from FromDictMixin.\n    This tests that the parameters are changed when set by the user.\n    \"\"\"\n    cls = ClassTest(x=4, a_string=\"xyz\")\n    values = cls.as_dict()\n    assert len(values) == 2\n    assert values[\"x\"] == 4\n    assert values[\"a_string\"] == \"xyz\"\n\ndef test_NUM_EPS():\n    cls = ClassTest(x=4, a_string=\"xyz\")\n    assert cls.NUM_EPS == 0.001\n\n    with pytest.raises(FrozenAttributeError):\n        cls.NUM_EPS = 2\n"
  },
  {
    "path": "tests/conftest.py",
    "content": "import copy\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nimport floris\nfrom floris.core import (\n    Core,\n    FlowField,\n    FlowFieldGrid,\n    PointsGrid,\n    TurbineGrid,\n)\n\n\ndef turbines_to_array(turbine_list: list):\n    return [[t.average_velocity, t.Ct, t.power, t.axial_induction] for t in turbine_list]\n\n\ndef assert_results_arrays(test: np.array, baseline: np.array):\n    if np.shape(test) != np.shape(baseline):\n        raise ValueError(\"test and baseline results have mismatched shapes.\")\n\n    for test_dim0, baseline_dim0 in zip(test, baseline):\n        for test_dim1, baseline_dim1 in zip(test_dim0, baseline_dim0):\n            assert np.allclose(test_dim1, baseline_dim1)\n\n\ndef assert_results(test: list, baseline: list):\n    if len(test) != len(baseline):\n        raise ValueError(\"assert_results: test and baseline results have mismatched lengths.\")\n\n    for i in range(len(test)):\n        for j, (t, b) in enumerate(zip(test[i], baseline[i])):\n            # print(j, t, b)\n            assert t == pytest.approx(b)\n\n\ndef print_test_values(\n    average_velocities: list,\n    thrusts: list,\n    powers: list,\n    axial_inductions: list,\n    max_findex_print: int | None =None\n):\n    n_findex, n_turb = np.shape(average_velocities)\n    if max_findex_print is not None:\n        n_findex = min(n_findex, max_findex_print)\n    for i in range(n_findex):\n        print(\"[\")\n        for j in range(n_turb):\n            print(\n                \"    [{:.7f}, {:.7f}, {:.7f}, {:.7f}],\".format(\n                    average_velocities[i,j], thrusts[i,j], powers[i,j],\n                    axial_inductions[i,j]\n                )\n            )\n        print(\"],\")\n\n\nWIND_DIRECTIONS = [\n    270.0,\n    270.0,\n    270.0,\n    270.0,\n    360.0,\n    360.0,\n    360.0,\n    360.0,\n    285.0,\n    285.0,\n    285.0,\n    285.0,\n    315.0,\n    315.0,\n    315.0,\n    315.0,\n]\nWIND_SPEEDS = [\n    8.0,\n    9.0,\n    10.0,\n    11.0,\n    8.0,\n    9.0,\n    10.0,\n    11.0,\n    8.0,\n    9.0,\n    10.0,\n    11.0,\n    8.0,\n    9.0,\n    10.0,\n    11.0,\n]\nTURBULENCE_INTENSITIES = [\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n    0.1,\n]\n\n# FINDEX is the length of the number of conditions, so it can be\n# len(WIND_DIRECTIONS) or len(WIND_SPEEDS\nN_FINDEX = len(WIND_DIRECTIONS)\n\nX_COORDS = [\n    0.0,\n    5 * 126.0,\n    10 * 126.0\n]\nY_COORDS = [\n    0.0,\n    0.0,\n    0.0\n]\nZ_COORDS = [\n    90.0,\n    90.0,\n    90.0\n]\nN_TURBINES = len(X_COORDS)\nROTOR_DIAMETER = 126.0\nTURBINE_GRID_RESOLUTION = 2\n\nDEMO_CP_CT_5MW_FILE = (\n    Path(floris.__file__).resolve().parent /\n    \"turbine_library/demo_cp_ct_surfaces/nrel_5MW_demo_cp_ct_surface.npz\"\n)\n\n## Unit test fixtures\n\n@pytest.fixture\ndef flow_field_fixture(sample_inputs_fixture):\n    flow_field_dict = sample_inputs_fixture.flow_field\n    return FlowField.from_dict(flow_field_dict)\n\n@pytest.fixture\ndef turbine_grid_fixture(sample_inputs_fixture) -> TurbineGrid:\n    turbine_coordinates = np.array(list(zip(X_COORDS, Y_COORDS, Z_COORDS)))\n    rotor_diameters = ROTOR_DIAMETER * np.ones( (N_TURBINES) )\n    return TurbineGrid(\n        turbine_coordinates=turbine_coordinates,\n        turbine_diameters=rotor_diameters,\n        wind_directions=np.array(WIND_DIRECTIONS),\n        grid_resolution=TURBINE_GRID_RESOLUTION,\n    )\n\n@pytest.fixture\ndef flow_field_grid_fixture(sample_inputs_fixture) -> FlowFieldGrid:\n    turbine_coordinates = np.array(list(zip(X_COORDS, Y_COORDS, Z_COORDS)))\n    rotor_diameters = ROTOR_DIAMETER * np.ones( (N_FINDEX, N_TURBINES) )\n    return FlowFieldGrid(\n        turbine_coordinates=turbine_coordinates,\n        turbine_diameters=rotor_diameters,\n        wind_directions=np.array(WIND_DIRECTIONS),\n        grid_resolution=[3,2,2]\n    )\n\n@pytest.fixture\ndef points_grid_fixture(sample_inputs_fixture) -> PointsGrid:\n    turbine_coordinates = np.array(list(zip(X_COORDS, Y_COORDS, Z_COORDS)))\n    rotor_diameters = ROTOR_DIAMETER * np.ones( (N_FINDEX, N_TURBINES) )\n    points_x = [0.0, 10.0]\n    points_y = [0.0, 0.0]\n    points_z = [1.0, 2.0]\n    return PointsGrid(\n        turbine_coordinates=turbine_coordinates,\n        turbine_diameters=rotor_diameters,\n        wind_directions=np.array(WIND_DIRECTIONS),\n        grid_resolution=None,\n        points_x=points_x,\n        points_y=points_y,\n        points_z=points_z,\n    )\n\n@pytest.fixture\ndef floris_fixture():\n    sample_inputs = SampleInputs()\n    return Core(sample_inputs.core)\n\n@pytest.fixture\ndef sample_inputs_fixture():\n    return SampleInputs()\n\n\nclass SampleInputs:\n    \"\"\"\n    SampleInputs class\n    \"\"\"\n\n    def __init__(self):\n        self.turbine = {\n            \"turbine_type\": \"nrel_5mw\",\n            \"rotor_diameter\": 125.88,\n            \"hub_height\": 90.0,\n            \"operation_model\": \"cosine-loss\",\n            \"power_thrust_table\": {\n                \"cosine_loss_exponent_yaw\": 1.88,\n                \"cosine_loss_exponent_tilt\": 1.88,\n                \"ref_air_density\": 1.225,\n                \"ref_tilt\": 5.0,\n                \"helix_a\": 1.802,\n                \"helix_power_b\": 4.568e-03,\n                \"helix_power_c\": 1.629e-10,\n                \"helix_thrust_b\": 1.027e-03,\n                \"helix_thrust_c\": 1.378e-06,\n                \"peak_shaving_fraction\": 0.2,\n                \"peak_shaving_TI_threshold\": 0.1,\n                \"power\": [\n                    0.0,\n                    0.0,\n                    40.51801151756921,\n                    177.6716250641970,\n                    403.900880943964,\n                    737.5889584824021,\n                    1187.177403061187,\n                    1239.245945375778,\n                    1292.518429372350,\n                    1347.321314747710,\n                    1403.257372557894,\n                    1460.701189873070,\n                    1519.641912597998,\n                    1580.174365096404,\n                    1642.110316691816,\n                    1705.758292831,\n                    1771.165952889397,\n                    2518.553107505315,\n                    3448.381605840943,\n                    3552.140809000129,\n                    3657.954543179412,\n                    3765.121299313842,\n                    3873.928844315059,\n                    3984.480022695550,\n                    4096.582833096852,\n                    4210.721306623712,\n                    4326.154305853405,\n                    4443.395565353604,\n                    4562.497934188341,\n                    4683.419890251577,\n                    4806.164748311019,\n                    4929.931918769215,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    5000.00,\n                    0.0,\n                    0.0,\n                ],\n                \"thrust_coefficient\": [\n                    0.0,\n                    0.0,\n                    1.132034888,\n                    0.999470963,\n                    0.917697381,\n                    0.860849503,\n                    0.815371198,\n                    0.811614904,\n                    0.807939328,\n                    0.80443352,\n                    0.800993851,\n                    0.79768116,\n                    0.794529244,\n                    0.791495834,\n                    0.788560434,\n                    0.787217182,\n                    0.787127977,\n                    0.785839257,\n                    0.783812219,\n                    0.783568108,\n                    0.783328285,\n                    0.781194418,\n                    0.777292539,\n                    0.773464375,\n                    0.769690236,\n                    0.766001924,\n                    0.762348072,\n                    0.758760824,\n                    0.755242872,\n                    0.751792927,\n                    0.748434131,\n                    0.745113997,\n                    0.717806682,\n                    0.672204789,\n                    0.63831272,\n                    0.610176496,\n                    0.585456847,\n                    0.563222111,\n                    0.542912273,\n                    0.399312061,\n                    0.310517829,\n                    0.248633226,\n                    0.203543725,\n                    0.169616419,\n                    0.143478955,\n                    0.122938861,\n                    0.106515296,\n                    0.093026095,\n                    0.081648606,\n                    0.072197368,\n                    0.064388275,\n                    0.057782745,\n                    0.0,\n                    0.0,\n                ],\n                \"wind_speed\": [\n                    0.0,\n                    2.9,\n                    3.0,\n                    4.0,\n                    5.0,\n                    6.0,\n                    7.0,\n                    7.1,\n                    7.2,\n                    7.3,\n                    7.4,\n                    7.5,\n                    7.6,\n                    7.7,\n                    7.8,\n                    7.9,\n                    8.0,\n                    9.0,\n                    10.0,\n                    10.1,\n                    10.2,\n                    10.3,\n                    10.4,\n                    10.5,\n                    10.6,\n                    10.7,\n                    10.8,\n                    10.9,\n                    11.0,\n                    11.1,\n                    11.2,\n                    11.3,\n                    11.4,\n                    11.5,\n                    11.6,\n                    11.7,\n                    11.8,\n                    11.9,\n                    12.0,\n                    13.0,\n                    14.0,\n                    15.0,\n                    16.0,\n                    17.0,\n                    18.0,\n                    19.0,\n                    20.0,\n                    21.0,\n                    22.0,\n                    23.0,\n                    24.0,\n                    25.0,\n                    25.1,\n                    50.0,\n                ],\n            },\n            \"TSR\": 8.0\n        }\n\n        self.controller_dependent_turbine_parameters = {\n            \"ref_air_density\": 1.225,\n            \"ref_tilt\": 5.0,\n            \"rated_rpm\": 12.1,\n            \"rotor_solidity\": 0.05132,\n            \"generator_efficiency\": 0.944,\n            \"rated_power\": 5000.0,\n            \"rotor_diameter\": 126,\n            \"beta\": -0.45891,\n            \"cd\": 0.0040638,\n            \"cl_alfa\": 4.275049,\n            \"cp_ct_data_file\": DEMO_CP_CT_5MW_FILE\n        }\n\n        self.turbine_floating = copy.deepcopy(self.turbine)\n        self.turbine_floating[\"floating_tilt_table\"] = {\n            \"tilt\": [\n                5.0,\n                5.0,\n                5.0,\n            ],\n            \"wind_speed\": [\n                0.0,\n                25.0,\n                50.0,\n            ],\n        }\n        self.turbine_floating[\"correct_cp_ct_for_tilt\"] = True\n\n        self.turbine_multi_dim = {\n            \"turbine_type\": 'iea_15MW_multi_dim_cp_ct',\n            \"hub_height\": 150.0,\n            \"rotor_diameter\": 242.24,\n            \"TSR\": 8.0,\n            \"multi_dimensional_cp_ct\": True,\n            \"power_thrust_table\": {\n                \"ref_air_density\": 1.225,\n                \"ref_tilt\": 6.0,\n                \"cosine_loss_exponent_yaw\": 1.88,\n                \"cosine_loss_exponent_tilt\": 1.88,\n                \"power_thrust_data_file\": 'iea_15MW_multi_dim_Tp_Hs.csv',\n            }\n        }\n\n        self.farm = {\n            \"layout_x\": X_COORDS,\n            \"layout_y\": Y_COORDS,\n            \"turbine_type\": [self.turbine]\n        }\n\n        self.flow_field = {\n            \"wind_speeds\": WIND_SPEEDS,\n            \"wind_directions\": WIND_DIRECTIONS,\n            \"turbulence_intensities\": TURBULENCE_INTENSITIES,\n            \"wind_shear\": 0.12,\n            \"wind_veer\": 0.0,\n            \"air_density\": 1.225,\n            \"reference_wind_height\": self.turbine[\"hub_height\"],\n        }\n\n        self.wake = {\n            \"model_strings\": {\n                \"velocity_model\": \"jensen\",\n                \"deflection_model\": \"jimenez\",\n                \"combination_model\": \"sosfs\",\n                \"turbulence_model\": \"crespo_hernandez\",\n            },\n            \"wake_deflection_parameters\": {\n                \"gauss\": {\n                    \"ad\": 0.0,\n                    \"alpha\": 0.58,\n                    \"bd\": 0.0,\n                    \"beta\": 0.077,\n                    \"dm\": 1.0,\n                    \"ka\": 0.38,\n                    \"kb\": 0.004\n                },\n                \"jimenez\": {\n                    \"ad\": 0.0,\n                    \"bd\": 0.0,\n                    \"kd\": 0.05,\n                },\n                \"empirical_gauss\": {\n                   \"horizontal_deflection_gain_D\": 3.0,\n                   \"vertical_deflection_gain_D\": -1,\n                   \"deflection_rate\": 22,\n                   \"mixing_gain_deflection\": 0.0,\n                   \"yaw_added_mixing_gain\": 0.0\n                },\n            },\n            \"wake_velocity_parameters\": {\n                \"gauss\": {\n                    \"alpha\": 0.58,\n                    \"beta\": 0.077,\n                    \"ka\": 0.38,\n                    \"kb\": 0.004\n                },\n                \"jensen\": {\n                    \"we\": 0.05,\n                },\n                \"cc\": {\n                    \"a_s\": 0.179367259,\n                    \"b_s\": 0.0118889215,\n                    \"c_s1\": 0.0563691592,\n                    \"c_s2\": 0.13290157,\n                    \"a_f\": 3.11,\n                    \"b_f\": -0.68,\n                    \"c_f\": 2.41,\n                    \"alpha_mod\": 1.0\n                },\n                \"turbopark\": {\n                    \"A\": 0.04,\n                    \"sigma_max_rel\": 4.0\n                },\n                \"turboparkgauss\": {\n                    \"A\": 0.04,\n                    \"include_mirror_wake\": True\n                },\n                \"empirical_gauss\": {\n                    \"wake_expansion_rates\": [0.023, 0.008],\n                    \"breakpoints_D\": [10],\n                    \"sigma_0_D\": 0.28,\n                    \"smoothing_length_D\": 2.0,\n                    \"mixing_gain_velocity\": 2.0,\n                    \"awc_wake_exp\": 1.2,\n                    \"awc_wake_denominator\": 400\n                },\n            },\n            \"wake_turbulence_parameters\": {\n                \"crespo_hernandez\": {\n                    \"initial\": 0.1,\n                    \"constant\": 0.5,\n                    \"ai\": 0.8,\n                    \"downstream\": -0.32\n                },\n                \"wake_induced_mixing\": {\n                    \"atmospheric_ti_gain\": 0.0\n                }\n            },\n            \"enable_secondary_steering\": False,\n            \"enable_yaw_added_recovery\": False,\n            \"enable_active_wake_mixing\": False,\n            \"enable_transverse_velocities\": False,\n        }\n\n        self.core = {\n            \"farm\": self.farm,\n            \"flow_field\": self.flow_field,\n            \"wake\": self.wake,\n            \"solver\": {\n                \"type\": \"turbine_grid\",\n                \"turbine_grid_points\": 3,\n            },\n            \"logging\": {\n                \"console\": {\"enable\": True, \"level\": 1},\n                \"file\": {\"enable\": False, \"level\": 1},\n            },\n            \"name\": \"conftest\",\n            \"description\": \"Inputs used for testing\",\n            \"floris_version\": \"v4\",\n        }\n\n        self.v3type_turbine = {\n            \"turbine_type\": \"nrel_5mw_v3type\",\n            \"rotor_diameter\": 125.88,\n            \"hub_height\": 90.0,\n            \"generator_efficiency\": 0.944,\n            \"operation_model\": \"cosine-loss\",\n            \"pP\": 1.88,\n            \"pT\": 1.88,\n            \"ref_density_cp_ct\": 1.225,\n            \"ref_tilt_cp_ct\": 5.0,\n            \"TSR\": 8.0,\n            \"power_thrust_table\": {\n                \"power\": [\n                    0.0,\n                    0.0,\n                    0.208546508,\n                    0.385795061,\n                    0.449038264,\n                    0.474546985,\n                    0.480994449,\n                    0.481172749,\n                    0.481235678,\n                    0.481305875,\n                    0.481238912,\n                    0.481167356,\n                    0.481081935,\n                    0.481007003,\n                    0.480880409,\n                    0.480789285,\n                    0.480737341,\n                    0.480111543,\n                    0.479218839,\n                    0.479120347,\n                    0.479022984,\n                    0.478834971,\n                    0.478597234,\n                    0.478324162,\n                    0.477994289,\n                    0.477665338,\n                    0.477253698,\n                    0.476819542,\n                    0.476368667,\n                    0.475896732,\n                    0.475404347,\n                    0.474814698,\n                    0.469087611,\n                    0.456886723,\n                    0.445156758,\n                    0.433837552,\n                    0.422902868,\n                    0.412332387,\n                    0.402110045,\n                    0.316270768,\n                    0.253224057,\n                    0.205881042,\n                    0.169640239,\n                    0.141430529,\n                    0.119144335,\n                    0.101304591,\n                    0.086856409,\n                    0.075029591,\n                    0.065256635,\n                    0.057109143,\n                    0.050263779,\n                    0.044470536,\n                    0.0,\n                    0.0,\n                ],\n                \"thrust\": [\n                    0.0,\n                    0.0,\n                    1.132034888,\n                    0.999470963,\n                    0.917697381,\n                    0.860849503,\n                    0.815371198,\n                    0.811614904,\n                    0.807939328,\n                    0.80443352,\n                    0.800993851,\n                    0.79768116,\n                    0.794529244,\n                    0.791495834,\n                    0.788560434,\n                    0.787217182,\n                    0.787127977,\n                    0.785839257,\n                    0.783812219,\n                    0.783568108,\n                    0.783328285,\n                    0.781194418,\n                    0.777292539,\n                    0.773464375,\n                    0.769690236,\n                    0.766001924,\n                    0.762348072,\n                    0.758760824,\n                    0.755242872,\n                    0.751792927,\n                    0.748434131,\n                    0.745113997,\n                    0.717806682,\n                    0.672204789,\n                    0.63831272,\n                    0.610176496,\n                    0.585456847,\n                    0.563222111,\n                    0.542912273,\n                    0.399312061,\n                    0.310517829,\n                    0.248633226,\n                    0.203543725,\n                    0.169616419,\n                    0.143478955,\n                    0.122938861,\n                    0.106515296,\n                    0.093026095,\n                    0.081648606,\n                    0.072197368,\n                    0.064388275,\n                    0.057782745,\n                    0.0,\n                    0.0,\n                ],\n                \"wind_speed\": [\n                    0.0,\n                    2.9,\n                    3.0,\n                    4.0,\n                    5.0,\n                    6.0,\n                    7.0,\n                    7.1,\n                    7.2,\n                    7.3,\n                    7.4,\n                    7.5,\n                    7.6,\n                    7.7,\n                    7.8,\n                    7.9,\n                    8.0,\n                    9.0,\n                    10.0,\n                    10.1,\n                    10.2,\n                    10.3,\n                    10.4,\n                    10.5,\n                    10.6,\n                    10.7,\n                    10.8,\n                    10.9,\n                    11.0,\n                    11.1,\n                    11.2,\n                    11.3,\n                    11.4,\n                    11.5,\n                    11.6,\n                    11.7,\n                    11.8,\n                    11.9,\n                    12.0,\n                    13.0,\n                    14.0,\n                    15.0,\n                    16.0,\n                    17.0,\n                    18.0,\n                    19.0,\n                    20.0,\n                    21.0,\n                    22.0,\n                    23.0,\n                    24.0,\n                    25.0,\n                    25.1,\n                    50.0,\n                ],\n            },\n        }\n"
  },
  {
    "path": "tests/controller_dependent_operation_model_unit_test.py",
    "content": "import logging\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom floris import FlorisModel\nfrom floris.core.turbine.controller_dependent_operation_model import ControllerDependentTurbine\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT, SimpleTurbine\nfrom tests.conftest import SampleInputs\n\n\ndef test_submodel_attributes():\n\n    assert hasattr(ControllerDependentTurbine, \"power\")\n    assert hasattr(ControllerDependentTurbine, \"thrust_coefficient\")\n    assert hasattr(ControllerDependentTurbine, \"axial_induction\")\n\ndef test_ControllerDependentTurbine_power_curve():\n    \"\"\"\n    Test that the power curve is correctly loaded and interpolated.\n    \"\"\"\n\n    n_turbines = 1\n    turbine_data = SampleInputs().turbine\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"] = (\n        SampleInputs().controller_dependent_turbine_parameters\n    )\n    data_file_path = Path(__file__).resolve().parents[1] / \"floris\" / \"turbine_library\"\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"] = \\\n        np.load(\n            data_file_path / turbine_data[\"power_thrust_table\"]\n                                         [\"controller_dependent_turbine_parameters\"]\n                                         [\"cp_ct_data_file\"]\n        )\n\n    N_test = 20\n    wind_speeds = np.tile(\n        np.linspace(0, 30, N_test)[:, None, None, None],\n        (1, n_turbines, 3, 3)\n    )\n\n    power_test = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=np.zeros((N_test, n_turbines)),\n        tilt_angles=turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((N_test, n_turbines)),\n        power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((N_test, n_turbines))\n    )\n\n    # Check that the powers all between 0 and rated\n    assert (power_test >= 0).all()\n    assert (power_test <= 5e6).all()\n\n    # Check that zero power is produced at zero wind speed\n    assert power_test[0, 0] == 0\n\n    # Check power is monotonically increasing, and also that it is flat above rated\n    # NOTE: no cut-out defined for the ControllerDependentTurbine\n    assert (np.diff(power_test.squeeze()) >= -1e4).all()\n    assert (power_test[wind_speeds.mean(axis=(2,3)) > 12.0] == 5e6).all()\n\n\ndef test_ControllerDependentTurbine_derating():\n\n    n_turbines = 1\n    turbine_data = SampleInputs().turbine\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"] = (\n        SampleInputs().controller_dependent_turbine_parameters\n    )\n    data_file_path = Path(__file__).resolve().parents[1] / \"floris\" / \"turbine_library\"\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"] = \\\n        np.load(\n            data_file_path / turbine_data[\"power_thrust_table\"]\n                                         [\"controller_dependent_turbine_parameters\"]\n                                         [\"cp_ct_data_file\"]\n        )\n\n    N_test = 20\n    tilt_angles_nom = turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((N_test, n_turbines))\n    # define power set points\n    power_setpoints = np.linspace(1e6,5e6,N_test).reshape(N_test,1) * np.ones((N_test, n_turbines))\n\n    # Set wind speed to above rated\n    wind_speeds = 15.0 * np.ones((N_test, n_turbines, 2, 2))\n\n    # First run without sending the power setpoints\n    power_baseline = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=25 * np.ones((N_test, n_turbines)),\n        tilt_angles=tilt_angles_nom,\n        power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((N_test, n_turbines))\n    ).squeeze()\n\n    # Now with power setpoints\n    power_test = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=25 * np.ones((N_test, n_turbines)),\n        tilt_angles=tilt_angles_nom,\n        power_setpoints=power_setpoints\n    )\n\n    # Check that power produced does not exceed baseline available power,\n    # and that power produced matches setpoints to within 0.1%\n    assert (power_test <= power_baseline).all()\n    assert np.allclose(power_test, power_setpoints, rtol=1e-4)\n\ndef test_ControllerDependentTurbine_yawing():\n\n    n_turbines = 1\n    turbine_data = SampleInputs().turbine\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"] = (\n        SampleInputs().controller_dependent_turbine_parameters\n    )\n    data_file_path = Path(__file__).resolve().parents[1] / \"floris\" / \"turbine_library\"\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"] = \\\n        np.load(\n            data_file_path / turbine_data[\"power_thrust_table\"]\n                                         [\"controller_dependent_turbine_parameters\"]\n                                         [\"cp_ct_data_file\"]\n        )\n\n    N_test = 20\n    tilt_angles_nom = turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((N_test, n_turbines))\n\n    # Choose a wind speed near rated for NREL 5MW\n    ws_above_rated = 12.0\n    wind_speeds = ws_above_rated * np.ones((N_test, n_turbines, 2, 2))\n    yaw_angle_array = np.linspace(-30,0,N_test)\n\n    power_test = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=yaw_angle_array.reshape(N_test,1) * np.ones((N_test, n_turbines)),\n        power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((N_test, n_turbines)),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n\n    # Check that for small yaw angles, we still produce rated power\n    assert np.allclose(power_test[-3:-1,0], 5e6)\n    # Check that power is (non-strictly) monotonically increasing as yaw angle\n    # increases from -30 to 0\n    assert (np.diff(power_test.squeeze()) >= -1e4).all()\n\ndef test_ControllerDependentTurbine_shear():\n\n    n_turbines = 1\n    turbine_data = SampleInputs().turbine\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"] = (\n        SampleInputs().controller_dependent_turbine_parameters\n    )\n    data_file_path = Path(__file__).resolve().parents[1] / \"floris\" / \"turbine_library\"\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"] = \\\n        np.load(\n            data_file_path / turbine_data[\"power_thrust_table\"]\n                                         [\"controller_dependent_turbine_parameters\"]\n                                         [\"cp_ct_data_file\"]\n        )\n\n    N_test = 31\n    tilt_angles_nom = turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((N_test, n_turbines))\n\n    # Create array of shear (3 values: 0, 0.15 0.3) (ws multiplier at top/bottom of rotor)\n    shear_array = np.linspace(0, 0.3, 3)\n    shear_points = 1 + shear_array[:, None] * np.linspace(-1, 1, 5)[None, :]\n\n    # Define wind speed array with n_grid = 5 (free stream wind speed 8.0 m/s)\n    wind_speeds_no_shear = 8.0 * np.ones((1, n_turbines, 5, 5))\n    wind_speeds_shear = wind_speeds_no_shear * shear_points[:, None, None, :]\n    wind_speeds_test = np.repeat(wind_speeds_shear, N_test, axis=0)\n\n    yaw_max = 30 # Maximum yaw to test\n    yaw_angles_test = np.linspace(-yaw_max, yaw_max, N_test).reshape(-1,1)\n\n    power_test = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds_test,\n        air_density=1.1,\n        yaw_angles=np.tile(yaw_angles_test, (3,1)),\n        power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((N_test*3, n_turbines)),\n        tilt_angles=np.tile(tilt_angles_nom, (3,1)),\n        tilt_interp=None\n    ).squeeze()\n\n    idx_mid = round((N_test-1)/2)\n    power_ratio_no_shear = power_test[:N_test] / power_test[idx_mid]\n    power_ratio_mid_shear = power_test[N_test:2*N_test] / power_test[idx_mid+N_test]\n    power_ratio_most_shear = power_test[2*N_test:] / power_test[idx_mid+2*N_test]\n\n    # Check symmetry of zero shear case\n    assert np.allclose(power_ratio_no_shear, power_ratio_no_shear[::-1])\n\n    # Check that shear ordering correct on the left\n    assert (power_ratio_no_shear[:idx_mid] >= power_ratio_mid_shear[:idx_mid]).all()\n    assert (power_ratio_mid_shear[:idx_mid] >= power_ratio_most_shear[:idx_mid]).all()\n\n    # And inverted on the right\n    assert (power_ratio_no_shear[idx_mid+1:] <= power_ratio_mid_shear[idx_mid+1:]).all()\n    assert (power_ratio_mid_shear[idx_mid+1:] <= power_ratio_most_shear[idx_mid+1:]).all()\n\ndef test_ControllerDependentTurbine_regression():\n    \"\"\"\n    Adding a regression test so that we can work with the model and stay confident that results\n    are not changing.\n    \"\"\"\n\n    n_turbines = 1\n    wind_speed = 10.0\n    turbine_data = SampleInputs().turbine\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"] = (\n        SampleInputs().controller_dependent_turbine_parameters\n    )\n    data_file_path = Path(__file__).resolve().parents[1] / \"floris\" / \"turbine_library\"\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"] = \\\n        np.load(\n            data_file_path / turbine_data[\"power_thrust_table\"]\n                                         [\"controller_dependent_turbine_parameters\"]\n                                         [\"cp_ct_data_file\"]\n        )\n\n    N_test = 20\n    tilt_angles_nom = turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((N_test, n_turbines))\n    power_setpoints_nom = POWER_SETPOINT_DEFAULT * np.ones((N_test, n_turbines))\n\n    yaw_max = 30 # Maximum yaw to test\n    yaw_angles_test = np.linspace(-yaw_max, yaw_max, N_test).reshape(-1,1)\n\n    power_base = np.array([\n        2395927.92868139,\n        2527726.50920564,\n        2644989.24683195,\n        2748134.16149699,\n        2837129.46422222,\n        2911510.74331788,\n        2971011.54743479,\n        3015566.03081713,\n        3045213.16926206,\n        3060014.98468406,\n        3060014.98468406,\n        3045213.16926206,\n        3015566.03081713,\n        2971011.54743479,\n        2911510.74331788,\n        2837129.46422222,\n        2748134.16149699,\n        2644989.24683195,\n        2527726.50920564,\n        2395927.92868139,\n    ])\n\n    thrust_coefficient_base = np.array([\n        0.65966861,\n        0.68401903,\n        0.70532378,\n        0.72373957,\n        0.73936337,\n        0.75223810,\n        0.76241954,\n        0.76997771,\n        0.77497954,\n        0.77746593,\n        0.77746593,\n        0.77497954,\n        0.76997771,\n        0.76241954,\n        0.75223810,\n        0.73936337,\n        0.72373957,\n        0.70532378,\n        0.68401903,\n        0.65966861,\n    ])\n\n    axial_induction_base = np.array([\n        0.20864674,\n        0.21929141,\n        0.22894655,\n        0.23757787,\n        0.24512918,\n        0.25152384,\n        0.25669950,\n        0.26061385,\n        0.26323979,\n        0.26455600,\n        0.26455600,\n        0.26323979,\n        0.26061385,\n        0.25669950,\n        0.25152384,\n        0.24512918,\n        0.23757787,\n        0.22894655,\n        0.21929141,\n        0.20864674,\n    ])\n\n    power = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((N_test, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1,\n        yaw_angles=yaw_angles_test,\n        power_setpoints=power_setpoints_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    ).squeeze()\n\n    thrust_coefficient = ControllerDependentTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((N_test, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1,\n        yaw_angles=yaw_angles_test,\n        power_setpoints=power_setpoints_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    ).squeeze()\n\n    axial_induction = ControllerDependentTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((N_test, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1,\n        yaw_angles=yaw_angles_test,\n        power_setpoints=power_setpoints_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    ).squeeze()\n\n    # print(power)\n    # print(thrust_coefficient)\n    # print(axial_induction)\n\n    assert np.allclose(power, power_base)\n    assert np.allclose(thrust_coefficient, thrust_coefficient_base)\n    assert np.allclose(axial_induction, axial_induction_base)\n\ndef test_ControllerDependentTurbine_integration():\n    \"\"\"\n    Test the ControllerDependentTurbine model with a range of wind speeds, and then\n    whether it works regardless of number of grid points.\n    \"\"\"\n\n    n_turbines = 1\n    turbine_data = SampleInputs().turbine\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"] = (\n        SampleInputs().controller_dependent_turbine_parameters\n    )\n    data_file_path = Path(__file__).resolve().parents[1] / \"floris\" / \"turbine_library\"\n    turbine_data[\"power_thrust_table\"][\"controller_dependent_turbine_parameters\"][\"cp_ct_data\"] = \\\n        np.load(\n            data_file_path / turbine_data[\"power_thrust_table\"]\n                                         [\"controller_dependent_turbine_parameters\"]\n                                         [\"cp_ct_data_file\"]\n        )\n\n    N_test = 6\n    tilt_angles_nom = turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((N_test, n_turbines))\n    power_setpoints_nom = POWER_SETPOINT_DEFAULT * np.ones((N_test, n_turbines))\n\n    # Check runs over a range of wind speeds\n    wind_speeds = np.linspace(1, 30, N_test)\n    wind_speeds = np.tile(wind_speeds[:,None,None,None], (1, 1, 3, 3))\n\n    power0 = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=0 * np.ones((N_test, n_turbines)),\n        power_setpoints=power_setpoints_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    ).squeeze()\n\n    power20 = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=20 * np.ones((N_test, n_turbines)),\n        power_setpoints=power_setpoints_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    ).squeeze()\n\n    assert (power0 - power20 >= -1e6).all()\n\n    # Won't compare; just checking runs as expected\n    ControllerDependentTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=0 * np.ones((N_test, n_turbines)),\n        power_setpoints=power_setpoints_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    ).squeeze()\n\n    ControllerDependentTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=20 * np.ones((N_test, n_turbines)),\n        power_setpoints=power_setpoints_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    ).squeeze()\n\n    # Try a set of wind speeds for 5 grid points; then 2; then a single grid point\n    # without any shear\n    N_test = 1\n    n_turbines = 1\n    tilt_angles_nom = turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((N_test, n_turbines))\n    power_setpoints_nom = POWER_SETPOINT_DEFAULT * np.ones((N_test, n_turbines))\n\n\n    wind_speeds = 10.0 * np.ones((N_test, n_turbines, 5, 5))\n    power5gp = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=0 * np.ones((N_test, n_turbines)),\n        power_setpoints=power_setpoints_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    ).squeeze()\n\n    wind_speeds = 10.0 * np.ones((N_test, n_turbines, 2, 2))\n    power2gp = ControllerDependentTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds,\n        air_density=1.1,\n        yaw_angles=0 * np.ones((N_test, n_turbines)),\n        power_setpoints=power_setpoints_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    ).squeeze()\n\n    assert np.allclose(power5gp, power2gp)\n\n    # No shear information for the TUM model to use\n    wind_speeds = 10.0 * np.ones((N_test, n_turbines, 1, 1))\n    with pytest.raises(ValueError):\n        ControllerDependentTurbine.power(\n            power_thrust_table=turbine_data[\"power_thrust_table\"],\n            velocities=wind_speeds,\n            air_density=1.1,\n            yaw_angles=0 * np.ones((N_test, n_turbines)),\n            power_setpoints=power_setpoints_nom,\n            tilt_angles=tilt_angles_nom,\n            tilt_interp=None\n        )\n\ndef test_CpCt_data_consistency():\n    \"\"\"\n    Test that the Cp/Ct data is consistent, within reason, with the \"normal\" data.\n\n    These tests currently do not pass, and the \"assert\" statements have been removed.\n    However, the code has been left in place to highlight the differences and leave room for\n    possibly updating the Cp/Ct data in future to match the reference power and thrust curves.\n    \"\"\"\n\n    n_turbines = 1\n    N_test = 6\n\n    wind_speeds = np.tile(\n        np.linspace(0, 30, N_test)[:, None, None, None],\n        (1, n_turbines, 3, 3)\n    )\n\n    # Check power, thrust, and axial induction for IEA 15MW, IEA 10MW, and NREL 5MW\n    for turbine in [\"iea_15MW\", \"iea_10MW\", \"nrel_5MW\"]:\n        # Get the turbine_data\n        yaml_file = Path(__file__).resolve().parent / \"data\" / \"input_full.yaml\"\n        fmodel = FlorisModel(configuration=yaml_file)\n        fmodel.set(turbine_type=[turbine])\n        power_thrust_table = fmodel.core.farm.turbine_map[0].power_thrust_table\n\n        tilt_angles_nom = power_thrust_table[\"ref_tilt\"] * np.ones((N_test, n_turbines))\n\n        power_base = SimpleTurbine.power(\n            power_thrust_table=power_thrust_table,\n            velocities=wind_speeds,\n            air_density=1.1,\n        ).squeeze()\n\n        power_test = ControllerDependentTurbine.power(\n            power_thrust_table=power_thrust_table,\n            velocities=wind_speeds,\n            air_density=1.1,\n            yaw_angles=np.zeros((N_test, n_turbines)),\n            tilt_angles=tilt_angles_nom,\n            power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((N_test, n_turbines))\n        ).squeeze()\n\n        thrust_coefficient_base = SimpleTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=wind_speeds,\n            air_density=1.1,\n        ).squeeze()\n\n        thrust_coefficient_test = ControllerDependentTurbine.thrust_coefficient(\n            power_thrust_table=power_thrust_table,\n            velocities=wind_speeds,\n            air_density=1.1,\n            yaw_angles=np.zeros((N_test, n_turbines)),\n            tilt_angles=tilt_angles_nom,\n            tilt_interp=None,\n            power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((N_test, n_turbines))\n        ).squeeze()\n\n        axial_induction_base = SimpleTurbine.axial_induction(\n            power_thrust_table=power_thrust_table,\n            velocities=wind_speeds,\n            air_density=1.1,\n        ).squeeze()\n\n        axial_induction_test = ControllerDependentTurbine.axial_induction(\n            power_thrust_table=power_thrust_table,\n            velocities=wind_speeds,\n            air_density=1.1,\n            yaw_angles=np.zeros((N_test, n_turbines)),\n            tilt_angles=tilt_angles_nom,\n            tilt_interp=None,\n            power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((N_test, n_turbines))\n        ).squeeze()\n\n        # Don't match below cut-in or above cut-out; this is known. Mask those out.\n        nonzero_power = power_base > 0\n\n        # Check within 5% of the base data (currently fails, \"asserts\" removed)\n        np.allclose(power_base[nonzero_power], power_test[nonzero_power], rtol=5e-2)\n        np.allclose(\n            thrust_coefficient_base[nonzero_power],\n            thrust_coefficient_test[nonzero_power],\n            rtol=5e-2\n        )\n        np.allclose(\n            axial_induction_base[nonzero_power],\n            axial_induction_test[nonzero_power],\n            rtol=5e-2\n        )\n\ndef test_CpCt_warning(caplog):\n    yaml_file = Path(__file__).resolve().parent / \"data\" / \"input_full.yaml\"\n    fmodel = FlorisModel(configuration=yaml_file)\n\n    with caplog.at_level(logging.WARNING):\n        fmodel.set_operation_model(\"controller-dependent\")\n    assert \"demonstration purposes only\" in caplog.text\n    caplog.clear()\n"
  },
  {
    "path": "tests/convert_v3_to_v4_test.py",
    "content": "import os\nfrom pathlib import Path\n\nimport floris\nfrom floris import FlorisModel\n\n\nCONVERT_FOLDER = Path(__file__).resolve().parent / \"v3_to_v4_convert_test\"\nFLORIS_FOLDER = Path(floris.__file__).resolve().parent\n\n\ndef test_v3_to_v4_convert():\n    # Note certain filenames\n    filename_v3_floris = \"gch.yaml\"\n    filename_v4_floris = \"gch_v4.yaml\"\n    filename_v3_turbine = \"nrel_5MW_v3.yaml\"\n    filename_v4_turbine = \"nrel_5MW_v3_v4.yaml\"\n\n    # Copy convert scripts from FLORIS_FOLDER to CONVERT_FOLDER\n    os.system(f\"cp {FLORIS_FOLDER / 'convert_turbine_v3_to_v4.py'} {CONVERT_FOLDER}\")\n    os.system(f\"cp {FLORIS_FOLDER / 'convert_floris_input_v3_to_v4.py'} {CONVERT_FOLDER}\")\n\n    # Change directory to the test folder\n    os.chdir(CONVERT_FOLDER)\n\n    # Run the converter on the turbine file\n    os.system(f\"python convert_turbine_v3_to_v4.py {filename_v3_turbine}\")\n\n    # Run the converter on the floris file\n    os.system(f\"python convert_floris_input_v3_to_v4.py {filename_v3_floris}\")\n\n    # Go through the file filename_v4_floris and replace f\"!include {filename_v3_turbine}\"\n    # with f\"!include {filename_v4_turbine}\"\n    with open(filename_v4_floris, \"r\") as file:\n        filedata = file.read()\n    filedata = filedata.replace(\n        f\"!include {filename_v3_turbine}\", f\"!include {filename_v4_turbine}\"\n    )\n    with open(filename_v4_floris, \"w\") as file:\n        file.write(filedata)\n\n    # Now confirm that the converted file can be loaded by FLORIS\n    fmodel = FlorisModel(filename_v4_floris)\n\n    # Now confirm this model runs\n    fmodel.run()\n\n    # Delete the newly created files to clean up\n    os.system(f\"rm {filename_v4_floris}\")\n    os.system(f\"rm {filename_v4_turbine}\")\n    os.system(\"rm convert_turbine_v3_to_v4.py\")\n    os.system(\"rm convert_floris_input_v3_to_v4.py\")\n"
  },
  {
    "path": "tests/core_unit_test.py",
    "content": "\nfrom pathlib import Path\n\nimport yaml\n\nfrom floris.core import (\n    Core,\n    Farm,\n    FlowField,\n    TurbineGrid,\n    WakeModelManager,\n)\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\nYAML_INPUT = TEST_DATA / \"input_full.yaml\"\nDICT_INPUT = yaml.load(open(YAML_INPUT, \"r\"), Loader=yaml.SafeLoader)\n\n\ndef test_read_yaml():\n    fmodel = Core.from_file(YAML_INPUT)\n    assert isinstance(fmodel, Core)\n\n\ndef test_read_dict():\n    fmodel = Core.from_dict(DICT_INPUT)\n    assert isinstance(fmodel, Core)\n\n\ndef test_init():\n    fmodel = Core.from_dict(DICT_INPUT)\n    assert isinstance(fmodel.farm, Farm)\n    assert isinstance(fmodel.wake, WakeModelManager)\n    assert isinstance(fmodel.flow_field, FlowField)\n\n\ndef test_asdict(turbine_grid_fixture: TurbineGrid):\n\n    floris = Core.from_dict(DICT_INPUT)\n    floris.flow_field.initialize_velocity_field(turbine_grid_fixture)\n    dict1 = floris.as_dict()\n\n    new_floris = Core.from_dict(dict1)\n    new_floris.flow_field.initialize_velocity_field(turbine_grid_fixture)\n    dict2 = new_floris.as_dict()\n\n    assert dict1 == dict2\n"
  },
  {
    "path": "tests/data/__init__.py",
    "content": ""
  },
  {
    "path": "tests/data/input_full.yaml",
    "content": "\nname: test_input\ndescription: Single turbine for testing\nfloris_version: v4\n\nlogging:\n  console:\n    enable: false\n    level: WARNING\n  file:\n    enable: false\n    level: WARNING\n\nsolver:\n  type: turbine_grid\n  turbine_grid_points: 3\n\nfarm:\n  layout_x:\n  - 0.0\n  layout_y:\n  - 0.0\n  turbine_type:\n  - nrel_5MW\n\nflow_field:\n  air_density: 1.225\n  reference_wind_height: 90.0\n  turbulence_intensities:\n  - 0.06\n  wind_directions:\n  - 270.0\n  wind_shear: 0.12\n  wind_speeds:\n  - 8.0\n  wind_veer: 0.0\n\nwake:\n  model_strings:\n    combination_model: sosfs\n    deflection_model: gauss\n    turbulence_model: crespo_hernandez\n    velocity_model: gauss\n\n  enable_secondary_steering: true\n  enable_yaw_added_recovery: true\n  enable_active_wake_mixing: true\n  enable_transverse_velocities: true\n\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n    turboparkgauss:\n      A: 0.04\n      include_mirror_wake: True\n\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.01\n      constant: 0.9\n      ai: 0.83\n      downstream: -0.25\n"
  },
  {
    "path": "tests/data/nrel_5MW_custom.yaml",
    "content": "turbine_type: 'nrel_5MW_custom'\nhub_height: 90.0\nrotor_diameter: 126.0\nTSR: 8.0\npower_thrust_table:\n  cosine_loss_exponent_yaw: 1.88\n  cosine_loss_exponent_tilt: 1.88\n  ref_air_density: 1.225\n  ref_tilt: 5.0\n  power:\n    - 0.0\n    - 0.0\n    - 40.518011517569214\n    - 177.67162506419703\n    - 403.900880943964\n    - 737.5889584824021\n    - 1187.1774030611875\n    - 1239.245945375778\n    - 1292.5184293723503\n    - 1347.3213147477102\n    - 1403.2573725578948\n    - 1460.7011898730707\n    - 1519.6419125979983\n    - 1580.174365096404\n    - 1642.1103166918167\n    - 1705.758292831\n    - 1771.1659528893977\n    - 2518.553107505315\n    - 3448.381605840943\n    - 3552.140809000129\n    - 3657.9545431794127\n    - 3765.121299313842\n    - 3873.928844315059\n    - 3984.4800226955504\n    - 4096.582833096852\n    - 4210.721306623712\n    - 4326.154305853405\n    - 4443.395565353604\n    - 4562.497934188341\n    - 4683.419890251577\n    - 4806.164748311019\n    - 4929.931918769215\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 5000.00\n    - 0.0\n    - 0.0\n  thrust_coefficient:\n    - 0.0\n    - 0.0\n    - 1.132034888\n    - 0.999470963\n    - 0.917697381\n    - 0.860849503\n    - 0.815371198\n    - 0.811614904\n    - 0.807939328\n    - 0.80443352\n    - 0.800993851\n    - 0.79768116\n    - 0.794529244\n    - 0.791495834\n    - 0.788560434\n    - 0.787217182\n    - 0.787127977\n    - 0.785839257\n    - 0.783812219\n    - 0.783568108\n    - 0.783328285\n    - 0.781194418\n    - 0.777292539\n    - 0.773464375\n    - 0.769690236\n    - 0.766001924\n    - 0.762348072\n    - 0.758760824\n    - 0.755242872\n    - 0.751792927\n    - 0.748434131\n    - 0.745113997\n    - 0.717806682\n    - 0.672204789\n    - 0.63831272\n    - 0.610176496\n    - 0.585456847\n    - 0.563222111\n    - 0.542912273\n    - 0.399312061\n    - 0.310517829\n    - 0.248633226\n    - 0.203543725\n    - 0.169616419\n    - 0.143478955\n    - 0.122938861\n    - 0.106515296\n    - 0.093026095\n    - 0.081648606\n    - 0.072197368\n    - 0.064388275\n    - 0.057782745\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.0\n    - 2.9\n    - 3.0\n    - 4.0\n    - 5.0\n    - 6.0\n    - 7.0\n    - 7.1\n    - 7.2\n    - 7.3\n    - 7.4\n    - 7.5\n    - 7.6\n    - 7.7\n    - 7.8\n    - 7.9\n    - 8.0\n    - 9.0\n    - 10.0\n    - 10.1\n    - 10.2\n    - 10.3\n    - 10.4\n    - 10.5\n    - 10.6\n    - 10.7\n    - 10.8\n    - 10.9\n    - 11.0\n    - 11.1\n    - 11.2\n    - 11.3\n    - 11.4\n    - 11.5\n    - 11.6\n    - 11.7\n    - 11.8\n    - 11.9\n    - 12.0\n    - 13.0\n    - 14.0\n    - 15.0\n    - 16.0\n    - 17.0\n    - 18.0\n    - 19.0\n    - 20.0\n    - 21.0\n    - 22.0\n    - 23.0\n    - 24.0\n    - 25.0\n    - 25.1\n    - 50.0\n"
  },
  {
    "path": "tests/data/wind_rose.csv",
    "content": "ws,wd,freq_val\n8,270,0.25\n9,270,0.25\n8,280,0.5\n"
  },
  {
    "path": "tests/data/wind_ti_rose.csv",
    "content": "ws,wd,ti,freq_val\n8,270,0.06,0.25\n9,270,0.06,0.25\n8,280,0.07,0.5\n"
  },
  {
    "path": "tests/data/wrg_test.wrg",
    "content": "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  61  76  220  54  74  220  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                   0      1000       0   90  9.6  2.31              0 12 116 107  341  86  93  228  61  76  220  54  74  220  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                   0      2000       0   90  9.7  2.36              0 12 116 106  409  86  93  228  61  76  220  54  74  220  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                1000         0       0   90  9.6  2.34              0 12 116 106  273  86  93  228  61  76  220  54  82  407  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                1000      1000       0   90  9.6  2.40              0 12 116 107  341  86  93  228  61  76  220  54  82  407  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n                1000      2000       0   90  9.7  2.46              0 12 116 106  409  86  93  228  61  76  220  54  82  407  66  79  220 121  98  244 177 107  279  84  89  232  43  70  195  36  75  188  53 100  201  98 111  267\n"
  },
  {
    "path": "tests/farm_unit_test.py",
    "content": "\nfrom copy import deepcopy\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom floris.core import Farm\nfrom floris.utilities import load_yaml\nfrom tests.conftest import (\n    N_FINDEX,\n    N_TURBINES,\n    SampleInputs,\n)\n\n\ndef test_farm_init_homogenous_turbines():\n    farm_data = SampleInputs().farm\n    turbine_data = SampleInputs().turbine\n\n    layout_x = farm_data[\"layout_x\"]\n    layout_y = farm_data[\"layout_y\"]\n    coordinates = np.array([\n        np.array([x, y, turbine_data[\"hub_height\"]])\n        for x, y in zip(layout_x, layout_y)\n    ])\n\n    farm = Farm(\n        layout_x=layout_x,\n        layout_y=layout_y,\n        turbine_type=[turbine_data]\n    )\n    # TODO: these all pass on mac and fail on linux\n    # turbine_type=[turbine_data]\n    # turbine_type=[turbine_data[\"turbine_type\"]]\n\n    farm.construct_hub_heights()\n    farm.set_yaw_angles_to_ref_yaw(N_FINDEX)\n\n    # Check initial values\n    np.testing.assert_array_equal(farm.coordinates, coordinates)\n    assert isinstance(farm.layout_x, np.ndarray)\n    assert isinstance(farm.layout_y, np.ndarray)\n\n\ndef test_asdict(sample_inputs_fixture: SampleInputs):\n    farm = Farm.from_dict(sample_inputs_fixture.farm)\n    farm.construct_hub_heights()\n    farm.construct_turbine_ref_tilts()\n    farm.set_yaw_angles_to_ref_yaw(N_FINDEX)\n    farm.set_tilt_to_ref_tilt(N_FINDEX)\n    farm.set_power_setpoints_to_ref_power(N_FINDEX)\n    farm.set_awc_modes_to_ref_mode(N_FINDEX)\n    farm.set_awc_amplitudes_to_ref_amp(N_FINDEX)\n    farm.set_awc_frequencies_to_ref_freq(N_FINDEX)\n    dict1 = farm.as_dict()\n\n    new_farm = farm.from_dict(dict1)\n    new_farm.construct_hub_heights()\n    new_farm.construct_turbine_ref_tilts()\n    new_farm.set_yaw_angles_to_ref_yaw(N_FINDEX)\n    new_farm.set_tilt_to_ref_tilt(N_FINDEX)\n    new_farm.set_power_setpoints_to_ref_power(N_FINDEX)\n    new_farm.set_awc_modes_to_ref_mode(N_FINDEX)\n    new_farm.set_awc_amplitudes_to_ref_amp(N_FINDEX)\n    new_farm.set_awc_frequencies_to_ref_freq(N_FINDEX)\n    dict2 = new_farm.as_dict()\n\n    assert dict1 == dict2\n\n\ndef test_check_turbine_type(sample_inputs_fixture: SampleInputs):\n    # 1 definition for multiple turbines in the farm\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    farm_data[\"turbine_type\"] = [\"nrel_5MW\"]\n    farm_data[\"layout_x\"] = np.arange(0, 500, 100)\n    farm_data[\"layout_y\"] = np.zeros(5)\n    farm = Farm.from_dict(farm_data)\n    assert len(farm.turbine_type) == 1\n    assert len(farm.turbine_definitions) == 5\n\n    # N definitions for M turbines\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    farm_data[\"turbine_type\"] = [\"nrel_5MW\", \"nrel_5MW\"]\n    farm_data[\"layout_x\"] = np.arange(0, 500, 100)\n    farm_data[\"layout_y\"] = np.zeros(5)\n    with pytest.raises(ValueError):\n        Farm.from_dict(farm_data)\n\n    # All list of strings from internal library\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    farm_data[\"turbine_type\"] = [\"nrel_5MW\", \"iea_10MW\", \"iea_15MW\", \"nrel_5MW\", \"nrel_5MW\"]\n    farm_data[\"layout_x\"] = np.arange(0, 500, 100)\n    farm_data[\"layout_y\"] = np.zeros(5)\n    farm = Farm.from_dict(farm_data)\n    assert len(farm.turbine_type) == 5\n    assert len(farm.turbine_definitions) == 5\n\n    # String not found in internal library\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    farm_data[\"turbine_type\"] = [\"asdf\"]\n    farm_data[\"layout_x\"] = np.arange(0, 500, 100)\n    farm_data[\"layout_y\"] = np.zeros(5)\n    with pytest.raises(FileNotFoundError):\n        Farm.from_dict(farm_data)\n\n    # All list of dicts from external library\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    external_library = Path(__file__).parent / \"data\"\n    turbine_def = load_yaml(external_library / \"nrel_5MW_custom.yaml\")\n    farm_data[\"turbine_type\"] = [turbine_def] * 5\n    farm_data[\"layout_x\"] = np.arange(0, 500, 100)\n    farm_data[\"layout_y\"] = np.zeros(5)\n    Farm.from_dict(farm_data)\n    assert len(farm.turbine_type) == 5\n    assert len(farm.turbine_definitions) == 5\n\n    # Check that error is correctly raised if two turbines have the same name\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    external_library = Path(__file__).parent / \"data\"\n    farm_data[\"layout_x\"] = np.arange(0, 500, 100)\n    farm_data[\"layout_y\"] = np.zeros(5)\n    turbine_def = load_yaml(external_library / \"nrel_5MW_custom.yaml\")\n    turbine_def_mod = deepcopy(turbine_def)\n    turbine_def_mod[\"hub_height\"] = 100.0 # Change the hub height of the last turbine\n    farm_data[\"turbine_type\"] = [turbine_def]*4 + [turbine_def_mod]\n    with pytest.raises(ValueError):\n        farm = Farm.from_dict(farm_data)\n    # Check this also raises an error in a nested level of the turbine definition\n    turbine_def_mod = deepcopy(turbine_def)\n    turbine_def_mod[\"power_thrust_table\"][\"wind_speed\"][-1] = -100.0\n    farm_data[\"turbine_type\"] = [turbine_def]*4 + [turbine_def_mod]\n    with pytest.raises(ValueError):\n        farm = Farm.from_dict(farm_data)\n\n    # Check that no error is raised, and the expected hub heights are seen,\n    # if turbine_type is correctly updated\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    external_library = Path(__file__).parent / \"data\"\n    farm_data[\"layout_x\"] = np.arange(0, 500, 100)\n    farm_data[\"layout_y\"] = np.zeros(5)\n    turbine_def = load_yaml(external_library / \"nrel_5MW_custom.yaml\")\n    turbine_def_mod = deepcopy(turbine_def)\n    turbine_def_mod[\"hub_height\"] = 100.0 # Change the hub height of the last turbine\n    turbine_def_mod[\"turbine_type\"] = \"nrel_5MW_custom_2\"\n    farm_data[\"turbine_type\"] = [turbine_def]*4 + [turbine_def_mod]\n    farm = Farm.from_dict(farm_data)\n    for i in range(4):\n        assert farm.turbine_definitions[i][\"hub_height\"] == turbine_def[\"hub_height\"]\n    assert farm.turbine_definitions[-1][\"hub_height\"] == 100.0\n    farm.construct_turbine_map()\n    for i in range(4):\n        assert farm.turbine_map[i].hub_height == turbine_def[\"hub_height\"]\n    assert farm.turbine_map[-1].hub_height == 100.0\n\n    # Duplicate type found in external and internal library\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    external_library = Path(__file__).parent / \"data\"\n    farm_data[\"turbine_library_path\"] = external_library\n    farm_data[\"turbine_type\"] = [\"nrel_5MW\"]\n    with pytest.raises(ValueError):\n        Farm.from_dict(farm_data)\n\n    # 1 turbine as string from internal library, 1 turbine as dict from external library\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    external_library = Path(__file__).parent / \"data\"\n    turbine_def = load_yaml(external_library / \"nrel_5MW_custom.yaml\")\n    farm_data[\"turbine_type\"] = [turbine_def] * 5\n    farm_data[\"layout_x\"] = np.arange(0, 500, 100)\n    farm_data[\"layout_y\"] = np.zeros(5)\n    farm_data[\"turbine_type\"] = [\"nrel_5MW\", turbine_def, \"nrel_5MW\", turbine_def, \"nrel_5MW\"]\n    Farm.from_dict(farm_data)\n    assert len(farm.turbine_type) == 5\n    assert len(farm.turbine_definitions) == 5\n\n    # 1 turbine as string from internal library, 1 turbine as string from external library\n    farm_data = deepcopy(sample_inputs_fixture.farm)\n    external_library = Path(__file__).parent / \"data\"\n    farm_data[\"turbine_library_path\"] = external_library\n    farm_data[\"turbine_type\"] = 4 * [\"iea_10MW\"] + [\"nrel_5MW_custom\"]\n    farm_data[\"layout_x\"] = np.arange(0, 500, 100)\n    farm_data[\"layout_y\"] = np.zeros(5)\n    Farm.from_dict(farm_data)\n    assert len(farm.turbine_type) == 5\n    assert len(farm.turbine_definitions) == 5\n\n\ndef test_farm_external_library(sample_inputs_fixture: SampleInputs):\n    external_library = Path(__file__).parent / \"data\"\n\n    # Demonstrate a passing case\n    farm_data = deepcopy(SampleInputs().farm)\n    farm_data[\"turbine_library_path\"] = external_library\n    farm_data[\"turbine_type\"] = [\"nrel_5MW_custom\"] * N_TURBINES\n    farm = Farm.from_dict(farm_data)\n    assert farm.turbine_library_path == external_library\n\n    # Demonstrate a file not existing in the user library, but exists in the internal library, so\n    # the loading is successful\n    farm_data[\"turbine_library_path\"] = external_library\n    farm_data[\"turbine_type\"] = [\"iea_10MW\"] * N_TURBINES\n    farm = Farm.from_dict(farm_data)\n    assert farm.turbine_definitions[0][\"turbine_type\"] == \"iea_10MW\"\n\n    # Demonstrate a failing case with an incorrect library location\n    farm_data[\"turbine_library_path\"] = external_library / \"turbine_library_path\"\n    with pytest.raises(FileExistsError):\n        Farm.from_dict(farm_data)\n\n    # Demonstrate a failing case where there is a duplicated turbine between the internal\n    # and external turbine libraries\n    farm_data = deepcopy(SampleInputs().farm)\n    farm_data[\"turbine_library_path\"] = external_library\n    farm_data[\"turbine_type\"] = [\"nrel_5MW\"] * N_TURBINES\n    with pytest.raises(ValueError):\n        Farm.from_dict(farm_data)\n\n    # Demonstrate a failing case where there a turbine does not exist in either\n    farm_data = deepcopy(SampleInputs().farm)\n    farm_data[\"turbine_library_path\"] = external_library\n    farm_data[\"turbine_type\"] = [\"FAKE_TURBINE\"] * N_TURBINES\n    with pytest.raises(FileNotFoundError):\n        Farm.from_dict(farm_data)\n"
  },
  {
    "path": "tests/floris_model_integration_test.py",
    "content": "import logging\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\nimport yaml\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n)\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT, POWER_SETPOINT_DISABLED\nfrom tests.conftest import SampleInputs\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\nYAML_INPUT = TEST_DATA / \"input_full.yaml\"\n\n\ndef test_default_init():\n    # Test getting the default dict\n    defaults = FlorisModel.get_defaults()\n    fmodel1 = FlorisModel(defaults)\n    assert isinstance(fmodel1, FlorisModel)\n\n    # Test that there are no side effects from changing the default dict\n    defaults2 = FlorisModel.get_defaults()\n    defaults2[\"farm\"][\"layout_x\"] = [0, 1000]\n    defaults2[\"farm\"][\"layout_y\"] = [0, 0]\n    fmodel2 = FlorisModel(defaults2)\n    assert fmodel2.core.as_dict() != FlorisModel(defaults).core.as_dict()\n\n    # Test using the \"default\" string\n    # This checks that the init works and that the default dictionary hasn't changed\n    fmodel3 = FlorisModel(\"defaults\")\n    assert fmodel1.core.as_dict() == fmodel3.core.as_dict()\n\ndef test_read_yaml():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    assert isinstance(fmodel, FlorisModel)\n\ndef test_assign_setpoints():\n\n    fmodel =  FlorisModel(configuration=YAML_INPUT)\n    fmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n\n    # Test setting yaw angles via a list, integers, numpy array\n    fmodel.set(yaw_angles=[[20.0, 30.0]])\n    fmodel.set(yaw_angles=[[20, 30]])\n    fmodel.set(yaw_angles=np.array([[20.0, 30.0]]))\n\n    # Test setting power setpoints in various ways\n    fmodel.set(power_setpoints=[[1e6, 2e6]])\n    fmodel.set(power_setpoints=np.array([[1e6, 2e6]]))\n\n    # Disable turbines\n    fmodel.set(disable_turbines=[[True, False]])\n    fmodel.set(disable_turbines=np.array([[True, False]]))\n\n    # Combination\n    fmodel.set(yaw_angles=[[0, 30]], power_setpoints=np.array([[1e6, None]]))\n\n    # power_setpoints and disable_turbines (disable_turbines overrides power_setpoints)\n    fmodel.set(power_setpoints=[[1e6, 2e6]], disable_turbines=[[True, False]])\n    assert np.allclose(fmodel.core.farm.power_setpoints, np.array([[POWER_SETPOINT_DISABLED, 2e6]]))\n\n    # Setting sequentially is equivalent to setting together\n    fmodel.reset_operation()\n    fmodel.set(disable_turbines=[[True, False]])\n    fmodel.set(yaw_angles=[[0, 30]])\n    assert np.allclose(\n        fmodel.core.farm.power_setpoints,\n        np.array([[POWER_SETPOINT_DISABLED, POWER_SETPOINT_DEFAULT]])\n    )\n    assert np.allclose(fmodel.core.farm.yaw_angles, np.array([[0, 30]]))\n\n    fmodel.set(disable_turbines=[[True, False]], yaw_angles=[[0, 30]])\n    assert np.allclose(\n        fmodel.core.farm.power_setpoints,\n        np.array([[POWER_SETPOINT_DISABLED, POWER_SETPOINT_DEFAULT]])\n    )\n    assert np.allclose(fmodel.core.farm.yaw_angles, np.array([[0, 30]]))\n\ndef test_set_run():\n    \"\"\"\n    These tests are designed to test the set / run sequence to ensure that inputs are\n    set when they should be, not set when they shouldn't be, and that the run sequence\n    retains or resets information as intended.\n    \"\"\"\n\n    # In FLORIS v3.2, running calculate_wake twice incorrectly set the yaw angles when the\n    # first time has non-zero yaw settings but the second run had all-zero yaw settings.\n    # The test below asserts that the yaw angles are correctly set in subsequent calls to run.\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    yaw_angles = 20 * np.ones((fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines))\n    fmodel.set(yaw_angles=yaw_angles)\n    fmodel.run()\n    assert fmodel.core.farm.yaw_angles == yaw_angles\n\n    yaw_angles = np.zeros((fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines))\n    fmodel.set(yaw_angles=yaw_angles)\n    fmodel.run()\n    assert fmodel.core.farm.yaw_angles == yaw_angles\n\n    # Verify making changes to the layout, wind speed, wind direction  and\n    # turbulence intensity both before and after running the calculation\n    fmodel.reset_operation()\n    fmodel.set(\n        layout_x=[0, 0],\n        layout_y=[0, 1000],\n        wind_speeds=[8, 8],\n        wind_directions=[270, 270],\n        turbulence_intensities=[0.06, 0.06]\n    )\n    assert np.array_equal(fmodel.core.farm.layout_x, np.array([0, 0]))\n    assert np.array_equal(fmodel.core.farm.layout_y, np.array([0, 1000]))\n    assert np.array_equal(fmodel.core.flow_field.wind_speeds, np.array([8, 8]))\n    assert np.array_equal(fmodel.core.flow_field.wind_directions, np.array([270, 270]))\n\n    # Double check that nothing has changed after running the calculation\n    fmodel.run()\n    assert np.array_equal(fmodel.core.farm.layout_x, np.array([0, 0]))\n    assert np.array_equal(fmodel.core.farm.layout_y, np.array([0, 1000]))\n    assert np.array_equal(fmodel.core.flow_field.wind_speeds, np.array([8, 8]))\n    assert np.array_equal(fmodel.core.flow_field.wind_directions, np.array([270, 270]))\n\n    # Verify that changing wind shear doesn't change the other settings above\n    fmodel.set(wind_shear=0.1)\n    assert fmodel.core.flow_field.wind_shear == 0.1\n    assert np.array_equal(fmodel.core.farm.layout_x, np.array([0, 0]))\n    assert np.array_equal(fmodel.core.farm.layout_y, np.array([0, 1000]))\n    assert np.array_equal(fmodel.core.flow_field.wind_speeds, np.array([8, 8]))\n    assert np.array_equal(fmodel.core.flow_field.wind_directions, np.array([270, 270]))\n\n    # Verify that operation set-points are retained after changing other settings\n    yaw_angles = 20 * np.ones((fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines))\n    fmodel.set(yaw_angles=yaw_angles)\n    assert np.array_equal(fmodel.core.farm.yaw_angles, yaw_angles)\n    fmodel.set()\n    assert np.array_equal(fmodel.core.farm.yaw_angles, yaw_angles)\n    fmodel.set(wind_speeds=[10, 10])\n    assert np.array_equal(fmodel.core.farm.yaw_angles, yaw_angles)\n    power_setpoints = 1e6 * np.ones((fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines))\n    fmodel.set(power_setpoints=power_setpoints)\n    assert np.array_equal(fmodel.core.farm.yaw_angles, yaw_angles)\n    assert np.array_equal(fmodel.core.farm.power_setpoints, power_setpoints)\n\n    # Test that setting power setpoints through the .set() function actually sets the\n    # power setpoints in the floris object\n    fmodel.reset_operation()\n    power_setpoints = 1e6 * np.ones((fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines))\n    fmodel.set(power_setpoints=power_setpoints)\n    fmodel.run()\n    assert np.array_equal(fmodel.core.farm.power_setpoints, power_setpoints)\n\n    # Similar to above, any \"None\" set-points should be set to the default value\n    power_setpoints = np.array([[1e6, None]])\n    fmodel.set(layout_x=[0, 0], layout_y=[0, 1000], power_setpoints=power_setpoints)\n    fmodel.run()\n    assert np.array_equal(\n        fmodel.core.farm.power_setpoints,\n        np.array([[power_setpoints[0, 0], POWER_SETPOINT_DEFAULT]])\n    )\n\ndef test_reset_operation():\n    # Calling the reset function should reset the power setpoints to the default values\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    yaw_angles = 20 * np.ones((fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines))\n    power_setpoints = 1e6 * np.ones((fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines))\n    fmodel.set(power_setpoints=power_setpoints, yaw_angles=yaw_angles)\n    fmodel.run()\n    fmodel.reset_operation()\n    assert fmodel.core.farm.yaw_angles == np.zeros(\n        (fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines)\n    )\n    assert fmodel.core.farm.power_setpoints == (\n        POWER_SETPOINT_DEFAULT * np.ones((fmodel.core.flow_field.n_findex,\n                                          fmodel.core.farm.n_turbines))\n    )\n\n    # Double check that running the calculate also doesn't change the operating set points\n    fmodel.run()\n    assert fmodel.core.farm.yaw_angles == np.zeros(\n        (fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines)\n    )\n    assert fmodel.core.farm.power_setpoints == (\n        POWER_SETPOINT_DEFAULT * np.ones((fmodel.core.flow_field.n_findex,\n                                          fmodel.core.farm.n_turbines))\n    )\n\ndef test_run_no_wake():\n    # In FLORIS v3.2, running calculate_no_wake twice incorrectly set the yaw angles when the first\n    # time has non-zero yaw settings but the second run had all-zero yaw settings. The test below\n    # asserts that the yaw angles are correctly set in subsequent calls to run_no_wake.\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    yaw_angles = 20 * np.ones((fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines))\n    fmodel.set(yaw_angles=yaw_angles)\n    fmodel.run_no_wake()\n    assert fmodel.core.farm.yaw_angles == yaw_angles\n\n    yaw_angles = np.zeros((fmodel.core.flow_field.n_findex, fmodel.core.farm.n_turbines))\n    fmodel.set(yaw_angles=yaw_angles)\n    fmodel.run_no_wake()\n    assert fmodel.core.farm.yaw_angles == yaw_angles\n\n    # With no wake and three turbines in a line, the power for all turbines with zero yaw\n    # should be the same\n    fmodel.reset_operation()\n    fmodel.set(layout_x=[0, 200, 4000], layout_y=[0, 0, 0])\n    fmodel.run_no_wake()\n    power_no_wake = fmodel.get_turbine_powers()\n    assert len(np.unique(power_no_wake)) == 1\n\ndef test_get_turbine_powers():\n    # Get turbine powers should return n_findex x n_turbine powers\n    # Apply the same wind speed and direction multiple times and confirm all equal\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 8.0, 8.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    turbulence_intensities = np.array([0.06, 0.06, 0.06])\n    n_findex = len(wind_directions)\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n    n_turbines = len(layout_x)\n\n    fmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=layout_x,\n        layout_y=layout_y,\n    )\n\n    fmodel.run()\n\n    turbine_powers = fmodel.get_turbine_powers()\n\n    assert turbine_powers.shape[0] == n_findex\n    assert turbine_powers.shape[1] == n_turbines\n    assert turbine_powers[0, 0] == turbine_powers[1, 0]\n\ndef test_get_farm_power():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 8.0, 8.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    turbulence_intensities = np.array([0.06, 0.06, 0.06])\n    n_findex = len(wind_directions)\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n    # n_turbines = len(layout_x)\n\n    fmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=layout_x,\n        layout_y=layout_y,\n    )\n\n    fmodel.run()\n\n    turbine_powers = fmodel.get_turbine_powers()\n    farm_powers = fmodel.get_farm_power()\n\n    assert farm_powers.shape[0] == n_findex\n\n    # Assert farm power is the same as summing turbine powers\n    # over the turbine axis\n    farm_power_from_turbine = turbine_powers.sum(axis=1)\n    np.testing.assert_almost_equal(farm_power_from_turbine, farm_powers)\n\n    # Test using weights to disable the second turbine\n    turbine_weights = np.array([1.0, 0.0])\n    farm_powers = fmodel.get_farm_power(turbine_weights=turbine_weights)\n\n    # Assert farm power is now equal to the 0th turbine since 1st is\n    # disabled\n    farm_power_from_turbine = turbine_powers[:, 0]\n    np.testing.assert_almost_equal(farm_power_from_turbine, farm_powers)\n\n    # Finally, test using weights only disable the 1 turbine on the final\n    # findex values\n    turbine_weights = np.array([[1.0, 1.0], [1.0, 1.0], [1.0, 0.0]])\n\n    farm_powers = fmodel.get_farm_power(turbine_weights=turbine_weights)\n    turbine_powers[-1, 1] = 0\n    farm_power_from_turbine = turbine_powers.sum(axis=1)\n    np.testing.assert_almost_equal(farm_power_from_turbine, farm_powers)\n\ndef test_disable_turbines():\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    # Set to mixed turbine model\n    with open(\n        str(\n            fmodel.core.as_dict()[\"farm\"][\"turbine_library_path\"]\n            / (fmodel.core.as_dict()[\"farm\"][\"turbine_type\"][0] + \".yaml\")\n        )\n    ) as t:\n        turbine_type = yaml.safe_load(t)\n    turbine_type[\"operation_model\"] = \"mixed\"\n    fmodel.set(turbine_type=[turbine_type])\n\n    # Init to n-findex = 2, n_turbines = 3\n    fmodel.set(\n        wind_speeds=np.array([8.,8.,]),\n        wind_directions=np.array([270.,270.]),\n        turbulence_intensities=np.array([0.06,0.06]),\n        layout_x = [0,1000,2000],\n        layout_y=[0,0,0]\n    )\n\n    # Confirm that using a disable value with wrong n_findex raises error\n    with pytest.raises(ValueError):\n        fmodel.set(disable_turbines=np.zeros((10, 3), dtype=bool))\n        fmodel.run()\n\n    # Confirm that using a disable value with wrong n_turbines raises error\n    with pytest.raises(ValueError):\n        fmodel.set(disable_turbines=np.zeros((2, 10), dtype=bool))\n        fmodel.run()\n\n    # Confirm that if all turbines are disabled, power is near 0 for all turbines\n    fmodel.set(disable_turbines=np.ones((2, 3), dtype=bool))\n    fmodel.run()\n    turbines_powers = fmodel.get_turbine_powers()\n    np.testing.assert_allclose(turbines_powers, 0, atol=0.1)\n\n    # Confirm the same for run_no_wake\n    fmodel.run_no_wake()\n    turbines_powers = fmodel.get_turbine_powers()\n    np.testing.assert_allclose(turbines_powers, 0, atol=0.1)\n\n    # Confirm that if all disabled values set to false, equivalent to running normally\n    fmodel.reset_operation()\n    fmodel.run()\n    turbines_powers_normal = fmodel.get_turbine_powers()\n    fmodel.set(disable_turbines=np.zeros((2, 3), dtype=bool))\n    fmodel.run()\n    turbines_powers_false_disable = fmodel.get_turbine_powers()\n    np.testing.assert_allclose(turbines_powers_normal,turbines_powers_false_disable,atol=0.1)\n\n    # Confirm the same for run_no_wake\n    fmodel.run_no_wake()\n    turbines_powers_normal = fmodel.get_turbine_powers()\n    fmodel.set(disable_turbines=np.zeros((2, 3), dtype=bool))\n    fmodel.run_no_wake()\n    turbines_powers_false_disable = fmodel.get_turbine_powers()\n    np.testing.assert_allclose(turbines_powers_normal,turbines_powers_false_disable,atol=0.1)\n\n    # Confirm the shutting off the middle turbine is like removing from the layout\n    # In terms of impact on third turbine\n    disable_turbines = np.zeros((2, 3), dtype=bool)\n    disable_turbines[:,1] = [True, True]\n    fmodel.set(disable_turbines=disable_turbines)\n    fmodel.run()\n    power_with_middle_disabled = fmodel.get_turbine_powers()\n\n    # Two turbine case to compare against above\n    fmodel_remove_middle = fmodel.copy()\n    fmodel_remove_middle.set(layout_x=[0,2000], layout_y=[0, 0])\n    fmodel_remove_middle.run()\n    power_with_middle_removed = fmodel_remove_middle.get_turbine_powers()\n\n    np.testing.assert_almost_equal(power_with_middle_disabled[0,2], power_with_middle_removed[0,1])\n    np.testing.assert_almost_equal(power_with_middle_disabled[1,2], power_with_middle_removed[1,1])\n\n    # Check that yaw angles are correctly set when turbines are disabled\n    fmodel.set(\n        layout_x=[0, 1000, 2000],\n        layout_y=[0, 0, 0],\n        disable_turbines=disable_turbines,\n        yaw_angles=np.ones((2, 3))\n    )\n    fmodel.run()\n    assert (fmodel.core.farm.yaw_angles == np.array([[1.0, 0.0, 1.0], [1.0, 0.0, 1.0]])).all()\n\ndef test_get_farm_aep(caplog):\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 8.0, 8.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    turbulence_intensities = np.array([0.06, 0.06, 0.06])\n    n_findex = len(wind_directions)\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n    # n_turbines = len(layout_x)\n\n    fmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=layout_x,\n        layout_y=layout_y,\n    )\n\n    fmodel.run()\n\n    farm_powers = fmodel.get_farm_power()\n\n    # Start with uniform frequency\n    freq = np.ones(n_findex)\n    freq = freq / np.sum(freq)\n\n    # Check warning raised if freq not passed; no warning if freq passed\n    with caplog.at_level(logging.WARNING):\n        fmodel.get_farm_AEP()\n    assert caplog.text != \"\" # Checking not empty\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        fmodel.get_farm_AEP(freq=freq)\n    assert caplog.text == \"\" # Checking empty\n\n    farm_aep = fmodel.get_farm_AEP(freq=freq)\n\n    aep = np.sum(np.multiply(freq, farm_powers) * 365 * 24)\n\n    # In this case farm_aep should match farm powers\n    np.testing.assert_allclose(farm_aep, aep)\n\n    # Also check get_expected_farm_power\n    expected_farm_power = fmodel.get_expected_farm_power(freq=freq)\n    np.testing.assert_allclose(expected_farm_power, aep / (365 * 24))\n\ndef test_expected_farm_power_regression():\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 8.0, 8.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    turbulence_intensities = np.array([0.06, 0.06, 0.06])\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n\n    fmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=layout_x,\n        layout_y=layout_y,\n    )\n\n    fmodel.run()\n\n    expected_farm_power = fmodel.get_expected_farm_power()\n\n    # Assert the expected farm power has not inadvetently changed\n    np.testing.assert_allclose(expected_farm_power, 3507908.918358342, atol=1e-1)\n\ndef test_expected_farm_power_equals_sum_of_expected_turbine_powers():\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 8.0, 8.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    turbulence_intensities = np.array([0.06, 0.06, 0.06])\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n\n    fmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=layout_x,\n        layout_y=layout_y,\n    )\n\n    fmodel.run()\n\n    expected_farm_power = fmodel.get_expected_farm_power()\n    expected_turbine_powers = fmodel.get_expected_turbine_powers()\n\n    # Assert the expected farm power is the sum of the expected turbine powers\n    np.testing.assert_allclose(expected_farm_power, np.sum(expected_turbine_powers))\n\ndef test_expected_farm_value_regression():\n\n    # Ensure this calculation hasn't changed unintentionally\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 8.0, 9.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    values = np.array([30.0, 20.0, 10.0])\n    time_series = TimeSeries(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.06,\n        values=values,\n    )\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n    fmodel.set(layout_x=layout_x, layout_y=layout_y, wind_data=time_series)\n    fmodel.run()\n\n    expected_farm_value = fmodel.get_expected_farm_value()\n    assert np.allclose(expected_farm_value,75108001.05154414 , atol=1e-1)\n\ndef test_get_farm_avp(caplog):\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([7.0, 8.0, 9.0])\n    wind_directions = np.array([260.0, 270.0, 280.0])\n    turbulence_intensities = np.array([0.07, 0.06, 0.05])\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n    # n_turbines = len(layout_x)\n\n    fmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=layout_x,\n        layout_y=layout_y,\n    )\n\n    fmodel.run()\n\n    farm_powers = fmodel.get_farm_power()\n\n    # Define frequencies\n    freq = np.array([0.25, 0.5, 0.25])\n\n    # Define values of energy produced (e.g., price per MWh)\n    values = np.array([30.0, 20.0, 10.0])\n\n    # Check warning raised if values not passed; no warning if values passed\n    with caplog.at_level(logging.WARNING):\n        fmodel.get_farm_AVP(freq=freq)\n    assert caplog.text != \"\" # Checking not empty\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        fmodel.get_farm_AVP(freq=freq, values=values)\n    assert caplog.text == \"\" # Checking empty\n\n    # Check that AVP is equivalent to AEP when values not passed\n    farm_aep = fmodel.get_farm_AEP(freq=freq)\n    farm_avp = fmodel.get_farm_AVP(freq=freq)\n\n    np.testing.assert_allclose(farm_avp, farm_aep)\n\n    # Now check that AVP is what we expect when values passed\n    farm_avp = fmodel.get_farm_AVP(freq=freq,values=values)\n\n    farm_values = np.multiply(values, farm_powers)\n    avp = np.sum(np.multiply(freq, farm_values) * 365 * 24)\n\n    np.testing.assert_allclose(farm_avp, avp)\n\n    # Also check get_expected_farm_value\n    expected_farm_power = fmodel.get_expected_farm_value(freq=freq, values=values)\n    np.testing.assert_allclose(expected_farm_power, avp / (365 * 24))\n\ndef test_set_ti():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    # Set wind directions, wind speeds and turbulence intensities with n_findex = 3\n    fmodel.set(\n        wind_speeds=[8.0, 8.0, 8.0],\n        wind_directions=[240.0, 250.0, 260.0],\n        turbulence_intensities=[0.1, 0.1, 0.1],\n    )\n\n    # Confirm can change turbulence intensities if not changing the length of the array\n    fmodel.set(turbulence_intensities=[0.12, 0.12, 0.12])\n\n    # Confirm that changes to wind speeds and directions without changing turbulence intensities\n    # raises an error\n    with pytest.raises(ValueError):\n        fmodel.set(\n            wind_speeds=[8.0, 8.0, 8.0, 8.0],\n            wind_directions=[240.0, 250.0, 260.0, 270.0],\n        )\n\n    # Changing the length of TI alone is not allowed\n    with pytest.raises(ValueError):\n        fmodel.set(turbulence_intensities=[0.12])\n\n    # Test that applying a float however raises an error\n    with pytest.raises(TypeError):\n        fmodel.set(turbulence_intensities=0.12)\n\ndef test_calculate_planes(caplog):\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    # The calculate_plane functions should run directly with the inputs as given\n    fmodel.calculate_horizontal_plane(90.0)\n    fmodel.calculate_y_plane(0.0)\n    fmodel.calculate_cross_plane(500.0)\n\n    # No longer support setting new wind conditions, must be done with set()\n    fmodel.set(\n        wind_speeds = [8.0, 8.0, 8.0],\n        wind_directions = [270.0, 270.0, 270.0],\n        turbulence_intensities = [0.1, 0.1, 0.1],\n    )\n    fmodel.calculate_horizontal_plane(\n        90.0,\n        findex_for_viz=1\n    )\n    fmodel.calculate_y_plane(\n        0.0,\n        findex_for_viz=1\n    )\n    fmodel.calculate_cross_plane(\n        500.0,\n        findex_for_viz=1\n    )\n\n    # Without specifying findex_for_viz should raise a logger warning.\n    with caplog.at_level(logging.WARNING):\n        fmodel.calculate_horizontal_plane(90.0)\n    assert caplog.text != \"\" # Checking not empty\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        fmodel.calculate_y_plane(0.0)\n    assert caplog.text != \"\" # Checking not empty\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        fmodel.calculate_cross_plane(500.0)\n    assert caplog.text != \"\" # Checking not empty\n\ndef test_get_turbine_powers_with_WindRose():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 10.0, 12.0, 8.0, 10.0, 12.0])\n    wind_directions = np.array([270.0, 270.0, 270.0, 280.0, 280.0, 280.0])\n    turbulence_intensities = 0.06 * np.ones_like(wind_speeds)\n\n    fmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=[0, 1000, 2000, 3000],\n        layout_y=[0, 0, 0, 0]\n    )\n    fmodel.run()\n    turbine_powers_simple = fmodel.get_turbine_powers()\n\n    # Now declare a WindRose with 2 wind directions and 3 wind speeds\n    # uniform TI and frequency\n    wind_rose = WindRose(\n        wind_directions=np.unique(wind_directions),\n        wind_speeds=np.unique(wind_speeds),\n        ti_table=0.06\n    )\n\n    # Set this wind rose, run\n    fmodel.set(wind_data=wind_rose)\n    fmodel.run()\n\n    # Get the turbine powers in the wind rose\n    turbine_powers_windrose = fmodel.get_turbine_powers()\n\n    # Turbine power should have shape (n_wind_directions, n_wind_speeds, n_turbines)\n    assert turbine_powers_windrose.shape == (2, 3, 4)\n    assert np.allclose(turbine_powers_simple.reshape(2, 3, 4), turbine_powers_windrose)\n    assert np.allclose(turbine_powers_simple, turbine_powers_windrose.reshape(2*3, 4))\n\n    # Test that if certain combinations in the wind rose have 0 frequency, the power in\n    # those locations is nan\n    wind_rose = WindRose(\n        wind_directions = np.array([270.0, 280.0]),\n        wind_speeds = np.array([8.0, 10.0, 12.0]),\n        ti_table=0.06,\n        freq_table=np.array([[0.25, 0.25, 0.0], [0.0, 0.0, 0.5]])\n    )\n    fmodel.set(wind_data=wind_rose)\n    fmodel.run()\n    turbine_powers = fmodel.get_turbine_powers()\n    assert np.isnan(turbine_powers[0, 2, 0])\n\ndef test_get_powers_with_wind_data():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 10.0, 12.0, 8.0, 10.0, 12.0])\n    wind_directions = np.array([270.0, 270.0, 270.0, 280.0, 280.0, 280.0])\n    turbulence_intensities = 0.06 * np.ones_like(wind_speeds)\n\n    fmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=[0, 1000, 2000, 3000],\n        layout_y=[0, 0, 0, 0]\n    )\n    fmodel.run()\n    farm_power_simple = fmodel.get_farm_power()\n\n    # Now declare a WindRose with 2 wind directions and 3 wind speeds\n    # uniform TI and frequency\n    wind_rose = WindRose(\n        wind_directions=np.unique(wind_directions),\n        wind_speeds=np.unique(wind_speeds),\n        ti_table=0.06\n    )\n\n    # Set this wind rose, run\n    fmodel.set(wind_data=wind_rose)\n    fmodel.run()\n\n    farm_power_windrose = fmodel.get_farm_power()\n\n    # Check dimensions and that the farm power is the sum of the turbine powers\n    assert farm_power_windrose.shape == (2, 3)\n    assert np.allclose(farm_power_windrose, fmodel.get_turbine_powers().sum(axis=2))\n\n    # Check that simple and windrose powers are consistent\n    assert np.allclose(farm_power_simple.reshape(2, 3), farm_power_windrose)\n    assert np.allclose(farm_power_simple, farm_power_windrose.flatten())\n\n    # Test that if the last turbine's weight is set to 0, the farm power is the same as the\n    # sum of the first 3 turbines\n    turbine_weights = np.array([1.0, 1.0, 1.0, 0.0])\n    farm_power_weighted = fmodel.get_farm_power(turbine_weights=turbine_weights)\n\n    assert np.allclose(farm_power_weighted, fmodel.get_turbine_powers()[:,:,:-1].sum(axis=2))\n\ndef test_get_and_set_param():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    # Get the wind speed\n    wind_speeds = fmodel.get_param(['flow_field', 'wind_speeds'])\n    assert wind_speeds[0] == 8.0\n\n    # Set the wind speed\n    fmodel.set_param(['flow_field', 'wind_speeds'], 10.0, param_idx=0)\n    wind_speed = fmodel.get_param(['flow_field', 'wind_speeds'], param_idx=0  )\n    assert wind_speed == 10.0\n\n    # Repeat with wake parameter\n    fmodel.set_param(['wake', 'wake_velocity_parameters', 'gauss', 'alpha'], 0.1)\n    alpha = fmodel.get_param(['wake', 'wake_velocity_parameters', 'gauss', 'alpha'])\n    assert alpha == 0.1\n\ndef test_get_operation_model():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    assert fmodel.get_operation_model() == \"cosine-loss\"\n\ndef test_set_operation_model():\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    fmodel.set_operation_model(\"simple-derating\")\n    assert fmodel.get_operation_model() == \"simple-derating\"\n\n    reference_wind_height = fmodel.reference_wind_height\n\n    # Check multiple turbine types works\n    fmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    fmodel.set_operation_model([\"simple-derating\", \"cosine-loss\"])\n    assert fmodel.get_operation_model() == [\"simple-derating\", \"cosine-loss\"]\n\n    # Check that setting a single turbine type, and then altering the operation model works\n    fmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    fmodel.set(turbine_type=[\"nrel_5MW\"], reference_wind_height=reference_wind_height)\n    fmodel.set_operation_model(\"simple-derating\")\n    assert fmodel.get_operation_model() == \"simple-derating\"\n\n    # Check that setting over mutliple turbine types works\n    fmodel.set(turbine_type=[\"nrel_5MW\", \"iea_15MW\"], reference_wind_height=reference_wind_height)\n    fmodel.set_operation_model(\"simple-derating\")\n    assert fmodel.get_operation_model() == \"simple-derating\"\n    fmodel.set_operation_model([\"simple-derating\", \"cosine-loss\"])\n    assert fmodel.get_operation_model() == [\"simple-derating\", \"cosine-loss\"]\n\n    # Check setting over single turbine type; then updating layout works\n    fmodel.set(turbine_type=[\"nrel_5MW\"], reference_wind_height=reference_wind_height)\n    fmodel.set_operation_model(\"simple-derating\")\n    fmodel.set(layout_x=[0, 0, 0], layout_y=[0, 1000, 2000])\n    assert fmodel.get_operation_model() == \"simple-derating\"\n\n    # Check that setting for multiple turbine types and then updating layout breaks\n    fmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    fmodel.set(turbine_type=[\"nrel_5MW\"], reference_wind_height=reference_wind_height)\n    fmodel.set_operation_model([\"simple-derating\", \"cosine-loss\"])\n    assert fmodel.get_operation_model() == [\"simple-derating\", \"cosine-loss\"]\n    with pytest.raises(ValueError):\n        fmodel.set(layout_x=[0, 0, 0], layout_y=[0, 1000, 2000])\n\n    # Check one more variation\n    fmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    fmodel.set(turbine_type=[\"nrel_5MW\", \"iea_15MW\"], reference_wind_height=reference_wind_height)\n    fmodel.set_operation_model(\"simple-derating\")\n    fmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    with pytest.raises(ValueError):\n        fmodel.set(layout_x=[0, 0, 0], layout_y=[0, 1000, 2000])\n\ndef test_set_operation():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    fmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n\n    # Check that not allowed to run(), then set_operation, then collect powers\n    fmodel.run()\n    fmodel.set_operation(yaw_angles=np.array([[25.0, 0.0]]))\n    with pytest.raises(RuntimeError):\n        fmodel.get_turbine_powers()\n\n    # Check that no issue if run is called first\n    fmodel.run()\n    fmodel.get_turbine_powers()\n\n    # Check that if arguments do not match number of turbines, raises error\n    with pytest.raises(ValueError):\n        fmodel.set_operation(yaw_angles=np.array([[25.0, 0.0, 20.0]]))\n\n    # Check that if arguments do not match n_findex, raises error\n    with pytest.raises(ValueError):\n        fmodel.set_operation(yaw_angles=np.array([[25.0, 0.0], [25.0, 0.0]]))\n        fmodel.run()\n\ndef test_reference_wind_height_methods(caplog):\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    # Check that if the turbine type is changed, a warning is raised/not raised regarding the\n    # reference wind height\n    with caplog.at_level(logging.WARNING):\n        fmodel.set(turbine_type=[\"iea_15MW\"])\n    assert caplog.text != \"\" # Checking not empty\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        fmodel.set(turbine_type=[\"iea_15MW\"], reference_wind_height=100.0)\n    assert caplog.text == \"\" # Checking empty\n\n    # Check that assigning the reference wind height to the turbine hub height works\n    assert fmodel.core.flow_field.reference_wind_height == 100.0 # Set in line above\n    fmodel.assign_hub_height_to_ref_height()\n    assert fmodel.core.flow_field.reference_wind_height == 150.0 # 150m is HH for IEA 15MW\n\n    with pytest.raises(ValueError):\n        fmodel.set(\n            layout_x = [0.0, 0.0],\n            layout_y = [0.0, 1000.0],\n            turbine_type=[\"nrel_5MW\", \"iea_15MW\"]\n        )\n        fmodel.assign_hub_height_to_ref_height() # Shouldn't allow due to multiple turbine types\n\ndef test_merge_floris_models():\n\n    # Check that the merge function extends the data as expected\n    fmodel1 = FlorisModel(configuration=YAML_INPUT)\n    fmodel1.set(\n        layout_x=[0, 1000],\n        layout_y=[0, 0]\n    )\n    fmodel2 = FlorisModel(configuration=YAML_INPUT)\n    fmodel2.set(\n        layout_x=[2000, 3000],\n        layout_y=[0, 0]\n    )\n\n    merged_fmodel = FlorisModel.merge_floris_models([fmodel1, fmodel2])\n    assert merged_fmodel.n_turbines == 4\n\n    # Check that this model will run without error\n    merged_fmodel.run()\n\n    # Verify error handling\n\n    ## Input list with incorrect types\n    fmodel_list = [fmodel1, \"not a floris model\"]\n    with pytest.raises(TypeError):\n        merged_fmodel = FlorisModel.merge_floris_models(fmodel_list)\n\ndef test_sample_flow_at_points():\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    u_inf = 8.0\n    n_points = 10\n    fmodel.set(\n        layout_x=[0],\n        layout_y=[0],\n        wind_speeds=[u_inf, u_inf],\n        wind_directions=[270.0, 180.0],\n        turbulence_intensities=[0.06, 0.06],\n    )\n\n    # set up sample points\n    p = np.linspace(1, 1001, n_points)\n    x = np.concatenate((p, np.zeros_like(p)))\n    y = np.concatenate((np.zeros_like(p), p))\n    z = 100 * np.ones(n_points * 2)\n\n    # Use sample_flow_at_points to get the flow at the sample points\n    u_sampled_1 = fmodel.sample_flow_at_points(x, y, z)\n\n    # Check that the behind-turbine velocities match in the two directions\n    assert np.allclose(u_sampled_1[0,:n_points], u_sampled_1[1,n_points:])\n    # Check also that points outside the wake are all reasonable\n    assert np.allclose(u_sampled_1[0,n_points:], u_sampled_1[1,:n_points])\n    assert np.all(u_sampled_1[0,n_points:] > u_inf)\n    assert np.all(u_sampled_1[0,n_points:] == u_sampled_1[0,n_points])\n\n    # Run again at a higher speed and check all sampled velocities are higher\n    fmodel.set(wind_speeds=[u_inf + 2.0, u_inf + 2.0])\n    u_sampled_2 = fmodel.sample_flow_at_points(x, y, z)\n    assert np.all(u_sampled_2 > u_sampled_1)\n\ndef test_sample_ti_at_points():\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    ti_inf = 0.8\n    n_points = 10\n    fmodel.set(\n        layout_x=[0],\n        layout_y=[0],\n        wind_speeds=[8.0, 8.0],\n        wind_directions=[270.0, 180.0],\n        turbulence_intensities=[ti_inf, ti_inf],\n    )\n\n    # set up sample points\n    p = np.linspace(1, 1001, n_points)\n    x = np.concatenate((p, np.zeros_like(p)))\n    y = np.concatenate((np.zeros_like(p), p))\n    z = 100 * np.ones(n_points * 2)\n\n    # Use sample_ti_at_points to get the TI at the sample points\n    ti_sampled_1 = fmodel.sample_ti_at_points(x, y, z)\n\n    # Check that the behind-turbine TIs match in the two directions\n    assert np.allclose(ti_sampled_1[0,:n_points], ti_sampled_1[1,n_points:])\n    # Check also that points outside the wake are all reasonable\n    assert np.allclose(ti_sampled_1[0,n_points:], ti_sampled_1[1,:n_points])\n    assert np.all(ti_sampled_1[0,n_points:] == ti_inf)\n\n    # Run again at a higher TI and check all sampled TIs are higher\n    fmodel.set(turbulence_intensities=[ti_inf + 0.02, ti_inf + 0.02])\n    ti_sampled_2 = fmodel.sample_ti_at_points(x, y, z)\n    assert np.all(ti_sampled_2 > ti_sampled_1)\n\ndef test_set_multidim():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    fmodel.set(turbine_type=[SampleInputs().turbine_multi_dim])\n\n    # No multidim condition has been set; should raise value error\n    with pytest.raises(ValueError):\n        fmodel.run()\n\n    # Set a multidim condition that is not a valid type\n    with pytest.raises(TypeError):\n        fmodel.set(multidim_conditions=\"invalid_type\")\n        fmodel.run()\n\n    # Set an invalid multidim condition (not all dimensions specified)\n    with pytest.raises(ValueError):\n        fmodel.set(multidim_conditions={\"Hs\": 1.0})\n        fmodel.run()\n\n    # Set an invalid key (but the correct total number of keys)\n    with pytest.raises(ValueError):\n        fmodel.set(multidim_conditions={\"invalid_key\": 2.0, \"Hs\": 1.0})\n        fmodel.run()\n\n    # Set with an invalid key (as well as other keys being correct)\n    with pytest.raises(ValueError):\n        fmodel.set(multidim_conditions={\"invalid_key\": 2.0, \"Hs\": 1.0, \"Tp\": 8.0})\n        fmodel.run()\n\n    # Set a valid multidim condition, order of dictionary keys should not matter\n    fmodel.set(multidim_conditions={\"Hs\": 1.0, \"Tp\": 8.0})\n    fmodel.run()\n    powers_1 = fmodel.get_turbine_powers()\n    fmodel.set(multidim_conditions={\"Tp\": 8.0, \"Hs\": 1.0})\n    fmodel.run()\n    powers_2 = fmodel.get_turbine_powers()\n    assert np.array_equal(powers_1, powers_2)\n\n    # Create a single-dimensional table\n    turbine = SampleInputs().turbine_multi_dim\n    turbine[\"power_thrust_table\"][\"power_thrust_data_file\"] = \"iea_15MW_multi_dim_TI.csv\"\n    fmodel.set(\n        turbine_type=[turbine],\n        turbine_library_path=Path(__file__).resolve().parent / \"data/\"\n    )\n    with pytest.raises(ValueError):\n        fmodel.set(multidim_conditions={\"TI\": 0.06, \"Tp\": 8.0})\n        fmodel.run()\n    fmodel.set(multidim_conditions={\"TI\": 0.06})\n    fmodel.run()\n\n    # Test multiple conditions at once\n    fmodel.set(\n        wind_speeds=[8.0, 8.0],\n        wind_directions=[270.0, 270.0],\n        turbulence_intensities=[0.06, 0.06],\n        multidim_conditions={\"TI\": [0.06, 0.08, 0.09]} # Too many\n    )\n    with pytest.raises(ValueError):\n        fmodel.run()\n\n    # Correct number\n    fmodel.set(multidim_conditions={\"TI\": [0.06, 0.08]})\n    fmodel.run()\n    powers_multi = fmodel.get_turbine_powers()\n\n    # Loop over conditions and check individuals\n    for i, ti in enumerate([0.06, 0.08]):\n        fmodel.set(\n            wind_speeds=[8.0],\n            wind_directions=[270.0],\n            turbulence_intensities=[0.06],\n            multidim_conditions={\"TI\": ti}\n        )\n        fmodel.run()\n        powers_single = fmodel.get_turbine_powers()\n        assert np.array_equal(powers_single, powers_multi[i:i+1,:])\n"
  },
  {
    "path": "tests/flow_field_unit_test.py",
    "content": "\nimport numpy as np\nimport pytest\n\nfrom floris.core import FlowField, TurbineGrid\nfrom tests.conftest import N_FINDEX, N_TURBINES\n\n\ndef test_n_findex(flow_field_fixture):\n    assert flow_field_fixture.n_findex == N_FINDEX\n\n\ndef test_initialize_velocity_field(flow_field_fixture, turbine_grid_fixture: TurbineGrid):\n    flow_field_fixture.wind_shear = 1.0\n    flow_field_fixture.initialize_velocity_field(turbine_grid_fixture)\n\n    # Check the shape of the velocity arrays: u_initial, v_initial, w_initial  and u, v, w\n    # Dimensions are (# findex, # turbines, N grid points, M grid points)\n    assert np.shape(flow_field_fixture.u_sorted)[0] == flow_field_fixture.n_findex\n    assert np.shape(flow_field_fixture.u_sorted)[1] == N_TURBINES\n    assert np.shape(flow_field_fixture.u_sorted)[2] == turbine_grid_fixture.grid_resolution\n    assert np.shape(flow_field_fixture.u_sorted)[3] == turbine_grid_fixture.grid_resolution\n\n    # Check that the wind speed profile was created correctly. By setting the shear\n    # exponent to 1.0 above, the shear profile is a linear function of height and\n    # the points on the turbine rotor are equally spaced about the rotor.\n    # This means that their average should equal the wind speed at the center\n    # which is the input wind speed.\n    shape = np.shape(flow_field_fixture.u_sorted[0, 0, :, :])\n    n_elements = shape[0] * shape[1]\n    average = (\n        np.sum(flow_field_fixture.u_sorted[:, 0, :, :], axis=(-2, -1))\n        / np.array([n_elements])\n    )\n    assert np.array_equal(average, flow_field_fixture.wind_speeds)\n\n\ndef test_asdict(flow_field_fixture: FlowField, turbine_grid_fixture: TurbineGrid):\n\n    flow_field_fixture.initialize_velocity_field(turbine_grid_fixture)\n    dict1 = flow_field_fixture.as_dict()\n\n    new_ff = FlowField.from_dict(dict1)\n    new_ff.initialize_velocity_field(turbine_grid_fixture)\n    dict2 = new_ff.as_dict()\n\n    assert dict1 == dict2\n\ndef test_len_ws_equals_len_wd(flow_field_fixture: FlowField, turbine_grid_fixture: TurbineGrid):\n\n    flow_field_fixture.initialize_velocity_field(turbine_grid_fixture)\n    dict1 = flow_field_fixture.as_dict()\n\n    # Test that having the 3 equal in lenght raises no error\n    dict1['wind_directions'] = np.array([180, 180])\n    dict1['wind_speeds'] = np.array([5., 6.])\n    dict1['turbulence_intensities'] = np.array([175., 175.])\n\n    FlowField.from_dict(dict1)\n\n    # Set the wind speeds as a different length of wind directions and turbulence_intensities\n    # And confirm error raised\n    dict1['wind_directions'] = np.array([180, 180])\n    dict1['wind_speeds'] = np.array([5., 6., 7.])\n    dict1['turbulence_intensities'] = np.array([175., 175.])\n\n    with pytest.raises(ValueError):\n        FlowField.from_dict(dict1)\n\n    # Set the wind directions as a different length of wind speeds and turbulence_intensities\n    dict1['wind_directions'] = np.array([180, 180, 180.])\n    # And confirm error raised\n    dict1['wind_speeds'] = np.array([5., 6.])\n    dict1['turbulence_intensities'] = np.array([175., 175.])\n\n    with pytest.raises(ValueError):\n        FlowField.from_dict(dict1)\n\ndef test_dim_ws_wd_ti(flow_field_fixture: FlowField, turbine_grid_fixture: TurbineGrid):\n\n    flow_field_fixture.initialize_velocity_field(turbine_grid_fixture)\n    dict1 = flow_field_fixture.as_dict()\n\n    # Test that having an extra dimension in wind_directions raises an error\n    with pytest.raises(ValueError):\n        dict1['wind_directions'] = np.array([[180, 180]])\n        dict1['wind_speeds'] = np.array([5., 6.])\n        dict1['turbulence_intensities'] = np.array([175., 175.])\n        FlowField.from_dict(dict1)\n\n    # Test that having an extra dimension in wind_speeds raises an error\n    with pytest.raises(ValueError):\n        dict1['wind_directions'] = np.array([180, 180])\n        dict1['wind_speeds'] = np.array([[5., 6.]])\n        dict1['turbulence_intensities'] = np.array([175., 175.])\n        FlowField.from_dict(dict1)\n\n    # Test that having an extra dimension in turbulence_intensities raises an error\n    with pytest.raises(ValueError):\n        dict1['wind_directions'] = np.array([180, 180])\n        dict1['wind_speeds'] = np.array([5., 6.])\n        dict1['turbulence_intensities'] = np.array([[175., 175.]])\n        FlowField.from_dict(dict1)\n\n\ndef test_turbulence_intensities_to_n_findex(flow_field_fixture, turbine_grid_fixture):\n    # Assert tubulence intensity has same length as n_findex\n    assert len(flow_field_fixture.turbulence_intensities) == flow_field_fixture.n_findex\n\n    # Assert turbulence_intensity_field is the correct shape\n    flow_field_fixture.initialize_velocity_field(turbine_grid_fixture)\n    assert flow_field_fixture.turbulence_intensity_field.shape == (N_FINDEX, N_TURBINES, 1, 1)\n\n    # Assert that turbulence_intensity_field has values matched to turbulence_intensity\n    for findex in range(N_FINDEX):\n        for t in range(N_TURBINES):\n            assert (\n                flow_field_fixture.turbulence_intensities[findex]\n                == flow_field_fixture.turbulence_intensity_field[findex, t, 0, 0]\n            )\n"
  },
  {
    "path": "tests/geometric_yaw_unit_test.py",
    "content": "\nimport numpy as np\nimport pandas as pd\n\nfrom floris import FlorisModel\nfrom floris.optimization.yaw_optimization.yaw_optimizer_geometric import (\n    _process_layout,\n    YawOptimizationGeometric,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\n# Inputs for basic yaw optimizations\nWIND_DIRECTIONS = [0.0, 90.0, 180.0, 270.0]\nWIND_SPEEDS = [8.0] * 4\nTURBULENCE_INTENSITIES = [0.06] * 4\nLAYOUT_X = [0.0, 600.0, 1200.0]\nLAYOUT_Y = [0.0, 0.0, 0.0]\nMAXIMUM_YAW_ANGLE = 25.0\n\ndef test_basic_optimization(sample_inputs_fixture):\n    \"\"\"\n    The Serial Refine (SR) method optimizes yaw angles based on a sequential, iterative yaw\n    optimization scheme. This test checks basic properties of the optimization result.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    fmodel.set(\n        layout_x=LAYOUT_X,\n        layout_y=LAYOUT_Y,\n        wind_directions=WIND_DIRECTIONS,\n        wind_speeds=WIND_SPEEDS,\n        turbulence_intensities=TURBULENCE_INTENSITIES\n    )\n    fmodel.set_operation_model(\"cosine-loss\")\n\n    yaw_opt = YawOptimizationGeometric(\n        fmodel,\n        minimum_yaw_angle=0.0,\n        maximum_yaw_angle=MAXIMUM_YAW_ANGLE\n    )\n    df_opt = yaw_opt.optimize()\n\n    # Unaligned conditions\n    assert np.allclose(df_opt.loc[0, \"yaw_angles_opt\"], 0.0)\n    assert np.allclose(df_opt.loc[2, \"yaw_angles_opt\"], 0.0)\n\n    # Check aligned conditions\n    # Check maximum and minimum are respected\n    assert (df_opt.loc[1, \"yaw_angles_opt\"] <= MAXIMUM_YAW_ANGLE).all()\n    assert (df_opt.loc[3, \"yaw_angles_opt\"] <= MAXIMUM_YAW_ANGLE).all()\n    assert (df_opt.loc[1, \"yaw_angles_opt\"] >= 0.0).all()\n    assert (df_opt.loc[3, \"yaw_angles_opt\"] >= 0.0).all()\n\n    # Check 90.0 and 270.0 are symmetric\n    assert np.allclose(df_opt.loc[1, \"yaw_angles_opt\"], np.flip(df_opt.loc[3, \"yaw_angles_opt\"]))\n\n    # Check last turbine's angles are zero at 270.0\n    assert np.allclose(df_opt.loc[3, \"yaw_angles_opt\"][-1], 0.0)\n\n    # YawOptimizationGeometric does not compute farm powers\n\ndef test_disabled_turbines(sample_inputs_fixture):\n    \"\"\"\n    Tests SR when some turbines are disabled and checks that the results are equivalent to removing\n    those turbines from the wind farm. Need a tight layout to ensure that the front-to-back distance\n    is not too large.\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    fmodel.set(\n        layout_x=LAYOUT_X,\n        layout_y=LAYOUT_Y,\n        wind_directions=WIND_DIRECTIONS,\n        wind_speeds=WIND_SPEEDS,\n        turbulence_intensities=TURBULENCE_INTENSITIES\n    )\n    fmodel.set_operation_model(\"mixed\")\n\n    # Disable the middle turbine in all wind conditions, run optimization, and extract results\n    fmodel.set(disable_turbines=[[False, True, False]]*4)\n    yaw_opt = YawOptimizationGeometric(\n        fmodel,\n        minimum_yaw_angle=0.0,\n        maximum_yaw_angle=MAXIMUM_YAW_ANGLE\n    )\n    df_opt = yaw_opt.optimize()\n    yaw_angles_opt_disabled = df_opt.loc[3, \"yaw_angles_opt\"]\n\n    # Set up a new wind farm with the middle turbine removed\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    fmodel.set(\n        layout_x=np.array(LAYOUT_X)[[0, 2]],\n        layout_y=np.array(LAYOUT_Y)[[0, 2]],\n        wind_directions=WIND_DIRECTIONS,\n        wind_speeds=WIND_SPEEDS,\n        turbulence_intensities=TURBULENCE_INTENSITIES\n    )\n    fmodel.set_operation_model(\"cosine-loss\")\n    yaw_opt = YawOptimizationGeometric(\n        fmodel,\n        minimum_yaw_angle=0.0,\n        maximum_yaw_angle=MAXIMUM_YAW_ANGLE\n    )\n    df_opt = yaw_opt.optimize()\n    yaw_angles_opt_removed = df_opt.loc[3, \"yaw_angles_opt\"]\n\n    assert np.allclose(yaw_angles_opt_disabled[[0, 2]], yaw_angles_opt_removed)\n\ndef test_process_layout():\n\n    # Test inside Jensen-like wake\n    dx, dy = _process_layout(\n        turbine_x=np.array([0.0, 1000.0]),\n        turbine_y=np.array([0.0, 499.0]),\n        rotor_diameter=1.0,\n        spread=0.5\n    )\n    assert dx[0] == 1000.0 # Distance to downstream turbine, which is inside the wake\n\n    # Test outside Jensen-like wake\n    dx, dy, = _process_layout(\n        turbine_x=np.array([0.0, 1000.0]),\n        turbine_y=np.array([0.0, 501.0]),\n        rotor_diameter=1.0,\n        spread=0.5\n    )\n    assert dx[0] == np.inf # Distance to downstream turbine, which is outside the wake\n\n    # Test effect of rotor diameter\n    dx, dy, = _process_layout(\n        turbine_x=np.array([0.0, 1000.0]),\n        turbine_y=np.array([0.0, 549.0]),\n        rotor_diameter=100.0,\n        spread=0.5\n    )\n    assert dx[0] != np.inf # This turbine is now inside the wake\n\n    dx, dy = _process_layout(\n        turbine_x=np.array([0.0, 1000.0]),\n        turbine_y=np.array([0.0, 551.0]),\n        rotor_diameter=100.0,\n        spread=0.5\n    )\n    assert dx[0] == np.inf # This turbine is now outside the wake\n"
  },
  {
    "path": "tests/heterogeneous_map_integration_test.py",
    "content": "import logging\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom floris import FlorisModel, TimeSeries\nfrom floris.heterogeneous_map import HeterogeneousMap\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\nYAML_INPUT = TEST_DATA / \"input_full.yaml\"\n\n\ndef test_declare_by_parameters():\n    HeterogeneousMap(\n        x=np.array([0.0, 0.0, 500.0, 500.0]),\n        y=np.array([0.0, 500.0, 0.0, 500.0]),\n        speed_multipliers=np.array(\n            [\n                [1.0, 1.0, 1.0, 1.0],\n                [1.0, 1.25, 1.0, 1.25],\n                [1.0, 1.0, 1.0, 1.25],\n                [1.0, 1.0, 1.0, 1.0],\n            ]\n        ),\n        wind_directions=np.array([0.0, 0.0, 90.0, 90.0]),\n        wind_speeds=np.array([5.0, 15.0, 5.0, 15.0]),\n    )\n\n\ndef test_heterogeneous_map_no_ws_no_wd():\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array(\n            [\n                [1.0, 1.1, 1.2],\n                [1.1, 1.1, 1.1],\n                [1.3, 1.4, 1.5],\n            ]\n        ),\n    }\n\n    # Should be single value if no wind_directions or wind_speeds\n    with pytest.raises(ValueError):\n        HeterogeneousMap(**heterogeneous_map_config)\n\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array([[1.0, 1.1, 1.2]]),\n    }\n\n    HeterogeneousMap(**heterogeneous_map_config)\n\n\ndef test_wind_direction_and_wind_speed_sizes():\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array(\n            [\n                [1.0, 1.1, 1.2],\n                [1.1, 1.1, 1.1],\n                [1.3, 1.4, 1.5],\n            ]\n        ),\n        \"wind_directions\": np.array([0.0, 90.0]),\n        \"wind_speeds\": np.array([10.0, 20.0, 30.0]),\n    }\n\n    # Should raise value error because wind_directions and wind_speeds are not the same size\n    with pytest.raises(ValueError):\n        HeterogeneousMap(**heterogeneous_map_config)\n\n        heterogeneous_map_config = {\n            \"x\": np.array([0.0, 1.0, 2.0]),\n            \"y\": np.array([0.0, 1.0, 2.0]),\n            \"speed_multipliers\": np.array(\n                [\n                    [1.0, 1.1, 1.2],\n                    [1.1, 1.1, 1.1],\n                    [1.3, 1.4, 1.5],\n                ]\n            ),\n            \"wind_directions\": np.array([0.0, 90.0]),\n            \"wind_speeds\": np.array([10.0, 20.0]),\n        }\n\n    # Should raise value error because wind_directions and wind_speeds are not = to the\n    # size of speed_multipliers in the 0th dimension\n    with pytest.raises(ValueError):\n        HeterogeneousMap(**heterogeneous_map_config)\n\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array(\n            [\n                [1.0, 1.1, 1.2],\n                [1.1, 1.1, 1.1],\n                [1.3, 1.4, 1.5],\n            ]\n        ),\n        \"wind_directions\": np.array([0.0, 90.0, 270.0]),\n        \"wind_speeds\": np.array([10.0, 20.0, 15.0]),\n    }\n\n    HeterogeneousMap(**heterogeneous_map_config)\n\n\ndef test_wind_direction_and_wind_speed_unique():\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array(\n            [\n                [1.0, 1.1, 1.2],\n                [1.1, 1.1, 1.1],\n                [1.3, 1.4, 1.5],\n            ]\n        ),\n        \"wind_directions\": np.array([0.0, 0.0, 270.0]),\n        \"wind_speeds\": np.array([10.0, 10.0, 15.0]),\n    }\n\n    # Raises error because of repeated wd/ws pair\n    with pytest.raises(ValueError):\n        HeterogeneousMap(**heterogeneous_map_config)\n\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array(\n            [\n                [1.0, 1.1, 1.2],\n                [1.1, 1.1, 1.1],\n                [1.3, 1.4, 1.5],\n            ]\n        ),\n        \"wind_directions\": np.array([0.0, 5.0, 270.0]),\n        \"wind_speeds\": np.array([10.0, 10.0, 15.0]),\n    }\n\n    # Should not raise error\n    HeterogeneousMap(**heterogeneous_map_config)\n\n\ndef test_get_heterogeneous_inflow_config_by_wind_direction():\n    # Test the function when only wind_directions is defined\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array(\n            [\n                [1.0, 1.1, 1.2],\n                [1.1, 1.1, 1.1],\n                [1.3, 1.4, 1.5],\n            ]\n        ),\n        \"wind_directions\": np.array([0, 90, 270]),\n    }\n\n    # Check for correctness\n    wind_directions = np.array([240, 80, 15])\n    wind_speeds = np.array([10.0, 20.0, 15.0])\n    expected_output = np.array([[1.3, 1.4, 1.5], [1.1, 1.1, 1.1], [1.0, 1.1, 1.2]])\n\n    hm = HeterogeneousMap(**heterogeneous_map_config)\n    output_dict = hm.get_heterogeneous_inflow_config(wind_directions, wind_speeds)\n    assert np.allclose(output_dict[\"speed_multipliers\"], expected_output)\n\n\ndef test_get_heterogeneous_inflow_config_by_wind_speed():\n    # Test the function when only wind_directions is defined\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array(\n            [\n                [1.0, 1.1, 1.2],\n                [1.1, 1.1, 1.1],\n                [1.3, 1.4, 1.5],\n            ]\n        ),\n        \"wind_speeds\": np.array([0, 10, 20]),\n    }\n\n    # Check for correctness\n    wind_directions = np.array([240, 80, 15])\n    wind_speeds = np.array([10.0, 10.0, 18.0])\n    expected_output = np.array([[1.1, 1.1, 1.1], [1.1, 1.1, 1.1], [1.3, 1.4, 1.5]])\n\n    hm = HeterogeneousMap(**heterogeneous_map_config)\n    output_dict = hm.get_heterogeneous_inflow_config(wind_directions, wind_speeds)\n    assert np.allclose(output_dict[\"speed_multipliers\"], expected_output)\n\n\ndef test_get_heterogeneous_inflow_config_by_wind_direction_and_wind_speed():\n    # Test the function when only wind_directions is defined\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array(\n            [[1.0, 1.1, 1.2], [1.1, 1.1, 1.1], [1.3, 1.4, 1.5], [1.4, 1.5, 1.6]]\n        ),\n        \"wind_directions\": np.array([0, 0, 90, 90]),\n        \"wind_speeds\": np.array([5.0, 15.0, 5.0, 15.0]),\n    }\n\n    hm = HeterogeneousMap(**heterogeneous_map_config)\n\n    # Check for correctness\n    wind_directions = np.array([91, 89, 350])\n    wind_speeds = np.array([4.0, 18.0, 12.0])\n    expected_output = np.array([[1.3, 1.4, 1.5], [1.4, 1.5, 1.6], [1.1, 1.1, 1.1]])\n\n    output_dict = hm.get_heterogeneous_inflow_config(wind_directions, wind_speeds)\n    assert np.allclose(output_dict[\"speed_multipliers\"], expected_output)\n\n\ndef test_get_heterogeneous_inflow_config_no_wind_direction_no_wind_speed():\n    # Test the function when only wind_directions is defined\n    heterogeneous_map_config = {\n        \"x\": np.array([0.0, 1.0, 2.0]),\n        \"y\": np.array([0.0, 1.0, 2.0]),\n        \"speed_multipliers\": np.array(\n            [\n                [1.0, 1.1, 1.2],\n            ]\n        ),\n    }\n\n    hm = HeterogeneousMap(**heterogeneous_map_config)\n\n    # Check for correctness\n    wind_directions = np.array([91, 89, 350])\n    wind_speeds = np.array([4.0, 18.0, 12.0])\n    expected_output = np.array([[1.0, 1.1, 1.2], [1.0, 1.1, 1.2], [1.0, 1.1, 1.2]])\n\n    output_dict = hm.get_heterogeneous_inflow_config(wind_directions, wind_speeds)\n    assert np.allclose(output_dict[\"speed_multipliers\"], expected_output)\n\n\ndef test_get_2d_heterogenous_map_from_3d():\n    hm_3d = HeterogeneousMap(\n        x=np.array(\n            [\n                0.0,\n                1.0,\n                2.0,\n                0.0,\n                1.0,\n                2.0,\n            ]\n        ),\n        y=np.array(\n            [\n                0.0,\n                1.0,\n                2.0,\n                0.0,\n                1.0,\n                2.0,\n            ]\n        ),\n        z=np.array([0.0, 0.0, 0.0, 1.0, 1.0, 1.0]),\n        speed_multipliers=np.array(\n            [\n                [1.0, 1.1, 1.2, 2.0, 2.1, 2.2],\n                [1.1, 1.1, 1.1, 2.1, 2.1, 2.1],\n                [1.3, 1.4, 1.5, 2.3, 2.4, 2.5],\n            ]\n        ),\n        wind_directions=np.array([0, 90, 270]),\n    )\n\n    hm_2d_0 = hm_3d.get_heterogeneous_map_2d(0.0)\n    hm_2d_1 = hm_3d.get_heterogeneous_map_2d(1.0)\n\n    # Test that x values in both cases are 0, 1, 2\n    assert np.allclose(hm_2d_0.x, np.array([0.0, 1.0, 2.0]))\n    assert np.allclose(hm_2d_1.x, np.array([0.0, 1.0, 2.0]))\n\n    # Test that the speed multipliers are correct\n    assert np.allclose(\n        hm_2d_0.speed_multipliers, np.array([[1.0, 1.1, 1.2], [1.1, 1.1, 1.1], [1.3, 1.4, 1.5]])\n    )\n    assert np.allclose(\n        hm_2d_1.speed_multipliers, np.array([[2.0, 2.1, 2.2], [2.1, 2.1, 2.1], [2.3, 2.4, 2.5]])\n    )\n\n    # Test that wind directions are the same between 2d and 3d\n    assert np.allclose(hm_2d_0.wind_directions, hm_3d.wind_directions)\n\n    # Test that wind speed is None in all cases\n    assert hm_3d.wind_speeds is None\n    assert hm_2d_0.wind_speeds is None\n    assert hm_2d_1.wind_speeds is None\n\n\ndef test_3d_het_and_shear():\n    # Define a 3D het map with 4 z locations and a single x and y where\n    # the speed ups are defined by the usual power low\n    wind_speed = 8.0\n    z_values_array = np.array([0.0, 100.0, 200.0, 300.0])\n    reference_wind_height = 90.0\n    wind_shear = 0.12\n    speed_multipliers_array = (z_values_array / reference_wind_height) ** wind_shear\n\n    # Define the x and y locations to be corners of a square that repeats\n    # for 4 different z locations\n    x_values = np.tile(np.array([-500.0, 500.0, -500.0, 500.0]), 4)\n    y_values = np.tile(np.array([-500.0, -500.0, 500.0, 500.0]), 4)\n\n    # Repeat each of the elements of z_values 4 times\n    z_values = np.repeat(z_values_array, 4)\n    speed_multipliers = np.repeat(speed_multipliers_array, 4)\n\n    # Reshape speed_multipliers to be (1,16)\n    speed_multipliers = speed_multipliers.reshape(1, -1)\n\n    # Build the 3d HeterogeneousMap\n    hm_3d = HeterogeneousMap(\n        x=x_values,\n        y=y_values,\n        z=z_values,\n        speed_multipliers=speed_multipliers,\n    )\n\n    # Get the FLORIS model\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    # Set the model to a single wind direction, speed and turbine\n    fmodel.set(\n        wind_directions=[270.0],\n        wind_speeds=[wind_speed],\n        layout_x=[0],\n        layout_y=[0],\n        wind_shear=wind_shear,\n    )\n\n    # Run the model\n    fmodel.run()\n\n    # Get the velocities 100 m in front of the turbine\n    # Use the calculate_y_plane method because sample_flow_at_points does not currently work\n    # with heterogeneous inflow\n    # u_at_points_shear = fmodel.sample_flow_at_points(x= -100.0 * np.ones_like(z_values_array),\n    #                                               y= 0.0 * np.ones_like(z_values_array),\n    #                                               z=z_values_array)\n    y_plane = fmodel.calculate_y_plane(\n        x_resolution=1,\n        z_resolution=4,\n        crossstream_dist=0.0,\n        x_bounds=[-100.0, -100.0],\n        z_bounds=[0.0, 300.0],\n    )\n    u_at_points_shear = y_plane.df[\"u\"].values\n\n    # Check that the velocities are as expected, ie the shear exponent of 0.12\n    # produces speeds expeted from the power law\n    assert np.allclose(u_at_points_shear, wind_speed * speed_multipliers_array)\n\n    # Now change the model such that shear is 0, while the 3D het map is applied\n    fmodel.set(\n        wind_shear=0.0,\n        heterogeneous_inflow_config=hm_3d.get_heterogeneous_inflow_config(\n            wind_directions=[270.0], wind_speeds=[wind_speed]\n        ),\n    )\n\n    # Run the model\n    fmodel.run()\n\n    # # Get the velocities 100 m in front of the turbine\n    y_plane_het = fmodel.calculate_y_plane(\n        x_resolution=1,\n        z_resolution=4,\n        crossstream_dist=0.0,\n        x_bounds=[-100.0, -100.0],\n        z_bounds=[0.0, 300.0],\n    )\n    u_at_points_het = y_plane_het.df[\"u\"].values\n\n    # Confirm this produces the same results as the shear model\n    assert np.allclose(u_at_points_het, u_at_points_shear)\n\n    # Finally confirm that applying both shear and het raises a value error\n    with pytest.raises(ValueError):\n        fmodel.set(\n            wind_shear=0.12,\n            heterogeneous_inflow_config=hm_3d.get_heterogeneous_inflow_config(\n                wind_directions=[270.0], wind_speeds=[wind_speed]\n            ),\n        )\n\n\ndef test_run_2d_het_map(caplog):\n    # Define a 2D het map and confirm the results are as expected\n    # when applied to FLORIS\n\n    # The side of the flow which is accelerated reverses for east versus west\n    het_map = HeterogeneousMap(\n        x=np.array([0.0, 0.0, 500.0, 500.0]),\n        y=np.array([0.0, 500.0, 0.0, 500.0]),\n        speed_multipliers=np.array(\n            [\n                [1.0, 2.0, 1.0, 2.0],  # Top accelerated\n                [2.0, 1.0, 2.0, 1.0],  # Bottom accelerated\n            ]\n        ),\n        wind_directions=np.array([270.0, 90.0]),\n        wind_speeds=np.array([8.0, 8.0]),\n    )\n\n    # Get the FLORIS model\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    time_series = TimeSeries(\n        wind_directions=np.array([270.0, 90.0]),\n        wind_speeds=8.0,\n        turbulence_intensities=0.06,\n        heterogeneous_map=het_map,\n    )\n\n    # Set the model to a turbines perpendicular to east/west flow with 0 turbine closer to bottom\n    # and turbine 1 closer to top, while turbine 2 is outside of heterogeneous specification.\n    fmodel.set(\n        wind_data=time_series,\n        layout_x=[250.0, 250.0, 250.0],\n        layout_y=[100.0, 400.0, 700.0],\n        wind_shear=0.0,\n    )\n\n\n    # Run the model. Should raise warning due to turbine outside of bounds with linear interpolation\n    with caplog.at_level(logging.WARNING):\n        fmodel.run()\n    assert caplog.text != \"\" # Checking not empty\n\n    # Get the turbine powers\n    powers = fmodel.get_turbine_powers()\n\n    # Assert that in the first condition, turbine 1 has higher power\n    assert powers[0, 1] > powers[0, 0]\n\n    # Assert that in the second condition, turbine 0 has higher power\n    assert powers[1, 0] > powers[1, 1]\n\n    # Assert that the power of turbine 1 equals in the first condition\n    # equals the power of turbine 0 in the second condition\n    assert powers[0, 1] == powers[1, 0]\n\n    # Check that turbine 2 is simply seeing the freestream wind speed\n    velocities = fmodel.turbine_average_velocities\n    assert np.allclose(velocities[:, 2], 8.0)\n\n    # Check that sample_flow_at_points runs\n    # Middle of bottom, middle of left\n    v = fmodel.sample_flow_at_points(\n        np.array([250, 0]),\n        np.array([0, 250]),\n        np.array([90, 90])\n    )\n    assert np.allclose(v[:,0], np.array([8.0, 16.0])) # Not waked\n    assert np.allclose(v[0,1], 12.0) # Not waked\n    assert v[1,1] < 12.0 # Slightly waked\n\ndef test_run_2d_het_map_nearest_neighbor(caplog):\n    # Define a 2D het map and confirm the results are as expected\n    # when applied to FLORIS\n\n    # The side of the flow which is accelerated reverses for east versus west\n    het_map = HeterogeneousMap(\n        x=np.array([0.0, 0.0, 500.0, 500.0]),\n        y=np.array([0.0, 500.0, 0.0, 500.0]),\n        speed_multipliers=np.array(\n            [\n                [1.0, 2.0, 1.0, 2.0],  # Top accelerated\n                [2.0, 1.0, 2.0, 1.0],  # Bottom accelerated\n            ]\n        ),\n        wind_directions=np.array([270.0, 90.0]),\n        wind_speeds=np.array([8.0, 8.0]),\n        interp_method='nearest',\n    )\n\n    # Get the FLORIS model\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    time_series = TimeSeries(\n        wind_directions=np.array([270.0, 90.0]),\n        wind_speeds=8.0,\n        turbulence_intensities=0.06,\n        heterogeneous_map=het_map,\n    )\n\n    # Set the model to a turbines perpendicular to east/west flow with 0 turbine closer to bottom\n    # and turbine 1 closer to top, while turbine 2 is outside of heterogeneous specification\n    # (but will still take on the nearest neighbor value).\n    fmodel.set(\n        wind_data=time_series,\n        layout_x=[250.0, 250.0, 250.0],\n        layout_y=[100.0, 400.0, 700.0],\n        wind_shear=0.0,\n    )\n\n    # Run the model. No turbine outside of bounds warning raised for nearest neighbor interpolation\n    with caplog.at_level(logging.WARNING):\n        fmodel.run()\n    assert caplog.text == \"\" # Checking empty\n\n    # Get the turbine powers\n    powers = fmodel.get_turbine_powers()\n\n    # Assert that in the first condition, turbine 1 has higher power\n    assert powers[0, 1] > powers[0, 0]\n\n    # Assert that in the second condition, turbine 0 has higher power\n    assert powers[1, 0] > powers[1, 1]\n\n    # Assert that the power of turbine 1 equals in the first condition\n    # equals the power of turbine 0 in the second condition\n    assert powers[0, 1] == powers[1, 0]\n\n    # Check that turbine 2 is takes the value of the top row.\n    velocities = fmodel.turbine_average_velocities\n    assert np.allclose(velocities[:, 2], 8.0*np.array([2.0, 1.0]))\n\n    # Check that sample_flow_at_points runs\n    # Middle of bottom, middle of left (slightly up)\n    v = fmodel.sample_flow_at_points(\n        np.array([250.0, 0]),\n        np.array([0, 251]),\n        np.array([90, 90])\n    )\n    assert np.allclose(v[:,0], np.array([8.0, 16.0])) # Not waked\n    assert np.allclose(v[0,1], 16.0) # Not waked\n    assert v[1,1] < 8.0 # Slightly waked\n\ndef test_het_config():\n\n    # Test that setting FLORIS with a heterogeneous inflow configuration\n    # works as expected and consistent with previous results\n\n    # Get the FLORIS model\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    # Change the layout to a 4 turbine layout in a box\n    fmodel.set(layout_x=[0, 0, 500.0, 500.0], layout_y=[0, 500.0, 0, 500.0])\n\n    # Set FLORIS to run for a single condition\n    fmodel.set(wind_speeds=[8.0], wind_directions=[270.0], turbulence_intensities=[0.06])\n\n    # Define the speed-ups of the heterogeneous inflow, and their locations.\n    # Note that heterogeneity is only applied within the bounds of the points defined in the\n    # heterogeneous_inflow_config dictionary.  In this case, set the inflow to be 1.25x the ambient\n    # wind speed for the upper turbines at y = 500m.\n    speed_ups = [[1.0, 1.25, 1.0, 1.25]]  # Note speed-ups has dimensions of n_findex X n_points\n    x_locs = [-500.0, -500.0, 1000.0, 1000.0]\n    y_locs = [-500.0, 1000.0, -500.0, 1000.0]\n\n    # Create the configuration dictionary to be used for the heterogeneous inflow.\n    heterogeneous_inflow_config = {\n        \"speed_multipliers\": speed_ups,\n        \"x\": x_locs,\n        \"y\": y_locs,\n    }\n\n    # Set the heterogeneous inflow configuration\n    fmodel.set(heterogeneous_inflow_config=heterogeneous_inflow_config)\n\n    # Run the FLORIS simulation\n    fmodel.run()\n\n    turbine_powers = fmodel.get_turbine_powers() / 1000.0\n\n    # Test that the turbine powers are consistent with previous implementation\n    # 2248.2, 2800.1, 466.2, 601.5 before the change\n    # Using almost equal assert\n    assert np.allclose(\n        turbine_powers, np.array([[2248.2, 2800.0, 466.2, 601.4]]), atol=1.0,\n    )\n"
  },
  {
    "path": "tests/layout_optimization_integration_test.py",
    "content": "import logging\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n)\nfrom floris.optimization.layout_optimization.layout_optimization_base import (\n    LayoutOptimization,\n)\nfrom floris.optimization.layout_optimization.layout_optimization_gridded import (\n    LayoutOptimizationGridded,\n)\nfrom floris.optimization.layout_optimization.layout_optimization_random_search import (\n    LayoutOptimizationRandomSearch,\n)\nfrom floris.optimization.layout_optimization.layout_optimization_scipy import (\n    LayoutOptimizationScipy,\n)\nfrom floris.wind_data import WindDataBase\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\nYAML_INPUT = TEST_DATA / \"input_full.yaml\"\n\ntest_boundaries = [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)]\n\n\ndef test_base_class(caplog):\n    # Get a test fi\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    # Now initiate layout optimization with a frequency matrix passed in the 3rd position\n    # (this should fail)\n    freq = np.ones((5, 5))\n    freq = freq / freq.sum()\n\n    # Check that warning is raised if fmodel does not contain wind_data\n    with caplog.at_level(logging.WARNING):\n        LayoutOptimization(fmodel, test_boundaries, 5)\n    assert caplog.text != \"\" # Checking not empty\n\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        LayoutOptimization(fmodel=fmodel, boundaries=test_boundaries, min_dist=5,)\n    assert caplog.text != \"\" # Checking not empty\n\n    time_series = TimeSeries(\n        wind_directions=fmodel.core.flow_field.wind_directions,\n        wind_speeds=fmodel.core.flow_field.wind_speeds,\n        turbulence_intensities=fmodel.core.flow_field.turbulence_intensities,\n    )\n    fmodel.set(wind_data=time_series)\n\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        LayoutOptimization(fmodel, test_boundaries, 5)\n    assert caplog.text != \"\" # Not empty, because get_farm_AEP called on TimeSeries\n\n    # Passing without keyword arguments should work, or with keyword arguments\n    LayoutOptimization(fmodel, test_boundaries, 5)\n    LayoutOptimization(fmodel=fmodel, boundaries=test_boundaries, min_dist=5)\n\n    # Check with WindRose on fmodel\n    fmodel.set(wind_data=time_series.to_WindRose())\n\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        LayoutOptimization(fmodel, test_boundaries, 5)\n    assert caplog.text == \"\" # Empty\n\n    LayoutOptimization(fmodel, test_boundaries, 5)\n    LayoutOptimization(fmodel=fmodel, boundaries=test_boundaries, min_dist=5)\n\ndef test_LayoutOptimizationRandomSearch():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    fmodel.set(layout_x=[0, 500], layout_y=[0, 0])\n\n    layout_opt = LayoutOptimizationRandomSearch(\n        fmodel=fmodel,\n        boundaries=test_boundaries,\n        min_dist_D=5,\n        seconds_per_iteration=1,\n        total_optimization_seconds=1,\n        use_dist_based_init=False,\n    )\n\n    # Check that the optimization runs\n    layout_opt.optimize()\n\ndef test_LayoutOptimizationGridded_initialization(caplog):\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    fmodel.set(layout_x=[0, 500], layout_y=[0, 0])\n\n    with pytest.raises(ValueError):\n        LayoutOptimizationGridded(\n            fmodel=fmodel,\n            boundaries=test_boundaries,\n            min_dist=None,\n            min_dist_D=None,\n        ) # No min_dist specified\n    with pytest.raises(ValueError):\n        LayoutOptimizationGridded(\n            fmodel=fmodel,\n            boundaries=test_boundaries,\n            min_dist=500,\n            min_dist_D=5\n        ) # min_dist specified in two ways\n\n    fmodel.core.farm.rotor_diameters[1] = 100.0\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        LayoutOptimizationGridded(\n            fmodel,\n            test_boundaries,\n            min_dist_D=5\n        )\n\ndef test_LayoutOptimizationGridded_basic():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    min_dist = 60\n\n    layout_opt = LayoutOptimizationGridded(\n        fmodel=fmodel,\n        boundaries=test_boundaries,\n        min_dist=min_dist,\n        rotation_step=5,\n        rotation_range=(0, 360),\n        translation_step=50,\n        hexagonal_packing=False,\n    )\n\n    n_turbs_opt, x_opt, y_opt = layout_opt.optimize()\n\n    # Check that the number of turbines is correct\n    assert n_turbs_opt == len(x_opt)\n\n    # Check that min_dist is respected\n    xx_diff = x_opt.reshape(-1,1) - x_opt.reshape(1,-1)\n    yy_diff = y_opt.reshape(-1,1) - y_opt.reshape(1,-1)\n    dists = np.sqrt(xx_diff**2 + yy_diff**2)\n    dists[np.arange(0, len(dists), 1), np.arange(0, len(dists), 1)] = np.inf\n    assert (dists > min_dist - 1e-6).all()\n\n    # Check all are indeed in bounds\n    assert (np.all(x_opt > 0.0) & np.all(x_opt < 1000.0)\n            & np.all(y_opt > 0.0) & np.all(y_opt < 1000.0))\n\n    # Check that the layout is at least as good as the basic rectangular fill\n    n_turbs_subopt = (1000 // min_dist + 1) ** 2\n\n    assert n_turbs_opt >= n_turbs_subopt\n\ndef test_LayoutOptimizationGridded_diagonal():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    turbine_spacing = 1000.0\n    corner = 2*turbine_spacing / np.sqrt(2)\n\n    # Create a \"thin\" boundary area at a 45 degree angle\n    boundaries_diag = [\n        (0.0, 0.0),\n        (0.0, 100.0),\n        (corner, corner+100.0),\n        (corner+100.0, corner+100.0),\n        (0.0, 0.0)\n    ]\n\n    layout_opt = LayoutOptimizationGridded(\n        fmodel=fmodel,\n        boundaries=boundaries_diag,\n        min_dist=turbine_spacing,\n        rotation_step=45, # To speed up test\n        rotation_range=(0, 360),\n        translation_step=50,\n        hexagonal_packing=False,\n    )\n\n    n_turbs_opt, x_opt, y_opt = layout_opt.optimize()\n\n    # Confirm that spacing is respected\n    xx_diff = x_opt.reshape(-1,1) - x_opt.reshape(1,-1)\n    yy_diff = y_opt.reshape(-1,1) - y_opt.reshape(1,-1)\n    dists = np.sqrt(xx_diff**2 + yy_diff**2)\n    dists[np.arange(0, len(dists), 1), np.arange(0, len(dists), 1)] = np.inf\n    assert (dists > turbine_spacing - 1e-6).all()\n\n    assert n_turbs_opt == 3 # 3 should fit in the diagonal\n\n    # Test a limited range of rotation\n    layout_opt = LayoutOptimizationGridded(\n        fmodel=fmodel,\n        boundaries=boundaries_diag,\n        min_dist=turbine_spacing,\n        rotation_step=5,\n        rotation_range=(0, 10),\n        translation_step=50,\n        hexagonal_packing=False,\n    )\n    n_turbs_opt, x_opt, y_opt = layout_opt.optimize()\n    assert n_turbs_opt < 3\n\n    # Test a coarse rotation\n    layout_opt = LayoutOptimizationGridded(\n        fmodel=fmodel,\n        boundaries=boundaries_diag,\n        min_dist=turbine_spacing,\n        rotation_step=60, # Not fine enough to find ideal 45 deg rotation\n        rotation_range=(0, 360),\n        translation_step=50,\n        hexagonal_packing=False,\n    )\n    n_turbs_opt, x_opt, y_opt = layout_opt.optimize()\n    assert n_turbs_opt < 3\n\n    # Test a coarse translation\n    layout_opt = LayoutOptimizationGridded(\n        fmodel=fmodel,\n        boundaries=boundaries_diag,\n        min_dist=turbine_spacing,\n        rotation_step=45,\n        rotation_range=(0, 10),\n        translation_step=300,\n        hexagonal_packing=False,\n    )\n    n_turbs_opt, x_opt, y_opt = layout_opt.optimize()\n    assert n_turbs_opt < 3\n\ndef test_LayoutOptimizationGridded_separate_boundaries():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    separate_boundaries = [\n        [(0.0, 0.0), (0.0, 100.0), (100.0, 100.0), (100.0, 0.0), (0.0, 0.0)],\n        [(200.0, 0.0), (200.0, 100.0), (300.0, 100.0), (300.0, 0.0), (200.0, 0.0)]\n    ]\n\n    layout_opt = LayoutOptimizationGridded(\n        fmodel=fmodel,\n        boundaries=separate_boundaries,\n        min_dist=150,\n        rotation_step=5,\n        rotation_range=(0, 360),\n        translation_step=50,\n        hexagonal_packing=False,\n    )\n\n    n_turbs_opt, x_opt, y_opt = layout_opt.optimize()\n    assert n_turbs_opt == 2 # One in each of the boundary areas\n\n    # Check they're inside as expected\n    assert ((0.0 <= y_opt) & (y_opt <= 100.0)).all()\n    assert (((0.0 <= x_opt) & (x_opt <= 100.0)) | ((200.0 <= x_opt) & (x_opt <= 300.0))).all()\n\n\ndef test_LayoutOptimizationGridded_hexagonal():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    spacing = 200\n\n    # First, run a square layout\n    layout_opt = LayoutOptimizationGridded(\n        fmodel=fmodel,\n        boundaries=test_boundaries,\n        min_dist=spacing,\n        rotation_step=5,\n        rotation_range=(0, 360),\n        translation_step=50,\n        hexagonal_packing=False,\n    )\n    n_turbs_opt_square = layout_opt.optimize()[0]\n\n    # Now, run a hexagonal layout\n    layout_opt = LayoutOptimizationGridded(\n        fmodel=fmodel,\n        boundaries=test_boundaries,\n        min_dist=spacing,\n        rotation_step=5,\n        rotation_range=(0, 360),\n        translation_step=50,\n        hexagonal_packing=True,\n    )\n    n_turbs_opt_hex = layout_opt.optimize()[0]\n\n    # Check that the hexagonal layout is better\n    assert n_turbs_opt_hex >= n_turbs_opt_square\n"
  },
  {
    "path": "tests/layout_visualization_test.py",
    "content": "\nfrom pathlib import Path\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nimport floris.layout_visualization as layoutviz\nfrom floris import FlorisModel\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\nYAML_INPUT = TEST_DATA / \"input_full.yaml\"\n\n\ndef test_get_wake_direction():\n    # Turbine 0 wakes Turbine 1 at 270 degrees\n    assert np.isclose(layoutviz.get_wake_direction(0, 0, 1, 0), 270.0)\n\n    # Turbine 0 wakes Turbine 1 at 0 degrees\n    assert np.isclose(layoutviz.get_wake_direction(0, 1, 0, 0), 0.0)\n\n    # Winds from the south\n    assert np.isclose(layoutviz.get_wake_direction(0, -1, 0, 0), 180.0)\n\ndef test_plotting_functions():\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    ax = layoutviz.plot_turbine_points(fmodel=fmodel)\n    assert isinstance(ax, plt.Axes)\n\n    ax = layoutviz.plot_turbine_labels(fmodel=fmodel)\n    assert isinstance(ax, plt.Axes)\n\n    ax = layoutviz.plot_turbine_rotors(fmodel=fmodel)\n    assert isinstance(ax, plt.Axes)\n\n    ax = layoutviz.plot_waking_directions(fmodel=fmodel)\n    assert isinstance(ax, plt.Axes)\n\n    # Add additional turbines to test plot farm terrain\n    fmodel.set(\n        layout_x=[0, 1000, 0, 1000, 3000],\n        layout_y=[0, 0, 2000, 2000, 3000],\n    )\n    ax = layoutviz.plot_farm_terrain(fmodel=fmodel)\n    assert isinstance(ax, plt.Axes)\n"
  },
  {
    "path": "tests/load_optimization_test.py",
    "content": "import numpy as np\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n)\nfrom floris.optimization.load_optimization.load_optimization import (\n    compute_farm_revenue,\n    compute_farm_voc,\n    compute_lti,\n    compute_net_revenue,\n    compute_turbine_voc,\n    find_A_to_satisfy_rev_voc_ratio,\n    find_A_to_satisfy_target_VOC_per_MW,\n    optimize_power_setpoints,\n)\n\n\ndef test_compute_lti_no_wake():\n    # If we pass in a two-turbine, two-findex case where the turbines are\n    # not aligned in flow, would expect to get back np.ones((2,2)) * ambient\n    fmodel = FlorisModel(configuration=\"defaults\")\n    fmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n    fmodel.set(\n        wind_speeds=[8.0, 8.0], wind_directions=[0.0, 0.0], turbulence_intensities=[0.06, 0.06]\n    )\n    fmodel.run()\n    ambient_lti = [0.12, 0.1]\n    load_ti = compute_lti(fmodel, ambient_lti)\n    assert load_ti.shape == (2, 2)\n    assert load_ti[0, 0] == ambient_lti[0]\n    assert load_ti[0, 1] == ambient_lti[0]\n    assert load_ti[1, 0] == ambient_lti[1]\n    assert load_ti[1, 1] == ambient_lti[1]\n\n\ndef test_compute_lti_wake():\n    # Test two turbines in a wake, n_findex = 1\n    fmodel = FlorisModel(configuration=\"defaults\")\n    fmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n    fmodel.set(wind_speeds=[8.0], wind_directions=[270.0], turbulence_intensities=[0.06])\n    fmodel.run()\n    ambient_lti = [0.1]\n    load_ti = compute_lti(fmodel, ambient_lti)\n    assert load_ti.shape == (1, 2)\n    np.testing.assert_almost_equal(load_ti[0, 0], ambient_lti)\n    assert load_ti[0, 1] > load_ti[0, 0]\n\n\ndef test_compute_turbine_voc_no_wake():\n    # If we pass in a two-turbine, two-findex case where the turbines are\n    # not aligned in flow, would expect to get back a 2x2 numpy array where\n    # all values are the same\n    fmodel = FlorisModel(configuration=\"defaults\")\n    fmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n    fmodel.set(\n        wind_speeds=[8.0, 8.0], wind_directions=[0.0, 0.0], turbulence_intensities=[0.06, 0.06]\n    )\n    fmodel.run()\n    ambient_lti = [0.12, 0.12]\n    voc = compute_turbine_voc(fmodel, 0.01, ambient_lti)\n    assert voc.shape == (2, 2)\n    assert voc[0, 0] == voc[0, 1]\n    assert voc[0, 0] == voc[1, 0]\n    assert voc[0, 0] == voc[1, 1]\n\n\ndef test_compute_turbine_voc_wake():\n    # Test two turbines in a wake, n_findex = 1\n    fmodel = FlorisModel(configuration=\"defaults\")\n    fmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n    fmodel.set(wind_speeds=[8.0], wind_directions=[270.0], turbulence_intensities=[0.06])\n    fmodel.run()\n    ambient_lti = [0.1]\n    voc = compute_turbine_voc(fmodel, 0.01, ambient_lti)\n    assert voc.shape == (1, 2)\n    assert voc[0, 1] > voc[0, 0]\n\n\ndef test_compute_net_revenue_no_wake():\n    # Assuming two turbines, two findex, no wake, and uniform value\n    # net_revenue should be a 2-element array with the same value\n    fmodel = FlorisModel(configuration=\"defaults\")\n    fmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n    time_series = TimeSeries(\n        wind_directions=np.array([0, 0]),\n        wind_speeds=8.0,\n        turbulence_intensities=0.06,\n        values=np.array([0.5, 0.5]),\n    )\n\n    fmodel.set(wind_data=time_series)\n    fmodel.run()\n    ambient_lti = [0.12, 0.12]\n    net_revenue = compute_net_revenue(fmodel, 1, ambient_lti)\n    assert net_revenue.shape == (2,)\n    assert net_revenue[0] == net_revenue[1]\n\ndef test_find_A_to_satisfy_rev_voc_ratio():\n    # Test the function that finds the A value that satisfies the revenue to voc ratio\n    target_rev_voc_ratio = 10.0\n\n    fmodel = FlorisModel(configuration=\"defaults\")\n    fmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n    N = 100\n    time_series = TimeSeries(\n        wind_directions=np.ones(N) * 270.0,\n        wind_speeds=8.0,\n        turbulence_intensities=0.06,\n        values=np.ones(N)\n    )\n    fmodel.set(wind_data=time_series)\n    fmodel.run()\n\n    ambient_lti = np.ones(N) * 0.1\n\n    A = find_A_to_satisfy_rev_voc_ratio(fmodel, target_rev_voc_ratio, ambient_lti)\n\n    farm_revenue = compute_farm_revenue(fmodel)\n\n    farm_voc = compute_farm_voc(fmodel, A, ambient_lti)\n\n    assert np.allclose(farm_revenue.sum() / farm_voc.sum(), target_rev_voc_ratio, atol=1e-4)\n\ndef test_find_A_to_satisfy_target_VOC_per_MW():\n    # Test the function that finds the A value that satisfies the average VOC/MW/findex\n    target_VOC_per_MW_findex = 10.0\n\n    fmodel = FlorisModel(configuration=\"defaults\")\n    fmodel.set(layout_x=[0, 500.0], layout_y=[0.0, 0.0])\n    N = 100\n    time_series = TimeSeries(\n        wind_directions=np.ones(N) * 270.0,\n        wind_speeds=8.0,\n        turbulence_intensities=0.06,\n        values=np.ones(N)\n    )\n    fmodel.set(wind_data=time_series)\n    fmodel.run()\n\n    ambient_lti = np.ones(N) * 0.1\n\n    A = find_A_to_satisfy_target_VOC_per_MW(fmodel, target_VOC_per_MW_findex, ambient_lti)\n\n    farm_power = fmodel.get_farm_power()\n\n    farm_voc = compute_farm_voc(fmodel, A, ambient_lti)\n\n    assert np.allclose(1e6 * farm_voc.sum() / farm_power.sum(), target_VOC_per_MW_findex, atol=1e-4)\n"
  },
  {
    "path": "tests/par_floris_model_unit_test.py",
    "content": "\nimport copy\nimport logging\n\nimport numpy as np\nimport pytest\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n    WindRose,\n)\nfrom floris.par_floris_model import ParFlorisModel\n\n\nDEBUG = False\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\ndef test_None_interface(sample_inputs_fixture):\n    \"\"\"\n    With interface=None, the ParFlorisModel should behave exactly like the FlorisModel.\n    (ParFlorisModel.run() simply calls the parent FlorisModel.run()).\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=None,\n        n_wind_condition_splits=2 # Not used when interface=None\n    )\n\n    fmodel.run()\n    pfmodel.run()\n\n    f_turb_powers = fmodel.get_turbine_powers()\n    pf_turb_powers = pfmodel.get_turbine_powers()\n\n    assert np.allclose(f_turb_powers, pf_turb_powers)\n\ndef test_multiprocessing_interface(sample_inputs_fixture):\n    \"\"\"\n    With interface=\"multiprocessing\", the ParFlorisModel should return the same powers\n    as the FlorisModel.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=\"multiprocessing\",\n        n_wind_condition_splits=2\n    )\n\n    fmodel.run()\n    pfmodel.run()\n\n    f_turb_powers = fmodel.get_turbine_powers()\n    pf_turb_powers = pfmodel.get_turbine_powers()\n\n    assert np.allclose(f_turb_powers, pf_turb_powers)\n\ndef test_pathos_interface(sample_inputs_fixture):\n    \"\"\"\n    With interface=\"pathos\", the ParFlorisModel should return the same powers\n    as the FlorisModel.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=\"pathos\",\n        n_wind_condition_splits=2\n    )\n\n    fmodel.run()\n    pfmodel.run()\n\n    f_turb_powers = fmodel.get_turbine_powers()\n    pf_turb_powers = pfmodel.get_turbine_powers()\n\n    assert np.allclose(f_turb_powers, pf_turb_powers)\n\n    # Run in powers_only mode\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=\"pathos\",\n        n_wind_condition_splits=2,\n        return_turbine_powers_only=True\n    )\n\n    pfmodel.run()\n    pf_turb_powers = pfmodel.get_turbine_powers()\n\n    assert np.allclose(f_turb_powers, pf_turb_powers)\n\ndef test_concurrent_interface(sample_inputs_fixture):\n    \"\"\"\n    With interface=\"concurrent\", the ParFlorisModel should return the same powers\n    as the FlorisModel.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=\"concurrent\",\n        n_wind_condition_splits=2,\n    )\n\n    fmodel.run()\n    pfmodel.run()\n\n    f_turb_powers = fmodel.get_turbine_powers()\n    pf_turb_powers = pfmodel.get_turbine_powers()\n\n    assert np.allclose(f_turb_powers, pf_turb_powers)\n\n    # Run in powers_only mode\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=\"concurrent\",\n        n_wind_condition_splits=2,\n        return_turbine_powers_only=True\n    )\n\n    pfmodel.run()\n    pf_turb_powers = pfmodel.get_turbine_powers()\n\n    assert np.allclose(f_turb_powers, pf_turb_powers)\n\ndef test_return_turbine_powers_only(sample_inputs_fixture):\n    \"\"\"\n    With return_turbine_powers_only=True, the ParFlorisModel should return only the\n    turbine powers, not the full results.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=\"multiprocessing\",\n        n_wind_condition_splits=2,\n        return_turbine_powers_only=True\n    )\n\n    fmodel.run()\n    pfmodel.run()\n\n    f_turb_powers = fmodel.get_turbine_powers()\n    pf_turb_powers = pfmodel.get_turbine_powers()\n\n    assert np.allclose(f_turb_powers, pf_turb_powers)\n\ndef test_run_error(sample_inputs_fixture, caplog):\n    \"\"\"\n    Check that an error is raised if an output is requested before calling run().\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=\"multiprocessing\",\n        n_wind_condition_splits=2\n    )\n\n    # In future versions, error will be raised\n    # with pytest.raises(RuntimeError):\n    #     pfmodel.get_turbine_powers()\n    # with pytest.raises(RuntimeError):\n    #     pfmodel.get_farm_AEP()\n\n    # For now, only a warning is raised for backwards compatibility\n    with caplog.at_level(logging.WARNING):\n        pfmodel.get_turbine_powers()\n    assert caplog.text != \"\" # Checking not empty\n    caplog.clear()\n\ndef test_configuration_compatibility(sample_inputs_fixture, caplog):\n    \"\"\"\n    Check that the ParFlorisModel is compatible with FlorisModel and\n    UncertainFlorisModel configurations.\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    # Allowed to instantiate ParFlorisModel using fmodel\n    with caplog.at_level(logging.WARNING):\n        ParFlorisModel(fmodel)\n    assert caplog.text == \"\" # Checking empty\n    caplog.clear()\n\n    pfmodel = ParFlorisModel(sample_inputs_fixture.core)\n    with caplog.at_level(logging.WARNING):\n        pfmodel.fmodel\n    assert caplog.text != \"\" # Checking not empty\n    caplog.clear()\n\n    with pytest.raises(AttributeError):\n        pfmodel.fmodel.core\n\ndef test_wind_data_objects(sample_inputs_fixture):\n    \"\"\"\n    Check that the ParFlorisModel is compatible with WindData objects.\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel = ParFlorisModel(sample_inputs_fixture.core, max_workers=2)\n\n    # Create a wind rose and set onto both models\n    wind_speeds = np.array([8.0, 10.0, 12.0, 8.0, 10.0, 12.0])\n    wind_directions = np.array([270.0, 270.0, 270.0, 280.0, 280.0, 280.0])\n    wind_rose = WindRose(\n        wind_directions=np.unique(wind_directions),\n        wind_speeds=np.unique(wind_speeds),\n        ti_table=0.06\n    )\n    fmodel.set(wind_data=wind_rose)\n    pfmodel.set(wind_data=wind_rose)\n\n    # Run; get turbine powers; compare results\n    fmodel.run()\n    powers_fmodel_wr = fmodel.get_turbine_powers()\n    pfmodel.run()\n    powers_pfmodel_wr = pfmodel.get_turbine_powers()\n\n    assert powers_fmodel_wr.shape == powers_pfmodel_wr.shape\n    assert np.allclose(powers_fmodel_wr, powers_pfmodel_wr)\n\n    # Test a TimeSeries object\n    wind_speeds = np.array([8.0, 8.0, 9.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    values = np.array([30.0, 20.0, 10.0])\n    time_series = TimeSeries(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.06,\n        values=values,\n    )\n    fmodel.set(wind_data=time_series)\n    pfmodel.set(wind_data=time_series)\n\n    fmodel.run()\n    powers_fmodel_ts = fmodel.get_turbine_powers()\n    pfmodel.run()\n    powers_pfmodel_ts = pfmodel.get_turbine_powers()\n\n    assert powers_fmodel_ts.shape == powers_pfmodel_ts.shape\n    assert np.allclose(powers_fmodel_ts, powers_pfmodel_ts)\n\ndef test_control_setpoints(sample_inputs_fixture):\n    \"\"\"\n    Check that the ParFlorisModel is compatible with control set points.\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel = ParFlorisModel(sample_inputs_fixture.core, n_wind_condition_splits=2)\n\n    # Set yaw angles\n    yaw_angles = np.tile(np.array([[10.0, 20.0, 30.0]]), (fmodel.n_findex,1))\n    fmodel.set(yaw_angles=yaw_angles)\n    pfmodel.set(yaw_angles=yaw_angles)\n\n    # Run; get turbine powers; compare results\n    fmodel.run()\n    powers_fmodel = fmodel.get_turbine_powers()\n    pfmodel.run()\n    powers_pfmodel = pfmodel.get_turbine_powers()\n\n    assert powers_fmodel.shape == powers_pfmodel.shape\n    assert np.allclose(powers_fmodel, powers_pfmodel)\n\n    # Reset yaw angles and test power setpoints\n    power_setpoints = np.tile(np.array([[1.0e6, 2.0e6, 1.0e12]]), (fmodel.n_findex,1))\n    fmodel.set_operation_model(\"simple-derating\")\n    pfmodel.set_operation_model(\"simple-derating\")\n    fmodel.reset_operation()\n    pfmodel.reset_operation()\n\n    fmodel.set(power_setpoints=power_setpoints)\n    pfmodel.set(power_setpoints=power_setpoints)\n    fmodel.run()\n    powers_fmodel = fmodel.get_turbine_powers()\n    pfmodel.run()\n    powers_pfmodel = pfmodel.get_turbine_powers()\n\n    assert powers_fmodel.shape == powers_pfmodel.shape\n    assert np.allclose(powers_fmodel, powers_pfmodel)\n\n    # Reset power setpoints and test disable_turbines\n    disable_turbines = np.tile(np.array([[False, True, False]]), (fmodel.n_findex,1))\n    fmodel.reset_operation()\n    pfmodel.reset_operation()\n\n    fmodel.set(disable_turbines=disable_turbines)\n    pfmodel.set(disable_turbines=disable_turbines)\n    fmodel.run()\n    powers_fmodel = fmodel.get_turbine_powers()\n    pfmodel.run()\n    powers_pfmodel = pfmodel.get_turbine_powers()\n    assert powers_fmodel.shape == powers_pfmodel.shape\n    assert np.allclose(powers_fmodel, powers_pfmodel)\n\n    # Test AWC set points\n    awc_modes = np.tile([[\"helix\", \"helix\", \"baseline\"]], (fmodel.n_findex,1))\n    awc_amplitudes = np.tile([[0.0, 2.0, 0.0]], (fmodel.n_findex,1))\n    fmodel.set_operation_model(\"awc\")\n    pfmodel.set_operation_model(\"awc\")\n    fmodel.reset_operation()\n    pfmodel.reset_operation()\n\n    # Run once without AWC as a check\n    fmodel.run()\n    powers_base = fmodel.get_turbine_powers()\n\n    # Now run with AWC\n    fmodel.set(awc_modes=awc_modes, awc_amplitudes=awc_amplitudes)\n    pfmodel.set(awc_modes=awc_modes, awc_amplitudes=awc_amplitudes)\n    fmodel.run()\n    powers_fmodel = fmodel.get_turbine_powers()\n    pfmodel.run()\n    powers_pfmodel = pfmodel.get_turbine_powers()\n    assert powers_fmodel.shape == powers_pfmodel.shape\n    assert np.allclose(powers_fmodel, powers_pfmodel)\n\n    # Confirm that AWC changed the powers from baseline\n    assert np.allclose(powers_base[:, 0], powers_fmodel[:, 0]) # 0 amplitude\n    assert not np.isclose(powers_base[:, 1], powers_fmodel[:, 1]).any() # Helix applied\n\ndef test_sample_flow_at_points(sample_inputs_fixture):\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    wind_speeds = np.array([8.0, 8.0, 9.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    fmodel.set(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.06 * np.ones_like(wind_speeds.flatten()),\n    )\n\n    x_test = np.array([500.0, 750.0, 1000.0, 1250.0, 1500.0])\n    y_test = np.array([0.0, 0.0, 0.0, 0.0, 0.0])\n    z_test = np.array([90.0, 90.0, 90.0, 90.0, 90.0])\n\n    ws_base = fmodel.sample_flow_at_points(x_test, y_test, z_test)\n\n    for interface in [\"multiprocessing\", \"pathos\", \"concurrent\"]:\n        pfmodel = ParFlorisModel(fmodel, max_workers=2, interface=interface)\n        ws_test = pfmodel.sample_flow_at_points(x_test, y_test, z_test)\n        assert np.allclose(ws_base, ws_test)\n\ndef test_sample_ti_at_points(sample_inputs_fixture):\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = \"crespo_hernandez\"\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    wind_speeds = np.array([8.0, 8.0, 9.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    fmodel.set(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.06 * np.ones_like(wind_speeds.flatten()),\n    )\n\n    x_test = np.array([500.0, 750.0, 1000.0, 1250.0, 1500.0])\n    y_test = np.array([0.0, 0.0, 0.0, 0.0, 0.0])\n    z_test = np.array([90.0, 90.0, 90.0, 90.0, 90.0])\n\n    ti_base = fmodel.sample_ti_at_points(x_test, y_test, z_test)\n\n    for interface in [\"multiprocessing\", \"pathos\", \"concurrent\"]:\n        pfmodel = ParFlorisModel(fmodel, max_workers=2, interface=interface)\n        ti_test = pfmodel.sample_ti_at_points(x_test, y_test, z_test)\n        assert np.allclose(ti_base, ti_test)\n\ndef test_copy(sample_inputs_fixture):\n    \"\"\"\n    Check that the ParFlorisModel copies correctly as a ParFlorisModel.\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    pfmodel = ParFlorisModel(sample_inputs_fixture.core, max_workers=2)\n    pfmodel_copy = pfmodel.copy()\n    assert isinstance(pfmodel_copy, ParFlorisModel)\n    assert pfmodel_copy.max_workers == 2\n\ndef test_heterogeneous_inflow_config(sample_inputs_fixture):\n    \"\"\"\n    Check that the ParFlorisModel works with heterogeneous_inflow_config set.\n    \"\"\"\n\n    heterogeneous_inflow_config = {\n        \"x\": np.array([-200.0, 2000.0, -200.0, 2000.0]),\n        \"y\": np.array([-200.0, -200.0, 200.0, 200.0]),\n        \"speed_multipliers\": np.array(\n            [\n                [1.0, 1.1, 1.2, 1.2],\n                [1.1, 1.1, 1.1, 1.1],\n                [1.0, 1.1, 1.2, 1.1],\n            ]\n        ),\n    }\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    wind_speeds = np.array([8.0, 8.0, 9.0])\n    turbulence_intensities = 0.06 * np.ones_like(wind_speeds)\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=\"multiprocessing\",\n        n_wind_condition_splits=2,\n    )\n\n    # Temporarily, run fmodel without heterogeneous_inflow_config to get baseline\n    fmodel.set(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n    )\n    fmodel.run()\n    baseline_powers = fmodel.get_turbine_powers()\n\n    # Set heterogeneous_flow_config cases and run\n    fmodel.set(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n        heterogeneous_inflow_config=heterogeneous_inflow_config,\n    )\n    pfmodel.set(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n        heterogeneous_inflow_config=heterogeneous_inflow_config,\n    )\n    fmodel.run()\n    pfmodel.run()\n\n    powers_fmodel = fmodel.get_turbine_powers()\n    assert (powers_fmodel != baseline_powers).any()  # Check no overlap to ensure test is valid\n    powers_pfmodel = pfmodel.get_turbine_powers()\n\n    # Confirm that the powers computed using the ParFlorisModel match those from the FlorisModel\n    assert np.allclose(powers_fmodel, powers_pfmodel)\n\n    # Repeat test with z component added\n    heterogeneous_inflow_config[\"z\"] = np.array([0.0, 0.0, 0.0, 1000.0])\n\n    fmodel.set(heterogeneous_inflow_config=heterogeneous_inflow_config, wind_shear=0.0)\n    pfmodel.set(heterogeneous_inflow_config=heterogeneous_inflow_config, wind_shear=0.0)\n    fmodel.run()\n    pfmodel.run()\n\n    powers_fmodel = fmodel.get_turbine_powers()\n    assert (powers_fmodel != baseline_powers).any()  # Check no overlap to ensure test is valid\n    powers_pfmodel = pfmodel.get_turbine_powers()\n    # Confirm that the powers computed using the ParFlorisModel match those from the FlorisModel\n    assert np.allclose(powers_fmodel, powers_pfmodel)\n\ndef test_multidim_conditions(sample_inputs_fixture):\n    \"\"\"\n    Check that the ParFlorisModel works with multidim_conditions set in the TimeSeries object.\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    fmodel.set(turbine_type=[sample_inputs_fixture.turbine_multi_dim])\n    pfmodel = ParFlorisModel(\n        sample_inputs_fixture.core,\n        interface=\"multiprocessing\",\n        n_wind_condition_splits=2\n    )\n    pfmodel.set(turbine_type=[sample_inputs_fixture.turbine_multi_dim])\n\n    # Create a TimeSeries object with multidim_conditions\n    wind_speeds = np.array([8.0]*6)\n    wind_directions = np.array([270.0]*6)\n    multidim_conditions = {\n        \"Tp\": np.array([5.0, 5.0, 6.0, 6.0, 7.0, 7.0]),\n        \"Hs\": np.array([3.0, 3.0, 3.0, 4.0, 4.0, 4.0]),\n    }\n    time_series = TimeSeries(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.06 * np.ones_like(wind_speeds.flatten()),\n        multidim_conditions=multidim_conditions\n    )\n\n    fmodel.set(wind_data=time_series)\n    pfmodel.set(wind_data=time_series)\n\n    fmodel.run()\n    pfmodel.run()\n\n    f_turb_powers = fmodel.get_turbine_powers()\n    pf_turb_powers = pfmodel.get_turbine_powers()\n\n    assert np.allclose(f_turb_powers, pf_turb_powers)\n"
  },
  {
    "path": "tests/parallel_floris_model_integration_test.py",
    "content": "\nimport copy\nimport logging\n\nimport numpy as np\nimport pytest\n\nfrom floris import (\n    FlorisModel,\n    ParallelFlorisModel,\n    UncertainFlorisModel,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\ndef test_raise_deprecation_warning(sample_inputs_fixture, caplog):\n    \"\"\"\n    Test that a warning is raised when instantiating the ParallelFlorisModel.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    caplog.clear()\n    with caplog.at_level(logging.WARNING):\n        ParallelFlorisModel(\n            fmodel=fmodel,\n            max_workers=2,\n            n_wind_condition_splits=2,\n            interface=\"concurrent\",\n            print_timings=False,\n        )\n    assert caplog.text != \"\" # Checking not empty\n    caplog.clear()\n\ndef test_parallel_turbine_powers(sample_inputs_fixture):\n    \"\"\"\n    The parallel computing interface behaves like the floris interface, but distributes\n    calculations among available cores to speed up the necessary computations. This test compares\n    the individual turbine powers computed with the parallel interface to those computed with\n    the serial floris interface. The expected result is that the turbine powers should be\n    exactly the same.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel_input = copy.deepcopy(fmodel)\n    fmodel.run()\n\n    serial_turbine_powers = fmodel.get_turbine_powers()\n\n    pfmodel = ParallelFlorisModel(\n        fmodel=pfmodel_input,\n        max_workers=2,\n        n_wind_condition_splits=2,\n        interface=\"concurrent\",\n        print_timings=False,\n    )\n\n    parallel_turbine_powers = pfmodel.get_turbine_powers()\n\n    if DEBUG:\n        print(serial_turbine_powers)\n        print(parallel_turbine_powers)\n\n    assert_results_arrays(parallel_turbine_powers, serial_turbine_powers)\n\ndef test_parallel_get_AEP(sample_inputs_fixture):\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    freq=np.linspace(0, 1, 16)/8\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    pfmodel_input = copy.deepcopy(fmodel)\n\n    fmodel.run()\n    serial_farm_AEP = fmodel.get_farm_AEP(freq=freq)\n\n    pfmodel = ParallelFlorisModel(\n        fmodel=pfmodel_input,\n        max_workers=2,\n        n_wind_condition_splits=2,\n        interface=\"concurrent\",\n        print_timings=False,\n    )\n\n    parallel_farm_AEP = pfmodel.get_farm_AEP(freq=freq)\n\n    assert np.allclose(parallel_farm_AEP, serial_farm_AEP)\n\ndef test_parallel_uncertain_error(sample_inputs_fixture):\n    \"\"\"\n\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    ufmodel = UncertainFlorisModel(\n        sample_inputs_fixture.core,\n        wd_sample_points=[-3, 0, 3],\n        wd_std=3\n    )\n\n    with pytest.raises(ValueError):\n        ParallelFlorisModel(\n            fmodel=ufmodel,\n            max_workers=2,\n            n_wind_condition_splits=2,\n            interface=\"multiprocessing\",\n            print_timings=False,\n        )\n"
  },
  {
    "path": "tests/reg_tests/cumulative_curl_regression_test.py",
    "content": "\nimport numpy as np\n\nfrom floris.core import (\n    average_velocity,\n    axial_induction,\n    Core,\n    power,\n    rotor_effective_velocity,\n    thrust_coefficient,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n    N_FINDEX,\n    N_TURBINES,\n    print_test_values,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"cc\"\nDEFLECTION_MODEL = \"gauss\"\n\nbaseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n            [5.4510872, 0.8920540, 554423.2959292, 0.3357243],\n            [5.0438692, 0.9152035, 418539.5184876, 0.3544008],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n            [6.1342847, 0.8547425, 797961.8242685, 0.3094367],\n            [5.6482366, 0.8808465, 620209.7062129, 0.3274069],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n            [6.8191059, 0.8235980, 1105849.4970759, 0.2899988],\n            [6.2802136, 0.8481059, 863569.7643645, 0.3051320],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n            [7.5591728, 0.7958161, 1495578.0671426, 0.2740664],\n            [6.9317813, 0.8184737, 1156507.0595179, 0.2869705],\n        ],\n    ]\n)\n\nyawed_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.4955257, 0.8895278, 569251.8849842, 0.3338132],\n            [5.0512690, 0.9147828, 421008.7273674, 0.3540401],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.1842430, 0.8524704, 820422.5044532, 0.3079521],\n            [5.6590417, 0.8802323, 623815.2315242, 0.3269626],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [6.8745497, 0.8210765, 1130776.3831297, 0.2885032],\n            [6.2938285, 0.8474867, 869690.8728188, 0.3047352],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [7.6186441, 0.7939637, 1530927.6220300, 0.2730439],\n            [6.9469619, 0.8177833, 1163332.0650645, 0.2865657],\n        ],\n    ]\n)\n\nyaw_added_recovery_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.5123171, 0.8885732, 574854.9880625, 0.3330968],\n            [5.0653039, 0.9139850, 425692.0104596, 0.3533584],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.2030677, 0.8516143, 828885.8701797, 0.3073957],\n            [5.6761588, 0.8792592, 629527.0166369, 0.3262611],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [6.8953509, 0.8201305, 1140128.3768208, 0.2879449],\n            [6.3135442, 0.8465900, 878554.8061141, 0.3041621],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [7.6397253, 0.7933242, 1543688.6272448, 0.2726920],\n            [6.9675202, 0.8168483, 1172574.8397092, 0.2860189],\n        ],\n    ]\n)\n\nsecondary_steering_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.4955262, 0.8895278, 569252.0553799, 0.3338132],\n            [5.0564287, 0.9144895, 422730.4667041, 0.3537891],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.1842436, 0.8524704, 820422.7619472, 0.3079521],\n            [5.6652985, 0.8798766, 625903.0435126, 0.3267059],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [6.8745503, 0.8210764, 1130776.6678583, 0.2885032],\n            [6.3010138, 0.8471599, 872921.3000764, 0.3045262],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [7.6186447, 0.7939637, 1530928.0140962, 0.2730439],\n            [6.9547367, 0.8174297, 1166827.5280695, 0.2863588],\n        ],\n    ]\n)\n\nfull_flow_baseline = np.array(\n    [\n        [\n            [\n                [7.88772361, 8.00000000, 8.10178821],\n                [7.88772361, 8.00000000, 8.10178821],\n                [7.88772361, 8.00000000, 8.10178821],\n                [7.88772361, 8.00000000, 8.10178821],\n                [7.88772361, 8.00000000, 8.10178821],\n            ],\n            [\n                [7.88772361, 8.        , 8.10178821],\n                [7.85396979, 7.96487892, 8.06803439],\n                [4.19559099, 4.28925565, 4.40965558],\n                [7.85396979, 7.96487892, 8.06803439],\n                [7.88772361, 8.        , 8.10178821],\n            ],\n            [\n                [7.88769642, 7.99997223, 8.10176102],\n                [7.58415314, 7.69072103, 7.79821773],\n                [4.16725762, 4.26342392, 4.38132221],\n                [7.58415314, 7.69072103, 7.79821773],\n                [7.88769642, 7.99997223, 8.10176102],\n            ],\n            [\n                [7.88513176, 7.99737618, 8.09919636],\n                [7.21888868, 7.32333558, 7.43301511],\n                [4.30201226, 4.40270245, 4.51689213],\n                [7.21888868, 7.32333558, 7.43301511],\n                [7.88513176, 7.99737618, 8.09919636],\n            ],\n            [\n                [7.86539121, 7.97748824, 8.0794561 ],\n                [7.0723371 , 7.1790733 , 7.28645574],\n                [5.8436738 , 5.95178931, 6.05791862],\n                [7.0723371 , 7.1790733 , 7.28645574],\n                [7.86539121, 7.97748824, 8.0794561 ],\n            ]\n        ]\n    ]\n)\n\n\n# Note: compare the yawed vs non-yawed results. The upstream turbine\n# power should be lower in the yawed case. The following turbine\n# powers should higher in the yawed case.\n\n\ndef test_regression_tandem(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], baseline)\n\n\ndef test_regression_rotation(sample_inputs_fixture):\n    \"\"\"\n    Turbines in tandem and rotated.\n    The result from 270 degrees should match the results from 360 degrees.\n\n    Wind from the West (Left)\n\n    ^\n    |\n    y\n\n    1|1         3\n     |\n     |\n     |\n    0|0         2\n     |----------|\n      0         1  x->\n\n\n    Wind from the North (Top), rotated\n\n    ^\n    |\n    y\n\n    1|3         2\n     |\n     |\n     |\n    0|1         0\n     |----------|\n      0         1  x->\n\n    In 270, turbines 2 and 3 are waked. In 360, turbines 0 and 2 are waked.\n    The test compares turbines 2 and 3 with 0 and 2 from 270 and 360.\n    \"\"\"\n    TURBINE_DIAMETER = 126.0\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = [\n        0.0,\n        0.0,\n        5 * TURBINE_DIAMETER,\n        5 * TURBINE_DIAMETER,\n    ]\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = [\n        0.0,\n        5 * TURBINE_DIAMETER,\n        0.0,\n        5 * TURBINE_DIAMETER\n    ]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0, 360.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0, 8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1, 0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    farm_avg_velocities = average_velocity(floris.flow_field.u)\n\n    t0_270 = farm_avg_velocities[0, 0]  # upstream\n    t1_270 = farm_avg_velocities[0, 1]  # upstream\n    t2_270 = farm_avg_velocities[0, 2]  # waked\n    t3_270 = farm_avg_velocities[0, 3]  # waked\n\n    t0_360 = farm_avg_velocities[1, 0]  # waked\n    t1_360 = farm_avg_velocities[1, 1]  # upstream\n    t2_360 = farm_avg_velocities[1, 2]  # waked\n    t3_360 = farm_avg_velocities[1, 3]  # upstream\n\n    assert np.allclose(t0_270, t1_360)\n    assert np.allclose(t1_270, t3_360)\n    assert np.allclose(t2_270, t0_360)\n    assert np.allclose(t3_270, t2_360)\n\n\ndef test_regression_yaw(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n                awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], yawed_baseline)\n\n\ndef test_regression_yaw_added_recovery(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed and yaw added recovery\n    correction enabled\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    sample_inputs_fixture.core[\"wake\"][\"enable_transverse_velocities\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_secondary_steering\"] = False\n    sample_inputs_fixture.core[\"wake\"][\"enable_yaw_added_recovery\"] = True\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], yaw_added_recovery_baseline)\n\n\ndef test_regression_secondary_steering(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed and secondary steering enabled\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    sample_inputs_fixture.core[\"wake\"][\"enable_transverse_velocities\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_secondary_steering\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_yaw_added_recovery\"] = False\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], secondary_steering_baseline)\n\n\ndef test_regression_small_grid_rotation(sample_inputs_fixture):\n    \"\"\"\n    This utilizes a 5x5 wind farm with the layout in a regular grid oriented along the cardinal\n    directions. The wind direction in this test is from 285 degrees which is slightly north of\n    west. The objective of this test is to create a case with a very slight rotation of the wind\n    farm to target the rotation and masking routines.\n\n    Where wake models are masked based on the x-location of a turbine, numerical precision\n    can cause masking to fail unexpectedly. For example, in the configuration here one of\n    the turbines has these delta x values;\n\n    [[4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]]\n\n    and therefore the masking statement is False when it should be True. This causes the current\n    turbine to be affected by its own wake. This test requires that at least in this particular\n    configuration the masking correctly filters grid points.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    X, Y = np.meshgrid(\n        6.0 * 126.0 * np.arange(0, 5, 1),\n        6.0 * 126.0 * np.arange(0, 5, 1)\n    )\n    X = X.flatten()\n    Y = Y.flatten()\n\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = X\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = Y\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    # farm_avg_velocities = average_velocity(floris.flow_field.u)\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n\n    # A \"column\" is oriented parallel to the wind direction\n    # Columns 1 - 4 should have the same power profile\n    # Column 5 leading turbine is completely unwaked\n    # and the rest of the turbines have a partial wake from their immediate upstream turbine\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,5:10])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,10:15])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,15:20])\n    assert np.allclose(farm_powers[8,20], farm_powers[8,0])\n    assert np.allclose(farm_powers[8,21], farm_powers[8,21:25])\n\n\ndef test_full_flow_solver(sample_inputs_fixture):\n    \"\"\"\n    Full flow solver test with the flow field planar grid.\n    This requires one wind condition, and the grid is deliberately coarse to allow for\n    visually comparing results, as needed.\n    The u-component of velocity is compared, and the array has the shape\n    (n_findex, n_turbines, n grid points in x, n grid points in y, 3 grid points in z).\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"solver\"] = {\n        \"type\": \"flow_field_planar_grid\",\n        \"normal_vector\": \"z\",\n        \"planar_coordinate\": sample_inputs_fixture.core[\"farm\"][\"turbine_type\"][0][\"hub_height\"],\n        \"flow_field_grid_points\": [5, 5],\n        \"flow_field_bounds\": [None, None],\n    }\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.solve_for_viz()\n\n    velocities = floris.flow_field.u_sorted\n\n    assert_results_arrays(velocities, full_flow_baseline)\n"
  },
  {
    "path": "tests/reg_tests/empirical_gauss_regression_test.py",
    "content": "\nimport numpy as np\n\nfrom floris.core import (\n    average_velocity,\n    axial_induction,\n    Core,\n    power,\n    rotor_effective_velocity,\n    thrust_coefficient,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n    N_FINDEX,\n    N_TURBINES,\n    print_test_values,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"empirical_gauss\"\nDEFLECTION_MODEL = \"empirical_gauss\"\nTURBULENCE_MODEL = \"wake_induced_mixing\"\n\n\nbaseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n            [5.8239250, 0.8708590, 678834.8317748, 0.3203190],\n            [5.9004356, 0.8665095, 704365.4950630, 0.3173183],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n            [6.5562701, 0.8355513, 987681.5731429, 0.2972386],\n            [6.6949231, 0.8292456, 1050018.3472064, 0.2933878],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n            [7.2923306, 0.8047024, 1343118.2404618, 0.2790376],\n            [7.4934722, 0.7978974, 1456951.3486441, 0.2752209],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n            [8.1353345, 0.7869536, 1872313.2273018, 0.2692152],\n            [8.2936951, 0.7867495, 1990669.8925423, 0.2691047],\n        ],\n    ]\n)\n\nyawed_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.8720857, 0.8681212, 694905.4822543, 0.3184244],\n            [5.9231111, 0.8652205, 711932.0521602, 0.3164383],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.6102438, 0.8330967, 1011947.5002467, 0.2957310],\n            [6.7207579, 0.8280707, 1061633.3882586, 0.2926782],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [7.3519418, 0.8026469, 1376375.4821341, 0.2778778],\n            [7.5221584, 0.7969827, 1473761.4857038, 0.2747128],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [8.1956906, 0.7868758, 1917422.6059783, 0.2691731],\n            [8.3187504, 0.7867172, 2009395.8987459, 0.2690872],\n        ],\n    ]\n)\n\ntilted_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7824685, 1734488.7059275, 0.2658985],\n            [5.8875889, 0.8705526, 704778.1875928, 0.3212047],\n            [5.9110415, 0.8692142, 712622.7895048, 0.3202651],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7812020, 2471404.7824861, 0.2652278],\n            [6.6276158, 0.8354859, 1026885.3722728, 0.2980366],\n            [6.7091646, 0.8317630, 1063636.4762428, 0.2957326],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7792154, 3383206.6144193, 0.2641794],\n            [7.3711242, 0.8050505, 1396968.1317078, 0.2799135],\n            [7.5109456, 0.8003819, 1477742.2826442, 0.2772650],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7520150, 4470666.5322783, 0.2502624],\n            [8.2150645, 0.7898565, 1946589.2518193, 0.2714076],\n            [8.3045772, 0.7897407, 2013649.9637290, 0.2713440],\n        ]\n    ]\n)\n\n\nyaw_added_recovery_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.8812867, 0.8675981, 697975.7537581, 0.3180646],\n            [5.9300836, 0.8648241, 714258.6740264, 0.3161686],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.6205487, 0.8326280, 1016580.4631213, 0.2954444],\n            [6.7286194, 0.8277131, 1065167.8381647, 0.2924627],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [7.3633114, 0.8022558, 1382735.2369962, 0.2776578],\n            [7.5308334, 0.7967093, 1478874.6141430, 0.2745612],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [8.2070431, 0.7868612, 1925907.3101195, 0.2691652],\n            [8.3266654, 0.7867070, 2015311.4552010, 0.2690817],\n        ],\n    ]\n)\n\nhelix_added_recovery_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n            [5.8239250, 0.8708590, 678834.8317748, 0.3203190],\n            [5.9004356, 0.8665095, 704365.4950630, 0.3173183],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n            [6.5562701, 0.8355513, 987681.5731429, 0.2972386],\n            [6.6949231, 0.8292456, 1050018.3472064, 0.2933878],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n            [7.2923306, 0.8047024, 1343118.2404618, 0.2790376],\n            [7.4934722, 0.7978974, 1456951.3486441, 0.2752209],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n            [8.1353345, 0.7869536, 1872313.2273018, 0.2692152],\n            [8.2936951, 0.7867495, 1990669.8925423, 0.2691047],\n        ],\n    ]\n)\n\nfull_flow_baseline = np.array(\n    [\n        [\n            [\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n            ],\n            [\n                [7.88772294, 7.99999928, 8.10178747],\n                [7.81880864, 7.9261404 , 8.02651415],\n                [4.66160854, 4.54241201, 4.57798522],\n                [7.81880864, 7.9261404 , 8.02651415],\n                [7.88772294, 7.99999928, 8.10178747],\n            ],\n            [\n                [7.88733339, 7.99958656, 8.10136247],\n                [7.60765422, 7.70390457, 7.79791213],\n                [5.19792855, 5.15875115, 5.18986616],\n                [7.60765422, 7.70390457, 7.79791213],\n                [7.88733339, 7.99958656, 8.10136247],\n            ],\n            [\n                [7.87220134, 7.98400571, 8.08549566],\n                [7.41124269, 7.50382311, 7.59416296],\n                [5.65108754, 5.65881944, 5.70295049],\n                [7.41124269, 7.50382311, 7.59416296],\n                [7.87220134, 7.98400571, 8.08549566],\n            ],\n            [\n                [7.83300625, 7.94438006, 8.04560619],\n                [7.37461427, 7.47355048, 7.56659807],\n                [6.47381486, 6.53210142, 6.59762329],\n                [7.37461427, 7.47355048, 7.56659807],\n                [7.83300625, 7.94438006, 8.04560619],\n            ],\n        ]\n    ]\n)\n\n\n# Note: compare the yawed vs non-yawed results. The upstream turbine\n# power should be lower in the yawed case. The following turbine\n# powers should higher in the yawed case.\n\n\ndef test_regression_tandem(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = TURBULENCE_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], baseline)\n\n\ndef test_regression_rotation(sample_inputs_fixture):\n    \"\"\"\n    Turbines in tandem and rotated.\n    The result from 270 degrees should match the results from 360 degrees.\n\n    Wind from the West (Left)\n\n    ^\n    |\n    y\n\n    1|1         3\n     |\n     |\n     |\n    0|0         2\n     |----------|\n      0         1  x->\n\n\n    Wind from the North (Top), rotated\n\n    ^\n    |\n    y\n\n    1|3         2\n     |\n     |\n     |\n    0|1         0\n     |----------|\n      0         1  x->\n\n    In 270, turbines 2 and 3 are waked. In 360, turbines 0 and 2 are waked.\n    The test compares turbines 2 and 3 with 0 and 2 from 270 and 360.\n    \"\"\"\n    TURBINE_DIAMETER = 126.0\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = TURBULENCE_MODEL\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = [\n        0.0,\n        0.0,\n        5 * TURBINE_DIAMETER,\n        5 * TURBINE_DIAMETER,\n    ]\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = [\n        0.0,\n        5 * TURBINE_DIAMETER,\n        0.0,\n        5 * TURBINE_DIAMETER\n    ]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0, 360.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0, 8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1, 0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    farm_avg_velocities = average_velocity(floris.flow_field.u)\n\n    t0_270 = farm_avg_velocities[0, 0]  # upstream\n    t1_270 = farm_avg_velocities[0, 1]  # upstream\n    t2_270 = farm_avg_velocities[0, 2]  # waked\n    t3_270 = farm_avg_velocities[0, 3]  # waked\n\n    t0_360 = farm_avg_velocities[1, 0]  # waked\n    t1_360 = farm_avg_velocities[1, 1]  # upstream\n    t2_360 = farm_avg_velocities[1, 2]  # waked\n    t3_360 = farm_avg_velocities[1, 3]  # upstream\n\n    assert np.allclose(t0_270, t1_360)\n    assert np.allclose(t1_270, t3_360)\n    assert np.allclose(t2_270, t0_360)\n    assert np.allclose(t3_270, t2_360)\n\n\ndef test_regression_yaw(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = TURBULENCE_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], yawed_baseline)\n\n\ndef test_regression_tilt(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine tilted\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = TURBULENCE_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    tilt_angles = np.zeros((N_FINDEX, N_TURBINES))\n    tilt_angles[:,0] = 8.0\n    floris.farm.tilt_angles = tilt_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], tilted_baseline)\n\n\ndef test_regression_yaw_added_recovery(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed and yaw added recovery\n    correction enabled\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = TURBULENCE_MODEL\n\n    # Turn on yaw added recovery\n    sample_inputs_fixture.core[\"wake\"][\"enable_yaw_added_recovery\"] = True\n    # First pass, leave at default value of 0; should then do nothing\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    # Compare to case where enable_yaw_added_recovery = False, since\n    # default gains are 0.\n    assert_results_arrays(test_results[0:4], yawed_baseline)\n\n    # Second pass, use nonzero gain\n    sample_inputs_fixture.core[\"wake\"][\"wake_deflection_parameters\"]\\\n        [\"empirical_gauss\"][\"yaw_added_mixing_gain\"] = 0.1\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], yaw_added_recovery_baseline)\n\ndef test_regression_helix(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine applying the helix\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = TURBULENCE_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    awc_modes = np.array([[\"helix\"]*N_TURBINES]*N_FINDEX)\n    awc_amplitudes = np.zeros((N_FINDEX, N_TURBINES))\n    awc_amplitudes[:,0] = 5.0\n    floris.farm.awc_amplitudes = awc_amplitudes\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], helix_added_recovery_baseline)\n\n\ndef test_regression_small_grid_rotation(sample_inputs_fixture):\n    \"\"\"\n    This utilizes a 5x5 wind farm with the layout in a regular grid oriented along the cardinal\n    directions. The wind direction in this test is from 285 degrees which is slightly north of\n    west. The objective of this test is to create a case with a very slight rotation of the wind\n    farm to target the rotation and masking routines.\n\n    Where wake models are masked based on the x-location of a turbine, numerical precision\n    can cause masking to fail unexpectedly. For example, in the configuration here one of\n    the turbines has these delta x values;\n\n    [[4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]]\n\n    and therefore the masking statement is False when it should be True. This causes the current\n    turbine to be affected by its own wake. This test requires that at least in this particular\n    configuration the masking correctly filters grid points.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = TURBULENCE_MODEL\n    X, Y = np.meshgrid(\n        6.0 * 126.0 * np.arange(0, 5, 1),\n        6.0 * 126.0 * np.arange(0, 5, 1)\n    )\n    X = X.flatten()\n    Y = Y.flatten()\n\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = X\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = Y\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    # farm_avg_velocities = average_velocity(floris.flow_field.u)\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n\n    # farm_eff_velocities = rotor_effective_velocity(\n    #     floris.flow_field.air_density,\n    #     floris.farm.ref_air_densities,\n    #     velocities,\n    #     yaw_angles,\n    #     tilt_angles,\n    #     floris.farm.ref_tilts,\n    #     floris.farm.pPs,\n    #     floris.farm.pTs,\n    #     floris.farm.turbine_tilt_interps,\n    #     floris.farm.correct_cp_ct_for_tilt,\n    #     floris.farm.turbine_type_map,\n    # )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        floris.flow_field.air_density,\n        floris.farm.turbine_power_functions,\n        floris.farm.yaw_angles,\n        floris.farm.tilt_angles,\n        floris.farm.power_setpoints,\n        floris.farm.awc_modes,\n        floris.farm.awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n\n    # A \"column\" is oriented parallel to the wind direction\n    # Columns 1 - 4 should have the same power profile\n    # Column 5 is completely unwaked in this model\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,5:10])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,10:15])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,15:20])\n    assert np.allclose(farm_powers[8,20], farm_powers[8,0])\n    assert np.allclose(farm_powers[8,21], farm_powers[8,21:25])\n\n\ndef test_full_flow_solver(sample_inputs_fixture):\n    \"\"\"\n    Full flow solver test with the flow field planar grid.\n    This requires one wind condition, and the grid is deliberately coarse to allow for\n    visually comparing results, as needed.\n    The u-component of velocity is compared, and the array has the shape\n    (n_findex, n_turbines, n grid points in x, n grid points in y, 3 grid points in z).\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = TURBULENCE_MODEL\n    sample_inputs_fixture.core[\"solver\"] = {\n        \"type\": \"flow_field_planar_grid\",\n        \"normal_vector\": \"z\",\n        \"planar_coordinate\": sample_inputs_fixture.core[\"farm\"][\"turbine_type\"][0][\"hub_height\"],\n        \"flow_field_grid_points\": [5, 5],\n        \"flow_field_bounds\": [None, None],\n    }\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.solve_for_viz()\n\n    velocities = floris.flow_field.u_sorted\n\n    if DEBUG:\n        print(velocities)\n\n    assert_results_arrays(velocities, full_flow_baseline)\n"
  },
  {
    "path": "tests/reg_tests/gauss_regression_test.py",
    "content": "\nimport numpy as np\n\nfrom floris.core import (\n    average_velocity,\n    axial_induction,\n    Core,\n    power,\n    rotor_effective_velocity,\n    thrust_coefficient,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n    N_FINDEX,\n    N_TURBINES,\n    print_test_values,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\nbaseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n            [5.9186455, 0.8654743, 710441.9192938, 0.3166113],\n            [6.0090150, 0.8604395, 741642.0177873, 0.3132110],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n            [6.6606465, 0.8308044, 1034608.0101396, 0.2943330],\n            [6.7947466, 0.8247058, 1094897.8563374, 0.2906592],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n            [7.4045198, 0.8008441, 1405853.7207176, 0.2768656],\n            [7.5868432, 0.7949439, 1511887.2179035, 0.2735844],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n            [8.2046271, 0.7868643, 1924101.6501936, 0.2691669],\n            [8.3491997, 0.7866780, 2032153.3223547, 0.2690660],\n        ],\n    ]\n)\n\nyawed_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.9521551, 0.8635694, 721623.6989382, 0.3153174],\n            [6.0131307, 0.8602523, 743492.3616581, 0.3130858],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.6982609, 0.8290938, 1051519.0079315, 0.2932960],\n            [6.7996516, 0.8244827, 1097103.0727816, 0.2905261],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [7.4461669, 0.7994645, 1429777.3846192, 0.2760940],\n            [7.5922658, 0.7947730, 1515083.3259879, 0.2734901],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [8.2481957, 0.7868081, 1956664.2629680, 0.2691365],\n            [8.3531097, 0.7866729, 2035075.5955678, 0.2690633],\n        ],\n    ]\n)\n\nfull_flow_baseline = np.array(\n    [\n        [\n            [\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n            ],\n            [\n                [7.88772264, 7.99999899, 8.10178721],\n                [7.80183828, 7.91077933, 8.01357204],\n                [4.05787708, 4.02142188, 4.16800363],\n                [7.80183828, 7.91077933, 8.01357204],\n                [7.88772264, 7.99999899, 8.10178721],\n            ],\n            [\n                [7.88365433, 7.9958357 , 8.09760849],\n                [7.54214774, 7.64551046, 7.74683377],\n                [4.99852407, 5.0247459 , 5.13417881],\n                [7.54214774, 7.64551046, 7.74683377],\n                [7.88365433, 7.9958357 , 8.09760849],\n            ],\n            [\n                [7.85066049, 7.96222083, 8.06371923],\n                [7.39444624, 7.49602334, 7.5951238 ],\n                [5.50716692, 5.55540288, 5.65662569],\n                [7.39444624, 7.49602334, 7.5951238 ],\n                [7.85066049, 7.96222083, 8.06371923],\n            ],\n            [\n                [7.79761973, 7.90832696, 8.009239  ],\n                [7.41896092, 7.52268669, 7.62030379],\n                [6.98565022, 7.0811275 , 7.17523349],\n                [7.41896092, 7.52268669, 7.62030379],\n                [7.79761973, 7.90832696, 8.009239  ],\n            ]\n        ]\n    ]\n)\n\n\n\"\"\"\n# These are the results from v2.4 develop branch\ngch_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9803783, 0.7605249, 1683956.3885389, 0.2548147],\n            [5.8920347, 0.8409478, 669953.8921404, 0.3005933],\n            [5.9690770, 0.8370054, 696678.9863587, 0.2981370],\n        ],\n        # 9 m/s\n        [\n            [8.9779256, 0.7596713, 2397237.3791443, 0.2543815],\n            [6.6299831, 0.8071465, 970496.1338006, 0.2804246],\n            [6.7527627, 0.8022061, 1027643.3724351, 0.2776299],\n        ],\n        # 10 m/s\n        [\n            [9.9754729, 0.7499157, 3283592.6005045, 0.2494847],\n            [7.3852773, 0.7796129, 1346745.9407360, 0.2652730],\n            [7.5343901, 0.7749587, 1428106.9252795, 0.2628074],\n        ],\n        # 11 m/s\n        [\n            [10.9730201, 0.7276532, 4344217.6993801, 0.2386508],\n            [8.1727131, 0.7624523, 1824643.2726943, 0.2563057],\n            [8.2996789, 0.7621064, 1911032.3885037, 0.2561283],\n        ]\n    ]\n)\n\nsecondary_steering_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9803783, 0.7605249, 1683956.3885389, 0.2548147],\n            [5.8728752, 0.8419282, 663307.6815433, 0.3012088],\n            [5.9488299, 0.8380415, 689655.4839532, 0.2987797],\n        ],\n        # 9 m/s\n        [\n            [8.9779256, 0.7596713, 2397237.3791443, 0.2543815],\n            [6.6084854, 0.8080115, 960490.1060497, 0.2809176],\n            [6.7305708, 0.8030991, 1017314.2281904, 0.2781324],\n        ],\n        # 10 m/s\n        [\n            [9.9754729, 0.7499157, 3283592.6005045, 0.2494847],\n            [7.3621072, 0.7803734, 1334476.0326665, 0.2656783],\n            [7.5106613, 0.7755721, 1413887.2753700, 0.2631309],\n        ],\n        # 11 m/s\n        [\n            [10.9730201, 0.7276532, 4344217.6993801, 0.2386508],\n            [8.1489930, 0.7625169, 1808503.8150366, 0.2563388],\n            [8.2759469, 0.7621711, 1894884.8361479, 0.2561615],\n        ]\n    ]\n)\n\"\"\"\n\n\ngch_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.9689340, 0.8626155, 727222.6050018, 0.3146730],\n            [6.0360908, 0.8592082, 753814.9629960, 0.3123888],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.7170645, 0.8282386, 1059972.8615898, 0.2927795],\n            [6.8249569, 0.8233319, 1108480.0451319, 0.2898405],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [7.4669332, 0.7987766, 1441706.3550352, 0.2757103],\n            [7.6196359, 0.7939336, 1531527.9847411, 0.2730273],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [8.2691610, 0.7867811, 1972333.4291742, 0.2691218],\n            [8.3808845, 0.7866371, 2055834.1618762, 0.2690439],\n        ],\n    ]\n)\n\nyaw_added_recovery_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.9689332, 0.8626156, 727222.3540334, 0.3146730],\n            [6.0305406, 0.8594606, 751319.6495844, 0.3125571],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.7170636, 0.8282387, 1059972.4826657, 0.2927795],\n            [6.8187909, 0.8236123, 1105707.8700965, 0.2900073],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [7.4669323, 0.7987766, 1441705.8203841, 0.2757103],\n            [7.6128912, 0.7941382, 1527445.2805280, 0.2731400],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [8.2691601, 0.7867811, 1972332.7278100, 0.2691218],\n            [8.3736743, 0.7866464, 2050445.3384596, 0.2690489],\n        ],\n    ]\n)\n\nsecondary_steering_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.9521559, 0.8635693, 721623.9542957, 0.3153174],\n            [6.0187788, 0.8599955, 746031.6889128, 0.3129141],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.6982618, 0.8290937, 1051519.3934629, 0.2932959],\n            [6.8059255, 0.8241974, 1099923.7444659, 0.2903559],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [7.4461678, 0.7994645, 1429777.9285494, 0.2760940],\n            [7.5991268, 0.7945568, 1519127.2504621, 0.2733708],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [8.2481967, 0.7868081, 1956664.9757307, 0.2691365],\n            [8.3604363, 0.7866635, 2040551.4040835, 0.2690582],\n        ],\n    ]\n)\n\n\n# Note: compare the yawed vs non-yawed results. The upstream turbine\n# power should be lower in the yawed case. The following turbine\n# powers should higher in the yawed case.\n\n\ndef test_regression_tandem(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], baseline)\n\n\ndef test_regression_rotation(sample_inputs_fixture):\n    \"\"\"\n    Turbines in tandem and rotated.\n    The result from 270 degrees should match the results from 360 degrees.\n\n    Wind from the West (Left)\n\n    ^\n    |\n    y\n\n    1|1         3\n     |\n     |\n     |\n    0|0         2\n     |----------|\n      0         1  x->\n\n\n    Wind from the North (Top), rotated\n\n    ^\n    |\n    y\n\n    1|3         2\n     |\n     |\n     |\n    0|1         0\n     |----------|\n      0         1  x->\n\n    In 270, turbines 2 and 3 are waked. In 360, turbines 0 and 2 are waked.\n    The test compares turbines 2 and 3 with 0 and 2 from 270 and 360.\n    \"\"\"\n    TURBINE_DIAMETER = 126.0\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = [\n        0.0,\n        0.0,\n        5 * TURBINE_DIAMETER,\n        5 * TURBINE_DIAMETER,\n    ]\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = [\n        0.0,\n        5 * TURBINE_DIAMETER,\n        0.0,\n        5 * TURBINE_DIAMETER\n    ]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0, 360.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0, 8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1, 0.1]\n\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    farm_avg_velocities = average_velocity(floris.flow_field.u)\n\n    t0_270 = farm_avg_velocities[0, 0]  # upstream\n    t1_270 = farm_avg_velocities[0, 1]  # upstream\n    t2_270 = farm_avg_velocities[0, 2]  # waked\n    t3_270 = farm_avg_velocities[0, 3]  # waked\n\n    t0_360 = farm_avg_velocities[1, 0]  # waked\n    t1_360 = farm_avg_velocities[1, 1]  # upstream\n    t2_360 = farm_avg_velocities[1, 2]  # waked\n    t3_360 = farm_avg_velocities[1, 3]  # upstream\n\n    assert np.allclose(t0_270, t1_360)\n    assert np.allclose(t1_270, t3_360)\n    assert np.allclose(t2_270, t0_360)\n    assert np.allclose(t3_270, t2_360)\n\n\ndef test_regression_yaw(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], yawed_baseline)\n\n\ndef test_regression_gch(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed, yaw added recovery\n    correction enabled, and secondary steering enabled\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    ### With GCH off (via conftest), GCH should be same as Gauss\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    # Don't use the test values here, gch is off! See the docstring.\n    # if DEBUG:\n    #     print_test_values(\n    #         farm_avg_velocities,\n    #         farm_cts,\n    #         farm_powers,\n    #         farm_axial_inductions,\n    #     )\n\n    assert_results_arrays(test_results[0:4], yawed_baseline)\n\n\n    ### With GCH on, the results should change\n    sample_inputs_fixture.core[\"wake\"][\"enable_transverse_velocities\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_secondary_steering\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_yaw_added_recovery\"] = True\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], gch_baseline)\n\n\ndef test_regression_yaw_added_recovery(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed and yaw added recovery\n    correction enabled\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    sample_inputs_fixture.core[\"wake\"][\"enable_transverse_velocities\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_secondary_steering\"] = False\n    sample_inputs_fixture.core[\"wake\"][\"enable_yaw_added_recovery\"] = True\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], yaw_added_recovery_baseline)\n\n\ndef test_regression_secondary_steering(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed and secondary steering enabled\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    sample_inputs_fixture.core[\"wake\"][\"enable_transverse_velocities\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_secondary_steering\"] = True\n    sample_inputs_fixture.core[\"wake\"][\"enable_yaw_added_recovery\"] = False\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], secondary_steering_baseline)\n\n\ndef test_regression_small_grid_rotation(sample_inputs_fixture):\n    \"\"\"\n    This utilizes a 5x5 wind farm with the layout in a regular grid oriented along the cardinal\n    directions. The wind direction in this test is from 285 degrees which is slightly north of\n    west. The objective of this test is to create a case with a very slight rotation of the wind\n    farm to target the rotation and masking routines.\n\n    Where wake models are masked based on the x-location of a turbine, numerical precision\n    can cause masking to fail unexpectedly. For example, in the configuration here one of\n    the turbines has these delta x values;\n\n    [[4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]]\n\n    and therefore the masking statement is False when it should be True. This causes the current\n    turbine to be affected by its own wake. This test requires that at least in this particular\n    configuration the masking correctly filters grid points.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    X, Y = np.meshgrid(\n        6.0 * 126.0 * np.arange(0, 5, 1),\n        6.0 * 126.0 * np.arange(0, 5, 1)\n    )\n    X = X.flatten()\n    Y = Y.flatten()\n\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = X\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = Y\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    # farm_avg_velocities = average_velocity(floris.flow_field.u)\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        floris.flow_field.air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n\n    # A \"column\" is oriented parallel to the wind direction\n    # Columns 1 - 4 should have the same power profile\n    # Column 5 leading turbine is completely unwaked\n    # and the rest of the turbines have a partial wake from their immediate upstream turbine\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,5:10])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,10:15])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,15:20])\n    assert np.allclose(farm_powers[8,20], farm_powers[8,0])\n    assert np.allclose(farm_powers[8,21], farm_powers[8,21:25])\n\n\ndef test_full_flow_solver(sample_inputs_fixture):\n    \"\"\"\n    Full flow solver test with the flow field planar grid.\n    This requires one wind condition, and the grid is deliberately coarse to allow for\n    visually comparing results, as needed.\n    The u-component of velocity is compared, and the array has the shape\n    (n_findex, n_turbines, n grid points in x, n grid points in y, 3 grid points in z).\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"solver\"] = {\n        \"type\": \"flow_field_planar_grid\",\n        \"normal_vector\": \"z\",\n        \"planar_coordinate\": sample_inputs_fixture.core[\"farm\"][\"turbine_type\"][0][\"hub_height\"],\n        \"flow_field_grid_points\": [5, 5],\n        \"flow_field_bounds\": [None, None],\n    }\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.solve_for_viz()\n\n    velocities = floris.flow_field.u_sorted\n\n    assert_results_arrays(velocities, full_flow_baseline)\n"
  },
  {
    "path": "tests/reg_tests/jensen_jimenez_regression_test.py",
    "content": "\nimport numpy as np\n\nfrom floris.core import (\n    average_velocity,\n    axial_induction,\n    Core,\n    power,\n    rotor_effective_velocity,\n    thrust_coefficient,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n    N_FINDEX,\n    N_TURBINES,\n    print_test_values,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"jensen\"\nDEFLECTION_MODEL = \"jimenez\"\n\n\nbaseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n            [6.0660565, 0.8578454, 767287.2198744, 0.3114830],\n            [5.5204712, 0.8881097, 577575.9208353, 0.3327500],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n            [6.8298067, 0.8231113, 1110660.4518964, 0.2897093],\n            [6.3668912, 0.8441639, 902538.9934586, 0.3026196],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n            [7.5982117, 0.7945856, 1518587.8467982, 0.2733867],\n            [7.2042504, 0.8077903, 1294847.7809883, 0.2807914],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n            [8.4970746, 0.7864874, 2142673.1558338, 0.2689629],\n            [7.9997342, 0.7871282, 1770992.0756703, 0.2693098],\n        ],\n    ]\n)\n\nyawed_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [6.0816475, 0.8571363, 774296.7271893, 0.3110134],\n            [5.5272875, 0.8877222, 579850.4298177, 0.3324606],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.8472506, 0.8223180, 1118503.0309148, 0.2892383],\n            [6.3747452, 0.8438067, 906070.0511419, 0.3023935],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [7.6174285, 0.7940006, 1530191.8035935, 0.2730642],\n            [7.2119500, 0.8075204, 1299067.3876318, 0.2806375],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [8.5159500, 0.7864631, 2156780.3499849, 0.2689497],\n            [8.0047998, 0.7871218, 1774753.2988553, 0.2693064],\n        ],\n    ]\n)\n\nfull_flow_baseline = np.array(\n    [\n        [\n            [\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n            ],\n            [\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [5.55736296, 5.63646825, 5.708184  ],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n            ],\n            [\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [5.11849406, 5.19135235, 5.25740466],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n            ],\n            [\n                [7.88772361, 8.        , 8.10178821],\n                [7.18032699, 7.28253407, 7.37519358],\n                [4.98829055, 5.05929547, 5.12366755],\n                [7.18032699, 7.28253407, 7.37519358],\n                [7.88772361, 8.        , 8.10178821],\n            ],\n            [\n                [7.88772361, 8.        , 8.10178821],\n                [6.97109947, 6.37648724, 7.16028784],\n                [6.28699612, 6.37648724, 6.45761864],\n                [6.97109947, 6.37648724, 7.16028784],\n                [7.88772361, 8.        , 8.10178821],\n            ]\n        ]\n    ]\n)\n\n# Note: compare the yawed vs non-yawed results. The upstream turbine\n# power should be lower in the yawed case. The following turbine\n# powers should higher in the yawed case.\n\n\ndef test_regression_tandem(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], baseline)\n\n\ndef test_regression_rotation(sample_inputs_fixture):\n    \"\"\"\n    Turbines in tandem and rotated.\n    The result from 270 degrees should match the results from 360 degrees.\n\n    Wind from the West (Left)\n\n    ^\n    |\n    y\n\n    1|1         3\n     |\n     |\n     |\n    0|0         2\n     |----------|\n      0         1  x->\n\n\n    Wind from the North (Top), rotated\n\n    ^\n    |\n    y\n\n    1|3         2\n     |\n     |\n     |\n    0|1         0\n     |----------|\n      0         1  x->\n\n    In 270, turbines 2 and 3 are waked. In 360, turbines 0 and 2 are waked.\n    The test compares turbines 2 and 3 with 0 and 2 from 270 and 360.\n    \"\"\"\n    TURBINE_DIAMETER = 126.0\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = [\n        0.0,\n        0.0,\n        5 * TURBINE_DIAMETER,\n        5 * TURBINE_DIAMETER,\n    ]\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = [\n        0.0,\n        5 * TURBINE_DIAMETER,\n        0.0,\n        5 * TURBINE_DIAMETER\n    ]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0, 360.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0, 8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1, 0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    farm_avg_velocities = average_velocity(floris.flow_field.u)\n\n    t0_270 = farm_avg_velocities[0, 0]  # upstream\n    t1_270 = farm_avg_velocities[0, 1]  # upstream\n    t2_270 = farm_avg_velocities[0, 2]  # waked\n    t3_270 = farm_avg_velocities[0, 3]  # waked\n\n    t0_360 = farm_avg_velocities[1, 0]  # waked\n    t1_360 = farm_avg_velocities[1, 1]  # upstream\n    t2_360 = farm_avg_velocities[1, 2]  # waked\n    t3_360 = farm_avg_velocities[1, 3]  # upstream\n\n    assert np.allclose(t0_270, t1_360)\n    assert np.allclose(t1_270, t3_360)\n    assert np.allclose(t2_270, t0_360)\n    assert np.allclose(t3_270, t2_360)\n\n\ndef test_regression_yaw(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4\n        )\n\n    assert_results_arrays(test_results[0:4], yawed_baseline)\n\n\ndef test_regression_small_grid_rotation(sample_inputs_fixture):\n    \"\"\"\n    This utilizes a 5x5 wind farm with the layout in a regular grid oriented along the cardinal\n    directions. The wind direction in this test is from 285 degrees which is slightly north of\n    west. The objective of this test is to create a case with a very slight rotation of the wind\n    farm to target the rotation and masking routines.\n\n    Where wake models are masked based on the x-location of a turbine, numerical precision\n    can cause masking to fail unexpectedly. For example, in the configuration here one of\n    the turbines has these delta x values;\n\n    [[4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]]\n\n    and therefore the masking statement is False when it should be True. This causes the current\n    turbine to be affected by its own wake. This test requires that at least in this particular\n    configuration the masking correctly filters grid points.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    X, Y = np.meshgrid(\n        6.0 * 126.0 * np.arange(0, 5, 1),\n        6.0 * 126.0 * np.arange(0, 5, 1)\n    )\n    X = X.flatten()\n    Y = Y.flatten()\n\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = X\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = Y\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    # farm_avg_velocities = average_velocity(floris.flow_field.u)\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n\n    # farm_eff_velocities = rotor_effective_velocity(\n    #     floris.flow_field.air_density,\n    #     floris.farm.ref_air_densities,\n    #     velocities,\n    #     yaw_angles,\n    #     tilt_angles,\n    #     floris.farm.ref_tilts,\n    #     floris.farm.pPs,\n    #     floris.farm.pTs,\n    #     floris.farm.turbine_tilt_interps,\n    #     floris.farm.correct_cp_ct_for_tilt,\n    #     floris.farm.turbine_type_map,\n    # )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n\n    # A \"column\" is oriented parallel to the wind direction\n    # Columns 1 - 4 should have the same power profile\n    # Column 5 is completely unwaked in this model\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,5:10])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,10:15])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,15:20])\n    assert np.allclose(farm_powers[8,20], farm_powers[8,20:25])\n\n\ndef test_full_flow_solver(sample_inputs_fixture):\n    \"\"\"\n    Full flow solver test with the flow field planar grid.\n    This requires one wind condition, and the grid is deliberately coarse to allow for\n    visually comparing results, as needed.\n    The u-component of velocity is compared, and the array has the shape\n    (n_findex, n_turbines, n grid points in x, n grid points in y, 3 grid points in z).\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"solver\"] = {\n        \"type\": \"flow_field_planar_grid\",\n        \"normal_vector\": \"z\",\n        \"planar_coordinate\": sample_inputs_fixture.core[\"farm\"][\"turbine_type\"][0][\"hub_height\"],\n        \"flow_field_grid_points\": [5, 5],\n        \"flow_field_bounds\": [None, None],\n    }\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.solve_for_viz()\n\n    velocities = floris.flow_field.u_sorted\n\n    assert_results_arrays(velocities, full_flow_baseline)\n"
  },
  {
    "path": "tests/reg_tests/none_regression_test.py",
    "content": "\nimport numpy as np\nimport pytest\n\nfrom floris.core import (\n    average_velocity,\n    axial_induction,\n    Core,\n    power,\n    rotor_effective_velocity,\n    thrust_coefficient,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n    N_FINDEX,\n    N_TURBINES,\n    print_test_values,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"none\"\nDEFLECTION_MODEL = \"none\"\n\n\nbaseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n        ],\n    ]\n)\n\nyawed_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9803783, 0.7605249, 1683956.3885389, 0.2548147],\n            [7.9803783, 0.7605249, 1683956.3885389, 0.2548147],\n            [7.9803783, 0.7605249, 1683956.3885389, 0.2548147],\n        ],\n        # 9 m/s\n        [\n            [8.9779256, 0.7596713, 2397237.3791443, 0.2543815],\n            [8.9779256, 0.7596713, 2397237.3791443, 0.2543815],\n            [8.9779256, 0.7596713, 2397237.3791443, 0.2543815],\n        ],\n        # 10 m/s\n        [\n            [9.9754729, 0.7499157, 3283592.6005045, 0.2494847],\n            [9.9754729, 0.7499157, 3283592.6005045, 0.2494847],\n            [9.9754729, 0.7499157, 3283592.6005045, 0.2494847],\n        ],\n        # 11 m/s\n        [\n            [10.9730201, 0.7276532, 4344217.6993801, 0.2386508],\n            [10.9730201, 0.7276532, 4344217.6993801, 0.2386508],\n            [10.9730201, 0.7276532, 4344217.6993801, 0.2386508],\n        ]\n    ]\n)\n\nfull_flow_baseline = np.array(\n    [\n        [\n            [\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n            ],\n            [\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n            ],\n            [\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n            ],\n            [\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n            ],\n            [\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n                [7.88772361, 8.         , 8.10178821],\n            ],\n        ]\n    ]\n)\n\n# Note: compare the yawed vs non-yawed results. The upstream turbine\n# power should be lower in the yawed case. The following turbine\n# powers should higher in the yawed case.\n\n\ndef test_regression_tandem(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], baseline)\n\n\ndef test_regression_rotation(sample_inputs_fixture):\n    \"\"\"\n    Turbines in tandem and rotated.\n    The result from 270 degrees should match the results from 360 degrees.\n\n    Wind from the West (Left)\n\n    ^\n    |\n    y\n\n    1|1         3\n     |\n     |\n     |\n    0|0         2\n     |----------|\n      0         1  x->\n\n\n    Wind from the North (Top), rotated\n\n    ^\n    |\n    y\n\n    1|3         2\n     |\n     |\n     |\n    0|1         0\n     |----------|\n      0         1  x->\n\n    In 270, turbines 2 and 3 are waked. In 360, turbines 0 and 2 are waked.\n    The test compares turbines 2 and 3 with 0 and 2 from 270 and 360.\n    \"\"\"\n    TURBINE_DIAMETER = 126.0\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = [\n        0.0,\n        0.0,\n        5 * TURBINE_DIAMETER,\n        5 * TURBINE_DIAMETER,\n    ]\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = [\n        0.0,\n        5 * TURBINE_DIAMETER,\n        0.0,\n        5 * TURBINE_DIAMETER\n    ]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0, 360.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0, 8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1, 0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    farm_avg_velocities = average_velocity(floris.flow_field.u)\n\n    t0_270 = farm_avg_velocities[0, 0]  # upstream\n    t1_270 = farm_avg_velocities[0, 1]  # upstream\n    t2_270 = farm_avg_velocities[0, 2]  # waked\n    t3_270 = farm_avg_velocities[0, 3]  # waked\n\n    t0_360 = farm_avg_velocities[1, 0]  # waked\n    t1_360 = farm_avg_velocities[1, 1]  # upstream\n    t2_360 = farm_avg_velocities[1, 2]  # waked\n    t3_360 = farm_avg_velocities[1, 3]  # upstream\n\n    assert np.allclose(t0_270, t1_360)\n    assert np.allclose(t1_270, t3_360)\n    assert np.allclose(t2_270, t0_360)\n    assert np.allclose(t3_270, t2_360)\n\n\ndef test_regression_yaw(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    with pytest.raises(ValueError):\n        floris.steady_state_atmospheric_condition()\n\n\ndef test_regression_small_grid_rotation(sample_inputs_fixture):\n    \"\"\"\n    This utilizes a 5x5 wind farm with the layout in a regular grid oriented along the cardinal\n    directions. The wind direction in this test is from 285 degrees which is slightly north of\n    west. The objective of this test is to create a case with a very slight rotation of the wind\n    farm to target the rotation and masking routines.\n\n    Where wake models are masked based on the x-location of a turbine, numerical precision\n    can cause masking to fail unexpectedly. For example, in the configuration here one of\n    the turbines has these delta x values;\n\n    [[4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]]\n\n    and therefore the masking statement is False when it should be True. This causes the current\n    turbine to be affected by its own wake. This test requires that at least in this particular\n    configuration the masking correctly filters grid points.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    X, Y = np.meshgrid(\n        6.0 * 126.0 * np.arange(0, 5, 1),\n        6.0 * 126.0 * np.arange(0, 5, 1)\n    )\n    X = X.flatten()\n    Y = Y.flatten()\n\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = X\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = Y\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    # farm_avg_velocities = average_velocity(floris.flow_field.u)\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n\n    # A \"column\" is oriented parallel to the wind direction\n    # Columns 1 - 4 should have the same power profile\n    # Column 5 leading turbine is completely unwaked\n    # and the rest of the turbines have a partial wake from their immediate upstream turbine\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,5:10])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,10:15])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,15:20])\n    assert np.allclose(farm_powers[8,20], farm_powers[8,0])\n    assert np.allclose(farm_powers[8,21], farm_powers[8,21:25])\n\n\ndef test_full_flow_solver(sample_inputs_fixture):\n    \"\"\"\n    Full flow solver test with the flow field planar grid.\n    This requires one wind condition, and the grid is deliberately coarse to allow for\n    visually comparing results, as needed.\n    The u-component of velocity is compared, and the array has the shape\n    (n_findex, n_turbines, n grid points in x, n grid points in y, 3 grid points in z).\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"solver\"] = {\n        \"type\": \"flow_field_planar_grid\",\n        \"normal_vector\": \"z\",\n        \"planar_coordinate\": sample_inputs_fixture.core[\"farm\"][\"turbine_type\"][0][\"hub_height\"],\n        \"flow_field_grid_points\": [5, 5],\n        \"flow_field_bounds\": [None, None],\n    }\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.solve_for_viz()\n\n    velocities = floris.flow_field.u_sorted\n\n    assert_results_arrays(velocities, full_flow_baseline)\n"
  },
  {
    "path": "tests/reg_tests/random_search_layout_opt_regression_test.py",
    "content": "\nimport numpy as np\nimport pandas as pd\n\nfrom floris import FlorisModel, WindRose\nfrom floris.optimization.layout_optimization.layout_optimization_random_search import (\n    LayoutOptimizationRandomSearch,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\nlocations_baseline_aep = np.array(\n    [\n        [0.0, 243.05304475, 1260.0],\n        [0.0, 959.83979244,    0.0],\n    ]\n)\nbaseline_aep = 45226182795.34081\n\nlocations_baseline_value = np.array(\n    [\n        [387.0, 100.0, 200.0, 300.0],\n        [192.0, 300.0, 100.0, 300.0],\n    ]\n)\nbaseline_value = 8780876351.32277\n\n\ndef test_random_search_layout_opt(sample_inputs_fixture):\n    \"\"\"\n    The SciPy optimization method optimizes turbine layout using SciPy's minimize method. This test\n    compares the optimization results from the SciPy layout optimization for a simple farm with a\n    simple wind rose to stored baseline results.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    boundaries = [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)]\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    wd_array = np.arange(0, 360.0, 5.0)\n    ws_array = np.array([8.0])\n\n    wind_rose = WindRose(\n        wind_directions=wd_array,\n        wind_speeds=ws_array,\n        ti_table=0.1,\n    )\n    D = 126.0 # Rotor diameter for the NREL 5 MW\n    fmodel.set(\n        layout_x=[0.0, 5 * D, 10 * D],\n        layout_y=[0.0, 0.0, 0.0],\n        wind_data=wind_rose\n    )\n\n    layout_opt = LayoutOptimizationRandomSearch(\n        fmodel=fmodel,\n        boundaries=boundaries,\n        min_dist_D=5,\n        seconds_per_iteration=1,\n        total_optimization_seconds=1,\n        use_dist_based_init=False,\n        random_seed=0,\n    )\n    sol = layout_opt._test_optimize()\n    optimized_aep = sol[0]\n    locations_opt = np.array([sol[1], sol[2]])\n\n    if DEBUG:\n        print(locations_opt)\n        print(optimized_aep)\n\n    assert_results_arrays(locations_opt, locations_baseline_aep)\n    assert np.isclose(optimized_aep, baseline_aep)\n\ndef test_random_search_layout_opt_value(sample_inputs_fixture):\n    \"\"\"\n    This test compares the optimization results from the SciPy layout optimization for a simple\n    farm with a simple wind rose to stored baseline results, optimizing for annual value production\n    instead of AEP. The value of the energy produced depends on the wind direction, causing the\n    optimal layout to differ from the case where the objective is maximum AEP. In this case, because\n    the value is much higher when the wind is from the north or south, the turbines are staggered to\n    avoid wake interactions for northerly and southerly winds.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    boundaries = [(0.0, 0.0), (0.0, 400.0), (400.0, 400.0), (400.0, 0.0), (0.0, 0.0)]\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    # set wind conditions and values using a WindData object with the default uniform frequency\n    wd_array = np.arange(0, 360.0, 5.0)\n    ws_array = np.array([8.0])\n\n    # Define the value table such that the value of the energy produced is\n    # significantly higher when the wind direction is close to the north or\n    # south, and zero when the wind is from the east or west.\n    value_table = (0.5 + 0.5*np.cos(2*np.radians(wd_array)))**10\n    value_table = value_table.reshape((len(wd_array),1))\n\n    wind_rose = WindRose(\n        wind_directions=wd_array,\n        wind_speeds=ws_array,\n        ti_table=0.1,\n        value_table=value_table\n    )\n\n    # Start with a rectangular 4-turbine array with 2D spacing\n    D = 126.0 # Rotor diameter for the NREL 5 MW\n    fmodel.set(\n        layout_x=200 + np.array([-1 * D, -1 * D, 1 * D, 1 * D]),\n        layout_y=200 + np.array([-1* D, 1 * D, -1 * D, 1 * D]),\n        wind_data=wind_rose,\n    )\n\n    layout_opt = LayoutOptimizationRandomSearch(\n        fmodel=fmodel,\n        boundaries=boundaries,\n        min_dist_D=5,\n        seconds_per_iteration=1,\n        total_optimization_seconds=1,\n        use_dist_based_init=True,\n        random_seed=0,\n        use_value=True,\n    )\n    sol = layout_opt._test_optimize()\n    optimized_value = sol[0]\n    locations_opt = np.array([sol[1], sol[2]])\n\n    if DEBUG:\n        print(locations_opt)\n        print(optimized_value)\n\n    assert_results_arrays(locations_opt, locations_baseline_value)\n    assert np.isclose(optimized_value, baseline_value)\n"
  },
  {
    "path": "tests/reg_tests/scipy_layout_opt_regression.py",
    "content": "\nimport numpy as np\nimport pandas as pd\n\nfrom floris import FlorisModel, WindRose\nfrom floris.optimization.layout_optimization.layout_optimization_scipy import (\n    LayoutOptimizationScipy,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\nbaseline = np.array(\n    [\n        [0.0, 495.37587653, 1000.0],\n        [5.0, 11.40800868, 24.93196392],\n    ]\n)\n\nbaseline_value = np.array(\n    [\n        [8.68262334e+01, 1.04360964e-12, 4.00000000e+02, 2.36100415e+02],\n        [1.69954798e-14, 4.00000000e+02, 0.00000000e+00, 4.00000000e+02],\n    ]\n)\n\n\ndef test_scipy_layout_opt(sample_inputs_fixture):\n    \"\"\"\n    The SciPy optimization method optimizes turbine layout using SciPy's minimize method. This test\n    compares the optimization results from the SciPy layout optimization for a simple farm with a\n    simple wind rose to stored baseline results.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    opt_options = {\n        \"maxiter\": 5,\n        \"disp\": True,\n        \"iprint\": 2,\n        \"ftol\": 1e-12,\n        \"eps\": 0.01,\n    }\n\n    boundaries = [(0.0, 0.0), (0.0, 1000.0), (1000.0, 1000.0), (1000.0, 0.0), (0.0, 0.0)]\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    wd_array = np.arange(0, 360.0, 5.0)\n    ws_array = 8.0 * np.ones_like(wd_array)\n    ti_array = 0.1 * np.ones_like(wd_array)\n    D = 126.0 # Rotor diameter for the NREL 5 MW\n    fmodel.set(\n        layout_x=[0.0, 5 * D, 10 * D],\n        layout_y=[0.0, 0.0, 0.0],\n        wind_directions=wd_array,\n        wind_speeds=ws_array,\n        turbulence_intensities=ti_array,\n    )\n\n    layout_opt = LayoutOptimizationScipy(fmodel, boundaries, optOptions=opt_options)\n    sol = layout_opt.optimize()\n    locations_opt = np.array([sol[0], sol[1]])\n\n    if DEBUG:\n        print(baseline)\n        print(locations_opt)\n\n    assert_results_arrays(locations_opt, baseline)\n\ndef test_scipy_layout_opt_value(sample_inputs_fixture):\n    \"\"\"\n    This test compares the optimization results from the SciPy layout optimization for a simple\n    farm with a simple wind rose to stored baseline results, optimizing for annual value production\n    instead of AEP. The value of the energy produced depends on the wind direction, causing the\n    optimal layout to differ from the case where the objective is maximum AEP. In this case, because\n    the value is much higher when the wind is from the north or south, the turbines are staggered to\n    avoid wake interactions for northerly and southerly winds.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    opt_options = {\n        \"maxiter\": 5,\n        \"disp\": True,\n        \"iprint\": 2,\n        \"ftol\": 1e-12,\n        \"eps\": 0.1,\n    }\n\n    boundaries = [(0.0, 0.0), (0.0, 400.0), (400.0, 400.0), (400.0, 0.0), (0.0, 0.0)]\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    # set wind conditions and values using a WindData object with the default uniform frequency\n    wd_array = np.arange(0, 360.0, 5.0)\n    ws_array = np.array([8.0])\n\n    # Define the value table such that the value of the energy produced is\n    # significantly higher when the wind direction is close to the north or\n    # south, and zero when the wind is from the east or west.\n    value_table = (0.5 + 0.5*np.cos(2*np.radians(wd_array)))**10\n    value_table = value_table.reshape((len(wd_array),1))\n\n    wind_rose = WindRose(\n        wind_directions=wd_array,\n        wind_speeds=ws_array,\n        ti_table=0.1,\n        value_table=value_table\n    )\n\n    # Start with a rectangular 4-turbine array with 2D spacing\n    D = 126.0 # Rotor diameter for the NREL 5 MW\n    fmodel.set(\n        layout_x=200 + np.array([-1 * D, -1 * D, 1 * D, 1 * D]),\n        layout_y=200 + np.array([-1* D, 1 * D, -1 * D, 1 * D]),\n        wind_data=wind_rose,\n    )\n\n    layout_opt = LayoutOptimizationScipy(\n        fmodel,\n        boundaries,\n        optOptions=opt_options,\n        use_value=True\n    )\n    sol = layout_opt.optimize()\n    locations_opt = np.array([sol[0], sol[1]])\n\n    if DEBUG:\n        print(baseline)\n        print(locations_opt)\n\n    assert_results_arrays(locations_opt, baseline_value)\n"
  },
  {
    "path": "tests/reg_tests/turbopark_regression_test.py",
    "content": "\nimport numpy as np\n\nfrom floris.core import (\n    average_velocity,\n    axial_induction,\n    Core,\n    power,\n    rotor_effective_velocity,\n    thrust_coefficient,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n    N_FINDEX,\n    N_TURBINES,\n    print_test_values,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"turbopark\"\nDEFLECTION_MODEL = \"gauss\"\nCOMBINATION_MODEL = \"fls\"\n\nbaseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n            [6.0332948, 0.8593353, 752557.9240063, 0.3124735],\n            [5.4029800, 0.8947888, 538370.5108659, 0.3378186],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n            [6.7887441, 0.8249788, 1092199.1775234, 0.2908223],\n            [6.0678594, 0.8577634, 768097.7785191, 0.3114286],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n            [7.5453629, 0.7962514, 1487438.4031455, 0.2743074],\n            [6.7548552, 0.8265200, 1076963.1412833, 0.2917453],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n            [8.3436376, 0.7866851, 2027996.3027579, 0.2690699],\n            [7.4626804, 0.7989174, 1439263.3915910, 0.2757889],\n        ],\n    ]\n)\n\n\nyawed_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [6.0523119, 0.8584704, 761107.7639542, 0.3118979],\n            [5.4177841, 0.8939472, 543310.4550423, 0.3371713],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.8101438, 0.8240055, 1101820.2623232, 0.2902415],\n            [6.0851644, 0.8569764, 775877.8906008, 0.3109077],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [7.5691494, 0.7955016, 1501458.3309846, 0.2738925],\n            [6.7745474, 0.8256244, 1085816.5021615, 0.2912085],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [8.3695194, 0.7866518, 2047340.0279521, 0.2690518],\n            [7.4830530, 0.7982426, 1450966.1620998, 0.2754129],\n        ],\n    ]\n)\n\n# Note: compare the yawed vs non-yawed results. The upstream turbine\n# power should be lower in the yawed case. The following turbine\n# powers should higher in the yawed case.\n\n\ndef test_regression_tandem(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"combination_model\"] = COMBINATION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], baseline)\n\n\ndef test_regression_rotation(sample_inputs_fixture):\n    \"\"\"\n    Turbines in tandem and rotated.\n    The result from 270 degrees should match the results from 360 degrees.\n\n    Wind from the West (Left)\n\n    ^\n    |\n    y\n\n    1|1         3\n     |\n     |\n     |\n    0|0         2\n     |----------|\n      0         1  x->\n\n\n    Wind from the North (Top), rotated\n\n    ^\n    |\n    y\n\n    1|3         2\n     |\n     |\n     |\n    0|1         0\n     |----------|\n      0         1  x->\n\n    In 270, turbines 2 and 3 are waked. In 360, turbines 0 and 2 are waked.\n    The test compares turbines 2 and 3 with 0 and 2 from 270 and 360.\n    \"\"\"\n    TURBINE_DIAMETER = 126.0\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"combination_model\"] = COMBINATION_MODEL\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = [\n        0.0,\n        0.0,\n        5 * TURBINE_DIAMETER,\n        5 * TURBINE_DIAMETER,\n    ]\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = [\n        0.0,\n        5 * TURBINE_DIAMETER,\n        0.0,\n        5 * TURBINE_DIAMETER\n    ]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0, 360.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0, 8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1, 0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    farm_avg_velocities = average_velocity(floris.flow_field.u)\n\n    t0_270 = farm_avg_velocities[0, 0]  # upstream\n    t1_270 = farm_avg_velocities[0, 1]  # upstream\n    t2_270 = farm_avg_velocities[0, 2]  # waked\n    t3_270 = farm_avg_velocities[0, 3]  # waked\n\n    t0_360 = farm_avg_velocities[1, 0]  # waked\n    t1_360 = farm_avg_velocities[1, 1]  # upstream\n    t2_360 = farm_avg_velocities[1, 2]  # waked\n    t3_360 = farm_avg_velocities[1, 3]  # upstream\n\n    assert np.allclose(t0_270, t1_360)\n    assert np.allclose(t1_270, t3_360)\n    assert np.allclose(t2_270, t0_360)\n    assert np.allclose(t3_270, t2_360)\n\n\ndef test_regression_yaw(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], yawed_baseline)\n\ndef test_regression_small_grid_rotation(sample_inputs_fixture):\n    \"\"\"\n    Where wake models are masked based on the x-location of a turbine, numerical precision\n    can cause masking to fail unexpectedly. For example, in the configuration here one of\n    the turbines has these delta x values;\n\n    [[4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]]\n\n    and therefore the masking statement is False when it should be True. This causes the current\n    turbine to be affected by its own wake. This test requires that at least in this particular\n    configuration the masking correctly filters grid points.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"combination_model\"] = COMBINATION_MODEL\n    X, Y = np.meshgrid(\n        6.0 * 126.0 * np.arange(0, 5, 1),\n        6.0 * 126.0 * np.arange(0, 5, 1)\n    )\n    X = X.flatten()\n    Y = Y.flatten()\n\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = X\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = Y\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    # farm_avg_velocities = average_velocity(floris.flow_field.u)\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        floris.flow_field.air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n\n    # A \"column\" is oriented parallel to the wind direction\n    # Columns 1 - 4 should have the same power profile\n    # Column 5 leading turbine is completely unwaked\n    # and the rest of the turbines have a partial wake from their immediate upstream turbine\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,5:10])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,10:15])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,15:20])\n    assert np.allclose(farm_powers[8,20], farm_powers[8,0])\n    assert np.allclose(farm_powers[8,21], farm_powers[8,21:25])\n\n'''\n## Not implemented in TurbOPark\ndef test_full_flow_solver(sample_inputs_fixture):\n    \"\"\"\n    Full flow solver test with the flow field planar grid.\n    This requires one wind condition, and the grid is deliberately coarse to allow for\n    visually comparing results, as needed.\n    The u-component of velocity is compared, and the array has the shape\n    (n_findex, n_turbines, n grid points in x, n grid points in y, 3 grid points in z).\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"solver\"] = {\n        \"type\": \"flow_field_planar_grid\",\n        \"normal_vector\": \"z\",\n        \"planar_coordinate\": sample_inputs_fixture.core[\"farm\"][\"turbine_type\"][0][\"hub_height\"],\n        \"flow_field_grid_points\": [5, 5],\n        \"flow_field_bounds\": [None, None],\n    }\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.solve_for_viz()\n\n    velocities = floris.flow_field.u_sorted\n    print(velocities)\n    assert_results_arrays(velocities, full_flow_baseline)\n'''\n"
  },
  {
    "path": "tests/reg_tests/turboparkgauss_regression_test.py",
    "content": "\nimport numpy as np\n\nfrom floris.core import (\n    average_velocity,\n    axial_induction,\n    Core,\n    power,\n    rotor_effective_velocity,\n    thrust_coefficient,\n)\nfrom tests.conftest import (\n    assert_results_arrays,\n    N_FINDEX,\n    N_TURBINES,\n    print_test_values,\n)\n\n\nDEBUG = False\nVELOCITY_MODEL = \"turboparkgauss\"\nDEFLECTION_MODEL = \"gauss\"\nCOMBINATION_MODEL = \"sosfs\"\n\nbaseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7871515, 1753954.4591792, 0.2693224],\n            [5.3669227, 0.8968386, 526338.6265211, 0.3394063],\n            [4.7291434, 0.9398463, 342625.1907593, 0.3773687],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7858774, 2496427.8618358, 0.2686331],\n            [6.0385619, 0.8590958, 754925.9561188, 0.3123139],\n            [5.2198714, 0.9051982, 477269.3475684, 0.3460505],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7838789, 3417797.0050916, 0.2675559],\n            [6.7109723, 0.8285157, 1057233.8964038, 0.2929467],\n            [5.7609373, 0.8744397, 657816.5966079, 0.3228276],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7565157, 4519404.3072862, 0.2532794],\n            [7.4177796, 0.8004049, 1413470.6329668, 0.2766196],\n            [6.3467168, 0.8450814, 893468.8191848, 0.3032015],\n        ],\n    ]\n)\n\n\nyawed_baseline = np.array(\n    [\n        # 8 m/s\n        [\n            [7.9736858, 0.7841561, 1741508.6722008, 0.2671213],\n            [5.3686096, 0.8967427, 526901.4969868, 0.3393316],\n            [4.7296392, 0.9398058, 342737.3617937, 0.3773274],\n        ],\n        # 9 m/s\n        [\n            [8.9703965, 0.7828869, 2480428.8963141, 0.2664440],\n            [6.0405714, 0.8590044, 755829.3886024, 0.3122531],\n            [5.2206194, 0.9051556, 477518.9548881, 0.3460159],\n        ],\n        # 10 m/s\n        [\n            [9.9671073, 0.7808960, 3395681.0032992, 0.2653854],\n            [6.7133964, 0.8284054, 1058323.7446597, 0.2928801],\n            [5.7619351, 0.8743830, 658149.5244311, 0.3227875],\n        ],\n        # 11 m/s\n        [\n            [10.9638180, 0.7536370, 4488242.9153943, 0.2513413],\n            [7.4229011, 0.8002352, 1416412.6499511, 0.2765247],\n            [6.3490875, 0.8449736, 894534.6529145, 0.3031330],\n        ],\n    ]\n)\n\nfull_flow_baseline = np.array(\n    [\n        [\n            [\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n                [7.88772361, 8.        , 8.10178821],\n            ],\n            [\n                [7.88772229, 7.99999863, 8.10178685],\n                [7.79725047, 7.90606371, 8.00885965],\n                [4.18190854, 4.15233328, 4.29539865],\n                [7.79725047, 7.90606371, 8.00885965],\n                [7.88772229, 7.99999863, 8.10178685],\n            ],\n            [\n                [7.88768632, 7.99996148, 8.1017499 ],\n                [7.66326846, 7.7681154 , 7.87123883],\n                [3.69538982, 3.66849132, 3.79562999],\n                [7.66326846, 7.7681154 , 7.87123883],\n                [7.88768632, 7.99996148, 8.1017499 ],\n            ],\n            [\n                [7.88740669, 7.99967377, 8.10146266],\n                [7.50793067, 7.6089272 , 7.71165714],\n                [3.64994795, 3.63535913, 3.74869   ],\n                [7.50793067, 7.6089272 , 7.71165714],\n                [7.88740669, 7.99967377, 8.10146266],\n            ],\n            [\n                [7.88664826, 7.99889554, 8.10068331],\n                [7.44424308, 7.54429736, 7.64614946],\n                [4.32643439, 4.33927499, 4.44299895],\n                [7.44424308, 7.54429736, 7.64614946],\n                [7.88664826, 7.99889554, 8.10068331],\n            ]\n        ]\n    ]\n)\n\n# Note: compare the yawed vs non-yawed results. The upstream turbine\n# power should be lower in the yawed case. The following turbine\n# powers should higher in the yawed case.\n\n\ndef test_regression_tandem(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"combination_model\"] = COMBINATION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], baseline)\n\n\ndef test_regression_rotation(sample_inputs_fixture):\n    \"\"\"\n    Turbines in tandem and rotated.\n    The result from 270 degrees should match the results from 360 degrees.\n\n    Wind from the West (Left)\n\n    ^\n    |\n    y\n\n    1|1         3\n     |\n     |\n     |\n    0|0         2\n     |----------|\n      0         1  x->\n\n\n    Wind from the North (Top), rotated\n\n    ^\n    |\n    y\n\n    1|3         2\n     |\n     |\n     |\n    0|1         0\n     |----------|\n      0         1  x->\n\n    In 270, turbines 2 and 3 are waked. In 360, turbines 0 and 2 are waked.\n    The test compares turbines 2 and 3 with 0 and 2 from 270 and 360.\n    \"\"\"\n    TURBINE_DIAMETER = 126.0\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"combination_model\"] = COMBINATION_MODEL\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = [\n        0.0,\n        0.0,\n        5 * TURBINE_DIAMETER,\n        5 * TURBINE_DIAMETER,\n    ]\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = [\n        0.0,\n        5 * TURBINE_DIAMETER,\n        0.0,\n        5 * TURBINE_DIAMETER\n    ]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0, 360.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0, 8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1, 0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    farm_avg_velocities = average_velocity(floris.flow_field.u)\n\n    t0_270 = farm_avg_velocities[0, 0]  # upstream\n    t1_270 = farm_avg_velocities[0, 1]  # upstream\n    t2_270 = farm_avg_velocities[0, 2]  # waked\n    t3_270 = farm_avg_velocities[0, 3]  # waked\n\n    t0_360 = farm_avg_velocities[1, 0]  # waked\n    t1_360 = farm_avg_velocities[1, 1]  # upstream\n    t2_360 = farm_avg_velocities[1, 2]  # waked\n    t3_360 = farm_avg_velocities[1, 3]  # upstream\n\n    assert np.allclose(t0_270, t1_360)\n    assert np.allclose(t1_270, t3_360)\n    assert np.allclose(t2_270, t0_360)\n    assert np.allclose(t3_270, t2_360)\n\n\ndef test_regression_yaw(sample_inputs_fixture):\n    \"\"\"\n    Tandem turbines with the upstream turbine yawed\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n\n    yaw_angles = np.zeros((N_FINDEX, N_TURBINES))\n    yaw_angles[:,0] = 5.0\n    floris.farm.yaw_angles = yaw_angles\n\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    n_turbines = floris.farm.n_turbines\n    n_findex = floris.flow_field.n_findex\n\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    air_density = floris.flow_field.air_density\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n    test_results = np.zeros((n_findex, n_turbines, 4))\n\n    farm_avg_velocities = average_velocity(\n        velocities,\n    )\n    farm_cts = thrust_coefficient(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_thrust_coefficient_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    farm_axial_inductions = axial_induction(\n        velocities,\n        turbulence_intensities,\n        air_density,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_axial_induction_functions,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.correct_cp_ct_for_tilt,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n    for i in range(n_findex):\n        for j in range(n_turbines):\n            test_results[i, j, 0] = farm_avg_velocities[i, j]\n            test_results[i, j, 1] = farm_cts[i, j]\n            test_results[i, j, 2] = farm_powers[i, j]\n            test_results[i, j, 3] = farm_axial_inductions[i, j]\n\n    if DEBUG:\n        print_test_values(\n            farm_avg_velocities,\n            farm_cts,\n            farm_powers,\n            farm_axial_inductions,\n            max_findex_print=4,\n        )\n\n    assert_results_arrays(test_results[0:4], yawed_baseline)\n\ndef test_regression_small_grid_rotation(sample_inputs_fixture):\n    \"\"\"\n    Where wake models are masked based on the x-location of a turbine, numerical precision\n    can cause masking to fail unexpectedly. For example, in the configuration here one of\n    the turbines has these delta x values;\n\n    [[4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]\n     [4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13 4.54747351e-13]]\n\n    and therefore the masking statement is False when it should be True. This causes the current\n    turbine to be affected by its own wake. This test requires that at least in this particular\n    configuration the masking correctly filters grid points.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"combination_model\"] = COMBINATION_MODEL\n    X, Y = np.meshgrid(\n        6.0 * 126.0 * np.arange(0, 5, 1),\n        6.0 * 126.0 * np.arange(0, 5, 1)\n    )\n    X = X.flatten()\n    Y = Y.flatten()\n\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = X\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = Y\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.initialize_domain()\n    floris.steady_state_atmospheric_condition()\n\n    # farm_avg_velocities = average_velocity(floris.flow_field.u)\n    velocities = floris.flow_field.u\n    turbulence_intensities = floris.flow_field.turbulence_intensity_field\n    yaw_angles = floris.farm.yaw_angles\n    tilt_angles = floris.farm.tilt_angles\n    power_setpoints = floris.farm.power_setpoints\n    awc_modes = floris.farm.awc_modes\n    awc_amplitudes = floris.farm.awc_amplitudes\n\n    farm_powers = power(\n        velocities,\n        turbulence_intensities,\n        floris.flow_field.air_density,\n        floris.farm.turbine_power_functions,\n        yaw_angles,\n        tilt_angles,\n        power_setpoints,\n        awc_modes,\n        awc_amplitudes,\n        floris.farm.turbine_tilt_interps,\n        floris.farm.turbine_type_map,\n        floris.farm.turbine_power_thrust_tables,\n    )\n\n    # A \"column\" is oriented parallel to the wind direction\n    # Columns 1 - 4 should have the same power profile\n    # Column 5 leading turbine is completely unwaked\n    # and the rest of the turbines have a partial wake from their immediate upstream turbine\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,5:10])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,10:15])\n    assert np.allclose(farm_powers[8,0:5], farm_powers[8,15:20])\n    assert np.allclose(farm_powers[8,20], farm_powers[8,0])\n    assert np.allclose(farm_powers[8,21], farm_powers[8,21:25])\n\n# TurboParkGauss enables full_flow_solver\ndef test_full_flow_solver(sample_inputs_fixture):\n    \"\"\"\n    Full flow solver test with the flow field planar grid.\n    This requires one wind condition, and the grid is deliberately coarse to allow for\n    visually comparing results, as needed.\n    The u-component of velocity is compared, and the array has the shape\n    (n_findex, n_turbines, n grid points in x, n grid points in y, 3 grid points in z).\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"solver\"] = {\n        \"type\": \"flow_field_planar_grid\",\n        \"normal_vector\": \"z\",\n        \"planar_coordinate\": sample_inputs_fixture.core[\"farm\"][\"turbine_type\"][0][\"hub_height\"],\n        \"flow_field_grid_points\": [5, 5],\n        \"flow_field_bounds\": [None, None],\n    }\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = [0.1]\n\n    floris = Core.from_dict(sample_inputs_fixture.core)\n    floris.solve_for_viz()\n\n    velocities = floris.flow_field.u_sorted\n\n    if DEBUG:\n        print(velocities)\n\n    assert_results_arrays(velocities, full_flow_baseline)\n"
  },
  {
    "path": "tests/reg_tests/turbulence_models_regression_test.py",
    "content": "from floris.core import Core\nfrom floris.core.wake_turbulence import NoneWakeTurbulence\n\n\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\ndef test_NoneWakeTurbulence(sample_inputs_fixture):\n\n    turbulence_intensities = [0.1, 0.05]\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"turbulence_model\"] = \"none\"\n    sample_inputs_fixture.core[\"farm\"][\"layout_x\"] = [0.0, 0.0, 600.0, 600.0]\n    sample_inputs_fixture.core[\"farm\"][\"layout_y\"] = [0.0, 600.0, 0.0, 600.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_directions\"] = [270.0, 360.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"wind_speeds\"] = [8.0, 8.0]\n    sample_inputs_fixture.core[\"flow_field\"][\"turbulence_intensities\"] = turbulence_intensities\n\n    core = Core.from_dict(sample_inputs_fixture.core)\n    core.initialize_domain()\n    core.steady_state_atmospheric_condition()\n\n    assert (\n        core.flow_field.turbulence_intensity_field_sorted[0,:] == turbulence_intensities[0]\n    ).all()\n    assert (\n        core.flow_field.turbulence_intensity_field_sorted[1,:] == turbulence_intensities[1]\n    ).all()\n"
  },
  {
    "path": "tests/reg_tests/yaw_optimization_regression_test.py",
    "content": "\nimport numpy as np\nimport pandas as pd\n\nfrom floris import FlorisModel\nfrom floris.optimization.yaw_optimization.yaw_optimizer_geometric import (\n    YawOptimizationGeometric,\n)\nfrom floris.optimization.yaw_optimization.yaw_optimizer_scipy import YawOptimizationScipy\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\nDEBUG = False\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\n# These inputs and baseline power are common for all optimization methods\nWIND_DIRECTIONS = [0.0, 90.0, 180.0, 270.0]\nWIND_SPEEDS = [8.0] * 4\nTURBULENCE_INTENSITIES = [0.1] * 4\nFARM_POWER_BASELINE = [5.261863e+06, 3.206038e+06, 5.261863e+06, 3.206038e+06]\n\n# These are the input data structures for each optimization method along with the output\n# optimized yaw angles\nbaseline_serial_refine = pd.DataFrame(\n        {\n        \"wind_direction\": WIND_DIRECTIONS,\n        \"wind_speed\": WIND_SPEEDS,\n        \"turbulence_intensity\": TURBULENCE_INTENSITIES,\n        \"yaw_angles_opt\": [\n            [0.0, 0.0, 0.0],\n            [0.0, 25.0, 15.625],\n            [0.0, 0.0, 0.0],\n            [15.625, 25.0, 0.0],\n        ],\n        \"farm_power_opt\": [5.261863e+06, 3.262218e+06, 5.261863e+06, 3.262218e+06],\n        \"farm_power_baseline\": FARM_POWER_BASELINE,\n    }\n)\n\nbaseline_geometric_yaw = pd.DataFrame(\n        {\n        \"wind_direction\": WIND_DIRECTIONS,\n        \"wind_speed\": WIND_SPEEDS,\n        \"turbulence_intensity\": TURBULENCE_INTENSITIES,\n        \"yaw_angles_opt\": [\n            [0.0, 0.0, 0.0],\n            [0.0, 19.9952335557674, 19.9952335557674],\n            [0.0, 0.0, 0.0],\n            [19.9952335557674, 19.9952335557674, 0.0],\n        ],\n        \"farm_power_opt\": [5.261863e+06, 3.252509e+06, 5.261863e+06, 3.252509e+06],\n        \"farm_power_baseline\": FARM_POWER_BASELINE,\n    }\n)\n\nbaseline_scipy = pd.DataFrame(\n        {\n        \"wind_direction\": WIND_DIRECTIONS,\n        \"wind_speed\": WIND_SPEEDS,\n        \"turbulence_intensity\": TURBULENCE_INTENSITIES,\n        \"yaw_angles_opt\": [\n            [0.0, 0.0, 0.0],\n            [0.0, 24.999999999999982, 12.165643400939755],\n            [0.0, 0.0, 0.0],\n            [12.165643399558299, 25.0, 0.0],\n        ],\n        \"farm_power_opt\": [5.261863e+06, 3.264975e+06, 5.261863e+06, 3.264975e+06],\n        \"farm_power_baseline\": FARM_POWER_BASELINE,\n    }\n)\n\n\ndef test_serial_refine(sample_inputs_fixture):\n    \"\"\"\n    The Serial Refine (SR) method optimizes yaw angles based on a sequential, iterative yaw\n    optimization scheme. This test compares the optimization results from the SR method for\n    a simple farm with a simple wind rose to stored baseline results.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    wd_array = np.arange(0.0, 360.0, 90.0)\n    ws_array = 8.0 * np.ones_like(wd_array)\n    ti_array = 0.1 * np.ones_like(wd_array)\n\n    D = 126.0 # Rotor diameter for the NREL 5 MW\n    fmodel.set(\n        layout_x=[0.0, 5 * D, 10 * D],\n        layout_y=[0.0, 0.0, 0.0],\n        wind_directions=wd_array,\n        wind_speeds=ws_array,\n        turbulence_intensities=ti_array,\n    )\n\n    yaw_opt = YawOptimizationSR(fmodel)\n    df_opt = yaw_opt.optimize()\n\n    if DEBUG:\n        print(baseline_serial_refine.to_string())\n        print(df_opt.to_string())\n\n    pd.testing.assert_frame_equal(df_opt, baseline_serial_refine)\n\n\ndef test_geometric_yaw(sample_inputs_fixture):\n    \"\"\"\n    The Geometric Yaw optimization method optimizes yaw angles using geometric data and derived\n    optimal yaw relationships. This test compares the optimization results from the Geometric Yaw\n    optimization for a simple farm with a simple wind rose to stored baseline results.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    wd_array = np.arange(0.0, 360.0, 90.0)\n    ws_array = 8.0 * np.ones_like(wd_array)\n    ti_array = 0.1 * np.ones_like(wd_array)\n    D = 126.0 # Rotor diameter for the NREL 5 MW\n    fmodel.set(\n        layout_x=[0.0, 5 * D, 10 * D],\n        layout_y=[0.0, 0.0, 0.0],\n        wind_directions=wd_array,\n        wind_speeds=ws_array,\n        turbulence_intensities=ti_array,\n    )\n    fmodel.run()\n    baseline_farm_power = fmodel.get_farm_power().squeeze()\n\n    yaw_opt = YawOptimizationGeometric(fmodel)\n    df_opt = yaw_opt.optimize()\n\n    yaw_angles_opt_geo = np.vstack(yaw_opt.yaw_angles_opt)\n    fmodel.set(yaw_angles=yaw_angles_opt_geo)\n    fmodel.run()\n    geo_farm_power = fmodel.get_farm_power().squeeze()\n\n    df_opt['farm_power_baseline'] = baseline_farm_power\n    df_opt['farm_power_opt'] = geo_farm_power\n\n    if DEBUG:\n        print(baseline_geometric_yaw.to_string())\n        print(df_opt.to_string())\n\n    pd.testing.assert_frame_equal(df_opt, baseline_geometric_yaw)\n\n\ndef test_scipy_yaw_opt(sample_inputs_fixture):\n    \"\"\"\n    The SciPy optimization method optimizes yaw angles using SciPy's minimize method. This test\n    compares the optimization results from the SciPy yaw optimization for a simple farm with a\n    simple wind rose to stored baseline results.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    opt_options = {\n        \"maxiter\": 5,\n        \"disp\": True,\n        \"iprint\": 2,\n        \"ftol\": 1e-12,\n        \"eps\": 0.5,\n    }\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    wd_array = np.arange(0.0, 360.0, 90.0)\n    ws_array = 8.0 * np.ones_like(wd_array)\n    ti_array = 0.1 * np.ones_like(wd_array)\n    D = 126.0 # Rotor diameter for the NREL 5 MW\n    fmodel.set(\n        layout_x=[0.0, 5 * D, 10 * D],\n        layout_y=[0.0, 0.0, 0.0],\n        wind_directions=wd_array,\n        wind_speeds=ws_array,\n        turbulence_intensities=ti_array,\n    )\n\n    yaw_opt = YawOptimizationScipy(fmodel, opt_options=opt_options)\n    df_opt = yaw_opt.optimize()\n\n    if DEBUG:\n        print(baseline_scipy.to_string())\n        print(df_opt.to_string())\n\n    # Only require matching up until 2 decimal places\n    pd.testing.assert_frame_equal(df_opt, baseline_scipy, check_exact=False, rtol=1e-5, atol=1e-2)\n"
  },
  {
    "path": "tests/rotor_velocity_unit_test.py",
    "content": "import numpy as np\n\nfrom floris.core import Turbine\nfrom floris.core.rotor_velocity import (\n    average_velocity,\n    compute_tilt_angles_for_floating_turbines,\n    compute_tilt_angles_for_floating_turbines_map,\n    cubic_cubature,\n    rotor_velocity_air_density_correction,\n    rotor_velocity_tilt_cosine_correction,\n    rotor_velocity_yaw_cosine_correction,\n    simple_cubature,\n)\nfrom tests.conftest import SampleInputs, WIND_SPEEDS\n\n\ndef test_rotor_velocity_air_density_correction():\n\n    wind_speed = 10.\n    ref_air_density = 1.225\n    test_density = 1.2\n\n    test_speed = rotor_velocity_air_density_correction(wind_speed, ref_air_density, ref_air_density)\n    assert test_speed == wind_speed\n\n    test_speed = rotor_velocity_air_density_correction(wind_speed, test_density, test_density)\n    assert test_speed == wind_speed\n\n    test_speed = rotor_velocity_air_density_correction(0., test_density, ref_air_density)\n    assert test_speed == 0.\n\n    test_speed = rotor_velocity_air_density_correction(wind_speed, test_density, ref_air_density)\n    assert np.allclose((test_speed/wind_speed)**3, test_density/ref_air_density)\n\n\ndef test_rotor_velocity_yaw_cosine_correction():\n    N_TURBINES = 4\n\n    wind_speed = average_velocity(10.0 * np.ones((1, 1, 3, 3)))\n    wind_speed_N_TURBINES = average_velocity(10.0 * np.ones((1, N_TURBINES, 3, 3)))\n\n    # Test a single turbine for zero yaw\n    yaw_corrected_velocities = rotor_velocity_yaw_cosine_correction(\n        cosine_loss_exponent_yaw=3.0,\n        yaw_angles=0.0,\n        rotor_effective_velocities=wind_speed,\n    )\n    np.testing.assert_allclose(yaw_corrected_velocities, wind_speed)\n\n    # Test a single turbine for non-zero yaw\n    yaw_corrected_velocities = rotor_velocity_yaw_cosine_correction(\n        cosine_loss_exponent_yaw=3.0,\n        yaw_angles=60.0,\n        rotor_effective_velocities=wind_speed,\n    )\n    np.testing.assert_allclose(yaw_corrected_velocities, 0.5 * wind_speed)\n\n    # Test multiple turbines for zero yaw\n    yaw_corrected_velocities = rotor_velocity_yaw_cosine_correction(\n        cosine_loss_exponent_yaw=3.0,\n        yaw_angles=np.zeros((1, N_TURBINES)),\n        rotor_effective_velocities=wind_speed_N_TURBINES,\n    )\n    np.testing.assert_allclose(yaw_corrected_velocities, wind_speed_N_TURBINES)\n\n    # Test multiple turbines for non-zero yaw\n    yaw_corrected_velocities = rotor_velocity_yaw_cosine_correction(\n        cosine_loss_exponent_yaw=3.0,\n        yaw_angles=np.ones((1, N_TURBINES)) * 60.0,\n        rotor_effective_velocities=wind_speed_N_TURBINES,\n    )\n    np.testing.assert_allclose(yaw_corrected_velocities, 0.5 * wind_speed_N_TURBINES)\n\n\ndef test_rotor_velocity_tilt_cosine_correction():\n    N_TURBINES = 4\n\n    wind_speed = average_velocity(10.0 * np.ones((1, 1, 3, 3)))\n    wind_speed_N_TURBINES = average_velocity(10.0 * np.ones((1, N_TURBINES, 3, 3)))\n\n    turbine_data = SampleInputs().turbine\n    turbine_floating_data = SampleInputs().turbine_floating\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_floating = Turbine.from_dict(turbine_floating_data)\n    turbine_type_map = np.array(N_TURBINES * [turbine.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n\n    # Test single non-floating turbine\n    tilt_corrected_velocities = rotor_velocity_tilt_cosine_correction(\n        #turbine_type_map=np.array([turbine_type_map[:, 0]]),\n        tilt_angles=5.0*np.ones((1, 1)),\n        ref_tilt=np.array([turbine.power_thrust_table[\"ref_tilt\"]]),\n        cosine_loss_exponent_tilt=np.array(\n            [turbine.power_thrust_table[\"cosine_loss_exponent_tilt\"]]\n        ),\n        tilt_interp=turbine.tilt_interp,\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        rotor_effective_velocities=wind_speed,\n    )\n\n    np.testing.assert_allclose(tilt_corrected_velocities, wind_speed)\n\n    # Test multiple non-floating turbines\n    tilt_corrected_velocities = rotor_velocity_tilt_cosine_correction(\n        #turbine_type_map=turbine_type_map,\n        tilt_angles=5.0*np.ones((1, N_TURBINES)),\n        ref_tilt=np.array([turbine.power_thrust_table[\"ref_tilt\"]] * N_TURBINES),\n        cosine_loss_exponent_tilt=np.array(\n            [turbine.power_thrust_table[\"cosine_loss_exponent_tilt\"]] * N_TURBINES\n        ),\n        tilt_interp=turbine.tilt_interp,\n        correct_cp_ct_for_tilt=np.array([[False] * N_TURBINES]),\n        rotor_effective_velocities=wind_speed_N_TURBINES,\n    )\n\n    np.testing.assert_allclose(tilt_corrected_velocities, wind_speed_N_TURBINES)\n\n    # Test single floating turbine\n    tilt_corrected_velocities = rotor_velocity_tilt_cosine_correction(\n        #turbine_type_map=np.array([turbine_type_map[:, 0]]),\n        tilt_angles=5.0*np.ones((1, 1)),\n        ref_tilt=np.array([turbine_floating.power_thrust_table[\"ref_tilt\"]]),\n        cosine_loss_exponent_tilt=np.array(\n            [turbine_floating.power_thrust_table[\"cosine_loss_exponent_tilt\"]]\n        ),\n        tilt_interp=turbine_floating.tilt_interp,\n        correct_cp_ct_for_tilt=np.array([[True]]),\n        rotor_effective_velocities=wind_speed,\n    )\n\n    np.testing.assert_allclose(tilt_corrected_velocities, wind_speed)\n\n    # Test multiple floating turbines\n    tilt_corrected_velocities = rotor_velocity_tilt_cosine_correction(\n        #turbine_type_map,\n        tilt_angles=5.0*np.ones((1, N_TURBINES)),\n        ref_tilt=np.array([turbine_floating.power_thrust_table[\"ref_tilt\"]] * N_TURBINES),\n        cosine_loss_exponent_tilt=np.array(\n            [turbine_floating.power_thrust_table[\"cosine_loss_exponent_tilt\"]] * N_TURBINES\n        ),\n        tilt_interp=turbine_floating.tilt_interp,\n        correct_cp_ct_for_tilt=np.array([[True] * N_TURBINES]),\n        rotor_effective_velocities=wind_speed_N_TURBINES,\n    )\n\n    np.testing.assert_allclose(tilt_corrected_velocities, wind_speed_N_TURBINES)\n\n    ## Test angles that are not the same as the reference tilt\n\n    # Test tilted \"back\" from reference tilt of 5 degrees\n    tilt_angle = 10.0 # Greater than the reference tilt\n    tilt_corrected_velocities = rotor_velocity_tilt_cosine_correction(\n        tilt_angles=tilt_angle*np.ones((1, N_TURBINES)),\n        ref_tilt=np.array([turbine_floating.power_thrust_table[\"ref_tilt\"]] * N_TURBINES),\n        cosine_loss_exponent_tilt=np.array(\n            [turbine_floating.power_thrust_table[\"cosine_loss_exponent_tilt\"]] * N_TURBINES\n        ),\n        tilt_interp=None, # Override wind-speed-based tilt interpolation\n        correct_cp_ct_for_tilt=np.array([[True] * N_TURBINES]),\n        rotor_effective_velocities=wind_speed_N_TURBINES,\n    )\n    assert (tilt_corrected_velocities < wind_speed_N_TURBINES).all()\n\n    # Test tilted \"forward\" from reference tilt of 5 degrees\n    tilt_angle = 0.0 # Less than the reference tilt\n    tilt_corrected_velocities = rotor_velocity_tilt_cosine_correction(\n        tilt_angles=tilt_angle*np.ones((1, N_TURBINES)),\n        ref_tilt=np.array([turbine_floating.power_thrust_table[\"ref_tilt\"]] * N_TURBINES),\n        cosine_loss_exponent_tilt=np.array(\n            [turbine_floating.power_thrust_table[\"cosine_loss_exponent_tilt\"]] * N_TURBINES\n        ),\n        tilt_interp=None, # Override wind-speed-based tilt interpolation\n        correct_cp_ct_for_tilt=np.array([[True] * N_TURBINES]),\n        rotor_effective_velocities=wind_speed_N_TURBINES,\n    )\n    assert (tilt_corrected_velocities > wind_speed_N_TURBINES).all()\n\n    # Test symmetry around zero tilt\n    tilt_angle = 3.0\n    tilt_negative = rotor_velocity_tilt_cosine_correction(\n        tilt_angles=-tilt_angle*np.ones((1, N_TURBINES)),\n        ref_tilt=np.array([turbine_floating.power_thrust_table[\"ref_tilt\"]] * N_TURBINES),\n        cosine_loss_exponent_tilt=np.array(\n            [turbine_floating.power_thrust_table[\"cosine_loss_exponent_tilt\"]] * N_TURBINES\n        ),\n        tilt_interp=None, # Override wind-speed-based tilt interpolation\n        correct_cp_ct_for_tilt=np.array([[True] * N_TURBINES]),\n        rotor_effective_velocities=wind_speed_N_TURBINES,\n    )\n    tilt_positive = rotor_velocity_tilt_cosine_correction(\n        tilt_angles=tilt_angle*np.ones((1, N_TURBINES)),\n        ref_tilt=np.array([turbine_floating.power_thrust_table[\"ref_tilt\"]] * N_TURBINES),\n        cosine_loss_exponent_tilt=np.array(\n            [turbine_floating.power_thrust_table[\"cosine_loss_exponent_tilt\"]] * N_TURBINES\n        ),\n        tilt_interp=None, # Override wind-speed-based tilt interpolation\n        correct_cp_ct_for_tilt=np.array([[True] * N_TURBINES]),\n        rotor_effective_velocities=wind_speed_N_TURBINES,\n    )\n    np.testing.assert_allclose(tilt_negative, tilt_positive)\n\ndef test_compute_tilt_angles_for_floating_turbines():\n    N_TURBINES = 4\n\n    wind_speed = 25.0\n    rotor_effective_velocities = average_velocity(wind_speed * np.ones((1, 1, 3, 3)))\n    rotor_effective_velocities_N_TURBINES = average_velocity(\n        wind_speed * np.ones((1, N_TURBINES, 3, 3))\n    )\n\n    turbine_floating_data = SampleInputs().turbine_floating\n    turbine_floating = Turbine.from_dict(turbine_floating_data)\n    turbine_type_map = np.array(N_TURBINES * [turbine_floating.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n\n    # Single turbine\n    tilt = compute_tilt_angles_for_floating_turbines(\n        #turbine_type_map=np.array([turbine_type_map[:, 0]]),\n        tilt_angles=5.0*np.ones((1, 1)),\n        tilt_interp=turbine_floating.tilt_interp,\n        rotor_effective_velocities=rotor_effective_velocities,\n    )\n\n    # calculate tilt again\n    truth_index = turbine_floating_data[\"floating_tilt_table\"][\"wind_speed\"].index(wind_speed)\n    tilt_truth = turbine_floating_data[\"floating_tilt_table\"][\"tilt\"][truth_index]\n    np.testing.assert_allclose(tilt, tilt_truth)\n\n    # Multiple turbines\n    tilt_N_turbines = compute_tilt_angles_for_floating_turbines_map(\n        turbine_type_map=np.array(turbine_type_map),\n        tilt_angles=5.0*np.ones((1, N_TURBINES)),\n        tilt_interps={turbine_floating.turbine_type: turbine_floating.tilt_interp},\n        rotor_effective_velocities=rotor_effective_velocities_N_TURBINES,\n    )\n\n    # calculate tilt again\n    truth_index = turbine_floating_data[\"floating_tilt_table\"][\"wind_speed\"].index(wind_speed)\n    tilt_truth = turbine_floating_data[\"floating_tilt_table\"][\"tilt\"][truth_index]\n    np.testing.assert_allclose(tilt_N_turbines, [[tilt_truth] * N_TURBINES])\n\ndef test_simple_cubature():\n\n    # Define a velocity array\n    velocities = np.ones((1, 1, 3, 3))\n\n    # Define sample cubature weights\n    cubature_weights = np.array([1., 1., 1.])\n\n    # Define the axis as last 2 dimensions\n    axis = (velocities.ndim-2, velocities.ndim-1)\n\n    # Calculate expected output based on the given inputs\n    expected_output = 1.0\n\n    # Call the function with the given inputs\n    result = simple_cubature(velocities, cubature_weights, axis)\n\n    # Check if the result matches the expected output\n    np.testing.assert_allclose(result, expected_output)\n\ndef test_cubic_cubature():\n\n    # Define a velocity array\n    velocities = np.ones((1, 1, 3, 3))\n\n    # Define sample cubature weights\n    cubature_weights = np.array([1., 1., 1.])\n\n    # Define the axis as last 2 dimensions\n    axis = (velocities.ndim-2, velocities.ndim-1)\n\n    # Calculate expected output based on the given inputs\n    expected_output = 1.0\n\n    # Call the function with the given inputs\n    result = cubic_cubature(velocities, cubature_weights, axis)\n\n    # Check if the result matches the expected output\n    np.testing.assert_allclose(result, expected_output)\n"
  },
  {
    "path": "tests/serial_refine_unit_test.py",
    "content": "\nimport numpy as np\nimport pandas as pd\n\nfrom floris import FlorisModel\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\nDEBUG = False\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\n# Inputs for basic yaw optimizations\nWIND_DIRECTIONS = [0.0, 90.0, 180.0, 270.0]\nWIND_SPEEDS = [8.0] * 4\nTURBULENCE_INTENSITIES = [0.06] * 4\nLAYOUT_X = [0.0, 600.0, 1200.0]\nLAYOUT_Y = [0.0, 0.0, 0.0]\nMAXIMUM_YAW_ANGLE = 25.0\n\ndef test_basic_optimization(sample_inputs_fixture):\n    \"\"\"\n    The Serial Refine (SR) method optimizes yaw angles based on a sequential, iterative yaw\n    optimization scheme. This test checks basic properties of the optimization result.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    fmodel.set(\n        layout_x=LAYOUT_X,\n        layout_y=LAYOUT_Y,\n        wind_directions=WIND_DIRECTIONS,\n        wind_speeds=WIND_SPEEDS,\n        turbulence_intensities=TURBULENCE_INTENSITIES\n    )\n    fmodel.set_operation_model(\"cosine-loss\")\n\n    yaw_opt = YawOptimizationSR(fmodel, minimum_yaw_angle=0.0, maximum_yaw_angle=MAXIMUM_YAW_ANGLE)\n    df_opt = yaw_opt.optimize()\n\n    # Unaligned conditions\n    assert np.allclose(df_opt.loc[0, \"yaw_angles_opt\"], 0.0)\n    assert np.allclose(df_opt.loc[2, \"yaw_angles_opt\"], 0.0)\n\n    # Check aligned conditions\n    # Check maximum and minimum are respected\n    assert (df_opt.loc[1, \"yaw_angles_opt\"] <= MAXIMUM_YAW_ANGLE).all()\n    assert (df_opt.loc[3, \"yaw_angles_opt\"] <= MAXIMUM_YAW_ANGLE).all()\n    assert (df_opt.loc[1, \"yaw_angles_opt\"] >= 0.0).all()\n    assert (df_opt.loc[3, \"yaw_angles_opt\"] >= 0.0).all()\n\n    # Check 90.0 and 270.0 are symmetric\n    assert np.allclose(df_opt.loc[1, \"yaw_angles_opt\"], np.flip(df_opt.loc[3, \"yaw_angles_opt\"]))\n\n    # Check last turbine's angles are zero at 270.0\n    assert np.allclose(df_opt.loc[3, \"yaw_angles_opt\"][-1], 0.0)\n\n    # Check that optimizer reports a power improvement\n    assert (df_opt[\"farm_power_opt\"] >= df_opt[\"farm_power_baseline\"]).all()\n\ndef test_disabled_turbines(sample_inputs_fixture):\n    \"\"\"\n    Tests SR when some turbines are disabled and checks that the results are equivalent to removing\n    those turbines from the wind farm. Need a tight layout to ensure that the front-to-back distance\n    is not too large.\n    \"\"\"\n\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n\n    fmodel.set(\n        layout_x=LAYOUT_X,\n        layout_y=LAYOUT_Y,\n        wind_directions=WIND_DIRECTIONS,\n        wind_speeds=WIND_SPEEDS,\n        turbulence_intensities=TURBULENCE_INTENSITIES\n    )\n    fmodel.set_operation_model(\"mixed\")\n\n    # Disable the middle turbine in all wind conditions, run optimization, and extract results\n    fmodel.set(disable_turbines=[[False, True, False]]*4)\n    yaw_opt = YawOptimizationSR(fmodel, minimum_yaw_angle=0.0, maximum_yaw_angle=MAXIMUM_YAW_ANGLE)\n    df_opt = yaw_opt.optimize()\n    yaw_angles_opt_disabled = df_opt.loc[3, \"yaw_angles_opt\"]\n    farm_power_opt_disabled = df_opt.loc[3, \"farm_power_opt\"]\n\n    # Set up a new wind farm with the middle turbine removed\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    fmodel.set(\n        layout_x=np.array(LAYOUT_X)[[0, 2]],\n        layout_y=np.array(LAYOUT_Y)[[0, 2]],\n        wind_directions=WIND_DIRECTIONS,\n        wind_speeds=WIND_SPEEDS,\n        turbulence_intensities=TURBULENCE_INTENSITIES\n    )\n    fmodel.set_operation_model(\"cosine-loss\")\n    yaw_opt = YawOptimizationSR(fmodel, minimum_yaw_angle=0.0, maximum_yaw_angle=MAXIMUM_YAW_ANGLE)\n    df_opt = yaw_opt.optimize()\n    yaw_angles_opt_removed = df_opt.loc[3, \"yaw_angles_opt\"]\n    farm_power_opt_removed = df_opt.loc[3, \"farm_power_opt\"]\n\n    assert np.allclose(yaw_angles_opt_disabled[[0, 2]], yaw_angles_opt_removed)\n    assert np.allclose(farm_power_opt_disabled, farm_power_opt_removed)\n"
  },
  {
    "path": "tests/turbine_grid_unit_test.py",
    "content": "\nimport numpy as np\n\nfrom floris.core import TurbineGrid\nfrom tests.conftest import (\n    N_FINDEX,\n    N_TURBINES,\n    TURBINE_GRID_RESOLUTION,\n)\n\n\n# def test_from_dict_as_dict(turbine_grid_fixture):\n#     grid_dict = turbine_grid_fixture.as_dict()\n#     new_grid = TurbineGrid.from_dict(grid_dict)\n#     assert new_grid == turbine_grid_fixture\n\n\ndef test_set_grid(turbine_grid_fixture):\n    expected_x_grid = [\n        [[0.0, 0.0], [0.0, 0.0]],\n        [[630.0, 630.0], [630.0, 630.0]],\n        [[1260.0, 1260.0], [1260.0, 1260.0]]\n    ]\n    expected_y_grid = [\n        [[-31.5, -31.5], [31.5, 31.5]],\n        [[-31.5, -31.5], [31.5, 31.5]],\n        [[-31.5, -31.5], [31.5, 31.5]]\n    ]\n    expected_z_grid = [\n        [[58.5, 121.5], [58.5, 121.5]],\n        [[58.5, 121.5], [58.5, 121.5]],\n        [[58.5, 121.5], [58.5, 121.5]]\n    ]\n\n    # subtract the test and expected values which should result in 0's\n    # then, search for any elements that are true and negate the results\n    # if an element is zero, the not will return true\n    # if an element is non-zero, the not will return false\n    np.testing.assert_array_equal(turbine_grid_fixture.x_sorted[0], expected_x_grid)\n    np.testing.assert_array_equal(turbine_grid_fixture.y_sorted[0], expected_y_grid)\n    np.testing.assert_array_equal(turbine_grid_fixture.z_sorted[0], expected_z_grid)\n\n    # These should have the following shape:\n    # (n findex, n turbines, grid resolution, grid resolution)\n    expected_shape = (N_FINDEX,N_TURBINES,TURBINE_GRID_RESOLUTION,TURBINE_GRID_RESOLUTION)\n    assert np.shape(turbine_grid_fixture.x_sorted) == expected_shape\n    assert np.shape(turbine_grid_fixture.y_sorted) == expected_shape\n    assert np.shape(turbine_grid_fixture.z_sorted) == expected_shape\n    assert np.shape(turbine_grid_fixture.x_sorted_inertial_frame) == expected_shape\n    assert np.shape(turbine_grid_fixture.y_sorted_inertial_frame) == expected_shape\n    assert np.shape(turbine_grid_fixture.z_sorted_inertial_frame) == expected_shape\n\n\ndef test_dimensions(turbine_grid_fixture):\n    assert np.shape(turbine_grid_fixture.x_sorted) == (\n        N_FINDEX,\n        N_TURBINES,\n        TURBINE_GRID_RESOLUTION,\n        TURBINE_GRID_RESOLUTION\n    )\n    assert np.shape(turbine_grid_fixture.y_sorted) == (\n        N_FINDEX,\n        N_TURBINES,\n        TURBINE_GRID_RESOLUTION,\n        TURBINE_GRID_RESOLUTION\n    )\n    assert np.shape(turbine_grid_fixture.z_sorted) == (\n        N_FINDEX,\n        N_TURBINES,\n        TURBINE_GRID_RESOLUTION,\n        TURBINE_GRID_RESOLUTION\n    )\n\n\ndef test_dynamic_properties(turbine_grid_fixture):\n    assert turbine_grid_fixture.n_turbines == N_TURBINES\n    assert turbine_grid_fixture.n_findex == N_FINDEX\n\n    turbine_grid_fixture.turbine_coordinates = np.append(\n        turbine_grid_fixture.turbine_coordinates,\n        np.array([[100.0, 200.0, 300.0]]),\n        axis=0\n    )\n    assert turbine_grid_fixture.n_turbines == N_TURBINES + 1\n\n    turbine_grid_fixture.wind_directions = [*turbine_grid_fixture.wind_directions, 0.0]\n    assert turbine_grid_fixture.n_findex == N_FINDEX + 1\n"
  },
  {
    "path": "tests/turbine_multi_dim_unit_test.py",
    "content": "\nfrom pathlib import Path\n\nimport numpy as np\nimport pandas as pd\nimport pytest\n\nfrom floris.core import (\n    Turbine,\n)\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT\nfrom floris.core.turbine.turbine import (\n    axial_induction,\n    power,\n    thrust_coefficient,\n)\nfrom tests.conftest import SampleInputs, WIND_SPEEDS\n\n\n# size 16 x 1 x 1 x 1\n# 16 wind speed and wind direction combinations from conftest\nWIND_CONDITION_BROADCAST = np.reshape(np.array(WIND_SPEEDS), (-1, 1, 1, 1))\n\nINDEX_FILTER = [0, 2]\n\n# NOTE: MultiDimensionalPowerThrustTable not used anywhere, so I'm commenting\n# this out.\n\n# def test_multi_dimensional_power_thrust_table():\n#     turbine_data = SampleInputs().turbine_multi_dim\n#     turbine_data[\"power_thrust_data_file\"] = CSV_INPUT\n#     df_data = pd.read_csv(turbine_data[\"power_thrust_data_file\"])\n#     flattened_dict = MultiDimensionalPowerThrustTable.from_dataframe(df_data)\n#     flattened_dict_base = {\n#         ('Tp', '2', 'Hs', '1'): [],\n#         ('Tp', '2', 'Hs', '5'): [],\n#         ('Tp', '4', 'Hs', '1'): [],\n#         ('Tp', '4', 'Hs', '5'): [],\n#     }\n#     assert flattened_dict == flattened_dict_base\n\n#     # Test for initialization errors\n#     for el in (\"ws\", \"Cp\", \"Ct\"):\n#         df_data = pd.read_csv(turbine_data[\"power_thrust_data_file\"])\n#         df = df_data.drop(el, axis=1)\n#         with pytest.raises(ValueError):\n#             MultiDimensionalPowerThrustTable.from_dataframe(df)\n\n\ndef test_turbine_init():\n    turbine_data = SampleInputs().turbine_multi_dim\n    turbine = Turbine.from_dict(turbine_data)\n    condition_tuple = (2, 1)\n    assert turbine.rotor_diameter == turbine_data[\"rotor_diameter\"]\n    assert turbine.hub_height == turbine_data[\"hub_height\"]\n    assert (\n        turbine.power_thrust_table[condition_tuple][\"cosine_loss_exponent_yaw\"]\n        == turbine_data[\"power_thrust_table\"][\"cosine_loss_exponent_yaw\"]\n    )\n    assert (\n        turbine.power_thrust_table[condition_tuple][\"cosine_loss_exponent_tilt\"]\n        == turbine_data[\"power_thrust_table\"][\"cosine_loss_exponent_tilt\"]\n    )\n\n    assert isinstance(turbine.power_thrust_table, dict)\n    assert callable(turbine.thrust_coefficient_function)\n    assert callable(turbine.power_function)\n    assert turbine.rotor_radius == turbine_data[\"rotor_diameter\"] / 2.0\n\n\ndef test_ct():\n    N_TURBINES = 4\n\n    turbine_data = SampleInputs().turbine_multi_dim\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_type_map = np.array(N_TURBINES * [turbine.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n    condition = {\"Tp\":2, \"Hs\":1}\n\n    # Single turbine\n    # yaw angle / fCt are (n wind direction, n wind speed, n turbine)\n    wind_speed = 10.0\n    thrust = thrust_coefficient(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((1, 1, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((1, 1)),\n        tilt_angles=np.ones((1, 1)) * 5.0,\n        power_setpoints=np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\\\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*1),\n        awc_amplitudes=np.zeros((1, 1)),\n        thrust_coefficient_functions={turbine.turbine_type: turbine.thrust_coefficient_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map[:,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=condition\n    )\n\n    np.testing.assert_allclose(thrust, np.array([[0.77958497]]))\n\n    # Multiple turbines with index filter\n    # 4 turbines with 3 x 3 grid arrays\n    thrusts = thrust_coefficient(\n        velocities=np.ones((N_TURBINES, 3, 3)) * WIND_CONDITION_BROADCAST,  # 16 x 4 x 3 x 3\n        turbulence_intensities=(\n            0.06 * np.ones((N_TURBINES, 3, 3))\n            * np.ones_like(WIND_CONDITION_BROADCAST)\n        ),\n        air_density=None,\n        yaw_angles=np.zeros((1, N_TURBINES)),\n        tilt_angles=np.ones((1, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((1, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*1),\n        awc_amplitudes=np.zeros((1, N_TURBINES)),\n        thrust_coefficient_functions={turbine.turbine_type: turbine.thrust_coefficient_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False] * N_TURBINES]),\n        turbine_type_map=turbine_type_map,\n        ix_filter=INDEX_FILTER,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=condition\n    )\n    assert len(thrusts[0]) == len(INDEX_FILTER)\n\n    thrusts_truth = np.array(\n        [\n            [0.77958497, 0.77958497],\n            [0.77958497, 0.77958497],\n            [0.77958497, 0.77958497],\n            [0.66749069, 0.66749069],\n            [0.77958497, 0.77958497],\n            [0.77958497, 0.77958497],\n            [0.77958497, 0.77958497],\n            [0.66749069, 0.66749069],\n            [0.77958497, 0.77958497],\n            [0.77958497, 0.77958497],\n            [0.77958497, 0.77958497],\n            [0.66749069, 0.66749069],\n            [0.77958497, 0.77958497],\n            [0.77958497, 0.77958497],\n            [0.77958497, 0.77958497],\n            [0.66749069, 0.66749069]\n        ]\n    )\n    np.testing.assert_allclose(thrusts, thrusts_truth)\n\ndef test_power():\n    N_TURBINES = 4\n    AIR_DENSITY = 1.225\n\n    turbine_data = SampleInputs().turbine_multi_dim\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_type_map = np.array(N_TURBINES * [turbine.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n    condition = {\"Tp\":2, \"Hs\":1}\n    condition_tuple = tuple(condition[k] for k in condition.keys())\n\n    # Single turbine\n    wind_speed = 10.0\n    p = power(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((1, 1, 3, 3)),\n        air_density=AIR_DENSITY,\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((1, 1)), # 1 findex, 1 turbine\n        tilt_angles=turbine.power_thrust_table[condition_tuple][\"ref_tilt\"] * np.ones((1, 1)),\n        power_setpoints=np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*1),\n        awc_amplitudes=np.zeros((1, 1)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map[:,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=condition,\n    )\n\n    power_truth = 12424759.67683091\n\n    np.testing.assert_allclose(p, power_truth)\n\n    # Multiple turbines with ix filter\n    velocities = np.ones((N_TURBINES, 3, 3)) * WIND_CONDITION_BROADCAST\n    p = power(\n        velocities=np.ones((N_TURBINES, 3, 3)) * WIND_CONDITION_BROADCAST,  # 16 x 4 x 3 x 3\n        turbulence_intensities=(\n            0.06 * np.ones((N_TURBINES, 3, 3))\n            * np.ones_like(WIND_CONDITION_BROADCAST)\n        ),\n        air_density=AIR_DENSITY,\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((1, N_TURBINES)),\n        tilt_angles=np.ones((1, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((1, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*1),\n        awc_amplitudes=np.zeros((1, N_TURBINES)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map,\n        ix_filter=INDEX_FILTER,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=condition\n    )\n    assert len(p[0]) == len(INDEX_FILTER)\n\n    power_truth = turbine.power_function(\n        power_thrust_table=turbine.power_thrust_table[condition_tuple],\n        velocities=velocities,\n        air_density=AIR_DENSITY,\n        yaw_angles=np.zeros((1, N_TURBINES)),\n        tilt_angles=np.ones((1, N_TURBINES)) * 5.0,\n        tilt_interp=turbine.tilt_interp,\n    )\n    np.testing.assert_allclose(p, power_truth[:, INDEX_FILTER[0]:INDEX_FILTER[1]])\n\n\ndef test_axial_induction():\n\n    N_TURBINES = 4\n\n    turbine_data = SampleInputs().turbine_multi_dim\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_type_map = np.array(N_TURBINES * [turbine.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n    condition = {\"Tp\":2, \"Hs\":1}\n\n    baseline_ai = np.array([[0.26551081]])\n\n    # Single turbine\n    wind_speed = 10.0\n    ai = axial_induction(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((1, 1, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((1, 1)),\n        tilt_angles=np.ones((1, 1)) * 5.0,\n        power_setpoints = np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*1),\n        awc_amplitudes=np.zeros((1, 1)),\n        axial_induction_functions={turbine.turbine_type: turbine.axial_induction_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map[0,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=condition\n    )\n    np.testing.assert_allclose(ai, baseline_ai)\n\n    # Multiple turbines with ix filter\n    ai = axial_induction(\n        velocities=np.ones((N_TURBINES, 3, 3)) * WIND_CONDITION_BROADCAST,  # 16 x 4 x 3 x 3\n        turbulence_intensities=(\n            0.06 * np.ones((N_TURBINES, 3, 3))\n            * np.ones_like(WIND_CONDITION_BROADCAST)\n        ),\n        air_density=None,\n        yaw_angles=np.zeros((1, N_TURBINES)),\n        tilt_angles=np.ones((1, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((1, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*1),\n        awc_amplitudes=np.zeros((1, N_TURBINES)),\n        axial_induction_functions={turbine.turbine_type: turbine.axial_induction_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False] * N_TURBINES]),\n        turbine_type_map=turbine_type_map,\n        ix_filter=INDEX_FILTER,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=condition\n    )\n\n    assert len(ai[0]) == len(INDEX_FILTER)\n\n    # Test the 10 m/s wind speed to use the same baseline as above\n    np.testing.assert_allclose(ai[2][0], baseline_ai)\n\n\ndef test_asdict(sample_inputs_fixture: SampleInputs):\n\n    turbine = Turbine.from_dict(sample_inputs_fixture.turbine)\n    dict1 = turbine.as_dict()\n\n    new_turb = Turbine.from_dict(dict1)\n    dict2 = new_turb.as_dict()\n\n    assert dict1 == dict2\n\ndef test_multiple_conditions():\n\n    N_TURBINES = 4\n    N_CONDITIONS = 2\n\n    turbine_data = SampleInputs().turbine_multi_dim\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_type_map = np.array(N_TURBINES * [turbine.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n\n    # First, test the same condition repeated\n    conditions = {\"Tp\":[2, 2], \"Hs\":[1, 1]}\n\n    # Single turbine\n    wind_speed = 10.0\n    thrust = thrust_coefficient(\n        velocities=wind_speed * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_angles=np.ones((N_CONDITIONS, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((N_CONDITIONS, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*N_CONDITIONS),\n        awc_amplitudes=np.zeros((N_CONDITIONS, N_TURBINES)),\n        thrust_coefficient_functions={turbine.turbine_type: turbine.thrust_coefficient_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=conditions\n    )\n    assert np.allclose(thrust, 0.77958497)\n\n    ai = axial_induction(\n        velocities=wind_speed * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_angles=np.ones((N_CONDITIONS, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((N_CONDITIONS, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*N_CONDITIONS),\n        awc_amplitudes=np.zeros((N_CONDITIONS, N_TURBINES)),\n        axial_induction_functions={turbine.turbine_type: turbine.axial_induction_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=conditions\n    )\n    assert np.allclose(ai, 0.26551081)\n\n    p = power(\n        velocities=wind_speed * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        air_density=1.225,\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_angles=turbine.power_thrust_table[(2,1)][\"ref_tilt\"] * np.ones(\n            (N_CONDITIONS, N_TURBINES)\n        ),  # Same ref_tilt on all power_thrust_tables\n        power_setpoints=np.ones((N_CONDITIONS, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*N_CONDITIONS),\n        awc_amplitudes=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=conditions,\n        correct_cp_ct_for_tilt=np.zeros((N_CONDITIONS, N_TURBINES), dtype=bool)\n    )\n    assert np.allclose(p, 12424759.67683091)\n\n    # Next, test different conditions (one which must be inferred)\n    conditions = {\"Tp\":[2, 4], \"Hs\":[1, 4]}\n    thrust = thrust_coefficient(\n        velocities=wind_speed * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_angles=np.ones((N_CONDITIONS, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((N_CONDITIONS, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*N_CONDITIONS),\n        awc_amplitudes=np.zeros((N_CONDITIONS, N_TURBINES)),\n        thrust_coefficient_functions={turbine.turbine_type: turbine.thrust_coefficient_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=conditions\n    )\n    assert np.allclose(thrust, np.array([[0.77958497], [0.09744812]]))\n\n    ai = axial_induction(\n        velocities=wind_speed * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_angles=np.ones((N_CONDITIONS, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((N_CONDITIONS, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*N_CONDITIONS),\n        awc_amplitudes=np.zeros((N_CONDITIONS, N_TURBINES)),\n        axial_induction_functions={turbine.turbine_type: turbine.axial_induction_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=conditions\n    )\n    assert np.allclose(ai, np.array([[0.26551081], [0.02498745]]))\n\n    p = power(\n        velocities=wind_speed * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        air_density=1.225,\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((N_CONDITIONS, N_TURBINES)),\n                tilt_angles=turbine.power_thrust_table[(2,1)][\"ref_tilt\"] * np.ones(\n            (N_CONDITIONS, N_TURBINES)\n        ),  # Same ref_tilt on all power_thrust_tables\n        power_setpoints=np.ones((N_CONDITIONS, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*N_CONDITIONS),\n        awc_amplitudes=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=conditions,\n    )\n    assert np.allclose(p, np.array([[12424759.67683091], [ 1553094.95985386]]))\n\n    # Multiple findices with broadcast multidim conditions\n    wind_speeds = np.array([10., 11.])\n    conditions = {\"Tp\":2, \"Hs\":1}\n    thrust = thrust_coefficient(\n        velocities=np.tile(wind_speeds[:,None,None,None], (1, N_TURBINES, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_angles=np.ones((N_CONDITIONS, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((N_CONDITIONS, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*N_CONDITIONS),\n        awc_amplitudes=np.zeros((N_CONDITIONS, N_TURBINES)),\n        thrust_coefficient_functions={turbine.turbine_type: turbine.thrust_coefficient_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=conditions\n    )\n    assert np.allclose(thrust, np.array([[0.77958497], [0.66749069]]))\n\n    ai = axial_induction(\n        velocities=np.tile(wind_speeds[:,None,None,None], (1, N_TURBINES, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_angles=np.ones((N_CONDITIONS, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((N_CONDITIONS, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*N_CONDITIONS),\n        awc_amplitudes=np.zeros((N_CONDITIONS, N_TURBINES)),\n        axial_induction_functions={turbine.turbine_type: turbine.axial_induction_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=conditions\n    )\n    assert np.allclose(ai, np.array([[0.26551081], [0.2118128]]))\n\n    p = power(\n        velocities=np.tile(wind_speeds[:,None,None,None], (1, N_TURBINES, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((N_CONDITIONS, N_TURBINES, 3, 3)),\n        air_density=1.225,\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_angles=turbine.power_thrust_table[(2,1)][\"ref_tilt\"] * np.ones(\n            (N_CONDITIONS, N_TURBINES)\n        ),  # Same ref_tilt on all power_thrust_tables\n        power_setpoints=np.ones((N_CONDITIONS, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*N_CONDITIONS),\n        awc_amplitudes=np.zeros((N_CONDITIONS, N_TURBINES)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        multidim_condition=conditions,\n    )\n    assert np.allclose(p, np.array([[12424759.67683091], [15000000.0]]))\n"
  },
  {
    "path": "tests/turbine_operation_models_unit_test.py",
    "content": "import numpy as np\nimport pytest\n\nfrom floris.core.turbine.operation_models import (\n    AWCTurbine,\n    CosineLossTurbine,\n    MixedOperationTurbine,\n    PeakShavingTurbine,\n    POWER_SETPOINT_DEFAULT,\n    SimpleDeratingTurbine,\n    SimpleTurbine,\n)\nfrom floris.utilities import cosd\nfrom tests.conftest import SampleInputs, WIND_SPEEDS\n\n\ndef test_submodel_attributes():\n\n    assert hasattr(SimpleTurbine, \"power\")\n    assert hasattr(SimpleTurbine, \"thrust_coefficient\")\n    assert hasattr(SimpleTurbine, \"axial_induction\")\n\n    assert hasattr(CosineLossTurbine, \"power\")\n    assert hasattr(CosineLossTurbine, \"thrust_coefficient\")\n    assert hasattr(CosineLossTurbine, \"axial_induction\")\n\n    assert hasattr(SimpleDeratingTurbine, \"power\")\n    assert hasattr(SimpleDeratingTurbine, \"thrust_coefficient\")\n    assert hasattr(SimpleDeratingTurbine, \"axial_induction\")\n\n    assert hasattr(MixedOperationTurbine, \"power\")\n    assert hasattr(MixedOperationTurbine, \"thrust_coefficient\")\n    assert hasattr(MixedOperationTurbine, \"axial_induction\")\n\n    assert hasattr(AWCTurbine, \"power\")\n    assert hasattr(AWCTurbine, \"thrust_coefficient\")\n    assert hasattr(AWCTurbine, \"axial_induction\")\n\n    assert hasattr(PeakShavingTurbine, \"power\")\n    assert hasattr(PeakShavingTurbine, \"thrust_coefficient\")\n    assert hasattr(PeakShavingTurbine, \"axial_induction\")\n\ndef test_SimpleTurbine():\n\n    n_turbines = 1\n    wind_speed = 10.0\n    turbine_data = SampleInputs().turbine\n\n    # Check that power works as expected\n    test_power = SimpleTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"], # Matches ref_air_density\n    )\n    truth_index = turbine_data[\"power_thrust_table\"][\"wind_speed\"].index(wind_speed)\n    baseline_power = turbine_data[\"power_thrust_table\"][\"power\"][truth_index] * 1000\n    assert np.allclose(baseline_power, test_power)\n\n    # Check that yaw and tilt angle have no effect\n    test_power = SimpleTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"], # Matches ref_air_density\n        yaw_angles=20 * np.ones((1, n_turbines)),\n        tilt_angles=5 * np.ones((1, n_turbines))\n    )\n    assert np.allclose(baseline_power, test_power)\n\n    # Check that a lower air density decreases power appropriately\n    test_power = SimpleTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1,\n    )\n    assert test_power < baseline_power\n\n\n    # Check that thrust coefficient works as expected\n    test_Ct = SimpleTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1, # Unused\n    )\n    baseline_Ct = turbine_data[\"power_thrust_table\"][\"thrust_coefficient\"][truth_index]\n    assert np.allclose(baseline_Ct, test_Ct)\n\n    # Check that yaw and tilt angle have no effect\n    test_Ct = SimpleTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1, # Unused\n        yaw_angles=20 * np.ones((1, n_turbines)),\n        tilt_angles=5 * np.ones((1, n_turbines))\n    )\n    assert np.allclose(baseline_Ct, test_Ct)\n\n\n    # Check that axial induction works as expected\n    test_ai = SimpleTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1, # Unused\n    )\n    baseline_ai = (\n        1 - np.sqrt(1 - turbine_data[\"power_thrust_table\"][\"thrust_coefficient\"][truth_index])\n    )/2\n    assert np.allclose(baseline_ai, test_ai)\n\n    # Check that yaw and tilt angle have no effect\n    test_ai = SimpleTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1, # Unused\n        yaw_angles=20 * np.ones((1, n_turbines)),\n        tilt_angles=5 * np.ones((1, n_turbines))\n    )\n    assert np.allclose(baseline_ai, test_ai)\n\ndef test_CosineLossTurbine():\n\n    n_turbines = 1\n    wind_speed = 10.0\n    turbine_data = SampleInputs().turbine\n\n    yaw_angles_nom = 0 * np.ones((1, n_turbines))\n    tilt_angles_nom = turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((1, n_turbines))\n    yaw_angles_test = 20 * np.ones((1, n_turbines))\n    tilt_angles_test = 0 * np.ones((1, n_turbines))\n\n\n    # Check that power works as expected\n    test_power = CosineLossTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"], # Matches ref_air_density\n        yaw_angles=yaw_angles_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    truth_index = turbine_data[\"power_thrust_table\"][\"wind_speed\"].index(wind_speed)\n    baseline_power = turbine_data[\"power_thrust_table\"][\"power\"][truth_index] * 1000\n    assert np.allclose(baseline_power, test_power)\n\n    # Check that yaw and tilt angle have an effect\n    test_power = CosineLossTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"], # Matches ref_air_density\n        yaw_angles=yaw_angles_test,\n        tilt_angles=tilt_angles_test,\n        tilt_interp=None\n    )\n    assert test_power < baseline_power\n\n    # Check that a lower air density decreases power appropriately\n    test_power = CosineLossTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1,\n        yaw_angles=yaw_angles_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    assert test_power < baseline_power\n\n\n    # Check that thrust coefficient works as expected\n    test_Ct = CosineLossTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1, # Unused\n        yaw_angles=yaw_angles_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    baseline_Ct = turbine_data[\"power_thrust_table\"][\"thrust_coefficient\"][truth_index]\n    assert np.allclose(baseline_Ct, test_Ct)\n\n    # Check that yaw and tilt angle have the expected effect\n    test_Ct = CosineLossTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1, # Unused\n        yaw_angles=yaw_angles_test,\n        tilt_angles=tilt_angles_test,\n        tilt_interp=None\n    )\n    assert test_Ct == (\n        baseline_Ct * cosd(yaw_angles_test)\n        * cosd(tilt_angles_test)\n        / cosd(turbine_data[\"power_thrust_table\"][\"ref_tilt\"])\n    )\n\n\n    # Check that thrust coefficient works as expected\n    test_ai = CosineLossTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1, # Unused\n        yaw_angles=yaw_angles_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    baseline_misalignment_loss = (\n        cosd(yaw_angles_nom)\n        * cosd(tilt_angles_nom)\n        / cosd(turbine_data[\"power_thrust_table\"][\"ref_tilt\"])\n    )\n    baseline_ai = (\n        1 - np.sqrt(1 - turbine_data[\"power_thrust_table\"][\"thrust_coefficient\"][truth_index])\n    ) / 2 / baseline_misalignment_loss\n    assert np.allclose(baseline_ai, test_ai)\n\n    # Check that yaw and tilt angle have the expected effect\n    test_ai = CosineLossTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1, # Unused\n        yaw_angles=yaw_angles_test,\n        tilt_angles=tilt_angles_test,\n        tilt_interp=None\n    )\n\n    assert test_Ct == (\n        baseline_Ct\n        * cosd(yaw_angles_test)\n        * cosd(tilt_angles_test)\n        / cosd(turbine_data[\"power_thrust_table\"][\"ref_tilt\"])\n    )\n\n\ndef test_SimpleDeratingTurbine():\n\n    n_turbines = 1\n    wind_speed = 10.0\n    turbine_data = SampleInputs().turbine\n\n\n    # Check that for no specified derating, matches SimpleTurbine\n    test_Ct = SimpleDeratingTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=None,\n    )\n    base_Ct = SimpleTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n    )\n    assert np.allclose(test_Ct, base_Ct)\n\n    test_power = SimpleDeratingTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=None,\n    )\n    base_power = SimpleTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n    )\n    assert np.allclose(test_power, base_power)\n\n    test_ai = SimpleDeratingTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=None,\n    )\n    base_ai = SimpleTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n    )\n    assert np.allclose(test_ai, base_ai)\n\n    # When power_setpoints are 0, turbine is shut down.\n    test_Ct = SimpleDeratingTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=np.zeros((1, n_turbines)),\n    )\n    assert np.allclose(test_Ct, 0)\n\n    test_power = SimpleDeratingTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=np.zeros((1, n_turbines)),\n    )\n    assert np.allclose(test_power, 0)\n\n    test_ai = SimpleDeratingTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=np.zeros((1, n_turbines)),\n    )\n    assert np.allclose(test_ai, 0)\n\n    # When power setpoints are less than available, results should be less than when no setpoint\n    wind_speed = 20 # High, so that turbine is above rated nominally\n    derated_power = 4.0e6\n    rated_power = 5.0e6\n    test_power = SimpleDeratingTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=derated_power * np.ones((1, n_turbines)),\n    )\n\n    rated_power = 5.0e6\n    test_Ct = SimpleDeratingTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=derated_power * np.ones((1, n_turbines)),\n    )\n    base_Ct = SimpleTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=derated_power * np.ones((1, n_turbines)),\n    )\n    assert np.allclose(test_Ct, derated_power/rated_power * base_Ct) # Is this correct?\n\n    # Mixed below and above rated\n    n_turbines = 2\n    wind_speeds_test = np.ones((1, n_turbines, 3, 3))\n    wind_speeds_test[0,0,:,:] = 20.0 # Above rated\n    wind_speeds_test[0,1,:,:] = 5.0 # Well below eated\n    test_power = SimpleDeratingTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds_test, # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=derated_power * np.ones((1, n_turbines)),\n    )\n    base_power = SimpleTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds_test, # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=derated_power * np.ones((1, n_turbines)),\n    )\n\n    assert test_power[0,0] < base_power[0,0]\n    assert test_power[0,0] == derated_power\n\n    assert test_power[0,1] == base_power[0,1]\n    assert test_power[0,1] < derated_power\n\ndef test_MixedOperationTurbine():\n\n    n_turbines = 1\n    wind_speed = 10.0\n    turbine_data = SampleInputs().turbine\n    tilt_angles_nom = turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((1, n_turbines))\n\n    # Check that for no specified derating or yaw angle, matches SimpleTurbine\n    test_Ct = MixedOperationTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((1, n_turbines)),\n        yaw_angles=np.zeros((1, n_turbines)),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    base_Ct = SimpleTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n    )\n\n    assert np.allclose(test_Ct, base_Ct)\n\n    test_power = MixedOperationTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((1, n_turbines)),\n        yaw_angles=np.zeros((1, n_turbines)),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    base_power = SimpleTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n    )\n    assert np.allclose(test_power, base_power)\n\n    test_ai = MixedOperationTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=POWER_SETPOINT_DEFAULT * np.ones((1, n_turbines)),\n        yaw_angles=np.zeros((1, n_turbines)),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    base_ai = SimpleTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n    )\n    assert np.allclose(test_ai, base_ai)\n\n    # Check that when power_setpoints are set, matches SimpleDeratingTurbine,\n    # while when yaw angles are set, matches CosineLossTurbine\n    n_turbines = 2\n    derated_power = 2.0e6\n\n    test_Ct = MixedOperationTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=np.array([[POWER_SETPOINT_DEFAULT, derated_power]]),\n        yaw_angles=np.array([[20.0, 0.0]]),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    base_Ct_dr = SimpleDeratingTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=np.array([[POWER_SETPOINT_DEFAULT, derated_power]]),\n    )\n    base_Ct_yaw = CosineLossTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        yaw_angles=np.array([[20.0, 0.0]]),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    base_Ct = np.array([[base_Ct_yaw[0,0], base_Ct_dr[0,1]]])\n    assert np.allclose(test_Ct, base_Ct)\n\n    # Do the same as above for power()\n    test_power = MixedOperationTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=np.array([[POWER_SETPOINT_DEFAULT, derated_power]]),\n        yaw_angles=np.array([[20.0, 0.0]]),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    base_power_dr = SimpleDeratingTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=np.array([[POWER_SETPOINT_DEFAULT, derated_power]]),\n    )\n    base_power_yaw = CosineLossTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        yaw_angles=np.array([[20.0, 0.0]]),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    base_power = np.array([[base_power_yaw[0,0], base_power_dr[0,1]]])\n    assert np.allclose(test_power, base_power)\n\n    # Finally, check axial induction\n    test_ai = MixedOperationTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=np.array([[POWER_SETPOINT_DEFAULT, derated_power]]),\n        yaw_angles=np.array([[20.0, 0.0]]),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    base_ai_dr = SimpleDeratingTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        power_setpoints=np.array([[POWER_SETPOINT_DEFAULT, derated_power]]),\n    )\n    base_ai_yaw = CosineLossTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        yaw_angles=np.array([[20.0, 0.0]]),\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    base_ai = np.array([[base_ai_yaw[0,0], base_ai_dr[0,1]]])\n    assert np.allclose(test_ai, base_ai)\n\n    # Check error raised when both yaw and power setpoints are set\n    with pytest.raises(ValueError):\n        # Second turbine has both a power setpoint and a yaw angle\n        MixedOperationTurbine.thrust_coefficient(\n            power_thrust_table=turbine_data[\"power_thrust_table\"],\n            velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n            air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n            power_setpoints=np.array([[POWER_SETPOINT_DEFAULT, derated_power]]),\n            yaw_angles=np.array([[0.0, 20.0]]),\n            tilt_angles=tilt_angles_nom,\n            tilt_interp=None\n        )\n\ndef test_AWCTurbine():\n\n    n_turbines = 1\n    wind_speed = 10.0\n    turbine_data = SampleInputs().turbine\n\n    # Baseline\n    base_Ct = SimpleTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n    )\n    base_power = SimpleTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n    )\n    base_ai = SimpleTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n    )\n\n    # Test no change to Ct, power, or ai when helix amplitudes are 0\n    test_Ct = AWCTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        awc_modes=np.array([[\"helix\"]*n_turbines]*1),\n        awc_amplitudes=np.zeros((1, n_turbines)),\n    )\n    assert np.allclose(test_Ct, base_Ct)\n\n    test_power = AWCTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        awc_modes=np.array([[\"helix\"]*n_turbines]*1),\n        awc_amplitudes=np.zeros((1, n_turbines)),\n    )\n    assert np.allclose(test_power, base_power)\n\n    test_ai = AWCTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        awc_modes=np.array([[\"helix\"]*n_turbines]*1),\n        awc_amplitudes=np.zeros((1, n_turbines)),\n    )\n    assert np.allclose(test_ai, base_ai)\n\n    # Test that Ct, power, and ai all decrease when helix amplitudes are non-zero\n    test_Ct = AWCTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        awc_modes=np.array([[\"helix\"]*n_turbines]*1),\n        awc_amplitudes=2*np.ones((1, n_turbines)),\n    )\n    assert test_Ct < base_Ct\n    assert test_Ct > 0\n\n    test_power = AWCTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        awc_modes=np.array([[\"helix\"]*n_turbines]*1),\n        awc_amplitudes=2*np.ones((1, n_turbines)),\n    )\n    assert test_power < base_power\n    assert test_power > 0\n\n    test_ai = AWCTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        awc_modes=np.array([[\"helix\"]*n_turbines]*1),\n        awc_amplitudes=2*np.ones((1, n_turbines)),\n    )\n    assert test_ai < base_ai\n    assert test_ai > 0\n\n    # Test a mixture of \"baseline\" and \"helix\" modes\n    n_turbines = 3\n    awc_modes_test = np.array(\n        [\n            [\"baseline\", \"baseline\", \"baseline\"],\n            [\"baseline\", \"helix\", \"helix\"]\n        ]\n    )\n    test_power = AWCTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((2, n_turbines, 3, 3)), # 2 findices, 3 turbines, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        awc_modes=awc_modes_test,\n        awc_amplitudes=2*np.ones((2, n_turbines)),\n    )\n    assert np.allclose(test_power[0,:], base_power)\n    assert np.allclose(test_power[1,0], base_power)\n    assert (test_power[1,1:] < base_power).all()\n\n    test_Ct = AWCTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((2, n_turbines, 3, 3)), # 2 findices, 3 turbines, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        awc_modes=awc_modes_test,\n        awc_amplitudes=2*np.ones((2, n_turbines)),\n    )\n    assert np.allclose(test_Ct[0,:], base_Ct)\n    assert np.allclose(test_Ct[1,0], base_Ct)\n    assert (test_Ct[1,1:] < base_Ct).all()\n\ndef test_PeakShavingTurbine():\n\n    n_turbines = 1\n    wind_speed = 10.0\n    turbulence_intensity_low = 0.05\n    turbulence_intensity_high = 0.2\n    turbine_data = SampleInputs().turbine\n\n\n    # Baseline\n    base_Ct = SimpleTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n    )\n    base_power = SimpleTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n    )\n    base_ai = SimpleTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n    )\n\n    # Test no change to Ct, power, or ai when below TI threshold\n    test_Ct = PeakShavingTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        turbulence_intensities=turbulence_intensity_low * np.ones((1, n_turbines, 3, 3)),\n    )\n    assert np.allclose(test_Ct, base_Ct)\n\n    test_power = PeakShavingTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n        turbulence_intensities=turbulence_intensity_low * np.ones((1, n_turbines, 3, 3)),\n    )\n    assert np.allclose(test_power, base_power)\n\n    test_ai = PeakShavingTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        turbulence_intensities=turbulence_intensity_low * np.ones((1, n_turbines, 3, 3)),\n    )\n    assert np.allclose(test_ai, base_ai)\n\n    # Test that Ct, power, and ai all decrease when above TI threshold\n    test_Ct = PeakShavingTurbine.thrust_coefficient(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        turbulence_intensities=turbulence_intensity_high * np.ones((1, n_turbines, 3, 3)),\n    )\n    assert test_Ct < base_Ct\n    assert test_Ct > 0\n\n    test_power = PeakShavingTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        turbulence_intensities=turbulence_intensity_high * np.ones((1, n_turbines, 3, 3)),\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n    )\n\n    assert test_power < base_power\n    assert test_power > 0\n\n    test_ai = PeakShavingTurbine.axial_induction(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        turbulence_intensities=turbulence_intensity_high * np.ones((1, n_turbines, 3, 3)),\n    )\n    assert test_ai < base_ai\n    assert test_ai > 0\n\n    # Test that, for an array of wind speeds, only wind speeds near rated are affected\n    wind_speeds = np.linspace(1, 20, 10)\n    turbulence_intensities = turbulence_intensity_high * np.ones_like(wind_speeds)\n    base_power = SimpleTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds[:, None, None, None],\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n    )\n    test_power = PeakShavingTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speeds[:, None, None, None],\n        turbulence_intensities=turbulence_intensities[:, None, None, None],\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"],\n    )\n    assert (test_power <= base_power).all()\n    assert test_power[0,0] == base_power[0,0]\n    assert test_power[-1,0] == base_power[-1,0]\n"
  },
  {
    "path": "tests/turbine_unit_test.py",
    "content": "\nimport os\nfrom pathlib import Path\n\nimport attr\nimport numpy as np\nimport pytest\nimport yaml\n\nfrom floris.core import (\n    average_velocity,\n    axial_induction,\n    power,\n    thrust_coefficient,\n    Turbine,\n)\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT\nfrom tests.conftest import SampleInputs, WIND_SPEEDS\n\n\n# size 16 x 1 x 1 x 1\n# 16 wind speed and wind direction combinations from conftest\nWIND_CONDITION_BROADCAST = np.reshape(np.array(WIND_SPEEDS), (-1, 1, 1, 1))\n\nINDEX_FILTER = [0, 2]\n\n\ndef test_turbine_init():\n    turbine_data = SampleInputs().turbine\n    turbine = Turbine.from_dict(turbine_data)\n    assert turbine.turbine_type == turbine_data[\"turbine_type\"]\n    assert turbine.rotor_diameter == turbine_data[\"rotor_diameter\"]\n    assert turbine.hub_height == turbine_data[\"hub_height\"]\n    assert (\n        turbine.power_thrust_table[\"cosine_loss_exponent_yaw\"]\n        == turbine_data[\"power_thrust_table\"][\"cosine_loss_exponent_yaw\"]\n    )\n    assert (\n        turbine.power_thrust_table[\"cosine_loss_exponent_tilt\"]\n        == turbine_data[\"power_thrust_table\"][\"cosine_loss_exponent_tilt\"]\n    )\n    assert turbine.TSR == turbine_data[\"TSR\"]\n    assert (\n        turbine.power_thrust_table[\"ref_air_density\"]\n        == turbine_data[\"power_thrust_table\"][\"ref_air_density\"]\n    )\n    assert turbine.power_thrust_table[\"ref_tilt\"] == turbine_data[\"power_thrust_table\"][\"ref_tilt\"]\n    assert np.array_equal(\n        turbine.power_thrust_table[\"wind_speed\"],\n        turbine_data[\"power_thrust_table\"][\"wind_speed\"]\n    )\n    assert np.array_equal(\n        turbine.power_thrust_table[\"power\"],\n        turbine_data[\"power_thrust_table\"][\"power\"]\n    )\n    assert np.array_equal(\n        turbine.power_thrust_table[\"thrust_coefficient\"],\n        turbine_data[\"power_thrust_table\"][\"thrust_coefficient\"]\n    )\n    assert turbine.rotor_radius == turbine.rotor_diameter / 2.0\n    assert turbine.rotor_area == np.pi * turbine.rotor_radius ** 2.0\n\n    assert callable(turbine.thrust_coefficient_function)\n    assert callable(turbine.power_function)\n\n\ndef test_rotor_radius():\n\n    turbine_data = SampleInputs().turbine\n    turbine = Turbine.from_dict(turbine_data)\n\n    # Test that the radius is set correctly from the input file\n    assert turbine.rotor_radius == turbine_data[\"rotor_diameter\"] / 2.0\n\n    # Test the radius setter method since it actually sets the diameter\n    turbine.rotor_radius = 200.0\n    assert turbine.rotor_diameter == 400.0\n\n    # Test the getter-method again\n    assert turbine.rotor_radius == 200.0\n\n\ndef test_rotor_area():\n\n    turbine_data = SampleInputs().turbine\n    turbine = Turbine.from_dict(turbine_data)\n\n    # Test that the area is set correctly from the input file\n    assert turbine.rotor_area == np.pi * (turbine_data[\"rotor_diameter\"] / 2.0) ** 2\n\n    # Test the area setter method since it actually sets the radius and then the diameter\n    turbine.rotor_area = np.pi\n    assert turbine.rotor_radius == 1\n    assert turbine.rotor_diameter == 2\n\n    # Test the getter-method again\n    assert turbine.rotor_area == np.pi\n\n\ndef test_average_velocity():\n    # TODO: why do we use cube root - mean - cube (like rms) instead of a simple average (np.mean)?\n    # Dimensions are (n_findex, n turbines, grid x, grid y)\n    velocities = np.ones((1, 1, 5, 5))\n    assert average_velocity(velocities, method=\"cubic-mean\") == 1\n\n    # Constructs an array of shape 1 x 2 x 3 x 3 with first turbine all 1, second turbine all 2\n    velocities = np.stack(\n        (\n            np.ones((1, 3, 3)),  # The first dimension here is the findex dimension and the second\n            2 * np.ones((1, 3, 3)),  # is the n turbine since we are stacking on axis=1\n        ),\n        axis=1,\n    )\n\n    # Pull out the first findex for the test\n    np.testing.assert_array_equal(\n        average_velocity(velocities, method=\"cubic-mean\")[0],\n        np.array([1, 2])\n    )\n\n    # Test boolean filter\n    ix_filter = [True, False, True, False]\n    velocities = np.stack(  # 4 turbines with 3 x 3 velocity array; shape (1,4,3,3)\n        [i * np.ones((1, 3, 3)) for i in range(1,5)],\n        # (\n        #     # The first dimension here is the findex dimension\n        #     # and second is the turbine dimension since we are stacking on axis=1\n        #     np.ones(\n        #         (1, 3, 3)\n        #     ),\n        #     2 * np.ones((1, 3, 3)),\n        #     3 * np.ones((1, 3, 3)),\n        #     4 * np.ones((1, 3, 3)),\n        # ),\n        axis=1,\n    )\n    avg = average_velocity(velocities, ix_filter, method=\"cubic-mean\")\n    assert avg.shape == (1, 2)  # 1 = n_findex, 2 turbines filtered\n\n    # Pull out the first findex for the comparison\n    assert np.allclose(avg[0], np.array([1.0, 3.0]))\n    # This fails in GitHub Actions due to a difference in precision:\n    # E           assert 3.0000000000000004 == 3.0\n    # np.testing.assert_array_equal(avg[0], np.array([1.0, 3.0]))\n\n    # Test integer array filter\n    # np.arange(1, 5).reshape((-1,1,1)) * np.ones((1, 1, 3, 3))\n    velocities = np.stack(  # 4 turbines with 3 x 3 velocity array; shape (1,4,3,3)\n        [i * np.ones((1, 3, 3)) for i in range(1,5)],\n        axis=1,\n    )\n    avg = average_velocity(velocities, INDEX_FILTER, method=\"cubic-mean\")\n    assert avg.shape == (1, 2)  # 1 findex, 2 turbines filtered\n\n    # Pull out the first findex for the comparison\n    assert np.allclose(avg[0], np.array([1.0, 3.0]))\n\n\ndef test_ct():\n    N_TURBINES = 4\n\n    turbine_data = SampleInputs().turbine\n    turbine_floating_data = SampleInputs().turbine_floating\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_floating = Turbine.from_dict(turbine_floating_data)\n    turbine_type_map = np.array(N_TURBINES * [turbine.turbine_type])\n\n    # Add the findex (0th) dimension\n    turbine_type_map = turbine_type_map[None, :]\n\n    # Single turbine\n    # yaw angle / fCt are (n_findex, n turbine)\n    wind_speed = 10.0\n    thrust = thrust_coefficient(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)),\n        turbulence_intensities=0.06 * np.zeros((1, 1, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((1, 1)),\n        tilt_angles=np.ones((1, 1)) * 5.0,\n        power_setpoints=np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array(\"baseline\"),\n        awc_amplitudes=np.zeros((1, 1)),\n        thrust_coefficient_functions={turbine.turbine_type: turbine.thrust_coefficient_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map[:,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n    )\n\n    truth_index = turbine_data[\"power_thrust_table\"][\"wind_speed\"].index(wind_speed)\n    np.testing.assert_allclose(\n        thrust,\n        turbine_data[\"power_thrust_table\"][\"thrust_coefficient\"][truth_index]\n    )\n\n    # Multiple turbines with index filter\n    # 4 turbines with 3 x 3 grid arrays\n    thrusts = thrust_coefficient(\n        velocities=np.ones((N_TURBINES, 3, 3)) * WIND_CONDITION_BROADCAST,  # 12 x 4 x 3 x 3\n        turbulence_intensities=(\n            0.06 * np.ones((N_TURBINES, 3, 3))\n            * np.ones_like(WIND_CONDITION_BROADCAST)\n        ),\n        air_density=None,\n        yaw_angles=np.zeros((1, N_TURBINES)),\n        tilt_angles=np.ones((1, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((1, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*1),\n        awc_amplitudes=np.zeros((1, N_TURBINES)),\n        thrust_coefficient_functions={turbine.turbine_type: turbine.thrust_coefficient_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False] * N_TURBINES]),\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        ix_filter=INDEX_FILTER,\n    )\n    assert len(thrusts[0]) == len(INDEX_FILTER)\n\n    for i in range(len(INDEX_FILTER)):\n        truth_index = turbine_data[\"power_thrust_table\"][\"wind_speed\"].index(WIND_SPEEDS[0])\n        np.testing.assert_allclose(\n            thrusts[0, i],\n            turbine_data[\"power_thrust_table\"][\"thrust_coefficient\"][truth_index]\n        )\n\n    # Single floating turbine; note that 'tilt_interp' is not set to None\n    thrust = thrust_coefficient(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)), # One findex, one turbine\n        turbulence_intensities=0.06 * np.ones((1, 1, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((1, 1)),\n        tilt_angles=np.ones((1, 1)) * 5.0,\n        power_setpoints=np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array(\"baseline\"),\n        awc_amplitudes=np.zeros((1, 1)),\n        thrust_coefficient_functions={\n            turbine.turbine_type: turbine_floating.thrust_coefficient_function\n        },\n        tilt_interps={turbine_floating.turbine_type: turbine_floating.tilt_interp},\n        correct_cp_ct_for_tilt=np.array([[True]]),\n        turbine_type_map=turbine_type_map[:,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n    )\n\n    truth_index = turbine_floating_data[\"power_thrust_table\"][\"wind_speed\"].index(wind_speed)\n    np.testing.assert_allclose(\n        thrust,\n        turbine_floating_data[\"power_thrust_table\"][\"thrust_coefficient\"][truth_index]\n    )\n\n\ndef test_power():\n    # AIR_DENSITY = 1.225\n\n    # Test that power is computed as expected for a single turbine\n    n_turbines = 1\n    wind_speed = 10.0\n    turbine_data = SampleInputs().turbine\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_type_map = np.array(n_turbines * [turbine.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n    test_power = power(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        turbulence_intensities=0.06 * np.ones((1, 1, 3, 3)),\n        air_density=turbine.power_thrust_table[\"ref_air_density\"],\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((1, 1)), # 1 findex, 1 turbine\n        power_setpoints=np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array(\"baseline\"),\n        awc_amplitudes=np.zeros((1, 1)),\n        tilt_angles=turbine.power_thrust_table[\"ref_tilt\"] * np.ones((1, 1)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map[:,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n    )\n\n    # Recompute using the provided power\n    truth_index = turbine_data[\"power_thrust_table\"][\"wind_speed\"].index(wind_speed)\n    baseline_power = turbine_data[\"power_thrust_table\"][\"power\"][truth_index] * 1000\n    assert np.allclose(baseline_power, test_power)\n\n\n    # At rated, the power calculated should be 5MW since the test data is the NREL 5MW turbine\n    wind_speed = 18.0\n    rated_power = power(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((1, 1, 3, 3)),\n        air_density=turbine.power_thrust_table[\"ref_air_density\"],\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((1, 1)), # 1 findex, 1 turbine\n        tilt_angles=turbine.power_thrust_table[\"ref_tilt\"] * np.ones((1, 1)),\n        power_setpoints=np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array(\"baseline\"),\n        awc_amplitudes=np.zeros((1, 1)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map[:,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n    )\n    assert np.allclose(rated_power, 5e6)\n\n\n    # At wind speed = 0.0, the power should be 0 based on the provided Cp curve\n    wind_speed = 0.0\n    zero_power = power(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((1, 1, 3, 3)),\n        air_density=turbine.power_thrust_table[\"ref_air_density\"],\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((1, 1)), # 1 findex, 1 turbine\n        tilt_angles=turbine.power_thrust_table[\"ref_tilt\"] * np.ones((1, 1)),\n        power_setpoints=np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array(\"baseline\"),\n        awc_amplitudes=np.zeros((1, 1)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map[:,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n    )\n    assert np.allclose(zero_power, 0.0)\n\n\n    # Test 4-turbine velocities array\n    n_turbines = 4\n    wind_speed = 10.0\n    turbine_data = SampleInputs().turbine\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_type_map = np.array(n_turbines * [turbine.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n    test_4_power = power(\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((1, n_turbines, 3, 3)),\n        air_density=turbine.power_thrust_table[\"ref_air_density\"],\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((1, n_turbines)),\n        tilt_angles=turbine.power_thrust_table[\"ref_tilt\"] * np.ones((1, n_turbines)),\n        power_setpoints=np.ones((1, n_turbines)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*n_turbines]*1),\n        awc_amplitudes=np.zeros((1, n_turbines)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n    )\n    baseline_4_power = baseline_power * np.ones((1, n_turbines))\n    assert np.allclose(baseline_4_power, test_4_power)\n    assert np.shape(baseline_4_power) == np.shape(test_4_power)\n\n\n    # Same as above but with the grid collapsed in the velocities array\n    turbine_data = SampleInputs().turbine\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_type_map = np.array(n_turbines * [turbine.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n    test_grid_power = power(\n        velocities=wind_speed * np.ones((1, n_turbines, 1)),\n        turbulence_intensities=0.06 * np.ones((1, n_turbines, 3)),\n        air_density=turbine.power_thrust_table[\"ref_air_density\"],\n        power_functions={turbine.turbine_type: turbine.power_function},\n        yaw_angles=np.zeros((1, n_turbines)),\n        tilt_angles=turbine.power_thrust_table[\"ref_tilt\"] * np.ones((1, n_turbines)),\n        power_setpoints=np.ones((1, n_turbines)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*n_turbines]*1),\n        awc_amplitudes=np.zeros((1, n_turbines)),\n        tilt_interps={turbine.turbine_type: turbine.tilt_interp},\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n    )\n    baseline_grid_power = baseline_power * np.ones((1, n_turbines))\n    assert np.allclose(baseline_grid_power, test_grid_power)\n    assert np.shape(baseline_grid_power) == np.shape(test_grid_power)\n\n\ndef test_axial_induction():\n\n    N_TURBINES = 4\n\n    turbine_data = SampleInputs().turbine\n    turbine_floating_data = SampleInputs().turbine_floating\n    turbine = Turbine.from_dict(turbine_data)\n    turbine_floating = Turbine.from_dict(turbine_floating_data)\n    turbine_type_map = np.array(N_TURBINES * [turbine.turbine_type])\n    turbine_type_map = turbine_type_map[None, :]\n\n    baseline_ai = 0.26752001107622186415\n\n    # Single turbine\n    wind_speed = 10.0\n    ai = axial_induction(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)), # 1 findex, 1 Turbine\n        turbulence_intensities=0.06 * np.ones((1, 1, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((1, 1)),\n        tilt_angles=np.ones((1, 1)) * 5.0,\n        power_setpoints=np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array(\"baseline\"),\n        awc_amplitudes=np.zeros((1, 1)),\n        axial_induction_functions={turbine.turbine_type: turbine.axial_induction_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False]]),\n        turbine_type_map=turbine_type_map[0,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n    )\n    np.testing.assert_allclose(ai, baseline_ai)\n\n    # Multiple turbines with ix filter\n    ai = axial_induction(\n        velocities=np.ones((N_TURBINES, 3, 3)) * WIND_CONDITION_BROADCAST,  # 12 x 4 x 3 x 3\n        turbulence_intensities=(\n            0.06 * np.ones((N_TURBINES, 3, 3))\n            * np.ones_like(WIND_CONDITION_BROADCAST)\n        ),\n        air_density=None,\n        yaw_angles=np.zeros((1, N_TURBINES)),\n        tilt_angles=np.ones((1, N_TURBINES)) * 5.0,\n        power_setpoints=np.ones((1, N_TURBINES)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array([[\"baseline\"]*N_TURBINES]*1),\n        awc_amplitudes=np.zeros((1, N_TURBINES)),\n        axial_induction_functions={turbine.turbine_type: turbine.axial_induction_function},\n        tilt_interps={turbine.turbine_type: None},\n        correct_cp_ct_for_tilt=np.array([[False] * N_TURBINES]),\n        turbine_type_map=turbine_type_map,\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n        ix_filter=INDEX_FILTER,\n    )\n\n    assert len(ai[0]) == len(INDEX_FILTER)\n\n    # Test the 10 m/s wind speed to use the same baseline as above\n    np.testing.assert_allclose(ai[2], baseline_ai)\n\n    # Single floating turbine; note that 'tilt_interp' is not set to None\n    ai = axial_induction(\n        velocities=wind_speed * np.ones((1, 1, 3, 3)),\n        turbulence_intensities=0.06 * np.ones((1, 1, 3, 3)),\n        air_density=None,\n        yaw_angles=np.zeros((1, 1)),\n        tilt_angles=np.ones((1, 1)) * 5.0,\n        power_setpoints=np.ones((1, 1)) * POWER_SETPOINT_DEFAULT,\n        awc_modes=np.array(\"baseline\"),\n        awc_amplitudes=np.zeros((1, 1)),\n        axial_induction_functions={turbine.turbine_type: turbine.axial_induction_function},\n        tilt_interps={turbine_floating.turbine_type: turbine_floating.tilt_interp},\n        correct_cp_ct_for_tilt=np.array([[True]]),\n        turbine_type_map=turbine_type_map[0,0],\n        turbine_power_thrust_tables={turbine.turbine_type: turbine.power_thrust_table},\n    )\n    np.testing.assert_allclose(ai, baseline_ai)\n\n\ndef test_asdict(sample_inputs_fixture: SampleInputs):\n\n    turbine = Turbine.from_dict(sample_inputs_fixture.turbine)\n    dict1 = turbine.as_dict()\n\n    new_turb = Turbine.from_dict(dict1)\n    dict2 = new_turb.as_dict()\n\n    assert dict1 == dict2\n"
  },
  {
    "path": "tests/turbine_utilities_unit_test.py",
    "content": "\nimport os\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\nimport yaml\n\nfrom floris.turbine_library import build_cosine_loss_turbine_dict, check_smooth_power_curve\nfrom tests.conftest import SampleInputs\n\n\ndef test_build_turbine_dict():\n\n    turbine_data_v3 = SampleInputs().v3type_turbine\n\n    # Mocked up turbine data\n    turbine_data_dict = {\n        \"wind_speed\":turbine_data_v3[\"power_thrust_table\"][\"wind_speed\"],\n        \"power_coefficient\":turbine_data_v3[\"power_thrust_table\"][\"power\"],\n        \"thrust_coefficient\":turbine_data_v3[\"power_thrust_table\"][\"thrust\"]\n    }\n\n    test_dict = build_cosine_loss_turbine_dict(\n        turbine_data_dict,\n        \"test_turbine\",\n        generator_efficiency=turbine_data_v3[\"generator_efficiency\"],\n        hub_height=turbine_data_v3[\"hub_height\"],\n        cosine_loss_exponent_yaw=turbine_data_v3[\"pP\"],\n        cosine_loss_exponent_tilt=turbine_data_v3[\"pT\"],\n        rotor_diameter=turbine_data_v3[\"rotor_diameter\"],\n        TSR=turbine_data_v3[\"TSR\"],\n        ref_air_density=turbine_data_v3[\"ref_density_cp_ct\"],\n        ref_tilt=turbine_data_v3[\"ref_tilt_cp_ct\"]\n    )\n\n    # Test correct error raised if power_coefficient version passed and generator efficiency\n    # not specified\n    with pytest.raises(KeyError):\n        build_cosine_loss_turbine_dict(\n            turbine_data_dict,\n            \"test_turbine\",\n            #generator_efficiency=turbine_data_v3[\"generator_efficiency\"],\n            hub_height=turbine_data_v3[\"hub_height\"],\n            cosine_loss_exponent_yaw=turbine_data_v3[\"pP\"],\n            cosine_loss_exponent_tilt=turbine_data_v3[\"pT\"],\n            rotor_diameter=turbine_data_v3[\"rotor_diameter\"],\n            TSR=turbine_data_v3[\"TSR\"],\n            ref_air_density=turbine_data_v3[\"ref_density_cp_ct\"],\n            ref_tilt=turbine_data_v3[\"ref_tilt_cp_ct\"]\n        )\n\n    # Directly compute power, thrust values\n    Cp = np.array(turbine_data_v3[\"power_thrust_table\"][\"power\"])\n    Ct = np.array(turbine_data_v3[\"power_thrust_table\"][\"thrust\"])\n    ws = np.array(turbine_data_v3[\"power_thrust_table\"][\"wind_speed\"])\n\n    P = (\n        0.5 * turbine_data_v3[\"ref_density_cp_ct\"]\n        * turbine_data_v3[\"generator_efficiency\"]\n        * (np.pi * turbine_data_v3[\"rotor_diameter\"]**2/4)\n        * Cp * ws**3\n    )\n    T = (\n        0.5 * turbine_data_v3[\"ref_density_cp_ct\"]\n        * (np.pi * turbine_data_v3[\"rotor_diameter\"]**2/4)\n        * Ct * ws**2\n    )\n\n    # Compare direct computation to those generated by build_cosine_loss_turbine_dict\n    assert np.allclose(Ct, test_dict[\"power_thrust_table\"][\"thrust_coefficient\"])\n    assert np.allclose(P/1000, test_dict[\"power_thrust_table\"][\"power\"])\n\n    # Check that dict keys match the v4 structure\n    turbine_data_v4 = SampleInputs().turbine\n    assert set(turbine_data_v4.keys()) >= set(test_dict.keys())\n    assert (\n        set(turbine_data_v4[\"power_thrust_table\"].keys())\n        >= set(test_dict[\"power_thrust_table\"].keys())\n    )\n\n    # Check thrust conversion from absolute value\n    turbine_data_dict = {\n        \"wind_speed\":turbine_data_v3[\"power_thrust_table\"][\"wind_speed\"],\n        \"power\": P/1000,\n        \"thrust\": T/1000\n    }\n\n    test_dict_2 = build_cosine_loss_turbine_dict(\n        turbine_data_dict,\n        \"test_turbine\",\n        hub_height=turbine_data_v4[\"hub_height\"],\n        cosine_loss_exponent_yaw=turbine_data_v4[\"power_thrust_table\"][\"cosine_loss_exponent_yaw\"],\n        cosine_loss_exponent_tilt=turbine_data_v4[\"power_thrust_table\"][\"cosine_loss_exponent_tilt\"],\n        rotor_diameter=turbine_data_v4[\"rotor_diameter\"],\n        TSR=turbine_data_v4[\"TSR\"],\n        ref_air_density=turbine_data_v4[\"power_thrust_table\"][\"ref_air_density\"],\n        ref_tilt=turbine_data_v4[\"power_thrust_table\"][\"ref_tilt\"]\n    )\n    assert np.allclose(Ct, test_dict_2[\"power_thrust_table\"][\"thrust_coefficient\"])\n\n\ndef test_check_smooth_power_curve():\n\n    p1 = np.array([0, 1, 2, 3, 3, 3, 3, 2, 1], dtype=float)*1000 # smooth\n    p2 = np.array([0, 1, 2, 3, 2.99, 3.01, 3, 2, 1], dtype=float)*1000 # non-smooth\n\n    p3 = p1.copy()\n    p3[5] = p3[5] + 9e-4  # just smooth enough\n\n    p4 = p1.copy()\n    p4[5] = p4[5] + 1.1e-3 # just not smooth enough\n\n    # Without a shutdown region\n    p5 = p1[:-3] # smooth\n    p6 = p2[:-3] # non-smooth\n\n    assert check_smooth_power_curve(p1)\n    assert not check_smooth_power_curve(p2)\n    assert check_smooth_power_curve(p3)\n    assert not check_smooth_power_curve(p4)\n    assert check_smooth_power_curve(p5)\n    assert not check_smooth_power_curve(p6)\n"
  },
  {
    "path": "tests/turboparkgauss_unit_test.py",
    "content": "from pathlib import Path\n\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom floris.turbine_library import build_cosine_loss_turbine_dict\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\nYAML_INPUT = TEST_DATA / \"input_full.yaml\"\n\ndef test_row_of_turbines():\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n\n    # Configure as turboparkgauss\n    fmodel_dict = fmodel.core.as_dict()\n    fmodel_dict[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"turboparkgauss\"\n    fmodel_dict[\"wake\"][\"model_strings\"][\"turbulence_model\"] = \"none\"\n    fmodel_dict[\"wake\"][\"model_strings\"][\"deflection_model\"] = \"none\"\n    fmodel_dict[\"wake\"][\"model_strings\"][\"combination_model\"] = \"sosfs\"\n    fmodel_dict[\"wake\"][\"enable_secondary_steering\"] = False\n    fmodel_dict[\"wake\"][\"enable_yaw_added_recovery\"] = False\n    fmodel_dict[\"wake\"][\"enable_active_wake_mixing\"] = False\n    fmodel_dict[\"wake\"][\"enable_transverse_velocities\"] = False\n    fmodel_dict[\"solver\"][\"type\"] = \"turbine_cubature_grid\"\n    fmodel_dict[\"solver\"][\"turbine_grid_points\"] = 6\n    fmodel = FlorisModel(configuration=fmodel_dict)\n\n    # Define turbine\n    const_CT_turb = build_cosine_loss_turbine_dict(\n        turbine_data_dict={\n            \"wind_speed\":[0.0, 30.0],\n            \"power\":[0.0, 1.0], # Not realistic but won't be used here\n            \"thrust_coefficient\":[0.75, 0.75]\n        },\n        turbine_name=\"ConstantCT\",\n        rotor_diameter=120.0,\n        hub_height=100.0,\n        ref_tilt=0.0,\n    )\n\n    # Set up problem and run\n    fmodel.set(\n        layout_x=np.linspace(0.0, 5400.0, 10),\n        layout_y=np.zeros(10),\n        wind_speeds=[8.0],\n        wind_directions=[270.0],\n        turbulence_intensities=[0.06],\n        wind_shear=0.0,\n        turbine_type=[const_CT_turb],\n    )\n    fmodel.run()\n\n    # Run and extract flow velocities at the turbines\n    velocities_row_normalized = fmodel.turbine_average_velocities[0,:] / 8.0\n\n    # Comparison data generated by running Ørsted's Matlab code\n    # https://github.com/OrstedRD/TurbOPark\n    velocities_comparison = np.array([\n        1.0,\n        0.709920677983239,\n        0.615355749367675,\n        0.551410465937128,\n        0.502600655337247,\n        0.463167556093190,\n        0.430238792036599,\n        0.402137593655074,\n        0.377783142608699,\n        0.356429516711137,\n    ])\n\n    # Compare the results\n    print(velocities_row_normalized)\n\n    np.testing.assert_allclose(\n        velocities_row_normalized,\n        velocities_comparison,\n        rtol=1e-2,\n    ) # Within 1% tolerance\n"
  },
  {
    "path": "tests/type_dec_unit_test.py",
    "content": "\nfrom pathlib import Path\nfrom typing import List\n\nimport numpy as np\nimport pytest\nfrom attrs import define, field\n\nfrom floris.type_dec import (\n    convert_to_path,\n    floris_array_converter,\n    floris_numeric_dict_converter,\n    FromDictMixin,\n    iter_validator,\n)\n\n\n@define\nclass AttrsDemoClass(FromDictMixin):\n    w: int\n    x: int = field(converter=int)\n    y: float = field(converter=float, default=2.1)\n    z: str = field(converter=str, default=\"z\")\n    non_initd: float = field(init=False)\n\n    def __attrs_post_init__(self):\n        self.non_initd = 1.1\n\n    liststr: List[str] = field(\n        factory=lambda:[\"qwerty\", \"asdf\"],\n        validator=iter_validator(list, str)\n    )\n    array: np.ndarray = field(\n        factory=lambda:[1.0, 2.0],\n        converter=floris_array_converter,\n        # validator=iter_validator(np.ndarray, floris_float_type)\n    )\n\n\ndef test_as_dict():\n    # Non-initialized attributes should not be exported\n    cls = AttrsDemoClass(w=0, x=1, liststr=[\"a\", \"b\"])\n    exported_dict = cls.as_dict()\n    assert \"non_initd\" not in exported_dict\n\n\ndef test_FromDictMixin_defaults():\n    # Test that the defaults set in the class definition are actually used\n    inputs = {\"w\": 0, \"x\": 1}\n    cls = AttrsDemoClass.from_dict(inputs)\n    defaults = {a.name: a.default for a in AttrsDemoClass.__attrs_attrs__ if a.default}\n    assert cls.y == defaults[\"y\"]\n    assert cls.z == defaults[\"z\"]\n    np.testing.assert_array_equal(cls.liststr, defaults[\"liststr\"].factory())\n    np.testing.assert_array_equal(cls.array, defaults[\"array\"].factory())\n\n    # Test that defaults can be overwritten\n    inputs = {\"w\": 0, \"x\": 1, \"y\": 4.5}\n    cls = AttrsDemoClass.from_dict(inputs)\n    defaults = {a.name: a.default for a in AttrsDemoClass.__attrs_attrs__ if a.default}\n    assert cls.y != defaults[\"y\"]\n\n\ndef test_FromDictMixin_custom():\n\n    inputs = {\n        \"w\": 0,\n        \"x\": 1,\n        \"y\": 2.3,\n        \"z\": \"asdf\",\n        \"liststr\": [\"a\", \"b\"],\n        \"array\": np.array([[1,2,3], [4,5,6]])\n    }\n\n    # Check that custom inputs are accepted\n    AttrsDemoClass.from_dict(inputs)\n\n    # Ensure extraneous inputs are not applied to the class\n    inputs2 = {**inputs, \"extra\": [3, 4, 5.5]}\n    with pytest.raises(AttributeError):\n        AttrsDemoClass.from_dict(inputs2)\n\n    # Test that missing required inputs raises an error\n    inputs = {}\n    with pytest.raises(AttributeError):\n        AttrsDemoClass.from_dict(inputs)\n\n\ndef test_iter_validator():\n\n    # Check the correct values work\n    _ = AttrsDemoClass(w=0, x=1, liststr=[\"a\", \"b\"])\n\n    # Check wrong member type\n    with pytest.raises(TypeError):\n        AttrsDemoClass(w=0, x=1, liststr=[4.3, 1])\n\n    # Check mixed member types\n    with pytest.raises(TypeError):\n        AttrsDemoClass(w=0, x=1, liststr=[4.3, \"1\"])\n\n    # Check wrong iterable type\n    with pytest.raises(TypeError):\n        AttrsDemoClass(w=0, x=1, liststr=(\"a\", \"b\"))\n\n\ndef test_array_converter():\n    array_input = [[1, 2, 3], [4.5, 6.3, 2.2]]\n    test_array = np.array(array_input)\n\n    # Test conversion on initialization\n    cls = AttrsDemoClass(w=0, x=1, array=array_input)\n    np.testing.assert_allclose(test_array, cls.array)\n\n    # Test conversion on reset\n    cls.array = array_input\n    np.testing.assert_allclose(test_array, cls.array)\n\n    # Test that a non-iterable item like a scalar number fails\n    with pytest.raises(TypeError):\n        cls.array = 1\n\n\ndef test_numeric_dict_converter():\n    \"\"\"\n    This function converts data in a dictionary to a numeric type.\n    If it can't convert the data, it will raise a TypeError.\n    It should support scalar, list, and numpy array types\n    for values in the dictionary.\n    \"\"\"\n    test_dict = {\n        \"scalar_string\": \"1\",\n        \"scalar_int\": 1,\n        \"scalar_float\": 1.0,\n        \"list_string\": [\"1\", \"2\", \"3\"],\n        \"list_int\": [1, 2, 3],\n        \"list_float\": [1.0, 2.0, 3.0],\n        \"array_string\": np.array([\"1\", \"2\", \"3\"]),\n        \"array_int\": np.array([1, 2, 3]),\n        \"array_float\": np.array([1.0, 2.0, 3.0]),\n    }\n    numeric_dict = floris_numeric_dict_converter(test_dict)\n    assert numeric_dict[\"scalar_string\"] == 1\n    assert numeric_dict[\"scalar_int\"] == 1\n    assert numeric_dict[\"scalar_float\"] == 1.0\n    np.testing.assert_allclose(numeric_dict[\"list_string\"], [1, 2, 3])\n    np.testing.assert_allclose(numeric_dict[\"list_int\"], [1, 2, 3])\n    np.testing.assert_allclose(numeric_dict[\"list_float\"], [1.0, 2.0, 3.0])\n    np.testing.assert_allclose(numeric_dict[\"array_string\"], [1, 2, 3])\n    np.testing.assert_allclose(numeric_dict[\"array_int\"], [1, 2, 3])\n    np.testing.assert_allclose(numeric_dict[\"array_float\"], [1.0, 2.0, 3.0])\n\n    test_dict = {\"scalar_fail\": \"a\"}\n    with pytest.raises(TypeError):\n        floris_numeric_dict_converter(test_dict)\n    test_dict = {\"list_fail\": [\"a\", \"2\", \"3\"]}\n    with pytest.raises(TypeError):\n        floris_numeric_dict_converter(test_dict)\n    test_dict = {\"array_fail\": np.array([\"a\", \"2\", \"3\"])}\n    with pytest.raises(TypeError):\n        floris_numeric_dict_converter(test_dict)\n\ndef test_convert_to_path():\n    str_input = Path(__file__)\n    expected_path = str_input.resolve()\n\n    # Test that a string works\n    test_str_input = convert_to_path(str_input)\n    assert test_str_input == expected_path\n\n    # Test that a pathlib.Path works\n    path_input = Path(str_input)\n    test_path_input = convert_to_path(path_input)\n    assert test_path_input == expected_path\n\n    # Test that both of those inputs are the same\n    # NOTE These first three asserts tests the relative path search\n    assert test_str_input == test_path_input\n\n    # Test absolute path\n    abs_path = expected_path\n    test_abs_path = convert_to_path(abs_path)\n    assert test_abs_path == expected_path\n\n    # Test a file\n    file_input = Path(__file__)\n    test_file = convert_to_path(file_input)\n    assert test_file == file_input\n\n    # Test that a non-existent folder fails, now that the conversion has a multi-pronged search\n    str_input = str(Path(__file__).parent / \"bad_path\")\n    with pytest.raises(FileExistsError):\n        convert_to_path(str_input)\n\n    # Test that invalid data types fail\n    with pytest.raises(TypeError):\n        convert_to_path(1)\n\n    with pytest.raises(TypeError):\n        convert_to_path(1.2)\n\n    with pytest.raises(TypeError):\n        convert_to_path({\"one\": 1})\n\n    with pytest.raises(TypeError):\n        convert_to_path([\"a\", 1])\n"
  },
  {
    "path": "tests/uncertain_floris_model_integration_test.py",
    "content": "from pathlib import Path\n\nimport numpy as np\nimport pytest\nimport yaml\n\nfrom floris import (\n    FlorisModel,\n    ParFlorisModel,\n    TimeSeries,\n)\nfrom floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT\nfrom floris.uncertain_floris_model import (\n    ApproxFlorisModel,\n    UncertainFlorisModel,\n    WindRose,\n)\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\nYAML_INPUT = TEST_DATA / \"input_full.yaml\"\n\n\ndef test_read_yaml():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n    assert isinstance(ufmodel, UncertainFlorisModel)\n\n\ndef test_rounded_inputs():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n\n    # Using defaults\n    # Example input array\n    input_array = np.array([[45.3, 7.6, 0.24, 90.7, 749], [60.1, 8.2, 0.3, 95.3, 751]])\n\n    # Expected output array after rounding\n    expected_output = np.array([[45.0, 8.0, 0.25, 91.0, 700.0], [60.0, 8.0, 0.3, 95.0, 800.0]])\n\n    # Call the function\n    rounded_inputs = ufmodel._get_rounded_inputs(input_array)\n\n    np.testing.assert_almost_equal(rounded_inputs, expected_output)\n\n\ndef test_expand_wind_directions():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n\n    input_array = np.array(\n        [[1, 20, 30], [40, 50, 60], [70, 80, 90], [100, 110, 120], [359, 140, 150]]\n    )\n\n    # Test even length\n    with pytest.raises(ValueError):\n        wd_sample_points = [-15, -10, -5, 5, 10, 15]  # Even lenght\n        ufmodel._expand_wind_directions(input_array, wd_sample_points)\n\n    # Test middle element not 0\n    with pytest.raises(ValueError):\n        wd_sample_points = [-15, -10, -5, 1, 5, 10, 15]  # Odd length, not 0 at the middle\n        ufmodel._expand_wind_directions(input_array, wd_sample_points)\n\n    # Test correction operations\n    wd_sample_points = [-15, -10, -5, 0, 5, 10, 15]  # Odd length, 0 at the middle\n    output_array = ufmodel._expand_wind_directions(input_array, wd_sample_points)\n\n    # Check if output shape is correct\n    assert output_array.shape[0] == 35\n\n    # Check 360 wrapping\n    # 1 - 15 = -14 -> 346\n    np.testing.assert_almost_equal(output_array[0, 0], 346.0)\n\n    # Check 360 wrapping\n    # 359 + 15 = 374 -> 14\n    np.testing.assert_almost_equal(output_array[-1, 0], 14.0)\n\n\ndef test_expand_wind_directions_with_yaw_nom():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n\n    # Assume 2 turbine\n    n_turbines = 2\n\n    # Assume n_findex = 2\n    input_array = np.array(\n        [[270.0, 8.0, 0.6, 0.0, 0.0, 0.0, 0.0], [270.0, 8.0, 0.6, 0.0, 2.0, 0.0, 0.0]]\n    )\n\n    # 3 sample points\n    wd_sample_points = [-3, 0, 3]\n\n    # Test correction operations\n    output_array = ufmodel._expand_wind_directions(input_array, wd_sample_points, True, n_turbines)\n\n    # Check the first direction\n    np.testing.assert_almost_equal(output_array[0, 0], 267)\n\n    # Check the first yaw\n    np.testing.assert_almost_equal(output_array[0, 4], -3)\n\n    # Rerun with fix_yaw_to_nominal_direction = False, and now the yaw should be 0\n    output_array = ufmodel._expand_wind_directions(input_array, wd_sample_points, False, n_turbines)\n\n    # Check the first direction\n    np.testing.assert_almost_equal(output_array[0, 0], 267)\n\n    # Check the first yaw\n    np.testing.assert_almost_equal(output_array[0, 4], 0)\n\n\ndef test_get_unique_inputs():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n\n    input_array = np.array(\n        [\n            [0, 1],\n            [0, 2],\n            [0, 1],\n            [1, 1],\n            [0, 1],\n        ]\n    )\n\n    expected_unique_inputs = np.array([[0, 1], [0, 2], [1, 1]])\n\n    unique_inputs, map_to_expanded_inputs = ufmodel._get_unique_inputs(input_array)\n\n    # test expected result\n    assert np.array_equal(unique_inputs, expected_unique_inputs)\n\n    # Test gets back to original\n    assert np.array_equal(unique_inputs[map_to_expanded_inputs], input_array)\n\n\ndef test_get_weights():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n    weights = ufmodel._get_weights(3.0, [-6, -3, 0, 3, 6])\n    np.testing.assert_allclose(\n        weights, np.array([0.05448868, 0.24420134, 0.40261995, 0.24420134, 0.05448868])\n    )\n\n\ndef test_uncertain_floris_model():\n    # Recompute uncertain result using certain result with 1 deg\n\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT, wd_sample_points=[-3, 0, 3], wd_std=3)\n\n    fmodel.set(\n        layout_x=[0, 300],\n        layout_y=[0, 0],\n        wind_speeds=[8.0, 8.0, 8.0],\n        wind_directions=[267.0, 270.0, 273],\n        turbulence_intensities=[0.06, 0.06, 0.06],\n    )\n\n    ufmodel.set(\n        layout_x=[0, 300],\n        layout_y=[0, 0],\n        wind_speeds=[8.0],\n        wind_directions=[270.0],\n        turbulence_intensities=[0.06],\n    )\n\n    fmodel.run()\n    ufmodel.run()\n\n    nom_powers = fmodel.get_turbine_powers()[:, 1].flatten()\n    unc_powers = ufmodel.get_turbine_powers()[:, 1].flatten()\n\n    weights = ufmodel.weights\n\n    np.testing.assert_allclose(np.sum(nom_powers * weights), unc_powers)\n\n\ndef test_uncertain_floris_model_setpoints():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT, wd_sample_points=[-3, 0, 3], wd_std=3)\n\n    fmodel.set(\n        layout_x=[0, 300],\n        layout_y=[0, 0],\n        wind_speeds=[8.0, 8.0, 8.0],\n        wind_directions=[267.0, 270.0, 273],\n        turbulence_intensities=[0.06, 0.06, 0.06],\n    )\n\n    ufmodel.set(\n        layout_x=[0, 300],\n        layout_y=[0, 0],\n        wind_speeds=[8.0],\n        wind_directions=[270.0],\n        turbulence_intensities=[0.06],\n    )\n    weights = ufmodel.weights\n\n    # Check setpoints dimensions are respected and reset_operation works\n    # Note that fmodel.set() does NOT raise ValueError---an AttributeError is raised only at\n    # fmodel.run()---whereas ufmodel.set raises ValueError immediately.\n    # fmodel.set(yaw_angles=np.array([[0.0, 0.0]]))\n    # with pytest.raises(AttributeError):\n    #     fmodel.run()\n    # with pytest.raises(ValueError):\n    #     ufmodel.set(yaw_angles=np.array([[0.0, 0.0]]))\n\n    fmodel.set(yaw_angles=np.array([[20.0, 0.0], [20.0, 0.0], [20.0, 0.0]]))\n    fmodel.run()\n    nom_powers = fmodel.get_turbine_powers()[:, 1].flatten()\n\n    ufmodel.set(yaw_angles=np.array([[20.0, 0.0]]))\n    ufmodel.run()\n    unc_powers = ufmodel.get_turbine_powers()[:, 1].flatten()\n\n    np.testing.assert_allclose(np.sum(nom_powers * weights), unc_powers)\n\n    # Drop yaw setpoints and rerun\n    fmodel.reset_operation()\n    fmodel.run()\n    nom_powers = fmodel.get_turbine_powers()[:, 1].flatten()\n\n    ufmodel.reset_operation()\n    ufmodel.run()\n    unc_powers = ufmodel.get_turbine_powers()[:, 1].flatten()\n\n    np.testing.assert_allclose(np.sum(nom_powers * weights), unc_powers)\n\n\ndef test_get_powers_with_wind_data():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 10.0, 12.0, 8.0, 10.0, 12.0])\n    wind_directions = np.array([270.0, 270.0, 270.0, 280.0, 280.0, 280.0])\n    turbulence_intensities = 0.06 * np.ones_like(wind_speeds)\n\n    ufmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=[0, 1000, 2000, 3000],\n        layout_y=[0, 0, 0, 0],\n    )\n    ufmodel.run()\n    farm_power_simple = ufmodel.get_farm_power()\n\n    # Now declare a WindRose with 2 wind directions and 3 wind speeds\n    # uniform TI and frequency\n    wind_rose = WindRose(\n        wind_directions=np.unique(wind_directions),\n        wind_speeds=np.unique(wind_speeds),\n        ti_table=0.06,\n    )\n\n    # Set this wind rose, run\n    ufmodel.set(wind_data=wind_rose)\n    ufmodel.run()\n\n    farm_power_windrose = ufmodel.get_farm_power()\n\n    # Check dimensions and that the farm power is the sum of the turbine powers\n    assert farm_power_windrose.shape == (2, 3)\n    assert np.allclose(farm_power_windrose, ufmodel.get_turbine_powers().sum(axis=2))\n\n    # Check that simple and windrose powers are consistent\n    assert np.allclose(farm_power_simple.reshape(2, 3), farm_power_windrose)\n    assert np.allclose(farm_power_simple, farm_power_windrose.flatten())\n\n    # Test that if the last turbine's weight is set to 0, the farm power is the same as the\n    # sum of the first 3 turbines\n    turbine_weights = np.array([1.0, 1.0, 1.0, 0.0])\n    farm_power_weighted = ufmodel.get_farm_power(turbine_weights=turbine_weights)\n\n    assert np.allclose(farm_power_weighted, ufmodel.get_turbine_powers()[:, :, :-1].sum(axis=2))\n\n\ndef test_AEP_with_wind_data():\n    wind_speeds = np.array([8.0, 10.0])\n    wind_directions = np.array([270.0, 280.0])\n    frequencies = np.array([[0.25, 0.25], [0.1, 0.4]])\n    wind_rose = WindRose(\n        wind_directions=np.unique(wind_directions),\n        wind_speeds=np.unique(wind_speeds),\n        freq_table=frequencies,\n        ti_table=0.06,\n    )\n\n    # Set wind_data on UncertainFlorisModel directly\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n    ufmodel.set(wind_data=wind_rose)\n    ufmodel.run()\n    aep_1 = ufmodel.get_farm_AEP()\n\n    # Set wind_data on FlorisModel and then set on UncertainFlorisModel\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    fmodel.set(wind_data=wind_rose)\n    ufmodel = UncertainFlorisModel(fmodel)\n    ufmodel.run()\n    aep_2 = ufmodel.get_farm_AEP()\n\n    # Check AEPs match\n    assert np.allclose(aep_1, aep_2)\n\n\ndef test_approx_floris_model():\n    afmodel = ApproxFlorisModel(configuration=YAML_INPUT, wd_resolution=1.0)\n\n    time_series = TimeSeries(\n        wind_directions=np.array([270.0, 270.1, 271.0, 271.1]),\n        wind_speeds=8.0,\n        turbulence_intensities=0.06,\n    )\n\n    afmodel.set(layout_x=np.array([0, 500]), layout_y=np.array([0, 0]), wind_data=time_series)\n\n    # Test that 0th and 1th values are the same, as are the 2nd and 3rd\n    afmodel.run()\n    power = afmodel.get_farm_power()\n    np.testing.assert_almost_equal(power[0], power[1])\n    np.testing.assert_almost_equal(power[2], power[3])\n\n    # Test with wind direction and wind speed varying\n    afmodel = ApproxFlorisModel(configuration=YAML_INPUT, wd_resolution=1.0, ws_resolution=1.0)\n    time_series = TimeSeries(\n        wind_directions=np.array([270.0, 270.1, 271.0, 271.1]),\n        wind_speeds=np.array([8.0, 8.1, 8.0, 9.0]),\n        turbulence_intensities=0.06,\n    )\n\n    afmodel.set(layout_x=np.array([0, 500]), layout_y=np.array([0, 0]), wind_data=time_series)\n    afmodel.run()\n\n    # In this case the 0th and 1st should be the same, but not the 2nd and 3rd\n    power = afmodel.get_farm_power()\n    np.testing.assert_almost_equal(power[0], power[1])\n    assert not np.allclose(power[2], power[3])\n\n    # Test copy method\n    assert isinstance(afmodel.copy(), ApproxFlorisModel)\n\n\ndef test_expected_farm_power_regression():\n    ufmodel = UncertainFlorisModel(\n        configuration=YAML_INPUT,\n        wd_sample_points=[0],\n    )  # Force equal to nominal\n\n    wind_speeds = np.array([8.0, 8.0, 8.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    turbulence_intensities = np.array([0.06, 0.06, 0.06])\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n\n    ufmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=layout_x,\n        layout_y=layout_y,\n    )\n\n    ufmodel.run()\n\n    expected_farm_power = ufmodel.get_expected_farm_power()\n\n    # Assert the expected farm power has not inadvetently changed\n    np.testing.assert_allclose(expected_farm_power, 3507908.918358342, atol=1e-1)\n\n\ndef test_expected_farm_power_equals_sum_of_expected_turbine_powers():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n\n    wind_speeds = np.array([8.0, 8.0, 8.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    turbulence_intensities = np.array([0.06, 0.06, 0.06])\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n\n    ufmodel.set(\n        wind_speeds=wind_speeds,\n        wind_directions=wind_directions,\n        turbulence_intensities=turbulence_intensities,\n        layout_x=layout_x,\n        layout_y=layout_y,\n    )\n\n    ufmodel.run()\n\n    expected_farm_power = ufmodel.get_expected_farm_power()\n    expected_turbine_powers = ufmodel.get_expected_turbine_powers()\n\n    # Assert the expected farm power is the sum of the expected turbine powers\n    np.testing.assert_allclose(expected_farm_power, np.sum(expected_turbine_powers))\n\n\ndef test_expected_farm_value_regression():\n    # Ensure this calculation hasn't changed unintentionally\n\n    ufmodel = UncertainFlorisModel(\n        configuration=YAML_INPUT,\n        wd_sample_points=[0],\n    )  # Force equal to nominal\n\n    wind_speeds = np.array([8.0, 8.0, 9.0])\n    wind_directions = np.array([270.0, 270.0, 270.0])\n    values = np.array([30.0, 20.0, 10.0])\n    time_series = TimeSeries(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.06,\n        values=values,\n    )\n\n    layout_x = np.array([0, 0])\n    layout_y = np.array([0, 1000])\n    ufmodel.set(layout_x=layout_x, layout_y=layout_y, wind_data=time_series)\n    ufmodel.run()\n\n    expected_farm_value = ufmodel.get_expected_farm_value()\n    assert np.allclose(expected_farm_value, 75108001.05154414, atol=1e-1)\n\n\ndef test_get_and_set_param():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n\n    # Set the wake parameter\n    ufmodel.set_param([\"wake\", \"wake_velocity_parameters\", \"gauss\", \"alpha\"], 0.1)\n    alpha = ufmodel.get_param([\"wake\", \"wake_velocity_parameters\", \"gauss\", \"alpha\"])\n    assert alpha == 0.1\n\n    # Confirm also correct in expanded floris model\n    alpha_e = ufmodel.fmodel_expanded.get_param(\n        [\"wake\", \"wake_velocity_parameters\", \"gauss\", \"alpha\"]\n    )\n    assert alpha_e == 0.1\n\n\ndef test_get_operation_model():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n    assert ufmodel.get_operation_model() == \"cosine-loss\"\n\n\ndef test_set_operation_model():\n    # Define a reference wind height for cases when there are changes to\n    # turbine_type\n\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n    ufmodel.set_operation_model(\"simple-derating\")\n    assert ufmodel.get_operation_model() == \"simple-derating\"\n\n    reference_wind_height = ufmodel.reference_wind_height\n\n    # Check multiple turbine types works\n    ufmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    ufmodel.set_operation_model([\"simple-derating\", \"cosine-loss\"])\n    assert ufmodel.get_operation_model() == [\"simple-derating\", \"cosine-loss\"]\n\n    # Confirm this passed through to expanded model\n    assert ufmodel.fmodel_expanded.get_operation_model() == [\"simple-derating\", \"cosine-loss\"]\n\n    # Check that setting a single turbine type, and then altering the operation model works\n    ufmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    ufmodel.set(turbine_type=[\"nrel_5MW\"], reference_wind_height=reference_wind_height)\n    ufmodel.set_operation_model(\"simple-derating\")\n    assert ufmodel.get_operation_model() == \"simple-derating\"\n\n    # Check that setting over mutliple turbine types works\n    ufmodel.set(turbine_type=[\"nrel_5MW\", \"iea_15MW\"], reference_wind_height=reference_wind_height)\n    ufmodel.set_operation_model(\"simple-derating\")\n    assert ufmodel.get_operation_model() == \"simple-derating\"\n    ufmodel.set_operation_model([\"simple-derating\", \"cosine-loss\"])\n    assert ufmodel.get_operation_model() == [\"simple-derating\", \"cosine-loss\"]\n\n    # Check setting over single turbine type; then updating layout works\n    ufmodel.set(turbine_type=[\"nrel_5MW\"], reference_wind_height=reference_wind_height)\n    ufmodel.set_operation_model(\"simple-derating\")\n    ufmodel.set(layout_x=[0, 0, 0], layout_y=[0, 1000, 2000])\n    assert ufmodel.get_operation_model() == \"simple-derating\"\n\n    # Check that setting for multiple turbine types and then updating layout breaks\n    ufmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    ufmodel.set(turbine_type=[\"nrel_5MW\"], reference_wind_height=reference_wind_height)\n    ufmodel.set_operation_model([\"simple-derating\", \"cosine-loss\"])\n    assert ufmodel.get_operation_model() == [\"simple-derating\", \"cosine-loss\"]\n    with pytest.raises(ValueError):\n        ufmodel.set(layout_x=[0, 0, 0], layout_y=[0, 1000, 2000])\n\n    # Check one more variation\n    ufmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    ufmodel.set(turbine_type=[\"nrel_5MW\", \"iea_15MW\"], reference_wind_height=reference_wind_height)\n    ufmodel.set_operation_model(\"simple-derating\")\n    ufmodel.set(layout_x=[0, 0], layout_y=[0, 1000])\n    with pytest.raises(ValueError):\n        ufmodel.set(layout_x=[0, 0, 0], layout_y=[0, 1000, 2000])\n\n\ndef test_parallel_uncertain_model():\n    ufmodel = UncertainFlorisModel(FlorisModel(configuration=YAML_INPUT))\n    pufmodel = UncertainFlorisModel(ParFlorisModel(configuration=YAML_INPUT))\n    assert isinstance(ufmodel.fmodel_expanded, FlorisModel)\n    assert isinstance(pufmodel.fmodel_expanded, ParFlorisModel)\n\n    # Run the models and compare outputs\n    ufmodel.run()\n    pufmodel.run()\n    powers_unc = ufmodel.get_turbine_powers()\n    powers_punc = pufmodel.get_turbine_powers()\n\n    assert np.allclose(powers_unc, powers_punc)\n\n\ndef test_copy():\n    \"\"\"\n    Check that the UncertainFlorisModel copy method works as expected for\n    both FlorisModel and ParFlorisModel.\n    \"\"\"\n    ufmodel = UncertainFlorisModel(FlorisModel(configuration=YAML_INPUT))\n\n    ufmodel_copy = ufmodel.copy()\n    assert isinstance(ufmodel_copy, UncertainFlorisModel)\n    assert isinstance(ufmodel_copy.fmodel_expanded, FlorisModel)\n\n    pufmodel = UncertainFlorisModel(ParFlorisModel(configuration=YAML_INPUT))\n    pufmodel_copy = pufmodel.copy()\n    assert isinstance(pufmodel_copy, UncertainFlorisModel)\n    assert isinstance(pufmodel_copy.fmodel_expanded, ParFlorisModel)\n\n\ndef test_invalid_wd_std():\n    \"\"\"\n    Test that the UncertainFlorisModel raises asn error with a wd_std of 0 or negative.\n    \"\"\"\n    with pytest.raises(ValueError):\n        UncertainFlorisModel(configuration=YAML_INPUT, wd_std=0.0)\n\n    with pytest.raises(ValueError):\n        UncertainFlorisModel(configuration=YAML_INPUT, wd_std=-1.0)\n\n\ndef test_turbine_average_velocities_shape_and_type():\n    \"\"\"\n    Test that turbine_average_velocities returns the correct shape and type.\n    \"\"\"\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n\n    # Set up a simple 2-turbine wind farm\n    ufmodel.set(\n        layout_x=[0, 500],\n        layout_y=[0, 0],\n        wind_speeds=[8.0, 10.0],\n        wind_directions=[270.0, 280.0],\n        turbulence_intensities=[0.06, 0.06],\n    )\n\n    ufmodel.run()\n\n    # Get turbine average velocities\n    velocities = ufmodel.turbine_average_velocities\n\n    # Check type\n    assert isinstance(velocities, np.ndarray)\n\n    # Check shape: should be (n_findex, n_turbines)\n    expected_shape = (ufmodel.n_findex, ufmodel.n_turbines)\n    assert velocities.shape == expected_shape\n\n    # Check that values are positive and reasonable\n    assert np.all(velocities > 0)\n    assert np.all(velocities < 20)  # Reasonable upper bound for wind speeds\n\n\ndef test_turbine_average_velocities_free_stream():\n    \"\"\"\n    Test that turbine_average_velocities returns the correct shape and type.\n    \"\"\"\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n\n    # Set up a simple 2-turbine wind farm with no wake interactions\n    ufmodel.set(\n        layout_x=[0, 0],\n        layout_y=[0, 1000],\n        wind_speeds=[8.0, 10.0],\n        wind_directions=[270.0, 280.0],\n        turbulence_intensities=[0.06, 0.06],\n        wind_shear=0.0,  # Turn off shear to simplify the test\n    )\n\n    ufmodel.run()\n\n    # Get turbine average velocities\n    velocities = ufmodel.turbine_average_velocities\n\n    # Velocities should be the same as the wind speeds but n_turbines columns repeated\n    assert np.allclose(velocities, np.array([[8.0, 8.0], [10.0, 10.0]]))\n\n\ndef test_turbine_average_velocities_uncertain_vs_certain():\n    \"\"\"\n    Test that turbine_average_velocities returns the same values for uncertain and certain models.\n    \"\"\"\n\n    # Set up (certain) FlorisModel\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    fmodel.set(\n        layout_x=[0, 500],\n        layout_y=[0, 0],\n        wind_speeds=[8.0, 10.0],\n        wind_directions=[270.0, 270.0],\n        turbulence_intensities=[0.06, 0.06],\n    )\n    fmodel.run()\n    velocities_certain = fmodel.turbine_average_velocities\n\n    # Create equivalent uncertain model\n    ufmodel = UncertainFlorisModel(configuration=fmodel)\n    ufmodel.run()\n    velocities_uncertain = ufmodel.turbine_average_velocities\n\n    # Check that the upstream turbine matches\n    assert np.allclose(velocities_uncertain[:, 0], velocities_certain[:, 0])\n    # Downstream turbine higher than certain when aligned\n    assert np.all(velocities_uncertain[:, 1] > velocities_certain[:, 1])\n\n    # Create a near 0-std uncertain model\n    ufmodel_zero_std = UncertainFlorisModel(configuration=fmodel, wd_std=1e-5)\n    ufmodel_zero_std.run()\n    velocities_uncertain_zero_std = ufmodel_zero_std.turbine_average_velocities\n\n    # Check that the uncertain model with 0 std matches the certain model\n    assert np.allclose(velocities_uncertain_zero_std, velocities_certain)\n\n\ndef test_multidim_conditions_flag(sample_inputs_fixture):\n    # make sure multidim conditions is correctly flagged\n    # Set wind speed and wind direction for n_findex = 2\n    wind_speeds = np.array([8.0, 8.0])\n    wind_directions = np.array([270.0, 270.0])\n\n    time_series = TimeSeries(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.06,\n    )\n\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT, wd_sample_points=[0])\n\n    ufmodel.set(wind_data=time_series)\n    assert ufmodel.fmodel_unexpanded.core.flow_field.multidim_conditions is None\n\n    # Define the multidim conditions\n    multidim_conditions = {\n        \"Tp\": np.array([5.0, 6.0]),\n        \"Hs\": np.array([3.0, 4.0]),\n    }\n\n    time_series = TimeSeries(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.06,\n        multidim_conditions=multidim_conditions,\n    )\n\n    ufmodel.set(wind_data=time_series, turbine_type=[sample_inputs_fixture.turbine_multi_dim])\n    assert ufmodel.fmodel_unexpanded.core.flow_field.multidim_conditions is not None\n\n\ndef test_multidim_conditions(sample_inputs_fixture):\n    \"\"\"\n    Test that the UncertainFlorisModel works with multidim_conditions set in the TimeSeries object.\n    \"\"\"\n    # Set wind speed and wind direction for n_findex = 2\n    wind_speeds = np.array([8.0, 8.0])\n    wind_directions = np.array([270.0, 270.0])\n\n    # Define the multidim conditions\n    multidim_conditions = {\n        \"Tp\": np.array([5.0, 6.0]),\n        \"Hs\": np.array([3.0, 4.0]),\n    }\n\n    time_series = TimeSeries(\n        wind_directions=wind_directions,\n        wind_speeds=wind_speeds,\n        turbulence_intensities=0.06,\n        multidim_conditions=multidim_conditions,\n    )\n\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT, wd_sample_points=[0])\n\n    # Set the ufmodel to two turbine case\n    ufmodel.set(layout_x=[0, 5000], layout_y=[0, 0])\n\n    # Set the ufmodel to use the multidim turbine\n    ufmodel.set(wind_data=time_series, turbine_type=[sample_inputs_fixture.turbine_multi_dim])\n    ufmodel.run()\n    powers_unc = ufmodel.get_turbine_powers()\n\n    # Rerun with multidim_conditions set to scalar values Tp = 5.0 and Hs = 3.0\n    ufmodel.set(multidim_conditions={\"Tp\": 5.0, \"Hs\": 3.0})\n    ufmodel.run()\n    powers_unc_scalar = ufmodel.get_turbine_powers()\n\n    # Check that the powers are the same for the first findex and different for the second findex\n    assert np.allclose(powers_unc[0, :], powers_unc_scalar[0, :])\n    assert not np.allclose(powers_unc[1, :], powers_unc_scalar[1, :])\n"
  },
  {
    "path": "tests/unified_momentum_operation_model_unit_test.py",
    "content": "import numpy as np\n\nfrom floris.core.turbine.unified_momentum_model import UnifiedMomentumModelTurbine\nfrom tests.conftest import SampleInputs\n\n\ndef test_submodel_attributes():\n\n    assert hasattr(UnifiedMomentumModelTurbine, \"power\")\n    assert hasattr(UnifiedMomentumModelTurbine, \"thrust_coefficient\")\n    assert hasattr(UnifiedMomentumModelTurbine, \"axial_induction\")\n\ndef test_UnifiedMomentumModelTurbine():\n\n    n_turbines = 1\n    wind_speed = 10.0\n    turbine_data = SampleInputs().turbine\n\n    yaw_angles_nom = 0 * np.ones((1, n_turbines))\n    tilt_angles_nom = turbine_data[\"power_thrust_table\"][\"ref_tilt\"] * np.ones((1, n_turbines))\n    yaw_angles_test = 20 * np.ones((1, n_turbines))\n    tilt_angles_test = 0 * np.ones((1, n_turbines))\n\n\n    # Check that power works as expected\n    test_power = UnifiedMomentumModelTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"], # Matches ref_air_density\n        yaw_angles=yaw_angles_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    truth_index = turbine_data[\"power_thrust_table\"][\"wind_speed\"].index(wind_speed)\n    baseline_power = turbine_data[\"power_thrust_table\"][\"power\"][truth_index] * 1000\n    assert np.allclose(baseline_power, test_power)\n\n    # Check that yaw and tilt angle have an effect\n    test_power = UnifiedMomentumModelTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=turbine_data[\"power_thrust_table\"][\"ref_air_density\"], # Matches ref_air_density\n        yaw_angles=yaw_angles_test,\n        tilt_angles=tilt_angles_test,\n        tilt_interp=None\n    )\n    assert test_power < baseline_power\n\n    # Check that a lower air density decreases power appropriately\n    test_power = UnifiedMomentumModelTurbine.power(\n        power_thrust_table=turbine_data[\"power_thrust_table\"],\n        velocities=wind_speed * np.ones((1, n_turbines, 3, 3)), # 1 findex, 1 turbine, 3x3 grid\n        air_density=1.1,\n        yaw_angles=yaw_angles_nom,\n        tilt_angles=tilt_angles_nom,\n        tilt_interp=None\n    )\n    assert test_power < baseline_power\n"
  },
  {
    "path": "tests/utilities_unit_test.py",
    "content": "\nfrom pathlib import Path\n\nimport attr\nimport numpy as np\nimport pytest\n\nfrom floris.utilities import (\n    check_and_identify_step_size,\n    cosd,\n    is_all_scalar_dict,\n    make_wind_directions_adjacent,\n    nested_get,\n    nested_set,\n    reverse_rotate_coordinates_rel_west,\n    rotate_coordinates_rel_west,\n    sind,\n    tand,\n    wind_delta,\n    wrap_180,\n    wrap_360,\n)\nfrom tests.conftest import (\n    X_COORDS,\n    Y_COORDS,\n    Z_COORDS,\n)\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\nYAML_INPUT = TEST_DATA / \"input_full.yaml\"\n\n\ndef test_cosd():\n    assert pytest.approx(cosd(0.0)) == 1.0\n    assert pytest.approx(cosd(90.0)) == 0.0\n    assert pytest.approx(cosd(180.0)) == -1.0\n    assert pytest.approx(cosd(270.0)) == 0.0\n\n\ndef test_sind():\n    assert pytest.approx(sind(0.0)) == 0.0\n    assert pytest.approx(sind(90.0)) == 1.0\n    assert pytest.approx(sind(180.0)) == 0.0\n    assert pytest.approx(sind(270.0)) == -1.0\n\n\ndef test_tand():\n    assert pytest.approx(tand(0.0)) == 0.0\n    assert pytest.approx(tand(45.0)) == 1.0\n    assert pytest.approx(tand(135.0)) == -1.0\n    assert pytest.approx(tand(180.0)) == 0.0\n    assert pytest.approx(tand(225.0)) == 1.0\n    assert pytest.approx(tand(315.0)) == -1.0\n\n\ndef test_wrap_180():\n    assert wrap_180(-180.0) == -180.0\n    assert wrap_180(180.0) == -180.0\n    assert wrap_180(-181.0) == 179.0\n    assert wrap_180(-179.0) == -179.0\n    assert wrap_180(179.0) == 179.0\n    assert wrap_180(181.0) == -179.0\n\n\ndef test_wrap_360():\n    assert wrap_360(0.0) == 0.0\n    assert wrap_360(360.0) == 0.0\n    assert wrap_360(-1.0) == 359.0\n    assert wrap_360(1.0) == 1.0\n    assert wrap_360(359.0) == 359.0\n    assert wrap_360(361.0) == 1.0\n\n\ndef test_wind_delta():\n    assert wind_delta(270.0) == 0.0\n    assert wind_delta(280.0) == 10.0\n    assert wind_delta(360.0) == 90.0\n    assert wind_delta(180.0) == 270.0\n    assert wind_delta(-10.0) == 80.0\n    assert wind_delta(-100.0) == 350.0\n\ndef test_make_wind_directions_adjacent():\n\n    test_conditions = [\n        [[0.0, 10.0], [0.0, 10.0]],\n        [[0.0, 350.], [-10., 0.]],\n        [[20.0, 25., 30.], [20.0, 25., 30.]],\n        [[0.0, 350., 355., ], [-10., -5, 0]],\n        [[0 ,2, 358], [-2, 0, 2]],\n        [[0, 1, 359], [-1, 0, 1]],\n        [np.arange(0,360,1), np.arange(0,360,1)],\n        [sorted(np.arange(330,390,1)%360),np.arange(-30,30,1) ],\n    ]\n\n    for test_cond in test_conditions:\n        wind_directions = np.array(test_cond[0])\n        expected_wind_directions = np.array(test_cond[1])\n\n        wind_directions_adjacent, sort_indices = make_wind_directions_adjacent(wind_directions)\n        np.testing.assert_array_equal(wind_directions_adjacent, expected_wind_directions)\n        np.testing.assert_array_equal(wind_directions[sort_indices]%360.0,\n                                      wind_directions_adjacent%360.0)\n\ndef test_check_and_identify_step_size():\n    # First set up a matrix of input directions, upsampling steps and expected ouputs\n    test_conditions = [\n        [[270.0, 280.0], 10.0],\n        [[0.0, 4.0], 4.0],\n        [[0.0, 358.0], 2.0],\n        [[0, 358], 2],\n        [[10, 20, 30], 10],\n        [[0, 10, 350], 10],\n        [[0,1,359],1.0],\n        [[0,356,358],2.0],\n        [[4, 8, 12, 16], 4],\n        [[0, 90, 180, 270], 90],\n        [[0, 5, 10,355], 5],\n        [np.arange(0,360,1), 1],\n        [sorted(np.arange(330,390,1)%360), 1],\n    ]\n\n    for test_cond in test_conditions:\n        wind_directions = np.array(test_cond[0])\n        expected_step = test_cond[1]\n\n        step_size = check_and_identify_step_size(wind_directions)\n        assert step_size == expected_step\n\n\ndef test_check_and_identify_step_size_value_error():\n    # First set up a matrix of input directions, upsampling steps and expected ouputs\n    test_conditions = [\n        [1,3,7], # Inconsistent step size\n        [4, 3, 2], # Decreasing\n        [5, 10, 15, 45], #Inconsistent step not connected to a wrapping\n    ]\n\n    for wind_directions in test_conditions:\n        with pytest.raises(ValueError):\n            check_and_identify_step_size(wind_directions)\n\n\ndef test_rotate_coordinates_rel_west():\n    coordinates = np.array(list(zip(X_COORDS, Y_COORDS, Z_COORDS)))\n\n    # For 270, the coordinates should not change.\n    wind_directions = np.array([270.0])\n    x_rotated, y_rotated, z_rotated, _, _ = rotate_coordinates_rel_west(\n        wind_directions,\n        coordinates\n    )\n\n    # Test that x_rotated has 2 dimensions\n    np.testing.assert_equal(np.ndim(x_rotated), 2)\n\n    # Assert the rotating to 270 doesn't change coordinates\n    np.testing.assert_array_equal(X_COORDS, x_rotated[0])\n    np.testing.assert_array_equal(Y_COORDS, y_rotated[0])\n    np.testing.assert_array_equal(Z_COORDS, z_rotated[0])\n\n    # For 360, the coordinates should be rotated 90 degrees counter clockwise\n    # from looking fown at the wind farm from above. The series of turbines\n    # in a line (same y, increasing x) should change to a series of turbines\n    # in parallel (same x, increasing y).\n    # Since the rotation in `rotate_coordinates_rel_west` happens about the\n    # center of all the points, adjust the coordinates so that the results are\n    # adjusted to the baseline values.\n    # NOTE: These adjustments are not general and will fail if the coordinates in\n    # conftest change.\n    wind_directions = np.array([360.0])\n    x_rotated, y_rotated, z_rotated, _, _ = rotate_coordinates_rel_west(\n        wind_directions,\n        coordinates\n    )\n    np.testing.assert_almost_equal(Y_COORDS, x_rotated[0] - np.min(x_rotated[0]))\n    np.testing.assert_almost_equal(X_COORDS, y_rotated[0] - np.min(y_rotated[0]))\n    np.testing.assert_almost_equal(\n        Z_COORDS + np.min(Z_COORDS),\n        z_rotated[0] + np.min(z_rotated[0])\n    )\n\n    wind_directions = np.array([90.0])\n    x_rotated, y_rotated, z_rotated, _, _ = rotate_coordinates_rel_west(\n        wind_directions, coordinates\n    )\n    np.testing.assert_almost_equal(X_COORDS[-1:-4:-1], x_rotated[0])\n    np.testing.assert_almost_equal(Y_COORDS, y_rotated[0])\n    np.testing.assert_almost_equal(Z_COORDS, z_rotated[0])\n\n\ndef test_reverse_rotate_coordinates_rel_west():\n    # Test that appplying the rotation, and then the reverse produces the original coordinates\n\n    # Test the reverse rotation\n    coordinates = np.array([[x, y, z] for x, y, z in zip(X_COORDS, Y_COORDS, Z_COORDS)])\n\n    # Rotate to 360 (as in above function)\n    wind_directions = np.array([360.0])\n\n    # Get the rotated coordinates\n    (\n        x_rotated,\n        y_rotated,\n        z_rotated,\n        x_center_of_rotation,\n        y_center_of_rotation,\n    ) = rotate_coordinates_rel_west(wind_directions, coordinates)\n\n    # Go up to 4 dimensions (reverse function is expecting grid)\n    grid_x = x_rotated[:, :,  None, None]\n    grid_y = y_rotated[:, :,  None, None]\n    grid_z = z_rotated[:, :,  None, None]\n\n    # Perform reverse rotation\n    grid_x_reversed, grid_y_reversed, grid_z_reversed = reverse_rotate_coordinates_rel_west(\n        wind_directions,\n        grid_x,\n        grid_y,\n        grid_z,\n        x_center_of_rotation,\n        y_center_of_rotation,\n    )\n\n    np.testing.assert_almost_equal(grid_x_reversed.squeeze(), coordinates[:,0].squeeze())\n    np.testing.assert_almost_equal(grid_y_reversed.squeeze(), coordinates[:,1].squeeze())\n    np.testing.assert_almost_equal(grid_z_reversed.squeeze(), coordinates[:,2].squeeze())\n\n\ndef test_nested_get():\n    example_dict = {\n        'a': {\n            'b': {\n                'c': 10\n            }\n        }\n    }\n\n    assert nested_get(example_dict, ['a', 'b', 'c']) == 10\n\n\ndef test_nested_set():\n    example_dict = {\n        'a': {\n            'b': {\n                'c': 10\n            }\n        }\n    }\n\n    nested_set(example_dict, ['a', 'b', 'c'], 20)\n    assert nested_get(example_dict, ['a', 'b', 'c']) == 20\n\n\ndef test_is_all_scalar_dict():\n    example_dict_1 = {\n        \"a\": 10,\n        \"b\": 20.5,\n    }\n    assert is_all_scalar_dict(example_dict_1)\n\n    example_dict_2 = {\n        \"a\": 10,\n        \"b\": np.array([1, 2, 3]),\n    }\n    assert not is_all_scalar_dict(example_dict_2)\n\n    example_dict_3 = {\n        \"a\": \"hello\",\n        \"b\": 5,\n    }\n    assert is_all_scalar_dict(example_dict_3)\n\n    example_dict_4 = {\n        \"a\": 1,\n        \"b\": {\"c\": 2},\n    }\n    assert not is_all_scalar_dict(example_dict_4)\n"
  },
  {
    "path": "tests/v3_to_v4_convert_test/gch.yaml",
    "content": "\n###\n# A name for this input file.\n# This is not currently only for the user's reference.\nname: GCH\n\n###\n# A description of the contents of this input file.\n# This is not currently only for the user's reference.\ndescription: Three turbines using Gauss Curl Hybrid model\n\n###\n# The earliest verion of FLORIS this input file supports.\n# This is not currently only for the user's reference.\nfloris_version: v3.0.0\n\n###\n# Configure the logging level and where to show the logs.\nlogging:\n\n  ###\n  # Settings for logging to the console (i.e. terminal).\n  console:\n\n    ###\n    # Can be \"true\" or \"false\".\n    enable: true\n\n    ###\n    # Set the severity to show output. Messages at this level or higher will be shown.\n    # Can be one of \"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\".\n    level: WARNING\n\n  ###\n  # Settings for logging to a file.\n  file:\n\n    ###\n    # Can be \"true\" or \"false\".\n    enable: false\n\n    ###\n    # Set the severity to show output. Messages at this level or higher will be shown.\n    # Can be one of \"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\".\n    level: WARNING\n\n###\n# Configure the solver for the type of simulation.\nsolver:\n\n  ###\n  # Select the solver type.\n  # Can be one of: \"turbine_grid\", \"flow_field_grid\", \"flow_field_planar_grid\".\n  type: turbine_grid\n\n  ###\n  # Options for the turbine type selected above. See the solver documentation for available parameters.\n  turbine_grid_points: 3\n\n###\n# Configure the turbine types and their placement within the wind farm.\nfarm:\n\n  ###\n  # Coordinates for the turbine locations in the x-direction which is typically considered\n  # to be the streamwise direction (left, right) when the wind is out of the west.\n  # The order of the coordinates here corresponds to the index of the turbine in the primary\n  # data structures.\n  layout_x:\n  - 0.0\n\n\n  ###\n  # Coordinates for the turbine locations in the y-direction which is typically considered\n  # to be the spanwise direction (up, down) when the wind is out of the west.\n  # The order of the coordinates here corresponds to the index of the turbine in the primary\n  # data structures.\n  layout_y:\n  - 0.0\n\n\n  ###\n  # Listing of turbine types for placement at the x and y coordinates given above.\n  # The list length must be 1 or the same as ``layout_x`` and ``layout_y``. If it is a\n  # single value, all turbines are of the same type. Otherwise, the turbine type\n  # is mapped to the location at the same index in ``layout_x`` and ``layout_y``.\n  # The types can be either a name included in the turbine_library or\n  # a full definition of a wind turbine directly.\n  turbine_type:\n  - !include nrel_5MW_v3.yaml\n\n###\n# Configure the atmospheric conditions.\nflow_field:\n\n  ###\n  # Air density.\n  air_density: 1.225\n\n  ###\n  # The height to consider the \"center\" of the vertical wind speed profile\n  # due to shear. With a shear exponent not 1, the wind speed at this height\n  # will be the value given in ``wind_speeds``. Above and below this height,\n  # the wind speed will change according to the shear profile; see\n  # :py:meth:`.FlowField.initialize_velocity_field`.\n  # For farms consisting of one wind turbine type, use ``reference_wind_height: -1``\n  # to use the hub height of the wind turbine definition. For multiple wind turbine\n  # types, the reference wind height must be given explicitly.\n  reference_wind_height: -1\n\n  ###\n  # The level of turbulence intensity level in the wind.\n  turbulence_intensity: 0.06\n\n  ###\n  # The wind directions to include in the simulation.\n  # 0 is north and 270 is west.\n  wind_directions:\n  - 270.0\n\n  ###\n  # The exponent used to model the wind shear profile; see\n  # :py:meth:`.FlowField.initialize_velocity_field`.\n  wind_shear: 0.12\n\n  ###\n  # The wind speeds to include in the simulation.\n  wind_speeds:\n  - 8.0\n\n  ###\n  # The wind veer as a constant value for all points in the grid.\n  wind_veer: 0.0\n\n  ###\n  # The conditions that are specified for use with the multi-dimensional Cp/Ct capbility.\n  # These conditions are external to FLORIS and specified by the user. They are used internally\n  # through a nearest-neighbor selection process to choose the correct Cp/Ct interpolants\n  # to use. These conditions are only used with the ``multidim_cp_ct`` velocity deficit model.\n  multidim_conditions:\n    Tp: 2.5\n    Hs: 3.01\n\n###\n# Configure the wake model.\nwake:\n\n  ###\n  # Select the models to use for the simulation.\n  # See :py:mod:`~.wake` for a list\n  # of available models and their descriptions.\n  model_strings:\n\n    ###\n    # Select the wake combination model.\n    combination_model: sosfs\n\n    ###\n    # Select the wake deflection model.\n    deflection_model: gauss\n\n    ###\n    # Select the wake turbulence model.\n    turbulence_model: crespo_hernandez\n\n    ###\n    # Select the wake velocity deficit model.\n    velocity_model: gauss\n\n  ###\n  # Can be \"true\" or \"false\".\n  enable_secondary_steering: true\n\n  ###\n  # Can be \"true\" or \"false\".\n  enable_yaw_added_recovery: true\n\n  ###\n  # Can be \"true\" or \"false\".\n  enable_transverse_velocities: true\n\n  ###\n  # Configure the parameters for the wake deflection model\n  # selected above.\n  # Additional blocks can be provided for\n  # models that are not enabled, but the enabled model\n  # must have a corresponding parameter block.\n  wake_deflection_parameters:\n    gauss:\n      ad: 0.0\n      alpha: 0.58\n      bd: 0.0\n      beta: 0.077\n      dm: 1.0\n      ka: 0.38\n      kb: 0.004\n    jimenez:\n      ad: 0.0\n      bd: 0.0\n      kd: 0.05\n\n  ###\n  # Configure the parameters for the wake velocity deficit model\n  # selected above.\n  # Additional blocks can be provided for\n  # models that are not enabled, but the enabled model\n  # must have a corresponding parameter block.\n  wake_velocity_parameters:\n    cc:\n      a_s: 0.179367259\n      b_s: 0.0118889215\n      c_s1: 0.0563691592\n      c_s2: 0.13290157\n      a_f: 3.11\n      b_f: -0.68\n      c_f: 2.41\n      alpha_mod: 1.0\n    gauss:\n      alpha: 0.58\n      beta: 0.077\n      ka: 0.38\n      kb: 0.004\n    jensen:\n      we: 0.05\n\n  ###\n  # Configure the parameters for the wake turbulence model\n  # selected above.\n  # Additional blocks can be provided for\n  # models that are not enabled, but the enabled model\n  # must have a corresponding parameter block.\n  wake_turbulence_parameters:\n    crespo_hernandez:\n      initial: 0.1\n      constant: 0.5\n      ai: 0.8\n      downstream: -0.32\n"
  },
  {
    "path": "tests/v3_to_v4_convert_test/nrel_5MW_v3.yaml",
    "content": "\n###\n# An ID for this type of turbine definition.\n# This is not currently used, but it will be enabled in the future. This should typically\n# match the root name of the file.\nturbine_type: 'nrel_5MW'\n\n###\n# Setting for generator losses to power.\ngenerator_efficiency: 1.0\n\n###\n# Hub height.\nhub_height: 90.0\n\n###\n# Cosine exponent for power loss due to yaw misalignment.\npP: 1.88\n\n###\n# Cosine exponent for power loss due to tilt.\npT: 1.88\n\n###\n# Rotor diameter.\nrotor_diameter: 126.0\n\n###\n# Tip speed ratio defined as linear blade tip speed normalized by the incoming wind speed.\nTSR: 8.0\n\n###\n# The air density at which the Cp and Ct curves are defined.\nref_density_cp_ct: 1.225\n\n###\n# The tilt angle at which the Cp and Ct curves are defined. This is used to capture\n# the effects of a floating platform on a turbine's power and wake.\nref_tilt_cp_ct: 5.0\n\n###\n# Cp and Ct as a function of wind speed for the turbine's full range of operating conditions.\npower_thrust_table:\n  power:\n    - 0.0\n    - 0.000000\n    - 0.000000\n    - 0.178085\n    - 0.289075\n    - 0.349022\n    - 0.384728\n    - 0.406059\n    - 0.420228\n    - 0.428823\n    - 0.433873\n    - 0.436223\n    - 0.436845\n    - 0.436575\n    - 0.436511\n    - 0.436561\n    - 0.436517\n    - 0.435903\n    - 0.434673\n    - 0.433230\n    - 0.430466\n    - 0.378869\n    - 0.335199\n    - 0.297991\n    - 0.266092\n    - 0.238588\n    - 0.214748\n    - 0.193981\n    - 0.175808\n    - 0.159835\n    - 0.145741\n    - 0.133256\n    - 0.122157\n    - 0.112257\n    - 0.103399\n    - 0.095449\n    - 0.088294\n    - 0.081836\n    - 0.075993\n    - 0.070692\n    - 0.065875\n    - 0.061484\n    - 0.057476\n    - 0.053809\n    - 0.050447\n    - 0.047358\n    - 0.044518\n    - 0.041900\n    - 0.039483\n    - 0.0\n    - 0.0\n  thrust:\n    - 0.0\n    - 0.0\n    - 0.0\n    - 0.99\n    - 0.99\n    - 0.97373036\n    - 0.92826162\n    - 0.89210543\n    - 0.86100905\n    - 0.835423\n    - 0.81237673\n    - 0.79225789\n    - 0.77584769\n    - 0.7629228\n    - 0.76156073\n    - 0.76261984\n    - 0.76169723\n    - 0.75232027\n    - 0.74026851\n    - 0.72987175\n    - 0.70701647\n    - 0.54054532\n    - 0.45509459\n    - 0.39343381\n    - 0.34250785\n    - 0.30487242\n    - 0.27164979\n    - 0.24361964\n    - 0.21973831\n    - 0.19918151\n    - 0.18131868\n    - 0.16537679\n    - 0.15103727\n    - 0.13998636\n    - 0.1289037\n    - 0.11970413\n    - 0.11087113\n    - 0.10339901\n    - 0.09617888\n    - 0.09009926\n    - 0.08395078\n    - 0.0791188\n    - 0.07448356\n    - 0.07050731\n    - 0.06684119\n    - 0.06345518\n    - 0.06032267\n    - 0.05741999\n    - 0.05472609\n    - 0.0\n    - 0.0\n  wind_speed:\n    - 0.0\n    - 2.0\n    - 2.5\n    - 3.0\n    - 3.5\n    - 4.0\n    - 4.5\n    - 5.0\n    - 5.5\n    - 6.0\n    - 6.5\n    - 7.0\n    - 7.5\n    - 8.0\n    - 8.5\n    - 9.0\n    - 9.5\n    - 10.0\n    - 10.5\n    - 11.0\n    - 11.5\n    - 12.0\n    - 12.5\n    - 13.0\n    - 13.5\n    - 14.0\n    - 14.5\n    - 15.0\n    - 15.5\n    - 16.0\n    - 16.5\n    - 17.0\n    - 17.5\n    - 18.0\n    - 18.5\n    - 19.0\n    - 19.5\n    - 20.0\n    - 20.5\n    - 21.0\n    - 21.5\n    - 22.0\n    - 22.5\n    - 23.0\n    - 23.5\n    - 24.0\n    - 24.5\n    - 25.0\n    - 25.01\n    - 25.02\n    - 50.0\n\n###\n# A boolean flag used when the user wants FLORIS to use the user-supplied multi-dimensional\n# Cp/Ct information.\nmulti_dimensional_cp_ct: False\n\n###\n# The path to the .csv file that contains the multi-dimensional Cp/Ct data. The format of this\n# file is such that any external conditions, such as wave height or wave period, that the\n# Cp/Ct data is dependent on come first, in column format. The last three columns of the .csv\n# file must be ``ws``, ``Cp``, and ``Ct``, in that order. An example of fictional data is given\n# in ``floris/turbine_library/iea_15MW_multi_dim_Tp_Hs.csv``.\npower_thrust_data_file: '../floris/turbine_library/iea_15MW_multi_dim_Tp_Hs.csv'\n"
  },
  {
    "path": "tests/wake_unit_tests.py",
    "content": "\nfrom floris.core import WakeModelManager\nfrom tests.conftest import SampleInputs\n\n\ndef test_asdict(sample_inputs_fixture: SampleInputs):\n\n    wake_model_manager = WakeModelManager.from_dict(sample_inputs_fixture.wake)\n    dict1 = wake_model_manager.as_dict()\n\n    new_wake = WakeModelManager.from_dict(dict1)\n    dict2 = new_wake.as_dict()\n\n    assert dict1 == dict2\n"
  },
  {
    "path": "tests/wind_data_integration_test.py",
    "content": "import copy\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom floris import (\n    TimeSeries,\n    WindRose,\n    WindTIRose,\n)\nfrom floris.wind_data import WindDataBase\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\n\n\nclass ChildClassTest(WindDataBase):\n    def __init__(self):\n        pass\n\n\ndef test_bad_inheritance():\n    \"\"\"\n    Verifies that a child class of WindDataBase must implement the unpack method.\n    \"\"\"\n    test_class = ChildClassTest()\n    with pytest.raises(NotImplementedError):\n        test_class.unpack()\n\n\ndef test_time_series_instantiation():\n    wind_directions = np.array([270, 280, 290])\n    wind_speeds = np.array([5, 5, 5])\n\n    # Test that TI require\n    with pytest.raises(TypeError):\n        TimeSeries(wind_directions, wind_speeds)\n\n    # Test that passing a float TI returns a list of length matched to wind directions\n    time_series = TimeSeries(wind_directions, wind_speeds, turbulence_intensities=0.06)\n    np.testing.assert_allclose(time_series.turbulence_intensities, [0.06, 0.06, 0.06])\n\n    # Test that passing floats to wind directions and wind speeds returns a list of\n    # length turbulence intensities\n    time_series = TimeSeries(270.0, 8.0, turbulence_intensities=np.array([0.06, 0.07, 0.08]))\n    np.testing.assert_allclose(time_series.wind_directions, [270, 270, 270])\n    np.testing.assert_allclose(time_series.wind_speeds, [8, 8, 8])\n\n    # Test that passing in all floats raises a type error\n    with pytest.raises(TypeError):\n        TimeSeries(270.0, 8.0, 0.06)\n\n    # Test casting of both wind speeds and TI\n    time_series = TimeSeries(wind_directions, 8.0, 0.06)\n    np.testing.assert_allclose(time_series.wind_speeds, [8, 8, 8])\n    np.testing.assert_allclose(time_series.turbulence_intensities, [0.06, 0.06, 0.06])\n\n    # Test the passing in a 1D array of turbulence intensities which is longer than the\n    # wind directions and wind speeds raises an error\n    with pytest.raises(ValueError):\n        TimeSeries(\n            wind_directions, wind_speeds, turbulence_intensities=np.array([0.06, 0.07, 0.08, 0.09])\n        )\n\n\ndef test_wind_rose_init():\n    \"\"\"\n    The wind directions and wind speeds can have any length, but the frequency\n    array must have shape (n wind directions, n wind speeds)\n    \"\"\"\n\n    # Test that passing in unevenly spaced wind directions or wind speeds raises an error\n    with pytest.raises(ValueError):\n        WindRose(np.array([270, 280, 290, 310]), np.array([6, 7]), 0.06)\n\n    with pytest.raises(ValueError):\n        WindRose(np.array([270, 280, 290]), np.array([6, 7, 10]), 0.06)\n\n    # Test that passing in decreasing wind directions raises an error\n    with pytest.raises(ValueError):\n        WindRose(np.array([290, 280, 270]), np.array([6, 7]), 0.06)\n\n    wind_directions = np.array([270, 280, 290])\n    wind_speeds = np.array([6, 7])\n\n    # Pass ti_table in as a single float and confirm it is broadcast to the correct shape\n    wind_rose = WindRose(wind_directions, wind_speeds, ti_table=0.06)\n    np.testing.assert_allclose(\n        wind_rose.ti_table, np.array([[0.06, 0.06], [0.06, 0.06], [0.06, 0.06]])\n    )\n\n    # Pass ti_table in as a 2D array and confirm it is used as is\n    ti_table = np.array([[0.06, 0.06], [0.06, 0.06], [0.06, 0.06]])\n    wind_rose = WindRose(wind_directions, wind_speeds, ti_table=ti_table)\n    np.testing.assert_allclose(wind_rose.ti_table, ti_table)\n\n    # Confirm passing in a ti_table that is 1D raises an error\n    with pytest.raises(ValueError):\n        WindRose(\n            wind_directions, wind_speeds, ti_table=np.array([0.06, 0.06, 0.06, 0.06, 0.06, 0.06])\n        )\n\n    # Confirm passing in a ti_table that is wrong dimensions raises an error\n    with pytest.raises(ValueError):\n        WindRose(wind_directions, wind_speeds, ti_table=np.ones((3, 3)))\n\n    # This should be ok since the frequency array shape matches the wind directions\n    # and wind speeds\n    _ = WindRose(wind_directions, wind_speeds, ti_table=0.06, freq_table=np.ones((3, 2)))\n\n    # This should raise an error since the frequency array shape does not\n    # match the wind directions and wind speeds\n    with pytest.raises(ValueError):\n        WindRose(wind_directions, wind_speeds, 0.06, np.ones((3, 3)))\n\n    # Test that instantiating with non-integer wind directions and wind speeds works\n    wind_directions = np.array([270.0, 280.0, 290.0])\n    wind_speeds = np.array([6.0, 7.0])\n    _ = WindRose(wind_directions, wind_speeds, ti_table=0.06)\n\n    wind_directions = np.array([270.5, 280.5, 290.5])\n    wind_speeds = np.array([6.5, 7.5])\n    _ = WindRose(wind_directions, wind_speeds, ti_table=0.06)\n\n    # Test that instantiating with non-integer steps works\n    _ = WindRose(\n        wind_directions=np.linspace(0.0, 360.0, 100, endpoint=False),\n        wind_speeds=np.array([5.0]),\n        ti_table=0.06,\n    )\n\ndef test_wind_rose_grid():\n    wind_directions = np.array([270, 280, 290])\n    wind_speeds = np.array([6, 7])\n\n    wind_rose = WindRose(wind_directions, wind_speeds, 0.06)\n\n    # Wind direction grid has the same dimensions as the frequency table\n    assert wind_rose.wd_grid.shape == wind_rose.freq_table.shape\n\n    # Flattening process occurs wd first\n    # This is each wind direction for each wind speed:\n    np.testing.assert_allclose(wind_rose.wd_flat, [270, 270, 280, 280, 290, 290])\n\n\ndef test_wind_rose_unpack():\n    wind_directions = np.array([270, 280, 290])\n    wind_speeds = np.array([6, 7])\n    freq_table = np.array([[1.0, 0.0], [0, 1.0], [0, 0]])\n\n    # First test using default assumption only non-zero frequency cases computed\n    wind_rose = WindRose(wind_directions, wind_speeds, 0.06, freq_table)\n\n    (\n        wind_directions_unpack,\n        wind_speeds_unpack,\n        ti_table_unpack,\n        freq_table_unpack,\n        value_table_unpack,\n        heterogeneous_inflow_config,\n    ) = wind_rose.unpack()\n\n    # Given the above frequency table with zeros for a few elements,\n    # we expect only the (270 deg, 6 m/s) and (280 deg, 7 m/s) rows\n    np.testing.assert_allclose(wind_directions_unpack, [270, 280])\n    np.testing.assert_allclose(wind_speeds_unpack, [6, 7])\n    np.testing.assert_allclose(ti_table_unpack, [0.06, 0.06])\n    np.testing.assert_allclose(freq_table_unpack, [0.5, 0.5])\n\n    # In this case n_findex is the length of the wind combinations that are\n    # non-zero frequency\n    assert wind_rose.n_findex == 2\n\n    # Now test computing 0-freq cases too\n    wind_rose = WindRose(\n        wind_directions, wind_speeds, freq_table, compute_zero_freq_occurrence=True\n    )\n\n    (\n        wind_directions_unpack,\n        wind_speeds_unpack,\n        ti_table_unpack,\n        freq_table_unpack,\n        value_table_unpack,\n        heterogeneous_inflow_config,\n    ) = wind_rose.unpack()\n\n    # Expect now to compute all combinations\n    np.testing.assert_allclose(wind_directions_unpack, [270, 270, 280, 280, 290, 290])\n\n    # In this case n_findex is the total number of wind combinations\n    assert wind_rose.n_findex == 6\n\n    # Adding tests of unpack_multidim_conditions here, since these will be included in unpack()\n    # in a future release\n    multidim_conditions_scalar = {\"TI\": 0.06, \"Hs\": 3.1}\n    wind_rose = WindRose(\n        wind_directions,\n        wind_speeds,\n        0.06,\n        freq_table,\n        multidim_conditions=multidim_conditions_scalar\n    )\n    multidim_conditions_unpacked = wind_rose.unpack_multidim_conditions()\n\n    for k, v in multidim_conditions_unpacked.items():\n        np.testing.assert_allclose(v, [multidim_conditions_scalar[k]] * wind_rose.n_findex)\n\n    # Array multi-dimensional conditions that are not the correct shape (n_wd x n_ws)\n    multidim_conditions_array_bad_shape = {\"a\": np.array([1, 2, 3, 4, 5, 6])}\n    with pytest.raises(ValueError):\n        WindRose(\n            wind_directions,\n            wind_speeds,\n            0.06,\n            freq_table,\n            multidim_conditions=multidim_conditions_array_bad_shape\n        )\n    # Correct shape multi-dimensional conditions, wrong number of values\n    multidim_conditions_array_wrong_size = {\"a\": np.array([[0.06, 0.07], [0.08, 0.09]])}\n    with pytest.raises(ValueError):\n        WindRose(\n            wind_directions,\n            wind_speeds,\n            0.06,\n            freq_table,\n            multidim_conditions=multidim_conditions_array_wrong_size\n        )\n    # Correct shape and size\n    multidim_conditions_array = {\"a\": np.array([[0.06, 0.07], [0.08, 0.09], [0.10, 0.11]])}\n    wind_rose = WindRose(\n        wind_directions,\n        wind_speeds,\n        0.06,\n        freq_table,\n        multidim_conditions=multidim_conditions_array\n    )\n    multidim_conditions_unpacked = wind_rose.unpack_multidim_conditions()\n\n    for k, v in multidim_conditions_unpacked.items():\n        assert k in multidim_conditions_array.keys()\n        assert v.shape == (2,) # 2 remaining conditions after frequency filtering\n\ndef test_unpack_for_reinitialize():\n    wind_directions = np.array([270, 280, 290])\n    wind_speeds = np.array([6, 7])\n    freq_table = np.array([[1.0, 0.0], [0, 1.0], [0, 0]])\n\n    # First test using default assumption only non-zero frequency cases computed\n    wind_rose = WindRose(wind_directions, wind_speeds, 0.06, freq_table)\n\n    (\n        wind_directions_unpack,\n        wind_speeds_unpack,\n        ti_table_unpack,\n        heterogeneous_inflow_config,\n    ) = wind_rose.unpack_for_reinitialize()\n\n    # Given the above frequency table, would only expect the\n    # (270 deg, 6 m/s) and (280 deg, 7 m/s) rows\n    np.testing.assert_allclose(wind_directions_unpack, [270, 280])\n    np.testing.assert_allclose(wind_speeds_unpack, [6, 7])\n    np.testing.assert_allclose(ti_table_unpack, [0.06, 0.06])\n\n\ndef test_wind_rose_downsample():\n    wind_directions = np.array([0, 2, 4, 6, 8, 10])\n    wind_speeds = np.array([8])\n    freq_table = np.array([[1.0], [1.0], [1.0], [1.0], [1.0], [1.0]])\n\n    wind_rose = WindRose(wind_directions, wind_speeds, ti_table=0.06, freq_table=freq_table)\n\n    # Test that aggregating without specifying new steps returns the same\n    wind_rose_aggregate = wind_rose.downsample(inplace=False)\n\n    np.testing.assert_allclose(wind_rose.wind_directions, wind_rose_aggregate.wind_directions)\n    np.testing.assert_allclose(wind_rose.wind_speeds, wind_rose_aggregate.wind_speeds)\n    np.testing.assert_allclose(wind_rose.freq_table_flat, wind_rose_aggregate.freq_table_flat)\n\n    # Now test aggregating the wind direction to 5 deg bins\n    wind_rose_aggregate = wind_rose.downsample(wd_step=5.0, inplace=False)\n    np.testing.assert_allclose(wind_rose_aggregate.wind_directions, [0, 5, 10])\n    np.testing.assert_allclose(wind_rose_aggregate.freq_table_flat, [2 / 6, 2 / 6, 2 / 6])\n\n    # Test that the default inplace behavior is to modifies the original object as expected\n    wind_rose_2 = copy.deepcopy(wind_rose)\n    wind_rose_2.downsample(inplace=True)\n    np.testing.assert_allclose(wind_rose.wind_directions, wind_rose_2.wind_directions)\n    np.testing.assert_allclose(wind_rose.wind_speeds, wind_rose_2.wind_speeds)\n    np.testing.assert_allclose(wind_rose.freq_table_flat, wind_rose_2.freq_table_flat)\n\n    wind_rose_2.downsample(wd_step=5.0, inplace=True)\n    np.testing.assert_allclose(wind_rose_aggregate.wind_directions, wind_rose_2.wind_directions)\n    np.testing.assert_allclose(wind_rose_aggregate.wind_speeds, wind_rose_2.wind_speeds)\n    np.testing.assert_allclose(wind_rose_aggregate.freq_table_flat, wind_rose_2.freq_table_flat)\n\n    # Test that aggregate function returns identical result to downsample function\n    wind_rose_aggregate = wind_rose.aggregate(wd_step=5.0, inplace=False)\n    wind_rose_downsample = wind_rose.downsample(wd_step=5.0, inplace=False)\n    np.testing.assert_allclose(\n        wind_rose_aggregate.freq_table_flat, wind_rose_downsample.freq_table_flat\n    )\n\n\ndef test_wind_rose_upsample_directions():\n    # Test wind direction upsampling under a range of conditions\n\n    # First set up a matrix of input directions, upsampling steps and expected ouputs\n    test_conditions = [\n        [[270.0, 280.0], 5.0, [267.5, 272.5, 277.5, 282.5]],\n        [[10, 12, 14.0], 1.0, [9.5, 10.5, 11.5, 12.5, 13.5, 14.5]],\n        [[0.0, 90.0, 180.0, 270.0], 1.0, np.arange(0.5, 360, 1.0)],\n        [[0.0, 10., 20.,], 5.0, [2.5, 7.5,12.5,  17.5, 22.5, 357.5]],\n    ]\n\n    for test_cond in test_conditions:\n        wind_directions = np.array(test_cond[0])\n        wd_step = test_cond[1]\n        expected_directions = np.array(test_cond[2])\n\n        # Single wind speed case\n        wind_speeds = np.array([8.0])\n        freq_table = np.ones((len(wind_directions), len(wind_speeds)))\n        freq_table = freq_table / np.sum(freq_table)\n        expected_freq_table = np.ones((len(expected_directions), len(wind_speeds)))\n        expected_freq_table = expected_freq_table / np.sum(expected_freq_table)\n\n        wind_rose = WindRose(wind_directions, wind_speeds, ti_table=0.06, freq_table=freq_table)\n        wind_rose_resample = wind_rose.upsample(wd_step=wd_step)\n\n        np.testing.assert_allclose(wind_rose_resample.wind_directions, expected_directions)\n        np.testing.assert_allclose(wind_rose_resample.wind_speeds, wind_speeds)\n        np.testing.assert_allclose(wind_rose_resample.freq_table, expected_freq_table)\n\n        # Two wind speed case\n        wind_speeds = np.array([8.0, 10.0])\n        freq_table = np.ones((len(wind_directions), len(wind_speeds)))\n        freq_table = freq_table / np.sum(freq_table)\n        expected_freq_table = np.ones((len(expected_directions), len(wind_speeds)))\n        expected_freq_table = expected_freq_table / np.sum(expected_freq_table)\n\n        wind_rose = WindRose(wind_directions, wind_speeds, ti_table=0.06, freq_table=freq_table)\n        wind_rose_resample = wind_rose.upsample(wd_step=wd_step)\n\n        np.testing.assert_allclose(wind_rose_resample.wind_directions, expected_directions)\n        np.testing.assert_allclose(wind_rose_resample.wind_speeds, wind_speeds)\n        np.testing.assert_allclose(wind_rose_resample.freq_table, expected_freq_table)\n\n\ndef test_wind_rose_upsample_speeds():\n    # Test wind speed upsampling under a range of conditions\n\n    # First set up a matrix of input directions, upsampling steps and expected outputs\n    test_conditions = [\n        [[5, 10.0], 1.0, [3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0]],\n        [np.arange(0, 25, 2.0), 1.0, np.arange(0, 25, 1.0)],\n    ]\n\n    for test_cond in test_conditions:\n        wind_speeds = np.array(test_cond[0])\n        ws_step = test_cond[1]\n        expected_speeds = np.array(test_cond[2])\n\n        # Single wind direction case\n        wind_directions = np.array([270.0])\n        freq_table = np.ones((len(wind_directions), len(wind_speeds)))\n        freq_table = freq_table / np.sum(freq_table)\n        expected_freq_table = np.ones((len(wind_directions), len(expected_speeds)))\n        expected_freq_table = expected_freq_table / np.sum(expected_freq_table)\n\n        wind_rose = WindRose(wind_directions, wind_speeds, ti_table=0.06, freq_table=freq_table)\n        wind_rose_resample = wind_rose.upsample(ws_step=ws_step)\n\n        np.testing.assert_allclose(wind_rose_resample.wind_directions, wind_directions)\n        np.testing.assert_allclose(wind_rose_resample.wind_speeds, expected_speeds)\n        np.testing.assert_allclose(wind_rose_resample.freq_table, expected_freq_table)\n\n        # Two wind direction case\n        wind_directions = np.array([270.0, 280.0])\n        freq_table = np.ones((len(wind_directions), len(wind_speeds)))\n        freq_table = freq_table / np.sum(freq_table)\n        expected_freq_table = np.ones((len(wind_directions), len(expected_speeds)))\n        expected_freq_table = expected_freq_table / np.sum(expected_freq_table)\n\n        wind_rose = WindRose(wind_directions, wind_speeds, ti_table=0.06, freq_table=freq_table)\n        wind_rose_resample = wind_rose.upsample(ws_step=ws_step)\n\n        np.testing.assert_allclose(wind_rose_resample.wind_directions, wind_directions)\n        np.testing.assert_allclose(wind_rose_resample.wind_speeds, expected_speeds)\n        np.testing.assert_allclose(wind_rose_resample.freq_table, expected_freq_table)\n\n\ndef test_wind_rose_upsample():\n    # Test that interpolating without specifying new steps returns the same wind rose\n    wind_directions = np.array([0, 2, 4, 6, 8, 10])\n    wind_speeds = np.array([8, 10])\n    freq_table = np.ones((6, 2))\n    freq_table = freq_table / np.sum(freq_table)\n\n    wind_rose = WindRose(wind_directions, wind_speeds, ti_table=0.06, freq_table=freq_table)\n    wind_rose_resample = wind_rose.upsample(inplace=False)\n\n    np.testing.assert_allclose(wind_rose.wind_directions, wind_rose_resample.wind_directions)\n    np.testing.assert_allclose(wind_rose.wind_speeds, wind_rose_resample.wind_speeds)\n    np.testing.assert_allclose(wind_rose.freq_table_flat, wind_rose_resample.freq_table_flat)\n\n    # Test interpolating TI along the wind direction axis\n    wind_directions = np.array([270, 280])\n    wind_speeds = np.array([6, 7])\n    ti_table = np.array([[0.06, 0.06], [0.07, 0.07]])\n    wind_rose = WindRose(wind_directions, wind_speeds, ti_table=ti_table)\n\n    wind_rose_resample = wind_rose.upsample(wd_step=5.0, ws_step=1.0, inplace=False)\n\n    # Check that the resample ti_table is correct\n    np.testing.assert_allclose(wind_rose_resample.wind_directions, [267.5, 272.5, 277.5, 282.5])\n    np.testing.assert_allclose(wind_rose_resample.wind_speeds, [6, 7])\n    np.testing.assert_allclose(\n        wind_rose_resample.ti_table,\n        np.array([[0.06, 0.06], [0.0625, 0.0625], [0.0675, 0.0675], [0.07, 0.07]]),\n    )\n\n    # Test interpolating frequency along the wind speed axis\n    freq_table = np.array([[1 / 6, 2 / 6], [1 / 6, 2 / 6]])\n    wind_rose = WindRose(wind_directions, wind_speeds, ti_table=0.06, freq_table=freq_table)\n\n    wind_rose_resample = wind_rose.upsample(wd_step=10.0, ws_step=0.5, inplace=False)\n\n    freq_table_expected = np.array(\n        [[1 / 6, 1.25 / 6, 1.75 / 6, 2 / 6], [1 / 6, 1.25 / 6, 1.75 / 6, 2 / 6]]\n    )\n    freq_table_expected = freq_table_expected / np.sum(freq_table_expected)\n\n    # Check that the resample freq_table is correct\n    np.testing.assert_allclose(wind_rose_resample.wind_directions, [270, 280])\n    np.testing.assert_allclose(wind_rose_resample.wind_speeds, [5.75, 6.25, 6.75, 7.25])\n    np.testing.assert_allclose(wind_rose_resample.freq_table, freq_table_expected)\n\n    # Test resampling both wind speed and wind directions\n    ti_table = np.array([[0.01, 0.02], [0.03, 0.04]])\n    wind_rose = WindRose(wind_directions, wind_speeds, ti_table=ti_table)\n    wind_rose_resample = wind_rose.upsample(wd_step=5.0, ws_step=0.5, inplace=False)\n\n    # Check that the resample ti_table is correct\n    np.testing.assert_allclose(wind_rose_resample.wind_directions, [267.5, 272.5, 277.5, 282.5])\n    np.testing.assert_allclose(wind_rose_resample.wind_speeds, [5.75, 6.25, 6.75, 7.25])\n\n    # Test the using the old function name returns the same result\n    wind_rose_resample_old = wind_rose.resample_by_interpolation(\n        wd_step=5.0, ws_step=0.5, inplace=False\n    )\n    np.testing.assert_allclose(\n        wind_rose_resample.wind_directions, wind_rose_resample_old.wind_directions\n    )\n    np.testing.assert_allclose(wind_rose_resample.wind_speeds, wind_rose_resample_old.wind_speeds)\n    np.testing.assert_allclose(wind_rose_resample.ti_table, wind_rose_resample_old.ti_table)\n    np.testing.assert_allclose(wind_rose_resample.freq_table, wind_rose_resample_old.freq_table)\n\ndef test_wind_rose_upsample_wrapping():\n\n    # Test that interpolating without specifying new steps returns the same wind rose\n    wind_directions = np.array([0, 10, 350])\n    wind_speeds = np.array([8])\n    freq_table = np.ones((3, 1))\n    freq_table[-1:, :] = 0.0\n    freq_table[1, :] = 2.0\n    freq_table = freq_table / np.sum(freq_table)\n\n    wind_rose = WindRose(wind_directions, wind_speeds, ti_table=0.06, freq_table=freq_table)\n    wind_rose_resample = wind_rose.upsample(wd_step = 5.0, inplace=False)\n\n    np.testing.assert_allclose(wind_rose_resample.wind_directions,\n                                [2.5, 7.5, 12.5, 347.5, 352.5, 357.5])\n    np.testing.assert_allclose(wind_rose.wind_speeds, wind_rose_resample.wind_speeds)\n\n    expected_freq_table = np.ones((6, 1))\n    expected_freq_table[0, :] = 1.25\n    expected_freq_table[1, :] = 1.75\n    expected_freq_table[2, :] = 2.0\n    expected_freq_table[3, :] = 0.0\n    expected_freq_table[4, :] = 0.25\n    expected_freq_table[5, :] = 0.75\n    expected_freq_table = expected_freq_table / np.sum(expected_freq_table)\n\n\n    np.testing.assert_allclose(wind_rose_resample.freq_table, expected_freq_table)\n\n\n\ndef test_wind_ti_rose_upsample_directions():\n    # Test wind direction upsampling under a range of conditions\n\n    # First set up a matrix of input directions, upsampling steps and expected ouputs\n    test_conditions = [\n        [[270.0, 280.0], 5.0, [267.5, 272.5, 277.5, 282.5]],\n        [[10, 12, 14.0], 1.0, [9.5, 10.5, 11.5, 12.5, 13.5, 14.5]],\n        [[0.0, 90.0, 180.0, 270.0], 1.0, np.arange(0.5, 360, 1.0)],\n    ]\n\n    for test_cond in test_conditions:\n        wind_directions = np.array(test_cond[0])\n        wd_step = test_cond[1]\n        expected_directions = np.array(test_cond[2])\n\n        # Single wind speed / ti case\n        wind_speeds = np.array([8.0])\n        turbulence_intensities = np.array([0.06])\n        freq_table = np.ones((len(wind_directions), len(wind_speeds), len(turbulence_intensities)))\n        freq_table = freq_table / np.sum(freq_table)\n        expected_freq_table = np.ones(\n            (len(expected_directions), len(wind_speeds), len(turbulence_intensities))\n        )\n        expected_freq_table = expected_freq_table / np.sum(expected_freq_table)\n\n        wind_ti_rose = WindTIRose(\n            wind_directions,\n            wind_speeds,\n            turbulence_intensities=turbulence_intensities,\n            freq_table=freq_table,\n        )\n        wind_ti_rose_resample = wind_ti_rose.upsample(wd_step=wd_step)\n\n        np.testing.assert_allclose(wind_ti_rose_resample.wind_directions, expected_directions)\n        np.testing.assert_allclose(wind_ti_rose_resample.wind_speeds, wind_speeds)\n        np.testing.assert_allclose(\n            wind_ti_rose_resample.turbulence_intensities, turbulence_intensities\n        )\n        np.testing.assert_allclose(wind_ti_rose_resample.freq_table, expected_freq_table)\n\n        # Multiple wind speed / ti case\n        wind_speeds = np.array([8.0, 10.0])\n        turbulence_intensities = np.array([0.06, 0.07])\n        freq_table = np.ones((len(wind_directions), len(wind_speeds), len(turbulence_intensities)))\n        freq_table = freq_table / np.sum(freq_table)\n        expected_freq_table = np.ones(\n            (len(expected_directions), len(wind_speeds), len(turbulence_intensities))\n        )\n        expected_freq_table = expected_freq_table / np.sum(expected_freq_table)\n\n        wind_ti_rose = WindTIRose(\n            wind_directions,\n            wind_speeds,\n            turbulence_intensities=turbulence_intensities,\n            freq_table=freq_table,\n        )\n        wind_ti_rose_resample = wind_ti_rose.upsample(wd_step=wd_step)\n\n        np.testing.assert_allclose(wind_ti_rose_resample.wind_directions, expected_directions)\n        np.testing.assert_allclose(wind_ti_rose_resample.wind_speeds, wind_speeds)\n        np.testing.assert_allclose(\n            wind_ti_rose_resample.turbulence_intensities, turbulence_intensities\n        )\n        np.testing.assert_allclose(wind_ti_rose_resample.freq_table, expected_freq_table)\n\n\ndef test_wind_ti_rose_upsample_speeds():\n    # Test wind speed upsampling under a range of conditions\n\n    # First set up a matrix of input directions, upsampling steps and expected ouputs\n    test_conditions = [\n        [[5, 10.0], 1.0, [3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0]],\n        [np.arange(0, 25, 2.0), 1.0, np.arange(0, 25, 1.0)],\n    ]\n\n    for test_cond in test_conditions:\n        wind_speeds = np.array(test_cond[0])\n        ws_step = test_cond[1]\n        expected_speeds = np.array(test_cond[2])\n\n        # Single wind direction / ti case\n        wind_directions = np.array([270.0])\n        turbulence_intensities = np.array([0.06])\n        freq_table = np.ones((len(wind_directions), len(wind_speeds), len(turbulence_intensities)))\n        freq_table = freq_table / np.sum(freq_table)\n        expected_freq_table = np.ones(\n            (len(wind_directions), len(expected_speeds), len(turbulence_intensities))\n        )\n        expected_freq_table = expected_freq_table / np.sum(expected_freq_table)\n\n        wind_ti_rose = WindTIRose(\n            wind_directions,\n            wind_speeds,\n            turbulence_intensities=turbulence_intensities,\n            freq_table=freq_table,\n        )\n        wind_ti_rose_resample = wind_ti_rose.upsample(ws_step=ws_step)\n\n        np.testing.assert_allclose(wind_ti_rose_resample.wind_directions, wind_directions)\n        np.testing.assert_allclose(wind_ti_rose_resample.wind_speeds, expected_speeds)\n        np.testing.assert_allclose(\n            wind_ti_rose_resample.turbulence_intensities, turbulence_intensities\n        )\n        np.testing.assert_allclose(wind_ti_rose_resample.freq_table, expected_freq_table)\n\n        # Multiple wind direction / ti case\n        wind_directions = np.array([270.0, 280.0])\n        turbulence_intensities = np.array([0.06, 0.07])\n        freq_table = np.ones((len(wind_directions), len(wind_speeds), len(turbulence_intensities)))\n        freq_table = freq_table / np.sum(freq_table)\n        expected_freq_table = np.ones(\n            (len(wind_directions), len(expected_speeds), len(turbulence_intensities))\n        )\n        expected_freq_table = expected_freq_table / np.sum(expected_freq_table)\n        wind_ti_rose = WindTIRose(\n            wind_directions,\n            wind_speeds,\n            turbulence_intensities=turbulence_intensities,\n            freq_table=freq_table,\n        )\n        wind_ti_rose_resample = wind_ti_rose.upsample(ws_step=ws_step)\n\n        np.testing.assert_allclose(wind_ti_rose_resample.wind_directions, wind_directions)\n        np.testing.assert_allclose(wind_ti_rose_resample.wind_speeds, expected_speeds)\n        np.testing.assert_allclose(\n            wind_ti_rose_resample.turbulence_intensities, turbulence_intensities\n        )\n        np.testing.assert_allclose(wind_ti_rose_resample.freq_table, expected_freq_table)\n\n\ndef test_upsample_ti_rose():\n    wind_directions = np.array([0, 2, 4, 6, 8, 10])\n    wind_speeds = np.array([8, 10])\n    turbulence_intensities = np.array([0.05, 0.1])\n    freq_table = np.ones((6, 2, 2))\n    freq_table = freq_table / np.sum(freq_table)\n\n    wind_ti_rose = WindTIRose(\n        wind_directions, wind_speeds, turbulence_intensities, freq_table=freq_table\n    )\n\n    # Test that interpolating without specifying new steps returns the same\n    wind_ti_rose_resample = wind_ti_rose.upsample(inplace=False)\n\n    np.testing.assert_allclose(wind_ti_rose.wind_directions, wind_ti_rose_resample.wind_directions)\n    np.testing.assert_allclose(wind_ti_rose.wind_speeds, wind_ti_rose_resample.wind_speeds)\n    np.testing.assert_allclose(\n        wind_ti_rose.turbulence_intensities, wind_ti_rose_resample.turbulence_intensities\n    )\n    np.testing.assert_allclose(wind_ti_rose.freq_table_flat, wind_ti_rose_resample.freq_table_flat)\n\n    # Test interpolating frequency along the wind speed axis\n    wind_directions = np.array([270, 280])\n    wind_speeds = np.array([6, 8])\n    turbulence_intensities = np.array([0.05, 0.1])\n    freq_table = np.ones((2, 2, 2))\n    freq_table[:, 1, :] = 2.0\n    freq_table = freq_table / np.sum(freq_table)\n    wind_ti_rose = WindTIRose(\n        wind_directions, wind_speeds, turbulence_intensities, freq_table=freq_table\n    )\n\n    wind_ti_rose_resample = wind_ti_rose.upsample(\n        wd_step=10.0, ws_step=1.0, ti_step=0.05, inplace=False\n    )\n\n    freq_table_expected = np.ones((2, 4, 2))\n    freq_table_expected[:, 0, :] = 1.0\n    freq_table_expected[:, 1, :] = 1.25\n    freq_table_expected[:, 2, :] = 1.75\n    freq_table_expected[:, 3, :] = 2.0\n    freq_table_expected = freq_table_expected / np.sum(freq_table_expected)\n\n    # Check that the resample freq_table is correct\n    np.testing.assert_allclose(wind_ti_rose_resample.wind_directions, [270, 280])\n    np.testing.assert_allclose(wind_ti_rose_resample.wind_speeds, [5.5, 6.5, 7.5, 8.5])\n    np.testing.assert_allclose(wind_ti_rose_resample.turbulence_intensities, [0.05, 0.1])\n    np.testing.assert_allclose(wind_ti_rose_resample.freq_table, freq_table_expected)\n\n\n    # Test interpolating frequency along the wind direction axis with wrapping\n    wind_directions = np.array([0, 350])\n    wind_speeds = np.array([7])\n    turbulence_intensities = np.array([0.1])\n    freq_table = np.ones((2, 1, 1))\n    freq_table[1, :, :] = 2.0\n    freq_table = freq_table / np.sum(freq_table)\n    wind_ti_rose = WindTIRose(\n        wind_directions, wind_speeds, turbulence_intensities, freq_table=freq_table\n    )\n\n    wind_ti_rose_resample = wind_ti_rose.upsample(\n        wd_step=5.0, inplace=False\n    )\n\n    freq_table_expected = np.ones((4, 1, 1))\n    freq_table_expected[0, :, :] = 1.0\n    freq_table_expected[1, :, :] = 2.0\n    freq_table_expected[2, :, :] = 1.75\n    freq_table_expected[3, :, :] = 1.25\n\n    freq_table_expected = freq_table_expected / np.sum(freq_table_expected)\n\n    # Check that the resample freq_table is correct\n    np.testing.assert_allclose(wind_ti_rose_resample.wind_directions, [ 2.5, 347.5, 352.5, 357.5])\n    np.testing.assert_allclose(wind_ti_rose_resample.wind_speeds, [7.0])\n    np.testing.assert_allclose(wind_ti_rose_resample.turbulence_intensities, [0.1])\n    np.testing.assert_allclose(wind_ti_rose_resample.freq_table, freq_table_expected)\n\n\ndef test_wrap_wind_directions_near_360():\n    wd_step = 5.0\n    wd_values = np.array([0, 180, 357, 357.5, 358])\n    time_series = TimeSeries(np.array([0]), np.array([0]), 0.06)\n\n    wd_wrapped = time_series._wrap_wind_directions_near_360(wd_values, wd_step)\n\n    expected_result = np.array([0, 180, 357, -wd_step / 2.0, -2.0])\n    assert np.allclose(wd_wrapped, expected_result)\n\n\ndef test_time_series_to_WindRose():\n    # Test just 1 wind speed\n    wind_directions = np.array([259.8, 260.2, 264.3])\n    wind_speeds = np.array([5.0, 5.0, 5.1])\n    time_series = TimeSeries(wind_directions, wind_speeds, 0.06)\n    wind_rose = time_series.to_WindRose(wd_step=2.0, ws_step=1.0)\n\n    # The wind directions should be 260, 262 and 264 because they're binned\n    # to the nearest 2 deg increment\n    assert np.allclose(wind_rose.wind_directions, [260, 262, 264])\n\n    # Freq table should have dimension of 3 wd x 1 ws because the wind speeds\n    # are all binned to the same value given the `ws_step` size\n    freq_table = wind_rose.freq_table\n    assert freq_table.shape[0] == 3\n    assert freq_table.shape[1] == 1\n\n    # The frequencies should [2/3, 0, 1/3] given that 2 of the data points\n    # fall in the 260 deg bin, 0 in the 262 deg bin and 1 in the 264 deg bin\n    assert np.allclose(freq_table.squeeze(), [2 / 3, 0, 1 / 3])\n\n    # Test just 2 wind speeds\n    wind_directions = np.array([259.8, 260.2, 264.3])\n    wind_speeds = np.array([5.0, 5.0, 6.1])\n    time_series = TimeSeries(wind_directions, wind_speeds, 0.06)\n    wind_rose = time_series.to_WindRose(wd_step=2.0, ws_step=1.0)\n\n    # The wind directions should be 260, 262 and 264\n    assert np.allclose(wind_rose.wind_directions, [260, 262, 264])\n\n    # The wind speeds should be 5 and 6\n    assert np.allclose(wind_rose.wind_speeds, [5, 6])\n\n    # Freq table should have dimension of 3 wd x 2 ws\n    freq_table = wind_rose.freq_table\n    assert freq_table.shape[0] == 3\n    assert freq_table.shape[1] == 2\n\n    # The frequencies should [2/3, 0, 1/3]\n    assert freq_table[0, 0] == 2 / 3\n    assert freq_table[2, 1] == 1 / 3\n\n    # The turbulence intensity table should be 0.06 for all bins\n    ti_table = wind_rose.ti_table\n\n    # Assert that table entires which are not nan are equal to 0.06\n    assert np.allclose(ti_table[~np.isnan(ti_table)], 0.06)\n\n\ndef test_time_series_to_WindRose_wrapping():\n    wind_directions = np.arange(0.0, 360.0, 0.25)\n    wind_speeds = 8.0 * np.ones_like(wind_directions)\n    time_series = TimeSeries(wind_directions, wind_speeds, 0.06)\n    wind_rose = time_series.to_WindRose(wd_step=2.0, ws_step=1.0)\n\n    # Expert for the first bin in this case to be 0, and the final to be 358\n    # and both to have equal numbers of points\n    np.testing.assert_almost_equal(wind_rose.wind_directions[0], 0)\n    np.testing.assert_almost_equal(wind_rose.wind_directions[-1], 358)\n    np.testing.assert_almost_equal(wind_rose.freq_table[0, 0], wind_rose.freq_table[-1, 0])\n\n\ndef test_time_series_to_WindRose_with_ti():\n    wind_directions = np.array([259.8, 260.2, 260.3, 260.1])\n    wind_speeds = np.array([5.0, 5.0, 5.1, 7.2])\n    turbulence_intensities = np.array([0.5, 1.0, 1.5, 2.0])\n    time_series = TimeSeries(\n        wind_directions,\n        wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n    )\n    wind_rose = time_series.to_WindRose(wd_step=2.0, ws_step=1.0)\n\n    # Turbulence intensity should average to 1 in the 5 m/s bin and 2 in the 7 m/s bin\n    ti_table = wind_rose.ti_table\n    np.testing.assert_almost_equal(ti_table[0, 0], 1)\n    np.testing.assert_almost_equal(ti_table[0, 2], 2)\n\n    # The 6 m/s bin should be empty\n    freq_table = wind_rose.freq_table\n    np.testing.assert_almost_equal(freq_table[0, 1], 0)\n\n\ndef test_wind_ti_rose_init():\n    \"\"\"\n    The wind directions, wind speeds, and turbulence intensities can have any\n    length, but the frequency array must have shape (n wind directions,\n    n wind speeds, n turbulence intensities)\n    \"\"\"\n    wind_directions = np.array([270, 280, 290, 300])\n    wind_speeds = np.array([6, 7, 8])\n    turbulence_intensities = np.array([0.05, 0.1])\n\n    # This should be ok\n    _ = WindTIRose(wind_directions, wind_speeds, turbulence_intensities)\n\n    # This should be ok since the frequency array shape matches the wind directions\n    # and wind speeds\n    _ = WindTIRose(wind_directions, wind_speeds, turbulence_intensities, np.ones((4, 3, 2)))\n\n    # This should raise an error since the frequency array shape does not\n    # match the wind directions and wind speeds\n    with pytest.raises(ValueError):\n        WindTIRose(wind_directions, wind_speeds, turbulence_intensities, np.ones((3, 3, 3)))\n\n    # Test that instantiating with non-integer wind directions and wind speeds works\n    _ = WindTIRose(wind_directions+0.5, wind_speeds+0.2, turbulence_intensities)\n\n    # Test that instantiating with non-integer steps works\n    _ = WindTIRose(\n        wind_directions=np.linspace(0.0, 360.0, 100, endpoint=False),\n        wind_speeds=np.array([5.0]),\n        turbulence_intensities=turbulence_intensities,\n    )\n\n\ndef test_wind_ti_rose_grid():\n    wind_directions = np.array([270, 280, 290, 300])\n    wind_speeds = np.array([6, 7, 8])\n    turbulence_intensities = np.array([0.05, 0.1])\n\n    wind_rose = WindTIRose(wind_directions, wind_speeds, turbulence_intensities)\n\n    # Wind direction grid has the same dimensions as the frequency table\n    assert wind_rose.wd_grid.shape == wind_rose.freq_table.shape\n\n    # Flattening process occurs wd first\n    # This is each wind direction for each wind speed:\n    np.testing.assert_allclose(wind_rose.wd_flat, 6 * [270] + 6 * [280] + 6 * [290] + 6 * [300])\n\n\ndef test_wind_ti_rose_unpack():\n    wind_directions = np.array([270, 280, 290, 300])\n    wind_speeds = np.array([6, 7, 8])\n    turbulence_intensities = np.array([0.05, 0.1])\n    freq_table = np.array(\n        [\n            [[1.0, 0.0], [1.0, 0.0], [0.0, 0.0]],\n            [[1.0, 0.0], [1.0, 0.0], [0.0, 0.0]],\n            [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]],\n            [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]],\n        ]\n    )\n\n    # First test using default assumption only non-zero frequency cases computed\n    wind_rose = WindTIRose(wind_directions, wind_speeds, turbulence_intensities, freq_table)\n\n    (\n        wind_directions_unpack,\n        wind_speeds_unpack,\n        turbulence_intensities_unpack,\n        freq_table_unpack,\n        value_table_unpack,\n        heterogeneous_inflow_config,\n    ) = wind_rose.unpack()\n\n    # Given the above frequency table with zeros for a few elements,\n    # we expect only combinations of wind directions of 270 and 280 deg,\n    # wind speeds of 6 and 7 m/s, and a TI of 5%\n    np.testing.assert_allclose(wind_directions_unpack, [270, 270, 280, 280])\n    np.testing.assert_allclose(wind_speeds_unpack, [6, 7, 6, 7])\n    np.testing.assert_allclose(turbulence_intensities_unpack, [0.05, 0.05, 0.05, 0.05])\n    np.testing.assert_allclose(freq_table_unpack, [0.25, 0.25, 0.25, 0.25])\n\n    # In this case n_findex is the length of the wind combinations that are\n    # non-zero frequency\n    assert wind_rose.n_findex == 4\n\n    # Now test computing 0-freq cases too\n    wind_rose = WindTIRose(\n        wind_directions,\n        wind_speeds,\n        turbulence_intensities,\n        freq_table,\n        compute_zero_freq_occurrence=True,\n    )\n\n    (\n        wind_directions_unpack,\n        wind_speeds_unpack,\n        turbulence_intensities_unpack,\n        freq_table_unpack,\n        value_table_unpack,\n        heterogeneous_inflow_config,\n    ) = wind_rose.unpack()\n\n    # Expect now to compute all combinations\n    np.testing.assert_allclose(\n        wind_directions_unpack, 6 * [270] + 6 * [280] + 6 * [290] + 6 * [300]\n    )\n\n    # In this case n_findex is the total number of wind combinations\n    assert wind_rose.n_findex == 24\n\n    # Adding tests of unpack_multidim_conditions here, since these will be included in unpack()\n    # in a future release\n    multidim_conditions_scalar = {\"TI\": 0.06, \"Hs\": 3.1}\n    wind_rose = WindTIRose(\n        wind_directions,\n        wind_speeds,\n        turbulence_intensities,\n        freq_table,\n        multidim_conditions=multidim_conditions_scalar\n    )\n    multidim_conditions_unpacked = wind_rose.unpack_multidim_conditions()\n\n    for k, v in multidim_conditions_unpacked.items():\n        np.testing.assert_allclose(v, [multidim_conditions_scalar[k]] * wind_rose.n_findex)\n\n    # Array multi-dimensional conditions that are not the correct shape (n_wd x n_ws x n_ti)\n    multidim_conditions_array_bad_shape = {\"a\": np.array([1, 2, 3, 4, 5, 6])}\n    with pytest.raises(ValueError):\n        WindTIRose(\n            wind_directions,\n            wind_speeds,\n            turbulence_intensities,\n            freq_table,\n            multidim_conditions=multidim_conditions_array_bad_shape\n        )\n    # Correct shape multi-dimensional conditions, wrong number of values\n    # [(4, 3, 1) instead of (4, 3, 2)]\n    multidim_conditions_array_wrong_size = {\"a\": np.array(\n        [\n            [[0.06], [0.07], [0.08]],\n            [[0.08], [0.07], [0.06]],\n            [[0.07], [0.07], [0.07]],\n            [[0.06], [0.06], [0.06]],\n        ]\n    )}\n    with pytest.raises(ValueError):\n        WindTIRose(\n            wind_directions,\n            wind_speeds,\n            turbulence_intensities,\n            freq_table,\n            multidim_conditions=multidim_conditions_array_wrong_size\n        )\n    # Correct shape and size\n    multidim_conditions_array = {\"a\": np.array(\n        [\n            [[0.06, 0.05], [0.07, 0.06], [0.08, 0.07]],\n            [[0.08, 0.08], [0.07, 0.07], [0.06, 0.06]],\n            [[0.07, 0.07], [0.07, 0.07], [0.07, 0.07]],\n            [[0.06, 0.05], [0.06, 0.05], [0.06, 0.05]],\n        ]\n    )}\n    wind_rose = WindTIRose(\n        wind_directions,\n        wind_speeds,\n        turbulence_intensities,\n        freq_table,\n        multidim_conditions=multidim_conditions_array\n    )\n    multidim_conditions_unpacked = wind_rose.unpack_multidim_conditions()\n\n    for k, v in multidim_conditions_unpacked.items():\n        assert k in multidim_conditions_array.keys()\n        assert v.shape == (4,) # 4 remaining conditions after frequency filtering\n\n\ndef test_wind_ti_rose_unpack_for_reinitialize():\n    wind_directions = np.array([270, 280, 290, 300])\n    wind_speeds = np.array([6, 7, 8])\n    turbulence_intensities = np.array([0.05, 0.1])\n    freq_table = np.array(\n        [\n            [[1.0, 0.0], [1.0, 0.0], [0.0, 0.0]],\n            [[1.0, 0.0], [1.0, 0.0], [0.0, 0.0]],\n            [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]],\n            [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]],\n        ]\n    )\n\n    # First test using default assumption only non-zero frequency cases computed\n    wind_rose = WindTIRose(wind_directions, wind_speeds, turbulence_intensities, freq_table)\n\n    (\n        wind_directions_unpack,\n        wind_speeds_unpack,\n        turbulence_intensities_unpack,\n        heterogeneous_inflow_config,\n    ) = wind_rose.unpack_for_reinitialize()\n\n    # Given the above frequency table with zeros for a few elements,\n    # we expect only combinations of wind directions of 270 and 280 deg,\n    # wind speeds of 6 and 7 m/s, and a TI of 5%\n    np.testing.assert_allclose(wind_directions_unpack, [270, 270, 280, 280])\n    np.testing.assert_allclose(wind_speeds_unpack, [6, 7, 6, 7])\n    np.testing.assert_allclose(turbulence_intensities_unpack, [0.05, 0.05, 0.05, 0.05])\n\n\ndef test_wind_ti_rose_aggregate():\n    wind_directions = np.array([0, 2, 4, 6, 8, 10])\n    wind_speeds = np.array([7, 8])\n    turbulence_intensities = np.array([0.02, 0.04, 0.06, 0.08, 0.1])\n    freq_table = np.ones((6, 2, 5))\n\n    wind_rose = WindTIRose(wind_directions, wind_speeds, turbulence_intensities, freq_table)\n\n    # Test that resampling with a new step size returns the same\n    wind_rose_aggregate = wind_rose.downsample()\n\n    np.testing.assert_allclose(wind_rose.wind_directions, wind_rose_aggregate.wind_directions)\n    np.testing.assert_allclose(wind_rose.wind_speeds, wind_rose_aggregate.wind_speeds)\n    np.testing.assert_allclose(\n        wind_rose.turbulence_intensities, wind_rose_aggregate.turbulence_intensities\n    )\n    np.testing.assert_allclose(wind_rose.freq_table_flat, wind_rose_aggregate.freq_table_flat)\n\n    # Now test resampling the turbulence intensities to 4% bins\n    wind_rose_aggregate = wind_rose.downsample(ti_step=0.04)\n    np.testing.assert_allclose(wind_rose_aggregate.turbulence_intensities, [0.04, 0.08, 0.12])\n    np.testing.assert_allclose(\n        wind_rose_aggregate.freq_table_flat, (1 / 60) * np.array(12 * [2, 2, 1])\n    )\n\n    # Test tha that inplace behavior is to modify the original object as expected\n    wind_rose_2 = copy.deepcopy(wind_rose)\n    wind_rose_2.downsample(inplace=True)\n    np.testing.assert_allclose(wind_rose.wind_directions, wind_rose_2.wind_directions)\n    np.testing.assert_allclose(wind_rose.wind_speeds, wind_rose_2.wind_speeds)\n    np.testing.assert_allclose(wind_rose.turbulence_intensities, wind_rose_2.turbulence_intensities)\n\n    wind_rose_2 = copy.deepcopy(wind_rose)\n    wind_rose_2.downsample(ti_step=0.04, inplace=True)\n    np.testing.assert_allclose(\n        wind_rose_aggregate.turbulence_intensities, wind_rose_2.turbulence_intensities\n    )\n    np.testing.assert_allclose(wind_rose_aggregate.freq_table_flat, wind_rose_2.freq_table_flat)\n\n\ndef test_time_series_to_WindTIRose():\n    wind_directions = np.array([259.8, 260.2, 260.3, 260.1])\n    wind_speeds = np.array([5.0, 5.0, 5.1, 7.2])\n    turbulence_intensities = np.array([0.05, 0.1, 0.15, 0.2])\n    time_series = TimeSeries(\n        wind_directions,\n        wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n    )\n    wind_rose = time_series.to_WindTIRose(wd_step=2.0, ws_step=1.0, ti_step=0.1)\n\n    # The binning should result in turbulence intensity bins of 0.1 and 0.2\n    tis_windrose = wind_rose.turbulence_intensities\n    np.testing.assert_almost_equal(tis_windrose, [0.1, 0.2])\n\n    # The 6 m/s bin should be empty\n    freq_table = wind_rose.freq_table\n    np.testing.assert_almost_equal(freq_table[0, 1, :], [0, 0])\n\n\ndef test_gen_heterogeneous_inflow_config():\n    wind_directions = np.array([259.8, 260.2, 260.3, 260.1, 270.0])\n    wind_speeds = 8.0\n    turbulence_intensities = 0.06\n\n    heterogeneous_map_config = {\n        \"speed_multipliers\": np.array(\n            [\n                [0.9, 0.9],\n                [1.0, 1.0],\n                [1.1, 1.2],\n            ]\n        ),\n        \"wind_directions\": np.array([250, 260, 270]),\n        \"x\": np.array([0, 1000]),\n        \"y\": np.array([0, 0]),\n    }\n\n    time_series = TimeSeries(\n        wind_directions,\n        wind_speeds,\n        turbulence_intensities=turbulence_intensities,\n        heterogeneous_map=heterogeneous_map_config,\n    )\n\n    (_, _, _, _, _, heterogeneous_inflow_config) = time_series.unpack()\n\n    expected_result = np.array([[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.1, 1.2]])\n    np.testing.assert_allclose(heterogeneous_inflow_config[\"speed_multipliers\"], expected_result)\n    np.testing.assert_allclose(heterogeneous_inflow_config[\"x\"], heterogeneous_inflow_config[\"x\"])\n\n\ndef test_heterogeneous_inflow_config_by_wd():\n    # Show that passing the config dict to the old heterogeneous_inflow_config_by_wd input\n    # is equivalent to passing it to the heterogeneous_map input\n\n    wind_directions = np.array([250.0, 260.0])\n    wind_speeds = np.array([8.0])\n\n    heterogeneous_map_config = {\n        \"speed_multipliers\": np.array(\n            [\n                [0.9, 0.9],\n                [1.0, 1.0],\n                [1.1, 1.2],\n            ]\n        ),\n        \"wind_directions\": np.array([250, 260, 270]),\n        \"x\": np.array([0, 1000]),\n        \"y\": np.array([0, 0]),\n    }\n\n    # Using heterogeneous_map input\n    wind_rose = WindRose(\n        wind_directions,\n        wind_speeds,\n        ti_table=0.06,\n        heterogeneous_map=heterogeneous_map_config,\n    )\n\n    (_, _, _, _, _, heterogeneous_inflow_config_a) = wind_rose.unpack()\n\n    # Using heterogeneous_inflow_config_by_wd input\n    wind_rose = WindRose(\n        wind_directions,\n        wind_speeds,\n        ti_table=0.06,\n        heterogeneous_inflow_config_by_wd=heterogeneous_map_config,\n    )\n\n    (_, _, _, _, _, heterogeneous_inflow_config_b) = wind_rose.unpack()\n\n    np.testing.assert_allclose(\n        heterogeneous_inflow_config_a[\"speed_multipliers\"],\n        heterogeneous_inflow_config_b[\"speed_multipliers\"],\n    )\n\n\ndef test_gen_heterogeneous_inflow_config_with_wind_directions_and_wind_speeds():\n    heterogeneous_map_config = {\n        \"speed_multipliers\": np.array([[0.9, 0.9], [1.0, 1.0], [1.1, 1.2], [1.2, 1.3]]),\n        \"wind_directions\": np.array([250, 260, 250, 260]),\n        \"wind_speeds\": np.array([5, 5, 10, 10]),\n        \"x\": np.array([0, 1000]),\n        \"y\": np.array([0, 0]),\n    }\n\n    time_series = TimeSeries(\n        wind_directions=np.array([259.8, 260.2, 260.3, 260.1, 200.0]),\n        wind_speeds=np.array([4, 9, 4, 9, 4]),\n        turbulence_intensities=0.06,\n        heterogeneous_map=heterogeneous_map_config,\n    )\n\n    (_, _, _, _, _, heterogeneous_inflow_config) = time_series.unpack()\n\n    expected_result = np.array([[1.0, 1.0], [1.2, 1.3], [1.0, 1.0], [1.2, 1.3], [0.9, 0.9]])\n    np.testing.assert_allclose(heterogeneous_inflow_config[\"speed_multipliers\"], expected_result)\n\n\ndef test_gen_heterogeneous_inflow_config_with_wind_directions_and_wind_speeds_wind_rose():\n    heterogeneous_map_config = {\n        \"speed_multipliers\": np.array([[0.9, 0.9], [1.0, 1.0], [1.1, 1.2], [1.2, 1.3]]),\n        \"wind_directions\": np.array([250, 260, 250, 260]),\n        \"wind_speeds\": np.array([5, 5, 10, 10]),\n        \"x\": np.array([0, 1000]),\n        \"y\": np.array([0, 0]),\n    }\n\n    wind_rose = WindRose(\n        wind_directions=np.array([250.0, 260.0]),\n        wind_speeds=np.array([9.0]),\n        ti_table=0.06,\n        heterogeneous_map=heterogeneous_map_config,\n    )\n\n    (_, _, _, _, _, heterogeneous_inflow_config) = wind_rose.unpack()\n\n    expected_result = np.array([[1.1, 1.2], [1.2, 1.3]])\n    np.testing.assert_allclose(heterogeneous_inflow_config[\"speed_multipliers\"], expected_result)\n\n\ndef test_read_csv_long():\n    # Read in the wind rose data from the csv file\n\n    # First confirm that the data raises value error when wrong columns passed\n    with pytest.raises(ValueError):\n        wind_rose = WindRose.read_csv_long(TEST_DATA / \"wind_rose.csv\")\n\n    # Since TI not specified in table, not giving a fixed TI should raise an error\n    with pytest.raises(ValueError):\n        wind_rose = WindRose.read_csv_long(\n            TEST_DATA / \"wind_rose.csv\", wd_col=\"wd\", ws_col=\"ws\", freq_col=\"freq_val\"\n        )\n\n    # Now read in with correct columns\n    wind_rose = WindRose.read_csv_long(\n        TEST_DATA / \"wind_rose.csv\",\n        wd_col=\"wd\",\n        ws_col=\"ws\",\n        freq_col=\"freq_val\",\n        ti_col_or_value=0.06,\n    )\n\n    # Confirm that data read in correctly, and the missing wd/ws bins are filled with zeros\n    expected_result = np.array([[0.25, 0.25], [0.5, 0]])\n    np.testing.assert_allclose(wind_rose.freq_table, expected_result)\n\n    # Confirm expected wind direction and wind speed values\n    expected_result = np.array([270, 280])\n    np.testing.assert_allclose(wind_rose.wind_directions, expected_result)\n\n    expected_result = np.array([8, 9])\n    np.testing.assert_allclose(wind_rose.wind_speeds, expected_result)\n\n    # Confirm expected TI values\n    expected_result = np.array([[0.06, 0.06], [0.06, np.nan]])\n\n    # Confirm all elements which aren't nan are close\n    np.testing.assert_allclose(\n        wind_rose.ti_table[~np.isnan(wind_rose.ti_table)],\n        expected_result[~np.isnan(expected_result)],\n    )\n\n\ndef test_read_csv_long_ti():\n    # Read in the wind rose data from the csv file\n\n    # Now read in with correct columns\n    wind_ti_rose = WindTIRose.read_csv_long(\n        TEST_DATA / \"wind_ti_rose.csv\",\n        wd_col=\"wd\",\n        ws_col=\"ws\",\n        ti_col=\"ti\",\n        freq_col=\"freq_val\",\n    )\n\n    # Confirm the shape of the frequency table\n    assert wind_ti_rose.freq_table.shape == (2, 2, 2)\n\n    # Confirm expected wind direction and wind speed values\n    expected_result = np.array([270, 280])\n    np.testing.assert_allclose(wind_ti_rose.wind_directions, expected_result)\n\n    expected_result = np.array([8, 9])\n    np.testing.assert_allclose(wind_ti_rose.wind_speeds, expected_result)\n\n    expected_result = np.array([0.06, 0.07])\n    np.testing.assert_allclose(wind_ti_rose.turbulence_intensities, expected_result)\n\ndef test_time_series_multidim():\n    # Test that TimeSeries can handle multidimensional wind speeds and turbulence intensities\n\n    wind_directions = np.array([270.0, 280.0, 290.0])\n    wind_speeds = np.array([5.0, 6.0, 7.0])\n    turbulence_intensities = np.array([0.06, 0.07, 0.06])\n\n    # Test scalar multidimensional conditions\n    multidim_conditions_scalar = {\"TI\": 0.06, \"Hs\": 3.1}\n    time_series = TimeSeries(\n        wind_directions,\n        wind_speeds,\n        turbulence_intensities,\n        multidim_conditions=copy.deepcopy(multidim_conditions_scalar),\n    )\n    multidim_conditions_unpacked = time_series.unpack_multidim_conditions()\n\n    for k, v in multidim_conditions_unpacked.items():\n        assert np.allclose(v, [multidim_conditions_scalar[k]] * len(wind_directions))\n\n    # Array multi-dimensional conditions that are not the correct length (n_findex)\n    multidim_conditions_array_bad_size = {\"TI\": np.array([1, 2, 3, 4])}\n    with pytest.raises(ValueError):\n        TimeSeries(\n            wind_directions,\n            wind_speeds,\n            turbulence_intensities,\n            multidim_conditions=multidim_conditions_array_bad_size\n        )\n    # Incorrect shape\n    multidim_conditions_array_bad_shape = {\n        \"TI\": np.array([[0.06, 0.07], [0.08, 0.09], [0.10, 0.11]])\n    }\n    with pytest.raises(ValueError):\n        TimeSeries(\n            wind_directions,\n            wind_speeds,\n            turbulence_intensities,\n            multidim_conditions=multidim_conditions_array_bad_shape\n        )\n    # Correct size and shape\n    multidim_conditions_array = {\"TI\": np.array([0.06, 0.07, 0.08])}\n    time_series = TimeSeries(\n        wind_directions,\n        wind_speeds,\n        turbulence_intensities,\n        multidim_conditions=copy.deepcopy(multidim_conditions_array),\n    )\n    multidim_conditions_unpacked = time_series.unpack_multidim_conditions()\n\n    for k, v in multidim_conditions_unpacked.items():\n        assert k in multidim_conditions_array.keys()\n        assert v.shape == (len(wind_directions),)\n"
  },
  {
    "path": "tests/wind_rose_wrg_test.py",
    "content": "import math\nfrom pathlib import Path\n\nimport numpy as np\nimport pytest\n\nimport floris\nfrom floris import (\n    FlorisModel,\n    UncertainFlorisModel,\n    WindRoseWRG,\n)\n\n\nTEST_DATA = Path(__file__).resolve().parent / \"data\"\nYAML_INPUT = TEST_DATA / \"input_full.yaml\"\n\nWRG_FILE_FILE = TEST_DATA / \"wrg_test.wrg\"\n\ndef test_load_wrg():\n    WindRoseWRG(WRG_FILE_FILE)\n\n\ndef test_read_header():\n    \"\"\"Test reading the header of a WRG file.\n\n    The header of a WRG file is the first line of the file and contains the\n    number of grid points in x and y, the minimum x and y coordinates, and the\n    grid size.\n    \"\"\"\n\n    wind_rose_wrg = WindRoseWRG(WRG_FILE_FILE)\n\n    assert wind_rose_wrg.nx == 2\n    assert wind_rose_wrg.ny == 3\n    assert wind_rose_wrg.xmin == 0.0\n    assert wind_rose_wrg.ymin == 0.0\n    assert wind_rose_wrg.grid_size == 1000.0\n\n    # Test x and y arrays\n    assert np.allclose(wind_rose_wrg.x_array, np.array([0.0, 1000.0]))\n    assert np.allclose(wind_rose_wrg.y_array, np.array([0.0, 1000.0, 2000.0]))\n\n    # Test number of grid points\n    assert wind_rose_wrg.n_gid == 6\n\n    # Test number of sectors\n    assert wind_rose_wrg.n_sectors == 12\n\n\ndef test_read_data():\n    \"\"\"Test reading the data of a WRG file.\n\n    The data of a WRG file is the information about each grid point, including\n    the x, y, z, and h coordinates, the frequency of each sector, and the Weibull\n    parameters for each sector.\n    \"\"\"\n\n    wind_rose_wrg = WindRoseWRG(WRG_FILE_FILE)\n\n    # Test z and h values\n    assert wind_rose_wrg.z == 0.0\n    assert wind_rose_wrg.h == 90.0\n\n    # Test the first and last gid for sector_freq, weibull_A, and weibull_k\n    assert wind_rose_wrg.sector_freq[0, 0, 0] == 116 / 1000.0\n    assert wind_rose_wrg.sector_freq[-1, -1, -1] == 98 / 1000.0\n\n    assert wind_rose_wrg.weibull_A[0, 0, 0] == 106 / 10.0\n    assert wind_rose_wrg.weibull_A[-1, -1, -1] == 111 / 10.0\n\n    assert wind_rose_wrg.weibull_k[0, 0, 0] == 273 / 100.0\n    assert wind_rose_wrg.weibull_k[-1, -1, -1] == 267 / 100.0\n\n\ndef test_build_interpolant_function_list():\n\n    wind_rose_wrg = WindRoseWRG(WRG_FILE_FILE)\n\n    # Initialize the values\n    x = np.array([0.0, 1000.0])\n    y = np.array([0.0, 500.0, 1000.0])\n    n_sectors = 3\n    data = np.ones((2, 3, 3))\n\n    # For the first sector, the point at (1000, 0) is 2.0\n    data[1, 0, 0] = 2.0\n\n    # For the second sector, the point at (1000, 500) is 3.0\n    data[1, 1, 1] = 3.0\n\n    function_list = wind_rose_wrg._build_interpolant_function_list(x, y, n_sectors, data)\n\n    # Length of the function list should be n_sectors\n    assert len(function_list) == n_sectors\n\n    # Test the interpolation in the first sector\n    test_value = function_list[0]((500, 0))\n    assert test_value == 1.5\n\n    # Test the interpolation in the second sector\n    test_value = function_list[1]((1000, 250))\n    assert test_value == 2.0\n\n    # Test using linear method\n    test_value = function_list[0]((500, 0), method=\"linear\")\n    assert test_value == 1.5\n\n    # Test using nearest method\n    test_value = function_list[0]((1001, 0), method=\"nearest\")\n    assert test_value == 2.0\n\n\ndef test_interpolate_data():\n    wind_rose_wrg = WindRoseWRG(WRG_FILE_FILE)\n\n    sector_freq = wind_rose_wrg.sector_freq\n\n    # Test that interpolating onto the point 0,0 returns the 1st row of the sector_freq\n    test_value = wind_rose_wrg._interpolate_data(0, 0, wind_rose_wrg.interpolant_sector_freq)\n    assert np.allclose(test_value, sector_freq[0, 0, :])\n\n    # Test the interpolating just out of bounds of 0,0 also yields the 1st row of the sector_freq\n    test_value = wind_rose_wrg._interpolate_data(-1, -1, wind_rose_wrg.interpolant_sector_freq)\n    assert np.allclose(test_value, sector_freq[0, 0, :])\n\n    # Test that value at x=500, y0, this is the average of the rows at [0,0] and [1,0]\n    test_value = wind_rose_wrg._interpolate_data(500, 0, wind_rose_wrg.interpolant_sector_freq)\n    assert np.allclose(test_value, (sector_freq[0, 0, :] + sector_freq[1, 0, :]) / 2)\n\n    # Test that value at x=0, y=500, this is the average of the rows at [0,0] and [0,1]\n    test_value = wind_rose_wrg._interpolate_data(0, 500, wind_rose_wrg.interpolant_sector_freq)\n    assert np.allclose(test_value, (sector_freq[0, 0, :] + sector_freq[0, 1, :]) / 2)\n\n\ndef test_generate_wind_speed_frequencies_from_weibull():\n    wind_rose_wrg = WindRoseWRG(WRG_FILE_FILE)\n\n    wind_speeds_in = np.array([0.0, 5.0, 10.0, 15.0])\n    wind_speeds, freq = wind_rose_wrg._generate_wind_speed_frequencies_from_weibull(\n        10.0, 2.0, wind_speeds=wind_speeds_in\n    )\n\n    # Test that the wind speeds are the same\n    assert np.allclose(wind_speeds, wind_speeds_in)\n\n    # Test that freq is the same length as wind_speeds\n    assert len(freq) == len(wind_speeds)\n\n    # Test that the frequencies sum to 1.0\n    assert np.allclose(np.sum(freq), 1.0)\n\n    # Test the correctness of the frequencies by reversing the process\n    wind_speeds = np.arange(0.0, 100.0, 1.0)\n    A_test = 9.0\n    k_test = 1.8\n    wind_speeds, freq = wind_rose_wrg._generate_wind_speed_frequencies_from_weibull(\n        A_test, k_test, wind_speeds=wind_speeds\n    )\n\n    # Test that the mean value matches theory\n    mean_value = np.sum(wind_speeds * freq)\n    assert np.allclose(mean_value, A_test * math.gamma(1 + 1 / k_test), rtol=0.1)\n\n\ndef test_get_wind_rose_at_point():\n    wind_rose_wrg = WindRoseWRG(WRG_FILE_FILE)\n\n    wind_speeds = np.arange(0.0, 26.0, 1.0)\n    n_wind_speeds = len(wind_speeds)\n\n    wind_rose = wind_rose_wrg.get_wind_rose_at_point(0, 0)\n\n    # Test that there are 12 wind directions at n_wind_speeds wind speeds\n    assert wind_rose.freq_table.shape == (12, n_wind_speeds)\n    assert len(wind_rose.wind_speeds) == n_wind_speeds\n    assert len(wind_rose.wind_directions) == 12\n\n    # Test that freq table generated at (0, 0) is the same at that of (-1 , -1)\n    wind_rose2 = wind_rose_wrg.get_wind_rose_at_point(-1, -1)\n    assert np.allclose(wind_rose.freq_table, wind_rose2.freq_table)\n\n    # Test that uneven spacing in wind_speeds is not allowed\n    with pytest.raises(ValueError):\n        _ = wind_rose_wrg.get_wind_rose_at_point(0, 0, wind_speeds=np.delete(wind_speeds, [2]))\n\ndef test_wind_rose_wrg_integration():\n\n    wind_rose_wrg = WindRoseWRG(WRG_FILE_FILE)\n\n    # Set a layout with two turbines\n    layout_x = np.array([0,  1000])\n    layout_y = np.array([0, 2000])\n\n    # Apply the layout\n    wind_rose_wrg.set_layout(layout_x, layout_y)\n\n    # Get a wind rose at the second turbine\n    wind_rose = wind_rose_wrg.get_wind_rose_at_point(1000, 2000)\n\n    # Also take the second wind rose from the wind_roses list\n    wind_rose2 = wind_rose_wrg.wind_roses[1]\n\n    # Show these are the same by compare the freq_table\n    assert np.allclose(wind_rose.freq_table, wind_rose2.freq_table)\n\n    # Check multidim_conditions are None\n    assert wind_rose_wrg.unpack_multidim_conditions() is None\n    assert wind_rose.unpack_multidim_conditions() is None\n\ndef test_apply_wrg_to_floris_model():\n    fmodel = FlorisModel(configuration=YAML_INPUT)\n    wind_rose_wrg = WindRoseWRG(WRG_FILE_FILE)\n    fmodel.set(wind_data=wind_rose_wrg)\n    fmodel.run()\n\ndef test_apply_wrg_to_ufloris_model():\n    ufmodel = UncertainFlorisModel(configuration=YAML_INPUT)\n    wind_rose_wrg = WindRoseWRG(WRG_FILE_FILE)\n    ufmodel.set(wind_data=wind_rose_wrg)\n    ufmodel.run()\n"
  },
  {
    "path": "tests/yaw_optimization_integration_test.py",
    "content": "import numpy as np\nimport pandas as pd\nimport pytest\n\nfrom floris import FlorisModel\nfrom floris.optimization.yaw_optimization.yaw_optimizer_sr import YawOptimizationSR\n\n\nDEBUG = False\nVELOCITY_MODEL = \"gauss\"\nDEFLECTION_MODEL = \"gauss\"\n\ndef test_yaw_optimization_limits(sample_inputs_fixture):\n    \"\"\"\n    The Serial Refine (SR) method optimizes yaw angles based on a sequential, iterative yaw\n    optimization scheme. This test compares the optimization results from the SR method for\n    a simple farm with a simple wind rose to stored baseline results.\n    \"\"\"\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"velocity_model\"] = VELOCITY_MODEL\n    sample_inputs_fixture.core[\"wake\"][\"model_strings\"][\"deflection_model\"] = DEFLECTION_MODEL\n\n    fmodel = FlorisModel(sample_inputs_fixture.core)\n    wd_array = np.arange(0.0, 360.0, 90.0)\n    ws_array = 8.0 * np.ones_like(wd_array)\n    ti_array = 0.1 * np.ones_like(wd_array)\n\n    D = 126.0 # Rotor diameter for the NREL 5 MW\n    fmodel.set(\n        layout_x=[0.0, 5 * D, 10 * D],\n        layout_y=[0.0, 0.0, 0.0],\n        wind_directions=wd_array,\n        wind_speeds=ws_array,\n        turbulence_intensities=ti_array,\n    )\n\n    # Asymmetric limits\n    yaw_opt = YawOptimizationSR(\n        fmodel,\n        minimum_yaw_angle=-10.0,\n        maximum_yaw_angle=20.0,\n    )\n    yaw_opt.optimize()\n\n    # Strictly positive limits\n    yaw_opt = YawOptimizationSR(\n        fmodel,\n        minimum_yaw_angle=5.0,\n        maximum_yaw_angle=20.0,\n    )\n    yaw_opt.optimize()\n\n    # Strictly negative limits\n    yaw_opt = YawOptimizationSR(\n        fmodel,\n        minimum_yaw_angle=-20.0,\n        maximum_yaw_angle=-5.0,\n    )\n    yaw_opt.optimize()\n\n    # Infeasible limits\n    with pytest.raises(ValueError):\n        yaw_opt = YawOptimizationSR(\n            fmodel,\n            minimum_yaw_angle=20.0,\n            maximum_yaw_angle=5.0,\n        )\n"
  }
]