diff --git a/enstools/feature/identification/_proto_gen/african_easterly_waves_pb2.py b/enstools/feature/identification/_proto_gen/african_easterly_waves_pb2.py
index bd45a72bbdcb4ef1cebf4a3efc37b22f848826f2..b591be132cd95f966a9dca278dcbdb4d3bc645b9 100644
--- a/enstools/feature/identification/_proto_gen/african_easterly_waves_pb2.py
+++ b/enstools/feature/identification/_proto_gen/african_easterly_waves_pb2.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: tmpk72e7pki
+# source: tmprwd5lvhe
 """Generated protocol buffer code."""
 from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
@@ -13,10 +13,10 @@ _sym_db = _symbol_database.Default()
 
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmpk72e7pki\"(\n\x0cLatLonPoints\x12\x0b\n\x03lat\x18\x01 \x01(\x02\x12\x0b\n\x03lon\x18\x02 \x01(\x02\"E\n\x0b\x42oundingBox\x12\x1a\n\x03min\x18\x01 \x01(\x0b\x32\r.LatLonPoints\x12\x1a\n\x03max\x18\x02 \x01(\x0b\x32\r.LatLonPoints\"[\n\nProperties\x12\x1f\n\x08line_pts\x18\x01 \x03(\x0b\x32\r.LatLonPoints\x12\x18\n\x02\x62\x62\x18\x02 \x01(\x0b\x32\x0c.BoundingBox\x12\x12\n\nlength_deg\x18\x03 \x01(\x02\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmprwd5lvhe\"(\n\x0cLatLonPoints\x12\x0b\n\x03lat\x18\x01 \x01(\x02\x12\x0b\n\x03lon\x18\x02 \x01(\x02\"E\n\x0b\x42oundingBox\x12\x1a\n\x03min\x18\x01 \x01(\x0b\x32\r.LatLonPoints\x12\x1a\n\x03max\x18\x02 \x01(\x0b\x32\r.LatLonPoints\"[\n\nProperties\x12\x1f\n\x08line_pts\x18\x01 \x03(\x0b\x32\r.LatLonPoints\x12\x18\n\x02\x62\x62\x18\x02 \x01(\x0b\x32\x0c.BoundingBox\x12\x12\n\nlength_deg\x18\x03 \x01(\x02\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
 
 _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
-_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmpk72e7pki_pb2', globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmprwd5lvhe_pb2', globals())
 if _descriptor._USE_C_DESCRIPTORS == False:
 
   DESCRIPTOR._options = None
diff --git a/enstools/feature/identification/_proto_gen/overlap_example_pb2.py b/enstools/feature/identification/_proto_gen/overlap_example_pb2.py
index 1dc65f74ab9611a9ce441e7d59d5817baf325233..c6ecd0b1ca8e7dc67c6864c3ae7f5e80b9215902 100644
--- a/enstools/feature/identification/_proto_gen/overlap_example_pb2.py
+++ b/enstools/feature/identification/_proto_gen/overlap_example_pb2.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: tmpsoxyup23
+# source: tmpu6sz1ynm
 """Generated protocol buffer code."""
 from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
@@ -13,10 +13,10 @@ _sym_db = _symbol_database.Default()
 
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmpsoxyup23\"P\n\nProperties\x12\x19\n\x08\x63\x65ntroid\x18\x01 \x01(\x0b\x32\x07.Vector\x12\x0c\n\x04size\x18\x02 \x01(\x05\x12\x19\n\x11list_of_something\x18\x03 \x03(\t\")\n\x06Vector\x12\t\n\x01x\x18\x01 \x02(\x02\x12\t\n\x01y\x18\x02 \x02(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmpu6sz1ynm\"P\n\nProperties\x12\x19\n\x08\x63\x65ntroid\x18\x01 \x01(\x0b\x32\x07.Vector\x12\x0c\n\x04size\x18\x02 \x01(\x05\x12\x19\n\x11list_of_something\x18\x03 \x03(\t\")\n\x06Vector\x12\t\n\x01x\x18\x01 \x02(\x02\x12\t\n\x01y\x18\x02 \x02(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
 
 _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
-_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmpsoxyup23_pb2', globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmpu6sz1ynm_pb2', globals())
 if _descriptor._USE_C_DESCRIPTORS == False:
 
   DESCRIPTOR._options = None
diff --git a/enstools/feature/identification/_proto_gen/pv_streamer_pb2.py b/enstools/feature/identification/_proto_gen/pv_streamer_pb2.py
index a52dcb409d3a928bc20e49a0170919f05f5e9135..0488d4cef0cc26b3ecd8e824e433539192454422 100644
--- a/enstools/feature/identification/_proto_gen/pv_streamer_pb2.py
+++ b/enstools/feature/identification/_proto_gen/pv_streamer_pb2.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: tmpej52ncue
+# source: tmp6_1_l8ic
 """Generated protocol buffer code."""
 from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
@@ -13,10 +13,10 @@ _sym_db = _symbol_database.Default()
 
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmpej52ncue\"4\n\tVectorGeo\x12\r\n\x05level\x18\x64 \x01(\x02\x12\x0b\n\x03lat\x18\x65 \x01(\x02\x12\x0b\n\x03lon\x18\x66 \x01(\x02\")\n\x06Vector\x12\t\n\x01z\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01x\x18\x03 \x01(\x02\"\xf6\x02\n\nProperties\x12\x1c\n\x08\x63\x65ntroid\x18\x01 \x01(\x0b\x32\n.VectorGeo\x12\x12\n\nvolume_km3\x18\x02 \x01(\x02\x12\x13\n\x0bvolume_km2K\x18\x03 \x01(\x02\x12\x10\n\x08\x61rea_km2\x18\x04 \x01(\x02\x12\x1c\n\x08min_bbox\x18\x05 \x01(\x0b\x32\n.VectorGeo\x12\x1c\n\x08max_bbox\x18\x06 \x01(\x0b\x32\n.VectorGeo\x12\x0e\n\x06max_pv\x18\x07 \x01(\x02\x12\x0e\n\x06\x61vg_pv\x18\x08 \x01(\x02\x12\x11\n\tis_cutoff\x18\t \x01(\x08\x12\x0e\n\x06length\x18\n \x01(\x02\x12\x14\n\x0clength_ratio\x18\x0b \x01(\x02\x12\x1b\n\nmajor_axis\x18\x0c \x01(\x0b\x32\x07.Vector\x12\x1c\n\x0bmedium_axis\x18\r \x01(\x0b\x32\x07.Vector\x12\x1b\n\nminor_axis\x18\x0e \x01(\x0b\x32\x07.Vector\x12\"\n\x1amajor_axis_orientation_deg\x18\x0f \x01(\x02\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmp6_1_l8ic\"4\n\tVectorGeo\x12\r\n\x05level\x18\x64 \x01(\x02\x12\x0b\n\x03lat\x18\x65 \x01(\x02\x12\x0b\n\x03lon\x18\x66 \x01(\x02\")\n\x06Vector\x12\t\n\x01z\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01x\x18\x03 \x01(\x02\"\xf6\x02\n\nProperties\x12\x1c\n\x08\x63\x65ntroid\x18\x01 \x01(\x0b\x32\n.VectorGeo\x12\x12\n\nvolume_km3\x18\x02 \x01(\x02\x12\x13\n\x0bvolume_km2K\x18\x03 \x01(\x02\x12\x10\n\x08\x61rea_km2\x18\x04 \x01(\x02\x12\x1c\n\x08min_bbox\x18\x05 \x01(\x0b\x32\n.VectorGeo\x12\x1c\n\x08max_bbox\x18\x06 \x01(\x0b\x32\n.VectorGeo\x12\x0e\n\x06max_pv\x18\x07 \x01(\x02\x12\x0e\n\x06\x61vg_pv\x18\x08 \x01(\x02\x12\x11\n\tis_cutoff\x18\t \x01(\x08\x12\x0e\n\x06length\x18\n \x01(\x02\x12\x14\n\x0clength_ratio\x18\x0b \x01(\x02\x12\x1b\n\nmajor_axis\x18\x0c \x01(\x0b\x32\x07.Vector\x12\x1c\n\x0bmedium_axis\x18\r \x01(\x0b\x32\x07.Vector\x12\x1b\n\nminor_axis\x18\x0e \x01(\x0b\x32\x07.Vector\x12\"\n\x1amajor_axis_orientation_deg\x18\x0f \x01(\x02\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
 
 _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
