gtrace.optcomp

Define optical components for gtrace.

Attributes

pi

array

sqrt

__author__

__copyright__

__credits__

__license__

__version__

__maintainer__

__email__

__status__

_FLAT_CURVATURE

_LENS_SHAPES

_SOLVE_ITERATIONS

Exceptions

LensGeometryError

Raised when the lens asked for cannot be made out of the blank it

Classes

_ProbeRay

A bare ray to ask an optics where its surfaces are.

Optics

A general optics class from which other specific

Mirror

Representing a partial reflective mirror.

CyMirror

Representing a partial reflective cylindrical mirror. Note that both HR and AR surfaces are treated as cylindrical if you specify non-zero ROC for them. The curve directions of the two surfaces must be the same.

Lens

A lens: a substrate that refracts at both faces.

CyLens

A cylindrical lens: a substrate that refracts at both faces and

Functions

_sagitta(invROC, r)

How far the middle of an arc stands off its own chord.

sagitta(inv_ROC, diameter)

Sagitta of a spherical face spanning an aperture.

lens_power(inv_ROC_HR, inv_ROC_AR, center_thickness, n)

Optical power 1/f of a thick lens, in gtrace's sign convention.

_lens_shape(shape)

Look a shape name up, defaulting to the symmetric family.

_check_center_thickness(thickness, sag_HR, sag_AR)

Refuse a blank the two faces would eat through.

_check_lens_inputs(f, n, diameter, thickness)

Reject the arguments no lens can be made from, whatever its shape.

_face_kind(inv_ROC)

Whether a face is convex, concave or flat, in the vocabulary the

_curvatures_at(f, family, flat_face, n, ...)

The two curvatures giving focal length f, for a centre thickness

solve_lens_curvatures(f[, shape, diameter, thickness, ...])

Curvatures of the two faces of a lens of focal length f.

rescale_lens_curvatures(inv_ROC_HR, inv_ROC_AR, f[, ...])

Scale both curvatures by one common factor until the lens has focal

_scale_root(a, b, C, s0, f)

Solve a*s^2 + b*s = C for the scale factor, on the branch that

Module Contents

gtrace.optcomp.pi
gtrace.optcomp.array
gtrace.optcomp.sqrt
gtrace.optcomp.__author__ = 'Yoichi Aso'
gtrace.optcomp.__credits__ = ['Yoichi Aso']
gtrace.optcomp.__license__ = 'BSD'
gtrace.optcomp.__version__ = '0.8.0'
gtrace.optcomp.__maintainer__ = 'Yoichi Aso'
gtrace.optcomp.__email__ = 'asoy01@gmail.com'
gtrace.optcomp.__status__ = 'Beta'
gtrace.optcomp._sagitta(invROC, r)

How far the middle of an arc stands off its own chord.

Parameters:
  • invROC (float) – Inverse radius of curvature. Zero is a flat face, which stands off nothing.

  • r (float) – Half the chord length.

Returns:

Never negative. The answer is a distance, and which side of the chord the arc is on is not asked here.

Return type:

float

class gtrace.optcomp._ProbeRay(pos, dirVect)

Bases: object

A bare ray to ask an optics where its surfaces are.

isHit() reads nothing but the origin and the direction of what it is given, so asking it a question about geometry does not need a beam with a q parameter, a power and a wavelength. Handing it a GaussianBeam would mean inventing those, and they would be a fiction: none of them takes part in the answer. verify_surfaces.py holds isHit() to that, by asking it the same question both ways.

pos
dirVect
class gtrace.optcomp.Optics

Bases: traits.api.HasTraits

A general optics class from which other specific optics classes are derived.

Variables:
  • name (str) – Name of the optics.

  • center (array) – Center position of the optics. array of shape(2,).

  • rotationAngle (float) – This angle defines the orientation of the optics.

  • max_stray_order (int or None) –

    Upper limit of the stray order computed when a beam hits this optics, overriding the order given to non_seq_trace. None means the trace-wide order is used.

    How deep the ghost beams inside a substrate are worth chasing depends on the part an element plays in the system - the ghosts of a beam splitter usually matter, those of a steering mirror usually do not - so it belongs to the element, next to term_on_HR, rather than to the trace.

name
center
rotationAngle
max_stray_order
isHit()

A function to see if a beam hits this optics or not.

Parameters:

beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

Returns:

The return value is a dictionary with the following keys: isHit, position, distance, face

isHit: This is a boolean to answer whether the beam hit the optics or not.

position: A numpy array containing the coordinate values of the intersection point between the beam and the optics. If isHit is False, this parameter does not mean anything.

distance The distance between the beam origin and the intersection point.

face: An optional string identifying which face of the optics was hit. For example, face can be either “HR” or “AR” for a mirror. face can also be “side”, meaning that the beam hits a side of the optics, which is not meant to be used, e.g. the side of a mirror. In this case, the beam have reached a dead end.

Return type:

Dict

hit(order=0, threshold=0.0)

A function to hit the optics with a beam.

This function attempts to hit the optics with the source beam, beam.

