1
0
mirror of https://github.com/aportelli/LatAnalyze.git synced 2024-11-10 00:45:36 +00:00

new fit: partial residuals and plots

This commit is contained in:
Antonin Portelli 2016-04-04 19:09:18 +01:00
parent f82b20dc73
commit 07bacf0e4b
10 changed files with 335 additions and 99 deletions

View File

@ -4,6 +4,7 @@
#include <LatAnalyze/Io.hpp>
#include <LatAnalyze/MinuitMinimizer.hpp>
#include <LatAnalyze/NloptMinimizer.hpp>
#include <LatAnalyze/Plot.hpp>
#include <LatAnalyze/RandGen.hpp>
#include <LatAnalyze/XYStatData.hpp>
@ -11,7 +12,7 @@ using namespace std;
using namespace Latan;
const Index nPoint1 = 10, nPoint2 = 10;
const double xErr = .1, yErr = .1;
const double xErr = .1, yErr = .3;
const double exactPar[2] = {0.5,5.};
const double dx1 = 10.0/static_cast<double>(nPoint1);
const double dx2 = 5.0/static_cast<double>(nPoint2);
@ -25,6 +26,7 @@ int main(void)
DoubleModel f([](const double *x, const double *p)
{return p[1]*exp(-x[0]*p[0])+x[1];}, 2, 2);
cout << "-- generating fake data..." << endl;
data.addXDim(nPoint1);
data.addXDim(nPoint2);
data.addYDim();
@ -34,10 +36,10 @@ int main(void)
data.x(i1, 0) = rg.gaussian(xBuf[0], xErr);
for (Index i2 = 0; i2 < nPoint2; ++i2)
{
xBuf[1] = i2*dx2;
data.x(i2, 1) = xBuf[1];
data.y(data.dataIndex(i1, i2)) = rg.gaussian(f(xBuf, exactPar),
yErr);
xBuf[1] = i2*dx2;
data.x(i2, 1) = xBuf[1];
data.y(data.dataIndex(i1, i2), 0) = rg.gaussian(f(xBuf, exactPar),
yErr);
}
}
data.setXError(0, DVec::Constant(data.getXSize(0), xErr));
@ -52,7 +54,7 @@ int main(void)
vector<Minimizer *> min{&globalMin, &localMin};
globalMin.setVerbosity(Minimizer::Verbosity::Normal);
globalMin.setPrecision(0.01);
globalMin.setPrecision(0.1);
globalMin.setMaxIteration(10000);
globalMin.useLowLimit(0);
globalMin.setLowLimit(0, 0.);
@ -65,10 +67,26 @@ int main(void)
localMin.setVerbosity(Minimizer::Verbosity::Normal);
// fit
cout << "-- fit..." << endl;
f.parName().setName(0, "m");
f.parName().setName(1, "A");
p = data.fit(min, init, f);
p.print();
// plot
Plot plot;
DVec ref(2);
XYStatData res;
cout << "-- generating plots..." << endl;
ref(1) = 0.;
res = data.getPartialResiduals(p, ref, 0);
plot << PlotRange(Axis::x, 0., 10.);
plot << Color("rgb 'blue'");
plot << PlotFunction(p.getModel().bind(0, ref), 0., 10.);
plot << Color("rgb 'red'");
plot << PlotData(res);
plot.display();
return EXIT_SUCCESS;
}

View File

@ -3,6 +3,7 @@
#include <LatAnalyze/CompiledModel.hpp>
#include <LatAnalyze/MinuitMinimizer.hpp>
#include <LatAnalyze/NloptMinimizer.hpp>
#include <LatAnalyze/Plot.hpp>
#include <LatAnalyze/RandGen.hpp>
#include <LatAnalyze/XYSampleData.hpp>
@ -11,7 +12,7 @@ using namespace Latan;
const Index nPoint1 = 10, nPoint2 = 10;
const Index nSample = 1000;
const double xErr = .1, yErr = .1;
const double xErr = .1, yErr = .3;
const double exactPar[2] = {0.5,5.};
const double dx1 = 10.0/static_cast<double>(nPoint1);
const double dx2 = 5.0/static_cast<double>(nPoint2);
@ -25,6 +26,7 @@ int main(void)
DoubleModel f([](const double *x, const double *p)
{return p[1]*exp(-x[0]*p[0])+x[1];}, 2, 2);
cout << "-- generating fake data..." << endl;
data.addXDim(nPoint1);
data.addXDim(nPoint2);
data.addYDim();
@ -36,9 +38,9 @@ int main(void)
data.x(i1, 0)[s] = rg.gaussian(xBuf[0], xErr);
for (Index i2 = 0; i2 < nPoint2; ++i2)
{
xBuf[1] = i2*dx2;
data.x(i2, 1)[s] = xBuf[1];
data.y(data.dataIndex(i1, i2))[s] =
xBuf[1] = i2*dx2;
data.x(i2, 1)[s] = xBuf[1];
data.y(data.dataIndex(i1, i2), 0)[s] =
rg.gaussian(f(xBuf, exactPar), yErr);
}
}
@ -52,7 +54,7 @@ int main(void)
MinuitMinimizer localMin;
vector<Minimizer *> min{&globalMin, &localMin};
globalMin.setPrecision(0.01);
globalMin.setPrecision(0.1);
globalMin.setMaxIteration(10000);
globalMin.useLowLimit(0);
globalMin.setLowLimit(0, 0.);
@ -64,10 +66,28 @@ int main(void)
globalMin.setHighLimit(1, 20.);
// fit
cout << "-- fit..." << endl;
f.parName().setName(0, "m");
f.parName().setName(1, "A");
p = data.fit(min, init, f);
p.print();
// plot
Plot plot;
DVec ref(2);
XYStatData res;
cout << "-- generating plots..." << endl;
ref(1) = 0.;
res = data.getPartialResiduals(p, ref, 0).getData();
plot << PlotRange(Axis::x, 0., 10.);
plot << Color("rgb 'blue'");
plot << PlotPredBand(p.getModel(_).bind(0, ref), 0., 10.);
plot << Color("rgb 'blue'");
plot << PlotFunction(p.getModel().bind(0, ref), 0., 10.);
plot << Color("rgb 'red'");
plot << PlotData(res);
plot.display();
return EXIT_SUCCESS;
}

View File

