Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooWorkspace.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * *
8 * Copyright (c) 2000-2005, Regents of the University of California *
9 * and Stanford University. All rights reserved. *
10 * *
11 * Redistribution and use in source and binary forms, *
12 * with or without modification, are permitted according to the terms *
13 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
14 *****************************************************************************/
15
16/**
17\file RooWorkspace.cxx
18\class RooWorkspace
19\ingroup Roofitcore
20
21Persistable container for RooFit projects. A workspace
22can contain and own variables, p.d.f.s, functions and datasets. All objects
23that live in the workspace are owned by the workspace. The `import()` method
24enforces consistency of objects upon insertion into the workspace (e.g. no
25duplicate object with the same name are allowed) and makes sure all objects
26in the workspace are connected to each other. Easy accessor methods like
27`pdf()`, `var()` and `data()` allow to refer to the contents of the workspace by
28object name. The entire RooWorkspace can be saved into a ROOT TFile and organises
29the consistent streaming of its contents without duplication.
30If a RooWorkspace contains custom classes, i.e. classes not in the
31ROOT distribution, portability of workspaces can be enhanced by
32storing the source code of those classes in the workspace as well.
33This process is also organized by the workspace through the
34`importClassCode()` method.
35
36### Seemingly random crashes when reading large workspaces
37When reading or loading workspaces with deeply nested PDFs, one can encounter
38ouf-of-memory errors if the stack size is too small. This manifests in crashes
39at seemingly random locations, or in the process silently ending.
40Unfortunately, ROOT neither recover from this situation, nor warn or give useful
41instructions. When suspecting to have run out of stack memory, check
42```
43ulimit -s
44```
45and try reading again.
46**/
47
48#include <RooWorkspace.h>
49
50#include <RooAbsData.h>
51#include <RooAbsPdf.h>
52#include <RooAbsStudy.h>
53#include <RooCategory.h>
54#include <RooCmdConfig.h>
55#include <RooConstVar.h>
56#include <RooFactoryWSTool.h>
57#include <RooLinkedListIter.h>
58#include <RooMsgService.h>
59#include <RooPlot.h>
60#include <RooRandom.h>
61#include <RooRealVar.h>
62#include <RooResolutionModel.h>
63#include <RooTObjWrap.h>
64#include <RooWorkspaceHandle.h>
65
66#include "TBuffer.h"
67#include "TInterpreter.h"
68#include "TClassTable.h"
69#include "TBaseClass.h"
70#include "TSystem.h"
71#include "TRegexp.h"
72#include "TROOT.h"
73#include "TFile.h"
74#include "TH1.h"
75#include "TClass.h"
76#include "strlcpy.h"
77
78
79#include "ROOT/StringUtils.hxx"
80
81#include <map>
82#include <sstream>
83#include <string>
84#include <iostream>
85#include <fstream>
86#include <cstring>
87#include <unordered_map>
88#include <unordered_set>
89
90namespace {
91
92// Infer from a RooArgSet name whether this set is used internally by
93// RooWorkspace to cache things.
94bool isCacheSet(std::string const& setName) {
95 // Check if the setName starts with CACHE_.
96 return setName.rfind("CACHE_", 0) == 0;
97}
98
99} // namespace
100
101using std::string, std::list, std::map, std::vector, std::ifstream, std::ofstream, std::fstream, std::make_unique;
102
103
104////////////////////////////////////////////////////////////////////////////////
105
106
107////////////////////////////////////////////////////////////////////////////////
108
109
112string RooWorkspace::_classFileExportDir = ".wscode.%s.%s" ;
113bool RooWorkspace::_autoClass = false ;
114
115
116////////////////////////////////////////////////////////////////////////////////
117/// Add `dir` to search path for class declaration (header) files. This is needed
118/// to find class headers custom classes are imported into the workspace.
120{
121 _classDeclDirList.push_back(dir) ;
122}
123
124
125////////////////////////////////////////////////////////////////////////////////
126/// Add `dir` to search path for class implementation (.cxx) files. This is needed
127/// to find class headers custom classes are imported into the workspace.
129{
130 _classImplDirList.push_back(dir) ;
131}
132
133
134////////////////////////////////////////////////////////////////////////////////
135/// Specify the name of the directory in which embedded source
136/// code is unpacked and compiled. The specified string may contain
137/// one '%s' token which will be substituted by the workspace name
138
140{
141 if (dir) {
142 _classFileExportDir = dir ;
143 } else {
144 _classFileExportDir = ".wscode.%s.%s" ;
145 }
146}
147
148
149////////////////////////////////////////////////////////////////////////////////
150/// If flag is true, source code of classes not the ROOT distribution
151/// is automatically imported if on object of such a class is imported
152/// in the workspace
153
155{
156 _autoClass = flag ;
157}
158
159
160
161////////////////////////////////////////////////////////////////////////////////
162/// Default constructor
163
165{
166}
167
168
169
170////////////////////////////////////////////////////////////////////////////////
171/// Construct empty workspace with given name and title
172
173RooWorkspace::RooWorkspace(const char* name, const char* title) :
174 TNamed(name,title?title:name), _classes(this)
175{
176}
177
178////////////////////////////////////////////////////////////////////////////////
179/// Construct empty workspace with given name and option to export reference to
180/// all workspace contents to a Cling namespace with the same name.
181
182RooWorkspace::RooWorkspace(const char* name, bool /*doCINTExport*/) :
183 TNamed(name,name), _classes(this)
184{
185}
186
187
188////////////////////////////////////////////////////////////////////////////////
189/// Workspace copy constructor
190
192 TNamed(other), _uuid(other._uuid), _classes(other._classes,this)
193{
194 // Copy owned nodes
195 other._allOwnedNodes.snapshot(_allOwnedNodes,true) ;
196
197 // Copy datasets
198 for(TObject *data2 : other._dataList) _dataList.Add(data2->Clone());
199
200 // Copy snapshots
201 for(auto * snap : static_range_cast<RooArgSet*>(other._snapshots)) {
202 auto snapClone = new RooArgSet;
203 snap->snapshot(*snapClone);
204 snapClone->setName(snap->GetName()) ;
205 _snapshots.Add(snapClone) ;
206 }
207
208 // Copy named sets
209 for (map<string,RooArgSet>::const_iterator iter3 = other._namedSets.begin() ; iter3 != other._namedSets.end() ; ++iter3) {
210 // Make RooArgSet with equivalent content of this workspace
211 _namedSets[iter3->first].add(*std::unique_ptr<RooArgSet>{_allOwnedNodes.selectCommon(iter3->second)});
212 }
213
214 // Copy generic objects
215 for(TObject * gobj : other._genObjects) {
216 _genObjects.Add(gobj->Clone());
217 }
218
219 for(TObject * gobj : allGenericObjects()) {
220 if (auto handle = dynamic_cast<RooWorkspaceHandle*>(gobj)) {
221 handle->ReplaceWS(this);
222 }
223 }
224}
225
226
227/// TObject::Clone() needs to be overridden.
228TObject *RooWorkspace::Clone(const char *newname) const
229{
230 auto out = new RooWorkspace{*this};
231 if(newname && std::string(newname) != GetName()) {
232 out->SetName(newname);
233 }
234 return out;
235}
236
237
238////////////////////////////////////////////////////////////////////////////////
239/// Workspace destructor
240
242{
243 // Delete contents
244 _dataList.Delete() ;
245 if (_dir) {
246 delete _dir ;
247 }
249
250 // WVE named sets too?
251
253
255 _views.Delete();
257
258}
259
260
261////////////////////////////////////////////////////////////////////////////////
262/// Import a RooAbsArg or RooAbsData set from a workspace in a file. Filespec should be constructed as "filename:wspacename:objectname"
263/// The arguments will be passed to the relevant import() or import(RooAbsData&, ...) import calls
264/// \note From python, use `Import()`, since `import` is a reserved keyword.
265/// \return due to historical reasons: false (0) on success and true (1) on failure
266bool RooWorkspace::import(const char* fileSpec,
267 const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3,
268 const RooCmdArg& arg4, const RooCmdArg& arg5, const RooCmdArg& arg6,
269 const RooCmdArg& arg7, const RooCmdArg& arg8, const RooCmdArg& arg9)
270{
271 // Parse file/workspace/objectname specification
272 std::vector<std::string> tokens = ROOT::Split(fileSpec, ":");
273
274 // Check that parsing was successful
275 if (tokens.size() != 3) {
276 std::ostringstream stream;
277 for (const auto& token : tokens) {
278 stream << "\n\t" << token;
279 }
280 coutE(InputArguments) << "RooWorkspace(" << GetName() << ") ERROR in file specification, expecting 'filename:wsname:objname', but '" << fileSpec << "' given."
281 << "\nTokens read are:" << stream.str() << std::endl;
282 return true ;
283 }
284
285 const std::string& filename = tokens[0];
286 const std::string& wsname = tokens[1];
287 const std::string& objname = tokens[2];
288
289 // Check that file can be opened
290 std::unique_ptr<TFile> f{TFile::Open(filename.c_str())};
291 if (f==nullptr) {
292 coutE(InputArguments) << "RooWorkspace(" << GetName() << ") ERROR opening file " << filename << std::endl ;
293 return false;
294 }
295
296 // That that file contains workspace
297 RooWorkspace* w = dynamic_cast<RooWorkspace*>(f->Get(wsname.c_str())) ;
298 if (w==nullptr) {
299 coutE(InputArguments) << "RooWorkspace(" << GetName() << ") ERROR: No object named " << wsname << " in file " << filename
300 << " or object is not a RooWorkspace" << std::endl ;
301 return false;
302 }
303
304 // Check that workspace contains object and forward to appropriate import method
305 RooAbsArg* warg = w->arg(objname.c_str()) ;
306 if (warg) {
307 bool ret = import(*warg,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) ;
308 return ret ;
309 }
310 RooAbsData* wdata = w->data(objname.c_str()) ;
311 if (wdata) {
312 bool ret = import(*wdata,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) ;
313 return ret ;
314 }
315
316 coutE(InputArguments) << "RooWorkspace(" << GetName() << ") ERROR: No RooAbsArg or RooAbsData object named " << objname
317 << " in workspace " << wsname << " in file " << filename << std::endl ;
318 return true ;
319}
320
321
322////////////////////////////////////////////////////////////////////////////////
323/// Import multiple RooAbsArg objects into workspace. For details on arguments see documentation
324/// of import() method for single RooAbsArg
325/// \note From python, use `Import()`, since `import` is a reserved keyword.
326/// \return due to historical reasons: false (0) on success and true (1) on failure
328 const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3,
329 const RooCmdArg& arg4, const RooCmdArg& arg5, const RooCmdArg& arg6,
330 const RooCmdArg& arg7, const RooCmdArg& arg8, const RooCmdArg& arg9)
331{
332 bool ret(false) ;
333 for(RooAbsArg * oneArg : args) {
334 ret |= import(*oneArg,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) ;
335 }
336 return ret ;
337}
338
339
340
341////////////////////////////////////////////////////////////////////////////////
342/// Import a RooAbsArg object, e.g. function, p.d.f or variable into the workspace. This import function clones the input argument and will
343/// own the clone. If a composite object is offered for import, e.g. a p.d.f with parameters and observables, the
344/// complete tree of objects is imported. If any of the _variables_ of a composite object (parameters/observables) are already
345/// in the workspace the imported p.d.f. is connected to the already existing variables. If any of the _function_ objects (p.d.f, formulas)
346/// to be imported already exists in the workspace an error message is printed and the import of the entire tree of objects is cancelled.
347/// Several optional arguments can be provided to modify the import procedure.
348///
349/// <table>
350/// <tr><th> Accepted arguments
351/// <tr><td> `RenameConflictNodes(const char* suffix)` <td> Add suffix to branch node name if name conflicts with existing node in workspace
352/// <tr><td> `RenameAllNodes(const char* suffix)` <td> Add suffix to all branch node names including top level node.
353/// <tr><td> `RenameAllVariables(const char* suffix)` <td> Add suffix to all variables of objects being imported.
354/// <tr><td> `RenameAllVariablesExcept(const char* suffix, const char* exceptionList)` <td> Add suffix to all variables names, except ones listed
355/// <tr><td> `RenameVariable(const char* inputName, const char* outputName)` <td> Rename a single variable as specified upon import.
356/// <tr><td> `RecycleConflictNodes()` <td> If any of the function objects to be imported already exist in the name space, connect the
357/// imported expression to the already existing nodes.
358/// \attention Use with care! If function definitions do not match, this alters the definition of your function upon import
359///
360/// <tr><td> `Silence()` <td> Do not issue any info message
361/// </table>
362///
363/// The RenameConflictNodes, RenameNodes and RecycleConflictNodes arguments are mutually exclusive. The RenameVariable argument can be repeated
364/// as often as necessary to rename multiple variables. Alternatively, a single RenameVariable argument can be given with
365/// two comma separated lists.
366/// \note From python, use `Import()`, since `import` is a reserved keyword.
367/// \return due to historical reasons: false (0) on success and true (1) on failure
369 const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3,
370 const RooCmdArg& arg4, const RooCmdArg& arg5, const RooCmdArg& arg6,
371 const RooCmdArg& arg7, const RooCmdArg& arg8, const RooCmdArg& arg9)
372{
373 RooLinkedList args ;
374 args.Add((TObject*)&arg1) ;
375 args.Add((TObject*)&arg2) ;
376 args.Add((TObject*)&arg3) ;
377 args.Add((TObject*)&arg4) ;
378 args.Add((TObject*)&arg5) ;
379 args.Add((TObject*)&arg6) ;
380 args.Add((TObject*)&arg7) ;
381 args.Add((TObject*)&arg8) ;
382 args.Add((TObject*)&arg9) ;
383
384 // Select the pdf-specific commands
385 RooCmdConfig pc("RooWorkspace::import(" + std::string(GetName()) + ")");
386
387 pc.defineString("conflictSuffix","RenameConflictNodes",0) ;
388 pc.defineInt("renameConflictOrig","RenameConflictNodes",0,0) ;
389 pc.defineString("allSuffix","RenameAllNodes",0) ;
390 pc.defineString("allVarsSuffix","RenameAllVariables",0) ;
391 pc.defineString("allVarsExcept","RenameAllVariables",1) ;
392 pc.defineString("varChangeIn","RenameVar",0,"",true) ;
393 pc.defineString("varChangeOut","RenameVar",1,"",true) ;
394 pc.defineString("factoryTag","FactoryTag",0) ;
395 pc.defineInt("useExistingNodes","RecycleConflictNodes",0,0) ;
396 pc.defineInt("silence","Silence",0,0) ;
397 pc.defineInt("noRecursion","NoRecursion",0,0) ;
398 pc.defineMutex("RenameConflictNodes","RenameAllNodes") ;
399 pc.defineMutex("RenameConflictNodes","RecycleConflictNodes") ;
400 pc.defineMutex("RenameAllNodes","RecycleConflictNodes") ;
401 pc.defineMutex("RenameVariable","RenameAllVariables") ;
402
403 // Process and check varargs
404 pc.process(args) ;
405 if (!pc.ok(true)) {
406 return true ;
407 }
408
409 // Decode renaming logic into suffix string and boolean for conflictOnly mode
410 const char* suffixC = pc.getString("conflictSuffix") ;
411 const char* suffixA = pc.getString("allSuffix") ;
412 const char* suffixV = pc.getString("allVarsSuffix") ;
413 const char* exceptVars = pc.getString("allVarsExcept") ;
414 const char* varChangeIn = pc.getString("varChangeIn") ;
415 const char* varChangeOut = pc.getString("varChangeOut") ;
416 bool renameConflictOrig = pc.getInt("renameConflictOrig") ;
417 Int_t useExistingNodes = pc.getInt("useExistingNodes") ;
418 Int_t silence = pc.getInt("silence") ;
419 Int_t noRecursion = pc.getInt("noRecursion") ;
420
421
422 // Turn zero length strings into null pointers
423 if (suffixC && strlen(suffixC)==0) suffixC = nullptr ;
424 if (suffixA && strlen(suffixA)==0) suffixA = nullptr ;
425
426 bool conflictOnly = suffixA ? false : true ;
427 const char* suffix = suffixA ? suffixA : suffixC ;
428
429 // Process any change in variable names
430 std::unordered_map<string,string> varMap ;
431 if (strlen(varChangeIn)>0) {
432
433 // Parse comma separated lists into map<string,string>
434 const std::vector<std::string> tokIn = ROOT::Split(varChangeIn, ", ", /*skipEmpty= */ true);
435 const std::vector<std::string> tokOut = ROOT::Split(varChangeOut, ", ", /*skipEmpty= */ true);
436 for (unsigned int i=0; i < tokIn.size(); ++i) {
437 varMap.insert(std::make_pair(tokIn[i], tokOut[i]));
438 }
439
440 assert(tokIn.size() == tokOut.size());
441 }
442
443 // Process RenameAllVariables argument if specified
444 // First convert exception list if provided
445 std::set<string> exceptVarNames ;
446 if (exceptVars && strlen(exceptVars)) {
447 const std::vector<std::string> toks = ROOT::Split(exceptVars, ", ", /*skipEmpty= */ true);
448 exceptVarNames.insert(toks.begin(), toks.end());
449 }
450
451 if (suffixV != nullptr && strlen(suffixV)>0) {
452 std::unique_ptr<RooArgSet> vars{inArg.getVariables()};
453 for (const auto v : *vars) {
454 if (exceptVarNames.find(v->GetName())==exceptVarNames.end()) {
455 varMap[v->GetName()] = Form("%s_%s",v->GetName(),suffixV) ;
456 }
457 }
458 }
459
460 // Scan for overlaps with current contents
461 RooAbsArg* wsarg = _allOwnedNodes.find(inArg.GetName()) ;
462
463 // Check for factory specification match
464 const char* tagIn = inArg.getStringAttribute("factory_tag") ;
465 const char* tagWs = wsarg ? wsarg->getStringAttribute("factory_tag") : nullptr ;
466 bool factoryMatch = (tagIn && tagWs && !strcmp(tagIn,tagWs)) ;
467 if (factoryMatch) {
468 ((RooAbsArg&)inArg).setAttribute("RooWorkspace::Recycle") ;
469 }
470
471 if (!suffix && wsarg && !useExistingNodes && !(inArg.isFundamental() && !varMap[inArg.GetName()].empty())) {
472 if (!factoryMatch) {
473 if (wsarg!=&inArg) {
474 coutE(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") ERROR importing object named " << inArg.GetName()
475 << ": another instance with same name already in the workspace and no conflict resolution protocol specified" << std::endl ;
476 return true ;
477 } else {
478 if (!silence) {
479 coutI(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") Object " << inArg.GetName() << " is already in workspace!" << std::endl ;
480 }
481 return true ;
482 }
483 } else {
484 if(!silence) {
485 coutI(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") Recycling existing object " << inArg.GetName() << " created with identical factory specification" << std::endl ;
486 }
487 }
488 }
489
490 // When existing nodes are recycled and no renaming is requested, nodes
491 // whose names already exist in the workspace are not cloned at all: the
492 // existing nodes are used anyway, and the clones would be discarded right
493 // after the import. One deliberate difference to the general code path:
494 // importWorkspaceHook() and the class-code import don't run for recycled
495 // nodes anymore, since there is no clone to run them on.
496 const bool pruneClones = useExistingNodes && !suffix && varMap.empty() && !noRecursion;
497
498 // Make list of conflicting nodes. With useExistingNodes, this list stays
499 // empty, and the branch set is only otherwise used by the rename-all mode
500 // that excludes pruning, so the scan is skipped when pruning is active.
501 RooArgSet conflictNodes ;
502 RooArgSet branchSet ;
503 if (!pruneClones) {
504 if (noRecursion) {
505 branchSet.add(inArg);
506 } else {
507 inArg.branchNodeServerList(&branchSet);
508 }
509
510 for (const auto branch : branchSet) {
511 RooAbsArg *wsbranch = _allOwnedNodes.find(branch->GetName());
512 if (wsbranch && wsbranch != branch && !branch->getAttribute("RooWorkspace::Recycle") && !useExistingNodes) {
513 conflictNodes.add(*branch);
514 }
515 }
516 }
517
518 // Terminate here if there are conflicts and no resolution protocol
519 if (!conflictNodes.empty() && !suffix && !useExistingNodes) {
520 coutE(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") ERROR object named " << inArg.GetName() << ": component(s) "
521 << conflictNodes << " already in the workspace and no conflict resolution protocol specified" << std::endl ;
522 return true ;
523 }
524
525 // Now create a working copy of the incoming object tree
526 RooArgSet cloneSet;
527 cloneSet.useHashMapForFind(true); // Accelerate finding
528 // Nodes of the input graph whose names already exist in the workspace and
529 // that are hence recycled instead of cloned.
530 std::vector<RooAbsArg const *> recycledSources;
531 if (pruneClones) {
532 // Traverse the whole graph like the snapshot in the general code path
533 // does (depth-first pre-order over the server links, keeping the first
534 // encountered instance for each name), but clone only the nodes whose
535 // names are not in the workspace yet.
536 std::vector<RooAbsArg const *> toClone;
537 std::unordered_set<TNamed const *> visited;
538 visited.insert(inArg.namePtr());
539 std::vector<RooAbsArg const *> stack{&inArg};
540 while (!stack.empty()) {
541 RooAbsArg const *arg = stack.back();
542 stack.pop_back();
543 if (RooAbsArg *wsnode = _allOwnedNodes.find(arg->GetName())) {
544 if (!silence) {
545 coutI(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") using existing copy of "
546 << wsnode->ClassName() << "::" << wsnode->GetName() << " for import of "
547 << inArg.ClassName() << "::" << inArg.GetName() << std::endl;
548 }
549 recycledSources.push_back(arg);
550 } else {
551 toClone.push_back(arg);
552 }
553 // Push the servers in reverse order so that they are popped in
554 // forward order, matching the traversal order of the snapshot.
555 auto const &servers = arg->servers().containedObjects();
556 for (auto it = servers.rbegin(); it != servers.rend(); ++it) {
557 if (visited.insert((*it)->namePtr()).second) {
558 stack.push_back(*it);
559 }
560 }
561 }
562 for (RooAbsArg const *arg : toClone) {
563 auto clone = std::unique_ptr<RooAbsArg>{static_cast<RooAbsArg *>(arg->Clone())};
564 clone->setAttribute("SnapShot_ExtRefClone");
565 cloneSet.addOwned(std::move(clone));
566 }
567 // Redirect the server links of the clones to the other clones or to the
568 // existing nodes in the workspace.
569 RooArgSet redirectSet;
570 redirectSet.useHashMapForFind(true);
571 redirectSet.add(cloneSet);
572 for (RooAbsArg const *arg : recycledSources) {
573 redirectSet.add(*_allOwnedNodes.find(arg->GetName()));
574 }
575 for (RooAbsArg *clone : cloneSet) {
576 clone->redirectServers(redirectSet, true);
577 }
578 } else {
579 RooArgSet(inArg).snapshot(cloneSet, !noRecursion);
580 }
581
582 // Import the expensive-object cache payloads for recycled nodes like the
583 // general code path does via the discarded clones, which always hand over
584 // the global cache instance because the cache pointer of a RooAbsArg is
585 // transient and not copied when cloning.
586 for (RooAbsArg const *arg : recycledSources) {
588 }
589
590 if (pruneClones && cloneSet.empty()) {
591 // The whole computation graph is already in the workspace.
592 return false;
593 }
594
595 RooAbsArg* cloneTop = cloneSet.find(inArg.GetName()) ;
596
597 // Mark all nodes for renaming if we are not in conflictOnly mode
598 if (!conflictOnly) {
599 conflictNodes.removeAll() ;
600 conflictNodes.add(branchSet) ;
601 }
602
603 // Mark nodes that are to be renamed with special attribute
604 // Track whether any node in cloneSet actually gets renamed below: only then
605 // does the working copy have to be cloned a second time (see there).
606 bool nodesRenamed = false ;
607 // With clone pruning, the top-level node itself may have been recycled, in
608 // which case it has no clone in cloneSet. No renaming can happen then, so
609 // the original name is already final.
610 string topName2 = cloneTop ? cloneTop->GetName() : inArg.GetName();
611 if (!renameConflictOrig) {
612 // Mark all nodes to be imported for renaming following conflict resolution protocol
613 for (const auto cnode : conflictNodes) {
614 RooAbsArg* cnode2 = cloneSet.find(cnode->GetName()) ;
615 string origName = cnode2->GetName() ;
616 cnode2->SetName(Form("%s_%s",cnode2->GetName(),suffix)) ;
617 cnode2->SetTitle(Form("%s (%s)",cnode2->GetTitle(),suffix)) ;
618 nodesRenamed = true ;
619 string tag = "ORIGNAME:" + origName;
620 cnode2->setAttribute(tag.c_str()) ;
621 if (!cnode2->getStringAttribute("origName")) {
622 cnode2->setStringAttribute("origName",origName.c_str());
623 }
624
625 // Save name of new top level node for later use
626 if (cnode2==cloneTop) {
627 topName2 = cnode2->GetName() ;
628 }
629
630 if (!silence) {
631 coutI(ObjectHandling) << "RooWorkspace::import(" << GetName()
632 << ") Resolving name conflict in workspace by changing name of imported node "
633 << origName << " to " << cnode2->GetName() << std::endl ;
634 }
635 }
636 } else {
637
638 // Rename all nodes already in the workspace to 'clear the way' for the imported nodes
639 for (const auto cnode : conflictNodes) {
640
641 string origName = cnode->GetName() ;
642 RooAbsArg* wsnode = _allOwnedNodes.find(origName.c_str()) ;
643 if (wsnode) {
644
645 if (!wsnode->getStringAttribute("origName")) {
646 wsnode->setStringAttribute("origName",wsnode->GetName()) ;
647 }
648
649 if (!_allOwnedNodes.find(Form("%s_%s",cnode->GetName(),suffix))) {
650 wsnode->SetName(Form("%s_%s",cnode->GetName(),suffix)) ;
651 wsnode->SetTitle(Form("%s (%s)",cnode->GetTitle(),suffix)) ;
652 } else {
653 // Name with suffix already taken, add additional suffix
654 for (unsigned int n=1; true; ++n) {
655 string newname = Form("%s_%s_%d",cnode->GetName(),suffix,n) ;
656 if (!_allOwnedNodes.find(newname.c_str())) {
657 wsnode->SetName(newname.c_str()) ;
658 wsnode->SetTitle(Form("%s (%s %d)",cnode->GetTitle(),suffix,n)) ;
659 break ;
660 }
661 }
662 }
663 if (!silence) {
664 coutI(ObjectHandling) << "RooWorkspace::import(" << GetName()
665 << ") Resolving name conflict in workspace by changing name of original node "
666 << origName << " to " << wsnode->GetName() << std::endl ;
667 }
668 } else {
669 coutW(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") Internal error: expected to find existing node "
670 << origName << " to be renamed, but didn't find it..." << std::endl ;
671 }
672
673 }
674 }
675
676 // Process any change in variable names
677 if (strlen(varChangeIn)>0 || (suffixV && strlen(suffixV)>0)) {
678
679 // Process all changes in variable names
680 for (const auto cnode : cloneSet) {
681
682 if (varMap.find(cnode->GetName())!=varMap.end()) {
683 string origName = cnode->GetName() ;
684 cnode->SetName(varMap[cnode->GetName()].c_str()) ;
685 nodesRenamed = true ;
686 string tag = "ORIGNAME:" + origName;
687 cnode->setAttribute(tag.c_str()) ;
688 if (!cnode->getStringAttribute("origName")) {
689 cnode->setStringAttribute("origName",origName.c_str()) ;
690 }
691
692 if (!silence) {
693 coutI(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") Changing name of variable "
694 << origName << " to " << cnode->GetName() << " on request" << std::endl ;
695 }
696
697 if (cnode==cloneTop) {
698 topName2 = cnode->GetName() ;
699 }
700
701 }
702 }
703 }
704
705 // Now clone again with renaming effective. Cloning re-resolves all server
706 // links by name, which is what makes the renaming above take effect. If
707 // nothing was renamed, the first working copy is already in its final state
708 // and cloning the whole computation graph a second time would only cost time
709 // and memory, so it is reused as-is. This is the common case: renaming only
710 // happens with an explicit Rename*() command argument or a name conflict.
711 RooArgSet renamedCloneSet;
712 if (nodesRenamed) {
713 renamedCloneSet.useHashMapForFind(true); // Faster finding
714 RooArgSet(*cloneTop).snapshot(renamedCloneSet, !noRecursion);
715 }
716 RooArgSet &cloneSet2 = nodesRenamed ? renamedCloneSet : cloneSet;
717 RooAbsArg* cloneTop2 = cloneSet2.find(topName2.c_str()) ;
718
719 // Perform any auxiliary imports at this point
720 for (const auto node : cloneSet2) {
721 if (node->importWorkspaceHook(*this)) {
722 coutE(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") ERROR object named " << node->GetName()
723 << " has an error in importing in one or more of its auxiliary objects, aborting" << std::endl ;
724 return true ;
725 }
726 }
727
728 RooArgSet recycledNodes ;
729 RooArgSet nodesToBeDeleted ;
730 for (const auto node : cloneSet2) {
731 if (_autoClass) {
732 if (!_classes.autoImportClass(node->IsA())) {
733 coutW(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") WARNING: problems import class code of object "
734 << node->ClassName() << "::" << node->GetName() << ", reading of workspace will require external definition of class" << std::endl ;
735 }
736 }
737
738 // Point expensiveObjectCache to copy in this workspace
739 RooExpensiveObjectCache& oldCache = node->expensiveObjectCache() ;
740 node->setExpensiveObjectCache(_eocache) ;
741 _eocache.importCacheObjects(oldCache,node->GetName(),true) ;
742
743 // Check if node is already in workspace (can only happen for variables or identical instances, unless RecycleConflictNodes is specified)
744 RooAbsArg* wsnode = _allOwnedNodes.find(node->GetName()) ;
745
746 if (wsnode) {
747 // Do not import node, add not to list of nodes that require reconnection
748 if (!silence && useExistingNodes) {
749 coutI(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") using existing copy of " << node->ClassName()
750 << "::" << node->GetName() << " for import of " << cloneTop2->ClassName() << "::"
751 << cloneTop2->GetName() << std::endl ;
752 }
753 recycledNodes.add(*_allOwnedNodes.find(node->GetName())) ;
754
755 // Delete clone of incoming node
756 nodesToBeDeleted.addOwned(std::unique_ptr<RooAbsArg>{node});
757
758 //cout << "WV: recycling existing node " << existingNode << " = " << existingNode->GetName() << " for imported node " << node << std::endl ;
759
760 } else {
761 // Import node
762 if (!silence) {
763 coutI(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") importing " << node->ClassName() << "::"
764 << node->GetName() << std::endl ;
765 }
766 _allOwnedNodes.addOwned(std::unique_ptr<RooAbsArg>{node});
767 node->setWorkspace(*this);
768 if (_openTrans) {
769 _sandboxNodes.add(*node) ;
770 } else {
771 if (_dir && node->IsA() != RooConstVar::Class()) {
772 _dir->InternalAppend(node) ;
773 }
774 }
775 }
776 }
777
778 // Reconnect any nodes that need to be
779 if (!recycledNodes.empty()) {
780 for (const auto node : cloneSet2) {
781 node->redirectServers(recycledNodes) ;
782 }
783 }
784
785 cloneSet2.releaseOwnership() ;
786
787 return false ;
788}
789
790
791
792////////////////////////////////////////////////////////////////////////////////
793/// Import a dataset (RooDataSet or RooDataHist) into the workspace. The workspace will contain a copy of the data.
794/// The dataset and its variables can be renamed upon insertion with the options below
795///
796/// <table>
797/// <tr><th> Accepted arguments
798/// <tr><td> `Rename(const char* suffix)` <td> Rename dataset upon insertion
799/// <tr><td> `RenameVariable(const char* inputName, const char* outputName)` <td> Change names of observables in dataset upon insertion
800/// <tr><td> `Silence` <td> Be quiet, except in case of errors
801/// \note From python, use `Import()`, since `import` is a reserved keyword.
802/// \return due to historical reasons: false (0) on success and true (1) on failure
804 const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3,
805 const RooCmdArg& arg4, const RooCmdArg& arg5, const RooCmdArg& arg6,
806 const RooCmdArg& arg7, const RooCmdArg& arg8, const RooCmdArg& arg9)
807
808{
809
810 RooLinkedList args ;
811 args.Add((TObject*)&arg1) ;
812 args.Add((TObject*)&arg2) ;
813 args.Add((TObject*)&arg3) ;
814 args.Add((TObject*)&arg4) ;
815 args.Add((TObject*)&arg5) ;
816 args.Add((TObject*)&arg6) ;
817 args.Add((TObject*)&arg7) ;
818 args.Add((TObject*)&arg8) ;
819 args.Add((TObject*)&arg9) ;
820
821 // Select the pdf-specific commands
822 RooCmdConfig pc(Form("RooWorkspace::import(%s)",GetName())) ;
823
824 pc.defineString("dsetName","Rename",0,"") ;
825 pc.defineString("varChangeIn","RenameVar",0,"",true) ;
826 pc.defineString("varChangeOut","RenameVar",1,"",true) ;
827 pc.defineInt("embedded","Embedded",0,0) ;
828 pc.defineInt("silence","Silence",0,0) ;
829
830 // Process and check varargs
831 pc.process(args) ;
832 if (!pc.ok(true)) {
833 return true ;
834 }
835
836 // Decode renaming logic into suffix string and boolean for conflictOnly mode
837 const char* dsetName = pc.getString("dsetName") ;
838 const char* varChangeIn = pc.getString("varChangeIn") ;
839 const char* varChangeOut = pc.getString("varChangeOut") ;
840 bool embedded = pc.getInt("embedded") ;
841 Int_t silence = pc.getInt("silence") ;
842
843 if (!silence)
844 coutI(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") importing dataset " << inData.GetName() << std::endl ;
845
846 // Transform empty string into null pointer
847 if (dsetName && strlen(dsetName)==0) {
848 dsetName=nullptr ;
849 }
850
851 RooLinkedList& dataList = embedded ? _embeddedDataList : _dataList ;
852 if (dataList.size() > 50 && dataList.getHashTableSize() == 0) {
853 // When the workspaces get larger, traversing the linked list becomes a bottleneck:
854 dataList.setHashTableSize(200);
855 }
856
857 // Check that no dataset with target name already exists
858 if (dsetName && dataList.FindObject(dsetName)) {
859 coutE(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") ERROR dataset with name " << dsetName << " already exists in workspace, import aborted" << std::endl ;
860 return true ;
861 }
862 if (!dsetName && dataList.FindObject(inData.GetName())) {
863 coutE(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") ERROR dataset with name " << inData.GetName() << " already exists in workspace, import aborted" << std::endl ;
864 return true ;
865 }
866
867 // Rename dataset if required
868 RooAbsData* clone ;
869 if (dsetName) {
870 if (!silence)
871 coutI(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") changing name of dataset from " << inData.GetName() << " to " << dsetName << std::endl ;
872 clone = static_cast<RooAbsData*>(inData.Clone(dsetName)) ;
873 } else {
874 clone = static_cast<RooAbsData*>(inData.Clone(inData.GetName())) ;
875 }
876
877
878 // Process any change in variable names
879 if (strlen(varChangeIn)>0) {
880 // Parse comma separated lists of variable name changes
881 const std::vector<std::string> tokIn = ROOT::Split(varChangeIn, ",");
882 const std::vector<std::string> tokOut = ROOT::Split(varChangeOut, ",");
883 for (unsigned int i=0; i < tokIn.size(); ++i) {
884 if (!silence)
885 coutI(ObjectHandling) << "RooWorkSpace::import(" << GetName() << ") changing name of dataset observable " << tokIn[i] << " to " << tokOut[i] << std::endl ;
886 clone->changeObservableName(tokIn[i].c_str(), tokOut[i].c_str());
887 }
888 }
889
890 // Now import the dataset observables, unless dataset is embedded
891 if (!embedded) {
892 for(RooAbsArg* carg : *clone->get()) {
893 if (!arg(carg->GetName())) {
894 import(*carg) ;
895 }
896 }
897 }
898
899 dataList.Add(clone) ;
900 if (_dir) {
901 _dir->InternalAppend(clone) ;
902 }
903
904 // Set expensive object cache of dataset internal buffers to that of workspace
905 for(RooAbsArg* carg : *clone->get()) {
906 carg->setExpensiveObjectCache(expensiveObjectCache()) ;
907 }
908
909
910 return false ;
911}
912
913
914
915
916////////////////////////////////////////////////////////////////////////////////
917/// Define a named RooArgSet with given constituents. If importMissing is true, any constituents
918/// of aset that are not in the workspace will be imported, otherwise an error is returned
919/// for missing components
920/// \return due to historical reasons: false (0) on success and true (1) on failure
921bool RooWorkspace::defineSet(const char* name, const RooArgSet& aset, bool importMissing)
922{
923 // Check if set was previously defined, if so print warning
924 map<string,RooArgSet>::iterator i = _namedSets.find(name) ;
925 if (i!=_namedSets.end()) {
926 coutW(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") WARNING redefining previously defined named set " << name << std::endl ;
927 }
928
929 RooArgSet wsargs ;
930
931 // Check all constituents of provided set
932 for (RooAbsArg* sarg : aset) {
933 // If missing, either import or report error
934 if (!arg(sarg->GetName())) {
935 if (importMissing) {
936 import(*sarg) ;
937 } else {
938 coutE(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") ERROR set constituent \"" << sarg->GetName()
939 << "\" is not in workspace and importMissing option is disabled" << std::endl ;
940 return true ;
941 }
942 }
943 wsargs.add(*arg(sarg->GetName())) ;
944 }
945
946
947 // Install named set
948 _namedSets[name].removeAll() ;
949 _namedSets[name].add(wsargs) ;
950
951 return false ;
952}
953
954//_____________________________________________________________________________
955// \return due to historical reasons: false (0) on success (always)
956bool RooWorkspace::defineSetInternal(const char *name, const RooArgSet &aset)
957{
958 // Define a named RooArgSet with given constituents. If importMissing is true, any constituents
959 // of aset that are not in the workspace will be imported, otherwise an error is returned
960 // for missing components
961
962 // Check if set was previously defined, if so print warning
963 map<string, RooArgSet>::iterator i = _namedSets.find(name);
964 if (i != _namedSets.end()) {
965 coutW(InputArguments) << "RooWorkspace::defineSet(" << GetName()
966 << ") WARNING redefining previously defined named set " << name << std::endl;
967 }
968
969 // Install named set
970 _namedSets[name].removeAll();
971 _namedSets[name].add(aset);
972
973 return false;
974}
975
976////////////////////////////////////////////////////////////////////////////////
977/// Define a named set in the workspace through a comma separated list of
978/// names of objects already in the workspace
979/// \return due to historical reasons: false (0) on success and true (1) on failure
980bool RooWorkspace::defineSet(const char* name, const char* contentList)
981{
982 // Check if set was previously defined, if so print warning
983 map<string,RooArgSet>::iterator i = _namedSets.find(name) ;
984 if (i!=_namedSets.end()) {
985 coutW(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") WARNING redefining previously defined named set " << name << std::endl ;
986 }
987
988 RooArgSet wsargs ;
989
990 // Check all constituents of provided set
991 for (const std::string& token : ROOT::Split(contentList, ",")) {
992 // If missing, either import or report error
993 if (!arg(token.c_str())) {
994 coutE(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") ERROR proposed set constituent \"" << token
995 << "\" is not in workspace" << std::endl ;
996 return true ;
997 }
998 wsargs.add(*arg(token.c_str())) ;
999 }
1000
1001 // Install named set
1002 _namedSets[name].removeAll() ;
1003 _namedSets[name].add(wsargs) ;
1004
1005 return false ;
1006}
1007
1008
1009
1010
1011////////////////////////////////////////////////////////////////////////////////
1012/// Define a named set in the workspace through a comma separated list of
1013/// names of objects already in the workspace
1014/// \return due to historical reasons: false (0) on success and true (1) on failure
1015bool RooWorkspace::extendSet(const char* name, const char* newContents)
1016{
1017 RooArgSet wsargs ;
1018
1019 // Check all constituents of provided set
1020 for (const std::string& token : ROOT::Split(newContents, ",")) {
1021 // If missing, either import or report error
1022 if (!arg(token.c_str())) {
1023 coutE(InputArguments) << "RooWorkspace::defineSet(" << GetName() << ") ERROR proposed set constituent \"" << token
1024 << "\" is not in workspace" << std::endl ;
1025 return true ;
1026 }
1027 wsargs.add(*arg(token.c_str())) ;
1028 }
1029
1030 // Extend named set
1031 _namedSets[name].add(wsargs,true) ;
1032
1033 return false ;
1034}
1035
1036
1037
1038////////////////////////////////////////////////////////////////////////////////
1039/// Return pointer to previously defined named set with given nmame
1040/// If no such set is found a null pointer is returned
1041
1043{
1044 std::map<string,RooArgSet>::iterator i = _namedSets.find(name.c_str());
1045 return (i!=_namedSets.end()) ? &(i->second) : nullptr;
1046}
1047
1048
1049
1050
1051////////////////////////////////////////////////////////////////////////////////
1052/// Rename set to a new name
1053/// \return due to historical reasons: false (0) on success and true (1) on failure
1054bool RooWorkspace::renameSet(const char* name, const char* newName)
1055{
1056 // First check if set exists
1057 if (!set(name)) {
1058 coutE(InputArguments) << "RooWorkspace::renameSet(" << GetName() << ") ERROR a set with name " << name
1059 << " does not exist" << std::endl ;
1060 return true ;
1061 }
1062
1063 // Check if no set exists with new name
1064 if (set(newName)) {
1065 coutE(InputArguments) << "RooWorkspace::renameSet(" << GetName() << ") ERROR a set with name " << newName
1066 << " already exists" << std::endl ;
1067 return true ;
1068 }
1069
1070 // Copy entry under 'name' to 'newName'
1071 _namedSets[newName].add(_namedSets[name]) ;
1072
1073 // Remove entry under old name
1074 _namedSets.erase(name) ;
1075
1076 return false ;
1077}
1078
1079
1080
1081
1082////////////////////////////////////////////////////////////////////////////////
1083/// Remove a named set from the workspace
1084/// \return due to historical reasons: false (0) on success and true (1) on failure
1086{
1087 // First check if set exists
1088 if (!set(name)) {
1089 coutE(InputArguments) << "RooWorkspace::removeSet(" << GetName() << ") ERROR a set with name " << name
1090 << " does not exist" << std::endl ;
1091 return true ;
1092 }
1093
1094 // Remove set with given name
1095 _namedSets.erase(name) ;
1096
1097 return false ;
1098}
1099
1100
1101
1102
1103////////////////////////////////////////////////////////////////////////////////
1104/// Open an import transaction operations.
1105/// \return true if successful, false if there is already an ongoing transaction
1106
1108{
1109 // Check that there was no ongoing transaction
1110 if (_openTrans) {
1111 return false ;
1112 }
1113
1114 // Open transaction
1115 _openTrans = true ;
1116 return true ;
1117}
1118
1119
1120
1121
1122////////////////////////////////////////////////////////////////////////////////
1123/// Cancel an ongoing import transaction. All objects imported since startTransaction()
1124/// will be removed and the transaction will be terminated.
1125/// \return true if cancel operation succeeds, return false if there was no open transaction
1126
1128{
1129 // Check that there is an ongoing transaction
1130 if (!_openTrans) {
1131 return false ;
1132 }
1133
1134 // Delete all objects in the sandbox
1135 for(RooAbsArg * tmpArg : _sandboxNodes) {
1136 _allOwnedNodes.remove(*tmpArg) ;
1137 }
1139
1140 // Mark transaction as finished
1141 _openTrans = false ;
1142
1143 return true ;
1144}
1145
1146/// Commit an ongoing import transaction.
1147/// \return true if commit succeeded, return false if there was no ongoing transaction
1149{
1150 // Check that there is an ongoing transaction
1151 if (!_openTrans) {
1152 return false ;
1153 }
1154
1155 // Publish sandbox nodes in directory and/or Cling if requested
1156 for(RooAbsArg* sarg : _sandboxNodes) {
1157 if (_dir && sarg->IsA() != RooConstVar::Class()) {
1158 _dir->InternalAppend(sarg) ;
1159 }
1160 }
1161
1162 // Remove all committed objects from the sandbox
1164
1165 // Mark transaction as finished
1166 _openTrans = false ;
1167
1168 return true ;
1169}
1170
1171
1172
1173
1174////////////////////////////////////////////////////////////////////////////////
1175/// \return true on success, false on failure
1176/// \see RooWorkspace::CodeRepo::autoImportClass
1177bool RooWorkspace::importClassCode(TClass* theClass, bool doReplace)
1178{
1179 return _classes.autoImportClass(theClass,doReplace) ;
1180}
1181
1182
1183
1184////////////////////////////////////////////////////////////////////////////////
1185/// Import code of all classes in the workspace that have a class name
1186/// that matches pattern 'pat' and which are not found to be part of
1187/// the standard ROOT distribution. If doReplace is true any existing
1188/// class code saved in the workspace is replaced
1189/// \return true on success, false on failure
1190bool RooWorkspace::importClassCode(const char* pat, bool doReplace)
1191{
1192 bool ret(true) ;
1193
1194 TRegexp re(pat,true) ;
1195 for (RooAbsArg * carg : _allOwnedNodes) {
1196 TString className = carg->ClassName() ;
1197 if (className.Index(re)>=0 && !_classes.autoImportClass(carg->IsA(),doReplace)) {
1198 coutW(ObjectHandling) << "RooWorkspace::import(" << GetName() << ") WARNING: problems import class code of object "
1199 << carg->ClassName() << "::" << carg->GetName() << ", reading of workspace will require external definition of class" << std::endl ;
1200 ret = false ;
1201 }
1202 }
1203
1204 return ret ;
1205}
1206
1207
1208
1209
1210
1211////////////////////////////////////////////////////////////////////////////////
1212/// Save snapshot of values and attributes (including "Constant") of given parameters.
1213/// \param[in] name Name of the snapshot.
1214/// \param[in] paramNames Comma-separated list of parameter names to be snapshot.
1215/// \return true always (success)
1216bool RooWorkspace::saveSnapshot(RooStringView name, const char* paramNames)
1217{
1218 return saveSnapshot(name,argSet(paramNames),false) ;
1219}
1220
1221
1222
1223
1224
1225////////////////////////////////////////////////////////////////////////////////
1226/// Save snapshot of values and attributes (including "Constant") of parameters 'params'.
1227/// If importValues is FALSE, the present values from the object in the workspace are
1228/// saved. If importValues is TRUE, the values of the objects passed in the 'params'
1229/// argument are saved
1230/// \return true always (success)
1231bool RooWorkspace::saveSnapshot(RooStringView name, const RooArgSet& params, bool importValues)
1232{
1233 RooArgSet actualParams;
1234 _allOwnedNodes.selectCommon(params, actualParams);
1235 auto snapshot = new RooArgSet;
1236 actualParams.snapshot(*snapshot);
1237
1238 snapshot->setName(name.c_str()) ;
1239
1240 if (importValues) {
1241 snapshot->assign(params) ;
1242 }
1243
1244 if (std::unique_ptr<RooArgSet> oldSnap{static_cast<RooArgSet*>(_snapshots.FindObject(name.c_str()))}) {
1245 coutI(ObjectHandling) << "RooWorkspace::saveSnapshot(" << GetName() << ") replacing previous snapshot with name " << name << std::endl ;
1246 _snapshots.Remove(oldSnap.get()) ;
1247 }
1248
1249 _snapshots.Add(snapshot) ;
1250
1251 return true ;
1252}
1253
1254
1255
1256
1257////////////////////////////////////////////////////////////////////////////////
1258/// Load the values and attributes of the parameters in the snapshot saved with
1259/// the given name
1260/// \return true on success, false on failure
1262{
1263 RooArgSet* snap = static_cast<RooArgSet*>(_snapshots.find(name)) ;
1264 if (!snap) {
1265 coutE(ObjectHandling) << "RooWorkspace::loadSnapshot(" << GetName() << ") no snapshot with name " << name << " is available" << std::endl ;
1266 return false ;
1267 }
1268
1269 RooArgSet actualParams;
1270 _allOwnedNodes.selectCommon(*snap, actualParams);
1271 actualParams.assign(*snap) ;
1272
1273 return true ;
1274}
1275
1276
1277////////////////////////////////////////////////////////////////////////////////
1278/// Return the RooArgSet containing a snapshot of variables contained in the workspace
1279///
1280/// Note that the variables of the objects in the snapshots are **copies** of the
1281/// variables in the workspace. To load the values of a snapshot in the workspace
1282/// variables, use loadSnapshot() instead.
1283
1285{
1286 return static_cast<RooArgSet*>(_snapshots.find(name));
1287}
1288
1289
1290////////////////////////////////////////////////////////////////////////////////
1291/// Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found
1292
1294{
1295 return dynamic_cast<RooAbsPdf*>(_allOwnedNodes.find(name.c_str())) ;
1296}
1297
1298
1299////////////////////////////////////////////////////////////////////////////////
1300/// Retrieve function (RooAbsReal) with given name. Note that all RooAbsPdfs are also RooAbsReals. A null pointer is returned if not found.
1301
1303{
1304 return dynamic_cast<RooAbsReal*>(_allOwnedNodes.find(name.c_str())) ;
1305}
1306
1307
1308////////////////////////////////////////////////////////////////////////////////
1309/// Retrieve real-valued variable (RooRealVar) with given name. A null pointer is returned if not found
1310
1312{
1313 return dynamic_cast<RooRealVar*>(_allOwnedNodes.find(name.c_str())) ;
1314}
1315
1316
1317////////////////////////////////////////////////////////////////////////////////
1318/// Retrieve discrete variable (RooCategory) with given name. A null pointer is returned if not found
1319
1321{
1322 return dynamic_cast<RooCategory*>(_allOwnedNodes.find(name.c_str())) ;
1323}
1324
1325
1326////////////////////////////////////////////////////////////////////////////////
1327/// Retrieve discrete function (RooAbsCategory) with given name. A null pointer is returned if not found
1328
1330{
1331 return dynamic_cast<RooAbsCategory*>(_allOwnedNodes.find(name.c_str())) ;
1332}
1333
1334
1335
1336////////////////////////////////////////////////////////////////////////////////
1337/// Return RooAbsArg with given name. A null pointer is returned if none is found.
1338
1340{
1341 return _allOwnedNodes.find(name.c_str()) ;
1342}
1343
1344
1345
1346////////////////////////////////////////////////////////////////////////////////
1347/// Return set of RooAbsArgs matching to given list of names
1348
1350{
1351 RooArgSet ret ;
1352
1353 for (const std::string& token : ROOT::Split(nameList, ",")) {
1354 RooAbsArg* oneArg = arg(token.c_str()) ;
1355 if (oneArg) {
1356 ret.add(*oneArg) ;
1357 } else {
1358 std::stringstream ss;
1359 ss << " RooWorkspace::argSet(" << GetName() << ") no RooAbsArg named \"" << token << "\" in workspace" ;
1360 const std::string errorMsg = ss.str();
1361 coutE(InputArguments) << errorMsg << std::endl;
1362 throw std::runtime_error(errorMsg);
1363 }
1364 }
1365 return ret ;
1366}
1367
1368
1369
1370////////////////////////////////////////////////////////////////////////////////
1371/// Return fundamental (i.e. non-derived) RooAbsArg with given name. Fundamental types
1372/// are e.g. RooRealVar, RooCategory. A null pointer is returned if none is found.
1373
1375{
1376 RooAbsArg* tmp = arg(name) ;
1377 if (!tmp) {
1378 return nullptr;
1379 }
1380 return tmp->isFundamental() ? tmp : nullptr;
1381}
1382
1383
1384
1385////////////////////////////////////////////////////////////////////////////////
1386/// Retrieve dataset (binned or unbinned) with given name. A null pointer is returned if not found
1387
1389{
1390 return static_cast<RooAbsData*>(_dataList.FindObject(name.c_str())) ;
1391}
1392
1393
1394////////////////////////////////////////////////////////////////////////////////
1395/// Retrieve dataset (binned or unbinned) with given name. A null pointer is returned if not found
1396
1398{
1399 return static_cast<RooAbsData*>(_embeddedDataList.FindObject(name.c_str())) ;
1400}
1401
1402
1403
1404
1405////////////////////////////////////////////////////////////////////////////////
1406/// Return set with all variable objects
1407
1409{
1410 RooArgSet ret ;
1411
1412 // Split list of components in pdfs, functions and variables
1413 for(RooAbsArg* parg : _allOwnedNodes) {
1414 if (parg->IsA()->InheritsFrom(RooRealVar::Class())) {
1415 ret.add(*parg) ;
1416 }
1417 }
1418
1419 return ret ;
1420}
1421
1422
1423////////////////////////////////////////////////////////////////////////////////
1424/// Return set with all category objects
1425
1427{
1428 RooArgSet ret ;
1429
1430 // Split list of components in pdfs, functions and variables
1431 for(RooAbsArg* parg : _allOwnedNodes) {
1432 if (parg->IsA()->InheritsFrom(RooCategory::Class())) {
1433 ret.add(*parg) ;
1434 }
1435 }
1436
1437 return ret ;
1438}
1439
1440
1441
1442////////////////////////////////////////////////////////////////////////////////
1443/// Return set with all function objects
1444
1446{
1447 RooArgSet ret ;
1448
1449 // Split list of components in pdfs, functions and variables
1450 for(RooAbsArg* parg : _allOwnedNodes) {
1451 if (parg->IsA()->InheritsFrom(RooAbsReal::Class()) &&
1452 !parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
1453 !parg->IsA()->InheritsFrom(RooConstVar::Class()) &&
1454 !parg->IsA()->InheritsFrom(RooRealVar::Class())) {
1455 ret.add(*parg) ;
1456 }
1457 }
1458
1459 return ret ;
1460}
1461
1462
1463////////////////////////////////////////////////////////////////////////////////
1464/// Return set with all category function objects
1465
1467{
1468 RooArgSet ret ;
1469
1470 // Split list of components in pdfs, functions and variables
1471 for(RooAbsArg* parg : _allOwnedNodes) {
1472 if (parg->IsA()->InheritsFrom(RooAbsCategory::Class()) &&
1473 !parg->IsA()->InheritsFrom(RooCategory::Class())) {
1474 ret.add(*parg) ;
1475 }
1476 }
1477 return ret ;
1478}
1479
1480
1481
1482////////////////////////////////////////////////////////////////////////////////
1483/// Return set with all resolution model objects
1484
1486{
1487 RooArgSet ret ;
1488
1489 // Split list of components in pdfs, functions and variables
1490 for(RooAbsArg* parg : _allOwnedNodes) {
1491 if (parg->IsA()->InheritsFrom(RooResolutionModel::Class())) {
1492 if (!(static_cast<RooResolutionModel*>(parg))->isConvolved()) {
1493 ret.add(*parg) ;
1494 }
1495 }
1496 }
1497 return ret ;
1498}
1499
1500
1501////////////////////////////////////////////////////////////////////////////////
1502/// Return set with all probability density function objects
1503
1505{
1506 RooArgSet ret ;
1507
1508 // Split list of components in pdfs, functions and variables
1509 for(RooAbsArg* parg : _allOwnedNodes) {
1510 if (parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
1511 !parg->IsA()->InheritsFrom(RooResolutionModel::Class())) {
1512 ret.add(*parg) ;
1513 }
1514 }
1515 return ret ;
1516}
1517
1518
1519
1520////////////////////////////////////////////////////////////////////////////////
1521/// Return list of all dataset in the workspace
1522
1523std::list<RooAbsData*> RooWorkspace::allData() const
1524{
1525 std::list<RooAbsData*> ret ;
1526 for(auto * dat : static_range_cast<RooAbsData*>(_dataList)) {
1527 ret.push_back(dat) ;
1528 }
1529 return ret ;
1530}
1531
1532
1533////////////////////////////////////////////////////////////////////////////////
1534/// Return list of all dataset in the workspace
1535
1536std::list<RooAbsData*> RooWorkspace::allEmbeddedData() const
1537{
1538 std::list<RooAbsData*> ret ;
1539 for(auto * dat : static_range_cast<RooAbsData*>(_embeddedDataList)) {
1540 ret.push_back(dat) ;
1541 }
1542 return ret ;
1543}
1544
1545
1546
1547////////////////////////////////////////////////////////////////////////////////
1548/// Return list of all generic objects in the workspace
1549
1550std::list<TObject*> RooWorkspace::allGenericObjects() const
1551{
1552 std::list<TObject*> ret ;
1553 for(TObject * gobj : _genObjects) {
1554
1555 // If found object is wrapper, return payload
1556 if (gobj->IsA()==RooTObjWrap::Class()) {
1557 ret.push_back((static_cast<RooTObjWrap*>(gobj))->obj()) ;
1558 } else {
1559 ret.push_back(gobj) ;
1560 }
1561 }
1562 return ret ;
1563}
1564
1565
1566namespace {
1567
1568std::string findFileInPath(std::string const &file, std::list<std::string> const &dirList)
1569{
1570 // Check list of additional paths
1571 for (std::string const &diter : dirList) {
1572 TString temp = file.c_str();
1573 const char *cpath = gSystem->PrependPathName(diter.c_str(), temp);
1574 std::string path = cpath;
1575 if (!gSystem->AccessPathName(path.c_str())) {
1576 // found file
1577 return path;
1578 }
1579 }
1580 return "";
1581}
1582
1583} // namespace
1584
1585
1586////////////////////////////////////////////////////////////////////////////////
1587/// Import code of class 'tc' into the repository. If code is already in repository it is only imported
1588/// again if doReplace is false. The names and location of the source files is determined from the information
1589/// in TClass. If no location is found in the TClass information, the files are searched in the workspace
1590/// search path, defined by addClassDeclImportDir() and addClassImplImportDir() for declaration and implementation
1591/// files respectively. If files cannot be found, abort with error status, otherwise update the internal
1592/// class-to-file map and import the contents of the files, if they are not imported yet.
1593/// \return true on success, false on failure
1595{
1596
1597 oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") request to import code of class " << tc->GetName() << std::endl ;
1598
1599 // *** PHASE 1 *** Check if file needs to be imported, or is in ROOT distribution, and check if it can be persisted
1600
1601 // Check if we already have the class (i.e. it is in the classToFile map)
1602 if (!doReplace && _c2fmap.find(tc->GetName())!=_c2fmap.end()) {
1603 oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") code of class " << tc->GetName() << " already imported, skipping" << std::endl ;
1604 return true ;
1605 }
1606
1607 // Check if class is listed in a ROOTMAP file - if so we can skip it because it is in the root distribution
1608 const char* mapEntry = gInterpreter->GetClassSharedLibs(tc->GetName()) ;
1609 if (mapEntry && strlen(mapEntry)>0) {
1610 oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") code of class " << tc->GetName() << " is in ROOT distribution, skipping " << std::endl ;
1611 return true ;
1612 }
1613
1614 // Retrieve file names through ROOT TClass interface
1615 string implfile = tc->GetImplFileName() ;
1616 string declfile = tc->GetDeclFileName() ;
1617
1618 // Check that file names are not empty
1619 if (implfile.empty() || declfile.empty()) {
1620 oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") ERROR: cannot retrieve code file names for class "
1621 << tc->GetName() << " through ROOT TClass interface, unable to import code" << std::endl ;
1622 return false ;
1623 }
1624
1625 // Check if header filename is found in ROOT distribution, if so, do not import class
1626 TString rootsys = gSystem->Getenv("ROOTSYS") ;
1627 if (TString(implfile.c_str()).Index(rootsys)>=0) {
1628 oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo(" << _wspace->GetName() << ") code of class " << tc->GetName() << " is in ROOT distribution, skipping " << std::endl ;
1629 return true ;
1630 }
1631
1632 // Require that class meets technical criteria to be persistable (i.e it has a default constructor)
1633 // (We also need a default constructor of abstract classes, but cannot check that through is interface
1634 // as TClass::HasDefaultCtor only returns true for callable default constructors)
1635 if (!(tc->Property() & kIsAbstract) && !tc->HasDefaultConstructor()) {
1636 oocoutW(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName() << ") WARNING cannot import class "
1637 << tc->GetName() << " : it cannot be persisted because it doesn't have a default constructor. Please fix " << std::endl ;
1638 return false ;
1639 }
1640
1641
1642 // *** PHASE 2 *** Check if declaration and implementation files can be located
1643
1644 std::string declpath;
1645 std::string implpath;
1646
1647 // Check if header file can be found in specified location
1648 // If not, scan through list of 'class declaration' paths in RooWorkspace
1649 if (gSystem->AccessPathName(declfile.c_str())) {
1650
1651 declpath = findFileInPath(declfile, RooWorkspace::_classDeclDirList);
1652
1653 // Header file cannot be found anywhere, warn user and abort operation
1654 if (declpath.empty()) {
1655 oocoutW(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName() << ") WARNING Cannot access code of class "
1656 << tc->GetName() << " because header file " << declfile << " is not found in current directory nor in $ROOTSYS" ;
1657 if (!_classDeclDirList.empty()) {
1658 ooccoutW(_wspace,ObjectHandling) << ", nor in the search path " ;
1659 auto diter = RooWorkspace::_classDeclDirList.begin() ;
1660
1661 while(diter!= RooWorkspace::_classDeclDirList.end()) {
1662
1663 if (diter!=RooWorkspace::_classDeclDirList.begin()) {
1664 ooccoutW(_wspace,ObjectHandling) << "," ;
1665 }
1666 ooccoutW(_wspace,ObjectHandling) << diter->c_str() ;
1667 ++diter ;
1668 }
1669 }
1670 ooccoutW(_wspace,ObjectHandling) << ". To fix this problem, add the required directory to the search "
1671 << "path using RooWorkspace::addClassDeclImportDir(const char* dir)" << std::endl ;
1672
1673 return false ;
1674 }
1675 }
1676
1677
1678 // Check if implementation file can be found in specified location
1679 // If not, scan through list of 'class implementation' paths in RooWorkspace
1680 if (gSystem->AccessPathName(implfile.c_str())) {
1681
1682 implpath = findFileInPath(implfile, RooWorkspace::_classImplDirList);
1683
1684 // Implementation file cannot be found anywhere, warn user and abort operation
1685 if (implpath.empty()) {
1686 oocoutW(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName() << ") WARNING Cannot access code of class "
1687 << tc->GetName() << " because implementation file " << implfile << " is not found in current directory nor in $ROOTSYS" ;
1688 if (!_classDeclDirList.empty()) {
1689 ooccoutW(_wspace,ObjectHandling) << ", nor in the search path " ;
1690 auto iiter = RooWorkspace::_classImplDirList.begin() ;
1691
1692 while(iiter!= RooWorkspace::_classImplDirList.end()) {
1693
1694 if (iiter!=RooWorkspace::_classImplDirList.begin()) {
1695 ooccoutW(_wspace,ObjectHandling) << "," ;
1696 }
1697 ooccoutW(_wspace,ObjectHandling) << iiter->c_str() ;
1698 ++iiter ;
1699 }
1700 }
1701 ooccoutW(_wspace,ObjectHandling) << ". To fix this problem add the required directory to the search "
1702 << "path using RooWorkspace::addClassImplImportDir(const char* dir)" << std::endl;
1703 return false;
1704 }
1705 }
1706
1707 char buf[64000];
1708
1709 // *** Phase 3 *** Prepare to import code from files into STL string buffer
1710 //
1711 // Code storage is organized in two linked maps
1712 //
1713 // _fmap contains stl strings with code, indexed on declaration file name
1714 //
1715 // _c2fmap contains list of declaration file names and list of base classes
1716 // and is indexed on class name
1717 //
1718 // Phase 3 is skipped if fmap already contains an entry with given filebasename
1719
1720 const std::string declfilename = !declpath.empty() ? gSystem->BaseName(declpath.c_str())
1721 : gSystem->BaseName(declfile.c_str());
1722
1723 // Split in base and extension
1724 int dotpos2 = strrchr(declfilename.c_str(),'.') - declfilename.c_str() ;
1725 string declfilebase = declfilename.substr(0,dotpos2) ;
1726 string declfileext = declfilename.substr(dotpos2+1) ;
1727
1728 list<string> extraHeaders ;
1729
1730 // If file has not been stored yet, enter stl strings with implementation and declaration in file map
1731 if (_fmap.find(declfilebase) == _fmap.end()) {
1732
1733 // Open declaration file
1734 std::fstream fdecl(!declpath.empty() ? declpath.c_str() : declfile.c_str());
1735
1736 // Abort import if declaration file cannot be opened
1737 if (!fdecl) {
1738 oocoutE(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
1739 << ") ERROR opening declaration file " << declfile << std::endl ;
1740 return false ;
1741 }
1742
1743 oocoutI(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
1744 << ") importing code of class " << tc->GetName()
1745 << " from " << (!implpath.empty() ? implpath.c_str() : implfile.c_str())
1746 << " and " << (!declpath.empty() ? declpath.c_str() : declfile.c_str()) << std::endl ;
1747
1748
1749 // Read entire file into an stl string
1750 string decl ;
1751 while(fdecl.getline(buf,1023)) {
1752
1753 // Look for include state of self
1754 bool processedInclude = false ;
1755 char* extincfile = nullptr ;
1756
1757 // Look for include of declaration file corresponding to this implementation file
1758 if (strstr(buf,"#include")) {
1759 // Process #include statements here
1760 char tmp[64000];
1761 strlcpy(tmp, buf, 64000);
1762 bool stdinclude = strchr(buf, '<');
1763 strtok(tmp, " <\"");
1764 char *incfile = strtok(nullptr, " <>\"");
1765
1766 if (!stdinclude) {
1767 // check if it lives in $ROOTSYS/include
1768 TString hpath = gSystem->Getenv("ROOTSYS");
1769 hpath += "/include/";
1770 hpath += incfile;
1771 if (gSystem->AccessPathName(hpath.Data())) {
1772 oocoutI(_wspace, ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
1773 << ") scheduling include file " << incfile << " for import" << std::endl;
1774 extraHeaders.push_back(incfile);
1775 extincfile = incfile;
1776 processedInclude = true;
1777 }
1778 }
1779 }
1780
1781 if (processedInclude) {
1782 decl += "// external include file below retrieved from workspace code storage\n" ;
1783 decl += Form("#include \"%s\"\n",extincfile) ;
1784 } else {
1785 decl += buf ;
1786 decl += '\n' ;
1787 }
1788 }
1789
1790 // Open implementation file
1791 fstream fimpl(!implpath.empty() ? implpath.c_str() : implfile.c_str()) ;
1792
1793 // Abort import if implementation file cannot be opened
1794 if (!fimpl) {
1795 oocoutE(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
1796 << ") ERROR opening implementation file " << implfile << std::endl ;
1797 return false ;
1798 }
1799
1800
1801 // Import entire implementation file into stl string
1802 string impl ;
1803 while(fimpl.getline(buf,1023)) {
1804 // Process #include statements here
1805
1806 // Look for include state of self
1807 bool foundSelfInclude=false ;
1808 bool processedInclude = false ;
1809 char* extincfile = nullptr ;
1810
1811 // Look for include of declaration file corresponding to this implementation file
1812 if (strstr(buf,"#include")) {
1813 // Process #include statements here
1814 char tmp[64000];
1815 strlcpy(tmp, buf, 64000);
1816 bool stdinclude = strchr(buf, '<');
1817 strtok(tmp, " <\"");
1818 char *incfile = strtok(nullptr, " <>\"");
1819
1820 if (strstr(incfile, declfilename.c_str())) {
1821 foundSelfInclude = true;
1822 }
1823
1824 if (!stdinclude && !foundSelfInclude) {
1825 // check if it lives in $ROOTSYS/include
1826 TString hpath = gSystem->Getenv("ROOTSYS");
1827 hpath += "/include/";
1828 hpath += incfile;
1829
1830 if (gSystem->AccessPathName(hpath.Data())) {
1831 oocoutI(_wspace, ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
1832 << ") scheduling include file " << incfile << " for import" << std::endl;
1833 extraHeaders.push_back(incfile);
1834 extincfile = incfile;
1835 processedInclude = true;
1836 }
1837 }
1838 }
1839
1840 // Explicitly rewrite include of own declaration file to string
1841 // any directory prefixes, copy all other lines verbatim in stl string
1842 if (foundSelfInclude) {
1843 // If include of self is found, substitute original include
1844 // which may have directory structure with a plain include
1845 impl += "// class declaration include file below retrieved from workspace code storage\n" ;
1846 impl += Form("#include \"%s.%s\"\n",declfilebase.c_str(),declfileext.c_str()) ;
1847 } else if (processedInclude) {
1848 impl += "// external include file below retrieved from workspace code storage\n" ;
1849 impl += Form("#include \"%s\"\n",extincfile) ;
1850 } else {
1851 impl += buf ;
1852 impl += '\n' ;
1853 }
1854 }
1855
1856 // Create entry in file map
1857 _fmap[declfilebase]._hfile = decl ;
1858 _fmap[declfilebase]._cxxfile = impl ;
1859 _fmap[declfilebase]._hext = declfileext ;
1860
1861 // Process extra includes now
1862 for (list<string>::iterator ehiter = extraHeaders.begin() ; ehiter != extraHeaders.end() ; ++ehiter ) {
1863 if (_ehmap.find(*ehiter) == _ehmap.end()) {
1864
1865 ExtraHeader eh ;
1866 eh._hname = ehiter->c_str() ;
1867 fstream fehdr(ehiter->c_str()) ;
1868 string ehimpl ;
1869 char buf2[1024] ;
1870 while(fehdr.getline(buf2,1023)) {
1871
1872 // Look for include of declaration file corresponding to this implementation file
1873 if (strstr(buf2,"#include")) {
1874 // Process #include statements here
1875 char tmp[64000];
1876 strlcpy(tmp, buf2, 64000);
1877 bool stdinclude = strchr(buf, '<');
1878 strtok(tmp, " <\"");
1879 char *incfile = strtok(nullptr, " <>\"");
1880
1881 if (!stdinclude) {
1882 // check if it lives in $ROOTSYS/include
1883 TString hpath = gSystem->Getenv("ROOTSYS");
1884 hpath += "/include/";
1885 hpath += incfile;
1886 if (gSystem->AccessPathName(hpath.Data())) {
1887 oocoutI(_wspace, ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
1888 << ") scheduling recursive include file " << incfile << " for import"
1889 << std::endl;
1890 extraHeaders.push_back(incfile);
1891 }
1892 }
1893 }
1894
1895 ehimpl += buf2;
1896 ehimpl += '\n';
1897 }
1898 eh._hfile = ehimpl.c_str();
1899
1900 _ehmap[ehiter->c_str()] = eh;
1901 }
1902 }
1903
1904 } else {
1905
1906 // Inform that existing file entry is being recycled because it already contained class code
1907 oocoutI(_wspace,ObjectHandling) << "RooWorkspace::autoImportClass(" << _wspace->GetName()
1908 << ") code of class " << tc->GetName()
1909 << " was already imported from " << (!implpath.empty() ? implpath : implfile)
1910 << " and " << (!declpath.empty() ? declpath.c_str() : declfile.c_str()) << std::endl;
1911
1912 }
1913
1914
1915 // *** PHASE 4 *** Import stl strings with code into workspace
1916 //
1917 // If multiple classes are declared in a single code unit, there will be
1918 // multiple _c2fmap entries all pointing to the same _fmap entry.
1919
1920 // Make list of all immediate base classes of this class
1921 TString baseNameList ;
1922 TList* bl = tc->GetListOfBases() ;
1923 std::list<TClass*> bases ;
1924 for(auto * base : static_range_cast<TBaseClass*>(*bl)) {
1925 if (baseNameList.Length()>0) {
1926 baseNameList += "," ;
1927 }
1928 baseNameList += base->GetClassPointer()->GetName() ;
1929 bases.push_back(base->GetClassPointer()) ;
1930 }
1931
1932 // Map class name to above _fmap entries, along with list of base classes
1933 // in _c2fmap
1934 _c2fmap[tc->GetName()]._baseName = baseNameList ;
1935 _c2fmap[tc->GetName()]._fileBase = declfilebase ;
1936
1937 // Recursive store all base classes.
1938 for(TClass* bclass : bases) {
1939 autoImportClass(bclass,doReplace) ;
1940 }
1941
1942 return true ;
1943}
1944
1945
1946////////////////////////////////////////////////////////////////////////////////
1947/// Create transient TDirectory representation of this workspace. This directory
1948/// will appear as a subdirectory of the directory that contains the workspace
1949/// and will have the name of the workspace suffixed with "Dir". The TDirectory
1950/// interface is read-only. Any attempt to insert objects into the workspace
1951/// directory representation will result in an error message. Note that some
1952/// ROOT object like TH1 automatically insert themselves into the current directory
1953/// when constructed. This will give error messages when done in a workspace
1954/// directory.
1955/// \return true (success) always
1957{
1958 if (_dir) return true ;
1959
1960 std::string title= "TDirectory representation of RooWorkspace " + std::string(GetName());
1961 _dir = new WSDir(GetName(),title.c_str(),this) ;
1962
1963 for (RooAbsArg * darg : _allOwnedNodes) {
1964 if (darg->IsA() != RooConstVar::Class()) {
1965 _dir->InternalAppend(darg) ;
1966 }
1967 }
1968
1969 return true ;
1970}
1971
1972
1973
1974////////////////////////////////////////////////////////////////////////////////
1975/// Import a clone of a generic TObject into workspace generic object container. Imported
1976/// object can be retrieved by name through the obj() method. The object is cloned upon
1977/// importation and the input argument does not need to live beyond the import call
1978///
1979/// \return due to historical reasons: false (0) on success and true (1) on failure
1980
1981bool RooWorkspace::import(TObject const& object, bool replaceExisting)
1982{
1983 // First check if object with given name already exists
1984 std::unique_ptr<TObject> oldObj{_genObjects.FindObject(object.GetName())};
1985 if (oldObj && !replaceExisting) {
1986 coutE(InputArguments) << "RooWorkspace::import(" << GetName() << ") generic object with name "
1987 << object.GetName() << " is already in workspace and replaceExisting flag is set to false" << std::endl ;
1988 return true ;
1989 }
1990
1991 // Grab the current state of the directory Auto-Add
1992 ROOT::DirAutoAdd_t func = object.IsA()->GetDirectoryAutoAdd();
1993 object.IsA()->SetDirectoryAutoAdd(nullptr);
1994 bool tmp = RooPlot::setAddDirectoryStatus(false) ;
1995
1996 if (oldObj) {
1997 _genObjects.Replace(oldObj.get(),object.Clone()) ;
1998 } else {
1999 _genObjects.Add(object.Clone()) ;
2000 }
2001
2002 // Reset the state of the directory Auto-Add
2003 object.IsA()->SetDirectoryAutoAdd(func);
2005
2006 return false ;
2007}
2008
2009
2010
2011
2012////////////////////////////////////////////////////////////////////////////////
2013/// Import a clone of a generic TObject into workspace generic object container.
2014/// The imported object will be stored under the given alias name rather than its
2015/// own name. Imported object can be retrieved its alias name through the obj() method.
2016/// The object is cloned upon importation and the input argument does not need to live beyond the import call
2017/// This method is mostly useful for importing objects that do not have a settable name such as TMatrix
2018///
2019/// \return due to historical reasons: false (0) on success and true (1) on failure
2020
2021bool RooWorkspace::import(TObject const& object, const char* aliasName, bool replaceExisting)
2022{
2023 // First check if object with given name already exists
2024 std::unique_ptr<TObject> oldObj{_genObjects.FindObject(aliasName)};
2025 if (oldObj && !replaceExisting) {
2026 coutE(InputArguments) << "RooWorkspace::import(" << GetName() << ") generic object with name "
2027 << aliasName << " is already in workspace and replaceExisting flag is set to false" << std::endl ;
2028 return true ;
2029 }
2030
2031 TDirectory::TContext ctx{nullptr}; // No self-registration to directories
2032 auto wrapper = new RooTObjWrap(object.Clone());
2033 wrapper->setOwning(true) ;
2034 wrapper->SetName(aliasName) ;
2035 wrapper->SetTitle(aliasName) ;
2036
2037 if (oldObj) {
2038 _genObjects.Replace(oldObj.get(),wrapper) ;
2039 } else {
2040 _genObjects.Add(wrapper) ;
2041 }
2042 return false ;
2043}
2044
2045
2046
2047
2048////////////////////////////////////////////////////////////////////////////////
2049/// Insert RooStudyManager module
2050/// \return due to historical reasons: false (0) on success and true (1) on failure
2052{
2053 RooAbsStudy* clone = static_cast<RooAbsStudy*>(study.Clone()) ;
2054 _studyMods.Add(clone) ;
2055 return false ;
2056}
2057
2058
2059
2060
2061////////////////////////////////////////////////////////////////////////////////
2062/// Remove all RooStudyManager modules
2063
2068
2069
2070
2071
2072////////////////////////////////////////////////////////////////////////////////
2073/// Return any type of object (RooAbsArg, RooAbsData or generic object) with given name)
2074
2076{
2077 // Try RooAbsArg first
2078 TObject* ret = arg(name) ;
2079 if (ret) return ret ;
2080
2081 // Then try RooAbsData
2082 ret = data(name) ;
2083 if (ret) return ret ;
2084
2085 // Finally try generic object store
2086 return genobj(name) ;
2087}
2088
2089
2090
2091////////////////////////////////////////////////////////////////////////////////
2092/// Return generic object with given name
2093
2095{
2096 // Find object by name
2097 TObject* gobj = _genObjects.FindObject(name.c_str()) ;
2098
2099 // Exit here if not found
2100 if (!gobj) return nullptr;
2101
2102 // If found object is wrapper, return payload
2103 if (gobj->IsA()==RooTObjWrap::Class()) return (static_cast<RooTObjWrap*>(gobj))->obj() ;
2104
2105 return gobj ;
2106}
2107
2108
2109
2110////////////////////////////////////////////////////////////////////////////////
2111/// \return true on success, false on failure
2112/// \see TDirectoryFile::cd
2113bool RooWorkspace::cd(const char* path)
2114{
2115 makeDir() ;
2116 return _dir->cd(path) ;
2117}
2118
2119
2120
2121////////////////////////////////////////////////////////////////////////////////
2122/// Save this current workspace into given file
2123/// \return true if file correctly written, false in case of error
2124
2125bool RooWorkspace::writeToFile(const char* fileName, bool recreate)
2126{
2127 std::unique_ptr<TFile> f{ TFile::Open(fileName, recreate ? "RECREATE" : "UPDATE") };
2128 if (!f || f->IsZombie())
2129 return false;
2130 auto bytes = Write();
2131 return bytes > 0;
2132}
2133
2134
2135
2136////////////////////////////////////////////////////////////////////////////////
2137/// Return instance to factory tool
2138
2140{
2141 if (_factory) {
2142 return *_factory;
2143 }
2144 cxcoutD(ObjectHandling) << "INFO: Creating RooFactoryWSTool associated with this workspace" << std::endl ;
2145 _factory = make_unique<RooFactoryWSTool>(*this);
2146 return *_factory;
2147}
2148
2149
2150
2151
2152////////////////////////////////////////////////////////////////////////////////
2153/// Short-hand function for `factory()->process(expr);`
2154///
2155/// \copydoc RooFactoryWSTool::process(const char*)
2157{
2158 return factory().process(expr.c_str()) ;
2159}
2160
2161
2162
2163
2164////////////////////////////////////////////////////////////////////////////////
2165/// Print contents of the workspace
2166
2168{
2169 bool treeMode(false) ;
2170 bool verbose(false);
2171 if (TString(opts).Contains("t")) {
2172 treeMode=true ;
2173 }
2174 if (TString(opts).Contains("v")) {
2175 verbose = true;
2176 }
2177
2178 std::cout << std::endl << "RooWorkspace(" << GetName() << ") " << GetTitle() << " contents" << std::endl << std::endl ;
2179
2180 RooArgSet pdfSet ;
2181 RooArgSet funcSet ;
2182 RooArgSet varSet ;
2183 RooArgSet catfuncSet ;
2184 RooArgSet convResoSet ;
2185 RooArgSet resoSet ;
2186
2187
2188 // Split list of components in pdfs, functions and variables
2189 for(RooAbsArg* parg : _allOwnedNodes) {
2190
2191 //---------------
2192
2193 if (treeMode) {
2194
2195 // In tree mode, only add nodes with no clients to the print lists
2196
2197 if (parg->IsA()->InheritsFrom(RooAbsPdf::Class())) {
2198 if (!parg->hasClients()) {
2199 pdfSet.add(*parg) ;
2200 }
2201 }
2202
2203 if (parg->IsA()->InheritsFrom(RooAbsReal::Class()) &&
2204 !parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
2205 !parg->IsA()->InheritsFrom(RooConstVar::Class()) &&
2206 !parg->IsA()->InheritsFrom(RooRealVar::Class())) {
2207 if (!parg->hasClients()) {
2208 funcSet.add(*parg) ;
2209 }
2210 }
2211
2212
2213 if (parg->IsA()->InheritsFrom(RooAbsCategory::Class()) &&
2214 !parg->IsA()->InheritsFrom(RooCategory::Class())) {
2215 if (!parg->hasClients()) {
2216 catfuncSet.add(*parg) ;
2217 }
2218 }
2219
2220 } else {
2221
2222 if (parg->IsA()->InheritsFrom(RooResolutionModel::Class())) {
2223 if ((static_cast<RooResolutionModel*>(parg))->isConvolved()) {
2224 convResoSet.add(*parg) ;
2225 } else {
2226 resoSet.add(*parg) ;
2227 }
2228 }
2229
2230 if (parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
2231 !parg->IsA()->InheritsFrom(RooResolutionModel::Class())) {
2232 pdfSet.add(*parg) ;
2233 }
2234
2235 if (parg->IsA()->InheritsFrom(RooAbsReal::Class()) &&
2236 !parg->IsA()->InheritsFrom(RooAbsPdf::Class()) &&
2237 !parg->IsA()->InheritsFrom(RooConstVar::Class()) &&
2238 !parg->IsA()->InheritsFrom(RooRealVar::Class())) {
2239 funcSet.add(*parg) ;
2240 }
2241
2242 if (parg->IsA()->InheritsFrom(RooAbsCategory::Class()) &&
2243 !parg->IsA()->InheritsFrom(RooCategory::Class())) {
2244 catfuncSet.add(*parg) ;
2245 }
2246 }
2247
2248 if (parg->IsA()->InheritsFrom(RooRealVar::Class())) {
2249 varSet.add(*parg) ;
2250 }
2251
2252 if (parg->IsA()->InheritsFrom(RooCategory::Class())) {
2253 varSet.add(*parg) ;
2254 }
2255
2256 }
2257
2258
2259 RooFit::MsgLevel oldLevel = RooMsgService::instance().globalKillBelow() ;
2260 RooMsgService::instance().setGlobalKillBelow(RooFit::WARNING) ;
2261
2262 if (!varSet.empty()) {
2263 varSet.sort() ;
2264 std::cout << "variables" << std::endl ;
2265 std::cout << "---------" << std::endl ;
2266 std::cout << varSet << std::endl ;
2267 std::cout << std::endl ;
2268 }
2269
2270 if (!pdfSet.empty()) {
2271 std::cout << "p.d.f.s" << std::endl ;
2272 std::cout << "-------" << std::endl ;
2273 pdfSet.sort() ;
2274 for(RooAbsArg* parg : pdfSet) {
2275 if (treeMode) {
2276 parg->printComponentTree() ;
2277 } else {
2278 parg->Print() ;
2279 }
2280 }
2281 std::cout << std::endl ;
2282 }
2283
2284 if (!treeMode) {
2285 if (!resoSet.empty()) {
2286 std::cout << "analytical resolution models" << std::endl ;
2287 std::cout << "----------------------------" << std::endl ;
2288 resoSet.sort() ;
2289 for(RooAbsArg* parg : resoSet) {
2290 parg->Print() ;
2291 }
2292 std::cout << std::endl ;
2293 }
2294 }
2295
2296 if (!funcSet.empty()) {
2297 std::cout << "functions" << std::endl ;
2298 std::cout << "--------" << std::endl ;
2299 funcSet.sort() ;
2300 for(RooAbsArg * parg : funcSet) {
2301 if (treeMode) {
2302 parg->printComponentTree() ;
2303 } else {
2304 parg->Print() ;
2305 }
2306 }
2307 std::cout << std::endl ;
2308 }
2309
2310 if (!catfuncSet.empty()) {
2311 std::cout << "category functions" << std::endl ;
2312 std::cout << "------------------" << std::endl ;
2313 catfuncSet.sort() ;
2314 for(RooAbsArg* parg : catfuncSet) {
2315 if (treeMode) {
2316 parg->printComponentTree() ;
2317 } else {
2318 parg->Print() ;
2319 }
2320 }
2321 std::cout << std::endl ;
2322 }
2323
2324 if (!_dataList.empty()) {
2325 std::cout << "datasets" << std::endl ;
2326 std::cout << "--------" << std::endl ;
2327 for(auto * data2 : static_range_cast<RooAbsData*>(_dataList)) {
2328 std::cout << data2->ClassName() << "::" << data2->GetName() << *data2->get() << std::endl;
2329 }
2330 std::cout << std::endl ;
2331 }
2332
2333 if (!_embeddedDataList.empty()) {
2334 std::cout << "embedded datasets (in pdfs and functions)" << std::endl ;
2335 std::cout << "-----------------------------------------" << std::endl ;
2336 for(auto * data2 : static_range_cast<RooAbsData*>(_embeddedDataList)) {
2337 std::cout << data2->ClassName() << "::" << data2->GetName() << *data2->get() << std::endl ;
2338 }
2339 std::cout << std::endl ;
2340 }
2341
2342 if (!_snapshots.empty()) {
2343 std::cout << "parameter snapshots" << std::endl ;
2344 std::cout << "-------------------" << std::endl ;
2345 for(auto * snap : static_range_cast<RooArgSet*>(_snapshots)) {
2346 std::cout << snap->GetName() << " = (" ;
2347 bool first(true) ;
2348 for(RooAbsArg* a : *snap) {
2349 if (first) { first=false ; } else { std::cout << "," ; }
2350 std::cout << a->GetName() << "=" ;
2351 a->printValue(std::cout) ;
2352 if (a->isConstant()) {
2353 std::cout << "[C]" ;
2354 }
2355 }
2356 std::cout << ")" << std::endl ;
2357 }
2358 std::cout << std::endl ;
2359 }
2360
2361
2362 if (!_namedSets.empty()) {
2363 std::cout << "named sets" << std::endl ;
2364 std::cout << "----------" << std::endl ;
2365 for (map<string,RooArgSet>::const_iterator it = _namedSets.begin() ; it != _namedSets.end() ; ++it) {
2366 if (verbose || !isCacheSet(it->first)) {
2367 std::cout << it->first << ":" << it->second << std::endl;
2368 }
2369 }
2370
2371 std::cout << std::endl ;
2372 }
2373
2374
2375 if (!_genObjects.empty()) {
2376 std::cout << "generic objects" << std::endl ;
2377 std::cout << "---------------" << std::endl ;
2378 for(TObject* gobj : _genObjects) {
2379 if (gobj->IsA()==RooTObjWrap::Class()) {
2380 std::cout << (static_cast<RooTObjWrap*>(gobj))->obj()->ClassName() << "::" << gobj->GetName() << std::endl ;
2381 } else {
2382 std::cout << gobj->ClassName() << "::" << gobj->GetName() << std::endl ;
2383 }
2384 }
2385 std::cout << std::endl ;
2386
2387 }
2388
2389 if (!_studyMods.empty()) {
2390 std::cout << "study modules" << std::endl ;
2391 std::cout << "-------------" << std::endl ;
2392 for(TObject* smobj : _studyMods) {
2393 std::cout << smobj->ClassName() << "::" << smobj->GetName() << std::endl ;
2394 }
2395 std::cout << std::endl ;
2396
2397 }
2398
2399 if (!_classes.listOfClassNames().empty()) {
2400 std::cout << "embedded class code" << std::endl ;
2401 std::cout << "-------------------" << std::endl ;
2402 std::cout << _classes.listOfClassNames() << std::endl ;
2403 std::cout << std::endl ;
2404 }
2405
2406 if (!_eocache.empty()) {
2407 std::cout << "embedded precalculated expensive components" << std::endl ;
2408 std::cout << "-------------------------------------------" << std::endl ;
2409 _eocache.print() ;
2410 }
2411
2412 RooMsgService::instance().setGlobalKillBelow(oldLevel) ;
2413
2414 return ;
2415}
2416
2417
2418////////////////////////////////////////////////////////////////////////////////
2419/// Custom streamer for the workspace. Stream contents of workspace
2420/// and code repository. When reading, read code repository first
2421/// and compile missing classes before proceeding with streaming
2422/// of workspace contents to avoid errors.
2423
2425{
2426 typedef ::RooWorkspace::CodeRepo thisClass;
2427
2428 // Stream an object of class RooWorkspace::CodeRepo.
2429 if (R__b.IsReading()) {
2430
2431 UInt_t R__s;
2432 UInt_t R__c;
2433 Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
2434
2435 // Stream contents of ClassFiles map
2436 Int_t count(0);
2437 R__b >> count;
2438 while (count--) {
2439 TString name;
2440 name.Streamer(R__b);
2441 _fmap[name]._hext.Streamer(R__b);
2442 _fmap[name]._hfile.Streamer(R__b);
2443 _fmap[name]._cxxfile.Streamer(R__b);
2444 }
2445
2446 // Stream contents of ClassRelInfo map
2447 count = 0;
2448 R__b >> count;
2449 while (count--) {
2450 TString name;
2451 name.Streamer(R__b);
2452 _c2fmap[name]._baseName.Streamer(R__b);
2453 _c2fmap[name]._fileBase.Streamer(R__b);
2454 }
2455
2456 if (R__v == 2) {
2457
2458 count = 0;
2459 R__b >> count;
2460 while (count--) {
2461 TString name;
2462 name.Streamer(R__b);
2463 _ehmap[name]._hname.Streamer(R__b);
2464 _ehmap[name]._hfile.Streamer(R__b);
2465 }
2466 }
2467
2468 R__b.CheckByteCount(R__s, R__c, thisClass::IsA());
2469
2470 // Instantiate any classes that are not defined in current session
2471 _compiledOK = !compileClasses();
2472
2473 } else {
2474
2475 UInt_t R__c;
2476 R__c = R__b.WriteVersion(thisClass::IsA(), true);
2477
2478 // Stream contents of ClassFiles map
2479 UInt_t count = _fmap.size();
2480 R__b << count;
2481 map<TString, ClassFiles>::iterator iter = _fmap.begin();
2482 while (iter != _fmap.end()) {
2483 TString key_copy(iter->first);
2484 key_copy.Streamer(R__b);
2485 iter->second._hext.Streamer(R__b);
2486 iter->second._hfile.Streamer(R__b);
2487 iter->second._cxxfile.Streamer(R__b);
2488
2489 ++iter;
2490 }
2491
2492 // Stream contents of ClassRelInfo map
2493 count = _c2fmap.size();
2494 R__b << count;
2495 map<TString, ClassRelInfo>::iterator iter2 = _c2fmap.begin();
2496 while (iter2 != _c2fmap.end()) {
2497 TString key_copy(iter2->first);
2498 key_copy.Streamer(R__b);
2499 iter2->second._baseName.Streamer(R__b);
2500 iter2->second._fileBase.Streamer(R__b);
2501 ++iter2;
2502 }
2503
2504 // Stream contents of ExtraHeader map
2505 count = _ehmap.size();
2506 R__b << count;
2507 map<TString, ExtraHeader>::iterator iter3 = _ehmap.begin();
2508 while (iter3 != _ehmap.end()) {
2509 TString key_copy(iter3->first);
2510 key_copy.Streamer(R__b);
2511 iter3->second._hname.Streamer(R__b);
2512 iter3->second._hfile.Streamer(R__b);
2513 ++iter3;
2514 }
2515
2516 R__b.SetByteCount(R__c, true);
2517 }
2518}
2519
2520
2521////////////////////////////////////////////////////////////////////////////////
2522/// Stream an object of class RooWorkspace. This is a standard ROOT streamer for the
2523/// I/O part. This custom function exists to detach all external client links
2524/// from the payload prior to writing the payload so that these client links
2525/// are not persisted. (Client links occur if external function objects use
2526/// objects contained in the workspace as input)
2527/// After the actual writing, these client links are restored.
2528
2530{
2531 if (R__b.IsReading()) {
2532
2533 R__b.ReadClassBuffer(RooWorkspace::Class(), this);
2534
2535 // Perform any pass-2 schema evolution here
2536 for (RooAbsArg *node : _allOwnedNodes) {
2537 node->ioStreamerPass2();
2538 }
2540
2541 // Make expensive object cache of all objects point to intermal copy.
2542 // Somehow this doesn't work OK automatically
2543 for (RooAbsArg *node : _allOwnedNodes) {
2544 node->setExpensiveObjectCache(_eocache);
2545 node->setWorkspace(*this);
2546 }
2547
2548 for(TObject * gobj : allGenericObjects()) {
2549 if (auto handle = dynamic_cast<RooWorkspaceHandle*>(gobj)) {
2550 handle->ReplaceWS(this);
2551 }
2552 }
2553
2554 } else {
2555
2556 // Make lists of external clients of WS objects, and remove those links temporarily
2557
2558 map<RooAbsArg *, vector<RooAbsArg *>> extClients;
2559 map<RooAbsArg *, vector<RooAbsArg *>> extValueClients;
2560 map<RooAbsArg *, vector<RooAbsArg *>> extShapeClients;
2561
2562 for (RooAbsArg *tmparg : _allOwnedNodes) {
2563
2564 // Loop over client list of this arg
2565 std::vector<RooAbsArg *> clientsTmp{tmparg->_clientList.begin(), tmparg->_clientList.end()};
2566 for (auto client : clientsTmp) {
2567 if (!_allOwnedNodes.containsInstance(*client)) {
2568
2569 const auto refCount = tmparg->_clientList.refCount(client);
2570 auto &bufferVec = extClients[tmparg];
2571
2572 bufferVec.insert(bufferVec.end(), refCount, client);
2573 tmparg->_clientList.Remove(client, true);
2574 }
2575 }
2576
2577 // Loop over value client list of this arg
2578 clientsTmp.assign(tmparg->_clientListValue.begin(), tmparg->_clientListValue.end());
2579 for (auto vclient : clientsTmp) {
2580 if (!_allOwnedNodes.containsInstance(*vclient)) {
2581 cxcoutD(ObjectHandling) << "RooWorkspace::Streamer(" << GetName() << ") element " << tmparg->GetName()
2582 << " has external value client link to " << vclient << " (" << vclient->GetName()
2583 << ") with ref count " << tmparg->_clientListValue.refCount(vclient) << std::endl;
2584
2585 const auto refCount = tmparg->_clientListValue.refCount(vclient);
2586 auto &bufferVec = extValueClients[tmparg];
2587
2588 bufferVec.insert(bufferVec.end(), refCount, vclient);
2589 tmparg->_clientListValue.Remove(vclient, true);
2590 }
2591 }
2592
2593 // Loop over shape client list of this arg
2594 clientsTmp.assign(tmparg->_clientListShape.begin(), tmparg->_clientListShape.end());
2595 for (auto sclient : clientsTmp) {
2596 if (!_allOwnedNodes.containsInstance(*sclient)) {
2597 cxcoutD(ObjectHandling) << "RooWorkspace::Streamer(" << GetName() << ") element " << tmparg->GetName()
2598 << " has external shape client link to " << sclient << " (" << sclient->GetName()
2599 << ") with ref count " << tmparg->_clientListShape.refCount(sclient) << std::endl;
2600
2601 const auto refCount = tmparg->_clientListShape.refCount(sclient);
2602 auto &bufferVec = extShapeClients[tmparg];
2603
2604 bufferVec.insert(bufferVec.end(), refCount, sclient);
2605 tmparg->_clientListShape.Remove(sclient, true);
2606 }
2607 }
2608 }
2609
2610 R__b.WriteClassBuffer(RooWorkspace::Class(), this);
2611
2612 // Reinstate clients here
2613
2614 for (auto &iterx : extClients) {
2615 for (auto client : iterx.second) {
2616 iterx.first->_clientList.Add(client);
2617 }
2618 }
2619
2620 for (auto &iterx : extValueClients) {
2621 for (auto client : iterx.second) {
2622 iterx.first->_clientListValue.Add(client);
2623 }
2624 }
2625
2626 for (auto &iterx : extShapeClients) {
2627 for (auto client : iterx.second) {
2628 iterx.first->_clientListShape.Add(client);
2629 }
2630 }
2631 }
2632}
2633
2634
2635
2636
2637////////////////////////////////////////////////////////////////////////////////
2638/// Return STL string with last of class names contained in the code repository
2639
2641{
2642 string ret ;
2643 map<TString,ClassRelInfo>::const_iterator iter = _c2fmap.begin() ;
2644 while(iter!=_c2fmap.end()) {
2645 if (!ret.empty()) {
2646 ret += ", " ;
2647 }
2648 ret += iter->first ;
2649 ++iter ;
2650 }
2651
2652 return ret ;
2653}
2654
2655namespace {
2656UInt_t crc32(const char* data, ULong_t sz, UInt_t crc)
2657{
2658 // update CRC32 with new data
2659
2660 // use precomputed table, rather than computing it on the fly
2661 static const UInt_t crctab[256] = { 0x00000000,
2662 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
2663 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
2664 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
2665 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
2666 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
2667 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
2668 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
2669 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
2670 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
2671 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
2672 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
2673 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
2674 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
2675 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
2676 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
2677 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
2678 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
2679 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
2680 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
2681 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
2682 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
2683 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
2684 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
2685 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
2686 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
2687 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
2688 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
2689 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
2690 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
2691 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
2692 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
2693 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
2694 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
2695 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
2696 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
2697 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
2698 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
2699 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
2700 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
2701 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
2702 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
2703 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
2704 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
2705 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
2706 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
2707 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
2708 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
2709 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
2710 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
2711 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
2712 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
2713 };
2714
2715 crc = ~crc;
2716 while (sz--) crc = (crc << 8) ^ UInt_t(*data++) ^ crctab[crc >> 24];
2717
2718 return ~crc;
2719}
2720
2721UInt_t crc32(const char* data)
2722{
2723 // Calculate crc32 checksum on given string
2724 unsigned long sz = strlen(data);
2725 switch (strlen(data)) {
2726 case 0:
2727 return 0;
2728 case 1:
2729 return data[0];
2730 case 2:
2731 return (data[0] << 8) | data[1];
2732 case 3:
2733 return (data[0] << 16) | (data[1] << 8) | data[2];
2734 case 4:
2735 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
2736 default:
2737 return crc32(data + 4, sz - 4, (data[0] << 24) | (data[1] << 16) |
2738 (data[2] << 8) | data[3]);
2739 }
2740}
2741
2742}
2743
2744////////////////////////////////////////////////////////////////////////////////
2745/// For all classes in the workspace for which no class definition is
2746/// found in the ROOT class table extract source code stored in code
2747/// repository into temporary directory set by
2748/// setClassFileExportDir(), compile classes and link them with
2749/// current ROOT session. If a compilation error occurs print
2750/// instructions for user how to fix errors and recover workspace and
2751/// abort import procedure.
2752/// \return true on success, false on failure
2753
2755{
2756 bool haveDir=false ;
2757
2758 // Retrieve name of directory in which to export code files
2759 string dirName = Form(_classFileExportDir.c_str(),_wspace->uuid().AsString(),_wspace->GetName()) ;
2760
2761 bool writeExtraHeaders(false) ;
2762
2763 // Process all class entries in repository
2764 map<TString,ClassRelInfo>::iterator iter = _c2fmap.begin() ;
2765 while(iter!=_c2fmap.end()) {
2766
2767 oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() now processing class " << iter->first.Data() << std::endl ;
2768
2769 // If class is already known, don't load
2770 if (gClassTable->GetDict(iter->first.Data())) {
2771 oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() Embedded class "
2772 << iter->first << " already in ROOT class table, skipping" << std::endl ;
2773 ++iter ;
2774 continue ;
2775 }
2776
2777 // Check that export directory exists
2778 if (!haveDir) {
2779
2780 // If not, make local directory to extract files
2781 if (!gSystem->AccessPathName(dirName.c_str())) {
2782 oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() reusing code export directory " << dirName.c_str()
2783 << " to extract coded embedded in workspace" << std::endl ;
2784 } else {
2785 if (gSystem->MakeDirectory(dirName.c_str())==0) {
2786 oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() creating code export directory " << dirName.c_str()
2787 << " to extract coded embedded in workspace" << std::endl ;
2788 } else {
2789 oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() ERROR creating code export directory " << dirName.c_str()
2790 << " to extract coded embedded in workspace" << std::endl ;
2791 return false ;
2792 }
2793 }
2794 haveDir=true ;
2795
2796 }
2797
2798 // First write any extra header files
2799 if (!writeExtraHeaders) {
2800 writeExtraHeaders = true ;
2801
2802 map<TString,ExtraHeader>::iterator extraIter = _ehmap.begin() ;
2803 while(extraIter!=_ehmap.end()) {
2804
2805 // Check if identical declaration file (header) is already written
2806 bool needEHWrite=true ;
2807 string fdname = Form("%s/%s",dirName.c_str(),extraIter->second._hname.Data()) ;
2808 ifstream ifdecl(fdname.c_str()) ;
2809 if (ifdecl) {
2810 TString contents ;
2811 char buf[64000];
2812 while (ifdecl.getline(buf, 64000)) {
2813 contents += buf;
2814 contents += "\n";
2815 }
2816 UInt_t crcFile = crc32(contents.Data());
2817 UInt_t crcWS = crc32(extraIter->second._hfile.Data());
2818 needEHWrite = (crcFile != crcWS);
2819 }
2820
2821 // Write declaration file if required
2822 if (needEHWrite) {
2823 oocoutI(_wspace, ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() Extracting extra header file "
2824 << fdname << std::endl;
2825
2826 // Extra headers may contain non-existing path - create first to be sure
2827 gSystem->MakeDirectory(gSystem->GetDirName(fdname.c_str()));
2828
2829 ofstream fdecl(fdname.c_str());
2830 if (!fdecl) {
2831 oocoutE(_wspace, ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() ERROR opening file " << fdname
2832 << " for writing" << std::endl;
2833 return false;
2834 }
2835 fdecl << extraIter->second._hfile.Data();
2836 fdecl.close();
2837 }
2838 ++extraIter;
2839 }
2840 }
2841
2842
2843 // Navigate from class to file
2844 ClassFiles& cfinfo = _fmap[iter->second._fileBase] ;
2845
2846 oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() now processing file with base " << iter->second._fileBase << std::endl ;
2847
2848 // If file is already processed, skip to next class
2849 if (cfinfo._extracted) {
2850 oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() file with base name " << iter->second._fileBase
2851 << " has already been extracted, skipping to next class" << std::endl ;
2852 continue ;
2853 }
2854
2855 // Check if identical declaration file (header) is already written
2856 bool needDeclWrite=true ;
2857 string fdname = Form("%s/%s.%s",dirName.c_str(),iter->second._fileBase.Data(),cfinfo._hext.Data()) ;
2858 ifstream ifdecl(fdname.c_str()) ;
2859 if (ifdecl) {
2860 TString contents ;
2861 char buf[64000];
2862 while (ifdecl.getline(buf, 64000)) {
2863 contents += buf;
2864 contents += "\n";
2865 }
2866 UInt_t crcFile = crc32(contents.Data()) ;
2867 UInt_t crcWS = crc32(cfinfo._hfile.Data()) ;
2868 needDeclWrite = (crcFile!=crcWS) ;
2869 }
2870
2871 // Write declaration file if required
2872 if (needDeclWrite) {
2873 oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() Extracting declaration code of class " << iter->first << ", file " << fdname << std::endl ;
2874 ofstream fdecl(fdname.c_str()) ;
2875 if (!fdecl) {
2876 oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() ERROR opening file "
2877 << fdname << " for writing" << std::endl ;
2878 return false ;
2879 }
2880 fdecl << cfinfo._hfile ;
2881 fdecl.close() ;
2882 }
2883
2884 // Check if identical implementation file is already written
2885 bool needImplWrite=true ;
2886 string finame = Form("%s/%s.cxx",dirName.c_str(),iter->second._fileBase.Data()) ;
2887 ifstream ifimpl(finame.c_str()) ;
2888 if (ifimpl) {
2889 TString contents ;
2890 char buf[64000];
2891 while (ifimpl.getline(buf, 64000)) {
2892 contents += buf;
2893 contents += "\n";
2894 }
2895 UInt_t crcFile = crc32(contents.Data()) ;
2896 UInt_t crcWS = crc32(cfinfo._cxxfile.Data()) ;
2897 needImplWrite = (crcFile!=crcWS) ;
2898 }
2899
2900 // Write implementation file if required
2901 if (needImplWrite) {
2902 oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() Extracting implementation code of class " << iter->first << ", file " << finame << std::endl ;
2903 ofstream fimpl(finame.c_str()) ;
2904 if (!fimpl) {
2905 oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() ERROR opening file"
2906 << finame << " for writing" << std::endl ;
2907 return false ;
2908 }
2909 fimpl << cfinfo._cxxfile ;
2910 fimpl.close() ;
2911 }
2912
2913 // Mark this file as extracted
2914 cfinfo._extracted = true ;
2915 oocxcoutD(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() marking code unit " << iter->second._fileBase << " as extracted" << std::endl ;
2916
2917 // Compile class
2918 oocoutI(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() Compiling code unit " << iter->second._fileBase.Data() << " to define class " << iter->first << std::endl ;
2919 bool ok = gSystem->CompileMacro(finame.c_str(),"k") ;
2920
2921 if (!ok) {
2922 oocoutE(_wspace,ObjectHandling) << "RooWorkspace::CodeRepo::compileClasses() ERROR compiling class " << iter->first.Data() << ", to fix this you can do the following: " << std::endl
2923 << " 1) Fix extracted source code files in directory " << dirName.c_str() << "/" << std::endl
2924 << " 2) In clean ROOT session compiled fixed classes by hand using '.x " << dirName.c_str() << "/ClassName.cxx+'" << std::endl
2925 << " 3) Reopen file with RooWorkspace with broken source code in UPDATE mode. Access RooWorkspace to force loading of class" << std::endl
2926 << " Broken instances in workspace will _not_ be compiled, instead precompiled fixed instances will be used." << std::endl
2927 << " 4) Reimport fixed code in workspace using 'RooWorkspace::importClassCode(\"*\",true)' method, Write() updated workspace to file and close file" << std::endl
2928 << " 5) Reopen file in clean ROOT session to confirm that problems are fixed" << std::endl ;
2929 return false ;
2930 }
2931
2932 ++iter ;
2933 }
2934
2935 return true ;
2936}
2937
2938
2939
2940////////////////////////////////////////////////////////////////////////////////
2941/// Internal access to TDirectory append method
2942
2947
2948
2949////////////////////////////////////////////////////////////////////////////////
2950/// Overload TDirectory interface method to prohibit insertion of objects in read-only directory workspace representation
2951
2953{
2954 if (dynamic_cast<RooAbsArg*>(obj) || dynamic_cast<RooAbsData*>(obj)) {
2955 coutE(ObjectHandling) << "RooWorkspace::WSDir::Add(" << GetName() << ") ERROR: Directory is read-only representation of a RooWorkspace, use RooWorkspace::import() to add objects" << std::endl ;
2956 } else {
2957 InternalAppend(obj) ;
2958 }
2959}
2960
2961
2962////////////////////////////////////////////////////////////////////////////////
2963/// Overload TDirectory interface method to prohibit insertion of objects in read-only directory workspace representation
2964
2966{
2967 if (dynamic_cast<RooAbsArg*>(obj) || dynamic_cast<RooAbsData*>(obj)) {
2968 coutE(ObjectHandling) << "RooWorkspace::WSDir::Add(" << GetName() << ") ERROR: Directory is read-only representation of a RooWorkspace, use RooWorkspace::import() to add objects" << std::endl ;
2969 } else {
2970 InternalAppend(obj) ;
2971 }
2972}
2973
2974
2975////////////////////////////////////////////////////////////////////////////////
2976/// If one of the TObject we have a referenced to is deleted, remove the
2977/// reference.
2978
2980{
2981 _dataList.RecursiveRemove(removedObj);
2982 if (removedObj == _dir) _dir = nullptr;
2983
2984 _allOwnedNodes.RecursiveRemove(removedObj); // RooArgSet
2985
2986 _dataList.RecursiveRemove(removedObj);
2988 _views.RecursiveRemove(removedObj);
2989 _snapshots.RecursiveRemove(removedObj);
2990 _genObjects.RecursiveRemove(removedObj);
2991 _studyMods.RecursiveRemove(removedObj);
2992
2993 std::vector<std::string> invalidSets;
2994
2995 for(auto &c : _namedSets) {
2996 auto const& setName = c.first;
2997 auto& set = c.second;
2998 std::size_t oldSize = set.size();
2999 set.RecursiveRemove(removedObj);
3000 // If the set is used internally by RooFit to cache parameters or
3001 // constraints, it is invalidated by object removal. We will keep track
3002 // of its name to remove the cache set later.
3003 if(set.size() < oldSize && isCacheSet(setName)) {
3004 invalidSets.emplace_back(setName);
3005 }
3006 }
3007
3008 // Remove the sets that got invalidated by the object removal
3009 for(std::string const& setName : invalidSets) {
3010 removeSet(setName.c_str());
3011 }
3012
3013 _eocache.RecursiveRemove(removedObj); // RooExpensiveObjectCache
3014}
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define coutI(a)
#define cxcoutD(a)
#define oocoutW(o, a)
#define oocxcoutD(o, a)
#define coutW(a)
#define oocoutE(o, a)
#define oocoutI(o, a)
#define coutE(a)
#define ooccoutW(o, a)
short Version_t
Class version identifier (short)
Definition RtypesCore.h:80
unsigned long ULong_t
Unsigned long integer 4 bytes (unsigned long). Size depends on architecture.
Definition RtypesCore.h:70
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:61
const char Option_t
Option string (const char)
Definition RtypesCore.h:81
R__EXTERN TClassTable * gClassTable
@ kIsAbstract
Definition TDictionary.h:71
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
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 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 bytes
char name[80]
Definition TGX11.cxx:142
#define gInterpreter
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2571
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
void setStringAttribute(const Text_t *key, const Text_t *value)
Associate string 'value' to this object under key 'key'.
static void ioStreamerPass2Finalize()
Method called by workspace container to finalize schema evolution issues that cannot be handled in a ...
const Text_t * getStringAttribute(const Text_t *key) const
Get string attribute mapped under key 'key'.
const RefCountList_t & servers() const
List of all servers of this object.
Definition RooAbsArg.h:146
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:89
A space to attach TBranches.
static TClass * Class()
virtual void removeAll()
Remove all arguments from our set, deleting them if we own them.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
void RecursiveRemove(TObject *obj) override
If one of the TObject we have a referenced to is deleted, remove the reference.
void assign(const RooAbsCollection &other) const
Sets the value, cache and constant attribute of any argument in our set that also appears in the othe...
Storage_t::size_type size() const
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
void useHashMapForFind(bool flag) const
void setName(const char *name)
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:55
virtual const RooArgSet * get() const
Definition RooAbsData.h:99
virtual bool changeObservableName(const char *from, const char *to)
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
static TClass * Class()
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
static TClass * Class()
Abstract base class for RooStudyManager modules.
Definition RooAbsStudy.h:33
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
RooArgSet * snapshot(bool deepCopy=true) const
Use RooAbsCollection::snapshot(), but return as RooArgSet.
Definition RooArgSet.h:159
bool containsInstance(const RooAbsArg &var) const override
Check if this exact instance is in this collection.
Definition RooArgSet.h:132
RooArgSet * selectCommon(const RooAbsCollection &refColl) const
Use RooAbsCollection::selecCommon(), but return as RooArgSet.
Definition RooArgSet.h:154
Object to represent discrete states.
Definition RooCategory.h:28
static TClass * Class()
Named container for two doubles, two integers two object points and three string pointers that can be...
Definition RooCmdArg.h:26
Configurable parser for RooCmdArg named arguments.
void defineMutex(const char *head, Args_t &&... tail)
Define arguments where any pair is mutually exclusive.
bool process(const RooCmdArg &arg)
Process given RooCmdArg.
bool ok(bool verbose) const
Return true of parsing was successful.
const char * getString(const char *name, const char *defaultValue="", bool convEmptyToNull=false) const
Return string property registered with name 'name'.
bool defineString(const char *name, const char *argName, int stringNum, const char *defValue="", bool appendMode=false)
Define double property name 'name' mapped to double in slot 'stringNum' in RooCmdArg with name argNam...
bool defineInt(const char *name, const char *argName, int intNum, int defValue=0)
Define integer property name 'name' mapped to integer in slot 'intNum' in RooCmdArg with name argName...
int getInt(const char *name, int defaultValue=0) const
Return integer property registered with name 'name'.
static TClass * Class()
Singleton class that serves as repository for objects that are expensive to calculate.
static RooExpensiveObjectCache & instance()
Return reference to singleton instance.
void importCacheObjects(RooExpensiveObjectCache &other, const char *ownerName, bool verbose=false)
Implementation detail of the RooWorkspace.
RooAbsArg * process(const char *expr)
Create a RooFit object from the given expression.
Collection class for internal use, storing a collection of RooAbsArg pointers in a doubly linked list...
bool empty() const
void RecursiveRemove(TObject *obj) override
If one of the TObject we have a referenced to is deleted, remove the reference.
bool Replace(const TObject *oldArg, const TObject *newArg)
Replace object 'oldArg' in collection with new object 'newArg'.
void Delete(Option_t *o=nullptr) override
Remove all elements in collection and delete all elements NB: Collection does not own elements,...
TObject * find(const char *name) const
Return pointer to object with given name in collection.
virtual void Add(TObject *arg)
void setHashTableSize(Int_t size)
Change the threshold for hash-table use to given size.
TObject * FindObject(const char *name) const override
Return pointer to object with given name.
virtual bool Remove(TObject *arg)
Remove object from collection.
static RooMsgService & instance()
Return reference to singleton instance.
static bool setAddDirectoryStatus(bool flag)
Configure whether new instances of RooPlot will add themselves to gDirectory.
Definition RooPlot.cxx:78
Variable that can be changed from the outside.
Definition RooRealVar.h:37
static TClass * Class()
RooResolutionModel is the base class for PDFs that represent a resolution model that can be convolute...
static TClass * Class()
The RooStringView is a wrapper around a C-style string that can also be constructed from a std::strin...
An interface to set and retrieve a workspace.
std::map< TString, ExtraHeader > _ehmap
RooWorkspace * _wspace
void Streamer(TBuffer &) override
Custom streamer for the workspace.
std::string listOfClassNames() const
Return STL string with last of class names contained in the code repository.
bool autoImportClass(TClass *tc, bool doReplace=false)
Import code of class 'tc' into the repository.
bool compileClasses()
For all classes in the workspace for which no class definition is found in the ROOT class table extra...
std::map< TString, ClassRelInfo > _c2fmap
std::map< TString, ClassFiles > _fmap
void InternalAppend(TObject *obj)
Internal access to TDirectory append method.
void Add(TObject *, bool) override
Overload TDirectory interface method to prohibit insertion of objects in read-only directory workspac...
TClass * IsA() const override
void Append(TObject *, bool) override
Overload TDirectory interface method to prohibit insertion of objects in read-only directory workspac...
Persistable container for RooFit projects.
RooExpensiveObjectCache _eocache
Cache for expensive objects.
TObject * obj(RooStringView name) const
Return any type of object (RooAbsArg, RooAbsData or generic object) with given name)
RooLinkedList _genObjects
List of generic objects.
static bool _autoClass
static std::list< std::string > _classDeclDirList
const RooArgSet * getSnapshot(const char *name) const
Return the RooArgSet containing a snapshot of variables contained in the workspace.
static void addClassDeclImportDir(const char *dir)
Add dir to search path for class declaration (header) files.
void Print(Option_t *opts=nullptr) const override
Print contents of the workspace.
RooLinkedList _dataList
List of owned datasets.
RooAbsCategory * catfunc(RooStringView name) const
Retrieve discrete function (RooAbsCategory) with given name. A null pointer is returned if not found.
WSDir * _dir
! Transient ROOT directory representation of workspace
static void addClassImplImportDir(const char *dir)
Add dir to search path for class implementation (.cxx) files.
RooAbsPdf * pdf(RooStringView name) const
Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found.
std::map< std::string, RooArgSet > _namedSets
Map of named RooArgSets.
RooAbsData * embeddedData(RooStringView name) const
Retrieve dataset (binned or unbinned) with given name. A null pointer is returned if not found.
RooCategory * cat(RooStringView name) const
Retrieve discrete variable (RooCategory) with given name. A null pointer is returned if not found.
void clearStudies()
Remove all RooStudyManager modules.
bool renameSet(const char *name, const char *newName)
Rename set to a new name.
std::unique_ptr< RooFactoryWSTool > _factory
! Factory tool associated with workspace
RooArgSet allVars() const
Return set with all variable objects.
RooArgSet argSet(RooStringView nameList) const
Return set of RooAbsArgs matching to given list of names.
bool writeToFile(const char *fileName, bool recreate=true)
Save this current workspace into given file.
const RooArgSet * set(RooStringView name)
Return pointer to previously defined named set with given nmame If no such set is found a null pointe...
bool cd(const char *path=nullptr)
RooArgSet allCats() const
Return set with all category objects.
void RecursiveRemove(TObject *obj) override
If one of the TObject we have a referenced to is deleted, remove the reference.
RooAbsArg * fundArg(RooStringView name) const
Return fundamental (i.e.
RooLinkedList _views
List of model views.
bool commitTransaction()
Commit an ongoing import transaction.
~RooWorkspace() override
Workspace destructor.
bool cancelTransaction()
Cancel an ongoing import transaction.
bool startTransaction()
Open an import transaction operations.
TObject * Clone(const char *newname="") const override
TObject::Clone() needs to be overridden.
RooArgSet allResolutionModels() const
Return set with all resolution model objects.
RooLinkedList _snapshots
List of parameter snapshots.
bool saveSnapshot(RooStringView, const char *paramNames)
Save snapshot of values and attributes (including "Constant") of given parameters.
RooArgSet allPdfs() const
Return set with all probability density function objects.
void Streamer(TBuffer &) override
Stream an object of class RooWorkspace.
TObject * genobj(RooStringView name) const
Return generic object with given name.
std::list< RooAbsData * > allData() const
Return list of all dataset in the workspace.
RooLinkedList _studyMods
List if StudyManager modules.
std::list< TObject * > allGenericObjects() const
Return list of all generic objects in the workspace.
static void setClassFileExportDir(const char *dir=nullptr)
Specify the name of the directory in which embedded source code is unpacked and compiled.
bool importClassCode(const char *pat="*", bool doReplace=false)
Import code of all classes in the workspace that have a class name that matches pattern 'pat' and whi...
bool makeDir()
Create transient TDirectory representation of this workspace.
RooArgSet allCatFunctions() const
Return set with all category function objects.
static std::string _classFileExportDir
static std::list< std::string > _classImplDirList
RooAbsReal * function(RooStringView name) const
Retrieve function (RooAbsReal) with given name. Note that all RooAbsPdfs are also RooAbsReals....
RooAbsArg * arg(RooStringView name) const
Return RooAbsArg with given name. A null pointer is returned if none is found.
RooWorkspace()
Default constructor.
bool removeSet(const char *name)
Remove a named set from the workspace.
static TClass * Class()
CodeRepo _classes
RooArgSet allFunctions() const
Return set with all function objects.
RooFactoryWSTool & factory()
Return instance to factory tool.
bool extendSet(const char *name, const char *newContents)
Define a named set in the workspace through a comma separated list of names of objects already in the...
RooExpensiveObjectCache & expensiveObjectCache()
RooArgSet _sandboxNodes
! Sandbox for incoming objects in a transaction
bool defineSetInternal(const char *name, const RooArgSet &aset)
bool _openTrans
! Is there a transaction open?
RooRealVar * var(RooStringView name) const
Retrieve real-valued variable (RooRealVar) with given name. A null pointer is returned if not found.
bool addStudy(RooAbsStudy &study)
Insert RooStudyManager module.
static void autoImportClassCode(bool flag)
If flag is true, source code of classes not the ROOT distribution is automatically imported if on obj...
RooLinkedList _embeddedDataList
List of owned datasets that are embedded in pdfs.
RooArgSet _allOwnedNodes
List of owned pdfs and components.
RooAbsData * data(RooStringView name) const
Retrieve dataset (binned or unbinned) with given name. A null pointer is returned if not found.
std::list< RooAbsData * > allEmbeddedData() const
Return list of all dataset in the workspace.
bool loadSnapshot(const char *name)
Load the values and attributes of the parameters in the snapshot saved with the given name.
bool defineSet(const char *name, const RooArgSet &aset, bool importMissing=false)
Define a named RooArgSet with given constituents.
bool import(const RooAbsArg &arg, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={})
Import a RooAbsArg object, e.g.
Buffer base class used for serializing objects.
Definition TBuffer.h:43
static DictFuncPtr_t GetDict(const char *cname)
Given the class name returns the Dictionary() function of a class (uses hash of name).
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
const char * GetName() const override
Return name of this collection.
Bool_t cd() override
Change current directory to "this" directory.
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
virtual void Append(TObject *obj, Bool_t replace=kFALSE)
Append object to this directory.
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:3802
A doubly linked list.
Definition TList.h:38
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:149
Mother of all ROOT objects.
Definition TObject.h:42
virtual void RecursiveRemove(TObject *obj)
Recursively remove this object from a list.
Definition TObject.cxx:683
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition TObject.cxx:987
Regular expression class.
Definition TRegexp.h:31
Basic string class.
Definition TString.h:137
const char * Data() const
Definition TString.h:385
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:661
virtual const char * Getenv(const char *env)
Get environment variable.
Definition TSystem.cxx:1687
virtual int MakeDirectory(const char *name)
Make a directory.
Definition TSystem.cxx:841
virtual const char * PrependPathName(const char *dir, TString &name)
Concatenate a directory and a file name.
Definition TSystem.cxx:1097
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition TSystem.cxx:1318
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:949
virtual int CompileMacro(const char *filename, Option_t *opt="", const char *library_name="", const char *build_dir="", UInt_t dirmode=0)
This method compiles and loads a shared library containing the code from the file "filename".
Definition TSystem.cxx:2901
virtual TString GetDirName(const char *pathname)
Return the directory name in pathname.
Definition TSystem.cxx:1047
const Int_t n
Definition legend1.C:16
void(* DirAutoAdd_t)(void *, TDirectory *)
Definition Rtypes.h:119
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
MsgLevel
Verbosity level for RooMsgService::StreamConfig in RooMsgService.