Module diskchef.engine.ctable

Class CTable(astropy.table.QTable) with additional features for CheF

Classes

class CTable (data=None, masked=False, names=None, dtype=None, meta=None, copy=True, rows=None, copy_indices=True, units=None, descriptions=None, coord_base: Literal['cylinder', 'sphere'] = 'cylinder', coord_style: Literal['center', 'edge'] = 'center', dims: Literal['2d', '3d'] = '2d')

Subclass of astropy.table.Qtable for DiskCheF

Features

puts name attribute to the __getitem__ output

returns appropriate columns with r and z properties

provides interpolate method that returns a Callable(r,z)

repr() call sets formats to "e"

Usage:

>>> tbl = CTable()
>>> tbl['Radius'] = [1, 2] * u.m; tbl['Data'] = [3e-4, 4e3]
>>> tbl # doctest: +NORMALIZE_WHITESPACE
<CTable length=2>
   Radius        Data
      m
  float64      float64
------------ ------------
1.000000e+00 3.000000e-04
2.000000e+00 4.000000e+03
>>> # Radius, Height, and some other keywords are achievable with r, z, and other respective properties
>>> tbl.r
<Quantity [1., 2.] m>
>>> # .name attribute is properly set for the returned Quantity
>>> tbl['Data'].name
'Data'
>>> tbl.r.name
'Radius'
>>> # Adding rows is not possible
>>> tbl.add_row([1*u.cm, 10])
Traceback (most recent call last):
   ...
diskchef.engine.exceptions.CHEFNotImplementedError: Adding rows (grid points) is not possible in CTable
>>> # Interpolation
>>> tbl = CTable()
>>> tbl["Radius"] = [1, 2, 3, 1, 2, 3] * u.au
>>> tbl["Height"] = [0, 0, 0, 1, 1, 1] * u.au
>>> tbl["Data"] = [2, 4, 6, 3, 5, 7] * u.K
>>> tbl  # doctest: +NORMALIZE_WHITESPACE
<CTable length=6>
   Radius       Height        Data
     AU           AU           K
  float64      float64      float64
