Skip to content

Commit

Permalink
merge base branch
Browse files Browse the repository at this point in the history
  • Loading branch information
MAfarrag committed Feb 5, 2025
2 parents 0d389c4 + 7b1d908 commit 3fcadf4
Show file tree
Hide file tree
Showing 35 changed files with 812 additions and 450 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.11", "3.12"]
python-version: ["3.9", "3.11", "3.12", "3.13"]
os: [ubuntu-latest, windows-latest, macos-13]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -23,7 +23,7 @@ jobs:
- name: Run image
uses: abatilo/[email protected]
with:
poetry-version: 1.8.3
poetry-version: 1.8.4
- name: Cache Poetry virtualenv
uses: actions/cache@v4
id: cache
Expand All @@ -49,7 +49,7 @@ jobs:
run: poetry run pytest --cov . --cov-report xml:coverage-reports/coverage-hydrolib-core.xml --junitxml=xunit-reports/xunit-result-hydrolib-core.xml

- name: Autoformat code if the check fails
if: ${{ (matrix.os == 'ubuntu-latest') && (matrix.python-version == 3.12) }}
if: ${{ (matrix.os == 'ubuntu-latest') && (matrix.python-version == 3.13) }}
run: |
poetry run isort .
poetry run black .
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ jobs:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: 3.12
python-version: 3.13

- name: Run image
uses: abatilo/[email protected]
with:
poetry-version: 1.8.3
poetry-version: 1.8.4
- name: Cache Poetry virtualenv
uses: actions/cache@v4
id: cache
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/docs_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ jobs:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: 3.12
python-version: 3.13

- name: Run image
uses: abatilo/[email protected]
with:
poetry-version: 1.8.3
poetry-version: 1.8.4
- name: Cache Poetry virtualenv
uses: actions/cache@v4
id: cache
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.12]
python-version: [3.13]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -29,7 +29,7 @@ jobs:
- name: Run image
uses: abatilo/[email protected]
with:
poetry-version: 1.8.3
poetry-version: 1.8.4

- name: Cache Poetry virtualenv
uses: actions/cache@v4
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ jobs:
- name: Set up python
uses: actions/setup-python@v5
with:
python-version: 3.12
python-version: 3.13

- name: Run image
uses: abatilo/[email protected]
with:
poetry-version: 1.8.3
poetry-version: 1.8.4

- name: Cache Poetry virtualenv
uses: actions/cache@v4
Expand Down
11 changes: 11 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 0.8.1 (2025-02-04)

### Feat

