Source code for py_eddy_tracker.appli.network

# -*- coding: utf-8 -*-
"""
Entry point to create and manipulate observations network
"""

import logging

from numpy import in1d, zeros

from .. import EddyParser
from ..observations.network import Network, NetworkObservations
from ..observations.tracking import TrackEddiesObservations

logger = logging.getLogger("pet")


[docs]def build_network(): parser = EddyParser("Merge eddies") parser.add_argument( "identification_regex", help="Give an expression which will use with glob" ) parser.add_argument("out", help="output file") parser.add_argument( "--window", "-w", type=int, help="Half time window to search eddy", default=1 ) parser.add_argument( "--min-overlap", "-p", type=float, help="minimum overlap area to associate observations", default=0.2, ) parser.add_argument( "--minimal-area", action="store_true", help="If True, use intersection/little polygon, else intersection/union", ) parser.add_argument( "--hybrid-area", action="store_true", help="If True, use minimal-area method if overlap is under min overlap, else intersection/union", ) parser.contour_intern_arg() parser.memory_arg() args = parser.parse_args() n = Network( args.identification_regex, window=args.window, intern=args.intern, memory=args.memory, ) group = n.group_observations( min_overlap=args.min_overlap, minimal_area=args.minimal_area, hybrid_area=args.hybrid_area ) n.build_dataset(group).write_file(filename=args.out)
[docs]def divide_network(): parser = EddyParser("Separate path for a same group (network)") parser.add_argument("input", help="input network file") parser.add_argument("out", help="output file") parser.contour_intern_arg() parser.add_argument( "--window", "-w", type=int, help="Half time window to search eddy", default=1 ) parser.add_argument( "--min-overlap", "-p", type=float, help="minimum overlap area to associate observations", default=0.2, ) parser.add_argument( "--minimal-area", action="store_true", help="If True, use intersection/little polygon, else intersection/union", ) parser.add_argument( "--hybrid-area", action="store_true", help="If True, use minimal-area method if overlap is under min overlap, else intersection/union", ) args = parser.parse_args() contour_name = TrackEddiesObservations.intern(args.intern, public_label=True) e = TrackEddiesObservations.load_file( args.input, include_vars=("time", "track", "latitude", "longitude", *contour_name), ) n = NetworkObservations.from_split_network( TrackEddiesObservations.load_file(args.input, raw_data=True), e.split_network( intern=args.intern, window=args.window, min_overlap=args.min_overlap, minimal_area=args.minimal_area, hybrid_area=args.hybrid_area ), ) n.write_file(filename=args.out)
[docs]def subset_network(): parser = EddyParser("Subset network") parser.add_argument("input", help="input network file") parser.add_argument("out", help="output file") parser.add_argument( "-l", "--length", nargs=2, type=int, help="Nb of days that must be covered by the network, first minimum number of day and last maximum number of day," "if value is negative, this bound won't be used", ) parser.add_argument( "--remove_dead_end", nargs=2, type=int, help="Remove short dead end, first is for minimal obs number and second for minimal segment time to keep", ) parser.add_argument( "--remove_trash", action="store_true", help="Remove trash (network id == 0)", ) parser.add_argument( "-p", "--period", nargs=2, type=int, help="Start day and end day, if it's a negative value we will add to day min and add to day max," "if 0 it is not used", ) args = parser.parse_args() n = NetworkObservations.load_file(args.input, raw_data=True) if args.length is not None: n = n.longer_than(*args.length) if args.remove_dead_end is not None: n = n.remove_dead_end(*args.remove_dead_end) if args.period is not None: n = n.extract_with_period(args.period) n.write_file(filename=args.out)
[docs]def quick_compare(): parser = EddyParser( """Tool to have a quick comparison between several network: - N : network - S : segment - Obs : observations """ ) parser.add_argument("ref", help="Identification file of reference") parser.add_argument("others", nargs="+", help="Identifications files to compare") parser.add_argument( "--path_out", default=None, help="Save each group in separate file" ) args = parser.parse_args() kw = dict( include_vars=[ "longitude", "latitude", "time", "track", "segment", "next_obs", "previous_obs", ] ) if args.path_out is not None: kw = dict() ref = NetworkObservations.load_file(args.ref, **kw) print( f"[ref] {args.ref} -> {ref.nb_network} network / {ref.nb_segment} segment / {len(ref)} obs " f"-> {ref.network_size(0)} trash obs, " f"{len(ref.merging_event())} merging, {len(ref.splitting_event())} spliting" ) others = { other: NetworkObservations.load_file(other, **kw) for other in args.others } # if args.path_out is not None: # groups_ref, groups_other = run_compare(ref, others, **kwargs) # if not exists(args.path_out): # mkdir(args.path_out) # for i, other_ in enumerate(args.others): # dirname_ = f"{args.path_out}/{other_.replace('/', '_')}/" # if not exists(dirname_): # mkdir(dirname_) # for k, v in groups_other[other_].items(): # basename_ = f"other_{k}.nc" # others[other_].index(v).write_file(filename=f"{dirname_}/{basename_}") # for k, v in groups_ref[other_].items(): # basename_ = f"ref_{k}.nc" # ref.index(v).write_file(filename=f"{dirname_}/{basename_}") # return display_compare(ref, others)
[docs]def run_compare(ref, others): outs = dict() for i, (k, other) in enumerate(others.items()): out = dict() print( f"[{i}] {k} -> {other.nb_network} network / {other.nb_segment} segment / {len(other)} obs " f"-> {other.network_size(0)} trash obs, " f"{len(other.merging_event())} merging, {len(other.splitting_event())} spliting" ) ref_id, other_id = ref.identify_in(other, size_min=2) m = other_id != -1 ref_id, other_id = ref_id[m], other_id[m] out["same N(N)"] = m.sum() out["same N(Obs)"] = ref.network_size(ref_id).sum() # For network which have same obs ref_, other_ = ref.networks(ref_id), other.networks(other_id) ref_segu, other_segu = ref_.identify_in(other_, segment=True) m = other_segu == -1 ref_track_no_match, _ = ref_.unique_segment_to_id(ref_segu[m]) ref_segu, other_segu = ref_segu[~m], other_segu[~m] m = ~in1d(ref_id, ref_track_no_match) out["same NS(N)"] = m.sum() out["same NS(Obs)"] = ref.network_size(ref_id[m]).sum() # Check merge/split def follow_obs(d, i_follow): m = i_follow != -1 i_follow = i_follow[m] t, x, y = ( zeros(m.size, d.time.dtype), zeros(m.size, d.longitude.dtype), zeros(m.size, d.latitude.dtype), ) t[m], x[m], y[m] = ( d.time[i_follow], d.longitude[i_follow], d.latitude[i_follow], ) return t, x, y def next_obs(d, i_seg): last_i = d.index_segment_track[1][i_seg] - 1 return follow_obs(d, d.next_obs[last_i]) def previous_obs(d, i_seg): first_i = d.index_segment_track[0][i_seg] return follow_obs(d, d.previous_obs[first_i]) tref, xref, yref = next_obs(ref_, ref_segu) tother, xother, yother = next_obs(other_, other_segu) m = (tref == tother) & (xref == xother) & (yref == yother) print(m.sum(), m.size, ref_segu.size, ref_track_no_match.size) tref, xref, yref = previous_obs(ref_, ref_segu) tother, xother, yother = previous_obs(other_, other_segu) m = (tref == tother) & (xref == xother) & (yref == yother) print(m.sum(), m.size, ref_segu.size, ref_track_no_match.size) ref_segu, other_segu = ref.identify_in(other, segment=True) m = other_segu != -1 out["same S(S)"] = m.sum() out["same S(Obs)"] = ref.segment_size()[ref_segu[m]].sum() outs[k] = out return outs
[docs]def display_compare(ref, others): def display(value, ref=None): if ref: outs = [f"{v/ref[k] * 100:.1f}% ({v})" for k, v in value.items()] else: outs = value return "".join([f"{v:^18}" for v in outs]) datas = run_compare(ref, others) ref_ = { "same N(N)": ref.nb_network, "same N(Obs)": len(ref), "same NS(N)": ref.nb_network, "same NS(Obs)": len(ref), "same S(S)": ref.nb_segment, "same S(Obs)": len(ref), } print(" ", display(ref_.keys())) for i, (_, v) in enumerate(datas.items()): print(f"[{i:2}] ", display(v, ref=ref_))