Skip to content

Conversation

@mhvk
Copy link
Contributor

@mhvk mhvk commented Sep 10, 2013

In #751, it was argued that Time and Quantity should interact properly, with @taldcroft giving a list of expected behavour:

  • One should be able to convert TimeDelta to different units with to().
  • Adding or subtracting Quantity and TimeDelta or Time (regardless of argument order) should give a TimeDelta.
  • Multiplying or dividing a TimeDelta by a Quantity should result in a Quantity.
  • Multiplying or dividing a DeltaTime by a scalar should result in a DeltaTime.

Furthermore, currently, input of Quantities is ignored -- just the value is taken (TimeDelta(10.*u.s, format='jd') silently gives a 10-day time difference; same for Time).

This PR addresses the initialisation of both Time and TimeDelta and implements most of the above -- the exception is that Quantity <OP> TimeDelta does not work, as Quantity (and ndarray) fail to return NotImplemented on trying to add a Time or TimeDelta [EDIT: now raised an issue, #1455])
Suggestions most welcome; if it is agreed this is in the right direction, I can add tests/documentation (PR's to my branch more than welcome...).

In [1]: from astropy.time import Time, TimeDelta; import astropy.units as u; import numpy as np

In [2]: t1=Time('2012-01-01', scale='utc')

In [3]: t1 + 1*u.d
Out[3]: <Time object: scale='utc' format='iso' value=2012-01-02 00:00:00.000>

In [4]: t1 + 1*u.yr
Out[4]: <Time object: scale='utc' format='iso' value=2012-12-31 05:59:59.000>
# u.yr = Julian year = 365.25 day, but there was a leap second and a leap day

In [5]: dt = Time('2013-01-01', scale='utc')-t1

In [6]: dt + 1.*u.d
Out[6]: <TimeDelta object: scale='tai' format='jd' value=367.000011574>

In [7]: dt * (10. * u.m / u.s**2)
Out[7]: <Quantity 3660.00011574 d m / s2>

In [8]: 10.*u.cycle / dt
ERROR: TypeError: scalar 'TimeDelta' object is not subscriptable. [astropy.time.core]
...   # Quantity should return NotImplemented so that TimeDelta can have a go
In [9]: 10. / dt
Out[9]: <Quantity 0.0273224035076 1 / d>

In [10]: dt.to(u.yr)
Out[10]: <Quantity 1.00205341978 yr>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be other.__sub__(self) -- could make a difference if the datatype is unsigned (I know that would be bad in other ways, but why not?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdboom - no, it has to call itself: the reason we can get here is if, e.g., one does Quantity - TimeDelta. For this case, python first gives Quantity a chance, looking up its __sub__ method. It should raise NotImplemented (it doesn't yet, but it should), as it doesn't know how to add to a TimeDelta. Then, python checks whether TimeDelta has a __rsub__ method, and gives that a chance: but of course this then should use its own method, as for this case we know other.__sub__ fails.

@mhvk
Copy link
Contributor Author

mhvk commented Sep 10, 2013

@mdboom - only one of your comments had a very clear answer -- the others all bring up in one way or another a more general question I was thinking about while implementing this: to what extent should Time start to depend on quantities? (@taldcroft may also want to pipe in).

Here, a range of options are available:

  • Right now, I opted to try to avoid importing astropy.units, rather just aiming to duck type, i.e., try whether something behaves like a quantity. An advantage is that at least in principle Time can still be pulled out of astropy and used on its own. But it meant that, e.g., I do things like other.to('day') rather than the u.Unit(getattr(other, 'unit', 1.), u.day) you suggested above.
  • I could import units locally, perhaps still hidden behind an if getattr(other, "to") statement that checks whether something at least potentially is a quantity.
  • Things would be somewhat easier if I just imported astropy.units on top. I was a bit wary about this, as for the sidereal time effort in Sidereal time #1418, I found I could not import from coordinates directly (since that imports Time, causing circular dependencies). But I just tried and can import units without problem (not surprisingly, really).
  • Rather than try to convert quantities to floats with units of day, might it be easier to use quantities, converting floats to a standard unit where necessary; i.e., should jd1 and jd2 be quantities with units of days? It would also, e.g., allow one to use unit as a proper Unit instead of a numerical scale factor.

Of course, these are mostly design choices and I'm not quite clear what the astropy "ideals" are in this respect. E.g., I noticed in various pieces of code that external routines are only imported locally (a procedure I followed for iers), but I'm not quite clear when that should or should not be done. A clear disadvantage would seem to be that one cannot tell from the top of the file any more what a routine really depends on.

@mhvk
Copy link
Contributor Author

mhvk commented Sep 15, 2013

@mbboom, @taldcroft - I added lots of test cases and rebased. But my questions above still hold...

Also, to avoid it disappearing in an outdated diff: @mboom, you asked

Would it be helpful to define Besselian year as a unit? It wouldn't be convertible to other years that way (because it requires an offset and unit conversions don't support that), but it might provide a consistent way to instantiate these things.

I'm not sure -- it seems a bit overkill, and I'm not sure how useful it is if it is not convertible (and I do not see how to convert it).

@mhvk
Copy link
Contributor Author

mhvk commented Sep 16, 2013

Just tried and failed to understand what the test failure was for python 3.3 -- suggestions welcome...
EDIT -- this has disappeared

@taldcroft
Copy link
Member

@mhvk - this and some of your other recent PRs are on my radar, but my day job is getting in the way big time. Apologies and thanks for your patience...

@mhvk
Copy link
Contributor Author

mhvk commented Sep 18, 2013

@mdboom, @taldcroft - I noticed that the test cases I added actually hadn't made it in -- the risks of git commit -a... Now they are in; it gives perhaps a better sense of what now is possible.

@mhvk
Copy link
Contributor Author

mhvk commented Sep 21, 2013

The travis build error is from the documentation, with a complaint that the right version of sphinx is not available.

@astrofrog
Copy link
Member

Ah right, I've opened a PR with a fix: #1478

@taldcroft
Copy link
Member

@mhvk - This is really great and a very good addition to Time. Thanks for the hard work!

It looks like there is still a test failure for python 3.3 that needs fixing. Otherwise what would be good is a section in the Time docs like Time and Quantities that gives examples like in your tests of how to use Quantities in Time. I think it should be the last subsection of Using Time objects after Time Deltas.

@astrofrog
Copy link
Member

@mhvk - you will need to rebase to get rid of the Sphinx failure.

@mhvk
Copy link
Contributor Author

mhvk commented Oct 5, 2013

@astrofrog - OK, rebased. Still to do are @taldcroft's suggested updates to the documentation.

@mhvk
Copy link
Contributor Author

mhvk commented Oct 7, 2013

@taldcroft - now updated the documentation. Maybe we can chat tomorrow about the more general questions I posed earlier (about where to import units, etc.)

@mhvk
Copy link
Contributor Author

mhvk commented Oct 14, 2013

@taldcroft, @mdboom, @astrofrog - this seems quite complete; just pinging in case it was being forgotten...

@astrofrog
Copy link
Member

@mhvk - there are a couple of warnings in the docs causing the failure:

/home/travis/build/astropy/astropy/docs/time/index.rst:618: ERROR: Undefined substitution referenced: "Quantity".
/home/travis/build/astropy/astropy/docs/time/index.rst:618: ERROR: Undefined substitution referenced: "Quantity".

I'll leave it up to @taldcroft to do a final review and merge.

@mhvk
Copy link
Contributor Author

mhvk commented Oct 14, 2013

@astrofrog - I made a correction, but travis seems to have balked for reasons that appear to be unrelated to this.

@astrofrog
Copy link
Member

I've restarted Travis

@taldcroft
Copy link
Member

@mhvk - I was (and am) waiting on a clean Travis doc build before merge, otherwise this looks fine (no, great!). The doc build error is occurring in astropy.time code so it may indeed be related. Are you able to build the docs locally?

@mhvk
Copy link
Contributor Author

mhvk commented Oct 15, 2013

@taldcroft - I finally moved over to python3 and thus could check the build failure -- it was an AttributeError in a condition that was meant to fail (but differently, not completely clear why 3.3 is different). To avoid this recurring, I changed some if not-good: raise to try: assert-good, except: raise; this seems safer and a bit more pythonesque.

Now if only travis would start, we'd know if this is OK (@astrofrog?)...

@astrofrog
Copy link
Member

@taldcroft - tests are passing, feel free to merge.

taldcroft added a commit that referenced this pull request Oct 15, 2013
Allow Time input/interaction/output with Quantities (closes #751)
@taldcroft taldcroft merged commit 04c7598 into astropy:master Oct 15, 2013
@mhvk mhvk deleted the time-accept-quantity branch October 15, 2013 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants