1 '''Defines the BeamTree class for theia.'''
2
3
4
5
6
7
8
9
10
11
12
13
14 import numpy as np
15 from ..helpers import settings
16 from ..helpers.units import mm, deg
17 from ..helpers.tools import formatter, shortRef
18 from ..helpers.geometry import rectToSph, linePlaneInter
19
21 '''
22
23 BeamTree class.
24
25 A BeamTree is a binary tree which allows to keep track of the beams as they
26 are traced throughout the optical setup. The Root of the tree is a Gaussian
27 beam and the other attributes are the daughter trees and all the data of the
28 interaction producing these with the Root beam
29
30 *=== Attributes ===*
31 Name: class attribute, name of object. [string]
32 Root: beam of this node of the tree. [GaussianBeam]
33 T: beam resulting from the transmission of the Root beam. [BeamTree]
34 R: beam resulting from the reflection of the Root beam. [BeamTree]
35
36 '''
37 Name = "BeamTree"
38
39 - def __init__(self, Root = None,
40 T = None, R = None):
41 '''BeamTree initializer.'''
42 self.Root = Root
43 self.T = T
44 self.R = R
45
47 '''String representation of a BeamTree, for print(tree).'''
48 return formatter(self.lines())
49
51 '''Returns the list of lines necessary to print the object.'''
52 return ["Tree: {",
53 "Root beam: %s" %(self.Root.Ref if not settings.short\
54 else shortRef(self.Root.Ref)),
55 "Number of beams: %s" %str(self.numberOfBeams()),
56 "}"]
57
59 '''Returns the string representation the tree of beams.
60
61 '''
62 before = ["Tree: Root beam = %s {" %str(self.Root.Ref)]
63 after = ["}"]
64 return formatter(before + self.beamLines() + after)
65
67 '''Returns the list of lines necessary to print the list of beams.
68
69 '''
70 if self.Root is not None:
71 ans = self.Root.lines()
72 if self.R is not None:
73 ans = ans + self.R.beamLines()
74 if self.T is not None:
75 ans = ans + self.T.beamLines()
76 return ans
77 return list()
78
80 '''Return the total number of beams.'''
81 if self.Root is None:
82 return 0
83 return 1 + (self.R.numberOfBeams() if self.R is not None else 0)\
84 + (self.T.numberOfBeams() if self.T is not None else 0)
85
87 '''Return the list of lines to write the output of simulation.'''
88 sList = list()
89 if self.Root is not None and (self.Root.N == 1 or not settings.short):
90 beam = self.Root
91 Ref = beam.Ref if not settings.short else shortRef(beam.Ref)
92 sph = rectToSph(beam.Dir)
93 if beam.Length == 0.:
94 sList = ["(%s, %s) [open] %s {" % (beam.Optic, beam.Face, Ref)]
95 else:
96 if self.R is None and self.T is None:
97 sList = ["(%s, %s) %sm [end] (%s, %s) %s {" \
98 % (beam.Optic, beam.Face, str(beam.Length),
99 beam.TargetOptic, beam.TargetFace, Ref)]
100 else:
101 sList = ["(%s, %s) %sm (%s, %s) %s {" \
102 % (beam.Optic, beam.Face, str(beam.Length),
103 beam.TargetOptic, beam.TargetFace, Ref)]
104
105 sList = sList + ["Waist Pos: (%s, %s)m" \
106 %(str(beam.DWx), str(beam.DWy)),
107 "Waist Size: (%s, %s)mm" \
108 %(str(beam.Wx/mm), str(beam.Wy/mm)),
109 "Direction: (%s, %s)deg" %(str(sph[0]/deg),
110 str(sph[1]/deg)),
111 "}"]
112 if self.R is not None:
113 sList = sList + self.R.outputLines()
114 if self.T is not None:
115 sList = sList + self.T.outputLines()
116
117 return sList
118
119
120 -def treeOfBeam(srcBeam, optList, order, threshold):
121 '''Function to calculate the tree of daughter beams of srcBeam.
122
123 srcBeam: Input beam. [GaussianBeam]
124 optList: List of optical components of the setup. [list of OpticalComponent]
125 order: order of simulation. [integer]
126 threshold: power threshold for daughter beams. [float]
127
128 Returns a BeamTree.
129
130 '''
131 if len(optList) == 0:
132
133 return BeamTree(Root = srcBeam)
134
135 if srcBeam is None:
136
137 return None
138
139 BRef = srcBeam.Ref if not settings.short else shortRef(srcBeam.Ref)
140
141
142 clippingOpts = ["Mirror", "ThinLens", "ThickLens", "BeamDump", "Special"]
143 waist = max(srcBeam.IWx,
144 srcBeam.IWy)
145
146
147 dist = settings.inf
148 finalOpt = None
149
150
151 for opt in optList:
152 dicoisHit = opt.isHit(srcBeam)
153 if dicoisHit['isHit'] and dicoisHit['distance'] < dist:
154 dist = dicoisHit['distance']
155 finalOpt = opt
156
157
158 if settings.antiClip:
159 for opt in optList:
160 if opt.Name in clippingOpts and not opt is finalOpt:
161
162 HClipDic = linePlaneInter(srcBeam.Pos, srcBeam.Dir,
163 opt.HRCenter, opt.HRNorm,
164 opt.Dia + 2 * settings.clipFactor * waist)
165
166 AClipDic = linePlaneInter(srcBeam.Pos, srcBeam.Dir,
167 opt.ARCenter, - opt.HRNorm,
168 opt.Dia + 2 * settings.clipFactor * waist)
169
170
171 Hif = HClipDic['isHit'] and HClipDic['distance'] < dist \
172 and np.linalg.norm(HClipDic['intersection point'] \
173 - opt.HRCenter) > opt.Dia/2.
174
175 Aif = AClipDic['isHit'] and AClipDic['distance'] < dist \
176 and np.linalg.norm(AClipDic['intersection point'] \
177 - opt.ARCenter) > opt.Dia/2.
178 if Hif or Aif and (srcBeam.N == 1. or not settings.short):
179 print "theia: Warning: Anti-clipping of beam %s on %s."\
180 %(BRef, opt.Ref)
181
182 if finalOpt is None:
183
184 if settings.info and (srcBeam.N == 1. or not settings.short):
185 print "theia: Info: Reached open beam %s." % BRef
186 return BeamTree(Root = srcBeam)
187
188
189 finalisHit = finalOpt.isHit(srcBeam)
190 finalHit = finalOpt.hit(srcBeam, order = order, threshold = threshold)
191
192
193 isClipped = False
194 if not finalisHit['face'] == 'Side' and finalOpt.Name in clippingOpts:
195 center = { 'HR': finalOpt.HRCenter,
196 'AR': finalOpt.ARCenter}[finalisHit['face']]
197 distance = np.linalg.norm(finalisHit['intersection point'] - center)
198 isClipped = distance + settings.clipFactor * waist > finalOpt.Dia/2.
199
200
201 if isClipped and settings.warning\
202 and (srcBeam.N == 1. or not settings.short):
203 print "theia: Warning: Clipping of beam %s on (%s, %s)."\
204 %(BRef, finalOpt.Ref, finalisHit['face'])
205
206 return BeamTree(Root = srcBeam,
207 T = treeOfBeam(finalHit['t'], optList, order, threshold),
208 R = treeOfBeam(finalHit['r'], optList, order, threshold))
209