Datasets in MagnetoPy: The Magnetometry Class¶
The Magnetometry class contains magnetometry data for a single sample along with methods for parsing, processing, and analyzing the data. Note that "single sample" means that in situations in which a single material is measured in multiple samples, each sample should be treated as a separate Magnetometry object.
import json
from pathlib import Path
import magnetopy as mp
DATA_PATH = Path("../../tests/data")
Creating a Magnetometry Object¶
To create a Magnetometry object, simply pass the path of the folder which contains all of the data files for the sample.
dset1 = mp.Magnetometry(DATA_PATH / "dataset1")
The default behavior sets the sample_id attribute to the name of the folder.
dset1.sample_id
'dataset1'
A different sample_id can be passed during object construction:
dset1 = mp.Magnetometry(DATA_PATH / "dataset1", sample_id="new_sample_id")
dset1.sample_id
'new_sample_id'
Since they can take a long time to process, raw data files (.rw.dat) files are ignored by default. If you need access to the raw data, pass parse_raw=True to the constructor.
dset2 = mp.Magnetometry(DATA_PATH / "dataset2")
try:
dset2.mvsh[0].plot_raw()
except mp.data_files.NoRawDataError as e:
print(e)
This DatFile object does not contain raw data.
dset2 = mp.Magnetometry(DATA_PATH / "dataset2", parse_raw=True)
fig, ax = dset2.mvsh[0].plot_raw()
Files and Experiments¶
For now we'll focus on the attributes files, mvsh, zfc, and fc. files contains a list of the data files comprising the dataset. The latter three contain lists of the MvsH, ZFC, and FC objects, respectively, which were found within the dataset's files.
For example, the following dataset, dset1, has several MvsH experiments found within one file, and a single "zfcfc" file which is separated into ZFC and FC experiments:
dset1 = mp.Magnetometry(DATA_PATH / "dataset1")
dset1.files
[DatFile(mvsh1.dat), DatFile(zfcfc1.dat)]
dset1.mvsh
[MvsH at 2 K, MvsH at 4 K, MvsH at 6 K, MvsH at 8 K, MvsH at 10 K, MvsH at 12 K, MvsH at 300 K]
Inspecting one of the MvsH objects shows which file it came from.
dset1.mvsh[0].as_dict()
{'_class_': 'MvsH',
'origin_file': 'mvsh1.dat',
'temperature': 2,
'field_range': (-70000.35156, 70000.375),
'field_correction_file': '',
'scaling': ['molar', 'eicosane']}
The zfc and fc attributes are single-item lists, and we can see that the ZFC and FC objects are from the same file.
dset1.zfc[0].origin_file, dset1.fc[0].origin_file
('zfcfc1.dat', 'zfcfc1.dat')
Experiment Getter Methods¶
The get_mvsh(), get_zfc(), and get_fc() are convenience methods for accessing specific experiment objects based on nominal values of temperature or field. For example, dset1 contains several MvsH experiments at various temperatures, and we can access the one at 2 K using the get_mvsh() method:
mvsh_2k = dset1.get_mvsh(2)
mvsh_2k.as_dict()
{'_class_': 'MvsH',
'origin_file': 'mvsh1.dat',
'temperature': 2,
'field_range': (-70000.35156, 70000.375),
'field_correction_file': '',
'scaling': ['molar', 'eicosane']}
Sample Info and Scaling Data¶
The sample_info attribute of Magnetometry objects contains information about the sample stored as a SampleInfo object. It's assumed that all files within the dataset are for the same sample, so the sample_info data is extracted from the header of the first file in the dataset.
dset1 = mp.Magnetometry(DATA_PATH / "dataset1")
dset1.sample_info.as_dict()
{'material': '[Er(TiPS2COT)I(THF)]2',
'comment': 'salmon powder in eicosane',
'mass': 19.8,
'volume': None,
'molecular_weight': 1566.22,
'size': None,
'shape': None,
'holder': 'Straw',
'holder_detail': 'Standard',
'offset': 66.27,
'eicosane_mass': 32.4,
'diamagnetic_correction': 0.0,
'_class_': 'SampleInfo'}
The data of the MvsH, ZFC, and FC objects within the dataset are automatically scaled during Magnetometry object creation based on 1) what information is found and placed in the sample_info attribute, and 2) value of the magnetic_data_scaling argument passed to the constructor. The default for this argument is "auto" which means that the data will be scaled based on the information found in the sample_info attribute. Other possible values are explained in the underlying utility function.
dset1.magnetic_data_scaling
['auto']
The individual experiment objects have a scaling attribute to record what scaling operations were done to it.
dset1.mvsh[0].scaling
['molar', 'eicosane']
We can force a dataset to have a particular scaling by passing the magnetic_data_scaling argument to the constructor.
dset1 = mp.Magnetometry(
DATA_PATH / "dataset1",
magnetic_data_scaling="mass"
)
dset1.mvsh[0].scaling
['mass']
Or we can change the scaling after Magnetometry object creation. For example, let's say the sample under investigation is a silica-shelled magnetite nanoparticle, and the sample_info.mass value represents the mass of the silica-shelled particles. We may want to use other experimental info, like TGA, to scale the data to the mass of the magnetite core. We can do this by changing the sample_info.mass value and then calling the scale_data method.
dset3 = mp.Magnetometry(DATA_PATH / "dataset3")
dset3.mvsh[0].simplified_data()['moment'].max()
70.7594230969757
dset3.mvsh[0].scaling
['mass']
So the as-read saturation magnetization from that M vs. H experiment is 70.8 emu/g. Now we can scale the data to the mass of the magnetite core.
dset3.sample_info.mass = dset3.sample_info.mass * 0.75
dset3.scale_dc_data()
dset3.mvsh[0].simplified_data()['moment'].max()
94.34589746263427
Correcting the Field in MvsH Objects for Flux Trapping¶
As discussed on the MvsH example page, the field in MvsH objects can be corrected for flux trapping by calling the MvsH.correct_field() method with the path to a file containing the Pd field calibration data. The Magnetometry class provides a convenience method for this, as it is likely that all MvsH objects within a dataset will be collected with the same sequence of field values.
The field correction can be applied during object creation by passing the true_field_correction argument to the constructor -- as with MvsH.correct_field(), this argument can be the path of the standard file or, as shown below, the name of the sequence defined in the user's Standard Calibration Library.
dset3_uncorrected = mp.Magnetometry(DATA_PATH / "dataset3")
dset3_corrected = mp.Magnetometry(
DATA_PATH / "dataset3",
true_field_correction="sequence_1"
)
fig, ax = mp.plot_mvsh(
[
dset3_uncorrected.mvsh[0],
dset3_corrected.mvsh[0],
],
normalized=True,
labels=[
"Uncorrected",
"Corrected",
],
xlim = (-0.025, 0.025),
ylim = (-0.5, 0.5),
)
Plotting¶
The Magnetometry class has some convenience methods for plotting all of the MvsH and ZFC/FC pairs within the dataset.
M vs. H¶
Magnetometry.plot_mvsh() works much the same as was described in the MvsH tutorial, but has an additional argument temperatures which filters the experiments to be plotted based on their nominal temperature.
dset1 = mp.Magnetometry(DATA_PATH / "dataset1")
fig, ax = dset1.plot_mvsh()
Now removing the 300 K experiment from the plot:
fig, ax = dset1.plot_mvsh([2, 4, 6, 8, 10, 12])
ZFC/FC¶
Magnetometry.plot_zfcfc() plots all of the pairs of ZFC and FC experiments within the dataset.
dset3 = mp.Magnetometry(DATA_PATH / "dataset3")
fig, ax = dset3.plot_zfcfc()
The fields argument can be used to filter the experiments to be plotted based on their nominal field.
fig, ax = dset3.plot_zfcfc(fields=[100])
The y_val argument changes the units of the y-axis. The default is "moment"; "chi" and "chi_t" are also available.
dset4 = mp.Magnetometry(DATA_PATH / "dataset4")
fig, ax = dset4.plot_zfcfc(y_val="chi_t")
Analyses and Serialization¶
Perhaps the most important aspect of MagnetoPy is the modular nature in which analyses can be developed and the way in which the results of those analyses can be serialized and shared. When publishing the results of an analysis of any scientific data, it is important that future readers, reviewers, and researchers have all of the information necessary to reproduce the analysis, going from the raw data to the final values and figures presented in the paper.
The next example notebook will explain how to create Analysis classes. For now, we will take a simple example class and use it to demonstrate how analyses can be performed on Magnetometry objects and how the results can be serialized and stored.
The SimpleMvsHAnalysis class takes a Magnetometry object and a temperature and returns basic information about the MvsH experiment at that temperature (e.g., the saturation magnetization and coercivity).
The following Magnetometry object has several MvsH experiments at various temperatures.
dset1 = mp.Magnetometry(DATA_PATH / "dataset1")
fig, ax = dset1.plot_mvsh()
Now let's make a list of SimpleMvsHAnalysis objects for each of the MvsH experiments in the dataset.
analyses: list[mp.SimpleMvsHAnalysis] = []
for mvsh in dset1.mvsh:
temperature = mvsh.temperature
analysis = mp.SimpleMvsHAnalysis(
dataset = dset1,
parsing_args = mp.SimpleMvsHAnalysisParsingArgs(
temperature = temperature,
segments = "auto",
),
)
analyses.append(analysis)
We can inspect the first SimpleMvsHAnalysis object to see what information it contains.
analyses[0].as_dict()
{'_class_': 'SimpleMvsHAnalysis',
'mvsh': MvsH at 2 K,
'parsing_args': SimpleMvsHAnalysisParsingArgs(temperature=2, segments='auto'),
'results': SimpleMvsHAnalysisResults(m_s=10.467101768993821, h_c=4501.3806155, m_r=8.573807168964388, moment_units='bohr magnetons/mol', field_units='Oe', segments=['forward', 'reverse'])}
Note how the MvsH object appears when converted to json. Someone reading a file containing the json representation of the SimpleMvsHAnalysis object would have access to:
- the input data: the name of the file from which the data was read, the temperature of the experiment, the scaling applied to the data (in this case a molar scaling with a correction for the eicosane matrix)
- the parsing arguments: in this case the temperature used to select the proper
MvsHobject from the dataset and the method in which segments of the M vs. H experiment were selected for analysis (in this case"auto", meaning that the analysis will use forward and/or reverse scans depending on availability) - the results of the the analysis: this include the actual values along with units and a list of analyzed segments
print(json.dumps(analyses[0].as_dict(), indent=4, default=(lambda x: x.as_dict())))
{
"_class_": "SimpleMvsHAnalysis",
"mvsh": {
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 2,
"field_range": [
-70000.35156,
70000.375
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
"parsing_args": {
"temperature": 2,
"segments": "auto",
"_class_": "SimpleMvsHAnalysisParsingArgs"
},
"results": {
"m_s": 10.467101768993821,
"h_c": 4501.3806155,
"m_r": 8.573807168964388,
"moment_units": "bohr magnetons/mol",
"field_units": "Oe",
"segments": [
"forward",
"reverse"
],
"_class_": "SimpleMvsHAnalysisResults"
}
}
All of the analyses can be added to the Magnetometry object using the add_analysis() method.
dset1.add_analysis(analyses)
When we're finished working on this dataset, we can serialize the Magnetometry object to a json file using the create_report() method. The report can be viewed here (it may help to install a json viewer extension for your browser, like this one for Chrome).
dset1.create_report(".")
Report written to dataset1.json
Alternatively, here is the json representation of the Magnetometry object as printed in the notebook:
print(dset1.as_json(indent=4))
{
"_class_": "Magnetometry",
"sample_id": "dataset1",
"files": [
{
"_class_": "DatFile",
"experiment_type": "magnetometry",
"local_path": "..\\..\\tests\\data\\dataset1\\mvsh1.dat",
"length": 2612152,
"date_created": "2020-07-11T11:07:00",
"sha512": "6fc436762a00b890eb3649eb50a885ced587781bf3b9738f04a49e768ad471f1671110f282e7be2ac2ed623a006abcc2da3914e09c165276b4bd63e06760b28f",
"experiments_in_file": [
"mvsh"
]
},
{
"_class_": "DatFile",
"experiment_type": "magnetometry",
"local_path": "..\\..\\tests\\data\\dataset1\\zfcfc1.dat",
"length": 261932,
"date_created": "2021-09-18T19:46:00",
"sha512": "f7cd14ea7ca9f3245780a608808b497b484f744774dd456a54dab73ef507a8aa75bd2383bc446af89b6aa5b57393b5f8773f77227d2e5fa5b8953980899ea64e",
"experiments_in_file": [
"zfcfc"
]
}
],
"sample_info": {
"material": "[Er(TiPS2COT)I(THF)]2",
"comment": "salmon powder in eicosane",
"mass": 19.8,
"volume": null,
"molecular_weight": 1566.22,
"size": null,
"shape": null,
"holder": "Straw",
"holder_detail": "Standard",
"offset": 66.27,
"eicosane_mass": 32.4,
"diamagnetic_correction": 0.0,
"_class_": "SampleInfo"
},
"mvsh": [
{
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 2,
"field_range": [
-70000.35156,
70000.375
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
{
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 4,
"field_range": [
-70000.28125,
70000.28906
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
{
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 6,
"field_range": [
-70000.26563,
70000.41406
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
{
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 8,
"field_range": [
-70000.27344,
70000.375
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
{
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 10,
"field_range": [
-70000.3125,
70000.46094
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
{
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 12,
"field_range": [
-70000.38672,
70000.35156
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
{
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 300,
"field_range": [
-70000.16406,
69999.8125
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
}
],
"zfc": [
{
"_class_": "ZFC",
"origin_file": "zfcfc1.dat",
"field": 100,
"temperature_range": [
5.00255632400513,
299.939453125
],
"scaling": [
"molar",
"eicosane"
]
}
],
"fc": [
{
"_class_": "FC",
"origin_file": "zfcfc1.dat",
"field": 100,
"temperature_range": [
5.00277781486511,
299.924865722656
],
"scaling": [
"molar",
"eicosane"
]
}
],
"analyses": [
{
"_class_": "SimpleMvsHAnalysis",
"mvsh": {
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 2,
"field_range": [
-70000.35156,
70000.375
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
"parsing_args": {
"temperature": 2,
"segments": "auto",
"_class_": "SimpleMvsHAnalysisParsingArgs"
},
"results": {
"m_s": 10.467101768993821,
"h_c": 4501.3806155,
"m_r": 8.573807168964388,
"moment_units": "bohr magnetons/mol",
"field_units": "Oe",
"segments": [
"forward",
"reverse"
],
"_class_": "SimpleMvsHAnalysisResults"
}
},
{
"_class_": "SimpleMvsHAnalysis",
"mvsh": {
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 4,
"field_range": [
-70000.28125,
70000.28906
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
"parsing_args": {
"temperature": 4,
"segments": "auto",
"_class_": "SimpleMvsHAnalysisParsingArgs"
},
"results": {
"m_s": 9.449626372913347,
"h_c": 3502.3714600000003,
"m_r": 4.485387018934844,
"moment_units": "bohr magnetons/mol",
"field_units": "Oe",
"segments": [
"forward",
"reverse"
],
"_class_": "SimpleMvsHAnalysisResults"
}
},
{
"_class_": "SimpleMvsHAnalysis",
"mvsh": {
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 6,
"field_range": [
-70000.26563,
70000.41406
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
"parsing_args": {
"temperature": 6,
"segments": "auto",
"_class_": "SimpleMvsHAnalysisParsingArgs"
},
"results": {
"m_s": 9.318969635074463,
"h_c": 1502.0551759999998,
"m_r": 1.2358785164429205,
"moment_units": "bohr magnetons/mol",
"field_units": "Oe",
"segments": [
"forward",
"reverse"
],
"_class_": "SimpleMvsHAnalysisResults"
}
},
{
"_class_": "SimpleMvsHAnalysis",
"mvsh": {
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 8,
"field_range": [
-70000.27344,
70000.375
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
"parsing_args": {
"temperature": 8,
"segments": "auto",
"_class_": "SimpleMvsHAnalysisParsingArgs"
},
"results": {
"m_s": 9.225003160337351,
"h_c": 355.58299255,
"m_r": 0.16487528361326864,
"moment_units": "bohr magnetons/mol",
"field_units": "Oe",
"segments": [
"forward",
"reverse"
],
"_class_": "SimpleMvsHAnalysisResults"
}
},
{
"_class_": "SimpleMvsHAnalysis",
"mvsh": {
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 10,
"field_range": [
-70000.3125,
70000.46094
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
"parsing_args": {
"temperature": 10,
"segments": "auto",
"_class_": "SimpleMvsHAnalysisParsingArgs"
},
"results": {
"m_s": 9.006286086184483,
"h_c": 1.338294357,
"m_r": 0.0183848844463972,
"moment_units": "bohr magnetons/mol",
"field_units": "Oe",
"segments": [
"forward",
"reverse"
],
"_class_": "SimpleMvsHAnalysisResults"
}
},
{
"_class_": "SimpleMvsHAnalysis",
"mvsh": {
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 12,
"field_range": [
-70000.38672,
70000.35156
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
"parsing_args": {
"temperature": 12,
"segments": "auto",
"_class_": "SimpleMvsHAnalysisParsingArgs"
},
"results": {
"m_s": 8.874340922463201,
"h_c": 7.7792181970000005,
"m_r": 0.0022978985335177027,
"moment_units": "bohr magnetons/mol",
"field_units": "Oe",
"segments": [
"forward",
"reverse"
],
"_class_": "SimpleMvsHAnalysisResults"
}
},
{
"_class_": "SimpleMvsHAnalysis",
"mvsh": {
"_class_": "MvsH",
"origin_file": "mvsh1.dat",
"temperature": 300,
"field_range": [
-70000.16406,
69999.8125
],
"field_correction_file": "",
"scaling": [
"molar",
"eicosane"
]
},
"parsing_args": {
"temperature": 300,
"segments": "auto",
"_class_": "SimpleMvsHAnalysisParsingArgs"
},
"results": {
"m_s": 0.9941340745856104,
"h_c": 4.778749943,
"m_r": 0.0009569688499523988,
"moment_units": "bohr magnetons/mol",
"field_units": "Oe",
"segments": [
"reverse"
],
"_class_": "SimpleMvsHAnalysisResults"
}
}
]
}