def fit(self,
            data='obsData',
            model_config='ModelConfig',
            param_const=None,
            param_values=None,
            param_ranges=None,
            poi_const=False,
            poi_value=None,
            poi_range=None,
            extended=False,
            num_cpu=1,
            process_strategy=0,
            offset=False,
            print_level=None,
            return_nll=False,
            **kwargs):
        """
        Fit a pdf to data in a workspace

        Parameters
        ----------

        workspace : RooWorkspace
            The workspace

        data : str or RooAbsData, optional (default='obsData')
            The name of the data or a RooAbsData instance.

        model_config : str or ModelConfig, optional (default='ModelConfig')
            The name of the ModelConfig in the workspace or a
            ModelConfig instance.

        param_const : dict, optional (default=None)
            A dict mapping parameter names to booleans setting
            the const state of the parameter

        param_values : dict, optional (default=None)
            A dict mapping parameter names to values

        param_ranges : dict, optional (default=None)
            A dict mapping parameter names to 2-tuples defining the ranges

        poi_const : bool, optional (default=False)
            If True, then make the parameter of interest (POI) constant

        poi_value : float, optional (default=None)
            If not None, then set the POI to this value

        poi_range : tuple, optional (default=None)
            If not None, then set the range of the POI with this 2-tuple

        extended : bool, optional (default=False)
            If True, add extended likelihood term (False by default)

        num_cpu : int, optional (default=1)
            Parallelize NLL calculation on multiple CPU cores.
            If negative then use all CPU cores.
            By default use only one CPU core.

        process_strategy : int, optional (default=0)
            **Strategy 0:** Divide events into N equal chunks.

            **Strategy 1:** Process event i%N in process N. Recommended for
            binned data with a substantial number of zero-bins, which will be
            distributed across processes more equitably in this strategy.

            **Strategy 2:** Process each component likelihood of a
            RooSimultaneous fully in a single process and distribute components
            over processes. This approach can be benificial if normalization
            calculation time dominates the total computation time of a
            component (since the normalization calculation must be performed
            in each process in strategies 0 and 1. However beware that if the
            RooSimultaneous components do not share many parameters this
            strategy is inefficient: as most minuit-induced likelihood
            calculations involve changing a single parameter, only 1 of the N
            processes will be active most of the time if RooSimultaneous
            components do not share many parameters.

            **Strategy 3:** Follow strategy 0 for all RooSimultaneous
            components, except those with less than 30 dataset entries,
            for which strategy 2 is followed.

        offset : bool, optional (default=False)
            Offset likelihood by initial value (so that starting value of FCN
            in minuit is zero). This can improve numeric stability in
            simultaneously fits with components with large likelihood values.

        print_level : int, optional (default=None)
            The verbosity level for the minimizer algorithm.
            If None (the default) then use the global default print level.
            If negative then all non-fatal messages will be suppressed.

        return_nll : bool, optional (default=False)
            If True then also return the RooAbsReal NLL function that was
            minimized.

        kwargs : dict, optional
            Remaining keyword arguments are passed to the minimize function

        Returns
        -------

        result : RooFitResult
            The fit result.

        func : RooAbsReal
            If return_nll is True, the NLL function is also returned.

        See Also
        --------

        minimize

        """
        if isinstance(model_config, string_types):
            model_config = self.obj(
                model_config, cls=ROOT.RooStats.ModelConfig)
        if isinstance(data, string_types):
            data = self.data(data)
        pdf = model_config.GetPdf()

        pois = model_config.GetParametersOfInterest()
        if pois.getSize() > 0:
            poi = pois.first()
            poi.setConstant(poi_const)
            if poi_value is not None:
                poi.setVal(poi_value)
            if poi_range is not None:
                poi.setRange(*poi_range)

        if param_const is not None:
            for param_name, const in param_const.items():
                var = self.var(param_name)
                var.setConstant(const)
        if param_values is not None:
            for param_name, param_value in param_values.items():
                var = self.var(param_name)
                var.setVal(param_value)
        if param_ranges is not None:
            for param_name, param_range in param_ranges.items():
                var = self.var(param_name)
                var.setRange(*param_range)

        if print_level < 0:
            msg_service = ROOT.RooMsgService.instance()
            msg_level = msg_service.globalKillBelow()
            msg_service.setGlobalKillBelow(ROOT.RooFit.FATAL)

        args = [
            ROOT.RooFit.Constrain(model_config.GetNuisanceParameters()),
            ROOT.RooFit.GlobalObservables(model_config.GetGlobalObservables())]
        if extended:
            args.append(ROOT.RooFit.Extended(True))
        if offset:
            args.append(ROOT.RooFit.Offset(True))
        if num_cpu != 1:
            if num_cpu == 0:
                raise ValueError("num_cpu must be non-zero")
            if num_cpu < 0:
                num_cpu = NCPU
            args.append(ROOT.RooFit.NumCPU(num_cpu, process_strategy))

        func = pdf.createNLL(data, *args)

        if print_level < 0:
            msg_service.setGlobalKillBelow(msg_level)

        result = minimize(func, print_level=print_level, **kwargs)

        if return_nll:
            return result, func
        return result
