Exemplo n.º 1
0
def test_return_orient(known_net):
    """Test cycle_return_to_original_orientation()."""
    orig = di.cycle_get_original_orientation(known_net.links,
                                             known_net.links['id'])
    links = known_net.links
    re_links = di.cycle_return_to_original_orientation(links, orig)
    # make assertions
    assert re_links['id'] == links['id']
    assert re_links['conn'] == links['conn']
    assert re_links['idx'] == links['idx']
    assert np.all(re_links['wid_pix'][0] == links['wid_pix'][0])
    assert np.all(re_links['certain_alg'][0] == links['certain_alg'][0])
    assert np.all(re_links['certain_order'][0] == links['certain_order'][0])
Exemplo n.º 2
0
def fix_delta_cycle(links, nodes, cyc_links, imshape):
    """
    Attempt to resolve a single cycle.

    Attempts to resolve a single cycle within a delta network. The general
    logic is that all link directions of the cycle are un-set except for those
    set by highly-reliable algorithms, and a modified direction-setting
    recipe is implemented to re-set these algorithms. This was developed
    according to the most commonly-encountered cases for real deltas, but could
    certainly be improved.


    Parameters
    ----------
    links : dict
        Network links and associated properties.
    nodes : dict
        Network nodes and associated properties.
    cyc_links : list
        Link ids comprising the cycle to fix.
    imshape : tuple
        Shape of binary mask as (nrows, ncols).

    Returns
    -------
    links : dict
        Network links and associated properties with cycle fixed, if possible.
    nodes : dict
        Network nodes and associated properties with cycle fixed, if possible.
    fixed : bool
        True if the cycle was resolved, else False.

    """
    def re_set_linkdirs(links, nodes, imshape):
        # Cycle links are attempted to be reset according to algorithms here.
        angthreshs = np.linspace(0, 1.2, 20)
        for a in angthreshs:
            links, nodes = dy.set_by_known_flow_directions(
                links,
                nodes,
                imshape,
                angthresh=a,
                lenthresh=0,
                alg=dy.algmap('known_fdr_rs'))

        return links, nodes

    # Track if fix was successful (1:yes, 0:no)
    fixed = 1

    # List of algorithm ids that should not be reset if previously used to
    # determine direction
    # dont_reset_algs = [-1, 0, 4, 5, 13]
    dont_reset_algs = [
        dy.algmap(key) for key in [
            'manual_set', 'inletoutlet', 'main_chans', 'bridges',
            'longest_steepest'
        ]
    ]

    # Simplest method: unset the cycle links and reset them according to angles
    # Get resettale links
    toreset = [
        l for l in cyc_links
        if links['certain_alg'][links['id'].index(l)] not in dont_reset_algs
    ]

    # Get original link orientations in case fix does not work
    orig = dy.cycle_get_original_orientation(links, toreset)

    # Set certainty of cycle links to zero
    for tr in toreset:
        links['certain'][links['id'].index(tr)] = 0

    links, nodes = re_set_linkdirs(links, nodes, imshape)

    # Check that all links were reset
    if sum([links['certain'][links['id'].index(l)]
            for l in toreset]) != len(toreset):
        fixed = 0

    # Check that cycle was resolved
    cyclenode = links['conn'][links['id'].index(toreset[0])][0]
    cyc_n, cyc_l = dy.get_cycles(links, nodes, checknode=cyclenode)

    # If the cycle was not fixed, try again, but set the cycle links AND the
    # links connected to the cycle to unknown
    if cyc_n is not None and cyclenode in cyc_n[0]:
        # First return to original orientation
        links = dy.cycle_return_to_original_orientation(links, orig)

        # Get all cycle links and those connected to cycle
        toreset = set()
        for cn in cyc_n[0]:
            conn = nodes['conn'][nodes['id'].index(cn)]
            toreset.update(conn)
        toreset = list(toreset)

        # Save original orientation in case cycle cannot be fixed
        orig_links = dy.cycle_get_original_orientation(links, toreset)

        # Un-set the cycle+connected links
        for tr in toreset:
            lidx = links['id'].index(tr)
            if links['certain_alg'][lidx] not in dont_reset_algs:
                links['certain'][lidx] = 0

        links, nodes = re_set_linkdirs(links, nodes, imshape)

        # See if the fix resolved the cycle - if not, reset to original
        cyc_n, cyc_l = dy.get_cycles(links, nodes, checknode=cyclenode)
        if cyc_n is not None and cyclenode in cyc_n[0]:
            links = dy.cycle_return_to_original_orientation(links, orig_links)
            fixed = 0

    return links, nodes, fixed
