Skip to content

Merge boundary forcings for quantity's that share the same bc file. - #993

Open
jeroen-deltares wants to merge 3 commits into
mainfrom
fix/978-merge-bc-file-forcings
Open

jeroen-deltares wants to merge 3 commits into
mainfrom
fix/978-merge-bc-file-forcings

Conversation

@jeroen-deltares

@jeroen-deltares jeroen-deltares commented Oct 24, 2025

Copy link
Copy Markdown
Contributor

Description

Type of change

Check relevant points.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

  • Please describe the tests that you ran to verify your changes.

  • Provide instructions so we can reproduce.

  • Please also list any relevant details for your test configuration

  • Test A

  • Test B

Checklist:

Prepare items below using:
[ ❌ ] (markdown: [ :x: ]) for TODO items
[ ✅ ] (markdown: [ :white_check_mark: ]) for DONE items
[ N/A ] for items that are not applicable for this PR.

  • updated version number in setup.py/pyproject.toml/environment.yml.
  • updated the lock file.
  • added changes to History.rst.
  • updated the latest version in README file.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • documentation are updated.

@MAfarrag
MAfarrag requested a review from Copilot November 4, 2025 09:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements boundary forcing merging to prevent data loss during boundary conversions. When multiple boundary conditions reference the same .bc file, their forcings are now consolidated into a single shared ForcingModel instead of being kept separate.

Key Changes

  • Added _merge_boundaries() method to consolidate forcings that share the same .bc filepath
  • Updated Boundary.forcingfile type annotation to support DiskOnlyFileModel in addition to ForcingModel

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
hydrolib/tools/extforce_convert/main_converter.py Implements the _merge_boundaries() method and calls it during save operations to merge forcings with identical .bc filepaths
hydrolib/core/dflowfm/ext/models.py Updates the forcingfile field type to allow DiskOnlyFileModel alongside ForcingModel in lists

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

for forcingfile in boundary.forcingfile:
bc_filepath = forcingfile.filepath
if bc_filepath in merged_boundaries:
merged_boundaries[bc_filepath].forcing.extend(forcingfile.forcing)

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direct extension of the forcing list can lead to duplicate entries if the same boundary is processed multiple times or if forcings are already present. Consider checking for duplicates before extending or using a set-based approach to ensure uniqueness of forcing entries.

Suggested change
merged_boundaries[bc_filepath].forcing.extend(forcingfile.forcing)
# Merge forcings, ensuring uniqueness and preserving order
existing_forcings = merged_boundaries[bc_filepath].forcing
new_forcings = forcingfile.forcing
seen = set()
unique_forcings = []
for f in existing_forcings + new_forcings:
if f not in seen:
unique_forcings.append(f)
seen.add(f)
merged_boundaries[bc_filepath].forcing = unique_forcings

Copilot uses AI. Check for mistakes.
Comment on lines +507 to +513
for forcingfile in boundary.forcingfile:
bc_filepath = forcingfile.filepath
if forcingfile not in forcing_list:
if bc_filepath in merged_boundaries:
forcing_list.append(merged_boundaries[bc_filepath])
else:
forcing_list.append(forcingfile)

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The identity check forcingfile not in forcing_list may not work as intended because it compares object references rather than the filepath property. If the same filepath has multiple ForcingModel instances, they won't be detected as duplicates. Consider comparing bc_filepath values instead or using a set to track already-added filepaths.

Suggested change
for forcingfile in boundary.forcingfile:
bc_filepath = forcingfile.filepath
if forcingfile not in forcing_list:
if bc_filepath in merged_boundaries:
forcing_list.append(merged_boundaries[bc_filepath])
else:
forcing_list.append(forcingfile)
seen_filepaths = set()
for forcingfile in boundary.forcingfile:
bc_filepath = forcingfile.filepath
if bc_filepath not in seen_filepaths:
if bc_filepath in merged_boundaries:
forcing_list.append(merged_boundaries[bc_filepath])
else:
forcing_list.append(forcingfile)
seen_filepaths.add(bc_filepath)

Copilot uses AI. Check for mistakes.
default_factory=lambda: DiskOnlyFileModel(None), alias="locationFile"
)
forcingfile: Union[ForcingModel, List[ForcingModel]] = Field(alias="forcingFile")
forcingfile: Union[ForcingModel, List[Union[ForcingModel, DiskOnlyFileModel]]] = (

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type signature allows ForcingModel as a single value but List[Union[ForcingModel, DiskOnlyFileModel]] as a list. This asymmetry is inconsistent - the single value case doesn't allow DiskOnlyFileModel. Consider changing to Union[ForcingModel, DiskOnlyFileModel, List[Union[ForcingModel, DiskOnlyFileModel]]] for consistency.

Suggested change
forcingfile: Union[ForcingModel, List[Union[ForcingModel, DiskOnlyFileModel]]] = (
forcingfile: Union[ForcingModel, DiskOnlyFileModel, List[Union[ForcingModel, DiskOnlyFileModel]]] = (

Copilot uses AI. Check for mistakes.
Comment on lines +496 to +498
if not isinstance(boundary.forcingfile, list):
boundary.forcingfile = [boundary.forcingfile]
for forcingfile in boundary.forcingfile:

Copilot AI Nov 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mutation of boundary.forcingfile from a single value to a list affects the original object and may have unintended side effects elsewhere in the codebase. Consider creating a local variable to hold the list representation instead of modifying the boundary object during the merge operation.

Suggested change
if not isinstance(boundary.forcingfile, list):
boundary.forcingfile = [boundary.forcingfile]
for forcingfile in boundary.forcingfile:
forcingfiles = boundary.forcingfile if isinstance(boundary.forcingfile, list) else [boundary.forcingfile]
for forcingfile in forcingfiles:

Copilot uses AI. Check for mistakes.
@sonarqubecloud

sonarqubecloud Bot commented Nov 4, 2025

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

polyline quantity is not properly moved to the new bc file

3 participants