Fit a pdf to data in a workspace

        Parameters
        ----------

        workspace : RooWorkspace
            The workspace

        data : str or RooAbsData, optional (default='obsData')
            The name of the data or a RooAbsData instance.

        model_config : str or ModelConfig, optional (default='ModelConfig')
            The name of the ModelConfig in the workspace or a
            ModelConfig instance.

        param_const : dict, optional (default=None)
            A dict mapping parameter names to booleans setting
            the const state of the parameter

        param_values : dict, optional (default=None)
            A dict mapping parameter names to values

        param_ranges : dict, optional (default=None)
            A dict mapping parameter names to 2-tuples defining the ranges

        poi_const : bool, optional (default=False)
            If True, then make the parameter of interest (POI) constant

        poi_value : float, optional (default=None)
            If not None, then set the POI to this value

        poi_range : tuple, optional (default=None)
            If not None, then set the range of the POI with this 2-tuple

        extended : bool, optional (default=False)
            If True, add extended likelihood term (False by default)

        num_cpu : int, optional (default=1)
            Parallelize NLL calculation on multiple CPU cores.
            If negative then use all CPU cores.
            By default use only one CPU core.

        process_strategy : int, optional (default=0)
            **Strategy 0:** Divide events into N equal chunks.

            **Strategy 1:** Process event i%N in process N. Recommended for
            binned data with a substantial number of zero-bins, which will be
            distributed across processes more equitably in this strategy.

            **Strategy 2:** Process each component likelihood of a
            RooSimultaneous fully in a single process and distribute components
            over processes. This approach can be benificial if normalization
            calculation time dominates the total computation time of a
            component (since the normalization calculation must be performed
            in each process in strategies 0 and 1. However beware that if the
            RooSimultaneous components do not share many parameters this
            strategy is inefficient: as most minuit-induced likelihood
            calculations involve changing a single parameter, only 1 of the N
            processes will be active most of the time if RooSimultaneous
            components do not share many parameters.

            **Strategy 3:** Follow strategy 0 for all RooSimultaneous
            components, except those with less than 30 dataset entries,
            for which strategy 2 is followed.

        offset : bool, optional (default=False)
            Offset likelihood by initial value (so that starting value of FCN
            in minuit is zero). This can improve numeric stability in
            simultaneously fits with components with large likelihood values.

        print_level : int, optional (default=None)
            The verbosity level for the minimizer algorithm.
            If None (the default) then use the global default print level.
            If negative then all non-fatal messages will be suppressed.

        return_nll : bool, optional (default=False)
            If True then also return the RooAbsReal NLL function that was
            minimized.

        kwargs : dict, optional
            Remaining keyword arguments are passed to the minimize function

        Returns
        -------

        result : RooFitResult
            The fit result.

        func : RooAbsReal
            If return_nll is True, the NLL function is also returned.

        See Also
        --------

        minimize