Exemplo n.º 3
0
def fix_river_cycle(links, nodes, cyclelinks, cyclenodes, imshape):
    """
    Attempt to fix a single cycle.

    Attempts to resolve a single cycle within a river network. The general
    logic is that all link directions of the cycle are un-set except for those
    set by highly-reliable algorithms, and a modified direction-setting
    recipe is implemented to re-set these algorithms. This was developed
    according to the most commonly-encountered cases for real braided rivers,
    but could certainly be improved.


    Parameters
    ----------
    links : dict
        Network links and associated properties.
    nodes : dict
        Network nodes and associated properties.
    cyclelinks : list
        List of link ids that comprise a cycle.
    cyclenodes : list
        List of node ids taht comprise a cycle.
    imshape : tuple
        Shape of binary mask as (nrows, ncols).

    Returns
    -------
    links : dict
        Network links and associated properties with the cycle fixed if
        possible.
    nodes : dict
        Network nodes and associated properties with the cycle fixed if
        possible.
    fixed : int
        1 if the cycle was resolved, else 0.

    """

    # dont_reset_algs = [20, 21, 22, 23, 0, 5]
    dont_reset_algs = [
        dy.algmap(key) for key in [
            'manual_set', 'cl_dist_guess', 'cl_ang_guess', 'cl_dist_set',
            'cl_ang_set', 'inletoutlet', 'bridges'
        ]
    ]

    fixed = 1  # One if fix was successful, else zero
    reset = 0  # One if original orientation need to be reset

    # If an artifical node triad is present, flip its direction and see if the
    # cycle is resolved.
    # See if any links are part of an artificial triad
    clset = set(cyclelinks)
    all_pars = []
    for i, pl in enumerate(links['parallels']):
        if len(clset.intersection(set(pl))) > 0:
            all_pars.append(pl)

    # Get continuity violators before flipping
    pre_sourcesink = dy.check_continuity(links, nodes)

    if len(
            all_pars
    ) == 1:  # There is one parallel link set, flip its direction and re-set other cycle links and see if cycle is resolved
        certzero = list(set(all_pars[0] + cyclelinks))
        orig_links = dy.cycle_get_original_orientation(
            links, certzero
        )  # Save the original orientations in case the cycle can't be fixed
        for cz in certzero:
            links['certain'][links['id'].index(cz)] = 0

        # Flip the links of the triad
        for l in all_pars[0]:
            links = lnu.flip_link(links, l)

    if len(
            all_pars
    ) > 1:  # If there are multiple parallel pairs, more code needs to be written for these cases
        print(
            'Multiple parallel pairs in the same cycle. Not implemented yet.')
        return links, nodes, 0

    elif len(
            all_pars
    ) == 0:  # No aritifical node triads; just re-set all the cycle links and see if cycle is resolved
        certzero = cyclelinks
        orig_links = dy.cycle_get_original_orientation(links, certzero)
        for cz in certzero:
            lidx = links['id'].index(cz)
            if links['certain_alg'][lidx] not in dont_reset_algs:
                links['certain'][lidx] = 0

    # Resolve the unknown cycle links
    links, nodes = re_set_linkdirs(links, nodes, imshape)

    # See if the fix violated continuity - if not, reset to original
    post_sourcesink = dy.check_continuity(links, nodes)
    if len(set(post_sourcesink) - set(pre_sourcesink)) > 0:
        reset = 1

    # See if the fix resolved the cycle - if not, reset to original
    cyc_n, cyc_l = dy.get_cycles(links, nodes, checknode=cyclenodes[0])
    if cyc_n is not None and cyclenodes[0] in cyc_n[0]:
        reset = 1

    # Return the links to their original orientations if cycle could not
    # be resolved
    if reset == 1:

        links = dy.cycle_return_to_original_orientation(links, orig_links)

        # Try a second method to fix the cycle: unset all the links of the
        # cycle AND the links connected to those links
        set_to_zero = set()
        for cn in cyclenodes:
            conn = nodes['conn'][nodes['id'].index(cn)]
            set_to_zero.update(conn)
        set_to_zero = list(set_to_zero)

        # Save original orientation in case cycle cannot be fixed
        orig_links = dy.cycle_get_original_orientation(links, set_to_zero)

        for s in set_to_zero:
            lidx = links['id'].index(s)
            if links['certain_alg'][lidx] not in dont_reset_algs:
                links['certain'][lidx] = 0

        links, nodes = re_set_linkdirs(links, nodes, imshape)

        # See if the fix violated continuity - if not, reset to original
        post_sourcesink = dy.check_continuity(links, nodes)
        if len(set(post_sourcesink) - set(pre_sourcesink)) > 0:
            reset = 1

        # See if the fix resolved the cycle - if not, reset to original
        cyc_n, cyc_l = dy.get_cycles(links, nodes, checknode=cyclenodes[0])
        if cyc_n is not None and cyclenodes[0] in cyc_n[0]:
            reset = 1

        if reset == 1:
            links = dy.cycle_return_to_original_orientation(links, orig_links)
            fixed = 0

    return links, nodes, fixed