Skip to content

Commit

Permalink
Merge pull request #68 from gshiroma/changes_after_calval_point_relea…
Browse files Browse the repository at this point in the history
…se_4

Changes after calval point release 4
  • Loading branch information
gshiroma authored Aug 28, 2023
2 parents b4baa49 + a30d267 commit e1bd926
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/rtc/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ def check_ancillary_inputs(check_ancillary_inputs_coverage,
if flag_1_ok and flag_2_ok:
# print messages to the user
logger.info(f' {coverage_logger_str}:'
' Full (with antimeridian crossing')
' Full (with antimeridian crossing)')

# update RTC-S1 product metadata
metadata_dict[coverage_metadata_str] = \
Expand Down
3 changes: 3 additions & 0 deletions src/rtc/defaults/rtc_s1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ runconfig:
# Location from where the output product can be retrieved (URL or DOI)
product_data_access:

# Location of the static layers product associated with this product (URL or DOI
static_layers_data_access:

# Save RTC-S1 bursts
save_bursts: True

Expand Down
3 changes: 3 additions & 0 deletions src/rtc/defaults/rtc_s1_static.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ runconfig:
# Location from where the output product can be retrieved (URL or DOI)
product_data_access:

# Location of the static layers product associated with this product (URL or DOI
static_layers_data_access:

# Save RTC-S1 bursts
save_bursts: True

Expand Down
29 changes: 26 additions & 3 deletions src/rtc/h5_prep.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,14 +258,20 @@ def create_hdf5_file(product_id, output_hdf5_file, orbit, burst, cfg,

hdf5_obj = h5py.File(output_hdf5_file, 'w')
hdf5_obj.attrs['Conventions'] = np.string_("CF-1.8")
hdf5_obj.attrs["contact"] = np.string_("operaops@jpl.nasa.gov")
hdf5_obj.attrs["contact"] = np.string_("operasds@jpl.nasa.gov")
hdf5_obj.attrs["institution"] = np.string_("NASA JPL")
hdf5_obj.attrs["project"] = np.string_("OPERA")
hdf5_obj.attrs["reference_document"] = np.string_(
"Product Specification Document for the OPERA Radiometric"
" Terrain-Corrected SAR Backscatter from Sentinel-1,"
" JPL D-108758, Rev. Working Version 1, May 31, 2023")
hdf5_obj.attrs["title"] = np.string_("OPERA RTC-S1 Product")
" JPL D-108758, Rev. Working Version 1, Aug 31, 2023")

# product type
product_type = cfg.groups.primary_executable.product_type
if product_type == STATIC_LAYERS_PRODUCT_TYPE:
hdf5_obj.attrs["title"] = np.string_("OPERA RTC-S1-STATIC Product")
else:
hdf5_obj.attrs["title"] = np.string_("OPERA RTC-S1 Product")

