'This routine sets up the names for all the parameters on a compound
model, including figuring out unique names for those parameters and
also mapping them back to their associated parameters of the underlying
submodels.
Setting this all up is costly, and only necessary for compound models
that a user will directly interact with.  For example when building an
expression like::
>>> M = (Model1 + Model2) * Model3  # doctest: +SKIP
the user will generally never interact directly with the temporary
result of the subexpression ``(Model1 + Model2)``.  So there\'s no need
to setup all the parameters for that temporary throwaway.  Only once
the full expression is built and the user initializes or introspects
``M`` is it necessary to determine its full parameterization.'

def _init_param_descriptors(cls):

    for param_name in cls.param_names:
        (submodel_idx, submodel_param) = cls._param_map[param_name]
        submodel = cls[submodel_idx]
        orig_param = getattr(submodel, submodel_param, None)
        if isinstance(submodel, Model):
            default = orig_param.value
        else:
            default = orig_param.default
        constraints = dict(((key, getattr(orig_param, key)) for key in Model.parameter_constraints))
        new_param = orig_param.copy(name=param_name, default=default, unit=orig_param.unit, **constraints)
        setattr(cls, param_name, new_param)
