46 if type(file) == type(
"str"):
47 raise RuntimeError,
"You should pass as argument to parseCards a file object, stream or a list of lines, not a string"
53 binline = []; processline = []; sigline = []
56 if len(f) < 1:
continue
58 nbins = int(f[1])
if f[1] !=
"*" else -1
60 nprocesses = int(f[1])+1
if f[1] !=
"*" else -1
62 nuisances = int(f[1])
if f[1] !=
"*" else -1
64 if not options.bin:
raise RuntimeError,
"Can use shapes only with binary output mode"
65 if len(f) < 4:
raise RuntimeError,
"Malformed shapes line"
66 if not ret.shapeMap.has_key(f[2]): ret.shapeMap[f[2]] = {}
67 if ret.shapeMap[f[2]].has_key(f[1]):
raise RuntimeError,
"Duplicate definition for process '%s', channel '%s'" % (f[1], f[2])
68 ret.shapeMap[f[2]][f[1]] = f[3:]
69 if f[0] ==
"Observation" or f[0] ==
"observation":
70 ret.obs = [ float(x)
for x
in f[1:] ]
71 if nbins == -1: nbins = len(ret.obs)
72 if len(ret.obs) != nbins:
raise RuntimeError,
"Found %d observations but %d bins have been declared" % (len(ret.obs), nbins)
74 if len(binline) != len(ret.obs):
raise RuntimeError,
"Found %d bins (%s) but %d bins have been declared" % (len(ret.bins), ret.bins, nbins)
76 ret.obs =
dict([(b,ret.obs[i])
for i,b
in enumerate(ret.bins)])
81 if re.match(
"[0-9]+", b): b =
"bin"+b
86 if len(binline) != len(processline):
raise RuntimeError,
"'bin' line has a different length than 'process' line."
89 if re.match(
"-?[0-9]+", processline[0])
and not re.match(
"-?[0-9]+", sigline[0]):
90 (processline,sigline) = (sigline,processline)
91 if len(sigline) != len(processline):
raise RuntimeError,
"'bin' line has a different length than 'process' line."
92 hadBins = (len(ret.bins) > 0)
93 for i,b
in enumerate(binline):
95 s = (int(sigline[i]) <= 0)
96 ret.keyline.append((b, processline[i], s))
98 if b
not in ret.bins:
raise RuntimeError,
"Bin %s not among the declared bins %s" % (b, ret.bins)
100 if b
not in ret.bins: ret.bins.append(b)
101 if p
not in ret.processes: ret.processes.append(p)
102 if nprocesses == -1: nprocesses = len(ret.processes)
103 if nbins == -1: nbins = len(ret.bins)
104 if not options.noJMax:
105 if nprocesses != len(ret.processes):
raise RuntimeError,
"Found %d processes (%s), declared jmax = %d" % (len(ret.processes),ret.processes,nprocesses)
106 if nbins != len(ret.bins):
raise RuntimeError,
"Found %d bins (%s), declared imax = %d" % (len(ret.bins),ret.bins,nbins)
107 ret.exp =
dict([(b,{})
for b
in ret.bins])
108 ret.isSignal =
dict([(p,
None)
for p
in ret.processes])
109 if ret.obs != []
and type(ret.obs) == list:
110 ret.obs =
dict([(b,ret.obs[i])
for i,b
in enumerate(ret.bins)])
111 for (b,p,s)
in ret.keyline:
112 if ret.isSignal[p] ==
None:
114 elif ret.isSignal[p] != s:
115 raise RuntimeError,
"Process %s is declared as signal in some bin and as background in some other bin" % p
116 ret.signals = [p
for p,s
in ret.isSignal.items()
if s ==
True]
117 if len(ret.signals) == 0:
raise RuntimeError,
"You must have at least one signal process (id <= 0)"
119 if processline == []:
raise RuntimeError,
"Missing line with process names before rate line"
120 if sigline == []:
raise RuntimeError,
"Missing line with process id before rate line"
121 if len(f[1:]) != len(ret.keyline):
raise RuntimeError,
"Malformed rate line: length %d, while bins and process lines have length %d" % (len(f[1:]), len(ret.keyline))
122 for (b,p,s),r
in zip(ret.keyline,f[1:]):
123 ret.exp[b][p] = float(r)
127 if l.startswith(
"--"):
continue
128 l = re.sub(
"\\s*#.*",
"",l)
129 l = re.sub(
"(?<=\\s)-+(\\s|$)",
" 0\\1",l);
131 if len(f) <= 1:
continue
133 lsyst = f[0]; pdf = f[1]; args = []; numbers = f[2:];
134 if lsyst.endswith(
"[nofloat]"):
135 lsyst = lsyst.replace(
"[nofloat]",
"")
137 if options.nuisancesToExclude
and isVetoed(lsyst, options.nuisancesToExclude):
138 if options.verbose > 0: stderr.write(
"Excluding nuisance %s selected by a veto pattern among %s\n" % (lsyst, options.nuisancesToExclude))
139 if nuisances != -1: nuisances -= 1
141 if re.match(
"[0-9]+",lsyst): lsyst =
"theta"+lsyst
142 if pdf ==
"lnN" or pdf ==
"lnU" or pdf ==
"gmM" or pdf ==
"trG" or pdf.startswith(
"shape"):
145 args = [int(f[2])]; numbers = f[3:];
147 args = [float(f[2]), float(f[3])]; numbers = f[4:];
152 if len(args) <= 1:
raise RuntimeError,
"Uncertainties of type 'param' must have at least two arguments (mean and sigma)"
153 ret.systs.append([lsyst,nofloat,pdf,args,[]])
155 elif pdf ==
"flatParam":
156 ret.flatParamNuisances[lsyst] =
True
160 raise RuntimeError,
"Unsupported pdf %s" % pdf
161 if len(numbers) < len(ret.keyline):
raise RuntimeError,
"Malformed systematics line %s of length %d: while bins and process lines have length %d" % (lsyst, len(numbers), len(ret.keyline))
162 errline =
dict([(b,{})
for b
in ret.bins])
164 for (b,p,s),r
in zip(ret.keyline,numbers):
166 if (pdf
not in [
"lnN",
"lnU"])
and (
"?" not in pdf):
raise RuntimeError,
"Asymmetric errors are allowed only for Log-normals"
167 errline[b][p] = [ float(x)
for x
in r.split(
"/") ]
169 errline[b][p] = float(r)
171 if pdf ==
"gmN" and ret.exp[b][p] == 0
and float(r) != 0: ret.exp[b][p] = 1e-6
172 ret.systs.append([lsyst,nofloat,pdf,args,errline])
175 np_bin = sum([(ret.exp[b][p] != 0)
for (b1,p,s)
in ret.keyline
if b1 == b])
176 ns_bin = sum([(ret.exp[b][p] != 0)
for (b1,p,s)
in ret.keyline
if b1 == b
and s ==
True])
177 nb_bin = sum([(ret.exp[b][p] != 0)
for (b1,p,s)
in ret.keyline
if b1 == b
and s !=
True])
178 if np_bin == 0:
raise RuntimeError,
"Bin %s has no processes contributing to it" % b
179 if ns_bin == 0:
raise RuntimeError,
"Bin %s has no signal processes contributing to it" % b
180 if nb_bin == 0:
raise RuntimeError,
"Bin %s has no background processes contributing to it" % b
183 for lsyst,nofloat,pdf,args,errline
in ret.systs:
186 syst2.append((lsyst,nofloat,pdf,args,errline))
188 for (b,p,s)
in ret.keyline:
190 nullEffect = (r == 0.0
or (pdf ==
"lnN" and r == 1.0))
191 if not nullEffect
and ret.exp[b][p] != 0: nonNullEntries += 1
192 if nonNullEntries != 0: syst2.append((lsyst,nofloat,pdf,args,errline))
193 elif nuisances != -1: nuisances -= 1
201 nuisances = len(ret.systs)
202 elif len(ret.systs) != nuisances:
203 raise RuntimeError,
"Found %d systematics, expected %d" % (len(ret.systs), nuisances)
205 ret.hasShapes = (len(ret.shapeMap) > 0)