Skip to content

Commit

Permalink
Change name of model_types parameter (#22)
Browse files Browse the repository at this point in the history
* Add a new page about other modelling software

* add more modelling software

* add more software

* Revert "add more software"

This reverts commit 0b9bf6c.

* Resources dir for docs, better coordinate system figure

* Simplify API for BenchmarkData and ReferenceModels

* Update to work with API changes

* API polishing

Move model_type into the dataframe/dataset function parameter
Make reference model API more pythonic
Update example code to match these changes

* Up the version number

* Change model_type to boundary_type - is more descriptive

* Up the version
  • Loading branch information
gavinmacaulay authored Aug 21, 2024
1 parent 853656f commit 456013e
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 84 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ packages = ["src/echosms"]

[project]
name = 'echosms'
version = '0.1.0'
version = '0.1.1'
license = {file = "LICENSE"}
keywords = ["acoustic", "backscatter", "model"]
authors = [
Expand Down
16 changes: 8 additions & 8 deletions src/echosms/dcmmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ def __init__(self):
self.long_name = 'deformed cylinder model'
self.short_name = 'dcm'
self.analytical_type = 'approximate analytical'
self.model_types = ['fixed rigid', 'pressure release', 'fluid filled']
self.boundary_types = ['fixed rigid', 'pressure release', 'fluid filled']
self.shapes = ['finite cylinder']
self.max_ka = 20 # [1]

def calculate_ts_single(self, medium_c, medium_rho, a, b, theta, f, model_type,
def calculate_ts_single(self, medium_c, medium_rho, a, b, theta, f, boundary_type,
target_c=None, target_rho=None, **kwargs):
"""
Calculate the scatter from a finite cylinder using the modal series deformed cylinder model.
Expand All @@ -44,14 +44,14 @@ def calculate_ts_single(self, medium_c, medium_rho, a, b, theta, f, model_type,
90 is dorsal, and 180 is tail on.
f : float
Frequencies to calculate the scattering at [Hz].
model_type : str
The model type. Supported model types are given in the model_types class attribute.
boundary_type : str
The model type. Supported model types are given in the boundary_types class attribute.
target_c : float, optional
Sound speed in the fluid inside the sphere [m/s].
Only required for `model_type` of ``fluid filled``.
Only required for `boundary_type` of ``fluid filled``.
target_rho : float, optional
Density of the fluid inside the sphere [kg/m³].
Only required for `model_type` of ``fluid filled``.
Only required for `boundary_type` of ``fluid filled``.
Returns
-------
Expand Down Expand Up @@ -81,7 +81,7 @@ def calculate_ts_single(self, medium_c, medium_rho, a, b, theta, f, model_type,
m = range(30) # this needs to vary with f

# Some code varies with model type.
match model_type:
match boundary_type:
case 'fixed rigid':
series = list(map(lambda m: (-1)**m * eta(m)*(jvp(m, Ka) / h1vp(m, Ka)), m))
case 'pressure release':
Expand All @@ -101,7 +101,7 @@ def Cm(m):
series = list(map(lambda m: 1j**(2*m) * eta(m) / (1 + 1j*Cm(m)), m))
case _:
raise ValueError(f'The {self.long_name} model does not support '
f'a model type of "{model_type}".')
f'a model type of "{boundary_type}".')

fbs = 1j*b/pi * (sin(kL*cos(theta_rad)) / (kL*cos(theta_rad))) * sum(series)
return 20*log10(abs(fbs)) # ts
27 changes: 14 additions & 13 deletions src/echosms/mssmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ class MSSModel(ScatterModelBase):
"""Modal series solution (MSS) scattering model.
This class calculates acoustic scatter from spheres and shells with various
boundary conditions, as listed in the ``model_types`` class attribute.
boundary conditions, as listed in the ``boundary_types`` class attribute.
"""

def __init__(self):
super().__init__()
self.long_name = 'modal series solution'
self.short_name = 'mss'
self.analytical_type = 'exact'
self.model_types = ['fixed rigid', 'pressure release', 'fluid filled',
'fluid shell fluid interior', 'fluid shell pressure release interior']
self.boundary_types = ['fixed rigid', 'pressure release', 'fluid filled',
'fluid shell fluid interior',
'fluid shell pressure release interior']
self.shapes = ['sphere']
self.max_ka = 20 # [1]

def calculate_ts_single(self, medium_c, medium_rho, a, theta, f, model_type,
def calculate_ts_single(self, medium_c, medium_rho, a, theta, f, boundary_type,
target_c=None, target_rho=None,
shell_c=None, shell_rho=None, shell_thickness=None,
**kwargs) -> float:
Expand All @@ -46,24 +47,24 @@ def calculate_ts_single(self, medium_c, medium_rho, a, theta, f, model_type,
90 is dorsal, and 180 is tail on.
f : float
Frequencies to calculate the scattering at [Hz].
model_type : str
The model type. Supported model types are given in the model_types class variable.
boundary_type : str
The boundary type. Supported types are given in the boundary_types class variable.
target_c : float, optional
Sound speed in the fluid inside the sphere [m/s].
Only required for `model_type` of ``fluid filled``.
Only required for `boundary_type` of ``fluid filled``.
target_rho : float, optional
Density of the fluid inside the sphere [kg/m³].
Only required for `model_type` of ``fluid filled``.
Only required for `boundary_type` of ``fluid filled``.
shell_c : float, optional
Sound speed in the spherical shell [m/s].
Only required for `model_type`s that include a fluid shell.
Only required for `boundary_type`s that include a fluid shell.
shell_rho : float, optional
Density in the spherical shell [kg/m³].
Only required for `model_type`s that include a fluid shell.
Only required for `boundary_type`s that include a fluid shell.
shell_thickness : float, optional
Thickness of the spherical shell [m]. This value is subtracted from ``a`` to give
the radius of the interior sphere.
Only required for `model_type`s that include a fluid shell.
Only required for `boundary_type`s that include a fluid shell.
Returns
-------
Expand All @@ -87,7 +88,7 @@ def calculate_ts_single(self, medium_c, medium_rho, a, theta, f, model_type,
n = np.arange(0, round(ka+20))

# Some code varies with model type.
match model_type:
match boundary_type:
case 'fixed rigid':
A = list(map(lambda x: -spherical_jn(x, ka, True) / h1(x, ka, True), n))
case 'pressure release':
Expand Down Expand Up @@ -141,7 +142,7 @@ def Cn_fspri(n):
A = list(map(Cn_fspri, n))
case _:
raise ValueError(f'The {self.long_name} model does not support '
f'a model type of "{model_type}".')
f'a model type of "{boundary_type}".')

fbs = -1j/k0 * np.sum((-1)**n * (2*n+1) * A)
return 20*log10(abs(fbs)) # ts
Expand Down
22 changes: 11 additions & 11 deletions src/echosms/psmsmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ def __init__(self):
self.long_name = 'prolate spheroidal modal series'
self.short_name = 'psms'
self.analytical_type = 'exact'
self.model_types = ['fixed rigid', 'pressure release', 'fluid filled']
self.boundary_types = ['fixed rigid', 'pressure release', 'fluid filled']
self.shapes = ['prolate spheroid']
self.max_ka = 10 # [1]

def calculate_ts_single(self, medium_c, medium_rho, a, b, theta, f, model_type,
def calculate_ts_single(self, medium_c, medium_rho, a, b, theta, f, boundary_type,
target_c=None, target_rho=None):
"""Prolate spheroid modal series (PSMS) solution model.
Expand All @@ -39,14 +39,14 @@ def calculate_ts_single(self, medium_c, medium_rho, a, b, theta, f, model_type,
90 is dorsal, and 180 is tail on.
f : float
Frequencies to calculate the scattering at [Hz].
model_type : str
The model type. Supported model types are given in the model_types class variable.
boundary_type : str
The model type. Supported model types are given in the boundary_types class variable.
target_c : float, optional
Sound speed in the fluid inside the target [m/s].
Only required for `model_type` of ``fluid filled``.
Only required for `boundary_type` of ``fluid filled``.
target_rho : float, optional
Density of the fluid inside the target [kg/m³].
Only required for `model_type` of ``fluid filled``.
Only required for `boundary_type` of ``fluid filled``.
Returns
-------
Expand All @@ -64,17 +64,17 @@ def calculate_ts_single(self, medium_c, medium_rho, a, b, theta, f, model_type,
“Prediction of krill target strength by liquid prolate spheroid
model,” Fish. Sci., 60, 261–265.
"""
match model_type:
match boundary_type:
case 'pressure release' | 'fluid filled':
pass
case 'fixed rigid':
raise ValueError(f'Model type "{model_type}" has not yet been implemented '
raise ValueError(f'Model type "{boundary_type}" has not yet been implemented '
f'for the {self.long_name} model.')
case _:
raise ValueError(f'The {self.long_name} model does not support '
f'a model type of "{model_type}".')
f'a model type of "{boundary_type}".')

if model_type == 'fluid filled':
if boundary_type == 'fluid filled':
hc = target_c / medium_c
rh = target_rho / medium_rho

Expand Down Expand Up @@ -125,7 +125,7 @@ def calculate_ts_single(self, medium_c, medium_rho, a, b, theta, f, model_type,
s_bs = pro_ang1(m, n, h0, np.cos(theta))
s_inc = pro_ang1(m, n, h0, np.cos(np.pi - theta))

match model_type:
match boundary_type:
case 'fluid filled':
# r_type1A, dr_type1A, r_type2A, dr_type2A = rswfp(m, n, h0, xi0, 3)
# r_type1B, dr_type1B, _, _ = rswfp(m, n, h0/hc, xi0, 3)
Expand Down
44 changes: 21 additions & 23 deletions src/echosms/referencemodels.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,39 @@
"""Reference model parameters."""

from pathlib import Path
import pandas as pd
import tomllib
import pandas as pd
pd.options.mode.copy_on_write = True


class ReferenceModels:
"""Provide access to reference scattering model parameters."""
"""Provide access to reference scattering model parameters.
Attributes
----------
definitions : dict
A dict representation of the ``target definitions.toml`` file.
"""

def __init__(self):
self.defsFilename = Path(__file__).parent/Path('resources')/Path('target definitions.toml')
self.defs_filename = Path(__file__).parent/Path('resources')/Path('target definitions.toml')

self.definitions = []

with open(self.defsFilename, 'rb') as f:
self.defs = tomllib.load(f)
with open(self.defs_filename, 'rb') as f:
self.definitions = tomllib.load(f)

# check that the names parameter is unique across all models

# Substitute parameters names in the target section by the values of those
# parameters.
for t in self.defs['target']:
for t in self.definitions['target']:
for k, v in t.items():
try:
t[k] = self.defs['parameters'][v]
t[k] = self.definitions['parameters'][v]
except (KeyError, TypeError):
pass

def models(self):
"""Provide the full set of model definitions.
Returns
-------
: dict
The contents of the ```target definitions.toml`` file in the form of a dict.
"""
return self.defs

def names(self):
"""Names of all model definitions.
Expand All @@ -44,7 +42,7 @@ def names(self):
: iterable of str
All model names in the ``target definitions/toml`` file.
"""
return [n['name'] for n in self.defs['target']]
return [n['name'] for n in self.definitions['target']]

def specification(self, name):
"""Model defintions for a particular model.
Expand All @@ -59,13 +57,13 @@ def specification(self, name):
: dict
The model definitions for the requested model or ``None`` if no model with that name.
"""
models = pd.DataFrame(self.defs['target'])
m = models.query('name == @name')
models = pd.DataFrame(self.definitions['target'])
m = models.loc[models['name'] == name]
if len(m) == 1:
m.dropna(axis=1, how='all', inplace=True)
return m.iloc[0].to_dict()
else:
return None

return None

def parameters(self, name):
"""Model parameters for a particular model.
Expand All @@ -87,7 +85,7 @@ def parameters(self, name):
s = self.specification(name)

if s is None:
return s
return None

# Remove the entries that are not parameters
p = s
Expand Down
Loading

0 comments on commit 456013e

Please sign in to comment.