Skip to content

Clean up and simplification of radiative transfer module#524

Merged
pgbrodrick merged 55 commits into
isofit:devfrom
unbohn:enhancement/rt_module_clean_up
Feb 3, 2025
Merged

Clean up and simplification of radiative transfer module#524
pgbrodrick merged 55 commits into
isofit:devfrom
unbohn:enhancement/rt_module_clean_up

Conversation

@unbohn

@unbohn unbohn commented Aug 3, 2024

Copy link
Copy Markdown
Collaborator

@pgbrodrick @davidraythompson This is a first draft for a simplification of radiative_transfer.py. The two main goals are:

  1. Clean up transmittance terms, so that, e.g., transm_down_dif only holds the diffuse downward transmittance and not the total transmittance (down * up, direct + diffuse), such as in the current sRTMnet and standard MODTRAN case.
  2. Integrate different model variations, namely the topography model, the glint model, and adjacency effects into one single radiance model, in particular, remove preclusive if-clauses.

There are two main problems/questions as of now:

  1. The proposed new implementation only works if at least one of the variables transm_up_dir and transm_up_dif is not zero. Otherwise, the term ((E_down_dir + E_down_dif) * (T_up_dir + T_up_dif)) / (1.0 - s_alb * bg) would be zero as well causing incorrectly modeled radiance. With sRTMnet and standard MODTRAN we currently don't have separated upward transmittance available. Proposed solution: deprecate single-transmittance mode in ISOFIT.
  2. Both the KF emulator and the universal LUT we've recently been testing provide separated direct and diffuse, but combined downward and upward fluxes. So again, both transm_up_dir and transm_up_dif would be zero. Proposed solution: train emulator and build LUT to output separated downward and upward fluxes.

Please find some more topics for discussion at in-line comments.

Let me know what you think!

@unbohn unbohn added the enhancement New feature or request label Aug 3, 2024
Comment thread isofit/radiative_transfer/radiative_transfer.py Outdated
Comment thread isofit/radiative_transfer/radiative_transfer.py Outdated
Comment thread isofit/radiative_transfer/radiative_transfer.py Outdated
Comment thread isofit/radiative_transfer/radiative_transfer.py
@davidraythompson

Copy link
Copy Markdown
Collaborator

Recording the discussion from yesterday's ISOFIT meeting. The following expression multiplies two quantities that are resampled from high spectral resolution:

(E_down_dir + E_down_dif) * (T_up_dir + T_up_dif)) / (1.0 - s_alb * bg)

A more accurate approach would calculate the reflected radiance transmitted along the bent (downwelling & upwelling) path, where the downward portion is separated into diffuse and direct terms and the upwelling portion is the total transmittance.

L_observed = L_path + [ L_diffusedown_totalup * rho_diffuse / (1.0 - s_alb * bg) ] 
                                     + [ L_directdown_totalup * rho_direct / (1.0 - s_alb * bg) ]

Here rho_diffuse and rho_direct come from the surface model; they would be identical for Lambertian surfaces but differ for glint surfaces. This still suffers from some inaccuracy via division by the spherical albedo term, which could contain high spectral resolution structure. Xu Liu's team is investigating the impact of this approximation.

@unbohn

unbohn commented Aug 6, 2024

Copy link
Copy Markdown
Collaborator Author

Thanks for recording the outcome from yesterday's discussion, @davidraythompson! This is absolutely the right direction. However, I'd like to clarify the implementation of the adjacency effects. In Guanter et al. (2009), the direct upward transmittance is multiplied by the target reflectance, while the diffuse upward transmittance is multiplied by the background reflectance:
image
In your suggestion, both direct and diffuse fluxes are multiplied by the target reflectance. Furthermore, if we implemented a separate multiplication by the two different reflectance terms, we'd end up combining both of them with the total upward transmittance. Any thoughts on this? I might also be missing something.

@davidraythompson

Copy link
Copy Markdown
Collaborator

Good point - if we want to model background reflectance independently we'd need to model four terms (all combinations of diffuse and direct on the downward and upward directions). Perhaps that is the best solution.

@unbohn

unbohn commented Aug 13, 2024

Copy link
Copy Markdown
Collaborator Author

Ok, sounds good! I'll work on a modified implementation that captures all the mentioned effects appropriately, i.e., that tries to minimize any inaccuracies due to multiplication of resampled quantities in the combined terms.

sky_glint = np.zeros(rfl.shape)

