-
Notifications
You must be signed in to change notification settings - Fork 11
FLOWFarm.jl Integration #182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
BTV25
wants to merge
15
commits into
NLRWindSystems:develop
Choose a base branch
from
BTV25:features/FLOWFarm
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
0279c24
add FLOWFarm to aero models
BTV25 da1c293
Added FLOWFarm integration tests. Added notes about flowfarm multithr…
BTV25 35ca39d
test update
BTV25 a6f02f8
correct tests
BTV25 524c0e5
format fixes
BTV25 ddf9908
version conflict fixed
BTV25 9306e87
repush
BTV25 608da85
update tests
BTV25 e9c91f2
test update
BTV25 6b823e7
correct, tests
BTV25 c9b0801
test updates
BTV25 4fc7b09
cleanup
BTV25 975d767
more cleanup
BTV25 8a5457e
Merge branch 'develop' into features/FLOWFarm
BTV25 f1e9363
test update
BTV25 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| name: FLOWFarm integration tests (Julia) | ||
|
|
||
| on: | ||
| push: | ||
| paths: | ||
| - "ard/farm_aero/flowfarm/**" | ||
| - "test/flowfarm/**" | ||
| pull_request: | ||
| paths: | ||
| - "ard/farm_aero/flowfarm/**" | ||
| - "test/flowfarm/**" | ||
| workflow_dispatch: # allow manual runs from the Actions UI | ||
|
|
||
| jobs: | ||
|
|
||
| test-julia: | ||
| name: Run FLOWFarm integration tests | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Python 3.12 | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.12" | ||
|
|
||
| - name: Set up Julia | ||
| uses: julia-actions/setup-julia@v2 | ||
| with: | ||
| version: "1.10" | ||
|
|
||
| - name: Cache Julia packages | ||
| uses: julia-actions/cache@v2 | ||
|
|
||
| - name: Install Ard with FLOWFarm extras | ||
| run: pip install ".[dev,flowfarm]" | ||
|
|
||
| - name: Pre-instantiate Julia environment | ||
| run: | | ||
| julia -e "using Pkg; Pkg.Registry.add(\"General\"); Pkg.Registry.update()" | ||
| julia --project=ard/farm_aero/flowfarm/julia_env -e "using Pkg; Pkg.instantiate(); Pkg.precompile()" | ||
|
|
||
| - name: Run FLOWFarm integration tests | ||
| run: | | ||
| pytest -m julia test/flowfarm/integration \ | ||
| --cov=ard \ | ||
| --cov-report=term-missing \ | ||
| -v |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| from . import floris | ||
| from . import flowfarm | ||
| from . import placeholder | ||
| from . import templates |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| # FLOWFarm Integration in Ard | ||
|
|
||
| This folder contains Ard's Python-Julia integration utilities for FLOWFarm. | ||
|
|
||
| ## Julia setup (required before first use) | ||
|
|
||
| FLOWFarm runs inside Julia via [JuliaCall](https://juliapy.github.io/PythonCall.jl/stable/). You need Julia installed before running any FLOWFarm components. Users who do not use FLOWFarm do not need Julia at all — it is loaded lazily only when a FLOWFarm component is initialized. | ||
|
|
||
| ### 1. Create a conda environment with Python + juliaup (recommended) | ||
|
|
||
| ```bash | ||
| conda create --name ard-FLOWFarm python=3.13 juliaup | ||
| conda activate ard-FLOWFarm | ||
| ``` | ||
|
|
||
| Set both Julia depots to a path inside the active conda env: | ||
|
|
||
| ```bash | ||
| conda env config vars set JULIA_DEPOT_PATH=${CONDA_PREFIX}/.julia | ||
| conda env config vars set JULIAUP_DEPOT_PATH=${CONDA_PREFIX}/.julia | ||
| conda deactivate | ||
| conda activate ard-FLOWFarm | ||
| ``` | ||
|
|
||
| Install Julia (1.x) using juliaup from that environment: | ||
|
|
||
| ```bash | ||
| juliaup add release | ||
| juliaup default release | ||
| julia --version | ||
| ``` | ||
|
|
||
| Then install Ard (including FLOWFarm dependencies): | ||
|
|
||
| ```bash | ||
| pip install -e ".[dev,flowfarm]" | ||
| ``` | ||
|
|
||
| ### 2. Pre-generate the Julia environment (optional) | ||
|
|
||
| On first use Ard will resolve and instantiate the Julia environment automatically. If you prefer to do this ahead of time — for example on an HPC cluster node without internet access at runtime — run once from your terminal: | ||
|
|
||
| ```bash | ||
| julia --project="<path-to-ard>/ard/farm_aero/flowfarm/julia_env" -e "using Pkg; Pkg.resolve(); Pkg.instantiate()" | ||
| ``` | ||
|
|
||
| Replace `<path-to-ard>` with the absolute path to the `Ard` directory. This downloads FLOWFarm and its dependencies. It may take several minutes on first run. | ||
|
|
||
| ## What this integration does | ||
|
|
||
| - Boots Julia through JuliaCall. | ||
| - Activates Ard's local Julia environment (`julia_env`). | ||
| - Loads FLOWFarm and builds farm and sparse structs for Ard components. | ||
| - Exposes helper functions used by the component wrapper in `ard/farm_aero/flowfarm/component.py`. | ||
|
|
||
| ## Threading and parallelism | ||
|
|
||
| ### OpenMDAO does not multithread | ||
|
|
||
| OpenMDAO is single-threaded by design. Its solver loops (Newton, Gauss-Seidel, NLBGS, etc.) are serial. The only parallelism OpenMDAO exposes is MPI-based **process** parallelism via `ParallelGroup`, which spawns separate processes — not threads. This means OpenMDAO will never call the FLOWFarm component from multiple threads simultaneously, so there is no concurrency risk from the OpenMDAO layer. | ||
|
|
||
| ### Julia internal threading (FLOWFarm parallelism) | ||
|
|
||
| Threading in this integration refers to Julia's own thread pool, which FLOWFarm can use internally to parallelize wake calculations across turbines. This is separate from and independent of OpenMDAO. | ||
|
|
||
| Julia's thread count is fixed at startup and cannot be changed at runtime. Configure it **before** importing Ard or JuliaCall: | ||
|
|
||
| ```python | ||
| import os | ||
| os.environ["PYTHON_JULIACALL_THREADS"] = "4" # or "auto" to use all cores | ||
| os.environ["PYTHON_JULIACALL_HANDLE_SIGNALS"] = "yes" | ||
| ``` | ||
|
|
||
| For threaded runs on shared-memory machines, also consider limiting BLAS and OpenMP thread pools to avoid nested oversubscription (Julia threads × BLAS threads × cores): | ||
|
|
||
| ```python | ||
| os.environ["OPENBLAS_NUM_THREADS"] = "1" | ||
| os.environ["OMP_NUM_THREADS"] = "1" | ||
| ``` | ||
|
|
||
| These must be set before the first `import ard` call in your script or notebook. | ||
|
|
||
| ### Why a pure Julia callback | ||
|
|
||
| The FLOWFarm update callback in Ard is implemented entirely in Julia (not as a Python callable passed into Julia). This is required for thread safety: JuliaCall does not support calling back into Python from Julia threads other than the main thread. Using a pure Julia callback avoids this restriction and allows FLOWFarm to use all available Julia threads. | ||
|
|
||
| ## Tolerance behavior | ||
|
|
||
| - FLOWFarm sparse-structure tolerance uses `modeling_options.flowfarm.tolerance`. | ||
| - If not provided, the default is `1e-16`. | ||
|
|
||
| Example: | ||
|
|
||
| ```yaml | ||
| modeling_options: | ||
| flowfarm: | ||
| tolerance: 1.0e-16 | ||
| ``` | ||
|
|
||
| ## Supported FLOWFarm names | ||
|
|
||
| Use the exact FLOWFarm constructor and model names expected by the integration. | ||
|
|
||
| ### Turbine model constructors | ||
|
|
||
| - `PowerModelCpPoints` | ||
| - `PowerModelConstantCp` | ||
| - `ThrustModelCtPoints` | ||
| - `ThrustModelConstantCt` | ||
|
|
||
| ### Wake model options | ||
|
|
||
| - `wake_deficit_model`: `JensenTopHat`, `JensenCosine`, `MultiZone`, `GaussOriginal`, `GaussYaw`, `GaussYawVariableSpread`, `GaussSimple`, `CumulativeCurl`, `NoWakeDeficit` | ||
| - `wake_deflection_model`: `NoYawDeflection`, `GaussYawDeflection`, `GaussYawVariableSpreadDeflection`, `JiminezYawDeflection`, `MultizoneDeflection` | ||
| - `wake_combination_model`: `LinearFreestreamSuperposition`, `SumOfSquaresFreestreamSuperposition`, `SumOfSquaresLocalVelocitySuperposition`, `LinearLocalVelocitySuperposition` | ||
| - `local_turbulence_model`: `LocalTIModelNoLocalTI`, `LocalTIModelMaxTI`, `LocalTIModelGaussTI` | ||
|
|
||
| ## Key files | ||
|
|
||
| - `_jl_bootstrap.py`: Julia runtime bootstrap and env activation helpers. | ||
| - `flowfarm_model.py`: FLOWFarm model-construction utilities and option validation. | ||
| - `component.py`: OpenMDAO component wrapper that uses this integration. | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Julia manifest warnings on first run | ||
|
|
||
| If you see warnings like "manifest resolved with a different julia version" or "project dependencies have changed since the manifest was last resolved", it means the local `Manifest.toml` is missing or stale. Ard will attempt to rebuild it automatically. If it does not, run: | ||
|
|
||
| ```bash | ||
| julia --project="<path-to-ard>/ard/farm_aero/flowfarm/julia_env" -e "using Pkg; Pkg.resolve(); Pkg.instantiate()" | ||
| ``` | ||
|
|
||
| Then restart your Jupyter kernel. The `Manifest.toml` is not committed to the repository — it is always generated locally for your Julia version. | ||
|
|
||
|
|
||
| This comes from your **global** Julia environment, not Ard's. JuliaCall triggers the IPython/Jupyter juliacall extension on import. | ||
|
|
||
| ### Wrong Julia version being used | ||
|
|
||
| If Julia 1.11+ is picked up instead of 1.10, check your `PATH`. `juliaup default 1.10` sets the default for commands run via juliaup, but if `/opt/homebrew/bin/julia` or another system Julia takes precedence in your shell, JuliaCall may use that instead. | ||
|
|
||
| ### Kernel/process crash when threads > 1 | ||
|
|
||
| - Ensure pure Julia callback path is active (current Ard default). | ||
| - Ensure thread env vars are set before importing Ard. | ||
| - Start with `PYTHON_JULIACALL_THREADS=1`, then increase. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| from .component import FLOWFarmAEP, FLOWFarmBatchPower, FLOWFarmComponent | ||
| from ._jl_bootstrap import ensure_flowfarm_loaded, get_julia_runtime | ||
|
|
||
| __all__ = [ | ||
| "FLOWFarmAEP", | ||
| "FLOWFarmBatchPower", | ||
| "FLOWFarmComponent", | ||
| "ensure_flowfarm_loaded", | ||
| "get_julia_runtime", | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # ard/farm_aero/flowfarm/_jl_bootstrap.py | ||
| from __future__ import annotations | ||
| import pathlib | ||
|
|
||
| _jl_runtime = None | ||
| _flowfarm_env_initialized = False | ||
|
|
||
|
|
||
| def get_julia_runtime(): | ||
| """Return (Main, Pkg) from JuliaCall with Ard-safe bootstrap behavior.""" | ||
| global _jl_runtime | ||
| if _jl_runtime is not None: | ||
| return _jl_runtime | ||
|
|
||
| from juliacall import Main as jl_main | ||
| from juliacall import Pkg as jl_pkg | ||
|
|
||
| _jl_runtime = (jl_main, jl_pkg) | ||
| return _jl_runtime | ||
|
|
||
|
|
||
| def ensure_flowfarm_loaded(): | ||
| """Activate Ard Julia env and load FLOWFarm in Julia Main.""" | ||
| global _flowfarm_env_initialized | ||
| jl_main, jl_pkg = get_julia_runtime() | ||
| if not _flowfarm_env_initialized: | ||
| env_dir = pathlib.Path(__file__).parent / "julia_env" | ||
| jl_pkg.activate(str(env_dir)) | ||
| jl_pkg.instantiate() | ||
| _flowfarm_env_initialized = True | ||
|
|
||
| if "FLOWFarm" not in dir(jl_main): | ||
| jl_main.seval("using FLOWFarm") | ||
| return jl_main |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.