Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooLagrangianMorphFunc.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooLagrangianMorphing *
4 * @(#)root/roofit:$Id$
5 * Authors: *
6 * Lydia Brenner (lbrenner@cern.ch), Carsten Burgard (cburgard@cern.ch) *
7 * Katharina Ecker (kecker@cern.ch), Adam Kaluza (akaluza@cern.ch) *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/** \class RooLagrangianMorphFunc
18 \ingroup Roofit
19Class RooLagrangianMorphing is a implementation of the method of Effective
20Lagrangian Morphing, described in ATL-PHYS-PUB-2015-047.
21Effective Lagrangian Morphing is a method to construct a continuous signal
22model in the coupling parameter space. Basic assumption is that shape and
23cross section of a physical distribution is proportional to it's
24squared matrix element.
25The signal model is constructed by a weighted sum over N input distributions.
26The calculation of the weights is based on Matrix Elements evaluated for the
27different input scenarios.
28The number of input files depends on the number of couplings in production
29and decay vertices, and also whether the decay and production vertices
30describe the same process or not.
31**/
32
33// uncomment to force UBLAS multiprecision matrices
34// #define USE_UBLAS 1
35// #undef USE_UBLAS
36
37#include "RooAbsCollection.h"
38#include "RooArgList.h"
39#include "RooArgProxy.h"
40#include "RooArgSet.h"
41#include "RooBinning.h"
42#include "RooDataHist.h"
43#include "RooFormulaVar.h"
44#include "RooHistFunc.h"
47#include "RooParamHistFunc.h"
48#include "RooProduct.h"
49#include "RooRealVar.h"
50#include "RooWorkspace.h"
51#include "RooFactoryWSTool.h"
52
53#include "ROOT/StringUtils.hxx"
54#include "TFile.h"
55#include "TFolder.h"
56#include "TH1.h"
57#include "TMap.h"
58#include "TParameter.h"
59#include "TRandom3.h"
60
61#include <algorithm>
62#include <array>
63#include <cmath>
64#include <cstddef>
65#include <iostream>
66#include <limits>
67#include <map>
68#include <memory>
69#include <sstream>
70#include <stdexcept>
71#include <type_traits>
72
73using std::string, std::make_unique, std::vector;
74
75
76//#define _DEBUG_
77
78///////////////////////////////////////////////////////////////////////////////
79// PREPROCESSOR MAGIC /////////////////////////////////////////////////////////
80///////////////////////////////////////////////////////////////////////////////
81
82// various preprocessor helpers
83#define NaN std::numeric_limits<double>::quiet_NaN()
84
85constexpr static double morphLargestWeight = 10e7;
86constexpr static double morphUnityDeviation = 10e-6;
87
88///////////////////////////////////////////////////////////////////////////////
89// TEMPLATE MAGIC /////////////////////////////////////////////////////////////
90///////////////////////////////////////////////////////////////////////////////
91
92template <typename Test, template <typename...> class Ref>
93struct is_specialization : std::false_type {
94};
95
96template <template <typename...> class Ref, typename... Args>
97struct is_specialization<Ref<Args...>, Ref> : std::true_type {
98};
99
100///////////////////////////////////////////////////////////////////////////////
101// LINEAR ALGEBRA HELPERS /////////////////////////////////////////////////////
102///////////////////////////////////////////////////////////////////////////////
103
104////////////////////////////////////////////////////////////////////////////////
105/// retrieve the size of a square matrix
106
107template <class MatrixT>
108inline size_t size(const MatrixT &matrix);
109template <>
110inline size_t size<TMatrixD>(const TMatrixD &mat)
111{
112 return mat.GetNrows();
113}
114
115////////////////////////////////////////////////////////////////////////////////
116/// write a matrix to a stream
117
118template <class MatrixT>
119void writeMatrixToStreamT(const MatrixT &matrix, std::ostream &stream)
120{
121 if (!stream.good()) {
122 return;
123 }
124 for (size_t i = 0; i < size(matrix); ++i) {
125 for (size_t j = 0; j < size(matrix); ++j) {
126#ifdef USE_UBLAS
127 stream << std::setprecision(RooFit::SuperFloatPrecision::digits10) << matrix(i, j) << "\t";
128#else
129 stream << matrix(i, j) << "\t";
130#endif
131 }
132 stream << std::endl;
133 }
134}
135
136////////////////////////////////////////////////////////////////////////////////
137/// write a matrix to a text file
138
139template <class MatrixT>
140inline void writeMatrixToFileT(const MatrixT &matrix, const char *fname)
141{
142 std::ofstream of(fname);
143 if (!of.good()) {
144 std::cerr << "unable to read file '" << fname << "'!" << std::endl;
145 }
147 of.close();
148}
149
150#ifdef USE_UBLAS
151
152// boost includes
153#pragma GCC diagnostic push
154#pragma GCC diagnostic ignored "-Wshadow"
155#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
156#include <boost/numeric/ublas/io.hpp>
157#include <boost/numeric/ublas/lu.hpp>
158#include <boost/numeric/ublas/matrix.hpp>
159#include <boost/numeric/ublas/matrix_expression.hpp>
160#include <boost/numeric/ublas/symmetric.hpp> //inc diag
161#include <boost/numeric/ublas/triangular.hpp>
162#include <boost/operators.hpp>
163
164#pragma GCC diagnostic pop
165
166typedef boost::numeric::ublas::matrix<RooFit::SuperFloat> Matrix;
167
168////////////////////////////////////////////////////////////////////////////////
169/// write a matrix
170
171inline void printMatrix(const Matrix &mat)
172{
173 for (size_t i = 0; i < mat.size1(); ++i) {
174 for (size_t j = 0; j < mat.size2(); ++j) {
175 std::cout << std::setprecision(RooFit::SuperFloatPrecision::digits10) << mat(i, j) << " ,\t";
176 }
177 std::cout << std::endl;
178 }
179}
180
181////////////////////////////////////////////////////////////////////////////////
182/// retrieve the size of a square matrix
183
184template <>
185inline size_t size<Matrix>(const Matrix &matrix)
186{
187 return matrix.size1();
188}
189
190////////////////////////////////////////////////////////////////////////////////
191/// create a new diagonal matrix of size n
192
193inline Matrix diagMatrix(size_t n)
194{
195 return boost::numeric::ublas::identity_matrix<RooFit::SuperFloat>(n);
196}
197
198////////////////////////////////////////////////////////////////////////////////
199/// convert a matrix into a TMatrixD
200
201inline TMatrixD makeRootMatrix(const Matrix &in)
202{
203 size_t n = size(in);
204 TMatrixD mat(n, n);
205 for (size_t i = 0; i < n; ++i) {
206 for (size_t j = 0; j < n; ++j) {
207 mat(i, j) = double(in(i, j));
208 }
209 }
210 return mat;
211}
212
213////////////////////////////////////////////////////////////////////////////////
214/// convert a TMatrixD into a matrix
215
216inline Matrix makeSuperMatrix(const TMatrixD &in)
217{
218 size_t n = in.GetNrows();
219 Matrix mat(n, n);
220 for (size_t i = 0; i < n; ++i) {
221 for (size_t j = 0; j < n; ++j) {
222 mat(i, j) = double(in(i, j));
223 }
224 }
225 return mat;
226}
227
228inline Matrix operator+=(const Matrix &rhs)
229{
230 return add(rhs);
231}
232inline Matrix operator*(const Matrix &m, const Matrix &otherM)
233{
234 return prod(m, otherM);
235}
236
237////////////////////////////////////////////////////////////////////////////////
238/// calculate the inverse of a matrix, returning the condition
239
241{
242 boost::numeric::ublas::permutation_matrix<size_t> pm(size(matrix));
245 try {
246 int res = lu_factorize(lu, pm);
247 if (res != 0) {
248 std::stringstream ss;
250 cxcoutP(Eval) << ss.str << std::endl;
251 }
252 // back-substitute to get the inverse
254 } catch (boost::numeric::ublas::internal_logic &error) {
255 // coutE(Eval) << "boost::numeric::ublas error: matrix is not invertible!"
256 // << std::endl;
257 }
259 RooFit::SuperFloat condition = mnorm * inorm;
260 return condition;
261}
262
263#else
264
265#include "TDecompLU.h"
267
268////////////////////////////////////////////////////////////////////////////////
269/// convert a matrix into a TMatrixD
270
272{
273 return TMatrixD(in);
274}
275
276////////////////////////////////////////////////////////////////////////////////
277/// convert a TMatrixD into a Matrix
278
280{
281 return in;
282}
283
284////////////////////////////////////////////////////////////////////////////////
285/// create a new diagonal matrix of size n
286
287inline Matrix diagMatrix(size_t n)
288{
289 TMatrixD mat(n, n);
290 mat.UnitMatrix();
291 return mat;
292}
293
294////////////////////////////////////////////////////////////////////////////////
295/// write a matrix
296
297inline void printMatrix(const TMatrixD &mat)
298{
299 writeMatrixToStreamT(mat, std::cout);
300}
301
302////////////////////////////////////////////////////////////////////////////////
303// calculate the inverse of a matrix, returning the condition
304
305inline double invertMatrix(const Matrix &matrix, Matrix &inverse)
306{
308 bool status = lu.Invert(inverse);
309 // check if the matrix is invertible
310 if (!status) {
311 std::cerr << " matrix is not invertible!" << std::endl;
312 }
313 double condition = lu.GetCondition();
314 const size_t n = size(inverse);
315 // sanitize numeric problems
316 for (size_t i = 0; i < n; ++i) {
317 for (size_t j = 0; j < n; ++j) {
318 if (std::abs(inverse(i, j)) < 1e-9)
319 inverse(i, j) = 0;
320 }
321 }
322 return condition;
323}
324#endif
325
326/////////////////////////////////////////////////////////////////////////////////
327// LOCAL FUNCTIONS AND DEFINITIONS
328// //////////////////////////////////////////////
329/////////////////////////////////////////////////////////////////////////////////
330/// anonymous namespace to prohibit use of these functions outside the class
331/// itself
332namespace {
333///////////////////////////////////////////////////////////////////////////////
334// HELPERS ////////////////////////////////////////////////////////////////////
335///////////////////////////////////////////////////////////////////////////////
336
337typedef std::vector<std::vector<bool>> FeynmanDiagram;
338typedef std::vector<std::vector<int>> MorphFuncPattern;
339typedef std::map<int, std::unique_ptr<RooAbsReal>> FormulaList;
340
341///////////////////////////////////////////////////////////////////////////////
342/// (-?-)
343
344inline TString makeValidName(std::string const& input)
345{
346 TString retval(input.c_str());
347 retval.ReplaceAll("/", "_");
348 retval.ReplaceAll("^", "");
349 retval.ReplaceAll("*", "X");
350 retval.ReplaceAll("[", "");
351 retval.ReplaceAll("]", "");
352 return retval;
353}
354
355//////////////////////////////////////////////////////////////////////////////
356/// concatenate the names of objects in a collection to a single string
357
358template <class List>
359std::string concatNames(const List &c, const char *sep)
360{
361 std::stringstream ss;
362 bool first = true;
363 for (auto itr : c) {
364 if (!first)
365 ss << sep;
366 ss << itr->GetName();
367 first = false;
368 }
369 return ss.str();
370}
371
372///////////////////////////////////////////////////////////////////////////////
373/// this is a workaround for the missing implicit conversion from
374/// SuperFloat<>double
375
376template <class A, class B>
377inline void assignElement(A &a, const B &b)
378{
379 a = static_cast<A>(b);
380}
381///////////////////////////////////////////////////////////////////////////////
382// read a matrix from a stream
383
384template <class MatrixT>
385inline MatrixT readMatrixFromStreamT(std::istream &stream)
386{
387 std::vector<std::vector<RooFit::SuperFloat>> matrix;
388 std::vector<RooFit::SuperFloat> line;
389 while (!stream.eof()) {
390 if (stream.peek() == '\n') {
391 stream.get();
392 stream.peek();
393 continue;
394 }
396 stream >> val;
397 line.push_back(val);
398 while (stream.peek() == ' ' || stream.peek() == '\t') {
399 stream.get();
400 }
401 if (stream.peek() == '\n') {
402 matrix.push_back(line);
403 line.clear();
404 }
405 }
406 MatrixT retval(matrix.size(), matrix.size());
407 for (size_t i = 0; i < matrix.size(); ++i) {
408 if (matrix[i].size() != matrix.size()) {
409 std::cerr << "matrix read from stream doesn't seem to be square!" << std::endl;
410 }
411 for (size_t j = 0; j < matrix[i].size(); ++j) {
412 assignElement(retval(i, j), matrix[i][j]);
413 }
414 }
415 return retval;
416}
417
418///////////////////////////////////////////////////////////////////////////////
419/// read a matrix from a text file
420
421template <class MatrixT>
422inline MatrixT readMatrixFromFileT(const char *fname)
423{
424 std::ifstream in(fname);
425 if (!in.good()) {
426 std::cerr << "unable to read file '" << fname << "'!" << std::endl;
427 }
429 in.close();
430 return mat;
431}
432
433///////////////////////////////////////////////////////////////////////////////
434/// convert a TH1* param hist into the corresponding ParamSet object
435
436template <class T>
437void readValues(std::map<const std::string, T> &myMap, TH1 *h_pc)
438{
439 if (h_pc) {
440 // loop over all bins of the param_card histogram
441 for (int ibx = 1; ibx <= h_pc->GetNbinsX(); ++ibx) {
442 // read the value of one parameter
443 const std::string s_coup(h_pc->GetXaxis()->GetBinLabel(ibx));
444 double coup_val = h_pc->GetBinContent(ibx);
445 // add it to the map
446 if (!s_coup.empty()) {
447 myMap[s_coup] = T(coup_val);
448 }
449 }
450 }
451}
452
453///////////////////////////////////////////////////////////////////////////////
454/// Set up folder ownership over its children, and treat likewise any subfolders.
455/// @param theFolder: folder to update. Assumed to be a valid pointer
457{
458 theFolder->SetOwner();
459 // And also need to set up ownership for nested folders
460 auto subdirs = theFolder->GetListOfFolders();
461 for (auto *thisfolder : dynamic_range_cast<TFolder *>(*subdirs)) {
462 if (thisfolder) {
463 // no explicit deletion here, will be handled by parent
465 }
466 }
467}
468
469///////////////////////////////////////////////////////////////////////////////
470/// Load a TFolder from a file while ensuring it owns its content.
471/// This avoids memory leaks. Note that when fetching objects
472/// from this folder, you need to clone them to prevent deletion.
473/// Also recursively updates nested subfolders accordingly
474/// @param inFile: Input file to read - assumed to be a valid pointer
475/// @param folderName: Name of the folder to read from the file
476/// @return a unique_ptr to the folder. Nullptr if not found.
477std::unique_ptr<TFolder> readOwningFolderFromFile(TDirectory *inFile, const std::string &folderName)
478{
479 std::unique_ptr<TFolder> theFolder(inFile->Get<TFolder>(folderName.c_str()));
480 if (!theFolder) {
481 std::cerr << "Error: unable to access data from folder '" << folderName << "' from file '" << inFile->GetName()
482 << "'!" << std::endl;
483 return nullptr;
484 }
486 return theFolder;
487}
488
489///////////////////////////////////////////////////////////////////////////////
490/// Helper to load a single object from a file-resident TFolder, while
491/// avoiding memory leaks.
492/// @tparam AObjType Type of object to load.
493/// @param inFile input file to load from. Expected to be a valid pointer
494/// @param folderName Name of the TFolder to load from the file
495/// @param objName Name of the object to load
496/// @param notFoundError If set, print a detailed error if we didn't find something
497/// @return Returns a pointer to a clone of the loaded object. Ownership assigned to the caller.
498template <class AObjType>
499std::unique_ptr<AObjType> loadFromFileResidentFolder(TDirectory *inFile, const std::string &folderName,
500 const std::string &objName, bool notFoundError = true)
501{
503 if (!folder) {
504 return nullptr;
505 }
506 AObjType *loadedObject = dynamic_cast<AObjType *>(folder->FindObject(objName.c_str()));
507 if (!loadedObject) {
508 if (notFoundError) {
509 std::stringstream errstr;
510 errstr << "Error: unable to retrieve object '" << objName << "' from folder '" << folderName
511 << "'. contents are:";
512 TIter next(folder->GetListOfFolders()->begin());
513 TFolder *f;
514 while ((f = static_cast<TFolder *>(next()))) {
515 errstr << " " << f->GetName();
516 }
517 std::cerr << errstr.str() << std::endl;
518 }
519 return nullptr;
520 }
521 // replace the loaded object by a clone, as the loaded folder will delete the original
522 // can use a static_cast - confirmed validity by initial cast above.
523 return std::unique_ptr<AObjType>{static_cast<AObjType *>(loadedObject->Clone())};
524}
525
526///////////////////////////////////////////////////////////////////////////////
527/// retrieve a ParamSet from a certain subfolder 'name' of the file
528
529template <class T>
530void readValues(std::map<const std::string, T> &myMap, TDirectory *file, const std::string &name,
531 const std::string &key = "param_card", bool notFoundError = true)
532{
534 readValues(myMap, h_pc.get());
535}
536
537///////////////////////////////////////////////////////////////////////////////
538/// retrieve the param_hists file and return a map of the parameter values
539/// by providing a list of names, only the param_hists of those subfolders are
540/// read leaving the list empty is interpreted as meaning 'read everything'
541
542template <class T>
543void readValues(std::map<const std::string, std::map<const std::string, T>> &inputParameters, TDirectory *f,
544 const std::vector<std::string> &names, const std::string &key = "param_card", bool notFoundError = true)
545{
546 inputParameters.clear();
547 // if the list of names is empty, we assume that this means 'all'
548 // loop over all folders in the file
549 for (size_t i = 0; i < names.size(); i++) {
550 const std::string name(names[i]);
551 // actually read an individual param_hist
553 }
554
555 // now the map is filled with all parameter values found for all samples
556}
557
558///////////////////////////////////////////////////////////////////////////////
559/// open the file and return a file pointer
560
561inline TDirectory *openFile(const std::string &filename)
562{
563 if (filename.empty()) {
564 return gDirectory;
565 } else {
566 TFile *file = TFile::Open(filename.c_str(), "READ");
567 if (!file || !file->IsOpen()) {
568 if (file)
569 delete file;
570 std::cerr << "could not open file '" << filename << "'!" << std::endl;
571 }
572 return file;
573 }
574}
575
576///////////////////////////////////////////////////////////////////////////////
577/// open the file and return a file pointer
578
579inline void closeFile(TDirectory *d)
580{
581 TFile *f = dynamic_cast<TFile *>(d);
582 if (f) {
583 f->Close();
584 delete f;
585 d = nullptr;
586 }
587}
588
589///////////////////////////////////////////////////////////////////////////////
590/// extract the operators from a single coupling
591template <class T2>
592inline void extractServers(const RooAbsArg &coupling, T2 &operators)
593{
594 int nservers = 0;
595 for (const auto server : coupling.servers()) {
597 nservers++;
598 }
599 if (nservers == 0) {
600 operators.add(coupling);
601 }
602}
603
604///////////////////////////////////////////////////////////////////////////////
605/// extract the operators from a list of couplings
606
608inline void extractOperators(const T1 &couplings, T2 &operators)
609{
610 // std::coutD(InputArguments) << "extracting operators from
611 // "<<couplings.size()<<" couplings" << std::endl;
612 for (auto itr : couplings) {
614 }
615}
616
617///////////////////////////////////////////////////////////////////////////////
618/// extract the operators from a list of vertices
619
621inline void extractOperators(const T1 &vec, T2 &operators)
622{
623 for (const auto &v : vec) {
625 }
626}
627
628///////////////////////////////////////////////////////////////////////////////
629/// extract the couplings from a given set and copy them to a new one
630
631template <class T1, class T2>
632inline void extractCouplings(const T1 &inCouplings, T2 &outCouplings)
633{
634 for (auto itr : inCouplings) {
635 if (!outCouplings.find(itr->GetName())) {
636 // std::coutD(InputArguments) << "adding parameter "<< obj->GetName() <<
637 // std::endl;
638 outCouplings.add(*itr);
639 }
640 }
641}
642
643////////////////////////////////////////////////////////////////////////////////
644/// set parameter values first set all values to defaultVal (if value not
645/// present in param_card then it should be 0)
646
647inline bool setParam(RooRealVar *p, double val, bool force)
648{
649 bool ok = true;
650 if (val > p->getMax()) {
651 if (force) {
652 p->setMax(val);
653 } else {
654 std::cerr << ": parameter " << p->GetName() << " out of bounds: " << val << " > " << p->getMax() << std::endl;
655 ok = false;
656 }
657 } else if (val < p->getMin()) {
658 if (force) {
659 p->setMin(val);
660 } else {
661 std::cerr << ": parameter " << p->GetName() << " out of bounds: " << val << " < " << p->getMin() << std::endl;
662 ok = false;
663 }
664 }
665 if (ok)
666 p->setVal(val);
667 return ok;
668}
669
670////////////////////////////////////////////////////////////////////////////////
671/// set parameter values first set all values to defaultVal (if value not
672/// present in param_card then it should be 0)
673
674template <class T1, class T2>
675inline bool setParams(const T2 &args, T1 val)
676{
677 for (auto *param : dynamic_range_cast<RooRealVar *>(args)) {
678 if (!param)
679 continue;
680 setParam(param, val, true);
681 }
682 return true;
683}
684
685////////////////////////////////////////////////////////////////////////////////
686/// set parameter values first set all values to defaultVal (if value not
687/// present in param_card then it should be 0)
688
689template <class T1, class T2>
690inline bool
691setParams(const std::map<const std::string, T1> &point, const T2 &args, bool force = false, T1 defaultVal = 0)
692{
693 bool ok = true;
694 for (auto *param : dynamic_range_cast<RooRealVar *>(args)) {
695 if (!param || param->isConstant())
696 continue;
697 ok = setParam(param, defaultVal, force) && ok;
698 }
699 // set all parameters to the values in the param_card histogram
700 for (auto paramit : point) {
701 // loop over all the parameters
702 const std::string param(paramit.first);
703 // retrieve them from the map
704 RooRealVar *p = dynamic_cast<RooRealVar *>(args.find(param.c_str()));
705 if (!p)
706 continue;
707 // set them to their nominal value
708 ok = setParam(p, paramit.second, force) && ok;
709 }
710 return ok;
711}
712
713////////////////////////////////////////////////////////////////////////////////
714/// set parameter values first set all values to defaultVal (if value not
715/// present in param_card then it should be 0)
716
717template <class T>
718inline bool setParams(TH1 *hist, const T &args, bool force = false)
719{
720 bool ok = true;
721
722 for (auto *param : dynamic_range_cast<RooRealVar *>(args)) {
723 if (!param)
724 continue;
725 ok = setParam(param, 0., force) && ok;
726 }
727
728 // set all parameters to the values in the param_card histogram
729 TAxis *ax = hist->GetXaxis();
730 for (int i = 1; i <= ax->GetNbins(); ++i) {
731 // loop over all the parameters
732 RooRealVar *p = dynamic_cast<RooRealVar *>(args.find(ax->GetBinLabel(i)));
733 if (!p)
734 continue;
735 // set them to their nominal value
736 ok = setParam(p, hist->GetBinContent(i), force) && ok;
737 }
738 return ok;
739}
740
741////////////////////////////////////////////////////////////////////////////////
742/// create a set of parameters
743
744template <class T>
745inline RooLagrangianMorphFunc::ParamSet getParams(const T &parameters)
746{
748 for (auto *param : dynamic_range_cast<RooRealVar *>(parameters)) {
749 if (!param)
750 continue;
751 retval[param->GetName()] = param->getVal();
752 }
753 return retval;
754}
755
756////////////////////////////////////////////////////////////////////////////////
757/// collect the histograms from the input file and convert them to RooFit
758/// objects
759
760void collectHistograms(const char *name, TDirectory *file, std::map<std::string, int> &list_hf, RooArgList &physics,
761 RooRealVar &var, const std::string &varname,
763{
764 bool binningOK = false;
765 for (auto sampleit : inputParameters) {
766 const std::string sample(sampleit.first);
767 auto hist = loadFromFileResidentFolder<TH1>(file, sample, varname, true);
768 if (!hist)
769 return;
770
771 if (normalize) {
772 hist->Scale(1. / hist->Integral());
773 }
774
775 auto it = list_hf.find(sample);
776 if (it != list_hf.end()) {
777 RooHistFunc *hf = static_cast<RooHistFunc *>(physics.at(it->second));
778 hf->setValueDirty();
779 // commenting out To-be-resolved
780 // RooDataHist* dh = &(hf->dataHist());
781 // RooLagrangianMorphFunc::setDataHistogram(hist,&var,dh);
782 // RooArgSet vars;
783 // vars.add(var);
784 // dh->importTH1(vars,*hist,1.,false);
785 } else {
786 if (!binningOK) {
787 int n = hist->GetNbinsX();
788 std::vector<double> bins;
789 for (int i = 1; i < n + 1; ++i) {
790 bins.push_back(hist->GetBinLowEdge(i));
791 }
792 bins.push_back(hist->GetBinLowEdge(n) + hist->GetBinWidth(n));
793 var.setBinning(RooBinning(n, &(bins[0])));
794 }
795
796 // generate the mean value
797 TString histname = makeValidName("dh_" + sample + "_" + name);
798 TString funcname = makeValidName("phys_" + sample + "_" + name);
799 RooArgSet vars;
800 vars.add(var);
801
802 auto dh = std::make_unique<RooDataHist>(histname.Data(), histname.Data(), vars, hist.get());
803 // add it to the list
804 auto hf = std::make_unique<RooHistFunc>(funcname.Data(), funcname.Data(), var, std::move(dh));
805 int idx = physics.size();
806 list_hf[sample] = idx;
807 physics.addOwned(std::move(hf));
808 }
809 // std::cout << "found histogram " << hist->GetName() << " with integral "
810 // << hist->Integral() << std::endl;
811 }
812}
813
814////////////////////////////////////////////////////////////////////////////////
815/// collect the RooAbsReal objects from the input directory
816
817void collectRooAbsReal(const char * /*name*/, TDirectory *file, std::map<std::string, int> &list_hf,
818 RooArgList &physics, const std::string &varname,
820{
821 for (auto sampleit : inputParameters) {
822 const std::string sample(sampleit.first);
824 if (!obj)
825 return;
826 auto it = list_hf.find(sample);
827 if (it == list_hf.end()) {
828 int idx = physics.size();
829 list_hf[sample] = idx;
830 physics.addOwned(std::move(obj));
831 }
832 }
833}
834
835////////////////////////////////////////////////////////////////////////////////
836/// collect the TParameter objects from the input file and convert them to
837/// RooFit objects
838
839template <class T>
840void collectCrosssections(const char *name, TDirectory *file, std::map<std::string, int> &list_xs, RooArgList &physics,
842{
843 for (auto sampleit : inputParameters) {
844 const std::string sample(sampleit.first);
845 auto obj = loadFromFileResidentFolder<TObject>(file, sample, varname, false);
846 TParameter<T> *xsection = nullptr;
847 TParameter<T> *error = nullptr;
848 TParameter<T> *p = dynamic_cast<TParameter<T> *>(obj.get());
849 if (p) {
850 xsection = p;
851 }
852 TPair *pair = dynamic_cast<TPair *>(obj.get());
853 if (pair) {
854 xsection = dynamic_cast<TParameter<T> *>(pair->Key());
855 error = dynamic_cast<TParameter<T> *>(pair->Value());
856 }
857 if (!xsection) {
858 std::stringstream errstr;
859 errstr << "Error: unable to retrieve cross section '" << varname << "' from folder '" << sample;
860 return;
861 }
862
863 auto it = list_xs.find(sample);
864 RooRealVar *xs;
865 if (it != list_xs.end()) {
866 xs = static_cast<RooRealVar *>(physics.at(it->second));
867 xs->setVal(xsection->GetVal());
868 } else {
869 std::string objname = "phys_" + std::string(name) + "_" + sample;
870 auto xsOwner = std::make_unique<RooRealVar>(objname.c_str(), objname.c_str(), xsection->GetVal());
871 xs = xsOwner.get();
872 xs->setConstant(true);
873 int idx = physics.size();
874 list_xs[sample] = idx;
875 physics.addOwned(std::move(xsOwner));
876 assert(physics.at(idx) == xs);
877 }
878 if (error) {
879 xs->setError(error->GetVal());
880 }
881 }
882}
883
884////////////////////////////////////////////////////////////////////////////////
885/// collect the TPair<TParameter,TParameter> objects from the input file and
886/// convert them to RooFit objects
887
888void collectCrosssectionsTPair(const char *name, TDirectory *file, std::map<std::string, int> &list_xs,
889 RooArgList &physics, const std::string &varname, const std::string &basefolder,
891{
892 auto pair = loadFromFileResidentFolder<TPair>(file, basefolder, varname, false);
893 if (!pair)
894 return;
895 if (dynamic_cast<TParameter<double> *>(pair->Key())) {
897 } else if (dynamic_cast<TParameter<float> *>(pair->Key())) {
899 } else {
900 std::cerr << "cannot morph objects of class 'TPair' if parameter is not "
901 "double or float!"
902 << std::endl;
903 }
904}
905
906///////////////////////////////////////////////////////////////////////////////
907// FORMULA CALCULATION ////////////////////////////////////////////////////////
908///////////////////////////////////////////////////////////////////////////////
909///////////////////////////////////////////////////////////////////////////////
910
911////////////////////////////////////////////////////////////////////////////////
912/// recursive function to determine polynomials
913
915 int vertexid, bool first)
916{
917 if (vertexid > 0) {
918 for (size_t i = 0; i < diagram[vertexid - 1].size(); ++i) {
919 if (!diagram[vertexid - 1][i])
920 continue;
921 std::vector<int> newterm(term);
922 newterm[i]++;
923 if (first) {
925 } else {
927 }
928 }
929 } else {
930 bool found = false;
931 for (size_t i = 0; i < morphfunc.size(); ++i) {
932 bool thisfound = true;
933 for (size_t j = 0; j < morphfunc[i].size(); ++j) {
934 if (morphfunc[i][j] != term[j]) {
935 thisfound = false;
936 break;
937 }
938 }
939 if (thisfound) {
940 found = true;
941 break;
942 }
943 }
944 if (!found) {
945 morphfunc.push_back(term);
946 }
947 }
948}
949
950////////////////////////////////////////////////////////////////////////////////
951/// calculate the morphing function pattern based on a vertex map
952
954{
955 int nvtx(diagram.size());
956 std::vector<int> term(diagram[0].size(), 0);
957
959}
960
961////////////////////////////////////////////////////////////////////////////////
962/// build a vertex map based on vertices and couplings appearing
963
964template <class List>
965inline void fillFeynmanDiagram(FeynmanDiagram &diagram, const std::vector<List *> &vertices, RooArgList &couplings)
966{
967 const int ncouplings = couplings.size();
968 // std::cout << "Number of couplings " << ncouplings << std::endl;
969 for (auto const &vertex : vertices) {
970 std::vector<bool> vertexCouplings(ncouplings, false);
971 int idx = -1;
972 for (auto *coupling : dynamic_range_cast<RooAbsReal *>(couplings)) {
973 idx++;
974 if (!coupling) {
975 std::cerr << "encountered invalid list of couplings in vertex!" << std::endl;
976 return;
977 }
978 if (vertex->find(coupling->GetName())) {
979 vertexCouplings[idx] = true;
980 }
981 }
982 diagram.push_back(vertexCouplings);
983 }
984}
985
986////////////////////////////////////////////////////////////////////////////////
987/// fill the matrix of coefficients
988
989template <class MatrixT, class T1, class T2>
991 const T1 &args, const RooLagrangianMorphFunc::FlagMap &flagValues, const T2 &flags)
992{
993 const size_t dim = inputParameters.size();
994 MatrixT matrix(dim, dim);
995 int row = 0;
996 for (auto sampleit : inputParameters) {
997 const std::string sample(sampleit.first);
998 // set all vars to value stored in input file
999 if (!setParams<double>(sampleit.second, args, true, 0)) {
1000 std::cout << "unable to set parameters for sample " << sample << "!" << std::endl;
1001 }
1002 auto flagit = flagValues.find(sample);
1003 if (flagit != flagValues.end() && !setParams<int>(flagit->second, flags, true, 1)) {
1004 std::cout << "unable to set parameters for sample " << sample << "!" << std::endl;
1005 }
1006 // loop over all the formulas
1007 int col = 0;
1008 for (auto const &formula : formulas) {
1009 if (!formula.second) {
1010 std::cerr << "Error: invalid formula encountered!" << std::endl;
1011 }
1012 matrix(row, col) = formula.second->getVal();
1013 col++;
1014 }
1015 row++;
1016 }
1017 return matrix;
1018}
1019
1020////////////////////////////////////////////////////////////////////////////////
1021/// check if the matrix is square
1022
1023inline void checkMatrix(const RooLagrangianMorphFunc::ParamMap &inputParameters, const FormulaList &formulas)
1024{
1025 if (inputParameters.size() != formulas.size()) {
1026 std::stringstream ss;
1027 ss << "matrix is not square, consistency check failed: " << inputParameters.size() << " samples, "
1028 << formulas.size() << " expressions:" << std::endl;
1029 ss << "formulas: " << std::endl;
1030 for (auto const &formula : formulas) {
1031 ss << formula.second->GetTitle() << std::endl;
1032 }
1033 ss << "samples: " << std::endl;
1034 for (auto sample : inputParameters) {
1035 ss << sample.first << std::endl;
1036 }
1037 std::cerr << ss.str() << std::endl;
1038 }
1039}
1040
1041////////////////////////////////////////////////////////////////////////////////
1042/// check if the entries in the inverted matrix are sensible
1043
1044inline void inverseSanity(const Matrix &matrix, const Matrix &inverse, double &unityDeviation, double &largestWeight)
1045{
1047
1048 unityDeviation = 0.;
1049 largestWeight = 0.;
1050 const size_t dim = size(unity);
1051 for (size_t i = 0; i < dim; ++i) {
1052 for (size_t j = 0; j < dim; ++j) {
1053 if (inverse(i, j) > largestWeight) {
1055 }
1056 if (std::abs(unity(i, j) - static_cast<int>(i == j)) > unityDeviation) {
1057 unityDeviation = std::abs((double)unity(i, j)) - static_cast<int>(i == j);
1058 }
1059 }
1060 }
1061}
1062
1063////////////////////////////////////////////////////////////////////////////////
1064/// check for name conflicts between the input samples and an argument set
1065template <class List>
1067{
1068 for (auto sampleit : inputParameters) {
1069 const std::string sample(sampleit.first);
1070 RooAbsArg *arg = args.find(sample.c_str());
1071 if (arg) {
1072 std::cerr << "detected name conflict: cannot use sample '" << sample
1073 << "' - a parameter with the same name of type '" << arg->ClassName() << "' is present in set '"
1074 << args.GetName() << "'!" << std::endl;
1075 }
1076 }
1077}
1078
1079////////////////////////////////////////////////////////////////////////////////
1080/// build the formulas corresponding to the given set of input files and
1081/// the physics process
1082
1085 const RooArgList &couplings, const RooArgList &flags,
1086 const std::vector<std::vector<std::string>> &nonInterfering)
1087{
1088 // example vbf hww:
1089 // Operators kSM, kHww, kAww, kHdwR,kHzz, kAzz
1090 // std::vector<bool> vertexProd = {true, true, true, true, true, true };
1091 // std::vector<bool> vertexDecay = {true, true, true, true, false,false};
1092 // diagram.push_back(vertexProd);
1093 // diagram.push_back(vertexDecay);
1094
1095 const int ncouplings = couplings.size();
1096 std::vector<bool> couplingsZero(ncouplings, true);
1097 std::map<TString, bool> flagsZero;
1098
1100 extractOperators(couplings, operators);
1101 size_t nOps = operators.size();
1102
1103 for (auto sampleit : inputParameters) {
1104 const std::string sample(sampleit.first);
1105 if (!setParams(sampleit.second, operators, true)) {
1106 std::cerr << "unable to set parameters for sample '" << sample << "'!" << std::endl;
1107 }
1108
1109 if (nOps != (operators.size())) {
1110 std::cerr << "internal error, number of operators inconsistent!" << std::endl;
1111 }
1112
1113 int idx = 0;
1114
1115 for (auto *obj0 : dynamic_range_cast<RooAbsReal *>(couplings)) {
1116 if (obj0->getVal() != 0) {
1117 couplingsZero[idx] = false;
1118 }
1119 idx++;
1120 }
1121 }
1122
1123 for (auto *obj1 : dynamic_range_cast<RooAbsReal *>(flags)) {
1124 int nZero = 0;
1125 int nNonZero = 0;
1126 for (auto sampleit : inputFlags) {
1127 const auto &flag = sampleit.second.find(obj1->GetName());
1128 if (flag != sampleit.second.end()) {
1129 if (flag->second == 0.) {
1130 nZero++;
1131 } else {
1132 nNonZero++;
1133 }
1134 }
1135 }
1136 if (nZero > 0 && nNonZero == 0) {
1137 flagsZero[obj1->GetName()] = true;
1138 } else {
1139 flagsZero[obj1->GetName()] = false;
1140 }
1141 }
1142
1143 FormulaList formulas;
1144 for (size_t i = 0; i < morphfunc.size(); ++i) {
1145 RooArgList ss;
1146 bool isZero = false;
1147 std::string reason;
1148 // check if this is a blacklisted interference term
1149 for (const auto &group : nonInterfering) {
1150 int nInterferingOperators = 0;
1151 for (size_t j = 0; j < morphfunc[i].size(); ++j) {
1152 if (morphfunc[i][j] % 2 == 0)
1153 continue; // even exponents are not interference terms
1154 // if the coupling is part of a "pairwise non-interfering group"
1155 if (std::find(group.begin(), group.end(), couplings.at(j)->GetName()) != group.end()) {
1157 }
1158 }
1159 if (nInterferingOperators > 1) {
1160 isZero = true;
1161 reason = "blacklisted interference term!";
1162 }
1163 }
1164 int nNP = 0;
1165 if (!isZero) {
1166 // prepare the term
1167 for (size_t j = 0; j < morphfunc[i].size(); ++j) {
1168 const int exponent = morphfunc[i][j];
1169 if (exponent == 0)
1170 continue;
1171 RooAbsReal *coupling = dynamic_cast<RooAbsReal *>(couplings.at(j));
1172 for (int k = 0; k < exponent; ++k) {
1173 ss.add(*coupling);
1174 if (coupling->getAttribute("NewPhysics")) {
1175 nNP++;
1176 }
1177 }
1178 std::string cname(coupling->GetName());
1179 if (coupling->getAttribute("LO") && exponent > 1) {
1180 isZero = true;
1181 reason = "coupling " + cname + " was listed as leading-order-only";
1182 }
1183 // mark the term as zero if any of the couplings are zero
1184 if (!isZero && couplingsZero[j]) {
1185 isZero = true;
1186 reason = "coupling " + cname + " is zero!";
1187 }
1188 }
1189 }
1190 // check and apply flags
1191 bool removedByFlag = false;
1192
1193 for (auto *obj : dynamic_range_cast<RooAbsReal *>(flags)) {
1194 if (!obj)
1195 continue;
1196 TString sval(obj->getStringAttribute("NewPhysics"));
1197 int val = atoi(sval);
1198 if (val == nNP) {
1199 if (flagsZero.find(obj->GetName()) != flagsZero.end() && flagsZero.at(obj->GetName())) {
1200 removedByFlag = true;
1201 reason = "flag " + std::string(obj->GetName()) + " is zero";
1202 }
1203 ss.add(*obj);
1204 }
1205 }
1206
1207 // create and add the formula
1208 if (!isZero && !removedByFlag) {
1209 // build the name
1210 const auto name = std::string(mfname) + "_pol" + std::to_string(i);
1211 formulas[i] = std::make_unique<RooProduct>(name.c_str(), ::concatNames(ss, " * ").c_str(), ss);
1212 }
1213 }
1214 return formulas;
1215}
1216
1217////////////////////////////////////////////////////////////////////////////////
1218/// create the weight formulas required for the morphing
1219
1220FormulaList createFormulas(const char *name, const RooLagrangianMorphFunc::ParamMap &inputs,
1222 const std::vector<std::vector<RooArgList *>> &diagrams, RooArgList &couplings,
1223 const RooArgList &flags, const std::vector<std::vector<std::string>> &nonInterfering)
1224{
1226
1227 for (const auto &vertices : diagrams) {
1229 ::fillFeynmanDiagram(d, vertices, couplings);
1231 }
1232 FormulaList retval = buildFormulas(name, inputs, inputFlags, morphfuncpattern, couplings, flags, nonInterfering);
1233 if (retval.empty()) {
1234 std::stringstream errorMsgStream;
1236 << "no formulas are non-zero, check if any if your couplings is floating and missing from your param_cards!"
1237 << std::endl;
1238 const auto errorMsg = errorMsgStream.str();
1239 throw std::runtime_error(errorMsg);
1240 }
1242 return retval;
1243}
1244
1245////////////////////////////////////////////////////////////////////////////////
1246/// build the sample weights required for the input templates
1247//
1248template <class T1>
1249inline void buildSampleWeights(T1 &weights, const char *fname, const RooLagrangianMorphFunc::ParamMap &inputParameters,
1250 FormulaList &formulas, const Matrix &inverse)
1251{
1252 int sampleidx = 0;
1253
1254 for (auto sampleit : inputParameters) {
1255 const std::string sample(sampleit.first);
1256 std::stringstream title;
1258 if (fname) {
1259 name_full.Append("_");
1260 name_full.Append(fname);
1261 name_full.Prepend("w_");
1262 }
1263
1264 int formulaidx = 0;
1265 // build the formula with the correct normalization
1266 auto sampleformula = std::make_unique<RooLinearCombination>(name_full.Data());
1267 for (auto const &formulait : formulas) {
1269 sampleformula->add(val, formulait.second.get());
1270 formulaidx++;
1271 }
1272 weights.addOwned(std::move(sampleformula));
1273 sampleidx++;
1274 }
1275}
1276
1277inline std::map<std::string, std::string>
1279 const Matrix &inverse)
1280{
1281 int sampleidx = 0;
1282 std::map<std::string, std::string> weights;
1283 for (auto sampleit : inputParameters) {
1284 const std::string sample(sampleit.first);
1285 std::stringstream str;
1286 int formulaidx = 0;
1287 // build the formula with the correct normalization
1288 for (auto const &formulait : formulas) {
1289 double val(inverse(formulaidx, sampleidx));
1290 if (val != 0.) {
1291 if (formulaidx > 0 && val > 0)
1292 str << " + ";
1293 str << val << "*(" << formulait.second->GetTitle() << ")";
1294 }
1295 formulaidx++;
1296 }
1297 weights[sample] = str.str();
1298 sampleidx++;
1299 }
1300 return weights;
1301}
1302} // namespace
1303
1304///////////////////////////////////////////////////////////////////////////////
1305// CacheElem magic ////////////////////////////////////////////////////////////
1306///////////////////////////////////////////////////////////////////////////////
1307
1309public:
1310 std::unique_ptr<RooRealSumFunc> _sumFunc = nullptr;
1312
1313 FormulaList _formulas;
1315
1319
1322
1323 //////////////////////////////////////////////////////////////////////////////
1324 /// retrieve the list of contained args
1325
1327 {
1328 RooArgList args(*_sumFunc);
1329 args.add(_weights);
1330 args.add(_couplings);
1331 for (auto const &it : _formulas) {
1332 args.add(*(it.second));
1333 }
1334 return args;
1335 }
1336
1337 //////////////////////////////////////////////////////////////////////////////
1338 /// create the basic objects required for the morphing
1339
1342 const std::vector<std::vector<RooListProxy *>> &diagramProxyList,
1343 const std::vector<std::vector<std::string>> &nonInterfering, const RooArgList &flags)
1344 {
1346 std::vector<std::vector<RooArgList *>> diagrams;
1347 for (const auto &diagram : diagramProxyList) {
1348 diagrams.emplace_back();
1349 for (RooArgList *vertex : diagram) {
1351 diagrams.back().emplace_back(vertex);
1352 }
1353 }
1356 }
1357
1358 //////////////////////////////////////////////////////////////////////////////
1359 /// build and invert the morphing matrix
1360 template <class List>
1362 const RooLagrangianMorphFunc::FlagMap &inputFlags, const List &flags)
1363 {
1367 if (size(matrix) < 1) {
1368 std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl;
1369 }
1371
1372 double condition = (double)(invertMatrix(matrix, inverse));
1373 double unityDeviation;
1374 double largestWeight;
1376 bool weightwarning(largestWeight > morphLargestWeight ? true : false);
1377 bool unitywarning(unityDeviation > morphUnityDeviation ? true : false);
1378
1379 if (false) {
1380 if (unitywarning) {
1381 oocxcoutW((TObject *)nullptr, Eval) << "Warning: The matrix inversion seems to be unstable. This can "
1382 "be a result to input samples that are not sufficiently "
1383 "different to provide any morphing power."
1384 << std::endl;
1385 } else if (weightwarning) {
1386 oocxcoutW((TObject *)nullptr, Eval) << "Warning: Some weights are excessively large. This can be a "
1387 "result to input samples that are not sufficiently different to "
1388 "provide any morphing power."
1389 << std::endl;
1390 }
1391 oocxcoutW((TObject *)nullptr, Eval) << " Please consider the couplings "
1392 "encoded in your samples to cross-check:"
1393 << std::endl;
1394 for (auto sampleit : inputParameters) {
1395 const std::string sample(sampleit.first);
1396 oocxcoutW((TObject *)nullptr, Eval) << " " << sample << ": ";
1397 // set all vars to value stored in input file
1398 setParams(sampleit.second, operators, true);
1399 bool first = true;
1400
1401 for (auto *obj : dynamic_range_cast<RooAbsReal *>(_couplings)) {
1402 if (!first)
1403 std::cerr << ", ";
1404 oocxcoutW((TObject *)nullptr, Eval) << obj->GetName() << "=" << obj->getVal();
1405 first = false;
1406 }
1407 oocxcoutW((TObject *)nullptr, Eval) << std::endl;
1408 }
1409 }
1410#ifndef USE_UBLAS
1411 _matrix.ResizeTo(matrix.GetNrows(), matrix.GetNrows());
1412 _inverse.ResizeTo(matrix.GetNrows(), matrix.GetNrows());
1413#endif
1414 _matrix = matrix;
1415 _inverse = inverse;
1416 _condition = condition;
1417 }
1418
1419 ////////////////////////////////////////////////////////////////////////////////
1420 /// build the final morphing function
1421
1423 const std::map<std::string, int> &storage, const RooArgList &physics,
1424 bool allowNegativeYields, RooRealVar *observable, RooRealVar *binWidth)
1425 {
1426 if (!binWidth) {
1427 std::cerr << "invalid bin width given!" << std::endl;
1428 return;
1429 }
1430 if (!observable) {
1431 std::cerr << "invalid observable given!" << std::endl;
1432 return;
1433 }
1434
1437
1438 // retrieve the weights
1440
1441 // build the products of element and weight for each sample
1442 size_t i = 0;
1445 for (auto sampleit : inputParameters) {
1446 // for now, we assume all the lists are nicely ordered
1448
1449 RooAbsReal *obj = static_cast<RooAbsReal *>(physics.at(storage.at(prodname.Data())));
1450
1451 if (!obj) {
1452 std::cerr << "unable to access physics object for " << prodname << std::endl;
1453 return;
1454 }
1455
1456 RooAbsReal *weight = static_cast<RooAbsReal *>(_weights.at(i));
1457
1458 if (!weight) {
1459 std::cerr << "unable to access weight object for " << prodname << std::endl;
1460 return;
1461 }
1462 prodname.Append("_");
1463 prodname.Append(name);
1464 RooArgList prodElems(*weight, *obj);
1465
1466 allowNegativeYields = true;
1467 auto prod = std::make_unique<RooProduct>(prodname, prodname, prodElems);
1468 if (!allowNegativeYields) {
1469 auto maxname = std::string(prodname) + "_max0";
1470 RooArgSet prodset(*prod);
1471
1472 auto max = std::make_unique<RooFormulaVar>(maxname.c_str(), "max(0," + prodname + ")", prodset);
1473 max->addOwnedComponents(std::move(prod));
1474 sumElements.addOwned(std::move(max));
1475 } else {
1476 sumElements.addOwned(std::move(prod));
1477 }
1478 scaleElements.add(*(binWidth));
1479 i++;
1480 }
1481
1482 // put everything together
1483 _sumFunc = make_unique<RooRealSumFunc>((std::string(name) + "_morphfunc").c_str(), name, sumElements, scaleElements);
1484
1485 if (!observable)
1486 std::cerr << "unable to access observable" << std::endl;
1487 _sumFunc->addServer(*observable);
1488 if (!binWidth)
1489 std::cerr << "unable to access bin width" << std::endl;
1490 _sumFunc->addServer(*binWidth);
1491 if (operators.empty())
1492 std::cerr << "no operators listed" << std::endl;
1493 _sumFunc->addServerList(operators);
1494 if (_weights.empty())
1495 std::cerr << "unable to access weight objects" << std::endl;
1496 _sumFunc->addOwnedComponents(std::move(sumElements));
1497 _sumFunc->addServerList(sumElements);
1498 _sumFunc->addServerList(scaleElements);
1499
1500#ifdef USE_UBLAS
1501 std::cout.precision(std::numeric_limits<double>::digits);
1502#endif
1503 }
1504 //////////////////////////////////////////////////////////////////////////////
1505 /// create all the temporary objects required by the class
1506
1508 {
1509 std::string obsName = func->getObservable()->GetName();
1511
1513
1514 cache->createComponents(func->_config.paramCards, func->_config.flagValues, func->GetName(), func->_diagrams,
1515 func->_nonInterfering, func->_flags);
1516
1517 cache->buildMatrix(func->_config.paramCards, func->_config.flagValues, func->_flags);
1518 if (obsName.empty()) {
1519 std::cerr << "Matrix inversion succeeded, but no observable was "
1520 "supplied. quitting..."
1521 << std::endl;
1522 return cache;
1523 }
1524
1525 oocxcoutP((TObject *)nullptr, ObjectHandling) << "observable: " << func->getObservable()->GetName() << std::endl;
1526 oocxcoutP((TObject *)nullptr, ObjectHandling) << "binWidth: " << func->getBinWidth()->GetName() << std::endl;
1527
1528 setParams(func->_flags, 1);
1529 cache->buildMorphingFunction(func->GetName(), func->_config.paramCards, func->_sampleMap, func->_physics,
1530 func->_config.allowNegativeYields, func->getObservable(), func->getBinWidth());
1531 setParams(values, func->_operators, true);
1532 setParams(func->_flags, 1);
1533 return cache;
1534 }
1535
1536 //////////////////////////////////////////////////////////////////////////////
1537 /// create all the temporary objects required by the class
1538 /// function variant with precomputed inverse matrix
1539
1541 {
1543
1545
1546 cache->createComponents(func->_config.paramCards, func->_config.flagValues, func->GetName(), func->_diagrams,
1547 func->_nonInterfering, func->_flags);
1548
1549#ifndef USE_UBLAS
1550 cache->_inverse.ResizeTo(inverse.GetNrows(), inverse.GetNrows());
1551#endif
1552 cache->_inverse = inverse;
1553 cache->_condition = NaN;
1554
1555 setParams(func->_flags, 1);
1556 cache->buildMorphingFunction(func->GetName(), func->_config.paramCards, func->_sampleMap, func->_physics,
1557 func->_config.allowNegativeYields, func->getObservable(), func->getBinWidth());
1558 setParams(values, func->_operators, true);
1559 setParams(func->_flags, 1);
1560 return cache;
1561 }
1562};
1563
1564///////////////////////////////////////////////////////////////////////////////
1565// Class Implementation ///////////////////////////////////////////////////////
1566///////////////////////////////////////////////////////////////////////////////
1567
1568////////////////////////////////////////////////////////////////////////////////
1569/// write a matrix to a file
1570
1575
1576////////////////////////////////////////////////////////////////////////////////
1577/// write a matrix to a stream
1578
1580{
1582}
1583
1584////////////////////////////////////////////////////////////////////////////////
1585/// read a matrix from a text file
1586
1591
1592////////////////////////////////////////////////////////////////////////////////
1593/// read a matrix from a stream
1594
1599
1600////////////////////////////////////////////////////////////////////////////////
1601/// setup observable, recycle existing observable if defined
1602
1604{
1605 // cxcoutP(ObjectHandling) << "setting up observable" << std::endl;
1606 RooRealVar *obs = nullptr;
1607 bool obsExists(false);
1608 if (_observables.at(0) != nullptr) {
1609 obs = static_cast<RooRealVar *>(_observables.at(0));
1610 obsExists = true;
1611 }
1612
1613 if (mode && mode->InheritsFrom(RooHistFunc::Class())) {
1614 obs = static_cast<RooRealVar *>(dynamic_cast<RooHistFunc *>(inputExample)->getHistObsList().first());
1615 obsExists = true;
1616 _observables.add(*obs);
1617 } else if (mode && mode->InheritsFrom(RooParamHistFunc::Class())) {
1618 obs = static_cast<RooRealVar *>(dynamic_cast<RooParamHistFunc *>(inputExample)->paramList().first());
1619 obsExists = true;
1620 _observables.add(*obs);
1621 }
1622
1623 // Note: "found!" will be printed if s2 is a substring of s1, both s1 and s2
1624 // are of type std::string. s1.find(s2)
1625 // obtain the observable
1626 if (!obsExists) {
1627 if (mode && mode->InheritsFrom(TH1::Class())) {
1628 TH1 *hist = static_cast<TH1 *>(inputExample);
1629 auto obsOwner =
1630 std::make_unique<RooRealVar>(obsname, obsname, hist->GetXaxis()->GetXmin(), hist->GetXaxis()->GetXmax());
1631 obs = obsOwner.get();
1632 addOwnedComponents(std::move(obsOwner));
1633 obs->setBins(hist->GetNbinsX());
1634 } else {
1635 auto obsOwner = std::make_unique<RooRealVar>(obsname, obsname, 0, 1);
1636 obs = obsOwner.get();
1637 addOwnedComponents(std::move(obsOwner));
1638 obs->setBins(1);
1639 }
1640 _observables.add(*obs);
1641 } else {
1642 if (strcmp(obsname, obs->GetName()) != 0) {
1643 coutW(ObjectHandling) << " name of existing observable " << _observables.at(0)->GetName()
1644 << " does not match expected name " << obsname << std::endl;
1645 }
1646 }
1647
1648 TString sbw = TString::Format("binWidth_%s", makeValidName(obs->GetName()).Data());
1649 auto binWidth = std::make_unique<RooRealVar>(sbw.Data(), sbw.Data(), 1.);
1650 double bw = obs->numBins() / (obs->getMax() - obs->getMin());
1651 binWidth->setVal(bw);
1652 binWidth->setConstant(true);
1653 _binWidths.addOwned(std::move(binWidth));
1654
1655 return obs;
1656}
1657
1658//#ifndef USE_MULTIPRECISION_LC
1659//#pragma GCC diagnostic push
1660//#pragma GCC diagnostic ignored "-Wunused-parameter"
1661//#endif
1662
1663////////////////////////////////////////////////////////////////////////////////
1664/// update sample weight (-?-)
1665
1667{
1668 //#ifdef USE_MULTIPRECISION_LC
1669 int sampleidx = 0;
1670 auto cache = this->getCache();
1671 const size_t n(size(cache->_inverse));
1672 for (auto sampleit : _config.paramCards) {
1673 const std::string sample(sampleit.first);
1674 // build the formula with the correct normalization
1675 RooLinearCombination *sampleformula = dynamic_cast<RooLinearCombination *>(this->getSampleWeight(sample.c_str()));
1676 if (!sampleformula) {
1677 coutE(ObjectHandling) << Form("unable to access formula for sample '%s'!", sample.c_str()) << std::endl;
1678 return;
1679 }
1680 cxcoutP(ObjectHandling) << "updating formula for sample '" << sample << "'" << std::endl;
1681 for (size_t formulaidx = 0; formulaidx < n; ++formulaidx) {
1682 const RooFit::SuperFloat val(cache->_inverse(formulaidx, sampleidx));
1683#ifdef USE_UBLAS
1684 if (val != val) {
1685#else
1686 if (std::isnan(val)) {
1687#endif
1688 coutE(ObjectHandling) << "refusing to propagate NaN!" << std::endl;
1689 }
1690 cxcoutP(ObjectHandling) << " " << formulaidx << ":" << sampleformula->getCoefficient(formulaidx) << " -> "
1691 << val << std::endl;
1692 sampleformula->setCoefficient(formulaidx, val);
1693 assert(sampleformula->getCoefficient(formulaidx) == val);
1694 }
1695 sampleformula->setValueDirty();
1696 ++sampleidx;
1697 }
1698 //#else
1699 // ERROR("updating sample weights currently not possible without boost!");
1700 //#endif
1701}
1702//#ifndef USE_MULTIPRECISION_LC
1703//#pragma GCC diagnostic pop
1704//#endif
1705
1706////////////////////////////////////////////////////////////////////////////////
1707/// read the parameters from the input file
1708
1714
1715////////////////////////////////////////////////////////////////////////////////
1716/// retrieve the physics inputs
1717
1719{
1720 std::string obsName;
1721 if (_config.observable) {
1723 if (_config.observableName.empty()) {
1725 } else {
1727 }
1728 } else {
1730 }
1731
1732 cxcoutP(InputArguments) << "initializing physics inputs from file " << file->GetName() << " with object name(s) '"
1733 << obsName << "'" << std::endl;
1734 auto folderNames = _config.folderNames;
1735 auto obj = loadFromFileResidentFolder<TObject>(file, folderNames.front(), obsName, true);
1736 if (!obj) {
1737 std::cerr << "unable to locate object '" << obsName << "' in folder '" << folderNames.front() << "'!"
1738 << std::endl;
1739 return;
1740 }
1741 std::string classname = obj->ClassName();
1742 TClass *mode = TClass::GetClass(obj->ClassName());
1743 this->setupObservable(obsName.c_str(), mode, obj.get());
1744
1745 if (classname.find("TH1") != std::string::npos) {
1746 collectHistograms(this->GetName(), file, _sampleMap, _physics, *static_cast<RooRealVar *>(_observables.at(0)),
1748 } else if (classname.find("RooHistFunc") != std::string::npos ||
1749 classname.find("RooParamHistFunc") != std::string::npos ||
1750 classname.find("PiecewiseInterpolation") != std::string::npos) {
1752 } else if (classname.find("TParameter<double>") != std::string::npos) {
1754 } else if (classname.find("TParameter<float>") != std::string::npos) {
1756 } else if (classname.find("TPair") != std::string::npos) {
1757 collectCrosssectionsTPair(this->GetName(), file, _sampleMap, _physics, obsName, folderNames[0],
1759 } else {
1760 std::cerr << "cannot morph objects of class '" << mode->GetName() << "'!" << std::endl;
1761 }
1762}
1763
1764////////////////////////////////////////////////////////////////////////////////
1765/// print all the parameters and their values in the given sample to the console
1766
1768{
1769 for (const auto &param : _config.paramCards.at(samplename)) {
1770 if (this->hasParameter(param.first.c_str())) {
1771 std::cout << param.first << " = " << param.second;
1772 if (this->isParameterConstant(param.first.c_str()))
1773 std::cout << " (const)";
1774 std::cout << std::endl;
1775 }
1776 }
1777}
1778
1779////////////////////////////////////////////////////////////////////////////////
1780/// print all the known samples to the console
1781
1783{
1784 // print all the known samples to the console
1785 for (auto folder : _config.folderNames) {
1786 std::cout << folder << std::endl;
1787 }
1788}
1789
1790////////////////////////////////////////////////////////////////////////////////
1791/// print the current physics values
1792
1794{
1795 for (const auto &sample : _sampleMap) {
1796 RooAbsArg *phys = _physics.at(sample.second);
1797 if (!phys)
1798 continue;
1799 phys->Print();
1800 }
1801}
1802
1803////////////////////////////////////////////////////////////////////////////////
1804/// constructor with proper arguments
1805
1806RooLagrangianMorphFunc::RooLagrangianMorphFunc(const char *name, const char *title, const Config &config)
1807 : RooAbsReal(name, title), _cacheMgr(this, 10, true, true), _physics("physics", "physics", this),
1808 _operators("operators", "set of operators", this), _observables("observables", "morphing observables", this),
1809 _binWidths("binWidths", "set of binWidth objects", this), _flags("flags", "flags", this), _config(config)
1810{
1811 this->init();
1813 this->setup(false);
1814
1815}
1816
1817////////////////////////////////////////////////////////////////////////////////
1818/// setup this instance with the given set of operators and vertices
1819/// if own=true, the class will own the operators template `<class Base>`
1820
1822{
1823 if (!_config.couplings.empty()) {
1825 std::vector<RooListProxy *> vertices;
1827 vertices.push_back(new RooListProxy("!couplings", "set of couplings in the vertex", this, true, false));
1828 if (own) {
1829 _operators.addOwned(std::move(operators));
1830 vertices[0]->addOwned(_config.couplings);
1831 } else {
1833 vertices[0]->add(_config.couplings);
1834 }
1835 _diagrams.push_back(vertices);
1836 }
1837
1839 std::vector<RooListProxy *> vertices;
1841 cxcoutP(InputArguments) << "prod/dec couplings provided" << std::endl;
1844 vertices.push_back(
1845 new RooListProxy("!production", "set of couplings in the production vertex", this, true, false));
1846 vertices.push_back(new RooListProxy("!decay", "set of couplings in the decay vertex", this, true, false));
1847 if (own) {
1848 _operators.addOwned(std::move(operators));
1849 vertices[0]->addOwned(_config.prodCouplings);
1850 vertices[1]->addOwned(_config.decCouplings);
1851 } else {
1852 cxcoutP(InputArguments) << "adding non-own operators" << std::endl;
1854 vertices[0]->add(_config.prodCouplings);
1855 vertices[1]->add(_config.decCouplings);
1856 }
1857 _diagrams.push_back(vertices);
1858 }
1859}
1860
1861////////////////////////////////////////////////////////////////////////////////
1862/// disable interference between terms
1863
1864void RooLagrangianMorphFunc::disableInterference(const std::vector<const char *> &nonInterfering)
1865{
1866 // disable interference between the listed operators
1867 std::stringstream name;
1868 name << "noInterference";
1869 for (auto c : nonInterfering) {
1870 name << c;
1871 }
1872 _nonInterfering.emplace_back();
1873 for (auto c : nonInterfering) {
1874 _nonInterfering.back().emplace_back(c);
1875 }
1876}
1877
1878////////////////////////////////////////////////////////////////////////////////
1879/// disable interference between terms
1880
1881void RooLagrangianMorphFunc::disableInterferences(const std::vector<std::vector<const char *>> &nonInterfering)
1882{
1883 // disable interferences between the listed groups of operators
1884 for (size_t i = 0; i < nonInterfering.size(); ++i) {
1885 this->disableInterference(nonInterfering[i]);
1886 }
1887}
1888
1889////////////////////////////////////////////////////////////////////////////////
1890/// initialise inputs required for the morphing function
1891
1893{
1894 std::string filename = _config.fileName;
1895 TDirectory *file = openFile(filename);
1896 if (!file) {
1897 coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl;
1898 return;
1899 }
1900 this->readParameters(file);
1902 this->collectInputs(file);
1903 closeFile(file);
1904 auto nNP0 = std::make_unique<RooRealVar>("nNP0", "nNP0", 1., 0, 1.);
1905 nNP0->setStringAttribute("NewPhysics", "0");
1906 nNP0->setConstant(true);
1907 _flags.addOwned(std::move(nNP0));
1908 auto nNP1 = std::make_unique<RooRealVar>("nNP1", "nNP1", 1., 0, 1.);
1909 nNP1->setStringAttribute("NewPhysics", "1");
1910 nNP1->setConstant(true);
1911 _flags.addOwned(std::move(nNP1));
1912 auto nNP2 = std::make_unique<RooRealVar>("nNP2", "nNP2", 1., 0, 1.);
1913 nNP2->setStringAttribute("NewPhysics", "2");
1914 nNP2->setConstant(true);
1915 _flags.addOwned(std::move(nNP2));
1916 auto nNP3 = std::make_unique<RooRealVar>("nNP3", "nNP3", 1., 0, 1.);
1917 nNP3->setStringAttribute("NewPhysics", "3");
1918 nNP3->setConstant(true);
1919 _flags.addOwned(std::move(nNP3));
1920 auto nNP4 = std::make_unique<RooRealVar>("nNP4", "nNP4", 1., 0, 1.);
1921 nNP4->setStringAttribute("NewPhysics", "4");
1922 nNP4->setConstant(true);
1923 _flags.addOwned(std::move(nNP4));
1924}
1925
1926////////////////////////////////////////////////////////////////////////////////
1927/// copy constructor
1928
1930 : RooAbsReal(other, name), _cacheMgr(other._cacheMgr, this), _scale(other._scale), _sampleMap(other._sampleMap),
1931 _physics(other._physics.GetName(), this, other._physics),
1932 _operators(other._operators.GetName(), this, other._operators),
1933 _observables(other._observables.GetName(), this, other._observables),
1934 _binWidths(other._binWidths.GetName(), this, other._binWidths), _flags{other._flags.GetName(), this, other._flags},
1935 _config(other._config)
1936{
1937 for (size_t j = 0; j < other._diagrams.size(); ++j) {
1938 std::vector<RooListProxy *> diagram;
1939 for (auto *elem : other._diagrams[j]) {
1940 RooListProxy *list = new RooListProxy(elem->GetName(), this, *elem);
1941 diagram.push_back(list);
1942 }
1943 _diagrams.push_back(diagram);
1944 }
1945}
1946
1947////////////////////////////////////////////////////////////////////////////////
1948/// set energy scale of the EFT expansion
1949
1951{
1952 _scale = val;
1953}
1954
1955////////////////////////////////////////////////////////////////////////////////
1956/// get energy scale of the EFT expansion
1957
1959{
1960 return _scale;
1961}
1962
1963////////////////////////////////////////////////////////////////////////////////
1964// default constructor
1965
1967 : _cacheMgr(this, 10, true, true), _operators("operators", "set of operators", this, true, false),
1968 _observables("observable", "morphing observable", this, true, false),
1969 _binWidths("binWidths", "set of bin width objects", this, true, false)
1970{
1971}
1972
1973////////////////////////////////////////////////////////////////////////////////
1974/// default destructor
1975
1977{
1978 for (auto const &diagram : _diagrams) {
1979 for (RooListProxy *vertex : diagram) {
1980 delete vertex;
1981 }
1982 }
1983}
1984
1985////////////////////////////////////////////////////////////////////////////////
1986/// calculate the number of samples needed to morph a bivertex, 2-2 physics
1987/// process
1988
1990{
1992 std::vector<bool> prod;
1993 std::vector<bool> dec;
1994 for (int i = 0; i < nboth; ++i) {
1995 prod.push_back(true);
1996 dec.push_back(true);
1997 }
1998 for (int i = 0; i < nprod; ++i) {
1999 prod.push_back(true);
2000 dec.push_back(false);
2001 }
2002 for (int i = 0; i < ndec; ++i) {
2003 prod.push_back(false);
2004 dec.push_back(true);
2005 }
2006 diagram.push_back(prod);
2007 diagram.push_back(dec);
2010 return morphfuncpattern.size();
2011}
2012
2013////////////////////////////////////////////////////////////////////////////////
2014/// calculate the number of samples needed to morph a certain physics process
2015
2016int RooLagrangianMorphFunc::countSamples(std::vector<RooArgList *> &vertices)
2017{
2019 RooArgList couplings;
2020 for (auto vertex : vertices) {
2022 extractCouplings(*vertex, couplings);
2023 }
2025 ::fillFeynmanDiagram(diagram, vertices, couplings);
2028 return morphfuncpattern.size();
2029}
2030
2031////////////////////////////////////////////////////////////////////////////////
2032/// create only the weight formulas. static function for external usage.
2033
2034std::map<std::string, std::string>
2036 const std::vector<std::vector<std::string>> &vertices_str)
2037{
2038 std::stack<RooArgList> ownedVertices;
2039 std::vector<RooArgList *> vertices;
2040 RooArgList couplings;
2041 for (const auto &vtx : vertices_str) {
2042 ownedVertices.emplace();
2043 auto &vertex = ownedVertices.top();
2044 for (const auto &c : vtx) {
2045 auto coupling = static_cast<RooRealVar *>(couplings.find(c.c_str()));
2046 if (!coupling) {
2047 auto couplingOwner = std::make_unique<RooRealVar>(c.c_str(), c.c_str(), 1., 0., 10.);
2048 coupling = couplingOwner.get();
2049 couplings.addOwned(std::move(couplingOwner));
2050 }
2051 vertex.add(*coupling);
2052 }
2053 vertices.push_back(&vertex);
2054 }
2055 auto retval = RooLagrangianMorphFunc::createWeightStrings(inputs, vertices, couplings);
2056 return retval;
2057}
2058
2059////////////////////////////////////////////////////////////////////////////////
2060/// create only the weight formulas. static function for external usage.
2061
2062std::map<std::string, std::string>
2064 const std::vector<RooArgList *> &vertices, RooArgList &couplings)
2065{
2066 return createWeightStrings(inputs, vertices, couplings, {}, {}, {});
2067}
2068
2069////////////////////////////////////////////////////////////////////////////////
2070/// create only the weight formulas. static function for external usage.
2071
2072std::map<std::string, std::string>
2074 const std::vector<RooArgList *> &vertices, RooArgList &couplings,
2075 const RooLagrangianMorphFunc::FlagMap &flagValues, const RooArgList &flags,
2076 const std::vector<std::vector<std::string>> &nonInterfering)
2077{
2078 FormulaList formulas = ::createFormulas("", inputs, flagValues, {vertices}, couplings, flags, nonInterfering);
2080 extractOperators(couplings, operators);
2082 if (size(matrix) < 1) {
2083 std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl;
2084 }
2086 double condition __attribute__((unused)) = (double)(invertMatrix(matrix, inverse));
2088 return retval;
2089}
2090
2091////////////////////////////////////////////////////////////////////////////////
2092/// create only the weight formulas. static function for external usage.
2093
2095 const std::vector<RooArgList *> &vertices, RooArgList &couplings,
2096 const RooLagrangianMorphFunc::FlagMap &flagValues,
2097 const RooArgList &flags,
2098 const std::vector<std::vector<std::string>> &nonInterfering)
2099{
2100 FormulaList formulas = ::createFormulas("", inputs, flagValues, {vertices}, couplings, flags, nonInterfering);
2102 extractOperators(couplings, operators);
2104 if (size(matrix) < 1) {
2105 std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl;
2106 }
2108 double condition __attribute__((unused)) = (double)(invertMatrix(matrix, inverse));
2110 ::buildSampleWeights(retval, (const char *)nullptr /* name */, inputs, formulas, inverse);
2111 return retval;
2112}
2113
2114////////////////////////////////////////////////////////////////////////////////
2115/// create only the weight formulas. static function for external usage.
2116
2118 const std::vector<RooArgList *> &vertices, RooArgList &couplings)
2119{
2120 RooArgList flags;
2121 FlagMap flagValues;
2122 return RooLagrangianMorphFunc::createWeights(inputs, vertices, couplings, flagValues, flags, {});
2123}
2124
2125////////////////////////////////////////////////////////////////////////////////
2126/// return the RooProduct that is the element of the RooRealSumPdfi
2127/// corresponding to the given sample name
2128
2130{
2131 auto mf = this->getFunc();
2132 if (!mf) {
2133 coutE(Eval) << "unable to retrieve morphing function" << std::endl;
2134 return nullptr;
2135 }
2136 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2138 prodname.Append("_");
2139 prodname.Append(this->GetName());
2140
2141 for (auto *prod : dynamic_range_cast<RooProduct *>(*args)) {
2142 if (!prod)
2143 continue;
2144 TString sname(prod->GetName());
2145 if (sname.CompareTo(prodname) == 0) {
2146 return prod;
2147 }
2148 }
2149 return nullptr;
2150}
2151////////////////////////////////////////////////////////////////////////////////
2152/// return the vector of sample names, used to build the morph func
2153
2154std::vector<std::string> RooLagrangianMorphFunc::getSamples() const
2155{
2156 return _config.folderNames;
2157}
2158
2159////////////////////////////////////////////////////////////////////////////////
2160/// retrieve the weight (prefactor) of a sample with the given name
2161
2163{
2164 auto cache = this->getCache();
2165 auto wname = std::string("w_") + name + "_" + this->GetName();
2166 return dynamic_cast<RooAbsReal *>(cache->_weights.find(wname.c_str()));
2167}
2168
2169////////////////////////////////////////////////////////////////////////////////
2170/// print the current sample weights
2171
2173{
2174 this->printSampleWeights();
2175}
2176
2177////////////////////////////////////////////////////////////////////////////////
2178/// print the current sample weights
2179
2181{
2182 auto *cache = this->getCache();
2183 for (const auto &sample : _sampleMap) {
2184 auto weightName = std::string("w_") + sample.first + "_" + this->GetName();
2185 auto weight = static_cast<RooAbsReal *>(cache->_weights.find(weightName.c_str()));
2186 if (!weight)
2187 continue;
2188 }
2189}
2190
2191////////////////////////////////////////////////////////////////////////////////
2192/// randomize the parameters a bit
2193/// useful to test and debug fitting
2194
2196{
2197 TRandom3 r;
2198
2199 for (auto *obj : dynamic_range_cast<RooRealVar *>(_operators)) {
2200 double val = obj->getVal();
2201 if (obj->isConstant())
2202 continue;
2203 double variation = r.Gaus(1, z);
2204 obj->setVal(val * variation);
2205 }
2206}
2207
2208////////////////////////////////////////////////////////////////////////////////
2209/// Retrieve the new physics objects and update the weights in the morphing
2210/// function.
2211
2213{
2214 auto cache = this->getCache();
2215
2216 std::string filename = _config.fileName;
2217 TDirectory *file = openFile(filename);
2218 if (!file) {
2219 coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl;
2220 return false;
2221 }
2222
2223 this->readParameters(file);
2224
2226 this->collectInputs(file);
2227
2228 cache->buildMatrix(_config.paramCards, _config.flagValues, _flags);
2229 this->updateSampleWeights();
2230
2231 closeFile(file);
2232 return true;
2233}
2234
2235////////////////////////////////////////////////////////////////////////////////
2236/// setup the morphing function with a predefined inverse matrix
2237/// call this function *before* any other after creating the object
2238
2240{
2241 auto cache = static_cast<RooLagrangianMorphFunc::CacheElem *>(
2242 _cacheMgr.getObj(nullptr, static_cast<RooArgSet const *>(nullptr)));
2244 if (cache) {
2245 std::string filename = _config.fileName;
2246 cache->_inverse = m;
2247 TDirectory *file = openFile(filename);
2248 if (!file) {
2249 coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl;
2250 return false;
2251 }
2252
2253 this->readParameters(file);
2255 this->collectInputs(file);
2256
2257 // then, update the weights in the morphing function
2258 this->updateSampleWeights();
2259
2260 closeFile(file);
2261 } else {
2263 if (!cache)
2264 coutE(Caching) << "unable to create cache!" << std::endl;
2265 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
2266 }
2267 return true;
2268}
2269
2270////////////////////////////////////////////////////////////////////////////////
2271// setup the morphing function with a predefined inverse matrix
2272// call this function *before* any other after creating the object
2273
2275{
2276 auto cache = static_cast<RooLagrangianMorphFunc::CacheElem *>(
2277 _cacheMgr.getObj(nullptr, static_cast<RooArgSet const *>(nullptr)));
2278 if (cache) {
2279 return false;
2280 }
2282 if (!cache)
2283 coutE(Caching) << "unable to create cache!" << std::endl;
2284 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
2285 return true;
2286}
2287
2288////////////////////////////////////////////////////////////////////////////////
2289/// write the inverse matrix to a file
2290
2292{
2293 auto cache = this->getCache();
2294 if (!cache)
2295 return false;
2296 writeMatrixToFileT(cache->_inverse, filename);
2297 return true;
2298}
2299
2300////////////////////////////////////////////////////////////////////////////////
2301/// retrieve the cache object
2302
2304{
2305 auto cache = static_cast<RooLagrangianMorphFunc::CacheElem *>(
2306 _cacheMgr.getObj(nullptr, static_cast<RooArgSet const *>(nullptr)));
2307 if (!cache) {
2308 cxcoutP(Caching) << "creating cache from getCache function for " << this << std::endl;
2309 cxcoutP(Caching) << "current storage has size " << _sampleMap.size() << std::endl;
2311 if (cache) {
2312 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
2313 } else {
2314 coutE(Caching) << "unable to create cache!" << std::endl;
2315 }
2316 }
2317 return cache;
2318}
2319
2320////////////////////////////////////////////////////////////////////////////////
2321/// return true if a cache object is present, false otherwise
2322
2324{
2325 return (bool)(_cacheMgr.getObj(nullptr, static_cast<RooArgSet *>(nullptr)));
2326}
2327
2328////////////////////////////////////////////////////////////////////////////////
2329/// set one parameter to a specific value
2330
2332{
2333 RooRealVar *param = this->getParameter(name);
2334 if (!param) {
2335 return;
2336 }
2337 if (value > param->getMax())
2338 param->setMax(value);
2339 if (value < param->getMin())
2340 param->setMin(value);
2341 param->setVal(value);
2342}
2343
2344////////////////////////////////////////////////////////////////////////////////
2345/// set one flag to a specific value
2346
2348{
2349 RooRealVar *param = this->getFlag(name);
2350 if (!param) {
2351 return;
2352 }
2353 param->setVal(value);
2354}
2355
2356////////////////////////////////////////////////////////////////////////////////
2357/// set one parameter to a specific value and range
2358
2359void RooLagrangianMorphFunc::setParameter(const char *name, double value, double min, double max)
2360{
2361 RooRealVar *param = this->getParameter(name);
2362 if (!param) {
2363 return;
2364 }
2365 param->setMin(min);
2366 param->setMax(max);
2367 param->setVal(value);
2368}
2369
2370////////////////////////////////////////////////////////////////////////////////
2371/// set one parameter to a specific value and range
2372void RooLagrangianMorphFunc::setParameter(const char *name, double value, double min, double max, double error)
2373{
2374 RooRealVar *param = this->getParameter(name);
2375 if (!param) {
2376 return;
2377 }
2378 param->setMin(min);
2379 param->setMax(max);
2380 param->setVal(value);
2381 param->setError(error);
2382}
2383
2384////////////////////////////////////////////////////////////////////////////////
2385/// return true if the parameter with the given name is set constant, false
2386/// otherwise
2387
2389{
2390 RooRealVar *param = this->getParameter(name);
2391 if (param) {
2392 return param->isConstant();
2393 }
2394 return true;
2395}
2396
2397////////////////////////////////////////////////////////////////////////////////
2398/// retrieve the RooRealVar object incorporating the parameter with the given
2399/// name
2401{
2402
2403 return dynamic_cast<RooRealVar *>(_operators.find(name));
2404}
2405
2406////////////////////////////////////////////////////////////////////////////////
2407/// retrieve the RooRealVar object incorporating the flag with the given name
2408
2410{
2411 return dynamic_cast<RooRealVar *>(_flags.find(name));
2412}
2413
2414////////////////////////////////////////////////////////////////////////////////
2415/// check if a parameter of the given name is contained in the list of known
2416/// parameters
2417
2419{
2420 return this->getParameter(name);
2421}
2422
2423////////////////////////////////////////////////////////////////////////////////
2424/// call setConstant with the boolean argument provided on the parameter with
2425/// the given name
2426
2428{
2429 RooRealVar *param = this->getParameter(name);
2430 if (param) {
2431 return param->setConstant(constant);
2432 }
2433}
2434
2435////////////////////////////////////////////////////////////////////////////////
2436/// set one parameter to a specific value
2437
2439{
2440 RooRealVar *param = this->getParameter(name);
2441 if (param) {
2442 return param->getVal();
2443 }
2444 return 0.0;
2445}
2446
2447////////////////////////////////////////////////////////////////////////////////
2448/// set the morphing parameters to those supplied in the given param hist
2449
2454
2455////////////////////////////////////////////////////////////////////////////////
2456/// set the morphing parameters to those supplied in the sample with the given
2457/// name
2458
2460{
2461 std::string filename = _config.fileName;
2462 TDirectory *file = openFile(filename);
2463 auto paramhist = loadFromFileResidentFolder<TH1>(file, foldername, "param_card");
2464 setParams(paramhist.get(), _operators, false);
2465 closeFile(file);
2466}
2467
2468/////////////////////////////////////////////////////////////////////////////////
2469/// retrieve the morphing parameters associated to the sample with the given
2470/// name
2471
2477
2478////////////////////////////////////////////////////////////////////////////////
2479/// set the morphing parameters to those supplied in the list with the given
2480/// name
2481
2483{
2484 for (auto *param : dynamic_range_cast<RooRealVar *>(*list)) {
2485 if (!param)
2486 continue;
2487 this->setParameter(param->GetName(), param->getVal());
2488 }
2489}
2490
2491////////////////////////////////////////////////////////////////////////////////
2492/// retrieve the histogram observable
2493
2495{
2496 if (_observables.empty()) {
2497 coutE(InputArguments) << "observable not available!" << std::endl;
2498 return nullptr;
2499 }
2500 return static_cast<RooRealVar *>(_observables.at(0));
2501}
2502
2503////////////////////////////////////////////////////////////////////////////////
2504/// retrieve the histogram observable
2505
2507{
2508 if (_binWidths.empty()) {
2509 coutE(InputArguments) << "bin width not available!" << std::endl;
2510 return nullptr;
2511 }
2512 return static_cast<RooRealVar *>(_binWidths.at(0));
2513}
2514
2515////////////////////////////////////////////////////////////////////////////////
2516/// retrieve a histogram output of the current morphing settings
2517
2519{
2520 return this->createTH1(name, false);
2521}
2522
2523////////////////////////////////////////////////////////////////////////////////
2524/// retrieve a histogram output of the current morphing settings
2525
2527{
2528 auto mf = std::make_unique<RooRealSumFunc>(*(this->getFunc()));
2529 RooRealVar *observable = this->getObservable();
2530
2531 const int nbins = observable->getBins();
2532
2533 auto hist = std::make_unique<TH1F>(name.c_str(), name.c_str(), nbins, observable->getBinning().array());
2534
2535 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2536 for (int i = 0; i < nbins; ++i) {
2537 observable->setBin(i);
2538 double val = 0;
2539 double unc2 = 0;
2540 double unc = 0;
2541 for (auto *prod : dynamic_range_cast<RooProduct *>(*args)) {
2542 if (!prod)
2543 continue;
2544 RooAbsArg *phys = prod->components().find(Form("phys_%s", prod->GetName()));
2545 RooHistFunc *hf = dynamic_cast<RooHistFunc *>(phys);
2546 if (!hf) {
2547 continue;
2548 }
2549 const RooDataHist &dhist = hf->dataHist();
2550 RooAbsReal *formula = dynamic_cast<RooAbsReal *>(prod->components().find(Form("w_%s", prod->GetName())));
2551 double weight = formula->getVal();
2552 const double w2 = dhist.weightSquared(i);
2553 unc2 += w2 * weight * weight;
2554 unc += sqrt(w2) * weight;
2555 val += dhist.weight(i) * weight;
2556 }
2557 hist->SetBinContent(i + 1, val);
2558 hist->SetBinError(i + 1, correlateErrors ? unc : sqrt(unc2));
2559 }
2560 return hist.release();
2561}
2562
2563////////////////////////////////////////////////////////////////////////////////
2564/// count the number of formulas that correspond to the current parameter set
2565
2567{
2568 int nFormulas = 0;
2569 auto mf = std::make_unique<RooRealSumFunc>(*(this->getFunc()));
2570 if (!mf)
2571 coutE(InputArguments) << "unable to retrieve morphing function" << std::endl;
2572 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2573 for (auto *prod : dynamic_range_cast<RooProduct *>(*args)) {
2574 if (prod->getVal() != 0) {
2575 nFormulas++;
2576 }
2577 }
2578 return nFormulas;
2579}
2580
2581////////////////////////////////////////////////////////////////////////////////
2582/// check if there is any morphing power provided for the given parameter
2583/// morphing power is provided as soon as any two samples provide different,
2584/// non-zero values for this parameter
2585
2587{
2588 std::string pname(paramname);
2589 double val = 0;
2590 bool isUsed = false;
2591 for (const auto &sample : _config.paramCards) {
2592 double thisval = sample.second.at(pname);
2593 if (thisval != val) {
2594 if (val != 0)
2595 isUsed = true;
2596 val = thisval;
2597 }
2598 }
2599 return isUsed;
2600}
2601
2602////////////////////////////////////////////////////////////////////////////////
2603/// check if there is any morphing power provided for the given coupling
2604/// morphing power is provided as soon as any two samples provide
2605/// different, non-zero values for this coupling
2606
2608{
2609 std::string cname(couplname);
2610 const RooArgList *args = this->getCouplingSet();
2611 RooAbsReal *coupling = dynamic_cast<RooAbsReal *>(args->find(couplname));
2612 if (!coupling)
2613 return false;
2615 double val = 0;
2616 bool isUsed = false;
2617 for (const auto &sample : _config.paramCards) {
2618 this->setParameters(sample.second);
2619 double thisval = coupling->getVal();
2620 if (thisval != val) {
2621 if (val != 0)
2622 isUsed = true;
2623 val = thisval;
2624 }
2625 }
2626 this->setParameters(params);
2627 return isUsed;
2628}
2629
2630////////////////////////////////////////////////////////////////////////////////
2631/// return the number of parameters in this morphing function
2632
2634{
2635 return this->getParameterSet()->size();
2636}
2637
2638////////////////////////////////////////////////////////////////////////////////
2639/// return the number of samples in this morphing function
2640
2642{
2643 // return the number of samples in this morphing function
2644 auto cache = getCache();
2645 return cache->_formulas.size();
2646}
2647
2648////////////////////////////////////////////////////////////////////////////////
2649/// print the contributing samples and their respective weights
2650
2652{
2653 auto mf = std::make_unique<RooRealSumFunc>(*(this->getFunc()));
2654 if (!mf) {
2655 std::cerr << "Error: unable to retrieve morphing function" << std::endl;
2656 return;
2657 }
2658 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2659 for (auto *formula : dynamic_range_cast<RooAbsReal*>(*args)) {
2660 if (formula) {
2661 TString name(formula->GetName());
2662 name.Remove(0, 2);
2663 name.Prepend("phys_");
2664 if (!args->find(name.Data())) {
2665 continue;
2666 }
2667 double val = formula->getVal();
2668 if (val != 0) {
2669 std::cout << formula->GetName() << ": " << val << " = " << formula->GetTitle() << std::endl;
2670 }
2671 }
2672 }
2673}
2674
2675////////////////////////////////////////////////////////////////////////////////
2676/// get the set of parameters
2677
2679{
2680 return &(_operators);
2681}
2682
2683////////////////////////////////////////////////////////////////////////////////
2684/// get the set of couplings
2685
2687{
2688 auto cache = getCache();
2689 return &(cache->_couplings);
2690}
2691
2692////////////////////////////////////////////////////////////////////////////////
2693/// retrieve a set of couplings (-?-)
2694
2696{
2698 for (auto *var : dynamic_range_cast<RooAbsReal *>(*(this->getCouplingSet()))) {
2699 if (!var)
2700 continue;
2701 const std::string name(var->GetName());
2702 double val = var->getVal();
2703 couplings[name] = val;
2704 }
2705 return couplings;
2706}
2707
2708////////////////////////////////////////////////////////////////////////////////
2709/// retrieve the parameter set
2710
2715
2716////////////////////////////////////////////////////////////////////////////////
2717/// retrieve a set of couplings (-?-)
2718
2720{
2721 setParams(params, _operators, false);
2722}
2723
2724////////////////////////////////////////////////////////////////////////////////
2725/// (currently similar to cloning the Pdf
2726
2727std::unique_ptr<RooWrapperPdf> RooLagrangianMorphFunc::createPdf() const
2728{
2729 auto cache = getCache();
2730 auto func = std::make_unique<RooRealSumFunc>(*(cache->_sumFunc));
2731
2732 // create a wrapper on the roorealsumfunc
2733 return std::make_unique<RooWrapperPdf>(Form("pdf_%s", func->GetName()), Form("pdf of %s", func->GetTitle()), *func);
2734}
2735
2736////////////////////////////////////////////////////////////////////////////////
2737/// get the func
2738
2740{
2741 auto cache = getCache();
2742 return cache->_sumFunc.get();
2743}
2744
2745////////////////////////////////////////////////////////////////////////////////
2746/// return extended mored capabilities
2747
2749{
2750 return this->createPdf()->extendMode();
2751}
2752
2753////////////////////////////////////////////////////////////////////////////////
2754/// return expected number of events for extended likelihood calculation,
2755/// this is the sum of all coefficients
2756
2758{
2759 return this->createPdf()->expectedEvents(nset);
2760}
2761
2762////////////////////////////////////////////////////////////////////////////////
2763/// return the number of expected events for the current parameter set
2764
2766{
2767 RooArgSet set;
2768 set.add(*this->getObservable());
2769 return this->createPdf()->expectedEvents(set);
2770}
2771
2772////////////////////////////////////////////////////////////////////////////////
2773/// return expected number of events for extended likelihood calculation,
2774/// this is the sum of all coefficients
2775
2777{
2778 return createPdf()->expectedEvents(&nset);
2779}
2780
2781////////////////////////////////////////////////////////////////////////////////
2782/// return the expected uncertainty for the current parameter set
2783
2785{
2786 RooRealVar *observable = this->getObservable();
2787 auto cache = this->getCache();
2788 double unc2 = 0;
2789 for (const auto &sample : _sampleMap) {
2790 RooAbsArg *phys = _physics.at(sample.second);
2791 auto weightName = std::string("w_") + sample.first + "_" + this->GetName();
2792 auto weight = static_cast<RooAbsReal *>(cache->_weights.find(weightName.c_str()));
2793 if (!weight) {
2794 coutE(InputArguments) << "unable to find object " + weightName << std::endl;
2795 return 0.0;
2796 }
2797 double newunc2 = 0;
2798 RooHistFunc *hf = dynamic_cast<RooHistFunc *>(phys);
2799 RooRealVar *rv = dynamic_cast<RooRealVar *>(phys);
2800 if (hf) {
2801 const RooDataHist &hist = hf->dataHist();
2802 for (Int_t j = 0; j < observable->getBins(); ++j) {
2803 newunc2 += hist.weightSquared(j);
2804 }
2805 } else if (rv) {
2806 newunc2 = pow(rv->getError(), 2);
2807 }
2808 double w = weight->getVal();
2809 unc2 += newunc2 * w * w;
2810 // std::cout << phys->GetName() << " : " << weight->GetName() << "
2811 // thisweight: " << w << " thisxsec2: " << newunc2 << " weight " << weight
2812 // << std::endl;
2813 }
2814 return sqrt(unc2);
2815}
2816
2817////////////////////////////////////////////////////////////////////////////////
2818/// print the parameters and their current values
2819
2821{
2822 // print the parameters and their current values
2823 for (auto *param : static_range_cast<RooRealVar *>(_operators)) {
2824 if (!param)
2825 continue;
2826 param->Print();
2827 }
2828}
2829
2830////////////////////////////////////////////////////////////////////////////////
2831/// print the flags and their current values
2832
2834{
2835 for (auto *param : static_range_cast<RooRealVar *>(_flags)) {
2836 if (!param)
2837 continue;
2838 param->Print();
2839 }
2840}
2841
2842////////////////////////////////////////////////////////////////////////////////
2843/// print a set of couplings
2844
2846{
2848 for (auto c : couplings) {
2849 std::cout << c.first << ": " << c.second << std::endl;
2850 }
2851}
2852
2853////////////////////////////////////////////////////////////////////////////////
2854/// retrieve the list of bin boundaries
2855
2856std::list<double> *RooLagrangianMorphFunc::binBoundaries(RooAbsRealLValue &obs, double xlo, double xhi) const
2857{
2858 return this->getFunc()->binBoundaries(obs, xlo, xhi);
2859}
2860
2861////////////////////////////////////////////////////////////////////////////////
2862/// retrieve the sample Hint
2863
2864std::list<double> *RooLagrangianMorphFunc::plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const
2865{
2866 return this->getFunc()->plotSamplingHint(obs, xlo, xhi);
2867}
2868
2869////////////////////////////////////////////////////////////////////////////////
2870/// call getVal on the internal function
2871
2873{
2874 // call getVal on the internal function
2875 const RooRealSumFunc *pdf = this->getFunc();
2877 for (auto &obs : _observables) {
2878 nSet.add(*obs);
2879 }
2880 if (pdf) {
2881 return _scale * pdf->getVal(&nSet);
2882 } else {
2883 std::cerr << "unable to acquire in-built function!" << std::endl;
2884 }
2885 return 0.;
2886}
2887
2888////////////////////////////////////////////////////////////////////////////////
2889/// check if this PDF is a binned distribution in the given observable
2890
2892{
2893 return this->getFunc()->isBinnedDistribution(obs);
2894}
2895
2896////////////////////////////////////////////////////////////////////////////////
2897/// check if observable exists in the RooArgSet (-?-)
2898
2900{
2901 return this->getFunc()->checkObservables(nset);
2902}
2903
2904////////////////////////////////////////////////////////////////////////////////
2905/// Force analytical integration for the given observable
2906
2908{
2909 return this->getFunc()->forceAnalyticalInt(arg);
2910}
2911
2912////////////////////////////////////////////////////////////////////////////////
2913/// Retrieve the mat
2914
2920
2921////////////////////////////////////////////////////////////////////////////////
2922/// Retrieve the matrix of coefficients
2923
2925{
2926 return this->getFunc()->analyticalIntegralWN(code, normSet, rangeName);
2927}
2928
2929////////////////////////////////////////////////////////////////////////////////
2930/// Retrieve the matrix of coefficients
2931
2932void RooLagrangianMorphFunc::printMetaArgs(std::ostream &os) const
2933{
2934 return this->getFunc()->printMetaArgs(os);
2935}
2936
2937////////////////////////////////////////////////////////////////////////////////
2938/// Retrieve the matrix of coefficients
2939
2941{
2942 auto cache = getCache();
2943 if (!cache)
2944 coutE(Caching) << "unable to retrieve cache!" << std::endl;
2945 return makeRootMatrix(cache->_matrix);
2946}
2947
2948////////////////////////////////////////////////////////////////////////////////
2949/// Retrieve the matrix of coefficients after inversion
2950
2952{
2953 auto cache = getCache();
2954 if (!cache)
2955 coutE(Caching) << "unable to retrieve cache!" << std::endl;
2956 return makeRootMatrix(cache->_inverse);
2957}
2958
2959////////////////////////////////////////////////////////////////////////////////
2960/// Retrieve the condition of the coefficient matrix. If the condition number
2961/// is very large, then the matrix is ill-conditioned and is almost singular.
2962/// The computation of the inverse is prone to large numerical errors
2963
2965{
2966 auto cache = getCache();
2967 if (!cache)
2968 coutE(Caching) << "unable to retrieve cache!" << std::endl;
2969 return cache->_condition;
2970}
2971
2972////////////////////////////////////////////////////////////////////////////////
2973/// Return the RooRatio form of products and denominators of morphing functions
2974
2975std::unique_ptr<RooRatio>
2977{
2978 RooArgList num;
2980 for (auto it : nr) {
2981 num.add(*it);
2982 }
2983 for (auto it : dr) {
2984 denom.add(*it);
2985 }
2986 // same for denom
2987 return make_unique<RooRatio>(name, title, num, denom);
2988}
2989
2990// Register the factory interface
2991
2992namespace {
2993
2994// Helper function for factory interface
2995std::vector<std::string> asStringV(std::string const &arg)
2996{
2997 std::vector<std::string> out;
2998
2999 for (std::string &tok : ROOT::Split(arg, ",{}", true)) {
3000 if (tok[0] == '\'') {
3001 out.emplace_back(tok.substr(1, tok.size() - 2));
3002 } else {
3003 throw std::runtime_error("Strings in factory expressions need to be in single quotes!");
3004 }
3005 }
3006
3007 return out;
3008}
3009
3010class LMIFace : public RooFactoryWSTool::IFace {
3011public:
3012 std::string
3013 create(RooFactoryWSTool &, const char *typeName, const char *instName, std::vector<std::string> args) override;
3014};
3015
3016std::string LMIFace::create(RooFactoryWSTool &ft, const char * /*typeName*/, const char *instanceName,
3017 std::vector<std::string> args)
3018{
3019 // Perform syntax check. Warn about any meta parameters other than the ones needed
3020 const std::array<std::string, 4> funcArgs{{"fileName", "observableName", "couplings", "folders"}};
3021 std::map<string, string> mappedInputs;
3022
3023 for (unsigned int i = 1; i < args.size(); i++) {
3024 if (args[i].find("$fileName(") != 0 && args[i].find("$observableName(") != 0 &&
3025 args[i].find("$couplings(") != 0 && args[i].find("$folders(") != 0 && args[i].find("$NewPhysics(") != 0) {
3026 throw std::string(Form("%s::create() ERROR: unknown token %s encountered", instanceName, args[i].c_str()));
3027 }
3028 }
3029
3030 for (unsigned int i = 0; i < args.size(); i++) {
3031 if (args[i].find("$NewPhysics(") == 0) {
3032 vector<string> subargs = ft.splitFunctionArgs(args[i].c_str());
3033 for (const auto &subarg : subargs) {
3034 std::vector<std::string> parts = ROOT::Split(subarg, "=");
3035 if (parts.size() == 2) {
3036 ft.ws().arg(parts[0])->setAttribute("NewPhysics", atoi(parts[1].c_str()));
3037 } else {
3038 throw std::string(Form("%s::create() ERROR: unknown token %s encountered, check input provided for %s",
3039 instanceName, subarg.c_str(), args[i].c_str()));
3040 }
3041 }
3042 } else {
3043 std::vector<string> subargs = ft.splitFunctionArgs(args[i].c_str());
3044 if (subargs.size() == 1) {
3045 string expr = ft.processExpression(subargs[0].c_str());
3046 for (auto const &param : funcArgs) {
3047 if (args[i].find(param) != string::npos)
3048 mappedInputs[param] = subargs[0];
3049 }
3050 } else {
3051 throw std::string(
3052 Form("Incorrect number of arguments in %s, have %d, expect 1", args[i].c_str(), (Int_t)subargs.size()));
3053 }
3054 }
3055 }
3056
3058 config.fileName = asStringV(mappedInputs["fileName"])[0];
3059 config.observableName = asStringV(mappedInputs["observableName"])[0];
3060 config.folderNames = asStringV(mappedInputs["folders"]);
3061 config.couplings.add(ft.asLIST(mappedInputs["couplings"].c_str()));
3062
3064
3065 return instanceName;
3066}
3067
3068static Int_t init();
3069
3070int dummy = init();
3071
3072Int_t init()
3073{
3074 RooFactoryWSTool::IFace *iface = new LMIFace;
3075 RooFactoryWSTool::registerSpecial("lagrangianmorph", iface);
3076 (void)dummy;
3077 return 0;
3078}
3079
3080} // namespace
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
RooCollectionProxy< RooArgList > RooListProxy
Definition RooAbsArg.h:51
ROOT::RRangeCast< T, true, Range_t > dynamic_range_cast(Range_t &&coll)
size_t size< TMatrixD >(const TMatrixD &mat)
void writeMatrixToStreamT(const MatrixT &matrix, std::ostream &stream)
write a matrix to a stream
TMatrixD Matrix
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
static constexpr double morphUnityDeviation
Matrix makeSuperMatrix(const TMatrixD &in)
convert a TMatrixD into a Matrix
static constexpr double morphLargestWeight
void writeMatrixToFileT(const MatrixT &matrix, const char *fname)
write a matrix to a text file
double invertMatrix(const Matrix &matrix, Matrix &inverse)
#define NaN
TMatrixD makeRootMatrix(const Matrix &in)
convert a matrix into a TMatrixD
Matrix diagMatrix(size_t n)
create a new diagonal matrix of size n
void printMatrix(const TMatrixD &mat)
write a matrix
#define oocxcoutW(o, a)
#define coutW(a)
#define oocxcoutP(o, a)
#define coutE(a)
#define cxcoutP(a)
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:385
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char cname
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:142
TMatrixT< Double_t > TMatrixD
Definition TMatrixDfwd.h:23
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2570
std::string & operator+=(std::string &left, const TString &right)
Definition TString.h:496
TTime operator*(const TTime &t1, const TTime &t2)
Definition TTime.h:85
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
bool isConstant() const
Check if the "Constant" attribute is set.
Definition RooAbsArg.h:283
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
Abstract base class for objects to be stored in RooAbsCache cache manager objects.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
Int_t numBins(const char *rangeName=nullptr) const override
virtual Int_t getBins(const char *name=nullptr) const
Get number of bins of currently defined range.
void setConstant(bool value=true)
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
void setBin(Int_t ibin, const char *rangeName=nullptr) override
Set value to center of bin 'ibin' of binning 'rangeName' (or of default binning if no range is specif...
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition RooArgList.h:110
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Implements a RooAbsBinning in terms of an array of boundary values, posing no constraints on the choi...
Definition RooBinning.h:27
Int_t setObj(const RooArgSet *nset, T *obj, const TNamed *isetRangeName=nullptr)
Setter function without integration set.
T * getObj(const RooArgSet *nset, Int_t *sterileIndex=nullptr, const TNamed *isetRangeName=nullptr)
Getter function without integration set.
bool addOwned(RooAbsArg &var, bool silent=false) override
Overloaded RooCollection_t::addOwned() method insert object into owning set and registers object as s...
bool add(const RooAbsArg &var, bool valueServer, bool shapeServer, bool silent)
Overloaded RooCollection_t::add() method insert object into set and registers object as server to own...
Container class to hold N-dimensional binned data.
Definition RooDataHist.h:40
double weightSquared(std::size_t i) const
Return squared weight sum of i-th bin.
Implementation detail of the RooWorkspace.
static void registerSpecial(const char *typeName, RooFactoryWSTool::IFace *iface)
Register foreign special objects in factory.
A real-valued function sampled from a multidimensional histogram.
Definition RooHistFunc.h:29
static TClass * Class()
static RooLagrangianMorphFunc::CacheElem * createCache(const RooLagrangianMorphFunc *func)
create all the temporary objects required by the class
void buildMatrix(const RooLagrangianMorphFunc::ParamMap &inputParameters, const RooLagrangianMorphFunc::FlagMap &inputFlags, const List &flags)
build and invert the morphing matrix
static RooLagrangianMorphFunc::CacheElem * createCache(const RooLagrangianMorphFunc *func, const Matrix &inverse)
create all the temporary objects required by the class function variant with precomputed inverse matr...
std::unique_ptr< RooRealSumFunc > _sumFunc
RooArgList containedArgs(Action) override
retrieve the list of contained args
void operModeHook(RooAbsArg::OperMode) override
Interface for changes of operation mode.
void createComponents(const RooLagrangianMorphFunc::ParamMap &inputParameters, const RooLagrangianMorphFunc::FlagMap &inputFlags, const char *funcname, const std::vector< std::vector< RooListProxy * > > &diagramProxyList, const std::vector< std::vector< std::string > > &nonInterfering, const RooArgList &flags)
create the basic objects required for the morphing
void buildMorphingFunction(const char *name, const RooLagrangianMorphFunc::ParamMap &inputParameters, const std::map< std::string, int > &storage, const RooArgList &physics, bool allowNegativeYields, RooRealVar *observable, RooRealVar *binWidth)
build the final morphing function
Class RooLagrangianMorphing is a implementation of the method of Effective Lagrangian Morphing,...
bool isParameterConstant(const char *paramname) const
return true if the parameter with the given name is set constant, false otherwise
bool isBinnedDistribution(const RooArgSet &obs) const override
check if this PDF is a binned distribution in the given observable
int nPolynomials() const
return the number of samples in this morphing function
void setParameter(const char *name, double value)
set one parameter to a specific value
RooArgSet createWeights(const ParamMap &inputs, const std::vector< RooArgList * > &vertices, RooArgList &couplings, const FlagMap &inputFlags, const RooArgList &flags, const std::vector< std::vector< std::string > > &nonInterfering)
create only the weight formulas. static function for external usage.
ParamSet getMorphParameters() const
retrieve the parameter set
double evaluate() const override
call getVal on the internal function
void disableInterference(const std::vector< const char * > &nonInterfering)
disable interference between terms
RooProduct * getSumElement(const char *name) const
return the RooProduct that is the element of the RooRealSumPdfi corresponding to the given sample nam...
RooRealVar * getBinWidth() const
retrieve the histogram observable
void writeMatrixToFile(const TMatrixD &matrix, const char *fname)
write a matrix to a file
RooRealVar * getParameter(const char *name) const
retrieve the RooRealVar object incorporating the parameter with the given name
bool useCoefficients(const TMatrixD &inverse)
setup the morphing function with a predefined inverse matrix call this function before any other afte...
const RooArgSet * getParameterSet() const
get the set of parameters
TMatrixD readMatrixFromStream(std::istream &stream)
read a matrix from a stream
std::vector< std::vector< std::string > > _nonInterfering
std::vector< std::string > getSamples() const
return the vector of sample names, used to build the morph func
int countSamples(std::vector< RooArgList * > &vertices)
calculate the number of samples needed to morph a certain physics process
ParamSet getCouplings() const
retrieve a set of couplings (-?-)
void printSampleWeights() const
print the current sample weights
std::map< const std::string, double > ParamSet
void writeMatrixToStream(const TMatrixD &matrix, std::ostream &stream)
write a matrix to a stream
std::map< const std::string, ParamSet > ParamMap
bool updateCoefficients()
Retrieve the new physics objects and update the weights in the morphing function.
RooRealVar * getObservable() const
retrieve the histogram observable
int countContributingFormulas() const
count the number of formulas that correspond to the current parameter set
std::list< double > * plotSamplingHint(RooAbsRealLValue &, double, double) const override
retrieve the sample Hint
RooRealVar * getFlag(const char *name) const
retrieve the RooRealVar object incorporating the flag with the given name
void randomizeParameters(double z)
randomize the parameters a bit useful to test and debug fitting
bool isCouplingUsed(const char *couplname)
check if there is any morphing power provided for the given coupling morphing power is provided as so...
void readParameters(TDirectory *f)
read the parameters from the input file
double getScale()
get energy scale of the EFT expansion
double getCondition() const
Retrieve the condition of the coefficient matrix.
TMatrixD getMatrix() const
Retrieve the matrix of coefficients.
void printWeights() const
print the current sample weights
void printCouplings() const
print a set of couplings
TMatrixD readMatrixFromFile(const char *fname)
read a matrix from a text file
~RooLagrangianMorphFunc() override
default destructor
void printParameters() const
print the parameters and their current values
void printPhysics() const
print the current physics values
static std::unique_ptr< RooRatio > makeRatio(const char *name, const char *title, RooArgList &nr, RooArgList &dr)
Return the RooRatio form of products and denominators of morphing functions.
void setFlag(const char *name, double value)
set one flag to a specific value
TH1 * createTH1(const std::string &name)
retrieve a histogram output of the current morphing settings
double expectedUncertainty() const
return the expected uncertainty for the current parameter set
int nParameters() const
return the number of parameters in this morphing function
bool hasParameter(const char *paramname) const
check if a parameter of the given name is contained in the list of known parameters
bool checkObservables(const RooArgSet *nset) const override
check if observable exists in the RooArgSet (-?-)
bool hasCache() const
return true if a cache object is present, false otherwise
void printFlags() const
print the flags and their current values
void setScale(double val)
set energy scale of the EFT expansion
TMatrixD getInvertedMatrix() const
Retrieve the matrix of coefficients after inversion.
double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Retrieve the matrix of coefficients.
void updateSampleWeights()
update sample weight (-?-)
void setParameters(const char *foldername)
set the morphing parameters to those supplied in the sample with the given name
RooObjCacheManager _cacheMgr
! The cache manager
bool isParameterUsed(const char *paramname) const
check if there is any morphing power provided for the given parameter morphing power is provided as s...
RooAbsPdf::ExtendMode extendMode() const
return extended mored capabilities
std::map< const std::string, FlagSet > FlagMap
bool forceAnalyticalInt(const RooAbsArg &arg) const override
Force analytical integration for the given observable.
void setParameterConstant(const char *paramname, bool constant) const
call setConstant with the boolean argument provided on the parameter with the given name
void disableInterferences(const std::vector< std::vector< const char * > > &nonInterfering)
disable interference between terms
void printSamples() const
print all the known samples to the console
double getParameterValue(const char *name) const
set one parameter to a specific value
void setup(bool ownParams=true)
setup this instance with the given set of operators and vertices if own=true, the class will own the ...
void printMetaArgs(std::ostream &os) const override
Retrieve the matrix of coefficients.
std::unique_ptr< RooWrapperPdf > createPdf() const
(currently similar to cloning the Pdf
RooAbsReal * getSampleWeight(const char *name)
retrieve the weight (prefactor) of a sample with the given name
std::map< std::string, std::string > createWeightStrings(const ParamMap &inputs, const std::vector< std::vector< std::string > > &vertices)
create only the weight formulas. static function for external usage.
Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &numVars, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Retrieve the mat.
std::vector< std::vector< RooListProxy * > > _diagrams
double expectedEvents() const
return the number of expected events for the current parameter set
std::map< std::string, int > _sampleMap
RooLagrangianMorphFunc::CacheElem * getCache() const
retrieve the cache object
RooRealVar * setupObservable(const char *obsname, TClass *mode, TObject *inputExample)
setup observable, recycle existing observable if defined
const RooArgList * getCouplingSet() const
get the set of couplings
RooRealSumFunc * getFunc() const
get the func
std::list< double > * binBoundaries(RooAbsRealLValue &, double, double) const override
retrieve the list of bin boundaries
void printEvaluation() const
print the contributing samples and their respective weights
bool writeCoefficients(const char *filename)
write the inverse matrix to a file
void collectInputs(TDirectory *f)
retrieve the physics inputs
void init()
initialise inputs required for the morphing function
RooLinearCombination is a class that helps perform linear combination of floating point numbers and p...
A histogram function that assigns scale parameters to every bin.
static TClass * Class()
Represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
std::list< double > * binBoundaries(RooAbsRealLValue &, double, double) const override
Retrieve bin boundaries if this distribution is binned in obs.
void printMetaArgs(std::ostream &os) const override
Customized printing of arguments of a RooRealSumFunc to more intuitively reflect the contents of the ...
Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &numVars, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Variant of getAnalyticalIntegral that is also passed the normalization set that should be applied to ...
double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Implements the actual analytical integral(s) advertised by getAnalyticalIntegral.
bool isBinnedDistribution(const RooArgSet &obs) const override
Tests if the distribution is binned. Unless overridden by derived classes, this always returns false.
bool checkObservables(const RooArgSet *nset) const override
Overloadable function in which derived classes can implement consistency checks of the variables.
std::list< double > * plotSamplingHint(RooAbsRealLValue &, double, double) const override
Interface for returning an optional hint for initial sampling points when constructing a curve projec...
bool forceAnalyticalInt(const RooAbsArg &arg) const override
Variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
void setError(double value)
Definition RooRealVar.h:61
void setMin(const char *name, double value, bool shared=true)
Set minimum of name range to given value.
void setBins(Int_t nBins, const char *name=nullptr, bool shared=true)
Create a uniform binning under name 'name' for this variable.
void setBinning(const RooAbsBinning &binning, const char *name=nullptr, bool shared=true)
Add given binning under name 'name' with this variable.
void setMax(const char *name, double value, bool shared=true)
Set maximum of name range to given value.
const RooAbsBinning & getBinning(const char *name=nullptr, bool verbose=true, bool createOnTheFly=false, bool shared=true) const override
Return binning definition with name.
Class to manage histogram axis.
Definition TAxis.h:32
Double_t GetXmax() const
Definition TAxis.h:142
Double_t GetXmin() const
Definition TAxis.h:141
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2999
LU Decomposition class.
Definition TDecompLU.h:24
Describe directory structure in memory.
Definition TDirectory.h:45
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
virtual Bool_t IsOpen() const
Returns kTRUE in case file is open and kFALSE if file is not open.
Definition TFile.cxx:1494
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:3801
void Close(Option_t *option="") override
Close a file.
Definition TFile.cxx:991
<div class="legacybox"><h2>Legacy Code</h2> TFolder is a legacy interface: there will be no bug fixes...
Definition TFolder.h:30
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:109
static TClass * Class()
TAxis * GetXaxis()
Definition TH1.h:571
virtual Int_t GetNbinsX() const
Definition TH1.h:541
virtual void SetBinError(Int_t bin, Double_t error)
Set the bin Error Note that this resets the bin eror option to be of Normal Type and for the non-empt...
Definition TH1.cxx:9436
virtual Double_t Integral(Option_t *option="") const
Return integral of bin contents.
Definition TH1.cxx:8170
virtual void SetBinContent(Int_t bin, Double_t content)
Set bin content see convention for numbering bins in TH1::GetBin In case the bin number is greater th...
Definition TH1.cxx:9452
virtual Double_t GetBinLowEdge(Int_t bin) const
Return bin lower edge for 1D histogram.
Definition TH1.cxx:9382
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition TH1.cxx:5239
virtual Double_t GetBinWidth(Int_t bin) const
Return bin width for 1D histogram.
Definition TH1.cxx:9393
virtual void Scale(Double_t c1=1, Option_t *option="")
Multiply this histogram by a constant c1.
Definition TH1.cxx:6815
Int_t GetNrows() const
TMatrixTBase< Element > & ResizeTo(Int_t nrows, Int_t ncols, Int_t=-1) override
Set size of the matrix to nrows x ncols New dynamic elements are created, the overlapping part of the...
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Mother of all ROOT objects.
Definition TObject.h:42
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:225
Class used by TMap to store (key,value) pairs.
Definition TMap.h:103
TObject * Value() const
Definition TMap.h:122
TObject * Key() const
Definition TMap.h:121
Random number generator class based on M.
Definition TRandom3.h:27
Basic string class.
Definition TString.h:137
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2459
TLine * line
RooCmdArg Silence(bool flag=true)
const Int_t n
Definition legend1.C:16
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
std::vector< std::string > folderNames
std::vector< std::vector< const char * > > nonInterfering
TMarker m
Definition textangle.C:8