PyFiberModes 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. PyFiberModes/.DS_Store +0 -0
  2. PyFiberModes/VERSION +1 -0
  3. PyFiberModes/__init__.py +38 -0
  4. PyFiberModes/constants.py +32 -0
  5. PyFiberModes/fiber/.DS_Store +0 -0
  6. PyFiberModes/fiber/__init__.py +0 -0
  7. PyFiberModes/fiber/factory.py +448 -0
  8. PyFiberModes/fiber/fiber.py +317 -0
  9. PyFiberModes/fiber/geometry/__init__.py +10 -0
  10. PyFiberModes/fiber/geometry/geometry.py +33 -0
  11. PyFiberModes/fiber/geometry/stepindex.py +181 -0
  12. PyFiberModes/fiber/geometry/supergaussian.py +193 -0
  13. PyFiberModes/fiber/material/__init__.py +13 -0
  14. PyFiberModes/fiber/material/air.py +20 -0
  15. PyFiberModes/fiber/material/claussiusmossotti.py +40 -0
  16. PyFiberModes/fiber/material/compmaterial.py +60 -0
  17. PyFiberModes/fiber/material/fixed.py +36 -0
  18. PyFiberModes/fiber/material/germania.py +14 -0
  19. PyFiberModes/fiber/material/material.py +107 -0
  20. PyFiberModes/fiber/material/sellmeier.py +47 -0
  21. PyFiberModes/fiber/material/sellmeiercomp.py +42 -0
  22. PyFiberModes/fiber/material/silica.py +15 -0
  23. PyFiberModes/fiber/material/sio2f.py +34 -0
  24. PyFiberModes/fiber/material/sio2geo2.py +36 -0
  25. PyFiberModes/fiber/material/sio2geo2cm.py +43 -0
  26. PyFiberModes/fiber/solver/__init__.py +12 -0
  27. PyFiberModes/fiber/solver/cuda.py +124 -0
  28. PyFiberModes/fiber/solver/cudasrc/besseldiff.c +28 -0
  29. PyFiberModes/fiber/solver/cudasrc/chareq.c +314 -0
  30. PyFiberModes/fiber/solver/cudasrc/constf.c +20 -0
  31. PyFiberModes/fiber/solver/cudasrc/hypergf.c +264 -0
  32. PyFiberModes/fiber/solver/cudasrc/ivf.c +49 -0
  33. PyFiberModes/fiber/solver/cudasrc/knf.c +166 -0
  34. PyFiberModes/fiber/solver/mlsif.py +289 -0
  35. PyFiberModes/fiber/solver/solver.py +119 -0
  36. PyFiberModes/fiber/solver/ssif.py +275 -0
  37. PyFiberModes/fiber/solver/tlsif.py +266 -0
  38. PyFiberModes/field.py +405 -0
  39. PyFiberModes/functions.py +137 -0
  40. PyFiberModes/mode.py +186 -0
  41. PyFiberModes/simulator/.DS_Store +0 -0
  42. PyFiberModes/simulator/__init__.py +15 -0
  43. PyFiberModes/simulator/psimulator.py +41 -0
  44. PyFiberModes/simulator/simulator.py +288 -0
  45. PyFiberModes/slrc.py +291 -0
  46. PyFiberModes/tools/__init__.py +0 -0
  47. PyFiberModes/tools/directories.py +41 -0
  48. PyFiberModes/wavelength.py +109 -0
  49. PyFiberModes-0.2.1.dist-info/METADATA +158 -0
  50. PyFiberModes-0.2.1.dist-info/RECORD +52 -0
  51. PyFiberModes-0.2.1.dist-info/WHEEL +5 -0
  52. PyFiberModes-0.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,317 @@
