Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7eff774
New units.typing esp. to simplify spectral flux density and radiance …
mkelley Nov 9, 2024
7756beb
New surfaces module.
mkelley Nov 11, 2024
448dc9a
Finish top-level description of surfaces
mkelley Nov 11, 2024
6fb7318
Alternative approach for ScatteredSunlight
mkelley Nov 11, 2024
05d0053
Test and bugfix ScatteredLight and ScatteredSunlight
mkelley Nov 11, 2024
db280e6
Rename ScatteredSunlight methods
mkelley Nov 11, 2024
848d1d1
Address black and codestyle incompatilibities
mkelley Nov 11, 2024
fc01a0b
sunlight tests need synphot
mkelley Nov 11, 2024
7d08c0e
Replace Surface._cos with more useful Surface._min_zero_cos
mkelley Nov 12, 2024
5322866
surface_brightness only available for astropy >= 6.1
mkelley Nov 12, 2024
6498d55
Remove unused imports.
mkelley Nov 12, 2024
999a381
Import classes into module __init__
mkelley Nov 12, 2024
8070ecf
Complete documentaion.
mkelley Nov 12, 2024
0e55a7f
Mark required packages for new doctests blocks
mkelley Nov 12, 2024
e2b9aa7
Avoid: each t must be a type. Got PhysicalType('angle')
mkelley Nov 12, 2024
a74835a
Fix incompatilibity with oldestdeps
mkelley Nov 12, 2024
334ce77
Thermal was not supposed to be checked in.
mkelley Nov 12, 2024
4441a94
Clarify as bidirectional reflectance
mkelley Nov 27, 2024
9f69b2f
Partial updates for new method names.
mkelley Dec 10, 2024
833e066
Simplify to avoid using instance variables
mkelley Sep 5, 2025
aad7ae3
Check in before stripping flux density.
mkelley Dec 14, 2025
bdbf7ed
Checking in
mkelley Dec 15, 2025
3bf2b65
Strip incident and emitted flux densities.
mkelley Dec 16, 2025
688f253
Add albedo and emissivity back in.
mkelley Dec 16, 2025
cdf0941
Clean up
mkelley Dec 16, 2025
f63316d
Finish scattered light module.
mkelley Dec 16, 2025
d661f0a
Rename methods: absorptance and emittance
mkelley Dec 16, 2025
76dbe9f
Start defining Sphere
mkelley Jan 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ Activity

sbpy/activity/index.rst

Surfaces and Shapes
-------------------

.. toctree:: :maxdepth: 2

sbpy/surfaces

Miscellaneous
-------------

Expand Down
119 changes: 119 additions & 0 deletions docs/sbpy/surfaces.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
Surfaces Module (`sbpy.surfaces`)
=================================

Introduction
------------

.. admonition:: warning

The surfaces module is being made available on a preview basis. The API is subject to change. Feedback on the approach is welcome.

The ``surfaces`` module describes the interaction of electromagnetic radiation with surfaces. Sbpy uses the :math:`(i, e, \phi)` model (angle of incidence, angle of emittance, and phase angle) to describe how light scatters and emits light. It has a flexible system that can incorporate most surface scattering Models that can be described with these three angles.

.. figure:: ../static/scattering-vectors.svg
:alt: Diagram of surface scattering and emittance vectors

Sbpy's geometric basis for surface scattering and emittance: :math:`n` is the surface normal vector, :math:`r_s` is the radial vector to the light source, and :math:`r_o` is the radial vector to the observer. The angle of incidence (:math:`i`), angle of emittance (:math:`e`), phase angle (:math:`\phi`) are labeled.

An implementation of the ``Surface`` model has methods to calculate electromagnetic absorptance, emittance, and bidirectional reflectance.


Getting Started
---------------

Currently the Lambertian surface model is implemented. A Lambertian surface absorbs and emits light uniformly in all directions.

Create an instance of the ``LambertianSurface`` model, and calculate the absorptance and emittance scale factors for :math:`(i, e, \phi) = (30^\circ, 60^\circ, 90^\circ)`. Let the albedo be 0.1 (emissivity = 0.9)::

>>> import astropy.units as u
>>> from sbpy.surfaces import LambertianSurface
>>>
>>> albedo = 0.1
>>> epsilon = 1 - albedo
>>> i, e, phi = [30, 60, 90] * u.deg
>>>
>>> surface = LambertianSurface()
>>> surface.absorptance(epsilon, i) # doctest: +FLOAT_CMP
<Quantity 0.77942286>
>>> surface.emittance(epsilon, e, phi) # doctest: +FLOAT_CMP
<Quantity 0.45>

Calculate the bidirectional reflectance for :math:`e=0`, and a range of incident angles::

.. plot::
:context: reset
:nofigs:

>>> import numpy as np
>>>
>>> e = 0 * u.deg
>>> i = np.linspace(-90, 90) * u.deg
>>> phi = np.abs(e - i) # calculate phase angle
>>> r = surface.reflectance(albedo, i, e, phi)

.. plot::
:include-source:
:context:

import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(i, r)
ax.set(xlabel="$i$ (deg)", ylabel="$r$ (1 / sr)")


Using Vectors Instead of Angles
-------------------------------

As an alternative to using :math:`(i, e, \phi)`, results may be calculated using vectors that define the normal direction, radial vector to the light source, and radial vector to the observer::

>>> # vectors equivalent to (i, e, phi) = (30, 60, 90) deg
>>> n = [1, 0, 0]
>>> r = [0.8660254, 0.5, 0] * u.au
>>> ro = [0.5, -0.8660254, 0] * u.au
>>>
>>> surface.reflectance_from_vectors(albedo, n, r, ro) # doctest: +FLOAT_CMP
<Quantity 0.0137832 1 / sr>


Build Your Own Surface Models
-----------------------------

To define your own surface model create a new class based on `~sbpy.surfaces.surface.Surface`, and define the methods for ``absorptance``, ``emittance``, and ``reflectance``. The `~sbpy.surfaces.lambertian.LambertianSurface` model may serve as a reference.

Here, we define a new surface model with surface properties proportional to :math:`\cos^2`::

>>> # use min_zero_cos(a) to ensure cos(a >= 90 deg) = 0
>>> from sbpy.surfaces.surface import Surface, min_zero_cos
>>>
>>> class Cos2Surface(Surface):
... """Surface properties proportional to :math:`\\cos^2`."""
...
... def absorptance(self, epsilon, i):
... return epsilon * min_zero_cos(i)**2
...
... def emittance(self, epsilon, e, phi):
... return epsilon * min_zero_cos(e)**2
...
... def reflectance(self, albedo, i, e, phi):
... return albedo * min_zero_cos(i)**2 * min_zero_cos(e)**2 / np.pi / u.sr

Create and use an instance of our new model::

>>> surface = Cos2Surface()
>>> albedo = 0.1
>>> epsilon = 1 - albedo
>>> i, e, phi = [30, 60, 90] * u.deg
>>>
>>> surface.absorptance(epsilon, i) # doctest: +FLOAT_CMP
<Quantity 0.675>
>>> surface.emittance(epsilon, e, phi) # doctest: +FLOAT_CMP
<Quantity 0.225>
>>> surface.reflectance(albedo, i, e, phi) # doctest: +FLOAT_CMP
<Quantity 0.00596831 1 / sr>


Reference/API
-------------
.. automodapi:: sbpy.surfaces
:no-heading:
:inherited-members:
127 changes: 127 additions & 0 deletions docs/static/scattering-vectors.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading