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