20#include "analysis/OrcaKinFit/SoftBWParticleConstraint.h" 
   21#include "analysis/OrcaKinFit/ParticleFitObject.h" 
   22#include <framework/logging/Logger.h> 
   24#include "Math/ProbFuncMathCore.h" 
   25#include "Math/QuantFuncMathCore.h" 
   37  namespace OrcaKinFit {
 
   39    SoftBWParticleConstraint::SoftBWParticleConstraint(
double gamma_, 
double emin_, 
double emax_)
 
   41      fitobjects(FitObjectContainer()), derivatives(std::vector <double> ()), flags(std::vector <int> ()),
 
   42      gamma(gamma_), emin(emin_), emax(emax_),
 
   44      atanxmin(0), atanxmax(0), diffatanx(0)
 
   49    double SoftBWParticleConstraint::getGamma()
 const 
   54    double SoftBWParticleConstraint::setGamma(
double gamma_)
 
   56      if (gamma_ != 0) gamma = std::abs(gamma_);
 
   61    double SoftBWParticleConstraint::getChi2()
 const 
   63      return penalty(getValue());
 
   66    double SoftBWParticleConstraint::getError()
 const 
   70      for (
unsigned int i = 0; i < fitobjects.size(); ++i) {
 
   71        const ParticleFitObject* foi = fitobjects[i];
 
   73        if (firstDerivatives(i, dgdpi)) {
 
   74          error2 += foi->getError2(dgdpi, getVarBasis());
 
   77      return std::sqrt(std::abs(error2));
 
  103    void SoftBWParticleConstraint::add2ndDerivativesToMatrix(
double* M, 
int idim)
 const 
  113      double e = getValue();
 
  114      double fact = penalty1stder(e);
 
  115      double fact2 = penalty2ndder(e);
 
  119      double d2GdPidPj[16];
 
  125      const int n = fitobjects.size();
 
  126      double* dPidAk = 
new double[n * KMAX * 4];
 
  127      bool* dPidAkval = 
new bool[n];
 
  129      for (
int i = 0; i < n; ++i) dPidAkval[i] = 
false;
 
  133      double d2GdPdAl[4 * KMAX];
 
  135      double d2GdAkdAl[KMAX * KMAX] = {0};
 
  141      int* parglobal = 
new int[KMAX * n];
 
  143      for (
int i = 0; i < n; ++i) {
 
  144        const ParticleFitObject* foi = fitobjects[i];
 
  146        for (
int klocal = 0; klocal < foi->getNPar(); ++klocal) {
 
  147          parglobal [KMAX * i + klocal] = foi->getGlobalParNum(klocal);
 
  152      for (
int i = 0; i < n; ++i) {
 
  153        const ParticleFitObject* foi = fitobjects[i];
 
  155        for (
int j = 0; j < n; ++j) {
 
  156          const ParticleFitObject* foj = fitobjects[j];
 
  158          if (secondDerivatives(i, j, d2GdPidPj)) {
 
  160              foi->getDerivatives(dPidAk + i * (KMAX * 4), KMAX * 4);
 
  164              foj->getDerivatives(dPidAk + j * (KMAX * 4), KMAX * 4);
 
  172            for (
int llocal = 0; llocal < foj->getNPar(); ++llocal) {
 
  173              for (
int ii = 0; ii < 4; ++ii) {
 
  175                int ind2 = (KMAX * 4) * j + 4 * llocal;
 
  176                double& r = d2GdPdAl[4 * llocal + ii];
 
  177                r  = d2GdPidPj[  ind1] * dPidAk[  ind2];   
 
  178                r += d2GdPidPj[++ind1] * dPidAk[++ind2];   
 
  179                r += d2GdPidPj[++ind1] * dPidAk[++ind2];   
 
  180                r += d2GdPidPj[++ind1] * dPidAk[++ind2];   
 
  189            for (
int klocal = 0; klocal < foi->getNPar(); ++klocal) {
 
  190              for (
int llocal = 0; llocal < foj->getNPar(); ++llocal) {
 
  191                int ind1 = 4 * llocal;
 
  192                int ind2 = (KMAX * 4) * i + 4 * klocal;
 
  193                double& r = d2GdAkdAl[KMAX * klocal + llocal];
 
  194                r  = d2GdPdAl[  ind1] * dPidAk[  ind2];    
 
  195                r += d2GdPdAl[++ind1] * dPidAk[++ind2];   
 
  196                r += d2GdPdAl[++ind1] * dPidAk[++ind2];   
 
  197                r += d2GdPdAl[++ind1] * dPidAk[++ind2];   
 
  201            for (
int klocal = 0; klocal < foi->getNPar(); ++klocal) {
 
  202              int kglobal = parglobal [KMAX * i + klocal];
 
  203              for (
int llocal = 0; llocal < foj->getNPar(); ++llocal) {
 
  204                int lglobal = parglobal [KMAX * j + llocal];
 
  205                M [idim * kglobal + lglobal] += fact * d2GdAkdAl[KMAX * klocal + llocal];
 
  230      double* v = 
new double[idim];
 
  231      for (
int i = 0; i < idim; ++i) v[i] = 0;
 
  235      for (
int i = 0; i < n; ++i) {
 
  236        const ParticleFitObject* foi = fitobjects[i];
 
  238        if (firstDerivatives(i, dgdpi)) {
 
  239          foi->addTo2ndDerivatives(M, idim, fact, dgdpi, getVarBasis());
 
  240          foi->addToGlobalChi2DerVector(v, idim, 1, dgdpi, getVarBasis());
 
  244      for (
int i = 0; i < idim; ++i) {
 
  245        if (
double vi = v[i]) {
 
  246          int ioffs = i * idim;
 
  247          for (
double* pvj = v; pvj < v + idim; ++pvj) {
 
  248            M[ioffs++] += fact2 * vi * (*pvj);
 
  260    void SoftBWParticleConstraint::addToGlobalChi2DerVector(
double* y, 
int idim)
 const 
  263      double r = penalty1stder(getValue());
 
  264      for (
unsigned int i = 0; i < fitobjects.size(); ++i) {
 
  265        const ParticleFitObject* foi = fitobjects[i];
 
  267        if (firstDerivatives(i, dgdpi)) {
 
  268          foi->addToGlobalChi2DerVector(y, idim, r, dgdpi, getVarBasis());
 
  273    void SoftBWParticleConstraint::test1stDerivatives()
 
  275      B2INFO(
"SoftBWParticleConstraint::test1stDerivatives for " << getName());
 
  277      for (
int i = 0; i < 100; ++i) y[i] = 0;
 
  278      addToGlobalChi2DerVector(y, 100);
 
  279      double eps = 0.00001;
 
  280      for (
unsigned int ifo = 0; ifo < fitobjects.size(); ++ifo) {
 
  281        ParticleFitObject* fo = fitobjects[ifo];
 
  283        for (
int ilocal = 0; ilocal < fo->getNPar(); ++ilocal) {
 
  284          int iglobal = fo->getGlobalParNum(ilocal);
 
  285          double calc = y[iglobal];
 
  286          double num = num1stDerivative(ifo, ilocal, eps);
 
  287          B2INFO(
"fo: " << fo->getName() << 
" par " << ilocal << 
"/" 
  288                 << iglobal << 
" (" << fo->getParamName(ilocal)
 
  289                 << 
") calc: " << calc << 
" - num: " << num << 
" = " << calc - num);
 
  293    void SoftBWParticleConstraint::test2ndDerivatives()
 
  295      B2INFO(
"SoftBWParticleConstraint::test2ndDerivatives for " << getName());
 
  296      const int idim = 100;
 
  297      double* M = 
new double[idim * idim];
 
  298      for (
int i = 0; i < idim * idim; ++i) M[i] = 0;
 
  299      add2ndDerivativesToMatrix(M, idim);
 
  301      B2INFO(
"eps=" << eps);
 
  303      for (
unsigned int ifo1 = 0; ifo1 < fitobjects.size(); ++ifo1) {
 
  304        ParticleFitObject* fo1 = fitobjects[ifo1];
 
  306        for (
unsigned int ifo2 = ifo1; ifo2 < fitobjects.size(); ++ifo2) {
 
  307          ParticleFitObject* fo2 = fitobjects[ifo2];
 
  309          for (
int ilocal1 = 0; ilocal1 < fo1->getNPar(); ++ilocal1) {
 
  310            int iglobal1 = fo1->getGlobalParNum(ilocal1);
 
  311            for (
int ilocal2 = (ifo1 == ifo2 ? ilocal1 : 0); ilocal2 < fo2->getNPar(); ++ilocal2) {
 
  312              int iglobal2 = fo2->getGlobalParNum(ilocal2);
 
  313              double calc = M[idim * iglobal1 + iglobal2];
 
  314              double num = num2ndDerivative(ifo1, ilocal1, eps, ifo2, ilocal2, eps);
 
  315              B2INFO(
"fo1: " << fo1->getName() << 
" par " << ilocal1 << 
"/" 
  316                     << iglobal1 << 
" (" << fo1->getParamName(ilocal1)
 
  317                     << 
"), fo2: " << fo2->getName() << 
" par " << ilocal2 << 
"/" 
  318                     << iglobal2 << 
" (" << fo2->getParamName(ilocal2)
 
  319                     << 
") calc: " << calc << 
" - num: " << num << 
" = " << calc - num);
 
  328    double SoftBWParticleConstraint::num1stDerivative(
int ifo, 
int ilocal, 
double eps)
 
  330      ParticleFitObject* fo = fitobjects[ifo];
 
  332      double save = fo->getParam(ilocal);
 
  333      fo->setParam(ilocal, save + eps);
 
  334      double v1 = getChi2();
 
  335      fo->setParam(ilocal, save - eps);
 
  336      double v2 = getChi2();
 
  337      double result = (v1 - v2) / (2 * eps);
 
  338      fo->setParam(ilocal, save);
 
  342    double SoftBWParticleConstraint::num2ndDerivative(
int ifo1, 
int ilocal1, 
double eps1,
 
  343                                                      int ifo2, 
int ilocal2, 
double eps2)
 
  347      if (ifo1 == ifo2 && ilocal1 == ilocal2) {
 
  348        ParticleFitObject* fo = fitobjects[ifo1];
 
  350        double save = fo->getParam(ilocal1);
 
  351        double v0 = getChi2();
 
  352        fo->setParam(ilocal1, save + eps1);
 
  353        double v1 = getChi2();
 
  354        fo->setParam(ilocal1, save - eps1);
 
  355        double v2 = getChi2();
 
  356        result = (v1 + v2 - 2 * v0) / (eps1 * eps1);
 
  357        fo->setParam(ilocal1, save);
 
  359        ParticleFitObject* fo1 = fitobjects[ifo1];
 
  361        ParticleFitObject* fo2 = fitobjects[ifo2];
 
  363        double save1 = fo1->getParam(ilocal1);
 
  364        double save2 = fo2->getParam(ilocal2);
 
  365        fo1->setParam(ilocal1, save1 + eps1);
 
  366        fo2->setParam(ilocal2, save2 + eps2);
 
  367        double v11 = getChi2();
 
  368        fo2->setParam(ilocal2, save2 - eps2);
 
  369        double v12 = getChi2();
 
  370        fo1->setParam(ilocal1, save1 - eps1);
 
  371        double v22 = getChi2();
 
  372        fo2->setParam(ilocal2, save2 + eps2);
 
  373        double v21 = getChi2();
 
  374        result = (v11 + v22 - v12 - v21) / (4 * eps1 * eps2);
 
  375        fo1->setParam(ilocal1, save1);
 
  376        fo2->setParam(ilocal2, save2);
 
  381    double SoftBWParticleConstraint::erfinv(
double x)
 
  391      return 2 * ROOT::Math::normal_quantile(std::sqrt(2.0) * x, 1.0) - 1;
 
  394    double SoftBWParticleConstraint::normal_quantile(
double x)
 
  396      return ROOT::Math::normal_quantile(x, 1.0);
 
  399    double SoftBWParticleConstraint::normal_quantile_1stderiv(
double x)
 
  401      double y = ROOT::Math::normal_quantile(x, 1.0);
 
  402      return 1 / normal_pdf(y);
 
  405    double SoftBWParticleConstraint::normal_quantile_2ndderiv(
double x)
 
  407      double y = ROOT::Math::normal_quantile(x, 1.0);
 
  408      return -y / pow(normal_pdf(y), 2);
 
  411    double SoftBWParticleConstraint::normal_pdf(
double x)
 
  413      static const double C_1_SQRT2PI = 1 / (std::sqrt(2 * M_PI));
 
  414      return C_1_SQRT2PI * std::exp(-0.5 * x * x);
 
  417    double SoftBWParticleConstraint::normal_pdf_deriv(
double x)
 
  419      static const double C_1_SQRT2PI = 1 / (std::sqrt(2 * M_PI));
 
  420      return -C_1_SQRT2PI * x * std::exp(-0.5 * x * x);
 
  423    double SoftBWParticleConstraint::penalty(
double e)
 const 
  425      double x = e / gamma;
 
  439      if (!cachevalid) updateCache();
 
  440      double F = 0.5 + std::atan(x) / diffatanx;
 
  441      if (F < 0 || F > 1 || !std::isfinite(F))
 
  442        B2INFO(
"SoftBWParticleConstraint::penalty: error for e=" << e
 
  443               << 
", gamma=" << gamma << 
" -> x=" << x << 
" => F=" << F);
 
  447      double result = std::pow(normal_quantile(F), 2);
 
  448      assert(std::isfinite(result));
 
  460    double SoftBWParticleConstraint::penalty1stder(
double e)
 const 
  462      double x = e / gamma;
 
  463      if (!cachevalid) updateCache();
 
  464      double F = 0.5 + std::atan(x) / diffatanx;
 
  465      double dF_de = 1. / ((1 + x * x) * diffatanx * gamma);
 
  466      double result = 2 * normal_quantile(F) * normal_quantile_1stderiv(F) * dF_de;
 
  467      assert(std::isfinite(result));
 
  471    double SoftBWParticleConstraint::penalty2ndder(
double e)
 const 
  473      double x = e / gamma;
 
  474      if (!cachevalid) updateCache();
 
  475      double F = 0.5 + std::atan(x) / diffatanx;
 
  476      double dF_de = 1. / ((1 + x * x) * diffatanx * gamma);
 
  477      double d2F_de2 = -2 * diffatanx * x * dF_de * dF_de;
 
  479      double result = 2 * pow(normal_quantile_1stderiv(F) * dF_de, 2)
 
  480                      + 2 * normal_quantile(F) * normal_quantile_2ndderiv(F) * dF_de * dF_de
 
  481                      + 2 * normal_quantile(F) * normal_quantile_1stderiv(F) * d2F_de2;
 
  482      assert(std::isfinite(result));
 
  488    void SoftBWParticleConstraint::invalidateCache()
 const 
  493    void SoftBWParticleConstraint::updateCache()
 const 
  495      if (emin == -numeric_limits<double>::infinity())
 
  497      else if (emin == numeric_limits<double>::infinity())
 
  499      else  atanxmin = std::atan(emin / gamma);
 
  500      if (emax == -numeric_limits<double>::infinity())
 
  502      else if (emax == numeric_limits<double>::infinity())
 
  504      else  atanxmax = std::atan(emax / gamma);
 
  505      diffatanx = atanxmax - atanxmin;
 
  508      B2INFO(
"SoftBWParticleConstraint::updateCache(): " 
  510             << 
", emin=" << emin << 
" -> atanxmin=" << atanxmin
 
  511             << 
", emax=" << emax << 
" -> atanxmax=" << atanxmax
 
  512             << 
" => diffatanx=" << diffatanx);
 
  516    bool SoftBWParticleConstraint::cacheValid()
 const 
  521    int SoftBWParticleConstraint::getVarBasis()
 const 
Abstract base class for different kinds of events.