dkist-processing-common 10.8.2__tar.gz → 10.8.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/CHANGELOG.rst +15 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/PKG-INFO +1 -1
- dkist_processing_common-10.8.3/dkist_processing_common/models/fried_parameter.py +41 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/quality.py +1 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/mixin/quality/_metrics.py +19 -14
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/quality_metrics.py +1 -1
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/write_l1.py +9 -2
- dkist_processing_common-10.8.3/dkist_processing_common/tests/test_fried_parameter.py +27 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_quality_mixin.py +32 -22
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_write_l1.py +33 -8
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common.egg-info/PKG-INFO +1 -1
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common.egg-info/SOURCES.txt +2 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/.gitignore +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/.pre-commit-config.yaml +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/.readthedocs.yml +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/.snyk +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/README.rst +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/bitbucket-pipelines.yml +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/changelog/.gitempty +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/_util/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/_util/constants.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/_util/graphql.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/_util/scratch.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/_util/tags.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/codecs/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/codecs/asdf.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/codecs/bytes.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/codecs/fits.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/codecs/iobase.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/codecs/json.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/codecs/path.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/codecs/quality.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/codecs/str.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/config.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/fonts/Lato-Regular.ttf +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/fonts/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/manual.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/constants.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/fits_access.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/flower_pot.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/graphql.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/message.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/message_queue_binding.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/metric_code.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/parameters.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/quality.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/tags.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/task_name.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/models/wavelength.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/cs_step.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/dsps_repeat.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/experiment_id_bud.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/id_bud.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/l0_fits_access.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/l1_fits_access.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/near_bud.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/proposal_id_bud.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/retarder.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/single_value_single_key_flower.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/task.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/time.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/unique_bud.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/parsers/wavelength.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/assemble_movie.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/base.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/l1_output_data.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/mixin/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/mixin/globus.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/mixin/input_dataset.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/mixin/interservice_bus.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/mixin/metadata_store.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/mixin/object_store.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/mixin/quality/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/mixin/quality/_base.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/output_data_base.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/parse_l0_input_data.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/teardown.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/transfer_input_data.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/trial_catalog.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tasks/trial_output_data.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/__init__.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/conftest.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_assemble_movie.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_assemble_quality.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_base.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_codecs.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_constants.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_cs_step.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_fits_access.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_flower_pot.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_input_dataset.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_interservice_bus.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_interservice_bus_mixin.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_manual_processing.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_output_data_base.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_parameters.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_parse_l0_input_data.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_publish_catalog_messages.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_quality.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_scratch.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_stems.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_submit_dataset_metadata.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_tags.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_task_name.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_task_parsing.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_teardown.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_transfer_input_data.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_transfer_l1_output_data.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_trial_catalog.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_trial_output_data.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/tests/test_workflow_task_base.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common.egg-info/dependency_links.txt +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common.egg-info/requires.txt +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common.egg-info/top_level.txt +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/docs/Makefile +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/docs/changelog.rst +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/docs/conf.py +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/docs/index.rst +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/docs/landing_page.rst +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/docs/make.bat +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/docs/requirements.txt +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/licenses/LICENSE.rst +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/pyproject.toml +0 -0
- {dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/setup.cfg +0 -0
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
v10.8.3 (2025-05-28)
|
|
2
|
+
====================
|
|
3
|
+
|
|
4
|
+
Features
|
|
5
|
+
--------
|
|
6
|
+
|
|
7
|
+
- Further constrain when the ATMOS_R0 header key is written in L1 data based on the following metrics:
|
|
8
|
+
|
|
9
|
+
* the ATMOS_R0 value in the L0 data must be less than or equal to 30cm
|
|
10
|
+
* the AO_LOCK value in the L0 data must be True
|
|
11
|
+
* the OOBSHIFT value in the L0 data must be less than 100
|
|
12
|
+
|
|
13
|
+
The wavefront sensor has about 1500 subapertures from which x and y shifts are measured. When the adaptive optics loop is locked, we count how many of these shifts exceed a threshold considered to be out of bounds. The r0 measurement gets less accurate as more of these shifts are out of bounds and so this is another way to detect outliers in the r0 value. (`#250 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/250>`__)
|
|
14
|
+
|
|
15
|
+
|
|
1
16
|
v10.8.2 (2025-05-27)
|
|
2
17
|
====================
|
|
3
18
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Helper methods to handle fried parameter / r0 validity."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def r0_valid(
|
|
5
|
+
r0: float | None = None,
|
|
6
|
+
ao_lock: bool | None = None,
|
|
7
|
+
num_out_of_bounds_ao_values: int | None = None,
|
|
8
|
+
) -> bool:
|
|
9
|
+
"""
|
|
10
|
+
Determine if the r0 value should be considered valid based on the following conditions.
|
|
11
|
+
|
|
12
|
+
* ATMOS_R0 does not exist in the header.
|
|
13
|
+
* the value of ATMOS_R0 is greater than 0.3m
|
|
14
|
+
* the AO is not locked
|
|
15
|
+
* the value of OOBSHIFT is greater than 100
|
|
16
|
+
|
|
17
|
+
When the adaptive optics system is not locked, the ATMOS_R0 keyword is still filled with the output of the
|
|
18
|
+
Fried parameter calculation. The inputs are not valid in this instance and the value should be removed.
|
|
19
|
+
|
|
20
|
+
Sometimes, due to timing differences between the calculation of the Fried parameter and the AO lock status being
|
|
21
|
+
updated, non-physical values can be recorded for ATMOS_R0 right on the edge of an AO_LOCK state change. To
|
|
22
|
+
combat this, any remaining R0 values greater than 30cm (which is beyond the realm of physical possibility for
|
|
23
|
+
solar observations) are also removed.
|
|
24
|
+
|
|
25
|
+
In addition, the number of AO out-of-bound values is given in the keyword OOBSHIFT and the AO team advises
|
|
26
|
+
that values under 100 are when the r0 value is considered reliable. If the OOBSHIFT key doesn't exist, this check
|
|
27
|
+
should be ignored.
|
|
28
|
+
"""
|
|
29
|
+
if r0 is None:
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
if r0 > 0.3:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
if ao_lock is not True:
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
if num_out_of_bounds_ao_values is not None and num_out_of_bounds_ao_values > 100:
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
return True
|
|
@@ -31,3 +31,4 @@ class L1QualityFitsAccess(L1FitsAccess):
|
|
|
31
31
|
self.light_level: float = self.header["LIGHTLVL"]
|
|
32
32
|
self.health_status: str = self.header["DSHEALTH"]
|
|
33
33
|
self.ao_status: int = self.header.get("AO_LOCK", None)
|
|
34
|
+
self.num_out_of_bounds_ao_values: int = self.header.get("OOBSHIFT", None)
|
|
@@ -20,6 +20,7 @@ from dkist_processing_pac.fitter.fitting_core import compare_I
|
|
|
20
20
|
from dkist_processing_pac.fitter.polcal_fitter import PolcalFitter
|
|
21
21
|
from pandas import DataFrame
|
|
22
22
|
|
|
23
|
+
from dkist_processing_common.models.fried_parameter import r0_valid
|
|
23
24
|
from dkist_processing_common.models.metric_code import MetricCode
|
|
24
25
|
from dkist_processing_common.models.quality import EfficiencyHistograms
|
|
25
26
|
from dkist_processing_common.models.quality import ModulationMatrixHistograms
|
|
@@ -203,7 +204,7 @@ class _SimplePlotQualityMixin:
|
|
|
203
204
|
return warnings
|
|
204
205
|
|
|
205
206
|
def quality_store_ao_status_and_fried_parameter(
|
|
206
|
-
self, datetimes: list[str], values: list[list[bool
|
|
207
|
+
self, datetimes: list[str], values: list[list[bool | float]]
|
|
207
208
|
):
|
|
208
209
|
"""
|
|
209
210
|
Collect and store datetime / value pairs for the boolean AO status and Fried parameter.
|
|
@@ -213,23 +214,27 @@ class _SimplePlotQualityMixin:
|
|
|
213
214
|
Because of how L1Metric.has_metric works, empty lists will not be passed to this method.
|
|
214
215
|
However, because of how L1Metric.store_metric works, one or both values can be None.
|
|
215
216
|
"""
|
|
216
|
-
|
|
217
|
-
ao_not_none = [ao for ao in
|
|
217
|
+
ao_lock_values = [value[0] for value in values]
|
|
218
|
+
ao_not_none = [ao for ao in ao_lock_values if ao is not None]
|
|
218
219
|
if len(ao_not_none) != 0:
|
|
219
220
|
self._record_values(values=ao_not_none, tags=Tag.quality(MetricCode.ao_status))
|
|
220
221
|
fried_values = [value[1] for value in values]
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
]
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
222
|
+
ao_oob_values = [value[2] for value in values]
|
|
223
|
+
fried_values_to_plot = []
|
|
224
|
+
datetimes_to_plot = []
|
|
225
|
+
# For each set of input data, check if the r0 is considered valid based on all data
|
|
226
|
+
for i in range(len(fried_values)):
|
|
227
|
+
if r0_valid(
|
|
228
|
+
r0=fried_values[i],
|
|
229
|
+
ao_lock=ao_lock_values[i],
|
|
230
|
+
num_out_of_bounds_ao_values=ao_oob_values[i],
|
|
231
|
+
):
|
|
232
|
+
fried_values_to_plot.append(fried_values[i])
|
|
233
|
+
datetimes_to_plot.append(datetimes[i])
|
|
234
|
+
if len(fried_values_to_plot) != 0:
|
|
230
235
|
self._record_2d_plot_values(
|
|
231
|
-
x_values=
|
|
232
|
-
y_values=
|
|
236
|
+
x_values=datetimes_to_plot,
|
|
237
|
+
y_values=fried_values_to_plot,
|
|
233
238
|
tags=Tag.quality(MetricCode.fried_parameter),
|
|
234
239
|
)
|
|
235
240
|
|
|
@@ -296,7 +296,7 @@ class QualityL1Metrics(WorkflowTaskBase, QualityMixin):
|
|
|
296
296
|
L1Metric(storage_method=self.quality_store_health_status, value_source="health_status"),
|
|
297
297
|
L1Metric(
|
|
298
298
|
storage_method=self.quality_store_ao_status_and_fried_parameter,
|
|
299
|
-
value_source=["ao_status", "fried_parameter"],
|
|
299
|
+
value_source=["ao_status", "fried_parameter", "num_out_of_bounds_ao_values"],
|
|
300
300
|
),
|
|
301
301
|
]
|
|
302
302
|
|
|
@@ -29,6 +29,7 @@ from sunpy.coordinates import Helioprojective
|
|
|
29
29
|
|
|
30
30
|
from dkist_processing_common.codecs.fits import fits_access_decoder
|
|
31
31
|
from dkist_processing_common.codecs.fits import fits_hdulist_encoder
|
|
32
|
+
from dkist_processing_common.models.fried_parameter import r0_valid
|
|
32
33
|
from dkist_processing_common.models.tags import Tag
|
|
33
34
|
from dkist_processing_common.models.wavelength import WavelengthRange
|
|
34
35
|
from dkist_processing_common.parsers.l0_fits_access import L0FitsAccess
|
|
@@ -373,8 +374,14 @@ class WriteL1Frame(WorkflowTaskBase, MetadataStoreMixin, ABC):
|
|
|
373
374
|
"""
|
|
374
375
|
# Replace header values in place
|
|
375
376
|
header = self.replace_header_values(header=header, data=data)
|
|
376
|
-
# Remove r0 value if
|
|
377
|
-
|
|
377
|
+
# Remove r0 value if r0 conditions are not met
|
|
378
|
+
r0_is_valid = r0_valid(
|
|
379
|
+
r0=header["ATMOS_R0"],
|
|
380
|
+
ao_lock=header.get("AO_LOCK", None),
|
|
381
|
+
num_out_of_bounds_ao_values=header.get("OOBSHIFT", None),
|
|
382
|
+
)
|
|
383
|
+
if not r0_is_valid:
|
|
384
|
+
header.pop("ATMOS_R0", None)
|
|
378
385
|
# Add the stats table
|
|
379
386
|
header = self.add_stats_headers(header=header, data=data)
|
|
380
387
|
# Add the datacenter table
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from dkist_processing_common.models.fried_parameter import r0_valid
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@pytest.mark.parametrize(
|
|
7
|
+
"r0, ao_lock, oob_shift, should_r0_exist",
|
|
8
|
+
[
|
|
9
|
+
pytest.param(0.2, True, 17, True, id="AO_LOCK_True_good_R0_good_oob"),
|
|
10
|
+
pytest.param(1, True, 17, False, id="AO_LOCK_True_bad_R0_good_oob"),
|
|
11
|
+
pytest.param(0.2, False, 17, False, id="AO_LOCK_False_good_R0_good_oob"),
|
|
12
|
+
pytest.param(1, False, 17, False, id="AO_LOCK_False_bad_R0_good_oob"),
|
|
13
|
+
pytest.param(0.2, True, 150, False, id="AO_LOCK_True_good_R0_bad_oob"),
|
|
14
|
+
pytest.param(1, True, 150, False, id="AO_LOCK_True_bad_R0_bad_oob"),
|
|
15
|
+
pytest.param(0.2, False, 150, False, id="AO_LOCK_False_good_R0_bad_oob"),
|
|
16
|
+
pytest.param(1, False, 150, False, id="AO_LOCK_False_bad_R0_bad_oob"),
|
|
17
|
+
pytest.param(0.2, None, 17, False, id="AO_LOCK_missing"),
|
|
18
|
+
pytest.param(0.2, True, None, True, id="OOBSHIFT_missing"),
|
|
19
|
+
],
|
|
20
|
+
)
|
|
21
|
+
def test_check_r0_valid(r0, ao_lock, oob_shift, should_r0_exist):
|
|
22
|
+
"""
|
|
23
|
+
:Given: values for r0, the ao_lock status, and the ao out of bound shift value
|
|
24
|
+
:When: checking for a valid state to use r0
|
|
25
|
+
:Then: valid conditions are marked True, invalid conditions marked False
|
|
26
|
+
"""
|
|
27
|
+
assert r0_valid(r0, ao_lock, oob_shift) == should_r0_exist
|
|
@@ -39,9 +39,9 @@ def quality_task(tmp_path, recipe_run_id):
|
|
|
39
39
|
@pytest.fixture
|
|
40
40
|
def plot_data():
|
|
41
41
|
datetimes_a = ["2021-01-01T01:01:01", "2021-01-01T02:01:01"]
|
|
42
|
-
values_a = [
|
|
42
|
+
values_a = [0.1, 0.2]
|
|
43
43
|
datetimes_b = ["2020-01-01T01:01:01", "2020-01-01T02:01:01"]
|
|
44
|
-
values_b = [
|
|
44
|
+
values_b = [0.15, 0.25]
|
|
45
45
|
return datetimes_a, values_a, datetimes_b, values_b
|
|
46
46
|
|
|
47
47
|
|
|
@@ -198,8 +198,9 @@ def test_store_ao_status_and_fried_parameter(quality_task, ao_values):
|
|
|
198
198
|
"""
|
|
199
199
|
task = quality_task
|
|
200
200
|
datetimes = ["2020-01-01T01:01:01", "2020-01-01T02:01:01"]
|
|
201
|
-
fried_values = [
|
|
202
|
-
|
|
201
|
+
fried_values = [0.1, 0.2]
|
|
202
|
+
oob_values = [25, 50]
|
|
203
|
+
combined_values = [[ao, r0, oob] for ao, r0, oob in zip(ao_values, fried_values, oob_values)]
|
|
203
204
|
task.quality_store_ao_status_and_fried_parameter(datetimes=datetimes, values=combined_values)
|
|
204
205
|
path = list(task.read(tags=Tag.quality("AO_STATUS")))
|
|
205
206
|
assert len(path) == 1
|
|
@@ -220,10 +221,11 @@ def test_store_ao_status_and_fried_parameter(quality_task, ao_values):
|
|
|
220
221
|
@pytest.mark.parametrize(
|
|
221
222
|
"combined_values",
|
|
222
223
|
[
|
|
223
|
-
pytest.param([[True, 1], [None, 2]], id="AO_some_none"),
|
|
224
|
-
pytest.param([[True, 1], [True, None]], id="Fried_some_none"),
|
|
225
|
-
pytest.param([[None, 1], [None, 2]], id="AO_all_none"),
|
|
226
|
-
pytest.param([[True, None], [True, None]], id="Fried_all_none"),
|
|
224
|
+
pytest.param([[True, 0.1, 25], [None, 0.2, 25]], id="AO_some_none"),
|
|
225
|
+
pytest.param([[True, 0.1, 25], [True, None, 25]], id="Fried_some_none"),
|
|
226
|
+
pytest.param([[None, 0.1, 25], [None, 0.2, 25]], id="AO_all_none"),
|
|
227
|
+
pytest.param([[True, None, 25], [True, None, 25]], id="Fried_all_none"),
|
|
228
|
+
pytest.param([[True, 0.1, None], [True, 0.2, None]], id="Out_of_bounds_all_none"),
|
|
227
229
|
],
|
|
228
230
|
)
|
|
229
231
|
def test_store_ao_status_and_fried_parameter_with_nones(quality_task, combined_values):
|
|
@@ -231,13 +233,14 @@ def test_store_ao_status_and_fried_parameter_with_nones(quality_task, combined_v
|
|
|
231
233
|
datetimes = ["2020-01-01T01:01:01", "2020-01-01T02:01:01"]
|
|
232
234
|
task.quality_store_ao_status_and_fried_parameter(datetimes=datetimes, values=combined_values)
|
|
233
235
|
path = list(task.read(tags=Tag.quality("AO_STATUS")))
|
|
234
|
-
ao_values = [ao for ao, r0 in combined_values]
|
|
235
|
-
fried_values = [r0 for ao, r0 in combined_values]
|
|
236
|
+
ao_values = [ao for ao, r0, oob in combined_values]
|
|
237
|
+
fried_values = [r0 for ao, r0, oob in combined_values]
|
|
238
|
+
ao_out_of_bounds = [oob for ao, r0, oob in combined_values]
|
|
236
239
|
if not all(ao is None for ao in ao_values):
|
|
237
240
|
assert len(path) == 1
|
|
238
241
|
with path[0].open() as f:
|
|
239
242
|
data = json.load(f)
|
|
240
|
-
assert len(data) == sum(1 for ao, r0 in combined_values if ao is not None)
|
|
243
|
+
assert len(data) == sum(1 for ao, r0, oob in combined_values if ao is not None)
|
|
241
244
|
else:
|
|
242
245
|
assert len(path) == 0
|
|
243
246
|
path = list(task.read(tags=Tag.quality("FRIED_PARAMETER")))
|
|
@@ -246,7 +249,7 @@ def test_store_ao_status_and_fried_parameter_with_nones(quality_task, combined_v
|
|
|
246
249
|
with path[0].open() as f:
|
|
247
250
|
data = json.load(f)
|
|
248
251
|
assert len(data["y_values"]) == sum(
|
|
249
|
-
1 for ao, r0 in combined_values if ao is True and r0 is not None
|
|
252
|
+
1 for ao, r0, oob in combined_values if ao is True and r0 is not None
|
|
250
253
|
)
|
|
251
254
|
else:
|
|
252
255
|
assert len(path) == 0
|
|
@@ -263,7 +266,8 @@ def test_build_ao_status(quality_task, plot_data):
|
|
|
263
266
|
datetimes = datetimes_a + datetimes_b
|
|
264
267
|
fried_values = values_a + values_b
|
|
265
268
|
ao_values = [False, True, True, True]
|
|
266
|
-
|
|
269
|
+
oob_values = [25, 50, None, 50]
|
|
270
|
+
combined_values = [[ao, r0, oob] for ao, r0, oob in zip(ao_values, fried_values, oob_values)]
|
|
267
271
|
task.quality_store_ao_status_and_fried_parameter(datetimes=datetimes, values=combined_values)
|
|
268
272
|
metric = task.quality_build_ao_status()
|
|
269
273
|
assert metric["name"] == "Adaptive Optics Status"
|
|
@@ -284,9 +288,15 @@ def test_build_fried_parameter(quality_task, plot_data):
|
|
|
284
288
|
task = quality_task
|
|
285
289
|
datetimes_a, fried_values_a, datetimes_b, fried_values_b = plot_data
|
|
286
290
|
ao_values_a = [True, True]
|
|
287
|
-
|
|
291
|
+
oob_values_a = [25, 50]
|
|
292
|
+
combined_values_a = [
|
|
293
|
+
[ao, r0, oob] for ao, r0, oob in zip(ao_values_a, fried_values_a, oob_values_a)
|
|
294
|
+
]
|
|
288
295
|
ao_values_b = [True, True]
|
|
289
|
-
|
|
296
|
+
oob_values_b = [25, 50]
|
|
297
|
+
combined_values_b = [
|
|
298
|
+
[ao, r0, oob] for ao, r0, oob in zip(ao_values_b, fried_values_b, oob_values_b)
|
|
299
|
+
]
|
|
290
300
|
task.quality_store_ao_status_and_fried_parameter(
|
|
291
301
|
datetimes=datetimes_a, values=combined_values_a
|
|
292
302
|
)
|
|
@@ -307,14 +317,14 @@ def test_build_fried_parameter(quality_task, plot_data):
|
|
|
307
317
|
"2021-01-01T02:01:01",
|
|
308
318
|
]
|
|
309
319
|
]
|
|
310
|
-
assert metric["plot_data"]["series_data"][""][1] == [
|
|
320
|
+
assert metric["plot_data"]["series_data"][""][1] == [0.15, 0.25, 0.1, 0.2]
|
|
311
321
|
assert metric["name"] == "Fried Parameter"
|
|
312
322
|
assert metric["metric_code"] == "FRIED_PARAMETER"
|
|
313
323
|
assert metric["facet"] is None
|
|
314
324
|
assert metric["warnings"] is None
|
|
315
325
|
assert (
|
|
316
326
|
metric["statement"]
|
|
317
|
-
== "Average valid Fried Parameter measurements for L1 dataset:
|
|
327
|
+
== "Average valid Fried Parameter measurements for L1 dataset: 0.18 ± 0.06 m"
|
|
318
328
|
)
|
|
319
329
|
|
|
320
330
|
|
|
@@ -340,12 +350,12 @@ def test_build_light_level(quality_task, plot_data):
|
|
|
340
350
|
"2021-01-01T02:01:01",
|
|
341
351
|
]
|
|
342
352
|
]
|
|
343
|
-
assert metric["plot_data"]["series_data"][""][1] == [
|
|
353
|
+
assert metric["plot_data"]["series_data"][""][1] == [0.15, 0.25, 0.1, 0.2]
|
|
344
354
|
assert metric["name"] == "Light Level"
|
|
345
355
|
assert metric["metric_code"] == "LIGHT_LEVEL"
|
|
346
356
|
assert metric["facet"] is None
|
|
347
357
|
assert metric["warnings"] is None
|
|
348
|
-
assert metric["statement"] == f"Average Light Level for L1 dataset:
|
|
358
|
+
assert metric["statement"] == f"Average Light Level for L1 dataset: 0.18 ± 0.06 adu"
|
|
349
359
|
|
|
350
360
|
|
|
351
361
|
def test_build_frame_average(quality_task, plot_data):
|
|
@@ -461,7 +471,7 @@ def test_build_noise(quality_task, plot_data):
|
|
|
461
471
|
"2021-01-01T02:01:01",
|
|
462
472
|
]
|
|
463
473
|
]
|
|
464
|
-
assert metric["plot_data"]["series_data"]["I"][1] == [
|
|
474
|
+
assert metric["plot_data"]["series_data"]["I"][1] == [0.15, 0.25, 0.1, 0.2]
|
|
465
475
|
assert metric["name"] == "Noise Estimation"
|
|
466
476
|
assert metric["metric_code"] == "NOISE"
|
|
467
477
|
assert metric["facet"] is None
|
|
@@ -493,7 +503,7 @@ def test_build_sensitivity(quality_task, plot_data):
|
|
|
493
503
|
"2021-01-01T02:01:01",
|
|
494
504
|
]
|
|
495
505
|
]
|
|
496
|
-
assert metric["plot_data"]["series_data"]["I"][1] == [
|
|
506
|
+
assert metric["plot_data"]["series_data"]["I"][1] == [0.15, 0.25, 0.1, 0.2]
|
|
497
507
|
assert metric["name"] == f"Sensitivity"
|
|
498
508
|
assert metric["metric_code"] == "SENSITIVITY"
|
|
499
509
|
assert metric["facet"] is None
|
|
@@ -692,7 +702,7 @@ def test_build_report(quality_task, plot_data):
|
|
|
692
702
|
task.quality_store_task_type_counts(task_type="dark", total_frames=100, frames_not_used=7)
|
|
693
703
|
task.quality_store_task_type_counts(task_type="gain", total_frames=100, frames_not_used=0)
|
|
694
704
|
task.quality_store_ao_status_and_fried_parameter(
|
|
695
|
-
datetimes=datetimes, values=[[True, values[0]], [True, values[1]]]
|
|
705
|
+
datetimes=datetimes, values=[[True, values[0], values[0]], [True, values[1], values[1]]]
|
|
696
706
|
)
|
|
697
707
|
task.quality_store_light_level(datetimes=datetimes, values=values)
|
|
698
708
|
task.quality_store_frame_average(
|
|
@@ -201,9 +201,32 @@ def write_l1_task_with_empty_waveband(recipe_run_id, tmp_path, request):
|
|
|
201
201
|
@pytest.fixture(
|
|
202
202
|
scope="function",
|
|
203
203
|
params=[
|
|
204
|
-
pytest.param(
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
pytest.param(
|
|
205
|
+
{"AO_LOCK": True, "ATMOS_R0": 0.2, "OOBSHIFT": 17}, id="AO_LOCK_True_good_R0_good_oob"
|
|
206
|
+
),
|
|
207
|
+
pytest.param(
|
|
208
|
+
{"AO_LOCK": True, "ATMOS_R0": 1, "OOBSHIFT": 17}, id="AO_LOCK_True_bad_R0_good_oob"
|
|
209
|
+
),
|
|
210
|
+
pytest.param(
|
|
211
|
+
{"AO_LOCK": False, "ATMOS_R0": 0.2, "OOBSHIFT": 17}, id="AO_LOCK_False_good_R0_good_oob"
|
|
212
|
+
),
|
|
213
|
+
pytest.param(
|
|
214
|
+
{"AO_LOCK": False, "ATMOS_R0": 1, "OOBSHIFT": 17}, id="AO_LOCK_False_bad_R0_good_oob"
|
|
215
|
+
),
|
|
216
|
+
pytest.param(
|
|
217
|
+
{"AO_LOCK": True, "ATMOS_R0": 0.2, "OOBSHIFT": 150}, id="AO_LOCK_True_good_R0_bad_oob"
|
|
218
|
+
),
|
|
219
|
+
pytest.param(
|
|
220
|
+
{"AO_LOCK": True, "ATMOS_R0": 1, "OOBSHIFT": 150}, id="AO_LOCK_True_bad_R0_bad_oob"
|
|
221
|
+
),
|
|
222
|
+
pytest.param(
|
|
223
|
+
{"AO_LOCK": False, "ATMOS_R0": 0.2, "OOBSHIFT": 150}, id="AO_LOCK_False_good_R0_bad_oob"
|
|
224
|
+
),
|
|
225
|
+
pytest.param(
|
|
226
|
+
{"AO_LOCK": False, "ATMOS_R0": 1, "OOBSHIFT": 150}, id="AO_LOCK_False_bad_R0_bad_oob"
|
|
227
|
+
),
|
|
228
|
+
pytest.param({"ATMOS_R0": 0.2, "OOBSHIFT": 17}, id="AO_LOCK_missing"),
|
|
229
|
+
pytest.param({"ATMOS_R0": 0.2, "AO_LOCK": True}, id="OOBSHIFT_missing"),
|
|
207
230
|
],
|
|
208
231
|
)
|
|
209
232
|
def write_l1_task_no_data(request, recipe_run_id, tmp_path, complete_common_header):
|
|
@@ -216,10 +239,10 @@ def write_l1_task_no_data(request, recipe_run_id, tmp_path, complete_common_head
|
|
|
216
239
|
):
|
|
217
240
|
task.scratch = WorkflowFileSystem(recipe_run_id=recipe_run_id, scratch_base_path=tmp_path)
|
|
218
241
|
header = complete_common_header
|
|
219
|
-
header.pop("AO_LOCK", None)
|
|
242
|
+
header.pop("AO_LOCK", None)
|
|
243
|
+
header.pop("ATMOS_R0", None)
|
|
244
|
+
header.pop("OOBSHIFT", None)
|
|
220
245
|
header.update(request.param)
|
|
221
|
-
fried_parameter = 0.2
|
|
222
|
-
header["ATMOS_R0"] = fried_parameter
|
|
223
246
|
hdu = fits.PrimaryHDU(data=np.random.random(size=(1, 1, 1)) * 1, header=header)
|
|
224
247
|
hdul = fits.HDUList([hdu])
|
|
225
248
|
task.write(
|
|
@@ -231,7 +254,9 @@ def write_l1_task_no_data(request, recipe_run_id, tmp_path, complete_common_head
|
|
|
231
254
|
encoder=fits_hdulist_encoder,
|
|
232
255
|
)
|
|
233
256
|
task.constants._update(asdict(FakeConstantDb()))
|
|
234
|
-
|
|
257
|
+
fried_parameter = request.param["ATMOS_R0"]
|
|
258
|
+
oob_shift = request.param.get("OOBSHIFT")
|
|
259
|
+
yield task, header, fried_parameter, oob_shift
|
|
235
260
|
task._purge()
|
|
236
261
|
|
|
237
262
|
|
|
@@ -650,7 +675,7 @@ def test_check_r0_ao_lock(write_l1_task_no_data):
|
|
|
650
675
|
:When: writing, check if the AO lock is on
|
|
651
676
|
:Then: write the r0 value if AO lock on, don't write if AO lock off
|
|
652
677
|
"""
|
|
653
|
-
task, header, r0 = write_l1_task_no_data
|
|
678
|
+
task, header, r0, _ = write_l1_task_no_data
|
|
654
679
|
header_after_check = task.remove_invalid_r0_values(header=header)
|
|
655
680
|
if header.get("AO_LOCK"):
|
|
656
681
|
assert header_after_check["ATMOS_R0"] == header["ATMOS_R0"]
|
|
@@ -35,6 +35,7 @@ dkist_processing_common/models/__init__.py
|
|
|
35
35
|
dkist_processing_common/models/constants.py
|
|
36
36
|
dkist_processing_common/models/fits_access.py
|
|
37
37
|
dkist_processing_common/models/flower_pot.py
|
|
38
|
+
dkist_processing_common/models/fried_parameter.py
|
|
38
39
|
dkist_processing_common/models/graphql.py
|
|
39
40
|
dkist_processing_common/models/message.py
|
|
40
41
|
dkist_processing_common/models/message_queue_binding.py
|
|
@@ -91,6 +92,7 @@ dkist_processing_common/tests/test_constants.py
|
|
|
91
92
|
dkist_processing_common/tests/test_cs_step.py
|
|
92
93
|
dkist_processing_common/tests/test_fits_access.py
|
|
93
94
|
dkist_processing_common/tests/test_flower_pot.py
|
|
95
|
+
dkist_processing_common/tests/test_fried_parameter.py
|
|
94
96
|
dkist_processing_common/tests/test_input_dataset.py
|
|
95
97
|
dkist_processing_common/tests/test_interservice_bus.py
|
|
96
98
|
dkist_processing_common/tests/test_interservice_bus_mixin.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dkist_processing_common-10.8.2 → dkist_processing_common-10.8.3}/dkist_processing_common/manual.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|