Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expanded normalization modifiers #434

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/cabinetry/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,10 @@ def histogram_is_needed(
else:
# handle non-nominal, non-data histograms
# this assumes that the systematic dict satisfies config schema requirements
if systematic["Type"] == "Normalization":
if systematic[template] == "Normalization":
# no histogram needed for normalization variation
histo_needed = False
elif systematic["Type"] == "NormPlusShape":
elif systematic["Type"] == "NormPlusShape" or systematic["Type"] == "Normalization":
# for a variation defined via a template, a histogram is needed (if
# sample is affected in region)
histo_needed = region_contains_modifier(region, systematic)
Expand Down
68 changes: 62 additions & 6 deletions src/cabinetry/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,16 @@ def normfactor_modifiers(
)
return modifiers

@staticmethod
def normalization_modifier(systematic: Dict[str, Any]) -> Dict[str, Any]:
# @staticmethod -- VK: had to disable that to pass self
def normalization_modifier(
self, region: Dict[str, Any], sample: Dict[str, Any], systematic: Dict[str, Any]
) -> Dict[str, Any]:
"""Returns a normalization modifier (OverallSys in `HistFactory`).

Args:
systematic (Dict[str, Any]): systematic for which modifier is constructed
region (Dict[str, Any]): region the systematic variation acts in
sample (Dict[str, Any]): sample the systematic variation acts on
systematic (Dict[str, Any]): the systematic variation under consideration

Returns:
Dict[str, Any]: single `normsys` modifier for ``pyhf`` workspace
Expand All @@ -107,14 +111,66 @@ def normalization_modifier(systematic: Dict[str, Any]) -> Dict[str, Any]:
modifier = {}
modifier.update({"name": modifier_name})
modifier.update({"type": "normsys"})

# VK: need to add a check agains Up/Down type agreement -- maybe at the level of the config file creation/validation
if systematic.get("Up").get("Normalization"):
if systematic.get("Up").get("Symmetrize"):
raise NotImplementedError("Symmetrization should happen on the Down variation.")
elif systematic.get("Down").get("Symmetrize"):
norm_effect_up = 1 + systematic["Up"]["Normalization"]
norm_effect_down = 1 - systematic["Up"]["Normalization"]
else:
norm_effect_up = 1 + systematic["Up"]["Normalization"]
norm_effect_down = 1 + systematic["Down"]["Normalization"]
else:
# need to calculate the normalisation factor from the histograms
if systematic.get("Up").get("Symmetrize"):
raise NotImplementedError("Symmetrization should happen on the Down variation.")
# load the up systematic variation histogram
histogram_up = histo.Histogram.from_config(
self.histogram_folder,
region,
sample,
systematic,
template="Up",
modified=True,
)
# also need the nominal histogram
histogram_nominal = histo.Histogram.from_config(
self.histogram_folder, region, sample, {}, modified=True
)

if systematic.get("Down").get("Symmetrize"):
# symmetrization according to "method 1" from issue #26:
# first normalization, then symmetrization

# normalize the variation to the same yield as nominal
norm_effect = histogram_up.normalize_to_yield(histogram_nominal)
norm_effect_up = norm_effect
norm_effect_down = 2 - norm_effect
else:
histogram_down = histo.Histogram.from_config(
self.histogram_folder,
region,
sample,
systematic,
template="Down",
modified=True,
)

norm_effect_up = sum(histogram_up.yields) / sum(histogram_nominal.yields)
norm_effect_down = sum(histogram_down.yields) / sum(histogram_nominal.yields)

# update the modifier data
modifier.update(
{
"data": {
"hi": 1 + systematic["Up"]["Normalization"],
"lo": 1 + systematic["Down"]["Normalization"],
"hi": norm_effect_up,
"lo": norm_effect_down,
}
}
)

return modifier

def normplusshape_modifiers(
Expand Down Expand Up @@ -240,7 +296,7 @@ def sys_modifiers(
f"adding OverallSys {systematic['Name']} to sample"
f" {sample['Name']} in region {region['Name']}"
)
modifiers.append(self.normalization_modifier(systematic))
modifiers.append(self.normalization_modifier(region, sample, systematic))
elif systematic["Type"] == "NormPlusShape":
# two modifiers are needed - an OverallSys for the norm effect,
# and a HistoSys for the shape variation
Expand Down
Loading