Source code for smart.polarity_separation_line
import numpy as np
import skimage as ski
from skimage.morphology import disk
import astropy.units as u
__all__ = ["separate_polarities", "polarity_separation_line_length", "get_strong_gradient_length"]
[docs]
@u.quantity_input
def separate_polarities(im_map, feature_mask, dilation_radius: u.Quantity[u.arcsec] = 3 * u.arcsec):
"""
Divide detected feature into a positive and a negative mask, and dilate both masks.
Parameters
----------
im_map : `~sunpy.map.Map`
Processed SunPy magnetogram map.
feature_mask : `~numpy.ndarray`
Binary mask of the feature.
dilation_radius : `int`, optional
Radius of the disk for binary dilation (default is 3 arcsecs).
Returns
-------
dilated_negmask : `~numpy.ndarray`
Dilated mask of the negative region of the feature.
dilated_posmask : `~numpy.ndarray`
Dilated mask of the positive region of the feature.
"""
feature_map = feature_mask * im_map.data
posmask = (feature_map > 0).astype(int)
negmask = (feature_map < 0).astype(int)
arcsec_to_pixel = 1 / ((im_map.scale[0] + im_map.scale[1]) / 2)
dilation_radius = (np.round(dilation_radius * arcsec_to_pixel)).to_value(u.pix)
dilated_posmask = ski.morphology.binary_dilation(posmask, disk(dilation_radius))
dilated_negmask = ski.morphology.binary_dilation(negmask, disk(dilation_radius))
return dilated_negmask, dilated_posmask
[docs]
def polarity_separation_line_length(dilated_negmask, dilated_posmask):
"""
Calculate the length of the polarity separation line (the boundary line between the positive and negative regions of an AR).
Parameters
----------
dilated_negmask : `~numpy.ndarray`
Dilated mask of the negative region of the feature.
dilated_posmask : `~numpy.ndarray`
Dilated mask of the positive region of the feature.
Returns
-------
psl_length : `~int`
The length of the polarity separation line.
psl_thinmask : `~numpy.ndarray`
Skeletonized mask of the polarity separation line.
"""
psl_mask = dilated_posmask * dilated_negmask
psl_thinmask = ski.morphology.thin(psl_mask)
psl_length = np.sum(psl_thinmask)
return psl_length, psl_thinmask
[docs]
@u.quantity_input
def get_strong_gradient_length(
im_map, feature_mask, psl_thinmask, threshold: u.Quantity[u.Gauss / u.Mm] = 50 * u.Gauss / u.Mm
):
"""
Calculate the length of the strong gradients in the magnetic field.
Parameters
----------
im_map : `~sunpy.map.Map`
Processed SunPy magnetogram map.
feature_mask : `~numpy.ndarray`
Mask of the feature being examined
psl_thinmask : `~numpy.ndarray`
Skeletonized mask of the polarity separation line.
threshold : `astropy.units.quantity.Quantity`
The threshold above which the gradient is considered strong.
Returns
-------
strong_gradient_length : `~int`
The length of the strong gradients in the magnetic field.
"""
feature_map = feature_mask * im_map.data
y_gradient, x_gradient = np.gradient(feature_map) * (u.Gauss / u.pix)
gradient = np.sqrt(x_gradient**2 + y_gradient**2)
meters_per_arcsec = im_map.rsun_meters / im_map.rsun_obs
meters_per_pixel = meters_per_arcsec * (im_map.scale[0] + im_map.scale[1]) / 2
gradient = (gradient / meters_per_pixel).to(u.Gauss / u.Mm)
strong_gradient_mask = (gradient > threshold) & (psl_thinmask > 0)
strong_gradient_length = np.sum(strong_gradient_mask)
return strong_gradient_length