Пример #1
0
def trace_to_surface(seeds, synoptic_map, rss=rss, nrho=60):
    """
    seeds : astropy.coordinates.SkyCoord
        Seed coordinates on the source surface.
    synoptic_map : sunpy.map.GenericMap
        Input synoptic magnetogram.
    rss : scalar
        Source surface radius.
    nrho : int
        Number of grid points in the radial direciton
        of the PFSS model.
    
    Returns
    -------
    flines : pfsspy.flines.field_lines
        Traced field lines.
    pfss_input : pfsspy.Input
        PFSS input.
    pfss_output : pfsspy.Output
        PFSS output.
    """
    pfss_input = pfsspy.Input(synoptic_map, nrho, rss)
    print('Computing PFSS...')
    pfss_output = pfsspy.pfss(pfss_input)

    tracer = pfsspy.tracing.FortranTracer(max_steps=2000)
    print('Tracing field lines...')
    flines = tracer.trace(seeds, pfss_output)
    return flines, pfss_input, pfss_output
Пример #2
0
 def __init__(self, nrho, rss, gong_map=sunpy.map.Map(get_gong_map())):
     self._nrho = nrho
     self._rss = rss
     self.gong_map = gong_map
     self.input = pfsspy.Input(self.gong_map, self.nrho, self.rss)
     self._output = pfsspy.pfss(self.input)
     self.tracer = tracing.PythonTracer()
Пример #3
0
def dipole_result(dipole_map):
    nr = 10
    rss = 2.5

    input = pfsspy.Input(dipole_map, nr, rss)
    output = pfsspy.pfss(input)
    return input, output
Пример #4
0
def test_sunpy_map_input(zero_map):
    zero_in, _ = zero_map
    # Check that loading an input map works
    header = {'cunit1': 'degree', 'cunit2': 'degree'}
    map = sunpy.map.Map((zero_in.br, header))
    input = pfsspy.Input(map, zero_in.grid.nr, zero_in.grid.rss)
    assert (input.br == zero_in.br).all()
Пример #5
0
def adapt2pfsspy(dt,
                 rss=2.5,
                 nr=60,
                 adapt_source="GONG",
                 realization="mean",
                 ret_magnetogram=False,
                 data_dir=DefaultPath):
    #Input : dt (datetime object), rss (source surface radius in Rs)
    YYYYMMDD = f'{dt.year}{dt.month:02d}{dt.day:02d}'
    A = {"GONG": 3, "HMI": 4}.get(adapt_source)
    filepath = sorted(glob.glob(f"{data_dir}/adapt40{A}*{YYYYMMDD}*.fts"))[0]
    stdout.write(f"Read in {filepath}\r")
    adapt_map = fits.open(filepath)
    if realization == "mean": br_adapt_ = np.mean(adapt_map[0].data, axis=0)
    elif isinstance(realization, int):
        br_adapt_ = adapt_map[0].data[realization, :, :]
    else:
        raise ValueError("realization should either be 'mean' or type int ")
    # Interpolate to Strumfric Grid (const lat spacing -> const cos(lat) spacing)
    lat_dr = np.linspace(-90, 90, br_adapt_.shape[0])
    lon_dr = np.linspace(0, 360, br_adapt_.shape[1])
    clat_dr = np.sin(np.radians(lat_dr))
    clat_dr_interp = np.linspace(clat_dr[0], clat_dr[-1], len(clat_dr))
    br_adapt = np.zeros(br_adapt_.shape)
    for ind, _ in enumerate(lon_dr):
        interper = interp1d(clat_dr, br_adapt_[:, ind])
        br_adapt[:, ind] = interper(clat_dr_interp)

    br_adapt -= np.mean(br_adapt)
    br_adapt *= 1e5  # G -> nT
    if ret_magnetogram: return br_adapt
    peri_input = pfsspy.Input(br_adapt, nr, rss, dtime=dt)
    peri_output = pfsspy.pfss(peri_input)

    return peri_output
Пример #6
0
def compute_pfss(gong_fname, dtime):
    gong_map = sunpy.map.Map(gong_fname)
    br = gong_map.data
    header = gong_map.meta

    br = br - np.mean(br)
    br = np.roll(br, header['CRVAL1'] + 180, axis=1)
    header['CRVAL1'] = 180
    header['DATE_ORI'] = header['DATE']
    header['date-obs'] = Time(dtime).isot

    gong_map = sunpy.map.Map(br, header)
    nrho = 60
    rss = 2.5

    input = pfsspy.Input(gong_map, nrho, rss)
    ssfile = gong_fname.with_suffix('.ssmap')

    if ssfile.exists():
        ssmap = np.loadtxt(ssfile)
        ssmap = sunpy.map.Map(ssmap, header)
    else:
        print('Calculating PFSS solution')
        # Compute PFSS solution and source surface map
        output = pfsspy.pfss(input)
        ssdata = output.source_surface_br.data
        np.savetxt(ssfile, ssdata)
        ssmap = output.source_surface_br

    return input, ssmap
