66
77from ..util import LayerError , _get_value_from_ds_datavar
88from .resample import fillnan_da
9+ from .shared import GridTypeDims
910
1011logger = logging .getLogger (__name__ )
1112
@@ -269,9 +270,9 @@ def split_layers_ds(
269270 split_dict [lay0 ] = [1 / split_dict [lay0 ]] * split_dict [lay0 ]
270271 elif hasattr (split_dict [lay0 ], "__iter__" ):
271272 # make sure the fractions add up to 1
272- assert np .isclose (np . sum ( split_dict [ lay0 ]), 1 ), (
273- f"Fractions for splitting layer ' { lay0 } ' do not add up to 1."
274- )
273+ assert np .isclose (
274+ np . sum ( split_dict [ lay0 ]), 1
275+ ), f"Fractions for splitting layer ' { lay0 } ' do not add up to 1."
275276 split_dict [lay0 ] = split_dict [lay0 ] / np .sum (split_dict [lay0 ])
276277 else :
277278 raise ValueError (
@@ -375,18 +376,9 @@ def layer_combine_top_bot(ds, combine_layers, layer="layer", top="top", bot="bot
375376 new_nlay = (
376377 ds [layer ].size - sum ((len (c ) for c in combine_layers )) + len (combine_layers )
377378 )
378-
379379 # create new DataArrays for storing new top/bot
380- new_bot = xr .DataArray (
381- data = np .nan ,
382- dims = ["layer" , "y" , "x" ],
383- coords = {"layer" : np .arange (new_nlay ), "y" : ds .y .data , "x" : ds .x .data },
384- )
385- new_top = xr .DataArray (
386- data = np .nan ,
387- dims = ["layer" , "y" , "x" ],
388- coords = {"layer" : np .arange (new_nlay ), "y" : ds .y .data , "x" : ds .x .data },
389- )
380+ new_bot = _get_empty_layered_da (ds [bot ], nlay = new_nlay )
381+ new_top = _get_empty_layered_da (ds [top ], nlay = new_nlay )
390382
391383 # dict to keep track of old and new layer indices
392384 reindexer = {}
@@ -411,7 +403,7 @@ def layer_combine_top_bot(ds, combine_layers, layer="layer", top="top", bot="bot
411403 "calculate new top/bot."
412404 )
413405 tops = ds [top ].data [c , ...]
414- bots = ds [bot ].data [c , :, : ]
406+ bots = ds [bot ].data [c , ... ]
415407 new_top .data [j ] = np .nanmax (tops , axis = 0 )
416408 new_bot .data [j ] = np .nanmin (bots , axis = 0 )
417409
@@ -453,25 +445,49 @@ def sum_param_combined_layers(da, reindexer):
453445 data array containing new parameters for combined layers and old
454446 parameters for unmodified layers.
455447 """
456- da_new = xr .DataArray (
457- data = np .nan ,
458- dims = ["layer" , "y" , "x" ],
459- coords = {
460- "layer" : np .arange (list (reindexer .keys ())[- 1 ] + 1 ),
461- "y" : da ["y" ],
462- "x" : da ["x" ],
463- },
464- )
465-
448+ da_new = _get_empty_layered_da (da , nlay = list (reindexer .keys ())[- 1 ] + 1 )
466449 for k , v in reindexer .items ():
467450 if isinstance (v , tuple ):
468- psum = np .sum (da .data [v , :, : ], axis = 0 )
451+ psum = np .sum (da .data [v , ... ], axis = 0 )
469452 else :
470453 psum = da .data [v ]
471454 da_new .data [k ] = psum
472455 return da_new
473456
474457
458+ def _get_empty_layered_da (da , nlay ):
459+ """Get empty DataArray with number of layer specified by nlay.
460+
461+ Parameters
462+ ----------
463+ da : xarray.DataArray
464+ original data array
465+ nlay : int
466+ number of layers
467+
468+ Returns
469+ -------
470+ da_new : xarray.DataArray
471+ new empty data array with updated number of layers
472+ """
473+ if set (GridTypeDims .STRUCTURED_LAYERED .value ).issubset (da .dims ):
474+ dims = GridTypeDims .STRUCTURED_LAYERED .value
475+ coords = {
476+ "layer" : np .arange (nlay ),
477+ "y" : da ["y" ],
478+ "x" : da ["x" ],
479+ }
480+ elif set (GridTypeDims .VERTEX_LAYERED .value ).issubset (da .dims ):
481+ dims = GridTypeDims .VERTEX_LAYERED .value
482+ coords = {
483+ "layer" : np .arange (nlay ),
484+ "icell2d" : da ["icell2d" ],
485+ }
486+ else :
487+ raise TypeError ("Cannot determine grid type of data array." )
488+ return xr .DataArray (data = np .nan , dims = dims , coords = coords )
489+
490+
475491def kheq_combined_layers (kh , thickness , reindexer ):
476492 """Calculate equivalent horizontal hydraulic conductivity.
477493
@@ -491,21 +507,12 @@ def kheq_combined_layers(kh, thickness, reindexer):
491507 for combined layers and original hydraulic conductivity in unmodified
492508 layers
493509 """
494- da_kh = xr .DataArray (
495- data = np .nan ,
496- dims = ["layer" , "y" , "x" ],
497- coords = {
498- "layer" : np .arange (list (reindexer .keys ())[- 1 ] + 1 ),
499- "y" : kh ["y" ],
500- "x" : kh ["x" ],
501- },
502- )
503-
510+ da_kh = _get_empty_layered_da (kh , nlay = list (reindexer .keys ())[- 1 ] + 1 )
504511 for k , v in reindexer .items ():
505512 if isinstance (v , tuple ):
506513 kheq = np .nansum (
507- thickness .data [v , :, : ] * kh .data [v , :, : ], axis = 0
508- ) / np .nansum (thickness .data [v , :, : ], axis = 0 )
514+ thickness .data [v , ... ] * kh .data [v , ... ], axis = 0
515+ ) / np .nansum (thickness .data [v , ... ], axis = 0 )
509516 kheq [np .isinf (kheq )] = np .nan
510517 else :
511518 kheq = kh .data [v ]
@@ -532,20 +539,11 @@ def kveq_combined_layers(kv, thickness, reindexer):
532539 for combined layers and original hydraulic conductivity in unmodified
533540 layers
534541 """
535- da_kv = xr .DataArray (
536- data = np .nan ,
537- dims = ["layer" , "y" , "x" ],
538- coords = {
539- "layer" : np .arange (list (reindexer .keys ())[- 1 ] + 1 ),
540- "y" : kv ["y" ],
541- "x" : kv ["x" ],
542- },
543- )
544-
542+ da_kv = _get_empty_layered_da (kv , nlay = list (reindexer .keys ())[- 1 ] + 1 )
545543 for k , v in reindexer .items ():
546544 if isinstance (v , tuple ):
547- kveq = np .nansum (thickness .data [v , :, : ], axis = 0 ) / np .nansum (
548- thickness .data [v , :, : ] / kv .data [v , :, : ], axis = 0
545+ kveq = np .nansum (thickness .data [v , ... ], axis = 0 ) / np .nansum (
546+ thickness .data [v , ... ] / kv .data [v , ... ], axis = 0
549547 )
550548 kveq [np .isinf (kveq )] = np .nan
551549 else :
@@ -564,6 +562,7 @@ def combine_layers_ds(
564562 kv = "kv" ,
565563 kD = "kD" ,
566564 c = "c" ,
565+ return_reindexer = False ,
567566):
568567 """Combine layers in Dataset.
569568
@@ -595,6 +594,9 @@ def combine_layers_ds(
595594 c : str, optional
596595 name of data variable containg resistance or c,
597596 by default 'c'. Not parsed if set to None.
597+ return_reindexer : bool, optional
598+ Return a dictionary that can be used to reindex variables from the original
599+ layer-dimension to the new layer-dimension when True. The default is False.
598600
599601 Returns
600602 -------
@@ -625,7 +627,7 @@ def combine_layers_ds(
625627 ----
626628 When passing integers to combine_layers, these are always intepreted as the
627629 layer index (i.e. starting at 0 and numbered consecutively), and not the
628- layer "name". If the dataset layer index is integer , only the layer index
630+ layer "name". If the dataset layer names are integers , only the layer index
629631 can be used to specify which layers to merge.
630632 """
631633 data_vars = []
@@ -634,10 +636,14 @@ def combine_layers_ds(
634636 data_vars .append (dv )
635637 parsed_dv = set ([top , bot ] + data_vars )
636638
637- dropped_dv = set (ds .data_vars .keys ()) - parsed_dv
638- if len (dropped_dv ) > 0 :
639- msg = f"Following data variables will be dropped: { dropped_dv } "
640- logger .warning (msg )
639+ check_remaining_dv = set (ds .data_vars .keys ()) - parsed_dv
640+ keep_dv = []
641+ for dv in check_remaining_dv :
642+ if "layer" in ds [dv ].dims :
643+ msg = f"Data variable has 'layer' dimension and will be dropped: { dv } "
644+ logger .warning (msg )
645+ else :
646+ keep_dv .append (dv )
641647
642648 # calculate new tops/bots
643649 logger .info ("Calculating new layer tops and bottoms..." )
@@ -700,16 +706,16 @@ def combine_layers_ds(
700706
701707 # calculate equivalent kh/kv
702708 if kh is not None :
703- logger .info (f "Calculate equivalent '{ kh } ' for combined layers." )
709+ logger .info ("Calculate equivalent '%s ' for combined layers." , kh )
704710 da_dict [kh ] = kheq_combined_layers (ds [kh ], thickness , reindexer )
705711 if kv is not None :
706- logger .info (f "Calculate equivalent '{ kv } ' for combined layers." )
712+ logger .info ("Calculate equivalent '%s ' for combined layers." , kv )
707713 da_dict [kv ] = kveq_combined_layers (ds [kv ], thickness , reindexer )
708714 if kD is not None and kD in ds :
709- logger .info (f "Calculate value '{ kD } ' for combined layers with sum." )
715+ logger .info ("Calculate value '%s ' for combined layers with sum." , kD )
710716 da_dict [kD ] = sum_param_combined_layers (ds [kD ], reindexer )
711717 if c is not None and c in ds :
712- logger .info (f "Calculate value '{ c } ' for combined layers with sum." )
718+ logger .info ("Calculate value '%s ' for combined layers with sum." , c )
713719 da_dict [c ] = sum_param_combined_layers (ds [c ], reindexer )
714720
715721 # get new layer names, based on first sub-layer from each combined layer
@@ -725,17 +731,19 @@ def combine_layers_ds(
725731 for k , da in da_dict .items ():
726732 da_dict [k ] = da .assign_coords (layer = layer_names )
727733
728- # add reindexer to attributes
729- attrs = ds . attrs . copy ()
730- attrs [ "combine_reindexer" ] = reindexer
734+ # add original data variables to new dataset
735+ for dv in keep_dv :
736+ da_dict [ dv ] = ds [ dv ]
731737
732738 # create new dataset
733739 logger .info ("Done! Created new dataset with combined layers!" )
734- ds_combine = xr .Dataset (da_dict , attrs = attrs )
740+ ds_combine = xr .Dataset (da_dict , attrs = ds . attrs )
735741
736742 # remove layer dimension from top
737743 ds_combine = remove_layer_dim_from_top (ds_combine , inconsistency_threshold = 1e-5 )
738744
745+ if return_reindexer :
746+ return ds_combine , reindexer
739747 return ds_combine
740748
741749
0 commit comments