Parameters:
  • beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

  • order (int, optional) – The largest stray_order a beam produced here may have. The count is carried over from the incident beam, not started afresh. Defaults 0.

  • threshold (float, optional) – The power threshold for internal reflection calculation. If the power of an auxiliary beam falls below this threshold, further propagation of this beam will not be performed. Defaults 0.0.

Returns:

(isHit, beamDict, face)

isHit This is a boolean to answer whether the beam hit the optics or not.

beamDict A dictionary containing resultant beams.

face An optional string identifying which face of the optics was hit. For a mirror, face is any of “HR”, “AR” or “side”.

Return type:

{boolean, dict, str}

get_corners()

The corners of the substrate, going around it.

Where get_side_info() describes the two sides as centre, normal and length - which is what hit testing needs - this gives the points themselves, which is what anything pointing at the element needs: a front end snapping a measurement to a corner, or a drawing that wants the outline.

The corners sit on the chord planes of the two faces, not on the faces themselves: a curved face leaves its apex a sagitta away from the line joining its two corners.

Returns:

Four points of shape (2,), starting at one end of the front face and going round the substrate.

Return type:

list of numpy.ndarray

contains_segment(p1, p2, rtol=1e-09)

Whether the straight segment from p1 to p2 lies wholly inside this substrate.

A point is measured against the same surfaces the tracer hits, so the answer agrees with what a beam would do. isHit() reports a surface only when it is approached from outside - it rejects any face the ray is leaving through - and that is what makes this simple: from inside the substrate, isHit() finds nothing at all, and an entry found partway along the segment means the segment starts outside.

Endpoints exactly on a face count as inside, since that is where a measurement is usually taken from: the optical thickness of a substrate is measured between the apexes of its two faces.

Parameters:
  • p1 (array_like) – The ends of the segment, in global coordinates.

  • p2 (array_like) – The ends of the segment, in global coordinates.

  • rtol (float, optional) – How close to an end an entry may be found and still be read as that end sitting on the face, relative to the length of the segment. Defaults 1e-9.

Return type:

bool

contains_point(point, dirVect=None, rtol=1e-09)

Whether a point lies inside this substrate.

Three questions, all put to isHit(), which reports a surface only when it is approached from outside:

  • looking one way from the point, is a surface entered?

  • looking the other way, is one entered?

  • coming from well outside, does the substrate begin before the point is reached?

From inside the substrate the first two find nothing: every face is one the ray is leaving through. Either of them finding something places the point outside - including the awkward case of a point in the hollow of a concave face, which is enclosed by the substrate on three sides and would fool any test that only asked how far the material reaches. The third question is what separates a point inside from one out in the open, where nothing is entered either.

A point on a face counts as inside, to within rtol of the reach of the probes.

Parameters:
  • point (array_like) – The point, in global coordinates.

  • dirVect (array_like, optional) – The line to look along. Defaults to the front face normal.

  • rtol (float, optional) – Tolerance, relative to the reach of the probes. Defaults 1e-9.

Return type:

bool

_probe_reach(point)

A distance that starts a probe ray outside this substrate, whatever direction it comes from.

_isHitSurface_(beam, surface_center, normal_vector, surface_size=1.0, inv_ROC=0.0)

Determine if a beam hit a surface

Parameters:

beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

Returns:

ans – A dictionary with the following keys: “isHit”: A boolean value whether the beam hit the surface or not. “Intersection Point”: numpy array of the coordinates of the intersection point. “distance”: Distance between the origin of the beam and the intersection point. “localNormVect”: A numpy array representing the normal vector of the surface at the intersection point. “localNormAngle”: The angle of the localNormVect.

Return type:

dict

class gtrace.optcomp.Mirror(HRcenter=[0.0, 0.0], normAngleHR=0.0, normVectHR=None, diameter=25.0 * cm, thickness=15.0 * cm, wedgeAngle=0.25 * pi / 180.0, inv_ROC_HR=1.0 / 7000.0, inv_ROC_AR=0.0, Refl_HR=0.99, Trans_HR=0.01, Refl_AR=0.01, Trans_AR=0.99, n=1.45, name='Mirror', HRtransmissive=False, HRreflective=True, term_on_HR=False, term_on_HR_order=0, term_on_HR_transmits=False, max_stray_order=None)

Bases: Optics

Representing a partial reflective mirror.