Пример #7
0
def zero_map():
    # Test a completely zero input
    ns = 30
    nphi = 20
    nr = 10
    rss = 2.5
    br = np.zeros((ns, nphi))

    input = pfsspy.Input(br, nr, rss)
    output = pfsspy.pfss(input)
    return input, output
Пример #8
0
def zero_map():
    # Test a completely zero input
    ns = 30
    nphi = 20
    nr = 10
    rss = 2.5
    br = np.zeros((nphi, ns))
    header = pfsspy.utils.carr_cea_wcs_header(Time('1992-12-21'), br.shape)
    input_map = Map((br.T, header))

    input = pfsspy.Input(input_map, nr, rss)
    output = pfsspy.pfss(input)
    return input, output
Пример #9
0
def test_bunit(gong_map):
    # Regression test to check that the output of pfss doesn't change
    m = sunpy.map.Map(gong_map)
    pfss_in = pfsspy.Input(m, 2, 2)
    pfss_out = pfsspy.pfss(pfss_in)
    assert pfss_out.bunit == u.G

    pfss_out.input_map.meta['bunit'] = 'notaunit'
    with pytest.warns(UserWarning, match='Could not parse unit string "notaunit"'):
        assert pfss_out.bunit is None

    pfss_out.input_map.meta.pop('bunit')
    assert pfss_out.bunit is None
Пример #10
0
def test_pfss(gong_map):
    # Regression test to check that the output of pfss doesn't change
    m = sunpy.map.Map(gong_map)
    # Resample to lower res for easier comparisons
    m = m.resample([30, 15] * u.pix)
    m = sunpy.map.Map(m.data - np.mean(m.data), m.meta)
    expected = np.loadtxt(test_data / 'br_in.txt')
    np.testing.assert_equal(m.data, expected)

    pfss_in = pfsspy.Input(m, 50, 2)
    pfss_out = pfsspy.pfss(pfss_in)

    br = pfss_out.source_surface_br.data
    expected = np.loadtxt(test_data / 'br_out.txt')
    # atol is emperically set for tests to pass on CI
    np.testing.assert_allclose(br, expected, atol=1e-13, rtol=0)
Пример #11
0
    def __init__(self,
                 gongMap,
                 SSradius: float = 2.5,
                 nrho: int = 25,
                 tracer=tracing.FortranTracer()):
        """
        PFSS solution to solar magnetic field is calculated on a 3D grid (phi, s, rho).
        rho = ln(r), and r is the standard spherical radial coordinate.
        """
        self.gongMap = gongMap
        self.SSradius = SSradius
        self.SSradiusRsun = SSradius * const.R_sun
        self.nrho = nrho

        self.input = pfsspy.Input(gongMap, nrho, SSradius)
        self.output = pfsspy.pfss(self.input)
        self.tracer = tracer
Пример #12
0
def dipole_map():
    # Test a completely zero input
    ntheta = 30
    nphi = 20
    nr = 10
    rss = 2.5

    phi = np.linspace(0, 2 * np.pi, nphi)
    theta = np.linspace(-np.pi / 2, np.pi / 2, ntheta)
    theta, phi = np.meshgrid(theta, phi)

    def dipole_Br(r, theta):
        return 2 * np.sin(theta) / r**3

    br = dipole_Br(1, theta).T
    input = pfsspy.Input(br, nr, rss)
    output = pfsspy.pfss(input)
    return input, output
Пример #13
0
def gong2pfsspy(dt,
                rss=2.5,
                nr=60,
                ret_magnetogram=False,
                data_dir=DefaultPath):
    #Input : dt (datetime object), rss (source surface radius in Rs)
    YYYYMMDD = f'{dt.year}{dt.month:02d}{dt.day:02d}'
    gongpath = f'mrzqs{YYYYMMDD}/'
    filepath = sorted(glob.glob(f'{data_dir}/mrzqs{YYYYMMDD[2:]}*.fits'))[0]
    stdout.write(f"Read in {filepath}\r")
    # Sunpy 1.03 error : need to fix header of gong maps to include units
    am = fits.open(filepath)[0]
    am.header.append(('CUNIT1', 'degree'))
    am.header.append(('CUNIT2', 'degree'))
    gong_map = sunpy.map.Map(am.data, am.header)
    br_gong = extract_br(gong_map)
    if ret_magnetogram: return br_gong
    peri_input = pfsspy.Input(br_gong, nr, rss, dtime=dt)
    peri_output = pfsspy.pfss(peri_input)

    return peri_output
