// Nsubjettiness Package // Questions/Comments? jthaler@jthaler.net // // Copyright (c) 2011-14 // Jesse Thaler, Ken Van Tilburg, Christopher K. Vermilion, and TJ Wilkason // //---------------------------------------------------------------------- // This file is part of FastJet contrib. // // It is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at // your option) any later version. // // It is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public // License for more details. // // You should have received a copy of the GNU General Public License // along with this code. If not, see . //---------------------------------------------------------------------- #include "Njettiness.hh" FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh namespace contrib { /////// // // Main Njettiness Class // /////// // Helper function to correlate one pass minimization with appropriate measure void Njettiness::setOnePassAxesFinder(MeasureMode measure_mode, AxesFinder* startingFinder, double beta, double Rcutoff) { if (measure_mode == normalized_measure || measure_mode == unnormalized_measure || measure_mode == normalized_cutoff_measure || measure_mode == unnormalized_cutoff_measure) { _axesFinder = new AxesFinderFromOnePassMinimization(startingFinder, beta, Rcutoff); } else if (measure_mode == geometric_measure || measure_mode == geometric_cutoff_measure) { _axesFinder = new AxesFinderFromGeometricMinimization(startingFinder, beta, Rcutoff); } else { std::cerr << "Minimization only set up for normalized_measure, unnormalized_measure, normalized_cutoff_measure, unnormalized_cutoff_measure, geometric_measure, geometric_cutoff_measure" << std::endl; exit(1); } } // Parsing needed for constructor to set AxesFinder and MeasureFunction // All of the parameter handling is here, and checking that number of parameters is correct. void Njettiness::setMeasureFunctionandAxesFinder(AxesMode axes_mode, MeasureMode measure_mode, double para1, double para2, double para3, double para4) { // definition of maximum Rcutoff for non-cutoff measures, changed later by other measures double Rcutoff = std::numeric_limits::max(); //large number // Most (but all measures have some kind of beta value) double beta = NAN; // The normalized measures have an R0 value. double R0 = NAN; // Find the MeasureFunction and set the parameters. switch (measure_mode) { case normalized_measure: beta = para1; R0 = para2; if(correctParameterCount(2, para1, para2, para3, para4)) _measureFunction = new DefaultNormalizedMeasure(beta, R0, Rcutoff); //normalized_measure requires 2 parameters, beta and R0 else { std::cerr << "normalized_measure needs 2 parameters (beta and R0)" << std::endl; exit(1); } break; case unnormalized_measure: beta = para1; if(correctParameterCount(1, para1, para2, para3, para4)) _measureFunction = new DefaultUnnormalizedMeasure(beta, Rcutoff); //unnormalized_measure requires 1 parameter, beta else { std::cerr << "unnormalized_measure needs 1 parameter (beta)" << std::endl; exit(1); } break; case geometric_measure: beta = para1; if(correctParameterCount(1, para1, para2, para3, para4)) _measureFunction = new GeometricMeasure(beta,Rcutoff); //geometric_measure requires 1 parameter, beta else { std::cerr << "geometric_measure needs 1 parameter (beta)" << std::endl; exit(1); } break; case normalized_cutoff_measure: beta = para1; R0 = para2; Rcutoff = para3; //Rcutoff parameter is 3rd parameter in normalized_cutoff_measure if(correctParameterCount(3, para1, para2, para3, para4)) _measureFunction = new DefaultNormalizedMeasure(beta, R0, Rcutoff); //normalized_cutoff_measure requires 3 parameters, beta, R0, and Rcutoff else { std::cerr << "normalized_cutoff_measure has 3 parameters (beta, R0, Rcutoff)" << std::endl; exit(1); } break; case unnormalized_cutoff_measure: beta = para1; Rcutoff = para2; //Rcutoff parameter is 2nd parameter in normalized_cutoff_measure if (correctParameterCount(2, para1, para2, para3, para4)) _measureFunction = new DefaultUnnormalizedMeasure(beta, Rcutoff); //unnormalized_cutoff_measure requires 2 parameters, beta and Rcutoff else { std::cerr << "unnormalized_cutoff_measure has 2 parameters (beta, Rcutoff)" << std::endl; exit(1); } break; case geometric_cutoff_measure: beta = para1; Rcutoff = para2; //Rcutoff parameter is 2nd parameter in geometric_cutoff_measure if(correctParameterCount(2, para1, para2, para3, para4)) _measureFunction = new GeometricMeasure(beta,Rcutoff); //geometric_cutoff_measure requires 2 parameters, beta and Rcutoff else { std::cerr << "geometric_cutoff_measure has 2 parameters (beta,Rcutoff)" << std::endl; exit(1); } break; default: assert(false); break; } // Choose which AxesFinder from user input. // Uses setOnePassAxesFinder helpful function to use beta and Rcutoff values about (if needed) switch (axes_mode) { case wta_kt_axes: _axesFinder = new AxesFinderFromWTA_KT(); break; case wta_ca_axes: _axesFinder = new AxesFinderFromWTA_CA(); break; case kt_axes: _axesFinder = new AxesFinderFromKT(); break; case ca_axes: _axesFinder = new AxesFinderFromCA(); break; case antikt_0p2_axes: _axesFinder = new AxesFinderFromAntiKT(0.2); break; case onepass_wta_kt_axes: setOnePassAxesFinder(measure_mode, new AxesFinderFromWTA_KT(), beta, Rcutoff); break; case onepass_wta_ca_axes: setOnePassAxesFinder(measure_mode, new AxesFinderFromWTA_CA(), beta, Rcutoff); break; case onepass_kt_axes: setOnePassAxesFinder(measure_mode, new AxesFinderFromKT(), beta, Rcutoff); break; case onepass_ca_axes: setOnePassAxesFinder(measure_mode, new AxesFinderFromCA(), beta, Rcutoff); break; case onepass_antikt_0p2_axes: setOnePassAxesFinder(measure_mode, new AxesFinderFromAntiKT(0.2), beta, Rcutoff); break; case onepass_manual_axes: setOnePassAxesFinder(measure_mode, new AxesFinderFromUserInput(), beta, Rcutoff); break; case min_axes: //full minimization is not defined for geometric_measure. if (measure_mode == normalized_measure || measure_mode == unnormalized_measure || measure_mode == normalized_cutoff_measure || measure_mode == unnormalized_cutoff_measure) //Defaults to 100 iteration to find minimum _axesFinder = new AxesFinderFromKmeansMinimization(new AxesFinderFromKT(), beta, Rcutoff, 100); else { std::cerr << "Multi-pass minimization only set up for normalized_measure, unnormalized_measure, normalized_cutoff_measure, unnormalized_cutoff_measure." << std::endl; exit(1); } break; case manual_axes: _axesFinder = new AxesFinderFromUserInput(); break; // These options have been commented out because they have not been fully tested // case wta2_kt_axes: // option for alpha = 2 added // _axesFinder = new AxesFinderFromWTA2_KT(); // break; // case wta2_ca_axes: // option for alpha = 2 added // _axesFinder = new AxesFinderFromWTA2_CA(); // break; // case onepass_wta2_kt_axes: // option for alpha = 2 added // setOnePassAxesFinder(measure_mode, new AxesFinderFromWTA2_KT(), beta, Rcutoff); // break; // case onepass_wta2_ca_axes: // option for alpha = 2 added // setOnePassAxesFinder(measure_mode, new AxesFinderFromWTA2_CA(), beta, Rcutoff); // break; default: assert(false); break; } } // setAxes for Manual mode void Njettiness::setAxes(std::vector myAxes) { if (_current_axes_mode == manual_axes || _current_axes_mode == onepass_manual_axes) { _currentAxes = myAxes; } else { std::cerr << "You can only use setAxes if using manual_axes or onepass_manual_axes measure mode" << std::endl; exit(1); } } // Calculates and returns all TauComponents that user would want. // This information is stored in _current_tau_components for later access as well. TauComponents Njettiness::getTauComponents(unsigned n_jets, const std::vector & inputJets) { if (inputJets.size() <= n_jets) { //if not enough particles, return zero _currentAxes = inputJets; _currentAxes.resize(n_jets,fastjet::PseudoJet(0.0,0.0,0.0,0.0)); _current_tau_components = TauComponents(); _seedAxes = _currentAxes; } else { _currentAxes = _axesFinder->getAxes(n_jets,inputJets,_currentAxes); // sets current Axes _seedAxes = _axesFinder->seedAxes(); // sets seed Axes (if one pass minimization was used) _current_tau_components = _measureFunction->result(inputJets, _currentAxes); // sets current Tau Values } return _current_tau_components; } // Partition a list of particles according to which N-jettiness axis they are closest to. // Return a vector of length _currentAxes.size() (which should be N). // Each vector element is a list of ints corresponding to the indices in // particles of the particles belonging to that jet. // TODO: Consider moving to MeasureFunction std::vector > Njettiness::getPartition(const std::vector & particles) { std::vector > partitions(_currentAxes.size()); for (unsigned i = 0; i < particles.size(); i++) { int j_min = -1; // find minimum distance double minR = std::numeric_limits::max(); //large number for (unsigned j = 0; j < _currentAxes.size(); j++) { double tempR = _measureFunction->jet_distance_squared(particles[i],_currentAxes[j]); // delta R distance if (tempR < minR) { minR = tempR; j_min = j; } } if (_measureFunction->do_cluster(particles[i],_currentAxes[j_min])) partitions[j_min].push_back(i); } return partitions; } // Having found axes, assign each particle in particles to an axis, and return a set of jets. // Each jet is the sum of particles closest to an axis (Njet = Naxes). // TODO: Consider moving to MeasureFunction std::vector Njettiness::getJets(const std::vector & particles) { std::vector jets(_currentAxes.size()); std::vector > partition = getPartition(particles); for (unsigned j = 0; j < partition.size(); ++j) { std::list::const_iterator it, itE; for (it = partition[j].begin(), itE = partition[j].end(); it != itE; ++it) { jets[j] += particles[*it]; } } return jets; } } // namespace contrib FASTJET_END_NAMESPACE