------------ ------------ ------------
1.000000e+00 0.000000e+00 2.000000e+00
2.000000e+00 0.000000e+00 4.000000e+00
3.000000e+00 0.000000e+00 6.000000e+00
1.000000e+00 1.000000e+00 3.000000e+00
2.000000e+00 1.000000e+00 5.000000e+00
3.000000e+00 1.000000e+00 7.000000e+00
>>> tbl.interpolate("Data")(1.5 * u.au, 0 * u.au)
<Quantity [3.] K>
>>> tbl.interpolate("Data")([1, 2.5] * u.au, [0.2, 0.8] * u.au)
<Quantity [2.2, 5.8] K>
>>> # Compatible units are allowed
>>> tbl.interpolate("Data")(1.5e8 * u.km, [0.2, 0.8] * u.au)
<Quantity [2.20537614, 2.80537614] K>
Expand source code
class CTable(QTable):
    """
    Subclass of astropy.table.Qtable for DiskCheF

    Features:

        puts `name` attribute to the `__getitem__` output

        returns appropriate columns with `r` and `z` properties

        provides `interpolate` method that returns a `Callable(r,z)`

        __repr__() call sets formats to "e"

    Usage:

    >>> tbl = CTable()
    >>> tbl['Radius'] = [1, 2] * u.m; tbl['Data'] = [3e-4, 4e3]
    >>> tbl # doctest: +NORMALIZE_WHITESPACE
    <CTable length=2>
       Radius        Data
          m
      float64      float64
    ------------ ------------
    1.000000e+00 3.000000e-04
    2.000000e+00 4.000000e+03
    >>> # Radius, Height, and some other keywords are achievable with r, z, and other respective properties
    >>> tbl.r
    <Quantity [1., 2.] m>

    >>> # .name attribute is properly set for the returned Quantity
    >>> tbl['Data'].name
    'Data'
    >>> tbl.r.name
    'Radius'

    >>> # Adding rows is not possible
    >>> tbl.add_row([1*u.cm, 10])
    Traceback (most recent call last):
       ...
    diskchef.engine.exceptions.CHEFNotImplementedError: Adding rows (grid points) is not possible in CTable

    >>> # Interpolation
    >>> tbl = CTable()
    >>> tbl["Radius"] = [1, 2, 3, 1, 2, 3] * u.au
    >>> tbl["Height"] = [0, 0, 0, 1, 1, 1] * u.au
    >>> tbl["Data"] = [2, 4, 6, 3, 5, 7] * u.K
    >>> tbl  # doctest: +NORMALIZE_WHITESPACE
    <CTable length=6>
       Radius       Height        Data
         AU           AU           K
      float64      float64      float64
    ------------ ------------ ------------
    1.000000e+00 0.000000e+00 2.000000e+00
    2.000000e+00 0.000000e+00 4.000000e+00
    3.000000e+00 0.000000e+00 6.000000e+00
    1.000000e+00 1.000000e+00 3.000000e+00
    2.000000e+00 1.000000e+00 5.000000e+00
    3.000000e+00 1.000000e+00 7.000000e+00
    >>> tbl.interpolate("Data")(1.5 * u.au, 0 * u.au)
    <Quantity [3.] K>
    >>> tbl.interpolate("Data")([1, 2.5] * u.au, [0.2, 0.8] * u.au)
    <Quantity [2.2, 5.8] K>
    >>> # Compatible units are allowed
    >>> tbl.interpolate("Data")(1.5e8 * u.km, [0.2, 0.8] * u.au)
    <Quantity [2.20537614, 2.80537614] K>
    """

    def __init__(self, data=None, masked=False, names=None, dtype=None,
                 meta=None, copy=True, rows=None, copy_indices=True,
                 units=None, descriptions=None, coord_base: Literal['cylinder', 'sphere'] = 'cylinder',
                 coord_style: Literal['center', 'edge'] = 'center', dims: Literal['2d', '3d'] = '2d',
                 ):
        super().__init__(data, masked, names, dtype, meta, copy, rows, copy_indices, units, descriptions)
        self.dust_list = []
        self.coord_base = coord_base
        self.coord_style = coord_style
        self.dims = dims
        for column in self.columns:
            try:
                self[column].info.format = "e"
            except ValueError:
                pass

    def __getitem__(self, item):
        try:
            column_quantity = super().__getitem__(item)
        except KeyError as e:
            if " number density" in item:
                column_quantity = self[item[:-len(" number density")]] * self["n(H+2H2)"]
            else:
                raise e
        if isinstance(column_quantity, (astropy.table.Column, u.Quantity)):
            column_quantity.name = item
        return column_quantity

    @property
    def r(self):
        """Column with radius coordinate"""
        return self['Radius']

    @cached_property
    def r_grid(self):
        """Column with radius coordinate"""
        return np.sort(np.unique(self.r)).to(u.au)

    @property
    def z(self):
        """Column with height coordinate"""
        return self['Height']

    @cached_property
    def z_grid(self):
        """Column with height coordinate"""
        return np.sort(np.unique(self.z)).to(u.au)

    @property
    def zr(self):
        return self['Height to radius']

    @cached_property
    def zr_grid(self):
        """Column with height coordinate"""
        return np.sort(np.unique(self.zr))

    @property
    def d(self):
        return self['Distance to star']

    @cached_property
    def d_grid(self):
        """Column with radius coordinate"""
        return np.sort(np.unique(self.d)).to(u.au)

    @property
    def theta(self):
        return self['Theta']

    @property
    def phi(self):
        return self['Phi']

    @cached_property
    def phi_grid(self):
        return np.sort(np.unique(self.phi)).to(u.rad)

    @cached_property
    def theta_grid(self):
        return np.sort(np.unique(self.theta)).to(u.rad)

    def interpolate(
            self,
            column: str,
            method: Literal['linear', 'nearest', 'cubic'] = 'linear',
            rescale: bool = False,
            fill_value: float = 0.0
    ) -> Callable[[u.Quantity, u.Quantity], u.Quantity]:
        """
        Interpolate the selected quantity
        Args:
            column: str -- column name of the table to interpolate
            method: to be passed to scipy.interpolation.griddata
            rescale: to be passed to scipy.interpolation.griddata
            fill_value: to be passed to scipy.interpolation.griddata

        Returns: callable(r, z) with interpolated value of column
        """

        def _interpolation(r: u.au, z: u.au):

            is_ordered = 0
            if self.coord_base == 'sphere':
                is_ordered += int(self.is_in_theta_regular_grid)
            elif self.coord_base == 'cylinder':
                is_ordered += int(self.is_in_z_regular_grid) + int(self.is_in_zr_regular_grid)
            if is_ordered == 0:
                interpolated = griddata(
                    points=(self.r.to(u.au).value, self.z.to(u.au).value),
                    values=self[column],
                    xi=(r.to(u.au).value, z.to(u.au).value),
                    method=method,
                    rescale=rescale,
                    fill_value=fill_value
                )
            elif is_ordered > 0:
                d = np.sqrt(r**2 + z**2)
                theta = np.pi / 2 * u.rad - np.arctan(z/r)
                if self.coord_base == 'sphere':
                    x_point = d.to(u.au).value
                    x_grid = self.d_grid.value
                    z_point = theta.to(u.rad).value
                    z_grid = self.theta_grid.value
                elif self.coord_base == 'cylinder':
                    x_point = r.to(u.au).value
                    x_grid = self.r_grid.value
                    if self.is_in_z_regular_grid:
                        z_point = z.to(u.au).value
                        z_grid = self.z_grid.value
                    elif self.is_in_zr_regular_grid:
                        z_point = z.to(u.au).value/r.to(u.au).value
                        z_grid = self.zr_grid.value

                values = np.array(self[column]).reshape((len(z_grid), len(x_grid)))
                interpolated = interpn(
                    points=(z_grid, x_grid),
                    values=values,
                    xi=(z_point, x_point),
                    method=method,
                    bounds_error=False,
                    fill_value=fill_value
                )
            if self[column].unit:
                interpolated = interpolated << self[column].unit
            return interpolated

        return _interpolation

    def interpolate3d(
            self,
            column: str,
            method: Literal['linear', 'nearest', 'cubic'] = 'linear',
            rescale: bool = False,
            fill_value: float = 0.0
    ) -> Callable[[u.Quantity, u.Quantity, u.Quantity], u.Quantity]:
        """
        Interpolate the selected quantity
        Args:
            column: str -- column name of the table to interpolate
            method: to be passed to scipy.interpolation.griddata
            rescale: to be passed to scipy.interpolation.griddata
            fill_value: to be passed to scipy.interpolation.griddata

        Returns: callable(r, z, phi) with interpolated value of column
        """

        def _interpolation(r: u.au, z: u.au, phi: u.rad):

            is_ordered = 0
            if self.coord_base == 'sphere':
                is_ordered += int(self.is_in_theta_regular_grid)
            elif self.coord_base == 'cylinder':
                is_ordered += int(self.is_in_z_regular_grid) + int(self.is_in_zr_regular_grid)
            if is_ordered == 0:
                interpolated = griddata(
                    points=(self.r.to(u.au).value, self.z.to(u.au).value, self.phi.to(u.rad).value),
                    values=self[column],
                    xi=(r.to(u.au).value, z.to(u.au).value, phi.to(u.rad).value),
                    method=method,
                    rescale=rescale,
                    fill_value=fill_value
                )
            elif is_ordered > 0:
                d = np.sqrt(r**2 + z**2)
                theta = np.pi / 2 * u.rad - np.arctan(z/r)
                if self.coord_base == 'sphere':
                    x_point = d.to(u.au).value
                    x_grid = self.d_grid.value
                    z_point = theta.to(u.rad).value
                    z_grid = self.theta_grid.value
                elif self.coord_base == 'cylinder':
                    x_point = r.to(u.au).value
                    x_grid = self.r_grid.value
                    if self.is_in_z_regular_grid:
                        z_point = z.to(u.au).value
                        z_grid = self.z_grid.value
                    elif self.is_in_zr_regular_grid:
                        z_point = z.to(u.au).value/r.to(u.au).value
                        z_grid = self.zr_grid.value
                    

                values = np.array(self[column]).reshape((len(self.phi_grid), len(z_grid), len(x_grid)))
                interpolated = interpn(
                    points=(self.phi_grid.value, z_grid, x_grid),
                    values=values,
                    xi=(phi.to(u.rad).value, z_point, x_point),
                    method=method,
                    bounds_error=False,
                    fill_value=fill_value
                )
                
            if self[column].unit:
                interpolated = interpolated << self[column].unit
            return interpolated

        return _interpolation

    @cached_property
    def is_in_zr_regular_grid(self) -> bool:
        """
        Returns: whether the table is on a grid of (R, z/R) or (r, z/R) for 2D or a grid of (R, z/R, phi) or (r, z/R, phi) for 3D
        """
        if 'Height to radius' not in self.colnames:
            return False
        if self.dims == '2d':
            if self.coord_base == 'cylinder':
                return len(self.r_grid) * len(self.zr_grid) == len(self)
            elif self.coord_base == 'sphere':
                return len(set(self.d)) * len(self.zr_grid) == len(self)
        elif self.dims == '3d':
            if self.coord_base == 'cylinder':
                return len(self.r_grid) * len(self.zr_grid) * len(self.phi_grid) == len(self)
            elif self.coord_base == 'sphere':
                return len(set(self.d)) * len(self.zr_grid) * len(self.phi_grid) == len(self)

    @cached_property
    def is_in_theta_regular_grid(self) -> bool:
        """
        Returns: whether the table is on a grid of (R, z/R) or (r, z/R) for 2D or a grid of (R, z/R, phi) or (r, z/R, phi) for 3D
        """
        if 'Theta' not in self.colnames:
            return False
        if self.dims == '2d':
            if self.coord_base == 'cylinder':
                return len(self.r_grid) * len(self.theta_grid) == len(self)
            elif self.coord_base == 'sphere':
                return len(set(self.d)) * len(self.theta_grid) == len(self)
        elif self.dims == '3d':
            if self.coord_base == 'cylinder':
                return len(self.r_grid) * len(self.theta_grid) * len(self.phi_grid) == len(self)
            elif self.coord_base == 'sphere':
                return len(set(self.d)) * len(self.theta_grid) * len(self.phi_grid) == len(self)

    @cached_property
    def is_in_z_regular_grid(self) -> bool:
        """
        Returns: whether the table is on a grid of (R, z) or (r, z) for 2D or a grid of (R, z, phi) or (r, z, phi) for 3D
        """
        if 'Height' not in self.colnames:
            return False
        if self.dims == '2d':
            if self.coord_base == 'cylinder':
                return len(self.r_grid) * len(self.z_grid) == len(self)
            elif self.coord_base == 'sphere':
                if len(set(self.d)) * len(self.z_grid) == len(self):
                    print('Girl get help')
                    return True
                else:
                    return False
        elif self.dims == '3d':
            if self.coord_base == 'cylinder':
                return len(self.r_grid) * len(self.z_grid) * len(self.phi_grid)  == len(self)
            elif self.coord_base == 'sphere':
                if len(set(self.d)) * len(self.z_grid) * len(self.phi_grid) == len(self):
                    print('Girl get help')
                    return True
                else:
                    return False

    def add_row(self, vals=None, mask=None):
        """
        Adding rows (grid points) is not possible in CTable

        Raises: CHEFNotImplementedError
        """
        raise CHEFNotImplementedError("Adding rows (grid points) is not possible in CTable")

    def __setitem__(self, key, value):
        super().__setitem__(key, value)
        try:
            self[key].info.format = "e"
        except ValueError:
            pass

    def __repr__(self):
        return self._base_repr_(html=False, max_width=-1, max_lines=-1)

    def __str__(self):
        return repr(self)

    @property
    def _dust_pop_sum(self):
        return sum([self[f"{dust.name} mass fraction"] for dust in self.dust_list])

    @property
    def dust_population_fully_set(self, atol=1e-5):
        """
        Check whether sum of mass fractions of dust populations is equal to 1
        """
        return np.all(abs(1 - self._dust_pop_sum) < atol)

    def normalize_dust(self):
        """
        Normalize the dust fractions so that the sum is 1
        """
        pop_sum = self._dust_pop_sum
        for dust in self.dust_list:
            dust.mass_fraction /= pop_sum
            dust.write_to_table()
        if not self.dust_population_fully_set:
            raise CHEFRuntimeError

    def column_density(self, colname: str, r: u.au = None) -> u.Quantity:
        """
        Calculate column density of `colname` on `r` grid
        Args:
            colname: name of the column to collapse
            r: grid (centers) for the output. If not specified, defaults to `sorted(set(self.r))`

        Returns:
            column density of `self[colname]` on `r` grid
        """
        if r is None:
            r = sorted(set(self.r))

        if self.is_in_zr_regular_grid:
            r_grid = sorted(set(self.r))
            coldenses = []
            for _r in r_grid:
                indices = self.r == _r
                value = self[colname][indices]
                z = self.z[indices]
                coldenses.append(np.trapz(value, z))
            coldenses = u.Quantity(coldenses)
            return np.interp(r, r_grid, coldenses)
        else:
            raise NotImplementedError("Column density is currently only implemented for zr grids")

    def check_zeros(self, column, nearest=True, warnings_on=False):
        """Replaces zeros in `self.table[column]` with the second smallest by absolute value element"""
        values_set = sorted(set(np.abs(self[column])))
        if 0 in u.Quantity(self[column]).value:
            if warnings_on:
                warnings.warn("Found zeros in %s" % column)
            index = self[column].value == 0
            if nearest:
                data = self[column][~index]
                if self.dims == '3d':
                    self[column] = griddata(
                        points=(self.r[~index].to(u.au).value, self.z[~index].to(u.au).value, self.phi[~index].to(u.rad).value),
                        values=data,
                        xi=(self.r.to(u.au).value, self.z.to(u.au).value, self.phi.to(u.rad).value),
                        method="nearest",
                    ) << self[column].unit
                elif self.dims == '2d':
                    self[column] = griddata(
                        points=(
                        self.r[~index].to(u.au).value, self.z[~index].to(u.au).value),
                        values=data,
                        xi=(self.r.to(u.au).value, self.z.to(u.au).value),
                        method="nearest",
                    ) << self[column].unit

            else:
                if len(values_set) > 2:
                    self[column][index] = values_set[1]
                else:
                    self[column][index] = values_set[1] / 1e6