-_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmpej52ncue_pb2', globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmp6_1_l8ic_pb2', globals())
 if _descriptor._USE_C_DESCRIPTORS == False:
 
   DESCRIPTOR._options = None
diff --git a/enstools/feature/identification/_proto_gen/storm_pb2.py b/enstools/feature/identification/_proto_gen/storm_pb2.py
index cd1cdde939e873066fa411059fc574a8d759f6b8..80b3a6d5543c9217f2a28c390b224ea099caa265 100644
--- a/enstools/feature/identification/_proto_gen/storm_pb2.py
+++ b/enstools/feature/identification/_proto_gen/storm_pb2.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: tmptzdfrp83
+# source: tmp5j9ikwmu
 """Generated protocol buffer code."""
 from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
@@ -13,10 +13,10 @@ _sym_db = _symbol_database.Default()
 
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmptzdfrp83\"\x1f\n\x03Pos\x12\x0b\n\x03lat\x18\x01 \x02(\x02\x12\x0b\n\x03lon\x18\x02 \x02(\x02\"B\n\nProperties\x12\x14\n\x0cmin_pressure\x18\x01 \x02(\x02\x12\x1e\n\x10min_pressure_pos\x18\x02 \x02(\x0b\x32\x04.Pos\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmp5j9ikwmu\"\x1f\n\x03Pos\x12\x0b\n\x03lat\x18\x01 \x02(\x02\x12\x0b\n\x03lon\x18\x02 \x02(\x02\"B\n\nProperties\x12\x14\n\x0cmin_pressure\x18\x01 \x02(\x02\x12\x1e\n\x10min_pressure_pos\x18\x02 \x02(\x0b\x32\x04.Pos\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
 
 _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
-_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmptzdfrp83_pb2', globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmp5j9ikwmu_pb2', globals())
 if _descriptor._USE_C_DESCRIPTORS == False:
 
   DESCRIPTOR._options = None
diff --git a/enstools/feature/identification/_proto_gen/template_pb2.py b/enstools/feature/identification/_proto_gen/template_pb2.py
index 86d1e7729b81b134c7ea89af353f4b410d891410..6bf872b1b54e9c0cfc67b032198b016e20c554a5 100644
--- a/enstools/feature/identification/_proto_gen/template_pb2.py
+++ b/enstools/feature/identification/_proto_gen/template_pb2.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: tmpfirnhda7
+# source: tmpopt40r92
 """Generated protocol buffer code."""
 from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
@@ -13,10 +13,10 @@ _sym_db = _symbol_database.Default()
 
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmpfirnhda7\"P\n\nProperties\x12\x19\n\x08\x63\x65ntroid\x18\x01 \x01(\x0b\x32\x07.Vector\x12\x0c\n\x04size\x18\x02 \x01(\x05\x12\x19\n\x11list_of_something\x18\x03 \x03(\t\")\n\x06Vector\x12\t\n\x01x\x18\x01 \x02(\x02\x12\t\n\x01y\x18\x02 \x02(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmpopt40r92\"P\n\nProperties\x12\x19\n\x08\x63\x65ntroid\x18\x01 \x01(\x0b\x32\x07.Vector\x12\x0c\n\x04size\x18\x02 \x01(\x05\x12\x19\n\x11list_of_something\x18\x03 \x03(\t\")\n\x06Vector\x12\t\n\x01x\x18\x01 \x02(\x02\x12\t\n\x01y\x18\x02 \x02(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
 
 _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
-_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmpfirnhda7_pb2', globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmpopt40r92_pb2', globals())
 if _descriptor._USE_C_DESCRIPTORS == False:
 
   DESCRIPTOR._options = None
diff --git a/enstools/feature/identification/_proto_gen/threshold_pb2.py b/enstools/feature/identification/_proto_gen/threshold_pb2.py
index f3a9ec9b844eaec5dbf2bf174cf90c1e707eb371..7ada12682434876d4f0274e95cab4fc43451d60f 100644
--- a/enstools/feature/identification/_proto_gen/threshold_pb2.py
+++ b/enstools/feature/identification/_proto_gen/threshold_pb2.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: tmp8j7ak3eo
+# source: tmprueqi544
 """Generated protocol buffer code."""
 from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
