def get_mass_breakdown(model, property_ids=None, stop_if_no_mass=True,
    detailed=False):
    """
    Gets a breakdown of the mass by property region.

    Parameters
    ----------
    property_ids : List[int] / int
        list of property ID
    stop_if_no_mass : bool; default=True
        prevents crashing if there are no elements
        setting this to False really doesn't make sense for non-DMIG models
    detailed : bool, optional, default : False
        Separates structural and nonstructural mass outputs.

    Returns
    -------
    pids_to_mass : dict {int : float, ...}
        Map from property id to mass (structural mass only if detailed is True).
    pids_to_mass_nonstructural : dict {int : float, ...}, optional
        Map from property id to nonstructural mass (only if detailed is True).
    mass_type_to_mass : dict {str : float, ...}
        Map from mass id to mass for mass elements.
        Used for CONM2s

    TODO: What about CONRODs?
    #'PBCOMP',
    #'PBMSECT',
    #'PBEAM3',
    #'PBEND',
    #'PIHEX',
    #'PCOMPS',

    """
    pid_eids = model.get_element_ids_dict_with_pids(property_ids,
        stop_if_no_eids=False, msg=' which is required by get_mass_breakdown')
    mass_type_to_mass = {}
    pids_to_mass = {}
    pids_to_mass_nonstructural = {}
    skipped_eid_pid = set()
    for eid, elem in model.masses.items():
        if elem.type not in mass_type_to_mass:
            mass_type_to_mass[elem.type] = elem.Mass()
        else:
            mass_type_to_mass[elem.type] += elem.Mass()
    properties_to_skip = {'PLPLANE', 'PPLANE', 'PELAS', 'PDAMP', 'PBUSH',
        'PBUSH1D', 'PBUSH2D', 'PELAST', 'PDAMPT', 'PBUSHT', 'PDAMP5',
        'PFAST', 'PGAP', 'PRAC2D', 'PRAC3D', 'PCONEAX', 'PVISC', 'PBCOMP',
        'PBEND', 'PBEAM3', 'PACABS', 'PAABSF', 'PACBAR'}
    bar_properties = {'PBAR', 'PBARL', 'PBEAM', 'PBEAML', 'PROD', 'PTUBE'}
    for pid, eids in pid_eids.items():
        prop = model.properties[pid]
        masses = []
        masses_nonstructural = []
        if prop.type == 'PSHELL':
            thickness = prop.t
            nsm = prop.nsm
            rho = prop.Rho()
            for eid in eids:
                elem = model.elements[eid]
                if elem.type in ['CQUADX']:
                    continue
                area = elem.Area()
                if detailed:
                    masses.append(area * (rho * thickness))
                    masses_nonstructural.append(area * nsm)
                else:
                    masses.append(area * (rho * thickness + nsm))
        elif prop.type in ['PCOMP', 'PCOMPG']:
            for eid in eids:
                elem = model.elements[eid]
                if detailed:
                    mass, mass_nonstructural = elem.Mass_breakdown()
                    masses.append(mass)
                    masses_nonstructural.append(mass_nonstructural)
                else:
                    masses.append(elem.Mass())
        elif prop.type in bar_properties:
            nsm = prop.nsm
            try:
                rho = prop.Rho()
            except AttributeError:
                print(prop)
                raise
            for eid in eids:
                elem = model.elements[eid]
                area = prop.Area()
                length = elem.Length()
                if detailed:
                    masses.append(length * (rho * area))
                    masses_nonstructural.append(length * nsm)
                else:
                    masses.append(length * (rho * area + nsm))
        elif prop.type in ['PSOLID', 'PCOMPS', 'PLSOLID', 'PIHEX']:
            rho = prop.Rho()
            for eid in eids:
                elem = model.elements[eid]
                if elem.type in ['CTETRA', 'CPENTA', 'CHEXA']:
                    masses.append(rho * elem.Volume())
                else:
                    key = elem.type, prop.type
                    if key not in skipped_eid_pid:
                        skipped_eid_pid.add(key)
                        model.log.debug('skipping mass %s' % str(key))
        elif prop.type in properties_to_skip:
            pass
        elif prop.type == 'PSHEAR':
            thickness = prop.t
            nsm = prop.nsm
            rho = prop.Rho()
            for eid in eids:
                elem = model.elements[eid]
                area = elem.Area()
                if detailed:
                    masses.append(area * (rho * thickness))
                    masses_nonstructural.append(area * nsm)
                else:
                    masses.append(area * (rho * thickness + nsm))
        elif prop.type in ['PBRSECT', 'PBMSECT']:
            model.log.warning('skipping:\n%s' % prop)
            continue
        else:
            raise NotImplementedError(prop)
        if masses:
            pids_to_mass[pid] = sum(masses)
        if masses_nonstructural:
            pids_to_mass_nonstructural[pid] = sum(masses_nonstructural)
    has_mass = len(mass_type_to_mass) > 0 or len(pids_to_mass) > 0
    if not has_mass:
        msg = 'No elements with mass were found'
        model.log.warning(msg)
        if stop_if_no_mass:
            raise RuntimeError(msg)
    if detailed:
        return pids_to_mass, pids_to_mass_nonstructural, mass_type_to_mass
    return pids_to_mass, mass_type_to_mass
