// StandardModel.cc is a part of the PYTHIA event generator.
// Copyright (C) 2026 Torbjorn Sjostrand.
// PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
// Please respect the MCnet Guidelines, see GUIDELINES for details.

// Function definitions (not found in the header) for the AlphaStrong class.

#include "Pythia8/StandardModel.h"

namespace Pythia8 {

//==========================================================================

// The AlphaStrong class.

//--------------------------------------------------------------------------

// Constants: could be changed here if desired, but normally should not.
// These are of technical nature, as described for each.

// Number of iterations to determine Lambda from given alpha_s.
const int AlphaStrong::NITER           = 10;

// MZ normalization scale
const double AlphaStrong::MZ           = 91.188;

// Always evaluate running alpha_s above Lambda3 to avoid disaster.
// Safety margin picked to freeze roughly for alpha_s = 10.
const double AlphaStrong::SAFETYMARGIN1 = 1.07;
const double AlphaStrong::SAFETYMARGIN2 = 1.33;

// CMW factor for 3, 4, 5, and 6 flavours.
const double AlphaStrong::FACCMW3         = 1.661;
const double AlphaStrong::FACCMW4         = 1.618;
const double AlphaStrong::FACCMW5         = 1.569;
const double AlphaStrong::FACCMW6         = 1.513;

//--------------------------------------------------------------------------

// Initialize alpha_strong calculation by finding Lambda values etc.

void AlphaStrong::init( double valueIn, int orderIn, int nfmaxIn,
  bool useCMWIn, double valueMaxIn, double renormShiftIn) {

  // Set default mass thresholds if not already done
  if (mt <= 1.) setThresholds(1.5, 4.8, 171.0);

  // Order of alpha_s evaluation.Default values.
  valueRef = valueIn;
  order    = max( 0, min( 3, orderIn ) );
  nfmax    = max( 5, min( 6, nfmaxIn ) );
  useCMW   = useCMWIn;
  lastCallToFull = false;
  Lambda3Save = Lambda4Save = Lambda5Save = Lambda6Save = scale2Min = 0.;

  // Fix alpha_s.
  if (order == 0) {

  // First order alpha_s: match at flavour thresholds.
  } else if (order == 1) {
    Lambda5Save = MZ * exp( -6. * M_PI / (23. * valueRef) );
    Lambda6Save = Lambda5Save * pow(Lambda5Save/mt, 2./21.);
    Lambda4Save = Lambda5Save * pow(mb/Lambda5Save, 2./25.);
    Lambda3Save = Lambda4Save * pow(mc/Lambda4Save, 2./27.);

  // Second or third order alpha_s: iterative match at flavour thresholds.
  } else {
    // The two-loop coefficients: b1 / b0^2
    double b16 = 234. / 441.;
    double b15 = 348. / 529.;
    double b14 = 462. / 625.;
    double b13 = 576. / 729.;
    // The three-loop coefficients: b2 * b0 / b1^2
    double b26 = -36855. / 109512.;
    double b25 = 224687. / 242208.;
    double b24 = 548575. / 426888.;
    double b23 = 938709. / 663552.;

    double logScale, loglogScale, correction, valueIter;
    // Find Lambda_5 at m_Z, starting from one-loop value.
    Lambda5Save = MZ * exp( -6. * M_PI / (23. * valueRef) );
    for (int iter = 0; iter < NITER; ++iter) {
      logScale    = 2. * log(MZ/Lambda5Save);
      loglogScale = log(logScale);
      correction  = 1. - b15 * loglogScale / logScale;
      if (order == 3) correction
        += pow2(b15 / logScale) * (pow2(loglogScale - 0.5) + b25 - 1.25);
      valueIter   = valueRef / correction;
      Lambda5Save = MZ * exp( -6. * M_PI / (23. * valueIter) );
    }

    // Find Lambda_6 at m_t, by requiring alphaS(nF=6,m_t) = alphaS(nF=5,m_t)
    double logScaleT    = 2. * log(mt/Lambda5Save);
    double loglogScaleT = log(logScaleT);
    correction =  1. - b15 * loglogScaleT / logScaleT;
    if (order == 3) correction
      += pow2(b15 / logScaleT) * (pow2(loglogScaleT - 0.5) + b25 - 1.25);
    double valueT       = 12. * M_PI / (23. * logScaleT) * correction;
    Lambda6Save         = Lambda5Save;
    for (int iter = 0; iter < NITER; ++iter) {
      logScale    = 2. * log(mt/Lambda6Save);
      loglogScale = log(logScale);
      correction  = 1. - b16 * loglogScale / logScale;
      if (order == 3) correction
        += pow2(b16 / logScale) * (pow2(loglogScale - 0.5) + b26 - 1.25);
      valueIter   = valueT / correction;
      Lambda6Save = mt * exp( -6. * M_PI / (21. * valueIter) );
    }

    // Find Lambda_4 at m_b, by requiring alphaS(nF=4,m_b) = alphaS(nF=5,m_b)
    double logScaleB    = 2. * log(mb/Lambda5Save);
    double loglogScaleB = log(logScaleB);
    correction = 1. - b15 * loglogScaleB / logScaleB;
    if (order == 3) correction
      += pow2(b15 / logScaleB) * (pow2(loglogScaleB - 0.5) + b25- 1.25);
    double valueB       = 12. * M_PI / (23. * logScaleB) * correction;
    Lambda4Save         = Lambda5Save;
    for (int iter = 0; iter < NITER; ++iter) {
      logScale    = 2. * log(mb/Lambda4Save);
      loglogScale = log(logScale);
      correction  = 1. - b14 * loglogScale / logScale;
      if (order == 3) correction
        += pow2(b14 / logScale) * (pow2(loglogScale - 0.5) + b24 - 1.25);
      valueIter   = valueB / correction;
      Lambda4Save = mb * exp( -6. * M_PI / (25. * valueIter) );
     }

    // Find Lambda_3 at m_c, by requiring alphaS(nF=3,m_c) = alphaS(nF=4,m_c)
    double logScaleC    = 2. * log(mc/Lambda4Save);
    double loglogScaleC = log(logScaleC);
    correction = 1. - b14 * loglogScaleC / logScaleC;
    if (order == 3) correction
      += pow2(b14 / logScaleC) * (pow2(loglogScaleC - 0.5) + b24 - 1.25);
    double valueC       = 12. * M_PI / (25. * logScaleC) * correction;
    Lambda3Save = Lambda4Save;
    for (int iter = 0; iter < NITER; ++iter) {
      logScale    = 2. * log(mc/Lambda3Save);
      loglogScale = log(logScale);
      correction  = 1. - b13 * loglogScale / logScale;
      if (order == 3) correction
        += pow2(b13 / logScale) * (pow2(loglogScale - 0.5) + b23 - 1.25);
      valueIter   = valueC / correction;
      Lambda3Save = mc * exp( -6. * M_PI / (27. * valueIter) );
    }
  }

  // Optionally rescale Lambda values by CMW factor.
  if (useCMW) {
    Lambda3Save *= FACCMW3;
    Lambda4Save *= FACCMW4;
    Lambda5Save *= FACCMW5;
    Lambda6Save *= FACCMW6;
  }

  // Maximum return value (to freeze effective coupling at max value).
  // Negative values => do not impose any specific uppper bound.
  valueMax = valueMaxIn;

  // Optionally shift renormalisation scale2 -> scale2 + x * Lambda3^2.
  // A value of x = 1 shifts the pole to input scale 0.
  // Values greater than 1 produce finite alphaS values at zero input scale.
  // Changes for perturbative input scales (>> Lambda3) are small since the
  // input scale is only shifted by O(Lambda3).
  renormShiftSave = 0.;
  if (renormShiftIn > 0.) renormShiftSave = renormShiftIn * pow2(Lambda3Save);

  // Impose SAFETYMARGINs to prevent getting too close to LambdaQCD.
  if (order == 1) scale2Min = pow2(SAFETYMARGIN1 * Lambda3Save);
  else if (order > 1) scale2Min = pow2(SAFETYMARGIN2 * Lambda3Save);

  // Save squares of mass and Lambda values as well.
  Lambda3Save2 = pow2(Lambda3Save);
  Lambda4Save2 = pow2(Lambda4Save);
  Lambda5Save2 = pow2(Lambda5Save);
  Lambda6Save2 = pow2(Lambda6Save);
  mc2          = pow2(mc);
  mb2          = pow2(mb);
  mt2          = pow2(mt);
  valueNow     = valueIn;
  scale2Now    = MZ * MZ;
  isInit       = true;

}

//--------------------------------------------------------------------------

// Calculate alpha_s value.

double AlphaStrong::alphaS( double scale2) {

  // Check for initialization and ensure minimal scale2 value.
  if (!isInit) return 0.;
  // Optionally shift argument to avoid pole.
  if (renormShiftSave > 0.) scale2 += renormShiftSave;
  // Freeze below minimum scale.
  if (scale2 < scale2Min) scale2 = scale2Min;

  // If equal to old scale then same answer.
  if (scale2 == scale2Now && (order < 2 || lastCallToFull)) return valueNow;
  scale2Now      = scale2;
  lastCallToFull = true;

  // Fix alpha_s.
  if (order == 0) {
    valueNow = valueRef;

  // First order alpha_s: differs by mass region.
  } else if (order == 1) {
    if (scale2 > mt2 && nfmax >= 6)
         valueNow = 12. * M_PI / (21. * log(scale2/Lambda6Save2));
    else if (scale2 > mb2)
         valueNow = 12. * M_PI / (23. * log(scale2/Lambda5Save2));
    else if (scale2 > mc2)
         valueNow = 12. * M_PI / (25. * log(scale2/Lambda4Save2));
    else valueNow = 12. * M_PI / (27. * log(scale2/Lambda3Save2));

  // Second order alpha_s: differs by mass region.
  } else {
    double Lambda2, b0, b1, b2;
    if (scale2 > mt2 && nfmax >= 6) {
      Lambda2 = Lambda6Save2;
      b0      = 21.;
      b1      = 234. / 441.;
      b2      = -36855. / 109512.;
    } else if (scale2 > mb2) {
      Lambda2 = Lambda5Save2;
      b0      = 23.;
      b1      = 348. / 529.;
      b2      = 224687. / 242208.;
    } else if (scale2 > mc2) {
      Lambda2 = Lambda4Save2;
      b0      = 25.;
      b1      = 462. / 625.;
      b2      = 548575. / 426888.;
    } else {
      Lambda2 = Lambda3Save2;
      b0      = 27.;
      b1      = 64. / 81.;
      b2      = 938709. / 663552.;
    }
    double logScale    = log(scale2/Lambda2);
    double loglogScale = log(logScale);
    double correction  = 1. - b1 * loglogScale / logScale;
    if (order == 3) correction
      += pow2(b1 / logScale) * (pow2(loglogScale - 0.5) + b2 - 1.25);
    valueNow = 12. * M_PI / (b0 * logScale) * correction;
  }

  // Done.
  return (valueMax <= 0. || valueNow < valueMax) ? valueNow : valueMax;

}

//--------------------------------------------------------------------------

// Calculate alpha_s value, but only use up to first-order piece.
// (To be combined with alphaS2OrdCorr.)

double  AlphaStrong::alphaS1Ord( double scale2) {

  // Check for initialization and ensure minimal scale2 value.
  if (!isInit) return 0.;
  if (scale2 < scale2Min) scale2 = scale2Min;

  // If equal to old scale then same answer.
  if (scale2 == scale2Now && (order < 2 || !lastCallToFull)) return valueNow;
  scale2Now      = scale2;
  lastCallToFull = false;

  // Fix alpha_S.
  if (order == 0) {
    valueNow = valueRef;

  // First/second/third order alpha_s: differs by mass region.
  } else {
    if (scale2 > mt2 && nfmax >= 6)
         valueNow = 12. * M_PI / (21. * log(scale2/Lambda6Save2));
    else if (scale2 > mb2)
         valueNow = 12. * M_PI / (23. * log(scale2/Lambda5Save2));
    else if (scale2 > mc2)
         valueNow = 12. * M_PI / (25. * log(scale2/Lambda4Save2));
    else valueNow = 12. * M_PI / (27. * log(scale2/Lambda3Save2));
  }

  // Done.
  return valueNow;
}

//--------------------------------------------------------------------------

// Calculates the second- or third-order extra factor in alpha_s.
// (To be combined with alphaS1Ord.)

double AlphaStrong::alphaS2OrdCorr( double scale2) {

  // Check for initialization and ensure minimal scale2 value.
  if (!isInit) return 1.;
  if (scale2 < scale2Min) scale2 = scale2Min;

  // Only meaningful for second-order calculations.
  if (order < 2) return 1.;

  // Second order correction term: differs by mass region.
  double Lambda2, b1, b2;
  if (scale2 > mt2 && nfmax >= 6) {
    Lambda2 = Lambda6Save2;
    b1      = 234. / 441.;
    b2      = -36855. / 109512.;
  } else if (scale2 > mb2) {
    Lambda2 = Lambda5Save2;
    b1      = 348. / 529.;
    b2      = 224687. / 242208.;
  } else if (scale2 > mc2) {
    Lambda2 = Lambda4Save2;
    b1      = 462. / 625.;
    b2      = 548575. / 426888.;
  } else {
    Lambda2 = Lambda3Save2;
    b1      = 64. / 81.;
    b2      = 938709. / 663552.;
  }
  double logScale    = log(scale2/Lambda2);
  double loglogScale = log(logScale);
  double correction  = 1. - b1 * loglogScale / logScale;
  if (order == 3) correction
    += pow2(b1 / logScale) * (pow2(loglogScale - 0.5) + b2 - 1.25);
  return correction;

}

//--------------------------------------------------------------------------

// muThres(2): tell what values of flavour thresholds are being used.

double AlphaStrong::muThres( int idQ) {
  int idAbs = abs(idQ);
  // Return the scale of each flavour threshold included in running.
  if (idAbs == 4) return mc;
  else if (idAbs == 5) return mb;
  else if (idAbs == 6 && nfmax >= 6) return mt;
  // Else return -1 (indicates no such threshold is included in running).
  return -1.;
}

double AlphaStrong::muThres2( int idQ) {
  int idAbs = abs(idQ);
  // Return the scale of each flavour threshold included in running.
  if (idAbs == 4) return mc2;
  else if (idAbs == 5) return mb2;
  else if (idAbs == 6 && nfmax >=6) return mt2;
  // Else return -1 (indicates no such threshold is included in running).
  return -1.;
}

//--------------------------------------------------------------------------

// facCMW: tells what values of the CMW factors are being used (if any).

double AlphaStrong::facCMW( int NFIn) {
  // Return unity if we are not doing CMW rescaling..
  if (!isInit || !useCMW) return 1.0;
  // Else return the NF-dependent value of the CMW rescaling factor.
  else if (NFIn <= 3) return FACCMW3;
  else if (NFIn == 4) return FACCMW4;
  else if (NFIn == 5) return FACCMW5;
  else return FACCMW6;
}

//==========================================================================

// The AlphaEM class.

//--------------------------------------------------------------------------

// Definitions of static variables.

// Z0 mass. Used for normalization scale.
const double AlphaEM::MZ         = 91.188;

// Effective thresholds for electron, muon, light quarks, tau+c, b.
const double AlphaEM::Q2STEP[5]  = {0.26e-6, 0.011, 0.25, 3.5, 90.};

// Running coefficients are sum charge2 / 3 pi in pure QED, here slightly
// enhanced for quarks to approximately account for QCD corrections.
const double AlphaEM::BRUNDEF[5] = {0.1061, 0.2122, 0.460, 0.700, 0.725};

//--------------------------------------------------------------------------

// Initialize alpha_EM calculation.

void AlphaEM::init(int orderIn, Settings* settingsPtr) {

  // Order. Read in alpha_EM value at 0 and m_Z, and mass of Z.
  order     = orderIn;
  alpEM0    = settingsPtr->parm("StandardModel:alphaEM0");
  alpEMmZ   = settingsPtr->parm("StandardModel:alphaEMmZ");
  mZ2       = MZ * MZ;

  // AlphaEM values at matching scales and matching b value.
  if (order <= 0) return;
  for (int i = 0; i < 5; ++i) bRun[i] = BRUNDEF[i];

  // Step down from mZ to tau/charm threshold.
  alpEMstep[4] = alpEMmZ / ( 1. + alpEMmZ * bRun[4]
    * log(mZ2 / Q2STEP[4]) );
  alpEMstep[3] = alpEMstep[4] / ( 1. - alpEMstep[4] * bRun[3]
    * log(Q2STEP[3] / Q2STEP[4]) );

  // Step up from me to light-quark threshold.
  alpEMstep[0] = alpEM0;
  alpEMstep[1] = alpEMstep[0] / ( 1. - alpEMstep[0] * bRun[0]
    * log(Q2STEP[1] / Q2STEP[0]) );
  alpEMstep[2] = alpEMstep[1] / ( 1. - alpEMstep[1] * bRun[1]
    * log(Q2STEP[2] / Q2STEP[1]) );

  // Fit b in range between light-quark and tau/charm to join smoothly.
  bRun[2] = (1./alpEMstep[3] - 1./alpEMstep[2])
    / log(Q2STEP[2] / Q2STEP[3]);

}

//--------------------------------------------------------------------------

// Calculate alpha_EM value

double AlphaEM::alphaEM( double scale2) {

  // Fix alphaEM; for order = -1 fixed at m_Z.
  if (order == 0)  return alpEM0;
  if (order <  0)  return alpEMmZ;

  // Running alphaEM.
  for (int i = 4; i >= 0; --i) if (scale2 > Q2STEP[i])
    return alpEMstep[i] / (1. - bRun[i] * alpEMstep[i]
      * log(scale2 / Q2STEP[i]) );
  return alpEM0;

}

//==========================================================================

// The CoupSM class.

//--------------------------------------------------------------------------

// Definitions of static variables: charges and axial couplings.
const double CoupSM::efSave[20] = { 0., -1./3., 2./3., -1./3., 2./3., -1./3.,
  2./3., -1./3., 2./3., 0., 0., -1., 0., -1., 0., -1., 0., -1., 0., 0.};
const double CoupSM::afSave[20] = { 0., -1., 1., -1., 1., -1., 1., -1., 1.,
  0., 0., -1., 1., -1., 1., -1., 1., -1., 1., 0.};

//--------------------------------------------------------------------------

// Initialize electroweak mixing angle and couplings, and CKM matrix elements.

void CoupSM::init(Settings& settings, Rndm* rndmPtrIn) {

  // Store input pointer;
  rndmPtr = rndmPtrIn;

  // Initialize the local AlphaStrong instance.
  double alphaSvalue  = settings.parm("SigmaProcess:alphaSvalue");
  int    alphaSorder  = settings.mode("SigmaProcess:alphaSorder");
  int    alphaSnfmax  = settings.mode("StandardModel:alphaSnfmax");
  alphaSlocal.init( alphaSvalue, alphaSorder, alphaSnfmax, false);

  // Initialize the local AlphaEM instance.
  int order = settings.mode("SigmaProcess:alphaEMorder");
  alphaEMlocal.init( order, &settings);

  // Read in electroweak mixing angle and the Fermi constant.
  s2tW    = settings.parm("StandardModel:sin2thetaW");
  c2tW    = 1. - s2tW;
  s2tWbar = settings.parm("StandardModel:sin2thetaWbar");
  GFermi  = settings.parm("StandardModel:GF");

  // Initialize electroweak couplings.
  for (int i = 0; i < 20; ++i) {
    vfSave[i]  = afSave[i] - 4. * s2tWbar * efSave[i];
    lfSave[i]  = afSave[i] - 2. * s2tWbar * efSave[i];
    rfSave[i]  =           - 2. * s2tWbar * efSave[i];
    ef2Save[i] = pow2(efSave[i]);
    vf2Save[i] = pow2(vfSave[i]);
    af2Save[i] = pow2(afSave[i]);
    efvfSave[i] = efSave[i] * vfSave[i];
    vf2af2Save[i] = vf2Save[i] + af2Save[i];
  }

  // Read in CKM matrix element values and store them.
  VCKMsave[1][1] = settings.parm("StandardModel:Vud");
  VCKMsave[1][2] = settings.parm("StandardModel:Vus");
  VCKMsave[1][3] = settings.parm("StandardModel:Vub");
  VCKMsave[2][1] = settings.parm("StandardModel:Vcd");
  VCKMsave[2][2] = settings.parm("StandardModel:Vcs");
  VCKMsave[2][3] = settings.parm("StandardModel:Vcb");
  VCKMsave[3][1] = settings.parm("StandardModel:Vtd");
  VCKMsave[3][2] = settings.parm("StandardModel:Vts");
  VCKMsave[3][3] = settings.parm("StandardModel:Vtb");

  // Also allow for the potential existence of a fourth generation.
  VCKMsave[1][4] = settings.parm("FourthGeneration:VubPrime");
  VCKMsave[2][4] = settings.parm("FourthGeneration:VcbPrime");
  VCKMsave[3][4] = settings.parm("FourthGeneration:VtbPrime");
  VCKMsave[4][1] = settings.parm("FourthGeneration:VtPrimed");
  VCKMsave[4][2] = settings.parm("FourthGeneration:VtPrimes");
  VCKMsave[4][3] = settings.parm("FourthGeneration:VtPrimeb");
  VCKMsave[4][4] = settings.parm("FourthGeneration:VtPrimebPrime");

  // Calculate squares of matrix elements.
  for(int i = 1; i < 5; ++i) for(int j = 1; j < 5; ++j)
    V2CKMsave[i][j] = pow2(VCKMsave[i][j]);

  // Sum VCKM^2_out sum for given incoming flavour, excluding top as partner.
  V2CKMout[1] = V2CKMsave[1][1] + V2CKMsave[2][1];
  V2CKMout[2] = V2CKMsave[1][1] + V2CKMsave[1][2] + V2CKMsave[1][3];
  V2CKMout[3] = V2CKMsave[1][2] + V2CKMsave[2][2];
  V2CKMout[4] = V2CKMsave[2][1] + V2CKMsave[2][2] + V2CKMsave[2][3];
  V2CKMout[5] = V2CKMsave[1][3] + V2CKMsave[2][3];
  V2CKMout[6] = V2CKMsave[3][1] + V2CKMsave[3][2] + V2CKMsave[3][3];
  V2CKMout[7] = V2CKMsave[1][4] + V2CKMsave[2][4];
  V2CKMout[8] = V2CKMsave[4][1] + V2CKMsave[4][2] + V2CKMsave[4][3];
  for (int i = 11; i <= 18; ++i) V2CKMout[i] = 1.;

}

//--------------------------------------------------------------------------

// Return CKM value for incoming flavours (sign irrelevant).

double CoupSM::VCKMid(int id1, int id2) {

  // Use absolute sign (want to cover both f -> f' W and f fbar' -> W).
  int id1Abs = abs(id1);
  int id2Abs = abs(id2);
  if (id1Abs == 0 || id2Abs == 0 || (id1Abs + id2Abs)%2 != 1) return 0.;

  // Ensure proper order before reading out from VCKMsave or lepton match.
  if (id1Abs%2 == 1) swap(id1Abs, id2Abs);
  if (id1Abs <= 8 && id2Abs <= 8) return VCKMsave[id1Abs/2][(id2Abs + 1)/2];
  if ( (id1Abs == 12 || id1Abs == 14 || id1Abs == 16 || id1Abs == 18)
    && id2Abs == id1Abs - 1 ) return 1.;

  // No more valid cases.
  return 0.;

}

//--------------------------------------------------------------------------

// Return squared CKM value for incoming flavours (sign irrelevant).

double CoupSM::V2CKMid(int id1, int id2) {

  // Use absolute sign (want to cover both f -> f' W and f fbar' -> W).
  int id1Abs = abs(id1);
  int id2Abs = abs(id2);
  if (id1Abs == 0 || id2Abs == 0 || (id1Abs + id2Abs)%2 != 1) return 0.;

  // Ensure proper order before reading out from V2CKMsave or lepton match.
  if (id1Abs%2 == 1) swap(id1Abs, id2Abs);
  if (id1Abs <= 8 && id2Abs <= 8) return V2CKMsave[id1Abs/2][(id2Abs + 1)/2];
  if ( (id1Abs == 12 || id1Abs == 14 || id1Abs == 16 || id1Abs == 18)
    && id2Abs == id1Abs - 1 ) return 1.;

  // No more valid cases.
  return 0.;

}

//--------------------------------------------------------------------------

// Pick an outgoing flavour for given incoming one, given CKM mixing.

int CoupSM::V2CKMpick(int id) {

  // Initial values.
  int idIn = abs(id);
  int idOut = 0;

  // Quarks: need to make random choice.
  if (idIn >= 1 && idIn <= 8) {
    double V2CKMrndm = rndmPtr->flat() * V2CKMout[idIn];
    if (idIn == 1) idOut = (V2CKMrndm < V2CKMsave[1][1]) ? 2 : 4;
    else if (idIn == 2) idOut = (V2CKMrndm < V2CKMsave[1][1]) ? 1
      : ( (V2CKMrndm < V2CKMsave[1][1] + V2CKMsave[1][2]) ? 3 : 5 );
    else if (idIn == 3) idOut = (V2CKMrndm < V2CKMsave[1][2]) ? 2 : 4;
    else if (idIn == 4) idOut = (V2CKMrndm < V2CKMsave[2][1]) ? 1
      : ( (V2CKMrndm < V2CKMsave[2][1] + V2CKMsave[2][2]) ? 3 : 5 );
    else if (idIn == 5) idOut = (V2CKMrndm < V2CKMsave[1][3]) ? 2 : 4;
    else if (idIn == 6) idOut = (V2CKMrndm < V2CKMsave[3][1]) ? 1
      : ( (V2CKMrndm < V2CKMsave[3][1] + V2CKMsave[3][2]) ? 3 : 5 );
    else if (idIn == 7) idOut = (V2CKMrndm < V2CKMsave[1][4]) ? 2 : 4;
    else if (idIn == 8) idOut = (V2CKMrndm < V2CKMsave[4][1]) ? 1
      : ( (V2CKMrndm < V2CKMsave[4][1] + V2CKMsave[4][2]) ? 3 : 5 );

  // Leptons: unambiguous.
  } else if (idIn >= 11 && idIn <= 18) {
    if (idIn%2 == 1) idOut = idIn + 1;
    else idOut             = idIn - 1;
  }

  // Done. Return with sign.
  return ( (id > 0) ? idOut : -idOut );

}

//==========================================================================

// The AlphaSUN class.

//--------------------------------------------------------------------------

// Constants: could be changed here if desired, but normally should not.
// These are of technical nature, as described for each.

// Number of iterations to determine Lambda from given alpha.
const int AlphaSUN::NITER           = 10;

// Always evaluate running alpha_s above Lambda to avoid disaster.
// Safety margin picked to freeze roughly for alpha = 10.
const double AlphaSUN::SAFETYMARGIN1 = 1.07;
const double AlphaSUN::SAFETYMARGIN2 = 1.33;

//--------------------------------------------------------------------------

void AlphaSUN::initColFac(int nCin, int nFin, int orderIn) {

  // Save input values. Calculate C_F.
  nC        = max( 2, nCin);
  nF        = max( 0, nFin);
  order     = max( 1, min( 3, orderIn));
  double CF = (nC * nC - 1.) / (2. * nC);

  // Beta coefficients from van Ritbergen et al. (hep-ph/9701390).
  double beta0 = (11./3.) * nC - (2./3.) * nF;
  double beta1 = (34./3.) * pow2(nC) - 2. * CF * nF - (10./3.) * nC * nF;
  double beta2 = (2857./54.) * pow3(nC) + pow2(CF) * nF
    - (205. / 18.) * CF * nC * nF - (1415. / 54.) * pow2(nC) * nF
    + (11. / 9.) * CF * pow2(nF) + (79. / 54.) * nC * pow2(nF);

  // Conversion from van Ritbergen to PDG 2006 eq. (9.5) conventions.
  beta1       *= 0.5;
  beta2       *= 2.;

  // Combinations of PDG beta used inside Pythia as shorthand.
  b0           = 3. * beta0;
  b1           = 2. * beta1 / pow2(beta0);
  b2           = beta2 * beta0 / (8. * pow2(beta1));

  // Done.
}

//--------------------------------------------------------------------------

// Translate an alpha value at a reference scale to equivalent Lambda value.

void AlphaSUN::findLambda(double alphaRef, double scaleRef) {

  // First order translation is straightforward.
  LambdaSave    = scaleRef * exp( -6. * M_PI / (b0 * alphaRef) );
  Lambda2Save   = pow2(LambdaSave);
  scale2Min     = pow2(SAFETYMARGIN1) * Lambda2Save;
  if (order == 1) return;

  // Second and third order obtained iteratively.
  double logScale, loglogScale, correction, alphaIter;
  for (int iter = 0; iter < NITER; ++iter) {
    logScale    = 2. * log(scaleRef / LambdaSave);
    loglogScale = log(logScale);
    correction  = 1. - b1 * loglogScale / logScale;
    if (order == 3) correction
      += pow2(b1 / logScale) * (pow2(loglogScale - 0.5) + b2 - 1.25);
    alphaIter   = alphaRef / correction;
    LambdaSave  = scaleRef * exp( -6. * M_PI / (b0 * alphaIter) );
  }
  Lambda2Save   = pow2(LambdaSave);
  scale2Min     = pow2(SAFETYMARGIN2) * Lambda2Save;

}

//--------------------------------------------------------------------------

// Return the alpha value at a squared scale.

double AlphaSUN::alpha( double scale2in) {

  double scale2 = max( scale2Min,scale2in);
  double logScale = log( scale2 / Lambda2Save);
  if (order == 1) return 12. * M_PI / (b0 * logScale);
  double loglogScale = log(logScale);
  if (order == 2) return  12. * M_PI / (b0 * logScale)
    * ( 1. - b1 * loglogScale / logScale );
  return 12. * M_PI / (b0 * logScale) * ( 1. - b1 * loglogScale / logScale
    + pow2(b1 / logScale) * (pow2(loglogScale - 0.5) + b2 - 1.25) );

}

//--------------------------------------------------------------------------

// Return the first-order alpha value at a squared scale for given Lambda.

double AlphaSUN::alpha1Ord( double scale2in) {

  double scale2 = max( scale2Min,scale2in);
  double logScale = log( scale2 / Lambda2Save);
  return 12. * M_PI / (b0 * logScale);

}

//--------------------------------------------------------------------------

// Return the correction factor from first to desired order.

double AlphaSUN::alpha2OrdCorr( double scale2in) {

  if (order == 1) return 1.;
  double scale2 = max( scale2Min,scale2in);
  double logScale = log( scale2 / Lambda2Save);
  double loglogScale = log(logScale);
  if (order == 2) return 1. - b1 * loglogScale / logScale;
  return 1. - b1 * loglogScale / logScale
    + pow2(b1 / logScale) * (pow2(loglogScale - 0.5) + b2 - 1.25);

}

//==========================================================================

} // end namespace Pythia8
