Source code for sasktran2.mie.distribution

import abc

import numpy as np
from scipy.stats import lognorm, rv_continuous


[docs] class ParticleSizeDistribution(abc.ABC): def __init__(self, identifier: str) -> None: """ Abstract class to define particle size distributions that Mie parameters can be integrated over. This class is a light wrapper on top of scipy.stats.rv_continuous which adds some additional information. Parameters ---------- identifier : str A unique identifier for the distribution """ self._identifier = identifier
[docs] @abc.abstractmethod def distribution(self, **kwargs) -> rv_continuous: """ Returns back the scipy object representing this distribution Returns ------- rv_continuous """ return self._distribution
@property def identifier(self) -> str: """ Get the unique identifier for this distribution Returns ------- str """ return self._identifier
[docs] @abc.abstractmethod def args(self): """ A list of arguments that are required to define this distribution when calling distribution """
[docs] def freeze(self, **kwargs): """ Freeze some of the arguments of this distribution. E.g. if `y` is an argument of this distrubtion, calling `freeze(y=5)` will return a new distribution that is the same as this one, but with `y` frozen to 5. Returns ------- ParticleSizeDistribution A new distribution with some of args frozen """ return FrozenDistribution(self, kwargs)
[docs] class LogNormalDistribution(ParticleSizeDistribution): def __init__(self) -> None: """ A log normal particle size distribution, defined by two parameters, the median radius and mode width """ super().__init__("lognormal")
[docs] def distribution(self, **kwargs): return lognorm(np.log(kwargs["mode_width"]), scale=kwargs["median_radius"])
[docs] def args(self): return ["median_radius", "mode_width"]
class FrozenDistribution(ParticleSizeDistribution): def __init__( self, base_distribution: ParticleSizeDistribution, frozen_parameters: dict ) -> None: """ A particle size distribution that is frozen in time, useful for testing Parameters ---------- base_distribution : ParticleSizeDistribution The distribution to freeze """ identifier = f"frozen_{base_distribution.identifier}" for key, value in frozen_parameters.items(): identifier += f"_{key}_{value}" if key not in base_distribution.args(): msg = f"Frozen key {key} not in base distribution args" raise ValueError(msg) super().__init__(identifier) self._distribution = base_distribution self._frozen_parameters = frozen_parameters self._args = [ arg for arg in base_distribution.args() if arg not in frozen_parameters ] def distribution(self, **kwargs): return self._distribution.distribution(**{**self._frozen_parameters, **kwargs}) def args(self): return self._args