Ancestors

  • astropy.table.table.QTable
  • astropy.table.table.Table

Instance variables

prop d
Expand source code
@property
def d(self):
    return self['Distance to star']
var d_grid

Column with radius coordinate

Expand source code
def __get__(self, instance, owner=None):
    if instance is None:
        return self
    if self.attrname is None:
        raise TypeError(
            "Cannot use cached_property instance without calling __set_name__ on it.")
    try:
        cache = instance.__dict__
    except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
        msg = (
            f"No '__dict__' attribute on {type(instance).__name__!r} "
            f"instance to cache {self.attrname!r} property."
        )
        raise TypeError(msg) from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        with self.lock:
            # check if another thread filled cache while we awaited lock
            val = cache.get(self.attrname, _NOT_FOUND)
            if val is _NOT_FOUND:
                val = self.func(instance)
                try:
                    cache[self.attrname] = val
                except TypeError:
                    msg = (
                        f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                        f"does not support item assignment for caching {self.attrname!r} property."
                    )
                    raise TypeError(msg) from None
    return val
prop dust_population_fully_set

Check whether sum of mass fractions of dust populations is equal to 1

Expand source code
@property
def dust_population_fully_set(self, atol=1e-5):
    """
    Check whether sum of mass fractions of dust populations is equal to 1
    """
    return np.all(abs(1 - self._dust_pop_sum) < atol)
