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 std::string, std::make_unique, std::vector;
77
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 std::cerr << "unable to read file '" << fname << "'!" << std::endl;
148 }
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
244{
245 boost::numeric::ublas::permutation_matrix<size_t> pm(size(matrix));
248 try {
249 int res = lu_factorize(lu, pm);
250 if (res != 0) {
251 std::stringstream ss;
253 cxcoutP(Eval) << ss.str << std::endl;
254 }
255 // back-substitute to get the inverse
257 } catch (boost::numeric::ublas::internal_logic &error) {
258 // coutE(Eval) << "boost::numeric::ublas error: matrix is not invertible!"
259 // << std::endl;
260 }
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{
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 }
324 }
325 return condition;
326}
327#endif
328
329/////////////////////////////////////////////////////////////////////////////////
330// LOCAL FUNCTIONS AND DEFINITIONS
331// //////////////////////////////////////////////
332/////////////////////////////////////////////////////////////////////////////////
333/// anonymous namespace to prohibit use of these functions outside the class
334/// itself
335namespace {
336///////////////////////////////////////////////////////////////////////////////
337// HELPERS ////////////////////////////////////////////////////////////////////
338///////////////////////////////////////////////////////////////////////////////
339
340typedef std::vector<std::vector<bool>> FeynmanDiagram;
341typedef std::vector<std::vector<int>> MorphFuncPattern;
342typedef std::map<int, std::unique_ptr<RooAbsReal>> FormulaList;
343
344///////////////////////////////////////////////////////////////////////////////
345/// (-?-)
346
347inline TString makeValidName(std::string const& input)
348{
349 TString retval(input.c_str());
350 retval.ReplaceAll("/", "_");
351 retval.ReplaceAll("^", "");
352 retval.ReplaceAll("*", "X");
353 retval.ReplaceAll("[", "");
354 retval.ReplaceAll("]", "");
355 return retval;
356}
357
358//////////////////////////////////////////////////////////////////////////////
359/// concatenate the names of objects in a collection to a single string
360
361template <class List>
362std::string concatNames(const List &c, const char *sep)
363{
364 std::stringstream ss;
365 bool first = true;
366 for (auto itr : c) {
367 if (!first)
368 ss << sep;
369 ss << itr->GetName();
370 first = false;
371 }
372 return ss.str();
373}
374
375///////////////////////////////////////////////////////////////////////////////
376/// this is a workaround for the missing implicit conversion from
377/// SuperFloat<>double
378
379template <class A, class B>
380inline void assignElement(A &a, const B &b)
381{
382 a = static_cast<A>(b);
383}
384///////////////////////////////////////////////////////////////////////////////
385// read a matrix from a stream
386
387template <class MatrixT>
388inline MatrixT readMatrixFromStreamT(std::istream &stream)
389{
390 std::vector<std::vector<RooFit::SuperFloat>> matrix;
391 std::vector<RooFit::SuperFloat> line;
392 while (!stream.eof()) {
393 if (stream.peek() == '\n') {
394 stream.get();
395 stream.peek();
396 continue;
397 }
399 stream >> val;
400 line.push_back(val);
401 while (stream.peek() == ' ' || stream.peek() == '\t') {
402 stream.get();
403 }
404 if (stream.peek() == '\n') {
405 matrix.push_back(line);
406 line.clear();
407 }
408 }
409 MatrixT retval(matrix.size(), matrix.size());
410 for (size_t i = 0; i < matrix.size(); ++i) {
411 if (matrix[i].size() != matrix.size()) {
412 std::cerr << "matrix read from stream doesn't seem to be square!" << std::endl;
413 }
414 for (size_t j = 0; j < matrix[i].size(); ++j) {
415 assignElement(retval(i, j), matrix[i][j]);
416 }
417 }
418 return retval;
419}
420
421///////////////////////////////////////////////////////////////////////////////
422/// read a matrix from a text file
423
424template <class MatrixT>
425inline MatrixT readMatrixFromFileT(const char *fname)
426{
427 std::ifstream in(fname);
428 if (!in.good()) {
429 std::cerr << "unable to read file '" << fname << "'!" << std::endl;
430 }
432 in.close();
433 return mat;
434}
435
436///////////////////////////////////////////////////////////////////////////////
437/// convert a TH1* param hist into the corresponding ParamSet object
438
439template <class T>
440void readValues(std::map<const std::string, T> &myMap, TH1 *h_pc)
441{
442 if (h_pc) {
443 // loop over all bins of the param_card histogram
444 for (int ibx = 1; ibx <= h_pc->GetNbinsX(); ++ibx) {
445 // read the value of one parameter
446 const std::string s_coup(h_pc->GetXaxis()->GetBinLabel(ibx));
447 double coup_val = h_pc->GetBinContent(ibx);
448 // add it to the map
449 if (!s_coup.empty()) {
450 myMap[s_coup] = T(coup_val);
451 }
452 }
453 }
454}
455
456///////////////////////////////////////////////////////////////////////////////
457/// Set up folder ownership over its children, and treat likewise any subfolders.
458/// @param theFolder: folder to update. Assumed to be a valid pointer
460{
461 theFolder->SetOwner();
462 // And also need to set up ownership for nested folders
463 auto subdirs = theFolder->GetListOfFolders();
464 for (auto *thisfolder : dynamic_range_cast<TFolder *>(*subdirs)) {
465 if (thisfolder) {
466 // no explicit deletion here, will be handled by parent
468 }
469 }
470}
471
472///////////////////////////////////////////////////////////////////////////////
473/// Load a TFolder from a file while ensuring it owns its content.
474/// This avoids memory leaks. Note that when fetching objects
475/// from this folder, you need to clone them to prevent deletion.
476/// Also recursively updates nested subfolders accordingly
477/// @param inFile: Input file to read - assumed to be a valid pointer
478/// @param folderName: Name of the folder to read from the file
479/// @return a unique_ptr to the folder. Nullptr if not found.
480std::unique_ptr<TFolder> readOwningFolderFromFile(TDirectory *inFile, const std::string &folderName)
481{
482 std::unique_ptr<TFolder> theFolder(inFile->Get<TFolder>(folderName.c_str()));
483 if (!theFolder) {
484 std::cerr << "Error: unable to access data from folder '" << folderName << "' from file '" << inFile->GetName()
485 << "'!" << std::endl;
486 return nullptr;
487 }
489 return theFolder;
490}
491
492///////////////////////////////////////////////////////////////////////////////
493/// Helper to load a single object from a file-resident TFolder, while
494/// avoiding memory leaks.
495/// @tparam AObjType Type of object to load.
496/// @param inFile input file to load from. Expected to be a valid pointer
497/// @param folderName Name of the TFolder to load from the file
498/// @param objName Name of the object to load
499/// @param notFoundError If set, print a detailed error if we didn't find something
500/// @return Returns a pointer to a clone of the loaded object. Ownership assigned to the caller.
501template <class AObjType>
502std::unique_ptr<AObjType> loadFromFileResidentFolder(TDirectory *inFile, const std::string &folderName,
503 const std::string &objName, bool notFoundError = true)
504{
506 if (!folder) {
507 return nullptr;
508 }
509 AObjType *loadedObject = dynamic_cast<AObjType *>(folder->FindObject(objName.c_str()));
510 if (!loadedObject) {
511 if (notFoundError) {
512 std::stringstream errstr;
513 errstr << "Error: unable to retrieve object '" << objName << "' from folder '" << folderName
514 << "'. contents are:";
515 TIter next(folder->GetListOfFolders()->begin());
516 TFolder *f;
517 while ((f = static_cast<TFolder *>(next()))) {
518 errstr << " " << f->GetName();
519 }
520 std::cerr << errstr.str() << std::endl;
521 }
522 return nullptr;
523 }
524 // replace the loaded object by a clone, as the loaded folder will delete the original
525 // can use a static_cast - confirmed validity by initial cast above.
526 return std::unique_ptr<AObjType>{static_cast<AObjType *>(loadedObject->Clone())};
527}
528
529///////////////////////////////////////////////////////////////////////////////
530/// retrieve a ParamSet from a certain subfolder 'name' of the file
531
532template <class T>
533void readValues(std::map<const std::string, T> &myMap, TDirectory *file, const std::string &name,
534 const std::string &key = "param_card", bool notFoundError = true)
535{
537 readValues(myMap, h_pc.get());
538}
539
540///////////////////////////////////////////////////////////////////////////////
541/// retrieve the param_hists file and return a map of the parameter values
542/// by providing a list of names, only the param_hists of those subfolders are
543/// read leaving the list empty is interpreted as meaning 'read everything'
544
545template <class T>
546void readValues(std::map<const std::string, std::map<const std::string, T>> &inputParameters, TDirectory *f,
547 const std::vector<std::string> &names, const std::string &key = "param_card", bool notFoundError = true)
548{
549 inputParameters.clear();
550 // if the list of names is empty, we assume that this means 'all'
551 // loop over all folders in the file
552 for (size_t i = 0; i < names.size(); i++) {
553 const std::string name(names[i]);
554 // actually read an individual param_hist
556 }
557
558 // now the map is filled with all parameter values found for all samples
559}
560
561///////////////////////////////////////////////////////////////////////////////
562/// open the file and return a file pointer
563
564inline TDirectory *openFile(const std::string &filename)
565{
566 if (filename.empty()) {
567 return gDirectory;
568 } else {
569 TFile *file = TFile::Open(filename.c_str(), "READ");
570 if (!file || !file->IsOpen()) {
571 if (file)
572 delete file;
573 std::cerr << "could not open file '" << filename << "'!" << std::endl;
574 }
575 return file;
576 }
577}
578
579///////////////////////////////////////////////////////////////////////////////
580/// open the file and return a file pointer
581
582inline void closeFile(TDirectory *d)
583{
584 TFile *f = dynamic_cast<TFile *>(d);
585 if (f) {
586 f->Close();
587 delete f;
588 d = nullptr;
589 }
590}
591
592///////////////////////////////////////////////////////////////////////////////
593/// extract the operators from a single coupling
594template <class T2>
595inline void extractServers(const RooAbsArg &coupling, T2 &operators)
596{
597 int nservers = 0;
598 for (const auto server : coupling.servers()) {
600 nservers++;
601 }
602 if (nservers == 0) {
603 operators.add(coupling);
604 }
605}
606
607///////////////////////////////////////////////////////////////////////////////
608/// extract the operators from a list of couplings
609
611inline void extractOperators(const T1 &couplings, T2 &operators)
612{
613 // std::coutD(InputArguments) << "extracting operators from
614 // "<<couplings.size()<<" couplings" << std::endl;
615 for (auto itr : couplings) {
617 }
618}
619
620///////////////////////////////////////////////////////////////////////////////
621/// extract the operators from a list of vertices
622
624inline void extractOperators(const T1 &vec, T2 &operators)
625{
626 for (const auto &v : vec) {
628 }
629}
630
631///////////////////////////////////////////////////////////////////////////////
632/// extract the couplings from a given set and copy them to a new one
633
634template <class T1, class T2>
635inline void extractCouplings(const T1 &inCouplings, T2 &outCouplings)
636{
637 for (auto itr : inCouplings) {
638 if (!outCouplings.find(itr->GetName())) {
639 // std::coutD(InputArguments) << "adding parameter "<< obj->GetName() <<
640 // std::endl;
641 outCouplings.add(*itr);
642 }
643 }
644}
645
646////////////////////////////////////////////////////////////////////////////////
647/// set parameter values first set all values to defaultVal (if value not
648/// present in param_card then it should be 0)
649
650inline bool setParam(RooRealVar *p, double val, bool force)
651{
652 bool ok = true;
653 if (val > p->getMax()) {
654 if (force) {
655 p->setMax(val);
656 } else {
657 std::cerr << ": parameter " << p->GetName() << " out of bounds: " << val << " > " << p->getMax() << std::endl;
658 ok = false;
659 }
660 } else if (val < p->getMin()) {
661 if (force) {
662 p->setMin(val);
663 } else {
664 std::cerr << ": parameter " << p->GetName() << " out of bounds: " << val << " < " << p->getMin() << std::endl;
665 ok = false;
666 }
667 }
668 if (ok)
669 p->setVal(val);
670 return ok;
671}
672
673////////////////////////////////////////////////////////////////////////////////
674/// set parameter values first set all values to defaultVal (if value not
675/// present in param_card then it should be 0)
676
677template <class T1, class T2>
678inline bool setParams(const T2 &args, T1 val)
679{
680 for (auto *param : dynamic_range_cast<RooRealVar *>(args)) {
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 *param : dynamic_range_cast<RooRealVar *>(args)) {
698 if (!param || param->isConstant())
699 continue;
700 ok = setParam(param, defaultVal, force) && ok;
701 }
702 // set all parameters to the values in the param_card histogram
703 for (auto paramit : point) {
704 // loop over all the parameters
705 const std::string param(paramit.first);
706 // retrieve them from the map
707 RooRealVar *p = dynamic_cast<RooRealVar *>(args.find(param.c_str()));
708 if (!p)
709 continue;
710 // set them to their nominal value
711 ok = setParam(p, paramit.second, force) && ok;
712 }
713 return ok;
714}
715
716////////////////////////////////////////////////////////////////////////////////
717/// set parameter values first set all values to defaultVal (if value not
718/// present in param_card then it should be 0)
719
720template <class T>
721inline bool setParams(TH1 *hist, const T &args, bool force = false)
722{
723 bool ok = true;
724
725 for (auto *param : dynamic_range_cast<RooRealVar *>(args)) {
726 if (!param)
727 continue;
728 ok = setParam(param, 0., force) && ok;
729 }
730
731 // set all parameters to the values in the param_card histogram
732 TAxis *ax = hist->GetXaxis();
733 for (int i = 1; i <= ax->GetNbins(); ++i) {
734 // loop over all the parameters
735 RooRealVar *p = dynamic_cast<RooRealVar *>(args.find(ax->GetBinLabel(i)));
736 if (!p)
737 continue;
738 // set them to their nominal value
739 ok = setParam(p, hist->GetBinContent(i), force) && ok;
740 }
741 return ok;
742}
743
744////////////////////////////////////////////////////////////////////////////////
745/// create a set of parameters
746
747template <class T>
748inline RooLagrangianMorphFunc::ParamSet getParams(const T &parameters)
749{
751 for (auto *param : dynamic_range_cast<RooRealVar *>(parameters)) {
752 if (!param)
753 continue;
754 retval[param->GetName()] = param->getVal();
755 }
756 return retval;
757}
758
759////////////////////////////////////////////////////////////////////////////////
760/// collect the histograms from the input file and convert them to RooFit
761/// objects
762
763void collectHistograms(const char *name, TDirectory *file, std::map<std::string, int> &list_hf, RooArgList &physics,
764 RooRealVar &var, const std::string &varname,
766{
767 bool binningOK = false;
768 for (auto sampleit : inputParameters) {
769 const std::string sample(sampleit.first);
770 auto hist = loadFromFileResidentFolder<TH1>(file, sample, varname, true);
771 if (!hist)
772 return;
773
774 if (normalize) {
775 hist->Scale(1. / hist->Integral());
776 }
777
778 auto it = list_hf.find(sample);
779 if (it != list_hf.end()) {
780 RooHistFunc *hf = static_cast<RooHistFunc *>(physics.at(it->second));
781 hf->setValueDirty();
782 // commenting out To-be-resolved
783 // RooDataHist* dh = &(hf->dataHist());
784 // RooLagrangianMorphFunc::setDataHistogram(hist,&var,dh);
785 // RooArgSet vars;
786 // vars.add(var);
787 // dh->importTH1(vars,*hist,1.,false);
788 } else {
789 if (!binningOK) {
790 int n = hist->GetNbinsX();
791 std::vector<double> bins;
792 for (int i = 1; i < n + 1; ++i) {
793 bins.push_back(hist->GetBinLowEdge(i));
794 }
795 bins.push_back(hist->GetBinLowEdge(n) + hist->GetBinWidth(n));
796 var.setBinning(RooBinning(n, &(bins[0])));
797 }
798
799 // generate the mean value
800 TString histname = makeValidName("dh_" + sample + "_" + name);
801 TString funcname = makeValidName("phys_" + sample + "_" + name);
802 RooArgSet vars;
803 vars.add(var);
804
805 auto dh = std::make_unique<RooDataHist>(histname.Data(), histname.Data(), vars, hist.get());
806 // add it to the list
807 auto hf = std::make_unique<RooHistFunc>(funcname.Data(), funcname.Data(), var, std::move(dh));
808 int idx = physics.size();
809 list_hf[sample] = idx;
810 physics.addOwned(std::move(hf));
811 }
812 // std::cout << "found histogram " << hist->GetName() << " with integral "
813 // << hist->Integral() << std::endl;
814 }
815}
816
817////////////////////////////////////////////////////////////////////////////////
818/// collect the RooAbsReal objects from the input directory
819
820void collectRooAbsReal(const char * /*name*/, TDirectory *file, std::map<std::string, int> &list_hf,
821 RooArgList &physics, const std::string &varname,
823{
824 for (auto sampleit : inputParameters) {
825 const std::string sample(sampleit.first);
827 if (!obj)
828 return;
829 auto it = list_hf.find(sample);
830 if (it == list_hf.end()) {
831 int idx = physics.size();
832 list_hf[sample] = idx;
833 physics.addOwned(std::move(obj));
834 }
835 }
836}
837
838////////////////////////////////////////////////////////////////////////////////
839/// collect the TParameter objects from the input file and convert them to
840/// RooFit objects
841
842template <class T>
843void collectCrosssections(const char *name, TDirectory *file, std::map<std::string, int> &list_xs, RooArgList &physics,
845{
846 for (auto sampleit : inputParameters) {
847 const std::string sample(sampleit.first);
848 auto obj = loadFromFileResidentFolder<TObject>(file, sample, varname, false);
849 TParameter<T> *xsection = nullptr;
850 TParameter<T> *error = nullptr;
851 TParameter<T> *p = dynamic_cast<TParameter<T> *>(obj.get());
852 if (p) {
853 xsection = p;
854 }
855 TPair *pair = dynamic_cast<TPair *>(obj.get());
856 if (pair) {
857 xsection = dynamic_cast<TParameter<T> *>(pair->Key());
858 error = dynamic_cast<TParameter<T> *>(pair->Value());
859 }
860 if (!xsection) {
861 std::stringstream errstr;
862 errstr << "Error: unable to retrieve cross section '" << varname << "' from folder '" << sample;
863 return;
864 }
865
866 auto it = list_xs.find(sample);
867 RooRealVar *xs;
868 if (it != list_xs.end()) {
869 xs = static_cast<RooRealVar *>(physics.at(it->second));
870 xs->setVal(xsection->GetVal());
871 } else {
872 std::string objname = "phys_" + std::string(name) + "_" + sample;
873 auto xsOwner = std::make_unique<RooRealVar>(objname.c_str(), objname.c_str(), xsection->GetVal());
874 xs = xsOwner.get();
875 xs->setConstant(true);
876 int idx = physics.size();
877 list_xs[sample] = idx;
878 physics.addOwned(std::move(xsOwner));
879 assert(physics.at(idx) == xs);
880 }
881 if (error) {
882 xs->setError(error->GetVal());
883 }
884 }
885}
886
887////////////////////////////////////////////////////////////////////////////////
888/// collect the TPair<TParameter,TParameter> objects from the input file and
889/// convert them to RooFit objects
890
891void collectCrosssectionsTPair(const char *name, TDirectory *file, std::map<std::string, int> &list_xs,
892 RooArgList &physics, const std::string &varname, const std::string &basefolder,
894{
895 auto pair = loadFromFileResidentFolder<TPair>(file, basefolder, varname, false);
896 if (!pair)
897 return;
898 if (dynamic_cast<TParameter<double> *>(pair->Key())) {
900 } else if (dynamic_cast<TParameter<float> *>(pair->Key())) {
902 } else {
903 std::cerr << "cannot morph objects of class 'TPair' if parameter is not "
904 "double or float!"
905 << std::endl;
906 }
907}
908
909///////////////////////////////////////////////////////////////////////////////
910// FORMULA CALCULATION ////////////////////////////////////////////////////////
911///////////////////////////////////////////////////////////////////////////////
912///////////////////////////////////////////////////////////////////////////////
913
914////////////////////////////////////////////////////////////////////////////////
915/// recursive function to determine polynomials
916
918 int vertexid, bool first)
919{
920 if (vertexid > 0) {
921 for (size_t i = 0; i < diagram[vertexid - 1].size(); ++i) {
922 if (!diagram[vertexid - 1][i])
923 continue;
924 std::vector<int> newterm(term);
925 newterm[i]++;
926 if (first) {
928 } else {
930 }
931 }
932 } else {
933 bool found = false;
934 for (size_t i = 0; i < morphfunc.size(); ++i) {
935 bool thisfound = true;
936 for (size_t j = 0; j < morphfunc[i].size(); ++j) {
937 if (morphfunc[i][j] != term[j]) {
938 thisfound = false;
939 break;
940 }
941 }
942 if (thisfound) {
943 found = true;
944 break;
945 }
946 }
947 if (!found) {
948 morphfunc.push_back(term);
949 }
950 }
951}
952
953////////////////////////////////////////////////////////////////////////////////
954/// calculate the morphing function pattern based on a vertex map
955
957{
958 int nvtx(diagram.size());
959 std::vector<int> term(diagram[0].size(), 0);
960
962}
963
964////////////////////////////////////////////////////////////////////////////////
965/// build a vertex map based on vertices and couplings appearing
966
967template <class List>
968inline void fillFeynmanDiagram(FeynmanDiagram &diagram, const std::vector<List *> &vertices, RooArgList &couplings)
969{
970 const int ncouplings = couplings.size();
971 // std::cout << "Number of couplings " << ncouplings << std::endl;
972 for (auto const &vertex : vertices) {
973 std::vector<bool> vertexCouplings(ncouplings, false);
974 int idx = -1;
975 for (auto *coupling : dynamic_range_cast<RooAbsReal *>(couplings)) {
976 idx++;
977 if (!coupling) {
978 std::cerr << "encountered invalid list of couplings in vertex!" << std::endl;
979 return;
980 }
981 if (vertex->find(coupling->GetName())) {
982 vertexCouplings[idx] = true;
983 }
984 }
985 diagram.push_back(vertexCouplings);
986 }
987}
988
989////////////////////////////////////////////////////////////////////////////////
990/// fill the matrix of coefficients
991
992template <class MatrixT, class T1, class T2>
994 const T1 &args, const RooLagrangianMorphFunc::FlagMap &flagValues, const T2 &flags)
995{
996 const size_t dim = inputParameters.size();
997 MatrixT matrix(dim, dim);
998 int row = 0;
999 for (auto sampleit : inputParameters) {
1000 const std::string sample(sampleit.first);
1001 // set all vars to value stored in input file
1002 if (!setParams<double>(sampleit.second, args, true, 0)) {
1003 std::cout << "unable to set parameters for sample " << sample << "!" << std::endl;
1004 }
1005 auto flagit = flagValues.find(sample);
1006 if (flagit != flagValues.end() && !setParams<int>(flagit->second, flags, true, 1)) {
1007 std::cout << "unable to set parameters for sample " << sample << "!" << std::endl;
1008 }
1009 // loop over all the formulas
1010 int col = 0;
1011 for (auto const &formula : formulas) {
1012 if (!formula.second) {
1013 std::cerr << "Error: invalid formula encountered!" << std::endl;
1014 }
1015 matrix(row, col) = formula.second->getVal();
1016 col++;
1017 }
1018 row++;
1019 }
1020 return matrix;
1021}
1022
1023////////////////////////////////////////////////////////////////////////////////
1024/// check if the matrix is square
1025
1026inline void checkMatrix(const RooLagrangianMorphFunc::ParamMap &inputParameters, const FormulaList &formulas)
1027{
1028 if (inputParameters.size() != formulas.size()) {
1029 std::stringstream ss;
1030 ss << "matrix is not square, consistency check failed: " << inputParameters.size() << " samples, "
1031 << formulas.size() << " expressions:" << std::endl;
1032 ss << "formulas: " << std::endl;
1033 for (auto const &formula : formulas) {
1034 ss << formula.second->GetTitle() << std::endl;
1035 }
1036 ss << "samples: " << std::endl;
1037 for (auto sample : inputParameters) {
1038 ss << sample.first << std::endl;
1039 }
1040 std::cerr << ss.str() << std::endl;
1041 }
1042}
1043
1044////////////////////////////////////////////////////////////////////////////////
1045/// check if the entries in the inverted matrix are sensible
1046
1047inline void inverseSanity(const Matrix &matrix, const Matrix &inverse, double &unityDeviation, double &largestWeight)
1048{
1050
1051 unityDeviation = 0.;
1052 largestWeight = 0.;
1053 const size_t dim = size(unity);
1054 for (size_t i = 0; i < dim; ++i) {
1055 for (size_t j = 0; j < dim; ++j) {
1056 if (inverse(i, j) > largestWeight) {
1058 }
1059 if (std::abs(unity(i, j) - static_cast<int>(i == j)) > unityDeviation) {
1060 unityDeviation = std::abs((double)unity(i, j)) - static_cast<int>(i == j);
1061 }
1062 }
1063 }
1064}
1065
1066////////////////////////////////////////////////////////////////////////////////
1067/// check for name conflicts between the input samples and an argument set
1068template <class List>
1070{
1071 for (auto sampleit : inputParameters) {
1072 const std::string sample(sampleit.first);
1073 RooAbsArg *arg = args.find(sample.c_str());
1074 if (arg) {
1075 std::cerr << "detected name conflict: cannot use sample '" << sample
1076 << "' - a parameter with the same name of type '" << arg->ClassName() << "' is present in set '"
1077 << args.GetName() << "'!" << std::endl;
1078 }
1079 }
1080}
1081
1082////////////////////////////////////////////////////////////////////////////////
1083/// build the formulas corresponding to the given set of input files and
1084/// the physics process
1085
1088 const RooArgList &couplings, const RooArgList &flags,
1089 const std::vector<std::vector<std::string>> &nonInterfering)
1090{
1091 // example vbf hww:
1092 // Operators kSM, kHww, kAww, kHdwR,kHzz, kAzz
1093 // std::vector<bool> vertexProd = {true, true, true, true, true, true };
1094 // std::vector<bool> vertexDecay = {true, true, true, true, false,false};
1095 // diagram.push_back(vertexProd);
1096 // diagram.push_back(vertexDecay);
1097
1098 const int ncouplings = couplings.size();
1099 std::vector<bool> couplingsZero(ncouplings, true);
1100 std::map<TString, bool> flagsZero;
1101
1103 extractOperators(couplings, operators);
1104 size_t nOps = operators.size();
1105
1106 for (auto sampleit : inputParameters) {
1107 const std::string sample(sampleit.first);
1108 if (!setParams(sampleit.second, operators, true)) {
1109 std::cerr << "unable to set parameters for sample '" << sample << "'!" << std::endl;
1110 }
1111
1112 if (nOps != (operators.size())) {
1113 std::cerr << "internal error, number of operators inconsistent!" << std::endl;
1114 }
1115
1116 int idx = 0;
1117
1118 for (auto *obj0 : dynamic_range_cast<RooAbsReal *>(couplings)) {
1119 if (obj0->getVal() != 0) {
1120 couplingsZero[idx] = false;
1121 }
1122 idx++;
1123 }
1124 }
1125
1126 for (auto *obj1 : dynamic_range_cast<RooAbsReal *>(flags)) {
1127 int nZero = 0;
1128 int nNonZero = 0;
1129 for (auto sampleit : inputFlags) {
1130 const auto &flag = sampleit.second.find(obj1->GetName());
1131 if (flag != sampleit.second.end()) {
1132 if (flag->second == 0.) {
1133 nZero++;
1134 } else {
1135 nNonZero++;
1136 }
1137 }
1138 }
1139 if (nZero > 0 && nNonZero == 0) {
1140 flagsZero[obj1->GetName()] = true;
1141 } else {
1142 flagsZero[obj1->GetName()] = false;
1143 }
1144 }
1145
1146 FormulaList formulas;
1147 for (size_t i = 0; i < morphfunc.size(); ++i) {
1148 RooArgList ss;
1149 bool isZero = false;
1150 std::string reason;
1151 // check if this is a blacklisted interference term
1152 for (const auto &group : nonInterfering) {
1153 int nInterferingOperators = 0;
1154 for (size_t j = 0; j < morphfunc[i].size(); ++j) {
1155 if (morphfunc[i][j] % 2 == 0)
1156 continue; // even exponents are not interference terms
1157 // if the coupling is part of a "pairwise non-interfering group"
1158 if (std::find(group.begin(), group.end(), couplings.at(j)->GetName()) != group.end()) {
1160 }
1161 }
1162 if (nInterferingOperators > 1) {
1163 isZero = true;
1164 reason = "blacklisted interference term!";
1165 }
1166 }
1167 int nNP = 0;
1168 if (!isZero) {
1169 // prepare the term
1170 for (size_t j = 0; j < morphfunc[i].size(); ++j) {
1171 const int exponent = morphfunc[i][j];
1172 if (exponent == 0)
1173 continue;
1174 RooAbsReal *coupling = dynamic_cast<RooAbsReal *>(couplings.at(j));
1175 for (int k = 0; k < exponent; ++k) {
1176 ss.add(*coupling);
1177 if (coupling->getAttribute("NewPhysics")) {
1178 nNP++;
1179 }
1180 }
1181 std::string cname(coupling->GetName());
1182 if (coupling->getAttribute("LO") && exponent > 1) {
1183 isZero = true;
1184 reason = "coupling " + cname + " was listed as leading-order-only";
1185 }
1186 // mark the term as zero if any of the couplings are zero
1187 if (!isZero && couplingsZero[j]) {
1188 isZero = true;
1189 reason = "coupling " + cname + " is zero!";
1190 }
1191 }
1192 }
1193 // check and apply flags
1194 bool removedByFlag = false;
1195
1196 for (auto *obj : dynamic_range_cast<RooAbsReal *>(flags)) {
1197 if (!obj)
1198 continue;
1199 TString sval(obj->getStringAttribute("NewPhysics"));
1200 int val = atoi(sval);
1201 if (val == nNP) {
1202 if (flagsZero.find(obj->GetName()) != flagsZero.end() && flagsZero.at(obj->GetName())) {
1203 removedByFlag = true;
1204 reason = "flag " + std::string(obj->GetName()) + " is zero";
1205 }
1206 ss.add(*obj);
1207 }
1208 }
1209
1210 // create and add the formula
1211 if (!isZero && !removedByFlag) {
1212 // build the name
1213 const auto name = std::string(mfname) + "_pol" + std::to_string(i);
1214 formulas[i] = std::make_unique<RooProduct>(name.c_str(), ::concatNames(ss, " * ").c_str(), ss);
1215 }
1216 }
1217 return formulas;
1218}
1219
1220////////////////////////////////////////////////////////////////////////////////
1221/// create the weight formulas required for the morphing
1222
1223FormulaList createFormulas(const char *name, const RooLagrangianMorphFunc::ParamMap &inputs,
1225 const std::vector<std::vector<RooArgList *>> &diagrams, RooArgList &couplings,
1226 const RooArgList &flags, const std::vector<std::vector<std::string>> &nonInterfering)
1227{
1229
1230 for (const auto &vertices : diagrams) {
1232 ::fillFeynmanDiagram(d, vertices, couplings);
1234 }
1235 FormulaList retval = buildFormulas(name, inputs, inputFlags, morphfuncpattern, couplings, flags, nonInterfering);
1236 if (retval.empty()) {
1237 std::stringstream errorMsgStream;
1239 << "no formulas are non-zero, check if any if your couplings is floating and missing from your param_cards!"
1240 << std::endl;
1241 const auto errorMsg = errorMsgStream.str();
1242 throw std::runtime_error(errorMsg);
1243 }
1245 return retval;
1246}
1247
1248////////////////////////////////////////////////////////////////////////////////
1249/// build the sample weights required for the input templates
1250//
1251template <class T1>
1252inline void buildSampleWeights(T1 &weights, const char *fname, const RooLagrangianMorphFunc::ParamMap &inputParameters,
1253 FormulaList &formulas, const Matrix &inverse)
1254{
1255 int sampleidx = 0;
1256
1257 for (auto sampleit : inputParameters) {
1258 const std::string sample(sampleit.first);
1259 std::stringstream title;
1261 if (fname) {
1262 name_full.Append("_");
1263 name_full.Append(fname);
1264 name_full.Prepend("w_");
1265 }
1266
1267 int formulaidx = 0;
1268 // build the formula with the correct normalization
1269 auto sampleformula = std::make_unique<RooLinearCombination>(name_full.Data());
1270 for (auto const &formulait : formulas) {
1272 sampleformula->add(val, formulait.second.get());
1273 formulaidx++;
1274 }
1275 weights.addOwned(std::move(sampleformula));
1276 sampleidx++;
1277 }
1278}
1279
1280inline std::map<std::string, std::string>
1282 const Matrix &inverse)
1283{
1284 int sampleidx = 0;
1285 std::map<std::string, std::string> weights;
1286 for (auto sampleit : inputParameters) {
1287 const std::string sample(sampleit.first);
1288 std::stringstream str;
1289 int formulaidx = 0;
1290 // build the formula with the correct normalization
1291 for (auto const &formulait : formulas) {
1292 double val(inverse(formulaidx, sampleidx));
1293 if (val != 0.) {
1294 if (formulaidx > 0 && val > 0)
1295 str << " + ";
1296 str << val << "*(" << formulait.second->GetTitle() << ")";
1297 }
1298 formulaidx++;
1299 }
1300 weights[sample] = str.str();
1301 sampleidx++;
1302 }
1303 return weights;
1304}
1305} // namespace
1306
1307///////////////////////////////////////////////////////////////////////////////
1308// CacheElem magic ////////////////////////////////////////////////////////////
1309///////////////////////////////////////////////////////////////////////////////
1310
1312public:
1313 std::unique_ptr<RooRealSumFunc> _sumFunc = nullptr;
1315
1316 FormulaList _formulas;
1318
1322
1325
1326 //////////////////////////////////////////////////////////////////////////////
1327 /// retrieve the list of contained args
1328
1330 {
1331 RooArgList args(*_sumFunc);
1332 args.add(_weights);
1333 args.add(_couplings);
1334 for (auto const &it : _formulas) {
1335 args.add(*(it.second));
1336 }
1337 return args;
1338 }
1339
1340 //////////////////////////////////////////////////////////////////////////////
1341 /// create the basic objects required for the morphing
1342
1345 const std::vector<std::vector<RooListProxy *>> &diagramProxyList,
1346 const std::vector<std::vector<std::string>> &nonInterfering, const RooArgList &flags)
1347 {
1349 std::vector<std::vector<RooArgList *>> diagrams;
1350 for (const auto &diagram : diagramProxyList) {
1351 diagrams.emplace_back();
1352 for (RooArgList *vertex : diagram) {
1354 diagrams.back().emplace_back(vertex);
1355 }
1356 }
1359 }
1360
1361 //////////////////////////////////////////////////////////////////////////////
1362 /// build and invert the morphing matrix
1363 template <class List>
1365 const RooLagrangianMorphFunc::FlagMap &inputFlags, const List &flags)
1366 {
1370 if (size(matrix) < 1) {
1371 std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl;
1372 }
1374
1375 double condition = (double)(invertMatrix(matrix, inverse));
1376 double unityDeviation;
1377 double largestWeight;
1379 bool weightwarning(largestWeight > morphLargestWeight ? true : false);
1380 bool unitywarning(unityDeviation > morphUnityDeviation ? true : false);
1381
1382 if (false) {
1383 if (unitywarning) {
1384 oocxcoutW((TObject *)nullptr, Eval) << "Warning: The matrix inversion seems to be unstable. This can "
1385 "be a result to input samples that are not sufficiently "
1386 "different to provide any morphing power."
1387 << std::endl;
1388 } else if (weightwarning) {
1389 oocxcoutW((TObject *)nullptr, Eval) << "Warning: Some weights are excessively large. This can be a "
1390 "result to input samples that are not sufficiently different to "
1391 "provide any morphing power."
1392 << std::endl;
1393 }
1394 oocxcoutW((TObject *)nullptr, Eval) << " Please consider the couplings "
1395 "encoded in your samples to cross-check:"
1396 << std::endl;
1397 for (auto sampleit : inputParameters) {
1398 const std::string sample(sampleit.first);
1399 oocxcoutW((TObject *)nullptr, Eval) << " " << sample << ": ";
1400 // set all vars to value stored in input file
1401 setParams(sampleit.second, operators, true);
1402 bool first = true;
1403
1404 for (auto *obj : dynamic_range_cast<RooAbsReal *>(_couplings)) {
1405 if (!first)
1406 std::cerr << ", ";
1407 oocxcoutW((TObject *)nullptr, Eval) << obj->GetName() << "=" << obj->getVal();
1408 first = false;
1409 }
1410 oocxcoutW((TObject *)nullptr, Eval) << std::endl;
1411 }
1412 }
1413#ifndef USE_UBLAS
1414 _matrix.ResizeTo(matrix.GetNrows(), matrix.GetNrows());
1415 _inverse.ResizeTo(matrix.GetNrows(), matrix.GetNrows());
1416#endif
1417 _matrix = matrix;
1418 _inverse = inverse;
1419 _condition = condition;
1420 }
1421
1422 ////////////////////////////////////////////////////////////////////////////////
1423 /// build the final morphing function
1424
1426 const std::map<std::string, int> &storage, const RooArgList &physics,
1427 bool allowNegativeYields, RooRealVar *observable, RooRealVar *binWidth)
1428 {
1429 if (!binWidth) {
1430 std::cerr << "invalid bin width given!" << std::endl;
1431 return;
1432 }
1433 if (!observable) {
1434 std::cerr << "invalid observable given!" << std::endl;
1435 return;
1436 }
1437
1440
1441 // retrieve the weights
1443
1444 // build the products of element and weight for each sample
1445 size_t i = 0;
1448 for (auto sampleit : inputParameters) {
1449 // for now, we assume all the lists are nicely ordered
1451
1452 RooAbsReal *obj = static_cast<RooAbsReal *>(physics.at(storage.at(prodname.Data())));
1453
1454 if (!obj) {
1455 std::cerr << "unable to access physics object for " << prodname << std::endl;
1456 return;
1457 }
1458
1459 RooAbsReal *weight = static_cast<RooAbsReal *>(_weights.at(i));
1460
1461 if (!weight) {
1462 std::cerr << "unable to access weight object for " << prodname << std::endl;
1463 return;
1464 }
1465 prodname.Append("_");
1466 prodname.Append(name);
1467 RooArgList prodElems(*weight, *obj);
1468
1469 allowNegativeYields = true;
1470 auto prod = std::make_unique<RooProduct>(prodname, prodname, prodElems);
1471 if (!allowNegativeYields) {
1472 auto maxname = std::string(prodname) + "_max0";
1473 RooArgSet prodset(*prod);
1474
1475 auto max = std::make_unique<RooFormulaVar>(maxname.c_str(), "max(0," + prodname + ")", prodset);
1476 max->addOwnedComponents(std::move(prod));
1477 sumElements.addOwned(std::move(max));
1478 } else {
1479 sumElements.addOwned(std::move(prod));
1480 }
1481 scaleElements.add(*(binWidth));
1482 i++;
1483 }
1484
1485 // put everything together
1486 _sumFunc = make_unique<RooRealSumFunc>((std::string(name) + "_morphfunc").c_str(), name, sumElements, scaleElements);
1487
1488 if (!observable)
1489 std::cerr << "unable to access observable" << std::endl;
1490 _sumFunc->addServer(*observable);
1491 if (!binWidth)
1492 std::cerr << "unable to access bin width" << std::endl;
1493 _sumFunc->addServer(*binWidth);
1494 if (operators.empty())
1495 std::cerr << "no operators listed" << std::endl;
1496 _sumFunc->addServerList(operators);
1497 if (_weights.empty())
1498 std::cerr << "unable to access weight objects" << std::endl;
1499 _sumFunc->addOwnedComponents(std::move(sumElements));
1500 _sumFunc->addServerList(sumElements);
1501 _sumFunc->addServerList(scaleElements);
1502
1503#ifdef USE_UBLAS
1504 std::cout.precision(std::numeric_limits<double>::digits);
1505#endif
1506 }
1507 //////////////////////////////////////////////////////////////////////////////
1508 /// create all the temporary objects required by the class
1509
1511 {
1512 std::string obsName = func->getObservable()->GetName();
1514
1516
1517 cache->createComponents(func->_config.paramCards, func->_config.flagValues, func->GetName(), func->_diagrams,
1518 func->_nonInterfering, func->_flags);
1519
1520 cache->buildMatrix(func->_config.paramCards, func->_config.flagValues, func->_flags);
1521 if (obsName.empty()) {
1522 std::cerr << "Matrix inversion succeeded, but no observable was "
1523 "supplied. quitting..."
1524 << std::endl;
1525 return cache;
1526 }
1527
1528 oocxcoutP((TObject *)nullptr, ObjectHandling) << "observable: " << func->getObservable()->GetName() << std::endl;
1529 oocxcoutP((TObject *)nullptr, ObjectHandling) << "binWidth: " << func->getBinWidth()->GetName() << std::endl;
1530
1531 setParams(func->_flags, 1);
1532 cache->buildMorphingFunction(func->GetName(), func->_config.paramCards, func->_sampleMap, func->_physics,
1533 func->_config.allowNegativeYields, func->getObservable(), func->getBinWidth());
1534 setParams(values, func->_operators, true);
1535 setParams(func->_flags, 1);
1536 return cache;
1537 }
1538
1539 //////////////////////////////////////////////////////////////////////////////
1540 /// create all the temporary objects required by the class
1541 /// function variant with precomputed inverse matrix
1542
1544 {
1546
1548
1549 cache->createComponents(func->_config.paramCards, func->_config.flagValues, func->GetName(), func->_diagrams,
1550 func->_nonInterfering, func->_flags);
1551
1552#ifndef USE_UBLAS
1553 cache->_inverse.ResizeTo(inverse.GetNrows(), inverse.GetNrows());
1554#endif
1555 cache->_inverse = inverse;
1556 cache->_condition = NaN;
1557
1558 setParams(func->_flags, 1);
1559 cache->buildMorphingFunction(func->GetName(), func->_config.paramCards, func->_sampleMap, func->_physics,
1560 func->_config.allowNegativeYields, func->getObservable(), func->getBinWidth());
1561 setParams(values, func->_operators, true);
1562 setParams(func->_flags, 1);
1563 return cache;
1564 }
1565};
1566
1567///////////////////////////////////////////////////////////////////////////////
1568// Class Implementation ///////////////////////////////////////////////////////
1569///////////////////////////////////////////////////////////////////////////////
1570
1571////////////////////////////////////////////////////////////////////////////////
1572/// write a matrix to a file
1573
1578
1579////////////////////////////////////////////////////////////////////////////////
1580/// write a matrix to a stream
1581
1583{
1585}
1586
1587////////////////////////////////////////////////////////////////////////////////
1588/// read a matrix from a text file
1589
1594
1595////////////////////////////////////////////////////////////////////////////////
1596/// read a matrix from a stream
1597
1602
1603////////////////////////////////////////////////////////////////////////////////
1604/// setup observable, recycle existing observable if defined
1605
1607{
1608 // cxcoutP(ObjectHandling) << "setting up observable" << std::endl;
1609 RooRealVar *obs = nullptr;
1610 bool obsExists(false);
1611 if (_observables.at(0) != nullptr) {
1612 obs = static_cast<RooRealVar *>(_observables.at(0));
1613 obsExists = true;
1614 }
1615
1616 if (mode && mode->InheritsFrom(RooHistFunc::Class())) {
1617 obs = static_cast<RooRealVar *>(dynamic_cast<RooHistFunc *>(inputExample)->getHistObsList().first());
1618 obsExists = true;
1619 _observables.add(*obs);
1620 } else if (mode && mode->InheritsFrom(RooParamHistFunc::Class())) {
1621 obs = static_cast<RooRealVar *>(dynamic_cast<RooParamHistFunc *>(inputExample)->paramList().first());
1622 obsExists = true;
1623 _observables.add(*obs);
1624 }
1625
1626 // Note: "found!" will be printed if s2 is a substring of s1, both s1 and s2
1627 // are of type std::string. s1.find(s2)
1628 // obtain the observable
1629 if (!obsExists) {
1630 if (mode && mode->InheritsFrom(TH1::Class())) {
1631 TH1 *hist = static_cast<TH1 *>(inputExample);
1632 auto obsOwner =
1633 std::make_unique<RooRealVar>(obsname, obsname, hist->GetXaxis()->GetXmin(), hist->GetXaxis()->GetXmax());
1634 obs = obsOwner.get();
1635 addOwnedComponents(std::move(obsOwner));
1636 obs->setBins(hist->GetNbinsX());
1637 } else {
1638 auto obsOwner = std::make_unique<RooRealVar>(obsname, obsname, 0, 1);
1639 obs = obsOwner.get();
1640 addOwnedComponents(std::move(obsOwner));
1641 obs->setBins(1);
1642 }
1643 _observables.add(*obs);
1644 } else {
1645 if (strcmp(obsname, obs->GetName()) != 0) {
1646 coutW(ObjectHandling) << " name of existing observable " << _observables.at(0)->GetName()
1647 << " does not match expected name " << obsname << std::endl;
1648 }
1649 }
1650
1651 TString sbw = TString::Format("binWidth_%s", makeValidName(obs->GetName()).Data());
1652 auto binWidth = std::make_unique<RooRealVar>(sbw.Data(), sbw.Data(), 1.);
1653 double bw = obs->numBins() / (obs->getMax() - obs->getMin());
1654 binWidth->setVal(bw);
1655 binWidth->setConstant(true);
1656 _binWidths.addOwned(std::move(binWidth));
1657
1658 return obs;
1659}
1660
1661//#ifndef USE_MULTIPRECISION_LC
1662//#pragma GCC diagnostic push
1663//#pragma GCC diagnostic ignored "-Wunused-parameter"
1664//#endif
1665
1666////////////////////////////////////////////////////////////////////////////////
1667/// update sample weight (-?-)
1668
1670{
1671 //#ifdef USE_MULTIPRECISION_LC
1672 int sampleidx = 0;
1673 auto cache = this->getCache();
1674 const size_t n(size(cache->_inverse));
1675 for (auto sampleit : _config.paramCards) {
1676 const std::string sample(sampleit.first);
1677 // build the formula with the correct normalization
1678 RooLinearCombination *sampleformula = dynamic_cast<RooLinearCombination *>(this->getSampleWeight(sample.c_str()));
1679 if (!sampleformula) {
1680 coutE(ObjectHandling) << Form("unable to access formula for sample '%s'!", sample.c_str()) << std::endl;
1681 return;
1682 }
1683 cxcoutP(ObjectHandling) << "updating formula for sample '" << sample << "'" << std::endl;
1684 for (size_t formulaidx = 0; formulaidx < n; ++formulaidx) {
1685 const RooFit::SuperFloat val(cache->_inverse(formulaidx, sampleidx));
1686#ifdef USE_UBLAS
1687 if (val != val) {
1688#else
1689 if (std::isnan(val)) {
1690#endif
1691 coutE(ObjectHandling) << "refusing to propagate NaN!" << std::endl;
1692 }
1693 cxcoutP(ObjectHandling) << " " << formulaidx << ":" << sampleformula->getCoefficient(formulaidx) << " -> "
1694 << val << std::endl;
1695 sampleformula->setCoefficient(formulaidx, val);
1696 assert(sampleformula->getCoefficient(formulaidx) == val);
1697 }
1698 sampleformula->setValueDirty();
1699 ++sampleidx;
1700 }
1701 //#else
1702 // ERROR("updating sample weights currently not possible without boost!");
1703 //#endif
1704}
1705//#ifndef USE_MULTIPRECISION_LC
1706//#pragma GCC diagnostic pop
1707//#endif
1708
1709////////////////////////////////////////////////////////////////////////////////
1710/// read the parameters from the input file
1711
1717
1718////////////////////////////////////////////////////////////////////////////////
1719/// retrieve the physics inputs
1720
1722{
1723 std::string obsName;
1724 if (_config.observable) {
1726 if (_config.observableName.empty()) {
1728 } else {
1730 }
1731 } else {
1733 }
1734
1735 cxcoutP(InputArguments) << "initializing physics inputs from file " << file->GetName() << " with object name(s) '"
1736 << obsName << "'" << std::endl;
1737 auto folderNames = _config.folderNames;
1738 auto obj = loadFromFileResidentFolder<TObject>(file, folderNames.front(), obsName, true);
1739 if (!obj) {
1740 std::cerr << "unable to locate object '" << obsName << "' in folder '" << folderNames.front() << "'!"
1741 << std::endl;
1742 return;
1743 }
1744 std::string classname = obj->ClassName();
1745 TClass *mode = TClass::GetClass(obj->ClassName());
1746 this->setupObservable(obsName.c_str(), mode, obj.get());
1747
1748 if (classname.find("TH1") != std::string::npos) {
1749 collectHistograms(this->GetName(), file, _sampleMap, _physics, *static_cast<RooRealVar *>(_observables.at(0)),
1751 } else if (classname.find("RooHistFunc") != std::string::npos ||
1752 classname.find("RooParamHistFunc") != std::string::npos ||
1753 classname.find("PiecewiseInterpolation") != std::string::npos) {
1755 } else if (classname.find("TParameter<double>") != std::string::npos) {
1757 } else if (classname.find("TParameter<float>") != std::string::npos) {
1759 } else if (classname.find("TPair") != std::string::npos) {
1760 collectCrosssectionsTPair(this->GetName(), file, _sampleMap, _physics, obsName, folderNames[0],
1762 } else {
1763 std::cerr << "cannot morph objects of class '" << mode->GetName() << "'!" << std::endl;
1764 }
1765}
1766
1767////////////////////////////////////////////////////////////////////////////////
1768/// print all the parameters and their values in the given sample to the console
1769
1771{
1772 for (const auto &param : _config.paramCards.at(samplename)) {
1773 if (this->hasParameter(param.first.c_str())) {
1774 std::cout << param.first << " = " << param.second;
1775 if (this->isParameterConstant(param.first.c_str()))
1776 std::cout << " (const)";
1777 std::cout << std::endl;
1778 }
1779 }
1780}
1781
1782////////////////////////////////////////////////////////////////////////////////
1783/// print all the known samples to the console
1784
1786{
1787 // print all the known samples to the console
1788 for (auto folder : _config.folderNames) {
1789 std::cout << folder << std::endl;
1790 }
1791}
1792
1793////////////////////////////////////////////////////////////////////////////////
1794/// print the current physics values
1795
1797{
1798 for (const auto &sample : _sampleMap) {
1799 RooAbsArg *phys = _physics.at(sample.second);
1800 if (!phys)
1801 continue;
1802 phys->Print();
1803 }
1804}
1805
1806////////////////////////////////////////////////////////////////////////////////
1807/// constructor with proper arguments
1808
1809RooLagrangianMorphFunc::RooLagrangianMorphFunc(const char *name, const char *title, const Config &config)
1810 : RooAbsReal(name, title), _cacheMgr(this, 10, true, true), _physics("physics", "physics", this),
1811 _operators("operators", "set of operators", this), _observables("observables", "morphing observables", this),
1812 _binWidths("binWidths", "set of binWidth objects", this), _flags("flags", "flags", this), _config(config)
1813{
1814 this->init();
1816 this->setup(false);
1817
1819}
1820
1821////////////////////////////////////////////////////////////////////////////////
1822/// setup this instance with the given set of operators and vertices
1823/// if own=true, the class will own the operators template `<class Base>`
1824
1826{
1827 if (!_config.couplings.empty()) {
1829 std::vector<RooListProxy *> vertices;
1831 vertices.push_back(new RooListProxy("!couplings", "set of couplings in the vertex", this, true, false));
1832 if (own) {
1833 _operators.addOwned(std::move(operators));
1834 vertices[0]->addOwned(_config.couplings);
1835 } else {
1837 vertices[0]->add(_config.couplings);
1838 }
1839 _diagrams.push_back(vertices);
1840 }
1841
1843 std::vector<RooListProxy *> vertices;
1845 cxcoutP(InputArguments) << "prod/dec couplings provided" << std::endl;
1848 vertices.push_back(
1849 new RooListProxy("!production", "set of couplings in the production vertex", this, true, false));
1850 vertices.push_back(new RooListProxy("!decay", "set of couplings in the decay vertex", this, true, false));
1851 if (own) {
1852 _operators.addOwned(std::move(operators));
1853 vertices[0]->addOwned(_config.prodCouplings);
1854 vertices[1]->addOwned(_config.decCouplings);
1855 } else {
1856 cxcoutP(InputArguments) << "adding non-own operators" << std::endl;
1858 vertices[0]->add(_config.prodCouplings);
1859 vertices[1]->add(_config.decCouplings);
1860 }
1861 _diagrams.push_back(vertices);
1862 }
1863}
1864
1865////////////////////////////////////////////////////////////////////////////////
1866/// disable interference between terms
1867
1868void RooLagrangianMorphFunc::disableInterference(const std::vector<const char *> &nonInterfering)
1869{
1870 // disable interference between the listed operators
1871 std::stringstream name;
1872 name << "noInterference";
1873 for (auto c : nonInterfering) {
1874 name << c;
1875 }
1876 _nonInterfering.emplace_back();
1877 for (auto c : nonInterfering) {
1878 _nonInterfering.back().emplace_back(c);
1879 }
1880}
1881
1882////////////////////////////////////////////////////////////////////////////////
1883/// disable interference between terms
1884
1885void RooLagrangianMorphFunc::disableInterferences(const std::vector<std::vector<const char *>> &nonInterfering)
1886{
1887 // disable interferences between the listed groups of operators
1888 for (size_t i = 0; i < nonInterfering.size(); ++i) {
1889 this->disableInterference(nonInterfering[i]);
1890 }
1891}
1892
1893////////////////////////////////////////////////////////////////////////////////
1894/// initialise inputs required for the morphing function
1895
1897{
1898 std::string filename = _config.fileName;
1899 TDirectory *file = openFile(filename);
1900 if (!file) {
1901 coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl;
1902 return;
1903 }
1904 this->readParameters(file);
1906 this->collectInputs(file);
1907 closeFile(file);
1908 auto nNP0 = std::make_unique<RooRealVar>("nNP0", "nNP0", 1., 0, 1.);
1909 nNP0->setStringAttribute("NewPhysics", "0");
1910 nNP0->setConstant(true);
1911 _flags.addOwned(std::move(nNP0));
1912 auto nNP1 = std::make_unique<RooRealVar>("nNP1", "nNP1", 1., 0, 1.);
1913 nNP1->setStringAttribute("NewPhysics", "1");
1914 nNP1->setConstant(true);
1915 _flags.addOwned(std::move(nNP1));
1916 auto nNP2 = std::make_unique<RooRealVar>("nNP2", "nNP2", 1., 0, 1.);
1917 nNP2->setStringAttribute("NewPhysics", "2");
1918 nNP2->setConstant(true);
1919 _flags.addOwned(std::move(nNP2));
1920 auto nNP3 = std::make_unique<RooRealVar>("nNP3", "nNP3", 1., 0, 1.);
1921 nNP3->setStringAttribute("NewPhysics", "3");
1922 nNP3->setConstant(true);
1923 _flags.addOwned(std::move(nNP3));
1924 auto nNP4 = std::make_unique<RooRealVar>("nNP4", "nNP4", 1., 0, 1.);
1925 nNP4->setStringAttribute("NewPhysics", "4");
1926 nNP4->setConstant(true);
1927 _flags.addOwned(std::move(nNP4));
1928}
1929
1930////////////////////////////////////////////////////////////////////////////////
1931/// copy constructor
1932
1934 : RooAbsReal(other, name), _cacheMgr(other._cacheMgr, this), _scale(other._scale), _sampleMap(other._sampleMap),
1935 _physics(other._physics.GetName(), this, other._physics),
1936 _operators(other._operators.GetName(), this, other._operators),
1937 _observables(other._observables.GetName(), this, other._observables),
1938 _binWidths(other._binWidths.GetName(), this, other._binWidths), _flags{other._flags.GetName(), this, other._flags},
1939 _config(other._config)
1940{
1941 for (size_t j = 0; j < other._diagrams.size(); ++j) {
1942 std::vector<RooListProxy *> diagram;
1943 for (auto *elem : other._diagrams[j]) {
1944 RooListProxy *list = new RooListProxy(elem->GetName(), this, *elem);
1945 diagram.push_back(list);
1946 }
1947 _diagrams.push_back(diagram);
1948 }
1950}
1951
1952////////////////////////////////////////////////////////////////////////////////
1953/// set energy scale of the EFT expansion
1954
1956{
1957 _scale = val;
1958}
1959
1960////////////////////////////////////////////////////////////////////////////////
1961/// get energy scale of the EFT expansion
1962
1964{
1965 return _scale;
1966}
1967
1968////////////////////////////////////////////////////////////////////////////////
1969// default constructor
1970
1972 : _cacheMgr(this, 10, true, true), _operators("operators", "set of operators", this, true, false),
1973 _observables("observable", "morphing observable", this, true, false),
1974 _binWidths("binWidths", "set of bin width objects", this, true, false)
1975{
1977}
1978
1979////////////////////////////////////////////////////////////////////////////////
1980/// default destructor
1981
1983{
1984 for (auto const &diagram : _diagrams) {
1985 for (RooListProxy *vertex : diagram) {
1986 delete vertex;
1987 }
1988 }
1990}
1991
1992////////////////////////////////////////////////////////////////////////////////
1993/// calculate the number of samples needed to morph a bivertex, 2-2 physics
1994/// process
1995
1997{
1999 std::vector<bool> prod;
2000 std::vector<bool> dec;
2001 for (int i = 0; i < nboth; ++i) {
2002 prod.push_back(true);
2003 dec.push_back(true);
2004 }
2005 for (int i = 0; i < nprod; ++i) {
2006 prod.push_back(true);
2007 dec.push_back(false);
2008 }
2009 for (int i = 0; i < ndec; ++i) {
2010 prod.push_back(false);
2011 dec.push_back(true);
2012 }
2013 diagram.push_back(prod);
2014 diagram.push_back(dec);
2017 return morphfuncpattern.size();
2018}
2019
2020////////////////////////////////////////////////////////////////////////////////
2021/// calculate the number of samples needed to morph a certain physics process
2022
2023int RooLagrangianMorphFunc::countSamples(std::vector<RooArgList *> &vertices)
2024{
2026 RooArgList couplings;
2027 for (auto vertex : vertices) {
2029 extractCouplings(*vertex, couplings);
2030 }
2032 ::fillFeynmanDiagram(diagram, vertices, couplings);
2035 return morphfuncpattern.size();
2036}
2037
2038////////////////////////////////////////////////////////////////////////////////
2039/// create only the weight formulas. static function for external usage.
2040
2041std::map<std::string, std::string>
2043 const std::vector<std::vector<std::string>> &vertices_str)
2044{
2045 std::stack<RooArgList> ownedVertices;
2046 std::vector<RooArgList *> vertices;
2047 RooArgList couplings;
2048 for (const auto &vtx : vertices_str) {
2049 ownedVertices.emplace();
2050 auto &vertex = ownedVertices.top();
2051 for (const auto &c : vtx) {
2052 auto coupling = static_cast<RooRealVar *>(couplings.find(c.c_str()));
2053 if (!coupling) {
2054 auto couplingOwner = std::make_unique<RooRealVar>(c.c_str(), c.c_str(), 1., 0., 10.);
2055 coupling = couplingOwner.get();
2056 couplings.addOwned(std::move(couplingOwner));
2057 }
2058 vertex.add(*coupling);
2059 }
2060 vertices.push_back(&vertex);
2061 }
2062 auto retval = RooLagrangianMorphFunc::createWeightStrings(inputs, vertices, couplings);
2063 return retval;
2064}
2065
2066////////////////////////////////////////////////////////////////////////////////
2067/// create only the weight formulas. static function for external usage.
2068
2069std::map<std::string, std::string>
2071 const std::vector<RooArgList *> &vertices, RooArgList &couplings)
2072{
2073 return createWeightStrings(inputs, vertices, couplings, {}, {}, {});
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 const RooLagrangianMorphFunc::FlagMap &flagValues, const RooArgList &flags,
2083 const std::vector<std::vector<std::string>> &nonInterfering)
2084{
2085 FormulaList formulas = ::createFormulas("", inputs, flagValues, {vertices}, couplings, flags, nonInterfering);
2087 extractOperators(couplings, operators);
2089 if (size(matrix) < 1) {
2090 std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl;
2091 }
2093 double condition __attribute__((unused)) = (double)(invertMatrix(matrix, inverse));
2095 return retval;
2096}
2097
2098////////////////////////////////////////////////////////////////////////////////
2099/// create only the weight formulas. static function for external usage.
2100
2102 const std::vector<RooArgList *> &vertices, RooArgList &couplings,
2103 const RooLagrangianMorphFunc::FlagMap &flagValues,
2104 const RooArgList &flags,
2105 const std::vector<std::vector<std::string>> &nonInterfering)
2106{
2107 FormulaList formulas = ::createFormulas("", inputs, flagValues, {vertices}, couplings, flags, nonInterfering);
2109 extractOperators(couplings, operators);
2111 if (size(matrix) < 1) {
2112 std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl;
2113 }
2115 double condition __attribute__((unused)) = (double)(invertMatrix(matrix, inverse));
2117 ::buildSampleWeights(retval, (const char *)nullptr /* name */, inputs, formulas, inverse);
2118 return retval;
2119}
2120
2121////////////////////////////////////////////////////////////////////////////////
2122/// create only the weight formulas. static function for external usage.
2123
2125 const std::vector<RooArgList *> &vertices, RooArgList &couplings)
2126{
2127 RooArgList flags;
2128 FlagMap flagValues;
2129 return RooLagrangianMorphFunc::createWeights(inputs, vertices, couplings, flagValues, flags, {});
2130}
2131
2132////////////////////////////////////////////////////////////////////////////////
2133/// return the RooProduct that is the element of the RooRealSumPdfi
2134/// corresponding to the given sample name
2135
2137{
2138 auto mf = this->getFunc();
2139 if (!mf) {
2140 coutE(Eval) << "unable to retrieve morphing function" << std::endl;
2141 return nullptr;
2142 }
2143 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2145 prodname.Append("_");
2146 prodname.Append(this->GetName());
2147
2148 for (auto *prod : dynamic_range_cast<RooProduct *>(*args)) {
2149 if (!prod)
2150 continue;
2151 TString sname(prod->GetName());
2152 if (sname.CompareTo(prodname) == 0) {
2153 return prod;
2154 }
2155 }
2156 return nullptr;
2157}
2158////////////////////////////////////////////////////////////////////////////////
2159/// return the vector of sample names, used to build the morph func
2160
2161std::vector<std::string> RooLagrangianMorphFunc::getSamples() const
2162{
2163 return _config.folderNames;
2164}
2165
2166////////////////////////////////////////////////////////////////////////////////
2167/// retrieve the weight (prefactor) of a sample with the given name
2168
2170{
2171 auto cache = this->getCache();
2172 auto wname = std::string("w_") + name + "_" + this->GetName();
2173 return dynamic_cast<RooAbsReal *>(cache->_weights.find(wname.c_str()));
2174}
2175
2176////////////////////////////////////////////////////////////////////////////////
2177/// print the current sample weights
2178
2180{
2181 this->printSampleWeights();
2182}
2183
2184////////////////////////////////////////////////////////////////////////////////
2185/// print the current sample weights
2186
2188{
2189 auto *cache = this->getCache();
2190 for (const auto &sample : _sampleMap) {
2191 auto weightName = std::string("w_") + sample.first + "_" + this->GetName();
2192 auto weight = static_cast<RooAbsReal *>(cache->_weights.find(weightName.c_str()));
2193 if (!weight)
2194 continue;
2195 }
2196}
2197
2198////////////////////////////////////////////////////////////////////////////////
2199/// randomize the parameters a bit
2200/// useful to test and debug fitting
2201
2203{
2204 TRandom3 r;
2205
2206 for (auto *obj : dynamic_range_cast<RooRealVar *>(_operators)) {
2207 double val = obj->getVal();
2208 if (obj->isConstant())
2209 continue;
2210 double variation = r.Gaus(1, z);
2211 obj->setVal(val * variation);
2212 }
2213}
2214
2215////////////////////////////////////////////////////////////////////////////////
2216/// Retrieve the new physics objects and update the weights in the morphing
2217/// function.
2218
2220{
2221 auto cache = this->getCache();
2222
2223 std::string filename = _config.fileName;
2224 TDirectory *file = openFile(filename);
2225 if (!file) {
2226 coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl;
2227 return false;
2228 }
2229
2230 this->readParameters(file);
2231
2233 this->collectInputs(file);
2234
2235 cache->buildMatrix(_config.paramCards, _config.flagValues, _flags);
2236 this->updateSampleWeights();
2237
2238 closeFile(file);
2239 return true;
2240}
2241
2242////////////////////////////////////////////////////////////////////////////////
2243/// setup the morphing function with a predefined inverse matrix
2244/// call this function *before* any other after creating the object
2245
2247{
2248 auto cache = static_cast<RooLagrangianMorphFunc::CacheElem *>(
2249 _cacheMgr.getObj(nullptr, static_cast<RooArgSet const *>(nullptr)));
2251 if (cache) {
2252 std::string filename = _config.fileName;
2253 cache->_inverse = m;
2254 TDirectory *file = openFile(filename);
2255 if (!file) {
2256 coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl;
2257 return false;
2258 }
2259
2260 this->readParameters(file);
2262 this->collectInputs(file);
2263
2264 // then, update the weights in the morphing function
2265 this->updateSampleWeights();
2266
2267 closeFile(file);
2268 } else {
2270 if (!cache)
2271 coutE(Caching) << "unable to create cache!" << std::endl;
2272 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
2273 }
2274 return true;
2275}
2276
2277////////////////////////////////////////////////////////////////////////////////
2278// setup the morphing function with a predefined inverse matrix
2279// call this function *before* any other after creating the object
2280
2282{
2283 auto cache = static_cast<RooLagrangianMorphFunc::CacheElem *>(
2284 _cacheMgr.getObj(nullptr, static_cast<RooArgSet const *>(nullptr)));
2285 if (cache) {
2286 return false;
2287 }
2289 if (!cache)
2290 coutE(Caching) << "unable to create cache!" << std::endl;
2291 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
2292 return true;
2293}
2294
2295////////////////////////////////////////////////////////////////////////////////
2296/// write the inverse matrix to a file
2297
2299{
2300 auto cache = this->getCache();
2301 if (!cache)
2302 return false;
2303 writeMatrixToFileT(cache->_inverse, filename);
2304 return true;
2305}
2306
2307////////////////////////////////////////////////////////////////////////////////
2308/// retrieve the cache object
2309
2311{
2312 auto cache = static_cast<RooLagrangianMorphFunc::CacheElem *>(
2313 _cacheMgr.getObj(nullptr, static_cast<RooArgSet const *>(nullptr)));
2314 if (!cache) {
2315 cxcoutP(Caching) << "creating cache from getCache function for " << this << std::endl;
2316 cxcoutP(Caching) << "current storage has size " << _sampleMap.size() << std::endl;
2318 if (cache) {
2319 _cacheMgr.setObj(nullptr, nullptr, cache, nullptr);
2320 } else {
2321 coutE(Caching) << "unable to create cache!" << std::endl;
2322 }
2323 }
2324 return cache;
2325}
2326
2327////////////////////////////////////////////////////////////////////////////////
2328/// return true if a cache object is present, false otherwise
2329
2331{
2332 return (bool)(_cacheMgr.getObj(nullptr, static_cast<RooArgSet *>(nullptr)));
2333}
2334
2335////////////////////////////////////////////////////////////////////////////////
2336/// set one parameter to a specific value
2337
2339{
2340 RooRealVar *param = this->getParameter(name);
2341 if (!param) {
2342 return;
2343 }
2344 if (value > param->getMax())
2345 param->setMax(value);
2346 if (value < param->getMin())
2347 param->setMin(value);
2348 param->setVal(value);
2349}
2350
2351////////////////////////////////////////////////////////////////////////////////
2352/// set one flag to a specific value
2353
2355{
2356 RooRealVar *param = this->getFlag(name);
2357 if (!param) {
2358 return;
2359 }
2360 param->setVal(value);
2361}
2362
2363////////////////////////////////////////////////////////////////////////////////
2364/// set one parameter to a specific value and range
2365
2366void RooLagrangianMorphFunc::setParameter(const char *name, double value, double min, double max)
2367{
2368 RooRealVar *param = this->getParameter(name);
2369 if (!param) {
2370 return;
2371 }
2372 param->setMin(min);
2373 param->setMax(max);
2374 param->setVal(value);
2375}
2376
2377////////////////////////////////////////////////////////////////////////////////
2378/// set one parameter to a specific value and range
2379void RooLagrangianMorphFunc::setParameter(const char *name, double value, double min, double max, double error)
2380{
2381 RooRealVar *param = this->getParameter(name);
2382 if (!param) {
2383 return;
2384 }
2385 param->setMin(min);
2386 param->setMax(max);
2387 param->setVal(value);
2388 param->setError(error);
2389}
2390
2391////////////////////////////////////////////////////////////////////////////////
2392/// return true if the parameter with the given name is set constant, false
2393/// otherwise
2394
2396{
2397 RooRealVar *param = this->getParameter(name);
2398 if (param) {
2399 return param->isConstant();
2400 }
2401 return true;
2402}
2403
2404////////////////////////////////////////////////////////////////////////////////
2405/// retrieve the RooRealVar object incorporating the parameter with the given
2406/// name
2408{
2409
2410 return dynamic_cast<RooRealVar *>(_operators.find(name));
2411}
2412
2413////////////////////////////////////////////////////////////////////////////////
2414/// retrieve the RooRealVar object incorporating the flag with the given name
2415
2417{
2418 return dynamic_cast<RooRealVar *>(_flags.find(name));
2419}
2420
2421////////////////////////////////////////////////////////////////////////////////
2422/// check if a parameter of the given name is contained in the list of known
2423/// parameters
2424
2426{
2427 return this->getParameter(name);
2428}
2429
2430////////////////////////////////////////////////////////////////////////////////
2431/// call setConstant with the boolean argument provided on the parameter with
2432/// the given name
2433
2435{
2436 RooRealVar *param = this->getParameter(name);
2437 if (param) {
2438 return param->setConstant(constant);
2439 }
2440}
2441
2442////////////////////////////////////////////////////////////////////////////////
2443/// set one parameter to a specific value
2444
2446{
2447 RooRealVar *param = this->getParameter(name);
2448 if (param) {
2449 return param->getVal();
2450 }
2451 return 0.0;
2452}
2453
2454////////////////////////////////////////////////////////////////////////////////
2455/// set the morphing parameters to those supplied in the given param hist
2456
2461
2462////////////////////////////////////////////////////////////////////////////////
2463/// set the morphing parameters to those supplied in the sample with the given
2464/// name
2465
2467{
2468 std::string filename = _config.fileName;
2469 TDirectory *file = openFile(filename);
2470 auto paramhist = loadFromFileResidentFolder<TH1>(file, foldername, "param_card");
2471 setParams(paramhist.get(), _operators, false);
2472 closeFile(file);
2473}
2474
2475/////////////////////////////////////////////////////////////////////////////////
2476/// retrieve the morphing parameters associated to the sample with the given
2477/// name
2478
2484
2485////////////////////////////////////////////////////////////////////////////////
2486/// set the morphing parameters to those supplied in the list with the given
2487/// name
2488
2490{
2491 for (auto *param : dynamic_range_cast<RooRealVar *>(*list)) {
2492 if (!param)
2493 continue;
2494 this->setParameter(param->GetName(), param->getVal());
2495 }
2496}
2497
2498////////////////////////////////////////////////////////////////////////////////
2499/// retrieve the histogram observable
2500
2502{
2503 if (_observables.empty()) {
2504 coutE(InputArguments) << "observable not available!" << std::endl;
2505 return nullptr;
2506 }
2507 return static_cast<RooRealVar *>(_observables.at(0));
2508}
2509
2510////////////////////////////////////////////////////////////////////////////////
2511/// retrieve the histogram observable
2512
2514{
2515 if (_binWidths.empty()) {
2516 coutE(InputArguments) << "bin width not available!" << std::endl;
2517 return nullptr;
2518 }
2519 return static_cast<RooRealVar *>(_binWidths.at(0));
2520}
2521
2522////////////////////////////////////////////////////////////////////////////////
2523/// retrieve a histogram output of the current morphing settings
2524
2526{
2527 return this->createTH1(name, false);
2528}
2529
2530////////////////////////////////////////////////////////////////////////////////
2531/// retrieve a histogram output of the current morphing settings
2532
2534{
2535 auto mf = std::make_unique<RooRealSumFunc>(*(this->getFunc()));
2536 RooRealVar *observable = this->getObservable();
2537
2538 const int nbins = observable->getBins();
2539
2540 auto hist = std::make_unique<TH1F>(name.c_str(), name.c_str(), nbins, observable->getBinning().array());
2541
2542 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2543 for (int i = 0; i < nbins; ++i) {
2544 observable->setBin(i);
2545 double val = 0;
2546 double unc2 = 0;
2547 double unc = 0;
2548 for (auto *prod : dynamic_range_cast<RooProduct *>(*args)) {
2549 if (!prod)
2550 continue;
2551 RooAbsArg *phys = prod->components().find(Form("phys_%s", prod->GetName()));
2552 RooHistFunc *hf = dynamic_cast<RooHistFunc *>(phys);
2553 if (!hf) {
2554 continue;
2555 }
2556 const RooDataHist &dhist = hf->dataHist();
2557 RooAbsReal *formula = dynamic_cast<RooAbsReal *>(prod->components().find(Form("w_%s", prod->GetName())));
2558 double weight = formula->getVal();
2559 const double w2 = dhist.weightSquared(i);
2560 unc2 += w2 * weight * weight;
2561 unc += sqrt(w2) * weight;
2562 val += dhist.weight(i) * weight;
2563 }
2564 hist->SetBinContent(i + 1, val);
2565 hist->SetBinError(i + 1, correlateErrors ? unc : sqrt(unc2));
2566 }
2567 return hist.release();
2568}
2569
2570////////////////////////////////////////////////////////////////////////////////
2571/// count the number of formulas that correspond to the current parameter set
2572
2574{
2575 int nFormulas = 0;
2576 auto mf = std::make_unique<RooRealSumFunc>(*(this->getFunc()));
2577 if (!mf)
2578 coutE(InputArguments) << "unable to retrieve morphing function" << std::endl;
2579 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2580 for (auto *prod : dynamic_range_cast<RooProduct *>(*args)) {
2581 if (prod->getVal() != 0) {
2582 nFormulas++;
2583 }
2584 }
2585 return nFormulas;
2586}
2587
2588////////////////////////////////////////////////////////////////////////////////
2589/// check if there is any morphing power provided for the given parameter
2590/// morphing power is provided as soon as any two samples provide different,
2591/// non-zero values for this parameter
2592
2594{
2595 std::string pname(paramname);
2596 double val = 0;
2597 bool isUsed = false;
2598 for (const auto &sample : _config.paramCards) {
2599 double thisval = sample.second.at(pname);
2600 if (thisval != val) {
2601 if (val != 0)
2602 isUsed = true;
2603 val = thisval;
2604 }
2605 }
2606 return isUsed;
2607}
2608
2609////////////////////////////////////////////////////////////////////////////////
2610/// check if there is any morphing power provided for the given coupling
2611/// morphing power is provided as soon as any two samples provide
2612/// different, non-zero values for this coupling
2613
2615{
2616 std::string cname(couplname);
2617 const RooArgList *args = this->getCouplingSet();
2618 RooAbsReal *coupling = dynamic_cast<RooAbsReal *>(args->find(couplname));
2619 if (!coupling)
2620 return false;
2622 double val = 0;
2623 bool isUsed = false;
2624 for (const auto &sample : _config.paramCards) {
2625 this->setParameters(sample.second);
2626 double thisval = coupling->getVal();
2627 if (thisval != val) {
2628 if (val != 0)
2629 isUsed = true;
2630 val = thisval;
2631 }
2632 }
2633 this->setParameters(params);
2634 return isUsed;
2635}
2636
2637////////////////////////////////////////////////////////////////////////////////
2638/// return the number of parameters in this morphing function
2639
2641{
2642 return this->getParameterSet()->size();
2643}
2644
2645////////////////////////////////////////////////////////////////////////////////
2646/// return the number of samples in this morphing function
2647
2649{
2650 // return the number of samples in this morphing function
2651 auto cache = getCache();
2652 return cache->_formulas.size();
2653}
2654
2655////////////////////////////////////////////////////////////////////////////////
2656/// print the contributing samples and their respective weights
2657
2659{
2660 auto mf = std::make_unique<RooRealSumFunc>(*(this->getFunc()));
2661 if (!mf) {
2662 std::cerr << "Error: unable to retrieve morphing function" << std::endl;
2663 return;
2664 }
2665 std::unique_ptr<RooArgSet> args{mf->getComponents()};
2666 for (auto *formula : dynamic_range_cast<RooAbsReal*>(*args)) {
2667 if (formula) {
2668 TString name(formula->GetName());
2669 name.Remove(0, 2);
2670 name.Prepend("phys_");
2671 if (!args->find(name.Data())) {
2672 continue;
2673 }
2674 double val = formula->getVal();
2675 if (val != 0) {
2676 std::cout << formula->GetName() << ": " << val << " = " << formula->GetTitle() << std::endl;
2677 }
2678 }
2679 }
2680}
2681
2682////////////////////////////////////////////////////////////////////////////////
2683/// get the set of parameters
2684
2686{
2687 return &(_operators);
2688}
2689
2690////////////////////////////////////////////////////////////////////////////////
2691/// get the set of couplings
2692
2694{
2695 auto cache = getCache();
2696 return &(cache->_couplings);
2697}
2698
2699////////////////////////////////////////////////////////////////////////////////
2700/// retrieve a set of couplings (-?-)
2701
2703{
2705 for (auto *var : dynamic_range_cast<RooAbsReal *>(*(this->getCouplingSet()))) {
2706 if (!var)
2707 continue;
2708 const std::string name(var->GetName());
2709 double val = var->getVal();
2710 couplings[name] = val;
2711 }
2712 return couplings;
2713}
2714
2715////////////////////////////////////////////////////////////////////////////////
2716/// retrieve the parameter set
2717
2722
2723////////////////////////////////////////////////////////////////////////////////
2724/// retrieve a set of couplings (-?-)
2725
2727{
2728 setParams(params, _operators, false);
2729}
2730
2731////////////////////////////////////////////////////////////////////////////////
2732/// (currently similar to cloning the Pdf
2733
2734std::unique_ptr<RooWrapperPdf> RooLagrangianMorphFunc::createPdf() const
2735{
2736 auto cache = getCache();
2737 auto func = std::make_unique<RooRealSumFunc>(*(cache->_sumFunc));
2738
2739 // create a wrapper on the roorealsumfunc
2740 return std::make_unique<RooWrapperPdf>(Form("pdf_%s", func->GetName()), Form("pdf of %s", func->GetTitle()), *func);
2741}
2742
2743////////////////////////////////////////////////////////////////////////////////
2744/// get the func
2745
2747{
2748 auto cache = getCache();
2749 return cache->_sumFunc.get();
2750}
2751
2752////////////////////////////////////////////////////////////////////////////////
2753/// return extended mored capabilities
2754
2756{
2757 return this->createPdf()->extendMode();
2758}
2759
2760////////////////////////////////////////////////////////////////////////////////
2761/// return expected number of events for extended likelihood calculation,
2762/// this is the sum of all coefficients
2763
2765{
2766 return this->createPdf()->expectedEvents(nset);
2767}
2768
2769////////////////////////////////////////////////////////////////////////////////
2770/// return the number of expected events for the current parameter set
2771
2773{
2774 RooArgSet set;
2775 set.add(*this->getObservable());
2776 return this->createPdf()->expectedEvents(set);
2777}
2778
2779////////////////////////////////////////////////////////////////////////////////
2780/// return expected number of events for extended likelihood calculation,
2781/// this is the sum of all coefficients
2782
2784{
2785 return createPdf()->expectedEvents(&nset);
2786}
2787
2788////////////////////////////////////////////////////////////////////////////////
2789/// return the expected uncertainty for the current parameter set
2790
2792{
2793 RooRealVar *observable = this->getObservable();
2794 auto cache = this->getCache();
2795 double unc2 = 0;
2796 for (const auto &sample : _sampleMap) {
2797 RooAbsArg *phys = _physics.at(sample.second);
2798 auto weightName = std::string("w_") + sample.first + "_" + this->GetName();
2799 auto weight = static_cast<RooAbsReal *>(cache->_weights.find(weightName.c_str()));
2800 if (!weight) {
2801 coutE(InputArguments) << "unable to find object " + weightName << std::endl;
2802 return 0.0;
2803 }
2804 double newunc2 = 0;
2805 RooHistFunc *hf = dynamic_cast<RooHistFunc *>(phys);
2806 RooRealVar *rv = dynamic_cast<RooRealVar *>(phys);
2807 if (hf) {
2808 const RooDataHist &hist = hf->dataHist();
2809 for (Int_t j = 0; j < observable->getBins(); ++j) {
2810 newunc2 += hist.weightSquared(j);
2811 }
2812 } else if (rv) {
2813 newunc2 = pow(rv->getError(), 2);
2814 }
2815 double w = weight->getVal();
2816 unc2 += newunc2 * w * w;
2817 // std::cout << phys->GetName() << " : " << weight->GetName() << "
2818 // thisweight: " << w << " thisxsec2: " << newunc2 << " weight " << weight
2819 // << std::endl;
2820 }
2821 return sqrt(unc2);
2822}
2823
2824////////////////////////////////////////////////////////////////////////////////
2825/// print the parameters and their current values
2826
2828{
2829 // print the parameters and their current values
2830 for (auto *param : static_range_cast<RooRealVar *>(_operators)) {
2831 if (!param)
2832 continue;
2833 param->Print();
2834 }
2835}
2836
2837////////////////////////////////////////////////////////////////////////////////
2838/// print the flags and their current values
2839
2841{
2842 for (auto *param : static_range_cast<RooRealVar *>(_flags)) {
2843 if (!param)
2844 continue;
2845 param->Print();
2846 }
2847}
2848
2849////////////////////////////////////////////////////////////////////////////////
2850/// print a set of couplings
2851
2853{
2855 for (auto c : couplings) {
2856 std::cout << c.first << ": " << c.second << std::endl;
2857 }
2858}
2859
2860////////////////////////////////////////////////////////////////////////////////
2861/// retrieve the list of bin boundaries
2862
2863std::list<double> *RooLagrangianMorphFunc::binBoundaries(RooAbsRealLValue &obs, double xlo, double xhi) const
2864{
2865 return this->getFunc()->binBoundaries(obs, xlo, xhi);
2866}
2867
2868////////////////////////////////////////////////////////////////////////////////
2869/// retrieve the sample Hint
2870
2871std::list<double> *RooLagrangianMorphFunc::plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const
2872{
2873 return this->getFunc()->plotSamplingHint(obs, xlo, xhi);
2874}
2875
2876////////////////////////////////////////////////////////////////////////////////
2877/// call getVal on the internal function
2878
2880{
2881 // call getVal on the internal function
2882 const RooRealSumFunc *pdf = this->getFunc();
2884 for (auto &obs : _observables) {
2885 nSet.add(*obs);
2886 }
2887 if (pdf) {
2888 return _scale * pdf->getVal(&nSet);
2889 } else {
2890 std::cerr << "unable to acquire in-built function!" << std::endl;
2891 }
2892 return 0.;
2893}
2894
2895////////////////////////////////////////////////////////////////////////////////
2896/// check if this PDF is a binned distribution in the given observable
2897
2899{
2900 return this->getFunc()->isBinnedDistribution(obs);
2901}
2902
2903////////////////////////////////////////////////////////////////////////////////
2904/// check if observable exists in the RooArgSet (-?-)
2905
2907{
2908 return this->getFunc()->checkObservables(nset);
2909}
2910
2911////////////////////////////////////////////////////////////////////////////////
2912/// Force analytical integration for the given observable
2913
2915{
2916 return this->getFunc()->forceAnalyticalInt(arg);
2917}
2918
2919////////////////////////////////////////////////////////////////////////////////
2920/// Retrieve the mat
2921
2927
2928////////////////////////////////////////////////////////////////////////////////
2929/// Retrieve the matrix of coefficients
2930
2932{
2933 return this->getFunc()->analyticalIntegralWN(code, normSet, rangeName);
2934}
2935
2936////////////////////////////////////////////////////////////////////////////////
2937/// Retrieve the matrix of coefficients
2938
2939void RooLagrangianMorphFunc::printMetaArgs(std::ostream &os) const
2940{
2941 return this->getFunc()->printMetaArgs(os);
2942}
2943
2944////////////////////////////////////////////////////////////////////////////////
2945/// Retrieve the matrix of coefficients
2946
2951
2952////////////////////////////////////////////////////////////////////////////////
2953/// Retrieve the matrix of coefficients
2954
2959
2960////////////////////////////////////////////////////////////////////////////////
2961/// Retrieve the matrix of coefficients
2962
2964{
2965 auto cache = getCache();
2966 if (!cache)
2967 coutE(Caching) << "unable to retrieve cache!" << std::endl;
2968 return makeRootMatrix(cache->_matrix);
2969}
2970
2971////////////////////////////////////////////////////////////////////////////////
2972/// Retrieve the matrix of coefficients after inversion
2973
2975{
2976 auto cache = getCache();
2977 if (!cache)
2978 coutE(Caching) << "unable to retrieve cache!" << std::endl;
2979 return makeRootMatrix(cache->_inverse);
2980}
2981
2982////////////////////////////////////////////////////////////////////////////////
2983/// Retrieve the condition of the coefficient matrix. If the condition number
2984/// is very large, then the matrix is ill-conditioned and is almost singular.
2985/// The computation of the inverse is prone to large numerical errors
2986
2988{
2989 auto cache = getCache();
2990 if (!cache)
2991 coutE(Caching) << "unable to retrieve cache!" << std::endl;
2992 return cache->_condition;
2993}
2994
2995////////////////////////////////////////////////////////////////////////////////
2996/// Return the RooRatio form of products and denominators of morphing functions
2997
2998std::unique_ptr<RooRatio>
3000{
3001 RooArgList num;
3003 for (auto it : nr) {
3004 num.add(*it);
3005 }
3006 for (auto it : dr) {
3007 denom.add(*it);
3008 }
3009 // same for denom
3010 return make_unique<RooRatio>(name, title, num, denom);
3011}
3012
3013// Register the factory interface
3014
3015namespace {
3016
3017// Helper function for factory interface
3018std::vector<std::string> asStringV(std::string const &arg)
3019{
3020 std::vector<std::string> out;
3021
3022 for (std::string &tok : ROOT::Split(arg, ",{}", true)) {
3023 if (tok[0] == '\'') {
3024 out.emplace_back(tok.substr(1, tok.size() - 2));
3025 } else {
3026 throw std::runtime_error("Strings in factory expressions need to be in single quotes!");
3027 }
3028 }
3029
3030 return out;
3031}
3032
3033class LMIFace : public RooFactoryWSTool::IFace {
3034public:
3035 std::string
3036 create(RooFactoryWSTool &, const char *typeName, const char *instName, std::vector<std::string> args) override;
3037};
3038
3039std::string LMIFace::create(RooFactoryWSTool &ft, const char * /*typeName*/, const char *instanceName,
3040 std::vector<std::string> args)
3041{
3042 // Perform syntax check. Warn about any meta parameters other than the ones needed
3043 const std::array<std::string, 4> funcArgs{{"fileName", "observableName", "couplings", "folders"}};
3044 std::map<string, string> mappedInputs;
3045
3046 for (unsigned int i = 1; i < args.size(); i++) {
3047 if (args[i].find("$fileName(") != 0 && args[i].find("$observableName(") != 0 &&
3048 args[i].find("$couplings(") != 0 && args[i].find("$folders(") != 0 && args[i].find("$NewPhysics(") != 0) {
3049 throw std::string(Form("%s::create() ERROR: unknown token %s encountered", instanceName, args[i].c_str()));
3050 }
3051 }
3052
3053 for (unsigned int i = 0; i < args.size(); i++) {
3054 if (args[i].find("$NewPhysics(") == 0) {
3055 vector<string> subargs = ft.splitFunctionArgs(args[i].c_str());
3056 for (const auto &subarg : subargs) {
3057 std::vector<std::string> parts = ROOT::Split(subarg, "=");
3058 if (parts.size() == 2) {
3059 ft.ws().arg(parts[0])->setAttribute("NewPhysics", atoi(parts[1].c_str()));
3060 } else {
3061 throw std::string(Form("%s::create() ERROR: unknown token %s encountered, check input provided for %s",
3062 instanceName, subarg.c_str(), args[i].c_str()));
3063 }
3064 }
3065 } else {
3066 std::vector<string> subargs = ft.splitFunctionArgs(args[i].c_str());
3067 if (subargs.size() == 1) {
3068 string expr = ft.processExpression(subargs[0].c_str());
3069 for (auto const &param : funcArgs) {
3070 if (args[i].find(param) != string::npos)
3071 mappedInputs[param] = subargs[0];
3072 }
3073 } else {
3074 throw std::string(
3075 Form("Incorrect number of arguments in %s, have %d, expect 1", args[i].c_str(), (Int_t)subargs.size()));
3076 }
3077 }
3078 }
3079
3081 config.fileName = asStringV(mappedInputs["fileName"])[0];
3082 config.observableName = asStringV(mappedInputs["observableName"])[0];
3083 config.folderNames = asStringV(mappedInputs["folders"]);
3084 config.couplings.add(ft.asLIST(mappedInputs["couplings"].c_str()));
3085
3087
3088 return instanceName;
3089}
3090
3091static Int_t init();
3092
3093int dummy = init();
3094
3095Int_t init()
3096{
3097 RooFactoryWSTool::IFace *iface = new LMIFace;
3098 RooFactoryWSTool::registerSpecial("lagrangianmorph", iface);
3099 (void)dummy;
3100 return 0;
3101}
3102
3103} // namespace
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
RooCollectionProxy< RooArgList > RooListProxy
Definition RooAbsArg.h:51
ROOT::RRangeCast< T, true, Range_t > dynamic_range_cast(Range_t &&coll)
size_t size< TMatrixD >(const TMatrixD &mat)
void writeMatrixToStreamT(const MatrixT &matrix, std::ostream &stream)
write a matrix to a stream
TMatrixD Matrix
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
static constexpr double morphUnityDeviation
Matrix makeSuperMatrix(const TMatrixD &in)
convert a TMatrixD into a Matrix
static constexpr double morphLargestWeight
void writeMatrixToFileT(const MatrixT &matrix, const char *fname)
write a matrix to a text file
double invertMatrix(const Matrix &matrix, Matrix &inverse)
#define NaN
TMatrixD makeRootMatrix(const Matrix &in)
convert a matrix into a TMatrixD
Matrix diagMatrix(size_t n)
create a new diagonal matrix of size n
void printMatrix(const TMatrixD &mat)
write a matrix
#define oocxcoutW(o, a)
#define coutW(a)
#define oocxcoutP(o, a)
#define coutE(a)
#define cxcoutP(a)
#define TRACE_DESTROY
Definition RooTrace.h:24
#define TRACE_CREATE
Definition RooTrace.h:23
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:385
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char cname
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:148
TMatrixT< Double_t > TMatrixD
Definition TMatrixDfwd.h:23
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2496
std::string & operator+=(std::string &left, const TString &right)
Definition TString.h:495
TTime operator*(const TTime &t1, const TTime &t2)
Definition TTime.h:85
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
bool isConstant() const
Check if the "Constant" attribute is set.
Definition RooAbsArg.h:283
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
Abstract base class for objects to be stored in RooAbsCache cache manager objects.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
Int_t numBins(const char *rangeName=nullptr) const override
virtual Int_t getBins(const char *name=nullptr) const
Get number of bins of currently defined range.
void setConstant(bool value=true)
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
void setBin(Int_t ibin, const char *rangeName=nullptr) override
Set value to center of bin 'ibin' of binning 'rangeName' (or of default binning if no range is specif...
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition RooArgList.h:110
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Implements a RooAbsBinning in terms of an array of boundary values, posing no constraints on the choi...
Definition RooBinning.h:27
Int_t setObj(const RooArgSet *nset, T *obj, const TNamed *isetRangeName=nullptr)
Setter function without integration set.
T * getObj(const RooArgSet *nset, Int_t *sterileIndex=nullptr, const TNamed *isetRangeName=nullptr)
Getter function without integration set.
bool addOwned(RooAbsArg &var, bool silent=false) override
Overloaded RooCollection_t::addOwned() method insert object into owning set and registers object as s...
bool add(const RooAbsArg &var, bool valueServer, bool shapeServer, bool silent)
Overloaded RooCollection_t::add() method insert object into set and registers object as server to own...
Container class to hold N-dimensional binned data.
Definition RooDataHist.h:40
double weightSquared(std::size_t i) const
Return squared weight sum of i-th bin.
Implementation detail of the RooWorkspace.
static void registerSpecial(const char *typeName, RooFactoryWSTool::IFace *iface)
Register foreign special objects in factory.
A real-valued function sampled from a multidimensional histogram.
Definition RooHistFunc.h:31
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.
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
RooObjCacheManager _cacheMgr
! The cache manager
bool isParameterUsed(const char *paramname) const
check if there is any morphing power provided for the given parameter morphing power is provided as s...
RooAbsPdf::ExtendMode extendMode() const
return extended mored capabilities
std::map< const std::string, FlagSet > FlagMap
bool forceAnalyticalInt(const RooAbsArg &arg) const override
Force analytical integration for the given observable.
void setParameterConstant(const char *paramname, bool constant) const
call setConstant with the boolean argument provided on the parameter with the given name
void disableInterferences(const std::vector< std::vector< const char * > > &nonInterfering)
disable interference between terms
void printSamples() const
print all the known samples to the console
double getParameterValue(const char *name) const
set one parameter to a specific value
void setup(bool ownParams=true)
setup this instance with the given set of operators and vertices if own=true, the class will own the ...
void printMetaArgs(std::ostream &os) const override
Retrieve the matrix of coefficients.
std::unique_ptr< RooWrapperPdf > createPdf() const
(currently similar to cloning the Pdf
RooAbsReal * getSampleWeight(const char *name)
retrieve the weight (prefactor) of a sample with the given name
std::map< std::string, std::string > createWeightStrings(const ParamMap &inputs, const std::vector< std::vector< std::string > > &vertices)
create only the weight formulas. static function for external usage.
Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &numVars, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Retrieve the mat.
std::vector< std::vector< RooListProxy * > > _diagrams
double expectedEvents() const
return the number of expected events for the current parameter set
std::map< std::string, int > _sampleMap
RooLagrangianMorphFunc::CacheElem * getCache() const
retrieve the cache object
RooRealVar * setupObservable(const char *obsname, TClass *mode, TObject *inputExample)
setup observable, recycle existing observable if defined
const RooArgList * getCouplingSet() const
get the set of couplings
RooRealSumFunc * getFunc() const
get the func
std::list< double > * binBoundaries(RooAbsRealLValue &, double, double) const override
retrieve the list of bin boundaries
void printEvaluation() const
print the contributing samples and their respective weights
bool writeCoefficients(const char *filename)
write the inverse matrix to a file
void collectInputs(TDirectory *f)
retrieve the physics inputs
void init()
initialise inputs required for the morphing function
RooLinearCombination is a class that helps perform linear combination of floating point numbers and p...
A histogram function that assigns scale parameters to every bin.
static TClass * Class()
Represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
std::list< double > * binBoundaries(RooAbsRealLValue &, double, double) const override
Retrieve bin boundaries if this distribution is binned in obs.
void printMetaArgs(std::ostream &os) const override
Customized printing of arguments of a RooRealSumFunc to more intuitively reflect the contents of the ...
Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &numVars, const RooArgSet *normSet, const char *rangeName=nullptr) const override
Variant of getAnalyticalIntegral that is also passed the normalization set that should be applied to ...
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
Variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
void setError(double value)
Definition RooRealVar.h:61
void setMin(const char *name, double value, bool shared=true)
Set minimum of name range to given value.
void setBins(Int_t nBins, const char *name=nullptr, bool shared=true)
Create a uniform binning under name 'name' for this variable.
void setBinning(const RooAbsBinning &binning, const char *name=nullptr, bool shared=true)
Add given binning under name 'name' with this variable.
void setMax(const char *name, double value, bool shared=true)
Set maximum of name range to given value.
const RooAbsBinning & getBinning(const char *name=nullptr, bool verbose=true, bool createOnTheFly=false, bool shared=true) const override
Return binning definition with name.
Class to manage histogram axis.
Definition TAxis.h:32
Double_t GetXmax() const
Definition TAxis.h:142
Double_t GetXmin() const
Definition TAxis.h:141
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2994
LU Decomposition class.
Definition TDecompLU.h:24
Describe directory structure in memory.
Definition TDirectory.h:45
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
virtual Bool_t IsOpen() const
Returns kTRUE in case file is open and kFALSE if file is not open.
Definition TFile.cxx:1489
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:3795
void Close(Option_t *option="") override
Close a file.
Definition TFile.cxx:989
<div class="legacybox"><h2>Legacy Code</h2> TFolder is a legacy interface: there will be no bug fixes...
Definition TFolder.h:30
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:109
static TClass * Class()
TAxis * GetXaxis()
Definition TH1.h:571
virtual Int_t GetNbinsX() const
Definition TH1.h:541
virtual void SetBinError(Int_t bin, Double_t error)
Set the bin Error Note that this resets the bin eror option to be of Normal Type and for the non-empt...
Definition TH1.cxx:9436
virtual Double_t Integral(Option_t *option="") const
Return integral of bin contents.
Definition TH1.cxx:8170
virtual void SetBinContent(Int_t bin, Double_t content)
Set bin content see convention for numbering bins in TH1::GetBin In case the bin number is greater th...
Definition TH1.cxx:9452
virtual Double_t GetBinLowEdge(Int_t bin) const
Return bin lower edge for 1D histogram.
Definition TH1.cxx:9382
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition TH1.cxx:5239
virtual Double_t GetBinWidth(Int_t bin) const
Return bin width for 1D histogram.
Definition TH1.cxx:9393
virtual void Scale(Double_t c1=1, Option_t *option="")
Multiply this histogram by a constant c1.
Definition TH1.cxx:6815
TMatrixTBase< Element > & ResizeTo(Int_t nrows, Int_t ncols, Int_t=-1) override
Set size of the matrix to nrows x ncols New dynamic elements are created, the overlapping part of the...
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Mother of all ROOT objects.
Definition TObject.h:42
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:227
Class used by TMap to store (key,value) pairs.
Definition TMap.h:103
TObject * Value() const
Definition TMap.h:122
TObject * Key() const
Definition TMap.h:121
Random number generator class based on M.
Definition TRandom3.h:27
Basic string class.
Definition TString.h:138
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:2385
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
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
std::vector< std::string > folderNames
std::vector< std::vector< const char * > > nonInterfering
TMarker m
Definition textangle.C:8