2727===========================================================================
2828
2929"""
30+ from matplotlib .dates import julian2num , num2date
31+
3032from py_eddy_tracker .observations import EddiesObservations , \
3133 VirtualEddiesObservations , TrackEddiesObservations
3234from numpy import bool_ , array , arange , ones , setdiff1d , zeros , uint16 , \
@@ -47,7 +49,7 @@ class Correspondances(list):
4749 # Track limit to 65535
4850 N_DTYPE = 'u2'
4951
50- def __init__ (self , datasets , virtual = 0 , class_method = None ):
52+ def __init__ (self , datasets , virtual = 0 , class_method = None , previous_correspondance = None ):
5153 """Initiate tracking
5254 """
5355 super (Correspondances , self ).__init__ ()
@@ -59,6 +61,7 @@ def __init__(self, datasets, virtual=0, class_method=None):
5961 self .class_method = EddiesObservations
6062 else :
6163 self .class_method = class_method
64+
6265 # To count ID
6366 self .current_id = 0
6467 # To know the number maximal of link between two state
@@ -76,10 +79,17 @@ def __init__(self, datasets, virtual=0, class_method=None):
7679 self .virtual = virtual > 0
7780 self .virtual_obs = None
7881 self .previous_virtual_obs = None
82+
83+ # Correspondance to prolongate
84+ self .filename_previous_correspondance = previous_correspondance
85+ self .previous_correspondance = self .load_compatible (self .filename_previous_correspondance )
86+
7987 if self .virtual :
8088 # Add field to dtype to follow virtual observations
8189 self .correspondance_dtype += [
90+ # True if it isn't a real obs
8291 ('virtual' , bool_ ),
92+ # Length of virtual segment
8393 ('virtual_length' , self .VIRTUAL_DTYPE )]
8494
8595 # Array to simply merged
@@ -93,6 +103,17 @@ def reset_dataset_cache(self):
93103 self .previous_obs = None
94104 self .current_obs = None
95105
106+ @property
107+ def period (self ):
108+ """To rethink
109+
110+ Returns: period coverage by obs
111+
112+ """
113+ date_start = num2date (julian2num (self .class_method .load_from_netcdf (self .datasets [0 ]).obs ['time' ][0 ] - 0.5 ))
114+ date_stop = num2date (julian2num (self .class_method .load_from_netcdf (self .datasets [- 1 ]).obs ['time' ][0 ] - 0.5 ))
115+ return date_start , date_stop
116+
96117 def swap_dataset (self , dataset ):
97118 """ Swap to next dataset
98119 """
@@ -138,6 +159,8 @@ def store_correspondance(self, i_previous, i_current, nb_real_obs):
138159 """
139160 # Create array to store correspondance data
140161 correspondance = array (i_previous , dtype = self .correspondance_dtype )
162+ if self .virtual :
163+ correspondance ['virtual_length' ][:] = 255
141164 # index from current_obs
142165 correspondance ['out' ] = i_current
143166
@@ -279,14 +302,33 @@ def recense_dead_id_to_extend(self):
279302 # Count
280303 self .virtual_obs ['segment_size' ][:] += 1
281304
305+ def load_state (self ):
306+ # If we have a previous file of correspondance, we will replay only recent part
307+ if self .previous_correspondance is not None :
308+ first_dataset = len (self .previous_correspondance .datasets )
309+ for correspondance in self .previous_correspondance [:first_dataset ]:
310+ self .append (correspondance )
311+ self .current_obs = self .class_method .load_from_netcdf (self .datasets [first_dataset - 2 ])
312+ flg_virtual = self .previous_correspondance .virtual
313+ with Dataset (self .filename_previous_correspondance ) as general_handler :
314+ self .current_id = general_handler .last_current_id
315+ # Load last virtual obs
316+ self .virtual_obs = VirtualEddiesObservations .from_netcdf (general_handler .groups ['LastVirtualObs' ])
317+ # Load and last previous virtual obs to be merge with current => will be previous2_obs
318+ self .current_obs = self .current_obs .merge (
319+ VirtualEddiesObservations .from_netcdf (general_handler .groups ['LastPreviousVirtualObs' ]))
320+ return first_dataset , flg_virtual
321+ return 1 , False
322+
282323 def track (self ):
283324 """Run tracking
284325 """
285- flg_virtual = False
286326 self .reset_dataset_cache ()
287- self .swap_dataset (self .datasets [0 ])
327+ first_dataset , flg_virtual = self .load_state ()
328+
329+ self .swap_dataset (self .datasets [first_dataset - 1 ])
288330 # We begin with second file, first one is in previous
289- for i , file_name in enumerate ( self .datasets [1 :]) :
331+ for file_name in self .datasets [first_dataset :] :
290332 self .swap_dataset (file_name )
291333 logging .debug ('%s match with previous state' , file_name )
292334 logging .debug ('%d obs to match' , len (self .current_obs ))
@@ -295,13 +337,11 @@ def track(self):
295337 if flg_virtual :
296338 logging .debug ('%d virtual obs will be add to previous' ,
297339 len (self .virtual_obs ))
298- # If you comment this the virtual fonctionnality will be
299- # disable
300340 self .previous_obs = self .previous_obs .merge (self .virtual_obs )
301-
302341 i_previous , i_current = self .previous_obs .tracking (
303342 self .current_obs )
304343
344+ # return true if the first time (previous2obs is none)
305345 if self .store_correspondance (i_previous , i_current , nb_real_obs ):
306346 continue
307347
@@ -310,9 +350,11 @@ def track(self):
310350 if self .virtual :
311351 flg_virtual = True
312352
313- def save (self , filename ):
353+ def save (self , filename , dict_completion = None ):
314354 self .prepare_merging ()
315355 nb_step = len (self .datasets ) - 1
356+ if isinstance (dict_completion , dict ):
357+ filename = filename .format (** dict_completion )
316358 logging .info ('Create correspondance file %s' , filename )
317359 with Dataset (filename , 'w' , format = 'NETCDF4' ) as h_nc :
318360 # Create dimensions
@@ -337,19 +379,46 @@ def save(self, filename):
337379
338380 for name , dtype in self .correspondance_dtype :
339381 if dtype is bool_ :
340- dtype = 'byte'
382+ dtype = 'u1'
383+ kwargs_cv = dict ()
384+ if 'u1' in dtype :
385+ kwargs_cv ['fill_value' ] = 255 ,
341386 h_nc .createVariable (zlib = True ,
342387 complevel = 1 ,
343388 varname = name ,
344389 datatype = dtype ,
345- dimensions = ('Nstep' , 'Nlink' ))
390+ dimensions = ('Nstep' , 'Nlink' ),
391+ ** kwargs_cv
392+ )
346393
347394 for i , correspondance in enumerate (self ):
348395 nb_elt = correspondance .shape [0 ]
349396 var_nb_link [i ] = nb_elt
350397 for name , _ in self .correspondance_dtype :
351398 h_nc .variables [name ][i , :nb_elt ] = correspondance [name ]
352- h_nc .virtual = int (self .virtual )
399+ h_nc .virtual_use = str (self .virtual )
400+ h_nc .virtual_max_segment = self .nb_virtual
401+ h_nc .last_current_id = self .current_id
402+ if self .virtual_obs is not None :
403+ group = h_nc .createGroup ('LastVirtualObs' )
404+ self .virtual_obs .to_netcdf (group )
405+ group = h_nc .createGroup ('LastPreviousVirtualObs' )
406+ self .previous_virtual_obs .to_netcdf (group )
407+ h_nc .module = self .class_method .__module__
408+ h_nc .classname = self .class_method .__qualname__
409+
410+ def load_compatible (self , filename ):
411+ if filename is None :
412+ return None
413+ previous_correspondance = Correspondances .load (filename )
414+ if self .nb_virtual != previous_correspondance .nb_virtual :
415+ raise Exception ('File of correspondance IN contains a different virtual segment size : file(%d), yaml(%d)' %
416+ (previous_correspondance .nb_virtual , self .nb_virtual ))
417+
418+ if self .class_method != previous_correspondance .class_method :
419+ raise Exception ('File of correspondance IN contains a different class method: file(%s), yaml(%s)' %
420+ (previous_correspondance .class_method , self .class_method ))
421+ return previous_correspondance
353422
354423 @classmethod
355424 def load (cls , filename ):
@@ -358,7 +427,11 @@ def load(cls, filename):
358427 datasets = list (h_nc .variables ['FileIn' ][:])
359428 datasets .append (h_nc .variables ['FileOut' ][- 1 ])
360429
361- obj = cls (datasets , h_nc .virtual )
430+ if hasattr (h_nc , 'module' ):
431+ class_method = getattr (__import__ (h_nc .module , globals (), locals (), h_nc .classname ), h_nc .classname )
432+ else :
433+ class_method = None
434+ obj = cls (datasets , h_nc .virtual_max_segment , class_method = class_method )
362435
363436 id_max = 0
364437 for i , nb_elt in enumerate (h_nc .variables ['nb_link' ][:]):
@@ -371,7 +444,8 @@ def load(cls, filename):
371444 for name , _ in obj .correspondance_dtype :
372445 if name == 'in' :
373446 continue
374- correspondance [name ] = h_nc .variables [name ][i , :nb_elt ]
447+ if name == 'virtual_length' :
448+ correspondance [name ] = 255
375449 correspondance [name ] = h_nc .variables [name ][i , :nb_elt ]
376450 id_max = max (id_max , correspondance ['id' ].max ())
377451 obj .append (correspondance )
0 commit comments