Variables:
  • curve_direction (str) – Either ‘h’ or ‘v’. If it is ‘h’ the mirror is curved in horizontal plane. If ‘v’, it is vertical.

  • HRcenter (array) – The position of the center of the arc of the HR surface. shape(2,).

  • HRcenterC (array) – The position of the center of the chord of the HR surface. shape(2,).

  • normVectHR (array) – Normal vector of the HR surface. shape(2,)

  • normAngleHR (float) – Angle of the HR normal vector. In radians.

  • ARcenter (array) – The position of the apex of the arc of the AR surface. shape(2,). Note that this is the counterpart of HRcenter, not of HRcenterC: it lies one sagitta out of the substrate. Anything that asks for the centre of a chord - line_arc_intersection(), or an arc drawn from its own chord - wants ARcenterC instead.

  • ARcenterC (array) – The position of the center of the chord of the AR surface. shape(2,).

  • normVectAR (array) – Normal vector of the HR surface. shape(2,)

  • normAngleAR (float) – Angle of the HR normal vector. In radians.

  • HRtransmissive (boolean) – A boolean value defaults to False. If True, this mirror is supposed to transmit beams on the HR surface. Therefore, for the first encounter of a beam on the HR surface of this mirror will not increase the stray_order. This flag should be set to True for beam splitters and input test masses.

  • HRreflective (boolean) – A boolean value defaults to True. If False, the HR surface of this optics is not supposed to reflect beams. Therefore, every reflection at the HR surface, from outside or from inside the substrate, increases the stray_order: such a reflection is a ghost. The mirror image of HRtransmissive. This flag should be set to False for lenses.

  • term_on_HR (boolean) – If this is True, a beam with stray_order <= self.term_on_HR_order will be terminated when it hits on HR. This is to avoid the inifinite loop of non-sequencial trace by forming a cavity.

  • term_on_HR_order (int) – Integer to specify the upper limit of the stray order used to judge whether to terminate the non sequential trace or not on HR reflection.

  • term_on_HR_transmits (boolean) – What term_on_HR stops. False, the default, stops the beam at the surface: nothing is computed, which is what term_on_HR has always done. True stops only the reflection that would form the cavity, and lets the element be hit as usual otherwise, so the beam transmitted through the substrate carries on and the ghosts inside it are unfolded, counted and capped by order and max_stray_order like any others. Only the external reflection off the HR is dropped; a ghost leaving through the HR from inside the substrate is not. Has no effect unless term_on_HR is True, as term_on_HR_order has none.

  • anchor_point (str) –

    The point the optics is held by: ‘HRcenter’, the apex of the HR arc, or ‘center’, the middle of the substrate. It is the point that stays put when inv_ROC_HR changes - the other one moves, since the sagitta between them is what the curvature changed - and the point the optics turns about when normAngleHR or normVectHR is assigned.

    Defaults to ‘HRcenter’. Regrinding a telescope mirror is done to change the magnification, not to move the beam, and a layout puts the spot on the HR surface, so the arc has to stay under the spot while the substrate moves back behind it; steering a mirror likewise pivots the reflection point, not the substrate.

    ’center’ is for an optics the beam goes through rather than off, where the substrate is what is bolted to the bench and the faces are free to move on it. Lens defaults to it.

HRcenter
HRcenterC
sagHR
normVectHR
normAngleHR
ARcenter
ARcenterC
sagAR
normVectAR
normAngleAR
diameter
ARdiameter
thickness
wedgeAngle
n
inv_ROC_HR
inv_ROC_AR
_geom_cache
Refl_HR
Trans_HR
Refl_AR
Trans_AR
anchor_point
draw_HR_marker = True
assembled_to = None
assembly_offset = None
assembly_angle = 0.0
fix_rotation = True
_assemble_name = None
name = 'Mirror'
HRtransmissive = False
HRreflective = True
term_on_HR = False
term_on_HR_order = 0
term_on_HR_transmits = False
max_stray_order = None
copy()
_geometry_key()

Every value the derived geometry below is computed from.

Used to decide whether a cached result still describes this optics: it is recomputed when the key differs from the one it was computed for. Comparing the values is deliberate, rather than listening for trait changes. An in-place write such as opt.center[0] = 5 fires no notification, so a cache invalidated by notification would go on returning the geometry of the old position, and nothing would say so.

Subclasses that compute their geometry from anything else must extend this. CyMirror does, for curve_direction.

Returns:

Comparable by value, and cheap to build - well under a microsecond, against tens of microseconds to recompute what it guards.

Return type:

tuple

_geometry()

The store of derived geometry for the current shape and pose.

Returns an empty dict once either has changed, so a caller finds what it put there only while that is still what the optics looks like.

Returns:

Whatever the callers have put in it, keyed by name.

Return type:

dict

_bounding_radius()

The radius of a circle about center that contains the whole substrate.

isHit() uses it to reject a beam before testing the four faces one at a time. It must never come out too small: a radius that cuts inside the substrate makes a beam that does hit the optics be reported as missing, and that is a wrong answer with nothing to announce it. So the corners are taken exactly, and the bulge of a curved face is added on top of them rather than fitted in.

Return type:

float

_misses_bounding_circle(beam)

Whether the beam stays clear of the circle that holds the whole substrate, and so cannot touch any face of it.

A test isHit() puts in front of the per-face ones. It is allowed to say False about a beam that misses - the faces are then asked and give the right answer - but it must never say True about one that hits. Tracing the KAGRA interferometer, 95% of the calls end here.

Parameters:

beam (gtrace.beam.GaussianBeam or _ProbeRay) – Anything with pos and dirVect.

Return type:

bool

get_side_info()

Return information on the sides of the mirror. Returned value is a list of two tuples like [(center1, normVect1, length1), (center2, normVect2, length2)] Each tuple corresponds to a side. center1 is the coordinates of the center of the side line. normVect1 is the normal vector of the side line. length1 is the length of the side line.

Do not write into what this returns. The same list and the same arrays are handed to every caller until the shape or the pose of the optics changes. Tracing a layout asks for this once per beam per element, which is thousands of times for the same answer.

Return type:

[(float, float, float), (float, float, float)]

get_corners()

