Incoherent Solver
A 2×2 isotropic solver that supports partly-incoherent stacks. Real coatings
often sit on a thick substrate (e.g. a 1 mm glass slide) that is far thicker than
the source's coherence length, so light reflected from its two surfaces does not
interfere in practice. A fully-coherent solver would produce dense, unphysical
Fabry–Perot ripples; this solver lets you mark each interior layer as coherent
('c') or incoherent ('i') via a c_list.
IncoherentIsotropicFilmSolver subclasses IsotropicFilmSolver
and shares its constructor and UX, with two differences:
- it takes an extra
c_listargument (one'c'/'i'code per interior layer), and simulate()returns real power coefficients(Rs, Rp, Ts, Tp)rather than complex amplitudes, because incoherent calculations discard phase by design.
The two semi-infinite media are always treated as incoherent. The solver is fully differentiable through layer thicknesses, so it can be used for inverse design of stacks that include thick substrates.
Isotropic only
Incoherent handling is currently available only for the 2×2 isotropic solver. Anisotropic incoherent TMM is tracked as future work.
difftmm.IncoherentIsotropicFilmSolver
IncoherentIsotropicFilmSolver(mat_in, mat_out, mat_ls, c_list, thickness_ls=None, thickness_min=0.0, thickness_max=1000.0, batch_size=1, sigmoid_param=False, device=torch.device('cuda'))
Bases: IsotropicFilmSolver
Multi-layer coating solver with partly-incoherent layer support.
Same UX as :class:IsotropicFilmSolver but additionally accepts a
c_list argument that marks each interior layer as coherent
('c') or incoherent ('i'). Returns real power coefficients
(Rs, Rp, Ts, Tp) rather than complex amplitudes, because
incoherent calculations discard phase by design.
Initialize the incoherent isotropic film solver.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mat_in
|
Incident medium. Float/complex scalar, str material name, or Material. |
required | |
mat_out
|
Exit medium. Float/complex scalar, str material name, or Material. |
required | |
mat_ls
|
Refractive indices of interior layers (length N). Each entry is a float/complex scalar, str material name, or Material. |
required | |
c_list
|
list of 'c'/'i' codes, length N. One per interior layer. |
required | |
thickness_ls
|
thicknesses of interior layers in um, length N. If None, random. |
None
|
|
thickness_min
|
minimum thickness in um. |
0.0
|
|
thickness_max
|
maximum thickness in um. Defaults to 1000 (um) so substrate-sized layers fit without special configuration. |
1000.0
|
|
batch_size
|
number of film stacks in the batch. |
1
|
|
sigmoid_param
|
if True, use sigmoid parameterization. |
False
|
|
device
|
torch device. |
device('cuda')
|
Raises:
| Type | Description |
|---|---|
ValueError
|
if |
Source code in difftmm-src/difftmm/film_solver_incoherent.py
coh_stack_power_RT_isotropic
staticmethod
Power-domain (Rs, Rp, Ts, Tp) for a coherent isotropic stack.
Thin wrapper around create_jones_matrix_isotropic that converts
complex amplitudes to real power coefficients. Used as a building block
for the incoherent TMM solver, where each coherent stack contributes its
forward/backward (R, T) to the intensity transfer matrix.
Layer convention: layers are ordered from the incident medium (n_in) to
the exit medium (n_out), i.e. the same physical order used by
tmm_numpy.coh_tmm. Internally, layers are reversed before being
passed to create_jones_matrix_isotropic, which stores them in the
reverse physical order due to its characteristic-matrix accumulation
convention.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_layers_1d
|
refractive index of each interior layer in physical order (n_in-side first), shape (batch, n_layer). Complex. |
required | |
d_1d
|
thickness of each interior layer in um, same physical ordering as n_layers_1d, shape (batch, n_layer). Real. |
required | |
wv_1d
|
wavelengths in um, shape (batch, n_wls). Real. |
required | |
n_in
|
scalar incident refractive index (top medium). |
required | |
n_out
|
scalar exit refractive index (bottom medium). |
required | |
theta_1d
|
incident angles in radians, shape (batch, n_angles). Real, in [0, pi/2]. |
required |
Returns:
| Type | Description |
|---|---|
|
Rs, Rp, Ts, Tp: real tensors, each shape (batch, n_wls, n_angles), in [0, 1]. |
Note
This helper is public-API: it is exposed via difftmm.__init__ in
Task 9. Other modules in this package use it as a building block for
the incoherent TMM solver, but external users may also call it
directly when they need power coefficients without phase.
Source code in difftmm-src/difftmm/film_solver_incoherent.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
group_layers_by_coherence
staticmethod
Group a layer-coherence list into coherent stacks and incoherent layers.
A "stack" is a maximal run of consecutive coherent layers, bracketed on each side by an incoherent layer (which is required to be present because the first and last layers are semi-infinite and must be 'i').
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
c_list
|
Sequence[str]
|
Per-layer coherence flags. Each entry is 'i' (incoherent) or 'c' (coherent). First and last entries must be 'i' because those layers are semi-infinite. |
required |
Returns:
| Type | Description |
|---|---|
Dict[str, object]
|
Dict with keys: - num_inc_layers (int): number of incoherent layers. - num_stacks (int): number of coherent stacks. - inc_alllayer_indices (List[int]): for each incoherent layer i, its index in the original layer list. - stack_alllayer_indices (List[List[int]]): for each stack s, the original indices of layers in [bracketing_inc, coh_layers..., bracketing_inc]. - stack_after_inc (List[Optional[int]]): for each incoherent layer i, the stack-index of the stack immediately after it, or None if the next layer is also incoherent (or there is no next layer). - inc_after_stack (List[int]): for each stack s, the incoherent-layer index that immediately precedes the stack. |
Raises:
| Type | Description |
|---|---|
ValueError
|
if the first or last entry is not 'i', or any entry is neither 'i' nor 'c'. |
Source code in difftmm-src/difftmm/film_solver_incoherent.py
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 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 | |
interface_power_RT
staticmethod
Fresnel power reflectance/transmittance at a single interface.
All inputs are complex tensors broadcastable to a common shape. Returns (Rs, Rp, Ts, Tp) as real tensors of that shape.
Math
r_s = (n_i cos_i - n_f cos_f) / (n_i cos_i + n_f cos_f) r_p = (n_f cos_i - n_i cos_f) / (n_f cos_i + n_i cos_f) t_s = 2 n_i cos_i / (n_i cos_i + n_f cos_f) t_p = 2 n_i cos_i / (n_f cos_i + n_i cos_f) R = |r|^2 T_s = |t_s|^2 * Re(n_f cos_f) / Re(n_i cos_i) T_p = |t_p|^2 * Re(n_f conj(cos_f)) / Re(n_i conj(cos_i))
Source code in difftmm-src/difftmm/film_solver_incoherent.py
create_intensity_RT_isotropic
staticmethod
Partly-incoherent intensity TMM for isotropic multi-layer films.
Each interior layer is marked coherent ('c') or incoherent ('i') via
c_list. The two semi-infinite media (n_in, n_out) are always
incoherent, so c_list describes only the interior layers and the
full coherence sequence is ['i'] + c_list + ['i'].
The algorithm
- Group consecutive coherent layers into stacks.
- For each stack, run the existing coherent 2x2 solver in both directions to get (R_fwd, T_fwd, R_bwd, T_bwd).
- Compute single-pass absorption P_i for each interior incoherent layer.
- Build real 2x2 intensity transfer matrices L_i and multiply.
- Read off total R and T.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_layers_1d
|
refractive indices of interior layers, shape (batch, n_layer). Complex. |
required | |
d_1d
|
thicknesses of interior layers in um, shape (batch, n_layer). Real. |
required | |
wv_1d
|
wavelengths in um, shape (batch, n_wls). Real. |
required | |
n_in
|
scalar incident refractive index (top medium). |
required | |
n_out
|
scalar exit refractive index (bottom medium). |
required | |
theta_1d
|
incident angles in radians, shape (batch, n_angles). Real, in [0, pi/2]. |
required | |
c_list
|
list of 'c'/'i' codes, length n_layer (interior layers only). |
required |
Returns:
| Type | Description |
|---|---|
|
Rs, Rp, Ts, Tp: real tensors, each shape (batch, n_wls, n_angles), in [0, 1]. |
Note
Inside any coherent sub-stack, the refractive indices of the bracketing incoherent layers must be identical across the batch dimension. Heterogeneous per-batch indices in stack-bracketing layers raise ValueError. Per-batch interior coherent-layer indices are still supported.
Source code in difftmm-src/difftmm/film_solver_incoherent.py
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 381 382 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 | |
simulate
Compute (Rs, Rp, Ts, Tp) for the configured stack.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
theta
|
angles in radians. 1D |
required | |
wvln
|
wavelengths in um. Scalar, list, or 1D tensor. |
required |
Returns:
| Type | Description |
|---|---|
|
Rs, Rp, Ts, Tp: real tensors of shape |