Skip to content
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

Modflow-MetaSWAP coupler mappings should use grid-agnostic wells or well adapter #728

Closed
JoerivanEngelen opened this issue Jan 8, 2024 · 4 comments
Assignees

Comments

@JoerivanEngelen
Copy link
Contributor

JoerivanEngelen commented Jan 8, 2024

The msw.CouplerMapping , msw.Sprinkling, and couplers.MetaMod (in primod) currently use the deprecated mf6.WellDisStructured object. We should start supporting the new architecture.

This will also require updates to:

We might be able to use the Mf6Well adapter directly here:

  • Less work to update existing _render method
  • No mf6 data needs to be provided to render method. With grid agnostic packages, this would be (idomain, bottom, top, k)
  • However, this makes it harder to clip and regrid this package object this would require the regrid_like to update the indices

The alternative is providing the grid agnostic Well package:

  • Easy to clip & regrid
  • This requires extra information to the _render method, all contained in the GroundwaterFlowModel object.

The third option is creating a GridWell package: A grid of well rates, comparable to other boundary conditions.

  • Behaves similair to other packages
  • Quite a change in public API: Would users like this?

Also: Since MODFLOW6 models have an idomain correction after regridding (some NPF cells may become inactive at edges, where idomain cells were not inactive), we always have to regrid the GroundwaterFlowModel first, before regridding MetaSWAP model.

@JoerivanEngelen
Copy link
Contributor Author

Refinement

  • CouplerMapping takes a StructuredDiscretization object. It has to be initialized again each time the Modflow model is clipped, regridded, or masked. So for this object using an Mf6Well object is sufficient.
  • Sprinkling is more complicated, crude sketch:
if type(well) == GridAgnosticWell
    sprink = Sprinkling(well)
    sprink.regrid_like(new_idomain)

    gwf_regridded = gwf_model.regrid_like(new_idomain)
    idomain_regridded = gwf_regridded["dis"]["idomain"]
    top_regridded = gwf_regridded["dis"]["top"]
    bottom_regridded = gwf_regridded["dis"]["bottom"]
    k_regridded = gwf_regridded["npf"]["k"]

    sprink._render(file, index, svat, idomain_regridded, top_regridded, bottom_regridded, k_regridded)
    # In _render, self.well.to_mf6_pkg is called

elif type(well) == Mf6Wel
    mf6_wel = well.to_mf6_pkg(idomain, top, bottom, k)
    sprink = Sprinkling(mf6_wel)

    gwf_regridded = gwf_model.regrid_like(new_idomain)
    idomain_regridded = gwf_regridded["dis"]["idomain"]
    top_regridded = gwf_regridded["dis"]["top"]
    bottom_regridded = gwf_regridded["dis"]["bottom"]
    k_regridded = gwf_regridded["npf"]["k"]
    mf6_wel_regrid = well.to_mf6_pkg(idomain_regridded, top_regridded, bottom_regridded, k_regridded)
    sprink.regrid_like(new_idomain)
    sprink.update_wel(mf6_wel_regrid)

    sprink._render(file, index, svat)

@JoerivanEngelen
Copy link
Contributor Author

JoerivanEngelen commented Aug 15, 2024

For this specific issue, running coupled simulations is not a hard requirement, as the rendered textfiles need to remain the same. However, for the future solving #1154 would be useful

@JoerivanEngelen JoerivanEngelen moved this from 🤝 Accepted to 📝Refined in iMOD Suite Oct 23, 2024
@JoerivanEngelen JoerivanEngelen self-assigned this Oct 23, 2024
JoerivanEngelen added a commit that referenced this issue Oct 23, 2024
# Description
This PR adds experimental MetaSWAP regridding. It doesn't work yet for
the sprinkling package, because this requires #728.
Mostly developed by @luitjansl , so all credits go to him for this
functionality.

# Checklist

- [ ] Links to correct issue
- [x] Update changelog, if changes affect users
- [ ] PR title starts with ``Issue #nr``, e.g. ``Issue #737``
- [x] Unit tests were added
- [ ] **If feature added**: Added/extended example

---------

Co-authored-by: luitjansl <[email protected]>
Co-authored-by: luitjan <[email protected]>
@JoerivanEngelen
Copy link
Contributor Author

JoerivanEngelen commented Oct 24, 2024

Doing some more thinking on this: It is probably better to refactor the MetaSWAP code base in such a way, that the MODFLOW objects are only necessary upon writing, instead of already upon initialization. For example for the Sprinkling package:

Current state:

class Sprinkling:
    def __init__(
        self,
        max_abstraction_groundwater: xr.DataArray,
        max_abstraction_surfacewater: xr.DataArray,
        modflow_wel: WellDisStructured
     ):
        self.well = modflow_wel
...

    def write(
        self,
        directory: Union[str, Path],
        index: np.ndarray,
        svat: xr.DataArray,
    ):
...

Initial idea:

class Sprinkling:
    def __init__(
        self,
        max_abstraction_groundwater: xr.DataArray,
        max_abstraction_surfacewater: xr.DataArray,
        modflow_wel: Well
     ):
        self.well = modflow_wel
...

    def write(
        self,
        directory: Union[str, Path],
        index: np.ndarray,
        svat: xr.DataArray,
    ):
...

Proposed:

class Sprinkling:
    def __init__(
        self,
        max_abstraction_groundwater: xr.DataArray,
        max_abstraction_surfacewater: xr.DataArray,
        mf6_wellname: str,
     ):
        self.mf6_wellname = mf6_wellname
...

    def write(
        self,
        directory: Union[str, Path],
        index: np.ndarray,
        svat: xr.DataArray,
        modflow_wel: Mf6Wel
    ):
...

This propsed approach has the following advantages over the initial idea:

  1. Modflow objects are only used when really necessary. This has the advantage that we can directly use the more low-level Mf6Wel object instead of the grid agnostic Well and LayeredWell packages, as the latter still have to be assigned to cells. We avoid having to conduct this twice.
  2. Mutations of Modflow data, for example regrid_like, do not have to be done twice. In the initial idea, regridding would have to be called once for the MetaSWAP model and once for the Modflow6Simulation, as we do not check wether the Modflow package assigned to the two different models is a copy or the same package for each model. The proposed approach also means no calls to Modflow6Package.regrid_like are done outside the mf6 module, reducing clutter a bit.

The same approach can be taken for the CouplerMapping object in iMOD Python, and the NodeSvatMapping, RechargeSvatMapping, WellSvatMapping objects in primod.

The MetaMod.write method would be the place fetch the Modflow packages and pass them on through to MetaSwapModel.write

@JoerivanEngelen
Copy link
Contributor Author

The proposed approach means quite a serious refactoring exercise. Best approach here is probably first trying to make this:

class Sprinkling:
    def __init__(
        self,
        max_abstraction_groundwater: xr.DataArray,
        max_abstraction_surfacewater: xr.DataArray,
        modflow_wel: Mf6Wel
     ):
        self.well = modflow_wel
...

    def write(
        self,
        directory: Union[str, Path],
        index: np.ndarray,
        svat: xr.DataArray,
    ):
...

With this we can test if no changes in derived mappings occur when coupling to Mf6Wel, instead of WellDisStructured.
It means the Sprinkling package still cannot be regridded, but this is acceptable for now, as this is already the present state.

I will create a separate issue with the proposed refactoring.

JoerivanEngelen added a commit that referenced this issue Oct 28, 2024
Fixes #728

# Description
This PR updates two MetaSWAP packages that depend on wells to use of the
deprecated ``WellDisStructured`` object to the ``Mf6Wel`` object.

It fixes the first small step of the big metaswap refactor. I chose a
feature branch as base branch to merge into, to still have the option to
create some hotfixes for a new release of iMOD Python while primod is
being updated.

I also renamed some variable names and dimension names with clearer
names. Furthermore, I type annotated some method.

# Checklist

- [x] Links to correct issue
- [x] Update changelog, if changes affect users
- [x] PR title starts with ``Issue #nr``, e.g. ``Issue #737``
- [ ] Unit tests were added
- [ ] **If feature added**: Added/extended example
@github-project-automation github-project-automation bot moved this from 🏗 In Progress to ✅ Done in iMOD Suite Oct 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: ✅ Done
Development

No branches or pull requests

1 participant