Repository: sunpy/sunpy

Issue:
HCRS<->HGS transformation doesn't handle a change in observation time
The HCRS<->HGS transformation doesn't currently look at the HCRS `obstime`, so it effectively assumes that the transformation is all at the HGS `obstime`.  This results in a very very very small inaccuracy in the transformation because the origin of HCRS (the Sun) is not completely stationary.

The transformation will need to be re-implemented as an `AffineTransform` instead of a `DynamicMatrixTransform` to be able to correct for the origin shift.


Discussion:

Resolving patch:
diff --git a/sunpy/coordinates/transformations.py b/sunpy/coordinates/transformations.py
--- a/sunpy/coordinates/transformations.py
+++ b/sunpy/coordinates/transformations.py
@@ -22,7 +22,8 @@
 from astropy.coordinates.baseframe import frame_transform_graph
 from astropy.coordinates.representation import (CartesianRepresentation, SphericalRepresentation,
                                                 UnitSphericalRepresentation)
-from astropy.coordinates.transformations import FunctionTransform, DynamicMatrixTransform
+from astropy.coordinates.transformations import (FunctionTransform, DynamicMatrixTransform,
+                                                 AffineTransform)
 from astropy.coordinates.matrix_utilities import matrix_product, rotation_matrix, matrix_transpose
 
 from sunpy.sun import constants
@@ -303,7 +304,7 @@ def _make_rotation_matrix_from_reprs(start_representation, end_representation):
                                                       CartesianRepresentation(0, 0, 1))
 
 
-@frame_transform_graph.transform(DynamicMatrixTransform, HCRS, HeliographicStonyhurst)
+@frame_transform_graph.transform(AffineTransform, HCRS, HeliographicStonyhurst)
 def hcrs_to_hgs(hcrscoord, hgsframe):
     """
     Convert from HCRS to Heliographic Stonyhurst (HGS).
@@ -341,15 +342,33 @@ def hcrs_to_hgs(hcrscoord, hgsframe):
         rot_matrix_list = [_make_rotation_matrix_from_reprs(vect, x_axis) for vect in hgs_x_axis_detilt]
         rot_matrix = np.stack(rot_matrix_list)
 
-    return matrix_product(rot_matrix, _SUN_DETILT_MATRIX)
+    total_matrix = matrix_product(rot_matrix, _SUN_DETILT_MATRIX)
+
+    # All of the above is calculated for the HGS observation time
+    # If the HCRS observation time is different, calculate the translation in origin
+    if np.any(hcrscoord.obstime != hgsframe.obstime):
+        sun_pos_old_icrs = get_body_barycentric('sun', hcrscoord.obstime)
+        offset_icrf = sun_pos_icrs - sun_pos_old_icrs
+        offset = offset_icrf.transform(total_matrix)
+    else:
+        offset = CartesianRepresentation(0, 0, 0)*u.m
+
+    return total_matrix, offset
 
 
-@frame_transform_graph.transform(DynamicMatrixTransform, HeliographicStonyhurst, HCRS)
+@frame_transform_graph.transform(AffineTransform, HeliographicStonyhurst, HCRS)
 def hgs_to_hcrs(hgscoord, hcrsframe):
     """
     Convert from Heliographic Stonyhurst to HCRS.
     """
-    return matrix_transpose(hcrs_to_hgs(hcrsframe, hgscoord))
+    # Calculate the matrix and offset in the HCRS->HGS direction
+    total_matrix, offset = hcrs_to_hgs(hcrsframe, hgscoord)
+
+    # Invert the transformation to get the HGS->HCRS transformation
+    reverse_matrix = matrix_transpose(total_matrix)
+    reverse_offset = (-offset).transform(reverse_matrix)
+
+    return reverse_matrix, reverse_offset
 
 
 @frame_transform_graph.transform(FunctionTransform, HeliographicStonyhurst, HeliographicStonyhurst)


Test patch:
diff --git a/sunpy/coordinates/tests/test_transformations.py b/sunpy/coordinates/tests/test_transformations.py
--- a/sunpy/coordinates/tests/test_transformations.py
+++ b/sunpy/coordinates/tests/test_transformations.py
@@ -300,8 +300,8 @@ def test_hgs_hgs():
     new = old.transform_to(HeliographicStonyhurst(obstime=obstime + 1*u.day))
 
     assert_quantity_allclose(new.lon, old.lon - 1*u.deg, atol=0.1*u.deg)  # due to Earth motion
-    assert_quantity_allclose(new.lat, old.lat)
-    assert_quantity_allclose(new.radius, old.radius)
+    assert_quantity_allclose(new.lat, old.lat, atol=1e-3*u.deg)
+    assert_quantity_allclose(new.radius, old.radius, atol=1e-5*u.AU)
 
 
 def test_hgc_hgc():
@@ -311,8 +311,8 @@ def test_hgc_hgc():
     new = old.transform_to(HeliographicCarrington(obstime=obstime + 1*u.day))
 
     assert_quantity_allclose(new.lon, old.lon - 14.1844*u.deg, atol=1e-4*u.deg)  # solar rotation
-    assert_quantity_allclose(new.lat, old.lat)
-    assert_quantity_allclose(new.radius, old.radius)
+    assert_quantity_allclose(new.lat, old.lat, atol=1e-4*u.deg)
+    assert_quantity_allclose(new.radius, old.radius, atol=1e-5*u.AU)
 
 
 def test_hgs_hcrs_sunspice():