'Wraps the method calculating the Jacobian of the function to account
for model constraints.
`scipy.optimize.leastsq` expects the function derivative to have the
above signature (parlist, (argtuple)). In order to accommodate model
constraints, instead of using p directly, we set the parameter list in
this function.'

@staticmethod
def _wrap_deriv(params, model, weights, x, y, z=None):

    if (weights is None):
        weights = 1.0
    if (any(model.fixed.values()) or any(model.tied.values())):
        if (z is None):
            full_deriv = (np.ravel(weights) * np.array(model.fit_deriv(x, *model.parameters)))
        else:
            full_deriv = (np.ravel(weights) * np.array(model.fit_deriv(x, y, *model.parameters)).T).T
        pars = [getattr(model, name) for name in model.param_names]
        fixed = [par.fixed for par in pars]
        tied = [par.tied for par in pars]
        tied = list(np.where([(par.tied is not False) for par in pars], True, tied))
        fix_and_tie = np.logical_or(fixed, tied)
        ind = np.logical_not(fix_and_tie)
        if (not model.col_fit_deriv):
            full_deriv = np.asarray(full_deriv).T
            residues = np.asarray(full_deriv[np.nonzero(ind)]).T
        else:
            residues = full_deriv[np.nonzero(ind)]
        return [np.ravel(_) for _ in residues]
    elif (z is None):
        return [np.ravel(_) for _ in (np.ravel(weights) * np.array(model.fit_deriv(x, *params)))]
    elif (not model.col_fit_deriv):
        return [np.ravel(_) for _ in (np.ravel(weights) * np.array(model.fit_deriv(x, y, *params)).T).T]
    else:
        return [np.ravel(_) for _ in (weights * np.array(model.fit_deriv(x, y, *params)))]
