微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Astropy Units equivalencies - 使用类和 SI 前缀的干涉测量基线

如何解决Astropy Units equivalencies - 使用类和 SI 前缀的干涉测量基线

作为 Astropy Units equivalencies - interferometry baselines 的后续。我想问一下如何为我的自定义单位使用 SI 前缀。到目前为止,按照附加链接中的建议,我从 astropy Quantity 创建了一个子类,然后覆盖了 .to 方法

这是我的代码

class uWavelength(un.Quantity):
    def __new__(cls,value,freq=None,dtype=None,copy=True,**kwargs):
        unit = un.Unit(un.def_unit('lambdas',format={'format': r'\lambda'},prefixes=True))
        self = super().__new__(cls,value=value,unit=unit,dtype=dtype,copy=copy,**kwargs)
        self.freq = freq
        if self.freq is not None:
            self.equivalencies = self.lambdas_equivalencies()
        return self

    @property
    def freq(self):
        return self._freq

    @freq.setter
    def freq(self,val):
        if val is not None:
            self._equivalencies = self.lambdas_equivalencies(restfreq=val)
        self._freq = val

    @property
    def equivalencies(self):
        return self._equivalencies

    @equivalencies.setter
    def equivalencies(self,val):
        self._equivalencies = val

    def lambdas_equivalencies(self,restfreq=None):

        if self.freq is not None:
            restfreq_hz = self.freq.to(un.Hz,equivalencies=un.spectral())
        elif restfreq is not None:
            restfreq_hz = restfreq.to(un.Hz,equivalencies=un.spectral())
        else:
            sys.exit("Frequency not provided")
        eq = [
            (self.unit,un.s,lambda x: x / restfreq_hz,lambda x: x * restfreq_hz),(self.unit,un.m,lambda x: x / restfreq_hz * co.c.to(un.m / un.s).value,lambda x: x / co.c.to(un.m / un.s).value * restfreq_hz),(un.m,lambda x: x / co.c.to(un.m / un.s).value,lambda x: x * co.c.to(un.m / un.s).value),]

        return eq

    def to(self,unit,restfreq=None,copy=True):
        equiv = []
        if restfreq is None:
            equiv = self.equivalencies
        else:
            equiv = self.lambdas_equivalencies(restfreq=restfreq)

        unit = un.Unit(unit)

        if copy:
            # Avoid using to_value to ensure that we make a copy. We also
            # don't want to slow down this method (esp. the scalar case).
            value = self._to_value(unit,equiv)
        else:
            # to_value only copies if necessary
            value = self.to_value(unit,equiv)
        return self._new_view(value,unit)class uWavelength(un.Quantity):
    def __new__(cls,unit)

但是,当我使用该类时,我只能使用单位 lambda,但我想使用 klambda 或 mega-lambda 等。根据 astropy,这可以通过使用参数 prefixes=True 来完成,但是这似乎不起作用。

解决方法

我认为您实际上不应该定义类的 __new__ 内的单位,因为它不允许您在实例化 uWavelength 时实际设置单位.

而是把它放在你的课堂之外:

lambdas = u.def_unit('lambdas',format={'format': r'\lambda'})

我认为文档并没有说清楚的一点是,当您使用 prefixes=True 时,除非您还提供 namespace= 参数,否则它不会真正做任何事情,即使如此,文档也没有非常清楚如何使用命名空间。我认为最好采用 astrofrog 的建议,明确声明所需的前缀单位,例如:

klambdas = u.def_unit('kilolambdas',represents=u.CompositeUnit(1e3,[lambdas],[1]),format={'format' : r'k\lambda'})```

unless you *really* need every imaginable SI prefix,you could try:

lambdas = u.def_unit('lambdas',format={'format': r'\lambda'},prefixes=True,namespace=globals())


and it will inject every prefixed unit into your module namespace.

Then,since you want your default unit for `uWavelength` to be `lambdas`,then both to reduce confusion,and also add some documentation of this fact (through the signature of `__new__`) specify:

```python
class uWavelength(un.Quantity):
    def __new__(cls,value,freq=None,unit=lambdas,dtype=None,copy=True,**kwargs):

此外,如果您愿意,可以添加如下检查:

        unit = u.Unit(unit)
        assert unit.is_equivalent(lambdas),'unit must be equivalent to lambdas'

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。