- Home
- Documentation
- API reference
- Corrections
- hyperproc.correct.cfactor
hyperproc.correct.cfactor¶
Source-derived reference
Generated from the current hyperproc 0.1.2 checkout.
Implementation: hyperproc/correct/cfactor.py. Signatures, defaults, docstrings, and expandable source are extracted statically; the module is not imported or executed. Names beginning with _ are implementation details, not a stable public API.
Use the function signature as the authority for individual parameter defaults and return annotations. Original docstrings sometimes group parameter names or wrap return descriptions across lines; these descriptions are preserved rather than inferred or rewritten.
Exported entry points¶
| Importable name | Definition |
|---|---|
hyperproc.correct.cfactor.band_weights |
hyperproc.correct.cfactor.band_weights |
hyperproc.correct.cfactor.band_map |
hyperproc.correct.cfactor.band_map |
hyperproc.correct.cfactor.model_reflectance |
hyperproc.correct.cfactor.model_reflectance |
hyperproc.correct.cfactor.c_factor |
hyperproc.correct.cfactor.c_factor |
hyperproc.correct.cfactor.nbar |
hyperproc.correct.cfactor.nbar |
hyperproc.correct.cfactor.view_profile |
hyperproc.correct.cfactor.view_profile |
hyperproc.correct.cfactor.model_agreement |
hyperproc.correct.cfactor.model_agreement |
hyperproc.correct.cfactor.lonlat_of |
hyperproc.correct.cfactor.lonlat_of |
hyperproc.correct.cfactor.angles_of |
hyperproc.correct.cfactor.angles_of |
Docstring evidence boundary
Original docstrings may contain historical validation claims or simplified scientific explanations. Their presence is not independent verification. Consult the maintained workflow guides and validation page before reusing such claims.
Satellite BRDF normalisation by the c-factor method (Roy et al. 2016).
A single spaceborne scene sees each pixel once, so it carries no information
about how that pixel's reflectance changes with Sun and view angle: the
airborne route in :mod:hyperproc.correct.brdf, which fits kernel weights to
the across-track spread of a flightline group, has nothing to fit. The
c-factor method borrows the shape instead. MODIS MCD43A1 gives, for every
500 m cell, the three RossThick-LiSparseReciprocal weights of the last 16
days, and the correction is the ratio of the modelled reflectance at the
target geometry to the modelled reflectance at the observed geometry::
f_iso + f_vol K_vol(target) + f_geo K_geo(target)
c(x, y, b) = ---------------------------------------------------
f_iso + f_vol K_vol(observed) + f_geo K_geo(observed)
rho_target = c * rho_observed
Only the ratio is used, so the absolute level of the MODIS retrieval never
enters: a bias in f_iso cancels. What does enter is the shape, which is
why the method is trusted well beyond MODIS's own seven bands.
from hyperproc.correct import cfactor
out = cfactor.nbar(ds) # fetches MCD43A1, corrects, returns a dataset
out = cfactor.nbar(ds, params=p, sza_ref="observed") # view-angle normalisation only
Target geometry¶
sza_ref=45, vza_ref=0, raa_ref=0 is the usual NBAR convention: nadir view,
a fixed Sun, comparable between scenes and dates. sza_ref="observed" keeps
each pixel's own Sun angle and removes only the view-angle effect, which is
what Roy et al. (2016) published for Landsat and is the safer choice for a
single scene, because it never extrapolates the kernel model in solar zenith.
sza_ref="mean" uses the scene's mean solar zenith.
Spectral mapping¶
MODIS gives seven c-factors; an imaging spectrometer has hundreds of bands.
spectral="nearest" (default) assigns each band to the spectrally closest
MODIS band, which is what Roy et al. published and what keeps every corrected
band traceable to one measured BRDF shape. spectral="interp" interpolates
the seven linearly in wavelength instead: the correction is then smooth, at the
cost of applying a shape no MODIS band actually measured. The difference is not
small. On the EMIT test granule the largest band-to-band jump in the c-factor
is 0.100 with "nearest" against 0.0035 with "interp", so a "nearest"
product carries visible steps at the wavelengths where the assignment
switches, near 1245, 1440 and 1885 nm.
SPECTRAL_MODES = ('interp', 'nearest')
module-attribute
¶
DEFAULT_CLIP = (0.25, 4.0)
module-attribute
¶
MIN_MODEL = 0.0001
module-attribute
¶
band_map(wavelength) -> np.ndarray
¶
Index (0-6) of the spectrally closest MODIS band for each wavelength (nm).
Inside a MODIS band's nominal range that band wins; outside, the band whose range edge is nearest.
Source code in hyperproc/correct/cfactor.py
band_weights(wavelength, mode: str = 'interp') -> np.ndarray
¶
(7, nwl) weights that turn seven MODIS c-factors into per-band ones.
| PARAMETER | DESCRIPTION |
|---|---|
wavelength
|
instrument band centres in nm.
|
mode
|
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
ndarray
|
A matrix whose columns sum to 1, so it is an average of the seven |
ndarray
|
c-factors and never changes their scale. |
Source code in hyperproc/correct/cfactor.py
model_reflectance(params, sza, vza, raa, volume: str = 'ross_thick', geometric: str = 'li_sparse_r', b_r: float = 1.0, h_b: float = 2.0)
¶
Kernel-driven reflectance from MCD43A1 weights, (..., 7).
| PARAMETER | DESCRIPTION |
|---|---|
params
|
|
sza, vza, raa
|
angles in degrees, broadcastable to
|
volume, geometric, b_r, h_b
|
kernel choice. The MODIS product is fitted
with RossThick and LiSparseReciprocal at
|
Source code in hyperproc/correct/cfactor.py
c_factor(params, sza, vza, raa, sza_ref=45.0, vza_ref=0.0, raa_ref=0.0, volume: str = 'ross_thick', geometric: str = 'li_sparse_r', b_r: float = 1.0, h_b: float = 2.0, clip=DEFAULT_CLIP) -> np.ndarray
¶
The per-MODIS-band correction ratio, (..., 7).
| PARAMETER | DESCRIPTION |
|---|---|
params
|
|
sza, vza, raa
|
observed geometry in degrees.
|
sza_ref
|
target solar zenith. A number,
DEFAULT:
|
vza_ref, raa_ref
|
target view geometry, nadir by default.
|
clip
|
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
ndarray
|
float32 |
ndarray
|
model is degenerate. |
Source code in hyperproc/correct/cfactor.py
lonlat_of(ds) -> tuple
¶
Per-pixel longitude and latitude for the grid a dataset is on.
Source code in hyperproc/correct/cfactor.py
angles_of(ds) -> tuple
¶
Solar zenith, view zenith and relative azimuth layers, in degrees.
Source code in hyperproc/correct/cfactor.py
_fill_gaps(c: np.ndarray, how: str) -> tuple
¶
Replace NaN c-factors; returns (filled, valid_mask).
Source code in hyperproc/correct/cfactor.py
nbar(ds: xr.Dataset, params=None, *, var: str | None = None, sza_ref=45.0, vza_ref: float = 0.0, raa_ref: float = 0.0, spectral: str = 'nearest', volume: str = 'ross_thick', geometric: str = 'li_sparse_r', b_r: float = 1.0, h_b: float = 2.0, clip=DEFAULT_CLIP, fill: str = 'none', qa_max: int | None = 3, mask_snow: bool = True, keep_c: bool = True, source: str = 'gee', cache_dir=None, date: str | None = None, days: int = 8, res: float | None = None, pad: float = 0.05, project: str | None = None, sampling: str = 'bilinear', verbose: bool = True) -> xr.Dataset
¶
Normalise a satellite reflectance cube to a common Sun/view geometry.
| PARAMETER | DESCRIPTION |
|---|---|
ds
|
a hyperproc dataset with a reflectance cube and per-pixel
TYPE:
|
params
|
MCD43A1 parameters as a :class:
DEFAULT:
|
var
|
the variable to correct; the main cube by default.
TYPE:
|
sza_ref, vza_ref, raa_ref
|
target geometry (see the module docstring).
|
spectral
|
TYPE:
|
volume, geometric, b_r, h_b
|
kernel choice; leave at the MODIS pair.
|
clip
|
bounds on the c-factor, or None.
DEFAULT:
|
fill
|
what to do where MODIS has no retrieval.
TYPE:
|
qa_max
|
keep MODIS cells whose band quality is <= this. The default 3 keeps every retrieval; a magnitude inversion scales all three weights together and that factor cancels in the ratio. Pass 1 for full inversions only, at the cost of holes in the correction.
TYPE:
|
mask_snow
|
drop cells the MODIS product flags as snow-covered.
TYPE:
|
keep_c
|
attach the seven c-factors as a
TYPE:
|
source, cache_dir, date, days, pad, res, project
|
passed to
:func:
|
sampling
|
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Dataset
|
A copy of |
Dataset
|
so nothing is computed until it is written), a |
Dataset
|
layer, optional |
Dataset
|
was done. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
the dataset has no geometry, or an argument is out of range. |
Source code in hyperproc/correct/cfactor.py
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | |
view_profile(before: xr.Dataset, after: xr.Dataset | None = None, wavelength: float = 865.0, var: str | None = None, step: float = 2.0, stride: int = 1, ndvi: tuple | None = None) -> dict
¶
Mean reflectance against view zenith, before and after normalisation.
A BRDF normalisation that works flattens the across-track brightness trend, so this is the self-consistency check a single scene can supply. It has one trap, and the trap gets worse the wider the swath: view zenith is a function of position, so the profile is also a transect across the scene, and what changes along it is largely the land cover, not the geometry. On a PACE granule, where view zenith runs from 22 to 71 degrees across a continent, the raw profile says almost nothing about BRDF.
ndvi=(lo, hi) restricts the profile to pixels in one vegetation-density
class, which holds the surface roughly constant so the remaining trend is
angular. That is the version worth believing.
| PARAMETER | DESCRIPTION |
|---|---|
before, after
|
the datasets to profile;
|
wavelength
|
band to profile, nm.
TYPE:
|
var
|
variable name; the main cube by default.
TYPE:
|
step
|
view-zenith bin width, degrees.
TYPE:
|
stride
|
subsample step in y and x, to keep the read cheap.
TYPE:
|
ndvi
|
keep only pixels whose NDVI (from the bands nearest 660 and
860 nm of
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict
|
dict with |
dict
|
pixel |
dict
|
|
Source code in hyperproc/correct/cfactor.py
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | |
model_agreement(ds: xr.Dataset, params, wavelength: float = 865.0, var: str | None = None, ndvi: tuple | None = (0.2, 0.5), vza_range: tuple | None = None, step: float = 20.0, stride: int = 1, min_count: int = 200) -> dict
¶
Does the borrowed MODIS shape actually describe this scene's angular signal?
The whole method rests on one assumption: that the angular response MODIS measured over 16 days at 500 m applies to what this sensor saw in one overpass. This checks it directly, and it is the check to trust when the view-zenith profile cannot be trusted.
Pixels are binned by relative azimuth folded to 0-180 degrees, where 0 is the hotspot (sensor looking from the Sun's direction) and 180 is forward scattering, holding vegetation density and view zenith roughly constant. In each bin the mean observed reflectance is compared with the mean reflectance the MODIS parameters predict at that same geometry. If the shape transfers, the two rise and fall together.
The same comparison is repeated with the azimuth turned by 180 degrees. That is a convention check with a sharp answer: relative azimuth is the one input whose sign or origin a reader can plausibly get wrong, and a scene that prefers the flipped version is telling you the geometry is backwards, not that the surface is unusual.
| PARAMETER | DESCRIPTION |
|---|---|
ds
|
the observed reflectance with geometry (before normalisation).
TYPE:
|
params
|
the MCD43A1 :class:
|
wavelength
|
band to test, nm. The MODIS band covering it is used.
TYPE:
|
var
|
variable name; the main cube by default.
TYPE:
|
ndvi
|
restrict to one vegetation-density class, or None for all pixels.
TYPE:
|
vza_range
|
restrict to a view-zenith range, or None (the default) for all. Narrow-swath sensors sit at a single view zenith, so a fixed window here silently empties the test.
TYPE:
|
step
|
azimuth bin width, degrees.
TYPE:
|
stride
|
subsample step in y and x.
TYPE:
|
min_count
|
bins with fewer pixels than this are dropped.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict
|
dict with |
dict
|
the correlation |
dict
|
alternative, and |
Source code in hyperproc/correct/cfactor.py
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | |