22Regridding
33==========
44
5- Most MF6 packages have spatial data arrays as input. These arrays
6- are discrete: they are defined over the simulation grid and contain
7- values associated to each cell.
5+ Introduction
6+ ------------
87
9- Regridding these package means: create a new package with
10- spatial data arrays defined over a different grid. Computing what
11- the values in these new arrays should be, is done by xugrid.
8+ Most MODFLOW 6 packages have spatial data arrays as input. These arrays are
9+ discrete: they are defined over the simulation grid and contain values
10+ associated to each cell.
11+
12+ Regridding these package means: create a new package with spatial data arrays
13+ defined over a different grid. Computing what the values in these new arrays
14+ should be, is done by xugrid.
1215
1316xugrid will compute a regridded array based on:
1417
1518- the original array
16- - the original discretization (this is described in the coordinates of the original arry)
19+ - the original discretization (this is described in the coordinates of the
20+ original arry)
1721- the new discretization
1822- a regridding method
1923
20- More information on the available regridding methods can be found in the xugrid documentation
21- https://deltares.github.io/xugrid/user_guide.html
24+ More information on the available regridding methods can be found in the xugrid
25+ documentation https://deltares.github.io/xugrid/user_guide.html
2226
2327The regridding method that should be used depends on the property being
2428regridded. For example a point-based property (whose value do not depend
4650# -----------------------------
4751#
4852# In many real-world models, some cells will be inactive or marked as "vertical
49- # passthrough" (VPT) in the idomain array of the simulation. Some packages require
50- # that all cells that are inactictive or VPT in idomain are excluded from the
51- # package as well. An example is the npf package: cells that are inactive or VPT
52- # in idomain, should not have conductivity data in the npf package. Therefore at
53- # the end of the regridding process, a final step consists in enforcing
54- # consistency between those of idomain and all the packages. This is a 2-step
55- # process:
53+ # passthrough" (VPT) in the idomain array of the simulation. Some packages
54+ # require that all cells that are inactictive or VPT in idomain are excluded
55+ # from the package as well. An example is the :class:`imod.mf6.NodePropertyFlow`
56+ # package: cells that are inactive or VPT in idomain, should not have
57+ # conductivity data in the npf package. Therefore at the end of the regridding
58+ # process, a final step consists in enforcing consistency between those of
59+ # idomain and all the packages. This is a 2-step process:
5660#
5761# 1) for cells that do not have inputs in crucial packages like npf or storage,
5862# idomain will be set to inactive.
8286# --------------------------------
8387#
8488# The regrid_like function is available on packages, models and simulations.
85- # When the default methods are acceptable, regridding the whole simulation is the most convenient
86- # from a user-perspective.
89+ # When the default methods are acceptable, regridding the whole simulation is
90+ # the most convenient from a user-perspective.
8791
8892import imod
8993
166170# When non-default methods are used for one or more packages, these should be
167171# regridded separately. In that case, the most convenient approach is likely:
168172#
169- # - pop the packages that should use non-default methods from the source simulation (the
170- # popping is optional, and is only recommended for packages whose presence is not
171- # mandatory for validation.)
172- # - regrid the source simulation: this takes care of all the packages that should use default methods.
173- # - regrid the package(s) where you want to use non-standard rergridding methods indivudually starting from the
174- # packages in the source simulation
175- # - insert the custom-regridded packages to the
176- # regridded simulation (or replace the package regridded with default methods with
177- # the one you just regridded with non-default methods if it was not popped)
178- #
179- # In code, consider an example where we want to regrid the recharge package using non default methods
180- # then we would do the following. First we'll load some example simulation.
181- # There is a separate example contained in :doc:`/examples/mf6/hondsrug`
182- # that you should look at if you are interested in the model building
173+ # - pop the packages that should use non-default methods from the source
174+ # simulation (the popping is optional, and is only recommended for packages
175+ # whose presence is not mandatory for validation.)
176+ # - regrid the source simulation: this takes care of all the packages that
177+ # should use default methods.
178+ # - regrid the package(s) where you want to use non-standard rergridding methods
179+ # indivudually starting from the packages in the source simulation
180+ # - insert the custom-regridded packages to the regridded simulation (or replace
181+ # the package regridded with default methods with the one you just regridded
182+ # with non-default methods if it was not popped)
183+ #
184+ # In code, consider an example where we want to regrid the recharge package
185+ # using non default methods then we would do the following. First we'll load
186+ # some example simulation. There is a separate example contained in
187+ # :doc:`/examples/mf6/hondsrug` that you should look at if you are interested in
188+ # the model building
183189
184190# %%
191+ #
185192# Set up the input needed for custom regridding. Create a regridder
186193# weight-cache. This object can (and should) be reused for all the packages that
187194# undergo custom regridding at this stage.
192199regrid_cache
193200
194201# %%
195- # Next, we'll remove the recharge package and obtain it as a variable. We'll do this for later use.
202+ #
203+ # Next, we'll remove the recharge package and obtain it as a variable. We'll do
204+ # this for later use.
196205
197206original_rch_package = original_simulation ["GWF" ].pop ("rch" )
198207
199208original_rch_package
200209
201210# %%
202- # Regrid the recharge package with a custom regridder. In this case we opt
203- # for the centroid locator regridder. This regridder is similar to using a
204- # "nearest neighbour" lookup.
211+ #
212+ # Regrid the recharge package with a custom regridder. In this case we opt for
213+ # the centroid locator regridder. This regridder is similar to using a "nearest
214+ # neighbour" lookup.
205215from imod .common .utilities .regrid import RegridderType
206216from imod .mf6 .regrid import RechargeRegridMethod
207217
226236# Comparison with histograms
227237# --------------------------
228238#
229- # In the next segment we will compare the input of the models on different grids.
230- # We advice to always check how your input is regridded. In this example we upscaled grid,
231- # many input parameters are regridded with a ``mean`` method. This means that their input
232- # range is reduced, which can be seen in tailings in the histograms becoming shorter
239+ # In the next segment we will compare the input of the models on different
240+ # grids. We advice to always check how your input is regridded. In this example
241+ # we upscaled grid, many input parameters are regridded with a ``mean`` method.
242+ # This means that their input range is reduced, which can be seen in tailings in
243+ # the histograms becoming shorter
233244
234245
235246def plot_histograms_side_by_side (array_original , array_regridded , title ):
@@ -321,6 +332,10 @@ def plot_histograms_side_by_side(array_original, array_regridded, title):
321332)
322333
323334# %%
335+ #
336+ # Compare simulation outputs
337+ # --------------------------
338+ #
324339# Let's compare outputs now.
325340
326341# Write simulation
@@ -356,40 +371,43 @@ def plot_histograms_side_by_side(array_original, array_regridded, title):
356371# %%
357372# A note on regridding conductivity
358373# ---------------------------------
359- # In the npf package, it is possible to use for definining the conductivity tensor:
374+ #
375+ # In the npf package, it is possible to use for definining the conductivity
376+ # tensor:
360377#
361378# - 1 array (K)
362379# - 2 arrays (K and K22)
363380# - 3 arrays (K, K22, K33)
364381#
365- # If 1 array is given the tensor
366- # is called isotropic. Defining only K gives the same behavior as specifying K,
367- # K22 and K33 with the same value. When regridding, K33 has a default method
368- # different from that of K and K22, but it can only be applied if K33 exists in
369- # the source model in the first place. So it is recommended to introduce K33 as a
370- # separate array in the source model even if it is isotropic.
371- # Also note that default regridding methods were chosen assuming that K and K22
372- # are roughly horizontal and K33 roughly vertical. But this may not be the case
373- # if the input arrays angle2 and/or angle3 have large values.
382+ # If 1 array is given the tensor is called isotropic. Defining only K gives the
383+ # same behavior as specifying K, K22 and K33 with the same value. When
384+ # regridding, K33 has a default method different from that of K and K22, but it
385+ # can only be applied if K33 exists in the source model in the first place. So
386+ # it is recommended to introduce K33 as a separate array in the source model
387+ # even if it is isotropic. Also note that default regridding methods were chosen
388+ # assuming that K and K22 are roughly horizontal and K33 roughly vertical. But
389+ # this may not be the case if the input arrays angle2 and/or angle3 have large
390+ # values.
374391#
375392# Regridding boundary conditions
376393# ------------------------------
394+ #
377395# Special care must be taken when regridding boundary conditions, and it is
378396# recommended that users verify the balance output of a regridded simulation and
379397# compare it to the original model. If the regridded simulation is a good
380- # representation of the original simulation, the mass contributions on the balance
381- # by the different boundary conditions should be comparable in both simulations.
382- # To achieve this, it may be necessary to tweak the input or the regridding
383- # methods. An example of this is upscaling recharge (so the target grid has
384- # coarser cells than the source grid). Its default method is averaging, with the
385- # following rules:
398+ # representation of the original simulation, the mass contributions on the
399+ # balance by the different boundary conditions should be comparable in both
400+ # simulations. To achieve this, it may be necessary to tweak the input or the
401+ # regridding methods. An example of this is upscaling recharge (so the target
402+ # grid has coarser cells than the source grid). Its default method is averaging,
403+ # with the following rules:
386404#
387405# - if a cell in the source grid is inactive in the source recharge package
388406# (meaning no recharge), it will not count when averaging. So if a target cell
389- # has partial overlap with one source recharge cell, and the rest of the target
390- # cell has no overlap with any source active recharge cell, it will get the
391- # recharge of the one cell it has overlap with. But since the target cell is
392- # larger, this effectively means the regridded recharge will be more in the
407+ # has partial overlap with one source recharge cell, and the rest of the
408+ # target cell has no overlap with any source active recharge cell, it will get
409+ # the recharge of the one cell it has overlap with. But since the target cell
410+ # is larger, this effectively means the regridded recharge will be more in the
393411# regridded simulation than it was in the source simulation
394412# - but we do the same regridding this time assigning a zero recharge to cells
395413# without recharge then the averaging will take the zero-recharge cells into
@@ -398,22 +416,29 @@ def plot_histograms_side_by_side(array_original, array_regridded, title):
398416#
399417# A note on regridding transport
400418# ------------------------------
401- # Transport simulations can be unstable if constraints related to the grid Peclet
402- # number and the courant number are exceeded. This can easily happen when
419+ #
420+ # Transport simulations can be unstable if constraints related to the grid
421+ # Peclet number and the courant number are exceeded. This can easily happen when
403422# regridding. It may be necessary to reduce the simulation's time step size
404423# especially when downscaling, to prevent numerical issues. Increasing
405424# dispersivities or the molecular diffusion constant can also help to stabilize
406- # the simulation. Inversely, when upscaling, a larger time step size can be acceptable.
425+ # the simulation. Inversely, when upscaling, a larger time step size can be
426+ # acceptable.
407427#
408428#
409429# Unsupported packages
410430# --------------------
431+ #
411432# Some packages cannot be regridded. This includes the Lake package and the UZF
412- # package. Such packages should be removed from the simulation before regridding,
413- # and then new packages should be created by the user and then added to the
414- # regridded simulation.
433+ # package. Such packages should be removed from the simulation before
434+ # regridding, and then new packages should be created by the user and then added
435+ # to the regridded simulation.
415436#
437+ # Listing all default regridding methods
438+ # --------------------------------------
416439#
440+ # MODFLOW 6
441+ # ^^^^^^^^^
417442# This code snippet prints all default methods:
418443#
419444import inspect
@@ -422,44 +447,68 @@ def plot_histograms_side_by_side(array_original, array_regridded, title):
422447
423448import pandas as pd
424449
425- regrid_method_setup = {
426- "package name" : [],
427- "array name" : [],
428- "method name" : [],
429- "function name" : [],
430- }
431- regrid_method_table = pd .DataFrame (regrid_method_setup )
432- # Get all classes in the imod.mf6 module (e.g. imod.mf6.NodePropertyFlow,
433- # imod.mf6.GroundwaterFlowModel, imod.mf6.River)
450+
451+ def collect_regrid_methods (classes : list ):
452+ """Collect all regrid methods from all list of package classes."""
453+ regrid_method_setup = {
454+ "package name" : [],
455+ "array name" : [],
456+ "method name" : [],
457+ "function name" : [],
458+ }
459+ regrid_method_table = pd .DataFrame (regrid_method_setup )
460+ counter = 0
461+ for obj in classes :
462+ if hasattr (obj , "_regrid_method" ):
463+ package_name = obj .__name__
464+ regrid_methods = asdict (obj .get_regrid_methods ())
465+ for array_name in regrid_methods .keys ():
466+ method_name = regrid_methods [array_name ][0 ].name
467+ function_name = ""
468+ if len (regrid_methods [array_name ]) > 0 :
469+ function_name = regrid_methods [array_name ][1 ]
470+ regrid_method_table .loc [counter ] = (
471+ package_name ,
472+ array_name ,
473+ method_name ,
474+ function_name ,
475+ )
476+ counter = counter + 1
477+
478+ # Set multi index to group with packages
479+ regrid_method_table = regrid_method_table .set_index (["package name" , "array name" ])
480+ return regrid_method_table
481+
482+
483+ # Get all classes in the imod.mf6 module (e.g.
484+ # :class:`imod.mf6.NodePropertyFlow`, :class:`imod.mf6.GroundwaterFlowModel`,
485+ # :class:`imod.mf6.River`)
434486mf6_classes = [
435487 obj for _ , obj in inspect .getmembers (sys .modules ["imod.mf6" ], inspect .isclass )
436488]
437489
438- counter = 0
439- for obj in mf6_classes :
440- if hasattr (obj , "_regrid_method" ):
441- package_name = obj .__name__
442- regrid_methods = asdict (obj .get_regrid_methods ())
443- for array_name in regrid_methods .keys ():
444- method_name = regrid_methods [array_name ][0 ].name
445- function_name = ""
446- if len (regrid_methods [array_name ]) > 0 :
447- function_name = regrid_methods [array_name ][1 ]
448- regrid_method_table .loc [counter ] = (
449- package_name ,
450- array_name ,
451- method_name ,
452- function_name ,
453- )
454- counter = counter + 1
455-
456- # Set multi index to group with packages
457- regrid_method_table = regrid_method_table .set_index (["package name" , "array name" ])
490+ mf6_regrid_methods = collect_regrid_methods (mf6_classes )
491+
458492# Pandas by default displays at max 60 rows, which this table exceeds.
459- nrows = regrid_method_table .shape [0 ]
493+ nrows = mf6_regrid_methods .shape [0 ]
460494# Configure pandas to increase the max amount of displayable rows.
461495pd .set_option ("display.max_rows" , nrows + 1 )
462496# Display rows:
463- regrid_method_table
497+ mf6_regrid_methods
498+
499+ # %%
500+ #
501+ # MetaSWAP
502+ # ^^^^^^^^^
503+ #
504+ # Let's list all default regridding methods for all MetaSWAP packages:
505+
506+ msw_classes = [
507+ obj for _ , obj in inspect .getmembers (sys .modules ["imod.msw" ], inspect .isclass )
508+ ]
509+
510+ msw_regrid_methods = collect_regrid_methods (msw_classes )
511+
512+ msw_regrid_methods
464513
465514# %%
0 commit comments