-
Notifications
You must be signed in to change notification settings - Fork 16
[Refactor | Feature] Introducing NDSL backend #370
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
Merged
romanc
merged 51 commits into
NOAA-GFDL:develop
from
FlorianDeconinck:feature/NDSL_Backend
Mar 4, 2026
Merged
Changes from 19 commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
e8f0f7f
Introducing Backend and updating downstream NDSL code
FlorianDeconinck 706a120
Lint new files
FlorianDeconinck 24d61aa
Some docs
FlorianDeconinck 359882a
Re-order init to go around the circluar dependency (and skip isort on…
FlorianDeconinck 52d5f59
Add backend exists check
FlorianDeconinck b849948
Add Backend equal and hash operators
FlorianDeconinck ba7909b
Fix forwarding of NDSL backend into GT4Py
FlorianDeconinck 3ece5dd
Fix forwarding of NDSL backend into GT4Py
FlorianDeconinck c61cd1e
Fix forwarding of NDSL backend into GT4Py
FlorianDeconinck 18cf989
Update all tests
FlorianDeconinck d4be82b
Save Backend as string in Quantity.attrs
FlorianDeconinck 2fb0de5
Fix bad backend given to stree merge test
FlorianDeconinck ee7e872
Introduce short name shortcuts
FlorianDeconinck 942dd7f
Merge branch 'develop' into feature/NDSL_Backend
FlorianDeconinck 305e785
Lint
FlorianDeconinck e7e4481
Fix translate: Backned is already properly built
FlorianDeconinck e1cdc6e
Add concatenation operations
FlorianDeconinck e68bcfc
Deprecate inlined `is_gpu_backend` check
FlorianDeconinck 03b4c50
Documentation
FlorianDeconinck bc5590e
Rework shortcuts for Final[Backend] variable
FlorianDeconinck d0381a8
Move `is_fortran_asligned` to Backend
FlorianDeconinck 998b3f2
Remove wrong default to `| None`
FlorianDeconinck 5d83835
Simplify the G2G comms test
FlorianDeconinck 31a8586
Better checking of expected Error
FlorianDeconinck 8e5dcfe
Lint
FlorianDeconinck 09ae4fe
Properly use global backend shortcuts within API shortcuts
FlorianDeconinck b66c2bd
Lint
FlorianDeconinck 32b4372
Fix unit tests
FlorianDeconinck 5e6dbdb
Lint
FlorianDeconinck b18bc5e
Added guardrail for Boilerplate code
FlorianDeconinck dac69a6
Merge branch 'develop' into feature/NDSL_Backend
FlorianDeconinck dd8dfc8
Expose loop_order, rework python backends
FlorianDeconinck d02683e
Fix tests
FlorianDeconinck b0b695d
Fix test caches
FlorianDeconinck d3c0b17
More fix to tests
FlorianDeconinck 1837d96
PR updartes: move test in config/, made loop_order an enum
FlorianDeconinck ffa6e39
Add a `force_build` option on the `set_distributed_cache` for fortran…
FlorianDeconinck b664b32
Merge branch 'develop' into feature/NDSL_Backend
FlorianDeconinck eec242d
Lint
FlorianDeconinck d270177
[TMP CI] Shift `pyFV3` translate to update branch
FlorianDeconinck 08891fc
Space change to trigger CI
FlorianDeconinck 4cc245c
Pull on test branch for pySHiELD CI
FlorianDeconinck 5cdb599
Update `CompilationConfig` to turn backend as a string into `Backend`
FlorianDeconinck 2d940a7
Typo
FlorianDeconinck 8bf39c8
Fix tests for CompilationConfig
FlorianDeconinck 5c13eae
Fix backend save in dace_config
FlorianDeconinck 40f0a2d
Fix dace config load
FlorianDeconinck ebcb258
[TMP CI] Update Pace branch
FlorianDeconinck c321fd6
tests: simple cleanup as code review
romanc a25176b
Merge remote-tracking branch 'origin/develop' into feature/NDSL_Backend
romanc 01e8717
tmp ci: point to noop translate test in hooks
romanc 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
Some comments aren't visible on the classic Files Changed page.
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
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 |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| from .backend import Backend, BackendFramework, BackendTargetDevice | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "Backend", | ||
| "BackendFramework", | ||
| "BackendTargetDevice", | ||
| ] | ||
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,184 @@ | ||
| from __future__ import annotations | ||
|
FlorianDeconinck marked this conversation as resolved.
Outdated
|
||
|
|
||
| from enum import Enum | ||
| from typing import Any | ||
|
|
||
| import gt4py.cartesian.backend as gt_backend | ||
|
|
||
|
|
||
| class BackendStrategy(Enum): | ||
| """Strategy for the code execution""" | ||
|
|
||
| STENCIL = "st" | ||
| ORCHESTRATION = "orch" | ||
|
|
||
|
|
||
| class BackendTargetDevice(Enum): | ||
| """Target device""" | ||
|
|
||
| CPU = "cpu" | ||
| GPU = "gpu" | ||
|
|
||
|
|
||
| class BackendFramework(Enum): | ||
| """Main lower-level framework (or language) backend relies on""" | ||
|
|
||
| GRIDTOOLS = "gt" | ||
| DACE = "dace" | ||
| PYTHON = "python" | ||
|
|
||
|
|
||
| _NDSL_TO_GT4PY_BACKEND_NAMING = { | ||
| "st:python:cpu:debug": "debug", | ||
| "st:python:cpu:numpy": "numpy", | ||
| "st:gt:cpu:IJK": "gt:cpu_kfirst", | ||
| "st:gt:cpu:KJI": "gt:cpu_ifirst", | ||
| "st:gt:gpu:KJI": "gt:gpu", | ||
| "st:dace:cpu:IJK": "dace:cpu_kfirst", | ||
| "orch:dace:cpu:IJK": "dace:cpu_kfirst", | ||
| "st:dace:cpu:KIJ": "dace:cpu", | ||
| "orch:dace:cpu:KIJ": "dace:cpu", | ||
| "st:dace:cpu:KJI": "dace:cpu_KJI", | ||
| "orch:dace:cpu:KJI": "dace:cpu_KJI", | ||
| "st:dace:gpu:KJI": "dace:gpu", | ||
| "orch:dace:gpu:KJI": "dace:gpu", | ||
| } | ||
| """Internal: match the NDSL backend names with the GT4Py names""" | ||
|
|
||
| _NDSL_SHORT_TO_LONG_NAME = { | ||
| "numpy": "st:python:cpu:numpy", | ||
| "debug": "st:python:cpu:debug", | ||
| "performance_cpu": "orch:dace:cpu:IJK", | ||
| "hybrid_fortran_cpu": "orch:dace:cpu:KJI", | ||
| "performance_gpu": "orch:dace:gpu:KJI", | ||
| } | ||
| """Internal: match short name to long name form""" | ||
|
|
||
|
|
||
| class Backend: | ||
| """Backend for NDSL. | ||
|
|
||
| The backend is a string concatenating information on the intent of the user | ||
| for a given execution seperated by a ':'. | ||
|
FlorianDeconinck marked this conversation as resolved.
Outdated
|
||
|
|
||
| It describes to NDSL the strategy, device and framwork to be used | ||
| on the frontend code. Additionaly, it gives a hint toward the macro-strategy | ||
|
FlorianDeconinck marked this conversation as resolved.
Outdated
|
||
| for loop ordering (IJK, KJI, etc.) or a more broad intent (debug, numpy). | ||
|
|
||
| For convenience, shorcuts are given to the most common needs (see internal | ||
| `_NDSL_SHORT_TO_LONG_NAME`). | ||
|
FlorianDeconinck marked this conversation as resolved.
Outdated
|
||
| """ | ||
|
|
||
| def __init__(self, ndsl_backend: str) -> None: | ||
| # Swap short form to long form | ||
| if ndsl_backend in _NDSL_SHORT_TO_LONG_NAME.keys(): | ||
| ndsl_backend = _NDSL_SHORT_TO_LONG_NAME[ndsl_backend] | ||
|
|
||
| # Checks for existence and form | ||
| if ndsl_backend not in _NDSL_TO_GT4PY_BACKEND_NAMING.keys(): | ||
|
FlorianDeconinck marked this conversation as resolved.
Outdated
|
||
| raise ValueError( | ||
| f"Unknown {ndsl_backend}, options are {list(_NDSL_TO_GT4PY_BACKEND_NAMING.keys())}" | ||
| ) | ||
| parts = ndsl_backend.split(":") | ||
| if len(parts) != 4: | ||
| raise ValueError(f"Backend {ndsl_backend} is ill-formed.") | ||
|
romanc marked this conversation as resolved.
|
||
|
|
||
| # Breakdown and save into internal parameters | ||
| self._humanly_readable = ndsl_backend | ||
| self._strategy = BackendStrategy(parts[0].lower()) | ||
| self._framework = BackendFramework(parts[1].lower()) | ||
| self._device = BackendTargetDevice(parts[2].lower()) | ||
| self._loop_order = parts[3] | ||
|
FlorianDeconinck marked this conversation as resolved.
Outdated
FlorianDeconinck marked this conversation as resolved.
Outdated
|
||
|
|
||
| # Check GPU capacity | ||
| if ( | ||
| self._device == BackendTargetDevice.GPU | ||
| and gt_backend.from_name(self.as_gt4py()).storage_info["device"] != "gpu" | ||
| ): | ||
| raise ValueError( | ||
| f"Coding error: NDSL backend requested {self._humanly_readable} " | ||
| f"translate to non-GPU {self.as_gt4py()} GT4Py backend" | ||
|
FlorianDeconinck marked this conversation as resolved.
Outdated
|
||
| ) | ||
|
|
||
| def __str__(self) -> str: | ||
| return self.as_humanly_readable() | ||
|
|
||
| def __repr__(self) -> str: | ||
| return self.as_humanly_readable() | ||
|
|
||
| def __eq__(self, other: object) -> bool: | ||
| return self._humanly_readable == self._humanly_readable | ||
|
romanc marked this conversation as resolved.
Outdated
|
||
|
|
||
| def __hash__(self) -> int: | ||
| return hash(self._humanly_readable) | ||
|
|
||
| def __add__(self, other: str) -> Any: | ||
| """Concatenation operators""" | ||
| if isinstance(other, Backend): | ||
| raise TypeError("OperationError: Backend cannot add to another Backend") | ||
| return str(self) + other | ||
|
|
||
| def __radd__(self, other: str) -> Any: | ||
| """Concatenation operators""" | ||
| if isinstance(other, Backend): | ||
| raise TypeError("OperationError: Backend cannot add to another Backend") | ||
| return other + str(self) | ||
|
|
||
| @staticmethod | ||
| def debug() -> Backend: | ||
| return Backend("debug") | ||
|
|
||
| @staticmethod | ||
| def python() -> Backend: | ||
| return Backend("numpy") | ||
|
|
||
| @staticmethod | ||
| def performance_cpu() -> Backend: | ||
| return Backend("performance_cpu") | ||
|
|
||
| @staticmethod | ||
| def hybrid_fortran_cpu() -> Backend: | ||
| return Backend("hybrid_fortran_cpu") | ||
|
|
||
| @staticmethod | ||
| def performance_gpu() -> Backend: | ||
| return Backend("performance_gpu") | ||
|
|
||
| @property | ||
| def device(self) -> BackendTargetDevice: | ||
| return self._device | ||
|
|
||
| @property | ||
| def framework(self) -> BackendFramework: | ||
| return self._framework | ||
|
|
||
|
FlorianDeconinck marked this conversation as resolved.
|
||
| def as_gt4py(self) -> str: | ||
| """Given a NDSL backend, give back a GT4Py equivalent""" | ||
| if self._humanly_readable in _NDSL_TO_GT4PY_BACKEND_NAMING.keys(): | ||
| return _NDSL_TO_GT4PY_BACKEND_NAMING[self._humanly_readable] | ||
| raise ValueError( | ||
| f"Backend {self._humanly_readable} cannot be translate to GT4Py" | ||
| ) | ||
|
FlorianDeconinck marked this conversation as resolved.
Outdated
|
||
|
|
||
| def as_humanly_readable(self) -> str: | ||
| return self._humanly_readable | ||
|
|
||
| def as_safe_for_path(self) -> str: | ||
| return self._humanly_readable.replace(":", "_") | ||
|
|
||
|
FlorianDeconinck marked this conversation as resolved.
|
||
| def is_orchestrated(self) -> bool: | ||
| return self._strategy == BackendStrategy.ORCHESTRATION | ||
|
|
||
| def is_stencil(self) -> bool: | ||
| return self._strategy == BackendStrategy.STENCIL | ||
|
|
||
| def is_gpu_backend(self) -> bool: | ||
| return self._device == BackendTargetDevice.GPU | ||
|
|
||
|
|
||
| # Those two internal values are used for default parameters values in functions/methods | ||
| # as it is bad practice to call a function in default argument value | ||
| _BACKEND_PERFORMANCE_CPU = Backend.performance_cpu() | ||
| """Internal: cache performance CPU. Please use Backend.performance_cpu().""" | ||
| _BACKEND_PYTHON = Backend.python() | ||
| """Internal: cache performance CPU. Please use Backend.python().""" | ||
|
FlorianDeconinck marked this conversation as resolved.
Outdated
|
||
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
Oops, something went wrong.
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.