@@ -13,10 +13,10 @@ _sym_db = _symbol_database.Default()
 
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmp8j7ak3eo\"6\n\tMaskArray\x12\r\n\x05shape\x18\x01 \x03(\x05\x12\x0c\n\x04\x64\x61ta\x18\x02 \x02(\x0c\x12\x0c\n\x04zlib\x18\x03 \x02(\x08\"u\n\nProperties\x12\x18\n\x04mask\x18\x01 \x02(\x0b\x32\n.MaskArray\x12\x17\n\x0fouter_threshold\x18\x02 \x02(\x02\x12\x17\n\x0finner_threshold\x18\x03 \x02(\x02\x12\x1b\n\x13\x63omparison_operator\x18\x04 \x02(\t\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btmprueqi544\"6\n\tMaskArray\x12\r\n\x05shape\x18\x01 \x03(\x05\x12\x0c\n\x04\x64\x61ta\x18\x02 \x02(\x0c\x12\x0c\n\x04zlib\x18\x03 \x02(\x08\"u\n\nProperties\x12\x18\n\x04mask\x18\x01 \x02(\x0b\x32\n.MaskArray\x12\x17\n\x0fouter_threshold\x18\x02 \x02(\x02\x12\x17\n\x0finner_threshold\x18\x03 \x02(\x02\x12\x1b\n\x13\x63omparison_operator\x18\x04 \x02(\t\")\n\tVoxelData\x12\r\n\x05index\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"-\n\nVertexData\x12\x10\n\x08position\x18\x01 \x03(\x02\x12\r\n\x05value\x18\x02 \x01(\x02\"+\n\x08\x46\x61\x63\x65\x44\x61ta\x12\x10\n\x08vertices\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x02\"C\n\x13VoxelRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12\x1e\n\nvoxel_data\x18\x02 \x03(\x0b\x32\n.VoxelData\"D\n\x12LineRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\"f\n\x16\x42oundaryRepresentation\x12\x0c\n\x04\x64\x65sc\x18\x01 \x01(\t\x12 \n\x0bvertex_data\x18\x02 \x03(\x0b\x32\x0b.VertexData\x12\x1c\n\tface_data\x18\x03 \x03(\x0b\x32\t.FaceData\"2\n\tGraphNode\x12\x0c\n\x04time\x18\x01 \x02(\t\x12\x17\n\x06object\x18\x02 \x02(\x0b\x32\x07.Object\"K\n\x0fGraphConnection\x12\x1a\n\x06parent\x18\x01 \x02(\x0b\x32\n.GraphNode\x12\x1c\n\x08\x63hildren\x18\x02 \x03(\x0b\x32\n.GraphNode\".\n\x0bObjectGraph\x12\x1f\n\x05\x65\x64ges\x18\x01 \x03(\x0b\x32\x10.GraphConnection\"\xc2\x01\n\x06Object\x12\n\n\x02id\x18\x01 \x02(\x05\x12%\n\x08line_rep\x18\x02 \x03(\x0b\x32\x13.LineRepresentation\x12\'\n\tvoxel_rep\x18\x03 \x01(\x0b\x32\x14.VoxelRepresentation\x12-\n\x0c\x62oundary_rep\x18\x04 \x03(\x0b\x32\x17.BoundaryRepresentation\x12\x1f\n\nproperties\x18\x05 \x01(\x0b\x32\x0b.Properties\x12\x0c\n\x04\x66lag\x18\x06 \x01(\x08\"8\n\x08Timestep\x12\x12\n\nvalid_time\x18\x01 \x01(\t\x12\x18\n\x07objects\x18\x02 \x03(\x0b\x32\x07.Object\"\x99\x01\n\x0cTrackableSet\x12\x11\n\tinit_time\x18\x01 \x01(\t\x12\x0e\n\x06member\x18\x02 \x01(\r\x12\r\n\x05level\x18\x03 \x01(\x02\x12\x1c\n\ttimesteps\x18\x04 \x03(\x0b\x32\t.Timestep\x12\x1b\n\x05graph\x18\x05 \x01(\x0b\x32\x0c.ObjectGraph\x12\x1c\n\x06tracks\x18\x06 \x03(\x0b\x32\x0c.ObjectGraph\"_\n\x12\x44\x61tasetDescription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x66ile\x18\x02 \x01(\t\x12\x10\n\x08run_time\x18\x03 \x02(\t\x12\x1b\n\x04sets\x18\x04 \x03(\x0b\x32\r.TrackableSet')
 
 _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
-_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmp8j7ak3eo_pb2', globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tmprueqi544_pb2', globals())
 if _descriptor._USE_C_DESCRIPTORS == False:
 
   DESCRIPTOR._options = None
diff --git a/enstools/feature/identification/aew_vortices/configuration.py b/enstools/feature/identification/aew_vortices/configuration.py
index 9d9e2436f7090c94f0e310a606e8382fef44f913..3997a877effa549fcb79ce4714a3d24ddcfaa6f5 100644
--- a/enstools/feature/identification/aew_vortices/configuration.py
+++ b/enstools/feature/identification/aew_vortices/configuration.py
@@ -2,6 +2,7 @@
 from os.path import expanduser, join
 from datetime import timedelta
 import numpy as np
+import os
 
 # data area
 # latN = 35
@@ -12,15 +13,33 @@ import numpy as np
 in_data = "/home/ws/he7273/phd_all/data/coll_oper/jjaso2021.nc"
 in_wts = "/home/ws/he7273/phd_all/data/coll_oper/jjaso2021.json"
 
+circles_file = "/home/ws/he7273/phd_all/data/aew/circles.nc"
+fig_dir = '/home/ws/he7273/phd_all/data/vortices/figs'
+
 # plot_dir = '/home/ws/he7273/phd_all/data/coll_oper/' # '/project/meteo/w2w/C3/fischer/belanger/plots/' # join('/home/ws/he7273/phd_all/data/aew/plots/') # '/project/meteo/w2w/C3/fischer/belanger/plots/'
 
+field = 'rv'
+bpf = True
+
+fig_dir = fig_dir + '_' + ('bpf' if bpf else 'no_bpf') + '_' + field + '/'
+try:
+    os.makedirs(fig_dir)
+except:
+    print("Failed to create dir.")
+
 levels = [700, 850]  # 700 hPa
 u_dim = 'u'
 v_dim = 'v'
 
+base_threshold = {'cv': 3e-5, 'cva': 1e-5, 'rv': 3e-5}
+
 # time of interest, if None all
 # june-oct is AEW season
 
-start_date = '2021-09-01T00:00' # '2022-08-01T00:00' # None # '2008-08-01T00:00' #  # '2008-08-01T00:00'
-end_date = '2021-09-05T00:00' # '2022-08-15T00:00'  # None # '2008-08-15T00:00' # None # '2008-08-03T00:00'
+start_date = '2021-08-23T00:00'  # '2022-08-01T00:00' # None # '2008-08-01T00:00' #  # '2008-08-01T00:00'
+end_date = '2021-09-03T00:00'  # '2022-08-15T00:00'  # None # '2008-08-15T00:00' # None # '2008-08-03T00:00'
+
+radius = 500000  # 500 km
+prominence_radius = 400000  # 300 km
 
+## TODO CV INSTEAD
diff --git a/enstools/feature/identification/aew_vortices/identification.py b/enstools/feature/identification/aew_vortices/identification.py
index d5ceee27e764fb332fb66be9b48f9aaa9424a599..bf241d3410bfb1240d68aa106cec8677c0ef38aa 100644
--- a/enstools/feature/identification/aew_vortices/identification.py
+++ b/enstools/feature/identification/aew_vortices/identification.py
@@ -1,8 +1,11 @@
+import skimage.morphology
+
 from enstools.feature.identification import IdentificationStrategy
 import xarray as xr
 import numpy as np
 import os, sys
-from .util import compute_field, interpolate_wavetroughs, create_wt_troughs_and_areas
+from .util import compute_field, interpolate_wavetroughs, create_wt_troughs_and_areas, bpf
+from .plotting import plot_kw_style
 
 import json
 from types import SimpleNamespace
@@ -16,11 +19,12 @@ from skimage.draw import line_aa
 from enstools.feature.util.enstools_utils import get_u_var, get_v_var, get_vertical_dim, get_longitude_dim, get_latitude_dim, get_init_time_dim, get_valid_time_dim
 import threading
 from skimage.draw import line
-
+from IMTreatment.vortex_criterions import get_lambda2, get_gamma
+from IMTreatment.core import VectorField, ScalarField, SpatialScalarFields, SpatialVectorFields
 
 class AEWVortexIdentification(IdentificationStrategy):
 
-    def __init__(self, field='cv', bpf=False, **kwargs):
+    def __init__(self, **kwargs):
         """
         Initialize
 
@@ -28,14 +32,15 @@ class AEWVortexIdentification(IdentificationStrategy):
 
         import enstools.feature.identification.aew_vortices.configuration as cfg
         self.config = cfg  # config
-        self.field = field
-        self.bpf = bpf
+        self.field = self.config.field
+        self.bpf = self.config.bpf
         
         json_path = cfg.in_wts
         with open(json_path) as f:
             wt_data = json.load(f, object_hook=lambda x: SimpleNamespace(**x))
 
         self.json_desc = wt_data
+        self.circles = xr.load_dataset(self.config.circles_file).circles
 
         pass
 
@@ -88,7 +93,11 @@ class AEWVortexIdentification(IdentificationStrategy):
 
         # BPF (optional) TODO
         if self.bpf:
-            dataset = aew_bpf(dataset)
+            dataset = bpf(dataset, u_name, v_name, min_days=2, max_days=6)
+            self.config.u_dim = 'u_bpf'
+            self.config.v_dim = 'v_bpf'
+            u_name = 'u_bpf'
+            v_name = 'v_bpf'
 
         self.json_desc = interpolate_wavetroughs(self.json_desc, african_easterly_waves_pb2, self.pb_dataset)
 
@@ -99,8 +108,33 @@ class AEWVortexIdentification(IdentificationStrategy):
         data_field = dataset[self.field]
         dataset['vortices'] = xr.zeros_like(dataset[self.field], dtype=int)
 
+        """
+        l2 = xr.zeros_like(dataset[u_name], dtype=float)
+        for time in dataset.time.values:
+            print(time)
+            dt = dataset.sel(level=850, time=time)
+
+            sx = ScalarField()
+            sx.import_from_arrays(dt.latitude.values.tolist(), dt.longitude.values.tolist(), dt[u_name].data)
+            sy = ScalarField()
+            sy.import_from_arrays(dt.latitude.values.tolist(), dt.longitude.values.tolist(), dt[v_name].data)
+
+            v = VectorField()
+            v.import_from_sfs(sx, sy)
+
+            cur_l2 = get_gamma(v)
+            print(cur_l2)
+            l2.loc[dict(level=850, time=time)] = cur_l2.values
+        print(l2)
+        dataset['lambda2'] = l2
+        dataset['lambda2'].attrs['long_name'] = 'lambda2'
+        dataset['lambda2'].attrs['standard_name'] = 'l2'
+        dataset['lambda2'].attrs['units'] = 'dunno'
+        """
+
+        dataset = create_wt_troughs_and_areas(dataset, self.json_desc, self.circles, False, d=self.config.radius)
+
         # search local max.
-        # TODO make sure lat and lon are in back
         neighborhood = generate_binary_structure(2, 2)
         # TODO depending on num dimensions. here 4d, with latlon back.
         neighborhood = np.pad([[neighborhood]], ((1,1),(1,1),(0,0),(0,0)))
@@ -109,17 +143,29 @@ class AEWVortexIdentification(IdentificationStrategy):
         # find peaks can give better results
         # max_lat = find_peaks(data_field.values, np.greater, axis=-2) # if more sophisiticated:
         # max_lon = find_peaks(data_field.values, np.greater, axis=-1) #  scipy.signal.find_peaks
-        print(max_mask.shape)
+
         dataset['vortices'].data = max_mask
 
-        # TODO filter:
-        #   prob > 66% clim
-        #   cluster? only rep?
+        # out: set data to 1, fakes to 2
+        dataset['wt_rea'] = xr.where(dataset.wt_rea > 0, 1, dataset.wt_rea)
+        dataset['wt_rea'] = xr.where(dataset.wt_rea < 0, 2, dataset.wt_rea)
+        dataset['infl_rea'] = xr.where(dataset.infl_rea > 0, 1, dataset.infl_rea)
+        dataset['infl_rea'] = xr.where(dataset.infl_rea < 0, 2, dataset.infl_rea)
+
+        # FILTER by threshold given in config.
+        thr = self.config.base_threshold[self.field]
+        if self.bpf:
+            thr = thr / 2 # TODO?
+        dataset['vortices'] = xr.where(dataset[self.field] > thr, dataset.vortices, 0)
+        # FILTER by area -> in vicinity of WT
+        dataset['vortices'] = xr.where(dataset['infl_rea'] != 0, dataset.vortices, 0)
+        dataset['vortices'] = dataset.vortices.transpose(..., lat_str, lon_str)
+
+
+        # self.config.prominence_radius
+
 
-        dataset = create_wt_troughs_and_areas(dataset, self.json_desc, False)
 
-        dataset.to_netcdf("/home/ws/he7273/phd_all/data/coll_oper/jjaso2021_test.nc")
-        exit()
         # filter vortices somehow, before? prob need after
         # add them to WT descs.
 
@@ -130,15 +176,6 @@ class AEWVortexIdentification(IdentificationStrategy):
         # maybe depending on whether they form a track?
 
 
-
-
-
-        maxima.keep_where(wt_area) # WT Area range see Fink/Reiner?
-
-        # add vortices to tracks?
-
-
-
         #if self.config.cv_name not in dataset.data_vars:
         #    print("Curvature Vorticity not found, trying to compute it out of U and V...")
         #    dataset = compute_cv(dataset, u_name, v_name, self.config.cv_name)
@@ -157,7 +194,48 @@ class AEWVortexIdentification(IdentificationStrategy):
     def identify(self, data_chunk: xr.Dataset, **kwargs):
 
         objs = []
+        v = data_chunk.vortices
+
+        ds = data_chunk.stack(z=["latitude", "longitude"])
+        ds = ds.where(ds.vortices > 0, drop=True)
+
+        # TODO maybe create WT+area also in here, so we have direct reference to IDs
+        # CLUSTER
+        # prominence of 2deg -> keep if it is the max peak in a 2deg circle?
+        #                    -> or discard if any peak within 2deg is higher? or is this the same?
+        # For each vortex...
+        for z in range(len(ds.z.data)):
+            if ds.vortices[z].item() == 0:
+                print("skip?")
+                continue
+            lon_vortex = ds.longitude[z].item()
+            lat_vortex = ds.latitude[z].item()
+            data_vertex = ds[self.field][z].item()
+
+            circle = self.circles.sel(longitude_center=lon_vortex, latitude_center=lat_vortex)
+
+            # is this efficient? compare manually with all other vortex pts
+            for zc in range(len(ds.z.data)):
+                lon_vc = ds.longitude[zc].item()
+                lat_vc = ds.latitude[zc].item()
+                data_c = ds[self.field][zc].item()
+
+                distance_c = circle.sel(longitude=lon_vc, latitude=lat_vc).item()
+                # if distance in promenance radius and other point has higher vorticity -> delete this point.
+                if distance_c < self.config.prominence_radius and data_c > data_vertex: # TODO what happens if two with exactly the same cv?
+                    # vortex in vicinity is higher. discard this.
+                    v.loc[dict(longitude=lon_vortex, latitude=lat_vortex)] = 0
+                    break
+
+        # data_chunk.vortices.values = skimage.morphology.binary_dilation(data_chunk.vortices.values)
+
+        # for each vortex
+        #  associate with its corresponding WT
+        #  put into json
+
+
 
+        """
         id_ = 1
         for path in []:
 
@@ -174,9 +252,20 @@ class AEWVortexIdentification(IdentificationStrategy):
             # objs.append(o)
             # id_ += 1
             break
+        """
 
         return data_chunk, objs
 
     def postprocess(self, dataset: xr.Dataset, data_desc, **kwargs):
+
+
+        plot_kw_style(dataset, self.json_desc, self.config)
+        print(dataset)
+        dataset.to_netcdf("/home/ws/he7273/phd_all/data/coll_oper/jjaso2021_test.nc")
+        exit()
+        # add vortices to tracks?
+
+
+
         return dataset, data_desc
 
diff --git a/enstools/feature/identification/aew_vortices/plotting.py b/enstools/feature/identification/aew_vortices/plotting.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf7c5453c74dadc4be63c0d4732c0fd0ae830fb0
--- /dev/null
+++ b/enstools/feature/identification/aew_vortices/plotting.py
@@ -0,0 +1,165 @@
+import xarray as xr
+import numpy as np
+import json
+from matplotlib import pyplot as plt
+import matplotlib as mpl
+from matplotlib import patches
+import cartopy.crs as ccrs
+import cartopy.feature as cfeature
+from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
+from PIL import Image
+from datetime import datetime
+
+def get_kitweather_rain_cm():
+    rgb_colors = []
+    pathtotxtfile = '/home/he7273/phd_all/data/tracked/'
+    filename_colorpalette = 'colorpalette_dyamond_prec_rate.txt'
+
+    with open(pathtotxtfile + filename_colorpalette, 'r') as f:
+        lines = f.readlines()
+    for i, line in enumerate(lines):
+        rgb_colors.append([float(line[0:3])/255, float(line[4:7])/255, float(line[8:11])/255, 1])
+    rgb_colors = [[1, 1, 1, 0]] + rgb_colors + [[0.35, 0, 0.4, 1]]
+    cmap = mpl.colors.ListedColormap(rgb_colors[1:-1]) # , name=colorpalette
+    cmap = cmap.with_extremes(bad='white', under=rgb_colors[0], over=rgb_colors[-1])
+
+    levels = [0.1,0.2,0.3,0.5,1,2,3,5,10,20,30,50]
+    norm = mpl.colors.BoundaryNorm(levels, cmap.N)
+
+    return levels, cmap, norm
+
+def pb_str_to_datetime(time_str):
+    return datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S')
+
+def get_track_wts_of_time(dt, all_nodes):
+    nodes = [n for n in all_nodes if pb_str_to_datetime(n.time) == dt]
+    return nodes
+
+def crop_top_bottom_whitespace(path):
+
+    # pixels from image left where a vertical column is scanned from top and bottom for non-white pixels
+    x_scan_position = 450
+    add_bottom_delta = 20
+
+    im = Image.open(path)
+    image_array_y = np.where(np.asarray(im.convert('L')) < 255, 1, 0)[:, x_scan_position]
+    vmargins = [np.where(image_array_y[2:] == 1)[0][0] + 2 + 1,
+                image_array_y[:-2].shape[0] - np.where(image_array_y[:-2] == 1)[0][-1] + 2]
+    im_cropped = Image.new('RGBA',(im.size[0], im.size[1] - vmargins[0] - vmargins[1] + add_bottom_delta), (0, 0, 0, 0))
+    im_cropped.paste(im.crop((0, vmargins[0], im.size[0], im.size[1] - vmargins[1] + add_bottom_delta)), (0, 0))
+    im.close()
+    im_cropped.save(path, 'png')
+    im_cropped.close()
+
+    return
+
+
+def plot_kw_style(dataset, dataset_desc, config):
+    set_ = dataset_desc.sets[0]
+
+    all_nodes = [e.parent for track in set_.tracks for e in track.edges]
+
+    for tidx, t in enumerate(dataset.time.data):
+        time_dt = datetime.utcfromtimestamp(t.astype(datetime) / 1e9)
+        fig_name = time_dt.strftime("%Y%m%dT%H.png")
+
+        # get WTs which are part of tracks for current ts
+        wts = get_track_wts_of_time(time_dt, all_nodes)
+        print(wts)
+        ds_t = dataset.sel(time=t)
+
+        resolution = 1600
+        cbar_space_px = 80
+        subplotparameters = mpl.figure.SubplotParams(left=0, bottom=0, right=1 - cbar_space_px / resolution, top=1,
+                                                 wspace=0, hspace=0)
+        fig, ax = plt.subplots(figsize=(resolution / 100, resolution / 100),
+                           dpi=100,
+                           subplotpars=subplotparameters,
+                           subplot_kw=dict(projection=ccrs.PlateCarree()))
+
+        extent = [-75, 45, -10, 40]
+
+        levels_rain, rain_cm, norm = get_kitweather_rain_cm()
+        distance_plot_to_cbar = 0.010
+        axins = ax.inset_axes([1 + distance_plot_to_cbar, 0.05, 0.015, 0.93],
+                          transform=ax.transAxes)
+        ticks_list = levels_rain
+        cbar = fig.colorbar(mpl.cm.ScalarMappable(cmap=rain_cm, norm=norm),
+                        cax=axins, extend='both', extendfrac=0.03,
+                        ticks=ticks_list)
+        unit_text = 'mm/hr'
+        y_off = -0.06
+        axins.text(0.25, y_off, unit_text, transform=axins.transAxes,
+               horizontalalignment='left', verticalalignment='center')
+
+        # field contour
+        levels = np.linspace(0, 1e-4, 50)
+
+        ds_t[config.field].sel(level=850).plot.contourf(levels=levels, cmap='viridis', subplot_kws={'transform_first': True})
+
+        """
+        ds_t.sel(level=700).plot.streamplot(x='longitude', y='latitude',
+                                            u=config.u_dim, v=config.v_dim,
+                           linewidth=0.6,
+                           arrowsize=0.5,
+                           density=6,
+                           color='blue')  # , transform_first=True not working, or is already implemented. still slow.
+        """
+
+        ds_t.sel(level=850).plot.streamplot(x='longitude', y='latitude',
+                                            u=config.u_dim, v=config.v_dim,
+                                            linewidth=0.3,
+                                            arrowsize=0.3,
+                                            density=8,
+                                            color='red')
+
+
+
+    # generate plot per pressure level, per time step
+
+        for obj_idx, node in enumerate(wts):
+            line_pts = node.object.properties.linePts
+            line = patches.Path([[p.lon, p.lat] for p in line_pts])
+
+            if node.object.id == -1:
+                patch = patches.PathPatch(line, linewidth=3, facecolor='none', edgecolor='orange')  # cmap(time_weight)
+            else:
+                patch = patches.PathPatch(line, linewidth=3, facecolor='none', edgecolor='green')  # cmap(time_weight)
+
+            ax.add_patch(patch)
+
+        # plot vortices
+        # ds_t.sel(level=700).vortices.plot.contourf(levels=[-0.5,0.5,99], colors=('#00000000', 'blue'), subplot_kws={'transform_first': True}, add_colorbar=False)
+        ds_t.sel(level=850).vortices.plot.contourf(levels=[-0.5,0.5,99], colors=('#00000000', 'orange'), subplot_kws={'transform_first': True}, add_colorbar=False)
+
+        # ds_t.prec_rate_rea.plot.contourf(levels=levels_rain, extend='max', subplot_kws={'transform_first': True},
+        #                  cmap=rain_cm, norm=norm, add_colorbar=False)
+
+        # ax.coastlines()
+        ax.add_feature(cfeature.BORDERS.with_scale('50m'), linewidth=0.3)
+        ax.add_feature(cfeature.COASTLINE.with_scale('50m'), linewidth=0.3)
+        ax.set_extent(extent, crs=ccrs.PlateCarree())
+        ax.add_feature(cfeature.LAND.with_scale('50m'), facecolor=list(np.array([255, 225, 171]) / 255))
+
+        ax.get_xaxis().set_ticklabels([])
+        ax.get_yaxis().set_ticklabels([])
+
+        gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=0.5, color='gray', alpha=0.5, linestyle='--')
+        gl.top_labels = False
+        gl.right_labels = False
+        gl.xformatter = LONGITUDE_FORMATTER
+        gl.yformatter = LATITUDE_FORMATTER
+
+        ax.set_title("")
+        fig.tight_layout()
+
+        plt.savefig(config.fig_dir + fig_name, format='png', backend='agg')
+
+        plt.close(fig)
+        crop_top_bottom_whitespace(config.fig_dir + fig_name)
+
+        print("Saved to " + fig_name)
+
+
+
+# for each timestep...
\ No newline at end of file
diff --git a/enstools/feature/identification/aew_vortices/run_identify.py b/enstools/feature/identification/aew_vortices/run_identify.py
index 9f546537634e37280da4b260bf3d52546d751f90..4065be0db5176b6e39769d8e21ea0902e1d07f5e 100644
--- a/enstools/feature/identification/aew_vortices/run_identify.py
+++ b/enstools/feature/identification/aew_vortices/run_identify.py
@@ -24,7 +24,7 @@ in_desc = cfg.in_wts
 pipeline.set_data_path(in_file)
 
 # init AEWIdentification strategy, can take different parameters
-i_strat = AEWVortexIdentification(field='cv', bpf=False)
+i_strat = AEWVortexIdentification()
 # t_strat = SomeTracking()
 
 pipeline.set_identification_strategy(i_strat)
diff --git a/enstools/feature/identification/aew_vortices/util.py b/enstools/feature/identification/aew_vortices/util.py
index 7e8dbd820b5fe5dcf86bc7416851ac8317bbac2a..565354eeefeb059d27bbe1c7b1f4128363a696e6 100644
--- a/enstools/feature/identification/aew_vortices/util.py
+++ b/enstools/feature/identification/aew_vortices/util.py
@@ -5,9 +5,11 @@ import math, json
 from enstools.feature.util.enstools_utils import get_u_var, get_v_var, get_vertical_dim, get_longitude_dim, \
     get_latitude_dim
 from skimage.draw import line
-from enstools.feature.util.data_utils import clip, pb_str_to_datetime64, datetime64_to_pb_str, get_json, pb_str_to_datetime
+from enstools.feature.util.data_utils import simplenamespace_to_proto, clip, pb_str_to_datetime64, datetime64_to_pb_str, proto_to_json, proto_to_simplenamespace, pb_str_to_datetime
 from types import SimpleNamespace
 from google.protobuf import json_format
+from scipy.signal import butter, lfilter, sosfiltfilt
+
 
 # calculates the dx's and dy's for each grid cell
 # takes list of latitudes and longitudes as input and returns field with dimensions len(lats) x len(lons)
@@ -75,6 +77,7 @@ def compute_vort(dataset, vtype, u_str, v_str, field_str):
     if vtype == 'relative':
         dataset[field_str].values = RV
         dataset[field_str].attrs = {'long_name': "Relative Vorticity", 'units': "s**-1"}
+        dataset[field_str] = dataset[field_str].chunk({lat_str: len(lats), lon_str: len(lons)})
         return dataset
 
 
@@ -106,6 +109,7 @@ def compute_vort(dataset, vtype, u_str, v_str, field_str):
     if vtype == 'shear':
         dataset[field_str].values = SV
         dataset[field_str].attrs = {'long_name': "Shear Vorticity", 'units': "s**-1"}
+        dataset[field_str] = dataset[field_str].chunk({lat_str: len(lats), lon_str: len(lons)})
         return dataset
 
     # remainder is CV
@@ -113,6 +117,7 @@ def compute_vort(dataset, vtype, u_str, v_str, field_str):
     if vtype == 'curvature':
         dataset[field_str].values = CV
         dataset[field_str].attrs = {'long_name': "Curvature Vorticity", 'units': "s**-1"}
+        dataset[field_str] = dataset[field_str].chunk({lat_str: len(lats), lon_str: len(lons)})
         return dataset
     return None
 
@@ -137,24 +142,22 @@ def compute_field(dataset, u_str, v_str, field_name):
 def create_fake_wt_edges(edge, child_idx, pb_ref, pb_desc):
     # make multiple edges out of this one
 
+
     parent_node = edge.parent
-    parent_node_pb = json_format.Parse(json.dumps(get_json(parent_node)), pb_ref.GraphNode(), ignore_unknown_fields=False)
+    parent_node_pb = simplenamespace_to_proto(parent_node, pb_ref.GraphNode())
     child_node = edge.children[child_idx]
-    child_node_pb = json_format.Parse(json.dumps(get_json(child_node)), pb_ref.GraphNode(), ignore_unknown_fields=False)
+    child_node_pb = simplenamespace_to_proto(child_node, pb_ref.GraphNode())
 
     parent_node_time = pb_str_to_datetime64(parent_node.time)
     child_node_time = pb_str_to_datetime64(child_node.time)
 
     delt = child_node_time - parent_node_time
-    print(delt)
     if delt != np.timedelta64(12, 'h'):
         print("NO 12h abort")
         print(delt)
-    else:
-        print("12h")
+        exit(1)
 
     fake_node_time = parent_node_time + 0.5 * delt # TODO assert only skip 1
-    parent_json = get_json(parent_node)
 
     # create fake node as copy of parent
     fake_node = pb_ref.GraphNode() # json_format.Parse(json.dumps(parent_json), pb_ref.GraphNode(), ignore_unknown_fields=False)
@@ -165,8 +168,8 @@ def create_fake_wt_edges(edge, child_idx, pb_ref, pb_desc):
     fake_node.object.flag = False
 
     # set properties: bb as mean of parent and child
-    parent_props = fake_node.object.properties
-    child_props = fake_node.object.properties
+    parent_props = parent_node.object.properties
+    child_props = child_node.object.properties
     fake_props = fake_node.object.properties
 
     fake_props.bb.min.lat = (parent_props.bb.min.lat + child_props.bb.min.lat) / 2.0
@@ -182,6 +185,8 @@ def create_fake_wt_edges(edge, child_idx, pb_ref, pb_desc):
     fake_props.line_pts[1].lat = fake_props.bb.max.lat
     fake_props.line_pts[1].lon = avg_lon
 
+    fake_props.length_deg = math.sqrt((fake_props.bb.max.lat - fake_props.bb.min.lat) ** 2 + (fake_props.bb.max.lon - fake_props.bb.min.lon) ** 2)
+
     # new edge:
     edge1 = pb_ref.GraphConnection()
     edge1.parent.CopyFrom(parent_node_pb)
@@ -211,25 +216,68 @@ def interpolate_wavetroughs(json_desc, pb_ref, pb_desc):
                     child_node_time = pb_str_to_datetime64(child_node.time)
 
                     if child_node_time - parent_node_time > np.timedelta64(6, 'h'):
-                        print("skipper")
+                        if "2021-09-01T12:00:00" == parent_node.time:
+                            print("a")
+                        if "2021-09-01T18:00:00" == parent_node.time:
+                            print("a")
+                        if "2021-09-02T00:00:00" == parent_node.time:
+                            print("a")
+                        print("Add fake WT at " + parent_node.time)
                         wt_edges = create_fake_wt_edges(edge, child_idx, pb_ref, pb_desc)
                         # old_edges.append((edge, child_idx))
                         new_edges.extend(wt_edges)
-                    else:
-                        print("non skipper")
+
 
             # TODO dont remove edges for now, quite complicated with splits. lets have transitives instead
             # remove old_edges from this track and from graph
 
-            track.edges.extend(new_edges)
-            set_.graph.edges.extend(new_edges)
+            new_edges_sn = [proto_to_simplenamespace(e) for e in new_edges]
+            track.edges.extend(new_edges_sn) # TODO sort
+            track.edges.sort(key=lambda item: item.parent.time)
+
+            set_.graph.edges.extend(new_edges_sn)
+            set_.graph.edges.sort(key=lambda item: item.parent.time)
             # print("EOT")
             # not to TS!
 
     return json_desc
 
+def butter_bandpass(lowcut, highcut, fs, order=5):
+    nyq = 0.5 * fs
+    low = lowcut / nyq
+    high = highcut / nyq
+    sos = butter(order, [low, high], analog=False, btype='band', output='sos')
+    return sos
+
+
+def butter_bandpass_filter(data, lowcut, highcut, fs, order=5, axis=-1):
+    sos = butter_bandpass(lowcut, highcut, fs, order=order)
+    y = sosfiltfilt(sos, data, axis=axis)
+    return y
+
+
+def bpf(dataset, u_str, v_str, min_days=2, max_days=6): # 2-6day bpf as default
+    time_res_hrs = (dataset.coords['time'].values[1] - dataset.coords['time'].values[0]).astype(
+        'timedelta64[h]') / np.timedelta64(1, 'h')  # 6 if 6hrly
+    time_res_days = time_res_hrs / 24.0  # 6/24 = 1/4
+    print("Execute bpf for " + str(min_days) + " to " + str(max_days) + " days.")
 
-def create_wt_troughs_and_areas(dataset, in_json, use_fc):
+    u_filtered = butter_bandpass_filter(dataset[u_str].data, time_res_days / 6, time_res_days / 2, 1, axis=0)  # time is dim0
+    v_filtered = butter_bandpass_filter(dataset[v_str].data, time_res_days / 6, time_res_days / 2, 1, axis=0)  # time is dim0
+
+    u_bpf = xr.zeros_like(dataset[u_str])
+    v_bpf = xr.zeros_like(dataset[v_str])
+    u_bpf.data = u_filtered
+    v_bpf.data = v_filtered
+
+    # u_bpf = ds.u.filter.bandpass([time_res_days/6, time_res_days/2], dim='time') # 2-6 days
+    # v_bpf = ds.v.filter.bandpass([time_res_days/6, time_res_days/2], dim='time')
+
+    dataset['u_bpf'] = u_bpf
+    dataset['v_bpf'] = v_bpf
+    return dataset
+
+def create_wt_troughs_and_areas(dataset, in_json, circles, use_fc, d=500000): # 500 km?
     print("Create WT lines...")
 
     if use_fc:
@@ -239,6 +287,7 @@ def create_wt_troughs_and_areas(dataset, in_json, use_fc):
         # dataset['wt_fc'] = xr.zeros_like(dataset.u700_fc, dtype=int)
     else:
         dataset['wt_rea'] = xr.zeros_like(dataset.u.isel(level=0).squeeze(), dtype=int)
+        dataset['infl_rea'] = xr.zeros_like(dataset.u.isel(level=0).squeeze(), dtype=int)
 
         #  for ts in ana_set.timesteps:
 
@@ -249,6 +298,9 @@ def create_wt_troughs_and_areas(dataset, in_json, use_fc):
     lons = len(dataset.longitude.data)
     lats = len(dataset.latitude.data)
 
+    wt_rea = dataset.wt_rea
+    infl_rea = dataset.infl_rea
+
     for wt_set in in_json.sets:
 
         cur_set = wt_set
@@ -264,7 +316,7 @@ def create_wt_troughs_and_areas(dataset, in_json, use_fc):
 
             for node in track_nodes:
 
-                vt = node.validTime
+                vt = node.time
                 """
                 try:
                 if use_fc:
@@ -272,11 +324,18 @@ def create_wt_troughs_and_areas(dataset, in_json, use_fc):
                     wt_da = set_ds.wt_fc.sel(step=diff_time)
                 else:
                 """
-                wt_da = set_ds.wt_rea.sel(time=vt)
+                try:
+                    wt_da = wt_rea.sel(time=vt)
+                    infl_da = infl_rea.sel(time=vt)
+                except KeyError:
+                    print("Skipping timestep (not in dataset) " + str(vt))
+                    continue
                 #except KeyError:
                 #continue
 
-                props = node.properties
+                props = node.object.properties
+                if not hasattr(props, 'linePts'):
+                    print("?")
 
                 for v_idx in range(len(props.linePts) - 1):
                     start_lonlat = props.linePts[v_idx].lon, props.linePts[v_idx].lat
@@ -294,21 +353,21 @@ def create_wt_troughs_and_areas(dataset, in_json, use_fc):
                     rr = clip(rr, 0, lons - 1)
                     cc = clip(cc, 0, lats - 1)
 
-                    wt_da.data[cc, rr] = wt.id
-
-                    lons_along_wt = lons_from(cc)
-                    lats_along_wt = lats_from(rr)
+                    wt_da.values[cc, rr] = node.object.id
 
                     # make circle
-                    for px_idx in range(len(lons_along_wt)):
+                    for px_idx in range(len(rr)):
 
-                        circle = circles.sel(longitude_center=lons_along_wt[px_idx], latitude_center=lats_along_wt[px_idx])
-                        influence_area = circle.where(circle < d, 0)
-
-                        circle_da = xr.where(influence_area, wt.id, circle_da)
+                        circle = circles.isel(longitude_center=rr[px_idx], latitude_center=cc[px_idx])
+                        influence_area = circle.where(circle < d, -1)
 
+                        # update influence area dataarray
+                        infl_da = xr.where(influence_area >= 0, node.object.id, infl_da)
 
+                wt_rea.loc[dict(time=vt)] = wt_da.values
+                infl_rea.loc[dict(time=vt)] = infl_da.values
 
+    return dataset
 
 """
 # from wavetrough line expand by d meters TODO also ahead on land. -> just also on trough and then shift ahead?
diff --git a/enstools/feature/identification/identification.proto b/enstools/feature/identification/identification.proto
index 805045f9d3a0b876d7f154ee6b1b57abb3670263..86d1f13d6aca198f7e64016af1573fc0192ec31f 100644
--- a/enstools/feature/identification/identification.proto
+++ b/enstools/feature/identification/identification.proto
@@ -44,6 +44,7 @@ message GraphNode {
 
 /* Connections of the tracking graph. A connection is defined as one node (parent, the key object),
    and all to its connected nodes. (list of children, typically of the consecutive timestep)
+   TODO maybe rewrite to allow only single children (1 connection)
  */
 message GraphConnection {
   required GraphNode parent = 1;
diff --git a/enstools/feature/tracking/african_easterly_waves/tracking.py b/enstools/feature/tracking/african_easterly_waves/tracking.py
index af1c6439da23384fb20acc91782da2465e89b832..63599a70ef7564ca8337ae37634054c685185436 100644
--- a/enstools/feature/tracking/african_easterly_waves/tracking.py
+++ b/enstools/feature/tracking/african_easterly_waves/tracking.py
@@ -145,8 +145,39 @@ class AEWTracking(ObjectComparisonTracking):
                 # us_nodes = get_upstream_nodes_at_time(t)
                 # nodes_in_path_ab = cut(ds_nodes, us_nodes)
 
+
         # then generate_tracks()
         kept_edges = [edge for x, edge in enumerate(track.edges) if keep_node[x]]
+        # add back empty parent nodes:
+
+
+        # heuristic fix: if x1->n and x2->n and times t(x1) < t(x2) < t(n)
+        # reconnect to x1->x2, x2->n
+        added_t_edges = False
+        for edge1 in kept_edges:
+            edge1_to_add = []
+            x1 = edge1.parent
+            x1t = pb_str_to_datetime(x1.time)
+            for edge2 in kept_edges:
+                if edge1 == edge2:
+                    continue
+
+                x2 = edge2.parent
+                x2t = pb_str_to_datetime(x2.time)
+                n = [ch for ch in edge1.children if ch in edge2.children] # common children
+
+                if len(n) > 1:
+                    print("More than 1 common child? Pick first.")
+                if len(n) == 0:
+                    continue
+                nt = pb_str_to_datetime(n[0].time)
+
+                if x1t < x2t < nt:
+                    added_t_edges = True
+                    edge1_to_add.append(x2)
+
+            edge1.children.extend(edge1_to_add)
+
         # regenerate tracks out of leftover edges. this also splits a track etc, and removes short ones
 
         # create return object
@@ -157,9 +188,10 @@ class AEWTracking(ObjectComparisonTracking):
         reduced_tg.graph.edges.extend(kept_edges)
 
         # clean up -> degenerate nodes (child without connections)
-        dg = DataGraph(reduced_tg, self, fix=True)
+        dg = DataGraph(reduced_tg, self, fix=True, remove_transitive=True)
         # if dg nodes same as input to this method, nothing changed, dont regenerate tracks.
         # otherwise stuck in infinite loop
+        # Also dont regenerate if added edges by above heuristic, tracks are still the same.
         if len(dg.graph.edges) == len(tracking_graph.graph.edges):
             dg.set_desc.tracks.append(dg.set_desc.graph)
             print("Nothing changed.")
@@ -168,7 +200,4 @@ class AEWTracking(ObjectComparisonTracking):
         print("Regenerate.")
         dg.generate_tracks(apply_filter=True)
 
-        # TODO
-        #   redo clim, plot which WTs not considered
-
         return dg
diff --git a/enstools/feature/tracking/tracking.py b/enstools/feature/tracking/tracking.py
index 157498f843d9553edc0995fc4dfed8d93f60cb0e..c468b1f1a2014750828a2880873ebdad82ba97d6 100644
--- a/enstools/feature/tracking/tracking.py
+++ b/enstools/feature/tracking/tracking.py
@@ -94,7 +94,7 @@ class TrackingStrategy(ABC):
         cons = sorted(cons, key=lambda c: c.parent.time)
 
         # remove transitive edges: a->b->c and a->c --> remove the a->c node
-        cons = TrackingStrategy.remove_transitive(cons)  # TODO more efficient maybe?
+        cons = TrackingStrategy.remove_transitive(cons, self.pb_reference)  # TODO more efficient maybe?
         # add graph nodes to ref graph
         obj_set.graph.edges.extend(cons)
 
@@ -158,7 +158,11 @@ class TrackingStrategy(ABC):
                 continue
 
             # get index of connected node in graph
-            c_node_idx = obj_node_list.index(c_node)
+            try:
+                c_node_idx = obj_node_list.index(c_node)
+            except ValueError:
+                print("Could not find children node as a parent node. Skip.")
+                continue
 
             # call recursively on this connected node
             c_node_downstream_indices = TrackingStrategy.get_downstream_node_indices(graph_list, c_node_idx,
@@ -244,10 +248,18 @@ class TrackingStrategy(ABC):
         return new_connection
 
     @staticmethod
-    def remove_transitive(connections):
+    def remove_transitive(connections, pb_ref):
+        # make deep copy
+
+        new_connections = []
+        for con in connections:
+            new_con = pb_ref.GraphConnection()
+            new_con.ParseFromString(con.SerializeToString())
+            new_connections.append(con)
+
         tn = 0
         # an edge is transitive (a->c if a->b->c exists), when the downstream nodes of "a" without this edge contains the end node ("c")
-        for con_id, con in enumerate(connections):
+        for con_id, con in enumerate(new_connections):
 
             children = con.children[:]
             # cant be transitive edge if only one child
@@ -257,9 +269,9 @@ class TrackingStrategy(ABC):
                 child_time = pb_str_to_datetime(cld.time)
                 con.children.remove(cld)  # remove edge temporarily
                 # and check if downstream nodes still contains end node of edge. if yes -> transitive
-                downstream_idxs = TrackingStrategy.get_downstream_node_indices(connections, con_id,
+                downstream_idxs = TrackingStrategy.get_downstream_node_indices(new_connections, con_id,
                                                                                 until_time=child_time)
-                downstream_objs = [connections[ds_idx].parent for ds_idx in downstream_idxs]
+                downstream_objs = [new_connections[ds_idx].parent for ds_idx in downstream_idxs]
                 if cld in downstream_objs:
                     # transitive
                     tn = tn + 1
@@ -268,6 +280,6 @@ class TrackingStrategy(ABC):
                     con.children.append(cld)
 
         print("Removed " + str(tn) + " transitive edges in current set.")
-        return connections
+        return new_connections
 
 # TODO what if tracks are the identification? e.g. AEW identification in Hovmoller
diff --git a/enstools/feature/util/data_utils.py b/enstools/feature/util/data_utils.py
index 7f720bf7c1befbba749ff8d8ec112a377839d0f2..3b4213ac26d0bd3bddaa989e191ceab3c0af8032 100644
--- a/enstools/feature/util/data_utils.py
+++ b/enstools/feature/util/data_utils.py
@@ -7,7 +7,10 @@ from enstools.feature.util.enstools_utils import get_vertical_dim, get_init_time
     get_latitude_dim, get_possible_time_dims, get_valid_time_dim
 from multiprocessing import Lock
 import pandas as pd
+from types import SimpleNamespace
 lock = Lock()
+from google.protobuf.json_format import MessageToJson
+from google.protobuf import json_format
 
 class SplitDimension:
     """
@@ -261,13 +264,28 @@ def pb_str_to_datetime64(time_str):
     dt = datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S')
     return np.datetime64(dt)
 
-def get_json(obj):
+def proto_to_json(obj):
     """
-    Convert objects (e.g. proto) to json recursively.
+    Convert proto to json recursively.
     """
-    return json.loads(
-            json.dumps(obj, default=lambda o: getattr(o, '__dict__', str(o)))
-    )
+    return MessageToJson(obj)
+
+def proto_to_simplenamespace(obj):
+    """
+        Convert proto to SimpleNamespace recursively.
+        """
+    j = MessageToJson(obj)
+    sn = json.loads(j, object_hook=lambda d: SimpleNamespace(**d))
+    return sn
 
 def clip(tup, mint, maxt):
-    return np.clip(tup, mint, maxt)
\ No newline at end of file
+    return np.clip(tup, mint, maxt)
+
+def simplenamespace_to_json(sn):
+    return json.dumps(sn, default=lambda s: vars(s))
+
+def simplenamespace_to_proto(sn, proto_obj):
+
+    json_str = simplenamespace_to_json(sn)
+    pb = json_format.Parse(json_str, proto_obj, ignore_unknown_fields=False)
+    return pb
\ No newline at end of file
diff --git a/enstools/feature/util/graph.py b/enstools/feature/util/graph.py
index 7ba7f6150a4238b47e45b896d2486d6f9df58d8f..f360ca20bd3f269e54efe5d6a7dee6368a9f22c6 100644
--- a/enstools/feature/util/graph.py
+++ b/enstools/feature/util/graph.py
@@ -1,5 +1,5 @@
 from enstools.feature.util.data_utils import pb_str_to_datetime
-
+from enstools.feature.tracking import TrackingStrategy
 
 class DataGraph:
     """
@@ -15,7 +15,7 @@ class DataGraph:
     To generate tracks, an instance of the latter one is needed.
     """
 
-    def __init__(self, set_desc=None, tr_tech=None, track=None, fix=False):
+    def __init__(self, set_desc=None, tr_tech=None, track=None, fix=False, remove_transitive=False):
         self.set_desc = set_desc
 
         # sort the edges in the graph by time.
@@ -30,7 +30,7 @@ class DataGraph:
         self.tr_tech = tr_tech
 
         if fix:
-            self.fix_graph()
+            self.fix_graph(remove_transitive=remove_transitive)
 
 
     def get_earliest_nodes(self):
@@ -79,7 +79,7 @@ class DataGraph:
 
         return nodes
 
-    def fix_graph(self):
+    def fix_graph(self, remove_transitive=False):
         """
         Fixes graph by removing orphaned edges. (Edges where endnode is not a valid node)
 
@@ -93,6 +93,13 @@ class DataGraph:
                 if child not in nodes:
                     edge.children.remove(child)
 
+        if remove_transitive:
+            non_tr_edges = TrackingStrategy.remove_transitive(self.graph.edges, self.tr_tech.pb_reference)
+            del self.graph.edges[:]
+            self.graph.edges.extend(non_tr_edges)
+
+
+
     def get_parents(self, node):
         """
         Get the parents of a node (previous timestep)