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
MvsH
object 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" } } ] }