Пример #14
0
def hmi2pfsspy(dt,
               rss=2.5,
               nr=60,
               ret_magnetogram=False,
               data_dir=DefaultPath):
    #Input : dt (datetime object), rss (source surface radius in Rs)
    YYYYMMDD = f'{dt.year}{dt.month:02d}{dt.day:02d}'
    filepath = glob.glob(
        f'{data_dir}/hmi.mrdailysynframe_small_720s.{YYYYMMDD}*.fits')[0]
    stdout.write(f"Read in {filepath}\r")
    hmi_fits = fits.open(filepath)[0]
    hmi_fits.header['CUNIT2'] = 'degree'
    for card in ['HGLN_OBS', 'CRDER1', 'CRDER2', 'CSYSER1', 'CSYSER2']:
        hmi_fits.header[card] = 0

    hmi_map = sunpy.map.Map(hmi_fits.data, hmi_fits.header)
    hmi_map.meta['CRVAL1'] = 120 + sun.L0(time=hmi_map.meta['T_OBS']).value
    br_hmi = extract_br(hmi_map)
    if ret_magnetogram: return br_hmi
    peri_input = pfsspy.Input(br_hmi, nr, rss, dtime=dt)
    peri_output = pfsspy.pfss(peri_input)
    return peri_output
Пример #15
0
def derosa2pfsspy(dt,
                  rss=2.5,
                  nr=60,
                  ret_magnetogram=False,
                  data_dir=DefaultPath):
    #Input : dt (datetime object), rss (source surface radius in Rs)
    YYYYMMDD = f'{dt.year}{dt.month:02d}{dt.day:02d}'
    dr_times = ['_000400.h5', '_060432.h5', '_120400.h5', '_180328.h5']
    dr_time = dr_times[np.argmin(np.abs(dt.hour - np.array([0, 6, 12, 18])))]
    filepath = f'{data_dir}/Bfield_{YYYYMMDD}{dr_time}'
    f = h5py.File(filepath, 'r')
    stdout.write(f"Read in {filepath}\r")
    fdata = f['ssw_pfss_extrapolation']
    br_dr = fdata['BR'][0, :, :, :] * 1e5
    nr_dr = fdata['NR']
    nlat_dr = fdata['NLAT']
    nlon_dr = fdata['NLON']
    r_dr = fdata['RIX'][0]
    lat_dr = fdata['LAT'][0]
    c_dr = np.cos(np.radians(90 - lat_dr))
    lon_dr = fdata['LON'][0]
    date = fdata['MODEL_DATE']
    magnetogram = br_dr[0, :, :]

    # Interpolate to Strumfric Grid (const lat spacing -> const cos(lat) spacing)
    clat_dr = np.sin(np.radians(lat_dr))
    clat_dr_interp = np.linspace(clat_dr[0], clat_dr[-1], len(clat_dr))
    br_dr_interp = np.zeros(magnetogram.shape)
    for ind, _ in enumerate(lon_dr):
        interper = interp1d(clat_dr, magnetogram[:, ind])
        br_dr_interp[:, ind] = interper(clat_dr_interp)
    br_dr_interp -= np.mean(
        br_dr_interp)  # Remove Mean offest for pfsspy FFT based PFSS extrap
    if ret_magnetogram: return (magnetogram, br_dr_interp)
    peri_input = pfsspy.Input(br_dr_interp, nr, rss, dtime=dt)
    peri_output = pfsspy.pfss(peri_input)
    return peri_output
Пример #16
0
def test_monopole_warning(dipole_map):
    dipole_map = sunpy.map.Map(dipole_map.data + 1, dipole_map.meta)
    with pytest.warns(UserWarning, match='Input data has a non-zero mean'):
        pfsspy.Input(dipole_map, 20, 2)
Пример #17
0
# so roll to get it at 0deg. This way the input magnetic field is in a
# Carrington frame of reference, which matters later when lining the field
# lines up with the AIA image.
br = np.roll(br, header['CRVAL1'] + 180, axis=1)

###############################################################################
# The PFSS solution is calculated on a regular 3D grid in (phi, s, rho), where
# rho = ln(r), and r is the standard spherical radial coordinate. We need to
# define the number of grid points in rho, and the source surface radius.
nrho = 60
rss = 2.5

###############################################################################
# From the boundary condition, number of radial grid points, and source
# surface, we now construct an `Input` object that stores this information
input = pfsspy.Input(br, nrho, rss, dtime=dtime)

###############################################################################
# Using the `Input` object, plot the input photospheric magnetic field
fig, ax = plt.subplots()
mesh = input.plot_input(ax)
fig.colorbar(mesh)
ax.set_title('Input field')

###############################################################################
# We can also plot the AIA map to give an idea of the global picture. There
# is a nice active region in the top right of the AIA plot, that can also
# be seen in the top left of the photospheric field plot above.
ax = plt.subplot(1, 1, 1, projection=aia)
aia.plot(ax)
Пример #18
0

br = dipole_Br(1, s).T


###############################################################################
# The PFSS solution is calculated on a regular 3D grid in (phi, s, rho), where
# rho = ln(r), and r is the standard spherical radial coordinate. We need to
# define the number of rho grid points, and the source surface radius.
nrho = 50
rss = 2.5

###############################################################################
# From the boundary condition, number of radial grid points, and source
# surface, we now construct an Input object that stores this information
input = pfsspy.Input(br, nrho, rss)

###############################################################################
# Using the Input object, plot the input field
m = input.map
fig = plt.figure()
ax = plt.subplot(projection=m)
m.plot()
plt.colorbar()
ax.set_title('Input dipole field')

###############################################################################
# Now calculate the PFSS solution.
output = pfsspy.pfss(input)

###############################################################################
Пример #19
0
def test_sunpy_map_input(zero_map):
    zero_in, _ = zero_map
    # Check that loading an input map works
    map = sunpy.map.Map((zero_in.br, {}))
    input = pfsspy.Input(map, zero_in.grid.nr, zero_in.grid.rss)
    assert (input.br == zero_in.br).all()
Пример #20
0
def test_non_map_input():
    with pytest.raises(ValueError, match='br must be a SunPy Map'):
        pfsspy.Input(np.random.rand(2, 2), 1, 1)
Пример #21
0
def test_nan_value(dipole_map):
    dipole_map.data[0, 0] = np.nan
    with pytest.raises(ValueError,
                       match='At least one value in the input is NaN'):
        pfsspy.Input(dipole_map, 5, 2.5)
Пример #22
0
def test_wrong_projection_error(dipole_map):
    dipole_map.meta['ctype1'] = 'HGLN-CAR'
    with pytest.raises(ValueError, match='must be CEA'):
        pfsspy.Input(dipole_map, 5, 2.5)
Пример #23
0
br = dipole_Br(1, s)

###############################################################################
# The PFSS solution is calculated on a regular 3D grid in (phi, s, rho), where
# rho = ln(r), and r is the standard spherical radial coordinate. We need to
# define the number of rho grid points, and the source surface radius.
nrho = 30
rss = 2.5

###############################################################################
# From the boundary condition, number of radial grid points, and source
# surface, we now construct an Input object that stores this information
header = pfsspy.utils.carr_cea_wcs_header(Time('2020-1-1'), br.shape)
input_map = sunpy.map.Map((br.T, header))
input = pfsspy.Input(input_map, nrho, rss)

###############################################################################
# Using the Input object, plot the input field
m = input.map
fig = plt.figure()
ax = plt.subplot(projection=m)
m.plot()
plt.colorbar()
ax.set_title('Input dipole field')

###############################################################################
# Now calculate the PFSS solution.
output = pfsspy.pfss(input)

###############################################################################
Пример #24
0
# Crop to the desired active region
aia_submap = aia.submap(
    SkyCoord(Tx=300 * u.arcsec, Ty=100 * u.arcsec, frame=aia.coordinate_frame),
    SkyCoord(Tx=650 * u.arcsec, Ty=450 * u.arcsec, frame=aia.coordinate_frame),
)

###############################
#    Field Extrapolation      #
###############################

# Define the number of grid points in rho
nrho = 100
# And the source surface radius.
rss = 2.5
# Construct an `Input` object that stores this information
pfss_input = pfsspy.Input(br, nrho, rss, dtime=aia_submap.date)
# Compute the PFSS solution from the GONG magnetic field input
pfss_output = pfsspy.pfss(pfss_input)

###############################
#    Field Line Tracing       #
###############################

center_hgc = aia_submap.center.transform_to('heliographic_carrington')
# Construct a grid of seed points to trace some magnetic field lines
# These seed points are grouped about the center of the AR
s, phi = np.meshgrid(
    np.linspace(
        np.sin(center_hgc.lat) - 0.07,
        np.sin(center_hgc.lat) + 0.03, 15),
    np.deg2rad(
Пример #25
0
br = br - np.nanmean(br)
offset = 5
# GONG maps have their LH edge at -180deg, so roll to get it at 0deg
br = np.roll(br, header['CRVAL1'] + 180 + offset, axis=1)

# Set up PFSS input
# ---

# In[8]:

import pfsspy
nr = 60  # Number of radial model points
rss = 2.5  # Source surface radius

# Create PFSS input object
input = pfsspy.Input(br, nr, rss, dtime=aia.date)

# Plot input magnetic field
import matplotlib.colors as mcolor
fig, ax = plt.subplots()
mesh = input.plot_input(ax, norm=mcolor.SymLogNorm(5))
fig.colorbar(mesh)
ax.set_title('Input GONG map')

# Calculate PFSS solution
# ---

# In[9]:

output = pfsspy.pfss(input)
Пример #26
0
# at your own risk!
gong_map = sunpy.map.Map(gong_fname)
# Remove the mean
gong_map = sunpy.map.Map(gong_map.data - np.mean(gong_map.data), gong_map.meta)

###############################################################################
# The PFSS solution is calculated on a regular 3D grid in (phi, s, rho), where
# rho = ln(r), and r is the standard spherical radial coordinate. We need to
# define the number of rho grid points, and the source surface radius.
nrho = 35
rss = 2.5

###############################################################################
# From the boundary condition, number of radial grid points, and source
# surface, we now construct an Input object that stores this information
input = pfsspy.Input(gong_map, nrho, rss)


def set_axes_lims(ax):
    ax.set_xlim(0, 360)
    ax.set_ylim(0, 180)


###############################################################################
# Using the Input object, plot the input field
m = input.map
fig = plt.figure()
ax = plt.subplot(projection=m)
m.plot()
plt.colorbar()
ax.set_title('Input field')
Пример #27
0
nr = 50
rss = 2.5

phi = np.linspace(0, 2 * np.pi, nphi)
theta = np.linspace(-np.pi / 2, np.pi / 2, ntheta)
theta, phi = np.meshgrid(theta, phi)


def dipole_Br(r, theta):
    return 2 * np.sin(theta) / r**3


br = dipole_Br(1, theta)
br = sunpy.map.Map(br.T,
                   pfsspy.utils.carr_cea_wcs_header('2010-01-01', br.shape))
pfss_input = pfsspy.Input(br, nr, rss)
pfss_output = pfsspy.pfss(pfss_input)
print('Computed PFSS solution')

###############################################################################
# Trace some field lines
seed0 = np.atleast_2d(np.array([1, 1, 0]))
tracers = [pfsspy.tracing.PythonTracer(), pfsspy.tracing.FortranTracer()]
nseeds = 2**np.arange(14)
times = [[], []]

for nseed in nseeds:
    print(nseed)
    seeds = np.repeat(seed0, nseed, axis=0)
    r, lat, lon = pfsspy.coords.cart2sph(seeds[:, 0], seeds[:, 1], seeds[:, 2])
    r = r * astropy.constants.R_sun
Пример #28
0
# to the FITS standard, so we need to fix them first.
hmi_map = sunpy.map.Map(files[0])
pfsspy.utils.fix_hmi_meta(hmi_map)
print('Data shape: ', hmi_map.data.shape)

###############################################################################
# Since this map is far to big to calculate a PFSS solution quickly, lets
# resample it down to a smaller size.
hmi_map = hmi_map.resample([360, 180] * u.pix)
print('New shape: ', hmi_map.data.shape)

###############################################################################
# Now calculate the PFSS solution
nrho = 35
rss = 2.5
input = pfsspy.Input(hmi_map, nrho, rss)
output = pfsspy.pfss(input)

###############################################################################
# Using the Output object we can plot the source surface field, and the
# polarity inversion line.
ss_br = output.source_surface_br
# Create the figure and axes
fig = plt.figure()
ax = plt.subplot(projection=ss_br)

# Plot the source surface map
ss_br.plot()
# Plot the polarity inversion line
ax.plot_coord(output.source_surface_pils[0])
# Plot formatting