The four corners of the substrate: the two ends of the HR chord first, then the two ends of the AR chord, going round.

The wedge is in here - it is what makes the two sides different lengths - and so is the fact that a curved face meets the sides at its chord rather than at its apex.

Returns:

Four points of shape (2,): HR left, HR right, AR right, AR left, where left and right are across the front face.

Return type:

list of numpy.ndarray

rotate(angle, center=False)

Rotate the optics rigidly about a pivot.

Parameters:
  • angle (float) – Angle of rotation, in radians.

  • center (boolean or array, optional) – The pivot. False, the default, is whatever point anchor_point names - the point the optics is held by, and the pivot the viewer turns it about. A mirror anchors on the apex of its HR face, so for every mirror this is what rotate() has always done; a lens anchors on the middle of its substrate and turns about that. True is the middle of the substrate whatever the anchor says. An array is a point in global coordinates.

translate(trVect)
draw(cv, drawName=False)

Draw itself

isHit(beam)

A function to see if a beam hits this optics or not.

Parameters:

beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

Returns:

The return value is a dictionary with the following keys: isHit, position, distance, face

isHit: This is a boolean to answer whether the beam hit the optics or not.

position: A numpy array containing the coordinate values of the intersection point between the beam and the optics. If isHit is False, this parameter does not mean anything.

distance The distance between the beam origin and the intersection point.

face: An optional string identifying which face of the optics was hit. For example, face can be either “HR” or “AR” for a mirror. face can also be “side”, meaning that the beam hits a side of the optics, which is not meant to be used, e.g. the side of a mirror. In this case, the beam have reached a dead end.

Return type:

Dict

hit(beam, order=0, threshold=0.0, face=False)

A function to hit the optics with a beam.

This function attempts to hit the optics with the source beam, beam.

Parameters:
  • beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

  • order (int, optional) – The largest stray_order a beam produced here may have. The count is carried over from the incident beam, not started afresh. Defaults 0.

  • threshold (float, optional) – The power threshold for internal reflection calculation. If the power of an auxiliary beam falls below this threshold, further propagation of this beam will not be performed. Defaults 0.0.

Returns:

(isHit, beamDict, face)

isHit This is a boolean to answer whether the beam hit the optics or not.

beamDict A dictionary containing resultant beams.

face An optional string identifying which face of the optics was hit. For a mirror, face is any of “HR”, “AR” or “side”.

Return type:

{boolean, dict, str}

hitFromHR(beam, order=0, threshold=0.0, verbose=False)

Compute the reflected and deflected beams when an input beam hit the HR surface.

A beam is produced as long as its stray_order is not above order and its power is over the threshold. The stray_order of the incident beam is carried over, so a beam that is already stray leaves less of the allowance for the ghosts made here.

Parameters:
  • beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

  • order (int, optional) – The largest stray_order a beam produced here may have. The count is carried over from the incident beam, not started afresh. Defaults 0.

  • threshold (float, optional) – The power threshold for internal reflection calculation. If the power of an auxiliary beam falls below this threshold, further propagation of this beam will not be performed. Defaults 0.0.

  • verbose (boolean, optional) – Print useful information.

Returns:

beams – Dictionary of reflected and deflected beams.

Return type:

dict

hitFromAR(beam, order=0, threshold=0.0, verbose=False)

Compute the reflected and deflected beams when an input beam hit the AR surface.

A beam is produced as long as its stray_order is not above order and its power is over the threshold. The stray_order of the incident beam is carried over, so a beam that is already stray leaves less of the allowance for the ghosts made here.

Parameters:
  • beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

  • order (int, optional) – The largest stray_order a beam produced here may have. The count is carried over from the incident beam, not started afresh. Defaults 0.

  • threshold (float, optional) – The power threshold for internal reflection calculation. If the power of an auxiliary beam falls below this threshold, further propagation of this beam will not be performed. Defaults 0.0.

  • verbose (boolean, optional) – Print useful information.

Returns:

beams – Dictionary of reflected and deflected beams.

Return type:

dict

_normAngleHR_changed(old, new)
_normVectHR_changed(old, new)
_HRcenterC_changed(old, new)
_HRcenter_changed(old, new)
_center_changed(old, new)
_wedgeAngle_changed(old, new)
_inv_ROC_HR_changed(old, new)
_inv_ROC_AR_changed(old, new)
_diameter_changed(old, new)
class gtrace.optcomp.CyMirror(HRcenter=[0.0, 0.0], normAngleHR=0.0, normVectHR=None, diameter=25.0 * cm, thickness=15.0 * cm, wedgeAngle=0.25 * pi / 180.0, inv_ROC_HR=1.0 / 7000.0, inv_ROC_AR=0.0, Refl_HR=0.99, Trans_HR=0.01, Refl_AR=0.01, Trans_AR=0.99, n=1.45, name='Mirror', HRtransmissive=False, HRreflective=True, term_on_HR=False, term_on_HR_order=0, term_on_HR_transmits=False, max_stray_order=None, curve_direction='h')

Bases: Mirror

Representing a partial reflective cylindrical mirror. Note that both HR and AR surfaces are treated as cylindrical if you specify non-zero ROC for them. The curve directions of the two surfaces must be the same.

