Source code for physicslab.experiment.curie_temperature

"""
Curie temperature.

Find Curie temperature from magnetization vs temperature measurement.
"""


import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from scipy.optimize import curve_fit

from physicslab.curves import spontaneous_magnetization
from physicslab.utility import _ColumnsBase, get_name


[docs]def process(data): """ Bundle method. Parameter :attr:`data` must include temperature and magnetization. See :class:`Columns` for details and column names. Supplying `None` for :attr:`data` returns :class:`pandas.Series` of the same columns with values being units. :param data: Measured data. If None, return units instead :type data: pandas.DataFrame :return: Derived quantities listed in :meth:`Columns.process` or units :rtype: pandas.Series """ if data is None: from physicslab.experiment import UNITS name = UNITS curie_temperature = 'K' else: name = get_name(data) measurement = Measurement(data) curie_temperature = measurement.analyze() return pd.Series( data=(curie_temperature,), index=Columns.process(), name=name)
[docs]class Columns(_ColumnsBase): """ Bases: :class:`physicslab.utility._ColumnsBase` Column names. """ TEMPERATURE = 'T' MAGNETIZATION = 'M' HIGH_TEMPERATURE_FIT = 'high_temperature_fit' CURIE_TEMPERATURE = 'curie_temperature'
[docs] @classmethod def mandatory(cls): """ Get the current values of the mandatory column names. :rtype: set(str) """ return {cls.TEMPERATURE, cls.MAGNETIZATION}
[docs] @classmethod def process(cls): """ Get the current values of the :func:`process` output column names. :rtype: lits(str) """ return [cls.CURIE_TEMPERATURE]
[docs]class Measurement(): """ Magnetization vs temperature measurement. :param pandas.DataFrame data: Magnetization and temperature data. :raises ValueError: If :attr:`data` is missing a mandatory column """ def __init__(self, data): if not Columns.mandatory().issubset(data.columns): raise ValueError('Missing mandatory column. See Columns class.') self.data = data
[docs] def analyze(self, p0=None): """ Find Curie temperature. :param p0: Initial guess of spontaneous magnetization curve parameters. If None, the parameters will be estimated automatically, defaults to None :type p0: tuple, optional :return: Curie temperature :rtype: float """ TC, fit_data = self.fit( T=self.data[Columns.TEMPERATURE], M=self.data[Columns.MAGNETIZATION], p0=p0, high_temperature_focus=True ) self.data[Columns.HIGH_TEMPERATURE_FIT] = fit_data return TC
[docs] def fit(self, T, M, p0=None, high_temperature_focus=False): """ Fit spontaneous magnetization curve to the data. Save the fit into :data:`Columns.HIGHTEMPERATUREFIT`. :param numpy.ndarray T: Temperature :param numpy.ndarray M: Magnetization :param p0: Initial guess of spontaneous magnetization curve parameters. If None, the parameters will be estimated automatically, defaults to None :type p0: tuple, optional :param high_temperature_focus: Give high temperature data more weight, defaults to False :type high_temperature_focus: bool, optional :return: Curie temperature, fit :rtype: tuple(float, numpy.ndarray) """ p0 = self._parameter_guess(T, M) sigma = 1 / T**2 if high_temperature_focus else None popt, pcov = curve_fit( f=spontaneous_magnetization, xdata=T, ydata=M, p0=p0, sigma=sigma) TC = popt[1] fit_data = spontaneous_magnetization(T, *popt) return TC, fit_data
def _parameter_guess(self, T, M): """ Try to guess :meth:`physicslab.curves.spontaneous_magnetization` parameters. :param numpy.ndarray T: Temperature :param numpy.ndarray M: Magnetization :return: M0, TC, a, b, zero :rtype: tuple """ M0 = max(M) TC = 0.9 * max(T) # At 90 %. a = 4 b = 0.6 zero = min(M) return M0, TC, a, b, zero
[docs]def plot(data_list): """ Simple plot data and fit for all measurement at once. :param data_list: :type data_list: list[pandas.DataFrame] :return: Same objects as from :meth:`matplotlib.pyplot.subplots` :rtype: tuple[~matplotlib.figure.Figure, ~matplotlib.axes.Axes] """ fig, ax = plt.subplots(num='Curie temperature') ax.set_title('Focus on high temperature part while fitting') for data in data_list: T = data[Columns.TEMPERATURE] ax.plot(T, data[Columns.MAGNETIZATION], 'ko') ax.plot(T, data[Columns.HIGH_TEMPERATURE_FIT], 'r-') ax.set_xlabel('Temperature / K') ax.set_ylabel('Magnetization / emu') return fig, ax