def test03_mueller_to_world_to_local(variant_scalar_mono_polarized): """ At a few places, coordinate changes between local BSDF reference frame and world coordinates need to take place. This change also needs to be applied to Mueller matrices used in computations involving polarization state. In practice, this is always a simple rotation of reference Stokes vectors (for incident & outgoing directions) of the Mueller matrix. To test this behavior we take any Mueller matrix (e.g. linear polarizer) for some arbitrary incident/outgoing directions in world coordinates and compute the round trip going to local frame and back again. """ from mitsuba.core import Frame3f, UnpolarizedSpectrum from mitsuba.render import SurfaceInteraction3f from mitsuba.render.mueller import linear_polarizer import numpy as np si = SurfaceInteraction3f() si.sh_frame = Frame3f(ek.normalize([1.0, 1.0, 1.0])) M = linear_polarizer(UnpolarizedSpectrum(1.0)) # Random incident and outgoing directions wi_world = ek.normalize([0.2, 0.0, 1.0]) wo_world = ek.normalize([0.0, -0.8, 1.0]) wi_local = si.to_local(wi_world) wo_local = si.to_local(wo_world) M_local = si.to_local_mueller(M, wi_world, wo_world) M_world = si.to_world_mueller(M_local, wi_local, wo_local) assert ek.allclose(M, M_world, atol=1e-5)
def test_sample_ray(variant_scalar_rgb, direction, origin): sample1 = [0.32, 0.87] sample2 = [0.16, 0.44] sensor = make_sensor(direction=direction, origin=origin) # Test regular ray sampling ray = sensor.sample_ray(1., 1., sample1, sample2, True) assert ek.allclose(ray[0].o, origin) assert ek.allclose(ray[0].d, ek.normalize(direction)) # Test ray differential sampling ray = sensor.sample_ray_differential(1., 1., sample2, sample1, True) assert ek.allclose(ray[0].o, origin) assert ek.allclose(ray[0].d, ek.normalize(direction)) assert not ray[0].has_differentials
def weight_measurements(spec, D, sigma, theta_i, phi_i, theta_o, phi_o, active=None): from mitsuba.core import MarginalContinuous2D0, Vector2f m_ndf = MarginalContinuous2D0(D, normalize=False) m_sigma = MarginalContinuous2D0(sigma, normalize=False) scaled = np.zeros(spec.shape) n_phi = spec.shape[-2] n_theta = spec.shape[-1] for i in range(phi_i.size): for j in range(theta_i.size): # Incient direction wi = spherical2cartesian(theta_i[j], phi_i[i]) u_wi = Vector2f(theta2u(theta_i[j]), phi2u(phi_i[i])) # Outgoing direction wo = spherical2cartesian(theta_o[i, j].flatten(), phi_o[i, j].flatten()) # Phase direction m = ek.normalize(wi + wo) theta_m, phi_m = cartesian2spherical(wo) u_m = Vector2f(theta2u(theta_m), phi2u(phi_m)) # Scale by inverse jacobian jacobian = m_ndf.eval(u_m) / (4 * m_sigma.eval(u_wi)) scaled[i, j] = spec[i, j] / np.reshape(jacobian, (n_phi, n_theta)) if not active is None: n_wavelenths = spec.shape[2] for i in range(n_wavelenths): scaled[:, :, i][~active] = 0 return scaled
def test_sample_ray(variant_scalar_rgb, direction, origin): sample1 = [0.32, 0.87] sample2 = [0.16, 0.44] direction_str = ",".join([str(x) for x in direction]) origin_str = ",".join([str(x) for x in origin]) sensor = example_sensor(params=xml_direction(direction_str) + xml_origin(origin_str)) # Test regular ray sampling ray = sensor.sample_ray(1., 1., sample1, sample2, True) assert ek.allclose(ray[0].o, origin) assert ek.allclose(ray[0].d, ek.normalize(direction)) # Test ray differential sampling ray = sensor.sample_ray_differential(1., 1., sample2, sample1, True) assert ek.allclose(ray[0].o, origin) assert ek.allclose(ray[0].d, ek.normalize(direction)) assert not ray[0].has_differentials
def test02_chi2_rough_grazing(variant_packet_rgb): xml = """<float name="alpha" value="0.5"/>""" wi = ek.normalize([0.8, 0.3, 0.05]) sample_func, pdf_func = BSDFAdapter("roughdielectric", xml, wi=wi) chi2 = ChiSquareTest(domain=SphericalDomain(), sample_func=sample_func, pdf_func=pdf_func, sample_dim=3) assert chi2.run()
def test01_chi2_smooth(variant_packet_rgb): xml = """<float name="alpha" value="0.05"/>""" wi = ek.normalize([1.0, 1.0, 1.0]) sample_func, pdf_func = BSDFAdapter("roughconductor", xml, wi=wi) chi2 = ChiSquareTest(domain=SphericalDomain(), sample_func=sample_func, pdf_func=pdf_func, sample_dim=3, ires=8) assert chi2.run()
def test07_chi2_rough_from_inside(variant_packet_rgb): xml = """<float name="alpha" value="0.5"/>""" wi = ek.normalize([0.2, -0.6, -0.5]) sample_func, pdf_func = BSDFAdapter("roughdielectric", xml, wi=wi) chi2 = ChiSquareTest(domain=SphericalDomain(), sample_func=sample_func, pdf_func=pdf_func, sample_dim=3, res=201) assert chi2.run()
def test02_sample_ray(variant_packet_spectral, origin, direction, aperture_rad, focus_dist): # Check the correctness of the sample_ray() method from mitsuba.core import sample_shifted, sample_rgb_spectrum, warp, Vector3f, Transform4f cam = create_camera(origin, direction, aperture=aperture_rad, focus_dist=focus_dist) time = 0.5 wav_sample = [0.5, 0.33, 0.1] pos_sample = [[0.2, 0.1, 0.2], [0.6, 0.9, 0.2]] aperture_sample = [0.5, 0.5] ray, spec_weight = cam.sample_ray(time, wav_sample, pos_sample, aperture_sample) # Importance sample wavelength and weight wav, spec = sample_rgb_spectrum(sample_shifted(wav_sample)) assert ek.allclose(ray.wavelengths, wav) assert ek.allclose(spec_weight, spec) assert ek.allclose(ray.time, time) assert ek.allclose(ray.o, origin) # Check that a [0.5, 0.5] position_sample and [0.5, 0.5] aperture_sample # generates a ray that points in the camera direction ray, _ = cam.sample_ray(0, 0, [0.5, 0.5], [0.5, 0.5]) assert ek.allclose(ray.d, direction, atol=1e-7) # ---------------------------------------- # Check correctness of aperture sampling pos_sample = [0.5, 0.5] aperture_sample = [[0.9, 0.4, 0.2], [0.6, 0.9, 0.7]] ray, _ = cam.sample_ray(time, wav_sample, pos_sample, aperture_sample) ray_centered, _ = cam.sample_ray(time, wav_sample, pos_sample, [0.5, 0.5]) trafo = Transform4f(cam.world_transform().eval(time).matrix.numpy()) tmp = warp.square_to_uniform_disk_concentric(aperture_sample) aperture_v = trafo.transform_vector(aperture_rad * Vector3f(tmp.x, tmp.y, 0)) # NOTE: here we assume near_clip = 1.0 assert ek.allclose(ray.o, ray_centered.o + aperture_v) assert ek.allclose(ray.d, ek.normalize(ray_centered.d * focus_dist - aperture_v))
def test06_chi2_rough_ggx_visible(variant_packet_rgb): xml = """<float name="alpha" value="0.5"/> <boolean name="sample_visible" value="true"/> <string name="distribution" value="ggx"/> """ wi = ek.normalize([0.5, 0.5, 0.001]) sample_func, pdf_func = BSDFAdapter("roughdielectric", xml, wi=wi) chi2 = ChiSquareTest(domain=SphericalDomain(), sample_func=sample_func, pdf_func=pdf_func, sample_dim=3) assert chi2.run()
def test02_eval(variant_packet_spectral, spectrum_key): # Check that eval() return the same values as the 'radiance' spectrum from mitsuba.render import SurfaceInteraction3f shape, spectrum = create_emitter_and_spectrum(spectrum_key) emitter = shape.emitter() it = SurfaceInteraction3f.zero(3) assert ek.allclose(emitter.eval(it), spectrum.eval(it)) # Check that eval return 0.0 when direction points inside the shape it.wi = ek.normalize([0.2, 0.2, -0.5]) assert ek.allclose(emitter.eval(it), 0.0)
def test05_chi2_aniso_ggx_visible(variant_packet_rgb): xml = """<float name="alpha_u" value="0.2"/> <float name="alpha_v" value="0.05"/> <string name="distribution" value="ggx"/> <boolean name="sample_visible" value="true"/>""" wi = ek.normalize([1.0, 1.0, 1.0]) sample_func, pdf_func = BSDFAdapter("roughconductor", xml, wi=wi) chi2 = ChiSquareTest(domain=SphericalDomain(), sample_func=sample_func, pdf_func=pdf_func, sample_dim=3, ires=8) assert chi2.run()
def test03_chi2_rough_beckmann_all(variant_packet_rgb): xml = """<float name="alpha" value="0.5"/> <boolean name="sample_visible" value="false"/> <string name="distribution" value="beckmann"/> """ wi = ek.normalize([0.5, 0.0, 0.5]) sample_func, pdf_func = BSDFAdapter("roughdielectric", xml, wi=wi) chi2 = ChiSquareTest(domain=SphericalDomain(), sample_func=sample_func, pdf_func=pdf_func, sample_dim=3, res=201) assert chi2.run()
def test11_chi2_aniso_lobe_trans(variant_packet_rgb): from mitsuba.render import BSDFContext xml = """ <float name="alpha_u" value="0.5"/> <float name="alpha_v" value="0.2"/> """ wi = ek.normalize([-0.5, -0.5, 0.1]) ctx = BSDFContext() ctx.component = 1 sample_func, pdf_func = BSDFAdapter("roughdielectric", xml, wi=wi, ctx=ctx) chi2 = ChiSquareTest(domain=SphericalDomain(), sample_func=sample_func, pdf_func=pdf_func, sample_dim=3, res=201) assert chi2.run()
def log_(a0): if not a0.IsFloat: raise Exception("log(): requires floating point operands!") ar, sr = _check1(a0) if not a0.IsSpecial: for i in range(sr): ar[i] = _ek.log(a0[i]) elif a0.IsComplex: ar.real = .5 * _ek.log(_ek.squared_norm(a0)) ar.imag = _ek.arg(a0) elif a0.IsQuaternion: qi_n = _ek.normalize(a0.imag) rq = _ek.norm(a0) acos_rq = _ek.acos(a0.real / rq) log_rq = _ek.log(rq) ar.imag = qi_n * acos_rq ar.real = log_rq else: raise Exception("log(): unsupported array type!") return ar
def test_sampling(variant_scalar_rgb, center, radius): """ We construct an irradiance meter attached to a sphere and assert that sampled rays originate at the sphere's surface """ from mitsuba.core import Vector3f center_v = Vector3f(center) sphere = example_shape(radius, center_v) sensor = sphere.sensor() num_samples = 100 wav_samples = np.random.rand(num_samples) pos_samples = np.random.rand(num_samples, 2) dir_samples = np.random.rand(num_samples, 2) for i in range(100): ray = sensor.sample_ray_differential(0.0, wav_samples[i], pos_samples[i], dir_samples[i])[0] # assert that the ray starts at the sphere surface assert ek.allclose(ek.norm(center_v - ray.o), radius) # assert that all rays point away from the sphere center assert ek.dot(ek.normalize(ray.o - center_v), ray.d) > 0.0
p = np.array([np.random.randint(res[0]), np.random.randint(res[1])]) * inv_res ray, _ = camera.sample_ray_differential(0.0, 0.5, p, [0.5, 0.5]) si = scene.ray_intersect(ray) ei = SpecularManifold.sample_emitter_interaction(si, scene.emitters(), sampler) solutions = [] solutions_uv = [] solutions_p = [] n_tries = 500 for tries in range(n_tries): print("Find solutions: %.2f%%" % (100 * tries / (n_tries - 1)), end="\r") success, si_final, _ = mf.sample_path(spec_shape, si, ei, sampler) if not success: continue direction = ek.normalize(si_final.p - si.p) duplicate = False for s in solutions: if np.abs((direction @ s) - 1) < 1e-5: duplicate = True break if duplicate: continue solutions.append(direction) solutions_uv.append(si_final.uv) solutions_p.append(si_final.p) print("") # print("Found {} solutions.".format(len(solutions)))
for j in range(res[0]): print("Identify glinty pixels: %.2f%%" % (100 * j / (res[0] - 1)), end="\r") for i in range(res[1]): if glint_mask[i, j] == 0: continue p = np.array([j + 0.5, i + 0.5]) * inv_res ray, _ = camera.sample_ray_differential(0.0, 0.5, p, [0.5, 0.5]) si = scene.ray_intersect(ray) si.compute_partials(ray) ei = SpecularManifold.sample_emitter_interaction( si, scene.emitters(), sampler) wi = ek.normalize(ray.o - si.p) wo = ek.normalize(ei.p - si.p) h = ek.normalize(wi + wo) n_offset = np.array([0, 0, 1]) for k in range(1): success, uv_final, _, = mf.sample_glint(ray.o, ei, si, sampler, n_offset) if success: glinty_pixels.append((i, j)) break print("") # print("Found {} glinty pixels".format(len(glinty_pixels))) idx = 238 # Manually chosen index that gives nice looking results
def test02_sample_pol_world(variant_scalar_mono_polarized): from mitsuba.core import Frame3f, Spectrum, UnpolarizedSpectrum from mitsuba.core.xml import load_string from mitsuba.render import BSDFContext, TransportMode, SurfaceInteraction3f, fresnel_conductor from mitsuba.render.mueller import stokes_basis, rotate_mueller_basis def spectrum_from_stokes(v): res = Spectrum(0.0) for i in range(4): res[i, 0] = v[i] return res # Create a Silver conductor BSDF and reflect different polarization states # at a 45˚ angle. # This test takes place in world coordinates and thus involves additional # coordinate system rotations. # # The setup is as follows: # - The mirror is positioned at [0, 0, 0], angled s.t. the surface normal # is along [1, 1, 0]. # - Incident ray w1 = [-1, 0, 0] strikes the mirror at a 45˚ angle and # reflects into direction w2 = [0, 1, 0] # - The corresponding Stokes bases are b1 = [0, 1, 0] and b2 = [1, 0, 0]. # Setup eta = 0.136125 + 4.010625j # IoR values of Ag at 635.816284nm bsdf = load_string("""<bsdf version='2.0.0' type='conductor'> <spectrum name="eta" value="{}"/> <spectrum name="k" value="{}"/> </bsdf>""".format(eta.real, eta.imag)) ctx = BSDFContext() ctx.mode = TransportMode.Importance si = SurfaceInteraction3f() si.p = [0, 0, 0] si.n = ek.normalize([1.0, 1.0, 0.0]) si.sh_frame = Frame3f(si.n) # Incident / outgoing directions and their Stokes bases w1 = ek.scalar.Vector3f([-1, 0, 0]) b1 = [0, 1, 0] w2 = ek.scalar.Vector3f([0, 1, 0]) b2 = [1, 0, 0] # Perform actual reflection si.wi = si.to_local(-w1) bs, M_tmp = bsdf.sample(ctx, si, 0.0, [0.0, 0.0]) M_world = si.to_world_mueller(M_tmp, -si.wi, bs.wo) # Test that outgoing direction is as predicted assert ek.allclose(si.to_world(bs.wo), w2, atol=1e-5) # Align reference frames s.t. polarization is expressed w.r.t. b1 & b2 M_world = rotate_mueller_basis(M_world, w1, stokes_basis(w1), b1, w2, stokes_basis(w2), b2) # Apply to unpolarized light and verify that it is equivalent to normal Fresnel a0 = M_world @ spectrum_from_stokes([1, 0, 0, 0]) F = fresnel_conductor(si.wi[2], ek.scalar.Complex2f(eta.real, eta.imag)) a0 = a0[0, 0] assert ek.allclose(a0[0], F, atol=1e-3) # Apply to horizontally polarized light (linear at 0˚) # Test that it is.. # 1) still fully polarized (though with reduced intensity) # 2) still horizontally polarized a1 = M_world @ spectrum_from_stokes([1, +1, 0, 0]) assert ek.allclose(a1[0, 0], ek.abs(a1[1, 0]), atol=1e-3) # 1) a1 /= a1[0, 0] assert ek.allclose(a1, spectrum_from_stokes([1, 1, 0, 0]), atol=1e-3) # 2) # Apply to vertically polarized light (linear at 90˚) # Test that it is.. # 1) still fully polarized (though with reduced intensity) # 2) still vertically polarized a2 = M_world @ spectrum_from_stokes([1, -1, 0, 0]) assert ek.allclose(a2[0, 0], ek.abs(a2[1, 0]), atol=1e-3) # 1) a2 /= a2[0, 0] assert ek.allclose(a2, spectrum_from_stokes([1, -1, 0, 0]), atol=1e-3) # 2) # Apply to (positive) diagonally polarized light (linear at +45˚) # Test that.. # 1) The polarization is flipped to -45˚ # 2) There is now also some (left) circular polarization a3 = M_world @ spectrum_from_stokes([1, 0, +1, 0]) assert ek.all(a3[2, 0] < UnpolarizedSpectrum(0.0)) assert ek.all(a3[3, 0] < UnpolarizedSpectrum(0.0)) # Apply to (negative) diagonally polarized light (linear at -45˚) # Test that.. # 1) The polarization is flipped to +45˚ # 2) There is now also some (right) circular polarization a4 = M_world @ spectrum_from_stokes([1, 0, -1, 0]) assert ek.all(a4[2, 0] > UnpolarizedSpectrum(0.0)) assert ek.all(a4[3, 0] > UnpolarizedSpectrum(0.0)) # Apply to right circularly polarized light # Test that the polarization is flipped to left circular a5 = M_world @ spectrum_from_stokes([1, 0, 0, +1]) assert ek.all(a5[3, 0] < UnpolarizedSpectrum(0.0)) # Apply to left circularly polarized light # Test that the polarization is flipped to right circular a6 = M_world @ spectrum_from_stokes([1, 0, 0, -1]) assert ek.all(a6[3, 0] > UnpolarizedSpectrum(0.0))
def test03_sample_ray_diff(variant_packet_spectral, origin, direction, aperture_rad, focus_dist): # Check the correctness of the sample_ray_differential() method from mitsuba.core import sample_shifted, sample_rgb_spectrum, warp, Vector3f, Transform4f cam = create_camera(origin, direction, aperture=aperture_rad, focus_dist=focus_dist) time = 0.5 wav_sample = [0.5, 0.33, 0.1] pos_sample = [[0.2, 0.1, 0.2], [0.6, 0.9, 0.2]] aperture_sample = [0.5, 0.5] ray, spec_weight = cam.sample_ray_differential(time, wav_sample, pos_sample, aperture_sample) # Importance sample wavelength and weight wav, spec = sample_rgb_spectrum(sample_shifted(wav_sample)) assert ek.allclose(ray.wavelengths, wav) assert ek.allclose(spec_weight, spec) assert ek.allclose(ray.time, time) assert ek.allclose(ray.o, origin) # ----------------------------------------_ # Check that the derivatives are orthogonal assert ek.allclose(ek.dot(ray.d_x - ray.d, ray.d_y - ray.d), 0, atol=1e-7) # Check that a [0.5, 0.5] position_sample and [0.5, 0.5] aperture_sample # generates a ray that points in the camera direction ray_center, _ = cam.sample_ray_differential(0, 0, [0.5, 0.5], [0.5, 0.5]) assert ek.allclose(ray_center.d, direction, atol=1e-7) # ---------------------------------------- # Check correctness of the ray derivatives aperture_sample = [[0.9, 0.4, 0.2], [0.6, 0.9, 0.7]] ray_center, _ = cam.sample_ray_differential(0, 0, [0.5, 0.5], aperture_sample) # Deltas in screen space dx = 1.0 / cam.film().crop_size().x dy = 1.0 / cam.film().crop_size().y # Sample the rays by offsetting the position_sample with the deltas (aperture centered) ray_dx, _ = cam.sample_ray_differential(0, 0, [0.5 + dx, 0.5], aperture_sample) ray_dy, _ = cam.sample_ray_differential(0, 0, [0.5, 0.5 + dy], aperture_sample) assert ek.allclose(ray_dx.d, ray_center.d_x) assert ek.allclose(ray_dy.d, ray_center.d_y) # -------------------------------------- # Check correctness of aperture sampling pos_sample = [0.5, 0.5] aperture_sample = [[0.9, 0.4, 0.2], [0.6, 0.9, 0.7]] ray, _ = cam.sample_ray(time, wav_sample, pos_sample, aperture_sample) ray_centered, _ = cam.sample_ray(time, wav_sample, pos_sample, [0.5, 0.5]) trafo = Transform4f(cam.world_transform().eval(time).matrix.numpy()) tmp = warp.square_to_uniform_disk_concentric(aperture_sample) aperture_v = trafo.transform_vector(aperture_rad * Vector3f(tmp.x, tmp.y, 0)) # NOTE: here we assume near_clip = 1.0 assert ek.allclose(ray.o, ray_centered.o + aperture_v) assert ek.allclose(ray.d, ek.normalize(ray_centered.d * focus_dist - aperture_v))
def test02_sample_pol_local(variant_scalar_mono_polarized): from mitsuba.core import Frame3f, Transform4f, Spectrum, UnpolarizedSpectrum, Vector3f from mitsuba.core.xml import load_string from mitsuba.render import BSDFContext, TransportMode, SurfaceInteraction3f, fresnel_conductor from mitsuba.render.mueller import stokes_basis, rotate_mueller_basis def spectrum_from_stokes(v): res = Spectrum(0.0) for i in range(4): res[i, 0] = v[i] return res # Create a Silver conductor BSDF and reflect different polarization states # at a 45˚ angle. # All tests take place directly in local BSDF coordinates. Here we only # want to make sure that the output of this looks like what you would # expect from a Mueller matrix describing specular reflection on a mirror. eta = 0.136125 + 4.010625j # IoR values of Ag at 635.816284nm bsdf = load_string("""<bsdf version='2.0.0' type='conductor'> <spectrum name="eta" value="{}"/> <spectrum name="k" value="{}"/> </bsdf>""".format(eta.real, eta.imag)) theta_i = 45 * ek.pi / 180 wi = Vector3f([-ek.sin(theta_i), 0, ek.cos(theta_i)]) ctx = BSDFContext() ctx.mode = TransportMode.Importance si = SurfaceInteraction3f() si.p = [0, 0, 0] si.wi = wi n = [0, 0, 1] si.sh_frame = Frame3f(n) bs, M_local = bsdf.sample(ctx, si, 0.0, [0.0, 0.0]) wo = bs.wo # Rotate into standard coordinates for specular reflection bi_s = ek.normalize(ek.cross(n, -wi)) bi_p = ek.normalize(ek.cross(-wi, bi_s)) bo_s = ek.normalize(ek.cross(n, wo)) bo_p = ek.normalize(ek.cross(wo, bi_s)) M_local = rotate_mueller_basis(M_local, -wi, stokes_basis(-wi), bi_p, wo, stokes_basis(wo), bo_p) # Apply to unpolarized light and verify that it is equivalent to normal Fresnel a0 = M_local @ spectrum_from_stokes([1, 0, 0, 0]) F = fresnel_conductor(ek.cos(theta_i), ek.scalar.Complex2f(eta.real, eta.imag)) a0 = a0[0, 0] assert ek.allclose(a0[0], F, atol=1e-3) # Apply to horizontally polarized light (linear at 0˚) # Test that it is.. # 1) still fully polarized (though with reduced intensity) # 2) still horizontally polarized a1 = M_local @ spectrum_from_stokes([1, +1, 0, 0]) assert ek.allclose(a1[0, 0], ek.abs(a1[1, 0]), atol=1e-3) # 1) a1 /= a1[0, 0] assert ek.allclose(a1, spectrum_from_stokes([1, 1, 0, 0]), atol=1e-3) # 2) # Apply to vertically polarized light (linear at 90˚) # Test that it is.. # 1) still fully polarized (though with reduced intensity) # 2) still vertically polarized a2 = M_local @ spectrum_from_stokes([1, -1, 0, 0]) assert ek.allclose(a2[0, 0], ek.abs(a2[1, 0]), atol=1e-3) # 1) a2 /= a2[0, 0] assert ek.allclose(a2, spectrum_from_stokes([1, -1, 0, 0]), atol=1e-3) # 2) # Apply to (positive) diagonally polarized light (linear at +45˚) # Test that.. # 1) The polarization is flipped to -45˚ # 2) There is now also some (left) circular polarization a3 = M_local @ spectrum_from_stokes([1, 0, +1, 0]) assert ek.all(a3[2, 0] < UnpolarizedSpectrum(0.0)) assert ek.all(a3[3, 0] < UnpolarizedSpectrum(0.0)) # Apply to (negative) diagonally polarized light (linear at -45˚) # Test that.. # 1) The polarization is flipped to +45˚ # 2) There is now also some (right) circular polarization a4 = M_local @ spectrum_from_stokes([1, 0, -1, 0]) assert ek.all(a4[2, 0] > UnpolarizedSpectrum(0.0)) assert ek.all(a4[3, 0] > UnpolarizedSpectrum(0.0)) # Apply to right circularly polarized light # Test that the polarization is flipped to left circular a5 = M_local @ spectrum_from_stokes([1, 0, 0, +1]) assert ek.all(a5[3, 0] < UnpolarizedSpectrum(0.0)) # Apply to left circularly polarized light # Test that the polarization is flipped to right circular a6 = M_local @ spectrum_from_stokes([1, 0, 0, -1]) assert ek.all(a6[3, 0] > UnpolarizedSpectrum(0.0))