Skip to content

Commit 7a079b0

Browse files
Merge branch 'develop'
2 parents 92b7b12 + 0d452cc commit 7a079b0

File tree

16 files changed

+893
-123
lines changed

16 files changed

+893
-123
lines changed

ReleaseNotes

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
Release v3.0.2, Thu 23 Jan 2025
2+
=======================================================
3+
4+
* Small fix in pyhf caching code (results should not change)
5+
* Fixes with parallelisation of resummino cross section computer
6+
* Tiny fix to allow '#' without subsequent whitespace as comment in text database
7+
18
Release v3.0.1, Thu 31 Oct 2024
29
=======================================================
310

docs/manual/source/ReleaseUpdate.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ What's New
3333
==========
3434
The major novelties of all releases since v1.0 are as follows:
3535

36+
New in Version 3.0.2:
37+
^^^^^^^^^^^^^^^^^^^^^
38+
39+
* Small fix in pyhf caching code (results should not change)
40+
* Fixes with parallelisation of :ref:`resummino cross section <xsecResummino>` computer
41+
* Tiny fix to allow '#' without subsequent whitespace as comment in text database
42+
3643
New in Version 3.0.1:
3744
^^^^^^^^^^^^^^^^^^^^^
3845

smodels/base/runtime.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010
1111
"""
1212

13+
from typing import Union
14+
1315
## place to keep the pointer to the model file (default = mssm)
1416
modelFile="smodels.share.models.mssm"
1517

16-
_experimental = False ## turn on experimental features
18+
_experimental = { "truncatedgaussians": False,
19+
"spey": False } ## experimental features
1720

1821
_deltas_rel_default = .2 ## the default relative error on the signal strength
1922

@@ -51,11 +54,16 @@ def filetype ( filename ):
5154
return None
5255

5356

54-
def experimentalFeatures():
55-
""" a simple boolean flag to turn experimental features on/off,
57+
def experimentalFeature( feature : str ) -> Union[None,bool]:
58+
""" method to check if a certain experimental feature is enabled.
5659
can be turned on and off via options:experimental in parameters.ini.
60+
:param feature: ask for feature
61+
62+
:returns: None if feature does not exist, else boolean
5763
"""
58-
return _experimental
64+
if not feature in _experimental:
65+
return None
66+
return _experimental[feature]
5967

6068
def nCPUs():
6169
""" obtain the number of *available* CPU cores on the machine, for several

smodels/experiment/databaseObj.py

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def _getSHA1(filename):
5858

5959
# some mechanism to remove lock files if the download got interrupted
6060
import atexit
61-
lockfiles = set()
61+
lockfiles = set()
6262

6363
def removeLockFiles( lockfiles ):
6464
""" remove cruft lockfiles """
@@ -73,13 +73,13 @@ def removeLockFiles( lockfiles ):
7373
atexit.register ( removeLockFiles, lockfiles )
7474

7575
class Database(object):
76-
"""
76+
"""
7777
Database object. Holds a list of SubDatabases and the ExpSMS map.
7878
Delegates all calls to SubDatabases.
7979
"""
8080

8181
def __init__(self, base=None, force_load=None,
82-
progressbar=False, subpickle=True,
82+
progressbar=False, subpickle=True,
8383
combinationsmatrix=None):
8484
"""
8585
:param base: path to the database, or pickle file (string), or http
@@ -99,17 +99,15 @@ def __init__(self, base=None, force_load=None,
9999
optionally specifying signal regions, e.g. { "anaid1:SR1":
100100
( "anaid2:SR2", "anaid3" ) }
101101
"""
102-
103102
self.subs = []
104-
105103
if "_fastlim" in base: # for backwards compatibility
106104
base = base.replace("_fastlim", "+fastlim")
107105
sstrings = base.split("+")
108106
for ss in sstrings:
109107
self.subs.append(SubDatabase(ss, force_load,
110-
progressbar, subpickle,
108+
progressbar, subpickle,
111109
combinationsmatrix))
112-
110+
113111