A cylinder focuses in one plane and does nothing in the other, so a beam leaving one of these is astigmatic even at normal incidence. Away from normal incidence the two directions are not a relabelling of each other: a surface of radius R at incidence theta presents an effective radius R*cos(theta) in the plane of incidence and R/cos(theta) perpendicular to it, so ‘h’ gives a focal length of R*cos(theta)/2 and ‘v’, of the same radius, gives R/(2*cos(theta)).

Only ‘h’ is visible in the drawing. What the plane of the trace cuts out of a ‘v’ cylinder is a straight line, so the faces are drawn straight and the focusing happens entirely out of the page.

The ray matrices are Siegman, Lasers, Table 15.1, with the curvature given to one plane and zero to the other; see cyl_refl_defl_angle. Note that only in reflection does the uncurved plane come out as the identity. In transmission it keeps the tilt scaling and the index change, and loses the power alone.

Variables:
  • curve_direction (str) – Either ‘h’ or ‘v’. If it is ‘h’ the mirror is curved in horizontal plane. If ‘v’, it is vertical.

  • HRcenter (array) – The position of the center of the arc of the HR surface. shape(2,).

  • HRcenterC (array) – The position of the center of the chord of the HR surface. shape(2,).

  • normVectHR (array) – Normal vector of the HR surface. shape(2,)

  • normAngleHR (float) – Angle of the HR normal vector. In radians.

  • ARcenter (array) – The position of the apex of the arc of the AR surface. shape(2,). Note that this is the counterpart of HRcenter, not of HRcenterC: it lies one sagitta out of the substrate. Anything that asks for the centre of a chord - line_arc_intersection(), or an arc drawn from its own chord - wants ARcenterC instead.

  • ARcenterC (array) – The position of the center of the chord of the AR surface. shape(2,).

  • normVectAR (array) – Normal vector of the HR surface. shape(2,)

  • normAngleAR (float) – Angle of the HR normal vector. In radians.

  • HRtransmissive (boolean) – A boolean value defaults to False. If True, this mirror is supposed to transmit beams on the HR surface. Therefore, for the first encounter of a beam on the HR surface of this mirror will not increase the stray_order. This flag should be set to True for beam splitters and input test masses.

  • HRreflective (boolean) – A boolean value defaults to True. If False, the HR surface of this optics is not supposed to reflect beams. Therefore, every reflection at the HR surface, from outside or from inside the substrate, increases the stray_order: such a reflection is a ghost. The mirror image of HRtransmissive. This flag should be set to False for lenses.

  • term_on_HR (boolean) – If this is True, a beam with stray_order <= self.term_on_HR_order will be terminated when it hits on HR. This is to avoid the inifinite loop of non-sequencial trace by forming a cavity.

  • term_on_HR_order (int) – Integer to specify the upper limit of the stray order used to judge whether to terminate the non sequential trace or not on HR reflection.

  • term_on_HR_transmits (boolean) – What term_on_HR stops. False, the default, stops the beam at the surface: nothing is computed, which is what term_on_HR has always done. True stops only the reflection that would form the cavity, and lets the element be hit as usual otherwise, so the beam transmitted through the substrate carries on and the ghosts inside it are unfolded, counted and capped by order and max_stray_order like any others. Only the external reflection off the HR is dropped; a ghost leaving through the HR from inside the substrate is not. Has no effect unless term_on_HR is True, as term_on_HR_order has none.

diameter = 0.25
HRcenter = [0.0, 0.0]
thickness = 0.15
wedgeAngle
ARdiameter
inv_ROC_HR = 0.00014285714285714287
inv_ROC_AR = 0.0
Refl_HR = 0.99
Trans_HR = 0.01
Refl_AR = 0.01
Trans_AR = 0.99
n = 1.45
name = 'Mirror'
HRtransmissive = False
HRreflective = True
term_on_HR = False
term_on_HR_order = 0
term_on_HR_transmits = False
max_stray_order = None
curve_direction = 'h'
copy()
_geometry_key()

Mirror’s key, and which way the cylinder is turned: that is what decides whether the faces meet the sides at their chords or at their apexes. See Mirror._geometry_key.

get_side_info()

Return information on the sides of the mirror. Returned value is a list of two tuples like [(center1, normVect1, length1), (center2, normVect2, length2)] Each tuple corresponds to a side. center1 is the coordinates of the center of the side line. normVect1 is the normal vector of the side line. length1 is the length of the side line.

Do not write into what this returns. The same list and the same arrays are handed to every caller until the shape or the pose of the optics changes. Tracing a layout asks for this once per beam per element, which is thousands of times for the same answer.

Return type:

[(float, float, float), (float, float, float)]

get_corners()

The four corners of the substrate. See Mirror.get_corners.

A cylinder curved across the plane of the drawing has no curvature in it, so its faces meet the sides at their apexes and the substrate is that much thicker in section. That is the same distinction get_side_info() makes, and for the same reason.

isHit(beam)

A function to see if a beam hits this optics or not.

Parameters:

beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

Returns:

The return value is a dictionary with the following keys: isHit, position, distance, face

isHit: This is a boolean to answer whether the beam hit the optics or not.

