RooFitResult* GenericModel::fitTo(RooDataSet* data)
   {
      // Perform fit of the pseudo-PDF to the data
      // On multi-core machines, this automatically uses all available processor cores

      SafeDelete(fLastFit);
#ifdef WITH_MULTICORE_CPU
      fLastFit = fModelPseudoPDF->fitTo(*data, Save(), NumCPU(WITH_MULTICORE_CPU));
#else
      fLastFit = fModelPseudoPDF->fitTo(*data, Save());
#endif

      SafeDelete(fParamDataHist);
      fParamDataHist = new RooDataHist("params", "params", GetParameters());

      // store weights of component pdfs => distribution of parameters
      fWeights.removeAll();
      const RooArgList& coefs = fModelPseudoPDF->coefList();
      for (int i = 0; i < GetNumberOfDataSets(); i++) {
         RooAbsReal* coef = (RooAbsReal*)coefs.at(i);
         RooRealVar w(Form("w%d", i), Form("Fitted weight of kernel#%d", i), coef->getVal());
         if (coef->InheritsFrom(RooRealVar::Class())) {
            w.setError(((RooRealVar*)coef)->getError());
         } else {
            w.setError(coef->getPropagatedError(*fLastFit));
         }
         fWeights.addClone(w);
         fParamDataHist->set(*GetParametersForDataset(i), w.getVal(), w.getError());
      }

      SafeDelete(fParameterPDF);
      fParameterPDF = new RooHistPdf("paramPDF", "paramPDF", GetParameters(), *fParamDataHist);

      return fLastFit;
   }
   void GenericModel::ConstructPseudoPDF(Bool_t)
   {
      // Build a parameterised pseudo-PDF from all the imported model datasets.
      // Each dataset is transformed into a RooNDKeysPdf kernel estimation p.d.f.
      // This p.d.f. models the distribution of an arbitrary input dataset as a
      // superposition of Gaussian kernels, one for each data point, each
      // contributing 1/N to the total integral of the p.d.f.
      //
      // If debug=kTRUE, each dataset and kernel PDF will be displayed in a canvas.
      // This can help to decide if the kernel smoothing parameter needs attention.

      if (!GetNumberOfDataSets()) {
         Error("ConstructPseudoPDF", "import model datasets with ImportModelData() first");
         return;
      }

      if (fModelPseudoPDF) {
         delete fModelPseudoPDF;
         fModelPseudoPDF = 0;
         fNDKeys.Delete();
         fFractions.removeAll();
      }
      //generate kernels
      RooArgList kernels;
      Double_t initialWeight = 1. / GetNumberOfDataSets();

      for (int i = 0; i < GetNumberOfDataSets(); i++) {

         Info("ConstructPseudoPDF", "Kernel estimation of dataset#%d...", i);
         RooNDKeysPdf* p = new RooNDKeysPdf(Form("NDK%d", i),
                                            Form("Kernel estimation of dataset#%d", i),
                                            GetObservables(),
                                            *((RooDataSet*)fDataSets[i]),
                                            "am", fSmoothing);
         fNDKeys.Add(p);
         kernels.add(*p);
         if (i < (GetNumberOfDataSets() - 1))
            fFractions.addClone(RooRealVar(Form("W%d", i), Form("fractional weight of kernel-PDF #%d", i), initialWeight, 0., 1.));

      }
      fModelPseudoPDF = new RooAddPdf("Model", "Pseudo-PDF constructed from kernels for model datasets", kernels, fFractions, kTRUE);
   }
   void GenericModel::plotOn(RooPlot* frame)
   {
      // Add the pseudo-PDF to the RooPlot
      // We plot:
      //    - the fit result with a 1-sigma error band;
      //    - each of the individual kernel PDF's

      //plot fit result with 1-sigma error band
      fModelPseudoPDF->plotOn(frame, VisualizeError(*fLastFit, 1), FillColor(kMagenta));
      fModelPseudoPDF->plotOn(frame);
      //plot individual kernels
      for (int i = 0; i < GetNumberOfDataSets(); i++) {
         fModelPseudoPDF->plotOn(frame, Components(*GetKernel(i)), LineStyle(kDashed), LineColor(kBlue + 4 * i));
      }
   }
