This notebook provides a step-by-step walk through of the processing of hysteresis loops. Each processing step is illustrated and described. This walk through can enable more granular data processing and illustrates the decision tree that is automatically implemented in the hysteresis
Install and import packages¶
import pmagpy.rockmag as rmag
import pmagpy.ipmag as ipmag
import pmagpy.contribution_builder as cb
from bokeh.plotting import figure, show
from bokeh.io import output_notebook
output_notebook(hide_banner=True)Import local data in MagIC format¶
In this demonstration we will be using local data.
The data is from the following publication:
Swanson-Hysell, N. L., Avery, M. S., Zhang, Y., Hodgin, E. B., Sherwood, R. J., Apen, F. E., et al. (2021). The paleogeography of Laurentia in its early years: New constraints from the Paleoproterozoic East-Central Minnesota Batholith. Tectonics, 40, e2021TC006751. https://
doi .org /10 .1029 /2021TC006751
# set the dir_path to the directory where the measurements.txt file is located
dir_path = '../example_data/ECMB'
# set the name of the MagIC file
ipmag.unpack_magic('magic_contribution_20213.txt',
dir_path = dir_path,
input_dir_path = dir_path,
print_progress=False)
# create a contribution object from the tables in the directory
contribution = cb.Contribution(dir_path)
measurements = contribution.tables['measurements'].df1 records written to file /Users/penokean/0000_GitHub/RockmagPy-notebooks/example_data/ECMB/contribution.txt
1 records written to file /Users/penokean/0000_GitHub/RockmagPy-notebooks/example_data/ECMB/locations.txt
90 records written to file /Users/penokean/0000_GitHub/RockmagPy-notebooks/example_data/ECMB/sites.txt
312 records written to file /Users/penokean/0000_GitHub/RockmagPy-notebooks/example_data/ECMB/samples.txt
1574 records written to file /Users/penokean/0000_GitHub/RockmagPy-notebooks/example_data/ECMB/specimens.txt
17428 records written to file /Users/penokean/0000_GitHub/RockmagPy-notebooks/example_data/ECMB/measurements.txt
-I- Using online data model
-I- Getting method codes from earthref.org
-I- Importing controlled vocabularies from https://earthref.org
Get hysteresis data from the measurements dataframe¶
The method codes relevant to hysteresis loops are:
LP-HYSfor regular hysteresis loopsLP-HYS-Ofor hysteresis loops as a function of orientationLP-HYS-Tfor hysteresis loops as a function of temperature
Inspect the original measurement level data¶
Below we investigate all the available specimens that have hysteresis data in the database for this contribution.
We extract the experimental data for an individual specimen.
measurements = measurements[measurements['method_codes'] == 'LP-HYS']
measurements.specimen.unique()<StringArray>
['NED1-5c', 'NED18-2c', 'NED2-8c', 'NED4-1c', 'NED6-6c']
Length: 5, dtype: str# filter and isolate specimen specific hysteresis loop data by specimen name
NED1_5c_hyst = measurements[measurements['specimen'] == 'NED1-5c'].reset_index(drop=True)
NED18_2c_hyst = measurements[measurements['specimen'] == 'NED18-2c'].reset_index(drop=True)
NED2_8c_hyst = measurements[measurements['specimen'] == 'NED2-8c'].reset_index(drop=True)
NED4_1c_hyst = measurements[measurements['specimen'] == 'NED4-1c'].reset_index(drop=True)
NED6_6c_hyst = measurements[measurements['specimen'] == 'NED6-6c'].reset_index(drop=True)Let’s take a look at the columns relevant to hysteresis data processing
magn_massis mass normalized magnetization (in Am^2/kg)meas_field_dcis the applied DC field (in T)
NED18_2c_hyst[['magn_mass', 'meas_field_dc']]Visualize the raw data with plot_hyst_loop¶
The function returns a Bokeh plot object which can be further customized before displaying
NED18_2c_plot = rmag.plot_hyst_loop(NED18_2c_hyst['meas_field_dc'], NED18_2c_hyst['magn_mass'],
'NED18-2c', line_color='orange', line_width=1, label='NED18-2c', return_figure=True)Loop processing¶
rockmagpy calculates the hysteresis loop parameters as available in the IRMDB software. Summary parameters can then be exported into the MagIC specimen data table.

The processing functions implement the protocol of Jackson and Solheid (2010) as realized in the hysteresis processing software of the Institute for Rock Magnetism (IRM). Paterson et al. (2018) present a related treatment of hysteresis data processing (implemented in HystLab) that is a complementary resource. This flowchart shows the decision tree for data processing.