position: A numpy array containing the coordinate values of the intersection point between the beam and the optics. If isHit is False, this parameter does not mean anything.

distance The distance between the beam origin and the intersection point.

face: An optional string identifying which face of the optics was hit. For example, face can be either “HR” or “AR” for a mirror. face can also be “side”, meaning that the beam hits a side of the optics, which is not meant to be used, e.g. the side of a mirror. In this case, the beam have reached a dead end.

Return type:

Dict

draw(cv, drawName=False)

Draw itself

hitFromHR(beam, order=0, threshold=0.0, verbose=False)

Compute the reflected and deflected beams when an input beam hit the HR surface.

A beam is produced as long as its stray_order is not above order and its power is over the threshold. The stray_order of the incident beam is carried over, so a beam that is already stray leaves less of the allowance for the ghosts made here.

Parameters:
  • beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

  • order (int, optional) – The largest stray_order a beam produced here may have. The count is carried over from the incident beam, not started afresh. Defaults 0.

  • threshold (float, optional) – The power threshold for internal reflection calculation. If the power of an auxiliary beam falls below this threshold, further propagation of this beam will not be performed. Defaults 0.0.

  • verbose (boolean, optional) – Print useful information.

Returns:

beams – Dictionary of reflected and deflected beams.

Return type:

dict

hitFromAR(beam, order=0, threshold=0.0, verbose=False)

Compute the reflected and deflected beams when an input beam hit the AR surface.

A beam is produced as long as its stray_order is not above order and its power is over the threshold. The stray_order of the incident beam is carried over, so a beam that is already stray leaves less of the allowance for the ghosts made here.

Parameters:
  • beam (gtrace.beam.GaussianBeam) – A GaussianBeam object to be interacted by the optics.

  • order (int, optional) – The largest stray_order a beam produced here may have. The count is carried over from the incident beam, not started afresh. Defaults 0.

  • threshold (float, optional) – The power threshold for internal reflection calculation. If the power of an auxiliary beam falls below this threshold, further propagation of this beam will not be performed. Defaults 0.0.

  • verbose (boolean, optional) – Print useful information.

Returns:

beams – Dictionary of reflected and deflected beams.

Return type:

dict

exception gtrace.optcomp.LensGeometryError

Bases: ValueError

Raised when the lens asked for cannot be made out of the blank it was given: a face steeper than its own aperture, two concave faces that would meet in the middle, or a focal length no substrate of that thickness can reach.

A subclass of ValueError, so that code catching the ordinary bad argument still catches these.

gtrace.optcomp._FLAT_CURVATURE = 0.0001
gtrace.optcomp._LENS_SHAPES
gtrace.optcomp._SOLVE_ITERATIONS = 100
gtrace.optcomp.sagitta(inv_ROC, diameter)

Sagitta of a spherical face spanning an aperture.

Parameters:
  • inv_ROC (float) – 1/ROC of the face. Positive for a concave face, as everywhere else in gtrace.

  • diameter (float) – Aperture the face has to span.

Returns:

The sagitta, positive when the face bulges out of the substrate and negative when it is hollowed into it. Zero for a face gtrace treats as flat.

Return type:

float

Raises:

LensGeometryError – If the radius is smaller than the semi-aperture, in which case no arc of that radius reaches across the face. Left to run, this is where the square root in Mirror’s sagitta goes complex and NaN starts spreading through the geometry.

gtrace.optcomp.lens_power(inv_ROC_HR, inv_ROC_AR, center_thickness, n)

Optical power 1/f of a thick lens, in gtrace’s sign convention.

The lensmaker’s equation with the thickness term, rewritten in terms of the inverse radii gtrace stores. Those are positive for a concave face on both sides of the substrate, where the usual convention measures both radii along the direction of propagation, so 1/R1 = -inv_ROC_HR and 1/R2 = +inv_ROC_AR.

Parameters:
  • inv_ROC_HR (float) – 1/ROC of the two faces.

  • inv_ROC_AR (float) – 1/ROC of the two faces.

  • center_thickness (float) – Distance between the two apexes, which is what the thickness term means. For a Mirror-like substrate this is thickness + sagHR + sagAR, not thickness.

  • n (float) – Index of refraction.

Returns:

1/f. Positive for a converging lens.

Return type:

float

gtrace.optcomp._lens_shape(shape)

Look a shape name up, defaulting to the symmetric family.

gtrace.optcomp._check_center_thickness(thickness, sag_HR, sag_AR)

Refuse a blank the two faces would eat through.

Raises:

LensGeometryError – If nothing is left in the middle.

gtrace.optcomp._check_lens_inputs(f, n, diameter, thickness)

Reject the arguments no lens can be made from, whatever its shape.

Returns:

The focal length, as a float.

Return type:

float

gtrace.optcomp._face_kind(inv_ROC)

Whether a face is convex, concave or flat, in the vocabulary the shape names use.

gtrace.optcomp._curvatures_at(f, family, flat_face, n, center_thickness, fixed)

The two curvatures giving focal length f, for a centre thickness held fixed. solve_lens_curvatures() iterates on the thickness around this.

gtrace.optcomp.solve_lens_curvatures(f, shape=None, diameter=1 * inch, thickness=6 * mm, n=1.45, inv_ROC_HR=None)

Curvatures of the two faces of a lens of focal length f.

Solved as a thick lens, which is what gtrace then traces: the beam is refracted at both faces with the substrate in between, so a curvature taken from the thin lens formula would come out a few parts in a thousand away from the focal length asked for. The centre thickness the thickness term needs itself depends on the curvatures through the sagittae, so the two are iterated to convergence. For a plano lens the thickness term vanishes and the answer is exact in one step.

Parameters:
  • f (float) – Focal length. Positive converges.

  • shape (str or None, optional) – One of the names in _LENS_SHAPES, spelt HR face first. None means the symmetric family: biconvex for a positive f, biconcave for a negative one.

  • diameter (float, optional) – Aperture the faces have to span. Defaults 1 inch.

  • thickness (float, optional) – Distance between the two chord planes, which is Mirror’s thickness and the thickness at the rim. Defaults 6 mm.

  • n (float, optional) – Index of refraction. Defaults 1.45.

  • inv_ROC_HR (float or None, optional) – 1/ROC of the HR face, for a meniscus, which f alone does not determine. Not accepted for the other families, where it is solved for.

Returns:

(inv_ROC_HR, inv_ROC_AR).

Return type:

(float, float)

Raises:

LensGeometryError – If the lens cannot be made: a face steeper than its aperture, a centre eaten through by two concave faces, a focal length out of reach of the substrate, or a shape contradicting the sign of f.

gtrace.optcomp.rescale_lens_curvatures(inv_ROC_HR, inv_ROC_AR, f, diameter=1 * inch, thickness=6 * mm, n=1.45)

Scale both curvatures by one common factor until the lens has focal length f.

This is how a lens changes focal length without changing shape. The ratio between the two faces is what makes a lens biconvex or plano-convex or a meniscus, and multiplying both by the same number leaves that ratio alone: a flat face stays flat, an equiconvex lens stays equiconvex, a meniscus keeps its bend. A negative factor turns the whole lens inside out, which is what asking a converging lens for a negative focal length means.

Parameters:
  • inv_ROC_HR (float) – The curvatures to scale. At least one must be non-zero: a flat substrate has no shape to keep.

  • inv_ROC_AR (float) – The curvatures to scale. At least one must be non-zero: a flat substrate has no shape to keep.

  • f (float) – The focal length wanted.

  • diameter (float, optional) – The substrate, as for solve_lens_curvatures().

  • thickness (float, optional) – The substrate, as for solve_lens_curvatures().

  • n (float, optional) – The substrate, as for solve_lens_curvatures().

Returns:

(inv_ROC_HR, inv_ROC_AR), scaled.

Return type:

(float, float)

Raises:

LensGeometryError – If no scaling of this shape reaches that focal length, or if the one that does cannot be cut from the substrate.

gtrace.optcomp._scale_root(a, b, C, s0, f)

Solve a*s^2 + b*s = C for the scale factor, on the branch that survives as the substrate thins.

class gtrace.optcomp.Lens(f=None, shape=None, center=None, HRcenter=None, normAngleHR=0.0, normVectHR=None, diameter=1 * inch, thickness=6 * mm, n=1.45, ROC_HR=None, inv_ROC_HR=None, inv_ROC_AR=None, wedgeAngle=0.0, Refl_HR=0.0, Trans_HR=1.0, Refl_AR=0.0, Trans_AR=1.0, name='Lens', HRtransmissive=True, HRreflective=False, term_on_HR=False, term_on_HR_order=0, term_on_HR_transmits=False, max_stray_order=None)

Bases: Mirror

A lens: a substrate that refracts at both faces.

Mechanically a Mirror whose two faces are both curved and both transmit, so everything a Mirror can do - non-sequential tracing, ghost beams off either face, drawing, dragging in the viewer - works unchanged. What it adds is the constructor: a lens is ordered by its focal length, and the curvatures follow.

The focal length is not stored anywhere. f is computed from the curvatures, the thickness and the index whenever it is read, and assigning to it reshapes the faces to match. The curvatures stay the one description of the lens, so the two can never disagree, and tuning a lens is what it looks like:

for f in np.arange(150, 400, 10)*mm:
    L.f = f
    layout.trace()
    ...

Setting f keeps the shape - both curvatures are scaled together - and keeps the lens where it is. set_focal_length() takes a shape as well, for changing that too.

Four defaults differ from Mirror, because they have to:

Mirror

Lens

wedgeAngle

0.25 deg

0, or the faces are not coaxial

HRtransmissive

False

True: the front face is meant to pass

HRreflective

True

False: its reflections are ghosts

Refl_HR/Trans_HR

0.99/0.01

0/1: both faces reflect nothing

HRtransmissive matters more than it looks. With it False a beam passing through the front face counts as one order of stray, so the main beam through a lens would be a ghost, and non_seq_trace would stop following it at a low order. HRreflective is its mirror image: with it False every reflection at the front face counts one order of stray, as reflections at the back face already do, so the ghosts off a lens carry the order a ghost deserves instead of passing for main beams.

