-
Notifications
You must be signed in to change notification settings - Fork 12
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
Fix track number/burst id calculation #77
Conversation
scripts helped make very small version, orbits manually shrunk
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.
@scottstanie thanks a lot for this PR. This is so crucial to make the CSLC-S1 workflow to properly work with the TrackFrame database.
My main concern with this PR is related to the unit test. It seems that you are trying to upload a bunch of small file in the repository to make the unit test to run. If I am not mistaken, we decided to avoid going down this route. Our best option would be to store the data on zenodo
, download them on the CI, run the unit tests. @LiangJYu and @rtburns-jpl might help you along the way.
If the above is correct, I recommend:
- Submit the unit test in a separate PR. You might need some time to set up the repository on
zenodo
and having the test running on the CI - Include a README file together with the data downloaded for the unit test. This should describe the source of the data, the region covered, what files they contain and why they have been selected for the unit test
@@ -652,8 +652,9 @@ def eap_compensation_lut(self): | |||
f' IPF version = {self.ipf_version}') | |||
|
|||
return self.burst_eap.compute_eap_compensation_lut(self.width) | |||
def bbox(self): |
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.
Any particular reason why we are removing this function?
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 removed this once I realized why the border
was a list of Polygon's, when it seemed like it was always a list of one single Polygon: opera-adt/burst_db#1
the anti-meridian crossing bursts (international date line) have two polygons, since it's conventional to split the latlon that way, so this function is giving an incorrect bbox for those ones. I can leave it in and submit an issue to correct it in the future if you'd like.
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.
fixing it might be as simple as
return shapely.geometry.MultiPolygon(b.border).bounds
as long as we don't care that it returns longitudes greater than 180:
In [5]: b = s1reader.load_bursts('S1A_IW_SLC__1SDV_20220110T181913_20220110T181938_041402_04EC40_E2D9.zip', None, 1)[0]
In [6]: b.border
Out[6]: [<shapely.geometry.polygon.Polygon object at 0x7fadef947670>, <shapely.geometry.polygon.Polygon object at 0x7fadef944d00>]
In [8]: b.border[0].bounds
Out[8]: (180.0, 52.19675210021637, 180.6997402722514, 52.44622930532407)
In [11]: import shapely.geometry
In [12]: shapely.geometry.MultiPolygon(b.border).bounds
Out[12]: (179.3998234765543, 52.19675210021637, 180.6997402722514, 52.50961732430616)
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.
Let's submit an issue separately. We do not want to have longitudes greater than 180 (if this is the only fix)
src/s1reader/s1_reader.py
Outdated
@@ -860,9 +850,106 @@ def _burst_from_safe_dir(safe_dir_path: str, id_str: str, orbit_path: str, flag_ | |||
else: | |||
msg = f'measurement directory NOT found in {safe_dir_path}' | |||
msg += ', continue with metadata only.' | |||
print(msg) | |||
# print(msg) |
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.
Is it intentional to have a comment here? Don't you want to just print the message for debugging purposes?
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.
ah sorry, I had turned this off while downloading the cycle of metadata so it didn't print the message 3 * 10 * (number of frames in a cycle) times. I'll turn it back on, but it would be nice to have it be a .debug
logging message once we switch in python logging or do #25
src/s1reader/s1_reader.py
Outdated
Relative orbit number at the start of the acquisition, from 1-175. | ||
end_track : int | ||
Relative orbit number at the end of the acquisition. | ||
subswath_name : str, {'IW1', 'IW2', 'IW3'} |
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.
Is this case-sensitive?
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.
nope, and I'll add a comment saying so
src/s1reader/s1_reader.py
Outdated
ESA Sentinel-1 Level 1 Detailed Algorithm Definition | ||
https://sentinels.copernicus.eu/documents/247904/1877131/S1-TN-MDA-52-7445_Sentinel-1+Level+1+Detailed+Algorithm+Definition_v2-4.pdf/83624863-6429-cfb8-2371-5c5ca82907b8 | ||
""" | ||
# Constants in Table 9-7 |
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.
Wondering again whether we should have a separate file in the repository where to insert all the constants
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.
Same comment here- I can move these to a constants file if you'd like, but i'm unsure if the constants would be easier to interpret if they're moved away from function that uses them. If we're planning on making a big constants.py
then I can start with these
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 don't think there's enough for a dedicated constants file. From a quick glance, I didn't see anything beyond 3 constants below in the repo.
What do you about moving get_burst_id
into its own file? A s1_burst_id.py
that's something like the following (some inspiration from):
from typing import ClassVar
from dataclasses import dataclass
@dataclass
class S1BurstID:
T_beam: ClassVar[float] = 2.758273 # interval of one burst [s]
T_pre: ClassVar[float] = 2.299849 # Preamble time interval [s]
T_orb: ClassVar[float] = 12 * 24 * 3600 / 175 # Nominal orbit period [s]
track_number: int
esa_burst_id: int
subswath_name: str
@classmethod
def params_to_id(cls,
sensing_time: datetime.datetime,
ascending_node_dt: datetime.datetime,
start_track: int,
end_track: int,
subswath_name: str):
# do same computations
return cls(track_numer, esa_burst_id, subswath)
@property
def as_str(self):
return f"t{self.track_number:03d}_{self.esa_burst_id:06d}_{self.subswath_name.lower()}"
We can then change this from str
to S1BurstID
Benefits:
- By importing this module, all the constants as accessible a class properties.
- Clearer way to import and generate JPL S1 burst IDs without having to dig through
s1_reader.py
.
tests/data/README.md
Outdated
@@ -0,0 +1,33 @@ | |||
- `make_empty_safe.sf` converts a full SDV SAFE folder into a 2.1 Mb folder of 1 vv-polarization annotation files. | |||
- `make_empty_img.py` Converts a measurement/ .tiff file into an all-zeros file < 50kb using SPARSE_OK=TRUE. |
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.
Not sure if it is intentional, but I do see that this PR is trying to upload a lot of files into the repository. @LiangJYu can correct me if I am wrong, but I thought we decided to upload all the test data on zenodo.org
in order to avoid increasing the size of the s1-reader repo. If this is the case, I would recommend to submit the unit test in a separate PR as this would require some more work (i.e. data uploading, set the CI) and we desperately need this PR for our CSLC-S1 Beta delivery
@@ -1 +1 @@ | |||
include src/s1reader/data/sentinel1_track_burst_id.txt | |||
recursive-include src/s1reader/data/ * |
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.
As a note: this will fix #85 by including all the files in the data folder
tests/create_esa_db_sample.py
Outdated
@@ -0,0 +1,47 @@ | |||
import pandas as pd |
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.
Not sure if pandas
is included in the dependency for s1-reader
?
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.
ok i'll keep that in mind for the other PR that I moved these test scripts to 👍
src/s1reader/s1_reader.py
Outdated
has_anx_crossing = (end_track == start_track + 1) or ( | ||
end_track == 1 and start_track == 175 | ||
) |
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.
has_anx_crossing = (end_track == start_track + 1) or ( | |
end_track == 1 and start_track == 175 | |
) | |
has_anx_crossing = (end_track == (start_track + 1) % 175) |
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.
haha I think i waffled back and forth between whether the modulo was clearer or the other one. i'll change to the modulo version
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.
(idk why i changed it back from this commit https://github.com/opera-adt/s1-reader/blob/dba751c6247481ebc5531ffaf11566bd03a25d34/src/s1reader/s1_reader.py#L890 )
------- | ||
str | ||
Search path to extract from the ET of the manifest.safe XML. | ||
|
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.
Nice improvement of the function!
Please add description for the returning namespace nsmap
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.
good idea, i added a comment and a link to the lxml document where it came from
src/s1reader/s1_reader.py
Outdated
ESA Sentinel-1 Level 1 Detailed Algorithm Definition | ||
https://sentinels.copernicus.eu/documents/247904/1877131/S1-TN-MDA-52-7445_Sentinel-1+Level+1+Detailed+Algorithm+Definition_v2-4.pdf/83624863-6429-cfb8-2371-5c5ca82907b8 | ||
""" | ||
# Constants in Table 9-7 |
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 don't think there's enough for a dedicated constants file. From a quick glance, I didn't see anything beyond 3 constants below in the repo.
What do you about moving get_burst_id
into its own file? A s1_burst_id.py
that's something like the following (some inspiration from):
from typing import ClassVar
from dataclasses import dataclass
@dataclass
class S1BurstID:
T_beam: ClassVar[float] = 2.758273 # interval of one burst [s]
T_pre: ClassVar[float] = 2.299849 # Preamble time interval [s]
T_orb: ClassVar[float] = 12 * 24 * 3600 / 175 # Nominal orbit period [s]
track_number: int
esa_burst_id: int
subswath_name: str
@classmethod
def params_to_id(cls,
sensing_time: datetime.datetime,
ascending_node_dt: datetime.datetime,
start_track: int,
end_track: int,
subswath_name: str):
# do same computations
return cls(track_numer, esa_burst_id, subswath)
@property
def as_str(self):
return f"t{self.track_number:03d}_{self.esa_burst_id:06d}_{self.subswath_name.lower()}"
We can then change this from str
to S1BurstID
Benefits:
- By importing this module, all the constants as accessible a class properties.
- Clearer way to import and generate JPL S1 burst IDs without having to dig through
s1_reader.py
.
@LiangJYu the new module is up, where you make the we'll have to change this bit in COMPASS to |
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.
LGTM. Really nice changes/additions to s1-reader!
also, perhaps I should open an issue in RTC for @gshiroma for the same small fix once this is merged in: https://github.com/opera-adt/RTC/blob/93c3118ea4cb91058c4afc0a9e410444b038a57f/src/rtc/runconfig.py#L428 which will just have to coerce to |
although I actually see one other change to the RTC repo: https://github.com/opera-adt/RTC/blob/cf04dc7ff68f559d3fa56605321c312a144b3e7b/src/rtc/h5_prep.py#L144 @LiangJYu do you think
def split(sep=None, maxsplit=-1):
return str(self).split(sep, maxsplit)
|
With regards to the RTC code, I think it would be clearer if it What other string methods were you think about besides |
i didn't have any others; I was just checking thoughts on trying to not break other code now that are expected it to be a string, vs. having everyone switch to use the new object |
Thank you, @scottstanie and @LiangJYu ! No problem if you guys decide to go ahead and make |
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.
@scottstanie Thanks for having addressed my comments. I have no comment left at this stage :). Nice work.
This PR implements several fixes to our burst id naming scheme:
For (1), We can double check our work with the manifest.safe file. In a crossing, theres two relativeOrbitNumbers:
For (2), i'm using the Sentinel-1 Level 1 Detailed Algorithm Definition section 9.25
I've also added 2 test data cases, where I included some scripts to shrink down the real data.
One note: the current test was one where the burst ids we were making were incorrect.
before:
expected_burst_id = f't071_{151200 + i}_iw3'
I have added a small sample of the ESA burst database with their geometries. I added a test that compares the overlap to make sure our id matches theirs.