populate_metadata_group(product_id, hdf5_obj, burst, cfg,
processing_datetime, is_mosaic)
Expand Down Expand Up @@ -383,6 +389,12 @@ def get_metadata_dict(product_id: str,
if not product_data_access:
product_data_access = '(NOT PROVIDED)'

# static layers data access (URL or DOI)
static_layers_data_access = \
cfg_in.groups.product_group.static_layers_data_access
if not static_layers_data_access:
static_layers_data_access = '(NOT PROVIDED)'

# platform ID
if burst_in.platform_id == 'S1A':
platform_id = 'Sentinel-1A'
Expand Down Expand Up @@ -488,6 +500,11 @@ def get_metadata_dict(product_id: str,
ALL_PRODUCTS,
'NASA JPL',
'Institution that created this product'],
'identification/contactInformation':
['contact_information',
ALL_PRODUCTS,
'[email protected]',
'Contact information for producer of this product'],
'identification/productVersion':
['product_version',
ALL_PRODUCTS,
Expand Down Expand Up @@ -583,6 +600,12 @@ def get_metadata_dict(product_id: str,
product_data_access,
'Location from where this product can be retrieved'
' (URL or DOI)'],
'identification/staticLayersDataAccess':
['static_layers_data_access',
STANDARD_RTC_S1_ONLY,
static_layers_data_access,
'Location of the static layers product associated with this'
' product (URL or DOI)'],
'metadata/sourceData/numberOfAcquisitions': # 1.6.4
['source_data_number_of_acquisitions',
ALL_PRODUCTS,
Expand Down
74 changes: 57 additions & 17 deletions src/rtc/rtc_s1_single_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
BROWSE_IMAGE_MIN_PERCENTILE = 3
BROWSE_IMAGE_MAX_PERCENTILE = 97

FLAG_BROWSE_DUAL_POL_REPEAT_COPOL = True


def populate_product_id(product_id, burst_in, processing_datetime,
product_version, pixel_spacing, product_type,
Expand Down Expand Up @@ -263,6 +265,37 @@ def compute_correction_lut(burst_in, dem_raster, scratch_path,
return rg_lut, az_lut


def _normalize_browse_image_band(band_image):
"""Helper function to normalize a browse image band
Parameters
----------
band_image : np.ndarray
Input image to be normalized
Returns
-------
band_image : np.ndarray
Normalized image
"""
vmin = np.nanpercentile(band_image, BROWSE_IMAGE_MIN_PERCENTILE)
vmax = np.nanpercentile(band_image, BROWSE_IMAGE_MAX_PERCENTILE)
logger.info(f' min ({BROWSE_IMAGE_MIN_PERCENTILE}% percentile):'
f' {vmin}')
logger.info(f' max ({BROWSE_IMAGE_MAX_PERCENTILE}% percentile):'
f' {vmax}')

# gamma correction: 0.5
is_not_negative = band_image - vmin >= 0
is_negative = band_image - vmin < 0
band_image[is_not_negative] = \
np.sqrt((band_image[is_not_negative] - vmin) / (vmax - vmin))
band_image[is_negative] = 0
band_image = np.clip(band_image, 0, 1)
return band_image


def save_browse_imagery(imagery_list, browse_image_filename,
pol_list, browse_image_height, browse_image_width,
temp_files_list, scratch_dir, logger):
Expand Down Expand Up @@ -353,37 +386,44 @@ def save_browse_imagery(imagery_list, browse_image_filename,

gdal_band = gdal_ds.GetRasterBand(1)
band_image = np.asarray(gdal_band.ReadAsArray(), dtype=np.float32)

band_list_index = expected_pol_order.index(pol)

if (n_images == 2 and not FLAG_BROWSE_DUAL_POL_REPEAT_COPOL and
band_list_index == 0):
co_pol_image = band_image.copy()
if (n_images == 2 and not FLAG_BROWSE_DUAL_POL_REPEAT_COPOL and
band_list_index == 1):
cross_pol_image = band_image.copy()

is_valid = np.isfinite(band_image)
if alpha_channel is None:
alpha_channel = np.asarray(is_valid,
dtype=np.float32)
vmin = np.nanpercentile(band_image, BROWSE_IMAGE_MIN_PERCENTILE)
vmax = np.nanpercentile(band_image, BROWSE_IMAGE_MAX_PERCENTILE)
logger.info(f' min ({BROWSE_IMAGE_MIN_PERCENTILE}% percentile):'
f' {vmin}')
logger.info(f' max ({BROWSE_IMAGE_MAX_PERCENTILE}% percentile):'
f' {vmax}')

# gamma correction: 0.5
is_not_negative = np.logical_and(is_valid, band_image - vmin >= 0)
is_negative = np.logical_and(is_valid, band_image - vmin < 0)
band_image[is_not_negative] = \
np.sqrt((band_image[is_not_negative] - vmin) / (vmax - vmin))
band_image[is_negative] = 0
band_image = np.clip(band_image, 0, 1)
band_list_index = expected_pol_order.index(pol)
band_list[band_list_index] = band_image

band_list[band_list_index] = \
_normalize_browse_image_band(band_image)

if n_images == 1:
image = np.dstack((band_list[0],
band_list[0],
band_list[0],
alpha_channel))
elif n_images == 2:
elif n_images == 2 and FLAG_BROWSE_DUAL_POL_REPEAT_COPOL:
image = np.dstack((band_list[0],
band_list[1],
band_list[0],
alpha_channel))
elif n_images == 2:

logger.info(f' pol ratio: {expected_pol_order[0]}/'
f'{expected_pol_order[1]}')
blue_channel = \
_normalize_browse_image_band(co_pol_image / cross_pol_image)
image = np.dstack((band_list[0],
band_list[1],
blue_channel,
alpha_channel))
else:
image = np.dstack((band_list[0],
band_list[1],
Expand Down
3 changes: 3 additions & 0 deletions src/rtc/schemas/rtc_s1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ runconfig:
# Location from where the output product can be retrieved (URL or DOI)
product_data_access: str(required=False)

# Location of the static layers product associated with this product (URL or DOI
static_layers_data_access: str(required=False)

# Save RTC-S1 products
save_bursts: bool(required=False)

Expand Down

0 comments on commit e1bd926

Please sign in to comment.