function groupConnectivityGraph = getGroupConnectivityGraph(groups, model)
    % groupConnectivityGraph get connectivity information for data type groups
    %
    % ggr = getGroupConnectivityGraph(groups, model) will return a digraph
    % MATLAB container with connectivity information about the 'groups' given
    % as input. The groups need come from a model hierarchy with top model
    % passed in as 'model'. The nodes of the digraph will be the ID of the
    % data type groups while the edges identify flow to and from a data
    % type group.
    %
    % Example:
    % model = 'vdp';
    % load_system(model);
    % env = DataTypeOptimization.EnvironmentProxy(model, model);
    % instrumentScenarios(env, Simulink.SimulationInput(model));
    % groups = env.getDataTypeGroups(...
    % SimulinkFixedPoint.AutoscalerConstraints.HardwareConstraintFactory.getConstraint(model));
    % ggr = fxptds.getGroupConnectivityGraph(groups, model);
    % plot(ggr);
    %
    % See also:
    % fxptds.DataTypeGroup, digraph, fxptopo.internal.SLTopoContainer
    
    % Copyright 2018-2019 The MathWorks, Inc.
    
    % get the handles for all group members in a map to be queried using
    % group ID
    groupConnectivityGraph = [];
    if ~isempty(groups)
        handleMap = containers.Map('KeyType', 'double', 'ValueType', 'any');
        for gIndex = 1:length(groups)
            members = groups{gIndex}.members.values;
            for mIndex = 1:length(members)
                if isprop(members{mIndex}.UniqueIdentifier.getObject, 'Handle')
                    uniqueID =  members{mIndex}.UniqueIdentifier;
                    pathItem = uniqueID.getElementName;
                    if isequal(pathItem, '1') || isequal(pathItem, 'Output')
                        handleMap(members{mIndex}.UniqueIdentifier.getObject.Handle) = groups{gIndex}.id;
                    end
                end
            end
        end
        
        % get a topology container and build the graph
        topologyGraph = fxptopo.internal.TransformTopologyContainer();
        topologyGraph.buildGraph(model);
        
        % map handles to group IDs
        % NOTE: it is possible that not all group members will be part of the
        % topology; internal path items such as accumulators are not
        % participating in topology
        gIDs = cell(length(topologyGraph.Graph.Nodes.Handle),1);
        for hIndex = 1:length(topologyGraph.Graph.Nodes.Handle)
            if handleMap.isKey(topologyGraph.Graph.Nodes.Handle(hIndex))
                gIDs{hIndex} = handleMap(topologyGraph.Graph.Nodes.Handle(hIndex));
            else
                gIDs{hIndex} = -1;
            end
        end
        
        % append GroupIDs as columns on the nodes
        groupGraph = digraph(topologyGraph.Graph.Edges, [topologyGraph.Graph.Nodes cell2table(gIDs, 'VariableNames', {'GroupID'})]);
        
        % make group connectivity graph
        groupIDs = groupGraph.Nodes.GroupID(groupGraph.Edges.EndNodes);
        % remove all nodes that do not map to a group 
        % NOTE: this is demarcated as -1 in the group ID column
        groupIDs(groupIDs(:,1)==-1,:) = ''; 
        
        % make sure there are enough edges to form a graph
        % NOTE: in the previous filtering step it is possible we made a trivial 
        % graph (i.e. 1 node or only a self looping graph). Make sure we
        % have a graph that is not trivial to move ahead
        if numel(groupIDs)>=2 && size(groupIDs,2)>1
            groupIDs(groupIDs(:,2)<0,:) = '';
            groupConnectivityGraph = simplify(digraph(groupIDs(:,1), groupIDs(:,2), 'omitselfloops'));
        end
    end
end

% LocalWords: omitselfloops