def get_rst_relations(docgraph):
    """
    returns a dictionary with RST relation root node IDs (str, e.g. 'rst:23')
    as keys and dictionaries describing these RST relations as values.

    Parameters
    ----------
    docgraph : DiscourseDocumentGraph
        a document graph which contains RST annotations

    Returns
    -------
    rst_relations : defaultdict(str)
        possible keys: 'tokens', 'nucleus', 'satellites', 'multinuc'
        maps from an RST relation root node ID (str, e.g. 'rst:23') to a
        dictionary describing this RST relation.
        The key 'tokens' maps to a list of token (node IDs) which the relation
        spans.
        If the dictionary contains the key 'multinuc', the relation is
        multinuclear and the keys 'nucleus' and 'satellites' contain nothing.
        The key 'multinuc' maps to a list of
        (node ID (str), RST reltype (str), list of token node IDs) triples;
        each one describes a nucleus.
        The key 'nucleus' maps to a list of token (node IDs) which the relation
        spans.
        The key 'satellites' maps to a list of
        (node ID (str), RST reltype (str), list of token node IDs) triples;
        each one describes a satellite.
    """
    rst_relations = defaultdict(lambda: defaultdict(str))

    for dom_node, _, _ in get_rst_relation_root_nodes(docgraph):
        neighbors = \
            list(select_neighbors_by_layer(docgraph, dom_node,
                                           layer={'rst:segment', 'rst:group'}))
        multinuc_nuc_count = 1
        directly_dominated_tokens = sorted([node for node in docgraph.neighbors(dom_node)
                                            if istoken(docgraph, node)], key=natural_sort_key)
        if directly_dominated_tokens:
            rst_relations[dom_node]['tokens'] = directly_dominated_tokens

        for neighbor in neighbors:
            for edge in docgraph[dom_node][neighbor]:  # multidigraph
                edge_attrs = docgraph[dom_node][neighbor][edge]

                if edge_attrs['edge_type'] == EdgeTypes.spanning_relation:
                    # a span always signifies the nucleus of a relation
                    # there can be only one
                    rst_relations[dom_node]['nucleus'] = (neighbor, get_span(docgraph, neighbor))
                elif edge_attrs['rst:rel_type'] == 'rst':
                    # a segment/group nucleus can dominate multiple satellites
                    # (in different RST relations)
                    satellite = (neighbor, edge_attrs['rst:rel_name'], get_span(docgraph, neighbor))
                    if 'satellites' in rst_relations[dom_node]:
                        rst_relations[dom_node]['satellites'].append(satellite)
                    else:
                        rst_relations[dom_node]['satellites'] = [satellite]
                elif edge_attrs['rst:rel_type'] == 'multinuc':
                    nucleus = (neighbor, edge_attrs['rst:rel_name'], get_span(docgraph, neighbor))
                    if 'multinuc' in rst_relations[dom_node]:
                        rst_relations[dom_node]['multinuc'].append(nucleus)
                    else:
                        rst_relations[dom_node]['multinuc'] = [nucleus]
                    multinuc_nuc_count += 1
                else:
                    raise NotImplementedError("unknown type of RST segment domination")
    return rst_relations