void Foam::vtkPV3Foam::convertMeshPointSets
(
    vtkMultiBlockDataSet* output
)
{
    if (debug)
    {
        Info<< "<beg> Foam::vtkPV3Foam::convertMeshPointSets" << endl;
        printMemory();
    }

    const selectionInfo& selector = selectInfoPointSets_;
    vtkDataArraySelection* arraySelection = reader_->GetRegionSelection();

    // Create the point sets and add as dataset
    if (selector.size())
    {
        const fvMesh& mesh = *meshPtr_;

        for
        (
            int regionId = selector.start();
            regionId < selector.end();
            ++regionId
        )
        {
            if (!selectedRegions_[regionId])
            {
                continue;
            }

            word selectName = getFirstWord
            (
                arraySelection->GetArrayName(regionId)
            );


            if (debug)
            {
                Info<< "Creating VTK mesh for pointSet: " << selectName
                    << " region index: " << regionId << endl;
            }

            const pointSet pSet(mesh, selectName);

            const label datasetId = GetNumberOfDataSets(output, selector);

            vtkPolyData* vtkmesh = vtkPolyData::New();
            addPointSetMesh
            (
                mesh,
                pSet,
                vtkmesh
            );
            AddToBlock
            (
                output, selector, datasetId, vtkmesh,
                selectName + ":pointSet"
            );
            selectedRegionDatasetIds_[regionId] = datasetId;
            vtkmesh->Delete();
        }
    }

    if (debug)
    {
        Info<< "<end> Foam::vtkPV3Foam::convertMeshPointSets" << endl;
        printMemory();
    }
}
void Foam::vtkPV3Foam::convertMeshPointZones
(
    vtkMultiBlockDataSet* output
)
{
    if (debug)
    {
        Info<< "<beg> Foam::vtkPV3Foam::convertMeshPointZones" << endl;
        printMemory();
    }

    const selectionInfo& selector = selectInfoPointZones_;
    const fvMesh& mesh = *meshPtr_;

    // Create the point sets and add as dataset
    if (selector.size())
    {
        const pointZoneMesh& pzMesh = mesh.pointZones();

        // use the zoneId directly instead of the name
        for (int zoneI=0; zoneI < selector.size(); ++zoneI)
        {
            const int regionId = selector.start() + zoneI;

            if (!selectedRegions_[regionId])
            {
                continue;
            }

            if (debug)
            {
                Info<< "Creating VTK mesh for pointZone: "
                    << zoneI << endl;
            }

            const label datasetId = GetNumberOfDataSets(output, selector);

            vtkPolyData* vtkmesh = vtkPolyData::New();

            addPointZoneMesh
            (
                mesh,
                pzMesh[zoneI],
                vtkmesh
            );

            AddToBlock
            (
                output, selector, datasetId, vtkmesh,
                pzMesh.names()[zoneI] + ":pointZone"
            );
            selectedRegionDatasetIds_[regionId] = datasetId;
            vtkmesh->Delete();
        }
    }

    if (debug)
    {
        Info<< "<end> Foam::vtkPV3Foam::convertMeshPointZones" << endl;
        printMemory();
    }
}
void Foam::vtkPV3Foam::convertMeshCellSets
(
    vtkMultiBlockDataSet* output
)
{
    if (debug)
    {
        Info<< "<beg> Foam::vtkPV3Foam::convertMeshCellSets" << endl;
        printMemory();
    }

    const selectionInfo& selector = selectInfoCellSets_;
    vtkDataArraySelection* arraySelection = reader_->GetRegionSelection();

    // Create the cell sets and add as dataset
    if (selector.size())
    {
        const fvMesh& mesh = *meshPtr_;

        for
        (
            int regionId = selector.start();
            regionId < selector.end();
            ++regionId)
        {
            if (!selectedRegions_[regionId])
            {
                continue;
            }

            word selectName = getFirstWord
            (
                arraySelection->GetArrayName(regionId)
            );

            if (debug)
            {
                Info<< "Creating VTK mesh for cellSet: " << selectName
                    << " region index: " << regionId << endl;
            }

            const cellSet cSet(mesh, selectName);
            fvMeshSubset subsetter
            (
                IOobject
                (
                    "set",
                    mesh.time().constant(),
                    mesh,
                    IOobject::NO_READ,
                    IOobject::NO_WRITE
                ),
                mesh
            );
            subsetter.setLargeCellSubset(cSet);

            const label datasetId = GetNumberOfDataSets(output, selector);

            vtkUnstructuredGrid* vtkmesh = vtkUnstructuredGrid::New();

            addVolumeMesh
            (
                subsetter.subMesh(),
                vtkmesh,
                csetSuperCells_[datasetId]
            );

            // renumber - superCells must contain global cell ids
            inplaceRenumber
            (
                subsetter.cellMap(),
                csetSuperCells_[datasetId]
            );

            AddToBlock
            (
                output, selector, datasetId, vtkmesh,
                selectName + ":cellSet"
            );
            selectedRegionDatasetIds_[regionId] = datasetId;
            vtkmesh->Delete();
        }
    }

    if (debug)
    {
        Info<< "<end> Foam::vtkPV3Foam::convertMeshCellSets" << endl;
        printMemory();
    }
}
void Foam::vtkPV3Foam::convertMeshCellZones
(
    vtkMultiBlockDataSet* output
)
{
    if (debug)
    {
        Info<< "<beg> Foam::vtkPV3Foam::convertMeshCellZones" << endl;
        printMemory();
    }

    const selectionInfo& selector = selectInfoCellZones_;
    const fvMesh& mesh = *meshPtr_;

    // Create the cell zone(s) and add as DataSet(CELLZONE, 0..n)
    if (selector.size())
    {
        const cellZoneMesh& czMesh = mesh.cellZones();

        // use the zoneId directly instead of the name
        for (int zoneI=0; zoneI < selector.size(); ++zoneI)
        {
            const int regionId = selector.start() + zoneI;

            if (!selectedRegions_[regionId])
            {
                continue;
            }

            if (debug)
            {
                Info<< "Creating VTK mesh for cellZone: "
                    << zoneI << endl;
            }

            fvMeshSubset subsetter
            (
                IOobject
                (
                    "set",
                    mesh.time().constant(),
                    mesh,
                    IOobject::NO_READ,
                    IOobject::NO_WRITE
                ),
                mesh
            );

            subsetter.setLargeCellSubset(labelHashSet(czMesh[zoneI]));

            const label datasetId = GetNumberOfDataSets(output, selector);

            vtkUnstructuredGrid* vtkmesh = vtkUnstructuredGrid::New();

            addVolumeMesh
            (
                subsetter.subMesh(),
                vtkmesh,
                zoneSuperCells_[datasetId]
            );

            // renumber - superCells must contain global cell ids
            inplaceRenumber
            (
                subsetter.cellMap(),
                zoneSuperCells_[datasetId]
            );

            AddToBlock
            (
                output, selector, datasetId, vtkmesh,
                czMesh.names()[zoneI] + ":cellZone"
            );
            selectedRegionDatasetIds_[regionId] = datasetId;
            vtkmesh->Delete();
        }
    }

    if (debug)
    {
        Info<< "<end> Foam::vtkPV3Foam::convertMeshCellZones" << endl;
        printMemory();
    }
}