Both faces default to reflecting nothing. A real lens does reflect, but a system of them makes so many faint ghosts that the picture is unreadable and the trace slow, and most of the time a lens is there to bend the main beam. Someone chasing the ghosts off a lens knows they are, and says so:

L = Lens(f=500*mm, Refl_HR=0.005, Trans_HR=0.995,
         Refl_AR=0.005, Trans_AR=0.995)
Variables:
  • f (float) – Focal length. Readable and writable; see the property.

  • center_thickness (float) – Distance between the two apexes, which is what a catalogue calls the thickness. thickness itself is Mirror’s: the distance between the two chord planes, i.e. at the rim. Read only.

Examples

A 500 mm biconvex lens, 1 inch across:

L = Lens(f=500*mm)

The same power as a plano-convex lens with the curved face towards the back, put 20 cm along the axis and turned to face the beam:

L = Lens(f=500*mm, shape='convex-plano', center=[0.2, 0.0],
         normAngleHR=pi)

A diverging lens. The symmetric default follows the sign of f, so this is biconcave:

L = Lens(f=-100*mm, thickness=3*mm)

A meniscus, which f alone does not determine: one radius is given and the other is solved for. ROC_HR is positive for a concave front face, as everywhere in gtrace:

L = Lens(f=200*mm, shape='meniscus', ROC_HR=-50*mm)
anchor_point
draw_HR_marker = False
copy()
property center_thickness

the thickness a catalogue quotes. thickness is the distance between the chord planes, i.e. at the rim.

Type:

Distance between the two apexes

property f

Focal length of the lens.

Reading it computes it from the curvatures, the centre thickness and the index as they stand, so it cannot go stale. Infinite for a substrate with no power left in it.

Assigning to it reshapes the two faces until the lens has that focal length, keeping its shape and leaving it where it is:

for f in np.arange(150, 400, 10)*mm:
    L.f = f
    layout.trace()

See set_focal_length(), which this calls, for what “keeping its shape” means and for how to change the shape as well.

set_focal_length(f, shape=None, ROC_HR=None)

Give the lens a new focal length.

Parameters:
  • f (float) – The focal length wanted.

  • shape (str or None, optional) –

    None, the usual case, keeps the shape the lens already has: both curvatures are scaled by one common factor, so a flat face stays flat and a meniscus keeps its bend. Asking a converging lens for a negative focal length turns it inside out, and the shape name follows.

    A name from the list the constructor takes instead solves both faces from scratch, which is how a lens changes shape without being rebuilt and losing its place in the layout.

  • ROC_HR (float or None, optional) – The front radius, when shape is ‘meniscus’.

Raises:

LensGeometryError – If the new focal length cannot be had. The lens is left exactly as it was: the whole solve, and every check on it, happens before anything is assigned.

Notes

Whatever anchor_point names stays put, which for a lens is the centre of the substrate. The faces move, since the sagittae change with the curvature, but the lens as a whole does not wander up the bench as it is tuned.

property shape

The name of the shape this lens currently has, spelt HR face first, or ‘plano-plano’ for a substrate with no power.

class gtrace.optcomp.CyLens(f=None, shape=None, center=None, HRcenter=None, normAngleHR=0.0, normVectHR=None, diameter=1 * inch, thickness=6 * mm, n=1.45, ROC_HR=None, inv_ROC_HR=None, inv_ROC_AR=None, wedgeAngle=0.0, Refl_HR=0.0, Trans_HR=1.0, Refl_AR=0.0, Trans_AR=1.0, name='CyLens', HRtransmissive=True, HRreflective=False, term_on_HR=False, term_on_HR_order=0, term_on_HR_transmits=False, max_stray_order=None, curve_direction='h')

Bases: Lens, CyMirror

A cylindrical lens: a substrate that refracts at both faces and focuses in one plane only.

It is ordered exactly like a Lens - by its focal length, solved as a thick lens - and shaped exactly like a CyMirror: both faces are cylinders sharing one curve_direction, so the focal length lives in that plane and the other plane sees nothing but a window. The two parents each contribute what they already know. Lens brings the ordering - the f property, set_focal_length(), shape, and the anchor on the middle of the substrate - and CyMirror brings the geometry and the ray matrices that put the power in one plane only.

The solver needs no change for a cylinder. In the curved plane a cylindrical lens is the lensmaker’s thick lens, and the distance between the apexes is thickness + sagHR + sagAR for either curve_direction: the axis of a cylinder curved out of the drawing lies in it, so the section the trace sees runs through the apexes.

As with CyMirror, only ‘h’ is visible in the drawing. A ‘v’ lens is drawn as a plain rectangle - what the plane of the trace cuts out of it - and its focusing happens entirely out of the page, carried by the beam’s qy.

The focal length f is quoted at normal incidence. Tilted, the two planes scale differently - see CyMirror and cyl_refl_defl_angle for what a tilt does to each plane.

Examples

A 500 mm cylindrical lens focusing in the plane of the drawing:

L = CyLens(f=500*mm)

The same power focusing out of the plane, which is drawn straight:

L = CyLens(f=500*mm, curve_direction='v')

The shapes a Lens can take, a CyLens can too:

L = CyLens(f=-100*mm, thickness=3*mm, shape='plano-concave')
curve_direction = 'h'
copy()