1
+ # This file is part of FiberModes.
2
+ #
3
+ # FiberModes is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ from . import geometry
9
+ from . import solver
10
+ from .solver.solver import FiberSolver
11
+ from math import sqrt, isnan, isinf
12
+ from PyFiberModes import Wavelength, Mode, ModeFamily
13
+ from PyFiberModes import constants
14
+ from PyFiberModes.functions import derivative
15
+ from PyFiberModes.field import Field
16
+ from itertools import count
17
+ import logging
18
+ from scipy.optimize import fixed_point
19
+ from functools import lru_cache
20
+
21
+
22
+ class Fiber(object):
23
+
24
+ """The Fiber object usually is build using
25
+ :py:class:`~PyFiberModes.fiber.factory.FiberFactory`.
26
+
27
+ """
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+ def __init__(self, r, f, fp, m, mp, names, Cutoff=None, Neff=None):
32
+
33
+ self._r = r
34
+ self._names = names
35
+
36
+ self.layers = []
37
+ for i, (f_, fp_, m_, mp_) in enumerate(zip(f, fp, m, mp)):
38
+ ri = self._r[i - 1] if i else 0
39
+ ro = self._r[i] if i < len(r) else float("inf")
40
+ layer = geometry.__dict__[f_](ri, ro, *fp_,
41
+ m=m_, mp=mp_, cm=m[-1], cmp=mp[-1])
42
+ self.layers.append(layer)
43
+
44
+ self.co_cache = {Mode("HE", 1, 1): 0,
45
+ Mode("LP", 0, 1): 0}
46
+ self.ne_cache = {}
47
+
48
+ self.setSolvers(Cutoff, Neff)
49
+
50
+ def __len__(self):
51
+ return len(self.layers)
52
+
53
+ def __str__(self):
54
+ s = "Fiber {\n"
55
+ for i, layer in enumerate(self.layers):
56
+ geom = str(layer)
57
+ radius = self.outerRadius(i)
58
+ radius = '' if isinf(radius) else ' {:.3f} µm'.format(radius*1e6)
59
+ name = self.name(i)
60
+ name = ' "{}"'.format(name) if name else ''
61
+ s += " {}{}{}\n".format(geom, radius, name)
62
+ s += "}"
63
+ return s
64
+
65
+ def fixedMatFiber(self, wl):
66
+ f = []
67
+ fp = []
68
+ m = []
69
+ mp = []
70
+ for layer in self.layers:
71
+ f.append(layer.__class__.__name__)
72
+ fp.append(layer._fp)
73
+ m.append("Fixed")
74
+ mp.append([layer._m.n(wl, *layer._mp)])
75
+ return Fiber(self._r, f, fp, m, mp, self._names,
76
+ self._cutoff.__class__, self._neff.__class__)
77
+
78
+ def name(self, layer):
79
+ return self._names[layer]
80
+
81
+ def _layer(self, r):
82
+ r = abs(r)
83
+ for i, r_ in enumerate(self._r):
84
+ if r < r_:
85
+ return self.layers[i]
86
+ return self.layers[-1]
87
+
88
+ def innerRadius(self, layer):
89
+ if layer < 0:
90
+ layer = len(self._r) + layer + 1
91
+ return self._r[layer-1] if layer else 0
92
+
93
+ def outerRadius(self, layer):
94
+ return self._r[layer] if layer < len(self._r) else float("inf")
95
+
96
+ def thickness(self, layer):
97
+ return self.outerRadius(layer) - self.innerRadius(layer)
98
+
99
+ def index(self, r, wl):
100
+ return self._layer(r).index(r, wl)
101
+
102
+ def minIndex(self, layer, wl):
103
+ return self.layers[layer].minIndex(wl)
104
+
105
+ def maxIndex(self, layer, wl):
106
+ return self.layers[layer].maxIndex(wl)
107
+
108
+ def _findCutoffSolver(self):
109
+ cutoff = FiberSolver
110
+ if all(isinstance(layer, geometry.StepIndex)
111
+ for layer in self.layers):
112
+ nlayers = len(self)
113
+ if nlayers == 2: # SSIF
114
+ cutoff = solver.ssif.Cutoff
115
+ elif nlayers == 3:
116
+ cutoff = solver.tlsif.Cutoff
117
+ return cutoff
118
+
119
+ def _findNeffSolver(self):
120
+ neff = solver.mlsif.Neff
121
+ if all(isinstance(layer, geometry.StepIndex)
122
+ for layer in self.layers):
123
+ nlayers = len(self)
124
+ if nlayers == 2: # SSIF
125
+ neff = solver.ssif.Neff
126
+ return neff
127
+
128
+ def setSolvers(self, Cutoff=None, Neff=None):
129
+ assert Cutoff is None or issubclass(Cutoff, FiberSolver)
130
+ assert Neff is None or issubclass(Neff, FiberSolver)
131
+ if Cutoff is None:
132
+ Cutoff = self._findCutoffSolver()
133
+ self._cutoff = Cutoff(self)
134
+ if Neff is None:
135
+ Neff = self._findNeffSolver()
136
+ self._neff = Neff(self)
137
+
138
+ def set_ne_cache(self, wl, mode, neff):
139
+ try:
140
+ self.ne_cache[wl][mode] = neff
141
+ except KeyError:
142
+ self.ne_cache[wl] = {mode: neff}
143
+
144
+ def NA(self, wl):
145
+ n1 = max(layer.maxIndex(wl) for layer in self.layers)
146
+ n2 = self.minIndex(-1, wl)
147
+ return sqrt(n1*n1 - n2*n2)
148
+
149
+ def V0(self, wl):
150
+ return Wavelength(wl).k0 * self.innerRadius(-1) * self.NA(wl)
151
+
152
+ def toWl(self, V0, maxiter=500, tol=1e-15):
153
+ """Convert V0 number to wavelength.
154
+
155
+ An iterative method is used, since the index can be wavelength
156
+ dependant.
157
+
158
+ """
159
+ if V0 == 0:
160
+ return float("inf")
161
+ if isinf(V0):
162
+ return 0
163
+
164
+ def f(x):
165
+ return constants.tpi / V0 * b * self.NA(x)
166
+
167
+ b = self.innerRadius(-1)
168
+
169
+ wl = f(1.55e-6)
170
+ if abs(wl - f(wl)) > tol:
171
+ for w in (1.55e-6, 5e-6, 10e-6):
172
+ try:
173
+ wl = fixed_point(f, w, xtol=tol, maxiter=maxiter)
174
+ except RuntimeError:
175
+ # FIXME: What should we do if it does not converge?
176
+ self.logger.info(
177
+ "toWl: did not converged from {}µm "
178
+ "for V0 = {} (wl={})".format(w * 1e6, V0, wl))
179
+ if wl > 0:
180
+ break
181
+
182
+ if wl == 0:
183
+ self.logger.error("toWl: did not converged for "
184
+ "V0 = {} (wl={})".format(V0, wl))
185
+
186
+ return Wavelength(wl)
187
+
188
+ def cutoff(self, mode):
189
+ try:
190
+ return self.co_cache[mode]
191
+ except KeyError:
192
+ co = self._cutoff(mode)
193
+ self.co_cache[mode] = co
194
+ return co
195
+
196
+ def cutoffWl(self, mode):
197
+ return self.toWl(self.cutoff(mode))
198
+
199
+ def neff(self, mode, wl, delta=1e-6, lowbound=None):
200
+ try:
201
+ return self.ne_cache[wl][mode]
202
+ except KeyError:
203
+ neff = self._neff(Wavelength(wl), mode, delta, lowbound)
204
+ self.set_ne_cache(wl, mode, neff)
205
+ return neff
206
+
207
+ def beta(self, omega, mode, p=0, delta=1e-6, lowbound=None):
208
+ wl = Wavelength(omega=omega)
209
+ if p == 0:
210
+ neff = self.neff(mode, wl, delta, lowbound)
211
+ return neff * wl.k0
212
+
213
+ m = 5
214
+ j = (m - 1) // 2
215
+ h = 1e12 # This value is critical for accurate computation
216
+ lb = lowbound
217
+ for i in range(m-1, -1, -1):
218
+ # Precompute neff using previous wavelength
219
+ o = omega + (i-j) * h
220
+ wl = Wavelength(omega=o)
221
+ lb = self.neff(mode, wl, delta, lb) + delta * 1.1
222
+
223
+ return derivative(
224
+ self.beta, omega, p, m, j, h, mode, 0, delta, lowbound)
225
+
226
+ def b(self, mode, wl, delta=1e-6, lowbound=None):
227
+ """Normalized propagation constant"""
228
+ neff = self.neff(mode, wl, delta, lowbound)
229
+ nmax = max(layer.maxIndex(wl) for layer in self.layers)
230
+ ncl = self.minIndex(-1, wl)
231
+ ncl2 = ncl*ncl
232
+ return (neff*neff - ncl2) / (nmax*nmax - ncl2)
233
+
234
+ def vp(self, mode, wl, delta=1e-6, lowbound=None):
235
+ return constants.c / self.neff(mode, wl, delta, lowbound)
236
+
237
+ def ng(self, mode, wl, delta=1e-6, lowbound=None):
238
+ return self.beta(Wavelength(wl).omega,
239
+ mode, 1, delta, lowbound) * constants.c
240
+
241
+ def vg(self, mode, wl, delta=1e-6, lowbound=None):
242
+ return 1 / self.beta(
243
+ Wavelength(wl).omega, mode, 1, delta, lowbound)
244
+
245
+ def D(self, mode, wl, delta=1e-6, lowbound=None):
246
+ return -(self.beta(
247
+ Wavelength(wl).omega, mode, 2, delta, lowbound) *
248
+ constants.tpi * constants.c * 1e6 / (wl * wl))
249
+
250
+ def S(self, mode, wl, delta=1e-6, lowbound=None):
251
+ return (self.beta(
252
+ Wavelength(wl).omega, mode, 3, delta, lowbound) *
253
+ (constants.tpi * constants.c / (wl * wl))**2 * 1e-3)
254
+
255
+ def findVmodes(self, wl, numax=None, mmax=None, delta=1e-6):
256
+ families = (ModeFamily.HE, ModeFamily.EH, ModeFamily.TE, ModeFamily.TM)
257
+ return self.findModes(families, wl, numax, mmax, delta)
258
+
259
+ def findLPmodes(self, wl, ellmax=None, mmax=None, delta=1e-6):
260
+ families = (ModeFamily.LP,)
261
+ return self.findModes(families, wl, ellmax, mmax, delta)
262
+
263
+ def findModes(self, families, wl, numax=None, mmax=None, delta=1e-6):
264
+ """Find all modes of given families, within given constraints
265
+
266
+
267
+
268
+ """
269
+ modes = set()
270
+ v0 = self.V0(wl)
271
+ for fam in families:
272
+ for nu in count(0):
273
+ try:
274
+ _mmax = mmax[nu]
275
+ except IndexError:
276
+ _mmax = mmax[-1]
277
+ except TypeError:
278
+ _mmax = mmax
279
+
280
+ if (fam is ModeFamily.TE or fam is ModeFamily.TM) and nu > 0:
281
+ break
282
+ if (fam is ModeFamily.HE or fam is ModeFamily.EH) and nu == 0:
283
+ continue
284
+ if numax is not None and nu > numax:
285
+ break
286
+ for m in count(1):
287
+ if _mmax is not None and m > _mmax:
288
+ break
289
+ mode = Mode(fam, nu, m)
290
+ try:
291
+ co = self.cutoff(mode)
292
+ if co > v0:
293
+ break
294
+ except (NotImplementedError, ValueError):
295
+ neff = self.neff(mode, wl, delta)
296
+ if isnan(neff):
297
+ break
298
+ modes.add(mode)
299
+ if m == 1:
300
+ break
301
+ return modes
302
+
303
+ def field(self, mode, wl, r, np=101):
304
+ """Return electro-magnetic field.
305
+
306
+ """
307
+ return Field(self, mode, wl, r, np)
308
+
309
+ @lru_cache(maxsize=None)
310
+ def _rfield(self, mode, wl, r):
311
+ neff = self.neff(mode, wl)
312
+ fct = {ModeFamily.LP: self._neff._lpfield,
313
+ ModeFamily.TE: self._neff._tefield,
314
+ ModeFamily.TM: self._neff._tmfield,
315
+ ModeFamily.EH: self._neff._ehfield,
316
+ ModeFamily.HE: self._neff._hefield}
317
+ return fct[mode.family](wl, mode.nu, neff, r)
@@ -0,0 +1,10 @@
1
+ """A geometry describes a function applied to the refractive index,
2
+ as function of the radial position.
3
+
4
+ """
5
+
6
+ from .stepindex import StepIndex
7
+ from .supergaussian import SuperGaussian
8
+
9
+
10
+ __all__ = ['StepIndex', 'SuperGaussian']
@@ -0,0 +1,33 @@
1
+ # This file is part of FiberModes.
2
+ #
3
+ # FiberModes is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # FiberModes is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with FiberModes. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ from PyFiberModes.fiber import material
17
+
18
+
19
+ class Geometry(object):
20
+
21
+ def __init__(self, ri, ro, *fp, m, mp, **kwargs):
22
+ self._m = material.__dict__[m]() # instantiate material object
23
+ self._mp = mp
24
+ cm = kwargs.get("cm", None)
25
+ if cm:
26
+ self._cm = material.__dict__[cm]()
27
+ self._cmp = kwargs.get("cmp")
28
+ self._fp = fp
29
+ self.ri = ri
30
+ self.ro = ro
31
+
32
+ def __str__(self):
33
+ return self.__class__.__name__ + ' ' + self._m.str(*self._mp)
@@ -0,0 +1,181 @@
1
+ from PyFiberModes.fiber.geometry.geometry import Geometry
2
+ from PyFiberModes import constants
3
+ from math import sqrt
4
+ import numpy
5
+ from scipy.special import jn, yn, iv, kn
6
+ from scipy.special import j0, y0, i0, k0
7
+ from scipy.special import j1, y1, i1, k1
8
+ from scipy.special import jvp, yvp, ivp, kvp
9
+
10
+
11
+ class StepIndex(Geometry):
12
+
13
+ DEFAULT_PARAMS = []
14
+
15
+ def index(self, r, wl):
16
+ if self.ri <= abs(r) <= self.ro:
17
+ return self._m.n(wl, *self._mp)
18
+ else:
19
+ return None
20
+
21
+ def minIndex(self, wl):
22
+ return self._m.n(wl, *self._mp)
23
+
24
+ def maxIndex(self, wl):
25
+ return self._m.n(wl, *self._mp)
26
+
27
+ def u(self, r, neff, wl):
28
+ return wl.k0 * r * sqrt(abs(self.index(r, wl)**2 - neff**2))
29
+
30
+ def Psi(self, r, neff, wl, nu, C):
31
+ u = self.u(r, neff, wl)
32
+ if neff < self.maxIndex(wl):
33
+ psi = (C[0] * jn(nu, u) + C[1] * yn(nu, u) if C[1] else
34
+ C[0] * jn(nu, u))
35
+ psip = u * (C[0] * jvp(nu, u) + C[1] * yvp(nu, u) if C[1] else
36
+ C[0] * jvp(nu, u))
37
+ else:
38
+ psi = (C[0] * iv(nu, u) + C[1] * kn(nu, u) if C[1] else
39
+ C[0] * iv(nu, u))
40
+ psip = u * (C[0] * ivp(nu, u) + C[1] * kvp(nu, u) if C[1] else
41
+ C[0] * ivp(nu, u))
42
+ # if numpy.isnan(psi):
43
+ # print(neff, self.maxIndex(wl), C, r)
44
+ return psi, psip
45
+
46
+ def lpConstants(self, r, neff, wl, nu, A):
47
+ u = self.u(r, neff, wl)
48
+ if neff < self.maxIndex(wl):
49
+ W = constants.pi / 2
50
+ return (W * (u * yvp(nu, u) * A[0] - yn(nu, u) * A[1]),
51
+ W * (jn(nu, u) * A[1] - u * jvp(nu, u) * A[0]))
52
+ else:
53
+ return ((u * kvp(nu, u) * A[0] - kn(nu, u) * A[1]),
54
+ (iv(nu, u) * A[1] - u * ivp(nu, u) * A[0]))
55
+
56
+ def EH_fields(self, ri, ro, nu, neff, wl, EH, tm=True):
57
+ """
58
+
59
+ modify EH in-place (for speed)
60
+
61
+ """
62
+ n = self.maxIndex(wl)
63
+ u = self.u(ro, neff, wl)
64
+
65
+ if ri == 0:
66
+ if nu == 0:
67
+ if tm:
68
+ self.C = numpy.array([1., 0., 0., 0.])
69
+ else:
70
+ self.C = numpy.array([0., 0., 1., 0.])
71
+ else:
72
+ self.C = numpy.zeros((4, 2))
73
+ self.C[0, 0] = 1 # Ez = 1
74
+ self.C[2, 1] = 1 # Hz = alpha
75
+ elif nu == 0:
76
+ self.C = numpy.zeros(4)
77
+ if tm:
78
+ c = constants.Y0 * n * n
79
+ idx = (0, 3)
80
+ self.C[:2] = self.tetmConstants(ri, ro, neff, wl, EH, c, idx)
81
+ else:
82
+ c = -constants.eta0
83
+ idx = (1, 2)
84
+ self.C[2:] = self.tetmConstants(ri, ro, neff, wl, EH, c, idx)
85
+ else:
86
+ self.C = self.vConstants(ri, ro, neff, wl, nu, EH)
87
+
88
+ # Compute EH fields
89
+ if neff < n:
90
+ c1 = wl.k0 * ro / u
91
+ F3 = jvp(nu, u) / jn(nu, u)
92
+ F4 = yvp(nu, u) / yn(nu, u)
93
+ else:
94
+ c1 = -wl.k0 * ro / u
95
+ F3 = ivp(nu, u) / iv(nu, u)
96
+ F4 = kvp(nu, u) / kn(nu, u)
97
+
98
+ c2 = neff * nu / u * c1
99
+ c3 = constants.eta0 * c1
100
+ c4 = constants.Y0 * n * n * c1
101
+
102
+ EH[0] = self.C[0] + self.C[1]
103
+ EH[1] = self.C[2] + self.C[3]
104
+ EH[2] = (c2 * (self.C[0] + self.C[1]) -
105
+ c3 * (F3 * self.C[2] + F4 * self.C[3]))
106
+ EH[3] = (c4 * (F3 * self.C[0] + F4 * self.C[1]) -
107
+ c2 * (self.C[2] + self.C[3]))
108
+
109
+ return EH
110
+
111
+ def vConstants(self, ri, ro, neff, wl, nu, EH):
112
+ a = numpy.zeros((4, 4))
113
+ n = self.maxIndex(wl)
114
+ u = self.u(ro, neff, wl)
115
+ urp = self.u(ri, neff, wl)
116
+
117
+ if neff < n:
118
+ B1 = jn(nu, u)
119
+ B2 = yn(nu, u)
120
+ F1 = jn(nu, urp) / B1
121
+ F2 = yn(nu, urp) / B2
122
+ F3 = jvp(nu, urp) / B1
123
+ F4 = yvp(nu, urp) / B2
124
+ c1 = wl.k0 * ro / u
125
+ else:
126
+ B1 = iv(nu, u)
127
+ B2 = kn(nu, u)
128
+ F1 = iv(nu, urp) / B1 if u else 1
129
+ F2 = kn(nu, urp) / B2
130
+ F3 = ivp(nu, urp) / B1 if u else 1
131
+ F4 = kvp(nu, urp) / B2
132
+ c1 = -wl.k0 * ro / u
133
+ c2 = neff * nu / urp * c1
134
+ c3 = constants.eta0 * c1
135
+ c4 = constants.Y0 * n * n * c1
136
+
137
+ a[0, 0] = F1
138
+ a[0, 1] = F2
139
+ a[1, 2] = F1
140
+ a[1, 3] = F2
141
+ a[2, 0] = F1 * c2
142
+ a[2, 1] = F2 * c2
143
+ a[2, 2] = -F3 * c3
144
+ a[2, 3] = -F4 * c3
145
+ a[3, 0] = F3 * c4
146
+ a[3, 1] = F4 * c4
147
+ a[3, 2] = -F1 * c2
148
+ a[3, 3] = -F2 * c2
149
+
150
+ return numpy.linalg.solve(a, EH)
151
+
152
+ def tetmConstants(self, ri, ro, neff, wl, EH, c, idx):
153
+ a = numpy.empty((2, 2))
154
+ n = self.maxIndex(wl)
155
+ u = self.u(ro, neff, wl)
156
+ urp = self.u(ri, neff, wl)
157
+
158
+ if neff < n:
159
+ B1 = j0(u)
160
+ B2 = y0(u)
161
+ F1 = j0(urp) / B1
162
+ F2 = y0(urp) / B2
163
+ F3 = -j1(urp) / B1
164
+ F4 = -y1(urp) / B2
165
+ c1 = wl.k0 * ro / u
166
+ else:
167
+ B1 = i0(u)
168
+ B2 = k0(u)
169
+ F1 = i0(urp) / B1
170
+ F2 = k0(urp) / B2
171
+ F3 = i1(urp) / B1
172
+ F4 = -k1(urp) / B2
173
+ c1 = -wl.k0 * ro / u
174
+ c3 = c * c1
175
+
176
+ a[0, 0] = F1
177
+ a[0, 1] = F2
178
+ a[1, 0] = F3 * c3
179
+ a[1, 1] = F4 * c3
180
+
181
+ return numpy.linalg.solve(a, EH.take(idx))