var is_in_theta_regular_grid

Returns: whether the table is on a grid of (R, z/R) or (r, z/R) for 2D or a grid of (R, z/R, phi) or (r, z/R, phi) for 3D

Expand source code
def __get__(self, instance, owner=None):
    if instance is None:
        return self
    if self.attrname is None:
        raise TypeError(
            "Cannot use cached_property instance without calling __set_name__ on it.")
    try:
        cache = instance.__dict__
    except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
        msg = (
            f"No '__dict__' attribute on {type(instance).__name__!r} "
            f"instance to cache {self.attrname!r} property."
        )
        raise TypeError(msg) from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        with self.lock:
            # check if another thread filled cache while we awaited lock
            val = cache.get(self.attrname, _NOT_FOUND)
            if val is _NOT_FOUND:
                val = self.func(instance)
                try:
                    cache[self.attrname] = val
                except TypeError:
                    msg = (
                        f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                        f"does not support item assignment for caching {self.attrname!r} property."
                    )
                    raise TypeError(msg) from None
    return val
var is_in_z_regular_grid

Returns: whether the table is on a grid of (R, z) or (r, z) for 2D or a grid of (R, z, phi) or (r, z, phi) for 3D

Expand source code
def __get__(self, instance, owner=None):
    if instance is None:
        return self
    if self.attrname is None:
        raise TypeError(
            "Cannot use cached_property instance without calling __set_name__ on it.")
    try:
        cache = instance.__dict__
    except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
        msg = (
            f"No '__dict__' attribute on {type(instance).__name__!r} "
            f"instance to cache {self.attrname!r} property."
        )
        raise TypeError(msg) from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        with self.lock:
            # check if another thread filled cache while we awaited lock
            val = cache.get(self.attrname, _NOT_FOUND)
            if val is _NOT_FOUND:
                val = self.func(instance)
                try:
                    cache[self.attrname] = val
                except TypeError:
                    msg = (
                        f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                        f"does not support item assignment for caching {self.attrname!r} property."
                    )
                    raise TypeError(msg) from None
    return val