114112
# Compute SMS dict with all results
115113
self._allExpSMSDict = ExpSMSDict(self.expResultList)
@@ -120,7 +118,7 @@ def __init__(self, base=None, force_load=None,
120118
@property
121119
def expResultList(self):
122120
"""
123-
The combined list of results, compiled from the
121+
The combined list of results, compiled from the
124122
the active results in each subdatabase.
125123
"""
126124

@@ -235,11 +233,11 @@ def getExpResults(self, analysisIDs=['all'], datasetIDs=['all'], txnames=['all']
235233
Select (filter) the results within the database satisfying the restrictions set by the arguments and returns the corresponding results.
236234
"""
237235

238-
self.selectExpResults(analysisIDs=analysisIDs, datasetIDs=datasetIDs,
239-
txnames=txnames, dataTypes=dataTypes,
236+
self.selectExpResults(analysisIDs=analysisIDs, datasetIDs=datasetIDs,
237+
txnames=txnames, dataTypes=dataTypes,
240238
useNonValidated=useNonValidated,
241239
onlyWithExpected=onlyWithExpected)
242-
240+
243241
return self.expResultList[:]
244242

245243
def selectExpResults(self, analysisIDs=['all'], datasetIDs=['all'], txnames=['all'],
@@ -420,8 +418,8 @@ def __init__(self, base=None, force_load=None,
420418
self._setParticles()
421419
self.txt_meta.printFastlimBanner()
422420
return
423-
logger.error("when initialising database: force_load=%s is not "
424-
"recognized. Valid values are: pcl, txt, None." % force_load)
421+
logger.error( f"when initialising database: force_load={force_load} is not "
422+
"recognized. Valid values are: pcl, txt, None." )
425423
raise SModelSError()
426424

427425
def __eq__(self, other):
@@ -462,16 +460,21 @@ def loadDatabase(self):
462460
it needs update, create new binary file, in
463461
case it does need an update.
464462
"""
465-
if not os.path.exists(self.pcl_meta.pathname):
466-
logger.info("Creating binary database ")
467-
logger.info("(this may take a few minutes, but it's done only once!)")
468-
self.loadTextDatabase()
469-
self.createBinaryFile()
470-
else:
471-
if self.needsUpdate():
463+
try:
464+
if not os.path.exists(self.pcl_meta.pathname):
465+
logger.info("Creating binary database ")
466+
logger.info("(this may take a few minutes, but it's done only once!)")
467+
self.loadTextDatabase()
472468
self.createBinaryFile()
473469
else:
474-
self.loadBinaryFile(lastm_only=False)
470+
if self.needsUpdate():
471+
self.createBinaryFile()
472+
else:
473+
self.loadBinaryFile(lastm_only=False)
474+
except Exception as e:
475+
import traceback
476+
logger.error ( "when loading database: {e}, {traceback.format_exc()}" )
477+
sys.exit(-1)
475478

476479
def loadTextDatabase(self):
477480
""" simply loads the textdabase """
@@ -557,7 +560,7 @@ def loadBinaryFile(self, lastm_only=False):
557560
t1 = time.time()-t0
558561
logger.info("Loaded database from %s in %.1f secs." %
559562
(self.pcl_meta.pathname, t1))
560-
self.databaseParticles = None
563+
self.databaseParticles = None
561564
try:
562565
self.databaseParticles = serializer.load(f)
563566
except EOFError as e:
@@ -669,7 +672,7 @@ def base(self):
669672
def lockFile ( self, filename : os.PathLike ):
670673
""" lock the file <filename>
671674
"""
672-
lockfile = os.path.join ( os.path.dirname ( filename ),
675+
lockfile = os.path.join ( os.path.dirname ( filename ),
673676
".lock_"+ os.path.basename ( filename ) )
674677
ctr = 0
675678
while ( ctr < 5 ):
@@ -700,7 +703,7 @@ def lockFile ( self, filename : os.PathLike ):
700703
def unlockFile ( self, filename : os.PathLike ):
701704
""" unlock the file <filename>
702705
"""
703-
lockfile = os.path.join ( os.path.dirname ( filename ),
706+
lockfile = os.path.join ( os.path.dirname ( filename ),
704707
".lock_"+ os.path.basename ( filename ) )
705708
if lockfile in lockfiles:
706709
lockfiles.remove( lockfile )
@@ -1079,7 +1082,7 @@ def setActiveExpResults(self, analysisIDs=['all'], datasetIDs=['all'], txnames=[
10791082
"""
10801083

10811084
self._activeResults = self.getExpResults(analysisIDs, datasetIDs, txnames,
1082-
dataTypes, useNonValidated,
1085+
dataTypes, useNonValidated,
10831086
onlyWithExpected)
10841087

10851088
def getExpResults(self, analysisIDs=['all'], datasetIDs=['all'], txnames=['all'],

smodels/experiment/infoObj.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def __init__(self, path=None):
4545
for i, tag in enumerate(tags):
4646
if not tag:
4747
continue
48-
if tag.startswith("# "): # a comment!
48+
if tag.startswith("#"): # a comment!
4949
continue
5050
line = content[i]
5151
value = line.split(':', 1)[1].strip()

smodels/matching/modelTester.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,10 @@ def testPoint(inputFile, outputDir, parser, database):
178178
useBest = False
179179
except (NoSectionError, NoOptionError):
180180
pass
181-
try:
182-
expFeatures = parser.getboolean("options", "experimentalFeatures")
183-
runtime._experimental = expFeatures
184-
except (NoSectionError, NoOptionError):
185-
pass
181+
182+
if parser.has_section ( "experimentalFeatures" ):
183+
featuresDict = dict(parser.items("experimentalFeatures"))
184+
setExperimentalFeatures( featuresDict )
186185

187186
allPredictions = theoryPredictionsFor(database, smstoplist,
188187
useBestDataset=useBest,
@@ -530,7 +529,11 @@ def getParameters(parameterFile):
530529
if ret == []:
531530
logger.error("No such file or directory: '%s'" % parameterFile)
532531
sys.exit()
533-
setExperimentalFlag(parser)
532+
533+
if parser.has_section ( "experimentalFeatures" ):
534+
featuresDict = dict(parser.items("experimentalFeatures"))
535+
setExperimentalFeatures(featuresDict)
536+
534537
try:
535538
runtime.modelFile = parser.get("particles", "model")
536539
except:
@@ -544,12 +547,15 @@ def getParameters(parameterFile):
544547
return parser
545548

546549

547-
def setExperimentalFlag(parser):
548-
""" set the experimental flag, if options:experimental = True """
549-
if parser.has_option("options", "experimental"):
550-
if parser.getboolean("options", "experimental"):
551-
runtime._experimental = True
550+
def setExperimentalFeatures(featuresDict):
551+
""" set the experimental features flats, if experimentalFeatures:* = True """
552552

553+
for feature in featuresDict.keys():
554+
if not feature in runtime._experimental:
555+
logger.warning ( f"'{feature}' is not a known experimental feature. will ignore." )
556+
continue
557+
flag = bool(featuresDict[feature])
558+
runtime._experimental[feature]=flag
553559

554560
def getAllInputFiles(inFile):
555561
"""

smodels/matching/theoryPrediction.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from smodels.matching.exceptions import SModelSMatcherError as SModelSError
1313
from smodels.matching import clusterTools
1414
from smodels.base.smodelsLogging import logger
15-
from smodels.statistics.statsTools import StatsComputer
1615
from typing import Union, Text, Dict
1716
import numpy as np
1817

@@ -144,10 +143,12 @@ def setStatsComputer(self):
144143
to define a statistical computer (upper limit result or no expected
145144
upper limits), set the computer to 'N/A'.
146145
"""
146+
from smodels.statistics.statsTools import getStatsComputerModule
147+
StatsComputer = getStatsComputerModule()
147148

148149
if self.dataType() == "upperLimit":
149-
from smodels.base.runtime import experimentalFeatures
150-
if not experimentalFeatures():
150+
from smodels.base.runtime import experimentalFeature
151+
if not experimentalFeature( "truncatedGaussians" ):
151152
computer = 'N/A'
152153
else:
153154
computer = StatsComputer.forTruncatedGaussian(self)
@@ -373,7 +374,8 @@ def computeStatistics(self, expected=False):
373374
self.cachedObjs[expected]["nll_sm"] = llhdDict["lsm"]
374375
self.cachedObjs[expected]["nllmax"] = llhdDict["lmax"]
375376
self.cachedObjs[expected]["muhat"] = llhdDict["muhat"]
376-
self.cachedObjs[expected]["sigma_mu"] = llhdDict["sigma_mu"]
377+
if "sigma_mu" in llhdDict:
378+
self.cachedObjs[expected]["sigma_mu"] = llhdDict["sigma_mu"]
377379

378380

379381
class TheoryPredictionsCombiner(TheoryPrediction):
@@ -522,6 +524,8 @@ def setStatsComputer(self):
522524
if any(tp.statsComputer == 'N/A' for tp in self.theoryPredictions):
523525
computer = 'N/A'
524526
else:
527+
from smodels.statistics.statsTools import getStatsComputerModule
528+
StatsComputer = getStatsComputerModule()
525529
computer = StatsComputer.forAnalysesComb(self.theoryPredictions, self.deltas_rel)
526530

527531
self._statsComputer = computer

smodels/share/BANNER

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
SModelS -- A tool for interpreting simplified-model results from the LHC,
99
see https://smodels.github.io/.
1010

11-
Copyright (C) 2012-2024 The SModelS collaboration, smodels-users@lists.oeaw.ac.at
12-
Current members: Mohammad Mahdi Altakach, Sabine Kraml, Andre Lessa, Sahana Narashima, Timothee Pascal, Camila Ramos, Humberto Reyes-Gonzalez, Yoxara Villamizar, Wolfgang Waltenberger
11+
Copyright (C) 2012-2025 The SModelS collaboration, smodels-users@lists.oeaw.ac.at
12+
Current members: Mohammad Mahdi Altakach, Sabine Kraml, Andre Lessa, Sahana Narashima, Timothee Pascal, Camila Ramos, Humberto Reyes-Gonzalez, Theo Reymermier, Yoxara Villamizar, Wolfgang Waltenberger
1313

1414
Previously involved in SModelS: Gael Alguero, Federico Ambrogi, Juhi Dutta, Jan Heisig, Charanjit K. Khosa, Suchita Kulkarni, Ursula Laa, Veronika Magerl, Wolfgang Magerl, Philipp Neuhuber, Doris Proschofsky, Jory Sonneveld, Michael Traub, Matthias Wolf, Alicia Wongel

smodels/statistics/basicStats.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ def CLsfromNLL(
2323
compute the CLs - alpha from the NLLs
2424
TODO: following needs explanation
2525
26-
:param nllA:
27-
:param nll0A:
28-
:param nll:
29-
:param nll0:
26+
:param nllA: negative log likelihood for Asimov data
27+
:param nll0A: negative log likelihood at muhat for Asimov data
28+
:param nll: negative log likelihood
29+
:param nll0: negative log likelihood at muhat
3030
:param return_type: (Text) can be "CLs-alpha", "1-CLs", "CLs" \
3131
CLs-alpha: returns CLs - 0.05 \
3232
1-CLs: returns 1-CLs value \

0 commit comments

Comments
 (0)