1
2
3 """
4 Module for calculating the opacity.
5
6 Author: R. Lombaert
7
8 """
9
10 import collections
11 import numpy as np
12 from astropy import constants as cst
13 from scipy.interpolate import InterpolatedUnivariateSpline as spline1d
14
15 from cc.modeling.profilers import Profiler
16 from cc.modeling.profilers import Density
17 from cc.tools.readers import KappaReader as KR
18 from cc.tools.numerical import Operators as op
19 from cc.data import Data
20
21
22 -def read_opacity(x,species,index=1,unit='cm',*args,**kwargs):
23
24 '''
25 Read the opacities with the KappaReader and interpolate.
26
27 Returns a tuple with the original grid, and the interpolation object. Used
28 by the Opacity class to set an interpolation object for a .opac/.particle
29 file through species given in usr/Dust.dat.
30
31 Additional args and kwargs can be passed to the interpolate method.
32
33 @param x: The x grid requested for the interpolation. Note that this is a
34 dummy variable to allow Profiler to work with this function.
35 @type x: array
36 @param species: The dust species (from Dust.dat)
37 @type species: string
38
39 @keyword index: The index of the kappas in the .opacity/.particle file.
40 0: extinction, 1: absorption, 2: scattering
41
42 (default: 1)
43 @type index: int
44 @keyword unit: The unit of the wavelength. Can be given as u.Unit()
45 object or as a string representation of those objects.
46 Can range from length, to frequency, and energy
47
48 (default: cm)
49 @type unit: str/u.Unit()
50
51 @return: The interpolator for the mass extinction/absorption/scattering
52 coefficients. (in cgs!)
53 @rtype: spline1d
54
55 '''
56
57 kr = KR.KappaReader()
58 return (kr.getWavelength(species,unit=unit),kr.getKappas(species,index),
59 kr.interpolate(species,index,unit=unit,*args,**kwargs))
60
61
62
64
65 '''
66 An interface for an opacity profile and any type of extinction quantity.
67
68 '''
69
70 - def __init__(self,l,func,dfunc=None,order=3,*args,**kwargs):
71
72 '''
73 Create an instance of the Opacity() class. Requires a wavelength grid.
74
75 The function can also be given as an interpolation object.
76
77 The optional args and kwargs give the additional arguments for the
78 opacity function, which are ignored in case func is an interpolation
79 object.
80
81 Eval and diff work with the mass extinction coefficient in cm2/g.
82
83 In case func refers to an interpolation object in KappaReader, the
84 args/kwargs should always contain an index indicating whether extinction
85 (default), absorption or scattering is requested:
86 - 0: extinction,
87 - 1: absorption,
88 - 2: scattering
89
90 Note that if func is an interpolator object, the original input x and y
91 grids can be passed as additional keywords xin/lin and yin, which would
92 then be arrays. Otherwise, the x and the interpolator(x) are set as
93 xin/lin and yin. xin/lin and yin are ignored if func is a function, even
94 if it returns an interpolator (in which case the original grids are
95 known)
96
97 Extrapolation is done outside of the "original" (depending on if xin/yin
98 are given) wavelength ranges according to a power law ~l^-alpha, with
99 alpha given upon eval() calls.
100
101 @param l: The wavelength points (cm)
102 @type l: array
103 @param func: The function that describes the opacity profile. Can be
104 given as an interpolation object, in which case lin and yin
105 keywords can be passed as arrays for the original grids.
106 @type func: function
107
108 @keyword dfunc: Function that describes the derivative of the profile
109 with respect to x. Can be given as an interpolation
110 object. If None, a generic central difference is taken &
111 interpolated with a spline of which the order can be
112 chosen.
113
114 (default: None)
115 @type dfunc: function/interpolation object
116 @keyword order: Order of the spline interpolation. Default is cubic.
117
118 (default: 3)
119 @type order: int
120
121 @keyword args: Additional parameters passed to the functions when eval
122 or diff are called.
123
124 (default: [])
125 @type args: tuple
126 @keyword kwargs: Additional keywords passed to the functions when eval
127 or diff are called.
128
129 (default: {})
130 @type kwargs: dict
131
132 '''
133
134
135 if kwargs.has_key('lin'):
136 kwargs['xin'] = kwargs['lin']
137 del kwargs['lin']
138
139
140 super(Opacity, self).__init__(l,func,dfunc,order,*args,**kwargs)
141
142
143
144 if kwargs.has_key('index'):
145 self.index = kwargs['index']
146 else:
147 self.index = 0
148
149
150 self.alpha = 2.
151
152
153
154 if not self.interp_func:
155 self.l = self.x
156 self.kappa = self.y
157 return
158
159
160
161
162
163
164
165 self.l = None
166 self.kappa = None
167 self.y = None
168
169
170
171
172 self.kappa = self.eval(self.x,alpha=2.)
173 self.y = self.kappa
174
175
176 if self.interp_dfunc:
177 self.dfunc = spline1d(x=self.x,y=op.diff_central(self.y,self.x),\
178 k=self.order)
179
180
181 self.dydx = self.dfunc(self.x,*self._dargs,**self._dkwargs)
182
183
184 self.l = self.x
185 self.dydl = self.dydx
186
187
188
189 - def __call__(self,l=None,*args,**kwargs):
190
191 '''
192 Evaluate the profile function at a coordinate point.
193
194 l can be any value or array. No warning is printed in case of
195 extrapolation, which is done with a power law at small or large l values
196 by the eval() function.
197
198 The default y-grid is returned if l is None.
199
200 Passes the call to eval. Additional keywords for the power law
201 extrapolation can be passed this way as well.
202
203 @keyword l: The primary coordinate point(s). If None, the default
204 coordinate grid is used.
205
206 (default: None)
207 @type l: array/float
208
209 @return: The profile evaluated at l
210 @rtype: array/float
211
212 '''
213
214 return self.eval(l,*args,**kwargs)
215
216
217
218 - def eval(self,l=None,alpha=2.):
219
220 '''
221 Evaluate the profile function at a coordinate point.
222
223 l can be any value or array. No warning is printed in case of
224 extrapolation, which is done with a power law at small or large l values
225
226 The default y-grid is returned if l is None and alpha is 2 (the default)
227
228 @keyword l: The coordinate point(s). If None, the default
229 coordinate grid is used.
230
231 (default: None)
232 @type l: array/float
233 @keyword alpha: The exponent of the wavelength-dependent power law
234 extrapolation, such that kappa ~ lambda^-alpha
235
236 (default: 2.)
237 @type alpha: float
238
239 @return: The profile evaluated at l
240 @rtype: array/float
241
242 '''
243
244
245 if l is None and alpha == self.alpha:
246 return self.y
247
248
249 if l is None:
250 l = self.l
251
252
253
254
255 y = super(Opacity,self).eval(l,warn=0)
256
257
258
259 if not self.interp_func: return y
260
261
262
263 lmin, lmax = self.xin[0], self.xin[-1]
264 ymin, ymax = self.yin[0], self.yin[-1]
265
266
267
268 larr, y = Data.arrayify(l), Data.arrayify(y)
269 y[larr<lmin] = ymin*(larr[larr<lmin]/lmin)**(-alpha)
270 y[larr>lmax] = ymax*(larr[larr>lmax]/lmax)**(-alpha)
271
272 return y if isinstance(l,collections.Iterable) else y[0]
273
274
275
276 - def diff(self,l=None,alpha=2.):
277
278 '''
279 Evaluate the derivative of the profile function at a coordinate point.
280
281 l can be any value or array. No warning is printed in case of
282 extrapolation, which is done with a power law at small or large l values
283
284 The default y-grid is returned if l is None and alpha is 2 (the default)
285
286 @keyword l: The coordinate point(s). If None, the default
287 coordinate grid is used.
288
289 (default: None)
290 @type l: array/float
291 @keyword alpha: The exponent of the wavelength-dependent power law
292 extrapolation, such that kappa ~ lambda^-alpha
293
294 (default: 2.)
295 @type alpha: float
296
297 @return: The derivative evaluated at l
298 @rtype: array/float
299
300 '''
301
302
303 if l is None and alpha == self.alpha:
304 return self.dydx
305
306
307 if l is None:
308 l = self.l
309
310
311
312
313
314 dydl = super(Opacity,self).diff(l,warn=0)
315
316
317
318 if not (self.interp_dfunc and self.interp_func): return dydl
319
320
321
322 lmin, lmax = self.xin[0], self.xin[-1]
323 ymin, ymax = self.yin[0], self.yin[-1]
324
325
326
327 larr, dydl = Data.arrayify(l), Data.arrayify(dydl)
328 dydl[larr<lmin] = ymin*(larr[larr<lmin]/lmin)**(-alpha-1.)*-alpha/lmin
329 dydl[larr>lmax] = ymax*(larr[larr>lmax]/lmax)**(-alpha-1.)*-alpha/lmax
330
331 return dydl if isinstance(l,collections.Iterable) else dydl[0]
332
333
334
336
337 '''
338 Calculate the extinction/absorption/scattering (depending on index)
339 efficiency for given grain size and porosity on a wavelength grid.
340
341 Follows: Q = (extinction cross section) / (geometric cross section)
342 where geometric cross section is the effective surface, hence
343 pi*a^2/(1-P)^(2/3), taking into account the porosity of the grain.
344
345 @param l: The wavelength points (cm)
346 @type l: array
347 @param a: The grain size (cm)
348 @type a: float
349 @param sd: The specific density of the dust species (g/cm3)
350 @type sd: float
351 @keyword P: The porosity of the grain (or equivalent, to represent
352 effective grain surface). Default is the spherical case. Is
353 given as the ratio of vacuum per unit volume of a grain.
354
355 (default: 0)
356 @type P: float
357 @keyword alpha: The exponent of the wavelength-dependent power law
358 extrapolation, such that kappa ~ lambda^-alpha
359
360 (default: 2.)
361 @type alpha: float
362
363 @return: The dimensionless extinction efficiencies
364 @rtype: array
365
366 '''
367
368 kappas = self.eval(l,alpha=alpha)
369 return kappas * 4./3. * sd * a * (1-P)**(2./3.)
370