var is_in_zr_regular_grid

Returns: whether the table is on a grid of (R, z/R) or (r, z/R) for 2D or a grid of (R, z/R, phi) or (r, z/R, phi) for 3D

Expand source code
def __get__(self, instance, owner=None):
    if instance is None:
        return self
    if self.attrname is None:
        raise TypeError(
            "Cannot use cached_property instance without calling __set_name__ on it.")
    try:
        cache = instance.__dict__
    except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
        msg = (
            f"No '__dict__' attribute on {type(instance).__name__!r} "
            f"instance to cache {self.attrname!r} property."
        )
        raise TypeError(msg) from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        with self.lock:
            # check if another thread filled cache while we awaited lock
            val = cache.get(self.attrname, _NOT_FOUND)
            if val is _NOT_FOUND:
                val = self.func(instance)
                try:
                    cache[self.attrname] = val
                except TypeError:
                    msg = (
                        f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                        f"does not support item assignment for caching {self.attrname!r} property."
                    )
                    raise TypeError(msg) from None
    return val
prop phi
Expand source code
@property
def phi(self):
    return self['Phi']
var phi_grid
Expand source code
def __get__(self, instance, owner=None):
    if instance is None:
        return self
    if self.attrname is None:
        raise TypeError(
            "Cannot use cached_property instance without calling __set_name__ on it.")
    try:
        cache = instance.__dict__
    except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
        msg = (
            f"No '__dict__' attribute on {type(instance).__name__!r} "
            f"instance to cache {self.attrname!r} property."
        )
        raise TypeError(msg) from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        with self.lock:
            # check if another thread filled cache while we awaited lock
            val = cache.get(self.attrname, _NOT_FOUND)
            if val is _NOT_FOUND:
                val = self.func(instance)
                try:
                    cache[self.attrname] = val
                except TypeError:
                    msg = (
                        f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                        f"does not support item assignment for caching {self.attrname!r} property."
                    )
                    raise TypeError(msg) from None
    return val
