#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Empirically based model (:mod:`hydrac.model.scattering.emp`)
============================================================
.. autoclass:: Emp
:members:
:private-members:
"""
import numpy as np
from hydrac.util.parameters import Parameters
[docs]class Emp(object):
"""Empirical models class.
This class deals with empirically defined models, so easy to compute due to
their parametric description. These models are called heuristic, as being
based on experimental measurements in controlled environments. These have
been formulated to describe the backscattering properties of irregularly
shaped marine sand or flocs suspensions following a:math:`1/4\\Phi` size
distribution.
The class calls the method
:func:`hydrac.model.scattering.scattering.Scattering.calc_f` to compute
the model for all :math:`ka` values.
Parameters
----------
obj : object
Scattering object from
:class:`hydrac.model.scattering.scattering.Scattering`
f : float (numpy.array)
Instrument frequencies
a : float (numpy.array)
Size vector
theta : float
Angle of observation (:math:`\\theta=0` for backscattering)
"""
def __init__(self, obj, f, a, theta=0):
self.obj = obj
self.obj.scattering.atmp = a
self.obj.scattering.theta = theta
self.obj.scattering.katmp = 2 * np.pi * np.outer(f, a) / self.obj.cw
self.f = f
if self.obj.particle.nature == 'MIN':
# exec('self.obj.scattering.' + _modname[0] +
# ',self.obj.scattering.' + _modname[1] + '=self.emp_min_func()')
self.obj.scattering.f_inftmp,\
self.obj.scattering.c_inftmp = self.emp_min_func()
elif self.obj.particle.nature == 'HYB':
# exec('self.obj.scattering.' + _modname[0] +
# ',self.obj.scattering.' + _modname[1] + '=self.emp_min_func()')
self.obj.scattering.f_inftmp,\
self.obj.scattering.c_inftmp = self.emp_hyb_func()
elif self.obj.particle.nature == 'ORG':
self.obj.scattering.f_inftmp =\
np.zeros(np.shape(self.obj.scattering.katmp))
self.obj.scattering.c_inftmp =\
np.zeros(np.shape(self.obj.scattering.katmp))
[docs] def emp_min_func(self):
"""
This method computes the Thorne & Meral (2008) model. This model is
only valid for backscattering, and describes the scattering properties
of irregularly shaped marine sand
Returns
-------
f_inf : float (numpy.array)
Model form function :math:`f_{\infty}`
c_inf : float (numpy.array)
Model total scattering cross-secton :math:`\\chi_{\infty}`
"""
kw = 1 / (self.obj.rho * self.obj.cw ** 2)
kr = 1 / (self.obj.particle.param.rhos *
self.obj.particle.param.c ** 2)
etak = (kr-kw) / (kw)
# etarho=3*(self.obj.particle.param.rhos-self.obj.water.paramw.rho)/...
# ...(2*self.obj.particle.param.rhos+self.obj.water.paramw.rho)
etarho = 3 * (self.obj.particle.param.rhos -
self.obj.rho) / (2 * self.obj.particle.param.rhos +
self.obj.rho)
kf = (2 / 3) * np.abs(etak - etarho)
kalph = (4 / 3) * (etak ** 2 + etarho ** 2 / 3) / 6
f_inf = np.array([[kf * row ** 2 *
(1 - 0.25 * np.exp(-((row - 1.5) / 0.5) ** 2)) *
(1 + 0.35 * np.exp(-((row - 2) / 2) ** 2)) /
(1.13 + 0.8 * kf * row ** 2)
for row in x]
for x in self.obj.scattering.katmp])
c_inf = np.array([[kalph * row ** 4 /
(1 + row ** 2 + 0.9 * kalph * row ** 4)
for row in x]
for x in self.obj.scattering.katmp])
return f_inf, c_inf
[docs] def emp_hyb_func(self):
"""
This method computes the Thorne et al. (2014) model. This model is
only valid for backscattering, and describes the scattering properties
of irregularly shaped marine and estuarine flocs
Returns
-------
f_inf : float (numpy.array)
Model form function :math:`f_{\infty}`
c_inf : float (numpy.array)
Model total scattering cross-secton :math:`\\chi_{\infty}`
"""
# kw=1/(self.obj.water.paramw.rho*self.obj.water.paramw.cw**2)
# kw=1/(self.obj.water.paramw.rho*self.obj.cw**2)
co = self.obj.cw
rho0 = self.obj.rho
ck = np.sqrt(self.obj.particle.param.cp ** 2 - (4 / 3) *
self.obj.particle.param.cs ** 2)
rhok = self.obj.particle.param.rhos
Co = 1 / (rho0 * co ** 2)
Ck = 1 / (rhok * ck ** 2)
gk = rhok / rho0
# hk = ck / co
# effective density
m = self.obj.particle.param.m
Cf = self.obj.particle.param.Cf
rhoex = list(Cf / (np.power(self.obj.scattering.atmp, m)))
self.obj.particle.param.rhoex = rhoex
self.obj.scattering.rhoex = rhoex
kkk = 2 * np.pi * np.array(self.obj.scattering.freq) / co
rhoex = Cf / (np.power(self.obj.scattering.katmp / kkk[0], m))
# gamma_o
beta1 = 1.05
# zeta_o values
beta2 = 1.05
# maximum physical value for effective density
rhoex[np.where(rhoex > (rhok - rho0))] = rhok - rho0
# not letting effective density go below zero
self.obj.scattering.update({'rhoex_param':
Parameters({'m': self.obj.particle.param.m,
'Cf': self.obj.particle.param.Cf,
'beta1': beta1,
'beta2': beta2,
'rhok': rhok,
'rho0': rho0})})
rhoex[np.where(rhoex < 0)] = 0
g = 1 + rhoex / rho0
g[np.where(g < beta1)] = beta1
phi = (gk - g) / (gk - 1)
# wood expression
vw = ((phi * rho0 + (1 - phi) * rhok) *
(phi * Co + (1 - phi) * Ck)) ** (- 0.5)
h = vw / co
h[np.where(h < beta2)] = beta2
e = g * h ** 2
kf = 2 * np.abs((e - 1) / (3 * e) + (g - 1) / (2 * g + 1))
alpha1 = 1.2
f_inf = np.array([coef * row ** 2 /
(1 + alpha1 * row ** 2)
for coef, row in zip(list(kf),
list(self.obj.scattering.katmp)
)])
kalfa = 2 * (((e - 1) / (3 * e)) **
2 + (1 / 3) * ((g - 1) / (2 * g + 1)) ** 2)
c_inf_tmp = np.array([coef *
row ** 4 /
(1 - 1.0 * row + 1.5 *
row ** 2 + coef * row ** 4)
for coef, row
in zip(list(kalfa),
list(self.obj.scattering.katmp))])
# viscous atten
# chi_hs scattering
rho = g
v = 1e-6
w = 2 * np.pi * self.obj.scattering.freq[0]
k = w / co
beta = np.sqrt(w / (2 * v))
pro = beta * self.obj.scattering.katmp / kkk[0]
delta = 0.5 * (1 + (9 / (2 * pro)))
s = (9 / (4 * pro)) * (1 + (1 / (pro)))
e1 = ((k * (rho - 1) ** 2) / 2)
e2 = s / (s ** 2 + (rho + delta) ** 2)
# converted to chi_hv values
e12 = e1 * e2
chiv = (4 * (self.obj.scattering.katmp / kkk[0]) / 3) * e12
# combine scat and visc atten chi_h
c_inf = c_inf_tmp + chiv
return f_inf, c_inf