1 # Cythonized parts of QPMS here
2 # -----------------------------
6 from .qpms_cdefs cimport qpms_permittivity_interpolator_from_yml
, qpms_permittivity_interpolator_free
, qpms_permittivity_interpolator_omega_min
, qpms_permittivity_interpolator_omega_max
, gsl_interp_type
, qpms_permittivity_interpolator_t
, gsl_interp_cspline
, qpms_permittivity_interpolator_eps_at_omega
, qpms_epsmu_const_g
, qpms_permittivity_interpolator_epsmu_g
, qpms_epsmu_const_g
, qpms_lorentzdrude_epsmu_g
, qpms_ldparams_triple_t
, qpms_lorentzdrude_eps
, cdouble
7 from .cycommon cimport make_c_string
12 from scipy
.constants
import e
as eV
, hbar
, c
13 from libc
.stdlib cimport malloc
, free
, calloc
, abort
15 class EpsMuGeneratorType
(enum
.Enum
):
17 PERMITTIVITY_INTERPOLATOR
= 2
22 """Permittivity and permeability of an isotropic material.
24 This wraps the C structure qpms_epsmu_t.
28 EpsMuGenerator : generates EpsMu objects as a function of frequency.
30 def __init__
(self, *args
,**kwargs
):
31 """EpsMu object constructor
36 Relative electric permittivity.
38 Relative magnetic permeability.
46 if 'eps' in kwargs
.keys
():
47 self.em
.eps
= kwargs
['eps']
48 if 'mu' in kwargs
.keys
():
49 self.em
.mu
= kwargs
['mu']
53 return 'EpsMu(' + repr(self.em
.eps
) + ', ' + repr(self.em
.mu
) + ')'
56 """Wavenumber of the material at frequency omega
61 Angular frequency in 1/s.
66 Wavenumber of the material at omega assuming permittivity and permeability
69 return self.n
* omega
/ c
72 """Refractive index of a material specified by this permittivity and permeability."""
74 return (self.em
.eps
* self.em
.mu
)**.5
76 """Wave impedance of a material specified by this permittivity and permeability."""
78 return (self.em
.mu
/ self.em
.eps
)**.5
80 cdef class LorentzDrudeModel
:
81 """Lorentz-Drude model of material permittivity.
83 This wraps the C structure qpms_ldparams_t.
85 Some materials are available in the `lorentz_drude` dictionary.
88 def __cinit__
(self, eps_inf
, omega_p
, f_arr
, omega_arr
, gamma_arr
):
89 cdef size_t n
= len(omega_arr
)
90 if (n
!= len(gamma_arr
) or n
!= len(f_arr
)):
91 raise ValueError("omega_arr, gamma_arr and f_arr must have equal lengths!")
92 cdef qpms_ldparams_t
*p
93 p
= <qpms_ldparams_t
*>malloc
(sizeof(qpms_ldparams_t
) + sizeof(qpms_ldparams_triple_t
) * n
)
94 p
[0].eps_inf
= eps_inf
95 p
[0].omega_p
= omega_p
99 p
[0].data
[i
].f
= f_arr
[i
]
100 p
[0].data
[i
].omega
= omega_arr
[i
]
101 p
[0].data
[i
].gamma
= gamma_arr
[i
]
104 def __dealloc__
(self):
108 def __call__
(self, omega
):
109 """Evaluates the permittivity at a given frequency
114 Angular frequency in 1/s.
119 Relative permittivity from the Lorentz-Drude model
121 return qpms_lorentzdrude_eps
(omega
, self.params
)
123 cdef class _CLorentzDrudeModel
:
124 """Lorentz-Drude model of material permittivity.
126 This is an auxilliary class making the pre-compiled C Lorentz-Drude models accessible.
127 For defining own Lorentz-Drude models from python, use LorentzDrudeModel class instead.
130 "Do not use directly. Do not use from Python. Use the link() method instead."
134 cdef link
(const qpms_ldparams_t
*params
):
135 self = _CLorentzDrudeModel
()
139 def __call__
(self, omega
):
140 """Evaluates the permittivity at a given frequency
145 Angular frequency in 1/s.
150 Relative permittivity from the Lorentz-Drude model
152 return qpms_lorentzdrude_eps
(omega
, self.params
)
154 cdef double eh
= eV
/hbar
156 # Some basic Lorentz-Drude parameters
158 'Au_py' : # This should give the same results as 'Au'; to be removed.
159 LorentzDrudeModel
(1, 9.03*eh
,
160 (0.76, 0.024, 0.01, 0.071, 0.601, 4.384),
161 (0, 0.415*eh
, 0.83*eh
, 2.969*eh
, 4.304*eh
, 13.32*eh
),
162 (0.053*eh
, 0.241*eh
, 0.345*eh
, 0.87*eh
, 2.494*eh
, 2.214*eh
)),
163 'Ag_py' : # This should give the same results as 'Ag'; to be removed.
164 LorentzDrudeModel
(1, 9.01*eh
,
165 (0.84, 0.065,0.124, 0.111, 0.840, 5.646),
166 (0, 0.816*eh
,4.481*eh
, 8.185*eh
, 9.083*eh
, 20.29*eh
),
167 (0.053*eh
, 3.886*eh
, 0.452*eh
,0.065*eh
, 0.916*eh
, 2.419*eh
)),
168 'Au' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_AU
),
169 'Ag' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_AG
),
170 'Cu' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_CU
),
171 'Al' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_AL
),
172 'Cr' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_CR
),
173 'Ti' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_TI
),
174 'Be' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_BE
),
175 'Ni' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_NI
),
176 'Pd' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_PD
),
177 'Pt' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_PT
),
178 'W' : _CLorentzDrudeModel
.link
(QPMS_LDPARAMS_W
),
182 cdef qpms_epsmu_t python_epsmu_generator
(cdouble omega
, const
void *params
):
183 cdef object fun
= <object> params
185 em
.eps
, em
.mu
= fun
(omega
)
190 cdef class EpsMuGenerator
:
191 def __init__
(self, what
):
192 if isinstance(what
, str):
193 if what
in lorentz_drude
.keys
():
194 what
= lorentz_drude
[what
]
196 try: what
= float(what
)
198 try: what
= complex(what
)
199 except ValueError as ve
:
200 raise ValueError("Trying to create EpsMuGenerator from a string that can't be parsed as a number (constant refractive index) nor supported lorentz-drude key") from ve
201 if isinstance(what
, int):
203 if isinstance(what
, (float, complex)):
204 what
= EpsMu
(what
**2)
205 if isinstance(what
, EpsMu
):
207 self.g
.function
= qpms_epsmu_const_g
208 self.g
.params
= (<EpsMu?
>self.holder
).rawpointer
()
209 elif isinstance(what
, LorentzDrudeModel
):
211 self.g
.function
= qpms_lorentzdrude_epsmu_g
212 self.g
.params
= (<LorentzDrudeModel?
>self.holder
).rawpointer
()
213 elif isinstance(what
, _CLorentzDrudeModel
):
215 self.g
.function
= qpms_lorentzdrude_epsmu_g
216 self.g
.params
= (<_CLorentzDrudeModel?
>self.holder
).rawpointer
()
217 elif isinstance(what
, MaterialInterpolator
):
219 self.g
.function
= qpms_permittivity_interpolator_epsmu_g
220 self.g
.params
= (<MaterialInterpolator?
>self.holder
).rawpointer
()
221 elif isinstance(what
, EpsMuGenerator
): # Copy constructor
222 self.holder
= (<EpsMuGenerator?
>what
).holder
223 self.g
= (<EpsMuGenerator?
>what
).g
225 warnings
.warn
("Custom python (eps,mu) generators are an experimental feature")
227 self.g
.function
= python_epsmu_generator
228 self.g
.params
= <const
void *> what
230 raise ValueError("Must be constructed from a number (refractive index), EpsMu, LorentzDrudeModel or MaterialInterpolator, or a python callable object that returns an (epsilon, mu) tuple.")
234 if(self.g
.function
== qpms_epsmu_const_g
):
235 return EpsMuGeneratorType
.CONSTANT
236 elif(self.g
.function
== qpms_lorentzdrude_epsmu_g
):
237 return EpsMuGeneratorType
.LORENTZ_DRUDE
238 elif(self.g
.function
== qpms_permittivity_interpolator_epsmu_g
):
239 return EpsMuGeneratorType
.PERMITTIVITY_INTERPOLATOR
240 elif(self.g
.function
== python_epsmu_generator
):
241 return EpsMuGeneratorType
.PYTHON_CALLABLE
243 raise ValueError("Damn, this is a bug.")
245 def __call__
(self, omega
):
247 if self.g
.function
== qpms_permittivity_interpolator_epsmu_g
:
248 i
= self.holder
.freq_interval
249 if(omega
< i
[0] or omega
> i
[1]):
250 raise ValueError("Input frequency %g is outside the interpolator domain (%g, %g)."
251 % (omega
, i
[0], i
[1]))
252 em
= self.g
.function
(omega
, self.g
.params
)
253 return EpsMu
(em
.eps
, em
.mu
)
260 return self(omega
).k
(omega
)
262 cdef qpms_epsmu_generator_t raw
(self):
266 cdef class MaterialInterpolator
:
268 Wrapper over the qpms_permittivity_interpolator_t structure.
271 def __cinit__
(self, filename
, *args
, **kwargs
):
272 '''Creates a permittivity interpolator.'''
273 cdef char *cpath
= make_c_string
(filename
)
274 self.interp
= qpms_permittivity_interpolator_from_yml
(cpath
, gsl_interp_cspline
)
276 raise IOError("Could not load permittivity data from %s" % filename
)
277 self.omegamin
= qpms_permittivity_interpolator_omega_min
(self.interp
)
278 self.omegamax
= qpms_permittivity_interpolator_omega_max
(self.interp
)
280 def __dealloc__
(self):
281 qpms_permittivity_interpolator_free
(self.interp
)
283 def __call__
(self, double freq
):
284 '''Returns interpolated permittivity, corresponding to a given angular frequency.'''
285 if freq
< self.omegamin
or freq
> self.omegamax
:
286 raise ValueError("Input frequency %g is outside the interpolator domain (%g, %g)."
287 % (freq
, self.minomega
, self.freqs
[self.maxomega
]))
288 return qpms_permittivity_interpolator_eps_at_omega
(self.interp
, freq
)
290 property freq_interval
:
292 return [self.omegamin
, self.omegamax
]