From b8fbfb65272ebcfc807eaba9653f537f0dd4b4cd Mon Sep 17 00:00:00 2001 From: Joep Vanlier Date: Tue, 2 Jul 2024 19:05:13 +0200 Subject: [PATCH] calibration: add application timestamp --- changelog.md | 1 + lumicks/pylake/calibration.py | 9 ++++++++- lumicks/pylake/tests/data/mock_file.py | 5 ++++- lumicks/pylake/tests/test_file/test_calibration_item.py | 2 ++ lumicks/pylake/tests/test_file/test_file_items.py | 1 + 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 0c9267d57..331fb9cc2 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,7 @@ * Added parameter `allow_overwrite` to [`lk.download_from_doi()`](https://lumicks-pylake.readthedocs.io/en/latest/_api/lumicks.pylake.download_from_doi.html#lumicks.pylake.download_from_doi) to allow re-downloading only those files where the checksum does not match. * Added force calibration information to channels accessed directly via the square bracket notation (e.g. `file["Force HF"]["Force 1x"].calibration`). * Calibration results and parameters are now accessible via properties which are listed when items are printed. See [calibration results](https://lumicks-pylake.readthedocs.io/en/latest/_api/lumicks.pylake.force_calibration.power_spectrum_calibration.CalibrationResults.html) and [calibration item](https://lumicks-pylake.readthedocs.io/en/latest/_api/lumicks.pylake.calibration.ForceCalibrationItem.html) API documentation for more information. +* Added `applied_at` property to a [calibration item](https://lumicks-pylake.readthedocs.io/en/latest/_api/lumicks.pylake.calibration.ForceCalibrationItem.html) obtained from a force slice. This property returns the timestamp in nanoseconds at which the force calibration was applied. * Added improved printing of calibration items under `channel.calibration` providing a more convenient overview of the items associated with a `Slice`. * Added parameter `titles` to customize title of each subplot in `[`Kymo.plot_with_channels()`](https://lumicks-pylake.readthedocs.io/en/latest/_api/lumicks.pylake.kymo.Kymo.html#lumicks.pylake.kymo.Kymo.plot_with_channels). diff --git a/lumicks/pylake/calibration.py b/lumicks/pylake/calibration.py index 4ff58d225..f16017c59 100644 --- a/lumicks/pylake/calibration.py +++ b/lumicks/pylake/calibration.py @@ -27,6 +27,11 @@ def _get_parameter(self, _, bluelake_key): if bluelake_key in self: return self[bluelake_key] + @property + def applied_at(self): + """Time the calibration was applied in nanoseconds since epoch""" + return self.data.get("Timestamp (ns)") + @property def _fitted_diode(self): """Diode parameters were fitted""" @@ -354,8 +359,10 @@ def from_field(hdf5, force_channel, time_field="Stop time (ns)") -> "ForceCalibr items = [] for calibration_item in hdf5["Calibration"].values(): if force_channel in calibration_item: - attrs = calibration_item[force_channel].attrs + attrs = dict(calibration_item[force_channel].attrs) if time_field in attrs.keys(): + # Copy the timestamp at which the calibration was applied into the item + attrs["Timestamp (ns)"] = calibration_item.attrs.get("Timestamp (ns)") items.append(ForceCalibrationItem(attrs)) return ForceCalibration(time_field=time_field, items=items) diff --git a/lumicks/pylake/tests/data/mock_file.py b/lumicks/pylake/tests/data/mock_file.py index 1cff31247..1e9ec508c 100644 --- a/lumicks/pylake/tests/data/mock_file.py +++ b/lumicks/pylake/tests/data/mock_file.py @@ -53,7 +53,7 @@ class MockDataFile_v2(MockDataFile_v1): def get_file_format_version(self): return 2 - def make_calibration_data(self, calibration_idx, group, attributes): + def make_calibration_data(self, calibration_idx, group, attributes, application_timestamp=None): if "Calibration" not in self.file: self.file.create_group("Calibration") @@ -64,6 +64,9 @@ def make_calibration_data(self, calibration_idx, group, attributes): # e.g. Force 1x, Force 1y ... etc if group not in self.file["Calibration"][calibration_idx]: self.file["Calibration"][calibration_idx].create_group(group) + self.file["Calibration"][calibration_idx].attrs["Timestamp (ns)"] = ( + application_timestamp if application_timestamp else attributes["Stop time (ns)"] + ) # Attributes field = self.file["Calibration"][calibration_idx][group] diff --git a/lumicks/pylake/tests/test_file/test_calibration_item.py b/lumicks/pylake/tests/test_file/test_calibration_item.py index 22bda3aed..416af9464 100644 --- a/lumicks/pylake/tests/test_file/test_calibration_item.py +++ b/lumicks/pylake/tests/test_file/test_calibration_item.py @@ -49,6 +49,7 @@ "gamma_0 (kg/s)": 8.388052385084746e-09, "kappa (pN/nm)": 0.2421057076519628, "Bead center height (um)": 1.0, + "Timestamp (ns)": 1696171386701856700, } @@ -168,6 +169,7 @@ def test_passive_item(compare_to_reference_dict, reference_data, calibration_dat assert item.diffusion_volts_std_err == ref_passive_fixed_diode_with_height["err_D (V^2/s)"] assert not item.diode_frequency_std_err assert not item.diode_relaxation_factor_std_err + assert item.applied_at is 1696171386701856700 compare_to_reference_dict(item.power_spectrum_params(), test_name="power") compare_to_reference_dict(item._model_params(), test_name="model") diff --git a/lumicks/pylake/tests/test_file/test_file_items.py b/lumicks/pylake/tests/test_file/test_file_items.py index 260eb2b2a..d2ed3b07d 100644 --- a/lumicks/pylake/tests/test_file/test_file_items.py +++ b/lumicks/pylake/tests/test_file/test_file_items.py @@ -54,6 +54,7 @@ def test_calibration(h5_file): assert f["Force HF"]["Force 1x"].calibration == f.force1x.calibration assert f["Force HF"]["Force 2x"].calibration == f.force2x.calibration + assert f.force1x.calibration[2].applied_at == 10 def test_marker(h5_file):