@ -54,6 +54,7 @@ void FitInterface::addXDim(const Index nData, const string name,
maxDataIndex_ *= nData;
createXData(name, nData);
scheduleLayoutInit();
scheduleDataCoordInit();
if (!name.empty())
{
xName().setName(getNXDim(), name);
@ -121,7 +122,7 @@ Index FitInterface::getYSize(const Index j) const
return static_cast<Index>(yDataIndex_[j].size());
}
Index FitInterface::getXFitSize(void) const
Index FitInterface::getXFitSize(void)
{
Index size = 0;
@ -133,7 +134,7 @@ Index FitInterface::getXFitSize(void) const
return size;
}
Index FitInterface::getXFitSize(const Index i) const
Index FitInterface::getXFitSize(const Index i)
{
set<Index> fitCoord;
vector<Index> v;
@ -185,6 +186,11 @@ Index FitInterface::getMaxDataIndex(void) const
return maxDataIndex_;
}
const set<Index> & FitInterface::getDataIndexSet(void) const
{
return dataIndexSet_;
}
VarName & FitInterface::xName(void)
{
return xName_;
@ -221,22 +227,13 @@ Index FitInterface::dataIndex(const vector<Index> &v) const
return k;
}
vector<Index> FitInterface::dataCoord(const Index k) const
const vector<Index> & FitInterface::dataCoord(const Index k)
{
vector<Index> v(getNXDim());
Index buf, dimProd;
checkDataIndex(k);
buf = k;
dimProd = 1;
for (Index d = getNXDim() - 1; d >= 0; --d)
{
v[d] = (buf/dimProd)%xSize_[d];
buf -= dimProd*v[d];
dimProd *= xSize_[d];
}
return v;
updateDataCoord();
return dataCoord_.at(k);
}
// enable fit points ///////////////////////////////////////////////////////////
@ -335,7 +332,12 @@ bool FitInterface::pointExists(const Index k, const Index j) const
return !(yDataIndex_[j].find(k) == yDataIndex_[j].end());
}
bool FitInterface::isXUsed(const Index r, const Index i, const bool inFit) const
bool FitInterface::isXExact(const Index i) const
{
return xIsExact_[i];
}
bool FitInterface::isXUsed(const Index r, const Index i, const bool inFit)
{
vector<Index> v;
@ -346,7 +348,7 @@ bool FitInterface::isXUsed(const Index r, const Index i, const bool inFit) const
{
if (p.second or !inFit)
{
v = dataCoord(p.first);
v = dataCoord(p.first);
if (v[i] == r)
{
return true;
@ -418,9 +420,29 @@ void FitInterface::registerDataPoint(const Index k, const Index j)
{
checkYDim(j);
yDataIndex_[j][k] = true;
dataIndexSet_.insert(k);
scheduleLayoutInit();
}
// coordinate buffering ////////////////////////////////////////////////////////
void FitInterface::scheduleDataCoordInit(void)
{
initDataCoord_ = true;
}
void FitInterface::updateDataCoord(void)
{
if (initDataCoord_)
{
dataCoord_.clear();
for (auto k: getDataIndexSet())
{
dataCoord_[k] = rowMajToCoord(k);
}
initDataCoord_ = false;
}
}
// global layout management ////////////////////////////////////////////////////
void FitInterface::scheduleLayoutInit(void)
{
@ -578,6 +600,25 @@ Index FitInterface::indY(const Index k, const Index j) const
return ind;
}
// function to convert an row-major index into coordinates /////////////////////
vector<Index> FitInterface::rowMajToCoord(const Index k) const
{
vector<Index> v(getNXDim());
Index buf, dimProd;
checkDataIndex(k);
buf = k;
dimProd = 1;
for (Index d = getNXDim() - 1; d >= 0; --d)
{
v[d] = (buf/dimProd)%xSize_[d];
buf -= dimProd*v[d];
dimProd *= xSize_[d];
}
return v;
}
// IO //////////////////////////////////////////////////////////////////////////
ostream & Latan::operator<<(ostream &out, FitInterface &f)
{

View File

@ -65,26 +65,27 @@ public:
const bool isExact = false);
void addYDim(const std::string name = "");
// access
Index getNXDim(void) const;
Index getNYDim(void) const;
Index getXSize(void) const;
Index getXSize(const Index i) const;
Index getYSize(void) const;
Index getYSize(const Index j) const;
Index getXFitSize(void) const;
Index getXFitSize(const Index i) const;
Index getYFitSize(void) const;
Index getYFitSize(const Index j) const;
Index getMaxDataIndex(void) const;
VarName & xName(void);
const VarName & xName(void) const;
VarName & yName(void);
const VarName & yName(void) const;
Index getNXDim(void) const;
Index getNYDim(void) const;
Index getXSize(void) const;
Index getXSize(const Index i) const;
Index getYSize(void) const;
Index getYSize(const Index j) const;
Index getXFitSize(void);
Index getXFitSize(const Index i);
Index getYFitSize(void) const;
Index getYFitSize(const Index j) const;
Index getMaxDataIndex(void) const;
const std::set<Index> & getDataIndexSet(void) const;
VarName & xName(void);
const VarName & xName(void) const;
VarName & yName(void);
const VarName & yName(void) const;
// Y dimension index helper
template <typename... Ts>
Index dataIndex(const Ts... is) const;
Index dataIndex(const std::vector<Index> &v) const;
std::vector<Index> dataCoord(const Index k) const;
Index dataIndex(const Ts... is) const;
Index dataIndex(const std::vector<Index> &v) const;
const std::vector<Index> & dataCoord(const Index k);
// enable fit points
void fitPoint(const bool isFitPoint, const Index k, const Index j = 0);
// variance interface
@ -98,7 +99,8 @@ public:
// tests
bool pointExists(const Index k) const;
bool pointExists(const Index k, const Index j) const;
bool isXUsed(const Index r, const Index i, const bool inFit = true) const;
bool isXExact(const Index i) const;
bool isXUsed(const Index r, const Index i, const bool inFit = true);
bool isFitPoint(const Index k, const Index j) const;
// make correlation filter for fit variance matrix
DMat makeCorrFilter(void);
@ -115,22 +117,31 @@ protected:
// abstract methods to create data containers
virtual void createXData(const std::string name, const Index nData) = 0;
virtual void createYData(const std::string name) = 0;
// coordinate buffering
void scheduleDataCoordInit(void);
void updateDataCoord(void);
// global layout management
void scheduleLayoutInit(void);
bool initVarMat(void);
void updateLayout(void);
Index indX(const Index r, const Index i) const;
Index indY(const Index k, const Index j) const;
private:
// function to convert an row-major index into coordinates
std::vector<Index> rowMajToCoord(const Index k) const;
protected:
Layout layout;
private:
VarName xName_, yName_;
std::vector<Index> xSize_;
std::vector<bool> xIsExact_;
std::vector<std::map<Index, bool>> yDataIndex_;
std::set<std::array<Index, 4>> xxCorr_, yyCorr_, xyCorr_;
Index maxDataIndex_{1};
bool initLayout_{true}, initVarMat_{true};
VarName xName_, yName_;
std::vector<Index> xSize_;
std::vector<bool> xIsExact_;
std::map<Index, std::vector<Index>> dataCoord_;
std::set<Index> dataIndexSet_;
std::vector<std::map<Index, bool>> yDataIndex_;
std::set<std::array<Index, 4>> xxCorr_, yyCorr_, xyCorr_;
Index maxDataIndex_{1};
bool initLayout_{true}, initVarMat_{true};
bool initDataCoord_{true};
};
std::ostream & operator<<(std::ostream &out, FitInterface &f);

View File

@ -167,20 +167,15 @@ PlotData::PlotData(const DMatSample &x, const DVec &y)
setCommand("'" + tmpFileName + "' u 1:3:2 w xerr");
}
//PlotData::PlotData(const XYStatData &data, const Index i, const Index j)
//{
// DMat d(data.getNData(), 4);
// string usingCmd, tmpFileName;
//
// d.col(0) = data.x(i);
// d.col(2) = data.y(j);
// d.col(1) = data.xxVar(i, i).diagonal().array().sqrt();
// d.col(3) = data.yyVar(j, j).diagonal().array().sqrt();
// usingCmd = (data.isXExact(i)) ? "u 1:3:4 w yerr" : "u 1:3:2:4 w xyerr";
// tmpFileName = dumpToTmpFile(d);
// pushTmpFile(tmpFileName);
// setCommand("'" + tmpFileName + "' " + usingCmd);
//}
PlotData::PlotData(XYStatData &data, const Index i, const Index j)
{
string usingCmd, tmpFileName;
usingCmd = (data.isXExact(i)) ? "u 1:3:4 w yerr" : "u 1:3:2:4 w xyerr";
tmpFileName = dumpToTmpFile(data.getTable(i, j));
pushTmpFile(tmpFileName);
setCommand("'" + tmpFileName + "' " + usingCmd);
}
// PlotHLine constructor ///////////////////////////////////////////////////////
PlotHLine::PlotHLine(const double y)

View File

@ -25,7 +25,7 @@
#include <LatAnalyze/Mat.hpp>
#include <LatAnalyze/MatSample.hpp>
#include <LatAnalyze/Histogram.hpp>
//#include <LatAnalyze/XYStatData.hpp>
#include <LatAnalyze/XYStatData.hpp>
#include <sstream>
#include <vector>
@ -94,7 +94,7 @@ public:
PlotData(const DMatSample &x, const DMatSample &y);
PlotData(const DVec &x, const DMatSample &y);
PlotData(const DMatSample &x, const DVec &y);
//PlotData(const XYStatData &data, const Index i = 0, const Index j = 0);
PlotData(XYStatData &data, const Index i = 0, const Index j = 0);
// destructor
virtual ~PlotData(void) = default;
};

View File

@ -138,6 +138,15 @@ const DSample & XYSampleData::x(const Index r, const Index i) const
return xData_[i][r];
}
const DMatSample & XYSampleData::x(const Index k)
{
checkDataIndex(k);
updateXMap();
return xMap_.at(k);
}
DSample & XYSampleData::y(const Index k, const Index j)
{
checkYDim(j);
@ -299,6 +308,74 @@ SampleFitResult XYSampleData::fit(Minimizer &minimizer,
return fit(mv, init, v);
}
// residuals ///////////////////////////////////////////////////////////////////
XYSampleData XYSampleData::getResiduals(const SampleFitResult &fit)
{
XYSampleData res(*this);
for (Index j = 0; j < getNYDim(); ++j)
{
const DoubleFunctionSample &f = fit.getModel(_, j);
for (auto &p: yData_[j])
{
res.y(p.first, j) -= f(x(p.first));
}
}
return res;
}
XYSampleData XYSampleData::getPartialResiduals(const SampleFitResult &fit,
const DVec &ref, const Index i)
{
XYSampleData res(*this);
DMatSample buf(nSample_);
buf.fill(ref);
for (Index j = 0; j < getNYDim(); ++j)
{
const DoubleFunctionSample &f = fit.getModel(_, j);
for (auto &p: yData_[j])
{
FOR_STAT_ARRAY(buf, s)
{
buf[s](i) = x(p.first)[s](i);
}
res.y(p.first, j) -= f(x(p.first)) - f(buf);
}
}
return res;
}
// buffer list of x vectors ////////////////////////////////////////////////////
void XYSampleData::scheduleXMapInit(void)
{
initXMap_ = true;
}
void XYSampleData::updateXMap(void)
{
if (initXMap_)
{
for (Index s = central; s < nSample_; ++s)
{
setDataToSample(s);
for (auto k: getDataIndexSet())
{
if (s == central)
{
xMap_[k].resize(nSample_);
}
xMap_[k][s] = data_.x(k);
}
}
initXMap_ = false;
}
}
// schedule data initilization from samples ////////////////////////////////////
void XYSampleData::scheduleDataInit(void)
{

View File

@ -75,15 +75,16 @@ public:
// destructor
virtual ~XYSampleData(void) = default;
// data access
DSample & x(const Index r, const Index i = 0);
const DSample & x(const Index r, const Index i = 0) const;
DSample & y(const Index k, const Index j = 0);
const DSample & y(const Index k, const Index j = 0) const;
const DMat & getXXVar(const Index i1, const Index i2);
const DMat & getYYVar(const Index j1, const Index j2);
const DMat & getXYVar(const Index i, const Index j);
DVec getXError(const Index i);
DVec getYError(const Index j);
DSample & x(const Index r, const Index i);
const DSample & x(const Index r, const Index i) const;
const DMatSample & x(const Index k);
DSample & y(const Index k, const Index j);
const DSample & y(const Index k, const Index j) const;
const DMat & getXXVar(const Index i1, const Index i2);
const DMat & getYYVar(const Index j1, const Index j2);
const DMat & getXYVar(const Index i, const Index j);
DVec getXError(const Index i);
DVec getYError(const Index j);
// get total fit variance matrix and its pseudo-inverse
const DMat & getFitVarMat(void);
const DMat & getFitVarMatPInv(void);
@ -102,7 +103,14 @@ public:
template <typename... Ts>
SampleFitResult fit(Minimizer &minimizer, const DVec &init,
const DoubleModel &model, const Ts... models);
// residuals
XYSampleData getResiduals(const SampleFitResult &fit);
XYSampleData getPartialResiduals(const SampleFitResult &fit, const DVec &x,
const Index i);
private:
// buffer list of x vectors
void scheduleXMapInit(void);
void updateXMap(void);
// schedule data initilization from samples
void scheduleDataInit(void);
// variance matrix computation
@ -114,9 +122,11 @@ private:
private:
std::vector<std::map<Index, DSample>> yData_;
std::vector<std::vector<DSample>> xData_;
std::map<Index, DMatSample> xMap_;
XYStatData data_;
Index nSample_, dataSample_{central};
bool initData_{true}, computeVarMat_{true};
bool initXMap_{true};
};
/******************************************************************************

View File

@ -96,6 +96,15 @@ const double & XYStatData::x(const Index r, const Index i) const
return xData_[i](r);
}
const DVec & XYStatData::x(const Index k)
{
checkDataIndex(k);
updateXMap();
return xMap_.at(k);
}
double & XYStatData::y(const Index k, const Index j)
{
checkYDim(j);
@ -206,6 +215,29 @@ DVec XYStatData::getYError(const Index j) const
return yyVar_(j, j).diagonal().cwiseSqrt();
}
DMat XYStatData::getTable(const Index i, const Index j)
{
checkXDim(i);
checkYDim(j);
DMat table(getYSize(j), 4);
Index row = 0;
for (auto &p: yData_[j])
{
Index k = p.first;
Index r = dataCoord(k)[i];
table(row, 0) = x(k)(i);
table(row, 2) = p.second;
table(row, 1) = xxVar_(i, i).diagonal().cwiseSqrt()(r);
table(row, 3) = yyVar_(j, j).diagonal().cwiseSqrt()(row);
row++;
}
return table;
}
// get total fit variance matrix ///////////////////////////////////////////////
const DMat & XYStatData::getFitVarMat(void)
{
@ -308,6 +340,44 @@ FitResult XYStatData::fit(Minimizer &minimizer, const DVec &init,
return fit(mv, init, v);
}
// residuals ///////////////////////////////////////////////////////////////////
XYStatData XYStatData::getResiduals(const FitResult &fit)
{
XYStatData res(*this);
for (Index j = 0; j < getNYDim(); ++j)
{
const DoubleFunction &f = fit.getModel(j);
for (auto &p: yData_[j])
{
res.y(p.first, j) -= f(x(p.first));
}
}
return res;
}
XYStatData XYStatData::getPartialResiduals(const FitResult &fit,
const DVec &ref, const Index i)
{
XYStatData res(*this);
DVec buf(ref);
for (Index j = 0; j < res.getNYDim(); ++j)
{
const DoubleFunction &f = fit.getModel(j);
for (auto &p: yData_[j])
{
buf(i) = x(p.first)(i);
res.y(p.first, j) -= f(x(p.first)) - f(buf);
}
}
return res;
}
// create data /////////////////////////////////////////////////////////////////
void XYStatData::createXData(const std::string name __dumb, const Index nData)
{
@ -450,24 +520,13 @@ void XYStatData::updateXMap(void)
{
if (initXMap_)
{
vector<Index> v;
set<Index> indSet;
for (Index j = 0; j < getNYDim(); ++j)
{
for (auto &p: yData_[j])
{
indSet.insert(p.first);
}
}
xMap_.clear();
for (auto k: indSet)
for (auto k: getDataIndexSet())
{
xMap_[k] = DVec(getNXDim());
v = dataCoord(k);
xMap_[k] = DVec(getNXDim());
for (Index i = 0; i < getNXDim(); ++i)
{
xMap_[k](i) = xData_[i](v[i]);
xMap_[k](i) = xData_[i](dataCoord(k)[i]);
}
}
initXMap_ = false;
@ -510,7 +569,6 @@ void XYStatData::updateChi2ModVec(const DVec p,
Index nPar = v[0]->getNPar(), a = 0, j, k, ind;
auto &par = p.segment(0, nPar), &xsi = p.segment(nPar, layout.totalXSize);
updateXMap();
for (Index jfit = 0; jfit < layout.nYFitDim; ++jfit)
for (Index sfit = 0; sfit < layout.ySize[jfit]; ++sfit)
{
@ -519,7 +577,7 @@ void XYStatData::updateChi2ModVec(const DVec p,
for (Index i = 0; i < getNXDim(); ++i)
{
ind = layout.xIndFromData[k][i] - layout.totalYSize;
xBuf_(i) = (ind >= 0) ? xsi(ind) : xMap_[k](i);
xBuf_(i) = (ind >= 0) ? xsi(ind) : x(k)(i);
}
chi2ModVec_(a) = (*v[j])(xBuf_.data(), par.data());
a++;

View File

@ -69,10 +69,11 @@ public:
// destructor
virtual ~XYStatData(void) = default;
// data access
double & x(const Index r, const Index i = 0);
const double & x(const Index r, const Index i = 0) const;
double & y(const Index k, const Index j = 0);
const double & y(const Index k, const Index j = 0) const;
double & x(const Index r, const Index);
const double & x(const Index r, const Index) const;
const DVec & x(const Index k);
double & y(const Index k, const Index);
const double & y(const Index k, const Index) const;
void setXXVar(const Index i1, const Index i2, const DMat &m);
void setYYVar(const Index j1, const Index j2, const DMat &m);
void setXYVar(const Index i, const Index j, const DMat &m);
@ -83,6 +84,7 @@ public:
const DMat & getXYVar(const Index i, const Index j) const;
DVec getXError(const Index i) const;
DVec getYError(const Index j) const;
DMat getTable(const Index i, const Index j);
// get total fit variance matrix and its pseudo-inverse
const DMat & getFitVarMat(void);
const DMat & getFitVarMatPInv(void);
@ -97,6 +99,10 @@ public:
template <typename... Ts>
FitResult fit(Minimizer &minimizer, const DVec &init,
const DoubleModel &model, const Ts... models);
// residuals
XYStatData getResiduals(const FitResult &fit);
XYStatData getPartialResiduals(const FitResult &fit, const DVec &ref,
const Index i);
protected:
// create data
virtual void createXData(const std::string name, const Index nData);