prop r

Column with radius coordinate

Expand source code
@property
def r(self):
    """Column with radius coordinate"""
    return self['Radius']
var r_grid

Column with radius coordinate

Expand source code
def __get__(self, instance, owner=None):
    if instance is None:
        return self
    if self.attrname is None:
        raise TypeError(
            "Cannot use cached_property instance without calling __set_name__ on it.")
    try:
        cache = instance.__dict__
    except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
        msg = (
            f"No '__dict__' attribute on {type(instance).__name__!r} "
            f"instance to cache {self.attrname!r} property."
        )
        raise TypeError(msg) from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        with self.lock:
            # check if another thread filled cache while we awaited lock
            val = cache.get(self.attrname, _NOT_FOUND)
            if val is _NOT_FOUND:
                val = self.func(instance)
                try:
                    cache[self.attrname] = val
                except TypeError:
                    msg = (
                        f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                        f"does not support item assignment for caching {self.attrname!r} property."
                    )
                    raise TypeError(msg) from None
    return val
prop theta
Expand source code
@property
def theta(self):
    return self['Theta']
var theta_grid
Expand source code
def __get__(self, instance, owner=None):
    if instance is None:
        return self
    if self.attrname is None:
        raise TypeError(
            "Cannot use cached_property instance without calling __set_name__ on it.")
    try:
        cache = instance.__dict__
    except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
        msg = (
            f"No '__dict__' attribute on {type(instance).__name__!r} "
            f"instance to cache {self.attrname!r} property."
        )
        raise TypeError(msg) from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        with self.lock:
            # check if another thread filled cache while we awaited lock
            val = cache.get(self.attrname, _NOT_FOUND)
            if val is _NOT_FOUND:
                val = self.func(instance)
                try:
                    cache[self.attrname] = val
                except TypeError:
                    msg = (
                        f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                        f"does not support item assignment for caching {self.attrname!r} property."
                    )
                    raise TypeError(msg) from None
    return val
