Skip to content

Commit dd80c38

Browse files
authored
Merge branch 'isce-framework:develop' into develop
2 parents 6e7e9d1 + fecf943 commit dd80c38

File tree

15 files changed

+188
-94
lines changed

15 files changed

+188
-94
lines changed

cxx/isce3/geometry/Topo.cpp

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "Topo.h"
22

33
#include <algorithm>
4+
#include <cassert>
45
#include <chrono>
56
#include <cmath>
67
#include <cstdio>
@@ -179,59 +180,76 @@ topo(Raster & demRaster, TopoLayers & layers)
179180
// Allocate vector for storing satellite position for each line
180181
std::vector<Vec3> satPosition(blockLength);
181182

182-
// For each line in block
183-
double tline;
184-
for (size_t blockLine = 0; blockLine < blockLength; ++blockLine) {
185-
186-
if (blockLine % std::max((int) (blockLength / 100), 1) == 0)
187-
printf("\rTopo progress (block %d/%d): %d%%",
188-
(int) block + 1, (int) nBlocks,
189-
(int) (blockLine * 1e2 / blockLength)),
190-
fflush(stdout);
191-
192-
// Global line index
193-
size_t line = lineStart + blockLine;
194-
195-
// Initialize orbital data for this azimuth line
196-
Basis TCNbasis;
197-
Vec3 pos, vel;
198-
_initAzimuthLine(line, tline, pos, vel, TCNbasis);
199-
200-
satPosition[blockLine] = pos;
201-
202-
// Compute velocity magnitude
203-
const double satVmag = vel.norm();
204-
205-
// For each slant range bin
206-
#pragma omp parallel for reduction(+:totalconv)
207-
for (size_t rbin = 0; rbin < _radarGrid.width(); ++rbin) {
208-
209-
// Get current slant range
210-
const double rng = _radarGrid.slantRange(rbin);
211-
212-
// Get current Doppler value
213-
const double dopfact = (0.5 * _radarGrid.wavelength()
214-
* (_doppler.eval(tline, rng) / satVmag)) * rng;
215-
216-
// Store slant range bin data in Pixel
217-
Pixel pixel(rng, dopfact, rbin);
218-
219-
// Initialize LLH to middle of input DEM and average height
220-
Vec3 llh = demInterp.midLonLat();
221-
222-
// Perform rdr->geo iterations
223-
int geostat = rdr2geo(
224-
pixel, TCNbasis, pos, vel, _ellipsoid, demInterp, llh,
225-
_radarGrid.lookSide(), _threshold, _numiter, _extraiter);
226-
totalconv += geostat;
227-
228-
// Save data in output arrays
229-
_setOutputTopoLayers(llh, layers, blockLine, pixel, pos, vel,
230-
TCNbasis, demInterp);
183+
// Get the midpoint of the DEM block in LLH coordinates.
184+
// This should always be safe since the call to `computeDEMBounds()`
185+
// above loads a block of the DEM raster.
186+
assert(demInterp.haveRaster());
187+
const auto dem_midpoint = demInterp.midLonLat();
188+
189+
#pragma omp parallel
190+
{
191+
// Thread-local count of the total number of rdr2geo calls that
192+
// converged successfully.
193+
size_t totalconv_thread = 0;
194+
195+
// For each line in block
196+
#pragma omp for
197+
for (size_t blockLine = 0; blockLine < blockLength; ++blockLine) {
198+
// Global line index
199+
size_t line = lineStart + blockLine;
200+
201+
// Initialize orbital data for this azimuth line
202+
Basis TCNbasis;
203+
double tline;
204+
Vec3 pos, vel;
205+
_initAzimuthLine(line, tline, pos, vel, TCNbasis);
206+
207+
satPosition[blockLine] = pos;
208+
209+
// Compute velocity magnitude
210+
const double satVmag = vel.norm();
211+
212+
// Initialize LLH to middle of input DEM block and average height.
213+
auto llh = dem_midpoint;
214+
215+
for (size_t rbin = 0; rbin < _radarGrid.width(); ++rbin) {
216+
217+
// Get current slant range
218+
const double rng = _radarGrid.slantRange(rbin);
219+
220+
// Get current Doppler value
221+
const double dopfact = (0.5 * _radarGrid.wavelength()
222+
* (_doppler.eval(tline, rng) / satVmag))
223+
* rng;
224+
225+
// Store slant range bin data in Pixel
226+
Pixel pixel(rng, dopfact, rbin);
227+
228+
// Perform rdr->geo iterations
229+
int geostat = rdr2geo(
230+
pixel, TCNbasis, pos, vel, _ellipsoid, demInterp, llh,
231+
_radarGrid.lookSide(), _threshold, _numiter, _extraiter);
232+
totalconv_thread += geostat;
233+
234+
// Save data in output arrays
235+
_setOutputTopoLayers(llh, layers, blockLine, pixel, pos, vel,
236+
TCNbasis, demInterp);
237+
238+
// If rdr2geo failed to converge, re-initialize the LLH estimate for
239+
// the next iteration. Otherwise, reuse the current solution as the
240+
// initial guess for the next range bin.
241+
if (geostat == 0) {
242+
llh = dem_midpoint;
243+
}
244+
}
245+
}
231246

232-
} // end OMP for loop pixels in block
233-
} // end for loop lines in block
234-
printf("\rTopo progress (block %d/%d): 100%%\n",
247+
// Collect the total number of converged rdr2geo calls from among all
248+
// threads.
249+
#pragma omp atomic
250+
totalconv += totalconv_thread;
251+
}
252+
printf("\rTopo progress (block %d/%d): Done\n",
235253
(int) block + 1, (int) nBlocks), fflush(stdout);
236254

237255
// Compute layover/shadow masks for the block
@@ -447,9 +465,9 @@ computeDEMBounds(Raster & demRaster, DEMInterpolator & demInterp, size_t lineOff
447465
}
448466

449467
void isce3::geometry::Topo::
450-
_setOutputTopoLayers(Vec3 & targetLLH, TopoLayers & layers, size_t line,
451-
Pixel & pixel, Vec3& pos, Vec3& vel, Basis & TCNbasis,
452-
DEMInterpolator & demInterp)
468+
_setOutputTopoLayers(const Vec3& targetLLH, TopoLayers & layers, size_t line,
469+
const Pixel& pixel, const Vec3& pos, const Vec3& vel,
470+
const Basis& TCNbasis, const DEMInterpolator& demInterp)
453471
{
454472
const double degrees = 180.0 / M_PI;
455473

cxx/isce3/geometry/Topo.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -305,14 +305,14 @@ class isce3::geometry::Topo {
305305
* @param[in] TCNbasis basis for the line under consideration
306306
* @param[in] demInterp DEM interpolator object used to compute local slope
307307
*/
308-
void _setOutputTopoLayers(isce3::core::Vec3 &,
309-
TopoLayers &,
310-
size_t,
311-
isce3::core::Pixel &,
312-
isce3::core::Vec3& pos,
313-
isce3::core::Vec3& vel,
314-
isce3::core::Basis &,
315-
DEMInterpolator &);
308+
void _setOutputTopoLayers(const isce3::core::Vec3& llh,
309+
TopoLayers& layers,
310+
size_t line,
311+
const isce3::core::Pixel& pixel,
312+
const isce3::core::Vec3& pos,
313+
const isce3::core::Vec3& vel,
314+
const isce3::core::Basis& TCNbasis,
315+
const DEMInterpolator& demInterp);
316316

317317
/** Main entry point for the module; internal creation of topo rasters */
318318
template<typename T> void _topo(T& dem, const std::string& outdir);

python/extensions/pybind_isce3/geometry/rdr2geo.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,13 @@ void addbinding(py::class_<Topo>& pyRdr2Geo)
229229
(meters or degrees)
230230
height_raster: isce3.io.Raster
231231
Output raster for height above ellipsoid (meters)
232-
incidence_raster: isce3.io.Raster
232+
incidence_angle_raster: isce3.io.Raster
233233
Output raster for incidence angle (degrees) computed from vertical
234234
at target
235235
heading_angle_raster: isce3.io.Raster
236236
Output raster for azimuth angle (degrees) computed anti-clockwise
237237
from EAST (Right hand rule)
238-
local_incidence_raster: isce3.io.Raster
238+
local_incidence_angle_raster: isce3.io.Raster
239239
Output raster for local incidence angle (degrees) at target
240240
local_psi_raster: isce3.io.Raster
241241
Output raster for local projection angle (degrees) at target

python/packages/nisar/products/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@
1111
populate_dataset_attrs_from_spec,
1212
)
1313
from .projection import build_projection_dataset_attrs_dict
14+
from .utils import get_static_layers_data_access

python/packages/nisar/products/utils.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import numpy as np
44
from numpy.typing import ArrayLike
5+
import journal
56

67

78
def to_bytes(s: str | ArrayLike) -> np.ndarray:
@@ -16,4 +17,60 @@ def to_bytes(s: str | ArrayLike) -> np.ndarray:
1617
numpy.ndarray
1718
The input string(s) converted to bytestrings with 'utf-8' encoding.
1819
"""
19-
return np.char.encode(s, encoding="utf-8")
20+
return np.char.encode(s, encoding="utf-8")
21+
22+
23+
def get_static_layers_data_access(
24+
static_layers_data_access_template: str | None,
25+
granule_id: str | None) -> str:
26+
"""
27+
Read the static layers data access template and replace the placeholder
28+
"{granule_id}" with the granule ID, if provided.
29+
30+
Parameters
31+
----------
32+
static_layers_data_access_template: str or None
33+
Template string for static layers data access. If the string contains
34+
the substring "{granule_id}", that substring will be replaced with
35+
the contents of `granule_id`.
36+
If set to `None` or an empty string, the function returns
37+
"(NOT SPECIFIED)"
38+
If the string is valid, i.e., it is not `None` or an empty string,
39+
and it does not contain the substring "{granule_id}", then
40+
`granule_id` is ignored.
41+
granule_id: str or None
42+
The granule ID, which will be used to replace the substring
43+
"{granule_id}" in `static_layers_data_access_template`.
44+
If the template string contains "{granule_id}", but `granule_id` is
45+
`None`, empty string, or "(NOT SPECIFIED)", the function raises an
46+
error.
47+
48+
Returns
49+
-------
50+
static_layers_data_access: str
51+
The static layers data access string with "{granule_id}" placeholder
52+
replaced. Returns "(NOT SPECIFIED)" if
53+
`static_layers_data_access_template` is `None` or an empty
54+
string.
55+
"""
56+
57+
if not static_layers_data_access_template:
58+
return '(NOT SPECIFIED)'
59+
60+
static_layers_data_access = static_layers_data_access_template
61+
62+
if '{granule_id}' in static_layers_data_access_template:
63+
if not granule_id or granule_id == '(NOT SPECIFIED)':
64+
error_msg = ('The placeholder "{granule_id}" is included in'
65+
' the static layers data access template,'
66+
' but the `granule_id` was not provided'
67+
" or is invalid")
68+
error_channel = journal.error('get_static_layers_data_access')
69+
error_channel.log(error_msg)
70+
raise ValueError(error_msg)
71+
72+
static_layers_data_access = \
73+
static_layers_data_access_template.replace('{granule_id}',
74+
granule_id)
75+
76+
return static_layers_data_access

python/packages/nisar/products/writers/BaseL2WriterSingleInput.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from isce3.core.types import truncate_mantissa
1212
from isce3.geometry import get_near_and_far_range_incidence_angles
1313
from nisar.products.readers.orbit import load_orbit
14+
from nisar.products.utils import get_static_layers_data_access
1415

1516

1617
LEXICOGRAPHIC_BASE_POLS = ['HH', 'HV', 'VH', 'VV']
@@ -808,12 +809,17 @@ def populate_identification_l2_specific(self):
808809
'identification/platformName',
809810
default='(NOT SPECIFIED)')
810811

811-
def populate_ceos_analysis_ready_data_parameters_l2_common(self):
812+
static_layers_data_access_runconfig = \
813+
self.cfg['primary_executable']['static_layers_data_access']
812814

813-
self.copy_from_runconfig(
814-
'{PRODUCT}/metadata/ceosAnalysisReadyData/staticLayersDataAccess',
815-
'ceos_analysis_ready_data/static_layers_data_access',
816-
default='(NOT SPECIFIED)')
815+
static_layers_data_access = get_static_layers_data_access(
816+
static_layers_data_access_runconfig, self.granule_id)
817+
818+
self.set_value(
819+
'identification/staticLayersDataAccess',
820+
static_layers_data_access)
821+
822+
def populate_ceos_analysis_ready_data_parameters_l2_common(self):
817823

818824
ceos_ard_document_identifier = \
819825
('https://ceos.org/ard/files/PFS/SAR/v1.0/CEOS-ARD_PFS'

share/nisar/defaults/gcov.yaml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ runconfig:
134134
# the corresponding metadata field will be set to "(NOT SPECIFIED)".
135135
product_doi:
136136

137+
# Data access for the static layers product associated with the
138+
# output product (URL or DOI). If not provided, the corresponding
139+
# metadata field will be set to "(NOT SPECIFIED)".
140+
# If this string contains the substring "{granule_id}", that substring
141+
# will be replaced with the granule ID.
142+
static_layers_data_access:
143+
137144
# Composite release ID (CRID). If not provided, the corresponding
138145
# metadata field will be set to b'A10000'.
139146
composite_release_id:
@@ -547,10 +554,6 @@ runconfig:
547554
# to populate the output product's metadata
548555
ceos_analysis_ready_data:
549556

550-
# NOT YET IMPLEMENTED
551-
# Data access for the static layers product associated with the output product (URL or DOI)
552-
static_layers_data_access:
553-
554557
# Estimated geometric accuracy (bias and standard deviation)
555558
# in meters in the X- and Y-directions over the coordinate
556559
# system defined by the product's EPSG code

share/nisar/defaults/gslc.yaml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ runconfig:
6767
product_type: GSLC
6868
product_version: 0.1.0
6969
product_doi:
70+
71+
# Data access for the static layers product associated with the
72+
# output product (URL or DOI). If not provided, the corresponding
73+
# metadata field will be set to "(NOT SPECIFIED)".
74+
# If this string contains the substring "{granule_id}", that substring
75+
# will be replaced with the granule ID.
76+
static_layers_data_access:
77+
7078
composite_release_id:
7179
processing_type:
7280
processing_center:
@@ -327,10 +335,6 @@ runconfig:
327335
# to populate the output product's metadata
328336
ceos_analysis_ready_data:
329337

330-
# NOT YET IMPLEMENTED
331-
# Data access for the static layers product associated with the output product (URL or DOI)
332-
static_layers_data_access:
333-
334338
# Estimated geometric accuracy (bias and standard deviation)
335339
# in meters in the X- and Y-directions over the coordinate
336340
# system defined by the product's EPSG code

share/nisar/schemas/gcov.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ runconfig:
6262
product_type: enum('GCOV')
6363
product_version: str('^\d+\.\d+\.\d+$', required=False)
6464
product_doi: str(required=False)
65+
66+
# Data access for the static layers product associated with the output
67+
# product (URL or DOI)
68+
static_layers_data_access: str(required=False)
69+
6570
composite_release_id: regex(r'\w\d\d\d\d\d', name='CRID', required=False)
6671
processing_type: enum('PR', 'UR', 'OD', required=False)
6772
product_accuracy: enum('P', 'M', 'N', 'F', required=False)
@@ -537,11 +542,6 @@ geocode_options:
537542

538543
ceos_analysis_ready_data_options:
539544

540-
# NOT YET IMPLEMENTED
541-
# Data access for the static layers product associated with the output
542-
# product (URL or DOI)
543-
static_layers_data_access: str(required=False)
544-
545545
# Estimated geometric accuracy (bias and standard deviation)
546546
# in meters in the X- and Y-directions over the coordinate
547547
# system defined by the product's EPSG code

share/nisar/schemas/gslc.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ runconfig:
6363
product_type: enum('GSLC')
6464
product_version: str('^\d+\.\d+\.\d+$', required=False)
6565
product_doi: str(required=False)
66+
67+
# Data access for the static layers product associated with the output
68+
# product (URL or DOI)
69+
static_layers_data_access: str(required=False)
70+
6671
composite_release_id: regex(r'\w\d\d\d\d\d', name='CRID', required=False)
6772
processing_type: enum('PR', 'UR', 'OD', required=False)
6873
product_accuracy: enum('P', 'M', 'N', 'F', required=False)
@@ -302,10 +307,6 @@ geocode_options:
302307

303308
ceos_analysis_ready_data_options:
304309

305-
# NOT YET IMPLEMENTED
306-
# Data access for the static layers product associated with the output product (URL or DOI)
307-
static_layers_data_access: str(required=False)
308-
309310
# Estimated geometric accuracy (bias and standard deviation)
310311
# in meters in the X- and Y-directions over the coordinate
311312
# system defined by the product's EPSG code

0 commit comments

Comments
 (0)