Repository: sunpy/sunpy

Issue:
What to do about `physics.solar_rotation`
### Provide a general description of the issue or problem.

When deprecating `image.coalignment` (#5957), it was revealed that `physics.solar_rotation.mapsequence_solar_derotate` depends on `image.coalignment.apply_shifts`. This led me down the rabbit hole of the `physics.solar_rotation` module.

`physics.solar_rotation` contains two functions:

* `calculate_solar_rotate_shift`
* `mapsequence_solar_derotate`

The latter is just a light wrapper around `apply_shifts` (which as mentioned above, we would like to deprecate). The former is just used by the latter to compute the shifts associated with rotation relative to some selected layer.  

I've mainly created this issue to discuss what we should do with this module. Leave it alone? Deprecate it and move it to `sunkit-image`? 

Given that it is such a lightweight wrapper, I could also imagine just adding an example gallery entry in `sunkit-image` on how to use `solar_rotate_coordinate` with `apply_shifts` to shift a map according to some relative shift in the center coordinate of the map. This would also make it explicitly to users what is happening under the hood, i.e. there is no warping or rotation, just shifts in the image plane.


Discussion:
Reading the docs for these, I'm downright confused by them. How is it even valid/possible to shift a map observed in a helioprojective coordinate system to compensate for solar rotation (which is a (latitude dependent) shift in Carrington longitude)? I vote we deprecate these, and point users to an example to differentially de-rotate a full map by a certain time interval.
@dstansby: I think you're over-thinking it.  The purpose of this module is apply shifts to a sequence of maps so that the centers of  the maps are all pointed at the same spot on the solar surface, accounting for solar rotation.  This simulates a telescope tracking, say, an active region over time.  A user may not want to actually transform/reproject the maps at all.
Ah, that makes sense. I think I am confused by the multiple meanings `rotate` have within our API. I think at least updating the function names (with deprecation etc. etc.) here to remove `rotate` or `rotation` would be a positive step. This would avoid confusion with:
- Rotating maps around the center of the Sun
- Differentially rotating maps forward/backwards in time
 I tried to brainstorm some other name ideas, but am a bit stumped though...
My proposed solution:

- Move both `calculate_solar_rotate_shift` and `mapsequence_solar_derotate` to `sunkit_image.coalignment` and rename `mapsequence_solar_derotate` to `mapsequence_coalign_by_derotation` (or something like that...it at least mirrors the naming convention of `mapsequence_coalign_by_match_template` which does the same thing, except calculates the shifts according to a cross-correlation to some layer in the sequence(
- Deprecate both of these functions and point people towards sunkit image.

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
@@ -11,12 +11,14 @@
 
 import sunpy.map
 from sunpy.physics.differential_rotation import solar_rotate_coordinate
+from sunpy.util.decorators import deprecated
 
 __author__ = 'J. Ireland'
 
 __all__ = ['calculate_solar_rotate_shift', 'mapsequence_solar_derotate']
 
 
+@deprecated(since='4.0', alternative='`sunkit_image.coalignment.calculate_solar_rotate_shift`')
 def calculate_solar_rotate_shift(mc, layer_index=0, **kwargs):
     """
     Calculate the shift that must be applied to each map contained in a mapsequence
@@ -84,6 +86,7 @@ def calculate_solar_rotate_shift(mc, layer_index=0, **kwargs):
     return {"x": xshift_arcseconds, "y": yshift_arcseconds}
 
 
+@deprecated(since='4.0', alternative='`sunkit_image.coalignment.mapsequence_coalign_by_rotation`')
 def mapsequence_solar_derotate(mc, layer_index=0, clip=True, shift=None, **kwargs):
     """
     Move the layers in a mapsequence according to the input shifts.


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
@@ -16,6 +16,9 @@
 import sunpy.map
 from sunpy.physics.solar_rotation import calculate_solar_rotate_shift, mapsequence_solar_derotate
 
+DEP_WARNING = r'''ignore:The {} function is deprecated and may be removed in version 4.1.
+\s+Use `sunkit_image.coalignment.{}` instead.:sunpy.util.exceptions.SunpyDeprecationWarning'''
+
 
 @pytest.fixture
 def aia171_test_map():
@@ -54,6 +57,9 @@ def known_displacements_layer_index1():
             'y': np.asarray([-0.263369, 0., 0.251137])}
 
 
+@pytest.mark.filterwarnings(DEP_WARNING.format(
+    'calculate_solar_rotate_shift', 'calculate_solar_rotate_shift'
+))
 def test_calculate_solar_rotate_shift(aia171_test_mapsequence, known_displacements_layer_index0, known_displacements_layer_index1):
     # Test that the default works
     test_output = calculate_solar_rotate_shift(aia171_test_mapsequence)
@@ -72,6 +78,12 @@ def test_calculate_solar_rotate_shift(aia171_test_mapsequence, known_displacemen
                     known_displacements_layer_index1['y'], rtol=5e-2, atol=1e-5)
 
 
+@pytest.mark.filterwarnings(DEP_WARNING.format(
+    'calculate_solar_rotate_shift', 'calculate_solar_rotate_shift'
+))
+@pytest.mark.filterwarnings(DEP_WARNING.format(
+    'mapsequence_solar_derotate', 'mapsequence_coalign_by_rotation'
+))
 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)