prop z

Column with height coordinate

Expand source code
@property
def z(self):
    """Column with height coordinate"""
    return self['Height']
var z_grid

Column with height coordinate

Expand source code
def __get__(self, instance, owner=None):
    if instance is None:
        return self
    if self.attrname is None:
        raise TypeError(
            "Cannot use cached_property instance without calling __set_name__ on it.")
    try:
        cache = instance.__dict__
    except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
        msg = (
            f"No '__dict__' attribute on {type(instance).__name__!r} "
            f"instance to cache {self.attrname!r} property."
        )
        raise TypeError(msg) from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        with self.lock:
            # check if another thread filled cache while we awaited lock
            val = cache.get(self.attrname, _NOT_FOUND)
            if val is _NOT_FOUND:
                val = self.func(instance)
                try:
                    cache[self.attrname] = val
                except TypeError:
                    msg = (
                        f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                        f"does not support item assignment for caching {self.attrname!r} property."
                    )
                    raise TypeError(msg) from None
    return val
prop zr
Expand source code
@property
def zr(self):
    return self['Height to radius']
var zr_grid

Column with height coordinate

Expand source code
def __get__(self, instance, owner=None):
    if instance is None:
        return self
    if self.attrname is None:
        raise TypeError(
            "Cannot use cached_property instance without calling __set_name__ on it.")
    try:
        cache = instance.__dict__
    except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
        msg = (
            f"No '__dict__' attribute on {type(instance).__name__!r} "
            f"instance to cache {self.attrname!r} property."
        )
        raise TypeError(msg) from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        with self.lock:
            # check if another thread filled cache while we awaited lock
            val = cache.get(self.attrname, _NOT_FOUND)
            if val is _NOT_FOUND:
                val = self.func(instance)
                try:
                    cache[self.attrname] = val
                except TypeError:
                    msg = (
                        f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                        f"does not support item assignment for caching {self.attrname!r} property."
                    )
                    raise TypeError(msg) from None
    return val

Methods

def add_row(self, vals=None, mask=None)

Adding rows (grid points) is not possible in CTable

Raises: CHEFNotImplementedError

def check_zeros(self, column, nearest=True, warnings_on=False)

Replaces zeros in self.table[column] with the second smallest by absolute value element

def column_density(self, colname: str, r: Unit("AU") = None)

Calculate column density of colname on r grid

Args

colname
name of the column to collapse
r
grid (centers) for the output. If not specified, defaults to sorted(set(self.r))

Returns

column density of self[colname] on r grid

def interpolate(self, column: str, method: Literal['linear', 'nearest', 'cubic'] = 'linear', rescale: bool = False, fill_value: float = 0.0) ‑> Callable[[astropy.units.quantity.Quantity, astropy.units.quantity.Quantity], astropy.units.quantity.Quantity]

Interpolate the selected quantity

Args

column
str – column name of the table to interpolate
method
to be passed to scipy.interpolation.griddata
rescale
to be passed to scipy.interpolation.griddata
fill_value
to be passed to scipy.interpolation.griddata

Returns: callable(r, z) with interpolated value of column

def interpolate3d(self, column: str, method: Literal['linear', 'nearest', 'cubic'] = 'linear', rescale: bool = False, fill_value: float = 0.0) ‑> Callable[[astropy.units.quantity.Quantity, astropy.units.quantity.Quantity, astropy.units.quantity.Quantity], astropy.units.quantity.Quantity]

Interpolate the selected quantity

Args

column
str – column name of the table to interpolate
method
to be passed to scipy.interpolation.griddata
rescale
to be passed to scipy.interpolation.griddata
fill_value
to be passed to scipy.interpolation.griddata

Returns: callable(r, z, phi) with interpolated value of column

def normalize_dust(self)

Normalize the dust fractions so that the sum is 1