Repository: sunpy/sunpy

Issue:
test_mapsequence_solar_derotate fails under 32bit with Astropy 3.2
When `test_mapsequence_solar_derotate` is run with the `clip` keyword (second stage of that test).

It fails with this output:

```python
        # Test that the shape of data is correct when clipped
        clipped_shape = (25, 18)
        for m in tmc:
>           assert(m.data.shape == clipped_shape)
E           assert (25, 19) == (25, 18)
E             At index 1 diff: 19 != 18
E             Use -v to get the full diff
```

Turns out that the return for where to clip is different.
 
32bit
```python
[_lower_clip(x.value), _upper_clip(x.value)] * u.pix
<Quantity [0., 2.] pix>
```

64bit
```python
[_lower_clip(x.value), _upper_clip(x.value)] * u.pix
<Quantity [1., 2.] pix>
```

The `x.value` is not the same.

32bit
```
array([-2.96311832e-15,  5.46585361e-01,  1.09445035e+00])
```

64bit
```
array([2.96311832e-15, 5.46585361e-01, 1.09445035e+00])
```

So it comes from `calculate_solar_rotate_shift`

32bit
```
{'x': <Quantity [-5.68434189e-14, -1.04855012e+01, -2.09955502e+01] arcsec>, 'y': <Quantity [5.68434189e-14, 2.68536149e-01, 5.23060756e-01] arcsec>}
```

64bit
```
{'x': <Quantity [ 5.68434189e-14, -1.04855012e+01, -2.09955502e+01] arcsec>, 'y': <Quantity [1.13686838e-13, 2.68536149e-01, 5.23060756e-01] arcsec>}
```

It would seem that the sign is the issue. 

Doing a git bisect on astropy got me to this PR that "broke" it.

https://github.com/astropy/astropy/pull/8594

For now, the test is skipped on 32bit. 
However it seems that https://github.com/sunpy/sunpy/pull/3223 fixed it?!


Discussion:
Great work finding it!!! 
Seems to be fixed by  #3223 but could be a deeper bug somewhere else. 
Based on my reviewing the code, here's the bug:

- `calculate_solar_rotate_shift()` differentially rotates each map in a MapSequence to the same observer coordinate of a base map in the sequence, *including* rotating a map to itself.
- Neither `calculate_solar_rotate_shift()` nor the function it calls, `solar_rotate_coordinate()`, recognize that this should be a no-op, so a new map is created that has "equal" HPC coordinates to the base map (after it is transformed to HGS and back).
- Prior to #3223, negative values for HPC theta_x, which is actually a longitude, were getting represented as something very large (~360 degrees * 3,600 arcseconds/degrees = ~1,296,000‬ arcseconds).
- Subtracting two numbers that are "equal" already has the chance of getting different near-zero answers in 32-bit versus 64-bit, and the fact that the numbers were very large greatly increased that chance.

Recognizing the no-op would be a good idea.
Ah that is why it failed on the first map in the sequence which should be the base map its rotating to? 
By default, yes

Resolving patch:
diff --git a/sunpy/physics/solar_rotation.py b/sunpy/physics/solar_rotation.py
--- a/sunpy/physics/solar_rotation.py
+++ b/sunpy/physics/solar_rotation.py
@@ -64,6 +64,10 @@ def calculate_solar_rotate_shift(mc, layer_index=0, **kwargs):
 
     # Calculate the rotations and the shifts
     for i, m in enumerate(mc):
+        # Skip the reference layer
+        if i == layer_index:
+            continue
+
         # Calculate the rotation of the center of the map 'm' at its
         # observation time to the observation time of the reference layer
         # indicated by "layer_index".


Test patch:
diff --git a/sunpy/physics/tests/test_solar_rotation.py b/sunpy/physics/tests/test_solar_rotation.py
--- a/sunpy/physics/tests/test_solar_rotation.py
+++ b/sunpy/physics/tests/test_solar_rotation.py
@@ -69,7 +69,6 @@ def test_calculate_solar_rotate_shift(aia171_test_mapsequence, known_displacemen
     assert_allclose(test_output['y'].to('arcsec').value, known_displacements_layer_index1['y'], rtol=5e-2, atol=1e-5)
 
 
-@skip_32bit
 def test_mapsequence_solar_derotate(aia171_test_mapsequence, aia171_test_submap):
     # Test that a mapsequence is returned when the clipping is False.
     tmc = mapsequence_solar_derotate(aia171_test_mapsequence, clip=False)
@@ -84,7 +83,7 @@ def test_mapsequence_solar_derotate(aia171_test_mapsequence, aia171_test_submap)
     assert(isinstance(tmc, sunpy.map.MapSequence))
 
     # Test that the shape of data is correct when clipped
-    clipped_shape = (25, 18)
+    clipped_shape = (25, 19)
     for m in tmc:
         assert(m.data.shape == clipped_shape)