The ZFC
and FC
Experiment Classes¶
The ZFC
and FC
classes contain the data of individual zero-field cooled and field cooled, respectively, experiments (i.e., variable temperature magnetization), along with a number of methods used for processing and working with the data.
The ZFC
and FC
classes are child classes of the ZFCFC
class. When discussing elements that apply to both we may refer to ZFCFC
.
from pathlib import Path
import magnetopy as mp
DATA_PATH = Path("../../tests/data")
Creating ZFC
and FC
Objects from Files¶
Note: The File Formatting page contains detailed information on how MagnetoPy automatically reads and parses the contents of a data file.
Files Containing a Single ZFCFC Experiment¶
It's common for a single data file to contain a ZFC experiment followed by an FC experiment. We can create ZFC
and FC
objects by passing such a file to their constructors, which will then extract only the relevant data from the file.
zfc1 = mp.ZFC(DATA_PATH / "zfcfc1.dat")
fc1 = mp.FC(DATA_PATH / "zfcfc1.dat")
zfc1, fc1
(ZFC at 100 Oe, FC at 100 Oe)
The as_dict()
method returns a dictionary of information about the experiment and any processing that has been performed on it. Note that these are all attributes of the ZFCFC
object, and can be accessed directly as well.
Since we just created these objects and haven't done any processing the scaling
attributes will be empty lists.
zfc1.as_dict()
{'origin_file': 'zfcfc1.dat', 'field': 100, 'temperature_range': (5.00255632400513, 299.939453125), 'scaling': []}
fc1.as_dict()
{'origin_file': 'zfcfc1.dat', 'field': 100, 'temperature_range': (5.00277781486511, 299.924865722656), 'scaling': []}
The data is stored in the data
attribute. The columns of this DataFrame
are created directly from the data file which, in this case, is a .dat file from a Quantum Design MPMS3. There are two additional columns at the end, "uncorrected_moment"
and "uncorrected_moment_err"
. The .dat file contains the magnetization data in one of two columns, depending on whether the measurements were done in DC or VSM mode. The ZFCFC
class automatically determines which column contains the data, and stores it in the "uncorrected_moment"
and "uncorrected_moment_err"
columns, which are used for subsequent processing.
zfc1.data.head()
Comment | Time Stamp (sec) | Temperature (K) | Magnetic Field (Oe) | Moment (emu) | M. Std. Err. (emu) | Transport Action | Averaging Time (sec) | Frequency (Hz) | Peak Amplitude (mm) | ... | Map 09 | Map 10 | Map 11 | Map 12 | Map 13 | Map 14 | Map 15 | Map 16 | uncorrected_moment | uncorrected_moment_err | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | 3.841157e+09 | 5.002556 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.004336 | 0.000216 |
1 | NaN | 3.841157e+09 | 5.530379 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.004346 | 0.000217 |
2 | NaN | 3.841157e+09 | 6.279785 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.004360 | 0.000217 |
3 | NaN | 3.841157e+09 | 7.018987 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.004381 | 0.000219 |
4 | NaN | 3.841157e+09 | 7.762416 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.004405 | 0.000220 |
5 rows × 91 columns
fc1.data.head()
Comment | Time Stamp (sec) | Temperature (K) | Magnetic Field (Oe) | Moment (emu) | M. Std. Err. (emu) | Transport Action | Averaging Time (sec) | Frequency (Hz) | Peak Amplitude (mm) | ... | Map 09 | Map 10 | Map 11 | Map 12 | Map 13 | Map 14 | Map 15 | Map 16 | uncorrected_moment | uncorrected_moment_err | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | 3.841161e+09 | 5.002778 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.011784 | 0.000588 |
1 | NaN | 3.841161e+09 | 5.524109 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.011784 | 0.000588 |
2 | NaN | 3.841161e+09 | 6.282274 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.011783 | 0.000588 |
3 | NaN | 3.841162e+09 | 7.036755 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.011782 | 0.000588 |
4 | NaN | 3.841162e+09 | 7.772961 | 100.072647 | NaN | NaN | 6 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.011782 | 0.000588 |
5 rows × 91 columns
Files Containing a Single ZFC or FC Experiment¶
Pass the file path to the correct constructor. If the file is commented, passing a ZFC file to the FC
constructor (or vice versa) will raise an error. If the file is not commented, the file name includes the word "zfc" or "fc", and is passed to the constructor that doesn't match the file name, the object will be created but a warning will be raised. The warning can be suppressed by passing suppress_warnings=True
to the constructor.
zfc4 = mp.ZFC(DATA_PATH / "zfc4a.dat")
fc4 = mp.FC(DATA_PATH / "fc4a.dat")
zfc4, fc4
(ZFC at 100 Oe, FC at 100 Oe)
try:
zfc4 = mp.ZFC(DATA_PATH / "fc4a.dat", suppress_warnings=True)
except mp.experiments.zfcfc.FieldDetectionError as e:
print(e)
Could not autodetect field for zfc. When not specificying a field, the DatFile must contain exactly one field. Found 0 fields.
zfc5 = mp.FC(DATA_PATH / "zfc5.dat")
zfc5.as_dict()
C:\Users\pcb74\Documents\lab\Python\MagnetoPy\magnetopy\data_files.py:398: FileNameWarning: You have initialized a FC object but the file name zfc5.dat indicates that it is ZFC. You can suppress this warning by passing `suppress_warnings=True` to the constructor. warnings.warn(
{'origin_file': 'zfc5.dat', 'field': 200, 'temperature_range': (2.00167036056519, 299.911483764648), 'scaling': []}
zfc5 = mp.FC(DATA_PATH / "zfc5.dat", suppress_warnings=True)
zfc5.as_dict()
{'origin_file': 'zfc5.dat', 'field': 200, 'temperature_range': (2.00167036056519, 299.911483764648), 'scaling': []}
Files Containing Multiple ZFC and/or FC Experiments¶
This is currently only supported for commented files. If there are multiple ZFCFC experiments at different fields, you'll need to pass the field
value to the constructor.
try:
zfc4 = mp.ZFC(DATA_PATH / "zfcfc4.dat")
except mp.experiments.zfcfc.FieldDetectionError as e:
print(e)
Could not autodetect field for zfc. When not specificying a field, the DatFile must contain exactly one field. Found 2 fields.
zfc4_100 = mp.ZFC(DATA_PATH / "zfcfc4.dat", field=100)
zfc4_1000 = mp.ZFC(DATA_PATH / "zfcfc4.dat", field=1000)
fc4_100 = mp.FC(DATA_PATH / "zfcfc4.dat", field=100)
fc4_1000 = mp.FC(DATA_PATH / "zfcfc4.dat", field=1000)
zfc4_100, zfc4_1000, fc4_100, fc4_1000
(ZFC at 100 Oe, ZFC at 1000 Oe, FC at 100 Oe, FC at 1000 Oe)
Creating Multiple ZFC or FC Objects from a Single File¶
If the file contains multiple ZFC and/or FC experiments, you can create a list of ZFC
/FC
objects using the get_all_in_file()
method.
zfc = mp.ZFC.get_all_in_file(DATA_PATH / "zfcfc4.dat")
zfc
[ZFC at 100.0 Oe, ZFC at 1000.0 Oe]
fc = mp.FC.get_all_in_file(DATA_PATH / "zfcfc4.dat")
fc
[FC at 100.0 Oe, FC at 1000.0 Oe]
Simplified Data¶
The columns given from the data file are likely more than we'll need for 98% of what we typically do with the data. Additionally, when MagnetoPy supports other file types from other instruments, we'll still want a standard interface upon which we can build anlayses and visualization methods. The simplified_data()
method returns a DataFrame
with only the relevant columns for a ZFCFC
experiment:
zfc = mp.ZFC(DATA_PATH / "zfcfc4.dat", field=1000)
zfc.simplified_data().head()
time | temperature | field | moment | moment_err | chi | chi_err | chi_t | chi_t_err | |
---|---|---|---|---|---|---|---|---|---|
0 | 3860761286 | 4.999953 | 1000.262024 | 0.002310 | 2.710000e-07 | 0.000002 | 2.709290e-10 | 0.000012 | 1.354632e-09 |
1 | 3860761289 | 5.039120 | 1000.262024 | 0.002310 | 2.820000e-07 | 0.000002 | 2.819261e-10 | 0.000012 | 1.420660e-09 |
2 | 3860761290 | 5.159641 | 1000.262024 | 0.002310 | 2.790000e-07 | 0.000002 | 2.789269e-10 | 0.000012 | 1.439163e-09 |
3 | 3860761293 | 5.360177 | 1000.262024 | 0.002311 | 3.160000e-07 | 0.000002 | 3.159172e-10 | 0.000012 | 1.693372e-09 |
4 | 3860761295 | 5.510782 | 1000.262024 | 0.002312 | 3.110000e-07 | 0.000002 | 3.109185e-10 | 0.000013 | 1.713404e-09 |
In this case we haven't done any scaling or processing, so the values of the "moment"
and "moment_err"
columns are the same as the values in the previously mentioned "uncorrected_moment"
and "uncorrected_moment_err"
columns. We'll see how to scale the data in the next section.
Scaling the Moment¶
Scaling is something you'll likely do through the Magnetometry
class, discussed in a later example notebook. However, the Magnetometry
class uses methods within the ZFCFC
class, and these methods can be used directly as well.
Scaling can be done using the scale_moment()
method. As is described in the underlying utility function, this method adds columns to the data
attribute of the ZFCFC
object that contain the magnetic moment, magnetic susceptibility, and magnetic susceptibility times temperature (and their errors). The columns added are "moment"
, "moment_err"
, "chi"
, "chi_err"
, "chi_t"
, and "chi_t_err"
. The units of these values depend on the values of the mass
, eicosane_mass
, molecular_weight
, and diamagnetic_correction
which are passed as arguments. A record of what scaling was applied is added to the scaling
attribute of the ZFCFC
object.
Here are the currently supported scaling options:
- If
mass
is given but notmolecular_weight
, the only available scaling is a mass correction. - If
mass
andmolecular
weight are given, a molar correction is applied. The molar correction can be further modified by givingeicosane_mass
and/ordiamagnetic_correction
.
We'll use the SampleInfo
class to read the sample information from the header of the .dat file:
zfc5_sample_info = mp.SampleInfo.from_dat_file(DATA_PATH / "zfc5.dat")
print(
f"""{zfc5_sample_info.mass = }
{zfc5_sample_info.eicosane_mass = }
{zfc5_sample_info.molecular_weight = }
{zfc5_sample_info.diamagnetic_correction = }"""
)
zfc5_sample_info.mass = 10.2 zfc5_sample_info.eicosane_mass = 28.8 zfc5_sample_info.molecular_weight = 1229.56 zfc5_sample_info.diamagnetic_correction = -0.00056176
zfc5 = mp.ZFC(DATA_PATH / "zfc5.dat")
zfc5.scale_moment(
mass = zfc5_sample_info.mass,
eicosane_mass = zfc5_sample_info.eicosane_mass,
molecular_weight = zfc5_sample_info.molecular_weight,
diamagnetic_correction = zfc5_sample_info.diamagnetic_correction,
)
The scaling
attribute records the scaling that was applied as a list of manipulations. In this case, with a mass, molecular weight, and eicosane mass, the scaling is recorded as a "molar"
scaling with "eicosane"
and "diamagnetic_correction"
corrections:
zfc5.scaling
['molar', 'eicosane', 'diamagnetic_correction']
zfc5.simplified_data().head()
time | temperature | field | moment | moment_err | chi | chi_err | chi_t | chi_t_err | |
---|---|---|---|---|---|---|---|---|---|
0 | 3.876038e+09 | 2.001670 | 199.96196 | 0.099940 | 0.005089 | 2.791363 | 0.142138 | 5.587388 | 0.284513 |
1 | 3.876038e+09 | 2.201302 | 199.96196 | 0.160750 | 0.008121 | 4.489811 | 0.226826 | 9.883431 | 0.499313 |
2 | 3.876039e+09 | 2.401609 | 199.96196 | 0.186832 | 0.009422 | 5.218290 | 0.263168 | 12.532294 | 0.632026 |
3 | 3.876039e+09 | 2.601313 | 199.96196 | 0.201812 | 0.010170 | 5.636663 | 0.284041 | 14.662723 | 0.738880 |
4 | 3.876039e+09 | 2.800433 | 199.96196 | 0.212596 | 0.010708 | 5.937875 | 0.299070 | 16.628622 | 0.837524 |
Plotting¶
The MagnetoPy function plot_zfcfc()
provides basic plotting capabilities for ZFCFC
objects. It can be used to plot a single pair of ZFC/FC experiments or multiple pairs of ZFC/FC experiments. In the former case it calls plot_single_zfcfc()
and in the latter case it calls plot_multiple_zfcfc()
. It shouldn't be necessary, but these functions can be called directly if desired.
There is a convenience function in the Magnetometry
class for plotting ZFCFC experiments.
Plot a Single ZFCFC
Experiment¶
The first two arguments of plot_zfcfc()
must be the ZFC
and FC
objects. Note how the y-axis units change based on scaling. The default behavior is to plot magnetization.
zfc5 = mp.ZFC(DATA_PATH / "zfc5.dat")
fc5 = mp.FC(DATA_PATH / "fc5.dat")
fig, ax = mp.plot_zfcfc(zfc5, fc5)
zfc5 = mp.ZFC(DATA_PATH / "zfc5.dat")
fc5 = mp.FC(DATA_PATH / "fc5.dat")
zfc5_sample_info = mp.SampleInfo.from_dat_file(DATA_PATH / "zfc5.dat")
fc5_sample_info = mp.SampleInfo.from_dat_file(DATA_PATH / "fc5.dat")
zfc5.scale_moment(
mass = zfc5_sample_info.mass,
)
fc5.scale_moment(
mass = fc5_sample_info.mass,
)
fig, ax = mp.plot_zfcfc(zfc5, fc5)
zfc5 = mp.ZFC(DATA_PATH / "zfc5.dat")
fc5 = mp.FC(DATA_PATH / "fc5.dat")
zfc5_sample_info = mp.SampleInfo.from_dat_file(DATA_PATH / "zfc5.dat")
fc5_sample_info = mp.SampleInfo.from_dat_file(DATA_PATH / "fc5.dat")
zfc5.scale_moment(
mass = zfc5_sample_info.mass,
molecular_weight=zfc5_sample_info.molecular_weight,
)
fc5.scale_moment(
mass = fc5_sample_info.mass,
molecular_weight=fc5_sample_info.molecular_weight,
)
fig, ax = mp.plot_zfcfc(zfc5, fc5)
The default behavior is to plot magnetization, but that can be changed by passing a y_val
argument. Possible values are "moment"
, "chi"
, and "chi_t"
.
zfc5 = mp.ZFC(DATA_PATH / "zfc5.dat")
fc5 = mp.FC(DATA_PATH / "fc5.dat")
zfc5_sample_info = mp.SampleInfo.from_dat_file(DATA_PATH / "zfc5.dat")
fc5_sample_info = mp.SampleInfo.from_dat_file(DATA_PATH / "fc5.dat")
zfc5.scale_moment(
mass = zfc5_sample_info.mass,
molecular_weight=zfc5_sample_info.molecular_weight,
)
fc5.scale_moment(
mass = fc5_sample_info.mass,
molecular_weight=fc5_sample_info.molecular_weight,
)
fig, ax = mp.plot_zfcfc(zfc5, fc5, y_val="chi_t")
Plotting Multiple ZFCFC
Experiments¶
The plot_zfcfc()
function can also be used to plot multiple pairs of ZFC/FC experiments. In this case the first two arguments must be lists of ZFC
and FC
objects. The label
argument can be used to label the curves in the legend, otherwise the field values are used as labels.
zfc4_100 = mp.ZFC(DATA_PATH / "zfcfc4.dat", field=100)
zfc4_1000 = mp.ZFC(DATA_PATH / "zfcfc4.dat", field=1000)
fc4_100 = mp.FC(DATA_PATH / "zfcfc4.dat", field=100)
fc4_1000 = mp.FC(DATA_PATH / "zfcfc4.dat", field=1000)
zfcfc4_sample_info = mp.SampleInfo.from_dat_file(DATA_PATH / "zfcfc4.dat")
zfc4_100.scale_moment(zfcfc4_sample_info.mass)
zfc4_1000.scale_moment(zfcfc4_sample_info.mass)
fc4_100.scale_moment(zfcfc4_sample_info.mass)
fc4_1000.scale_moment(zfcfc4_sample_info.mass)
fig, ax = mp.plot_zfcfc([zfc4_100, zfc4_1000], [fc4_100, fc4_1000])
The normalized
argument is often useful for multiple sets of ZFC/FC experiments.
fig, ax = mp.plot_zfcfc([zfc4_100, zfc4_1000], [fc4_100, fc4_1000], normalized=True)
Plotting Raw Data¶
The ZFCFC
class has plot_raw()
and plot_raw_residuals()
methods for plotting the raw data. These are often more convenient than the related DatFile
methods, since the DatFile
method would require the user to slice out ZFC or FC data from a file which contained both.
zfc5 = mp.ZFC(DATA_PATH / "zfc5.dat", parse_raw=True)
fig, ax = zfc5.plot_raw()
fig, ax = zfc5.plot_raw_residual()