""" scattering.scatterer.py
Copyright (C) 2017 - 2018 Davide Ori dori@uni-koeln.de
Institute for Geophysics and Meteorology - University of Cologne
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
This module implements the scatterer class which is the parent class for
all of the specific scattering models.
The parent scatterer class is intended to provide an abstraction layer or a
common interface to the various scattering models.
"""
import sys
import numpy as np
from pamtra2.libs.refractiveIndex import utilities as ref_utils
from . import scattering_utilities as scatt_utils
[docs]light_speed = 299792458.
[docs]class Scatterer(object):
""" Parent Scatterer class from which every scattering method inherits
Attributes:
diameter: Equivalent size of the target in meters. The user should know
how to properly define it.
frequency, wavelength: The frequency [Hz] or the wavelength [meters] of
incident light, see set_electromagnetic_wave function for details.
refractive_index, dielectric_permittivity: The refractive index or the
relative dielectric permittivity of the scattering target, see
set_dielectric_properties for further details
alpha, beta, gamma: Euler angles of the particle orientation...
... still do not know if I need all of them
theta_inc, theta_sca:
phi_inc, phi_sca:
"""
def __init__(self,
diameter=1.,
frequency=None,
wavelength=None,
refractive_index=None,
dielectric_permittivity=None,
alpha=0.0,
beta=0.0,
theta_inc=0.0,
theta_sca=0.0,
phi_inc=0.0,
phi_sca=0.0,
aspect_ratio=1,
volume=-99,
):
# first, convert inputs to arrays
diameter, diameter_scalar = self.makeArray(diameter)
refractive_index, refractive_index_scalar = self.makeArray(
refractive_index)
dielectric_permittivity, dielectric_permittivity_scalar = self.makeArray(
dielectric_permittivity)
frequency, frequency_scalar = self.makeArray(frequency)
wavelength, wavelength_scalar = self.makeArray(wavelength)
aspect_ratio, aspect_ratio_scalar = self.makeArray(aspect_ratio)
volume, volume_scalar = self.makeArray(volume)
if (
diameter_scalar and
refractive_index_scalar and
dielectric_permittivity_scalar and
frequency_scalar and
wavelength_scalar and
aspect_ratio_scalar and
volume_scalar
):
self.scalar_input = True
else:
self.scalar_input = False
self.diameter = diameter
self.aspect_ratio = aspect_ratio
self.volume = volume
self.set_electromagnetic_wave(wavelength, frequency)
self.set_dielectric_properties(refractive_index,
dielectric_permittivity)
self.ravel_input()
self.wavenumber = 2.0*np.pi/self.wavelength
self.size_parameter = scatt_utils.size_parameter(0.5*self.diameter,
self.wavelength)
self.set_scattering_geometry([theta_inc, theta_sca, phi_inc, phi_sca,
alpha, beta])
[docs] def makeArray(self, var):
# to make sure it is an array
if var is None:
scalar_input = True
else:
var = np.asarray(var)
scalar_input = False
if var.ndim == 0:
var = var[np.newaxis] # Makes x 1D
scalar_input = True
return var, scalar_input
[docs] def unravel_output(self):
# black to original shape!
if self.scalar_input:
# if scalars were initialy provided, make arrays scalar again
self.S = np.squeeze(self.S)
self.Cabs = np.squeeze(self.Cabs)
self.Csca = np.squeeze(self.Csca)
self.Cext = np.squeeze(self.Cext)
self.Cbck = np.squeeze(self.Cbck)
else:
self.S = self.S.reshape(self.shapeIn+(2, 2,))
self.Cabs = self.Cabs.reshape(self.shapeIn)
self.Csca = self.Csca.reshape(self.shapeIn)
self.Cext = self.Cext.reshape(self.shapeIn)
self.Cbck = self.Cbck.reshape(self.shapeIn)
[docs] def set_electromagnetic_wave(self, wavelength, frequency):
""" Convenience setter of the properties of the incoming electromagnetic
wave
This setter function resolve the ambiguity of specifing either
wavelength or the frequency which should not be set indipendently in
orderto avoid internal inconsistencies
Parameters
----------
wavelength : scalar real wavelength [meters] of the incoming
electromagnetic wave
frequency : scalar real frequency [Hz] of the incoming electromagnetic
wave
"""
if (wavelength is None):
if (frequency is None):
raise AttributeError('Either frequency or wavelength' +
'must be set')
else:
self.frequency = frequency
self.wavelength = light_speed/frequency
elif (frequency is None):
self.wavelength = wavelength
self.frequency = light_speed/wavelength
else:
raise AttributeError('Both frequency and wavelength have been'
+ 'defined')
[docs] def set_dielectric_properties(self, refractive_index,
dielectric_permittivity):
""" Convenience setter of the dielectric properties of the scatterer
instance
This setter resolve the ambiguity of specifing either dielectric
permittivity or the refractive index of the medium which should not be
set independently in order to avoid internal inconsistencies
Parameters
----------
refractive_index : scalar complex refractive index [dimensionless] of
the scattering target
dielectric_permittivity : scalar complex relative dielectric
permittivity [dimensionless] of the scattering target
"""
if (refractive_index is None):
if (dielectric_permittivity is None):
# raise AttributeError('Dielectric permittivity or refractive' +
# ' index should be defined')
# need to allow this for DB based scattering ???
self.refractive_index = None
self.dielectric_permittivity = None
else:
self.dielectric_permittivity = np.array(
dielectric_permittivity)
self.refractive_index = ref_utils.eps2n(
self.dielectric_permittivity)
self.K2 = ref_utils.K2(self.dielectric_permittivity)
elif (dielectric_permittivity is None):
self.refractive_index = np.array(refractive_index)
self.dielectric_permittivity = ref_utils.n2eps(
self.refractive_index)
self.K2 = ref_utils.K2(self.dielectric_permittivity)
else:
raise AttributeError('Both dielectric permittivity and refractive'
+ ' index have been defined')
[docs] def set_scattering_geometry(self, geometry):
""" Convenience setter of the scattering geometry that takes as input
a 4-element array containing all 4 incident and scattering angles
Any update of the geometry should call the scattering_angle function in
order to correctly update this value
Parameters
----------
geometry : A tuple of 6 elements containing (theta_inc, theta_sca,
phi_inc, phi_sca, alpha, beta) [rad]
"""
(self.theta_inc, self.theta_sca, self.phi_inc, self.phi_sca,
self.alpha, self.beta) = geometry
angles = scatt_utils.scattering_angle(self.theta_inc, self.theta_sca,
self.phi_inc, self.phi_sca)
self.scatt_angle, self.rot_alpha, self.rot_beta = angles
[docs] def estimate_amplitude_matrix(self, S1, S2, S34, Ra, Rb):
S1234 = np.zeros(S1.shape + (2, 2,)) + 0.0j
S1234[..., 0, 0] = S2
S1234[..., 0, 1] = S34
S1234[..., 1, 0] = S34
S1234[..., 1, 1] = S1
# @ operator applies only to two last dimesnions.
self.S = Rb@S1234@Ra.T
[docs]class Liu_DB(Scatterer):
def __init__(self):
Scatterer.__init__(self)
print('I am a Liu_DB instance')
raise NotImplementedError('Liu_DB is not implemented yet')
[docs]class Hong_DB(Scatterer):
def __init__(self):
Scatterer.__init__(self)
print('I am a Hong_DB instance')
raise NotImplementedError('Hong_DB is not implemented yet')
[docs]class Leinonen_DB(Scatterer):
def __init__(self):
Scatterer.__init__(self)
print('I am a Leinonen_DB instance')
raise NotImplementedError('Leinonen_DB is not implemented yet')
[docs]class Aydin_DB(Scatterer):
def __init__(self):
Scatterer.__init(self)
print('I am a Aydin_DB instance')
raise NotImplementedError('Aydin_DB is not implemented yet')