# adjacency effects
bg = geom.bg_rfl if geom.bg_rfl is not None else rfl

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pgbrodrick @davidraythompson In cases where we don't have geom.bg_rfl populated, should bg also contain the glint terms or should it just be rfl?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Just thinking out loud...

  • glint is likely (though not always) spatially autocorrelated
  • we can't know whether or not it is
  • if we do include it, I think it would come into lines 219/220 now, so as to continue to separate sun and sky glint into appropriate sections (sun w/ direct, sky with diffuse....I think?)
  • technically, if the bg is different, we should be solving for two more terms (background sun & sky glint), though presumably with increasing degeneracy. At the limit though, we could enable the glint model to have 4 terms, which would be the most general way to handle it.

All that said, my default answer is probably to keep it glint-free, acknowledging that this creates a discrepancy when it's not true. What does @davidraythompson think?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidraythompson Please let us know your thoughts about this!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in our meeting, I think that it may be simplest to have bg_rfl be a single vector with n values for n spectrometer channels - the effective background reflectance quantity needed for our mulitple scattering calculations. We'll have to be careful about how we calculate this quantity, but we could start with the lambertian assumption (i.e. that the average directional reflectance we measure of the enclosing superpixel is the same everywhere). I hypothesize this would fail in the edge case of a large placid lake acting as a specular reflector, but should get better for more typical wavy surfaces; the distribution of surface facets becomes more uniform over larger areas, right?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, that's what I would expect as well. Another option in the frame of the lambertian assumption might be to take the prior mean from the surface model as background reflectance. In case we run ISOFIT per pixel, we wouldn't have access to the average directional reflectance from the superpixel.

Comment thread isofit/radiative_transfer/radiative_transfer.py Outdated
@unbohn

unbohn commented Dec 3, 2024

Copy link
Copy Markdown
Collaborator Author

@pgbrodrick @davidraythompson @jammont @evan-greenbrg This PR is finally ready for your review! All checks are passing now and running some tests on AVIRIS-3 data gave me the exact same reflectance results as with the current dev branch. Please go ahead and test with other processing pipelines as you wish.

@unbohn unbohn marked this pull request as ready for review December 3, 2024 16:07
evan-greenbrg added a commit to evan-greenbrg/isofit that referenced this pull request Dec 3, 2024
Handling glint_model outside of templates

fixed to handle topography model

Optimized surface indexing, and added better logging for multisurface

bug in abspath handling

left the abspath statement in

Removed surface dir support

adding temporary handling of multi-transmittance luts

adding command line support for class file in apply_oe

Commenting out L592-597. Check with Niklas for utility of these lines

Trying another fix for missing case2

Updated test_rfls and two_albedo method in line with isofit#524

update template construction for lut without obszen

added custom surface model hash

updated to example syntax

keeping original n_core values constant

add flag to pass directions for applyoe to run multipart_transmittance

Cleaning up code
Comment thread isofit/radiative_transfer/radiative_transfer.py Outdated
Comment thread isofit/radiative_transfer/radiative_transfer.py Outdated
@davidraythompson

Copy link
Copy Markdown
Collaborator

Overall this looks absolutely fantastic. There are a few places, noted in specific comments, where using variable names and terminology in a more consistent way might help clarify the physical interpretations of the different variables.

@unbohn

unbohn commented Dec 19, 2024

Copy link
Copy Markdown
Collaborator Author

Thanks for the comments, @davidraythompson! The use of variable names and terminology should be more consistent now.

@evan-greenbrg evan-greenbrg left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@unbohn Here's a line-by-line review of the proposed changes. All the question I have here are very minor.

Comment thread isofit/core/forward.py Outdated
Comment thread isofit/core/forward.py Outdated
Comment thread isofit/radiative_transfer/luts.py Outdated
Comment thread isofit/radiative_transfer/radiative_transfer.py Outdated
Comment thread isofit/radiative_transfer/radiative_transfer.py
Comment thread isofit/radiative_transfer/radiative_transfer.py
Comment thread isofit/radiative_transfer/radiative_transfer.py
Comment thread isofit/radiative_transfer/radiative_transfer.py Outdated
Comment thread isofit/radiative_transfer/radiative_transfer.py Outdated
Comment thread isofit/radiative_transfer/radiative_transfer_engine.py
@unbohn unbohn force-pushed the enhancement/rt_module_clean_up branch from 561e5b8 to 5e22d7c Compare January 27, 2025 22:22
Comment thread isofit/radiative_transfer/radiative_transfer.py
@pgbrodrick

Copy link
Copy Markdown
Collaborator

This Herculean effort is now ready for merge! Congratulations @unbohn and thanks to the full team. There may be small tweaks needed for additional optimization and performance.

@pgbrodrick pgbrodrick merged commit 1cfb2b0 into isofit:dev Feb 3, 2025
@unbohn unbohn deleted the enhancement/rt_module_clean_up branch February 11, 2026 20:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants