# Difference between propagate\_with\_solar\_surface and transform\_with\_sun\_center

**URL:** <https://community.openastronomy.org/t/difference-between-propagate-with-solar-surface-and-transform-with-sun-center/532>\
**Category:** Development\
**Tags:** sunpy, question\
**Created:** [December 6, 2022, 11:08am UTC](https://community.openastronomy.org/t/difference-between-propagate-with-solar-surface-and-transform-with-sun-center/532 "2022-12-06T11:08:46Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![GiuliaMRonca](https://dub1.discourse-cdn.com/flex005/user_avatar/community.openastronomy.org/giuliamronca/32/305_2.png) [@GiuliaMRonca](https://community.openastronomy.org/u/GiuliaMRonca)\
**Post date:** [December 6, 2022, 11:08am UTC](https://community.openastronomy.org/t/difference-between-propagate-with-solar-surface-and-transform-with-sun-center/532/1 "2022-12-06T11:08:46Z")

</div>

Hello,

I want to differentially rotate an image, using the procedure explained in [Differentially rotating a map — SunPy 4.1.0 documentation](https://docs.sunpy.org/en/stable/generated/gallery/differential_rotation/reprojected_map.html#sphx-glr-generated-gallery-differential-rotation-reprojected-map-py)

I used to do that one year ago with this procedure:

```
# Reproject the map from the input frame to the output frame.
with transform_with_sun_center():
    arr, _ = reproject_interp(mapname, out_wcs, out_shape)
# Create the output map and preserve the original map’s plot settings.
out_warp = sunpy.map.Map(arr, out_wcs)

```

This is what was suggested at the time. Now, I see that the suggested function is:

with propagate\_with\_solar\_surface():  
out\_warp = aiamap.reproject\_to([out\_wcs])

I have read about the difference in the dedicated pages, but it is still not clear to me what exactly changes in one case or the other. Does this upgrade mean that what I did previously with the _transform\_with\_sun\_center_ function is wrong?

---

<div class="post-metadata">

**Author:** ![ayshih](https://dub1.discourse-cdn.com/flex005/user_avatar/community.openastronomy.org/ayshih/32/84_2.png) [@ayshih](https://community.openastronomy.org/u/ayshih)\
**Post date:** [December 6, 2022, 7:57pm UTC](https://community.openastronomy.org/t/difference-between-propagate-with-solar-surface-and-transform-with-sun-center/532/2 "2022-12-06T19:57:21Z")

</div>

Thanks for asking!

First, I’ll clarify that the `transform_with_sun_center()` context manager is solely about ignoring the slow translational motion of the Sun through inertial space. (The `propagate_with_solar_surface()` context manager ignores this translational motion as well.)  
`transform_with_sun_center()` by itself does not incorporate any notion of differential rotation.

The “old” approach for differentially rotating a map actually requires an important modification to the `WCS` instance prior to your quoted code snippet:

```python
out_wcs = WCS(...)

# Assuming appropriate definitions of out_frame and in_time
from sunpy.coordinates import RotatedSunFrame
rot_frame = RotatedSunFrame(base=out_frame, rotated_time=in_time)
out_wcs.coordinate_frame = rot_frame

with transform_with_sun_center():
    arr, _ = reproject_interp(aiamap, out_wcs, out_shape)
out_warp = sunpy.map.Map(arr, out_wcs)

```

and should be contrasted against the “new” approach:

```python
out_wcs = WCS(...)

# No modification to out_wcs is needed

with propagate_with_solar_surface():
    arr, _ = reproject_interp(aiamap, out_wcs, out_shape)
out_warp = sunpy.map.Map(arr, out_wcs)

```

which is further even simpler using the now-available `reproject_to()` method:

```python
out_wcs = WCS(...)

with propagate_with_solar_surface():
    out_warp = aiamap.reproject_to(out_wcs)

```

In other words:

- With the `propagate_with_solar_surface()` context manager, it is no longer necessary to modify the `WCS` instance to include a `RotatedSunFrame` instance.
- With the `reproject_to()` method, it is no longer necessary to manually call `reproject_interp()` and handle the returned data array.

None of the reprojected output has changed, and your old code is likely not wrong (but feel free to share it so that it can be checked!). Switching to the current approach is simply about simplifying your code.

---

<div class="post-metadata">

**Author:** ![GiuliaMRonca](https://dub1.discourse-cdn.com/flex005/user_avatar/community.openastronomy.org/giuliamronca/32/305_2.png) [@GiuliaMRonca](https://community.openastronomy.org/u/GiuliaMRonca)\
**Post date:** [December 12, 2022, 7:08pm UTC](https://community.openastronomy.org/t/difference-between-propagate-with-solar-surface-and-transform-with-sun-center/532/3 "2022-12-12T19:08:27Z")

</div>

Hi @ayshih ,  
thanks for your reply. It was really helpful.

I also tried to subtract one image from the other to qualitatively check the difference in the approaches.  
I am going to share my code. If you could tell me your opinion, I would love to read it.

I have a set of sunpy maps (here after called  
raw=sunpy.map.Map(event+‘/raw\_img/\*.fits’, sequence=True)  
). They are images taken on March 07 2012.  
raw[0] corresponds to 2012-03-06 at 23:32:00.620  
while raw[i=350] corresponds to 2012-03-09 at 11:32:00.62

base\_raw=raw[0]  
base\_updated= update\_pointing(base\_raw)  
base\_registered = register(base\_updated)  
basemap= normalize\_exposure(base\_registered)  
new\_dimensions = [2048, 2048] \* u.pixel # Resampling  
basemap = basemap.resample(new\_dimensions)

i=350

if raw[i].meta[‘exptime’]\>2.9 and raw[i].meta[‘exptime’]\<3:

```
smap_raw =raw[i]
smap_updated_pointing_old= update_pointing(smap_raw)
smap_registered = register(smap_updated_pointing_old)
smap= normalize_exposure(smap_registered)
new_dimensions = [2048, 2048] * u.pixel
map_old = smap.resample(new_dimensions)

```

Then I differentially rotate smap\_raw first with both the methods:

base\_time= sunpy.time.parse\_time(basemap.meta[‘date-obs’])  
t= sunpy.time.parse\_time(map\_old.meta[‘date-obs’])  
time\_diff= -(t-base\_time).to(u.min)  
out\_old=diff\_rot(map\_old, time\_diff, basemap)  
out\_new=diff\_rot\_new(map\_old, time\_diff, basemap)

The two functions are below:

def diff\_rot(mapname, time\_diff, basemap):

```
#NOTE: to go back in time, time_diff MUST be negative
in_time = mapname.date
out_time = in_time + time_diff
out_frame = Helioprojective(observer='earth', obstime= out_time, rsun= mapname.meta['rsun_ref']*u.m)
rot_frame = RotatedSunFrame(base=out_frame, rotated_time=in_time)

out_shape = mapname.data.shape
# WCS converts cdelt and cunit from arcsec to deg
out_wcs = basemap.wcs
out_wcs.coordinate_frame = rot_frame

# Reproject the map from the input frame to the output frame.
with transform_with_sun_center():
    arr, _ = reproject_interp(mapname, out_wcs, out_shape)
# Create the output map and preserve the original map’s plot settings.
out_warp = sunpy.map.Map(arr, out_wcs)
out_warp.plot_settings = mapname.plot_settings

mapname.meta["date-obs"]=mapname.meta["date-obs"]
if mapname.name[0:3]=='AIA':
    out_warp.meta["waveunit"] = mapname.meta["waveunit"]
    out_warp.meta["exptime"] = mapname.meta['exptime']
    out_warp.meta["wavelnth"] = mapname.meta['wavelnth']
    out_warp.meta["instrume"]= mapname.meta['instrume']
    out_warp.meta["telescop"]= mapname.meta['telescop']
    out_warp.meta["rsun_obs"]= mapname.meta['rsun_obs']

out_warp.meta["cdelt1"]=mapname.meta['cdelt1']
out_warp.meta["cdelt2"]=mapname.meta['cdelt2']
out_warp.meta["cunit1"]=mapname.meta['cunit1']
out_warp.meta["cunit2"]=mapname.meta['cunit2']

return out_warp

```

And here is the “new” version of the differential rotation function:

from astropy.coordinates import SkyCoord  
from astropy.wcs import WCS

import sunpy.map  
from sunpy.coordinates import Helioprojective, propagate\_with\_solar\_surface

def diff\_rot\_new(mapname, time\_diff, basemap):

```
#NOTE: to go back in time, time_diff MUST be negative
in_time = mapname.date
out_time = in_time + time_diff

out_frame = Helioprojective(observer='earth', obstime= out_time, rsun= mapname.meta['rsun_ref']*u.m)

# WCS converts cdelt and cunit from arcsec to deg
out_wcs = basemap.wcs

# Reproject the map from the input frame to the output frame.
with propagate_with_solar_surface():
    out_warp = mapname.reproject_to(out_wcs)

out_warp.meta["date-obs"]=mapname.meta["date-obs"]
if mapname.name[0:3]=='AIA':
    out_warp.meta["waveunit"] = mapname.meta["waveunit"]
    out_warp.meta["exptime"] = mapname.meta['exptime']
    out_warp.meta["wavelnth"] = mapname.meta['wavelnth']
    out_warp.meta["instrume"]= mapname.meta['instrume']
    out_warp.meta["telescop"]= mapname.meta['telescop']
    out_warp.meta["rsun_obs"]= mapname.meta['rsun_obs']
    out_warp.meta["pc1_1"]= mapname.meta['pc1_1']
    out_warp.meta["pc1_2"]= mapname.meta['pc1_2']
    out_warp.meta["pc2_1"]= mapname.meta['pc2_1']
    out_warp.meta["pc2_2"]= mapname.meta['pc2_2']
    
out_warp.meta["cdelt1"]=mapname.meta['cdelt1']
out_warp.meta["cdelt2"]=mapname.meta['cdelt2']
out_warp.meta["cunit1"]=mapname.meta['cunit1']
out_warp.meta["cunit2"]=mapname.meta['cunit2']

return out_warp

```

As I told you, I then tried to subtract one image from the other:

diff = out\_new.data - out\_old.data

You can see the results.  
There is some misalignement in the pixel positions so the difference’s value is quite high sometimes, especially close to the active regions, where bright and dark pixels are very close to each other.  
Here I limited the plot to -7 and +7 values (maximum value is +155, minimum value is -193)

 ![compare_diff_rot-YES-UPDATE-20120309-11-32-00](https://europe1.discourse-cdn.com/flex005/uploads/openastronomy/original/1X/d82a358fdadcd76617d8c1a609cc898531d7f619.png)

---

<div class="post-metadata">

**Author:** ![GiuliaMRonca](https://dub1.discourse-cdn.com/flex005/user_avatar/community.openastronomy.org/giuliamronca/32/305_2.png) [@GiuliaMRonca](https://community.openastronomy.org/u/GiuliaMRonca)\
**Post date:** [December 12, 2022, 7:08pm UTC](https://community.openastronomy.org/t/difference-between-propagate-with-solar-surface-and-transform-with-sun-center/532/4 "2022-12-12T19:08:58Z")

</div>

In percentage, the difference is interesting, too.

diff = out\_new.data - out\_old.data  
perc= ( diff / out\_new.data )\*100  
meta = out\_new.meta  
perc\_map = sunpy.map.Map(perc, meta)

 ![compare_diff_rot-perc-20120306-23-32-00](https://europe1.discourse-cdn.com/flex005/uploads/openastronomy/original/1X/b9775d307f04108699fe7e6699cff5e947da8d9c.png)

I think this is mostly due to a misalignement of the pixels, rather than an error, but coul this lead to any problem in the future? Especially when different people process images with different methods

---

<div class="post-metadata">

**Author:** ![ayshih](https://dub1.discourse-cdn.com/flex005/user_avatar/community.openastronomy.org/ayshih/32/84_2.png) [@ayshih](https://community.openastronomy.org/u/ayshih)\
**Post date:** [December 13, 2022, 2:29am UTC](https://community.openastronomy.org/t/difference-between-propagate-with-solar-surface-and-transform-with-sun-center/532/5 "2022-12-13T02:29:54Z")

</div>

The reason that there is a discrepancy between the outputs from your two functions is because there is a difference in the target coordinate frame. In short, `diff_rot()` reprojects to an observer at Earth center, while `diff_rot_new()` reprojects to an observer at SDO’s location. Accordingly, the reprojection is slightly different.

# `diff_rot()`

You have:

```auto
out_frame = Helioprojective(observer='earth', obstime= out_time, rsun= mapname.meta['rsun_ref']*u.m)

```

Since `out_time = in_time + time_diff = mapname.date + (basemap.date - mapname.date) = basemap.date`, we can rewrite this as:

```auto
out_frame = Helioprojective(observer='earth', obstime=basemap.date, rsun=basemap.coordinate_frame.rsun)

```

However, note that the observer is specified as Earth and _not_ SDO. The analogous call if you want the observer to be SDO would be:

```auto
out_frame = Helioprojective(observer=basemap.observer_coordinate, obstime=basemap.date, rsun=basemap.coordinate_frame.rsun)

```

or far more simply:

```auto
out_frame = basemap.coordinate_frame

```

Because you explicitly attach a coordinate frame to `out_wcs`, the reprojection will use that coordinate frame – with the observer at Earth – instead of accessing the observer information contained in `out_wcs`.

# `diff_rot_new()`

You have `out_frame` defined the same way, with the observer specified as Earth instead of as SDO. However, defining `out_frame` is misleading because it is never used. Instead, because you reproject directly to `out_wcs`, which contains the observer location as SDO, the target coordinate frame has the observer as SDO.

---

<div class="post-metadata">

**Author:** ![GiuliaMRonca](https://dub1.discourse-cdn.com/flex005/user_avatar/community.openastronomy.org/giuliamronca/32/305_2.png) [@GiuliaMRonca](https://community.openastronomy.org/u/GiuliaMRonca)\
**Post date:** [December 13, 2022, 9:35am UTC](https://community.openastronomy.org/t/difference-between-propagate-with-solar-surface-and-transform-with-sun-center/532/6 "2022-12-13T09:35:14Z")

</div>

I see.  
It is perfect now and my doubts are cleared.

Thank you very much!
