-
Notifications
You must be signed in to change notification settings - Fork 2
Ewm6834 fix default record #452
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
Changes from all commits
796093e
5abc3a6
cfbf802
1534d9a
cafe2e9
db0bb2e
15509a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from typing import Dict, List | ||
|
||
from snapred.backend.dao.calibration.Calibration import Calibration | ||
from snapred.backend.dao.indexing.Record import Record | ||
from snapred.meta.mantid.WorkspaceNameGenerator import WorkspaceName, WorkspaceType | ||
|
||
|
||
class CalibrationDefaultRecord(Record, extra="ignore"): | ||
""" | ||
|
||
The refer to the CalibrationRecord class for a more in-depth explanation of Calibration Records. | ||
This class contains the default, most basic information contained within the default Calibration. | ||
|
||
""" | ||
|
||
# inherits from Record | ||
# - runNumber | ||
# - useLiteMode | ||
# - version | ||
# override this to point at the correct daughter class | ||
# NOTE the version on the calculationParameters MUST match the version on the record | ||
# this should be enforced by a validator | ||
calculationParameters: Calibration | ||
|
||
# specific to calibration records | ||
workspaces: Dict[WorkspaceType, List[WorkspaceName]] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,18 @@ | ||
from typing import List, Optional | ||
from pydantic import ConfigDict | ||
|
||
from pydantic import BaseModel, ConfigDict | ||
from snapred.backend.dao.normalization import NormalizationRecord | ||
|
||
from snapred.backend.dao.indexing.Versioning import VERSION_DEFAULT | ||
from snapred.backend.dao.Limit import Limit | ||
from snapred.backend.dao.normalization.Normalization import Normalization | ||
from snapred.meta.mantid.WorkspaceNameGenerator import WorkspaceName | ||
|
||
|
||
class CreateNormalizationRecordRequest(BaseModel, extra="forbid"): | ||
class CreateNormalizationRecordRequest(NormalizationRecord, extra="forbid"): | ||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do see the purpose of this, but the necessity for this extra layer struck me as a bit weird. That is, if this is basically just a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did think this data object was kinda odd, I didnt look too closely at it. Looking further into how its used there's a bit of a smell. |
||
The needed data to create a NormalizationRecord. | ||
""" | ||
|
||
runNumber: str | ||
useLiteMode: bool | ||
version: Optional[int] = None | ||
calculationParameters: Normalization | ||
backgroundRunNumber: str | ||
smoothingParameter: float | ||
workspaceNames: List[WorkspaceName] = [] | ||
calibrationVersionUsed: Optional[int] = VERSION_DEFAULT | ||
crystalDBounds: Limit[float] | ||
|
||
model_config = ConfigDict( | ||
# required in order to use 'WorkspaceName' | ||
arbitrary_types_allowed=True, | ||
) | ||
|
||
@classmethod | ||
def parseVersion(cls, version, *, exclude_none: bool = False, exclude_default: bool = False) -> int | None: # noqa: ARG003 | ||
return version |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ | |
) | ||
from pydantic import validate_call | ||
|
||
from snapred.backend.dao.indexing.Versioning import VERSION_DEFAULT | ||
from snapred.backend.dao.ingredients import GroceryListItem | ||
from snapred.backend.dao.state import DetectorState | ||
from snapred.backend.data.LocalDataService import LocalDataService | ||
|
@@ -26,6 +27,7 @@ | |
from snapred.meta.mantid.WorkspaceNameGenerator import ( | ||
NameBuilder, | ||
WorkspaceName, | ||
WorkspaceType, | ||
) | ||
from snapred.meta.mantid.WorkspaceNameGenerator import ( | ||
WorkspaceNameGenerator as wng, | ||
|
@@ -44,6 +46,8 @@ class GroceryService: | |
Just send me a list. | ||
""" | ||
|
||
diffcalTableFileExtension: str = ".h5" | ||
|
||
def __init__(self, dataService: LocalDataService = None): | ||
# 'LocalDataService' is a singleton: | ||
# declare it here as an instance attribute, rather than a class attribute, | ||
|
@@ -212,23 +216,36 @@ def _createGroupingFilename(self, runNumber: str, groupingScheme: str, useLiteMo | |
def _createDiffcalOutputWorkspaceFilename(self, item: GroceryListItem) -> str: | ||
ext = Config["calibration.diffraction.output.extension"] | ||
return str( | ||
Path(self._getCalibrationDataPath(item.runNumber, item.useLiteMode, item.version)) | ||
self._getCalibrationDataPath(item.runNumber, item.useLiteMode, item.version) | ||
/ (self._createDiffcalOutputWorkspaceName(item) + ext) | ||
) | ||
|
||
@validate_call | ||
def _createDiffcalDiagnosticWorkspaceFilename(self, item: GroceryListItem) -> str: | ||
ext = Config["calibration.diffraction.diagnostic.extension"] | ||
return str( | ||
Path(self._getCalibrationDataPath(item.runNumber, item.useLiteMode, item.version)) | ||
self._getCalibrationDataPath(item.runNumber, item.useLiteMode, item.version) | ||
/ (self._createDiffcalOutputWorkspaceName(item) + ext) | ||
) | ||
|
||
def _createDiffcalTableFilepathFromWsName( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand this. I could do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, and possibly more importantly, what happens when these argument values are in contradiction with each other? |
||
self, runNumber: str, useLiteMode: bool, version: Optional[int], wsName: WorkspaceName | ||
) -> str: | ||
calibrationDataPath = self._getCalibrationDataPath(runNumber, useLiteMode, version) | ||
expectedWsName = self.createDiffcalTableWorkspaceName(runNumber, useLiteMode, version) | ||
if wsName != expectedWsName: | ||
raise ValueError( | ||
f"Workspace name {wsName} does not match the expected diffcal table workspace name for run {runNumber}", | ||
f"(i.e. {expectedWsName})", | ||
) | ||
|
||
return str(calibrationDataPath / (wsName + self.diffcalTableFileExtension)) | ||
|
||
@validate_call | ||
def _createDiffcalTableFilename(self, runNumber: str, useLiteMode: bool, version: Optional[int]) -> str: | ||
def _createDiffcalTableFilepath(self, runNumber: str, useLiteMode: bool, version: Optional[int]) -> str: | ||
return str( | ||
Path(self._getCalibrationDataPath(runNumber, useLiteMode, version)) | ||
/ (self._createDiffcalTableWorkspaceName(runNumber, useLiteMode, version) + ".h5") | ||
/ (self.createDiffcalTableWorkspaceName(runNumber, useLiteMode, version) + self.diffcalTableFileExtension) | ||
) | ||
|
||
@validate_call | ||
|
@@ -245,7 +262,10 @@ def _createNormalizationWorkspaceFilename(self, runNumber: str, useLiteMode: boo | |
def _createReductionPixelMaskWorkspaceFilename(self, runNumber: str, useLiteMode: bool, timestamp: float) -> str: | ||
return str( | ||
Path(self._getReductionDataPath(runNumber, useLiteMode, timestamp)) | ||
/ (self._createReductionPixelMaskWorkspaceName(runNumber, useLiteMode, timestamp) + ".h5") | ||
/ ( | ||
self._createReductionPixelMaskWorkspaceName(runNumber, useLiteMode, timestamp) | ||
+ self.diffcalTableFileExtension | ||
) | ||
) | ||
|
||
## WORKSPACE NAME METHODS | ||
|
@@ -285,14 +305,41 @@ def _createDiffcalOutputWorkspaceName(self, item: GroceryListItem) -> WorkspaceN | |
.build() | ||
) | ||
|
||
def lookupDiffcalTableWorkspaceName( | ||
self, runNumber: str, useLiteMode: bool, version: Optional[int] | ||
) -> WorkspaceName: | ||
indexer = self.dataService.calibrationIndexer(runNumber, useLiteMode) | ||
if not isinstance(version, int): | ||
version = indexer.latestApplicableVersion(runNumber) | ||
|
||
record = indexer.readRecord(version) | ||
if record is None: | ||
raise RuntimeError(f"Could not find calibration record for run {runNumber} and version {version}") | ||
|
||
# find first difcal table in record | ||
wsTableNameTuple = next(filter(lambda t: t[0] == WorkspaceType.DIFFCAL_TABLE, record.workspaces.items()), None) | ||
if wsTableNameTuple is None: | ||
raise RuntimeError( | ||
f"Could not find diffcal table in record for run {runNumber} in workspaces: {record.workspaces}" | ||
) | ||
# grab first value in list value of tuple | ||
tableWorkspaceName = wsTableNameTuple[1][0] | ||
return tableWorkspaceName | ||
|
||
@validate_call | ||
def _createDiffcalTableWorkspaceName( | ||
def createDiffcalTableWorkspaceName( | ||
self, | ||
runNumber: str, | ||
useLiteMode: bool, # noqa: ARG002 | ||
version: Optional[int], | ||
) -> WorkspaceName: | ||
return wng.diffCalTable().runNumber(runNumber).version(version).build() | ||
""" | ||
NOTE: This method will IGNORE runNumber if the provided version is VERSION_DEFAULT | ||
""" | ||
wsName = wng.diffCalTable().runNumber(runNumber).version(version).build() | ||
if version == VERSION_DEFAULT: | ||
wsName = wsName = wng.diffCalTable().runNumber("default").version(VERSION_DEFAULT).build() | ||
return wsName | ||
|
||
@validate_call | ||
def _createDiffcalMaskWorkspaceName( | ||
|
@@ -854,7 +901,7 @@ def fetchCalibrationWorkspaces(self, item: GroceryListItem) -> Dict[str, Any]: | |
:rtype: Dict[str, Any] | ||
""" | ||
runNumber, version, useLiteMode = item.runNumber, item.version, item.useLiteMode | ||
tableWorkspaceName = self._createDiffcalTableWorkspaceName(runNumber, useLiteMode, version) | ||
tableWorkspaceName = self.lookupDiffcalTableWorkspaceName(runNumber, useLiteMode, version) | ||
maskWorkspaceName = self._createDiffcalMaskWorkspaceName(runNumber, useLiteMode, version) | ||
|
||
if self.workspaceDoesExist(tableWorkspaceName): | ||
|
@@ -865,7 +912,7 @@ def fetchCalibrationWorkspaces(self, item: GroceryListItem) -> Dict[str, Any]: | |
} | ||
else: | ||
# table + mask are in the same hdf5 file: | ||
filename = self._createDiffcalTableFilename(runNumber, useLiteMode, version) | ||
filename = self._createDiffcalTableFilepathFromWsName(runNumber, useLiteMode, version, tableWorkspaceName) | ||
|
||
# Unless overridden: use a cached workspace as the instrument donor. | ||
instrumentPropertySource, instrumentSource = ( | ||
|
@@ -888,9 +935,10 @@ def fetchCalibrationWorkspaces(self, item: GroceryListItem) -> Dict[str, Any]: | |
|
||
return data | ||
|
||
# this isnt really a fetch method, this generates data | ||
@validate_call | ||
def fetchDefaultDiffCalTable(self, runNumber: str, useLiteMode: bool, version: int) -> WorkspaceName: | ||
tableWorkspaceName = self._createDiffcalTableWorkspaceName("default", useLiteMode, version) | ||
tableWorkspaceName = self.createDiffcalTableWorkspaceName("default", useLiteMode, version) | ||
self.mantidSnapper.CalculateDiffCalTable( | ||
"Generate the default diffcal table", | ||
InputWorkspace=self._fetchInstrumentDonor(runNumber, useLiteMode), | ||
|
@@ -1074,7 +1122,8 @@ def fetchGroceryList(self, groceryList: Iterable[GroceryListItem]) -> List[Works | |
# NOTE: fetchCalibrationWorkspaces will set the workspace name | ||
# to that of the table workspace. Because of possible confusion with | ||
# the behavior of the mask workspace, the workspace name is overridden here. | ||
tableWorkspaceName = self._createDiffcalTableWorkspaceName( | ||
|
||
tableWorkspaceName = self.lookupDiffcalTableWorkspaceName( | ||
item.runNumber, item.useLiteMode, item.version | ||
) | ||
res = self.fetchCalibrationWorkspaces(item) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,9 +25,8 @@ | |
StateConfig, | ||
StateId, | ||
) | ||
from snapred.backend.dao.calibration import Calibration, CalibrationRecord | ||
from snapred.backend.dao.calibration import Calibration, CalibrationDefaultRecord, CalibrationRecord | ||
from snapred.backend.dao.indexing.IndexEntry import IndexEntry | ||
from snapred.backend.dao.indexing.Record import Record | ||
from snapred.backend.dao.indexing.Versioning import VERSION_DEFAULT | ||
from snapred.backend.dao.Limit import Limit, Pair | ||
from snapred.backend.dao.normalization import Normalization, NormalizationRecord | ||
|
@@ -57,6 +56,7 @@ | |
) | ||
from snapred.meta.mantid.WorkspaceNameGenerator import ( | ||
WorkspaceName, | ||
WorkspaceType, | ||
) | ||
from snapred.meta.mantid.WorkspaceNameGenerator import ( | ||
WorkspaceNameGenerator as wng, | ||
|
@@ -845,7 +845,7 @@ def _writeDefaultDiffCalTable(self, runNumber: str, useLiteMode: bool): | |
indexer = self.calibrationIndexer(runNumber, useLiteMode) | ||
version = indexer.defaultVersion() | ||
grocer = GroceryService() | ||
filename = Path(grocer._createDiffcalTableWorkspaceName("default", useLiteMode, version) + ".h5") | ||
filename = Path(grocer.createDiffcalTableWorkspaceName("default", useLiteMode, version) + ".h5") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't get this: why does "default" subsume the <run number> position (especially as "default" as a string is not a legitimate <run number>), but not just use the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realized later that possibly there's no meaningful <run number> where this is actually required. I would like to see these "default" names centralized somewhere (we have the same requirement for < version > ), but that doesn't have much to do with this PR. |
||
outWS = grocer.fetchDefaultDiffCalTable(runNumber, useLiteMode, version) | ||
|
||
calibrationDataPath = indexer.versionPath(version) | ||
|
@@ -897,6 +897,9 @@ def generateInstrumentStateFromRoot(self, runId: str): | |
@ExceptionHandler(StateValidationException) | ||
# NOTE if you are debugging and got here, coment out the ExceptionHandler and try again | ||
def initializeState(self, runId: str, useLiteMode: bool, name: str = None): | ||
from snapred.backend.data.GroceryService import GroceryService | ||
|
||
grocer = GroceryService() | ||
stateId, _ = self.generateStateId(runId) | ||
|
||
instrumentState = self.generateInstrumentStateFromRoot(runId) | ||
|
@@ -922,12 +925,18 @@ def initializeState(self, runId: str, useLiteMode: bool, name: str = None): | |
creationDate=datetime.datetime.now(), | ||
version=version, | ||
) | ||
|
||
# NOTE: this creates a bare record without any other CalibrationRecord data | ||
record = Record( | ||
defaultDiffCalTableName = grocer.createDiffcalTableWorkspaceName("default", liteMode, version) | ||
workspaces: Dict[WorkspaceType, List[WorkspaceName]] = { | ||
wngt.DIFFCAL_TABLE: [defaultDiffCalTableName], | ||
} | ||
record = CalibrationDefaultRecord( | ||
runNumber=runId, | ||
useLiteMode=liteMode, | ||
version=version, | ||
calculationParameters=calibration, | ||
workspaces=workspaces, | ||
) | ||
entry = indexer.createIndexEntry( | ||
runNumber=runId, | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm tempted to suggest, that because this is a
NormalizationRecord
, the "normalization" part ofnormalizationCalibrantSamplePath
is redundant. And that to clarify the usage, the "normalization" only be added at theReductionRecord.normalizationCalibrantSamplePath
. (However, I can go either way on this.)