gaussopt.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  1. """
  2. Gaussian optics.
  3. The module implements:
  4. - Ray transfer matrices for geometrical and gaussian optics.
  5. See RayTransferMatrix, GeometricRay and BeamParameter
  6. - Conjugation relations for geometrical and gaussian optics.
  7. See geometric_conj*, gauss_conj and conjugate_gauss_beams
  8. The conventions for the distances are as follows:
  9. focal distance
  10. positive for convergent lenses
  11. object distance
  12. positive for real objects
  13. image distance
  14. positive for real images
  15. """
  16. __all__ = [
  17. 'RayTransferMatrix',
  18. 'FreeSpace',
  19. 'FlatRefraction',
  20. 'CurvedRefraction',
  21. 'FlatMirror',
  22. 'CurvedMirror',
  23. 'ThinLens',
  24. 'GeometricRay',
  25. 'BeamParameter',
  26. 'waist2rayleigh',
  27. 'rayleigh2waist',
  28. 'geometric_conj_ab',
  29. 'geometric_conj_af',
  30. 'geometric_conj_bf',
  31. 'gaussian_conj',
  32. 'conjugate_gauss_beams',
  33. ]
  34. from sympy.core.expr import Expr
  35. from sympy.core.numbers import (I, pi)
  36. from sympy.core.sympify import sympify
  37. from sympy.functions.elementary.complexes import (im, re)
  38. from sympy.functions.elementary.miscellaneous import sqrt
  39. from sympy.functions.elementary.trigonometric import atan2
  40. from sympy.matrices.dense import Matrix, MutableDenseMatrix
  41. from sympy.polys.rationaltools import together
  42. from sympy.utilities.misc import filldedent
  43. ###
  44. # A, B, C, D matrices
  45. ###
  46. class RayTransferMatrix(MutableDenseMatrix):
  47. """
  48. Base class for a Ray Transfer Matrix.
  49. It should be used if there is not already a more specific subclass mentioned
  50. in See Also.
  51. Parameters
  52. ==========
  53. parameters :
  54. A, B, C and D or 2x2 matrix (Matrix(2, 2, [A, B, C, D]))
  55. Examples
  56. ========
  57. >>> from sympy.physics.optics import RayTransferMatrix, ThinLens
  58. >>> from sympy import Symbol, Matrix
  59. >>> mat = RayTransferMatrix(1, 2, 3, 4)
  60. >>> mat
  61. Matrix([
  62. [1, 2],
  63. [3, 4]])
  64. >>> RayTransferMatrix(Matrix([[1, 2], [3, 4]]))
  65. Matrix([
  66. [1, 2],
  67. [3, 4]])
  68. >>> mat.A
  69. 1
  70. >>> f = Symbol('f')
  71. >>> lens = ThinLens(f)
  72. >>> lens
  73. Matrix([
  74. [ 1, 0],
  75. [-1/f, 1]])
  76. >>> lens.C
  77. -1/f
  78. See Also
  79. ========
  80. GeometricRay, BeamParameter,
  81. FreeSpace, FlatRefraction, CurvedRefraction,
  82. FlatMirror, CurvedMirror, ThinLens
  83. References
  84. ==========
  85. .. [1] https://en.wikipedia.org/wiki/Ray_transfer_matrix_analysis
  86. """
  87. def __new__(cls, *args):
  88. if len(args) == 4:
  89. temp = ((args[0], args[1]), (args[2], args[3]))
  90. elif len(args) == 1 \
  91. and isinstance(args[0], Matrix) \
  92. and args[0].shape == (2, 2):
  93. temp = args[0]
  94. else:
  95. raise ValueError(filldedent('''
  96. Expecting 2x2 Matrix or the 4 elements of
  97. the Matrix but got %s''' % str(args)))
  98. return Matrix.__new__(cls, temp)
  99. def __mul__(self, other):
  100. if isinstance(other, RayTransferMatrix):
  101. return RayTransferMatrix(Matrix.__mul__(self, other))
  102. elif isinstance(other, GeometricRay):
  103. return GeometricRay(Matrix.__mul__(self, other))
  104. elif isinstance(other, BeamParameter):
  105. temp = self*Matrix(((other.q,), (1,)))
  106. q = (temp[0]/temp[1]).expand(complex=True)
  107. return BeamParameter(other.wavelen,
  108. together(re(q)),
  109. z_r=together(im(q)))
  110. else:
  111. return Matrix.__mul__(self, other)
  112. @property
  113. def A(self):
  114. """
  115. The A parameter of the Matrix.
  116. Examples
  117. ========
  118. >>> from sympy.physics.optics import RayTransferMatrix
  119. >>> mat = RayTransferMatrix(1, 2, 3, 4)
  120. >>> mat.A
  121. 1
  122. """
  123. return self[0, 0]
  124. @property
  125. def B(self):
  126. """
  127. The B parameter of the Matrix.
  128. Examples
  129. ========
  130. >>> from sympy.physics.optics import RayTransferMatrix
  131. >>> mat = RayTransferMatrix(1, 2, 3, 4)
  132. >>> mat.B
  133. 2
  134. """
  135. return self[0, 1]
  136. @property
  137. def C(self):
  138. """
  139. The C parameter of the Matrix.
  140. Examples
  141. ========
  142. >>> from sympy.physics.optics import RayTransferMatrix
  143. >>> mat = RayTransferMatrix(1, 2, 3, 4)
  144. >>> mat.C
  145. 3
  146. """
  147. return self[1, 0]
  148. @property
  149. def D(self):
  150. """
  151. The D parameter of the Matrix.
  152. Examples
  153. ========
  154. >>> from sympy.physics.optics import RayTransferMatrix
  155. >>> mat = RayTransferMatrix(1, 2, 3, 4)
  156. >>> mat.D
  157. 4
  158. """
  159. return self[1, 1]
  160. class FreeSpace(RayTransferMatrix):
  161. """
  162. Ray Transfer Matrix for free space.
  163. Parameters
  164. ==========
  165. distance
  166. See Also
  167. ========
  168. RayTransferMatrix
  169. Examples
  170. ========
  171. >>> from sympy.physics.optics import FreeSpace
  172. >>> from sympy import symbols
  173. >>> d = symbols('d')
  174. >>> FreeSpace(d)
  175. Matrix([
  176. [1, d],
  177. [0, 1]])
  178. """
  179. def __new__(cls, d):
  180. return RayTransferMatrix.__new__(cls, 1, d, 0, 1)
  181. class FlatRefraction(RayTransferMatrix):
  182. """
  183. Ray Transfer Matrix for refraction.
  184. Parameters
  185. ==========
  186. n1 :
  187. Refractive index of one medium.
  188. n2 :
  189. Refractive index of other medium.
  190. See Also
  191. ========
  192. RayTransferMatrix
  193. Examples
  194. ========
  195. >>> from sympy.physics.optics import FlatRefraction
  196. >>> from sympy import symbols
  197. >>> n1, n2 = symbols('n1 n2')
  198. >>> FlatRefraction(n1, n2)
  199. Matrix([
  200. [1, 0],
  201. [0, n1/n2]])
  202. """
  203. def __new__(cls, n1, n2):
  204. n1, n2 = map(sympify, (n1, n2))
  205. return RayTransferMatrix.__new__(cls, 1, 0, 0, n1/n2)
  206. class CurvedRefraction(RayTransferMatrix):
  207. """
  208. Ray Transfer Matrix for refraction on curved interface.
  209. Parameters
  210. ==========
  211. R :
  212. Radius of curvature (positive for concave).
  213. n1 :
  214. Refractive index of one medium.
  215. n2 :
  216. Refractive index of other medium.
  217. See Also
  218. ========
  219. RayTransferMatrix
  220. Examples
  221. ========
  222. >>> from sympy.physics.optics import CurvedRefraction
  223. >>> from sympy import symbols
  224. >>> R, n1, n2 = symbols('R n1 n2')
  225. >>> CurvedRefraction(R, n1, n2)
  226. Matrix([
  227. [ 1, 0],
  228. [(n1 - n2)/(R*n2), n1/n2]])
  229. """
  230. def __new__(cls, R, n1, n2):
  231. R, n1, n2 = map(sympify, (R, n1, n2))
  232. return RayTransferMatrix.__new__(cls, 1, 0, (n1 - n2)/R/n2, n1/n2)
  233. class FlatMirror(RayTransferMatrix):
  234. """
  235. Ray Transfer Matrix for reflection.
  236. See Also
  237. ========
  238. RayTransferMatrix
  239. Examples
  240. ========
  241. >>> from sympy.physics.optics import FlatMirror
  242. >>> FlatMirror()
  243. Matrix([
  244. [1, 0],
  245. [0, 1]])
  246. """
  247. def __new__(cls):
  248. return RayTransferMatrix.__new__(cls, 1, 0, 0, 1)
  249. class CurvedMirror(RayTransferMatrix):
  250. """
  251. Ray Transfer Matrix for reflection from curved surface.
  252. Parameters
  253. ==========
  254. R : radius of curvature (positive for concave)
  255. See Also
  256. ========
  257. RayTransferMatrix
  258. Examples
  259. ========
  260. >>> from sympy.physics.optics import CurvedMirror
  261. >>> from sympy import symbols
  262. >>> R = symbols('R')
  263. >>> CurvedMirror(R)
  264. Matrix([
  265. [ 1, 0],
  266. [-2/R, 1]])
  267. """
  268. def __new__(cls, R):
  269. R = sympify(R)
  270. return RayTransferMatrix.__new__(cls, 1, 0, -2/R, 1)
  271. class ThinLens(RayTransferMatrix):
  272. """
  273. Ray Transfer Matrix for a thin lens.
  274. Parameters
  275. ==========
  276. f :
  277. The focal distance.
  278. See Also
  279. ========
  280. RayTransferMatrix
  281. Examples
  282. ========
  283. >>> from sympy.physics.optics import ThinLens
  284. >>> from sympy import symbols
  285. >>> f = symbols('f')
  286. >>> ThinLens(f)
  287. Matrix([
  288. [ 1, 0],
  289. [-1/f, 1]])
  290. """
  291. def __new__(cls, f):
  292. f = sympify(f)
  293. return RayTransferMatrix.__new__(cls, 1, 0, -1/f, 1)
  294. ###
  295. # Representation for geometric ray
  296. ###
  297. class GeometricRay(MutableDenseMatrix):
  298. """
  299. Representation for a geometric ray in the Ray Transfer Matrix formalism.
  300. Parameters
  301. ==========
  302. h : height, and
  303. angle : angle, or
  304. matrix : a 2x1 matrix (Matrix(2, 1, [height, angle]))
  305. Examples
  306. ========
  307. >>> from sympy.physics.optics import GeometricRay, FreeSpace
  308. >>> from sympy import symbols, Matrix
  309. >>> d, h, angle = symbols('d, h, angle')
  310. >>> GeometricRay(h, angle)
  311. Matrix([
  312. [ h],
  313. [angle]])
  314. >>> FreeSpace(d)*GeometricRay(h, angle)
  315. Matrix([
  316. [angle*d + h],
  317. [ angle]])
  318. >>> GeometricRay( Matrix( ((h,), (angle,)) ) )
  319. Matrix([
  320. [ h],
  321. [angle]])
  322. See Also
  323. ========
  324. RayTransferMatrix
  325. """
  326. def __new__(cls, *args):
  327. if len(args) == 1 and isinstance(args[0], Matrix) \
  328. and args[0].shape == (2, 1):
  329. temp = args[0]
  330. elif len(args) == 2:
  331. temp = ((args[0],), (args[1],))
  332. else:
  333. raise ValueError(filldedent('''
  334. Expecting 2x1 Matrix or the 2 elements of
  335. the Matrix but got %s''' % str(args)))
  336. return Matrix.__new__(cls, temp)
  337. @property
  338. def height(self):
  339. """
  340. The distance from the optical axis.
  341. Examples
  342. ========
  343. >>> from sympy.physics.optics import GeometricRay
  344. >>> from sympy import symbols
  345. >>> h, angle = symbols('h, angle')
  346. >>> gRay = GeometricRay(h, angle)
  347. >>> gRay.height
  348. h
  349. """
  350. return self[0]
  351. @property
  352. def angle(self):
  353. """
  354. The angle with the optical axis.
  355. Examples
  356. ========
  357. >>> from sympy.physics.optics import GeometricRay
  358. >>> from sympy import symbols
  359. >>> h, angle = symbols('h, angle')
  360. >>> gRay = GeometricRay(h, angle)
  361. >>> gRay.angle
  362. angle
  363. """
  364. return self[1]
  365. ###
  366. # Representation for gauss beam
  367. ###
  368. class BeamParameter(Expr):
  369. """
  370. Representation for a gaussian ray in the Ray Transfer Matrix formalism.
  371. Parameters
  372. ==========
  373. wavelen : the wavelength,
  374. z : the distance to waist, and
  375. w : the waist, or
  376. z_r : the rayleigh range.
  377. n : the refractive index of medium.
  378. Examples
  379. ========
  380. >>> from sympy.physics.optics import BeamParameter
  381. >>> p = BeamParameter(530e-9, 1, w=1e-3)
  382. >>> p.q
  383. 1 + 1.88679245283019*I*pi
  384. >>> p.q.n()
  385. 1.0 + 5.92753330865999*I
  386. >>> p.w_0.n()
  387. 0.00100000000000000
  388. >>> p.z_r.n()
  389. 5.92753330865999
  390. >>> from sympy.physics.optics import FreeSpace
  391. >>> fs = FreeSpace(10)
  392. >>> p1 = fs*p
  393. >>> p.w.n()
  394. 0.00101413072159615
  395. >>> p1.w.n()
  396. 0.00210803120913829
  397. See Also
  398. ========
  399. RayTransferMatrix
  400. References
  401. ==========
  402. .. [1] https://en.wikipedia.org/wiki/Complex_beam_parameter
  403. .. [2] https://en.wikipedia.org/wiki/Gaussian_beam
  404. """
  405. #TODO A class Complex may be implemented. The BeamParameter may
  406. # subclass it. See:
  407. # https://groups.google.com/d/topic/sympy/7XkU07NRBEs/discussion
  408. def __new__(cls, wavelen, z, z_r=None, w=None, n=1):
  409. wavelen = sympify(wavelen)
  410. z = sympify(z)
  411. n = sympify(n)
  412. if z_r is not None and w is None:
  413. z_r = sympify(z_r)
  414. elif w is not None and z_r is None:
  415. z_r = waist2rayleigh(sympify(w), wavelen, n)
  416. elif z_r is None and w is None:
  417. raise ValueError('Must specify one of w and z_r.')
  418. return Expr.__new__(cls, wavelen, z, z_r, n)
  419. @property
  420. def wavelen(self):
  421. return self.args[0]
  422. @property
  423. def z(self):
  424. return self.args[1]
  425. @property
  426. def z_r(self):
  427. return self.args[2]
  428. @property
  429. def n(self):
  430. return self.args[3]
  431. @property
  432. def q(self):
  433. """
  434. The complex parameter representing the beam.
  435. Examples
  436. ========
  437. >>> from sympy.physics.optics import BeamParameter
  438. >>> p = BeamParameter(530e-9, 1, w=1e-3)
  439. >>> p.q
  440. 1 + 1.88679245283019*I*pi
  441. """
  442. return self.z + I*self.z_r
  443. @property
  444. def radius(self):
  445. """
  446. The radius of curvature of the phase front.
  447. Examples
  448. ========
  449. >>> from sympy.physics.optics import BeamParameter
  450. >>> p = BeamParameter(530e-9, 1, w=1e-3)
  451. >>> p.radius
  452. 1 + 3.55998576005696*pi**2
  453. """
  454. return self.z*(1 + (self.z_r/self.z)**2)
  455. @property
  456. def w(self):
  457. """
  458. The radius of the beam w(z), at any position z along the beam.
  459. The beam radius at `1/e^2` intensity (axial value).
  460. See Also
  461. ========
  462. w_0 :
  463. The minimal radius of beam.
  464. Examples
  465. ========
  466. >>> from sympy.physics.optics import BeamParameter
  467. >>> p = BeamParameter(530e-9, 1, w=1e-3)
  468. >>> p.w
  469. 0.001*sqrt(0.2809/pi**2 + 1)
  470. """
  471. return self.w_0*sqrt(1 + (self.z/self.z_r)**2)
  472. @property
  473. def w_0(self):
  474. """
  475. The minimal radius of beam at `1/e^2` intensity (peak value).
  476. See Also
  477. ========
  478. w : the beam radius at `1/e^2` intensity (axial value).
  479. Examples
  480. ========
  481. >>> from sympy.physics.optics import BeamParameter
  482. >>> p = BeamParameter(530e-9, 1, w=1e-3)
  483. >>> p.w_0
  484. 0.00100000000000000
  485. """
  486. return sqrt(self.z_r/(pi*self.n)*self.wavelen)
  487. @property
  488. def divergence(self):
  489. """
  490. Half of the total angular spread.
  491. Examples
  492. ========
  493. >>> from sympy.physics.optics import BeamParameter
  494. >>> p = BeamParameter(530e-9, 1, w=1e-3)
  495. >>> p.divergence
  496. 0.00053/pi
  497. """
  498. return self.wavelen/pi/self.w_0
  499. @property
  500. def gouy(self):
  501. """
  502. The Gouy phase.
  503. Examples
  504. ========
  505. >>> from sympy.physics.optics import BeamParameter
  506. >>> p = BeamParameter(530e-9, 1, w=1e-3)
  507. >>> p.gouy
  508. atan(0.53/pi)
  509. """
  510. return atan2(self.z, self.z_r)
  511. @property
  512. def waist_approximation_limit(self):
  513. """
  514. The minimal waist for which the gauss beam approximation is valid.
  515. Explanation
  516. ===========
  517. The gauss beam is a solution to the paraxial equation. For curvatures
  518. that are too great it is not a valid approximation.
  519. Examples
  520. ========
  521. >>> from sympy.physics.optics import BeamParameter
  522. >>> p = BeamParameter(530e-9, 1, w=1e-3)
  523. >>> p.waist_approximation_limit
  524. 1.06e-6/pi
  525. """
  526. return 2*self.wavelen/pi
  527. ###
  528. # Utilities
  529. ###
  530. def waist2rayleigh(w, wavelen, n=1):
  531. """
  532. Calculate the rayleigh range from the waist of a gaussian beam.
  533. See Also
  534. ========
  535. rayleigh2waist, BeamParameter
  536. Examples
  537. ========
  538. >>> from sympy.physics.optics import waist2rayleigh
  539. >>> from sympy import symbols
  540. >>> w, wavelen = symbols('w wavelen')
  541. >>> waist2rayleigh(w, wavelen)
  542. pi*w**2/wavelen
  543. """
  544. w, wavelen = map(sympify, (w, wavelen))
  545. return w**2*n*pi/wavelen
  546. def rayleigh2waist(z_r, wavelen):
  547. """Calculate the waist from the rayleigh range of a gaussian beam.
  548. See Also
  549. ========
  550. waist2rayleigh, BeamParameter
  551. Examples
  552. ========
  553. >>> from sympy.physics.optics import rayleigh2waist
  554. >>> from sympy import symbols
  555. >>> z_r, wavelen = symbols('z_r wavelen')
  556. >>> rayleigh2waist(z_r, wavelen)
  557. sqrt(wavelen*z_r)/sqrt(pi)
  558. """
  559. z_r, wavelen = map(sympify, (z_r, wavelen))
  560. return sqrt(z_r/pi*wavelen)
  561. def geometric_conj_ab(a, b):
  562. """
  563. Conjugation relation for geometrical beams under paraxial conditions.
  564. Explanation
  565. ===========
  566. Takes the distances to the optical element and returns the needed
  567. focal distance.
  568. See Also
  569. ========
  570. geometric_conj_af, geometric_conj_bf
  571. Examples
  572. ========
  573. >>> from sympy.physics.optics import geometric_conj_ab
  574. >>> from sympy import symbols
  575. >>> a, b = symbols('a b')
  576. >>> geometric_conj_ab(a, b)
  577. a*b/(a + b)
  578. """
  579. a, b = map(sympify, (a, b))
  580. if a.is_infinite or b.is_infinite:
  581. return a if b.is_infinite else b
  582. else:
  583. return a*b/(a + b)
  584. def geometric_conj_af(a, f):
  585. """
  586. Conjugation relation for geometrical beams under paraxial conditions.
  587. Explanation
  588. ===========
  589. Takes the object distance (for geometric_conj_af) or the image distance
  590. (for geometric_conj_bf) to the optical element and the focal distance.
  591. Then it returns the other distance needed for conjugation.
  592. See Also
  593. ========
  594. geometric_conj_ab
  595. Examples
  596. ========
  597. >>> from sympy.physics.optics.gaussopt import geometric_conj_af, geometric_conj_bf
  598. >>> from sympy import symbols
  599. >>> a, b, f = symbols('a b f')
  600. >>> geometric_conj_af(a, f)
  601. a*f/(a - f)
  602. >>> geometric_conj_bf(b, f)
  603. b*f/(b - f)
  604. """
  605. a, f = map(sympify, (a, f))
  606. return -geometric_conj_ab(a, -f)
  607. geometric_conj_bf = geometric_conj_af
  608. def gaussian_conj(s_in, z_r_in, f):
  609. """
  610. Conjugation relation for gaussian beams.
  611. Parameters
  612. ==========
  613. s_in :
  614. The distance to optical element from the waist.
  615. z_r_in :
  616. The rayleigh range of the incident beam.
  617. f :
  618. The focal length of the optical element.
  619. Returns
  620. =======
  621. a tuple containing (s_out, z_r_out, m)
  622. s_out :
  623. The distance between the new waist and the optical element.
  624. z_r_out :
  625. The rayleigh range of the emergent beam.
  626. m :
  627. The ration between the new and the old waists.
  628. Examples
  629. ========
  630. >>> from sympy.physics.optics import gaussian_conj
  631. >>> from sympy import symbols
  632. >>> s_in, z_r_in, f = symbols('s_in z_r_in f')
  633. >>> gaussian_conj(s_in, z_r_in, f)[0]
  634. 1/(-1/(s_in + z_r_in**2/(-f + s_in)) + 1/f)
  635. >>> gaussian_conj(s_in, z_r_in, f)[1]
  636. z_r_in/(1 - s_in**2/f**2 + z_r_in**2/f**2)
  637. >>> gaussian_conj(s_in, z_r_in, f)[2]
  638. 1/sqrt(1 - s_in**2/f**2 + z_r_in**2/f**2)
  639. """
  640. s_in, z_r_in, f = map(sympify, (s_in, z_r_in, f))
  641. s_out = 1 / ( -1/(s_in + z_r_in**2/(s_in - f)) + 1/f )
  642. m = 1/sqrt((1 - (s_in/f)**2) + (z_r_in/f)**2)
  643. z_r_out = z_r_in / ((1 - (s_in/f)**2) + (z_r_in/f)**2)
  644. return (s_out, z_r_out, m)
  645. def conjugate_gauss_beams(wavelen, waist_in, waist_out, **kwargs):
  646. """
  647. Find the optical setup conjugating the object/image waists.
  648. Parameters
  649. ==========
  650. wavelen :
  651. The wavelength of the beam.
  652. waist_in and waist_out :
  653. The waists to be conjugated.
  654. f :
  655. The focal distance of the element used in the conjugation.
  656. Returns
  657. =======
  658. a tuple containing (s_in, s_out, f)
  659. s_in :
  660. The distance before the optical element.
  661. s_out :
  662. The distance after the optical element.
  663. f :
  664. The focal distance of the optical element.
  665. Examples
  666. ========
  667. >>> from sympy.physics.optics import conjugate_gauss_beams
  668. >>> from sympy import symbols, factor
  669. >>> l, w_i, w_o, f = symbols('l w_i w_o f')
  670. >>> conjugate_gauss_beams(l, w_i, w_o, f=f)[0]
  671. f*(1 - sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)))
  672. >>> factor(conjugate_gauss_beams(l, w_i, w_o, f=f)[1])
  673. f*w_o**2*(w_i**2/w_o**2 - sqrt(w_i**2/w_o**2 -
  674. pi**2*w_i**4/(f**2*l**2)))/w_i**2
  675. >>> conjugate_gauss_beams(l, w_i, w_o, f=f)[2]
  676. f
  677. """
  678. #TODO add the other possible arguments
  679. wavelen, waist_in, waist_out = map(sympify, (wavelen, waist_in, waist_out))
  680. m = waist_out / waist_in
  681. z = waist2rayleigh(waist_in, wavelen)
  682. if len(kwargs) != 1:
  683. raise ValueError("The function expects only one named argument")
  684. elif 'dist' in kwargs:
  685. raise NotImplementedError(filldedent('''
  686. Currently only focal length is supported as a parameter'''))
  687. elif 'f' in kwargs:
  688. f = sympify(kwargs['f'])
  689. s_in = f * (1 - sqrt(1/m**2 - z**2/f**2))
  690. s_out = gaussian_conj(s_in, z, f)[0]
  691. elif 's_in' in kwargs:
  692. raise NotImplementedError(filldedent('''
  693. Currently only focal length is supported as a parameter'''))
  694. else:
  695. raise ValueError(filldedent('''
  696. The functions expects the focal length as a named argument'''))
  697. return (s_in, s_out, f)
  698. #TODO
  699. #def plot_beam():
  700. # """Plot the beam radius as it propagates in space."""
  701. # pass
  702. #TODO
  703. #def plot_beam_conjugation():
  704. # """
  705. # Plot the intersection of two beams.
  706. #
  707. # Represents the conjugation relation.
  708. #
  709. # See Also
  710. # ========
  711. #
  712. # conjugate_gauss_beams
  713. # """
  714. # pass