Skip to content

Commit

Permalink
Did some work on the documentation. Added an API file. Moved the Gene…
Browse files Browse the repository at this point in the history
…ralLens into its own module.
  • Loading branch information
bryancole committed Jan 30, 2021
1 parent d0d91fa commit 366c0ee
Show file tree
Hide file tree
Showing 15 changed files with 476 additions and 275 deletions.
31 changes: 31 additions & 0 deletions doc/source/gaussian_beamlet_propagation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
============================
Gaussian Beamlet Propagation
============================

Gaussian beams are a solution to the paraxial wave equation. It turns out that the propagation of such modes
can be represented by a chief ray and a number of skew marginal rays which define the 1/e^2 edge (and divergence) of the beam.
It has been shown that such the propagation of such modes obeys the rules of geometric ray tracing (i.e. Snell's law).

An arbirary wavefront can be decomposed into a set of paraxial Gaussian beamlets (called "Gausslets" henceforth) and
propagated through an optical system using raytracing. This method provides a convenient route to extend a geometric ray-tracing
algorithm to obtain a physical-optics modelling solution. The method has been successfully employed in a number of commercial
optical modelling packages, such as CODE-V, FRED and ASAP. Given a set of Gausslets, the vector (E) field can be evaluated at
any position by summing the fields from each Gausslet.

The method is accurate provided some restrictions are observed:

* The Gausslets must remain paraxial (i.e. more-or-less collimated).

* Individual Gausslets should interact with refracting or reflecting surfaces over a sufficiently small area such that the
surface may be considered locally parabolic.

Typically, if either of these restrictions are violated, the solution is to interrupt the ray-tracing operation to evaluate
the field, then decompose the field into a new set of Gausslets. In cases where the incident Gausslet is sampling too large
an area of the surface for it to be considered parabolic, the field is decomposed into a grid of smaller Gausslets. At the
other extreme, Gausslets incident on a small aperture may be decomposed into a set of spatially overlapped Gausslets with
range of directions. Such an angle decomposition is sometimes known as a "Gabor Decomposition".

Raypier Gausslet Implementation
===============================

Raypier support Gausslet tracing through a GaussletCollection data-structure.
112 changes: 112 additions & 0 deletions doc/source/general_optics.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
The General Optic Framework
===========================

The General Optic framework provides the most flexible means of defining optical components. The GeneralLens class
is an optic which is composed of:

* A shape (from raypier.shapes)
* A list of surfaces (from raypier.faces)
* A list of materials (from raypier.materials)

These are high-level objects which aim to streamline the process of configuring a custom optical element. The general optic
framework is appropriate for optical elements which fit the "planar" model of a outline defined in the XY-plane with a
surface sag defined in z as a function of (x,y). Many optics are not a good fit for this description (e.g. prisms) and
hence other sub-modules provide these components.


Shapes
......

Shapes define the 2D outline of the optic in its local XY-plane (remember that every component has its own local
coordinate system. The optic can have any position and orientation in the global frame of reference).

There are two shape primitives, at the time of writing:

* RectangleShape

* CircleShape

There are two more I have yet to implement, being PolygonShape and EllipseShape.

Shapes support boolean operation so that
they can be combined into more complex shapes. For example, to make a rectangular lens
with a hole in it. You simply XOR a RectangleShape and a CircleShape, as follows::

from raypier.api import CircleShape, RectangleShape
my_shape = RectangleShape(width=30,height=25) ^ CircleShape(radius=3.0)
Likewise, shapes support AND and OR, giving you the intersection and the union of the two
shapes respectively. Internally, NOT is also available but annoyingly, the VTK boolean
operations for implicit functions don't seem to offer a way to invert them, so I couldn't
get the "not" visualisation to work.

Surfaces
........

The surfaces represent the geometry of the faces of the GeneralLens. While a simple singlet lens
will have two surfaces, a doublet will have 3. In fact, any number of surfaces can be added.

I wanted to call the _surfaces_ list of the GeneralLens "faces" but faces is already overused as an
attribute name.

There are 6 core face types supported by the General Optic framework:

* Planar
* Spherical
* Cylinderical
* Conic (a conic surface of revolution)
* Aspheric
* Axicon

These all have a "mirror" boolean trait. If this is true, the face is considered 100% reflective.
Otherwise, the reflection and transmission characteristics will be derived from the dielectric
material coefficients on either side of the surface.

Materials
.........

The materials list gives the optical properties of the dielectric on either side of each surface.
For ``n`` surfaces, we need ``n-1`` materials.

Materials define their dispersion functions either as constant values, given as refractive index and absorption-coefficient,
or as functions obtained from a database of optical properties (taken from _https://refractiveindex.info/ ). In the later
case, you can specify the dielectric material by name e.g. "N-BK7".


Put all this together, here's in example::

s1 = RectangleShape(width=30,height=25) ^ CircleShape(radius=3.0)
f1 = SphericalFace(z_height=8.0, curvature=50.0)
m1 = OpticalMaterial(from_database=False, refractive_index=1.5)
f2 = PlanarFace(z_height=1.0)
m2 = OpticalMaterial(from_database=False, refractive_index=1.1)
f3 = SphericalFace(z_height=-8.0, curvature=-50.0)
m3 = OpticalMaterial(from_database=False, refractive_index=1.6)
f4 = PlanarFace(z_height=-9.0, invert=False)
faces = [f1,f2,f3,f4]
mats = [m1, m2, m3]
lens = GeneralLens(centre=(0,0,50),
shape=s1,
surfaces=faces,
materials=mats)
src = HexagonalRayFieldSource(gauss_width=5.0,
display="wires",
opacity=0.1,
show_normals=True)
model = RayTraceModel(optics=[lens], sources=[src])
model.configure_traits()
Gives us the following result:

.. image:: images/lens_with_hole.png



Binary file added doc/source/images/axicon_trace.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/source/images/bessel_beam_xy.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/source/images/bessel_beam_xz.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/source/images/lens_with_hole.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ Contents:
:maxdepth: 2

introduction
general_optics
gaussian_beamlet_propagation
cython_branch_info
creating_new_optics

Examples <examples/index>

API Reference <api_ref/index>

Indices and tables
Expand Down
33 changes: 33 additions & 0 deletions doc/source/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The main features of ray-trace are:
- STEP export of models for integration with CAD design (using PythonOCC)
- Saving / Loading models in YAML format.
- Trace rays with full polarisation and phase information
- Physical optics propagation with "Gausslet" tracing and beam decomposition
- Dielectric Materials with simple-coating supported, including dispersion
- A basic library of materials (from RefractiveIndex.info)
-
Expand Down Expand Up @@ -46,3 +47,35 @@ Once you have the requirements, building raypier requires a compiler. The usual
should work [no sudo if you're on Windows]. I've never tried building on a Mac.

If I could figure out how the heck conda-forge worked, I'd probably use it.


The Components of a Raypier Model
=================================

The RayTraceModel object is a container for the following components:

* Optics - these represent your optical elements like lenses, mirrors polarisers etc.

* Sources - these generate the input rays for the model. The sources also hold the traced rays output of the tracing operation

* Probes - These are objects which select or sample the tracing operation result. Probes have a 3D position and orientation.

* Results - Results represent calculated quantities to be evaluated after each trace. Results do not have a 3D position.

* Constraints - Constraints are auxillary objects used to co-ordinate the parameters of a model for more convenient manipulation.


While all of the above objects are optional, you probably want at least one source object in your model (otherwise, the result
will be rather uninteresting).


Exploring the GUI
=================

Raypier is based on the Traits/TraitsUI framework. The Traits library provides a notification framework and improved type-declaration.
TraitsUI is a GUI framework that extends Traits to make developing custom GUIs fast and easy. The UI for *any* traited object
can be invoked with a call to my_object.configure_traits(). Typically, I recommend you define your base optical model in a
script where an instance of RayTraceModel is created, then launch ui GUI with a call to the model's configure_traits() method. Lets see
this in action::

14 changes: 4 additions & 10 deletions examples/bessel_beam_example.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@


from raypier.lenses import GeneralLens
from raypier.faces import AxiconFace, PlanarFace
from raypier.materials import OpticalMaterial
from raypier.shapes import CircleShape
from raypier.tracer import RayTraceModel
from raypier.gausslet_sources import CollimatedGaussletSource
from raypier.fields import EFieldPlane
from raypier.probes import GaussletCapturePlane
from raypier.api import GeneralLens, AxiconFace, PlanarFace, OpticalMaterial, CircleShape,\
RayTraceModel, CollimatedGaussletSource, EFieldPlane, GaussletCapturePlane, IntensitySurface

from raypier.intensity_image import IntensityImageView
from raypier.intensity_surface import IntensitySurface


shape = CircleShape(radius=2.0)

Expand Down
17 changes: 0 additions & 17 deletions examples/ctracer_demo_lens.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@
"""
import sys
sys.path.append('..')
import pyximport
pyximport.install()

from raypier.sources import ConfocalRaySource
from raypier.tracer import RayTraceModel
from raypier.lenses import PlanoConvexLens

import numpy


source = ConfocalRaySource(focus=(0,0,0),
direction=(0,1,0),
Expand All @@ -36,18 +32,5 @@
model = RayTraceModel(optics=[l1,],
sources=[source,])

#model.trace_detail_async()
#import time
#start = time.clock()
#model.trace_all()
#end = time.clock()
#print "traced in", end - start

#import timeit
#t = timeit.Timer("model.update = True","from __main__ import model")
#ret = t.timeit(10)
#print "time:", ret



model.configure_traits()
18 changes: 7 additions & 11 deletions examples/general_lens_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,16 @@



from raypier.shapes import CircleShape, RectangleShape
from raypier.faces import SphericalFace, PlanarFace
from raypier.api import CircleShape, RectangleShape
from raypier.api import SphericalFace, PlanarFace

from raypier.materials import OpticalMaterial
from raypier.lenses import GeneralLens
from raypier.tracer import RayTraceModel
from raypier.sources import HexagonalRayFieldSource
from raypier.api import OpticalMaterial
from raypier.api import GeneralLens
from raypier.api import RayTraceModel
from raypier.api import HexagonalRayFieldSource


#s1 = CircleShape(radius=20.0) ^ RectangleShape(width=5.,height=3.)
s1 = RectangleShape(width=30,height=25)# ^ CircleShape(radius=3.0)

# s1 = RectangleShape(width=30,height=20) | RectangleShape(width=20,height=30) | CircleShape(radius=5.0, centre=(-10,-10)) |\
# CircleShape(radius=5.0, centre=(10,-10)) | CircleShape(radius=5.0, centre=(10,10)) | CircleShape(radius=5.0, centre=(-10,10))
s1 = RectangleShape(width=30,height=25) ^ CircleShape(radius=3.0)

f1 = SphericalFace(z_height=8.0, curvature=50.0)
m1 = OpticalMaterial(from_database=False, refractive_index=1.5)
Expand Down
24 changes: 24 additions & 0 deletions raypier/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@


from .shapes import CircleShape, RectangleShape

from .general_optic import GeneralLens

from .faces import PlanarFace, SphericalFace, CylindericalFace, AsphericFace, ConicFace, \
AxiconFace

from .materials import OpticalMaterial, air

from .sources import ConfocalRaySource, ConfocalRayFieldSource, ParallelRaySource,\
GaussianBeamRaySource, SingleRaySource, HexagonalRayFieldSource, AdHocSource,\
BroadbandRaySource

from .gausslet_sources import CollimatedGaussletSource

from .tracer import RayTraceModel

from .fields import EFieldPlane

from .probes import RayCapturePlace, GaussletCapturePlane

from .intensity_surface import IntensitySurface

0 comments on commit 366c0ee

Please sign in to comment.