Skip to content

Commit

Permalink
More work on docs. Added core.shapes.PolygonShape.
Browse files Browse the repository at this point in the history
  • Loading branch information
bryancole committed Mar 2, 2021
1 parent 819817a commit acb6ad7
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 57 deletions.
1 change: 1 addition & 0 deletions doc/source/api_ref/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ API Reference
faces
shapes
materials
distortions

core <core/index>
25 changes: 5 additions & 20 deletions doc/source/distortions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,30 +56,15 @@ More general distortions can be applied using the :py:class:`raypier.distortions

As previously, instances of this object are passed to a :py:class:`raypier.faces.DistortionFace` , along
with the base-surface to which the distortion is to be applied.

.. py:class:: ZernikeSeries(unit_radius=10.0, coefficients=[])
:canonical: raypier.distortions.ZernikeSeries

Describes a general distortion defined in terms of Zernike polynomials.
The ANSI single-index (J) notation is used to identify coefficients.

A recursive algorithm is used for evaluation of the function with caching
for efficient evaluation where many non-zero coefficients exist.

Both the given parameters are traits on this object and updates to either
one will automatically update the internal state of the object (and trigger
re-tracing of the model).

:param float unit_radius: Specifies the unit-radius for the Zernike polynomials.
:param list coefficients: A sequence of coefficient amplitudes, given a tuples (J, amplitude).
E.g. [(0,0.1),(2,0.3),(7,2.34)]. Any number of coefficients
can be specified.


An example of the this class in action can be seen here:

.. literalinclude:: /../../examples/zernike_distortion_example.py

.. image:: images/zernike_distortion_example.png
Here's what the model looks like in the UI.

.. image:: images/zernike_distortions_example.png

This example also demonstrates the use of a Constraints object to provide some UI controls for
easier adjustment of the relevant model parameters.

74 changes: 37 additions & 37 deletions doc/source/gaussian_beamlet_propagation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,33 +46,34 @@ Evaluating the E-field

The nice thing about Gausslet ray-tracing is that you can evaluate the E-field at any point in your model. For script-based analysis,
you can give any GaussletCollection object (obtained from a source-object after a tracing operation) to the
:py:function:`raypier.core.fields.eval_Efield_from_gausslets` function.
:py:func:`raypier.core.fields.eval_Efield_from_gausslets` function.

.. py:module:: raypier.core.fields
.. py:function:: eval_Efield_from_gausslets(gc : GaussletCollection, points : ndarray[:,3], wavelengths=None, blending=1.0) -> Efield ndarray[:,3]
:canonical: raypier.core.fields.eval_Efield_from_gausslets

Calculates the vector E-field is each of the points given. The returned
array of field-vectors will have the same length as `points` and
has `numpy.complex128` dtype.

:param GaussletCollection gc: The set of Gausslets for which the field should be calculated
:param ndarray[N,3] points: An array of shape (N,3) giving the points at which the field will be evaluated.
:param ndarray[] wavelengths: A 1d array containing the wavelengths to be used for the field calculation,
overriding the wavelengths data contained by the GaussletCollection object.
:param float blending: The 1/width of each Gaussian mode at the evaluation points. A value of unity (the default),
means the parabasal rays are determined to be the 1/e point in the field amplitude.

.. py:class:: EFieldSummation(gc : GaussletCollection, points : ndarray[:,3], wavelengths=None, blending=1.0) -> EFieldSummation object
For situations where you wish to evaluate the E-field from a set of Gausslets with different sets of evaluation points,
this class provides a small optimisation by performing the maths to convert ray-intercepts to Gaussian mode parameters
up front.

.. py:method:: evaluate(points : ndarray[:,3]) -> Efield ndarray[:,3]
Called to calculate the E-field for the given points.
Algorithms for evaluation of E-fields are provided here.

.. py:function:: raypier.core.fields.eval_Efield_from_gausslets(gc : GaussletCollection, points : ndarray[N,3], wavelengths=None, blending=1.0) -> Efield ndarray[N,3]
Calculates the vector E-field is each of the points given. The returned
array of field-vectors will have the same length as `points` and
has `numpy.complex128` dtype.

:param GaussletCollection gc: The set of Gausslets for which the field should be calculated
:param ndarray[N,3] points: An array of shape (N,3) giving the points at which the field will be evaluated.
:param ndarray[] wavelengths: A 1d array containing the wavelengths to be used for the field calculation,
overriding the wavelengths data contained by the GaussletCollection object.
:param float blending: The 1/width of each Gaussian mode at the evaluation points. A value of unity (the default),
means the parabasal rays are determined to be the 1/e point in the field amplitude.

.. py:class:: EFieldSummation(gc : GaussletCollection, points : ndarray[N,3], wavelengths=None, blending=1.0) -> EFieldSummation object
For situations where you wish to evaluate the E-field from a set of Gausslets with different sets of evaluation points,
this class provides a small optimisation by performing the maths to convert ray-intercepts to Gaussian mode parameters
up front.

.. py:method:: evaluate(points : ndarray[N,3]) -> Efield ndarray[N,3]
Called to calculate the E-field for the given points.


Beam Decomposition
Expand All @@ -90,56 +91,55 @@ will, in general, not join originate from the end-point of the input-rays.
High level `Optics` objects for beam decomposition are provided here.

.. py:class:: PositionDecompositionPlane(BaseDecompositionPlane)
:canonical: raypier.gausslets.PositionDecompositionPlane
.. py:class:: raypier.gausslets.PositionDecompositionPlane(BaseDecompositionPlane)
Defines a plane at which position-decomposition will be beformed.

.. py:attribute:: radius
:type: float
.. py:attribute:: radius
Sets the radius used for capturing incoming rays. Rays outside of this will "miss"

.. py:attribute:: curvature
:type: float
An approximate radius-of-curvature to the beam focus. This is used to improve the
phase-unwrapping of the wavefront. The default is zero, which means a plane-wave
is assumed. Negative values imply a focus behind the decomposition plane (i.e.
on the opposite side to the plane direction vector).

.. py:attribute:: resolution
:type: float
Sets the resampling density of the decomposition, in terms of the number
of new rays per `radius` extent.

.. py:attribute:: blending
:type: float
Sets the blending values for the new rays. The new rays will have Gaussian
1/e**2 intensity widths equal to `spacing`/`blending`, where the `spacing`
value is `radius`/`resolution`.

.. py:class:: AngleDecomposition(BaseDecompositionPlane)
.. py:class:: AngleDecomposition(BaseDecompositionPlane)
Defines a plane at which Gabor (angle)-decomposition is to be performed.

.. py:attribute:: sample_spacing
:type: float
Sets the sample-spacing at the decomposition plane, in microns.

.. py:attribute:: width
:type: int
A value in the range 1->512 to set the number of samples along the width of the sample-plane.

.. py:attribute:: height
:type: int
A value in the range 1->512 to set the number of samples along the height of the sample-plane.

.. py:attribute:: mask
:type: ndarray[:,:]
A 2d array with shape matching the (width, height) and dtype numpy.float64 . The array
values should be in the range 0.0 -> 1.0. This will be used to mask the input E-field.

.. py:attribute:: max_angle
:type: float
Limits the angular divergence of the outgoing rays.


Expand Down
38 changes: 38 additions & 0 deletions raypier/core/cshapes.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ from .ctracer cimport Shape, sep_, \
vector_t, subvv_, dotprod_, mag_sq_, norm_,\
addvv_, multvs_, mag_, cross_

import numpy as np


cdef class LogicalOpShape(Shape):
def __and__(self, Shape other):
Expand Down Expand Up @@ -133,3 +135,39 @@ cdef class RectangleShape(BasicShape):
return 1
else:
return 0


cdef class PolygonShape(BasicShape):
cdef:
double[:,:] _coordinates

property coordinates:
def __get__(self):
return np.asarray(self._coordinates)

def __set__(self, val):
self._coordinates = val

cdef bint point_inside_c(self, double X, double Y):
cdef:
int i, size, ct=0
double y1, y2, h, x, x1, x2
double[:,:] pts = self._coordinates

size = pts.shape[0]

y1 = pts[size-1,1]
x1 = pts[size-1,0]
for i in range(size):
y2 = pts[i,1]
x2 = pts[i,0]
h = (Y - y1) / (y2 - y1)
if 0 < h <= 1.0:
x = x1 + h*(x2 - x1)
if x > X:
ct = not ct
y1 = y2
x1 = x2
return ct!=0


32 changes: 32 additions & 0 deletions raypier/distortions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,24 @@ class BaseDistortion(HasTraits):


class NullDistortion(BaseDistortion):
"""Any zero-amplitude distortion. Mainly used in testing.
"""
pass


class SimpleTestZernikeJ7(BaseDistortion):
"""
An implementation of a specific Zernike polynomial
distortion, using J=7. Mainly used in testing.
"""

#: Defines the unit-radius for the Zernike polynomial function.
unit_radius = Float(10.0)

#: RMS amplitude of the distortion
amplitude = Float(0.001)

#: The underlying core.Distortion object
c_distortion = Instance(cdistortions.SimpleTestZernikeJ7, ())

traits_view = View(VGroup(
Expand All @@ -48,8 +59,29 @@ def on_params_change(self, evt):


class ZernikeSeries(BaseDistortion):
"""
Represents a general surface distortion in terms of a sequence of Zernike polynomials.
The Zernike terms are identified using the ANSI standard single-index notation (J).
The standard normalisation is used such that the amplitude coefficients give the RMS
deviation of the surface over the unit-disk.
A recursive algorithm is used for evaluation of the function with caching
for efficient evaluation where many non-zero coefficients exist.
Both the given parameters are traits on this object and updates to either
one will automatically update the internal state of the object (and trigger
re-tracing of the model).
This class is intended to be used with the DistortionSurface to wrap any underlying ShapedFace.
"""

#: The unit-radius for the Zernike polynomial radial function
unit_radius = Float(10.0)

#: A list of (int,float) tuples giving the amplitudes of all non-zero Zernike coefficients.
#: in terms of the ANSI standard single index J = (n*(n+1) + m)/2.
#: Any number of coefficients can be given.
coefficients = List(Tuple(Int,Float))

c_distortion = Instance(cdistortions.ZernikeDistortion)
Expand Down

0 comments on commit acb6ad7

Please sign in to comment.