4444from xarray import DataTree
4545from xarray .backends .common import AbstractDataStore , BackendArray , BackendEntrypoint
4646from xarray .backends .file_manager import CachingFileManager
47+ from xarray .backends .locks import SerializableLock , ensure_lock
4748from xarray .backends .store import StoreBackendEntrypoint
4849from xarray .core import indexing
4950from xarray .core .utils import FrozenDict , close_on_error
7879 string_dict ,
7980)
8081
82+ NEXRADL2_LOCK = SerializableLock ()
83+
84+
8185#: mapping from NEXRAD names to CfRadial2/ODIM
8286nexrad_mapping = {
8387 "REF" : "DBZH" ,
@@ -1324,36 +1328,32 @@ def __init__(self, datastore, name, var):
13241328 self .shape = (nrays , nbins )
13251329
13261330 def _getitem (self , key ):
1327- # read the data if not available
1328- try :
1329- data = self .datastore .ds ["sweep_data" ][self .name ]["data" ]
1330- print ("ZZZZZAA:" , self .name , data , key )
1331- except KeyError :
1332- print ("XXXXX:" , self .group , self .name )
1333- self .datastore .root .get_data (self .group , self .name )
1334- data = self .datastore .ds ["sweep_data" ][self .name ]["data" ]
1335- print ("ZZZZZBB:" , self .name , data , key )
1336- print ("YY0:" , self .name , len (data ), len (data [0 ]))
1337- # see 3.2.4.17.6 Table XVII-I Data Moment Characteristics and Conversion for Data Names
1338- word_size = self .datastore .ds ["sweep_data" ][self .name ]["word_size" ]
1339- if self .name == "PHI" and word_size == 16 :
1340- # 10 bit mask, but only for 2 byte data
1341- x = np .uint16 (0x3FF )
1342- elif self .name == "ZDR" and word_size == 16 :
1343- # 11 bit mask, but only for 2 byte data
1344- x = np .uint16 (0x7FF )
1345- else :
1346- x = np .uint8 (0xFF )
1347- print ("YY1:" , self .name , len (data [0 ]), self .shape )
1348- if len (data [0 ]) < self .shape [1 ]:
1349- return np .pad (
1350- np .vstack (data ) & x ,
1351- ((0 , 0 ), (0 , self .shape [1 ] - len (data [0 ]))),
1352- mode = "constant" ,
1353- constant_values = 0 ,
1354- )[key ]
1355- else :
1356- return (np .vstack (data ) & x )[key ]
1331+ with self .datastore .lock :
1332+ # read the data if not available
1333+ try :
1334+ data = self .datastore .ds ["sweep_data" ][self .name ]["data" ]
1335+ except KeyError :
1336+ self .datastore .root .get_data (self .group , self .name )
1337+ data = self .datastore .ds ["sweep_data" ][self .name ]["data" ]
1338+ # see 3.2.4.17.6 Table XVII-I Data Moment Characteristics and Conversion for Data Names
1339+ word_size = self .datastore .ds ["sweep_data" ][self .name ]["word_size" ]
1340+ if self .name == "PHI" and word_size == 16 :
1341+ # 10 bit mask, but only for 2 byte data
1342+ x = np .uint16 (0x3FF )
1343+ elif self .name == "ZDR" and word_size == 16 :
1344+ # 11 bit mask, but only for 2 byte data
1345+ x = np .uint16 (0x7FF )
1346+ else :
1347+ x = np .uint8 (0xFF )
1348+ if len (data [0 ]) < self .shape [1 ]:
1349+ return np .pad (
1350+ np .vstack (data ) & x ,
1351+ ((0 , 0 ), (0 , self .shape [1 ] - len (data [0 ]))),
1352+ mode = "constant" ,
1353+ constant_values = 0 ,
1354+ )[key ]
1355+ else :
1356+ return (np .vstack (data ) & x )[key ]
13571357
13581358 def __getitem__ (self , key ):
13591359 return indexing .explicit_indexing_adapter (
@@ -1365,24 +1365,29 @@ def __getitem__(self, key):
13651365
13661366
13671367class NexradLevel2Store (AbstractDataStore ):
1368- def __init__ (self , manager , group = None ):
1368+ def __init__ (self , manager , group = None , lock = NEXRADL2_LOCK ):
13691369 self ._manager = manager
13701370 self ._group = int (group [6 :])
13711371 self ._filename = self .filename
1372+ self .lock = ensure_lock (lock )
13721373
13731374 @classmethod
1374- def open (cls , filename , mode = "r" , group = None , ** kwargs ):
1375+ def open (cls , filename , mode = "r" , group = None , lock = None , ** kwargs ):
1376+ if lock is None :
1377+ lock = NEXRADL2_LOCK
13751378 manager = CachingFileManager (
13761379 NEXRADLevel2File , filename , mode = mode , kwargs = kwargs
13771380 )
1378- return cls (manager , group = group )
1381+ return cls (manager , group = group , lock = lock )
13791382
13801383 @classmethod
1381- def open_groups (cls , filename , groups , mode = "r" , ** kwargs ):
1384+ def open_groups (cls , filename , groups , mode = "r" , lock = None , ** kwargs ):
1385+ if lock is None :
1386+ lock = NEXRADL2_LOCK
13821387 manager = CachingFileManager (
13831388 NEXRADLevel2File , filename , mode = mode , kwargs = kwargs
13841389 )
1385- return {group : cls (manager , group = group ) for group in groups }
1390+ return {group : cls (manager , group = group , lock = lock ) for group in groups }
13861391
13871392 @property
13881393 def filename (self ):
@@ -1534,6 +1539,7 @@ def open_dataset(
15341539 use_cftime = None ,
15351540 decode_timedelta = None ,
15361541 group = None ,
1542+ lock = None ,
15371543 first_dim = "auto" ,
15381544 reindex_angle = False ,
15391545 fix_second_angle = False ,
@@ -1543,6 +1549,7 @@ def open_dataset(
15431549 store = NexradLevel2Store .open (
15441550 filename_or_obj ,
15451551 group = group ,
1552+ lock = lock ,
15461553 loaddata = False ,
15471554 )
15481555
@@ -1610,6 +1617,7 @@ def open_nexradlevel2_datatree(
16101617 fix_second_angle = False ,
16111618 site_coords = True ,
16121619 optional = True ,
1620+ lock = None ,
16131621 ** kwargs ,
16141622):
16151623 """Open a NEXRAD Level2 dataset as an `xarray.DataTree`.
@@ -1732,6 +1740,7 @@ def open_nexradlevel2_datatree(
17321740 fix_second_angle = fix_second_angle ,
17331741 site_coords = site_coords ,
17341742 optional = optional ,
1743+ lock = lock ,
17351744 ** kwargs ,
17361745 )
17371746 ls_ds : list [xr .Dataset ] = [sweep_dict [sweep ] for sweep in sweep_dict .keys ()]
@@ -1771,10 +1780,12 @@ def open_sweeps_as_dict(
17711780 fix_second_angle = False ,
17721781 site_coords = True ,
17731782 optional = True ,
1783+ lock = None ,
17741784 ** kwargs ,
17751785):
17761786 stores = NexradLevel2Store .open_groups (
17771787 filename = filename_or_obj ,
1788+ lock = lock ,
17781789 groups = sweeps ,
17791790 )
17801791 groups_dict = {}
0 commit comments