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 }
146 writeMatrixToStreamT(matrix, of);
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
240inline RooFit::SuperFloat invertMatrix(const Matrix &matrix, Matrix &inverse)
241{
242 boost::numeric::ublas::permutation_matrix<size_t> pm(size(matrix));
243 RooFit::SuperFloat mnorm = norm_inf(matrix);
244 Matrix lu(matrix);
245 try {
246 int res = lu_factorize(lu, pm);
247 if (res != 0) {
248 std::stringstream ss;
249 ::writeMatrixToStreamT(matrix, ss);
250 cxcoutP(Eval) << ss.str << std::endl;
251 }
252 // back-substitute to get the inverse
253 lu_substitute(lu, pm, inverse);
254 } catch (boost::numeric::ublas::internal_logic &error) {
255 // coutE(Eval) << "boost::numeric::ublas error: matrix is not invertible!"
256 // << std::endl;
257 }
258 RooFit::SuperFloat inorm = norm_inf(inverse);
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{
307 TDecompLU lu(matrix);
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 }
428 MatrixT mat = readMatrixFromStreamT<MatrixT>(in);
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
456void setOwnerRecursive(TFolder *theFolder)
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
464 setOwnerRecursive(thisfolder);
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 }
485 setOwnerRecursive(theFolder.get());
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{
502 auto folder = readOwningFolderFromFile(inFile, folderName);
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{
533 auto h_pc = loadFromFileResidentFolder<TH1F>(file, name, key, notFoundError);
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
552 readValues(inputParameters[name], f, name, key, notFoundError);
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()) {
596 extractServers(*server, operators);
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
607template <class T1, class T2, typename std::enable_if<!is_specialization<T1, std::vector>::value, T1>::type * = nullptr>
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) {
613 extractServers(*itr, operators);
614 }
615}
616
617///////////////////////////////////////////////////////////////////////////////
618/// extract the operators from a list of vertices
619
620template <class T1, class T2, typename std::enable_if<is_specialization<T1, std::vector>::value, T1>::type * = nullptr>
621inline void extractOperators(const T1 &vec, T2 &operators)
622{
623 for (const auto &v : vec) {
624 extractOperators(v, operators);
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,
762 const RooLagrangianMorphFunc::ParamMap &inputParameters, bool normalize)
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,
819 const RooLagrangianMorphFunc::ParamMap &inputParameters)
820{
821 for (auto sampleit : inputParameters) {
822 const std::string sample(sampleit.first);
823 auto obj = loadFromFileResidentFolder<RooAbsReal>(file, sample, varname, true);
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,
841 const std::string &varname, const RooLagrangianMorphFunc::ParamMap &inputParameters)
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,
890 const RooLagrangianMorphFunc::ParamMap &inputParameters)
891{
892 auto pair = loadFromFileResidentFolder<TPair>(file, basefolder, varname, false);
893 if (!pair)
894 return;
895 if (dynamic_cast<TParameter<double> *>(pair->Key())) {
896 collectCrosssections<double>(name, file, list_xs, physics, varname, inputParameters);
897 } else if (dynamic_cast<TParameter<float> *>(pair->Key())) {
898 collectCrosssections<float>(name, file, list_xs, physics, varname, inputParameters);
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
914void collectPolynomialsHelper(const FeynmanDiagram &diagram, MorphFuncPattern &morphfunc, std::vector<int> &term,
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) {
924 ::collectPolynomialsHelper(diagram, morphfunc, newterm, vertexid, false);
925 } else {
926 ::collectPolynomialsHelper(diagram, morphfunc, newterm, vertexid - 1, true);
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
953void collectPolynomials(MorphFuncPattern &morphfunc, const FeynmanDiagram &diagram)
954{
955 int nvtx(diagram.size());
956 std::vector<int> term(diagram[0].size(), 0);
957
958 ::collectPolynomialsHelper(diagram, morphfunc, term, nvtx, true);
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>
990inline MatrixT buildMatrixT(const RooLagrangianMorphFunc::ParamMap &inputParameters, const FormulaList &formulas,
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{
1046 Matrix unity(inverse * matrix);
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) {
1054 largestWeight = (double)inverse(i, j);
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>
1066inline void checkNameConflict(const RooLagrangianMorphFunc::ParamMap &inputParameters, List &args)
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
1083FormulaList buildFormulas(const char *mfname, const RooLagrangianMorphFunc::ParamMap &inputParameters,
1084 const RooLagrangianMorphFunc::FlagMap &inputFlags, const MorphFuncPattern &morphfunc,
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
1099 RooArgList operators;
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()) {
1156 nInterferingOperators++;
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,
1221 const RooLagrangianMorphFunc::FlagMap &inputFlags,
1222 const std::vector<std::vector<RooArgList *>> &diagrams, RooArgList &couplings,
1223 const RooArgList &flags, const std::vector<std::vector<std::string>> &nonInterfering)
1224{
1225 MorphFuncPattern morphfuncpattern;
1226
1227 for (const auto &vertices : diagrams) {
1228 FeynmanDiagram d;
1229 ::fillFeynmanDiagram(d, vertices, couplings);
1230 ::collectPolynomials(morphfuncpattern, d);
1231 }
1232 FormulaList retval = buildFormulas(name, inputs, inputFlags, morphfuncpattern, couplings, flags, nonInterfering);
1233 if (retval.empty()) {
1234 std::stringstream errorMsgStream;
1235 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 }
1241 checkMatrix(inputs, retval);
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;
1257 TString name_full(makeValidName(sample));
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) {
1268 const RooFit::SuperFloat val(inverse(formulaidx, sampleidx));
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>
1278buildSampleWeightStrings(const RooLagrangianMorphFunc::ParamMap &inputParameters, const FormulaList &formulas,
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
1340 inline void createComponents(const RooLagrangianMorphFunc::ParamMap &inputParameters,
1341 const RooLagrangianMorphFunc::FlagMap &inputFlags, const char *funcname,
1342 const std::vector<std::vector<RooListProxy *>> &diagramProxyList,
1343 const std::vector<std::vector<std::string>> &nonInterfering, const RooArgList &flags)
1344 {
1345 RooArgList operators;
1346 std::vector<std::vector<RooArgList *>> diagrams;
1347 for (const auto &diagram : diagramProxyList) {
1348 diagrams.emplace_back();
1349 for (RooArgList *vertex : diagram) {
1350 extractCouplings(*vertex, _couplings);
1351 diagrams.back().emplace_back(vertex);
1352 }
1353 }
1354 extractOperators(_couplings, operators);
1355 _formulas = ::createFormulas(funcname, inputParameters, inputFlags, diagrams, _couplings, flags, nonInterfering);
1356 }
1357
1358 //////////////////////////////////////////////////////////////////////////////
1359 /// build and invert the morphing matrix
1360 template <class List>
1361 inline void buildMatrix(const RooLagrangianMorphFunc::ParamMap &inputParameters,
1362 const RooLagrangianMorphFunc::FlagMap &inputFlags, const List &flags)
1363 {
1364 RooArgList operators;
1365 extractOperators(_couplings, operators);
1366 Matrix matrix(buildMatrixT<Matrix>(inputParameters, _formulas, operators, inputFlags, flags));
1367 if (size(matrix) < 1) {
1368 std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl;
1369 }
1370 Matrix inverse(diagMatrix(size(matrix)));
1371
1372 double condition = (double)(invertMatrix(matrix, inverse));
1373 double unityDeviation;
1374 double largestWeight;
1375 inverseSanity(matrix, inverse, unityDeviation, 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
1422 inline void buildMorphingFunction(const char *name, const RooLagrangianMorphFunc::ParamMap &inputParameters,
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
1435 RooArgList operators;
1436 extractOperators(_couplings, operators);
1437
1438 // retrieve the weights
1439 ::buildSampleWeights(_weights, name, inputParameters, _formulas, _inverse);
1440
1441 // build the products of element and weight for each sample
1442 size_t i = 0;
1443 RooArgList sumElements;
1444 RooArgList scaleElements;
1445 for (auto sampleit : inputParameters) {
1446 // for now, we assume all the lists are nicely ordered
1447 TString prodname(makeValidName(sampleit.first));
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();
1510 RooLagrangianMorphFunc::ParamSet values = getParams(func->_operators);
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 {
1542 RooLagrangianMorphFunc::ParamSet values = getParams(func->_operators);
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
1571void RooLagrangianMorphFunc::writeMatrixToFile(const TMatrixD &matrix, const char *fname)
1572{
1573 writeMatrixToFileT(matrix, fname);
1574}
1575
1576////////////////////////////////////////////////////////////////////////////////
1577/// write a matrix to a stream
1578
1579void RooLagrangianMorphFunc::writeMatrixToStream(const TMatrixD &matrix, std::ostream &stream)
1580{
1581 writeMatrixToStreamT(matrix, stream);
1582}
1583
1584////////////////////////////////////////////////////////////////////////////////
1585/// read a matrix from a text file
1586
1588{
1589 return readMatrixFromFileT<TMatrixD>(fname);
1590}
1591
1592////////////////////////////////////////////////////////////////////////////////
1593/// read a matrix from a stream
1594
1596{
1597 return readMatrixFromStreamT<TMatrixD>(stream);
1598}
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// Support for the deprecated RooParamHistFunc, to be removed in ROOT 6.46
1614#ifdef _MSC_VER
1615#pragma warning(push)
1616#pragma warning(disable : 4996)
1617#else
1618#pragma GCC diagnostic push
1619#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1620#endif
1621 if (mode && mode->InheritsFrom(RooHistFunc::Class())) {
1622 obs = static_cast<RooRealVar *>(dynamic_cast<RooHistFunc *>(inputExample)->getHistObsList().first());
1623 obsExists = true;
1624 _observables.add(*obs);
1625 } else if (mode && mode->InheritsFrom(RooParamHistFunc::Class())) {
1626 obs = static_cast<RooRealVar *>(dynamic_cast<RooParamHistFunc *>(inputExample)->paramList().first());
1627 obsExists = true;
1628 _observables.add(*obs);
1629 }
1630#ifdef _MSC_VER
1631#pragma warning(pop)
1632#else
1633#pragma GCC diagnostic pop
1634#endif
1635
1636 // Note: "found!" will be printed if s2 is a substring of s1, both s1 and s2
1637 // are of type std::string. s1.find(s2)
1638 // obtain the observable
1639 if (!obsExists) {
1640 if (mode && mode->InheritsFrom(TH1::Class())) {
1641 TH1 *hist = static_cast<TH1 *>(inputExample);
1642 auto obsOwner =
1643 std::make_unique<RooRealVar>(obsname, obsname, hist->GetXaxis()->GetXmin(), hist->GetXaxis()->GetXmax());
1644 obs = obsOwner.get();
1645 addOwnedComponents(std::move(obsOwner));
1646 obs->setBins(hist->GetNbinsX());
1647 } else {
1648 auto obsOwner = std::make_unique<RooRealVar>(obsname, obsname, 0, 1);
1649 obs = obsOwner.get();
1650 addOwnedComponents(std::move(obsOwner));
1651 obs->setBins(1);
1652 }
1653 _observables.add(*obs);
1654 } else {
1655 if (strcmp(obsname, obs->GetName()) != 0) {
1656 coutW(ObjectHandling) << " name of existing observable " << _observables.at(0)->GetName()
1657 << " does not match expected name " << obsname << std::endl;
1658 }
1659 }
1660
1661 TString sbw = TString::Format("binWidth_%s", makeValidName(obs->GetName()).Data());
1662 auto binWidth = std::make_unique<RooRealVar>(sbw.Data(), sbw.Data(), 1.);
1663 double bw = obs->numBins() / (obs->getMax() - obs->getMin());
1664 binWidth->setVal(bw);
1665 binWidth->setConstant(true);
1666 _binWidths.addOwned(std::move(binWidth));
1667
1668 return obs;
1669}
1670
1671//#ifndef USE_MULTIPRECISION_LC
1672//#pragma GCC diagnostic push
1673//#pragma GCC diagnostic ignored "-Wunused-parameter"
1674//#endif
1675
1676////////////////////////////////////////////////////////////////////////////////
1677/// update sample weight (-?-)
1678
1680{
1681 //#ifdef USE_MULTIPRECISION_LC
1682 int sampleidx = 0;
1683 auto cache = this->getCache();
1684 const size_t n(size(cache->_inverse));
1685 for (auto sampleit : _config.paramCards) {
1686 const std::string sample(sampleit.first);
1687 // build the formula with the correct normalization
1688 RooLinearCombination *sampleformula = dynamic_cast<RooLinearCombination *>(this->getSampleWeight(sample.c_str()));
1689 if (!sampleformula) {
1690 coutE(ObjectHandling) << Form("unable to access formula for sample '%s'!", sample.c_str()) << std::endl;
1691 return;
1692 }
1693 cxcoutP(ObjectHandling) << "updating formula for sample '" << sample << "'" << std::endl;
1694 for (size_t formulaidx = 0; formulaidx < n; ++formulaidx) {
1695 const RooFit::SuperFloat val(cache->_inverse(formulaidx, sampleidx));
1696#ifdef USE_UBLAS
1697 if (val != val) {
1698#else
1699 if (std::isnan(val)) {
1700#endif
1701 coutE(ObjectHandling) << "refusing to propagate NaN!" << std::endl;
1702 }
1703 cxcoutP(ObjectHandling) << " " << formulaidx << ":" << sampleformula->getCoefficient(formulaidx) << " -> "
1704 << val << std::endl;
1705 sampleformula->setCoefficient(formulaidx, val);
1706 assert(sampleformula->getCoefficient(formulaidx) == val);
1707 }
1708 sampleformula->setValueDirty();
1709 ++sampleidx;
1710 }
1711 //#else
1712 // ERROR("updating sample weights currently not possible without boost!");
1713 //#endif
1714}
1715//#ifndef USE_MULTIPRECISION_LC
1716//#pragma GCC diagnostic pop
1717//#endif
1718
1719////////////////////////////////////////////////////////////////////////////////
1720/// read the parameters from the input file
1721
1723{
1724 readValues<double>(_config.paramCards, f, _config.folderNames, "param_card", true);
1725 readValues<int>(_config.flagValues, f, _config.folderNames, "flags", false);
1726}
1727
1728////////////////////////////////////////////////////////////////////////////////
1729/// retrieve the physics inputs
1730
1732{
1733 std::string obsName;
1734 if (_config.observable) {
1736 if (_config.observableName.empty()) {
1737 obsName = _observables.at(0)->GetName();
1738 } else {
1739 obsName = _config.observableName;
1740 }
1741 } else {
1742 obsName = _config.observableName;
1743 }
1744
1745 cxcoutP(InputArguments) << "initializing physics inputs from file " << file->GetName() << " with object name(s) '"
1746 << obsName << "'" << std::endl;
1747 auto folderNames = _config.folderNames;
1748 auto obj = loadFromFileResidentFolder<TObject>(file, folderNames.front(), obsName, true);
1749 if (!obj) {
1750 std::cerr << "unable to locate object '" << obsName << "' in folder '" << folderNames.front() << "'!"
1751 << std::endl;
1752 return;
1753 }
1754 std::string classname = obj->ClassName();
1755 TClass *mode = TClass::GetClass(obj->ClassName());
1756 this->setupObservable(obsName.c_str(), mode, obj.get());
1757
1758 if (classname.find("TH1") != std::string::npos) {
1759 collectHistograms(this->GetName(), file, _sampleMap, _physics, *static_cast<RooRealVar *>(_observables.at(0)),
1761 } else if (classname.find("RooHistFunc") != std::string::npos ||
1762 classname.find("RooParamHistFunc") != std::string::npos ||
1763 classname.find("PiecewiseInterpolation") != std::string::npos) {
1764 collectRooAbsReal(this->GetName(), file, _sampleMap, _physics, obsName, _config.paramCards);
1765 } else if (classname.find("TParameter<double>") != std::string::npos) {
1766 collectCrosssections<double>(this->GetName(), file, _sampleMap, _physics, obsName, _config.paramCards);
1767 } else if (classname.find("TParameter<float>") != std::string::npos) {
1768 collectCrosssections<float>(this->GetName(), file, _sampleMap, _physics, obsName, _config.paramCards);
1769 } else if (classname.find("TPair") != std::string::npos) {
1770 collectCrosssectionsTPair(this->GetName(), file, _sampleMap, _physics, obsName, folderNames[0],
1772 } else {
1773 std::cerr << "cannot morph objects of class '" << mode->GetName() << "'!" << std::endl;
1774 }
1775}
1776
1777////////////////////////////////////////////////////////////////////////////////
1778/// print all the parameters and their values in the given sample to the console
1779
1780void RooLagrangianMorphFunc::printParameters(const char *samplename) const
1781{
1782 for (const auto &param : _config.paramCards.at(samplename)) {
1783 if (this->hasParameter(param.first.c_str())) {
1784 std::cout << param.first << " = " << param.second;
1785 if (this->isParameterConstant(param.first.c_str()))
1786 std::cout << " (const)";
1787 std::cout << std::endl;
1788 }
1789 }
1790}
1791
1792////////////////////////////////////////////////////////////////////////////////
1793/// print all the known samples to the console
1794
1796{
1797 // print all the known samples to the console
1798 for (auto folder : _config.folderNames) {
1799 std::cout << folder << std::endl;
1800 }
1801}
1802
1803////////////////////////////////////////////////////////////////////////////////
1804/// print the current physics values
1805
1807{
1808 for (const auto &sample : _sampleMap) {
1809 RooAbsArg *phys = _physics.at(sample.second);
1810 if (!phys)
1811 continue;
1812 phys->Print();
1813 }
1814}
1815
1816////////////////////////////////////////////////////////////////////////////////
1817/// constructor with proper arguments
1818
1819RooLagrangianMorphFunc::RooLagrangianMorphFunc(const char *name, const char *title, const Config &config)
1820 : RooAbsReal(name, title), _cacheMgr(this, 10, true, true), _physics("physics", "physics", this),
1821 _operators("operators", "set of operators", this), _observables("observables", "morphing observables", this),
1822 _binWidths("binWidths", "set of binWidth objects", this), _flags("flags", "flags", this), _config(config)
1823{
1824 this->init();
1826 this->setup(false);
1827
1828}
1829
1830////////////////////////////////////////////////////////////////////////////////
1831/// setup this instance with the given set of operators and vertices
1832/// if own=true, the class will own the operators template `<class Base>`
1833
1835{
1836 if (!_config.couplings.empty()) {
1837 RooArgList operators;
1838 std::vector<RooListProxy *> vertices;
1839 extractOperators(_config.couplings, operators);
1840 vertices.push_back(new RooListProxy("!couplings", "set of couplings in the vertex", this, true, false));
1841 if (own) {
1842 _operators.addOwned(std::move(operators));
1843 vertices[0]->addOwned(_config.couplings);
1844 } else {
1845 _operators.add(operators);
1846 vertices[0]->add(_config.couplings);
1847 }
1848 _diagrams.push_back(vertices);
1849 }
1850
1852 std::vector<RooListProxy *> vertices;
1853 RooArgList operators;
1854 cxcoutP(InputArguments) << "prod/dec couplings provided" << std::endl;
1855 extractOperators(_config.prodCouplings, operators);
1856 extractOperators(_config.decCouplings, operators);
1857 vertices.push_back(
1858 new RooListProxy("!production", "set of couplings in the production vertex", this, true, false));
1859 vertices.push_back(new RooListProxy("!decay", "set of couplings in the decay vertex", this, true, false));
1860 if (own) {
1861 _operators.addOwned(std::move(operators));
1862 vertices[0]->addOwned(_config.prodCouplings);
1863 vertices[1]->addOwned(_config.decCouplings);
1864 } else {
1865 cxcoutP(InputArguments) << "adding non-own operators" << std::endl;
1866 _operators.add(operators);
1867 vertices[0]->add(_config.prodCouplings);
1868 vertices[1]->add(_config.decCouplings);
1869 }
1870 _diagrams.push_back(vertices);
1871 }
1872}
1873
1874////////////////////////////////////////////////////////////////////////////////
1875/// disable interference between terms
1876
1877void RooLagrangianMorphFunc::disableInterference(const std::vector<const char *> &nonInterfering)
1878{
1879 // disable interference between the listed operators
1880 std::stringstream name;
1881 name << "noInterference";
1882 for (auto c : nonInterfering) {
1883 name << c;
1884 }
1885 _nonInterfering.emplace_back();
1886 for (auto c : nonInterfering) {
1887 _nonInterfering.back().emplace_back(c);
1888 }
1889}
1890
1891////////////////////////////////////////////////////////////////////////////////
1892/// disable interference between terms
1893
1894void RooLagrangianMorphFunc::disableInterferences(const std::vector<std::vector<const char *>> &nonInterfering)
1895{
1896 // disable interferences between the listed groups of operators
1897 for (size_t i = 0; i < nonInterfering.size(); ++i) {
1898 this->disableInterference(nonInterfering[i]);
1899 }
1900}
1901
1902////////////////////////////////////////////////////////////////////////////////
1903/// initialise inputs required for the morphing function
1904
1906{
1907 std::string filename = _config.fileName;
1908 TDirectory *file = openFile(filename);
1909 if (!file) {
1910 coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl;
1911 return;
1912 }
1913 this->readParameters(file);
1914 checkNameConflict(_config.paramCards, _operators);
1915 this->collectInputs(file);
1916 closeFile(file);
1917 auto nNP0 = std::make_unique<RooRealVar>("nNP0", "nNP0", 1., 0, 1.);
1918 nNP0->setStringAttribute("NewPhysics", "0");
1919 nNP0->setConstant(true);
1920 _flags.addOwned(std::move(nNP0));
1921 auto nNP1 = std::make_unique<RooRealVar>("nNP1", "nNP1", 1., 0, 1.);
1922 nNP1->setStringAttribute("NewPhysics", "1");
1923 nNP1->setConstant(true);
1924 _flags.addOwned(std::move(nNP1));
1925 auto nNP2 = std::make_unique<RooRealVar>("nNP2", "nNP2", 1., 0, 1.);
1926 nNP2->setStringAttribute("NewPhysics", "2");
1927 nNP2->setConstant(true);
1928 _flags.addOwned(std::move(nNP2));
1929 auto nNP3 = std::make_unique<RooRealVar>("nNP3", "nNP3", 1., 0, 1.);
1930 nNP3->setStringAttribute("NewPhysics", "3");
1931 nNP3->setConstant(true);
1932 _flags.addOwned(std::move(nNP3));
1933 auto nNP4 = std::make_unique<RooRealVar>("nNP4", "nNP4", 1., 0, 1.);
1934 nNP4->setStringAttribute("NewPhysics", "4");
1935 nNP4->setConstant(true);
1936 _flags.addOwned(std::move(nNP4));
1937}
1938
1939////////////////////////////////////////////////////////////////////////////////
1940/// copy constructor
1941
1943 : RooAbsReal(other, name), _cacheMgr(other._cacheMgr, this), _scale(other._scale), _sampleMap(other._sampleMap),
1944 _physics(other._physics.GetName(), this, other._physics),
1945 _operators(other._operators.GetName(), this, other._operators),
1946 _observables(other._observables.GetName(), this, other._observables),
1947 _binWidths(other._binWidths.GetName(), this, other._binWidths), _flags{other._flags.GetName(), this, other._flags},
1948 _config(other._config)
1949{
1950 for (size_t j = 0; j < other._diagrams.size(); ++j) {
1951 std::vector<RooListProxy *> diagram;
1952 for (auto *elem : other._diagrams[j]) {
1953 RooListProxy *list = new RooListProxy(elem->GetName(), this, *elem);
1954 diagram.push_back(list);
1955 }
1956 _diagrams.push_back(diagram);
1957 }
1958}
1959
1960////////////////////////////////////////////////////////////////////////////////
1961/// set energy scale of the EFT expansion
1962
1964{
1965 _scale = val;
1966}
1967
1968////////////////////////////////////////////////////////////////////////////////
1969/// get energy scale of the EFT expansion
1970
1972{
1973 return _scale;
1974}
1975
1976////////////////////////////////////////////////////////////////////////////////
1977// default constructor
1978
1980 : _cacheMgr(this, 10, true, true), _operators("operators", "set of operators", this, true, false),
1981 _observables("observable", "morphing observable", this, true, false),
1982 _binWidths("binWidths", "set of bin width objects", this, true, false)
1983{
1984}
1985
1986////////////////////////////////////////////////////////////////////////////////
1987/// default destructor
1988
1990{
1991 for (auto const &diagram : _diagrams) {
1992 for (RooListProxy *vertex : diagram) {
1993 delete vertex;
1994 }
1995 }
1996}
1997
1998////////////////////////////////////////////////////////////////////////////////
1999/// calculate the number of samples needed to morph a bivertex, 2-2 physics
2000/// process
2001
2002int RooLagrangianMorphFunc::countSamples(int nprod, int ndec, int nboth)
2003{
2004 FeynmanDiagram diagram;
2005 std::vector<bool> prod;
2006 std::vector<bool> dec;
2007 for (int i = 0; i < nboth; ++i) {
2008 prod.push_back(true);
2009 dec.push_back(true);
2010 }
2011 for (int i = 0; i < nprod; ++i) {
2012 prod.push_back(true);
2013 dec.push_back(false);
2014 }
2015 for (int i = 0; i < ndec; ++i) {
2016 prod.push_back(false);
2017 dec.push_back(true);
2018 }
2019 diagram.push_back(prod);
2020 diagram.push_back(dec);
2021 MorphFuncPattern morphfuncpattern;
2022 ::collectPolynomials(morphfuncpattern, diagram);
2023 return morphfuncpattern.size();
2024}
2025
2026////////////////////////////////////////////////////////////////////////////////
2027/// calculate the number of samples needed to morph a certain physics process
2028
2029int RooLagrangianMorphFunc::countSamples(std::vector<RooArgList *> &vertices)
2030{
2031 RooArgList operators;
2032 RooArgList couplings;
2033 for (auto vertex : vertices) {
2034 extractOperators(*vertex, operators);
2035 extractCouplings(*vertex, couplings);
2036 }
2037 FeynmanDiagram diagram;
2038 ::fillFeynmanDiagram(diagram, vertices, couplings);
2039 MorphFuncPattern morphfuncpattern;
2040 ::collectPolynomials(morphfuncpattern, diagram);
2041 return morphfuncpattern.size();
2042}
2043
2044////////////////////////////////////////////////////////////////////////////////
2045/// create only the weight formulas. static function for external usage.
2046
2047std::map<std::string, std::string>
2049 const std::vector<std::vector<std::string>> &vertices_str)
2050{
2051 std::stack<RooArgList> ownedVertices;
2052 std::vector<RooArgList *> vertices;
2053 RooArgList couplings;
2054 for (const auto &vtx : vertices_str) {
2055 ownedVertices.emplace();
2056 auto &vertex = ownedVertices.top();
2057 for (const auto &c : vtx) {
2058 auto coupling = static_cast<RooRealVar *>(couplings.find(c.c_str()));
2059 if (!coupling) {
2060 auto couplingOwner = std::make_unique<RooRealVar>(c.c_str(), c.c_str(), 1., 0., 10.);
2061 coupling = couplingOwner.get();
2062 couplings.addOwned(std::move(couplingOwner));
2063 }
2064 vertex.add(*coupling);
2065 }
2066 vertices.push_back(&vertex);
2067 }
2068 auto retval = RooLagrangianMorphFunc::createWeightStrings(inputs, vertices, couplings);
2069 return retval;
2070}
2071
2072////////////////////////////////////////////////////////////////////////////////
2073/// create only the weight formulas. static function for external usage.
2074
2075std::map<std::string, std::string>
2077 const std::vector<RooArgList *> &vertices, RooArgList &couplings)
2078{
2079 return createWeightStrings(inputs, vertices, couplings, {}, {}, {});
2080}
2081
2082////////////////////////////////////////////////////////////////////////////////
2083/// create only the weight formulas. static function for external usage.
2084
2085std::map<std::string, std::string>
2087 const std::vector<RooArgList *> &vertices, RooArgList &couplings,
2088 const RooLagrangianMorphFunc::FlagMap &flagValues, const RooArgList &flags,
2089 const std::vector<std::vector<std::string>> &nonInterfering)
2090{
2091 FormulaList formulas = ::createFormulas("", inputs, flagValues, {vertices}, couplings, flags, nonInterfering);
2092 RooArgSet operators;
2093 extractOperators(couplings, operators);
2094 Matrix matrix(::buildMatrixT<Matrix>(inputs, formulas, operators, flagValues, flags));
2095 if (size(matrix) < 1) {
2096 std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl;
2097 }
2098 Matrix inverse(::diagMatrix(size(matrix)));
2099 double condition __attribute__((unused)) = (double)(invertMatrix(matrix, inverse));
2100 auto retval = buildSampleWeightStrings(inputs, formulas, inverse);
2101 return retval;
2102}
2103
2104////////////////////////////////////////////////////////////////////////////////
2105/// create only the weight formulas. static function for external usage.
2106
2108 const std::vector<RooArgList *> &vertices, RooArgList &couplings,
2109 const RooLagrangianMorphFunc::FlagMap &flagValues,
2110 const RooArgList &flags,
2111 const std::vector<std::vector<std::string>> &nonInterfering)
2112{
2113 FormulaList formulas = ::createFormulas("", inputs, flagValues, {vertices}, couplings, flags, nonInterfering);
2114 RooArgSet operators;
2115 extractOperators(couplings, operators);
2116 Matrix matrix(::buildMatrixT<Matrix>(inputs, formulas, operators, flagValues, flags));
2117 if (size(matrix) < 1) {
2118 std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl;
2119 }
2120 Matrix inverse(::diagMatrix(size(matrix)));
2121 double condition __attribute__((unused)) = (double)(invertMatrix(matrix, inverse));
2122 RooArgSet retval;
2123 ::buildSampleWeights(retval, (const char *)nullptr /* name */, inputs, formulas, inverse);
2124 return retval;
2125}
2126
2127////////////////////////////////////////////////////////////////////////////////
2128/// create only the weight formulas. static function for external usage.
2129
2131 const std::vector<RooArgList *> &vertices, RooArgList &couplings)
2132{
2133 RooArgList flags;
2134 FlagMap flagValues;
2135 return RooLagrangianMorphFunc::createWeights(inputs, vertices, couplings, flagValues, flags, {});
2136}
2137
2138////////////////////////////////////////////////////////////////////////////////
2139/// return the RooProduct that is the element of the RooRealSumPdfi
2140/// corresponding to the given sample name
2141
2143{
2144 auto mf = this->getFunc();
2145 if (!mf) {
2146 coutE(Eval) << "unable to retrieve morphing function" << std::endl;
2147 return nullptr;
2148 }
2149 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2150 TString prodname(name);
2151 prodname.Append("_");
2152 prodname.Append(this->GetName());
2153
2154 for (auto *prod : dynamic_range_cast<RooProduct *>(*args)) {
2155 if (!prod)
2156 continue;
2157 TString sname(prod->GetName());
2158 if (sname.CompareTo(prodname) == 0) {
2159 return prod;
2160 }
2161 }
2162 return nullptr;
2163}
2164////////////////////////////////////////////////////////////////////////////////
2165/// return the vector of sample names, used to build the morph func
2166
2167std::vector<std::string> RooLagrangianMorphFunc::getSamples() const
2168{
2169 return _config.folderNames;
2170}
2171
2172////////////////////////////////////////////////////////////////////////////////
2173/// retrieve the weight (prefactor) of a sample with the given name
2174
2176{
2177 auto cache = this->getCache();
2178 auto wname = std::string("w_") + name + "_" + this->GetName();
2179 return dynamic_cast<RooAbsReal *>(cache->_weights.find(wname.c_str()));
2180}
2181
2182////////////////////////////////////////////////////////////////////////////////
2183/// print the current sample weights
2184
2186{
2187 this->printSampleWeights();
2188}
2189
2190////////////////////////////////////////////////////////////////////////////////
2191/// print the current sample weights
2192
2194{
2195 auto *cache = this->getCache();
2196 for (const auto &sample : _sampleMap) {
2197 auto weightName = std::string("w_") + sample.first + "_" + this->GetName();
2198 auto weight = static_cast<RooAbsReal *>(cache->_weights.find(weightName.c_str()));
2199 if (!weight)
2200 continue;
2201 }
2202}
2203
2204////////////////////////////////////////////////////////////////////////////////
2205/// randomize the parameters a bit
2206/// useful to test and debug fitting
2207
2209{
2210 TRandom3 r;
2211
2212 for (auto *obj : dynamic_range_cast<RooRealVar *>(_operators)) {
2213 double val = obj->getVal();
2214 if (obj->isConstant())
2215 continue;
2216 double variation = r.Gaus(1, z);
2217 obj->setVal(val * variation);
2218 }
2219}
2220
2221////////////////////////////////////////////////////////////////////////////////
2222/// Retrieve the new physics objects and update the weights in the morphing
2223/// function.
2224
2226{
2227 auto cache = this->getCache();
2228
2229 std::string filename = _config.fileName;
2230 TDirectory *file = openFile(filename);
2231 if (!file) {
2232 coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl;
2233 return false;
2234 }
2235
2236 this->readParameters(file);
2237
2238 checkNameConflict(_config.paramCards, _operators);
2239 this->collectInputs(file);
2240
2241 cache->buildMatrix(_config.paramCards, _config.flagValues, _flags);
2242 this->updateSampleWeights();
2243
2244 closeFile(file);
2245 return true;
2246}
2247
2248////////////////////////////////////////////////////////////////////////////////
2249/// setup the morphing function with a predefined inverse matrix
2250/// call this function *before* any other after creating the object
2251
2253{
2254 auto cache = static_cast<RooLagrangianMorphFunc::CacheElem *>(
2255 _cacheMgr.getObj(nullptr, static_cast<RooArgSet const *>(nullptr)));
2256 Matrix m = makeSuperMatrix(inverse);
2257 if (cache) {
2258 std::string filename = _config.fileName;
2259 cache->_inverse = m;
2260 TDirectory *file = openFile(filename);
2261 if (!file) {
2262 coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl;
2263 return false;
2264 }
2265
2266 this->readParameters(file);
2267 checkNameConflict(_config.paramCards, _operators);
2268 this->collectInputs(file);
2269
2270 // then, update the weights in the morphing function
2271 this->updateSampleWeights();
2272
2273 closeFile(file);
2274 } else {
2276 if (!cache)
2277 coutE(Caching) << "unable to create cache!" << std::endl;
2278 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
2279 }
2280 return true;
2281}
2282
2283////////////////////////////////////////////////////////////////////////////////
2284// setup the morphing function with a predefined inverse matrix
2285// call this function *before* any other after creating the object
2286
2288{
2289 auto cache = static_cast<RooLagrangianMorphFunc::CacheElem *>(
2290 _cacheMgr.getObj(nullptr, static_cast<RooArgSet const *>(nullptr)));
2291 if (cache) {
2292 return false;
2293 }
2294 cache = RooLagrangianMorphFunc::CacheElem::createCache(this, readMatrixFromFileT<Matrix>(filename));
2295 if (!cache)
2296 coutE(Caching) << "unable to create cache!" << std::endl;
2297 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
2298 return true;
2299}
2300
2301////////////////////////////////////////////////////////////////////////////////
2302/// write the inverse matrix to a file
2303
2305{
2306 auto cache = this->getCache();
2307 if (!cache)
2308 return false;
2309 writeMatrixToFileT(cache->_inverse, filename);
2310 return true;
2311}
2312
2313////////////////////////////////////////////////////////////////////////////////
2314/// retrieve the cache object
2315
2317{
2318 auto cache = static_cast<RooLagrangianMorphFunc::CacheElem *>(
2319 _cacheMgr.getObj(nullptr, static_cast<RooArgSet const *>(nullptr)));
2320 if (!cache) {
2321 cxcoutP(Caching) << "creating cache from getCache function for " << this << std::endl;
2322 cxcoutP(Caching) << "current storage has size " << _sampleMap.size() << std::endl;
2324 if (cache) {
2325 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
2326 } else {
2327 coutE(Caching) << "unable to create cache!" << std::endl;
2328 }
2329 }
2330 return cache;
2331}
2332
2333////////////////////////////////////////////////////////////////////////////////
2334/// return true if a cache object is present, false otherwise
2335
2337{
2338 return (bool)(_cacheMgr.getObj(nullptr, static_cast<RooArgSet *>(nullptr)));
2339}
2340
2341////////////////////////////////////////////////////////////////////////////////
2342/// set one parameter to a specific value
2343
2345{
2346 RooRealVar *param = this->getParameter(name);
2347 if (!param) {
2348 return;
2349 }
2350 if (value > param->getMax())
2351 param->setMax(value);
2352 if (value < param->getMin())
2353 param->setMin(value);
2354 param->setVal(value);
2355}
2356
2357////////////////////////////////////////////////////////////////////////////////
2358/// set one flag to a specific value
2359
2361{
2362 RooRealVar *param = this->getFlag(name);
2363 if (!param) {
2364 return;
2365 }
2366 param->setVal(value);
2367}
2368
2369////////////////////////////////////////////////////////////////////////////////
2370/// set one parameter to a specific value and range
2371
2372void RooLagrangianMorphFunc::setParameter(const char *name, double value, double min, double max)
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}
2382
2383////////////////////////////////////////////////////////////////////////////////
2384/// set one parameter to a specific value and range
2385void RooLagrangianMorphFunc::setParameter(const char *name, double value, double min, double max, double error)
2386{
2387 RooRealVar *param = this->getParameter(name);
2388 if (!param) {
2389 return;
2390 }
2391 param->setMin(min);
2392 param->setMax(max);
2393 param->setVal(value);
2394 param->setError(error);
2395}
2396
2397////////////////////////////////////////////////////////////////////////////////
2398/// return true if the parameter with the given name is set constant, false
2399/// otherwise
2400
2402{
2403 RooRealVar *param = this->getParameter(name);
2404 if (param) {
2405 return param->isConstant();
2406 }
2407 return true;
2408}
2409
2410////////////////////////////////////////////////////////////////////////////////
2411/// retrieve the RooRealVar object incorporating the parameter with the given
2412/// name
2414{
2415
2416 return dynamic_cast<RooRealVar *>(_operators.find(name));
2417}
2418
2419////////////////////////////////////////////////////////////////////////////////
2420/// retrieve the RooRealVar object incorporating the flag with the given name
2421
2423{
2424 return dynamic_cast<RooRealVar *>(_flags.find(name));
2425}
2426
2427////////////////////////////////////////////////////////////////////////////////
2428/// check if a parameter of the given name is contained in the list of known
2429/// parameters
2430
2432{
2433 return this->getParameter(name);
2434}
2435
2436////////////////////////////////////////////////////////////////////////////////
2437/// call setConstant with the boolean argument provided on the parameter with
2438/// the given name
2439
2440void RooLagrangianMorphFunc::setParameterConstant(const char *name, bool constant) const
2441{
2442 RooRealVar *param = this->getParameter(name);
2443 if (param) {
2444 return param->setConstant(constant);
2445 }
2446}
2447
2448////////////////////////////////////////////////////////////////////////////////
2449/// set one parameter to a specific value
2450
2452{
2453 RooRealVar *param = this->getParameter(name);
2454 if (param) {
2455 return param->getVal();
2456 }
2457 return 0.0;
2458}
2459
2460////////////////////////////////////////////////////////////////////////////////
2461/// set the morphing parameters to those supplied in the given param hist
2462
2464{
2465 setParams(paramhist, _operators, false);
2466}
2467
2468////////////////////////////////////////////////////////////////////////////////
2469/// set the morphing parameters to those supplied in the sample with the given
2470/// name
2471
2472void RooLagrangianMorphFunc::setParameters(const char *foldername)
2473{
2474 std::string filename = _config.fileName;
2475 TDirectory *file = openFile(filename);
2476 auto paramhist = loadFromFileResidentFolder<TH1>(file, foldername, "param_card");
2477 setParams(paramhist.get(), _operators, false);
2478 closeFile(file);
2479}
2480
2481/////////////////////////////////////////////////////////////////////////////////
2482/// retrieve the morphing parameters associated to the sample with the given
2483/// name
2484
2486{
2487 const std::string name(foldername);
2488 return _config.paramCards.at(name);
2489}
2490
2491////////////////////////////////////////////////////////////////////////////////
2492/// set the morphing parameters to those supplied in the list with the given
2493/// name
2494
2496{
2497 for (auto *param : dynamic_range_cast<RooRealVar *>(*list)) {
2498 if (!param)
2499 continue;
2500 this->setParameter(param->GetName(), param->getVal());
2501 }
2502}
2503
2504////////////////////////////////////////////////////////////////////////////////
2505/// retrieve the histogram observable
2506
2508{
2509 if (_observables.empty()) {
2510 coutE(InputArguments) << "observable not available!" << std::endl;
2511 return nullptr;
2512 }
2513 return static_cast<RooRealVar *>(_observables.at(0));
2514}
2515
2516////////////////////////////////////////////////////////////////////////////////
2517/// retrieve the histogram observable
2518
2520{
2521 if (_binWidths.empty()) {
2522 coutE(InputArguments) << "bin width not available!" << std::endl;
2523 return nullptr;
2524 }
2525 return static_cast<RooRealVar *>(_binWidths.at(0));
2526}
2527
2528////////////////////////////////////////////////////////////////////////////////
2529/// retrieve a histogram output of the current morphing settings
2530
2532{
2533 return this->createTH1(name, false);
2534}
2535
2536////////////////////////////////////////////////////////////////////////////////
2537/// retrieve a histogram output of the current morphing settings
2538
2539TH1 *RooLagrangianMorphFunc::createTH1(const std::string &name, bool correlateErrors)
2540{
2541 auto mf = std::make_unique<RooRealSumFunc>(*(this->getFunc()));
2542 RooRealVar *observable = this->getObservable();
2543
2544 const int nbins = observable->getBins();
2545
2546 auto hist = std::make_unique<TH1F>(name.c_str(), name.c_str(), nbins, observable->getBinning().array());
2547
2548 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2549 for (int i = 0; i < nbins; ++i) {
2550 observable->setBin(i);
2551 double val = 0;
2552 double unc2 = 0;
2553 double unc = 0;
2554 for (auto *prod : dynamic_range_cast<RooProduct *>(*args)) {
2555 if (!prod)
2556 continue;
2557 RooAbsArg *phys = prod->components().find(Form("phys_%s", prod->GetName()));
2558 RooHistFunc *hf = dynamic_cast<RooHistFunc *>(phys);
2559 if (!hf) {
2560 continue;
2561 }
2562 const RooDataHist &dhist = hf->dataHist();
2563 RooAbsReal *formula = dynamic_cast<RooAbsReal *>(prod->components().find(Form("w_%s", prod->GetName())));
2564 double weight = formula->getVal();
2565 const double w2 = dhist.weightSquared(i);
2566 unc2 += w2 * weight * weight;
2567 unc += sqrt(w2) * weight;
2568 val += dhist.weight(i) * weight;
2569 }
2570 hist->SetBinContent(i + 1, val);
2571 hist->SetBinError(i + 1, correlateErrors ? unc : sqrt(unc2));
2572 }
2573 return hist.release();
2574}
2575
2576////////////////////////////////////////////////////////////////////////////////
2577/// count the number of formulas that correspond to the current parameter set
2578
2580{
2581 int nFormulas = 0;
2582 auto mf = std::make_unique<RooRealSumFunc>(*(this->getFunc()));
2583 if (!mf)
2584 coutE(InputArguments) << "unable to retrieve morphing function" << std::endl;
2585 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2586 for (auto *prod : dynamic_range_cast<RooProduct *>(*args)) {
2587 if (prod->getVal() != 0) {
2588 nFormulas++;
2589 }
2590 }
2591 return nFormulas;
2592}
2593
2594////////////////////////////////////////////////////////////////////////////////
2595/// check if there is any morphing power provided for the given parameter
2596/// morphing power is provided as soon as any two samples provide different,
2597/// non-zero values for this parameter
2598
2599bool RooLagrangianMorphFunc::isParameterUsed(const char *paramname) const
2600{
2601 std::string pname(paramname);
2602 double val = 0;
2603 bool isUsed = false;
2604 for (const auto &sample : _config.paramCards) {
2605 double thisval = sample.second.at(pname);
2606 if (thisval != val) {
2607 if (val != 0)
2608 isUsed = true;
2609 val = thisval;
2610 }
2611 }
2612 return isUsed;
2613}
2614
2615////////////////////////////////////////////////////////////////////////////////
2616/// check if there is any morphing power provided for the given coupling
2617/// morphing power is provided as soon as any two samples provide
2618/// different, non-zero values for this coupling
2619
2621{
2622 std::string cname(couplname);
2623 const RooArgList *args = this->getCouplingSet();
2624 RooAbsReal *coupling = dynamic_cast<RooAbsReal *>(args->find(couplname));
2625 if (!coupling)
2626 return false;
2628 double val = 0;
2629 bool isUsed = false;
2630 for (const auto &sample : _config.paramCards) {
2631 this->setParameters(sample.second);
2632 double thisval = coupling->getVal();
2633 if (thisval != val) {
2634 if (val != 0)
2635 isUsed = true;
2636 val = thisval;
2637 }
2638 }
2639 this->setParameters(params);
2640 return isUsed;
2641}
2642
2643////////////////////////////////////////////////////////////////////////////////
2644/// return the number of parameters in this morphing function
2645
2647{
2648 return this->getParameterSet()->size();
2649}
2650
2651////////////////////////////////////////////////////////////////////////////////
2652/// return the number of samples in this morphing function
2653
2655{
2656 // return the number of samples in this morphing function
2657 auto cache = getCache();
2658 return cache->_formulas.size();
2659}
2660
2661////////////////////////////////////////////////////////////////////////////////
2662/// print the contributing samples and their respective weights
2663
2665{
2666 auto mf = std::make_unique<RooRealSumFunc>(*(this->getFunc()));
2667 if (!mf) {
2668 std::cerr << "Error: unable to retrieve morphing function" << std::endl;
2669 return;
2670 }
2671 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2672 for (auto *formula : dynamic_range_cast<RooAbsReal*>(*args)) {
2673 if (formula) {
2674 TString name(formula->GetName());
2675 name.Remove(0, 2);
2676 name.Prepend("phys_");
2677 if (!args->find(name.Data())) {
2678 continue;
2679 }
2680 double val = formula->getVal();
2681 if (val != 0) {
2682 std::cout << formula->GetName() << ": " << val << " = " << formula->GetTitle() << std::endl;
2683 }
2684 }
2685 }
2686}
2687
2688////////////////////////////////////////////////////////////////////////////////
2689/// get the set of parameters
2690
2692{
2693 return &(_operators);
2694}
2695
2696////////////////////////////////////////////////////////////////////////////////
2697/// get the set of couplings
2698
2700{
2701 auto cache = getCache();
2702 return &(cache->_couplings);
2703}
2704
2705////////////////////////////////////////////////////////////////////////////////
2706/// retrieve a set of couplings (-?-)
2707
2709{
2711 for (auto *var : dynamic_range_cast<RooAbsReal *>(*(this->getCouplingSet()))) {
2712 if (!var)
2713 continue;
2714 const std::string name(var->GetName());
2715 double val = var->getVal();
2716 couplings[name] = val;
2717 }
2718 return couplings;
2719}
2720
2721////////////////////////////////////////////////////////////////////////////////
2722/// retrieve the parameter set
2723
2728
2729////////////////////////////////////////////////////////////////////////////////
2730/// retrieve a set of couplings (-?-)
2731
2733{
2734 setParams(params, _operators, false);
2735}
2736
2737////////////////////////////////////////////////////////////////////////////////
2738/// (currently similar to cloning the Pdf
2739
2740std::unique_ptr<RooWrapperPdf> RooLagrangianMorphFunc::createPdf() const
2741{
2742 auto cache = getCache();
2743 auto func = std::make_unique<RooRealSumFunc>(*(cache->_sumFunc));
2744
2745 // create a wrapper on the roorealsumfunc
2746 return std::make_unique<RooWrapperPdf>(Form("pdf_%s", func->GetName()), Form("pdf of %s", func->GetTitle()), *func);
2747}
2748
2749////////////////////////////////////////////////////////////////////////////////
2750/// get the func
2751
2753{
2754 auto cache = getCache();
2755 return cache->_sumFunc.get();
2756}
2757
2758////////////////////////////////////////////////////////////////////////////////
2759/// return extended mored capabilities
2760
2762{
2763 return this->createPdf()->extendMode();
2764}
2765
2766////////////////////////////////////////////////////////////////////////////////
2767/// return expected number of events for extended likelihood calculation,
2768/// this is the sum of all coefficients
2769
2771{
2772 return this->createPdf()->expectedEvents(nset);
2773}
2774
2775////////////////////////////////////////////////////////////////////////////////
2776/// return the number of expected events for the current parameter set
2777
2779{
2780 RooArgSet set;
2781 set.add(*this->getObservable());
2782 return this->createPdf()->expectedEvents(set);
2783}
2784
2785////////////////////////////////////////////////////////////////////////////////
2786/// return expected number of events for extended likelihood calculation,
2787/// this is the sum of all coefficients
2788
2790{
2791 return createPdf()->expectedEvents(&nset);
2792}
2793
2794////////////////////////////////////////////////////////////////////////////////
2795/// return the expected uncertainty for the current parameter set
2796
2798{
2799 RooRealVar *observable = this->getObservable();
2800 auto cache = this->getCache();
2801 double unc2 = 0;
2802 for (const auto &sample : _sampleMap) {
2803 RooAbsArg *phys = _physics.at(sample.second);
2804 auto weightName = std::string("w_") + sample.first + "_" + this->GetName();
2805 auto weight = static_cast<RooAbsReal *>(cache->_weights.find(weightName.c_str()));
2806 if (!weight) {
2807 coutE(InputArguments) << "unable to find object " + weightName << std::endl;
2808 return 0.0;
2809 }
2810 double newunc2 = 0;
2811 RooHistFunc *hf = dynamic_cast<RooHistFunc *>(phys);
2812 RooRealVar *rv = dynamic_cast<RooRealVar *>(phys);
2813 if (hf) {
2814 const RooDataHist &hist = hf->dataHist();
2815 for (Int_t j = 0; j < observable->getBins(); ++j) {
2816 newunc2 += hist.weightSquared(j);
2817 }
2818 } else if (rv) {
2819 newunc2 = pow(rv->getError(), 2);
2820 }
2821 double w = weight->getVal();
2822 unc2 += newunc2 * w * w;
2823 // std::cout << phys->GetName() << " : " << weight->GetName() << "
2824 // thisweight: " << w << " thisxsec2: " << newunc2 << " weight " << weight
2825 // << std::endl;
2826 }
2827 return sqrt(unc2);
2828}
2829
2830////////////////////////////////////////////////////////////////////////////////
2831/// print the parameters and their current values
2832
2834{
2835 // print the parameters and their current values
2836 for (auto *param : static_range_cast<RooRealVar *>(_operators)) {
2837 if (!param)
2838 continue;
2839 param->Print();
2840 }
2841}
2842
2843////////////////////////////////////////////////////////////////////////////////
2844/// print the flags and their current values
2845
2847{
2848 for (auto *param : static_range_cast<RooRealVar *>(_flags)) {
2849 if (!param)
2850 continue;
2851 param->Print();
2852 }
2853}
2854
2855////////////////////////////////////////////////////////////////////////////////
2856/// print a set of couplings
2857
2859{
2861 for (auto c : couplings) {
2862 std::cout << c.first << ": " << c.second << std::endl;
2863 }
2864}
2865
2866////////////////////////////////////////////////////////////////////////////////
2867/// retrieve the list of bin boundaries
2868
2869std::list<double> *RooLagrangianMorphFunc::binBoundaries(RooAbsRealLValue &obs, double xlo, double xhi) const
2870{
2871 return this->getFunc()->binBoundaries(obs, xlo, xhi);
2872}
2873
2874////////////////////////////////////////////////////////////////////////////////
2875/// retrieve the sample Hint
2876
2877std::list<double> *RooLagrangianMorphFunc::plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const
2878{
2879 return this->getFunc()->plotSamplingHint(obs, xlo, xhi);
2880}
2881
2882////////////////////////////////////////////////////////////////////////////////
2883/// call getVal on the internal function
2884
2886{
2887 // call getVal on the internal function
2888 const RooRealSumFunc *pdf = this->getFunc();
2889 RooArgSet nSet;
2890 for (auto &obs : _observables) {
2891 nSet.add(*obs);
2892 }
2893 if (pdf) {
2894 return _scale * pdf->getVal(&nSet);
2895 } else {
2896 std::cerr << "unable to acquire in-built function!" << std::endl;
2897 }
2898 return 0.;
2899}
2900
2901////////////////////////////////////////////////////////////////////////////////
2902/// check if this PDF is a binned distribution in the given observable
2903
2905{
2906 return this->getFunc()->isBinnedDistribution(obs);
2907}
2908
2909////////////////////////////////////////////////////////////////////////////////
2910/// check if observable exists in the RooArgSet (-?-)
2911
2913{
2914 return this->getFunc()->checkObservables(nset);
2915}
2916
2917////////////////////////////////////////////////////////////////////////////////
2918/// Force analytical integration for the given observable
2919
2921{
2922 return this->getFunc()->forceAnalyticalInt(arg);
2923}
2924
2925////////////////////////////////////////////////////////////////////////////////
2926/// Retrieve the mat
2927
2929 const char *rangeName) const
2930{
2931 return this->getFunc()->getAnalyticalIntegralWN(allVars, numVars, normSet, rangeName);
2932}
2933
2934////////////////////////////////////////////////////////////////////////////////
2935/// Retrieve the matrix of coefficients
2936
2937double RooLagrangianMorphFunc::analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName) const
2938{
2939 return this->getFunc()->analyticalIntegralWN(code, normSet, rangeName);
2940}
2941
2942////////////////////////////////////////////////////////////////////////////////
2943/// Retrieve the matrix of coefficients
2944
2945void RooLagrangianMorphFunc::printMetaArgs(std::ostream &os) const
2946{
2947 return this->getFunc()->printMetaArgs(os);
2948}
2949
2950////////////////////////////////////////////////////////////////////////////////
2951/// Retrieve the matrix of coefficients
2952
2954{
2955 auto cache = getCache();
2956 if (!cache)
2957 coutE(Caching) << "unable to retrieve cache!" << std::endl;
2958 return makeRootMatrix(cache->_matrix);
2959}
2960
2961////////////////////////////////////////////////////////////////////////////////
2962/// Retrieve the matrix of coefficients after inversion
2963
2965{
2966 auto cache = getCache();
2967 if (!cache)
2968 coutE(Caching) << "unable to retrieve cache!" << std::endl;
2969 return makeRootMatrix(cache->_inverse);
2970}
2971
2972////////////////////////////////////////////////////////////////////////////////
2973/// Retrieve the condition of the coefficient matrix. If the condition number
2974/// is very large, then the matrix is ill-conditioned and is almost singular.
2975/// The computation of the inverse is prone to large numerical errors
2976
2978{
2979 auto cache = getCache();
2980 if (!cache)
2981 coutE(Caching) << "unable to retrieve cache!" << std::endl;
2982 return cache->_condition;
2983}
2984
2985////////////////////////////////////////////////////////////////////////////////
2986/// Return the RooRatio form of products and denominators of morphing functions
2987
2988std::unique_ptr<RooRatio>
2989RooLagrangianMorphFunc::makeRatio(const char *name, const char *title, RooArgList &nr, RooArgList &dr)
2990{
2991 RooArgList num;
2992 RooArgList denom;
2993 for (auto it : nr) {
2994 num.add(*it);
2995 }
2996 for (auto it : dr) {
2997 denom.add(*it);
2998 }
2999 // same for denom
3000 return make_unique<RooRatio>(name, title, num, denom);
3001}
3002
3003// Register the factory interface
3004
3005namespace {
3006
3007// Helper function for factory interface
3008std::vector<std::string> asStringV(std::string const &arg)
3009{
3010 std::vector<std::string> out;
3011
3012 for (std::string &tok : ROOT::Split(arg, ",{}", true)) {
3013 if (tok[0] == '\'') {
3014 out.emplace_back(tok.substr(1, tok.size() - 2));
3015 } else {
3016 throw std::runtime_error("Strings in factory expressions need to be in single quotes!");
3017 }
3018 }
3019
3020 return out;
3021}
3022
3023class LMIFace : public RooFactoryWSTool::IFace {
3024public:
3025 std::string
3026 create(RooFactoryWSTool &, const char *typeName, const char *instName, std::vector<std::string> args) override;
3027};
3028
3029std::string LMIFace::create(RooFactoryWSTool &ft, const char * /*typeName*/, const char *instanceName,
3030 std::vector<std::string> args)
3031{
3032 // Perform syntax check. Warn about any meta parameters other than the ones needed
3033 const std::array<std::string, 4> funcArgs{{"fileName", "observableName", "couplings", "folders"}};
3034 std::map<string, string> mappedInputs;
3035
3036 for (unsigned int i = 1; i < args.size(); i++) {
3037 if (args[i].find("$fileName(") != 0 && args[i].find("$observableName(") != 0 &&
3038 args[i].find("$couplings(") != 0 && args[i].find("$folders(") != 0 && args[i].find("$NewPhysics(") != 0) {
3039 throw std::string(Form("%s::create() ERROR: unknown token %s encountered", instanceName, args[i].c_str()));
3040 }
3041 }
3042
3043 for (unsigned int i = 0; i < args.size(); i++) {
3044 if (args[i].find("$NewPhysics(") == 0) {
3045 vector<string> subargs = ft.splitFunctionArgs(args[i].c_str());
3046 for (const auto &subarg : subargs) {
3047 std::vector<std::string> parts = ROOT::Split(subarg, "=");
3048 if (parts.size() == 2) {
3049 ft.ws().arg(parts[0])->setAttribute("NewPhysics", atoi(parts[1].c_str()));
3050 } else {
3051 throw std::string(Form("%s::create() ERROR: unknown token %s encountered, check input provided for %s",
3052 instanceName, subarg.c_str(), args[i].c_str()));
3053 }
3054 }
3055 } else {
3056 std::vector<string> subargs = ft.splitFunctionArgs(args[i].c_str());
3057 if (subargs.size() == 1) {
3058 string expr = ft.processExpression(subargs[0].c_str());
3059 for (auto const &param : funcArgs) {
3060 if (args[i].find(param) != string::npos)
3061 mappedInputs[param] = subargs[0];
3062 }
3063 } else {
3064 throw std::string(
3065 Form("Incorrect number of arguments in %s, have %d, expect 1", args[i].c_str(), (Int_t)subargs.size()));
3066 }
3067 }
3068 }
3069
3071 config.fileName = asStringV(mappedInputs["fileName"])[0];
3072 config.observableName = asStringV(mappedInputs["observableName"])[0];
3073 config.folderNames = asStringV(mappedInputs["folders"]);
3074 config.couplings.add(ft.asLIST(mappedInputs["couplings"].c_str()));
3075
3076 ft.ws().import(RooLagrangianMorphFunc{instanceName, instanceName, config}, RooFit::Silence());
3077
3078 return instanceName;
3079}
3080
3081static Int_t init();
3082
3083int dummy = init();
3084
3085Int_t init()
3086{
3087 RooFactoryWSTool::IFace *iface = new LMIFace;
3088 RooFactoryWSTool::registerSpecial("lagrangianmorph", iface);
3089 (void)dummy;
3090 return 0;
3091}
3092
3093} // 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
#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:2571
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
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
void Print(Option_t *options=nullptr) const override
Print the object to the defaultPrintStream().
Definition RooAbsArg.h:239
bool isConstant() const
Check if the "Constant" attribute is set.
Definition RooAbsArg.h:284
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
void setValueDirty()
Mark the element dirty. This forces a re-evaluation when a value is requested.
Definition RooAbsArg.h:405
virtual double * array() const =0
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...
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:1495
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:3802
void Close(Option_t *option="") override
Close a file.
Definition TFile.cxx:992
<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:226
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:2460
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