Interpolate the raw data and re-grid them into an upper and a lower branch with exactly the same and symmetric field steps¶
The applied DC field values through the upper and lower branches during experiments are usually not exactly symmetric about the origin. We need to correct for the slight mismatching between the field steps by splitting the loop into an upper branch and a lower branch, interpolating the branches and unifying their field axis to be the same and be symmetric about 0.
The function
rmag.grid_hyst_loopaccomplishes this task.
NED18_2c_hyst_grid_field, NED18_2c_hyst_grid_magnetization = rmag.grid_hyst_loop(NED18_2c_hyst['meas_field_dc'],
NED18_2c_hyst['magn_mass'])
NED18_2c_plot_grid = rmag.plot_hyst_loop(NED18_2c_hyst_grid_field, NED18_2c_hyst_grid_magnetization, specimen_name='NED18-2c',
p=NED18_2c_plot, line_color='goldenrod', label='NED18-2c gridded', legend_location='top_left', return_figure=True)Perform linearity test on the whole loop¶
If the whole loop is linear, the sample is dominated by paramagnetic or diamagnetic materials and no ferromagnetic parameters can be estimated (the high-field slope is the result to report).
If the whole loop is not linear, we should move on to further processing.
The
FNLstatistic is a lack-of-fit F ratio from an ANOVA partition in which the upper branch and the inverted lower branch are treated as replicate measurements (Jackson and Solheid, 2010).FNLvalues above ~1.25 reject whole-loop linearity at 95% confidence for typical loop sizes.The resulting stats dictionary from the
hyst_linearity_testfunction has a keyloop_is_linearwith a boolean value that signals whether the loop is linear or not.process_hyst_loopimplements this as a decision-tree exit: a statistically linear loop terminates with only χHF reported (from the whole-loop regression) and the ferromagnetic parameters as NaN. Passingfit_linear_loop=Trueoverrides the exit and processes the loop in full, which can be useful when a weak ferromagnetic signal near the noise level is of interest.
loop_linearity = rmag.hyst_linearity_test(NED18_2c_hyst_grid_field, NED18_2c_hyst_grid_magnetization)
loop_linearity{'SST': 31.31588187151477,
'SSR': 29.911856290407343,
'SSD': 1.404025581107423,
'R_squared': 0.9551657019633689,
'SSPE': 0.000117113729198881,
'SSLF': 1.403908467378224,
'MSPE': 2.927843229972025e-07,
'MSLF': 0.0035274082094930255,
'MSR': 29.911856290407343,
'MSD': 0.0017594305527661941,
'FL': 17000.87351750237,
'FNL': 12047.804245061063,
'slope': 0.33421603926557925,
'intercept': 3.292628865865779e-05,
'loop_is_linear': False}Loop centering¶
In the example case, the loop is not linear, so we need to isolate the ferromagnetic component from the paramagnetic component.
We need to center the loop to remove any offset in the field and moment axes that could be present in the data.
centering_results = rmag.hyst_loop_centering(NED18_2c_hyst_grid_field, NED18_2c_hyst_grid_magnetization)
NED18_2c_hyst_centered_H, NED18_2c_hyst_centered_M = centering_results['centered_H'], centering_results['centered_M']
NED18_2c_plot_centered = rmag.plot_hyst_loop(NED18_2c_hyst_centered_H, NED18_2c_hyst_centered_M, specimen_name='NED18-2c', p=NED18_2c_plot_grid, line_color='red', label='NED18-2c offset corrected', legend_location='top_left', return_figure=True)Quality factor Q¶
Once the loop has been centered, the quality factor Q can be calculated. Following Jackson and Solheid (2010), Q is the decimal log of the signal/noise ratio, where the noise is quantified from the mean square mismatch between symmetrically equivalent moments of the offset-corrected loop. The convention used is , matching the IRM’s processing software and HystLab (Paterson et al., 2018, eq. 4); note that the corresponding equation as printed in Jackson and Solheid (2010) omits the square root, although the values reported in that paper include it (see Paterson et al., 2018). A higher value indicates better quality data. Note this value can deviate from that currently calculated in the IRM VSM Ferret as that value is estimated from the FNL statistic.
High Q values (e.g., 2 or greater) indicate that deviations from inversion symmetry due to all possible sources (noise, drift, and inherent asymmetry) are small. Conversely, low values indicate that at least one of these is significant. When Q falls below ~0.3 (signal/noise ~2) it becomes difficult to compute meaningful parameters for the loop, and when Q < 2 the automated processing skips the horizontal (field) offset correction because it cannot be robustly determined.
centering_results['Q']2.4287561471446177Loop drift correction¶
Sometimes spurious changes occur in measured signal strength on time scales comparable to that of the loop measurement. Drift is typically manifested by failure of loops to close, by lack of even symmetry in Mrh, and/or by failure of Mrh to decrease to zero in large (positive or negative) fields.
In many cases a correction is not strictly necessary as the drift signal is small. The default approach is to examine the smoothed error curve Me (the mismatch between the upper branch and the inverted lower branch) and determine whether a high-field drift correction or an upper branch drift correction is appropriate.
If you zoom in on the ~1 T region of the loop above, you will find that there is a slight difference between the beginning and end points.
The
Me_drift_correctionfunction corrects the drift by subtracting a smoothed Me curve either in the high-field region (when the largest errors occur above 75% of the maximum field) or over the entire upper branch of the loop.
NED18_2c_hyst_drift_corr_magnetization = rmag.Me_drift_correction(NED18_2c_hyst_centered_H, NED18_2c_hyst_centered_M)NED18_2c_plot_drift_corr = rmag.plot_hyst_loop(NED18_2c_hyst_centered_H, NED18_2c_hyst_drift_corr_magnetization, specimen_name='NED18-2c', p=NED18_2c_plot_centered, line_color='blue', label='NED18-2c drift corrected', legend_location='top_left', return_figure=True)Calculate the Mr (remanent magnetization), Mrh (remanence component), Mih (induced component), Me (error), Brh (field corresponding to 1/2 Mr)¶
The function
calc_Mr_Mrh_Mih_Brhcalculates these values and curves.Mrh = (M+ - M-)/2 and Mih = (M+ + M-)/2 where M+ and M- are the upper and lower branches; for a well-behaved loop, Mrh is an even function of field and Mih is odd (Jackson and Solheid, 2010).
Below we print out the Mr value and Brh value.
H, Mr, Mrh, Mih, Me, Brh = rmag.calc_Mr_Mrh_Mih_Brh(NED18_2c_hyst_centered_H, NED18_2c_hyst_drift_corr_magnetization)
print('Mr: ', Mr, 'Brh: ', Brh)Mr: 0.013721758647117336 Brh: 0.03653374612762557
NED18_2c_plot_drift_corr.line(H, Mrh, line_color='green', legend_label='Mrh', line_width=1)
NED18_2c_plot_drift_corr.line(H, Mih, line_color='purple', legend_label='Mih', line_width=1)
NED18_2c_plot_drift_corr.line(H, Me, line_color='brown', legend_label='Me', line_width=1)
show(NED18_2c_plot_drift_corr)Test loop closure¶
When there are significant high coercivity components in the sample such as hematite or goethite, the hysteresis branches will not be overlapping at the highest applied fields.
In that case, hysteresis processing stops as we are not able to estimate Ms: the ferromagnetic and linear contributions cannot be separated, so
process_hyst_loopreports the slope-independent parameters (Mr and Brh, computed from Mrh in which any linear-in-field contribution cancels) together with the data quality statistics (FNL, FNL60/70/80, Q, SNR, HAR), while Ms, χHF, and Bc are reported as NaN. Passingfit_open_loop=True(orNL_fit=True, which implies it) forces the high-field fit anyway---useful if residual instrument drift, rather than a genuinely open loop, trips the test.If the loop is closed, we move on to the next step of testing loop saturation.
The
loop_closure_testfunction tests loop closure usingH,Mrh, andMe: the signal is the field-reflection average of Mrh in the high-field window (Mrh is an even function of field for a well-behaved loop, so this average estimates the true remanent hysteretic signal), and the noise is estimated from the high-field portion of the error curve Me, following the implementation in HystLab (Paterson et al., 2018, section 4.5). The loop is judged closed when the high-field signal-to-noise ratio is below 8 dB or the ratio of high-field to total Mrh area is below -48 dB.
loop_closure_test = rmag.loop_closure_test(H, Mrh, Me)
loop_closure_test['loop_is_closed']FalseTest loop saturation (high-field linearity test)¶
In the example case, the loop is closed, so we proceed to test the loop saturation. This test allows us to determine the appropriate approach for fitting the high-field portion of the loop and determining Ms.
The lack of saturation can cause a loop to deviate from linearity at high fields. Although such a deviation from linearity can be subtle to the eye, it can have a significant effect on estimates of Ms. As developed in Jackson and Solheid (2010), a linearity test is conducted over high-field windows starting at 60%, 70%, and 80% of the maximum field. If the loop statistically deviates from linearity in all of these windows (FNL > 2.5), it would be inappropriate to use a linear fit to the high-field data to correct for the paramagnetic or diamagnetic slope, and an approach-to-saturation fit is required. Otherwise, a linear fit is applied over the window starting at the lowest field fraction that is statistically linear (the
saturation_cutoff).In the example case, the loop is not saturated at 60%, 70%, and 80% of the maximum field range. Therefore, an approach to saturation fit needs to be used for isolating the ferromagnetic loop and then calculating the Ms and the high field susceptibility values.
loop_saturation_test_result = rmag.hyst_loop_saturation_test(NED18_2c_hyst_centered_H, NED18_2c_hyst_drift_corr_magnetization)
loop_saturation_test_result{'FNL60': 98.71245833061079,
'FNL70': 25.24999808936752,
'FNL80': 17.47848462911585,
'saturation_cutoff': 0.92,
'loop_is_saturated': False}Fit high-field slope and get the intercept as Ms¶
In this case, the loop is not saturated at high fields and we should use an approach to saturation fit to calculate the Ms value.
But to show the difference between a linear fit and a saturation fit, we will also perform a linear fit on the high-field data and use it to correct the loop.
We use the
linear_HF_fitfunction to estimate the high-field susceptibility (and the Ms intercept in the case where the loop is saturated). Note that the returnedchi_HFis the fitted slope converted to SI units (multiplied by ).We then use the resultant
chi_HFto correct the loop using thehyst_slope_correctionfunction (which applies the inverse unit conversion internally).
chi_HF, Ms = rmag.linear_HF_fit(NED18_2c_hyst_centered_H, NED18_2c_hyst_drift_corr_magnetization, loop_saturation_test_result['saturation_cutoff'])
NED18_2c_hyst_linear_ferro_M = rmag.hyst_slope_correction(NED18_2c_hyst_centered_H, NED18_2c_hyst_drift_corr_magnetization, chi_HF)
print('Ms based on linear fitting: ', Ms)Ms based on linear fitting: 0.11376164642895595
NED18_2c_plot_linear_ferro = rmag.plot_hyst_loop(NED18_2c_hyst_centered_H, NED18_2c_hyst_linear_ferro_M,
specimen_name='NED18-2c', p=NED18_2c_plot_drift_corr,
line_color='dodgerblue', label='NED18-2c linear high-field corrected', return_figure=True)Perform approach-to-saturation fit and estimate a more appropriate Ms¶
In this example case, a linear fit would underestimate the Ms value.
A more appropriate Ms value can be estimated using a nonlinear approach-to-saturation fit with the
hyst_HF_nonlinear_optimizationfunction.By default (
fit_type='IRM'), the model used at the IRM is fit:Alternative model forms of (Fabian, 2006) are available with
fit_type='Fabian'(free ) andfit_type='Fabian_fixed_beta'().The returned
Fnl_linstatistic (Jackson and Solheid, 2010, eq. 21) tests whether the nonlinear fit significantly improves on a linear fit; values above ~3-3.5 indicate a significant improvement.
NL_fit_result = rmag.hyst_HF_nonlinear_optimization(NED18_2c_hyst_centered_H, NED18_2c_hyst_drift_corr_magnetization,
HF_cutoff=0.6, fit_type='IRM')
NL_fit_result{'chi_HF': 2.0311887043509852e-07,
'Ms': 0.1208155437705446,
'a_1': -1.8446127659932517e-21,
'a_2': -0.0016026252474735587,
'Fnl_lin': 150.88409867832559}Now let’s use the approach-to-saturation fit result to correct the loop.
NED18_2c_hyst_NL_ferro_M = rmag.hyst_slope_correction(NED18_2c_hyst_centered_H, NED18_2c_hyst_drift_corr_magnetization,
NL_fit_result['chi_HF'])Plot the ferromagnetic component together with the previous intermediate products¶
You may click on the legend items to hide the curves
The preferred final ferromagnetic component is shown in pink
NED18_2c_plot_NL_ferro = rmag.plot_hyst_loop(NED18_2c_hyst_centered_H, NED18_2c_hyst_NL_ferro_M,
specimen_name='NED18-2c', p=NED18_2c_plot_drift_corr,
line_color='pink', label='NED18-2c non-linear high-field correction',
legend_location='bottom_right', return_figure=True)Inspect the differences between applying a linear high field slope fit vs. an approach-to-saturation fit¶
high_field_fit_inspection_plot = rmag.plot_hyst_loop(NED18_2c_hyst_centered_H, NED18_2c_hyst_NL_ferro_M,
specimen_name='NED18-2c',
line_color='pink', label='NED18-2c non-linear high-field correction',
legend_location='bottom_right')
high_field_fit_inspection_plot = rmag.plot_hyst_loop(NED18_2c_hyst_centered_H, NED18_2c_hyst_linear_ferro_M,
specimen_name='NED18-2c', p=high_field_fit_inspection_plot,
line_color='dodgerblue', label='NED18-2c linear high-field corrected', return_figure=True)Calculate the quality factor of the ferromagnetic component loop¶
Qf is the quality factor Q recomputed on the slope-corrected (ferromagnetic component) loop (the of Jackson and Solheid, 2010). The high-field slope correction affects the mean square signal strength but not the noise, so Qf quantifies the signal/noise of the isolated ferromagnetic loop.
M_sn_f, Qf = rmag.calc_Q(NED18_2c_hyst_centered_H, NED18_2c_hyst_NL_ferro_M)
print('Qf: ', Qf)Qf: 3.4359428570949433
Calculate Bc¶
This calculation is based on the ferromagnetic component loop.
There will be a difference if you use the loops before high-field slope correction.
The Bc value is calculated as the average of the lower and upper branch.
The value shown is in unit of Tesla.
Bc = rmag.calc_Bc(NED18_2c_hyst_centered_H, NED18_2c_hyst_NL_ferro_M)
print('Bc: ', Bc)Bc: 0.010038809582344791
The process_hyst_loop function¶
The process_hyst_loop function applies all of the above steps using the decision tree to process the data. The summary table includes the parameters developed above as well as the hysteresis shape parameter of Fabian (2003), where is the area of the ferromagnetic loop. Options include NL_fit=True to force an approach-to-saturation fit, centering_protocol='iterative' for weak ferromagnetic loops superimposed on a strong linear background, and the decision-tree overrides fit_open_loop=True (proceed with the high-field fitting for a loop the closure test flags as open; implied by NL_fit=True) and fit_linear_loop=True (fully process a loop that passes the whole-loop linearity test).
NED18_2c_hyst_process_result = rmag.process_hyst_loop(NED18_2c_hyst['meas_field_dc'].values, NED18_2c_hyst['magn_mass'].values, 'NED18-2c')References¶
Fabian, K. (2003). Some additional parameters to estimate domain state from isothermal magnetization measurements. Earth and Planetary Science Letters, 213(3-4), 337–345. https://
Fabian, K. (2006). Approach to saturation analysis of hysteresis measurements in rock magnetism and evidence for stress dominated magnetic anisotropy in young mid-ocean ridge basalt. Physics of the Earth and Planetary Interiors, 154, 299–307. Fabian (2006)
Jackson, M., & Solheid, P. (2010). On the quantitative analysis and evaluation of magnetic hysteresis data. Geochemistry, Geophysics, Geosystems, 11(4), Q04Z15. Jackson & Solheid (2010)
Paterson, G. A., Zhao, X., Jackson, M., & Heslop, D. (2018). Measuring, processing, and analyzing hysteresis data. Geochemistry, Geophysics, Geosystems, 19(7), 1925–1945. Paterson et al. (2018)
Swanson-Hysell, N. L., Avery, M. S., Zhang, Y., Hodgin, E. B., Sherwood, R. J., Apen, F. E., et al. (2021). The paleogeography of Laurentia in its early years: New constraints from the Paleoproterozoic East-Central Minnesota Batholith. Tectonics, 40, e2021TC006751. Swanson‐Hysell et al. (2021)
- Fabian, K. (2006). Approach to saturation analysis of hysteresis measurements in rock magnetism and evidence for stress dominated magnetic anisotropy in young mid-ocean ridge basalt. Physics of the Earth and Planetary Interiors, 154(3–4), 299–307. 10.1016/j.pepi.2005.06.016
- Jackson, M., & Solheid, P. (2010). On the quantitative analysis and evaluation of magnetic hysteresis data. Geochemistry, Geophysics, Geosystems, 11(4). 10.1029/2009gc002932
- Paterson, G. A., Zhao, X., Jackson, M., & Heslop, D. (2018). Measuring, Processing, and Analyzing Hysteresis Data. Geochemistry, Geophysics, Geosystems, 19(7), 1925–1945. 10.1029/2018gc007620
- Swanson‐Hysell, N. L., Avery, M. S., Zhang, Y., Hodgin, E. B., Sherwood, R. J., Apen, F. E., Boerboom, T. J., Keller, C. B., & Cottle, J. M. (2021). The Paleogeography of Laurentia in Its Early Years: New Constraints From the Paleoproterozoic East‐Central Minnesota Batholith. Tectonics, 40(5). 10.1029/2021tc006751