1+ from typing import Union
2+
3+ import xarray as xr
14import xcdat as xc
25
6+ from pcmdi_metrics .io import da_to_ds , get_longitude , select_subset
7+
38
4- def load_regions_specs ():
9+ def load_regions_specs () -> dict :
510 regions_specs = {
611 # Mean Climate
712 "global" : {},
@@ -35,7 +40,10 @@ def load_regions_specs():
3540 "NAO" : {"domain" : {"latitude" : (20.0 , 80 ), "longitude" : (- 90 , 40 )}},
3641 "SAM" : {"domain" : {"latitude" : (- 20.0 , - 90 ), "longitude" : (0 , 360 )}},
3742 "PNA" : {"domain" : {"latitude" : (20.0 , 85 ), "longitude" : (120 , 240 )}},
43+ "NPO" : {"domain" : {"latitude" : (20.0 , 85 ), "longitude" : (120 , 240 )}},
3844 "PDO" : {"domain" : {"latitude" : (20.0 , 70 ), "longitude" : (110 , 260 )}},
45+ "NPGO" : {"domain" : {"latitude" : (20.0 , 70 ), "longitude" : (110 , 260 )}},
46+ "AMO" : {"domain" : {"latitude" : (0.0 , 70 ), "longitude" : (- 80 , 0 )}},
3947 # Monsoon domains for Wang metrics
4048 # All monsoon domains
4149 "AllMW" : {"domain" : {"latitude" : (- 40.0 , 45.0 ), "longitude" : (0.0 , 360.0 )}},
@@ -45,7 +53,8 @@ def load_regions_specs():
4553 # South American Monsoon
4654 "SAMM" : {"domain" : {"latitude" : (- 45.0 , 0.0 ), "longitude" : (240.0 , 330.0 )}},
4755 # North African Monsoon
48- "NAFM" : {"domain" : {"latitude" : (0.0 , 45.0 ), "longitude" : (310.0 , 60.0 )}},
56+ # "NAFM": {"domain": {"latitude": (0.0, 45.0), "longitude": (310.0, 60.0)}},
57+ "NAFM" : {"domain" : {"latitude" : (0.0 , 45.0 ), "longitude" : (- 50.0 , 60.0 )}},
4958 # South African Monsoon
5059 "SAFM" : {"domain" : {"latitude" : (- 45.0 , 0.0 ), "longitude" : (0.0 , 90.0 )}},
5160 # Asian Summer Monsoon
@@ -70,55 +79,77 @@ def load_regions_specs():
7079 return regions_specs
7180
7281
73- def region_subset (ds , regions_specs , region = None ):
74- """
75- d: xarray.Dataset
76- regions_specs: dict
77- region: string
82+ def region_subset (
83+ ds : Union [xr .Dataset , xr .DataArray ],
84+ region : str ,
85+ data_var : str = "variable" ,
86+ regions_specs : dict = None ,
87+ debug : bool = False ,
88+ ) -> Union [xr .Dataset , xr .DataArray ]:
89+ """_summary_
90+
91+ Parameters
92+ ----------
93+ ds : Union[xr.Dataset, xr.DataArray]
94+ _description_
95+ region : str
96+ _description_
97+ data_var : str, optional
98+ _description_, by default None
99+ regions_specs : dict, optional
100+ _description_, by default None
101+ debug: bool, optional
102+ Turn on debug print, by default False
103+
104+ Returns
105+ -------
106+ Union[xr.Dataset, xr.DataArray]
107+ _description_
78108 """
109+ if isinstance (ds , xr .DataArray ):
110+ is_dataArray = True
111+ ds = da_to_ds (ds , data_var )
112+ else :
113+ is_dataArray = False
114+
115+ if regions_specs is None :
116+ regions_specs = load_regions_specs ()
117+
118+ if "domain" in regions_specs [region ]:
119+ if "latitude" in regions_specs [region ]["domain" ]:
120+ lat0 = regions_specs [region ]["domain" ]["latitude" ][0 ]
121+ lat1 = regions_specs [region ]["domain" ]["latitude" ][1 ]
122+ # proceed subset
123+ ds = select_subset (ds , lat = (min (lat0 , lat1 ), max (lat0 , lat1 )))
124+ if debug :
125+ print ("region_subset, latitude subsetted, ds:" , ds )
126+
127+ if "longitude" in regions_specs [region ]["domain" ]:
128+ lon0 = regions_specs [region ]["domain" ]["longitude" ][0 ]
129+ lon1 = regions_specs [region ]["domain" ]["longitude" ][1 ]
130+
131+ # check original dataset longitude range
132+ lon_min = get_longitude (ds ).min ().values .item ()
133+ lon_max = get_longitude (ds ).max ().values .item ()
134+
135+ # Check if longitude range swap is needed
136+ if min (lon0 , lon1 ) < 0 :
137+ # when subset region lon is defined in (-180, 180) range
138+ if min (lon_min , lon_max ) < 0 :
139+ # if original data lon range is (-180, 180), no treatment needed
140+ pass
141+ else :
142+ # if original data lon range is (0, 360), convert and swap lon
143+ ds = xc .swap_lon_axis (ds , to = (- 180 , 180 ))
144+
145+ # proceed subset
146+ # ds = select_subset(ds, lon=(min(lon0, lon1), max(lon0, lon1)))
147+ ds = select_subset (ds , lon = (lon0 , lon1 ))
148+ if debug :
149+ print ("region_subset, longitude subsetted, ds:" , ds )
79150
80- if (region is None ) or (
81- (region is not None ) and (region not in list (regions_specs .keys ()))
82- ):
83- print ("Error: region not defined" )
151+ # return the same type
152+ if is_dataArray :
153+ return ds [data_var ]
84154 else :
85- if "domain" in list (regions_specs [region ].keys ()):
86- if "latitude" in list (regions_specs [region ]["domain" ].keys ()):
87- lat0 = regions_specs [region ]["domain" ]["latitude" ][0 ]
88- lat1 = regions_specs [region ]["domain" ]["latitude" ][1 ]
89- # proceed subset
90- if "latitude" in (ds .coords .dims ):
91- ds = ds .sel (latitude = slice (lat0 , lat1 ))
92- elif "lat" in (ds .coords .dims ):
93- ds = ds .sel (lat = slice (lat0 , lat1 ))
94-
95- if "longitude" in list (regions_specs [region ]["domain" ].keys ()):
96- lon0 = regions_specs [region ]["domain" ]["longitude" ][0 ]
97- lon1 = regions_specs [region ]["domain" ]["longitude" ][1 ]
98-
99- # check original dataset longitude range
100- if "longitude" in (ds .coords .dims ):
101- lon_min = ds .longitude .min ()
102- lon_max = ds .longitude .max ()
103- elif "lon" in (ds .coords .dims ):
104- lon_min = ds .lon .min ()
105- lon_max = ds .lon .max ()
106-
107- # longitude range swap if needed
108- if (
109- min (lon0 , lon1 ) < 0
110- ): # when subset region lon is defined in (-180, 180) range
111- if (
112- min (lon_min , lon_max ) < 0
113- ): # if original data lon range is (-180, 180) no treatment needed
114- pass
115- else : # if original data lon range is (0, 360), convert swap lon
116- ds = xc .swap_lon_axis (ds , to = (- 180 , 180 ))
117-
118- # proceed subset
119- if "longitude" in (ds .coords .dims ):
120- ds = ds .sel (longitude = slice (lon0 , lon1 ))
121- elif "lon" in (ds .coords .dims ):
122- ds = ds .sel (lon = slice (lon0 , lon1 ))
123-
124- return ds
155+ return ds
0 commit comments