-
Notifications
You must be signed in to change notification settings - Fork 26
-
Notifications
You must be signed in to change notification settings - Fork 26
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
Improve readability of quality indicators bit unpacking #60
Comments
I agree that the current implementation is not well documented, but I still find it easier to read than the numpy magic involved in the proposed alternative. I'd be ok with just adding a nice docstring to the current method. Any other opinions? |
@carloshorn @sfinkens I agree with Stephan. We can just update the documentation about it. I saw what you suggested @carloshorn and I have to admit, it felt like a numpy magic trick to me as well ;-) But again, it is a matter of getting used to it, I guess. |
The thing is that when the developer sees the bitwise shifting in its current implementation, it is easy to relate it to the POD/KLM documentation. @carloshorn Do you see any reason the current implementation might break under certain circumstances? If so, then we should definitely fix it. |
I find the magic trick impressive, though 🙂 |
I prefer self explanatory code which does not require a relation to a documentation by giving all information through object names and comment lines if necessary. When I saw the selected example code for the first time, I was scared by the bit shifting and hard coded numbers. The second look revealed that it was the bit swiping for a 32 bit integer, but I would not say that this is obvious to everybody. |
Regarding unpackbits: the problem I see is that it will eat up 8 times more memory than the packed array, so I'd rather keep the bitshifting logic. from enum import Enum
class QFlags(Enum):
FATAL_FLAG = 0 # Data should not be used for product generation
CALIBRATION = 4 # Insufficient data for calibration
NO_EARTH_LOCATION = 5 # Earth location data not available
def _get_corrupt_mask(self, flags=[QFlags.FATAL_FLAG, QFlags.CALIBRATION, QFlags.NO_EARTH_LOCATION]):
"""Get mask for corrupt scanlines."""
mask = None
for flag in flags:
if mask is None:
mask = (self.scans['quality_indicators'] << flag) >> 31
else:
mask |= (self.scans['quality_indicators'] << flag) >> 31
return mask.astype(bool) |
Ah, I didn't see your last answer @carloshorn before I posted my answer. But it looks like we are thinking alike in the end :) |
@carloshorn I see your good point about self-explanatory code. Makes sense. I like your last suggestion. Thanks. |
Sounds good! |
I actually though of a more efficient implementation last night: from enum import IntFlag
class QFlag(IntFlag):
FATAL_FLAG = 2**0 # Data should not be used for product generation
CALIBRATION = 2**4 # Insufficient data for calibration
NO_EARTH_LOCATION = 2**5 # Earth location data not available
def _get_corrupt_mask(self, flags=QFlag.FATAL_FLAG | QFlag.CALIBRATION | QFlag.NO_EARTH_LOCATION):
"""Get mask for corrupt scanlines.
*flags* is the ORed bitmask that defines corrupt values, by default it is:
QFlag.FATAL_FLAG | QFlag.CALIBRATION | QFlag.NO_EARTH_LOCATION
"""
return (self.scans['quality_indicators'] & flags.value).astype(bool) This is more efficient because we perform only one boolean operation with the array. |
That looks good as well. Thanks. |
I like the use of IntFlag for the pod/klm specific bit mapping and I appreciate the re-usability of the method. A good candidate would be: Lines 489 to 499 in 2d7fbaf
To me it appears natural to move the generalised method to the parent class ( Reader ) and set QFlag as attribute in the children.
def _get_corrupt_mask(self, flags=None):
"""Get mask for corrupt scanlines.
*flags* is the ORed bitmask that defines corrupt values, by default it is:
QFlag.FATAL_FLAG | QFlag.CALIBRATION | QFlag.NO_EARTH_LOCATION
"""
if flags is None:
flags = self.QFlag.FATAL_FLAG | self.QFlag.CALIBRATION | self.QFlag.NO_EARTH_LOCATION
return (self.scans['quality_indicators'] & flags.value).astype(bool)
I agree, in detail, the efficiency results from not allocating "throwaway"-arrays. |
Excellent! |
Sounds good @carloshorn! |
The current reader access to the quality indicators bit field, e.g.
pygac/pygac/pod_reader.py
Lines 482 to 487 in 2d7fbaf
See #55 (comment) for an implementation proposal.
The text was updated successfully, but these errors were encountered: