Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e42102b
new file structure
Sep 3, 2025
f56dc6e
enable preview for PR, do not forget to disable
Sep 3, 2025
f349013
fix y-axis typo
Sep 3, 2025
cf99f75
reset comments in make.jl
Sep 4, 2025
003b411
introduce CI dependent eval for sim scripts with worst exec. time
Sep 4, 2025
5ad7290
update mirror.md showcase plots
Sep 4, 2025
19c49b9
update beamsplitters.md showcase plots
Sep 4, 2025
c34de6b
update michelson.md showcase plots
Sep 4, 2025
c17ff7e
introduce global flag for cond. save
Sep 4, 2025
a04fb0d
update detectors.md showcase plots
Sep 4, 2025
25b2bc8
rm take_screenshot helper fct.
StackEnjoyer Sep 4, 2025
f40c9e8
update lenses.md showcase plots v1
StackEnjoyer Sep 4, 2025
f5480b7
fix aspherical surface render bug
Sep 5, 2025
ba61a4c
update lenses.md showcase plots v2
Sep 5, 2025
9e4eab8
add doc dev section for cond include
Sep 5, 2025
0160f2a
update rays.md fresnel plots
Sep 5, 2025
0997fc4
add iirl schematic
Sep 5, 2025
1b76200
add intersection and interaction section content
Sep 5, 2025
8a05ab6
update double_gauss.md example
Sep 5, 2025
018968a
more core API docs
Sep 5, 2025
7fb67ad
fix some typos
Sep 5, 2025
12adbe6
add tip for placeholder enable and disable in devdocs
Sep 5, 2025
e35e925
change dropdown menu structure
Sep 5, 2025
8d86a95
more core API docs
Sep 7, 2025
326f7e8
misc changes
Sep 7, 2025
650e7ce
Part 1 of moving parts of the Optical elements docs to the API sectio…
Sep 8, 2025
1984756
extend visibility arg interface
Sep 10, 2025
cfa3287
Part 2 of moving parts of the Optical elements docs to the API sectio…
Sep 10, 2025
0fa4033
delete test.md
Sep 10, 2025
8080b78
Update doublet lens and lens group images for cond. load
Sep 10, 2025
b137c5f
sdf api docs
Sep 11, 2025
aa7662d
test for zero length dir vector in ray constructors
Sep 11, 2025
e652bb7
at 1e-6 default Beam wavelength
Sep 11, 2025
81d21fc
fix Intersectable related issues
Sep 11, 2025
6698e9a
mesh api docs
Sep 11, 2025
c6a5f41
Minor changes for clarity
Sep 11, 2025
d848221
move tracing logic section to core API docs
StackEnjoyer Sep 11, 2025
85df450
update systems.md
Sep 12, 2025
00f9962
fix CI issues
Sep 12, 2025
8b67726
add ray tests
Sep 12, 2025
4348e1c
fix typos in runtests.jl
Sep 12, 2025
140167d
try and fix .svg fig
Sep 12, 2025
792edb0
update iirl.svg font to arial
Sep 12, 2025
97189a8
fix polray dir atol testing
Sep 12, 2025
f431821
reset push_preview to false
Sep 12, 2025
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ using Pkg; Pkg.add("BeamletOptics")

# Examples

For a variety of illustrated examples and tutorials, refer to the **Tutorials** and **Examples** sections of the documentation linked to above.
For a variety of illustrated examples and tutorials, refer to the **Tutorials** and **Examples** in the **Getting started** sections of the documentation linked to above.
70 changes: 41 additions & 29 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ using BeamletOptics
using Documenter
using DocumenterCitations

CairoMakie.activate!()

DocMeta.setdocmeta!(BeamletOptics, :DocTestSetup, :(using BeamletOptics); recursive=true)

bib = CitationBibliography(joinpath(@__DIR__, "src", "refs.bib"))
Expand All @@ -22,38 +20,52 @@ makedocs(;
size_threshold_ignore=["reference.md"],
sidebar_sitename = false,
),
pagesonly=true,
pages=[
"Home" => "index.md",
"Tutorials" => Any[
"Beam expander" => "tutorials/expander.md",
"Miniature microscope" => "tutorials/microscope.md",
"Michelson interferometer" => "tutorials/michelson.md"
],
"Examples" => Any[
"Spherical lenses" => "examples/spherical_lenses.md",
"Aspherical lenses" => "examples/aspherical_lenses.md",
"Double Gauss lens" => "examples/double_gauss.md",
"Lens groups" => "examples/lens_groups.md",
"Getting started" => Any[
"Tutorials" => Any[
"Beam expander" => joinpath("tutorials", "expander.md"),
"Miniature microscope" => joinpath("tutorials", "microscope.md"),
"Michelson interferometer" => joinpath("tutorials", "michelson.md"),
],
"Examples" => Any[
"Spherical lenses" => joinpath("examples", "spherical_lenses.md"),
"Aspherical lenses" => joinpath("examples", "aspherical_lenses.md"),
"Double Gauss lens" => joinpath("examples", "double_gauss.md"),
"Lens groups" => joinpath("examples", "lens_groups.md"),
],
],
"Basics" => Any[
"Introduction" => "basics/intro.md",
"Rays" => "basics/rays.md",
"Beams" => "basics/beams.md",
"Optical elements" => "basics/elements.md",
"Optical systems" => "basics/systems.md",
"Visualization" => "basics/render.md"
],
"Components" => Any[
"Overview" => "components/components.md",
"Mirrors" => "components/mirrors.md",
"Lenses" => "components/lenses.md",
"Beamsplitters" => "components/beamsplitters.md",
"Detectors" => "components/detectors.md",
"Polarizers" => "components/polarizers.md",
"Introduction" => joinpath("basics", "intro.md"),
"Rays" => joinpath("basics", "rays.md"),
"Beams" => joinpath("basics", "beams.md"),
"Optical components" => Any[
"Overview" => joinpath("basics", "components", "components.md"),
"Mirrors" => joinpath("basics", "components", "mirrors.md"),
"Lenses" => joinpath("basics", "components", "lenses.md"),
"Beamsplitters" => joinpath("basics", "components", "beamsplitters.md"),
"Detectors" => joinpath("basics", "components", "detectors.md"),
"Polarizing components" => joinpath("basics", "components", "polarizers.md"),
],
"Optical systems" => joinpath("basics", "systems.md"),
"Visualization" => joinpath("basics", "render.md"),
],
"Developer Documentation" => Any[
"Dev. guide" => "guide.md",
"API design" => "design.md",
"Developer guide" => Any[
"Contributing" => joinpath("api", "contribute.md"),
"Documentation development" => joinpath("api", "docdev.md"),
],
"API design" => Any[
"Introduction" => joinpath("api", "api.md"),
"Conventions" => joinpath("api", "conventions.md"),
"Core design" => joinpath("api", "core.md"),
"Geometry" => Any[
"Geometry representation" => joinpath("api", "geometry.md"),
"Meshes" => joinpath("api", "meshes.md"),
"SDFs" => joinpath("api", "sdfs.md"),
],
],
],
"Reference" => "reference.md"
],
Expand All @@ -64,4 +76,4 @@ deploydocs(;
repo="github.com/JuliaPhysics/BeamletOptics.jl.git",
devbranch="master",
push_preview=false,
)
)
11 changes: 11 additions & 0 deletions docs/src/api/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# API design

This part of the documentation is intended for users that want to change the internals of BMO. You can develop the package locally by typing `] dev BeamletOptics` in the REPL. An overview of all relevant topics is provided below. The following sections assume that you are in principle familiar with the concept of rays and beams, as well as optical elements -- e.g. mirrors -- in the context of this package. If not, it is recommended that you read the [Rays](@ref), [Beams](@ref) and [Optical components](@ref) sections first.

!!! warning
The developer section is very much WIP...

```@contents
Pages = ["conventions.md", "core.md", "geometry.md", "meshes.md", "sdfs.md"]
Depth = 2
```
17 changes: 17 additions & 0 deletions docs/src/api/contribute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Contributing

While not strictly adhering to the [SciML Style Guide](https://github.com/SciML/SciMLStyle), we recommend consulting the guide as a baseline for contributions to this package. Refer to the [SciML Contributors Guide](https://github.com/SciML/ColPrac/blob/master/README.md) as well. Ideally, your contribution features:

- tests for new or changed functionality
- docstrings for relevant functions
- documentation and examples

We would also love to feature your work with this package as part of the **Examples** section.

# Contributors

The following is a list of people who have made significant contributions to the development of BMO:

- Hugo Uittenbosch
- Oliver Kliebisch
- Aurelius Manny
30 changes: 30 additions & 0 deletions docs/src/api/conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Conventions

In order to ensure implicit and explicit compliance with large parts of the API, the following conventions need to be used. Below you can find some essential conventions that need to be followed. For specific components or parts of the code base, refer to the documentation if certain guidelines need to be followed.

!!! warning
Failure to comply with the following conventions can lead to spurious effects and silent bugs when using the API of this package!

## Global optical axis

Commonly, the z-axis is used as the principal optical axis when defining equations or alignment of optical systems and models. **This is not the case for BMO**, which uses the global y-axis in positive direction as the "global optical axis" in which effects are described. This is motivated by the plotting axes of [Makie](https://docs.makie.org/stable/), which uses a coordinate system where the x- and y-axis form the horizontal plane and the z-axis is orthogonal (upwards).

!!! info
For (optical) equations that are depended on a global coordinate system, use a basis where the **global y-axis (`[0,1,0]`)** is the optical axis and the x-z-axes form the transverse plane. Global propagation along this axis is defined with a direction vector of `[0,1,0]`.

## Right-handedness

All **coordinate systems** are or must be defined **right-handed**! All normal vectors are or must be defined right-handed!

## Counter-clockwise rotation

All **rotations** are or must be performed in a **counter-clockwise** manner for a positive rotation angle ``\theta > 0`` and vice-versa!
For a definition of rotation matrix order, refer to this [article](https://dominicplein.medium.com/extrinsic-intrinsic-rotation-do-i-multiply-from-right-or-left-357c38c1abfd).

## Normal vector direction

For a closed volume BMO assumes that the surface normal vector points outside of the volume.

!!! info "Normal vector direction definition"
Equations to calculate optical effects often rely on the normal vector at the ray intersection location to work correctly and point in a specific direction.
It is important to ensure that this condition is fulfilled when spurious effects occur.
105 changes: 105 additions & 0 deletions docs/src/api/core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Core design

The BMO package is intended to provide optical simulation capabilites with as much "out-of-the-box" comfort as possible, meaning that users should not have to worry about e.g. providing the correct optical sequence and exact alignment of objects. The following five design principles are core assumptions of the underlying API:

1. Optical interactions are decoupled from the underlying geometry representation
2. Optical elements are closed volumes or must mimic as such (exceptions apply, e.g. coatings)
3. Elements should be easily moveable and have working interactions for most angles of incidence
3. Without additional knowledge, tracing is performed non-sequentially
4. With additional knowledge, tracing is performed sequentially

## Intersect-Interact-Repeat-Loop

The first two principles will be elaborated upon in more detail in the [Geometry representation](@ref) section. For the latter two design decisions, the following high-level solver schematic can be used to abstract the steps that are performed when calling [`solve_system!`](@ref) with an input system and beam:

```@raw html
<img src="../iir_loop.svg" alt="my figure" style="width:100%; height:auto;"/>
```

This scheme is loosely referred to as the **Intersect-Interact-Repeat-Loop** and consists of the following steps:

1. Calculate the closest **Intersection** between a ray/beam and the objects within the system
2. Calculate the optical **Interaction** that occurs at the surface or within the volume of the element
3. Attach or overwrite the next part of the ray chain or beam tree
4. Use the new information to repeat 1.

Once this procedure has been completed, the alignment of the system or other time-dependent optical properties (e.g. the phase of a Gaussian beamlet) can be updated. When rerunning the solver, the algorithm will try to reuse information about the previously intersected objects to speed up the calculation of the next simulation step. This is described in more detail in the sections: [Tracing systems](@ref) and [Retracing systems](@ref).

The next sections will focus on the **Intersection** and **Interaction** steps.

## Intersections

Calculating intersections between straight lines, i.e. rays, and surfaces is a central challenge for every geometrical optics simulator. This must be done with high numerical precision, since many optical effects are sensitive on the order of the wavelength of the light under consideration with respect to position and direction [Hecht:2018; p. 265 ff](@cite). In order to define this mathematically or algorithmically, many different methods exist [Hanrahan:1989](@cite). The first question is, how is the geometry of the problem defined. This topic is treated in the [Geometry representation](@ref) section. The second question concerns then the algorithm or equation that allows to calculate the point of intersection between a ray and the surface of the element. This function is called `intersect3d` and is, at its core, defined for each `shape` and `ray`:

```@docs; canonical=false
BeamletOptics.intersect3d(::BeamletOptics.AbstractShape, ::BeamletOptics.AbstractRay)
```

Regardless of the underlying concrete implementation, each call of `intersect3d` must return `nothing` or the following type:

```@docs; canonical=false
BeamletOptics.Intersection
```

Since an optical element can consist of multiple joint shapes, the return type must store which specific part of the object was hit.

## Interactions

Optical interactions are performed after the point of intersection has been determined. The `interact3d` interface allows users to implement algorithms that calculate or try to mimic optical effects. The fidelity of the algorithm is effectively only limited by the amount of information that can be passed into the `interact3d` interface. The method is defined as follows:

```@docs; canonical=false
BeamletOptics.interact3d(::BeamletOptics.AbstractSystem, ::BeamletOptics.AbstractObject, ::BeamletOptics.AbstractBeam, ::BeamletOptics.AbstractRay)
```

As with the `intersect3d` method, a predefined return type must be provided in order to make the [`solve_system!`](@ref) interface work. The `AbstractInteraction` is used in order to create "building blocks" from which the output beam is constructed.

```@docs; canonical=false
BeamletOptics.AbstractInteraction
```

The `interact3d` return type limits the interface to only accepting one new `beam` segment per interaction at the moment. The developer needs to take into account that after e.g. a lens surface air-to-glass interaction, the solver "forgets" that the next logical step is to immediatly test against the lens again, since the most likely step will be the refraction at the glass-to-air surface. In order to alleviate this issue, the `Hint` type can be used.

## Hints

As mentioned in the previous section, the [`BeamletOptics.Hint`](@ref) interface allows developers to manipulate the non-sequential solver algorithm into testing against a specific component and shape during the next cycle of the [Intersect-Interact-Repeat-Loop](@ref). This interface has very high priority during intersection testing.

```@docs; canonical=false
BeamletOptics.Hint
```

The main reason for this is the intersection ambiguity encountered at interfaces between air-tight component interfaces, e.g. [Plate beamsplitters](@ref) or cemented [Doublet lenses](@ref). This is caused by the fact that for a ray with a starting point at this interface, technically both shapes are being "touched" at the same time. Additional program logic considering the ray direction of propagation can not always resolve this ambiguity. Therefore the task of providing additional information to the solver via the `Hint` interface is placed as a **burden on the developer**.

!!! tip
Use of the `Hint` interface is primarily intended for multishape objects with joint surfaces.

## Tracing logic

### Tracing systems

In the initial state, is is assumed that the problem consists of `objects <: AbstractObject` (in a system) and a `beam <: AbstractBeam` with a defined starting position and direction. No additional information is provided, and the specific path of the beam is not known beforehand. Consequently, brute force tracing of the optical system is required, involving testing against each individual element to determine the trajectory of the beam.

```@docs; canonical=false
BeamletOptics.trace_system!
```

This non-sequential mode is comparatively safe in determining the "true" beam path, but will scale suboptimally in time-complexity with the amount of optical elements. After solving the system, the beam path is known and can be potentially reused in the future.

!!! info "Object order"
Unlike with classic, surface-based ray tracers, the order in which objects are listed in the [`System`](@ref) object vector/tuple is not considered for the purpose of tracing or retracing.

### Retracing systems

Once a system has been traced for the first time, the system and beam can be solved again. However, this time the solver will try to reuse as much information from the previous run as possible by testing if the previous beam trajectory is still valid in a sequential tracing mode. Retracing systems assumes that the kinematic changes (e.g. optomechanical aligment) between the current tracing procedure and the previous one are small. If an intersection along the beam trajectory becomes invalid, the solver will perform a non-sequential trace for all invalidated parts of the beam.

```@docs; canonical=false
BeamletOptics.retrace_system!
```

## CPU and GPU support

Parallizing the execution of a [`solve_system!`](@ref) call on the CPU is straight-forward for systems that do not feature objects which can be mutated during runtime, e.g. detectors like the [`Photodetector`](@ref). For each beam or ray the solution is independent and the solver can run on multiple threads. Special consideration needs to be taken when implementing mutable elements as mentioned above, since multiple threads might be able to access the underlying memory, leading to race conditions. Specifically, this means ensuring atomic write and read access.

With respect to GPU acceleration, this is not the case. Currently, all available implementations of [`solve_system!`](@ref) are highly branching algorithms which can not be implemented in a parallized way easily. This will most likley require a specific new subtype of the [`BeamletOptics.AbstractSystem`](@ref) with determinable sequential properties. This is not a development goal as of the writing of this section.



Loading