- Support Fortran scientific notation in .tim files (e.g., 1d0) (#720)
- Corrected comment for layerType (#697)

### Fix

- failing docs (#728)

## 0.8.0 (2024-07-09)

### Feat
Expand Down
21 changes: 5 additions & 16 deletions docs/guides/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,38 +62,27 @@ To prepare for releasing, please make sure you have a clean checkout of the late
* Go to the root level your hydrolib-core checkout location
* Open your command line in this location
* Perform the following commands:
* If commitizen is not installed yet:
* Ensure that you are using the poetry environment (this contains commitizen), optionally run this command in a fresh environment:
```
pip install commitizen
poetry install
```
* Prepare the Changelog before bumping the release version:
* Update the Changelog before bumping the release version (use the version tag instead of the raw version number (so without "v" in our case)):
```
cz changelog --unreleased-version="0.3.1" --incremental
```
In the above command, use the version tag instead of the raw version number (so without "v" in our case).
If you don't know the version tag yet, you can do a dry-run of the next step, for example via:
```
cz bump --dry-run --increment PATCH
```
* In the updated `docs/changelog.md`, manually add links to GitHub PR numbers (or issue numbers) at the end of each line, if appropriate.
It is recommended to use the macros `{{gh_pr(123)}}`, resp. `{{gh_issue(345)}}` to get automatic hyperlinks (where 123 and 345 are GitHub's PR and issue numbers, respectively).
* Use MAJOR, MINOR or PATCH to increment the version
```
cz bump --increment {MAJOR,MINOR,PATCH}
```
* Or let commitizen detect the increment automatically
```
cz bump
```
* Push the tags and changes to git
```
git push --tags
git push
```
* Build the wheels and publish the package to PyPi
* Build the wheels and publish the package to PyPi (get an API token in your PyPI account)
```
poetry build
poetry publish
poetry publish --username __token__ --password [PYPI_API_TOKEN]
```
You will need a PyPI account and permissions for this publish step. Ask a maintainer for help if you need this.
* Go to the hydrolib-core GitHub page.
Expand Down
2 changes: 1 addition & 1 deletion hydrolib/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.8.0"
__version__ = "0.8.1"
8 changes: 1 addition & 7 deletions hydrolib/core/dflowfm/bc/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ class ForcingModel(INIModel):
The `ForcingModel` class is the top-level model that aggregates metadata
and multiple `[Forcing]` blocks. It provides functionality for parsing,
serializing, and managing data within a boundary conditions (.bc) file.
serializing, and managing data within a .bc file.
Attributes:
general (ForcingGeneral):
Expand All @@ -969,12 +969,6 @@ class ForcingModel(INIModel):
serializer_config (DataBlockINIBasedSerializerConfig, optional):
Serialization settings. Default to a predefined configuration.
Returns:
None
Raises:
ValueError: If invalid data is provided during initialization or parsing.
See Also:
ForcingBase: Represents individual forcing blocks within the file.
ForcingGeneral: Metadata model for the `[General]` section.
Expand Down
3 changes: 2 additions & 1 deletion hydrolib/core/dflowfm/ext/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from .models import Boundary, ExtGeneral, ExtModel, Lateral, Meteo
from .models import Boundary, ExtGeneral, ExtModel, Lateral, Meteo, SourceSink

__all__ = [
"Boundary",
"Lateral",
"Meteo",
"ExtGeneral",
"ExtModel",
"SourceSink",
]
14 changes: 8 additions & 6 deletions hydrolib/core/dflowfm/ext/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Boundary(INIBasedModel):
locationfile: DiskOnlyFileModel = Field(
default_factory=lambda: DiskOnlyFileModel(None), alias="locationFile"
)
forcingfile: ForcingModel = Field(alias="forcingFile")
forcingfile: Union[ForcingModel, List[ForcingModel]] = Field(alias="forcingFile")
bndwidth1d: Optional[float] = Field(alias="bndWidth1D")
bndbldepth: Optional[float] = Field(alias="bndBlDepth")

Expand Down Expand Up @@ -212,7 +212,9 @@ class SourceSink(INIBasedModel):
zsink: Optional[Union[float, List[float]]] = Field(alias="zSink")
area: Optional[float] = Field(alias="Area")

bc_forcing: ForcingModel = Field(alias="bcForcing")
discharge: ForcingData = Field(alias="discharge")
salinitydelta: Optional[ForcingData] = Field(alias="salinityDelta")
temperaturedelta: Optional[ForcingData] = Field(alias="temperatureDelta")

@classmethod
def _exclude_from_validation(cls, input_data: Optional[dict] = None) -> Set:
Expand Down Expand Up @@ -380,7 +382,7 @@ def is_intermediate_link(self) -> bool:


class ExtGeneral(INIGeneral):
"""The external forcing file's `[General]` section with file meta data."""
"""The external forcing file's `[General]` section with file meta-data."""

_header: Literal["General"] = "General"
fileversion: str = Field("2.01", alias="fileVersion")
Expand All @@ -397,19 +399,19 @@ class ExtModel(INIModel):
general (ExtGeneral): `[General]` block with file metadata.
boundary (List[Boundary]): List of `[Boundary]` blocks for all boundary conditions.
lateral (List[Lateral]): List of `[Lateral]` blocks for all lateral discharges.
source_sink (List[SourceSink]): List of `[SourceSink]` blocks for all source/sink terms.
sourcesink (List[SourceSink]): List of `[SourceSink]` blocks for all source/sink terms.
meteo (List[Meteo]): List of `[Meteo]` blocks for all meteorological forcings.
"""

general: ExtGeneral = ExtGeneral()
boundary: List[Boundary] = Field(default_factory=list)
lateral: List[Lateral] = Field(default_factory=list)
source_sink: List[SourceSink] = Field(default_factory=list)
sourcesink: List[SourceSink] = Field(default_factory=list)
meteo: List[Meteo] = Field(default_factory=list)
serializer_config: INISerializerConfig = INISerializerConfig(
section_indent=0, property_indent=0
)
_split_to_list = make_list_validator("boundary", "lateral", "meteo")
_split_to_list = make_list_validator("boundary", "lateral", "meteo", "sourcesink")

@classmethod
def _ext(cls) -> str:
Expand Down
4 changes: 2 additions & 2 deletions hydrolib/core/dflowfm/ini/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,12 @@ def validate(cls: Type["INIBasedModel"], value: Any) -> "INIBasedModel":
return super().validate(value)

@classmethod
def _exclude_from_validation(cls, input_data: Optional = None) -> Set:
def _exclude_from_validation(cls, input_data: Optional[dict] = None) -> Set:
"""
Fields that should not be checked when validating existing fields as they will be dynamically added.
Args:
input_data (Optional): Input data to process.
input_data (Optional[dict]): Input data to process.
Returns:
Set: Set of field names to exclude from validation.
Expand Down
31 changes: 26 additions & 5 deletions hydrolib/core/dflowfm/tim/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from hydrolib.core.basemodel import BaseModel, ModelSaveSettings, ParsableFileModel
from hydrolib.core.dflowfm.tim.parser import TimParser
from hydrolib.core.dflowfm.tim.serializer import TimSerializer, TimSerializerConfig
from hydrolib.core.utils import FortranUtils


class TimRecord(BaseModel):
Expand Down Expand Up @@ -176,6 +177,26 @@ def _get_serializer(
def _get_parser(cls) -> Callable[[Path], Dict]:
return TimParser.parse

@validator("timeseries", pre=True, check_fields=True, allow_reuse=True)
def replace_fortran_scientific_notation_for_floats(cls, value, field):
for record in value:
if isinstance(record, dict):
record["time"] = FortranUtils.replace_fortran_scientific_notation(
record["time"]
)
record["data"] = FortranUtils.replace_fortran_scientific_notation(
record["data"]
)
elif isinstance(record, TimRecord):
record.time = FortranUtils.replace_fortran_scientific_notation(
record.time
)
record.data = FortranUtils.replace_fortran_scientific_notation(
record.data
)

return value

@validator("timeseries")
@classmethod
def _validate_timeseries_values(cls, v: List[TimRecord]) -> List[TimRecord]:
Expand Down Expand Up @@ -367,7 +388,7 @@ def get_units(self):
>>> tim_model = TimModel(filepath="tests/data/input/source-sink/tim-5-columns.tim")
>>> tim_model.quantities_names = ["discharge", "waterlevel", "temperature", "salinity", "initialtracer"]
>>> print(tim_model.get_units())
['m3/s', 'm', 'C', 'ppt', '-']
['m3/s', 'm', 'degC', '1e-3', '-']
```
"""
Expand All @@ -390,14 +411,14 @@ def map_to_units(quantities_names: List[str]) -> List[str]:
>>> from hydrolib.core.dflowfm.tim.models import TimModel
>>> quantities_names = ["discharge", "waterlevel", "salinity", "temperature"]
>>> TimModel.map_to_units(quantities_names)
['m3/s', 'm', 'ppt', 'C']
['m3/s', 'm', '1e-3', 'degC']
"""
# Define the mapping of keywords to units
unit_mapping = {
"discharge": "m3/s",
"waterlevel": "m",
"salinity": "ppt",
"temperature": "C",
"salinity": "1e-3",
"temperature": "degC",
}

# Generate the list of units based on the mapping
Expand All @@ -408,7 +429,7 @@ def map_to_units(quantities_names: List[str]) -> List[str]:
units.append(unit)
break
else:
# Append "Unknown" if no keywords match
# Append "-" if no keywords match
units.append("-")

return units
22 changes: 22 additions & 0 deletions hydrolib/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from pathlib import Path
from typing import Any, Callable, List, Optional

from pydantic import validator
from pydantic.v1.fields import ModelField
from strenum import StrEnum


Expand Down Expand Up @@ -332,3 +334,23 @@ def _calculate_md5_checksum(filepath: Path) -> str:
for chunk in iter(lambda: file.read(4096), b""):
md5_hash.update(chunk)
return md5_hash.hexdigest()


class FortranUtils:
"""Utility class for Fortran specific conventions."""

_scientific_exp_d_notation_regex = re.compile(
r"([\d.]+)([dD])([+-]?\d{1,3})"
) # matches a float: 1d9, 1D-3, 1.D+4, etc.

@staticmethod
def replace_fortran_scientific_notation(value):
"""Replace Fortran scientific notation ("D" in exponent) with standard
scientific notation ("e" in exponent).
"""
if isinstance(value, str):
return FortranUtils._scientific_exp_d_notation_regex.sub(r"\1e\3", value)
elif isinstance(value, list):
return list(map(FortranUtils.replace_fortran_scientific_notation, value))

return value
Loading

0 comments on commit 3fcadf4

Please sign in to comment.