<jupyter_start><jupyter_text>Light sourcesLight sources are **generators** of rays. They are useful to sample spatial, angular or spectral properties of rays automatically. Make a default light object (with no arguments) emits rays as: * vertically, direction = (0, 0, 1) * from origin, position = (0, 0, 0) * wavelength = 555nm this is somewhat similar to a laser.<jupyter_code>light = Light()
list(light.emit(1))<jupyter_output><empty_output><jupyter_text>Note that the `emit` method is a Python generator so to get out the value it needs to be iterated.  Sampling directionsSupply a `phase_function` to sample angular ranges,```pythonLight(direction=isotropic)Light(direction=lambertian)```Some phase functions takes arguments, such as `cone(half_angle)`,```pythonLight(direction=functools.partial(cone, np.pi/8))```<jupyter_code>world = Node(
    name="world (air)",
    geometry=Sphere(
        radius=10.0,
        material=Material(refractive_index=1.0)
    )
)
scene = Scene(world)
light = Light(
    direction=functools.partial(cone, np.pi/4)
)
vis = MeshcatRenderer()
vis.render(scene)
for ray in light.emit(100):
    steps = photon_tracer.follow(scene, ray)
    path, decisions = zip(*steps)
    vis.add_ray_path(path)
vis.vis.jupyter_cell()<jupyter_output>You can open the visualizer by visiting the following URL:
http://127.0.0.1:7017/static/<jupyter_text>Samping positionsA spatial mask defines allowed locations from which rays can be generated.```pythonLight(position=functools.partial(rectangular_mask, 1, 1))   half side-length (x, y)Light(position=functools.partial(cube_mask, 1, 1, 1))   half side-length (x, y, z)Light(position=functools.partial(circular_mask, 1))   radius of the circle````functools.partial` is used because these take arguments.<jupyter_code># Square emitter
light = Light(position=functools.partial(square_mask, 1, 0.3))
vis = MeshcatRenderer()
vis.render(scene)
for ray in light.emit(100):
    steps = photon_tracer.follow(scene, ray)
    path, decisions = zip(*steps)
    vis.add_ray_path(path)
vis.vis.jupyter_cell()<jupyter_output>You can open the visualizer by visiting the following URL:
http://127.0.0.1:7022/static/<jupyter_text>Any combination of position and divergenceThe power of the delegate approach is that, the angular and position delegates are independent, meaning that any combination is allowed and trivial to configure. In the example below we have used a cone divergence with a square mask```pythonLight(    position=position=functools.partial(square_mask, 1, 0.3),    direction=lambertian)```  Sampling a spectrumTo sample wavelength from a spectrum use a `Distribution` object.Let's make an emission spectrum based on a Gaussian centred at 600nm. If you have experimental data you could import it as x, y column and use that instead.<jupyter_code>def make_emission_spectrum(wavelengths):
    return np.exp(-((wavelengths-600.0)/50.0)**2)
x = np.linspace(400, 800)
y = np.exp(-((x-600.0)/50.0)**2)
plt.plot(x, y)
plt.xlabel('Wavelength (nm)')
plt.grid(linestyle='dotted')
dist = Distribution(x, y)
dist.sample(np.random.uniform())
light = Light(
    wavelength=lambda: dist.sample(np.random.uniform())
)<jupyter_output><empty_output><jupyter_text>Emit 10000 rays and plot a histogram of the distribution of wavelengths against the input.<jupyter_code>plt.hist([x.wavelength for x in list(light.emit(10000))], bins=20, density=True, histtype='step', label='sample')
plt.plot(x, y/np.trapz(y, x), label='distribution')
plt.legend()
plt.xlabel("Wavelength (nm)")
plt.grid(linestyle='dotted')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12056935528886407, 'fraction_numerical': 0.025676807144850683, 'mean_word_length': 5.879078694817658, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '481549', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1228, 'n_tokens_neox': 1125, 'n_words': 332, 'path': 'examples/003 Lights.ipynb', 'repo_name': 'KColdrick/pvtrace', 'size': '3583'}