From 1fbf19364e59b50ac06d4fcbfa066e9cf33be71f Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Sun, 17 Sep 2023 13:01:31 +0200 Subject: [PATCH 01/46] test update --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 35 +++++ src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 137 ++++++++++++++++++ .../qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 58 ++++++++ 3 files changed, 230 insertions(+) create mode 100644 src/sas/qtgui/Utilities/MuMagTool/MuMag.py create mode 100644 src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py create mode 100644 src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py new file mode 100644 index 0000000000..0dd2f1df24 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -0,0 +1,35 @@ +from sas.qtgui.Utilities.MuMagTool.UI.MuMagUI import Ui_MainWindow +from PySide6.QtWidgets import QWidget +from PySide6 import QtWidgets +import MuMagLib + + +def on_press_2(): + print("HELLO") + +class MuMag(QtWidgets.QMainWindow, Ui_MainWindow): + def __init__(self, parent=None): + super().__init__() + + self.setupUi(self) + self.pushButton.clicked.connect(self.import_data_button_callback) + self.pushButton_2.clicked.connect(self.plot_experimental_data_button_callback) + self.pushButton.clicked.connect(on_press_2) + + def import_data_button_callback(self): + MuMagLib.import_data_button_callback_sub() + + def plot_experimental_data_button_callback(self): + MuMagLib.plot_experimental_data() + + +def main(): + """ Show a demo of the slider """ + app = QtWidgets.QApplication([]) + form = MuMag() + form.show() + app.exec_() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py new file mode 100644 index 0000000000..e299a5473a --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -0,0 +1,137 @@ +import numpy as np +import math +import matplotlib.pyplot as plt +import matplotlib.pylab as pl +import scipy.optimize as scopt +from tkinter import * +from tkinter import filedialog +from tkinter import messagebox +from tkinter import ttk +import os +import os.path +from datetime import datetime +from PyQt6.QtWidgets import QFileDialog +import string + +##################################################################################################################### +def get_directory(): + fname = QFileDialog.getOpenFileName() + if fname: + fname = fname[0] + index = [i for i, val in enumerate(fname) if val == "/"] + fname = fname[0:index[-1]+1] + return fname + +##################################################################################################################### +# Import experimental data and get information from filenames +def import_data_button_callback_sub(): + + global q_exp + global I_exp + global sigma_exp + global B_0_exp + global Ms_exp + global Hdem_exp + global DataCounter + + #print('here') + DataCounter = 0 + # Predefine array's + #DIR = filedialog.askdirectory() + DIR = get_directory() + #print('here') + for name in os.listdir(DIR): + if name.find(".csv") != -1: + data = np.genfromtxt(DIR + '/' + name) + Lq = len(data[:, 0]) + if DataCounter == 0: + q_exp = np.array([np.zeros(Lq)]) + I_exp = np.array([np.zeros(Lq)]) + sigma_exp = np.array([np.zeros(Lq)]) + B_0_exp = np.array([np.zeros(1)]) + Ms_exp = np.array([np.zeros(1)]) + Hdem_exp = np.array([np.zeros(1)]) + DataCounter = DataCounter + 1 + else: + q_exp = np.append(q_exp, [np.zeros(Lq)], axis=0) + I_exp = np.append(I_exp, [np.zeros(Lq)], axis=0) + sigma_exp = np.append(sigma_exp, [np.zeros(Lq)], axis=0) + B_0_exp = np.append(B_0_exp, [np.zeros(1)]) + Ms_exp = np.append(Ms_exp, [np.zeros(1)]) + Hdem_exp = np.append(Hdem_exp, [np.zeros(1)]) + DataCounter = DataCounter + 1 + + #print('here') + # Load the data and sort the data + for name in os.listdir(DIR): + if name.find(".csv") != -1: + + str_name = name[0:len(name)-4] + str_name = str_name.split('_') + idx = int(str_name[0]) + B0 = float(str_name[1]) + Ms = float(str_name[2]) + Hdem = float(str_name[3]) + + data = np.genfromtxt(DIR + '/' + name) + + B_0_exp[idx-1] = B0 + Ms_exp[idx-1] = Ms + Hdem_exp[idx-1] = Hdem + q_exp[idx-1, :] = data[:, 0].T * 1e9 + I_exp[idx-1, :] = data[:, 1].T + sigma_exp[idx-1, :] = data[:, 2].T + + +################################################################################################################ +# Plot Experimental Data: Generate Figure +def plot_exp_data(q, I_exp, B_0, x_min, x_max, y_min, y_max): + + fig = plt.figure() + fig.tight_layout() + ax = fig.add_subplot(1, 1, 1) + + colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) + for k in np.arange(0, len(B_0)): + plt.plot(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label='B_0 = ' + str(B_0[k]) + ' T') + plt.plot(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) + + box = ax.get_position() + ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) + + plt.xlabel('q [1/nm]') + plt.ylabel('I_exp') + plt.xlim(x_min, x_max) + plt.ylim(y_min, y_max) + plt.yscale('log') + plt.xscale('log') + plt.grid(True, which="both", linestyle='--') + plt.legend(loc='center left', bbox_to_anchor=(1, 0.5)) + plt.show() + + + +##################################################################################################################### +# Plot Experimental Data: Set Bounds and Call Plotting Function +def plot_experimental_data(): + global q_exp + global I_exp + global sigma_exp + global B_0_exp + + if np.size(q_exp) > 1: + q_exp_min = np.amin(q_exp)*1e-9 + q_exp_min = 10**(np.floor(np.log10(q_exp_min))) * np.floor(q_exp_min/10**(np.floor(np.log10(q_exp_min)))) + + q_exp_max = np.amax(q_exp)*1e-9 + q_exp_max = 10**(np.floor(np.log10(q_exp_max))) * np.ceil(q_exp_max/10**(np.floor(np.log10(q_exp_max)))) + + I_exp_min = np.amin(I_exp) + I_exp_min = 10**(np.floor(np.log10(I_exp_min))) * np.floor(I_exp_min/10**(np.floor(np.log10(I_exp_min)))) + + I_exp_max = np.amax(I_exp) + I_exp_max = 10 ** (np.floor(np.log10(I_exp_max))) * np.ceil(I_exp_max / 10 ** (np.floor(np.log10(I_exp_max)))) + + plot_exp_data(q_exp*1e-9, I_exp, B_0_exp*1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) + else: + messagebox.showerror(title="Error!", message="No experimental data available! Please import experimental data!") \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui new file mode 100644 index 0000000000..54c33a64cd --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -0,0 +1,58 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + 20 + 20 + 113 + 32 + + + + Import Data + + + + + + 140 + 20 + 113 + 32 + + + + Plot Data + + + + + + + 0 + 0 + 800 + 22 + + + + + + + + From b2ea0642894c13b3c507a5f380545cda40fc3d77 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Sun, 17 Sep 2023 14:50:08 +0200 Subject: [PATCH 02/46] connected MuMag Fitter to the main sasview gui in MainWindow & GuiManager --- src/sas/qtgui/MainWindow/GuiManager.py | 8 ++++++++ src/sas/qtgui/MainWindow/UI/MainWindowUI.ui | 8 +++++++- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 2 +- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/sas/qtgui/MainWindow/GuiManager.py b/src/sas/qtgui/MainWindow/GuiManager.py index 5e13147d41..05ca07f834 100644 --- a/src/sas/qtgui/MainWindow/GuiManager.py +++ b/src/sas/qtgui/MainWindow/GuiManager.py @@ -33,6 +33,7 @@ from sas.qtgui.Utilities.ResultPanel import ResultPanel from sas.qtgui.Utilities.OrientationViewer.OrientationViewer import show_orientation_viewer from sas.qtgui.Utilities.HidableDialog import hidable_dialog +from sas.qtgui.Utilities.MuMagTool.MuMag import MuMag from sas.qtgui.Utilities.Reports.ReportDialog import ReportDialog from sas.qtgui.Utilities.Preferences.PreferencesPanel import PreferencesPanel @@ -191,6 +192,7 @@ def addWidgets(self): self.SLDCalculator = SldPanel(self) self.DVCalculator = DensityPanel(self) self.KIESSIGCalculator = KiessigPanel(self) + self.MuMag_Fitter = MuMag(self) self.SlitSizeCalculator = SlitSizeCalculator(self) self.GENSASCalculator = GenericScatteringCalculator(self) self.ResolutionCalculator = ResolutionCalculatorPanel(self) @@ -688,6 +690,7 @@ def addTriggers(self): self._workspace.actionSLD_Calculator.triggered.connect(self.actionSLD_Calculator) self._workspace.actionDensity_Volume_Calculator.triggered.connect(self.actionDensity_Volume_Calculator) self._workspace.actionKeissig_Calculator.triggered.connect(self.actionKiessig_Calculator) + self._workspace.actionMuMag_Fitter.triggered.connect(self.actionMuMag_Fitter) #self._workspace.actionKIESSING_Calculator.triggered.connect(self.actionKIESSING_Calculator) self._workspace.actionSlit_Size_Calculator.triggered.connect(self.actionSlit_Size_Calculator) self._workspace.actionSAS_Resolution_Estimator.triggered.connect(self.actionSAS_Resolution_Estimator) @@ -979,6 +982,11 @@ def actionKiessig_Calculator(self): """ self.KIESSIGCalculator.show() + def actionMuMag_Fitter(self): + """ + """ + self.MuMag_Fitter.show() + def actionSlit_Size_Calculator(self): """ """ diff --git a/src/sas/qtgui/MainWindow/UI/MainWindowUI.ui b/src/sas/qtgui/MainWindow/UI/MainWindowUI.ui index 44b176e8aa..d66115c3e7 100755 --- a/src/sas/qtgui/MainWindow/UI/MainWindowUI.ui +++ b/src/sas/qtgui/MainWindow/UI/MainWindowUI.ui @@ -24,7 +24,7 @@ 0 0 915 - 20 + 22 @@ -91,6 +91,7 @@ + @@ -619,6 +620,11 @@ Preferences... + + + MuMag Fitter + + diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 0dd2f1df24..428d095118 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -1,7 +1,7 @@ from sas.qtgui.Utilities.MuMagTool.UI.MuMagUI import Ui_MainWindow from PySide6.QtWidgets import QWidget from PySide6 import QtWidgets -import MuMagLib +from sas.qtgui.Utilities.MuMagTool import MuMagLib def on_press_2(): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index e299a5473a..20cc209cbf 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -10,7 +10,7 @@ import os import os.path from datetime import datetime -from PyQt6.QtWidgets import QFileDialog +from PySide6.QtWidgets import QFileDialog import string ##################################################################################################################### From ca14f1d5d80ee87572683dc857742ae1d64ec965 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:31:33 +0200 Subject: [PATCH 03/46] next update of the UI of MuMag adding buttons and text edit fields, change of button names --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 8 +- .../qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 206 +++++++++++++++++- 2 files changed, 206 insertions(+), 8 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 428d095118..fe3adba444 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -4,17 +4,13 @@ from sas.qtgui.Utilities.MuMagTool import MuMagLib -def on_press_2(): - print("HELLO") - class MuMag(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super().__init__() self.setupUi(self) - self.pushButton.clicked.connect(self.import_data_button_callback) - self.pushButton_2.clicked.connect(self.plot_experimental_data_button_callback) - self.pushButton.clicked.connect(on_press_2) + self.ImportDataButton.clicked.connect(self.import_data_button_callback) + self.PlotDataButton.clicked.connect(self.plot_experimental_data_button_callback) def import_data_button_callback(self): MuMagLib.import_data_button_callback_sub() diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui index 54c33a64cd..4729a32303 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -14,7 +14,7 @@ MainWindow - + 20 @@ -27,7 +27,7 @@ Import Data - + 140 @@ -40,6 +40,208 @@ Plot Data + + + + 10 + 120 + 131 + 32 + + + + Simple Fit + + + + + + 10 + 160 + 131 + 32 + + + + Compare Results + + + + + + 12 + 200 + 131 + 32 + + + + Save Result + + + + + + 250 + 130 + 104 + 31 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">0.6</p></body></html> + + + + + + 390 + 200 + 104 + 31 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">20</p></body></html> + + + + + + 250 + 200 + 104 + 31 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5</p></body></html> + + + + + + 530 + 130 + 104 + 31 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">75</p></body></html> + + + + + + 530 + 200 + 104 + 31 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">200</p></body></html> + + + + + + 170 + 210 + 60 + 16 + + + + A [pJ/m]: + + + + + + 280 + 180 + 60 + 16 + + + + min + + + + + + 420 + 180 + 60 + 16 + + + + max + + + + + + 550 + 180 + 60 + 16 + + + + samples + + + + + + 150 + 140 + 91 + 16 + + + + q_max [1/nm] + + + + + + 390 + 140 + 121 + 16 + + + + mu_0*H_min [mT] + + From dca1714e85cefb8afdf715eadfc5e488e9298a28 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:06:53 +0200 Subject: [PATCH 04/46] Added python scripts including functionalities for perpendicular and parallel scattering geometry --- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 148 ++++++++- .../Utilities/MuMagTool/MuMagParallelGeo.py | 248 ++++++++++++++ .../MuMagTool/MuMagPerpendicularGeo.py | 309 ++++++++++++++++++ 3 files changed, 704 insertions(+), 1 deletion(-) create mode 100644 src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py create mode 100644 src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 20cc209cbf..c264b768b2 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -134,4 +134,150 @@ def plot_experimental_data(): plot_exp_data(q_exp*1e-9, I_exp, B_0_exp*1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) else: - messagebox.showerror(title="Error!", message="No experimental data available! Please import experimental data!") \ No newline at end of file + messagebox.showerror(title="Error!", message="No experimental data available! Please import experimental data!") + + +####################################################################################################################### + + + + + +####################################################################################################################### + +def SimpleFit_FitButtonCallback(): + + global q_exp + global I_exp + global sigma_exp + global B_0_exp + global Ms_exp + global Hdem_exp + + global SimpleFit_q_exp + global SimpleFit_I_exp + global SimpleFit_sigma_exp + global SimpleFit_B_0_exp + global SimpleFit_Ms_exp + global SimpleFit_Hdem_exp + global SimpleFit_I_fit + global SimpleFit_A + global SimpleFit_chi_q + global SimpleFit_S_H_fit + global SimpleFit_S_M_fit + global SimpleFit_I_res_fit + global SimpleFit_A_opt + global SimpleFit_chi_q_opt + global SimpleFit_A_sigma + global SimpleFit_SANSgeometry + + if np.size(q_exp) > 1: + q_max = float(SimpleFitqmaxEntry.get()) + H_min = float(SimpleFitHminEntry.get()) + A1 = float(SimpleFitA1Entry.get()) + A2 = float(SimpleFitA2Entry.get()) + A_N = int(SimpleFitANEntry.get()) + SANSgeometry = SANSgeometryVariable.get() + + # search index for q_max + q_diff = (q_exp[0, :]*1e-9 - q_max)**2 + K_q = np.where(q_diff == np.min(q_diff)) + K_q = K_q[0][0] + + # search index for H_min + H_diff = (B_0_exp - H_min)**2 + K_H = np.where(H_diff == np.min(H_diff)) + K_H = K_H[0][0] + + # apply the restrictions + mu_0 = 4*math.pi*1e-7 + q = q_exp[K_H:, 0:K_q] + I_exp_red = I_exp[K_H:, 0:K_q] + sigma = sigma_exp[K_H:, 0:K_q] + H_0 = np.outer(B_0_exp[K_H:]/mu_0 * 1e-3, np.ones(K_q)) + H_dem = np.outer(Hdem_exp[K_H:], np.ones(K_q))/mu_0 * 1e-3 + Ms = np.outer(Ms_exp[K_H:], np.ones(K_q))/mu_0 * 1e-3 + + # Least Squares Fit in case of perpendicular SANS geometry + if SANSgeometry == "perpendicular": + A_1 = A1 * 1e-12 + A_2 = A2 * 1e-12 + A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M \ + = SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + + A_opt = OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + + I_opt = SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + + d2chi_dA2 = FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + + N_mu = len(I_exp_red[0, :]) + N_nu = len(I_exp_red[:, 0]) + A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + + PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty * 1e12) + + # Save to global Variables + SimpleFit_q_exp = q + SimpleFit_I_exp = I_exp_red + SimpleFit_sigma_exp = sigma + SimpleFit_B_0_exp = B_0_exp[K_H:] + SimpleFit_Ms_exp = Ms_exp[K_H:] + SimpleFit_Hdem_exp = Hdem_exp[K_H:] + SimpleFit_I_fit = I_opt + SimpleFit_A = A + SimpleFit_chi_q = chi_q + SimpleFit_S_H_fit = S_H_opt + SimpleFit_S_M_fit = S_M_opt + SimpleFit_I_res_fit = I_res_opt + SimpleFit_A_opt = A_opt + SimpleFit_chi_q_opt = chi_q_opt + SimpleFit_A_sigma = A_Uncertainty + SimpleFit_SANSgeometry = "perpendicular" + + elif SANSgeometry == "parallel ": + A_1 = A1 * 1e-12 + A_2 = A2 * 1e-12 + A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ + = SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + + A_opt = OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = LSQ_PAR(q, I_exp_red, sigma, + Ms, H_0, + H_dem, + A_opt) + + I_opt = SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + + d2chi_dA2 = FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + N_mu = len(I_exp_red[0, :]) + N_nu = len(I_exp_red[:, 0]) + A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + + PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, + I_res_opt, S_H_opt, A_Uncertainty * 1e12) + + # Save to global Variables + SimpleFit_q_exp = q + SimpleFit_I_exp = I_exp_red + SimpleFit_sigma_exp = sigma + SimpleFit_B_0_exp = B_0_exp[K_H:] + SimpleFit_Ms_exp = Ms_exp[K_H:] + SimpleFit_Hdem_exp = Hdem_exp[K_H:] + SimpleFit_I_fit = I_opt + SimpleFit_A = A + SimpleFit_chi_q = chi_q + SimpleFit_S_H_fit = S_H_opt + SimpleFit_I_res_fit = I_res_opt + SimpleFit_A_opt = A_opt + SimpleFit_chi_q_opt = chi_q_opt + SimpleFit_A_sigma = A_Uncertainty + SimpleFit_SANSgeometry = "parallel" + + else: + messagebox.showerror(title="Error!", + message="No experimental Data available! Please import experimental data!") + + + diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py new file mode 100644 index 0000000000..3de0bc48e9 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py @@ -0,0 +1,248 @@ +import numpy as np +import scipy.optimize as scopt +import matplotlib.pyplot as plt + + +#################################################################################################### +# Functions for the analysis of parallel SANS ###################################################### +#################################################################################################### +# Lorentzian Model for the generation of clean synthetic test data for perpendicular SANS geometry +def LorentzianModelPAR(q, A, M_s, H_0, H_dem, a_H, l_c): + + # All inputs in SI-units + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 2 + + # Lorentzian functions for S_H, S_M + S_H = a_H**2/(1 + q**2 * l_c**2)**2 + + # Magnetic SANS cross sections + I_M = R_H * S_H + + # Model of I_res + idx = np.argmax(H_0[:, 1]) + I_res = 0.9 * I_M[idx, :] + + # Total SANS cross section + I_sim = I_res + I_M + sigma = 0 * I_sim + 1 + + return I_sim, sigma, S_H, I_res + +#################################################################################################### +# Least squares method for parallel SANS geometry +def LSQ_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A): + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 2 + + # Non-negative least squares loop + L_nu = len(q[1, :]) + S_H = np.zeros((1, L_nu)) + I_res = np.zeros((1, L_nu)) + sigma_S_H = np.zeros((1, L_nu)) + sigma_I_res = np.zeros((1, L_nu)) + for nu in np.arange(0, L_nu): + A = np.array([1/sigma[:, nu], R_H[:, nu]/sigma[:, nu]]).T + y = I_exp[:, nu]/sigma[:, nu] + c = np.matmul(A.T, y) + H = np.dot(A.T, A) + + # non-negative linear least squares + x = scopt.nnls(H, c) + I_res[0, nu] = x[0][0] + S_H[0, nu] = x[0][1] + + Gamma = np.linalg.inv(np.dot(H.T, H)) + sigma_I_res[0, nu] = Gamma[0, 0] + sigma_S_H[0, nu] = Gamma[1, 1] + + I_sim = I_res + R_H * S_H + s_q = np.mean(((I_exp - I_sim)/sigma)**2, axis=0) + + sigma_S_H = np.sqrt(np.abs(sigma_S_H * s_q)) + sigma_I_res = np.sqrt(np.abs(sigma_I_res * s_q)) + + chi_q = np.mean(s_q) + + return chi_q, I_res, S_H, sigma_I_res, sigma_S_H + +#################################################################################################### +# Least squares method for parallel SANS geometry +def chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A): + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 2 + + # Non-negative least squares loop + L_nu = len(q[0, :]) + S_H = np.zeros((1, L_nu)) + I_res = np.zeros((1, L_nu)) + for nu in np.arange(0, L_nu): + A = np.array([1/sigma[:, nu], R_H[:, nu]/sigma[:, nu]]).T + y = I_exp[:, nu]/sigma[:, nu] + + c = np.matmul(A.T, y) + H = np.dot(A.T, A) + + # non-negative linear least squares + x = scopt.nnls(H, c) + I_res[0, nu] = x[0][0] + S_H[0, nu] = x[0][1] + + I_sim = I_res + R_H * S_H + s_q = np.mean(((I_exp - I_sim)/sigma)**2, axis=0) + chi_q = np.mean(s_q) + + return chi_q + +#################################################################################################### +# Sweep over Exchange Stiffness A for parallel SANS geometry +def SweepA_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_1, A_2, A_N): + + A = np.linspace(A_1, A_2, A_N) + chi_q = np.zeros(len(A)) + for k in np.arange(0, len(A)): + chi_q[k], I_res, S_H, sigma_I_res, sigma_S_H = LSQ_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A[k]) + + min_idx = np.argmin(chi_q) + A_opt = A[min_idx] + + chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = LSQ_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_opt) + + return A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H + +#################################################################################################### +# find optimal Exchange Stiffness A for parallel SANS geometry using fsolve function (slow and very accurate) +def OptimA_fsolve_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_initial): + + def func(A): + return chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A) + + return scopt.fsolve(func, A_initial) + +#################################################################################################### +# find optimal Exchange Stiffness A for parallel SANS geometry using successive parabolic interpolation (fast and accurate) +# implemented as Jarratt's Method +def OptimA_SPI_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_1, eps): + + delta = A_1 * 0.1 + + x_1 = A_1 - delta + x_2 = A_1 + x_3 = A_1 + delta + + y_1 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, x_1) + y_2 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, x_2) + y_3 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, x_3) + + x_4 = x_3 + 0.5 * ((x_2 - x_3)**2 * (y_3 - y_1) + (x_1 - x_3)**2 * (y_2 - y_3))/((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) + while np.abs(2 * (x_4 - x_3)/(x_4 + x_3)) > eps: + + x_1 = x_2 + x_2 = x_3 + x_3 = x_4 + + y_1 = y_2 + y_2 = y_3 + y_3 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, x_3) + + x_4 = x_3 + 0.5 * ((x_2 - x_3) ** 2 * (y_3 - y_1) + (x_1 - x_3) ** 2 * (y_2 - y_3)) / ((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) + + return x_4 + +#################################################################################################### +# 1D-Cross-Section of the parallel model +def SANS_Model_PAR(q, S_H, I_res, M_s, H_0, H_dem, A): + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 2 + + return I_res + R_H * S_H + +#################################################################################################### +# Plot Fitting results of simple fit +def PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, A_Uncertainty): + + fig, axs = plt.subplots(2, 2) + A_uncertainty_str = str(A_Uncertainty) + A_opt_str = str(A_opt * 1e12) + axs[0, 0].set_title('A_opt = (' + A_opt_str[0:5] + ' +/- ' + A_uncertainty_str[0:4] + ') pJ/m') + axs[0, 0].plot(A * 1e12, chi_q) + axs[0, 0].plot(A_opt * 1e12, chi_q_opt, 'o') + axs[0, 0].grid() + axs[0, 0].set_xlim([min(A * 1e12), max(A * 1e12)]) + axs[0, 0].set(xlabel='A [pJ/m]', ylabel='chi^2') + + axs[0, 1].plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') + axs[0, 1].set_yscale('log') + axs[0, 1].set_xscale('log') + axs[0, 1].grid() + axs[0, 1].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axs[0, 1].set(xlabel='q [1/nm]', ylabel='I_res') + axs[0, 1].legend() + + axs[1, 0].plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') + axs[1, 0].set_yscale('log') + axs[1, 0].set_xscale('log') + axs[1, 0].grid() + axs[1, 0].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axs[1, 0].set(xlabel='q [1/nm]', ylabel='S_H') + axs[1, 0].legend() + + plt.tight_layout() + plt.show() + +#################################################################################################### +def PlotSweepFitResultPAR(q_max_mat, H_min_mat, A_opt_mat): + fig = plt.figure() + ax = plt.axes(projection='3d') + ax.plot_surface(q_max_mat * 1e-9, H_min_mat, A_opt_mat * 1e12) + ax.set(xlabel='q_max [1/nm]', ylabel='H_min [mT]', zlabel='A_opt [pJ/m]') + ax.grid() + + plt.tight_layout() + plt.show() + +#################################################################################################### +# Second Order Derivative of chi-square function via Finite Differences +def FDM2Ord_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_opt): + + p = 0.01 + dA = A_opt * p + A1 = A_opt - 2*dA + A2 = A_opt - 1*dA + A3 = A_opt + A4 = A_opt + 1*dA + A5 = A_opt + 2*dA + + chi1 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A1) + chi2 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A2) + chi3 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A3) + chi4 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A4) + chi5 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A5) + + d2_chi_dA2 = (-chi1 + 16 * chi2 - 30 * chi3 + 16 * chi4 - chi5)/(12 * dA**2) + + return d2_chi_dA2 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py new file mode 100644 index 0000000000..0605f43d0c --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py @@ -0,0 +1,309 @@ +import numpy as np +import scipy.optimize as scopt +import matplotlib.pyplot as plt + + +#################################################################################################### +# Functions for the analysis of perpendicular SANS ################################################# +#################################################################################################### +# Lorentzian Model for the generation of clean synthetic test data for perpendicular SANS geometry +def LorentzianModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c): + + # All inputs in SI-units + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2*A)/(mu_0 * M_s * H_i)) + H_eff = H_i * (1 + l_H**2 * q**2) + p = M_s/H_eff + R_H = p**2 / 4 * (2 + 1/np.sqrt(1 + p)) + R_M = (np.sqrt(1 + p) - 1)/2 + + # Lorentzian functions for S_H, S_M + S_H = a_H**2/(1 + q**2 * l_c**2)**2 + S_M = a_M**2/(1 + q**2 * l_c**2)**2 + + # Magnetic SANS cross sections + I_M = R_H * S_H + R_M * S_M + + # Model of I_res + idx = np.argmax(H_0[:, 1]) + print(H_0[idx, 1]*mu_0*1e3) + I_res = 0.9 * I_M[idx, :] + + # Total SANS cross section + I_sim = I_res + I_M + sigma = 0 * I_sim + 1 + + return I_sim, sigma, S_H, S_M, I_res + +#################################################################################################### +# Lorentzian Model for the generation of noisy synthetic test data for perpendicular SANS geometry +def LorentzianNoisyModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c, beta): + + # All inputs in SI-units + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2*A)/(mu_0 * M_s * H_i)) + H_eff = H_i * (1 + l_H**2 * q**2) + p = M_s/H_eff + R_H = p**2 / 4 * (2 + 1/np.sqrt(1 + p)) + R_M = (np.sqrt(1 + p) - 1)/2 + + # Lorentzian functions for S_H, S_M + S_H = a_H**2/(1 + q**2 * l_c**2)**2 + S_M = a_M**2/(1 + q**2 * l_c**2)**2 + + # Magnetic SANS cross sections + I_M = R_H * S_H + R_M * S_M + + # Model of I_res + idx = np.argmax(H_0[:, 1]) + I_res = 0.9 * I_M[idx, :] + + # Model of standard deviation + sigma = beta * (I_res + I_M) + + # Total SANS cross section + I_sim = I_res + I_M + sigma * np.random.randn(len(sigma[:, 1]), len(sigma[1, :])) + + return I_sim, sigma, S_H, S_M, I_res + +#################################################################################################### +# Least squares method for perpendicular SANS geometry +def LSQ_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A): + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) + R_M = (np.sqrt(1 + p) - 1) / 2 + + # Non-negative least squares loop + L_nu = len(q[1, :]) + S_H = np.zeros((1, L_nu)) + S_M = np.zeros((1, L_nu)) + I_res = np.zeros((1, L_nu)) + sigma_S_H = np.zeros((1, L_nu)) + sigma_S_M = np.zeros((1, L_nu)) + sigma_I_res = np.zeros((1, L_nu)) + for nu in np.arange(0, L_nu): + A = np.array([1/sigma[:, nu], R_H[:, nu]/sigma[:, nu], R_M[:, nu]/sigma[:, nu]]).T + y = I_exp[:, nu]/sigma[:, nu] + c = np.matmul(A.T, y) + H = np.dot(A.T, A) + + # non-negative linear least squares + x = scopt.nnls(H, c) + I_res[0, nu] = x[0][0] + S_H[0, nu] = x[0][1] + S_M[0, nu] = x[0][2] + + Gamma = np.linalg.inv(np.dot(H.T, H)) + sigma_I_res[0, nu] = Gamma[0, 0] + sigma_S_H[0, nu] = Gamma[1, 1] + sigma_S_M[0, nu] = Gamma[2, 2] + + I_sim = I_res + R_H * S_H + R_M * S_M + s_q = np.mean(((I_exp - I_sim)/sigma)**2, axis=0) + + sigma_S_H = np.sqrt(np.abs(sigma_S_H * s_q)) + sigma_S_M = np.sqrt(np.abs(sigma_S_M * s_q)) + sigma_I_res = np.sqrt(np.abs(sigma_I_res * s_q)) + + chi_q = np.mean(s_q) + + return chi_q, I_res, S_H, S_M, sigma_I_res, sigma_S_H, sigma_S_M + +#################################################################################################### +# Least squares method for perpendicular SANS geometry +def chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A): + + # Micromagnetic Model + A = abs(A) + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) + R_M = (np.sqrt(1 + p) - 1) / 2 + + # Non-negative least squares loop + L_nu = len(q[0, :]) + S_H = np.zeros((1, L_nu)) + S_M = np.zeros((1, L_nu)) + I_res = np.zeros((1, L_nu)) + for nu in np.arange(0, L_nu): + A = np.array([1/sigma[:, nu], R_H[:, nu]/sigma[:, nu], R_M[:, nu]/sigma[:, nu]]).T + y = I_exp[:, nu]/sigma[:, nu] + + c = np.matmul(A.T, y) + H = np.dot(A.T, A) + + # non-negative linear least squares + x = scopt.nnls(H, c) + I_res[0, nu] = x[0][0] + S_H[0, nu] = x[0][1] + S_M[0, nu] = x[0][2] + + I_sim = I_res + R_H * S_H + R_M * S_M + s_q = np.mean(((I_exp - I_sim)/sigma)**2, axis=0) + chi_q = np.mean(s_q) + + return chi_q + +#################################################################################################### +# Sweep over Exchange Stiffness A for perpendicular SANS geometry +def SweepA_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_1, A_2, A_N): + + A = np.linspace(A_1, A_2, A_N) + chi_q = np.zeros(len(A)) + for k in np.arange(0, len(A)): + chi_q[k], I_res, S_H, S_M, sigma_I_res, sigma_S_H, sigma_S_M = LSQ_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A[k]) + + min_idx = np.argmin(chi_q) + A_opt = A[min_idx] + + chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = LSQ_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_opt) + + return A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M + +#################################################################################################### +# find optimal Exchange Stiffness A for perpendicular SANS geometry using fsolve function (slow and very accurate) +def OptimA_fsolve_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_initial): + + def func(A): + return chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A) + + return scopt.fsolve(func, A_initial) + +#################################################################################################### +# find optimal Exchange Stiffness A for perpendicular SANS geometry using +# successive parabolic interpolation (fast and accurate) +# implemented as Jarratt's Method +def OptimA_SPI_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_1, eps): + + delta = A_1 * 0.1 + + x_1 = A_1 - delta + x_2 = A_1 + x_3 = A_1 + delta + + y_1 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, x_1) + y_2 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, x_2) + y_3 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, x_3) + + x_4 = x_3 + 0.5 * ((x_2 - x_3)**2 * (y_3 - y_1) + (x_1 - x_3)**2 * (y_2 - y_3))/((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) + while np.abs(2 * (x_4 - x_3)/(x_4 + x_3)) > eps: + + x_1 = x_2 + x_2 = x_3 + x_3 = x_4 + + y_1 = y_2 + y_2 = y_3 + y_3 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, x_3) + + x_4 = x_3 + 0.5 * ((x_2 - x_3) ** 2 * (y_3 - y_1) + (x_1 - x_3) ** 2 * (y_2 - y_3)) / ((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) + + return x_4 + +#################################################################################################### +# 1D-Cross-Section of the perendicular model +def SANS_Model_PERP(q, S_H, S_M, I_res, M_s, H_0, H_dem, A): + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) + R_M = (np.sqrt(1 + p) - 1) / 2 + + return I_res + R_H * S_H + R_M * S_M + +#################################################################################################### +# Plot Fitting results of simple fit +def PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty): + + fig, axs = plt.subplots(2, 2) + + if A_Uncertainty < 1e-4: + A_Uncertainty = 0 + + A_uncertainty_str = str(A_Uncertainty) + + A_opt_str = str(A_opt * 1e12) + axs[0, 0].set_title('A_opt = (' + A_opt_str[0:5] + ' +/- ' + A_uncertainty_str[0:4] + ') pJ/m') + axs[0, 0].plot(A * 1e12, chi_q) + axs[0, 0].plot(A_opt * 1e12, chi_q_opt, 'o') + axs[0, 0].grid() + axs[0, 0].set_xlim([min(A * 1e12), max(A * 1e12)]) + axs[0, 0].set(xlabel='A [pJ/m]', ylabel='chi^2') + + axs[0, 1].plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') + axs[0, 1].set_yscale('log') + axs[0, 1].set_xscale('log') + axs[0, 1].grid() + axs[0, 1].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axs[0, 1].set(xlabel='q [1/nm]', ylabel='I_res') + axs[0, 1].legend() + + axs[1, 0].plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') + axs[1, 0].set_yscale('log') + axs[1, 0].set_xscale('log') + axs[1, 0].grid() + axs[1, 0].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axs[1, 0].set(xlabel='q [1/nm]', ylabel='S_H') + axs[1, 0].legend() + + axs[1, 1].plot(q[0, :] * 1e-9, S_M_opt[0, :], label='fit') + axs[1, 1].set_yscale('log') + axs[1, 1].set_xscale('log') + axs[1, 1].grid() + axs[1, 1].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axs[1, 1].set(xlabel='q [1/nm]', ylabel='S_M') + axs[1, 1].legend() + + plt.tight_layout() + plt.show() + +#################################################################################################### +def PlotSweepFitResultPERP(q_max_mat, H_min_mat, A_opt_mat): + fig = plt.figure() + ax = plt.axes(projection='3d') + ax.plot_surface(q_max_mat * 1e-9, H_min_mat, A_opt_mat * 1e12) + ax.set(xlabel='q_max [1/nm]', ylabel='H_min [mT]', zlabel='A_opt [pJ/m]') + ax.grid() + + plt.tight_layout() + plt.show() + +#################################################################################################### +# Second Order Derivative of chi-square function via Finite Differences +def FDM2Ord_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_opt): + + p = 0.001 + dA = A_opt * p + A1 = A_opt - 2*dA + A2 = A_opt - 1*dA + A3 = A_opt + A4 = A_opt + 1*dA + A5 = A_opt + 2*dA + + chi1 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A1) + chi2 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A2) + chi3 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A3) + chi4 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A4) + chi5 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A5) + + d2_chi_dA2 = (-chi1 + 16 * chi2 - 30 * chi3 + 16 * chi4 - chi5)/(12 * dA**2) + + return d2_chi_dA2 \ No newline at end of file From 28559db38a41828621150adcce4b4223778c3866 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:12:38 +0200 Subject: [PATCH 05/46] added selector in UI for selction of the perpendicular or parallel scattering geometry --- .../qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui index 4729a32303..e35b993643 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -242,6 +242,26 @@ p, li { white-space: pre-wrap; } mu_0*H_min [mT] + + + + 270 + 20 + 171 + 26 + + + + + perpendicular + + + + + parallel + + + From f78d9ffa4a950ffc4841fa995238ebcd8bcbf519 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:54:20 +0200 Subject: [PATCH 06/46] added functionality to the simple fit button --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 11 +++++ src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 44 ++++++++++--------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index fe3adba444..1113fc790e 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -11,6 +11,7 @@ def __init__(self, parent=None): self.setupUi(self) self.ImportDataButton.clicked.connect(self.import_data_button_callback) self.PlotDataButton.clicked.connect(self.plot_experimental_data_button_callback) + self.SimpleFitButton.clicked.connect(self.simple_fit_button_callback) def import_data_button_callback(self): MuMagLib.import_data_button_callback_sub() @@ -18,6 +19,16 @@ def import_data_button_callback(self): def plot_experimental_data_button_callback(self): MuMagLib.plot_experimental_data() + def simple_fit_button_callback(self): + q_max = float(self.qMaxEdit.toPlainText()) + H_min = float(self.HminEdit.toPlainText()) + A1 = float(self.AMinEdit.toPlainText()) + A2 = float(self.AMaxEdit.toPlainText()) + A_N = int(self.ASamplesEdit.toPlainText()) + SANSgeometry = self.ScatteringGeometrySelect.currentText() + + MuMagLib.SimpleFit_FitButtonCallback(q_max, H_min, A1, A2, A_N, SANSgeometry) + def main(): """ Show a demo of the slider """ diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index c264b768b2..ff630981b9 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -13,6 +13,10 @@ from PySide6.QtWidgets import QFileDialog import string +import MuMagPerpendicularGeo +import MuMagParallelGeo + + ##################################################################################################################### def get_directory(): fname = QFileDialog.getOpenFileName() @@ -145,7 +149,7 @@ def plot_experimental_data(): ####################################################################################################################### -def SimpleFit_FitButtonCallback(): +def SimpleFit_FitButtonCallback(q_max, H_min, A1, A2, A_N, SANSgeometry): global q_exp global I_exp @@ -172,12 +176,12 @@ def SimpleFit_FitButtonCallback(): global SimpleFit_SANSgeometry if np.size(q_exp) > 1: - q_max = float(SimpleFitqmaxEntry.get()) - H_min = float(SimpleFitHminEntry.get()) - A1 = float(SimpleFitA1Entry.get()) - A2 = float(SimpleFitA2Entry.get()) - A_N = int(SimpleFitANEntry.get()) - SANSgeometry = SANSgeometryVariable.get() + #q_max = float(SimpleFitqmaxEntry.get()) + #H_min = float(SimpleFitHminEntry.get()) + #A1 = float(SimpleFitA1Entry.get()) + #A2 = float(SimpleFitA2Entry.get()) + #A_N = int(SimpleFitANEntry.get()) + #SANSgeometry = SANSgeometryVariable.get() # search index for q_max q_diff = (q_exp[0, :]*1e-9 - q_max)**2 @@ -203,20 +207,20 @@ def SimpleFit_FitButtonCallback(): A_1 = A1 * 1e-12 A_2 = A2 * 1e-12 A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M \ - = SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + = MuMagPerpendicularGeo.SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) - A_opt = OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = MuMagPerpendicularGeo.LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - I_opt = SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + I_opt = MuMagPerpendicularGeo.SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) - d2chi_dA2 = FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + d2chi_dA2 = MuMagPerpendicularGeo.FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) N_mu = len(I_exp_red[0, :]) N_nu = len(I_exp_red[:, 0]) A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) - PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty * 1e12) + MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty * 1e12) # Save to global Variables SimpleFit_q_exp = q @@ -240,22 +244,22 @@ def SimpleFit_FitButtonCallback(): A_1 = A1 * 1e-12 A_2 = A2 * 1e-12 A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ - = SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) - A_opt = OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = LSQ_PAR(q, I_exp_red, sigma, + A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = MuMagParallelGeo.LSQ_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - I_opt = SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + I_opt = MuMagParallelGeo.SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) - d2chi_dA2 = FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + d2chi_dA2 = MuMagParallelGeo.FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) N_mu = len(I_exp_red[0, :]) N_nu = len(I_exp_red[:, 0]) A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) - PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, + MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, A_Uncertainty * 1e12) # Save to global Variables @@ -279,5 +283,3 @@ def SimpleFit_FitButtonCallback(): messagebox.showerror(title="Error!", message="No experimental Data available! Please import experimental data!") - - From a66411f9feafb1882eda7d7b721b535c734a8f38 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:05:42 +0200 Subject: [PATCH 07/46] change of the global variable coding style to class coding style, so no global variables anymore --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 9 +- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 511 +++++++++--------- 2 files changed, 250 insertions(+), 270 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 1113fc790e..faeb6e4b08 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -7,17 +7,17 @@ class MuMag(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super().__init__() - + self.MuMagLib_obj = MuMagLib.MuMagLib() self.setupUi(self) self.ImportDataButton.clicked.connect(self.import_data_button_callback) self.PlotDataButton.clicked.connect(self.plot_experimental_data_button_callback) self.SimpleFitButton.clicked.connect(self.simple_fit_button_callback) def import_data_button_callback(self): - MuMagLib.import_data_button_callback_sub() + self.MuMagLib_obj.import_data_button_callback_sub() def plot_experimental_data_button_callback(self): - MuMagLib.plot_experimental_data() + self.MuMagLib_obj.plot_experimental_data() def simple_fit_button_callback(self): q_max = float(self.qMaxEdit.toPlainText()) @@ -26,8 +26,7 @@ def simple_fit_button_callback(self): A2 = float(self.AMaxEdit.toPlainText()) A_N = int(self.ASamplesEdit.toPlainText()) SANSgeometry = self.ScatteringGeometrySelect.currentText() - - MuMagLib.SimpleFit_FitButtonCallback(q_max, H_min, A1, A2, A_N, SANSgeometry) + self.MuMagLib_obj.SimpleFit_FitButtonCallback(q_max, H_min, A1, A2, A_N, SANSgeometry) def main(): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index ff630981b9..f1f4ad1b12 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -17,269 +17,250 @@ import MuMagParallelGeo -##################################################################################################################### -def get_directory(): - fname = QFileDialog.getOpenFileName() - if fname: - fname = fname[0] - index = [i for i, val in enumerate(fname) if val == "/"] - fname = fname[0:index[-1]+1] - return fname - -##################################################################################################################### -# Import experimental data and get information from filenames -def import_data_button_callback_sub(): - - global q_exp - global I_exp - global sigma_exp - global B_0_exp - global Ms_exp - global Hdem_exp - global DataCounter - - #print('here') - DataCounter = 0 - # Predefine array's - #DIR = filedialog.askdirectory() - DIR = get_directory() - #print('here') - for name in os.listdir(DIR): - if name.find(".csv") != -1: - data = np.genfromtxt(DIR + '/' + name) - Lq = len(data[:, 0]) - if DataCounter == 0: - q_exp = np.array([np.zeros(Lq)]) - I_exp = np.array([np.zeros(Lq)]) - sigma_exp = np.array([np.zeros(Lq)]) - B_0_exp = np.array([np.zeros(1)]) - Ms_exp = np.array([np.zeros(1)]) - Hdem_exp = np.array([np.zeros(1)]) - DataCounter = DataCounter + 1 - else: - q_exp = np.append(q_exp, [np.zeros(Lq)], axis=0) - I_exp = np.append(I_exp, [np.zeros(Lq)], axis=0) - sigma_exp = np.append(sigma_exp, [np.zeros(Lq)], axis=0) - B_0_exp = np.append(B_0_exp, [np.zeros(1)]) - Ms_exp = np.append(Ms_exp, [np.zeros(1)]) - Hdem_exp = np.append(Hdem_exp, [np.zeros(1)]) - DataCounter = DataCounter + 1 - - #print('here') - # Load the data and sort the data - for name in os.listdir(DIR): - if name.find(".csv") != -1: - - str_name = name[0:len(name)-4] - str_name = str_name.split('_') - idx = int(str_name[0]) - B0 = float(str_name[1]) - Ms = float(str_name[2]) - Hdem = float(str_name[3]) - - data = np.genfromtxt(DIR + '/' + name) - - B_0_exp[idx-1] = B0 - Ms_exp[idx-1] = Ms - Hdem_exp[idx-1] = Hdem - q_exp[idx-1, :] = data[:, 0].T * 1e9 - I_exp[idx-1, :] = data[:, 1].T - sigma_exp[idx-1, :] = data[:, 2].T - - -################################################################################################################ -# Plot Experimental Data: Generate Figure -def plot_exp_data(q, I_exp, B_0, x_min, x_max, y_min, y_max): - - fig = plt.figure() - fig.tight_layout() - ax = fig.add_subplot(1, 1, 1) - - colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) - for k in np.arange(0, len(B_0)): - plt.plot(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label='B_0 = ' + str(B_0[k]) + ' T') - plt.plot(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) - - box = ax.get_position() - ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) - - plt.xlabel('q [1/nm]') - plt.ylabel('I_exp') - plt.xlim(x_min, x_max) - plt.ylim(y_min, y_max) - plt.yscale('log') - plt.xscale('log') - plt.grid(True, which="both", linestyle='--') - plt.legend(loc='center left', bbox_to_anchor=(1, 0.5)) - plt.show() - - - -##################################################################################################################### -# Plot Experimental Data: Set Bounds and Call Plotting Function -def plot_experimental_data(): - global q_exp - global I_exp - global sigma_exp - global B_0_exp - - if np.size(q_exp) > 1: - q_exp_min = np.amin(q_exp)*1e-9 - q_exp_min = 10**(np.floor(np.log10(q_exp_min))) * np.floor(q_exp_min/10**(np.floor(np.log10(q_exp_min)))) - - q_exp_max = np.amax(q_exp)*1e-9 - q_exp_max = 10**(np.floor(np.log10(q_exp_max))) * np.ceil(q_exp_max/10**(np.floor(np.log10(q_exp_max)))) - - I_exp_min = np.amin(I_exp) - I_exp_min = 10**(np.floor(np.log10(I_exp_min))) * np.floor(I_exp_min/10**(np.floor(np.log10(I_exp_min)))) - - I_exp_max = np.amax(I_exp) - I_exp_max = 10 ** (np.floor(np.log10(I_exp_max))) * np.ceil(I_exp_max / 10 ** (np.floor(np.log10(I_exp_max)))) - - plot_exp_data(q_exp*1e-9, I_exp, B_0_exp*1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) - else: - messagebox.showerror(title="Error!", message="No experimental data available! Please import experimental data!") - - -####################################################################################################################### - - - - - -####################################################################################################################### - -def SimpleFit_FitButtonCallback(q_max, H_min, A1, A2, A_N, SANSgeometry): - - global q_exp - global I_exp - global sigma_exp - global B_0_exp - global Ms_exp - global Hdem_exp - - global SimpleFit_q_exp - global SimpleFit_I_exp - global SimpleFit_sigma_exp - global SimpleFit_B_0_exp - global SimpleFit_Ms_exp - global SimpleFit_Hdem_exp - global SimpleFit_I_fit - global SimpleFit_A - global SimpleFit_chi_q - global SimpleFit_S_H_fit - global SimpleFit_S_M_fit - global SimpleFit_I_res_fit - global SimpleFit_A_opt - global SimpleFit_chi_q_opt - global SimpleFit_A_sigma - global SimpleFit_SANSgeometry - - if np.size(q_exp) > 1: - #q_max = float(SimpleFitqmaxEntry.get()) - #H_min = float(SimpleFitHminEntry.get()) - #A1 = float(SimpleFitA1Entry.get()) - #A2 = float(SimpleFitA2Entry.get()) - #A_N = int(SimpleFitANEntry.get()) - #SANSgeometry = SANSgeometryVariable.get() - - # search index for q_max - q_diff = (q_exp[0, :]*1e-9 - q_max)**2 - K_q = np.where(q_diff == np.min(q_diff)) - K_q = K_q[0][0] - - # search index for H_min - H_diff = (B_0_exp - H_min)**2 - K_H = np.where(H_diff == np.min(H_diff)) - K_H = K_H[0][0] - - # apply the restrictions - mu_0 = 4*math.pi*1e-7 - q = q_exp[K_H:, 0:K_q] - I_exp_red = I_exp[K_H:, 0:K_q] - sigma = sigma_exp[K_H:, 0:K_q] - H_0 = np.outer(B_0_exp[K_H:]/mu_0 * 1e-3, np.ones(K_q)) - H_dem = np.outer(Hdem_exp[K_H:], np.ones(K_q))/mu_0 * 1e-3 - Ms = np.outer(Ms_exp[K_H:], np.ones(K_q))/mu_0 * 1e-3 - - # Least Squares Fit in case of perpendicular SANS geometry - if SANSgeometry == "perpendicular": - A_1 = A1 * 1e-12 - A_2 = A2 * 1e-12 - A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M \ - = MuMagPerpendicularGeo.SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) - - A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = MuMagPerpendicularGeo.LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - - I_opt = MuMagPerpendicularGeo.SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) - - d2chi_dA2 = MuMagPerpendicularGeo.FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - - N_mu = len(I_exp_red[0, :]) - N_nu = len(I_exp_red[:, 0]) - A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) - - MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty * 1e12) - - # Save to global Variables - SimpleFit_q_exp = q - SimpleFit_I_exp = I_exp_red - SimpleFit_sigma_exp = sigma - SimpleFit_B_0_exp = B_0_exp[K_H:] - SimpleFit_Ms_exp = Ms_exp[K_H:] - SimpleFit_Hdem_exp = Hdem_exp[K_H:] - SimpleFit_I_fit = I_opt - SimpleFit_A = A - SimpleFit_chi_q = chi_q - SimpleFit_S_H_fit = S_H_opt - SimpleFit_S_M_fit = S_M_opt - SimpleFit_I_res_fit = I_res_opt - SimpleFit_A_opt = A_opt - SimpleFit_chi_q_opt = chi_q_opt - SimpleFit_A_sigma = A_Uncertainty - SimpleFit_SANSgeometry = "perpendicular" - - elif SANSgeometry == "parallel ": - A_1 = A1 * 1e-12 - A_2 = A2 * 1e-12 - A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ - = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) - - A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = MuMagParallelGeo.LSQ_PAR(q, I_exp_red, sigma, - Ms, H_0, - H_dem, - A_opt) - - I_opt = MuMagParallelGeo.SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) - - d2chi_dA2 = MuMagParallelGeo.FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - N_mu = len(I_exp_red[0, :]) - N_nu = len(I_exp_red[:, 0]) - A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) - - MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, - I_res_opt, S_H_opt, A_Uncertainty * 1e12) - - # Save to global Variables - SimpleFit_q_exp = q - SimpleFit_I_exp = I_exp_red - SimpleFit_sigma_exp = sigma - SimpleFit_B_0_exp = B_0_exp[K_H:] - SimpleFit_Ms_exp = Ms_exp[K_H:] - SimpleFit_Hdem_exp = Hdem_exp[K_H:] - SimpleFit_I_fit = I_opt - SimpleFit_A = A - SimpleFit_chi_q = chi_q - SimpleFit_S_H_fit = S_H_opt - SimpleFit_I_res_fit = I_res_opt - SimpleFit_A_opt = A_opt - SimpleFit_chi_q_opt = chi_q_opt - SimpleFit_A_sigma = A_Uncertainty - SimpleFit_SANSgeometry = "parallel" - - else: - messagebox.showerror(title="Error!", - message="No experimental Data available! Please import experimental data!") + +class MuMagLib(): + def __init__(self): + + # attributes for the input data + self.q_exp = 0 + self.I_exp = 0 + self.sigma_exp = 0 + self.B_0_exp = 0 + self.Ms_exp = 0 + self.Hdem_exp = 0 + self.DataCounter = 0 + + # attributes for the simple fit result + self.SimpleFit_q_exp = 0 + self.SimpleFit_I_exp = 0 + self.SimpleFit_sigma_exp = 0 + self.SimpleFit_B_0_exp = 0 + self.SimpleFit_Ms_exp = 0 + self.SimpleFit_Hdem_exp = 0 + self.SimpleFit_I_fit = 0 + self.SimpleFit_A = 0 + self.SimpleFit_chi_q = 0 + self.SimpleFit_S_H_fit = 0 + self.SimpleFit_S_M_fit = 0 + self.SimpleFit_I_res_fit = 0 + self.SimpleFit_A_opt = 0 + self.SimpleFit_chi_q_opt = 0 + self.SimpleFit_A_sigma = 0 + self.SimpleFit_SANSgeometry = 0 + + + + ##################################################################################################################### + def get_directory(self): + fname = QFileDialog.getOpenFileName() + if fname: + fname = fname[0] + index = [i for i, val in enumerate(fname) if val == "/"] + fname = fname[0:index[-1]+1] + return fname + + ##################################################################################################################### + # Import experimental data and get information from filenames + def import_data_button_callback_sub(self): + + self.DataCounter = 0 + # Predefine array's + DIR = self.get_directory() + for name in os.listdir(DIR): + if name.find(".csv") != -1: + data = np.genfromtxt(DIR + '/' + name) + Lq = len(data[:, 0]) + if self.DataCounter == 0: + self.q_exp = np.array([np.zeros(Lq)]) + self.I_exp = np.array([np.zeros(Lq)]) + self.sigma_exp = np.array([np.zeros(Lq)]) + self.B_0_exp = np.array([np.zeros(1)]) + self.Ms_exp = np.array([np.zeros(1)]) + self.Hdem_exp = np.array([np.zeros(1)]) + self.DataCounter = self.DataCounter + 1 + else: + self.q_exp = np.append(self.q_exp, [np.zeros(Lq)], axis=0) + self.I_exp = np.append(self.I_exp, [np.zeros(Lq)], axis=0) + self.sigma_exp = np.append(self.sigma_exp, [np.zeros(Lq)], axis=0) + self.B_0_exp = np.append(self.B_0_exp, [np.zeros(1)]) + self.Ms_exp = np.append(self.Ms_exp, [np.zeros(1)]) + self.Hdem_exp = np.append(self.Hdem_exp, [np.zeros(1)]) + self.DataCounter = self.DataCounter + 1 + + # Load the data and sort the data + for name in os.listdir(DIR): + if name.find(".csv") != -1: + str_name = name[0:len(name)-4] + str_name = str_name.split('_') + idx = int(str_name[0]) + data = np.genfromtxt(DIR + '/' + name) + self.B_0_exp[idx-1] = float(str_name[1]) + self.Ms_exp[idx-1] = float(str_name[2]) + self.Hdem_exp[idx-1] = float(str_name[3]) + self.q_exp[idx-1, :] = data[:, 0].T * 1e9 + self.I_exp[idx-1, :] = data[:, 1].T + self.sigma_exp[idx-1, :] = data[:, 2].T + + + ################################################################################################################ + # Plot Experimental Data: Generate Figure + def plot_exp_data(self, q, I_exp, B_0, x_min, x_max, y_min, y_max): + + fig = plt.figure() + fig.tight_layout() + ax = fig.add_subplot(1, 1, 1) + + colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) + for k in np.arange(0, len(B_0)): + plt.plot(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label='B_0 = ' + str(B_0[k]) + ' T') + plt.plot(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) + + box = ax.get_position() + ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) + + plt.xlabel('q [1/nm]') + plt.ylabel('I_exp') + plt.xlim(x_min, x_max) + plt.ylim(y_min, y_max) + plt.yscale('log') + plt.xscale('log') + plt.grid(True, which="both", linestyle='--') + plt.legend(loc='center left', bbox_to_anchor=(1, 0.5)) + plt.show() + + + + ##################################################################################################################### + # Plot Experimental Data: Set Bounds and Call Plotting Function + def plot_experimental_data(self): + + if np.size(self.q_exp) > 1: + q_exp_min = np.amin(self.q_exp)*1e-9 + q_exp_min = 10**(np.floor(np.log10(q_exp_min))) * np.floor(q_exp_min/10**(np.floor(np.log10(q_exp_min)))) + + q_exp_max = np.amax(self.q_exp)*1e-9 + q_exp_max = 10**(np.floor(np.log10(q_exp_max))) * np.ceil(q_exp_max/10**(np.floor(np.log10(q_exp_max)))) + + I_exp_min = np.amin(self.I_exp) + I_exp_min = 10**(np.floor(np.log10(I_exp_min))) * np.floor(I_exp_min/10**(np.floor(np.log10(I_exp_min)))) + + I_exp_max = np.amax(self.I_exp) + I_exp_max = 10 ** (np.floor(np.log10(I_exp_max))) * np.ceil(I_exp_max / 10 ** (np.floor(np.log10(I_exp_max)))) + + self.plot_exp_data(self.q_exp*1e-9, self.I_exp, self.B_0_exp*1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) + else: + messagebox.showerror(title="Error!", message="No experimental data available! Please import experimental data!") + + + ####################################################################################################################### + + + + + + ####################################################################################################################### + + def SimpleFit_FitButtonCallback(self, q_max, H_min, A1, A2, A_N, SANSgeometry): + + if np.size(self.q_exp) > 1: + + # search index for q_max + q_diff = (self.q_exp[0, :]*1e-9 - q_max)**2 + K_q = np.where(q_diff == np.min(q_diff)) + K_q = K_q[0][0] + + # search index for H_min + H_diff = (self.B_0_exp - H_min)**2 + K_H = np.where(H_diff == np.min(H_diff)) + K_H = K_H[0][0] + + # apply the restrictions + mu_0 = 4*math.pi*1e-7 + q = self.q_exp[K_H:, 0:K_q] + I_exp_red = self.I_exp[K_H:, 0:K_q] + sigma = self.sigma_exp[K_H:, 0:K_q] + H_0 = np.outer(self.B_0_exp[K_H:]/mu_0 * 1e-3, np.ones(K_q)) + H_dem = np.outer(self.Hdem_exp[K_H:], np.ones(K_q))/mu_0 * 1e-3 + Ms = np.outer(self.Ms_exp[K_H:], np.ones(K_q))/mu_0 * 1e-3 + + # Least Squares Fit in case of perpendicular SANS geometry + if SANSgeometry == "perpendicular": + A_1 = A1 * 1e-12 + A_2 = A2 * 1e-12 + A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M \ + = MuMagPerpendicularGeo.SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + + A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = MuMagPerpendicularGeo.LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + + I_opt = MuMagPerpendicularGeo.SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + + d2chi_dA2 = MuMagPerpendicularGeo.FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + + N_mu = len(I_exp_red[0, :]) + N_nu = len(I_exp_red[:, 0]) + A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + + MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty * 1e12) + + # Save to global Variables + self.SimpleFit_q_exp = q + self.SimpleFit_I_exp = I_exp_red + self.SimpleFit_sigma_exp = sigma + self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] + self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] + self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] + self.SimpleFit_I_fit = I_opt + self.SimpleFit_A = A + self.SimpleFit_chi_q = chi_q + self.SimpleFit_S_H_fit = S_H_opt + self.SimpleFit_S_M_fit = S_M_opt + self.SimpleFit_I_res_fit = I_res_opt + self.SimpleFit_A_opt = A_opt + self.SimpleFit_chi_q_opt = chi_q_opt + self.SimpleFit_A_sigma = A_Uncertainty + self.SimpleFit_SANSgeometry = "perpendicular" + + elif SANSgeometry == "parallel ": + A_1 = A1 * 1e-12 + A_2 = A2 * 1e-12 + A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ + = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + + A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = MuMagParallelGeo.LSQ_PAR(q, I_exp_red, sigma, + Ms, H_0, + H_dem, + A_opt) + + I_opt = MuMagParallelGeo.SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + + d2chi_dA2 = MuMagParallelGeo.FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + N_mu = len(I_exp_red[0, :]) + N_nu = len(I_exp_red[:, 0]) + A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + + MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, + I_res_opt, S_H_opt, A_Uncertainty * 1e12) + + # Save to global Variables + self.SimpleFit_q_exp = q + self.SimpleFit_I_exp = I_exp_red + self.SimpleFit_sigma_exp = sigma + self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] + self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] + self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] + self.SimpleFit_I_fit = I_opt + self.SimpleFit_A = A + self.SimpleFit_chi_q = chi_q + self.SimpleFit_S_H_fit = S_H_opt + self.SimpleFit_I_res_fit = I_res_opt + self.SimpleFit_A_opt = A_opt + self.SimpleFit_chi_q_opt = chi_q_opt + self.SimpleFit_A_sigma = A_Uncertainty + self.SimpleFit_SANSgeometry = "parallel" + + else: + messagebox.showerror(title="Error!", + message="No experimental Data available! Please import experimental data!") From 315bf072fc1a308ef39796cb8bc4c630c15d379b Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 18 Sep 2023 17:17:18 +0200 Subject: [PATCH 08/46] added panel for doing the plots inside of the MuMagTool MainWindow, so that the plot got not its own new figure --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 4 +- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 1 - .../qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 425 ++++++++---------- 3 files changed, 200 insertions(+), 230 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index faeb6e4b08..7a404ae3e3 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -1,10 +1,10 @@ -from sas.qtgui.Utilities.MuMagTool.UI.MuMagUI import Ui_MainWindow +from sas.qtgui.Utilities.MuMagTool.UI.MuMagUI import Ui_MuMagTool from PySide6.QtWidgets import QWidget from PySide6 import QtWidgets from sas.qtgui.Utilities.MuMagTool import MuMagLib -class MuMag(QtWidgets.QMainWindow, Ui_MainWindow): +class MuMag(QtWidgets.QMainWindow, Ui_MuMagTool): def __init__(self, parent=None): super().__init__() self.MuMagLib_obj = MuMagLib.MuMagLib() diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index f1f4ad1b12..08957351ca 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -17,7 +17,6 @@ import MuMagParallelGeo - class MuMagLib(): def __init__(self): diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui index e35b993643..7007c98aaa 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -1,266 +1,237 @@ - MainWindow - + MuMagTool + 0 0 - 800 + 703 600 - MainWindow + MuMagTool - + - 20 - 20 - 113 - 32 + 0 + 0 + 161 + 131 - + Import Data - - - - - 140 - 20 - 113 - 32 - - - - Plot Data - - - - - - 10 - 120 - 131 - 32 - - - - Simple Fit - - - - - - 10 - 160 - 131 - 32 - - - - Compare Results - - - - - - 12 - 200 - 131 - 32 - - - - Save Result - - - - - - 250 - 130 - 104 - 31 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + 0 + 20 + 161 + 111 + + + + + + + Plot Data + + + + + + + Import Data + + + + + + + + perpendicular + + + + + parallel + + + + + + + + + + + 160 + 0 + 541 + 131 + + + + Simple Fit Tool + + + + + 10 + 20 + 521 + 111 + + + + + + + A [pJ/m]: + + + + + + + max + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">0.6</p></body></html> - - - - - - 390 - 200 - 104 - 31 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5</p></body></html> + + + + + + + min + + + + + + + q_max [1/nm] + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">20</p></body></html> - - - - - - 250 - 200 - 104 - 31 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">0.6</p></body></html> + + + + + + + Simple Fit + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5</p></body></html> - - - - - - 530 - 130 - 104 - 31 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">20</p></body></html> + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">75</p></body></html> - - - - - - 530 - 200 - 104 - 31 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">200</p></body></html> + + + + + + + samples + + + + + + + mu_0*H_min [mT] + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">200</p></body></html> - - - - - - 170 - 210 - 60 - 16 - - - - A [pJ/m]: - - - - - - 280 - 180 - 60 - 16 - - - - min - - - - - - 420 - 180 - 60 - 16 - - - - max - - - - - - 550 - 180 - 60 - 16 - - - - samples - - - - - - 150 - 140 - 91 - 16 - - - - q_max [1/nm] - - - - - - 390 - 140 - 121 - 16 +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">75</p></body></html> + + + + + + + Compare Results + + + + + + + Save Result + + + + + + + + + + 0 + 130 + 701 + 431 - - mu_0*H_min [mT] + + GroupBox - - - - - 270 - 20 - 171 - 26 - - - - - perpendicular - - - - - parallel + + + + 20 + 40 + 501 + 221 + - + @@ -268,7 +239,7 @@ p, li { white-space: pre-wrap; } 0 0 - 800 + 703 22 From 9b82c1a1d0db33066a180f91081fa349e05fda50 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 18 Sep 2023 18:05:57 +0200 Subject: [PATCH 09/46] update test --- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 08957351ca..5c6c76fdf0 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -47,8 +47,6 @@ def __init__(self): self.SimpleFit_A_sigma = 0 self.SimpleFit_SANSgeometry = 0 - - ##################################################################################################################### def get_directory(self): fname = QFileDialog.getOpenFileName() From cfc2536f87d6f188b518daf854c50e003a124862 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 18 Sep 2023 18:08:18 +0200 Subject: [PATCH 10/46] test update --- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 5c6c76fdf0..c8d2dd0135 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -13,9 +13,8 @@ from PySide6.QtWidgets import QFileDialog import string -import MuMagPerpendicularGeo import MuMagParallelGeo - +import MuMagPerpendicularGeo class MuMagLib(): def __init__(self): From 3f6b4ebab58ac21fd15f88135c6518d0f9faa6b2 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 18 Sep 2023 18:22:24 +0200 Subject: [PATCH 11/46] solved import problem with folder --- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 5 +++-- src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py | 1 - src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index c8d2dd0135..afa28c4b58 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -13,8 +13,9 @@ from PySide6.QtWidgets import QFileDialog import string -import MuMagParallelGeo -import MuMagPerpendicularGeo +from sas.qtgui.Utilities.MuMagTool import MuMagParallelGeo +from sas.qtgui.Utilities.MuMagTool import MuMagPerpendicularGeo + class MuMagLib(): def __init__(self): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py index 3de0bc48e9..dd8e85a05f 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py @@ -10,7 +10,6 @@ def LorentzianModelPAR(q, A, M_s, H_0, H_dem, a_H, l_c): # All inputs in SI-units - # Micromagnetic Model mu_0 = 4 * np.pi * 1e-7 H_i = H_0 - H_dem diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py index 0605f43d0c..b2e00bf2ba 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py @@ -3,6 +3,7 @@ import matplotlib.pyplot as plt + #################################################################################################### # Functions for the analysis of perpendicular SANS ################################################# #################################################################################################### From ae5021871f02ebf971b122ecb49059c592ec07f7 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Wed, 20 Sep 2023 17:40:18 +0200 Subject: [PATCH 12/46] test commit --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 2 +- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 7a404ae3e3..7f1cabf9b7 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -26,7 +26,7 @@ def simple_fit_button_callback(self): A2 = float(self.AMaxEdit.toPlainText()) A_N = int(self.ASamplesEdit.toPlainText()) SANSgeometry = self.ScatteringGeometrySelect.currentText() - self.MuMagLib_obj.SimpleFit_FitButtonCallback(q_max, H_min, A1, A2, A_N, SANSgeometry) + self.MuMagLib_obj.simple_fit_button_callback(q_max, H_min, A1, A2, A_N, SANSgeometry) def main(): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index afa28c4b58..014a92e425 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -157,7 +157,7 @@ def plot_experimental_data(self): ####################################################################################################################### - def SimpleFit_FitButtonCallback(self, q_max, H_min, A1, A2, A_N, SANSgeometry): + def simple_fit_button_callback(self, q_max, H_min, A1, A2, A_N, SANSgeometry): if np.size(self.q_exp) > 1: From 99bcb5b9633467e79e7b7f0dd50b2a5e49c1a036 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:19:03 +0200 Subject: [PATCH 13/46] added TEST data --- .../10_1000_1340_10.csv | 105 ++++++++++++++++++ .../11_2000_1340_10.csv | 105 ++++++++++++++++++ .../12_3000_1340_10.csv | 105 ++++++++++++++++++ .../13_8000_1340_10.csv | 105 ++++++++++++++++++ .../1_0_1340_10.csv | 105 ++++++++++++++++++ .../2_20_1340_10.csv | 105 ++++++++++++++++++ .../3_35_1340_10.csv | 105 ++++++++++++++++++ .../4_50_1340_10.csv | 105 ++++++++++++++++++ .../5_75_1340_10.csv | 105 ++++++++++++++++++ .../6_100_1340_10.csv | 105 ++++++++++++++++++ .../7_200_1340_10.csv | 105 ++++++++++++++++++ .../8_300_1340_10.csv | 105 ++++++++++++++++++ .../9_600_1340_10.csv | 105 ++++++++++++++++++ .../1_33_1640_22.874115.csv | 60 ++++++++++ .../2_42_1640_23.456895.csv | 60 ++++++++++ .../3_61_1640_23.748285.csv | 60 ++++++++++ .../4_103_1640_24.039675.csv | 60 ++++++++++ .../5_312_1640_24.331065.csv | 60 ++++++++++ .../6_1270_1640_24.331065.csv | 60 ++++++++++ .../1_8000_1600_1.csv | 53 +++++++++ .../2_10000_1600_1.csv | 53 +++++++++ .../3_12000_1600_1.csv | 53 +++++++++ .../4_14000_1600_1.csv | 53 +++++++++ .../5_16000_1600_1.csv | 53 +++++++++ 24 files changed, 1990 insertions(+) create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1.csv create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv new file mode 100644 index 0000000000..8e9c70665b --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv @@ -0,0 +1,105 @@ +3.624299999999999744e-02 7.295645247999999583e+01 1.637502872666669873e+01 +4.068929999999999769e-02 3.496757764333329987e+01 1.132330254166670080e+01 +4.510000000000000120e-02 2.871506291000000033e+01 8.366418418333330109e+00 +4.957960000000000145e-02 3.062621534000000167e+01 6.807088010000000189e+00 +5.414959999999999912e-02 1.698840335499999910e+01 5.315930135000000334e+00 +5.867460000000000037e-02 1.810732352000000134e+01 4.582343003333329889e+00 +6.313670000000000393e-02 1.758858145166669829e+01 3.753068668333329860e+00 +6.771770000000000567e-02 1.874808681500000063e+01 3.129801861666670071e+00 +7.237100000000000477e-02 1.219239694000000007e+01 2.701832888333330018e+00 +7.692330000000000001e-02 1.502033604000000011e+01 2.415586504999999828e+00 +8.164470000000000061e-02 1.051882241166670084e+01 2.003147743333329789e+00 +8.639470000000000482e-02 1.266539752666670005e+01 1.813845073333330005e+00 +9.106759999999999855e-02 1.164225125833329955e+01 1.590423455000000041e+00 +9.573710000000000553e-02 9.248378555000000389e+00 1.453449206666669991e+00 +1.004952999999999957e-01 1.082198768499999986e+01 1.296534581666670016e+00 +1.052397000000000055e-01 9.754544071666670035e+00 1.192202876666669908e+00 +1.099886000000000058e-01 9.770793396666670461e+00 1.074958141666670031e+00 +1.148422000000000054e-01 9.667035006666669261e+00 9.803857316666669819e-01 +1.197769999999999946e-01 8.381104240000000871e+00 8.964596183333329860e-01 +1.247698000000000002e-01 7.884219706666669936e+00 8.320707283333329540e-01 +1.298370000000000080e-01 8.175124921666670375e+00 7.497416000000000080e-01 +1.349077999999999944e-01 7.421197476666669957e+00 7.207336583333330271e-01 +1.399244000000000043e-01 8.545903931666670061e+00 6.648524133333330033e-01 +1.450733999999999913e-01 7.172791390000000433e+00 6.314494133333330428e-01 +1.502658000000000049e-01 6.110795001666669890e+00 5.924928833333330536e-01 +1.556062000000000001e-01 7.011488443333329990e+00 5.430119199999999813e-01 +1.572456999999999883e-01 7.121472013333329798e+00 1.740741033333330079e-01 +1.609471000000000096e-01 7.438929439999999893e+00 5.263131250000000483e-01 +1.661874999999999880e-01 6.540084590000000198e+00 4.946959550000000205e-01 +1.706292000000000086e-01 6.367655253333330378e+00 1.455746566666669961e-01 +1.715615000000000057e-01 6.476111691666670112e+00 4.707941449999999972e-01 +1.771270000000000067e-01 5.720913878333329983e+00 4.355610400000000104e-01 +1.827315999999999940e-01 6.117868691666670244e+00 4.186226383333330192e-01 +1.842428999999999872e-01 5.857041180000000402e+00 1.254778649999999940e-01 +1.883173999999999959e-01 5.849837826666670182e+00 4.069392433333329784e-01 +1.939794999999999991e-01 5.447672994999999574e+00 3.927526633333329742e-01 +1.982414999999999872e-01 5.391186461666669594e+00 1.085076650000000031e-01 +1.997663000000000078e-01 5.394637556666670442e+00 3.662608233333329855e-01 +2.055810999999999888e-01 5.784545713333329786e+00 3.603836316666669815e-01 +2.114655000000000007e-01 4.574601945000000391e+00 3.312713700000000094e-01 +2.120113000000000136e-01 5.084515549999999884e+00 9.927742500000000248e-02 +2.161903000000000019e-01 4.516358434999999893e+00 4.168106166666670220e-01 +2.259823999999999999e-01 4.782964421666670241e+00 8.791053666666670541e-02 +2.397845000000000115e-01 4.501217386666669817e+00 8.259429166666669431e-02 +2.537096999999999825e-01 4.179436571666670375e+00 7.562756833333329765e-02 +2.676275000000000182e-01 3.979478888333329856e+00 6.987285499999999761e-02 +2.817857999999999752e-01 3.702226940000000077e+00 6.482911333333329917e-02 +2.956398000000000081e-01 3.605992423333329810e+00 6.203536333333330155e-02 +3.099044000000000243e-01 3.377018353333329781e+00 5.670042833333330257e-02 +3.240645999999999805e-01 3.095807218333329836e+00 5.498817999999999762e-02 +3.388027000000000122e-01 2.841171323333330001e+00 4.897826333333329951e-02 +3.539140000000000064e-01 2.795649415000000193e+00 4.845330666666670255e-02 +3.687090000000000090e-01 2.622854690000000044e+00 4.475559833333329907e-02 +3.839813000000000254e-01 2.527809641666669993e+00 4.273165666666670082e-02 +3.988975000000000160e-01 2.232305030000000023e+00 4.094381166666669764e-02 +4.106734000000000218e-01 2.129986383333330124e+00 4.154637366666669857e-02 +4.136514000000000024e-01 2.084593566666669950e+00 3.891198166666669928e-02 +4.290628000000000219e-01 1.988620215000000080e+00 3.594587333333330165e-02 +4.295516999999999808e-01 1.964928603499999982e+00 3.519640899999999795e-02 +4.446014999999999828e-01 1.750614441666670018e+00 3.497378000000000292e-02 +4.466716000000000020e-01 1.709819834666669980e+00 3.112847050000000157e-02 +4.603325999999999807e-01 1.676685876666669905e+00 3.265084166666670090e-02 +4.685437000000000074e-01 1.638395569999999912e+00 3.101072850000000103e-02 +4.764860000000000206e-01 1.575855291666669933e+00 3.097528500000000171e-02 +4.834083000000000130e-01 1.443926158166670026e+00 2.913516383333330032e-02 +4.923204999999999942e-01 1.443778989999999984e+00 3.072023333333330150e-02 +5.046621000000000024e-01 1.382474827333330047e+00 2.709115466666670025e-02 +5.082708000000000226e-01 1.368563626666670086e+00 2.832584499999999880e-02 +5.230728999999999518e-01 1.117650907000000027e+00 2.515010599999999846e-02 +5.249162000000000550e-01 1.271594368333329950e+00 2.652784333333330080e-02 +5.416775999999999813e-01 1.132208539999999930e+00 2.601087833333329963e-02 +5.444001000000000534e-01 1.080469498666670081e+00 2.559191900000000117e-02 +5.583067999999999920e-01 1.032465565000000085e+00 2.510816333333330125e-02 +5.612614999999999688e-01 1.012286258500000091e+00 2.336018449999999885e-02 +5.753956999999999544e-01 9.763539783333330391e-01 2.332539999999999961e-02 +5.834072999999999620e-01 8.965217239999999643e-01 2.303063099999999933e-02 +5.927398999999999862e-01 9.096560916666670549e-01 2.248173499999999922e-02 +6.005747000000000169e-01 8.250965611666669641e-01 2.186496933333329992e-02 +6.099058000000000535e-01 8.168162183333329551e-01 2.170944500000000082e-02 +6.218546000000000351e-01 7.414260915000000507e-01 2.121375600000000028e-02 +6.275003000000000108e-01 7.444278466666669480e-01 2.046154333333330064e-02 +6.412082999999999533e-01 6.366966366666669819e-01 1.883217216666669899e-02 +6.447154999999999969e-01 6.422991433333330447e-01 2.075286000000000144e-02 +6.655497999999999692e-01 5.866493959999999896e-01 1.815403650000000160e-02 +6.843702000000000396e-01 5.515869356666670553e-01 2.025276583333330063e-02 +7.058105999999999547e-01 4.475886111666669831e-01 1.701240433333330027e-02 +7.258693999999999980e-01 4.775394179999999933e-01 1.840697383333329828e-02 +7.490480000000000471e-01 4.047520649999999942e-01 1.505153366666669990e-02 +7.720086999999999922e-01 3.731668894999999875e-01 1.706827766666670076e-02 +7.920989999999999975e-01 3.681129878333330163e-01 1.507231049999999996e-02 +8.155097999999999514e-01 3.208610430000000124e-01 1.529166149999999953e-02 +8.364475000000000104e-01 2.962226738333330056e-01 1.456896033333330079e-02 +8.619377000000000288e-01 2.765821119999999911e-01 1.371801400000000060e-02 +8.846403999999999934e-01 2.799105873333330163e-01 1.446314666666670065e-02 +9.081462000000000145e-01 2.318482950000000098e-01 1.260493333333330065e-02 +9.334447000000000161e-01 2.175556724999999914e-01 1.357374916666670081e-02 +9.551832000000000100e-01 1.903255399999999875e-01 1.273357800000000060e-02 +9.812971999999999806e-01 1.841620115000000002e-01 1.195187833333329931e-02 +1.006807800000000030e+00 1.608915558333330054e-01 1.233432733333329930e-02 +1.030406600000000061e+00 1.533644885000000069e-01 1.172346633333330029e-02 +1.057784300000000011e+00 1.661925581666670038e-01 1.091501716666670035e-02 +1.084600999999999926e+00 1.630933589999999933e-01 1.128103283333329980e-02 +1.109902299999999897e+00 1.327154809999999963e-01 1.088576583333330031e-02 +1.137751600000000085e+00 1.179623709999999964e-01 1.042595833333329926e-02 +1.166036300000000026e+00 1.293750036666669878e-01 1.024355400000000020e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv new file mode 100644 index 0000000000..bfbf36dcd1 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv @@ -0,0 +1,105 @@ +3.625559999999999894e-02 4.452644707000000324e+01 1.628119149999999848e+01 +4.070349999999999663e-02 2.677295466333330154e+01 1.128515222166669929e+01 +4.511570000000000163e-02 2.350029203500000108e+01 8.338724138333329705e+00 +4.959680000000000338e-02 1.744413458166669884e+01 6.751264438333329565e+00 +5.416850000000000137e-02 9.909433441666669395e+00 5.280963783333329609e+00 +5.869510000000000005e-02 1.174714312999999954e+01 4.547423594999999708e+00 +6.315869999999999818e-02 1.312634901166670076e+01 3.725749208333330120e+00 +6.774130000000000429e-02 1.654730030333330149e+01 3.113655078333330106e+00 +7.239619999999999389e-02 7.792796271666669661e+00 2.672180411666670086e+00 +7.695009999999999351e-02 1.265325572666669984e+01 2.397233363333330036e+00 +8.167309999999999848e-02 6.069752713333330441e+00 1.971069876666670107e+00 +8.642469999999999319e-02 1.300927747833329917e+01 1.813635340000000040e+00 +9.109929999999999417e-02 9.757094948333330464e+00 1.573592551666670003e+00 +9.577040000000000552e-02 5.713518095000000407e+00 1.422093728333329921e+00 +1.005303000000000030e-01 7.313534973333330136e+00 1.265234731666670109e+00 +1.052763000000000032e-01 8.841184973333330532e+00 1.182077201666670074e+00 +1.100268999999999969e-01 7.404252198333329815e+00 1.051346621666670034e+00 +1.148821000000000009e-01 8.380590695000000423e+00 9.664303683333329564e-01 +1.198187000000000002e-01 7.413483668333330279e+00 8.855263516666670442e-01 +1.248133000000000020e-01 6.593134025000000342e+00 8.175650066666669824e-01 +1.298822000000000032e-01 6.731246111666670195e+00 7.333046399999999521e-01 +1.349548000000000136e-01 5.519098301666669926e+00 6.986229283333329487e-01 +1.399730999999999892e-01 7.581442331666670142e+00 6.528076566666669578e-01 +1.451239000000000001e-01 4.842304316666670161e+00 6.043489516666670225e-01 +1.503181000000000100e-01 5.135523888333329623e+00 5.802922499999999539e-01 +1.556604000000000043e-01 6.037988904999999740e+00 5.310080216666670516e-01 +1.573070000000000024e-01 6.020141886666669606e+00 1.700767950000000028e-01 +1.610031000000000101e-01 6.268605329999999753e+00 5.111983383333329467e-01 +1.662453999999999876e-01 5.536486726666669966e+00 4.815289200000000269e-01 +1.706957000000000058e-01 5.285752210000000062e+00 1.415798849999999887e-01 +1.716212000000000015e-01 5.016643598333329734e+00 4.522174083333330152e-01 +1.771887000000000045e-01 5.127789406666670047e+00 4.276572833333330270e-01 +1.827951999999999910e-01 5.311901800000000229e+00 4.077617766666670196e-01 +1.843146999999999980e-01 5.273006283333329769e+00 1.230909116666669967e-01 +1.883829999999999949e-01 4.028933333333330147e+00 3.832458766666669847e-01 +1.940469999999999973e-01 4.805727509999999647e+00 3.842635300000000198e-01 +1.983187999999999895e-01 4.783697818333330076e+00 1.059592133333329966e-01 +1.998358000000000079e-01 4.823453656666670142e+00 3.585670233333330126e-01 +2.056525999999999910e-01 4.659267076666670171e+00 3.454626916666669878e-01 +2.115392000000000106e-01 3.961550343333330115e+00 3.229926716666670083e-01 +2.120939000000000019e-01 4.350835990000000209e+00 9.606802500000000133e-02 +2.162656000000000023e-01 4.681036608333330129e+00 4.188060433333329891e-01 +2.260705000000000076e-01 4.224838659999999635e+00 8.541253666666670519e-02 +2.398779000000000050e-01 3.935926101666670007e+00 7.996145500000000073e-02 +2.538084999999999924e-01 3.694058728333330155e+00 7.335489833333329324e-02 +2.677318000000000198e-01 3.684019681666669932e+00 6.840629833333329579e-02 +2.818956000000000239e-01 3.452043701666669850e+00 6.355296333333329550e-02 +2.957549999999999901e-01 3.354666878333329993e+00 6.073878666666669701e-02 +3.100250999999999979e-01 3.092418856666669935e+00 5.527531000000000111e-02 +3.241909000000000041e-01 2.870290291666670157e+00 5.380070499999999728e-02 +3.389346999999999777e-01 2.729991994999999783e+00 4.836916333333329820e-02 +3.540519999999999778e-01 2.658729508333330216e+00 4.771163500000000224e-02 +3.688526999999999778e-01 2.488934241666670211e+00 4.403299000000000102e-02 +3.841308999999999974e-01 2.412009111666669980e+00 4.209804999999999797e-02 +3.990528999999999882e-01 2.203036439999999985e+00 4.070905166666669711e-02 +4.105667000000000066e-01 1.996977714666670067e+00 4.083280150000000164e-02 +4.138126999999999778e-01 2.043262161666670185e+00 3.862582833333329940e-02 +4.292300000000000004e-01 1.982205959999999934e+00 3.583282166666670182e-02 +4.294401999999999942e-01 1.834877223666669943e+00 3.458454216666669717e-02 +4.447747000000000228e-01 1.712660204999999936e+00 3.471672166666670001e-02 +4.465555999999999970e-01 1.615437673500000004e+00 3.068944266666669834e-02 +4.605119999999999769e-01 1.681440621666669966e+00 3.260043333333329657e-02 +4.684220000000000050e-01 1.529958281999999947e+00 3.049975383333329917e-02 +4.766716999999999760e-01 1.561241171666670091e+00 3.083583000000000157e-02 +4.832827000000000095e-01 1.369049060333330070e+00 2.875037449999999842e-02 +4.925123000000000140e-01 1.406416503333330015e+00 3.046807833333330107e-02 +5.045309999999999517e-01 1.316827885166669931e+00 2.677764066666669940e-02 +5.084689000000000014e-01 1.339987331666669945e+00 2.812536666666669988e-02 +5.229369999999999852e-01 1.082862526333330022e+00 2.496820599999999973e-02 +5.251208000000000542e-01 1.259172833333330077e+00 2.640966666666669932e-02 +5.418887000000000009e-01 1.134540908333329989e+00 2.596733000000000027e-02 +5.442586999999999842e-01 1.026980480500000015e+00 2.532101549999999854e-02 +5.585244000000000320e-01 1.057657990000000048e+00 2.518052499999999874e-02 +5.611156999999999950e-01 9.343203683333329845e-01 2.299225916666669881e-02 +5.756198999999999621e-01 9.598931866666670087e-01 2.319752666666670057e-02 +5.832557000000000436e-01 8.443178690000000541e-01 2.277228483333329848e-02 +5.929708999999999675e-01 9.115965033333329748e-01 2.244499833333329919e-02 +6.004186999999999719e-01 7.992612106666669991e-01 2.172028233333329894e-02 +6.101434999999999498e-01 8.528685350000000387e-01 2.184797833333329900e-02 +6.216930999999999985e-01 7.049236858333329803e-01 2.102741616666670144e-02 +6.277447999999999917e-01 7.853513183333330483e-01 2.062051499999999898e-02 +6.410417000000000476e-01 6.132204243333330140e-01 1.871036433333329863e-02 +6.449667999999999513e-01 7.011444599999999694e-01 2.101788333333329956e-02 +6.653769000000000489e-01 5.661603698333329548e-01 1.804829366666670099e-02 +6.841924999999999812e-01 5.085138883333329973e-01 2.002898349999999994e-02 +7.056272000000000100e-01 4.352650703333330040e-01 1.694186849999999855e-02 +7.256808000000000147e-01 4.355121908333329794e-01 1.820155999999999857e-02 +7.488534000000000024e-01 3.927147446666670039e-01 1.498729066666669961e-02 +7.718082000000000553e-01 3.535320510000000138e-01 1.696024266666670138e-02 +7.918933000000000222e-01 3.527103021666669891e-01 1.499266833333330086e-02 +8.152979999999999672e-01 3.240461856666669860e-01 1.528614783333329986e-02 +8.362302999999999820e-01 2.791947966666670222e-01 1.448550166666670060e-02 +8.617137999999999742e-01 2.463675190000000070e-01 1.359101549999999943e-02 +8.844106000000000467e-01 2.696912470000000228e-01 1.440389033333329925e-02 +9.079102999999999479e-01 2.246905299999999994e-01 1.256477649999999946e-02 +9.332021999999999817e-01 2.085629360000000043e-01 1.352310049999999944e-02 +9.549351000000000367e-01 1.738771078333329889e-01 1.265774100000000013e-02 +9.810423000000000338e-01 1.708308721666670082e-01 1.189189666666670003e-02 +1.006546299999999894e+00 1.505248680000000061e-01 1.228292216666669948e-02 +1.030138999999999916e+00 1.537520601666670095e-01 1.171224066666669977e-02 +1.057509599999999939e+00 1.534308791666670058e-01 1.086003916666669969e-02 +1.084319299999999986e+00 1.338797798333329903e-01 1.116524300000000004e-02 +1.109614000000000100e+00 1.189064603333330056e-01 1.082743033333329920e-02 +1.137456000000000023e+00 1.107916548333330031e-01 1.039160416666670000e-02 +1.165733499999999978e+00 1.125385351666669947e-01 1.017680349999999963e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv new file mode 100644 index 0000000000..9ae1c5f3eb --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv @@ -0,0 +1,105 @@ +3.624610000000000332e-02 5.667029333499999666e+01 1.635708034166669833e+01 +4.069289999999999713e-02 2.663486052833329865e+01 1.131616966500000032e+01 +4.510390000000000232e-02 2.091145430999999988e+01 8.353784624999999409e+00 +4.958379999999999732e-02 1.655762528666669908e+01 6.766916158333329712e+00 +5.415430000000000244e-02 7.405398096666670149e+00 5.285856098333329811e+00 +5.867970000000000130e-02 1.609157327499999823e+01 4.579871853333330023e+00 +6.314219999999999555e-02 2.074624494500000083e+01 3.774208823333330187e+00 +6.772359999999999491e-02 1.622769223499999924e+01 3.121007619999999871e+00 +7.237720000000000264e-02 8.100976058333330343e+00 2.681633823333330113e+00 +7.692999999999999838e-02 7.297140411666670268e+00 2.370097993333330155e+00 +8.165179999999999660e-02 8.662000215000000836e+00 1.993900453333329992e+00 +8.640209999999999557e-02 1.195176863500000053e+01 1.811378463333330080e+00 +9.107550000000000368e-02 1.017929826333329935e+01 1.581605778333329937e+00 +9.574539999999999440e-02 8.299761948333330253e+00 1.447854706666670044e+00 +1.005039999999999961e-01 7.184010728333330320e+00 1.267957188333330043e+00 +1.052488000000000035e-01 7.705754226666670093e+00 1.175315996666669971e+00 +1.099981000000000014e-01 6.940137736666669888e+00 1.050239939999999983e+00 +1.148520999999999986e-01 7.227232895000000212e+00 9.582211533333330200e-01 +1.197872999999999993e-01 6.058664864999999899e+00 8.747766333333329980e-01 +1.247806000000000054e-01 5.235616768333329674e+00 8.060124016666669888e-01 +1.298481999999999970e-01 6.895559143333329644e+00 7.374701233333329498e-01 +1.349194999999999978e-01 5.596115646666669718e+00 7.017485283333330104e-01 +1.399364999999999915e-01 7.271002904999999572e+00 6.515097483333329720e-01 +1.450858999999999899e-01 5.001139740000000167e+00 6.081432883333329764e-01 +1.502787999999999902e-01 5.397041578333330314e+00 5.852662783333330010e-01 +1.556196999999999997e-01 5.201047356666670396e+00 5.230793849999999523e-01 +1.572660999999999920e-01 5.527525920000000426e+00 1.689539216666670063e-01 +1.609609999999999930e-01 6.050507654999999652e+00 5.103277550000000495e-01 +1.662019000000000135e-01 5.215723743333329665e+00 4.792083599999999999e-01 +1.706513000000000058e-01 5.031433279999999897e+00 1.411615750000000113e-01 +1.715762999999999872e-01 4.986483428333330359e+00 4.534299233333329848e-01 +1.771423000000000025e-01 5.106750501666669884e+00 4.289189133333329851e-01 +1.827474000000000043e-01 5.398633823333329751e+00 4.103611200000000236e-01 +1.842668000000000084e-01 4.914610723333329823e+00 1.221897900000000065e-01 +1.883336999999999928e-01 4.776135458333330419e+00 3.942386333333329773e-01 +1.939963000000000104e-01 4.310256373333330338e+00 3.794851616666670147e-01 +1.982673000000000074e-01 4.375084450000000125e+00 1.047416733333329936e-01 +1.997836000000000056e-01 4.425991520000000179e+00 3.548793383333330165e-01 +2.055989000000000011e-01 4.542295369999999721e+00 3.452195166666670034e-01 +2.114837999999999996e-01 4.392925553333330235e+00 3.296180283333329797e-01 +2.120387999999999995e-01 4.102498828333329683e+00 9.538819833333339604e-02 +2.162090000000000123e-01 4.067448908333330060e+00 4.099168333333330083e-01 +2.260118000000000127e-01 3.879140883333330070e+00 8.427184499999999800e-02 +2.398155999999999899e-01 3.717842756666669857e+00 7.930888666666670306e-02 +2.537425999999999848e-01 3.531988756666669893e+00 7.293178499999999898e-02 +2.676623000000000197e-01 3.501111030000000124e+00 6.786378666666670334e-02 +2.818223999999999729e-01 3.329498083333330083e+00 6.325724833333329356e-02 +2.956782000000000021e-01 3.079447669999999970e+00 5.969948499999999658e-02 +3.099446000000000145e-01 2.946954811666670171e+00 5.483356999999999815e-02 +3.241067000000000253e-01 2.705831398333330196e+00 5.323661166666669720e-02 +3.388467000000000007e-01 2.601996516666670090e+00 4.799289000000000333e-02 +3.539599999999999969e-01 2.517872383333330077e+00 4.725612833333329987e-02 +3.687568999999999986e-01 2.374362781666670141e+00 4.368410333333330037e-02 +3.840311000000000141e-01 2.195996148333330122e+00 4.125977166666670165e-02 +3.989493000000000067e-01 2.109030429999999789e+00 4.042385333333330111e-02 +4.107986000000000137e-01 1.888483604166669938e+00 4.043749766666669687e-02 +4.137051999999999952e-01 1.969810571666670063e+00 3.843483833333329741e-02 +4.291185000000000138e-01 1.859797011666669997e+00 3.539587999999999762e-02 +4.296826999999999730e-01 1.762954635166670059e+00 3.439219566666670141e-02 +4.446591999999999767e-01 1.624618943333330012e+00 3.443567000000000156e-02 +4.468077999999999772e-01 1.588049316333330019e+00 3.067751716666669917e-02 +4.603923999999999794e-01 1.585295316666669896e+00 3.227559333333329672e-02 +4.686866000000000088e-01 1.509168766666669992e+00 3.051112400000000058e-02 +4.765479000000000243e-01 1.429500135000000061e+00 3.031986666666669841e-02 +4.835556999999999772e-01 1.309360340500000053e+00 2.857159116666670162e-02 +4.923843999999999999e-01 1.363123808333329912e+00 3.037624166666669928e-02 +5.048160000000000425e-01 1.296483956833329954e+00 2.677855866666669846e-02 +5.083368000000000331e-01 1.254868451666669937e+00 2.782200166666669999e-02 +5.232324000000000419e-01 1.028253859833329953e+00 2.481625150000000071e-02 +5.249844000000000177e-01 1.223231273333329927e+00 2.634227000000000096e-02 +5.417480000000000073e-01 1.058531658333329961e+00 2.569255333333329838e-02 +5.445661000000000529e-01 1.022632484000000064e+00 2.537817800000000124e-02 +5.583793000000000228e-01 1.009770163333330029e+00 2.504100833333329848e-02 +5.614325999999999484e-01 9.522996788333329965e-01 2.313905700000000107e-02 +5.754704000000000486e-01 9.158985283333339611e-01 2.307270666666669939e-02 +5.835850999999999678e-01 8.544030651666669751e-01 2.288279616666670166e-02 +5.928168000000000326e-01 8.553651300000000290e-01 2.224781666666670113e-02 +6.007578000000000085e-01 7.747371155000000176e-01 2.167619850000000042e-02 +6.099849999999999994e-01 7.987110383333330121e-01 2.165553833333330042e-02 +6.220442000000000471e-01 6.615610463333330138e-01 2.089781950000000124e-02 +6.275817000000000201e-01 7.150054516666669580e-01 2.035196333333329916e-02 +6.414037999999999684e-01 6.088626698333330367e-01 1.874337833333329997e-02 +6.447992000000000168e-01 6.630811316666670452e-01 2.089752166666669977e-02 +6.657526999999999751e-01 5.716572943333330103e-01 1.811807299999999843e-02 +6.845788999999999902e-01 5.092866856666670161e-01 2.008440916666669879e-02 +7.060256999999999783e-01 4.113589818333330261e-01 1.688841199999999848e-02 +7.260906999999999778e-01 4.258370573333329911e-01 1.820484666666670123e-02 +7.492763000000000062e-01 3.814062795000000006e-01 1.498164383333329928e-02 +7.722440999999999889e-01 3.582434820000000020e-01 1.702263550000000097e-02 +7.923405000000000031e-01 3.290160251666670033e-01 1.493438950000000078e-02 +8.157583999999999946e-01 3.190799841666669967e-01 1.530228649999999975e-02 +8.367025000000000157e-01 2.762952625000000273e-01 1.450753649999999943e-02 +8.622005000000000363e-01 2.544186793333330088e-01 1.365137966666669922e-02 +8.849101000000000328e-01 2.424038613333329983e-01 1.432358516666669933e-02 +9.084231000000000389e-01 2.172930054999999971e-01 1.256612799999999933e-02 +9.337292000000000369e-01 2.202721591666670087e-01 1.359930866666670020e-02 +9.554743999999999460e-01 1.777866800000000025e-01 1.269970833333330072e-02 +9.815962999999999772e-01 1.676419470000000134e-01 1.190602366666669923e-02 +1.007114700000000029e+00 1.595580418333329975e-01 1.234223233333330005e-02 +1.030720700000000045e+00 1.541775503333329966e-01 1.173861049999999975e-02 +1.058106800000000014e+00 1.554276226666669869e-01 1.088984299999999975e-02 +1.084931700000000054e+00 1.440364893333329899e-01 1.122487333333329999e-02 +1.110240600000000022e+00 1.198653424999999995e-01 1.085281416666670010e-02 +1.138098400000000066e+00 1.211473946666670048e-01 1.044690799999999954e-02 +1.166391799999999979e+00 1.189307901666669942e-01 1.021903716666669980e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv new file mode 100644 index 0000000000..ee5f13e079 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 6.302187949999999717e+01 1.635904319500000170e+01 +4.070000000000000007e-02 2.785521429499999968e+01 1.130956581166669928e+01 +4.511180000000000051e-02 1.008215536333329965e+01 8.312546360000000689e+00 +4.959249999999999770e-02 1.581932412333330085e+01 6.758513281666670203e+00 +5.416379999999999806e-02 7.750620351666669627e+00 5.282679641666669923e+00 +5.868999999999999911e-02 1.257659237500000060e+01 4.560014873333329888e+00 +6.315320000000000655e-02 1.891331758666670027e+01 3.761777425000000008e+00 +6.773540000000000116e-02 1.328150150333330082e+01 3.102479755000000061e+00 +7.238989999999999314e-02 9.795755306666670492e+00 2.689289660000000026e+00 +7.694339999999999513e-02 1.021541878833330053e+01 2.386645821666669942e+00 +8.166600000000000248e-02 7.264236756666670125e+00 1.982897978333330036e+00 +8.641719999999999957e-02 9.727612021666670827e+00 1.793249476666670006e+00 +9.109140000000000292e-02 9.940133039999999198e+00 1.578285125000000066e+00 +9.576210000000000278e-02 5.869161616666669801e+00 1.426304660000000002e+00 +1.005216000000000026e-01 6.271050506666670188e+00 1.258989316666669911e+00 +1.052672000000000052e-01 4.575212496666670070e+00 1.144957958333330028e+00 +1.100174000000000013e-01 6.675946670000000083e+00 1.046739891666669919e+00 +1.148721999999999938e-01 4.569861300000000348e+00 9.307519933333330275e-01 +1.198083000000000065e-01 4.073412075000000243e+00 8.536948699999999945e-01 +1.248023999999999939e-01 5.517398765000000260e+00 8.081908083333330106e-01 +1.298709000000000113e-01 6.055929844999999645e+00 7.277152516666669513e-01 +1.349431000000000103e-01 4.214499321666670184e+00 6.853886750000000028e-01 +1.399610000000000021e-01 4.711855326666669619e+00 6.206856016666669751e-01 +1.451112999999999986e-01 4.280988370000000209e+00 5.992362466666669718e-01 +1.503050999999999970e-01 3.350940026666669791e+00 5.604130616666670450e-01 +1.556469000000000047e-01 4.037392881666669986e+00 5.086757983333329847e-01 +1.572660999999999920e-01 4.116049464999999685e+00 1.639383783333329958e-01 +1.609891999999999990e-01 4.767404383333330387e+00 4.936060199999999787e-01 +1.662309999999999899e-01 4.092517224999999925e+00 4.643677516666669947e-01 +1.706513000000000058e-01 3.775210913333329810e+00 1.365719850000000068e-01 +1.716062999999999894e-01 4.067082121666669714e+00 4.413313999999999848e-01 +1.771733000000000058e-01 3.397890750000000182e+00 4.070909349999999871e-01 +1.827794000000000085e-01 4.061001236666670344e+00 3.925402433333329832e-01 +1.842668000000000084e-01 3.799252254999999856e+00 1.178310383333329991e-01 +1.883665999999999952e-01 3.208655455000000156e+00 3.733191000000000148e-01 +1.940302000000000138e-01 3.206445976666670195e+00 3.650098783333329822e-01 +1.982673000000000074e-01 3.425276903333330125e+00 1.008325449999999956e-01 +1.998185000000000100e-01 3.354815260000000077e+00 3.406662516666669749e-01 +2.056348000000000065e-01 3.721227830000000125e+00 3.339491649999999923e-01 +2.115208000000000088e-01 3.612948971666670062e+00 3.193275150000000062e-01 +2.120387999999999995e-01 3.205896688333329969e+00 9.145261000000000362e-02 +2.162467999999999890e-01 3.645113248333330169e+00 4.021025750000000176e-01 +2.260118000000000127e-01 3.104582965000000083e+00 8.081593333333329798e-02 +2.398155999999999899e-01 3.037513673333330111e+00 7.613482000000000582e-02 +2.537425999999999848e-01 2.836682165000000033e+00 6.969811833333329487e-02 +2.676623000000000197e-01 2.819590748333329788e+00 6.462849833333329796e-02 +2.818223999999999729e-01 2.721404538333330070e+00 6.033223166666670106e-02 +2.956782000000000021e-01 2.736251186666669888e+00 5.799425166666669768e-02 +3.099446000000000145e-01 2.543946483333329844e+00 5.286760000000000070e-02 +3.241067000000000253e-01 2.287160831666669836e+00 5.112056499999999976e-02 +3.388467000000000007e-01 2.288673078333329780e+00 4.649771999999999933e-02 +3.539599999999999969e-01 2.199149091666670053e+00 4.568711999999999773e-02 +3.687568999999999986e-01 2.068072668333329922e+00 4.217328666666669834e-02 +3.840311000000000141e-01 1.969221529999999998e+00 4.012745166666670249e-02 +3.989493000000000067e-01 1.908232941666669902e+00 3.938963333333329875e-02 +4.107629999999999892e-01 1.727702871333330004e+00 3.958386533333330126e-02 +4.137051999999999952e-01 1.726875600000000066e+00 3.720425833333330240e-02 +4.291185000000000138e-01 1.581841901666670047e+00 3.398506666666670228e-02 +4.296455000000000135e-01 1.691278518333330094e+00 3.404221949999999830e-02 +4.446591999999999767e-01 1.488087740000000103e+00 3.374035333333329917e-02 +4.467690999999999746e-01 1.413946998166669911e+00 2.991126200000000096e-02 +4.603923999999999794e-01 1.391984139999999925e+00 3.130147333333330173e-02 +4.686460000000000070e-01 1.392956528666670080e+00 2.997462383333330052e-02 +4.765479000000000243e-01 1.301627080000000047e+00 2.965699000000000113e-02 +4.835137999999999936e-01 1.193676802499999967e+00 2.800566683333330018e-02 +4.923843999999999999e-01 1.242278698333330045e+00 2.973970833333329858e-02 +5.047722000000000042e-01 1.149708217833329993e+00 2.613050733333329920e-02 +5.083368000000000331e-01 1.161310218333329924e+00 2.733334000000000111e-02 +5.231871000000000160e-01 9.503032668333329935e-01 2.446244750000000148e-02 +5.249844000000000177e-01 1.102167341666669964e+00 2.571981833333330039e-02 +5.417480000000000073e-01 9.754589783333329489e-01 2.525416166666670167e-02 +5.445189000000000279e-01 9.366835949999999800e-01 2.497178450000000008e-02 +5.583793000000000228e-01 8.831162099999999571e-01 2.438054666666670048e-02 +5.613839000000000468e-01 8.824506341666670250e-01 2.281443349999999828e-02 +5.754704000000000486e-01 8.100822066666669707e-01 2.253018666666670167e-02 +5.835346000000000144e-01 7.776236106666669645e-01 2.252483566666670101e-02 +5.928168000000000326e-01 7.764561633333330049e-01 2.182597999999999830e-02 +6.007057000000000091e-01 6.983251131666670108e-01 2.131793766666669962e-02 +6.099849999999999994e-01 7.099790583333329685e-01 2.117932666666669933e-02 +6.219902999999999960e-01 6.466382168333330016e-01 2.081252199999999997e-02 +6.275817000000000201e-01 6.603706066666670260e-01 2.006477833333330033e-02 +6.413482000000000349e-01 5.710830485000000234e-01 1.856948533333329862e-02 +6.447992000000000168e-01 5.732715750000000332e-01 2.040912500000000018e-02 +6.656950000000000367e-01 5.203726888333329859e-01 1.789587166666670170e-02 +6.845196000000000058e-01 4.749653629999999738e-01 1.990720683333329841e-02 +7.059646000000000532e-01 3.822856073333329996e-01 1.675657983333329881e-02 +7.260278000000000009e-01 3.886542691666670102e-01 1.802539466666670115e-02 +7.492113999999999718e-01 3.564554191666670091e-01 1.487377883333330063e-02 +7.721772000000000080e-01 3.333074428333330230e-01 1.689668533333330003e-02 +7.922717999999999705e-01 3.187338046666670088e-01 1.488059016666670037e-02 +8.156877999999999629e-01 3.010368924999999862e-01 1.521491216666670011e-02 +8.366301000000000432e-01 2.406595508333330136e-01 1.435568400000000050e-02 +8.621258000000000532e-01 2.223576200000000058e-01 1.352156766666669924e-02 +8.848333999999999921e-01 2.207387865000000060e-01 1.422139816666669922e-02 +9.083444000000000518e-01 2.134049949999999862e-01 1.254214099999999971e-02 +9.336484000000000449e-01 1.885945263333330124e-01 1.346345033333330027e-02 +9.553916000000000075e-01 1.698076676666669949e-01 1.265998783333329922e-02 +9.815112999999999754e-01 1.668850050000000029e-01 1.189438716666670059e-02 +1.007027499999999964e+00 1.441018685000000077e-01 1.227580483333329947e-02 +1.030631400000000086e+00 1.406578583333329968e-01 1.168073399999999991e-02 +1.058015099999999986e+00 1.399035711666669901e-01 1.082874783333329961e-02 +1.084837700000000016e+00 1.486492919999999884e-01 1.123307866666669978e-02 +1.110144500000000090e+00 1.008698655000000027e-01 1.077987283333329931e-02 +1.137999800000000006e+00 1.027075286666670056e-01 1.037853683333330064e-02 +1.166290800000000072e+00 1.157098001666670012e-01 1.020088966666670045e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv new file mode 100644 index 0000000000..1c5c261ee3 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 2.859171986188329811e+03 2.282233352000000082e+01 +4.070000000000000007e-02 1.037695935384999984e+03 1.390765389166669941e+01 +4.511180000000000051e-02 4.617414862783330136e+02 9.644274246666670436e+00 +4.959249999999999770e-02 2.830472148050000101e+02 7.651757100000000200e+00 +5.416379999999999806e-02 1.737180786733329967e+02 5.901133003333329796e+00 +5.868999999999999911e-02 1.284318533800000068e+02 5.055296333333330061e+00 +6.315320000000000655e-02 1.083304533916670067e+02 4.179970964999999872e+00 +6.773540000000000116e-02 8.164665742500000079e+01 3.449109084999999908e+00 +7.238989999999999314e-02 6.842710629666669320e+01 3.015091889999999886e+00 +7.694339999999999513e-02 6.503887503333329789e+01 2.712566869999999852e+00 +8.166600000000000248e-02 5.768616606333330310e+01 2.292022508333329878e+00 +8.641719999999999957e-02 4.726633163000000337e+01 2.052834279999999900e+00 +9.109140000000000292e-02 4.170182763166670270e+01 1.806841736666670029e+00 +9.576210000000000278e-02 3.278791741500000256e+01 1.635979810000000034e+00 +1.005216000000000026e-01 3.137094696333329935e+01 1.457612156666669989e+00 +1.052672000000000052e-01 2.858316747499999977e+01 1.352856671666669897e+00 +1.100174000000000013e-01 2.685582243333330155e+01 1.222659363333330029e+00 +1.148721999999999938e-01 2.463809722666670154e+01 1.115379456666669933e+00 +1.198083000000000065e-01 1.979913578000000030e+01 1.002652691666670037e+00 +1.248023999999999939e-01 1.884005529499999909e+01 9.371682333333329895e-01 +1.298709000000000113e-01 2.011378014833330141e+01 8.660532583333330203e-01 +1.349431000000000103e-01 1.548196221999999977e+01 8.040137483333329449e-01 +1.399610000000000021e-01 1.553817986500000004e+01 7.396018783333330182e-01 +1.451112999999999986e-01 1.380290046833330031e+01 7.008050850000000498e-01 +1.503050999999999970e-01 1.290957537833329916e+01 6.659874700000000258e-01 +1.556469000000000047e-01 1.188963399333329995e+01 5.958023666666669715e-01 +1.572456999999999883e-01 1.305280697499999931e+01 1.930089849999999940e-01 +1.609891999999999990e-01 1.134609165166670053e+01 5.714861916666670316e-01 +1.662309999999999899e-01 1.103891432833330022e+01 5.468199316666669807e-01 +1.706292000000000086e-01 1.121912493499999997e+01 1.614639983333329976e-01 +1.716062999999999894e-01 1.098087770333330049e+01 5.221648316666670508e-01 +1.771733000000000058e-01 9.846715853333330770e+00 4.826313150000000052e-01 +1.827794000000000085e-01 1.030369242166669963e+01 4.679303400000000002e-01 +1.842428999999999872e-01 9.629214631666670243e+00 1.387244099999999924e-01 +1.883665999999999952e-01 9.108624106666670883e+00 4.454082083333330000e-01 +1.940302000000000138e-01 8.056377178333329780e+00 4.232006716666670276e-01 +1.982414999999999872e-01 8.605072379999999299e+00 1.202604099999999981e-01 +1.998185000000000100e-01 8.229729869999999892e+00 3.995894999999999864e-01 +2.056348000000000065e-01 8.070094290000000115e+00 3.879820366666669740e-01 +2.115208000000000088e-01 7.741634115000000094e+00 3.686955350000000187e-01 +2.120113000000000136e-01 7.664225765000000301e+00 1.093220133333329958e-01 +2.162467999999999890e-01 7.363320653333330412e+00 4.626756216666669808e-01 +2.259823999999999999e-01 6.848802841666669750e+00 9.609777999999999376e-02 +2.397845000000000115e-01 6.337189861666669977e+00 9.020952999999999611e-02 +2.537096999999999825e-01 5.738702153333330003e+00 8.211384833333329469e-02 +2.676275000000000182e-01 5.346591223333329701e+00 7.572218666666670484e-02 +2.817857999999999752e-01 5.009933698333330021e+00 7.051459333333330581e-02 +2.956398000000000081e-01 4.597692046666669974e+00 6.646157833333329878e-02 +3.099044000000000243e-01 4.193400725000000051e+00 6.031815000000000093e-02 +3.240645999999999805e-01 3.804645918333330101e+00 5.825413166666670167e-02 +3.388027000000000122e-01 3.560888523333329836e+00 5.213344166666669666e-02 +3.539140000000000064e-01 3.375211385000000064e+00 5.107971833333330158e-02 +3.687090000000000090e-01 3.188264295000000192e+00 4.732182333333329743e-02 +3.839813000000000254e-01 2.892990108333330035e+00 4.441047333333329739e-02 +3.988975000000000160e-01 2.640608908333330174e+00 4.290645666666669661e-02 +4.106379000000000001e-01 2.501690660833329805e+00 4.331324033333330131e-02 +4.136514000000000024e-01 2.477246653333330162e+00 4.077528500000000139e-02 +4.290628000000000219e-01 2.358423203333329887e+00 3.769917166666669761e-02 +4.295145000000000213e-01 2.266923564999999918e+00 3.645828216666670285e-02 +4.446014999999999828e-01 2.023246533333329822e+00 3.627248666666670063e-02 +4.466328999999999994e-01 2.032174506166669836e+00 3.243397416666669864e-02 +4.603325999999999807e-01 1.951935533333329920e+00 3.395880333333330114e-02 +4.685032000000000085e-01 1.797322475499999905e+00 3.168831166666669780e-02 +4.764860000000000206e-01 1.814704324999999896e+00 3.212894000000000166e-02 +4.833663999999999739e-01 1.722621554333330085e+00 3.037123383333329915e-02 +4.923204999999999942e-01 1.658358661666669898e+00 3.178619500000000320e-02 +5.046184000000000225e-01 1.539108265666669917e+00 2.774163983333330016e-02 +5.082708000000000226e-01 1.547966548333330028e+00 2.920229666666670013e-02 +5.230276000000000369e-01 1.345057283333330078e+00 2.608127533333329945e-02 +5.249162000000000550e-01 1.417396718333330030e+00 2.724554333333329900e-02 +5.416775999999999813e-01 1.270799306666670070e+00 2.670250999999999875e-02 +5.443529999999999758e-01 1.250087865666670073e+00 2.633086933333329827e-02 +5.583067999999999920e-01 1.165305416666670091e+00 2.577655499999999961e-02 +5.612129000000000145e-01 1.147836548999999984e+00 2.393862083333329893e-02 +5.753956999999999544e-01 1.115183805000000028e+00 2.400332833333329932e-02 +5.833568000000000087e-01 1.044019996999999922e+00 2.366755300000000090e-02 +5.927398999999999862e-01 1.004017331666670065e+00 2.296542000000000028e-02 +6.005226999999999649e-01 9.482225546666670501e-01 2.240195116666670108e-02 +6.099058000000000535e-01 9.388455449999999480e-01 2.233828499999999939e-02 +6.218008000000000424e-01 8.511757086666670302e-01 2.168908733333330119e-02 +6.275003000000000108e-01 8.553386066666669452e-01 2.101305833333329959e-02 +6.411527999999999672e-01 7.761240236666669956e-01 1.940277716666670080e-02 +6.447154999999999969e-01 7.270576883333329521e-01 2.120466833333330137e-02 +6.654921999999999782e-01 7.007768106666669716e-01 1.861042133333330045e-02 +6.843110000000000026e-01 6.466361541666669766e-01 2.069310833333330019e-02 +7.057493999999999712e-01 5.771519323333329510e-01 1.752841666666669906e-02 +7.258065000000000211e-01 5.204018098333329512e-01 1.860044799999999859e-02 +7.489831000000000127e-01 4.984340896666670240e-01 1.540761000000000040e-02 +7.719418000000000113e-01 4.436713720000000083e-01 1.738589999999999927e-02 +7.920304000000000233e-01 4.316635041666669892e-01 1.532890283333330009e-02 +8.154392000000000307e-01 3.868879691666670118e-01 1.556857449999999969e-02 +8.363751000000000380e-01 3.670109628333330098e-01 1.484866983333330004e-02 +8.618630000000000457e-01 3.329731463333330255e-01 1.392995016666669951e-02 +8.845638000000000112e-01 3.302565831666670060e-01 1.467645416666669977e-02 +9.080675999999999748e-01 2.757098590000000016e-01 1.276754683333329934e-02 +9.333637999999999657e-01 2.804865558333329845e-01 1.382540016666669938e-02 +9.551005000000000189e-01 2.398962168333330092e-01 1.292395533333329932e-02 +9.812121999999999788e-01 2.360268241666670097e-01 1.213837400000000039e-02 +1.006720599999999965e+00 2.134167958333330062e-01 1.253179649999999930e-02 +1.030317399999999939e+00 2.102511210000000130e-01 1.193319533333330081e-02 +1.057692700000000041e+00 2.135461601666669984e-01 1.107935333333330032e-02 +1.084507099999999946e+00 1.969431385000000034e-01 1.140526600000000071e-02 +1.109806099999999907e+00 1.561050018333330069e-01 1.096976283333329916e-02 +1.137653000000000025e+00 1.629041234999999976e-01 1.057719600000000051e-02 +1.165935399999999955e+00 1.774132069999999894e-01 1.040658966666670009e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv new file mode 100644 index 0000000000..3fc8956177 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv @@ -0,0 +1,105 @@ +3.623980000000000257e-02 4.717095203250000282e+02 1.736400694499999986e+01 +4.068580000000000113e-02 2.786014172683330230e+02 1.198827076999999974e+01 +4.509610000000000007e-02 1.807710803516669955e+02 8.834240069999999889e+00 +4.957530000000000270e-02 1.404167299050000111e+02 7.187393765000000379e+00 +5.414490000000000275e-02 1.070548824566670021e+02 5.660295944999999662e+00 +5.866960000000000230e-02 9.429733434666670178e+01 4.914365443333330141e+00 +6.313130000000000130e-02 8.753748113499999306e+01 4.086659178333330367e+00 +6.771190000000000542e-02 8.007891920833330346e+01 3.441741584999999937e+00 +7.236470000000000402e-02 5.999202779333329971e+01 2.970499293333329849e+00 +7.691660000000000164e-02 5.902839900166669906e+01 2.678938321666669786e+00 +8.163760000000000461e-02 4.960764509333330352e+01 2.245417474999999996e+00 +8.638719999999999732e-02 4.414010876166670272e+01 2.032560301666670011e+00 +9.105969999999999342e-02 4.256424763833329905e+01 1.812761751666670085e+00 +9.572880000000000278e-02 3.308233848333330229e+01 1.638201501666670001e+00 +1.004865999999999954e-01 2.810971494833329842e+01 1.433384486666670066e+00 +1.052305999999999936e-01 2.588485028666670118e+01 1.331128581666670030e+00 +1.099790999999999963e-01 2.266535039333329848e+01 1.188278135000000013e+00 +1.148321999999999954e-01 2.068870146000000076e+01 1.081535063333330049e+00 +1.197666000000000008e-01 1.976825064833330003e+01 1.002416109999999971e+00 +1.247589999999999949e-01 1.708519936000000072e+01 9.212166283333329542e-01 +1.298257999999999912e-01 1.961539944500000132e+01 8.615532866666669731e-01 +1.348960999999999910e-01 1.509279464499999968e+01 8.002327049999999886e-01 +1.399122999999999895e-01 1.461401991333329953e+01 7.302237983333329518e-01 +1.450607999999999898e-01 1.234817605166669985e+01 6.862621599999999544e-01 +1.502527999999999919e-01 1.236984282499999921e+01 6.604921383333329787e-01 +1.555927000000000004e-01 1.196552256666669933e+01 5.966093183333329719e-01 +1.572660999999999920e-01 1.278021405166670021e+01 1.919547649999999994e-01 +1.609331999999999985e-01 1.153752966666669977e+01 5.736198133333330063e-01 +1.661730999999999903e-01 1.078861117833329963e+01 5.440816866666670082e-01 +1.706513000000000058e-01 1.087118622666669943e+01 1.601861350000000073e-01 +1.715465999999999935e-01 9.877732214999999982e+00 5.101304616666669789e-01 +1.771117000000000108e-01 1.016148657499999963e+01 4.860413033333330080e-01 +1.827158000000000115e-01 1.012859923499999937e+01 4.659961616666670192e-01 +1.842668000000000084e-01 9.892309961666670759e+00 1.394281016666669981e-01 +1.883010999999999990e-01 9.370592901666670471e+00 4.483600366666670167e-01 +1.939626999999999879e-01 7.953713988333330320e+00 4.220674716666670268e-01 +1.982673000000000074e-01 8.536490116666669792e+00 1.198682733333329975e-01 +1.997490000000000099e-01 8.016174306666670191e+00 3.972042266666669930e-01 +2.055633000000000044e-01 7.936747634999999690e+00 3.864501066666670148e-01 +2.114472000000000018e-01 7.092097319999999705e+00 3.613801233333330254e-01 +2.120387999999999995e-01 7.719984431666669700e+00 1.093860133333330042e-01 +2.161715999999999915e-01 7.279911723333330364e+00 4.614210216666669861e-01 +2.260118000000000127e-01 6.899103116666670310e+00 9.616077666666669743e-02 +2.398155999999999899e-01 6.131303501666669931e+00 8.927448999999999801e-02 +2.537425999999999848e-01 5.657937448333330011e+00 8.168489666666670090e-02 +2.676623000000000197e-01 5.142021448333330191e+00 7.478100833333330144e-02 +2.818223999999999729e-01 4.914665098333330207e+00 7.002304500000000598e-02 +2.956782000000000021e-01 4.446721935000000236e+00 6.572301166666670580e-02 +3.099446000000000145e-01 4.282954679999999570e+00 6.061547666666670248e-02 +3.241067000000000253e-01 3.767117071666670203e+00 5.800978500000000121e-02 +3.388467000000000007e-01 3.499952983333329826e+00 5.180699999999999888e-02 +3.539599999999999969e-01 3.303444670000000194e+00 5.069738166666670071e-02 +3.687568999999999986e-01 2.950319708333330126e+00 4.620904333333329672e-02 +3.840311000000000141e-01 2.864367984999999894e+00 4.422433499999999656e-02 +3.989493000000000067e-01 2.552979848333329915e+00 4.244176999999999672e-02 +4.107629999999999892e-01 2.431688859833330163e+00 4.295243233333329719e-02 +4.137051999999999952e-01 2.340746346666669808e+00 4.009275166666669693e-02 +4.291185000000000138e-01 2.236674611666670032e+00 3.708904500000000104e-02 +4.296455000000000135e-01 2.145105044333329936e+00 3.592934700000000037e-02 +4.446591999999999767e-01 1.951663006666670030e+00 3.589577499999999782e-02 +4.467690999999999746e-01 1.941018092166669984e+00 3.204738566666669869e-02 +4.603923999999999794e-01 1.841567858333329921e+00 3.340552499999999841e-02 +4.686460000000000070e-01 1.795296687500000044e+00 3.165418133333330192e-02 +4.765479000000000243e-01 1.725552725000000009e+00 3.166947999999999985e-02 +4.835137999999999936e-01 1.648896234833330032e+00 3.002704050000000111e-02 +4.923843999999999999e-01 1.592235150000000043e+00 3.142748499999999806e-02 +5.047722000000000042e-01 1.524318554666669989e+00 2.765916716666669967e-02 +5.083368000000000331e-01 1.470192684999999999e+00 2.879683666666670028e-02 +5.231871000000000160e-01 1.276008043333330066e+00 2.578494833333330044e-02 +5.249844000000000177e-01 1.335736669999999959e+00 2.682150333333329847e-02 +5.417480000000000073e-01 1.255200871666670048e+00 2.659473333333330081e-02 +5.445189000000000279e-01 1.181751707666669926e+00 2.602010650000000092e-02 +5.583793000000000228e-01 1.119981195000000040e+00 2.552491833333329907e-02 +5.613839000000000468e-01 1.109540133333329903e+00 2.376074416666670158e-02 +5.754704000000000486e-01 1.035568078333330089e+00 2.359670999999999991e-02 +5.835346000000000144e-01 1.009673415166669974e+00 2.350527950000000019e-02 +5.928168000000000326e-01 9.958746566666669686e-01 2.289775833333329916e-02 +6.007057000000000091e-01 9.162153768333329840e-01 2.224946400000000005e-02 +6.099849999999999994e-01 8.912180400000000446e-01 2.207391333333329902e-02 +6.219902999999999960e-01 8.127960751666669648e-01 2.151158183333330004e-02 +6.275817000000000201e-01 8.004247816666669735e-01 2.072389499999999912e-02 +6.413482000000000349e-01 7.426332359999999744e-01 1.925514349999999861e-02 +6.447992000000000168e-01 7.076525866666669717e-01 2.108122000000000121e-02 +6.656950000000000367e-01 6.442563610000000551e-01 1.837696600000000152e-02 +6.845196000000000058e-01 6.085390748333330269e-01 2.050695833333330068e-02 +7.059646000000000532e-01 5.280073378333329792e-01 1.732566899999999840e-02 +7.260278000000000009e-01 5.220653703333330009e-01 1.859470200000000115e-02 +7.492113999999999718e-01 4.598426163333330097e-01 1.525465250000000023e-02 +7.721772000000000080e-01 4.332637708333330062e-01 1.732895283333329983e-02 +7.922717999999999705e-01 4.105990393333330268e-01 1.523655316666669944e-02 +8.156877999999999629e-01 3.602943534999999975e-01 1.545041316666669919e-02 +8.366301000000000432e-01 3.406887861666669792e-01 1.473824349999999957e-02 +8.621258000000000532e-01 3.067601776666670221e-01 1.382606316666670082e-02 +8.848333999999999921e-01 3.015524316666670090e-01 1.454982116666670051e-02 +9.083444000000000518e-01 2.607474308333330160e-01 1.270642616666669937e-02 +9.336484000000000449e-01 2.588003018333330241e-01 1.373286349999999940e-02 +9.553916000000000075e-01 2.226530176666670080e-01 1.285228899999999938e-02 +9.815112999999999754e-01 2.127235584999999929e-01 1.205009299999999957e-02 +1.007027499999999964e+00 2.082924603333330127e-01 1.250585733333330063e-02 +1.030631400000000086e+00 1.912464838333330086e-01 1.185822249999999960e-02 +1.058015099999999986e+00 1.948314409999999941e-01 1.101004149999999966e-02 +1.084837700000000016e+00 1.896849941666670092e-01 1.137308499999999979e-02 +1.110144500000000090e+00 1.497566153333330097e-01 1.094208966666669960e-02 +1.137999800000000006e+00 1.454676966666670068e-01 1.051448583333330043e-02 +1.166290800000000072e+00 1.467227160000000030e-01 1.029956333333329963e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv new file mode 100644 index 0000000000..5ef6a32666 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 2.531792558183329902e+02 1.680830338499999854e+01 +4.070000000000000007e-02 1.901177223299999923e+02 1.173664666500000031e+01 +4.511180000000000051e-02 1.217924648083329942e+02 8.645296186666669769e+00 +4.959249999999999770e-02 1.094275780066670052e+02 7.073034475000000043e+00 +5.416379999999999806e-02 8.791320813333329909e+01 5.581711248333330211e+00 +5.868999999999999911e-02 8.309104453833330695e+01 4.860535583333329690e+00 +6.315320000000000655e-02 7.081360745666670198e+01 4.003961999999999577e+00 +6.773540000000000116e-02 6.343291181166669901e+01 3.355398363333330192e+00 +7.238989999999999314e-02 4.842191466166669755e+01 2.903796691666669982e+00 +7.694339999999999513e-02 4.694420552666669977e+01 2.605583116666669863e+00 +8.166600000000000248e-02 4.367521950333330238e+01 2.207077676666670207e+00 +8.641719999999999957e-02 3.957930205499999943e+01 1.999356729999999915e+00 +9.109140000000000292e-02 3.553857484166670133e+01 1.762052579999999979e+00 +9.576210000000000278e-02 2.783675838666669833e+01 1.597004463333330015e+00 +1.005216000000000026e-01 2.705964543666669897e+01 1.423240978333329965e+00 +1.052672000000000052e-01 2.262947438833329983e+01 1.302317253333330038e+00 +1.100174000000000013e-01 2.182584247666670052e+01 1.179366926666669979e+00 +1.148721999999999938e-01 2.121788853500000016e+01 1.084366495000000041e+00 +1.198083000000000065e-01 1.779511935000000022e+01 9.833421683333329888e-01 +1.248023999999999939e-01 1.651748253666670152e+01 9.145048883333329881e-01 +1.298709000000000113e-01 1.721928703000000027e+01 8.380137100000000228e-01 +1.349431000000000103e-01 1.436323046666669967e+01 7.917284633333330213e-01 +1.399610000000000021e-01 1.550343697666670018e+01 7.379972516666669646e-01 +1.451112999999999986e-01 1.303663926666670037e+01 6.920347900000000108e-01 +1.503050999999999970e-01 1.200503839166669984e+01 6.556345366666670449e-01 +1.556469000000000047e-01 1.229304255666670009e+01 5.989305183333329952e-01 +1.573070000000000024e-01 1.257057899666670053e+01 1.910309249999999903e-01 +1.609891999999999990e-01 1.193592632666669928e+01 5.769697900000000379e-01 +1.662309999999999899e-01 1.125234698666669964e+01 5.482133000000000145e-01 +1.706957000000000058e-01 1.058112505166669948e+01 1.590339783333329926e-01 +1.716062999999999894e-01 1.070644689999999954e+01 5.183003699999999547e-01 +1.771733000000000058e-01 9.479454351666669609e+00 4.778282466666670114e-01 +1.827794000000000085e-01 9.400985496666670826e+00 4.569814249999999967e-01 +1.843146999999999980e-01 9.549487438333329692e+00 1.380682866666670117e-01 +1.883665999999999952e-01 8.342261173333330504e+00 4.359566316666669827e-01 +1.940302000000000138e-01 8.124126898333329905e+00 4.232381216666670221e-01 +1.983187999999999895e-01 8.328415036666669380e+00 1.189532799999999946e-01 +1.998185000000000100e-01 8.328210934999999537e+00 3.999954083333330246e-01 +2.056348000000000065e-01 8.350671104999999983e+00 3.905236483333329733e-01 +2.115208000000000088e-01 6.929636241666670138e+00 3.588886250000000167e-01 +2.120939000000000019e-01 7.535892504999999630e+00 1.085254183333329986e-01 +2.162467999999999890e-01 7.407988318333329936e+00 4.625349066666670228e-01 +2.260705000000000076e-01 6.743451298333329902e+00 9.541167166666669752e-02 +2.398779000000000050e-01 6.099490819999999758e+00 8.899463999999999986e-02 +2.538084999999999924e-01 5.555039073333330357e+00 8.113394833333330280e-02 +2.677318000000000198e-01 5.152730110000000252e+00 7.469547999999999466e-02 +2.818956000000000239e-01 4.837557096666669665e+00 6.957829666666670576e-02 +2.957549999999999901e-01 4.369791838333330070e+00 6.527595833333330044e-02 +3.100250999999999979e-01 4.110463069999999774e+00 5.977720166666670304e-02 +3.241909000000000041e-01 3.813721606666669928e+00 5.811357666666670113e-02 +3.389346999999999777e-01 3.461479851666669827e+00 5.155417166666669687e-02 +3.540519999999999778e-01 3.230298750000000219e+00 5.028755499999999767e-02 +3.688526999999999778e-01 2.998165658333329819e+00 4.634052999999999783e-02 +3.841308999999999974e-01 2.784144708333330165e+00 4.378963833333329725e-02 +3.990528999999999882e-01 2.595613363333329815e+00 4.256657166666669850e-02 +4.108341999999999827e-01 2.335089765499999803e+00 4.258898366666669794e-02 +4.138126999999999778e-01 2.324415418333329875e+00 3.994880166666670007e-02 +4.292300000000000004e-01 2.216248561666669836e+00 3.693022666666669757e-02 +4.297198999999999880e-01 2.134554158666670087e+00 3.596130699999999791e-02 +4.447747000000000228e-01 1.890609146666669904e+00 3.555346833333330320e-02 +4.468464999999999798e-01 1.908117816499999897e+00 3.198120466666670020e-02 +4.605119999999999769e-01 1.871098863333330087e+00 3.348654166666670262e-02 +4.687272000000000105e-01 1.810652348333330108e+00 3.178039216666669886e-02 +4.766716999999999760e-01 1.698277889999999957e+00 3.148857166666670093e-02 +4.835976000000000163e-01 1.613169754500000108e+00 2.993151466666670035e-02 +4.925123000000000140e-01 1.548358499999999971e+00 3.116390166666669834e-02 +5.048597000000000223e-01 1.494630669833330039e+00 2.759253283333330115e-02 +5.084689000000000014e-01 1.491590500000000041e+00 2.885127333333329866e-02 +5.232776999999999568e-01 1.248566430833329965e+00 2.572220416666669979e-02 +5.251208000000000542e-01 1.383180581666670017e+00 2.700447666666670049e-02 +5.418887000000000009e-01 1.221960488333329931e+00 2.639246833333330072e-02 +5.446132999999999669e-01 1.208971178333329899e+00 2.618446533333329898e-02 +5.585244000000000320e-01 1.107120358333330001e+00 2.542247833333330029e-02 +5.614812000000000136e-01 1.085889866500000078e+00 2.370511449999999909e-02 +5.756198999999999621e-01 1.024119451666670066e+00 2.350574000000000066e-02 +5.836356999999999795e-01 9.666399098333330331e-01 2.336446566666669847e-02 +5.929708999999999675e-01 9.753983600000000198e-01 2.276144833333329856e-02 +6.008097999999999494e-01 8.857038164999999630e-01 2.215761016666669900e-02 +6.101434999999999498e-01 9.144217283333330171e-01 2.215592499999999992e-02 +6.220980999999999872e-01 8.054969749999999484e-01 2.151697083333330152e-02 +6.277447999999999917e-01 7.972735800000000372e-01 2.067797666666670170e-02 +6.414592999999999545e-01 7.033510668333330385e-01 1.912904316666669963e-02 +6.449667999999999513e-01 7.010848466666670387e-01 2.101707333333329916e-02 +6.658104000000000244e-01 6.363828563333330246e-01 1.837497983333330129e-02 +6.846381999999999746e-01 5.758642446666669690e-01 2.039069533333329881e-02 +7.060868999999999618e-01 5.109788090000000338e-01 1.728495966666670006e-02 +7.261535999999999547e-01 4.885223020000000194e-01 1.847847583333329935e-02 +7.493412999999999879e-01 4.387949984999999775e-01 1.519840233333329994e-02 +7.723109999999999697e-01 3.923397161666670185e-01 1.717436333333329998e-02 +7.924090999999999774e-01 3.993512075000000272e-01 1.521433699999999965e-02 +8.158290999999999737e-01 3.564691013333329828e-01 1.545670316666669999e-02 +8.367750000000000465e-01 3.230009236666669947e-01 1.469029500000000078e-02 +8.622752000000000194e-01 2.878051181666669844e-01 1.377513966666669976e-02 +8.849867000000000150e-01 2.848005155000000177e-01 1.450056933333329981e-02 +9.085018000000000260e-01 2.630901753333330095e-01 1.273161166666669959e-02 +9.338100999999999763e-01 2.556641304999999753e-01 1.373873700000000087e-02 +9.555571000000000481e-01 2.110106781666669928e-01 1.282516266666670034e-02 +9.816814000000000373e-01 1.989191335000000116e-01 1.201689483333330012e-02 +1.007201999999999931e+00 1.798726026666669919e-01 1.241756500000000020e-02 +1.030810000000000004e+00 1.697684260000000001e-01 1.179553216666670047e-02 +1.058198500000000042e+00 1.911874938333329998e-01 1.101163099999999916e-02 +1.085025700000000093e+00 1.546144220000000014e-01 1.126302133333329999e-02 +1.110336800000000013e+00 1.274498698333330071e-01 1.087918116666669946e-02 +1.138196999999999903e+00 1.312019681666669879e-01 1.048030450000000079e-02 +1.166492899999999944e+00 1.202452754999999984e-01 1.022370933333329943e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv new file mode 100644 index 0000000000..51227d3b8e --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv @@ -0,0 +1,105 @@ +3.624299999999999744e-02 2.421839941750000094e+02 1.681259771499999900e+01 +4.068929999999999769e-02 1.253477160583330061e+02 1.158261931833330038e+01 +4.510000000000000120e-02 1.038159109083329952e+02 8.606540843333329249e+00 +4.957960000000000145e-02 9.508877155000000414e+01 7.037626288333330038e+00 +5.414959999999999912e-02 7.142443308833330207e+01 5.530319266666669620e+00 +5.867460000000000037e-02 6.747951957166669956e+01 4.803320423333330424e+00 +6.313670000000000393e-02 6.491403129500000091e+01 3.984481885000000112e+00 +6.771770000000000567e-02 5.688806046833330043e+01 3.329560004999999823e+00 +7.237100000000000477e-02 4.031379161166670144e+01 2.864987329999999943e+00 +7.692330000000000001e-02 4.363721252500000247e+01 2.591659659999999921e+00 +8.164470000000000061e-02 3.499940050499999700e+01 2.159604903333330217e+00 +8.639470000000000482e-02 3.331168452000000002e+01 1.961486934999999932e+00 +9.106759999999999855e-02 3.141853618500000067e+01 1.737193953333330043e+00 +9.573710000000000553e-02 2.514925802833329982e+01 1.580249494999999893e+00 +1.004952999999999957e-01 2.418445705499999931e+01 1.404480071666670105e+00 +1.052397000000000055e-01 2.311071394833329862e+01 1.309208076666670051e+00 +1.099886000000000058e-01 2.234431306333329914e+01 1.186371084999999992e+00 +1.148422000000000054e-01 2.015011891333330141e+01 1.077548355000000013e+00 +1.197769999999999946e-01 1.762490517499999854e+01 9.840672733333329925e-01 +1.247698000000000002e-01 1.703488854000000075e+01 9.213895800000000413e-01 +1.298370000000000080e-01 1.644401272166669870e+01 8.327218266666670532e-01 +1.349077999999999944e-01 1.614025673666670002e+01 8.110203433333329492e-01 +1.399244000000000043e-01 1.432045983666669997e+01 7.277294366666670067e-01 +1.450733999999999913e-01 1.348007003166670081e+01 6.981156733333330200e-01 +1.502658000000000049e-01 1.217057146500000009e+01 6.589065133333330548e-01 +1.556062000000000001e-01 1.311354035333330081e+01 6.087518283333329672e-01 +1.573412999999999895e-01 1.262766263333329952e+01 1.918068450000000036e-01 +1.609471000000000096e-01 1.195521582166669994e+01 5.786270049999999721e-01 +1.661874999999999880e-01 1.070419187999999977e+01 5.435432616666669992e-01 +1.707328999999999930e-01 1.060603477499999947e+01 1.596232366666670011e-01 +1.715615000000000057e-01 1.106375028666669991e+01 5.234683166666670440e-01 +1.771270000000000067e-01 9.097135046666670277e+00 4.748174949999999783e-01 +1.827315999999999940e-01 9.232441778333329907e+00 4.562185283333329844e-01 +1.843548999999999882e-01 9.582483613333330652e+00 1.386399050000000077e-01 +1.883173999999999959e-01 9.681451038333330317e+00 4.521609416666669823e-01 +1.939794999999999991e-01 8.227612430000000643e+00 4.254379616666669750e-01 +1.983621000000000134e-01 8.295318078333329126e+00 1.192443799999999970e-01 +1.997663000000000078e-01 8.131970284999999521e+00 3.988034016666670012e-01 +2.055810999999999888e-01 7.142658796666670362e+00 3.773835349999999922e-01 +2.114655000000000007e-01 7.164933761666669731e+00 3.624743966666669759e-01 +2.121402000000000010e-01 7.387669431666670228e+00 1.083523799999999981e-01 +2.161903000000000019e-01 6.864321103333329788e+00 4.553583783333329804e-01 +2.261198000000000097e-01 6.847039901666669870e+00 9.614554833333330275e-02 +2.399302000000000101e-01 6.151464958333329847e+00 8.952354166666670610e-02 +2.538638999999999757e-01 5.563245829999999614e+00 8.146051666666670465e-02 +2.677901999999999783e-01 5.162996156666669556e+00 7.501275500000000040e-02 +2.819571000000000160e-01 4.731078383333329640e+00 6.938886333333330048e-02 +2.958196000000000159e-01 4.470382223333330352e+00 6.595420000000000449e-02 +3.100928000000000018e-01 4.071269568333329758e+00 5.983178000000000107e-02 +3.242616999999999861e-01 3.818289136666670025e+00 5.835058500000000342e-02 +3.390086999999999962e-01 3.464278166666669989e+00 5.175618166666669934e-02 +3.541291999999999773e-01 3.297458013333330218e+00 5.076983000000000190e-02 +3.689332000000000167e-01 3.070901008333330129e+00 4.683460500000000137e-02 +3.842147000000000201e-01 2.769801061666670172e+00 4.388707166666670073e-02 +3.991399999999999948e-01 2.510583560000000158e+00 4.232430333333329908e-02 +4.106022999999999756e-01 2.374815773499999949e+00 4.286182233333329927e-02 +4.139030000000000209e-01 2.373871081666670158e+00 4.032223833333330176e-02 +4.293236999999999748e-01 2.231085370000000179e+00 3.713437166666670036e-02 +4.294773000000000063e-01 2.156539414333329852e+00 3.612328016666670194e-02 +4.448717999999999839e-01 1.876962131666670031e+00 3.561285166666670193e-02 +4.465942999999999996e-01 1.963582529333329996e+00 3.226501116666669750e-02 +4.606124999999999803e-01 1.886281606666670108e+00 3.367513833333329876e-02 +4.684626000000000068e-01 1.795604685000000034e+00 3.177854483333329705e-02 +4.767757000000000245e-01 1.729912848333329922e+00 3.174894833333329752e-02 +4.833245999999999931e-01 1.643333701666670033e+00 3.012282700000000132e-02 +4.926197999999999966e-01 1.601281793333330095e+00 3.152871666666669931e-02 +5.045747000000000426e-01 1.513868059666670041e+00 2.772222300000000070e-02 +5.085798000000000263e-01 1.480025179999999940e+00 2.889593166666670071e-02 +5.229823000000000111e-01 1.292098316666669966e+00 2.594417883333329997e-02 +5.252354000000000189e-01 1.389690103333329985e+00 2.712855999999999948e-02 +5.420070000000000165e-01 1.207626951666670001e+00 2.641061333333330138e-02 +5.443057999999999508e-01 1.171074812333330106e+00 2.606778300000000062e-02 +5.586463000000000401e-01 1.131968480000000055e+00 2.562754666666669859e-02 +5.611642999999999493e-01 1.119771183833329964e+00 2.388942000000000149e-02 +5.757455000000000211e-01 1.050324178333329916e+00 2.370775166666670014e-02 +5.833063000000000553e-01 9.890430198333329814e-01 2.349970633333330061e-02 +5.931003000000000247e-01 9.529422783333330038e-01 2.272385333333330065e-02 +6.004707000000000239e-01 9.087951714999999986e-01 2.229426183333330092e-02 +6.102765999999999469e-01 8.968441200000000224e-01 2.213925333333329956e-02 +6.217470000000000496e-01 8.116193323333330545e-01 2.157820200000000119e-02 +6.278818000000000454e-01 7.745292049999999984e-01 2.063141833333330052e-02 +6.410972000000000337e-01 7.304547335000000086e-01 1.926881999999999900e-02 +6.451074999999999449e-01 7.030634049999999746e-01 2.109099333333330079e-02 +6.654345000000000399e-01 6.451808323333330097e-01 1.843812350000000044e-02 +6.842517000000000182e-01 5.969281796666670026e-01 2.051784966666669874e-02 +7.056883000000000461e-01 4.875458616666670242e-01 1.721726566666669997e-02 +7.257436999999999916e-01 5.206052460000000215e-01 1.864389433333329960e-02 +7.489183000000000368e-01 4.716855048333329914e-01 1.534349166666670004e-02 +7.718749999999999778e-01 3.996116843333329949e-01 1.723059933333330115e-02 +7.919618000000000491e-01 3.949704010000000265e-01 1.521841983333330033e-02 +8.153685999999999989e-01 3.711572033333330189e-01 1.553813883333329988e-02 +8.363026999999999544e-01 3.373120053333329982e-01 1.476541233333330053e-02 +8.617884000000000100e-01 3.012111169999999727e-01 1.384248800000000001e-02 +8.844872000000000289e-01 3.093801609999999869e-01 1.462152149999999991e-02 +9.079890000000000461e-01 2.725293346666670113e-01 1.278188633333329945e-02 +9.332829999999999737e-01 2.562172424999999976e-01 1.375849099999999943e-02 +9.550178000000000278e-01 2.195073688333329942e-01 1.287299783333330054e-02 +9.811271999999999771e-01 1.993873673333330099e-01 1.203331399999999982e-02 +1.006633399999999900e+00 1.965978770000000042e-01 1.249421516666670076e-02 +1.030228200000000038e+00 1.888581198333330047e-01 1.187900783333330039e-02 +1.057601100000000072e+00 2.019180355000000093e-01 1.106158266666669963e-02 +1.084413199999999966e+00 1.710308969999999873e-01 1.133507299999999933e-02 +1.109710100000000033e+00 1.385269876666669897e-01 1.092970799999999978e-02 +1.137554500000000024e+00 1.323425321666669985e-01 1.049619949999999920e-02 +1.165834400000000048e+00 1.352444690000000060e-01 1.028587266666670073e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv new file mode 100644 index 0000000000..e4a5c8ff19 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv @@ -0,0 +1,105 @@ +3.623830000000000107e-02 1.262534512933330006e+02 1.649893105666669868e+01 +4.068399999999999794e-02 1.096408472683330046e+02 1.152156481833329948e+01 +4.509420000000000095e-02 6.843298548666669490e+01 8.484508865000000455e+00 +4.957310000000000189e-02 5.337196919333329959e+01 6.882409771666670117e+00 +5.414259999999999906e-02 4.824018401499999698e+01 5.433445991666670416e+00 +5.866699999999999693e-02 4.665372951666670076e+01 4.705492196666670068e+00 +6.312850000000000406e-02 5.221271013999999866e+01 3.917987768333329957e+00 +6.770890000000000242e-02 4.827582027833329903e+01 3.280544881666669799e+00 +7.236159999999999815e-02 3.618855914666669804e+01 2.837183351666670017e+00 +7.691330000000000389e-02 3.079150051333330040e+01 2.510836073333329921e+00 +8.163410000000000111e-02 3.296728457500000076e+01 2.143401925000000041e+00 +8.638339999999999907e-02 3.069841431000000043e+01 1.940150145000000048e+00 +9.105580000000000618e-02 2.710592771666669876e+01 1.703459686666670025e+00 +9.572469999999999590e-02 2.329590637833329936e+01 1.563327263333329942e+00 +1.004822999999999966e-01 2.091072460333329985e+01 1.376591528333330094e+00 +1.052260000000000001e-01 1.912562908333330114e+01 1.273402691666670083e+00 +1.099742999999999971e-01 1.787115249333330169e+01 1.146192773333329917e+00 +1.148272999999999933e-01 1.794118791666669921e+01 1.055988855000000060e+00 +1.197614000000000040e-01 1.653599519333329937e+01 9.723875616666669552e-01 +1.247536000000000062e-01 1.582743532666670028e+01 9.084356083333330334e-01 +1.298200999999999938e-01 1.478155951166669979e+01 8.152435350000000192e-01 +1.348902999999999908e-01 1.334408521333329922e+01 7.818770066666670404e-01 +1.399062000000000083e-01 1.377281605666670039e+01 7.205883533333330426e-01 +1.450545000000000029e-01 1.181691977333330001e+01 6.799812333333330461e-01 +1.502462999999999993e-01 1.213584320000000005e+01 6.572146300000000219e-01 +1.555860000000000021e-01 1.192358865166669979e+01 5.953690533333330093e-01 +1.572933999999999999e-01 1.181612013833330010e+01 1.889312700000000123e-01 +1.609261999999999915e-01 1.175466066000000076e+01 5.752044899999999572e-01 +1.661659000000000053e-01 1.042143580833329963e+01 5.392668716666669804e-01 +1.706808999999999965e-01 1.011778497999999971e+01 1.577585016666669948e-01 +1.715392000000000028e-01 9.758357795000000223e+00 5.081139666666669719e-01 +1.771040000000000114e-01 8.903400566666670457e+00 4.716962699999999731e-01 +1.827079000000000064e-01 9.178007346666669619e+00 4.546196783333329994e-01 +1.842987000000000097e-01 9.009516103333330861e+00 1.364224366666670074e-01 +1.882929000000000130e-01 8.406366826666669567e+00 4.368516150000000264e-01 +1.939542999999999962e-01 7.892936534999999587e+00 4.208100816666670019e-01 +1.983015999999999945e-01 7.968528981666669786e+00 1.178380566666669960e-01 +1.997403000000000095e-01 7.734987613333330181e+00 3.934730833333329736e-01 +2.055543999999999982e-01 7.979108915000000302e+00 3.863922049999999886e-01 +2.114380999999999899e-01 6.834691483333330098e+00 3.579354766666669740e-01 +2.120755000000000001e-01 7.473622876666669690e+00 1.084324933333330049e-01 +2.161621999999999988e-01 6.843431601666670083e+00 4.540542233333330069e-01 +2.260508999999999991e-01 6.624537448333329692e+00 9.508442500000000019e-02 +2.398570999999999898e-01 6.030806045000000282e+00 8.883706333333329930e-02 +2.537865999999999733e-01 5.548485336666669987e+00 8.121552666666670417e-02 +2.677086000000000188e-01 5.056279183333329819e+00 7.439664999999999473e-02 +2.818711999999999884e-01 4.746517688333329765e+00 6.929181333333329917e-02 +2.957293999999999756e-01 4.360488485000000303e+00 6.532353000000000465e-02 +3.099983000000000044e-01 4.042259101666670240e+00 5.956615500000000257e-02 +3.241628999999999761e-01 3.667612291666670021e+00 5.754424666666670130e-02 +3.389054000000000233e-01 3.392261260000000167e+00 5.132888666666669819e-02 +3.540212999999999832e-01 3.153369070000000107e+00 5.001504333333330055e-02 +3.688208000000000042e-01 2.957433689999999782e+00 4.622241666666670329e-02 +3.840975999999999835e-01 2.782086464999999897e+00 4.383930500000000202e-02 +3.990183999999999953e-01 2.497954614999999823e+00 4.216718166666669904e-02 +4.106379000000000001e-01 2.347253106833329994e+00 4.254085666666670290e-02 +4.137768000000000002e-01 2.313526113333329803e+00 3.995030166666670157e-02 +4.291927999999999854e-01 2.205677500000000180e+00 3.693004333333330114e-02 +4.295145000000000213e-01 2.125140473833329935e+00 3.583346700000000079e-02 +4.447362000000000259e-01 1.900926653333329996e+00 3.564656666666669860e-02 +4.466328999999999994e-01 1.939722618500000051e+00 3.202840516666669718e-02 +4.604721999999999982e-01 1.890633683333329929e+00 3.361991000000000285e-02 +4.685032000000000085e-01 1.753475375666670111e+00 3.146806816666670309e-02 +4.766304000000000096e-01 1.692544018333330014e+00 3.150160500000000197e-02 +4.833663999999999739e-01 1.571138671166669942e+00 2.967553150000000126e-02 +4.924697000000000102e-01 1.562743266666670072e+00 3.127265833333330025e-02 +5.046184000000000225e-01 1.517538195333330009e+00 2.762060549999999920e-02 +5.084248000000000101e-01 1.452519751666669912e+00 2.870172666666670133e-02 +5.230276000000000369e-01 1.280607860833330003e+00 2.579378549999999937e-02 +5.250753000000000226e-01 1.364635400000000054e+00 2.694985833333329861e-02 +5.418418000000000401e-01 1.180339848333330055e+00 2.622176999999999841e-02 +5.443529999999999758e-01 1.172893769833329936e+00 2.597214383333330129e-02 +5.584759999999999724e-01 1.116791568333330043e+00 2.550004666666669945e-02 +5.612129000000000145e-01 1.071752901666670033e+00 2.359418099999999879e-02 +5.755700000000000260e-01 1.003165499999999932e+00 2.343291166666670172e-02 +5.833568000000000087e-01 9.490407108333329678e-01 2.324037416666669895e-02 +5.929195000000000437e-01 9.286979850000000036e-01 2.255620333333329883e-02 +6.005226999999999649e-01 8.938147573333330431e-01 2.214501316666669939e-02 +6.100906000000000384e-01 8.779068549999999860e-01 2.199904499999999832e-02 +6.218008000000000424e-01 8.078191183333329750e-01 2.148254866666670163e-02 +6.276903999999999817e-01 7.890844949999999969e-01 2.066168499999999908e-02 +6.411527999999999672e-01 6.990414535000000207e-01 1.907308200000000162e-02 +6.449108999999999536e-01 7.027759316666669642e-01 2.104888333333329933e-02 +6.654921999999999782e-01 6.693195063333330364e-01 1.846815400000000051e-02 +6.843110000000000026e-01 5.654079498333329790e-01 2.030432683333329921e-02 +7.057493999999999712e-01 4.733216641666669888e-01 1.710506283333329894e-02 +7.258065000000000211e-01 4.881572298333329840e-01 1.844279849999999957e-02 +7.489831000000000127e-01 4.439720878333329734e-01 1.519038399999999948e-02 +7.719418000000000113e-01 4.063687451666669892e-01 1.720554133333329974e-02 +7.920304000000000233e-01 4.025809184999999957e-01 1.519988700000000047e-02 +8.154392000000000307e-01 3.522328571666670238e-01 1.541253149999999988e-02 +8.363751000000000380e-01 3.005755748333330257e-01 1.457862766666669953e-02 +8.618630000000000457e-01 2.801856756666670223e-01 1.372444566666669932e-02 +8.845638000000000112e-01 3.046253318333330129e-01 1.455751649999999925e-02 +9.080675999999999748e-01 2.540008221666669730e-01 1.267830250000000041e-02 +9.333637999999999657e-01 2.481020686666670083e-01 1.368678783333330054e-02 +9.551005000000000189e-01 1.938199579999999866e-01 1.274076333333330063e-02 +9.812121999999999788e-01 1.905731619999999904e-01 1.196892649999999926e-02 +1.006720599999999965e+00 1.784818836666670072e-01 1.239337400000000040e-02 +1.030317399999999939e+00 1.750911911666669929e-01 1.179671083333330012e-02 +1.057692700000000041e+00 1.705610396666669970e-01 1.092493383333329945e-02 +1.084507099999999946e+00 1.719191243333330066e-01 1.130716749999999965e-02 +1.109806099999999907e+00 1.366376699999999889e-01 1.089438483333329995e-02 +1.137653000000000025e+00 1.239800338333330032e-01 1.044124700000000072e-02 +1.165935399999999955e+00 1.310211675000000076e-01 1.024458533333330069e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv new file mode 100644 index 0000000000..2b03b80a54 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 1.213206534416670053e+02 1.651067908166670151e+01 +4.070000000000000007e-02 8.158564289333330066e+01 1.146150313666669973e+01 +4.511180000000000051e-02 6.728303165833330013e+01 8.493610868333329122e+00 +4.959249999999999770e-02 5.609321657833329766e+01 6.902234358333330100e+00 +5.416379999999999806e-02 4.208391674666670212e+01 5.417946521666669568e+00 +5.868999999999999911e-02 4.572918046833329697e+01 4.708583066666670369e+00 +6.315320000000000655e-02 4.506950746166670285e+01 3.890110903333329873e+00 +6.773540000000000116e-02 3.932771859999999720e+01 3.240109296666669803e+00 +7.238989999999999314e-02 3.425092975666670014e+01 2.830867521666669884e+00 +7.694339999999999513e-02 2.785716006499999864e+01 2.497106951666669961e+00 +8.166600000000000248e-02 2.647316349333329910e+01 2.106834523333330100e+00 +8.641719999999999957e-02 2.865549820000000025e+01 1.929370503333329934e+00 +9.109140000000000292e-02 2.617781355833329826e+01 1.699746431666669944e+00 +9.576210000000000278e-02 2.262414874833330103e+01 1.560889624999999947e+00 +1.005216000000000026e-01 2.072404344833330114e+01 1.377539340000000001e+00 +1.052672000000000052e-01 1.924028949499999896e+01 1.276625569999999987e+00 +1.100174000000000013e-01 1.836748323999999855e+01 1.152518286666670111e+00 +1.148721999999999938e-01 1.699007782666669897e+01 1.049408108333329981e+00 +1.198083000000000065e-01 1.493712180833330017e+01 9.595881783333329862e-01 +1.248023999999999939e-01 1.484142020166670051e+01 9.009069050000000356e-01 +1.298709000000000113e-01 1.473895257666669956e+01 8.163899350000000110e-01 +1.349431000000000103e-01 1.308340819666669930e+01 7.807371766666669766e-01 +1.399610000000000021e-01 1.350568340499999920e+01 7.192249033333329988e-01 +1.451112999999999986e-01 1.173611615333330072e+01 6.804578466666669767e-01 +1.503050999999999970e-01 1.154060497666669960e+01 6.523238550000000080e-01 +1.556469000000000047e-01 1.191625231333330071e+01 5.964806683333330195e-01 +1.573344999999999883e-01 1.139197852166670089e+01 1.879402166666669927e-01 +1.609891999999999990e-01 1.125507998666670062e+01 5.708663616666670437e-01 +1.662309999999999899e-01 1.041113468166670053e+01 5.402433599999999503e-01 +1.707255000000000023e-01 1.013307594333329931e+01 1.580824633333330065e-01 +1.716062999999999894e-01 9.500610554999999735e+00 5.062648633333329817e-01 +1.771733000000000058e-01 8.706795813333329193e+00 4.704599616666669815e-01 +1.827794000000000085e-01 9.156035623333330875e+00 4.553047450000000107e-01 +1.843469000000000080e-01 9.118870355000000316e+00 1.370399833333330042e-01 +1.883665999999999952e-01 7.952454938333329615e+00 4.325042000000000053e-01 +1.940302000000000138e-01 8.034647969999999972e+00 4.232443883333329993e-01 +1.983534999999999882e-01 8.119139649999999264e+00 1.185909816666669975e-01 +1.998185000000000100e-01 7.527596430000000005e+00 3.919050766666670182e-01 +2.056348000000000065e-01 7.553855535000000287e+00 3.822255366666669762e-01 +2.115208000000000088e-01 6.617426820000000376e+00 3.561540533333329983e-01 +2.121309999999999862e-01 7.390867828333330003e+00 1.083323783333329932e-01 +2.162467999999999890e-01 6.635593964999999983e+00 4.517541333333329745e-01 +2.261101000000000083e-01 6.488236141666670065e+00 9.474941333333329607e-02 +2.399198999999999915e-01 5.939089416666670118e+00 8.864513000000000253e-02 +2.538528999999999924e-01 5.445706584999999933e+00 8.096326333333329905e-02 +2.677785999999999778e-01 5.020975218333330048e+00 7.440106833333330616e-02 +2.819448999999999983e-01 4.782109235000000069e+00 6.958310166666670238e-02 +2.958067999999999809e-01 4.377367741666669865e+00 6.553075166666670615e-02 +3.100794000000000050e-01 4.070373518333330054e+00 5.980910666666670178e-02 +3.242476000000000247e-01 3.688249826666670117e+00 5.775312500000000238e-02 +3.389940000000000175e-01 3.411490240000000007e+00 5.151532000000000333e-02 +3.541138999999999815e-01 3.221007965000000084e+00 5.041618500000000225e-02 +3.689172000000000007e-01 2.942401639999999929e+00 4.624927499999999941e-02 +3.841980999999999868e-01 2.767105533333329870e+00 4.386071833333329839e-02 +3.991226999999999969e-01 2.564823933333329808e+00 4.256582833333329846e-02 +4.106734000000000218e-01 2.300881685499999829e+00 4.238948299999999864e-02 +4.138850000000000029e-01 2.413576710000000070e+00 4.049426666666670199e-02 +4.293050999999999950e-01 2.233726248333329778e+00 3.713503166666669991e-02 +4.295516999999999808e-01 2.156876818999999834e+00 3.601888033333330158e-02 +4.448524999999999840e-01 1.902652508333330106e+00 3.572283666666670188e-02 +4.466716000000000020e-01 1.934442038833330102e+00 3.205653166666670023e-02 +4.605926000000000187e-01 1.874115690000000001e+00 3.360869833333329781e-02 +4.685437000000000074e-01 1.737730488500000003e+00 3.144913299999999717e-02 +4.767550999999999872e-01 1.772107871666670054e+00 3.193823833333329920e-02 +4.834083000000000130e-01 1.581873448666669901e+00 2.976716433333330067e-02 +4.925984999999999947e-01 1.570737606666670061e+00 3.137136000000000091e-02 +5.046621000000000024e-01 1.492830698499999942e+00 2.756047650000000016e-02 +5.085577999999999488e-01 1.485373084999999982e+00 2.891283166666670096e-02 +5.230728999999999518e-01 1.159546245333330061e+00 2.533816566666670031e-02 +5.252126000000000294e-01 1.354185358333330091e+00 2.695080999999999866e-02 +5.419834999999999514e-01 1.186315898333329955e+00 2.629908666666670031e-02 +5.444001000000000534e-01 1.201936935333330014e+00 2.613158683333329999e-02 +5.586221000000000103e-01 1.109243371666670086e+00 2.550917499999999852e-02 +5.612614999999999688e-01 1.098874749833330000e+00 2.373973216666670077e-02 +5.757206000000000268e-01 1.029040688333330067e+00 2.359920000000000073e-02 +5.834072999999999620e-01 9.811238644999999980e-01 2.340685516666669852e-02 +5.930746000000000073e-01 9.534806916666670462e-01 2.272023833333329870e-02 +6.005747000000000169e-01 8.956047156666669951e-01 2.218217800000000031e-02 +6.102501999999999649e-01 8.805252883333329894e-01 2.205115333333329888e-02 +6.218546000000000351e-01 8.076579554999999688e-01 2.150926133333330020e-02 +6.278546000000000404e-01 8.143317416666669972e-01 2.081983000000000097e-02 +6.412082999999999533e-01 7.185076576666670212e-01 1.917512450000000146e-02 +6.450795999999999752e-01 7.187583950000000499e-01 2.116659499999999985e-02 +6.655497999999999692e-01 6.417931828333329758e-01 1.838261283333330123e-02 +6.843702000000000396e-01 5.677104609999999996e-01 2.033867249999999835e-02 +7.058105999999999547e-01 5.146355146666670155e-01 1.728668516666670082e-02 +7.258693999999999980e-01 5.183306771666670310e-01 1.859332783333330144e-02 +7.490480000000000471e-01 4.413184218333329745e-01 1.519721516666669957e-02 +7.720086999999999922e-01 4.069291728333330194e-01 1.722663266666669968e-02 +7.920989999999999975e-01 3.912903401666669723e-01 1.517220816666670080e-02 +8.155097999999999514e-01 3.620392363333330144e-01 1.546880433333329939e-02 +8.364475000000000104e-01 3.218374210000000124e-01 1.467598383333330002e-02 +8.619377000000000288e-01 2.793489951666670024e-01 1.373524349999999915e-02 +8.846403999999999934e-01 2.729738648333330242e-01 1.444214883333330007e-02 +9.081462000000000145e-01 2.731246803333329809e-01 1.275928200000000026e-02 +9.334447000000000161e-01 2.513956430000000020e-01 1.371339566666670076e-02 +9.551832000000000100e-01 2.075616728333329886e-01 1.280443116666669934e-02 +9.812971999999999806e-01 2.026315226666670077e-01 1.202260966666669935e-02 +1.006807800000000030e+00 1.715856353333329865e-01 1.237966916666670067e-02 +1.030406600000000061e+00 1.813217336666670121e-01 1.183022066666669994e-02 +1.057784300000000011e+00 1.874246033333329953e-01 1.099227083333330010e-02 +1.084600999999999926e+00 1.682342156666669919e-01 1.130467983333329970e-02 +1.109902299999999897e+00 1.305937931666669993e-01 1.088363799999999930e-02 +1.137751600000000085e+00 1.264251891666670069e-01 1.045857849999999936e-02 +1.166036300000000026e+00 1.206125236666669986e-01 1.021913349999999977e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv new file mode 100644 index 0000000000..e8e9c9a0bc --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 8.265676436333329491e+01 1.638320715333329858e+01 +4.070000000000000007e-02 5.464383480166669926e+01 1.136626790833330070e+01 +4.511180000000000051e-02 2.996549328500000087e+01 8.362137733333330658e+00 +4.959249999999999770e-02 3.902000664833330035e+01 6.829579628333330099e+00 +5.416379999999999806e-02 2.960868386499999971e+01 5.359635035000000158e+00 +5.868999999999999911e-02 2.775202533166670094e+01 4.620562245000000345e+00 +6.315320000000000655e-02 2.923420741833329828e+01 3.806268636666669813e+00 +6.773540000000000116e-02 2.925570898666670061e+01 3.181662941666670186e+00 +7.238989999999999314e-02 2.438109743166669929e+01 2.769415394999999780e+00 +7.694339999999999513e-02 2.082174377999999848e+01 2.449056793333329818e+00 +8.166600000000000248e-02 2.093264007666670068e+01 2.067833788333329981e+00 +8.641719999999999957e-02 2.065156679166669917e+01 1.869354308333329939e+00 +9.109140000000000292e-02 2.096371475999999845e+01 1.658336066666669995e+00 +9.576210000000000278e-02 1.686565956500000141e+01 1.512923419999999908e+00 +1.005216000000000026e-01 1.674424940666670025e+01 1.343149441666670052e+00 +1.052672000000000052e-01 1.453594207833329932e+01 1.233355748333329949e+00 +1.100174000000000013e-01 1.743436942499999986e+01 1.141890178333329953e+00 +1.148721999999999938e-01 1.514907325499999935e+01 1.030380964999999982e+00 +1.198083000000000065e-01 1.335097668833330076e+01 9.427780516666669497e-01 +1.248023999999999939e-01 1.334016233833330034e+01 8.846290449999999472e-01 +1.298709000000000113e-01 1.370878951499999943e+01 8.044898483333330352e-01 +1.349431000000000103e-01 1.169732300833329930e+01 7.648545733333329544e-01 +1.399610000000000021e-01 1.178831958166670013e+01 6.994071549999999471e-01 +1.451112999999999986e-01 1.065116290166669977e+01 6.676857533333330208e-01 +1.503050999999999970e-01 9.325193926666669242e+00 6.273500633333329857e-01 +1.556469000000000047e-01 1.029459589333329994e+01 5.781039766666670188e-01 +1.572456999999999883e-01 1.000640059000000015e+01 1.830944850000000013e-01 +1.609891999999999990e-01 1.045812633999999974e+01 5.605480683333330383e-01 +1.662309999999999899e-01 9.379805284999999770e+00 5.273011283333329802e-01 +1.706292000000000086e-01 9.152038171666669442e+00 1.545153300000000063e-01 +1.716062999999999894e-01 9.072271783333329509e+00 5.002084749999999858e-01 +1.771733000000000058e-01 8.299759079999999400e+00 4.647556766666670058e-01 +1.827794000000000085e-01 8.918414625000000484e+00 4.514085349999999996e-01 +1.842428999999999872e-01 8.303275895000000517e+00 1.338776349999999948e-01 +1.883665999999999952e-01 8.087114149999999668e+00 4.329608600000000029e-01 +1.940302000000000138e-01 6.940626968333329927e+00 4.097805333333329747e-01 +1.982414999999999872e-01 7.399220633333330355e+00 1.156899150000000043e-01 +1.998185000000000100e-01 7.671813116666670318e+00 3.925434549999999856e-01 +2.056348000000000065e-01 7.058416683333329722e+00 3.753756766666669908e-01 +2.115208000000000088e-01 6.186979153333330039e+00 3.502447450000000240e-01 +2.120113000000000136e-01 6.509825833333329648e+00 1.046767516666669978e-01 +2.162467999999999890e-01 6.237968744999999871e+00 4.443455150000000242e-01 +2.259823999999999999e-01 6.054194650000000344e+00 9.278840666666669790e-02 +2.397845000000000115e-01 5.564811654999999746e+00 8.685724833333340056e-02 +2.537096999999999825e-01 5.167096618333330227e+00 7.958348833333329930e-02 +2.676275000000000182e-01 4.857346653333330266e+00 7.348198000000000230e-02 +2.817857999999999752e-01 4.540460176666670122e+00 6.833893833333329337e-02 +2.956398000000000081e-01 4.237780543333330208e+00 6.471250666666669704e-02 +3.099044000000000243e-01 3.935048769999999863e+00 5.903304000000000190e-02 +3.240645999999999805e-01 3.478254921666669830e+00 5.662396666666669881e-02 +3.388027000000000122e-01 3.303115776666670111e+00 5.088800999999999741e-02 +3.539140000000000064e-01 3.111107356666670043e+00 4.976782999999999901e-02 +3.687090000000000090e-01 2.860701315000000022e+00 4.573441000000000312e-02 +3.839813000000000254e-01 2.699693565000000017e+00 4.341666500000000012e-02 +3.988975000000000160e-01 2.495346641666670084e+00 4.210437499999999944e-02 +4.106734000000000218e-01 2.304978501333330154e+00 4.227540733333329942e-02 +4.136514000000000024e-01 2.281161938333330141e+00 3.975256666666669714e-02 +4.290628000000000219e-01 2.190969609999999790e+00 3.681797500000000278e-02 +4.295516999999999808e-01 2.110397390999999789e+00 3.571657216666670326e-02 +4.446014999999999828e-01 1.879588453333330023e+00 3.550642500000000118e-02 +4.466716000000000020e-01 1.816268564666670082e+00 3.148649049999999866e-02 +4.603325999999999807e-01 1.793649588333330103e+00 3.313105499999999953e-02 +4.685437000000000074e-01 1.770170460833329962e+00 3.148902633333330175e-02 +4.764860000000000206e-01 1.682140176666669928e+00 3.141608500000000331e-02 +4.834083000000000130e-01 1.536765404999999918e+00 2.947832866666669910e-02 +4.923204999999999942e-01 1.511959243333329983e+00 3.099057499999999937e-02 +5.046621000000000024e-01 1.465441131499999994e+00 2.736933133333329868e-02 +5.082708000000000226e-01 1.365583310000000106e+00 2.825172333333330135e-02 +5.230728999999999518e-01 1.154780808166669948e+00 2.524863800000000033e-02 +5.249162000000000550e-01 1.329800611666670074e+00 2.675280666666670151e-02 +5.416775999999999813e-01 1.188958583333330044e+00 2.623523499999999911e-02 +5.444001000000000534e-01 1.154485974333330001e+00 2.585743066666670170e-02 +5.583067999999999920e-01 1.077189841666670089e+00 2.527868166666669830e-02 +5.612614999999999688e-01 1.051792144833330056e+00 2.347724083333330158e-02 +5.753956999999999544e-01 1.014095294999999952e+00 2.346036166666670003e-02 +5.834072999999999620e-01 9.588631039999999661e-01 2.325032483333330097e-02 +5.927398999999999862e-01 9.388917833333330076e-01 2.258296499999999998e-02 +6.005747000000000169e-01 8.756694673333329515e-01 2.203778849999999886e-02 +6.099058000000000535e-01 8.473022983333330371e-01 2.182166666666670099e-02 +6.218546000000000351e-01 7.881510335000000422e-01 2.137202599999999883e-02 +6.275003000000000108e-01 7.785123416666670515e-01 2.058900166666670015e-02 +6.412082999999999533e-01 7.088910750000000371e-01 1.908878433333329946e-02 +6.447154999999999969e-01 6.898300916666669780e-01 2.096122833333330035e-02 +6.655497999999999692e-01 6.325061706666670336e-01 1.830133016666669887e-02 +6.843702000000000396e-01 5.535274884999999978e-01 2.022582083333330019e-02 +7.058105999999999547e-01 4.772884753333330177e-01 1.710068249999999873e-02 +7.258693999999999980e-01 4.794482545000000040e-01 1.838371499999999839e-02 +7.490480000000000471e-01 4.303608649999999813e-01 1.512209783333329921e-02 +7.720086999999999922e-01 3.958678310000000033e-01 1.713988450000000080e-02 +7.920989999999999975e-01 3.804415833333329999e-01 1.509590366666670007e-02 +8.155097999999999514e-01 3.391658666666669819e-01 1.534219399999999997e-02 +8.364475000000000104e-01 2.920511656666670008e-01 1.453006433333330072e-02 +8.619377000000000288e-01 2.768105268333330149e-01 1.369777266666669970e-02 +8.846403999999999934e-01 2.773741731666670152e-01 1.443021766666669967e-02 +9.081462000000000145e-01 2.284839270000000033e-01 1.257401600000000036e-02 +9.334447000000000161e-01 2.262680790000000108e-01 1.358766933333330033e-02 +9.551832000000000100e-01 2.014745451666669906e-01 1.275664699999999943e-02 +9.812971999999999806e-01 1.828399243333329871e-01 1.193000216666669985e-02 +1.006807800000000030e+00 1.768480391666669982e-01 1.237525766666669989e-02 +1.030406600000000061e+00 1.607457411666670111e-01 1.173357283333329934e-02 +1.057784300000000011e+00 1.603443938333329877e-01 1.087976483333330004e-02 +1.084600999999999926e+00 1.672401265000000026e-01 1.127955949999999950e-02 +1.109902299999999897e+00 1.308651896666669923e-01 1.086452716666670010e-02 +1.137751600000000085e+00 1.208445169999999985e-01 1.042120399999999988e-02 +1.166036300000000026e+00 1.219414448333329959e-01 1.020481383333330001e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv new file mode 100644 index 0000000000..c576fb9ba4 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv @@ -0,0 +1,105 @@ +3.625710000000000044e-02 7.586499487000000386e+01 1.637401323166670153e+01 +4.070529999999999982e-02 4.481643682666670259e+01 1.134473448500000003e+01 +4.511769999999999670e-02 3.187475403666670104e+01 8.372120233333330219e+00 +4.959899999999999726e-02 2.997679580000000144e+01 6.801308398333329563e+00 +5.417079999999999812e-02 2.394855565499999983e+01 5.340431286666669664e+00 +5.869760000000000255e-02 2.142582576833330066e+01 4.594792676666670239e+00 +6.316149999999999542e-02 3.089957102166669856e+01 3.816311058333329953e+00 +6.774429999999999341e-02 2.654007947166670078e+01 3.169185818333330129e+00 +7.239929999999999977e-02 1.943375908333329960e+01 2.742530958333329938e+00 +7.695340000000000513e-02 1.976728253666669843e+01 2.443851029999999813e+00 +8.167670000000000485e-02 1.925900297000000094e+01 2.058348746666669893e+00 +8.642850000000000532e-02 1.891829230833329945e+01 1.858069830000000033e+00 +9.110319999999999530e-02 1.827805419833330092e+01 1.639507476666669961e+00 +9.577460000000000140e-02 1.569160155166670023e+01 1.504524439999999963e+00 +1.005346000000000017e-01 1.326347007166669911e+01 1.315847523333329994e+00 +1.052808999999999967e-01 1.528716061000000082e+01 1.240626203333329958e+00 +1.100316999999999962e-01 1.357029930000000029e+01 1.108701733333329997e+00 +1.148871000000000059e-01 1.268526336333330029e+01 1.008324261666670107e+00 +1.198237999999999942e-01 1.157206131499999913e+01 9.266636050000000013e-01 +1.248187000000000046e-01 1.139260776499999928e+01 8.664271866666669597e-01 +1.298877999999999977e-01 1.288652256499999993e+01 7.969746983333330093e-01 +1.349605999999999861e-01 1.079102049499999971e+01 7.560191466666670301e-01 +1.399791999999999981e-01 1.105679143000000053e+01 6.920319183333329960e-01 +1.451301000000000119e-01 1.044385611833330074e+01 6.659680816666669889e-01 +1.503246000000000027e-01 9.389620521666669717e+00 6.284466633333329888e-01 +1.556671000000000027e-01 9.365269319999999453e+00 5.685768949999999711e-01 +1.572933999999999999e-01 9.202126339999999516e+00 1.807199866666669985e-01 +1.610100999999999893e-01 9.725111731666670423e+00 5.526473100000000027e-01 +1.662526000000000004e-01 8.453553321666669618e+00 5.170390433333329483e-01 +1.706808999999999965e-01 8.508661829999999426e+00 1.525917300000000087e-01 +1.716285999999999923e-01 8.248625778333330771e+00 4.912094450000000223e-01 +1.771963000000000010e-01 7.860151886666669974e+00 4.601271083333329792e-01 +1.828030999999999962e-01 8.179063558333330874e+00 4.431557566666670112e-01 +1.842987000000000097e-01 7.789301021666670266e+00 1.322509683333329966e-01 +1.883911000000000058e-01 7.284922560000000047e+00 4.239183200000000151e-01 +1.940553999999999890e-01 6.860865920000000173e+00 4.091373166666669725e-01 +1.983015999999999945e-01 6.984366938333329777e+00 1.143283233333329957e-01 +1.998445000000000082e-01 7.321059296666669880e+00 3.888106266666669919e-01 +2.056614999999999971e-01 6.516638536666669701e+00 3.691254600000000163e-01 +2.115482999999999947e-01 5.813378858333329902e+00 3.460794933333329881e-01 +2.120755000000000001e-01 6.410695145000000039e+00 1.044179233333329959e-01 +2.162748999999999922e-01 6.046752721666670105e+00 4.416217800000000193e-01 +2.260508999999999991e-01 5.970100884999999913e+00 9.257100833333330170e-02 +2.398570999999999898e-01 5.328183368333330172e+00 8.599138666666669706e-02 +2.537865999999999733e-01 5.025059630000000332e+00 7.909936500000000481e-02 +2.677086000000000188e-01 4.638679231666669622e+00 7.265197833333329747e-02 +2.818711999999999884e-01 4.320586221666670390e+00 6.748263000000000178e-02 +2.957293999999999756e-01 4.003143766666670267e+00 6.376038000000000538e-02 +3.099983000000000044e-01 3.820362695000000031e+00 5.861029000000000239e-02 +3.241628999999999761e-01 3.476478435000000200e+00 5.668581000000000314e-02 +3.389054000000000233e-01 3.203212216666670109e+00 5.052067666666670148e-02 +3.540212999999999832e-01 3.082675891666669887e+00 4.970334166666669912e-02 +3.688208000000000042e-01 2.852994409999999981e+00 4.575685000000000169e-02 +3.840975999999999835e-01 2.619206445000000105e+00 4.310591500000000159e-02 +3.990183999999999953e-01 2.447015261666670050e+00 4.192961333333330293e-02 +4.106022999999999756e-01 2.250148667666670210e+00 4.208387400000000028e-02 +4.137768000000000002e-01 2.199470903333330174e+00 3.941821333333329902e-02 +4.291927999999999854e-01 2.152990283333330090e+00 3.668624166666670239e-02 +4.294773000000000063e-01 2.066339865166670009e+00 3.559078633333329772e-02 +4.447362000000000259e-01 1.856158275000000080e+00 3.543832166666670280e-02 +4.465942999999999996e-01 1.863514126000000104e+00 3.172593550000000345e-02 +4.604721999999999982e-01 1.785743791666670077e+00 3.313367500000000132e-02 +4.684626000000000068e-01 1.701883971166670007e+00 3.125393900000000141e-02 +4.766304000000000096e-01 1.673134868333330028e+00 3.141082333333330284e-02 +4.833245999999999931e-01 1.561424375333329895e+00 2.963426116666669982e-02 +4.924697000000000102e-01 1.528741043333329941e+00 3.110879000000000075e-02 +5.045747000000000426e-01 1.440318964999999896e+00 2.730927600000000038e-02 +5.084248000000000101e-01 1.414442154999999923e+00 2.852017166666670142e-02 +5.229823000000000111e-01 1.195010044500000035e+00 2.544837383333330150e-02 +5.250753000000000226e-01 1.305492214999999900e+00 2.666661666666670163e-02 +5.418418000000000401e-01 1.152673440000000049e+00 2.608773333333330030e-02 +5.443057999999999508e-01 1.145610492499999911e+00 2.585580999999999990e-02 +5.584759999999999724e-01 1.067225758333329999e+00 2.525753999999999846e-02 +5.611642999999999493e-01 1.067666433166670092e+00 2.357715833333329930e-02 +5.755700000000000260e-01 1.029394661666670041e+00 2.355942499999999842e-02 +5.833063000000000553e-01 9.377488744999999959e-01 2.319254466666669998e-02 +5.929195000000000437e-01 9.657185166666669707e-01 2.274125999999999925e-02 +6.004707000000000239e-01 8.602252591666670334e-01 2.200228683333330104e-02 +6.100906000000000384e-01 8.435776883333330201e-01 2.182633499999999879e-02 +6.217470000000000496e-01 7.760975660000000165e-01 2.134885499999999992e-02 +6.276903999999999817e-01 7.741666183333330009e-01 2.058969000000000077e-02 +6.410972000000000337e-01 7.019246166666669451e-01 1.908517183333329967e-02 +6.449108999999999536e-01 6.851353900000000108e-01 2.095862666666669857e-02 +6.654345000000000399e-01 5.961630181666669470e-01 1.818150283333330036e-02 +6.842517000000000182e-01 5.507593983333329835e-01 2.023759049999999948e-02 +7.056883000000000461e-01 4.903288296666670210e-01 1.717216466666670119e-02 +7.257436999999999916e-01 4.865799499999999833e-01 1.843612033333329875e-02 +7.489183000000000368e-01 4.252237993333329857e-01 1.512044316666670031e-02 +7.718749999999999778e-01 3.910920323333330062e-01 1.713838283333329882e-02 +7.919618000000000491e-01 3.921714671666670093e-01 1.515910683333330025e-02 +8.153685999999999989e-01 3.357406613333330236e-01 1.534501599999999952e-02 +8.363026999999999544e-01 3.075498956666670169e-01 1.460560383333329992e-02 +8.617884000000000100e-01 2.857851470000000171e-01 1.374501849999999921e-02 +8.844872000000000289e-01 2.740424961666669823e-01 1.443190633333329975e-02 +9.079890000000000461e-01 2.574230581666669959e-01 1.269050000000000039e-02 +9.332829999999999737e-01 2.258197691666669893e-01 1.359980449999999980e-02 +9.550178000000000278e-01 1.934376846666669980e-01 1.273933533333329940e-02 +9.811271999999999771e-01 1.665732448333329951e-01 1.188447333333329976e-02 +1.006633399999999900e+00 1.640185443333329884e-01 1.234030849999999922e-02 +1.030228200000000038e+00 1.357939996666669979e-01 1.165456533333330061e-02 +1.057601100000000072e+00 1.607766528333330058e-01 1.089187166666670016e-02 +1.084413199999999966e+00 1.505459054999999935e-01 1.123158833333329915e-02 +1.109710100000000033e+00 1.282342724999999961e-01 1.086581349999999994e-02 +1.137554500000000024e+00 1.161345933333329944e-01 1.041549200000000015e-02 +1.165834400000000048e+00 1.239725849999999963e-01 1.022116500000000081e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv new file mode 100644 index 0000000000..c869ca7dec --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 5.114892415500000311e+01 1.631213251166670020e+01 +4.070000000000000007e-02 4.576787608166669941e+01 1.134772132833330005e+01 +4.511180000000000051e-02 4.331816215999999997e+01 8.407984515000000769e+00 +4.959249999999999770e-02 2.519454865000000154e+01 6.784784965000000057e+00 +5.416379999999999806e-02 1.407789967999999980e+01 5.302135776666670353e+00 +5.868999999999999911e-02 1.337527417166669963e+01 4.558895663333330184e+00 +6.315320000000000655e-02 2.088227957833329995e+01 3.767553325000000175e+00 +6.773540000000000116e-02 2.352067832833330030e+01 3.153463791666669902e+00 +7.238989999999999314e-02 1.459065788833330046e+01 2.714546644999999980e+00 +7.694339999999999513e-02 1.643097480333329941e+01 2.423213508333330157e+00 +8.166600000000000248e-02 1.564276924666670077e+01 2.035339249999999822e+00 +8.641719999999999957e-02 1.609254856500000130e+01 1.837833853333330048e+00 +9.109140000000000292e-02 1.279946007166670086e+01 1.598433549999999981e+00 +9.576210000000000278e-02 1.168004799999999932e+01 1.472505774999999906e+00 +1.005216000000000026e-01 1.239115217500000021e+01 1.308776653333330042e+00 +1.052672000000000052e-01 1.104442360666669920e+01 1.203200884999999998e+00 +1.100174000000000013e-01 1.264824788499999997e+01 1.100505863333330003e+00 +1.148721999999999938e-01 1.068150069333329988e+01 9.895295950000000396e-01 +1.198083000000000065e-01 1.062919121333329997e+01 9.177280949999999660e-01 +1.248023999999999939e-01 8.480228023333330256e+00 8.376397483333329896e-01 +1.298709000000000113e-01 1.054387282333330056e+01 7.736622133333329598e-01 +1.349431000000000103e-01 8.823326103333329229e+00 7.353996000000000421e-01 +1.399610000000000021e-01 9.107303678333330765e+00 6.707318450000000487e-01 +1.451112999999999986e-01 7.568946575000000010e+00 6.354211899999999691e-01 +1.503050999999999970e-01 7.486937655000000191e+00 6.076642716666670330e-01 +1.556469000000000047e-01 8.316071640000000542e+00 5.572019216666670438e-01 +1.572933999999999999e-01 8.082806423333330770e+00 1.772221983333329975e-01 +1.609891999999999990e-01 8.406204656666670161e+00 5.374420016666670019e-01 +1.662309999999999899e-01 7.305961626666669595e+00 5.035922400000000243e-01 +1.706808999999999965e-01 7.409980823333330413e+00 1.490785450000000067e-01 +1.716062999999999894e-01 7.126663556666669841e+00 4.782201200000000263e-01 +1.771733000000000058e-01 6.104670323333330373e+00 4.398585833333329975e-01 +1.827794000000000085e-01 6.314649313333330127e+00 4.207942599999999755e-01 +1.842987000000000097e-01 6.985669296666669581e+00 1.295300000000000062e-01 +1.883665999999999952e-01 7.196837438333330006e+00 4.229003000000000068e-01 +1.940302000000000138e-01 5.456149725000000394e+00 3.926154199999999928e-01 +1.983015999999999945e-01 6.101519538333329606e+00 1.111746183333330029e-01 +1.998185000000000100e-01 6.715507050000000255e+00 3.818104066666669905e-01 +2.056348000000000065e-01 5.954089436666669677e+00 3.622545733333329965e-01 +2.115208000000000088e-01 5.823000606666670187e+00 3.462099583333330122e-01 +2.120755000000000001e-01 5.689073146666670411e+00 1.016859966666670001e-01 +2.162467999999999890e-01 5.274567024999999632e+00 4.291691899999999782e-01 +2.260508999999999991e-01 5.306054011666669901e+00 9.002336499999999408e-02 +2.398570999999999898e-01 4.872989734999999989e+00 8.416759833333330165e-02 +2.537865999999999733e-01 4.590923198333330291e+00 7.736351666666670124e-02 +2.677086000000000188e-01 4.288802803333330083e+00 7.121471833333330170e-02 +2.818711999999999884e-01 4.093612151666669696e+00 6.655526166666669852e-02 +2.957293999999999756e-01 3.790488160000000217e+00 6.286535166666669394e-02 +3.099983000000000044e-01 3.646502630000000078e+00 5.789795166666669712e-02 +3.241628999999999761e-01 3.269809508333330061e+00 5.578990999999999811e-02 +3.389054000000000233e-01 3.057003066666669877e+00 4.992672166666670130e-02 +3.540212999999999832e-01 3.010102380000000188e+00 4.942106333333329965e-02 +3.688208000000000042e-01 2.669906414999999811e+00 4.496581333333329877e-02 +3.840975999999999835e-01 2.619258584999999862e+00 4.314465499999999704e-02 +3.990183999999999953e-01 2.335828473333330102e+00 4.143680999999999753e-02 +4.106379000000000001e-01 2.148179208166669962e+00 4.160297799999999879e-02 +4.137768000000000002e-01 2.129094906666670006e+00 3.911823833333329808e-02 +4.291927999999999854e-01 2.070782439999999891e+00 3.633175833333329718e-02 +4.295145000000000213e-01 2.006558257333329820e+00 3.534480766666669993e-02 +4.447362000000000259e-01 1.796411879999999961e+00 3.518650999999999723e-02 +4.466328999999999994e-01 1.795892682000000073e+00 3.145603500000000025e-02 +4.604721999999999982e-01 1.744876515000000072e+00 3.296921333333330262e-02 +4.685032000000000085e-01 1.640983006833329982e+00 3.099933850000000102e-02 +4.766304000000000096e-01 1.643527214999999986e+00 3.129624333333329983e-02 +4.833663999999999739e-01 1.494623838666669924e+00 2.933965966666670158e-02 +4.924697000000000102e-01 1.485128543333330109e+00 3.092004166666669981e-02 +5.046184000000000225e-01 1.428664912499999939e+00 2.726148050000000087e-02 +5.084248000000000101e-01 1.392996424999999983e+00 2.844018666666670025e-02 +5.230276000000000369e-01 1.160762609500000098e+00 2.531033383333329903e-02 +5.250753000000000226e-01 1.272159111666669951e+00 2.652694499999999969e-02 +5.418418000000000401e-01 1.157124196666670102e+00 2.613007999999999997e-02 +5.443529999999999758e-01 1.137421045666670016e+00 2.582160033333329857e-02 +5.584759999999999724e-01 1.068463686666669910e+00 2.528335666666670090e-02 +5.612129000000000145e-01 1.030207043666669930e+00 2.342105016666670009e-02 +5.755700000000000260e-01 9.590708749999999894e-01 2.323855999999999838e-02 +5.833568000000000087e-01 9.226566683333330410e-01 2.312843766666669923e-02 +5.929195000000000437e-01 9.361494049999999900e-01 2.261169999999999847e-02 +6.005226999999999649e-01 8.377321681666669573e-01 2.190618299999999921e-02 +6.100906000000000384e-01 8.074355933333330348e-01 2.165867833333329912e-02 +6.218008000000000424e-01 7.338905468333329907e-01 2.116956166666670094e-02 +6.276903999999999817e-01 7.588048750000000453e-01 2.052974999999999939e-02 +6.411527999999999672e-01 6.602236648333329461e-01 1.891721183333330142e-02 +6.449108999999999536e-01 6.976061483333330093e-01 2.103810166666670103e-02 +6.654921999999999782e-01 5.868389913333329488e-01 1.814479133333329886e-02 +6.843110000000000026e-01 5.442379206666669855e-01 2.020865366666670104e-02 +7.057493999999999712e-01 4.561023925000000090e-01 1.703726683333330050e-02 +7.258065000000000211e-01 4.680557555000000036e-01 1.835656600000000124e-02 +7.489831000000000127e-01 4.286472281666670048e-01 1.513358700000000043e-02 +7.719418000000000113e-01 3.942902281666669784e-01 1.715291783333329836e-02 +7.920304000000000233e-01 3.917498161666669865e-01 1.515774683333329965e-02 +8.154392000000000307e-01 3.437863165000000221e-01 1.537817166666670052e-02 +8.363751000000000380e-01 2.882515494999999817e-01 1.453092849999999998e-02 +8.618630000000000457e-01 2.511196196666670155e-01 1.361783299999999933e-02 +8.845638000000000112e-01 2.644882184999999830e-01 1.439263916666670001e-02 +9.080675999999999748e-01 2.444909116666670046e-01 1.264447816666670020e-02 +9.333637999999999657e-01 2.291532736666669900e-01 1.361314100000000048e-02 +9.551005000000000189e-01 1.942403736666669933e-01 1.274254833333329957e-02 +9.812121999999999788e-01 1.854263468333330056e-01 1.195107366666670057e-02 +1.006720599999999965e+00 1.833105325000000119e-01 1.241118433333330065e-02 +1.030317399999999939e+00 1.560276093333330116e-01 1.172809033333330024e-02 +1.057692700000000041e+00 1.687616888333330067e-01 1.091902633333330028e-02 +1.084507099999999946e+00 1.609880563333329906e-01 1.126864266666669986e-02 +1.109806099999999907e+00 1.237764021666669934e-01 1.085079116666669979e-02 +1.137653000000000025e+00 1.252411816666670064e-01 1.044549983333330039e-02 +1.165935399999999955e+00 1.143170270000000016e-01 1.018908599999999998e-02 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv new file mode 100644 index 0000000000..160f11da23 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv @@ -0,0 +1,60 @@ +2.732000000000000053e-02 5.247581629999999677e+03 5.122294999999999732e+01 +3.090999999999999998e-02 3.911350339999999960e+03 4.422301999999999822e+01 +3.452999999999999819e-02 2.897911560000000009e+03 3.806515000000000271e+01 +3.812999999999999723e-02 2.151411560000000009e+03 3.279795000000000016e+01 +4.173999999999999932e-02 1.629610879999999952e+03 2.854479999999999862e+01 +4.542999999999999816e-02 1.229812930000000051e+03 2.479730999999999952e+01 +4.646000000000000130e-02 1.191418850000000020e+03 2.440716000000000108e+01 +4.909000000000000169e-02 9.198557799999999816e+02 2.144593000000000060e+01 +5.254999999999999949e-02 7.981839199999999437e+02 1.997728999999999999e+01 +5.270999999999999991e-02 7.205761899999999969e+02 1.898125999999999891e+01 +5.630999999999999894e-02 5.509914999999999736e+02 1.659806000000000026e+01 +5.870999999999999830e-02 5.012570499999999925e+02 1.583125000000000071e+01 +5.988000000000000267e-02 4.332142900000000054e+02 1.471757999999999988e+01 +6.353999999999999926e-02 3.420333299999999781e+02 1.307732999999999990e+01 +6.482999999999999874e-02 3.398080699999999865e+02 1.303472000000000008e+01 +6.716999999999999360e-02 2.726683699999999817e+02 1.167622000000000071e+01 +7.073000000000000120e-02 2.204248299999999858e+02 1.049821000000000026e+01 +7.095999999999999530e-02 2.235476199999999949e+02 1.057230999999999987e+01 +7.434999999999999942e-02 1.760958799999999940e+02 9.383390000000000342e+00 +7.724000000000000310e-02 1.542382200000000125e+02 8.781750000000000611e+00 +7.799999999999999989e-02 1.457825499999999863e+02 8.537639999999999674e+00 +8.164000000000000423e-02 1.201677600000000012e+02 7.751380000000000159e+00 +8.346000000000000640e-02 1.089934400000000068e+02 7.382189999999999586e+00 +8.525000000000000633e-02 9.836262000000000683e+01 7.012940000000000396e+00 +8.881999999999999618e-02 8.192439000000000249e+01 6.400170000000000137e+00 +8.962000000000000521e-02 7.733648999999999774e+01 6.218379999999999797e+00 +9.572999999999999565e-02 5.882012000000000285e+01 5.423099999999999810e+00 +1.018000000000000016e-01 4.406902000000000186e+01 4.694090000000000096e+00 +1.080300000000000010e-01 3.487624000000000279e+01 4.175900000000000389e+00 +1.141999999999999960e-01 2.769241999999999848e+01 3.721049999999999969e+00 +1.202399999999999997e-01 2.227824000000000026e+01 3.337530000000000108e+00 +1.263900000000000023e-01 1.858717000000000041e+01 3.048540000000000028e+00 +1.325999999999999956e-01 1.587791999999999959e+01 2.817619999999999791e+00 +1.388199999999999990e-01 1.416899000000000086e+01 2.661669999999999980e+00 +1.449499999999999955e-01 1.174597999999999942e+01 2.423430000000000195e+00 +1.509900000000000131e-01 1.047161000000000008e+01 2.288190000000000168e+00 +1.571599999999999941e-01 9.681599999999999540e+00 2.200180000000000025e+00 +1.633799999999999975e-01 8.894579999999999487e+00 2.108859999999999957e+00 +1.695599999999999885e-01 8.317479999999999762e+00 2.039299999999999891e+00 +1.756800000000000028e-01 7.913870000000000182e+00 1.989200000000000079e+00 +1.818599999999999939e-01 7.771530000000000271e+00 1.971230000000000038e+00 +1.880699999999999872e-01 7.882909999999999862e+00 1.985309999999999908e+00 +1.941799999999999915e-01 7.707720000000000127e+00 1.963130000000000042e+00 +2.002800000000000136e-01 7.676859999999999573e+00 1.959189999999999987e+00 +2.064199999999999924e-01 7.872259999999999813e+00 1.983970000000000011e+00 +2.126000000000000112e-01 7.870400000000000063e+00 1.983729999999999993e+00 +2.187500000000000000e-01 7.977940000000000254e+00 1.997239999999999904e+00 +2.248699999999999866e-01 8.152039999999999509e+00 2.018920000000000048e+00 +2.310500000000000054e-01 8.298420000000000130e+00 2.036960000000000104e+00 +2.372700000000000087e-01 8.716689999999999827e+00 2.087660000000000071e+00 +2.434399999999999897e-01 8.782600000000000406e+00 2.095540000000000180e+00 +2.495600000000000041e-01 8.933479999999999421e+00 2.113469999999999960e+00 +2.556899999999999729e-01 9.374109999999999943e+00 2.164960000000000218e+00 +2.618500000000000272e-01 9.457430000000000447e+00 2.174560000000000048e+00 +2.680500000000000105e-01 9.702469999999999928e+00 2.202550000000000008e+00 +2.742100000000000093e-01 9.923930000000000362e+00 2.227549999999999919e+00 +2.802999999999999936e-01 1.008966000000000030e+01 2.246070000000000011e+00 +2.864599999999999924e-01 1.031367999999999974e+01 2.270869999999999944e+00 +2.926699999999999857e-01 1.058960000000000079e+01 2.301039999999999974e+00 +2.988199999999999745e-01 1.062256999999999962e+01 2.304619999999999891e+00 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv new file mode 100644 index 0000000000..80562dff52 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv @@ -0,0 +1,60 @@ +2.732000000000000053e-02 3.883615650000000187e+03 4.406595000000000084e+01 +3.090000000000000038e-02 3.072013609999999971e+03 3.919192000000000320e+01 +3.452999999999999819e-02 2.355659860000000208e+03 3.431953000000000031e+01 +3.812999999999999723e-02 1.806985030000000052e+03 3.005815000000000126e+01 +4.173999999999999932e-02 1.389839799999999968e+03 2.636132999999999882e+01 +4.542000000000000204e-02 1.072684349999999995e+03 2.315906000000000020e+01 +4.644000000000000211e-02 9.624380499999999756e+02 2.193669999999999831e+01 +4.907999999999999863e-02 8.065360500000000457e+02 2.008153000000000077e+01 +5.253000000000000030e-02 6.666923000000000457e+02 1.825777000000000072e+01 +5.270999999999999991e-02 6.432540800000000445e+02 1.793395999999999901e+01 +5.630000000000000282e-02 4.985809499999999730e+02 1.578894000000000020e+01 +5.868999999999999911e-02 4.290448299999999904e+02 1.464658000000000015e+01 +5.986999999999999961e-02 3.918163299999999936e+02 1.399671999999999983e+01 +6.353000000000000314e-02 3.098850299999999720e+02 1.244758999999999993e+01 +6.481000000000000649e-02 2.946982499999999732e+02 1.213874000000000031e+01 +6.715999999999999748e-02 2.516384400000000028e+02 1.121692000000000000e+01 +7.072000000000000508e-02 2.028407500000000141e+02 1.007076999999999956e+01 +7.094000000000000306e-02 1.948358800000000031e+02 9.870050000000000878e+00 +7.434000000000000330e-02 1.633427599999999984e+02 9.037219999999999587e+00 +7.721000000000000085e-02 1.371933899999999937e+02 8.282310000000000727e+00 +7.799000000000000377e-02 1.347819700000000012e+02 8.209199999999999164e+00 +8.162999999999999423e-02 1.123165999999999940e+02 7.493879999999999875e+00 +8.343000000000000416e-02 9.602442000000000633e+01 6.929079999999999906e+00 +8.523999999999999633e-02 9.249591999999999814e+01 6.800589999999999691e+00 +8.880000000000000393e-02 7.934887999999999408e+01 6.298759999999999692e+00 +8.959000000000000297e-02 7.016214999999999691e+01 5.922930000000000028e+00 +9.568999999999999728e-02 5.357988000000000284e+01 5.175900000000000389e+00 +1.017699999999999994e-01 4.050641000000000247e+01 4.500359999999999694e+00 +1.079900000000000027e-01 3.194395000000000095e+01 3.996500000000000163e+00 +1.141599999999999976e-01 2.563089000000000084e+01 3.579870000000000108e+00 +1.202000000000000013e-01 2.144641999999999982e+01 3.274630000000000152e+00 +1.263499999999999901e-01 1.696240999999999843e+01 2.912249999999999783e+00 +1.325600000000000112e-01 1.453672000000000075e+01 2.695990000000000109e+00 +1.387700000000000045e-01 1.265718999999999994e+01 2.515670000000000073e+00 +1.449000000000000010e-01 1.114897000000000027e+01 2.361029999999999962e+00 +1.509399999999999908e-01 1.005156999999999989e+01 2.241830000000000211e+00 +1.571099999999999997e-01 9.313710000000000377e+00 2.157970000000000166e+00 +1.633300000000000030e-01 8.668530000000000513e+00 2.081890000000000018e+00 +1.695099999999999940e-01 7.810069999999999624e+00 1.976120000000000099e+00 +1.756300000000000083e-01 7.695079999999999920e+00 1.961519999999999930e+00 +1.817999999999999894e-01 7.222220000000000084e+00 1.900290000000000035e+00 +1.880100000000000104e-01 7.386999999999999567e+00 1.921850000000000058e+00 +1.941199999999999870e-01 7.239320000000000199e+00 1.902539999999999898e+00 +2.002200000000000091e-01 7.279099999999999682e+00 1.907759999999999900e+00 +2.063500000000000056e-01 7.406340000000000146e+00 1.924360000000000070e+00 +2.125299999999999967e-01 7.439199999999999591e+00 1.928630000000000067e+00 +2.186800000000000133e-01 7.556879999999999598e+00 1.943820000000000103e+00 +2.247899999999999898e-01 7.730520000000000280e+00 1.966029999999999944e+00 +2.309799999999999909e-01 8.106099999999999639e+00 2.013220000000000010e+00 +2.371999999999999942e-01 8.398609999999999687e+00 2.049220000000000041e+00 +2.433599999999999930e-01 8.171440000000000481e+00 2.021319999999999784e+00 +2.494800000000000073e-01 8.478289999999999438e+00 2.058920000000000083e+00 +2.556100000000000039e-01 8.796279999999999433e+00 2.097170000000000201e+00 +2.617700000000000027e-01 8.973420000000000840e+00 2.118189999999999795e+00 +2.679699999999999860e-01 9.270730000000000359e+00 2.152989999999999959e+00 +2.741299999999999848e-01 9.463879999999999626e+00 2.175300000000000011e+00 +2.802100000000000146e-01 9.409150000000000347e+00 2.169000000000000039e+00 +2.863700000000000134e-01 9.709509999999999863e+00 2.203349999999999920e+00 +2.925800000000000067e-01 9.851300000000000168e+00 2.219380000000000130e+00 +2.987299999999999955e-01 9.904920000000000613e+00 2.225410000000000110e+00 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv new file mode 100644 index 0000000000..6e68726d83 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv @@ -0,0 +1,60 @@ +2.732000000000000053e-02 2.792353740000000016e+03 3.736545000000000272e+01 +3.090000000000000038e-02 2.271702040000000125e+03 3.370239000000000118e+01 +3.452000000000000207e-02 1.788897279999999910e+03 2.990733000000000175e+01 +3.812000000000000111e-02 1.407023470000000088e+03 2.652380000000000138e+01 +4.173000000000000320e-02 1.095009520000000066e+03 2.339882000000000062e+01 +4.542000000000000204e-02 8.376734699999999521e+02 2.046549999999999869e+01 +4.644000000000000211e-02 7.836296200000000454e+02 1.979430999999999941e+01 +4.907000000000000250e-02 6.414952399999999670e+02 1.790943000000000040e+01 +5.253000000000000030e-02 5.516777200000000221e+02 1.660839999999999961e+01 +5.269999999999999685e-02 5.141714299999999866e+02 1.603388999999999953e+01 +5.628999999999999976e-02 3.988418399999999906e+02 1.412165000000000070e+01 +5.868999999999999911e-02 3.579082799999999907e+02 1.337737000000000087e+01 +5.985999999999999654e-02 3.164397999999999911e+02 1.257854999999999990e+01 +6.351999999999999313e-02 2.486343500000000120e+02 1.114976000000000056e+01 +6.481000000000000649e-02 2.482066299999999899e+02 1.114016999999999946e+01 +6.715000000000000135e-02 2.006787799999999891e+02 1.001695999999999920e+01 +7.070999999999999508e-02 1.657927200000000028e+02 9.104739999999999611e+00 +7.094000000000000306e-02 1.667760000000000105e+02 9.131700000000000372e+00 +7.431999999999999718e-02 1.326982299999999952e+02 8.145500000000000185e+00 +7.721000000000000085e-02 1.181177100000000024e+02 7.684980000000000366e+00 +7.796999999999999764e-02 1.108474499999999949e+02 7.444709999999999717e+00 +8.161999999999999811e-02 9.087302999999999997e+01 6.740660000000000096e+00 +8.343000000000000416e-02 8.290343000000000018e+01 6.438299999999999912e+00 +8.522000000000000408e-02 7.588799000000000206e+01 6.159869999999999735e+00 +8.878999999999999393e-02 6.486343999999999710e+01 5.694890000000000008e+00 +8.959000000000000297e-02 6.133471999999999724e+01 5.537810000000000343e+00 +9.568999999999999728e-02 4.711737999999999715e+01 4.853729999999999656e+00 +1.017699999999999994e-01 3.554666000000000281e+01 4.215840000000000032e+00 +1.079900000000000027e-01 2.833098000000000027e+01 3.763710000000000111e+00 +1.141599999999999976e-01 2.318925000000000125e+01 3.405089999999999950e+00 +1.202000000000000013e-01 1.876435000000000031e+01 3.063029999999999919e+00 +1.263499999999999901e-01 1.568601999999999919e+01 2.800539999999999807e+00 +1.325600000000000112e-01 1.346410000000000018e+01 2.594619999999999926e+00 +1.387700000000000045e-01 1.173840000000000039e+01 2.422639999999999905e+00 +1.449000000000000010e-01 1.054757999999999996e+01 2.296469999999999789e+00 +1.509399999999999908e-01 9.084839999999999804e+00 2.131299999999999972e+00 +1.571099999999999997e-01 8.239589999999999748e+00 2.029729999999999812e+00 +1.633300000000000030e-01 7.767660000000000231e+00 1.970739999999999936e+00 +1.695099999999999940e-01 7.631929999999999659e+00 1.953449999999999909e+00 +1.756300000000000083e-01 7.253739999999999633e+00 1.904430000000000067e+00 +1.817999999999999894e-01 6.968580000000000219e+00 1.866630000000000011e+00 +1.880100000000000104e-01 7.029829999999999579e+00 1.874810000000000088e+00 +1.941199999999999870e-01 6.805609999999999715e+00 1.844670000000000032e+00 +2.002200000000000091e-01 7.007130000000000081e+00 1.871779999999999999e+00 +2.063500000000000056e-01 7.083709999999999951e+00 1.881979999999999986e+00 +2.125299999999999967e-01 6.971890000000000143e+00 1.867070000000000007e+00 +2.186800000000000133e-01 7.549360000000000070e+00 1.942849999999999966e+00 +2.247899999999999898e-01 7.451310000000000322e+00 1.930199999999999916e+00 +2.309799999999999909e-01 7.449589999999999712e+00 1.929969999999999963e+00 +2.371999999999999942e-01 7.776720000000000077e+00 1.971889999999999921e+00 +2.433599999999999930e-01 8.157130000000000436e+00 2.019550000000000178e+00 +2.494800000000000073e-01 8.339280000000000470e+00 2.041970000000000063e+00 +2.556100000000000039e-01 8.448100000000000165e+00 2.055250000000000021e+00 +2.617700000000000027e-01 8.746420000000000528e+00 2.091219999999999857e+00 +2.679699999999999860e-01 9.040720000000000312e+00 2.126110000000000166e+00 +2.741299999999999848e-01 9.130409999999999471e+00 2.136629999999999807e+00 +2.802100000000000146e-01 9.247719999999999274e+00 2.150319999999999787e+00 +2.863700000000000134e-01 9.291150000000000020e+00 2.155359999999999943e+00 +2.925800000000000067e-01 9.640140000000000597e+00 2.195469999999999811e+00 +2.987299999999999955e-01 9.537290000000000489e+00 2.183720000000000105e+00 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv new file mode 100644 index 0000000000..c33506202f --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv @@ -0,0 +1,60 @@ +2.733000000000000013e-02 2.320909860000000208e+03 3.406544999999999845e+01 +3.090999999999999998e-02 1.910828909999999951e+03 3.090978000000000137e+01 +3.454000000000000126e-02 1.519815650000000005e+03 2.756643000000000043e+01 +3.814000000000000029e-02 1.188850680000000011e+03 2.438083999999999918e+01 +4.175000000000000239e-02 9.312768700000000308e+02 2.157865999999999929e+01 +4.544000000000000122e-02 7.201697299999999586e+02 1.897589999999999932e+01 +4.646000000000000130e-02 6.728012599999999566e+02 1.834122999999999948e+01 +4.909999999999999781e-02 5.453608799999999519e+02 1.651304000000000016e+01 +5.256000000000000255e-02 4.724414499999999748e+02 1.536946999999999974e+01 +5.272000000000000297e-02 4.318700699999999983e+02 1.469472999999999985e+01 +5.632000000000000201e-02 3.382353699999999890e+02 1.300453000000000081e+01 +5.870999999999999830e-02 3.073326000000000136e+02 1.239621999999999957e+01 +5.988999999999999879e-02 2.634156100000000151e+02 1.147639999999999993e+01 +6.356000000000000538e-02 2.076918699999999944e+02 1.019048000000000087e+01 +6.483999999999999486e-02 2.125336499999999944e+02 1.030857999999999919e+01 +6.718999999999999972e-02 1.688028199999999970e+02 9.187020000000000408e+00 +7.073999999999999733e-02 1.362696899999999971e+02 8.254379999999999384e+00 +7.097000000000000530e-02 1.410024300000000039e+02 8.396499999999999631e+00 +7.435999999999999555e-02 1.127603699999999947e+02 7.508670000000000400e+00 +7.724999999999999922e-02 9.965560999999999581e+01 7.058880000000000265e+00 +7.800999999999999601e-02 9.194693999999999789e+01 6.780369999999999564e+00 +8.165999999999999648e-02 7.522768999999999551e+01 6.133009999999999629e+00 +8.347000000000000253e-02 7.049939999999999429e+01 5.937149999999999928e+00 +8.526000000000000245e-02 6.411020000000000607e+01 5.661719999999999864e+00 +8.883000000000000618e-02 5.376234999999999786e+01 5.184709999999999930e+00 +8.963000000000000134e-02 5.217504000000000275e+01 5.107590000000000074e+00 +9.574000000000000565e-02 4.054399999999999693e+01 4.502439999999999998e+00 +1.018199999999999938e-01 3.096013999999999911e+01 3.934470000000000134e+00 +1.080399999999999971e-01 2.426012000000000057e+01 3.482819999999999805e+00 +1.142200000000000021e-01 1.991522000000000148e+01 3.155569999999999986e+00 +1.202600000000000058e-01 1.696463999999999928e+01 2.912440000000000140e+00 +1.264099999999999946e-01 1.406012999999999913e+01 2.651429999999999954e+00 +1.326199999999999879e-01 1.186475000000000080e+01 2.435649999999999871e+00 +1.388300000000000090e-01 1.075843000000000060e+01 2.319310000000000205e+00 +1.449699999999999878e-01 9.447770000000000223e+00 2.173449999999999882e+00 +1.510100000000000053e-01 8.521739999999999426e+00 2.064189999999999969e+00 +1.571799999999999864e-01 7.782460000000000377e+00 1.972620000000000040e+00 +1.634099999999999997e-01 7.576889999999999681e+00 1.946390000000000065e+00 +1.695800000000000085e-01 7.175270000000000259e+00 1.894109999999999960e+00 +1.756999999999999951e-01 6.609770000000000145e+00 1.817930000000000046e+00 +1.818799999999999861e-01 6.690150000000000041e+00 1.828950000000000076e+00 +1.880999999999999894e-01 6.763010000000000410e+00 1.838889999999999914e+00 +1.942000000000000115e-01 6.479930000000000412e+00 1.799989999999999979e+00 +2.003099999999999881e-01 6.931930000000000369e+00 1.861709999999999976e+00 +2.064499999999999946e-01 7.058690000000000353e+00 1.878649999999999931e+00 +2.126300000000000134e-01 6.966739999999999711e+00 1.866379999999999928e+00 +2.187699999999999922e-01 7.155350000000000321e+00 1.891469999999999985e+00 +2.248999999999999888e-01 7.328820000000000334e+00 1.914260000000000073e+00 +2.310800000000000076e-01 7.623789999999999623e+00 1.952409999999999979e+00 +2.373000000000000109e-01 7.870739999999999625e+00 1.983780000000000099e+00 +2.434699999999999920e-01 7.865639999999999965e+00 1.983130000000000059e+00 +2.495900000000000063e-01 8.081390000000000740e+00 2.010149999999999881e+00 +2.557300000000000129e-01 8.480309999999999349e+00 2.059159999999999879e+00 +2.618900000000000117e-01 8.708700000000000330e+00 2.086710000000000065e+00 +2.680899999999999950e-01 8.823320000000000718e+00 2.100389999999999979e+00 +2.742499999999999938e-01 9.030450000000000088e+00 2.124909999999999854e+00 +2.803300000000000236e-01 9.222670000000000812e+00 2.147400000000000198e+00 +2.864999999999999769e-01 9.345430000000000348e+00 2.161649999999999849e+00 +2.927100000000000257e-01 9.660539999999999239e+00 2.197789999999999910e+00 +2.988600000000000145e-01 9.559969999999999857e+00 2.186319999999999819e+00 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv new file mode 100644 index 0000000000..17968ec9ed --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv @@ -0,0 +1,60 @@ +2.733000000000000013e-02 1.791495509999999967e+03 2.992905000000000015e+01 +3.091999999999999957e-02 1.477992469999999912e+03 2.718449000000000026e+01 +3.454000000000000126e-02 1.172791189999999915e+03 2.421561000000000163e+01 +3.814000000000000029e-02 9.196233300000000099e+02 2.144322000000000017e+01 +4.175000000000000239e-02 7.160111200000000053e+02 1.892102999999999824e+01 +4.544000000000000122e-02 5.391461900000000469e+02 1.641867999999999839e+01 +4.646000000000000130e-02 4.929036699999999769e+02 1.569877999999999929e+01 +4.909999999999999781e-02 4.129331099999999992e+02 1.436894000000000027e+01 +5.256000000000000255e-02 3.482022600000000239e+02 1.319473999999999947e+01 +5.272999999999999909e-02 3.242194700000000012e+02 1.273222999999999949e+01 +5.632000000000000201e-02 2.454095199999999863e+02 1.107722000000000051e+01 +5.870999999999999830e-02 2.218204599999999971e+02 1.053139000000000003e+01 +5.990000000000000185e-02 1.931666899999999885e+02 9.827680000000000859e+00 +6.356000000000000538e-02 1.505020900000000097e+02 8.674739999999999895e+00 +6.483999999999999486e-02 1.511605900000000133e+02 8.693690000000000140e+00 +6.718999999999999972e-02 1.202856799999999993e+02 7.755180000000000184e+00 +7.074999999999999345e-02 9.616129999999999711e+01 6.934020000000000294e+00 +7.097000000000000530e-02 9.870516999999999541e+01 7.025140000000000384e+00 +7.435999999999999555e-02 7.818730999999999653e+01 6.252489999999999881e+00 +7.724999999999999922e-02 6.837958000000000425e+01 5.847199999999999953e+00 +7.802000000000000601e-02 6.371482000000000312e+01 5.644239999999999924e+00 +8.165999999999999648e-02 5.179379999999999740e+01 5.088899999999999757e+00 +8.347000000000000253e-02 4.836007000000000033e+01 4.917320000000000135e+00 +8.526999999999999857e-02 4.457972000000000179e+01 4.721210000000000129e+00 +8.884000000000000230e-02 3.751116999999999990e+01 4.330770000000000231e+00 +8.963000000000000134e-02 3.544118999999999886e+01 4.209579999999999878e+00 +9.574000000000000565e-02 2.739192999999999856e+01 3.700810000000000155e+00 +1.018199999999999938e-01 2.084316000000000102e+01 3.228250000000000064e+00 +1.080399999999999971e-01 1.702296000000000120e+01 2.917440000000000033e+00 +1.142200000000000021e-01 1.391883999999999943e+01 2.638069999999999915e+00 +1.202600000000000058e-01 1.148202000000000034e+01 2.396040000000000170e+00 +1.264099999999999946e-01 9.887589999999999435e+00 2.223460000000000214e+00 +1.326199999999999879e-01 8.618710000000000093e+00 2.075899999999999856e+00 +1.388300000000000090e-01 7.875820000000000043e+00 1.984420000000000073e+00 +1.449699999999999878e-01 7.119869999999999699e+00 1.886779999999999902e+00 +1.510100000000000053e-01 6.691399999999999793e+00 1.829129999999999923e+00 +1.571799999999999864e-01 6.133020000000000138e+00 1.751139999999999919e+00 +1.634099999999999997e-01 5.984770000000000145e+00 1.729850000000000110e+00 +1.695800000000000085e-01 5.802669999999999995e+00 1.703330000000000011e+00 +1.756999999999999951e-01 5.772070000000000256e+00 1.698830000000000062e+00 +1.818799999999999861e-01 5.866640000000000299e+00 1.712690000000000046e+00 +1.880999999999999894e-01 5.880740000000000300e+00 1.714749999999999996e+00 +1.942000000000000115e-01 5.856810000000000294e+00 1.711260000000000003e+00 +2.003099999999999881e-01 6.138060000000000294e+00 1.751870000000000038e+00 +2.064499999999999946e-01 6.406990000000000407e+00 1.789830000000000032e+00 +2.126300000000000134e-01 6.462060000000000137e+00 1.797509999999999941e+00 +2.187699999999999922e-01 6.501079999999999970e+00 1.802929999999999922e+00 +2.248999999999999888e-01 6.991179999999999950e+00 1.869650000000000034e+00 +2.310800000000000076e-01 7.014639999999999986e+00 1.872779999999999889e+00 +2.373000000000000109e-01 7.136879999999999669e+00 1.889029999999999987e+00 +2.434699999999999920e-01 7.547889999999999766e+00 1.942660000000000053e+00 +2.495900000000000063e-01 7.608620000000000161e+00 1.950460000000000083e+00 +2.557300000000000129e-01 7.913459999999999717e+00 1.989149999999999974e+00 +2.618900000000000117e-01 8.245919999999999916e+00 2.030510000000000037e+00 +2.680899999999999950e-01 8.604509999999999437e+00 2.074190000000000200e+00 +2.742499999999999938e-01 8.711750000000000327e+00 2.087070000000000203e+00 +2.803300000000000236e-01 8.863739999999999952e+00 2.105199999999999960e+00 +2.864999999999999769e-01 8.911099999999999355e+00 2.110819999999999919e+00 +2.927100000000000257e-01 9.338430000000000675e+00 2.160839999999999872e+00 +2.988600000000000145e-01 9.385640000000000427e+00 2.166290000000000049e+00 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv new file mode 100644 index 0000000000..72272ed89c --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv @@ -0,0 +1,60 @@ +2.732000000000000053e-02 1.517870979999999918e+03 2.754878000000000071e+01 +3.090999999999999998e-02 1.252144950000000108e+03 2.502143999999999835e+01 +3.452999999999999819e-02 9.849326300000000174e+02 2.219157999999999831e+01 +3.812999999999999723e-02 7.635778900000000249e+02 1.953941999999999979e+01 +4.173999999999999932e-02 5.910564900000000534e+02 1.719093000000000160e+01 +4.542999999999999816e-02 4.454160299999999779e+02 1.492340000000000089e+01 +4.644000000000000211e-02 4.097451399999999921e+02 1.431337000000000081e+01 +4.907999999999999863e-02 3.412573399999999992e+02 1.306249000000000038e+01 +5.254000000000000337e-02 2.833860500000000116e+02 1.190348999999999968e+01 +5.270999999999999991e-02 2.587516299999999774e+02 1.137434999999999974e+01 +5.630000000000000282e-02 1.972410900000000140e+02 9.930790000000000006e+00 +5.868999999999999911e-02 1.820288400000000024e+02 9.540150000000000574e+00 +5.988000000000000267e-02 1.548462399999999946e+02 8.799039999999999750e+00 +6.353999999999999926e-02 1.208091600000000057e+02 7.772039999999999615e+00 +6.481000000000000649e-02 1.228846300000000014e+02 7.838510000000000311e+00 +6.716999999999999360e-02 9.485747999999999536e+01 6.886849999999999916e+00 +7.072000000000000508e-02 7.616365000000000407e+01 6.171050000000000146e+00 +7.094999999999999918e-02 7.959243999999999630e+01 6.308419999999999916e+00 +7.434000000000000330e-02 6.139544999999999675e+01 5.540549999999999642e+00 +7.721999999999999698e-02 5.528307999999999822e+01 5.257520000000000415e+00 +7.799000000000000377e-02 5.105310999999999666e+01 5.052380000000000315e+00 +8.164000000000000423e-02 4.131436000000000064e+01 4.545020000000000060e+00 +8.343000000000000416e-02 3.883191999999999666e+01 4.406349999999999767e+00 +8.523999999999999633e-02 3.386838999999999800e+01 4.115120000000000111e+00 +8.881000000000000005e-02 2.873742000000000019e+01 3.790610000000000035e+00 +8.959999999999999909e-02 2.744166999999999845e+01 3.704159999999999897e+00 +9.569999999999999341e-02 2.114314999999999856e+01 3.251399999999999846e+00 +1.017799999999999955e-01 1.639198000000000022e+01 2.862859999999999960e+00 +1.079999999999999988e-01 1.302345000000000041e+01 2.551810000000000134e+00 +1.141699999999999937e-01 1.067233000000000054e+01 2.310010000000000119e+00 +1.202099999999999974e-01 8.927680000000000504e+00 2.112779999999999880e+00 +1.263600000000000001e-01 7.691300000000000026e+00 1.961030000000000051e+00 +1.325600000000000112e-01 6.633219999999999672e+00 1.821159999999999890e+00 +1.387799999999999867e-01 6.187759999999999927e+00 1.758939999999999948e+00 +1.449100000000000110e-01 5.397269999999999790e+00 1.642749999999999932e+00 +1.509500000000000008e-01 5.127299999999999969e+00 1.601140000000000008e+00 +1.571200000000000097e-01 4.947350000000000136e+00 1.572789999999999910e+00 +1.633400000000000130e-01 4.791970000000000063e+00 1.547900000000000054e+00 +1.695200000000000040e-01 4.839830000000000076e+00 1.555609999999999937e+00 +1.756399999999999906e-01 4.855599999999999916e+00 1.558140000000000081e+00 +1.818099999999999994e-01 4.971189999999999998e+00 1.576580000000000092e+00 +1.880199999999999927e-01 4.996179999999999843e+00 1.580540000000000056e+00 +1.941299999999999970e-01 5.231489999999999974e+00 1.617329999999999934e+00 +2.002299999999999913e-01 5.461660000000000181e+00 1.652519999999999989e+00 +2.063699999999999979e-01 5.566430000000000433e+00 1.668299999999999894e+00 +2.125400000000000067e-01 5.749649999999999928e+00 1.695529999999999982e+00 +2.186899999999999955e-01 5.962720000000000020e+00 1.726660000000000084e+00 +2.248100000000000098e-01 6.366220000000000212e+00 1.784129999999999994e+00 +2.309900000000000009e-01 6.576419999999999710e+00 1.813339999999999952e+00 +2.372100000000000042e-01 6.993730000000000224e+00 1.869990000000000041e+00 +2.433800000000000130e-01 7.112300000000000288e+00 1.885780000000000012e+00 +2.494999999999999996e-01 7.346860000000000390e+00 1.916619999999999990e+00 +2.556300000000000239e-01 7.629410000000000025e+00 1.953130000000000033e+00 +2.617900000000000227e-01 7.827810000000000379e+00 1.978359999999999896e+00 +2.679900000000000060e-01 8.252810000000000201e+00 2.031359999999999832e+00 +2.741399999999999948e-01 8.304840000000000444e+00 2.037749999999999950e+00 +2.802200000000000246e-01 8.705450000000000799e+00 2.086320000000000174e+00 +2.863899999999999779e-01 8.881330000000000169e+00 2.107289999999999885e+00 +2.926000000000000267e-01 9.112230000000000274e+00 2.134510000000000129e+00 +2.987500000000000155e-01 9.303969999999999629e+00 2.156849999999999934e+00 diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1.csv new file mode 100644 index 0000000000..efaf03f7e5 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1.csv @@ -0,0 +1,53 @@ +0.02466 11161.7 105.066 +0.02779 8582.24 78.8702 +0.03118 6929.14 63.4309 +0.03472 5567.83 52.0489 +0.03798 4896.87 48.9428 +0.04103 4301.45 44.2537 +0.04439 3931.56 35.32 +0.04789 3532.24 33.8506 +0.05145 3225.93 29.1479 +0.05487 3001.52 30.0366 +0.05809 2808.67 26.8966 +0.06147 2656.59 24.6464 +0.06487 2544.49 24.3544 +0.06823 2417.04 22.1946 +0.07159 2285.04 21.753 +0.07491 2209.24 20.4624 +0.07817 2057.47 19.703 +0.08149 2022.7 18.6311 +0.08492 1895.55 17.4353 +0.08832 1842.28 17.2068 +0.09171 1764.56 16.4013 +0.09497 1702.47 16.2564 +0.09818 1650.68 15.7993 +0.10176 1598.61 13.5448 +0.10537 1517.07 14.6455 +0.10864 1470.19 13.6872 +0.11191 1422.64 13.7771 +0.11529 1373.82 12.5952 +0.11874 1333.67 12.468 +0.12204 1309.38 12.7116 +0.1253 1256.04 11.6755 +0.12868 1224.03 11.535 +0.13213 1180.94 10.9145 +0.13557 1163.16 10.9427 +0.13878 1135.89 11.2995 +0.14204 1129.91 10.3422 +0.14544 1101.7 10.3463 +0.14888 1050.46 9.68171 +0.1523 1034.3 9.79525 +0.15558 1022.51 9.86417 +0.15895 1003.15 9.06883 +0.16231 984.02 9.61305 +0.16567 956.076 8.69603 +0.16916 941.039 8.81872 +0.17256 914.22 8.5457 +0.1759 903.557 8.49062 +0.1792 862.822 8.49027 +0.18246 857.39 8.12443 +0.18596 822.372 7.58423 +0.18945 803.539 7.77639 +0.19275 787.933 7.6279 +0.19605 759.06 7.64242 +0.1993 746.444 7.32989 diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1.csv new file mode 100644 index 0000000000..ede4f81215 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1.csv @@ -0,0 +1,53 @@ +0.02466 9785.87 100.498 +0.02779 7387.61 74.8808 +0.03118 5638.9 58.6706 +0.03472 4473.77 47.7572 +0.03797 3723.19 43.7134 +0.04102 3256.4 39.3915 +0.04439 2850.7 30.7019 +0.04789 2561.59 29.3595 +0.05145 2280.01 24.9612 +0.05487 2158.85 25.8372 +0.05809 1997.24 23.0262 +0.06147 1891.61 21.0832 +0.06486 1796.03 20.6896 +0.06823 1698.02 18.8045 +0.07158 1613.84 18.4277 +0.0749 1560.07 17.3367 +0.07817 1481.58 16.8421 +0.08149 1400.5 15.6189 +0.08492 1362.71 14.8771 +0.08832 1326.21 14.6884 +0.09171 1308.1 14.1935 +0.09497 1238.48 13.9232 +0.09817 1217.12 13.6217 +0.10176 1182.01 11.7148 +0.10536 1125.29 12.6688 +0.10863 1086.39 11.8029 +0.1119 1069.27 11.9783 +0.11528 1037.53 10.9946 +0.11874 1000.25 10.8391 +0.12203 1030.21 11.3207 +0.12529 996.562 10.4091 +0.12867 937.635 10.1418 +0.13213 932.787 9.7458 +0.13557 936.093 9.83598 +0.13878 902.903 10.118 +0.14204 895.331 9.2379 +0.14544 894.523 9.3444 +0.14887 873.213 8.84172 +0.15229 870.028 8.99453 +0.15558 846.466 8.9992 +0.15895 842.358 8.32813 +0.1623 809.53 8.74144 +0.16566 822.783 8.08431 +0.16915 792.943 8.10552 +0.17255 774.308 7.87783 +0.1759 781.539 7.90816 +0.17919 756.562 7.97296 +0.18245 745.925 7.59066 +0.18596 725.982 7.13904 +0.18944 711.483 7.3287 +0.19275 709.157 7.24903 +0.19604 677.704 7.2411 +0.19929 659.648 6.90112 diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1.csv new file mode 100644 index 0000000000..1c96f3d5fd --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1.csv @@ -0,0 +1,53 @@ +0.02467 9119.79 98.2483 +0.02779 6716.34 72.6007 +0.03118 4992.66 56.2161 +0.03472 3831.98 45.1388 +0.03798 3145.6 40.9924 +0.04103 2635.02 36.2785 +0.0444 2353.33 28.4064 +0.04789 2051.02 26.7601 +0.05146 1820.51 22.7202 +0.05487 1702.5 23.3101 +0.0581 1582.43 20.8224 +0.06148 1455.78 18.7977 +0.06487 1396.8 18.5029 +0.06824 1347.58 16.9495 +0.07159 1258.02 16.4371 +0.07491 1231.28 15.5554 +0.07818 1164.47 15.0776 +0.0815 1146.97 14.2378 +0.08493 1109.77 13.533 +0.08833 1040.08 13.1167 +0.09172 1030.03 12.6919 +0.09498 996.502 12.5769 +0.09819 973.153 12.2625 +0.10178 933.855 10.4847 +0.10538 941.324 11.6421 +0.10865 891.14 10.747 +0.11192 890.927 10.9919 +0.1153 863.999 10.0862 +0.11876 860.652 10.1051 +0.12205 833.905 10.2392 +0.12531 831.414 9.54046 +0.12869 796.354 9.38666 +0.13215 809.376 9.11842 +0.13559 805.133 9.14629 +0.1388 791.474 9.50691 +0.14205 787.287 8.69915 +0.14546 761.22 8.65866 +0.1489 779.201 8.38098 +0.15232 771.323 8.50152 +0.1556 748.08 8.49235 +0.15897 748.238 7.8713 +0.16233 756.864 8.48551 +0.16569 723.545 7.61209 +0.16918 723.039 7.76626 +0.17258 714.249 7.58349 +0.17592 707.068 7.55031 +0.17922 695.999 7.67253 +0.18248 687.854 7.31121 +0.18599 672.503 6.89206 +0.18947 656.046 7.05985 +0.19277 644.64 6.93548 +0.19607 633.62 7.0287 +0.19932 617.369 6.7009 diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1.csv new file mode 100644 index 0000000000..e349acefe4 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1.csv @@ -0,0 +1,53 @@ +0.02466 8578.27 96.3713 +0.02778 6201.5 70.6884 +0.03117 4666.55 54.9081 +0.03471 3532.71 43.8556 +0.03797 2779.72 39.1195 +0.04102 2401.14 35.0436 +0.04438 2010.93 26.6446 +0.04788 1789.13 25.3004 +0.05144 1629 21.7057 +0.05485 1414.39 21.5471 +0.05808 1338.47 19.3969 +0.06145 1255.55 17.6425 +0.06485 1194.78 17.2789 +0.06822 1131.88 15.6792 +0.07157 1093.29 15.4062 +0.07489 1076.75 14.6325 +0.07815 990.83 13.9891 +0.08147 993.984 13.3123 +0.0849 949.429 12.5828 +0.0883 906.082 12.3081 +0.09169 901.543 11.9196 +0.09495 883.023 11.8721 +0.09815 842.784 11.4424 +0.10174 819.526 9.8676 +0.10534 802.736 10.7893 +0.10861 795.767 10.1828 +0.11188 791.163 10.3837 +0.11526 783.07 9.63416 +0.11872 771.734 9.59199 +0.12201 755.014 9.75865 +0.12527 763.25 9.14929 +0.12865 738.983 9.05459 +0.1321 735.65 8.71334 +0.13554 713.743 8.62175 +0.13875 720.548 9.08471 +0.142 726.975 8.37203 +0.14541 705.893 8.34698 +0.14884 717.099 8.0504 +0.15226 709.825 8.16294 +0.15554 709.595 8.27884 +0.15891 699.293 7.61937 +0.16227 704.678 8.19256 +0.16563 698.926 7.48706 +0.16912 685.563 7.56396 +0.17251 673.043 7.36594 +0.17586 671.398 7.36238 +0.17915 664.082 7.50135 +0.18241 667.157 7.20373 +0.18592 646.099 6.75787 +0.1894 640.973 6.98357 +0.1927 634.489 6.88246 +0.196 608.639 6.89728 +0.19924 599.163 6.60299 diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1.csv new file mode 100644 index 0000000000..03d157c583 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1.csv @@ -0,0 +1,53 @@ +0.02466 8403.24 95.8365 +0.02779 5866.26 69.5434 +0.03118 4356.78 53.6923 +0.03472 3299.25 42.8649 +0.03798 2597.38 38.2386 +0.04103 2129.79 33.557 +0.04439 1878.69 25.9888 +0.04789 1624.61 24.3861 +0.05145 1439.52 20.6737 +0.05487 1263.65 20.5759 +0.05809 1171.99 18.386 +0.06147 1079.56 16.577 +0.06487 1041.15 16.3129 +0.06823 1001.7 14.8847 +0.07159 961.645 14.563 +0.07491 923.442 13.6706 +0.07817 896.915 13.3973 +0.08149 883.652 12.6286 +0.08492 862.753 12.0581 +0.08832 824.722 11.795 +0.09171 784.35 11.1756 +0.09497 769.294 11.1579 +0.09818 755.349 10.8901 +0.10176 749.016 9.48228 +0.10537 742.393 10.4072 +0.10864 731.812 9.80011 +0.11191 725.902 9.97489 +0.11529 687.755 9.06119 +0.11874 695.826 9.13917 +0.12204 706.826 9.47552 +0.1253 686.062 8.69528 +0.12868 672.907 8.67583 +0.13213 693.14 8.48682 +0.13557 670.728 8.38538 +0.13878 665.705 8.76139 +0.14204 671.833 8.08011 +0.14544 675.608 8.18129 +0.14888 672.094 7.81614 +0.1523 674.683 7.97469 +0.15558 656.506 7.99112 +0.15895 676.236 7.50792 +0.16231 665.98 7.99164 +0.16567 649.237 7.2359 +0.16916 663.887 7.46039 +0.17256 654.732 7.28088 +0.1759 649.138 7.26044 +0.1792 637.918 7.36805 +0.18246 634.954 7.04588 +0.18596 615.952 6.61209 +0.18945 606.075 6.80618 +0.19275 602.38 6.72418 +0.19605 583.877 6.77081 +0.1993 592.832 6.58159 From 4730392f4423959b6bf46674be40c00b2d14c702 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Wed, 20 Sep 2023 18:00:07 +0100 Subject: [PATCH 14/46] Put plot in window --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 26 ++++++- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 72 +++++++++++-------- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 7f1cabf9b7..004ffed49c 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -1,23 +1,42 @@ from sas.qtgui.Utilities.MuMagTool.UI.MuMagUI import Ui_MuMagTool -from PySide6.QtWidgets import QWidget +from PySide6.QtWidgets import QWidget, QVBoxLayout from PySide6 import QtWidgets from sas.qtgui.Utilities.MuMagTool import MuMagLib +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.figure import Figure + +import matplotlib.pylab as pl +import numpy as np class MuMag(QtWidgets.QMainWindow, Ui_MuMagTool): def __init__(self, parent=None): super().__init__() - self.MuMagLib_obj = MuMagLib.MuMagLib() self.setupUi(self) + + self.MuMagLib_obj = MuMagLib.MuMagLib() + + # Callbacks self.ImportDataButton.clicked.connect(self.import_data_button_callback) self.PlotDataButton.clicked.connect(self.plot_experimental_data_button_callback) self.SimpleFitButton.clicked.connect(self.simple_fit_button_callback) + # Plotting + layout = QVBoxLayout() + self.PlotDisplayPanel.setLayout(layout) + + self.fig = Figure() #Figure(figsize=(width, height), dpi=dpi) + self.axes = self.fig.add_subplot(111) + + figure_canvas = FigureCanvas(self.fig) + + layout.addWidget(figure_canvas) + def import_data_button_callback(self): self.MuMagLib_obj.import_data_button_callback_sub() def plot_experimental_data_button_callback(self): - self.MuMagLib_obj.plot_experimental_data() + self.MuMagLib_obj.plot_experimental_data(self.fig) def simple_fit_button_callback(self): q_max = float(self.qMaxEdit.toPlainText()) @@ -29,6 +48,7 @@ def simple_fit_button_callback(self): self.MuMagLib_obj.simple_fit_button_callback(q_max, H_min, A1, A2, A_N, SANSgeometry) + def main(): """ Show a demo of the slider """ app = QtWidgets.QApplication([]) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 014a92e425..71c53ec429 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -99,37 +99,9 @@ def import_data_button_callback_sub(self): self.sigma_exp[idx-1, :] = data[:, 2].T - ################################################################################################################ - # Plot Experimental Data: Generate Figure - def plot_exp_data(self, q, I_exp, B_0, x_min, x_max, y_min, y_max): - - fig = plt.figure() - fig.tight_layout() - ax = fig.add_subplot(1, 1, 1) - - colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) - for k in np.arange(0, len(B_0)): - plt.plot(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label='B_0 = ' + str(B_0[k]) + ' T') - plt.plot(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) - - box = ax.get_position() - ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) - - plt.xlabel('q [1/nm]') - plt.ylabel('I_exp') - plt.xlim(x_min, x_max) - plt.ylim(y_min, y_max) - plt.yscale('log') - plt.xscale('log') - plt.grid(True, which="both", linestyle='--') - plt.legend(loc='center left', bbox_to_anchor=(1, 0.5)) - plt.show() - - - ##################################################################################################################### # Plot Experimental Data: Set Bounds and Call Plotting Function - def plot_experimental_data(self): + def plot_experimental_data(self, figure): if np.size(self.q_exp) > 1: q_exp_min = np.amin(self.q_exp)*1e-9 @@ -144,12 +116,50 @@ def plot_experimental_data(self): I_exp_max = np.amax(self.I_exp) I_exp_max = 10 ** (np.floor(np.log10(I_exp_max))) * np.ceil(I_exp_max / 10 ** (np.floor(np.log10(I_exp_max)))) - self.plot_exp_data(self.q_exp*1e-9, self.I_exp, self.B_0_exp*1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) + self.plot_exp_data(figure, self.q_exp*1e-9, self.I_exp, self.B_0_exp*1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) else: messagebox.showerror(title="Error!", message="No experimental data available! Please import experimental data!") - ####################################################################################################################### + + + ################################################################################################################ + # Plot Experimental Data: Generate Figure + def plot_exp_data(self, figure, q, I_exp, B_0, x_min, x_max, y_min, y_max): + + # figure.tight_layout() + + ax = figure.subplots() + + # print(ax) + + # ax.cla() + + + + colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) + for k in np.arange(0, len(B_0)): + print(k) + ax.loglog(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label='B_0 = ' + str(B_0[k]) + ' T') + ax.loglog(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) + + figure.canvas.draw() + + # box = ax.get_position() + # ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) + # + # ax.xlabel('q [1/nm]') + # ax.ylabel('I_exp') + # ax.xlim(x_min, x_max) + # ax.ylim(y_min, y_max) + # ax.yscale('log') + # ax.xscale('log') + # ax.grid(True, which="both", linestyle='--') + # ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) + + + + From eb6887a9215ca5034c6e81b1c99b487374ff38f2 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Thu, 18 Jan 2024 22:16:13 +0100 Subject: [PATCH 15/46] new update of the mumag tool --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 3 +-- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 27 +++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 004ffed49c..a45bb4f341 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -29,14 +29,13 @@ def __init__(self, parent=None): self.axes = self.fig.add_subplot(111) figure_canvas = FigureCanvas(self.fig) - layout.addWidget(figure_canvas) def import_data_button_callback(self): self.MuMagLib_obj.import_data_button_callback_sub() def plot_experimental_data_button_callback(self): - self.MuMagLib_obj.plot_experimental_data(self.fig) + self.MuMagLib_obj.plot_experimental_data(self.fig, self.axes) def simple_fit_button_callback(self): q_max = float(self.qMaxEdit.toPlainText()) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 71c53ec429..479f349a25 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -101,7 +101,7 @@ def import_data_button_callback_sub(self): ##################################################################################################################### # Plot Experimental Data: Set Bounds and Call Plotting Function - def plot_experimental_data(self, figure): + def plot_experimental_data(self, figure, axes): if np.size(self.q_exp) > 1: q_exp_min = np.amin(self.q_exp)*1e-9 @@ -116,7 +116,7 @@ def plot_experimental_data(self, figure): I_exp_max = np.amax(self.I_exp) I_exp_max = 10 ** (np.floor(np.log10(I_exp_max))) * np.ceil(I_exp_max / 10 ** (np.floor(np.log10(I_exp_max)))) - self.plot_exp_data(figure, self.q_exp*1e-9, self.I_exp, self.B_0_exp*1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) + self.plot_exp_data(figure, axes, self.q_exp*1e-9, self.I_exp, self.B_0_exp*1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) else: messagebox.showerror(title="Error!", message="No experimental data available! Please import experimental data!") @@ -125,24 +125,29 @@ def plot_experimental_data(self, figure): ################################################################################################################ # Plot Experimental Data: Generate Figure - def plot_exp_data(self, figure, q, I_exp, B_0, x_min, x_max, y_min, y_max): - - # figure.tight_layout() - - ax = figure.subplots() + def plot_exp_data(self, figure, axes, q, I_exp, B_0, x_min, x_max, y_min, y_max): + ax = axes # print(ax) - # ax.cla() - - colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) for k in np.arange(0, len(B_0)): print(k) - ax.loglog(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label='B_0 = ' + str(B_0[k]) + ' T') + ax.loglog(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label=r'$B_0 = ' + str(B_0[k]) + '$ T') ax.loglog(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) + ax.set_xlabel(r'$q$ [1/nm]', usetex=True) + ax.set_ylabel(r'$I_{\mathrm{exp}}$', usetex=True) + ax.set_xlim(x_min, x_max) + ax.set_ylim(y_min, y_max) + figure.tight_layout() + + # ax.yscale('log') + # ax.xscale('log') + #ax.grid(True, which="both", linestyle='--') + #ax.legend(loc='center left', bbox_to_anchor=(1, 0.5), usetex=True) + figure.canvas.draw() # box = ax.get_position() From c9d017f527bc760bd41d3e0c7ea08585cca9f72c Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Fri, 19 Jan 2024 01:19:16 +0100 Subject: [PATCH 16/46] Update: Plot in the UI window --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 43 ++++++++++-- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 35 ++-------- .../Utilities/MuMagTool/MuMagParallelGeo.py | 55 +++++++-------- .../MuMagTool/MuMagPerpendicularGeo.py | 67 +++++++++---------- .../qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 34 +++++----- 5 files changed, 120 insertions(+), 114 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index a45bb4f341..de8eadc1f7 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -27,26 +27,57 @@ def __init__(self, parent=None): self.fig = Figure() #Figure(figsize=(width, height), dpi=dpi) self.axes = self.fig.add_subplot(111) - - figure_canvas = FigureCanvas(self.fig) - layout.addWidget(figure_canvas) + self.axes.set_visible(False) + self.axes1 = self.fig.add_subplot(221) + self.axes1.set_visible(False) + self.axes2 = self.fig.add_subplot(222) + self.axes2.set_visible(False) + self.axes3 = self.fig.add_subplot(223) + self.axes3.set_visible(False) + self.axes4 = self.fig.add_subplot(224) + self.axes4.set_visible(False) + + self.figure_canvas = FigureCanvas(self.fig) + layout.addWidget(self.figure_canvas) def import_data_button_callback(self): self.MuMagLib_obj.import_data_button_callback_sub() def plot_experimental_data_button_callback(self): + self.axes.set_visible(True) + self.axes1.set_visible(False) + self.axes2.set_visible(False) + self.axes3.set_visible(False) + self.axes4.set_visible(False) + self.axes.cla() + self.axes1.cla() + self.axes2.cla() + self.axes3.cla() + self.axes4.cla() self.MuMagLib_obj.plot_experimental_data(self.fig, self.axes) + self.figure_canvas.draw() def simple_fit_button_callback(self): + self.axes.set_visible(False) + self.axes1.set_visible(True) + self.axes2.set_visible(True) + self.axes3.set_visible(True) + self.axes4.set_visible(True) + self.axes.cla() + self.axes1.cla() + self.axes2.cla() + self.axes3.cla() + self.axes4.cla() + q_max = float(self.qMaxEdit.toPlainText()) H_min = float(self.HminEdit.toPlainText()) A1 = float(self.AMinEdit.toPlainText()) A2 = float(self.AMaxEdit.toPlainText()) A_N = int(self.ASamplesEdit.toPlainText()) SANSgeometry = self.ScatteringGeometrySelect.currentText() - self.MuMagLib_obj.simple_fit_button_callback(q_max, H_min, A1, A2, A_N, SANSgeometry) - - + self.MuMagLib_obj.simple_fit_button_callback(q_max, H_min, A1, A2, A_N, SANSgeometry, + self.fig, self.axes1, self.axes2, self.axes3, self.axes4) + self.figure_canvas.draw() def main(): """ Show a demo of the slider """ diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 479f349a25..1b00ede6c1 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -128,6 +128,7 @@ def plot_experimental_data(self, figure, axes): def plot_exp_data(self, figure, axes, q, I_exp, B_0, x_min, x_max, y_min, y_max): ax = axes + # print(ax) # ax.cla() @@ -142,37 +143,12 @@ def plot_exp_data(self, figure, axes, q, I_exp, B_0, x_min, x_max, y_min, y_max) ax.set_xlim(x_min, x_max) ax.set_ylim(y_min, y_max) figure.tight_layout() - - # ax.yscale('log') - # ax.xscale('log') - #ax.grid(True, which="both", linestyle='--') #ax.legend(loc='center left', bbox_to_anchor=(1, 0.5), usetex=True) - figure.canvas.draw() - # box = ax.get_position() - # ax.set_position([box.x0, box.y0, box.width * 0.8, box.height]) - # - # ax.xlabel('q [1/nm]') - # ax.ylabel('I_exp') - # ax.xlim(x_min, x_max) - # ax.ylim(y_min, y_max) - # ax.yscale('log') - # ax.xscale('log') - # ax.grid(True, which="both", linestyle='--') - # ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)) - - - - - - - - - ####################################################################################################################### - def simple_fit_button_callback(self, q_max, H_min, A1, A2, A_N, SANSgeometry): + def simple_fit_button_callback(self, q_max, H_min, A1, A2, A_N, SANSgeometry, figure, axes1, axes2, axes3, axes4): if np.size(self.q_exp) > 1: @@ -213,7 +189,9 @@ def simple_fit_button_callback(self, q_max, H_min, A1, A2, A_N, SANSgeometry): N_nu = len(I_exp_red[:, 0]) A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) - MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty * 1e12) + MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, + S_H_opt, S_M_opt, A_Uncertainty * 1e12, + figure, axes1, axes2, axes3, axes4) # Save to global Variables self.SimpleFit_q_exp = q @@ -253,7 +231,8 @@ def simple_fit_button_callback(self, q_max, H_min, A1, A2, A_N, SANSgeometry): A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, - I_res_opt, S_H_opt, A_Uncertainty * 1e12) + I_res_opt, S_H_opt, A_Uncertainty * 1e12, + figure, axes1, axes2, axes3, axes4) # Save to global Variables self.SimpleFit_q_exp = q diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py index dd8e85a05f..1302353fdd 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py @@ -182,36 +182,37 @@ def SANS_Model_PAR(q, S_H, I_res, M_s, H_0, H_dem, A): #################################################################################################### # Plot Fitting results of simple fit -def PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, A_Uncertainty): +def PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, A_Uncertainty, + figure, axes1, axes2, axes3, axes4): + + if A_Uncertainty < 1e-4: + A_Uncertainty = 0 - fig, axs = plt.subplots(2, 2) A_uncertainty_str = str(A_Uncertainty) A_opt_str = str(A_opt * 1e12) - axs[0, 0].set_title('A_opt = (' + A_opt_str[0:5] + ' +/- ' + A_uncertainty_str[0:4] + ') pJ/m') - axs[0, 0].plot(A * 1e12, chi_q) - axs[0, 0].plot(A_opt * 1e12, chi_q_opt, 'o') - axs[0, 0].grid() - axs[0, 0].set_xlim([min(A * 1e12), max(A * 1e12)]) - axs[0, 0].set(xlabel='A [pJ/m]', ylabel='chi^2') - - axs[0, 1].plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') - axs[0, 1].set_yscale('log') - axs[0, 1].set_xscale('log') - axs[0, 1].grid() - axs[0, 1].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axs[0, 1].set(xlabel='q [1/nm]', ylabel='I_res') - axs[0, 1].legend() - - axs[1, 0].plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') - axs[1, 0].set_yscale('log') - axs[1, 0].set_xscale('log') - axs[1, 0].grid() - axs[1, 0].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axs[1, 0].set(xlabel='q [1/nm]', ylabel='S_H') - axs[1, 0].legend() - - plt.tight_layout() - plt.show() + axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m', + usetex=True) + axes1.plot(A * 1e12, chi_q) + axes1.plot(A_opt * 1e12, chi_q_opt, 'o') + axes1.set_xlim([min(A * 1e12), max(A * 1e12)]) + axes1.set_xlabel('$A$ [pJ/m]', usetex=True) + axes1.set_ylabel('$\chi^2$', usetex=True) + + axes2.plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') + axes2.set_yscale('log') + axes2.set_xscale('log') + axes2.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axes2.set_xlabel('$q$ [1/nm]', usetex=True) + axes2.set_ylabel('$I_{\mathrm{res}}$', usetex=True) + + axes3.plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') + axes3.set_yscale('log') + axes3.set_xscale('log') + axes3.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axes3.set_xlabel('$q$ [1/nm]', usetex=True) + axes3.set_ylabel('$S_H$', usetex=True) + + figure.tight_layout() #################################################################################################### def PlotSweepFitResultPAR(q_max_mat, H_min_mat, A_opt_mat): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py index b2e00bf2ba..7be0aa61d0 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py @@ -232,49 +232,44 @@ def SANS_Model_PERP(q, S_H, S_M, I_res, M_s, H_0, H_dem, A): #################################################################################################### # Plot Fitting results of simple fit -def PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty): - - fig, axs = plt.subplots(2, 2) +def PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty, + figure, axes1, axes2, axes3, axes4): if A_Uncertainty < 1e-4: A_Uncertainty = 0 A_uncertainty_str = str(A_Uncertainty) - A_opt_str = str(A_opt * 1e12) - axs[0, 0].set_title('A_opt = (' + A_opt_str[0:5] + ' +/- ' + A_uncertainty_str[0:4] + ') pJ/m') - axs[0, 0].plot(A * 1e12, chi_q) - axs[0, 0].plot(A_opt * 1e12, chi_q_opt, 'o') - axs[0, 0].grid() - axs[0, 0].set_xlim([min(A * 1e12), max(A * 1e12)]) - axs[0, 0].set(xlabel='A [pJ/m]', ylabel='chi^2') - - axs[0, 1].plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') - axs[0, 1].set_yscale('log') - axs[0, 1].set_xscale('log') - axs[0, 1].grid() - axs[0, 1].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axs[0, 1].set(xlabel='q [1/nm]', ylabel='I_res') - axs[0, 1].legend() - - axs[1, 0].plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') - axs[1, 0].set_yscale('log') - axs[1, 0].set_xscale('log') - axs[1, 0].grid() - axs[1, 0].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axs[1, 0].set(xlabel='q [1/nm]', ylabel='S_H') - axs[1, 0].legend() - - axs[1, 1].plot(q[0, :] * 1e-9, S_M_opt[0, :], label='fit') - axs[1, 1].set_yscale('log') - axs[1, 1].set_xscale('log') - axs[1, 1].grid() - axs[1, 1].set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axs[1, 1].set(xlabel='q [1/nm]', ylabel='S_M') - axs[1, 1].legend() + axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m', usetex=True) + axes1.plot(A * 1e12, chi_q) + axes1.plot(A_opt * 1e12, chi_q_opt, 'o') + axes1.set_xlim([min(A * 1e12), max(A * 1e12)]) + axes1.set_xlabel('$A$ [pJ/m]', usetex=True) + axes1.set_ylabel('$\chi^2$', usetex=True) + + axes2.plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') + axes2.set_yscale('log') + axes2.set_xscale('log') + axes2.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axes2.set_xlabel('$q$ [1/nm]', usetex=True) + axes2.set_ylabel('$I_{\mathrm{res}}$', usetex=True) + + axes3.plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') + axes3.set_yscale('log') + axes3.set_xscale('log') + axes3.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axes3.set_xlabel('$q$ [1/nm]', usetex=True) + axes3.set_ylabel('$S_H$', usetex=True) + + axes4.plot(q[0, :] * 1e-9, S_M_opt[0, :], label='fit') + axes4.set_yscale('log') + axes4.set_xscale('log') + axes4.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axes4.set_xlabel('$q$ [1/nm]', usetex=True) + axes4.set_ylabel('$S_M$', usetex=True) + + figure.tight_layout() - plt.tight_layout() - plt.show() #################################################################################################### def PlotSweepFitResultPERP(q_max_mat, H_min_mat, A_opt_mat): diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui index 7007c98aaa..3aaa0d3826 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -6,7 +6,7 @@ 0 0 - 703 + 761 600 @@ -20,7 +20,7 @@ 0 0 161 - 131 + 121 @@ -32,7 +32,7 @@ 0 20 161 - 111 + 101 @@ -50,7 +50,7 @@ - + @@ -72,8 +72,8 @@ 160 0 - 541 - 131 + 601 + 121 @@ -84,8 +84,8 @@ 10 20 - 521 - 111 + 581 + 101 @@ -214,21 +214,21 @@ p, li { white-space: pre-wrap; } 0 - 130 - 701 - 431 + 120 + 761 + 441 - GroupBox + Display - 20 - 40 - 501 - 221 + 0 + 20 + 761 + 411 @@ -239,7 +239,7 @@ p, li { white-space: pre-wrap; } 0 0 - 703 + 761 22 From f1a5d812f5bf551804f37c4dd8d5da9912192834 Mon Sep 17 00:00:00 2001 From: Funkmich008 <87016586+Funkmich008@users.noreply.github.com> Date: Mon, 22 Jan 2024 05:17:55 +0100 Subject: [PATCH 17/46] Update: Functionality of the compare button and save button --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 51 ++++- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 203 +++++++++++++++++- 2 files changed, 235 insertions(+), 19 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index de8eadc1f7..a9dfaded9d 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -20,6 +20,8 @@ def __init__(self, parent=None): self.ImportDataButton.clicked.connect(self.import_data_button_callback) self.PlotDataButton.clicked.connect(self.plot_experimental_data_button_callback) self.SimpleFitButton.clicked.connect(self.simple_fit_button_callback) + self.CompareResultsButton.clicked.connect(self.compare_data_button_callback) + self.SaveResultsButton.clicked.connect(self.save_data_button_callback) # Plotting layout = QVBoxLayout() @@ -58,16 +60,6 @@ def plot_experimental_data_button_callback(self): self.figure_canvas.draw() def simple_fit_button_callback(self): - self.axes.set_visible(False) - self.axes1.set_visible(True) - self.axes2.set_visible(True) - self.axes3.set_visible(True) - self.axes4.set_visible(True) - self.axes.cla() - self.axes1.cla() - self.axes2.cla() - self.axes3.cla() - self.axes4.cla() q_max = float(self.qMaxEdit.toPlainText()) H_min = float(self.HminEdit.toPlainText()) @@ -75,10 +67,49 @@ def simple_fit_button_callback(self): A2 = float(self.AMaxEdit.toPlainText()) A_N = int(self.ASamplesEdit.toPlainText()) SANSgeometry = self.ScatteringGeometrySelect.currentText() + + self.axes.cla() + self.axes1.cla() + self.axes2.cla() + self.axes3.cla() + self.axes4.cla() + self.axes.set_visible(False) + if SANSgeometry == 'perpendicular': + self.axes1.set_visible(True) + self.axes2.set_visible(True) + self.axes3.set_visible(True) + self.axes4.set_visible(True) + elif SANSgeometry == 'parallel': + self.axes1.set_visible(True) + self.axes2.set_visible(True) + self.axes3.set_visible(True) + self.axes4.set_visible(False) + self.MuMagLib_obj.simple_fit_button_callback(q_max, H_min, A1, A2, A_N, SANSgeometry, self.fig, self.axes1, self.axes2, self.axes3, self.axes4) self.figure_canvas.draw() + def compare_data_button_callback(self): + self.axes.cla() + self.axes1.cla() + self.axes2.cla() + self.axes3.cla() + self.axes4.cla() + self.axes.set_visible(True) + self.axes1.set_visible(False) + self.axes2.set_visible(False) + self.axes3.set_visible(False) + self.axes4.set_visible(False) + + self.MuMagLib_obj.SimpleFit_CompareButtonCallback(self.fig, self.axes) + + + + def save_data_button_callback(self): + self.MuMagLib_obj.save_button_callback() + + + def main(): """ Show a demo of the slider """ app = QtWidgets.QApplication([]) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 1b00ede6c1..d9f62e320e 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -16,7 +16,6 @@ from sas.qtgui.Utilities.MuMagTool import MuMagParallelGeo from sas.qtgui.Utilities.MuMagTool import MuMagPerpendicularGeo - class MuMagLib(): def __init__(self): @@ -98,7 +97,6 @@ def import_data_button_callback_sub(self): self.I_exp[idx-1, :] = data[:, 1].T self.sigma_exp[idx-1, :] = data[:, 2].T - ##################################################################################################################### # Plot Experimental Data: Set Bounds and Call Plotting Function def plot_experimental_data(self, figure, axes): @@ -128,13 +126,9 @@ def plot_experimental_data(self, figure, axes): def plot_exp_data(self, figure, axes, q, I_exp, B_0, x_min, x_max, y_min, y_max): ax = axes - - # print(ax) - # ax.cla() - colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) for k in np.arange(0, len(B_0)): - print(k) + #print(k) ax.loglog(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label=r'$B_0 = ' + str(B_0[k]) + '$ T') ax.loglog(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) @@ -143,7 +137,6 @@ def plot_exp_data(self, figure, axes, q, I_exp, B_0, x_min, x_max, y_min, y_max) ax.set_xlim(x_min, x_max) ax.set_ylim(y_min, y_max) figure.tight_layout() - #ax.legend(loc='center left', bbox_to_anchor=(1, 0.5), usetex=True) figure.canvas.draw() ####################################################################################################################### @@ -211,7 +204,8 @@ def simple_fit_button_callback(self, q_max, H_min, A1, A2, A_N, SANSgeometry, fi self.SimpleFit_A_sigma = A_Uncertainty self.SimpleFit_SANSgeometry = "perpendicular" - elif SANSgeometry == "parallel ": + elif SANSgeometry == "parallel": + A_1 = A1 * 1e-12 A_2 = A2 * 1e-12 A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ @@ -255,3 +249,194 @@ def simple_fit_button_callback(self, q_max, H_min, A1, A2, A_N, SANSgeometry, fi messagebox.showerror(title="Error!", message="No experimental Data available! Please import experimental data!") +###################################################################################################################### + def save_button_callback(self): + + SimpleFit_q_exp = self.SimpleFit_q_exp + SimpleFit_I_exp = self.SimpleFit_I_exp + SimpleFit_sigma_exp = self.SimpleFit_sigma_exp + SimpleFit_B_0_exp = self.SimpleFit_B_0_exp + SimpleFit_Ms_exp = self.SimpleFit_Ms_exp + SimpleFit_Hdem_exp = self.SimpleFit_Hdem_exp + SimpleFit_I_fit = self.SimpleFit_I_fit + SimpleFit_A = self.SimpleFit_A + SimpleFit_chi_q = self.SimpleFit_chi_q + SimpleFit_S_H_fit = self.SimpleFit_S_H_fit + SimpleFit_S_M_fit = self.SimpleFit_S_M_fit + SimpleFit_I_res_fit = self.SimpleFit_I_res_fit + SimpleFit_A_opt = self.SimpleFit_A_opt + SimpleFit_chi_q_opt = self.SimpleFit_chi_q_opt + SimpleFit_A_sigma = self.SimpleFit_A_sigma + SimpleFit_SANSgeometry = self.SimpleFit_SANSgeometry + + print('hello') + print(np.size(SimpleFit_q_exp)) + + if np.size(SimpleFit_q_exp) > 1: + if SimpleFit_SANSgeometry == 'perpendicular': + DIR = QFileDialog.getExistingDirectory() + + now = datetime.now() + TimeStamp = now.strftime("%d_%m_%Y__%H_%M_%S") + FolderName = "SimpleFitResults_" + TimeStamp + path = os.path.join(DIR, FolderName) + os.mkdir(path) + + InfoFile = open(path + "/InfoFile.txt", "w") + InfoFile.write("FitMagneticSANS Toolbox - SimpleFit Results Info File \n\n") + InfoFile.write("Timestamp: " + TimeStamp + " \n\n") + InfoFile.write("SANS geometry: " + SimpleFit_SANSgeometry + "\n\n") + InfoFile.write("Maximal Scattering Vector: q_max = " + + str(np.amax(SimpleFit_q_exp*1e-9)) + " 1/nm \n") + InfoFile.write("Minimal Applied Field: mu_0*H_min = " + + str(np.around(np.amin(SimpleFit_B_0_exp), 0)) + " mT \n\n") + InfoFile.write("Result for the exchange stiffness constant: A = (" + + str(np.around(SimpleFit_A_opt*1e12, 3)) + " +/- " + + str(np.around(SimpleFit_A_sigma*1e12, 2)) + ") pJ/m \n") + InfoFile.close() + + FolderName2 = "SANS_Intensity_Fit" + path2 = os.path.join(path, FolderName2) + os.mkdir(path2) + + for k in np.arange(0, np.size(SimpleFit_B_0_exp)): + np.savetxt(os.path.join(path2, str(k+1) + "_" + str(SimpleFit_B_0_exp[k]) + "_" + + str(SimpleFit_Ms_exp[k]) + "_" + str(SimpleFit_Hdem_exp[k]) + ".csv"), + np.array([SimpleFit_q_exp[k, :].T, SimpleFit_I_fit[k, :].T]).T, delimiter=" ") + + FolderName3 = "SANS_Intensity_Exp" + path3 = os.path.join(path, FolderName3) + os.mkdir(path3) + + for k in np.arange(0, np.size(SimpleFit_B_0_exp)): + np.savetxt(os.path.join(path3, str(k+1) + "_" + str(SimpleFit_B_0_exp[k]) + "_" + + str(SimpleFit_Ms_exp[k]) + "_" + str(SimpleFit_Hdem_exp[k]) + ".csv"), + np.array([SimpleFit_q_exp[k, :].T, SimpleFit_I_exp[k, :].T, + SimpleFit_sigma_exp[k, :]]).T, delimiter=" ") + + FolderName4 = "Fit_Results" + path4 = os.path.join(path, FolderName4) + os.mkdir(path4) + + np.savetxt(os.path.join(path4, "chi.csv"), np.array([SimpleFit_A, SimpleFit_chi_q]).T, delimiter=" ") + np.savetxt(os.path.join(path4, "S_H.csv"), np.array([SimpleFit_q_exp[0, :].T, + SimpleFit_S_H_fit[0, :]]).T, delimiter=" ") + np.savetxt(os.path.join(path4, "S_M.csv"), np.array([SimpleFit_q_exp[0, :].T, + SimpleFit_S_M_fit[0, :]]).T, delimiter=" ") + np.savetxt(os.path.join(path4, "I_res.csv"), np.array([SimpleFit_q_exp[0, :].T, + SimpleFit_I_res_fit[0, :]]).T, delimiter=" ") + + elif SimpleFit_SANSgeometry == 'parallel': + DIR = QFileDialog.getExistingDirectory() + + now = datetime.now() + TimeStamp = now.strftime("%d_%m_%Y__%H_%M_%S") + FolderName = "SimpleFitResults_" + TimeStamp + path = os.path.join(DIR, FolderName) + os.mkdir(path) + + InfoFile = open(path + "/InfoFile.txt", "w") + InfoFile.write("FitMagneticSANS Toolbox - SimpleFit Results Info File \n\n") + InfoFile.write("Timestamp: " + TimeStamp + " \n\n") + InfoFile.write("SANS geometry: " + SimpleFit_SANSgeometry + "\n\n") + InfoFile.write("Maximal Scattering Vector: q_max = " + + str(np.amax(SimpleFit_q_exp * 1e-9)) + " 1/nm \n") + InfoFile.write("Minimal Applied Field: mu_0*H_min = " + + str(np.around(np.amin(SimpleFit_B_0_exp), 0)) + " mT \n\n") + InfoFile.write("Result for the exchange stiffness constant: A = (" + + str(np.around(SimpleFit_A_opt * 1e12, 3)) + " +/- " + + str(np.around(SimpleFit_A_sigma * 1e12, 2)) + ") pJ/m \n") + InfoFile.close() + + FolderName2 = "SANS_Intensity_Fit" + path2 = os.path.join(path, FolderName2) + os.mkdir(path2) + + for k in np.arange(0, np.size(SimpleFit_B_0_exp)): + np.savetxt(os.path.join(path2, str(k + 1) + "_" + str(int(SimpleFit_B_0_exp[k])) + "_" + str( + int(SimpleFit_Ms_exp[k])) + "_" + str(int(SimpleFit_Hdem_exp[k])) + ".csv"), + np.array([SimpleFit_q_exp[k, :].T, SimpleFit_I_fit[k, :].T]).T, delimiter=" ") + + FolderName3 = "SANS_Intensity_Exp" + path3 = os.path.join(path, FolderName3) + os.mkdir(path3) + + for k in np.arange(0, np.size(SimpleFit_B_0_exp)): + np.savetxt(os.path.join(path3, str(k + 1) + "_" + str(int(SimpleFit_B_0_exp[k])) + "_" + str( + int(SimpleFit_Ms_exp[k])) + "_" + str(int(SimpleFit_Hdem_exp[k])) + ".csv"), + np.array([SimpleFit_q_exp[k, :].T, SimpleFit_I_exp[k, :].T, SimpleFit_sigma_exp[k, :]]).T, + delimiter=" ") + + FolderName4 = "Fit_Results" + path4 = os.path.join(path, FolderName4) + os.mkdir(path4) + + np.savetxt(os.path.join(path4, "chi.csv"), np.array([SimpleFit_A, SimpleFit_chi_q]).T, delimiter=" ") + np.savetxt(os.path.join(path4, "S_H.csv"), np.array([SimpleFit_q_exp[0, :].T, + SimpleFit_S_H_fit[0, :]]).T, delimiter=" ") + np.savetxt(os.path.join(path4, "I_res.csv"), np.array([SimpleFit_q_exp[0, :].T, + SimpleFit_I_res_fit[0, :]]).T, delimiter=" ") + + else: + messagebox.showerror(title="Error!", message="No SimpleFit results available!") + + +################################################################################################################# + + def SimpleFit_CompareButtonCallback(self, figure, axes): + + SimpleFit_q_exp = self.SimpleFit_q_exp + SimpleFit_I_exp = self.SimpleFit_I_exp + SimpleFit_sigma_exp = self.SimpleFit_sigma_exp + SimpleFit_B_0_exp = self.SimpleFit_B_0_exp + SimpleFit_Ms_exp = self.SimpleFit_Ms_exp + SimpleFit_Hdem_exp = self.SimpleFit_Hdem_exp + SimpleFit_I_fit = self.SimpleFit_I_fit + SimpleFit_A = self.SimpleFit_A + SimpleFit_chi_q = self.SimpleFit_chi_q + SimpleFit_S_H_fit = self.SimpleFit_S_H_fit + SimpleFit_S_M_fit = self.SimpleFit_S_M_fit + SimpleFit_I_res_fit = self.SimpleFit_I_res_fit + SimpleFit_A_opt = self.SimpleFit_A_opt + SimpleFit_chi_q_opt = self.SimpleFit_chi_q_opt + SimpleFit_A_sigma = self.SimpleFit_A_sigma + SimpleFit_SANSgeometry = self.SimpleFit_SANSgeometry + + if np.size(SimpleFit_q_exp) > 1: + q_exp_min = np.amin(SimpleFit_q_exp) * 1e-9 + q_exp_min = 10 ** (np.floor(np.log10(q_exp_min))) * np.floor(q_exp_min / 10 ** (np.floor(np.log10(q_exp_min)))) + + q_exp_max = np.amax(SimpleFit_q_exp) * 1e-9 + q_exp_max = 10 ** (np.floor(np.log10(q_exp_max))) * np.ceil(q_exp_max / 10 ** (np.floor(np.log10(q_exp_max)))) + + I_exp_min = np.amin(SimpleFit_I_exp) + I_exp_min = 10 ** (np.floor(np.log10(I_exp_min))) * np.floor(I_exp_min / 10 ** (np.floor(np.log10(I_exp_min)))) + + I_exp_max = np.amax(SimpleFit_I_exp) + I_exp_max = 10 ** (np.floor(np.log10(I_exp_max))) * np.ceil(I_exp_max / 10 ** (np.floor(np.log10(I_exp_max)))) + + self.PlotCompareExpFitData(figure, axes, SimpleFit_q_exp * 1e-9, SimpleFit_I_exp, SimpleFit_I_fit, SimpleFit_B_0_exp * 1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) + else: + messagebox.showerror(title="Error!", message="No SimpleFit results available!") + + def PlotCompareExpFitData(self, figure, axes, q, I_exp, I_fit, B_0, x_min, x_max, y_min, y_max): + + fig = figure + fig.tight_layout() + ax = axes + + colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) + for k in np.arange(0, len(B_0)): + ax.loglog(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) + + colors = pl.cm.YlGn(np.linspace(0, 1, len(B_0))) + for k in np.arange(0, len(B_0)): + ax.plot(q[k, :], I_fit[k, :], linestyle='solid', color=colors[k], + linewidth=0.5, label='(fit) B_0 = ' + str(B_0[k]) + ' T') + + ax.set_xlabel(r'$q$ [1/nm]', usetex=True) + ax.set_ylabel(r'$I_{\mathrm{exp}}$', usetex=True) + ax.set_xlim(x_min, x_max) + ax.set_ylim(y_min, y_max) + figure.tight_layout() + figure.canvas.draw() From 82857fd41fec4c63407eb30dc9d797cdfac08327 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Tue, 21 May 2024 11:57:46 +0100 Subject: [PATCH 18/46] Fixed latex problem, some variable renaming --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 103 +++++++++--------- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 8 +- .../Utilities/MuMagTool/MuMagParallelGeo.py | 15 ++- .../MuMagTool/MuMagPerpendicularGeo.py | 18 +-- 4 files changed, 73 insertions(+), 71 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index a9dfaded9d..4395d8eaae 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -4,7 +4,8 @@ from sas.qtgui.Utilities.MuMagTool import MuMagLib from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas -from matplotlib.figure import Figure +# from matplotlib.figure import Figure +import matplotlib.pyplot as plt import matplotlib.pylab as pl import numpy as np @@ -27,17 +28,17 @@ def __init__(self, parent=None): layout = QVBoxLayout() self.PlotDisplayPanel.setLayout(layout) - self.fig = Figure() #Figure(figsize=(width, height), dpi=dpi) - self.axes = self.fig.add_subplot(111) - self.axes.set_visible(False) - self.axes1 = self.fig.add_subplot(221) - self.axes1.set_visible(False) - self.axes2 = self.fig.add_subplot(222) - self.axes2.set_visible(False) - self.axes3 = self.fig.add_subplot(223) - self.axes3.set_visible(False) - self.axes4 = self.fig.add_subplot(224) - self.axes4.set_visible(False) + self.fig = plt.figure() #Figure(figsize=(width, height), dpi=dpi) + self.simple_fit_axes = self.fig.add_subplot(111) + self.simple_fit_axes.set_visible(False) + self.chi_squared_axes = self.fig.add_subplot(221) + self.chi_squared_axes.set_visible(False) + self.residuals_axes = self.fig.add_subplot(222) + self.residuals_axes.set_visible(False) + self.s_h_axes = self.fig.add_subplot(223) + self.s_h_axes.set_visible(False) + self.longitudinal_scattering_axes = self.fig.add_subplot(224) + self.longitudinal_scattering_axes.set_visible(False) self.figure_canvas = FigureCanvas(self.fig) layout.addWidget(self.figure_canvas) @@ -46,17 +47,19 @@ def import_data_button_callback(self): self.MuMagLib_obj.import_data_button_callback_sub() def plot_experimental_data_button_callback(self): - self.axes.set_visible(True) - self.axes1.set_visible(False) - self.axes2.set_visible(False) - self.axes3.set_visible(False) - self.axes4.set_visible(False) - self.axes.cla() - self.axes1.cla() - self.axes2.cla() - self.axes3.cla() - self.axes4.cla() - self.MuMagLib_obj.plot_experimental_data(self.fig, self.axes) + self.simple_fit_axes.set_visible(True) + self.chi_squared_axes.set_visible(False) + self.residuals_axes.set_visible(False) + self.s_h_axes.set_visible(False) + self.longitudinal_scattering_axes.set_visible(False) + + self.simple_fit_axes.cla() + self.chi_squared_axes.cla() + self.residuals_axes.cla() + self.s_h_axes.cla() + self.longitudinal_scattering_axes.cla() + + self.MuMagLib_obj.plot_experimental_data(self.fig, self.simple_fit_axes) self.figure_canvas.draw() def simple_fit_button_callback(self): @@ -68,40 +71,40 @@ def simple_fit_button_callback(self): A_N = int(self.ASamplesEdit.toPlainText()) SANSgeometry = self.ScatteringGeometrySelect.currentText() - self.axes.cla() - self.axes1.cla() - self.axes2.cla() - self.axes3.cla() - self.axes4.cla() - self.axes.set_visible(False) + self.simple_fit_axes.cla() + self.chi_squared_axes.cla() + self.residuals_axes.cla() + self.s_h_axes.cla() + self.longitudinal_scattering_axes.cla() + self.simple_fit_axes.set_visible(False) if SANSgeometry == 'perpendicular': - self.axes1.set_visible(True) - self.axes2.set_visible(True) - self.axes3.set_visible(True) - self.axes4.set_visible(True) + self.chi_squared_axes.set_visible(True) + self.residuals_axes.set_visible(True) + self.s_h_axes.set_visible(True) + self.longitudinal_scattering_axes.set_visible(True) elif SANSgeometry == 'parallel': - self.axes1.set_visible(True) - self.axes2.set_visible(True) - self.axes3.set_visible(True) - self.axes4.set_visible(False) + self.chi_squared_axes.set_visible(True) + self.residuals_axes.set_visible(True) + self.s_h_axes.set_visible(True) + self.longitudinal_scattering_axes.set_visible(False) self.MuMagLib_obj.simple_fit_button_callback(q_max, H_min, A1, A2, A_N, SANSgeometry, - self.fig, self.axes1, self.axes2, self.axes3, self.axes4) + self.fig, self.chi_squared_axes, self.residuals_axes, self.s_h_axes, self.longitudinal_scattering_axes) self.figure_canvas.draw() def compare_data_button_callback(self): - self.axes.cla() - self.axes1.cla() - self.axes2.cla() - self.axes3.cla() - self.axes4.cla() - self.axes.set_visible(True) - self.axes1.set_visible(False) - self.axes2.set_visible(False) - self.axes3.set_visible(False) - self.axes4.set_visible(False) - - self.MuMagLib_obj.SimpleFit_CompareButtonCallback(self.fig, self.axes) + self.simple_fit_axes.cla() + self.chi_squared_axes.cla() + self.residuals_axes.cla() + self.s_h_axes.cla() + self.longitudinal_scattering_axes.cla() + self.simple_fit_axes.set_visible(True) + self.chi_squared_axes.set_visible(False) + self.residuals_axes.set_visible(False) + self.s_h_axes.set_visible(False) + self.longitudinal_scattering_axes.set_visible(False) + + self.MuMagLib_obj.SimpleFit_CompareButtonCallback(self.fig, self.simple_fit_axes) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index d9f62e320e..c8bd7f0ecd 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -132,8 +132,8 @@ def plot_exp_data(self, figure, axes, q, I_exp, B_0, x_min, x_max, y_min, y_max) ax.loglog(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label=r'$B_0 = ' + str(B_0[k]) + '$ T') ax.loglog(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) - ax.set_xlabel(r'$q$ [1/nm]', usetex=True) - ax.set_ylabel(r'$I_{\mathrm{exp}}$', usetex=True) + ax.set_xlabel(r'$q$ [1/nm]') + ax.set_ylabel(r'$I_{\mathrm{exp}}$') ax.set_xlim(x_min, x_max) ax.set_ylim(y_min, y_max) figure.tight_layout() @@ -434,8 +434,8 @@ def PlotCompareExpFitData(self, figure, axes, q, I_exp, I_fit, B_0, x_min, x_max ax.plot(q[k, :], I_fit[k, :], linestyle='solid', color=colors[k], linewidth=0.5, label='(fit) B_0 = ' + str(B_0[k]) + ' T') - ax.set_xlabel(r'$q$ [1/nm]', usetex=True) - ax.set_ylabel(r'$I_{\mathrm{exp}}$', usetex=True) + ax.set_xlabel(r'$q$ [1/nm]') + ax.set_ylabel(r'$I_{\mathrm{exp}}$') ax.set_xlim(x_min, x_max) ax.set_ylim(y_min, y_max) figure.tight_layout() diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py index 1302353fdd..fb69206e4b 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py @@ -190,27 +190,26 @@ def PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_ A_uncertainty_str = str(A_Uncertainty) A_opt_str = str(A_opt * 1e12) - axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m', - usetex=True) + axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m') axes1.plot(A * 1e12, chi_q) axes1.plot(A_opt * 1e12, chi_q_opt, 'o') axes1.set_xlim([min(A * 1e12), max(A * 1e12)]) - axes1.set_xlabel('$A$ [pJ/m]', usetex=True) - axes1.set_ylabel('$\chi^2$', usetex=True) + axes1.set_xlabel('$A$ [pJ/m]') + axes1.set_ylabel('$\chi^2$') axes2.plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') axes2.set_yscale('log') axes2.set_xscale('log') axes2.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axes2.set_xlabel('$q$ [1/nm]', usetex=True) - axes2.set_ylabel('$I_{\mathrm{res}}$', usetex=True) + axes2.set_xlabel('$q$ [1/nm]') + axes2.set_ylabel('$I_{\mathrm{res}}$') axes3.plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') axes3.set_yscale('log') axes3.set_xscale('log') axes3.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axes3.set_xlabel('$q$ [1/nm]', usetex=True) - axes3.set_ylabel('$S_H$', usetex=True) + axes3.set_xlabel('$q$ [1/nm]') + axes3.set_ylabel('$S_H$') figure.tight_layout() diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py index 7be0aa61d0..c031b5a806 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py @@ -240,33 +240,33 @@ def PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S A_uncertainty_str = str(A_Uncertainty) A_opt_str = str(A_opt * 1e12) - axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m', usetex=True) + axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m') axes1.plot(A * 1e12, chi_q) axes1.plot(A_opt * 1e12, chi_q_opt, 'o') axes1.set_xlim([min(A * 1e12), max(A * 1e12)]) - axes1.set_xlabel('$A$ [pJ/m]', usetex=True) - axes1.set_ylabel('$\chi^2$', usetex=True) + axes1.set_xlabel('$A$ [pJ/m]') + axes1.set_ylabel('$\chi^2$') axes2.plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') axes2.set_yscale('log') axes2.set_xscale('log') axes2.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axes2.set_xlabel('$q$ [1/nm]', usetex=True) - axes2.set_ylabel('$I_{\mathrm{res}}$', usetex=True) + axes2.set_xlabel('$q$ [1/nm]') + axes2.set_ylabel('$I_{\mathrm{res}}$') axes3.plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') axes3.set_yscale('log') axes3.set_xscale('log') axes3.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axes3.set_xlabel('$q$ [1/nm]', usetex=True) - axes3.set_ylabel('$S_H$', usetex=True) + axes3.set_xlabel('$q$ [1/nm]') + axes3.set_ylabel('$S_H$') axes4.plot(q[0, :] * 1e-9, S_M_opt[0, :], label='fit') axes4.set_yscale('log') axes4.set_xscale('log') axes4.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axes4.set_xlabel('$q$ [1/nm]', usetex=True) - axes4.set_ylabel('$S_M$', usetex=True) + axes4.set_xlabel('$q$ [1/nm]') + axes4.set_ylabel('$S_M$') figure.tight_layout() From 820dbf4262c1fb287112d798a446e3123954f037 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Tue, 21 May 2024 12:06:50 +0100 Subject: [PATCH 19/46] Cleaning up --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 45 +++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 4395d8eaae..93efcba998 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -66,38 +66,55 @@ def simple_fit_button_callback(self): q_max = float(self.qMaxEdit.toPlainText()) H_min = float(self.HminEdit.toPlainText()) - A1 = float(self.AMinEdit.toPlainText()) - A2 = float(self.AMaxEdit.toPlainText()) - A_N = int(self.ASamplesEdit.toPlainText()) - SANSgeometry = self.ScatteringGeometrySelect.currentText() + exchange_A_min = float(self.AMinEdit.toPlainText()) + exchange_A_max = float(self.AMaxEdit.toPlainText()) + exchange_A_n = int(self.ASamplesEdit.toPlainText()) + experiment_geometry = self.ScatteringGeometrySelect.currentText() + # Clear axes self.simple_fit_axes.cla() self.chi_squared_axes.cla() self.residuals_axes.cla() self.s_h_axes.cla() self.longitudinal_scattering_axes.cla() + + # Set axes visibility self.simple_fit_axes.set_visible(False) - if SANSgeometry == 'perpendicular': - self.chi_squared_axes.set_visible(True) - self.residuals_axes.set_visible(True) - self.s_h_axes.set_visible(True) + self.chi_squared_axes.set_visible(True) + self.residuals_axes.set_visible(True) + self.s_h_axes.set_visible(True) + + if experiment_geometry == 'perpendicular': self.longitudinal_scattering_axes.set_visible(True) - elif SANSgeometry == 'parallel': - self.chi_squared_axes.set_visible(True) - self.residuals_axes.set_visible(True) - self.s_h_axes.set_visible(True) + else: self.longitudinal_scattering_axes.set_visible(False) - self.MuMagLib_obj.simple_fit_button_callback(q_max, H_min, A1, A2, A_N, SANSgeometry, - self.fig, self.chi_squared_axes, self.residuals_axes, self.s_h_axes, self.longitudinal_scattering_axes) + + self.MuMagLib_obj.simple_fit_button_callback( + q_max, + H_min, + exchange_A_min, + exchange_A_max, + exchange_A_n, + experiment_geometry, + self.fig, + self.chi_squared_axes, + self.residuals_axes, + self.s_h_axes, + self.longitudinal_scattering_axes) + self.figure_canvas.draw() def compare_data_button_callback(self): + + # Clear axes self.simple_fit_axes.cla() self.chi_squared_axes.cla() self.residuals_axes.cla() self.s_h_axes.cla() self.longitudinal_scattering_axes.cla() + + # Set visibility self.simple_fit_axes.set_visible(True) self.chi_squared_axes.set_visible(False) self.residuals_axes.set_visible(False) From 09c12fedb8f0f58c37660a221aef02a367abcad1 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Tue, 21 May 2024 12:29:25 +0100 Subject: [PATCH 20/46] Dataclass for loading operation --- .../qtgui/Utilities/MuMagTool/experimental_data.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/sas/qtgui/Utilities/MuMagTool/experimental_data.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py b/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py new file mode 100644 index 0000000000..d6449474e2 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py @@ -0,0 +1,14 @@ +from dataclasses import dataclass + +import numpy as np + +from sas.qtgui.Plotting.PlotterData import Data1D + + +@dataclass +class ExperimentalData: + input_data: Data1D + + applied_field: float + saturation_magnetisation: float + demagnetising_field: float From e99133d51006fe5a5ebef971686c130eea2c742d Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Tue, 21 May 2024 13:54:38 +0100 Subject: [PATCH 21/46] Dataclass for results --- .../Utilities/MuMagTool/experimental_data.py | 4 ++- .../qtgui/Utilities/MuMagTool/fit_result.py | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/sas/qtgui/Utilities/MuMagTool/fit_result.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py b/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py index d6449474e2..3caf8efb29 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py +++ b/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py @@ -7,7 +7,9 @@ @dataclass class ExperimentalData: - input_data: Data1D + """ Datapoint used as input for the MuMag tool""" + + scattering_curve: Data1D applied_field: float saturation_magnetisation: float diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py new file mode 100644 index 0000000000..e9d08e9455 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py @@ -0,0 +1,28 @@ +from dataclasses import dataclass + +import numpy as np + +from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData + + +@dataclass +class FitResults: + """ Output the MuMag fit """ + truncated_input_data: list[ExperimentalData] + + q: np.ndarray + I_fit: np.ndarray + + S_H: np.ndarray + S_M: np.ndarray + + I_residual: np.ndarray # Nuclear + Magnetic cross section at complete magnetic saturation + + exchange_A: np.ndarray + exchange_A_chi_sq: np.ndarray + + optimal_A: float + optimal_A_chi_sq: float + optimal_A_stdev: float # check + + geometry: str \ No newline at end of file From c33809d8d8916167bc10ae45cd47e2208b99fa9a Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Tue, 21 May 2024 15:46:41 +0100 Subject: [PATCH 22/46] Directory selection --- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index c8bd7f0ecd..1c48d73fbb 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -10,6 +10,8 @@ import os import os.path from datetime import datetime + +from PySide6 import QtWidgets from PySide6.QtWidgets import QFileDialog import string @@ -47,13 +49,15 @@ def __init__(self): self.SimpleFit_SANSgeometry = 0 ##################################################################################################################### - def get_directory(self): - fname = QFileDialog.getOpenFileName() - if fname: - fname = fname[0] - index = [i for i, val in enumerate(fname) if val == "/"] - fname = fname[0:index[-1]+1] - return fname + + @staticmethod + def directory_popup(): + directory = QFileDialog.getExistingDirectory() + + if directory.strip() == "": + return None + else: + return directory ##################################################################################################################### # Import experimental data and get information from filenames @@ -61,10 +65,14 @@ def import_data_button_callback_sub(self): self.DataCounter = 0 # Predefine array's - DIR = self.get_directory() - for name in os.listdir(DIR): + directory = MuMagLib.directory_popup() + + if directory is None: + return + + for name in os.listdir(directory): if name.find(".csv") != -1: - data = np.genfromtxt(DIR + '/' + name) + data = np.genfromtxt(directory + '/' + name) Lq = len(data[:, 0]) if self.DataCounter == 0: self.q_exp = np.array([np.zeros(Lq)]) @@ -84,12 +92,12 @@ def import_data_button_callback_sub(self): self.DataCounter = self.DataCounter + 1 # Load the data and sort the data - for name in os.listdir(DIR): + for name in os.listdir(directory): if name.find(".csv") != -1: str_name = name[0:len(name)-4] str_name = str_name.split('_') idx = int(str_name[0]) - data = np.genfromtxt(DIR + '/' + name) + data = np.genfromtxt(directory + '/' + name) self.B_0_exp[idx-1] = float(str_name[1]) self.Ms_exp[idx-1] = float(str_name[2]) self.Hdem_exp[idx-1] = float(str_name[3]) @@ -440,3 +448,10 @@ def PlotCompareExpFitData(self, figure, axes, q, I_exp, I_fit, B_0, x_min, x_max ax.set_ylim(y_min, y_max) figure.tight_layout() figure.canvas.draw() + +if __name__ == "__main__": + + app = QtWidgets.QApplication([]) + # app.exec_() + + MuMagLib.directory_popup() From f5bf60c622b35019fd35407aecd81843da5586df Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Tue, 21 May 2024 17:10:00 +0100 Subject: [PATCH 23/46] Refactored first few methods of MuMagLib --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 4 +- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 169 ++++++++---------- 2 files changed, 79 insertions(+), 94 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 93efcba998..e2f4233616 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -44,7 +44,7 @@ def __init__(self, parent=None): layout.addWidget(self.figure_canvas) def import_data_button_callback(self): - self.MuMagLib_obj.import_data_button_callback_sub() + self.MuMagLib_obj.import_data() def plot_experimental_data_button_callback(self): self.simple_fit_axes.set_visible(True) @@ -59,7 +59,7 @@ def plot_experimental_data_button_callback(self): self.s_h_axes.cla() self.longitudinal_scattering_axes.cla() - self.MuMagLib_obj.plot_experimental_data(self.fig, self.simple_fit_axes) + self.MuMagLib_obj.plot_exp_data(self.fig, self.simple_fit_axes) self.figure_canvas.draw() def simple_fit_button_callback(self): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 1c48d73fbb..334b26c42f 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -17,38 +17,15 @@ from sas.qtgui.Utilities.MuMagTool import MuMagParallelGeo from sas.qtgui.Utilities.MuMagTool import MuMagPerpendicularGeo +from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData + +from sasdata.dataloader.loader import Loader + class MuMagLib(): def __init__(self): - # attributes for the input data - self.q_exp = 0 - self.I_exp = 0 - self.sigma_exp = 0 - self.B_0_exp = 0 - self.Ms_exp = 0 - self.Hdem_exp = 0 - self.DataCounter = 0 - - # attributes for the simple fit result - self.SimpleFit_q_exp = 0 - self.SimpleFit_I_exp = 0 - self.SimpleFit_sigma_exp = 0 - self.SimpleFit_B_0_exp = 0 - self.SimpleFit_Ms_exp = 0 - self.SimpleFit_Hdem_exp = 0 - self.SimpleFit_I_fit = 0 - self.SimpleFit_A = 0 - self.SimpleFit_chi_q = 0 - self.SimpleFit_S_H_fit = 0 - self.SimpleFit_S_M_fit = 0 - self.SimpleFit_I_res_fit = 0 - self.SimpleFit_A_opt = 0 - self.SimpleFit_chi_q_opt = 0 - self.SimpleFit_A_sigma = 0 - self.SimpleFit_SANSgeometry = 0 - - ##################################################################################################################### + self.input_data: list[ExperimentalData] | None = None @staticmethod def directory_popup(): @@ -59,91 +36,99 @@ def directory_popup(): else: return directory - ##################################################################################################################### - # Import experimental data and get information from filenames - def import_data_button_callback_sub(self): - self.DataCounter = 0 - # Predefine array's + def import_data(self): + """Import experimental data and get information from filenames""" + + # Get the directory from the user directory = MuMagLib.directory_popup() if directory is None: return - for name in os.listdir(directory): - if name.find(".csv") != -1: - data = np.genfromtxt(directory + '/' + name) - Lq = len(data[:, 0]) - if self.DataCounter == 0: - self.q_exp = np.array([np.zeros(Lq)]) - self.I_exp = np.array([np.zeros(Lq)]) - self.sigma_exp = np.array([np.zeros(Lq)]) - self.B_0_exp = np.array([np.zeros(1)]) - self.Ms_exp = np.array([np.zeros(1)]) - self.Hdem_exp = np.array([np.zeros(1)]) - self.DataCounter = self.DataCounter + 1 - else: - self.q_exp = np.append(self.q_exp, [np.zeros(Lq)], axis=0) - self.I_exp = np.append(self.I_exp, [np.zeros(Lq)], axis=0) - self.sigma_exp = np.append(self.sigma_exp, [np.zeros(Lq)], axis=0) - self.B_0_exp = np.append(self.B_0_exp, [np.zeros(1)]) - self.Ms_exp = np.append(self.Ms_exp, [np.zeros(1)]) - self.Hdem_exp = np.append(self.Hdem_exp, [np.zeros(1)]) - self.DataCounter = self.DataCounter + 1 - - # Load the data and sort the data - for name in os.listdir(directory): - if name.find(".csv") != -1: - str_name = name[0:len(name)-4] - str_name = str_name.split('_') - idx = int(str_name[0]) - data = np.genfromtxt(directory + '/' + name) - self.B_0_exp[idx-1] = float(str_name[1]) - self.Ms_exp[idx-1] = float(str_name[2]) - self.Hdem_exp[idx-1] = float(str_name[3]) - self.q_exp[idx-1, :] = data[:, 0].T * 1e9 - self.I_exp[idx-1, :] = data[:, 1].T - self.sigma_exp[idx-1, :] = data[:, 2].T - - ##################################################################################################################### - # Plot Experimental Data: Set Bounds and Call Plotting Function - def plot_experimental_data(self, figure, axes): + # Load the data + loader = Loader() + input_names = [name for name in os.listdir(directory) if name.lower().endswith(".csv")] + input_paths = [os.path.join(directory, filename) for filename in input_names] - if np.size(self.q_exp) > 1: - q_exp_min = np.amin(self.q_exp)*1e-9 - q_exp_min = 10**(np.floor(np.log10(q_exp_min))) * np.floor(q_exp_min/10**(np.floor(np.log10(q_exp_min)))) + input_data = loader.load(input_paths) - q_exp_max = np.amax(self.q_exp)*1e-9 - q_exp_max = 10**(np.floor(np.log10(q_exp_max))) * np.ceil(q_exp_max/10**(np.floor(np.log10(q_exp_max)))) + data = [] + for filename, data1d in zip(input_names, input_data): - I_exp_min = np.amin(self.I_exp) - I_exp_min = 10**(np.floor(np.log10(I_exp_min))) * np.floor(I_exp_min/10**(np.floor(np.log10(I_exp_min)))) + # Extract the metadata from the filename + filename_parts = filename.split(".") + filename = ".".join(filename_parts[-1]) + + parts = filename.split("_") + + applied_field = float(parts[1]) # mT + saturation_magnetisation = float(parts[2]) # mT + demagnetising_field = float(parts[3]) # mT + + # Create input data object + data.append(ExperimentalData( + scattering_curve=data1d, + applied_field=applied_field, + saturation_magnetisation=saturation_magnetisation, + demagnetising_field=demagnetising_field)) + + self.input_data = sorted(data, key=lambda x: x.applied_field) + + def nice_log_plot_bounds(self, data: list[np.ndarray]): + """ Get nice bounds for the loglog plots + + :return: (lower, upper) bounds appropriate to pass to plt.xlim/ylim + """ + + upper = np.amax(np.array(data)) + lower = np.amin(np.array(data)) + + return ( + 10 ** (np.floor(np.log10(lower))) * np.floor(lower / 10 ** (np.floor(np.log10(lower)))), + 10 ** (np.floor(np.log10(upper))) * np.ceil(upper / 10 ** (np.floor(np.log10(upper)))) + ) - I_exp_max = np.amax(self.I_exp) - I_exp_max = 10 ** (np.floor(np.log10(I_exp_max))) * np.ceil(I_exp_max / 10 ** (np.floor(np.log10(I_exp_max)))) - self.plot_exp_data(figure, axes, self.q_exp*1e-9, self.I_exp, self.B_0_exp*1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) - else: - messagebox.showerror(title="Error!", message="No experimental data available! Please import experimental data!") ################################################################################################################ - # Plot Experimental Data: Generate Figure - def plot_exp_data(self, figure, axes, q, I_exp, B_0, x_min, x_max, y_min, y_max): + # + def plot_exp_data(self, figure, axes): + """ Plot Experimental Data: Generate Figure """ + + if self.input_data is None: + + messagebox.showerror( + title="Error!", + message="No experimental data available! Please import experimental data!") + + return ax = axes - colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) - for k in np.arange(0, len(B_0)): - #print(k) - ax.loglog(q[k, :], I_exp[k, :], linestyle='-', color=colors[k], linewidth=0.5, label=r'$B_0 = ' + str(B_0[k]) + '$ T') - ax.loglog(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) + colors = pl.cm.jet(np.linspace(0, 1, len(self.input_data))) + + for i, datum in enumerate(self.input_data): + + ax.loglog(datum.scattering_curve.x, + datum.scattering_curve.y, + linestyle='-', color=colors[i], linewidth=0.5, + label=r'$B_0 = ' + str(datum.applied_field) + '$ T') + + ax.loglog(datum.scattering_curve.x, + datum.scattering_curve.y, '.', + color=colors[i], linewidth=0.3, markersize=1) + + # Plot limits + qlim = self.nice_log_plot_bounds([datum.scattering_curve.q for datum in self.input_data]) + ilim = self.nice_log_plot_bounds([datum.scattering_curve.I for datum in self.input_data]) ax.set_xlabel(r'$q$ [1/nm]') ax.set_ylabel(r'$I_{\mathrm{exp}}$') - ax.set_xlim(x_min, x_max) - ax.set_ylim(y_min, y_max) + ax.set_xlim(qlim) + ax.set_ylim(ilim) figure.tight_layout() figure.canvas.draw() From 88300aef4d02032e0bd712d234931df041abdc10 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Tue, 21 May 2024 17:13:34 +0100 Subject: [PATCH 24/46] Bugfixes --- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 334b26c42f..faa8c77821 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -58,10 +58,11 @@ def import_data(self): # Extract the metadata from the filename filename_parts = filename.split(".") - filename = ".".join(filename_parts[-1]) + filename = ".".join(filename_parts[:-1]) parts = filename.split("_") + applied_field = float(parts[1]) # mT saturation_magnetisation = float(parts[2]) # mT demagnetising_field = float(parts[3]) # mT @@ -122,8 +123,8 @@ def plot_exp_data(self, figure, axes): color=colors[i], linewidth=0.3, markersize=1) # Plot limits - qlim = self.nice_log_plot_bounds([datum.scattering_curve.q for datum in self.input_data]) - ilim = self.nice_log_plot_bounds([datum.scattering_curve.I for datum in self.input_data]) + qlim = self.nice_log_plot_bounds([datum.scattering_curve.x for datum in self.input_data]) + ilim = self.nice_log_plot_bounds([datum.scattering_curve.y for datum in self.input_data]) ax.set_xlabel(r'$q$ [1/nm]') ax.set_ylabel(r'$I_{\mathrm{exp}}$') From 84e91df8dad7ec3b94adc40c1c1ab13d7881ec7c Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Tue, 21 May 2024 18:00:04 +0100 Subject: [PATCH 25/46] More changes --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 29 +-- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 209 +++++++++--------- .../Utilities/MuMagTool/experimental_data.py | 9 + .../Utilities/MuMagTool/fit_parameters.py | 10 + 4 files changed, 138 insertions(+), 119 deletions(-) create mode 100644 src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index e2f4233616..a26eb18b35 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -10,6 +10,9 @@ import matplotlib.pylab as pl import numpy as np +from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters + + class MuMag(QtWidgets.QMainWindow, Ui_MuMagTool): def __init__(self, parent=None): super().__init__() @@ -62,14 +65,17 @@ def plot_experimental_data_button_callback(self): self.MuMagLib_obj.plot_exp_data(self.fig, self.simple_fit_axes) self.figure_canvas.draw() + def fit_parameters(self) -> FitParameters: + return FitParameters( + q_max = float(self.qMaxEdit.toPlainText()), + min_applied_field= float(self.HminEdit.toPlainText()), + exchange_A_min = float(self.AMinEdit.toPlainText()), + exchange_A_max = float(self.AMaxEdit.toPlainText()), + exchange_A_n = int(self.ASamplesEdit.toPlainText()), + experiment_geometry = self.ScatteringGeometrySelect.currentText()) + def simple_fit_button_callback(self): - q_max = float(self.qMaxEdit.toPlainText()) - H_min = float(self.HminEdit.toPlainText()) - exchange_A_min = float(self.AMinEdit.toPlainText()) - exchange_A_max = float(self.AMaxEdit.toPlainText()) - exchange_A_n = int(self.ASamplesEdit.toPlainText()) - experiment_geometry = self.ScatteringGeometrySelect.currentText() # Clear axes self.simple_fit_axes.cla() @@ -84,19 +90,16 @@ def simple_fit_button_callback(self): self.residuals_axes.set_visible(True) self.s_h_axes.set_visible(True) - if experiment_geometry == 'perpendicular': + parameters = self.fit_parameters() + + if parameters.experiment_geometry == 'perpendicular': self.longitudinal_scattering_axes.set_visible(True) else: self.longitudinal_scattering_axes.set_visible(False) self.MuMagLib_obj.simple_fit_button_callback( - q_max, - H_min, - exchange_A_min, - exchange_A_max, - exchange_A_n, - experiment_geometry, + parameters, self.fig, self.chi_squared_axes, self.residuals_axes, diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index faa8c77821..3dec90a405 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -18,6 +18,7 @@ from sas.qtgui.Utilities.MuMagTool import MuMagParallelGeo from sas.qtgui.Utilities.MuMagTool import MuMagPerpendicularGeo from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData +from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters from sasdata.dataloader.loader import Loader @@ -133,116 +134,112 @@ def plot_exp_data(self, figure, axes): figure.tight_layout() figure.canvas.draw() - ####################################################################################################################### - - def simple_fit_button_callback(self, q_max, H_min, A1, A2, A_N, SANSgeometry, figure, axes1, axes2, axes3, axes4): - - if np.size(self.q_exp) > 1: - - # search index for q_max - q_diff = (self.q_exp[0, :]*1e-9 - q_max)**2 - K_q = np.where(q_diff == np.min(q_diff)) - K_q = K_q[0][0] - - # search index for H_min - H_diff = (self.B_0_exp - H_min)**2 - K_H = np.where(H_diff == np.min(H_diff)) - K_H = K_H[0][0] - - # apply the restrictions - mu_0 = 4*math.pi*1e-7 - q = self.q_exp[K_H:, 0:K_q] - I_exp_red = self.I_exp[K_H:, 0:K_q] - sigma = self.sigma_exp[K_H:, 0:K_q] - H_0 = np.outer(self.B_0_exp[K_H:]/mu_0 * 1e-3, np.ones(K_q)) - H_dem = np.outer(self.Hdem_exp[K_H:], np.ones(K_q))/mu_0 * 1e-3 - Ms = np.outer(self.Ms_exp[K_H:], np.ones(K_q))/mu_0 * 1e-3 - - # Least Squares Fit in case of perpendicular SANS geometry - if SANSgeometry == "perpendicular": - A_1 = A1 * 1e-12 - A_2 = A2 * 1e-12 - A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M \ - = MuMagPerpendicularGeo.SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) - - A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = MuMagPerpendicularGeo.LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - - I_opt = MuMagPerpendicularGeo.SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) - - d2chi_dA2 = MuMagPerpendicularGeo.FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - - N_mu = len(I_exp_red[0, :]) - N_nu = len(I_exp_red[:, 0]) - A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) - - MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, - S_H_opt, S_M_opt, A_Uncertainty * 1e12, - figure, axes1, axes2, axes3, axes4) - - # Save to global Variables - self.SimpleFit_q_exp = q - self.SimpleFit_I_exp = I_exp_red - self.SimpleFit_sigma_exp = sigma - self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] - self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] - self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] - self.SimpleFit_I_fit = I_opt - self.SimpleFit_A = A - self.SimpleFit_chi_q = chi_q - self.SimpleFit_S_H_fit = S_H_opt - self.SimpleFit_S_M_fit = S_M_opt - self.SimpleFit_I_res_fit = I_res_opt - self.SimpleFit_A_opt = A_opt - self.SimpleFit_chi_q_opt = chi_q_opt - self.SimpleFit_A_sigma = A_Uncertainty - self.SimpleFit_SANSgeometry = "perpendicular" - - elif SANSgeometry == "parallel": - - A_1 = A1 * 1e-12 - A_2 = A2 * 1e-12 - A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ - = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) - - A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = MuMagParallelGeo.LSQ_PAR(q, I_exp_red, sigma, - Ms, H_0, - H_dem, - A_opt) - - I_opt = MuMagParallelGeo.SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) - - d2chi_dA2 = MuMagParallelGeo.FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - N_mu = len(I_exp_red[0, :]) - N_nu = len(I_exp_red[:, 0]) - A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) - - MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, - I_res_opt, S_H_opt, A_Uncertainty * 1e12, - figure, axes1, axes2, axes3, axes4) - - # Save to global Variables - self.SimpleFit_q_exp = q - self.SimpleFit_I_exp = I_exp_red - self.SimpleFit_sigma_exp = sigma - self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] - self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] - self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] - self.SimpleFit_I_fit = I_opt - self.SimpleFit_A = A - self.SimpleFit_chi_q = chi_q - self.SimpleFit_S_H_fit = S_H_opt - self.SimpleFit_I_res_fit = I_res_opt - self.SimpleFit_A_opt = A_opt - self.SimpleFit_chi_q_opt = chi_q_opt - self.SimpleFit_A_sigma = A_Uncertainty - self.SimpleFit_SANSgeometry = "parallel" - else: + def simple_fit_button_callback(self, parameters: FitParameters, figure, axes1, axes2, axes3, axes4): + + if self.input_data is None: messagebox.showerror(title="Error!", message="No experimental Data available! Please import experimental data!") + return None + + # Use an index for data upto qmax based on first data set + # Not ideal, would be preferable make sure the data was + # compatible, using something like interpolation TODO + square_distance_from_qmax = (self.input_data[0].scattering_curve.x - parameters.q_max) ** 2 + max_q_index = np.argmin(square_distance_from_qmax)[0] + + filtered_inputs = [datum.restrict_by_index(max_q_index) + for datum in self.input_data + if datum.applied_field > parameters.min_applied_field] + + + + # Least Squares Fit in case of perpendicular SANS geometry + if parameters.experiment_geometry == "perpendicular": + + A_1 = A1 * 1e-12 + A_2 = A2 * 1e-12 + + A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M \ + = MuMagPerpendicularGeo.SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + + A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = MuMagPerpendicularGeo.LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + + I_opt = MuMagPerpendicularGeo.SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + + d2chi_dA2 = MuMagPerpendicularGeo.FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + + N_mu = len(I_exp_red[0, :]) + N_nu = len(I_exp_red[:, 0]) + A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + + MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, + S_H_opt, S_M_opt, A_Uncertainty * 1e12, + figure, axes1, axes2, axes3, axes4) + + # Save to global Variables + self.SimpleFit_q_exp = q + self.SimpleFit_I_exp = I_exp_red + self.SimpleFit_sigma_exp = sigma + self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] + self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] + self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] + self.SimpleFit_I_fit = I_opt + self.SimpleFit_A = A + self.SimpleFit_chi_q = chi_q + self.SimpleFit_S_H_fit = S_H_opt + self.SimpleFit_S_M_fit = S_M_opt + self.SimpleFit_I_res_fit = I_res_opt + self.SimpleFit_A_opt = A_opt + self.SimpleFit_chi_q_opt = chi_q_opt + self.SimpleFit_A_sigma = A_Uncertainty + self.SimpleFit_SANSgeometry = "perpendicular" + + else: + + A_1 = A1 * 1e-12 + A_2 = A2 * 1e-12 + A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ + = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + + A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = MuMagParallelGeo.LSQ_PAR(q, I_exp_red, sigma, + Ms, H_0, + H_dem, + A_opt) + + I_opt = MuMagParallelGeo.SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + + d2chi_dA2 = MuMagParallelGeo.FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + N_mu = len(I_exp_red[0, :]) + N_nu = len(I_exp_red[:, 0]) + A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + + MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, + I_res_opt, S_H_opt, A_Uncertainty * 1e12, + figure, axes1, axes2, axes3, axes4) + + # Save to global Variables + self.SimpleFit_q_exp = q + self.SimpleFit_I_exp = I_exp_red + self.SimpleFit_sigma_exp = sigma + self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] + self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] + self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] + self.SimpleFit_I_fit = I_opt + self.SimpleFit_A = A + self.SimpleFit_chi_q = chi_q + self.SimpleFit_S_H_fit = S_H_opt + self.SimpleFit_I_res_fit = I_res_opt + self.SimpleFit_A_opt = A_opt + self.SimpleFit_chi_q_opt = chi_q_opt + self.SimpleFit_A_sigma = A_Uncertainty + self.SimpleFit_SANSgeometry = "parallel" + + + ###################################################################################################################### def save_button_callback(self): diff --git a/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py b/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py index 3caf8efb29..0aee94cd93 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py +++ b/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py @@ -14,3 +14,12 @@ class ExperimentalData: applied_field: float saturation_magnetisation: float demagnetising_field: float + + def restrict_by_index(self, max_index: int): + """ Remove all points from data up to given index""" + + x = self.scattering_curve.x[:max_index] + y = self.scattering_curve.y[:max_index] + dy = self.scattering_curve.dy[:max_index] + + return Data1D(x=x, y=y, dy=dy) diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py b/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py new file mode 100644 index 0000000000..8fc671bbb9 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass + +@dataclass +class FitParameters: + q_max: float + min_applied_field: float + exchange_A_min: float + exchange_A_max: float + exchange_A_n: int + experiment_geometry: str \ No newline at end of file From 8ccfd98b71f566d5fe8e6d674d9263c95cf8d20f Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Thu, 23 May 2024 16:48:36 +0100 Subject: [PATCH 26/46] Updates to GUI --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 12 +- .../qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 479 ++++++++++-------- 2 files changed, 264 insertions(+), 227 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index a26eb18b35..7ab5482ce3 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -67,12 +67,12 @@ def plot_experimental_data_button_callback(self): def fit_parameters(self) -> FitParameters: return FitParameters( - q_max = float(self.qMaxEdit.toPlainText()), - min_applied_field= float(self.HminEdit.toPlainText()), - exchange_A_min = float(self.AMinEdit.toPlainText()), - exchange_A_max = float(self.AMaxEdit.toPlainText()), - exchange_A_n = int(self.ASamplesEdit.toPlainText()), - experiment_geometry = self.ScatteringGeometrySelect.currentText()) + q_max=self.qMaxSpinBox.value(), + min_applied_field=self.hMinSpinBox.value(), + exchange_A_min=self.aMinSpinBox.value(), + exchange_A_max=self.aMaxSpinBox.value(), + exchange_A_n=self.aSamplesSpinBox.value(), + experiment_geometry=self.ScatteringGeometrySelect.currentText()) def simple_fit_button_callback(self): diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui index 3aaa0d3826..dc852b42e6 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -6,241 +6,278 @@ 0 0 - 761 - 600 + 549 + 481 MuMagTool - - - - 0 - 0 - 161 - 121 - - - - Import Data - - - - - 0 - 20 - 161 - 101 - - - - - - - Plot Data - - - - - - - Import Data - - - - - - - - perpendicular + + + + + + + + Import Data - - - - parallel + + + + + Import Data + + + + + + + Plot Data + + + + + + + Simple Fit + + + + + + + Compare Results + + + + + + + Save Result + + + + + + + + + + Simple Fit Tool - - - - - - - - - - 160 - 0 - 601 - 121 - - - - Simple Fit Tool - - - - - 10 - 20 - 581 - 101 - - - - - - - A [pJ/m]: - - - - - - - max - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5</p></body></html> - - - - - - - min - - - - - - - q_max [1/nm] - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">0.6</p></body></html> - - - - - - - Simple Fit - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">20</p></body></html> - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">200</p></body></html> - - - - - - - samples - - - - - - - mu_0*H_min [mT] - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">75</p></body></html> - - - - - - - Compare Results - - - - - - - Save Result - - - - - - - - - - 0 - 120 - 761 - 441 - - - - Display - - - - - 0 - 20 - 761 - 411 - - - - + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 7 + + + + + Maximum q + + + + + + + Applied Field (μ<sub>0</sub> H<sub>min</sub>): + + + + + + + + 0 + + + + + 10000.000000000000000 + + + 75.000000000000000 + + + + + + + mT + + + + + + + + + + + 0 + + + + + 0.010000000000000 + + + 0.010000000000000 + + + 0.600000000000000 + + + + + + + nm<sup>-1</sup> + + + + + + + + + + A: + + + + + + + + 0 + + + + + 100000.000000000000000 + + + 5.000000000000000 + + + + + + + to + + + + + + + 100000.000000000000000 + + + 20.000000000000000 + + + + + + + pJ/m, + + + + + + + 10000 + + + 200 + + + + + + + steps + + + + + + + + + + Analysis Method: + + + + + + + + 0 + + + + + + perpendicular + + + + + parallel + + + + + + + + + + + + + + + + + + + + Display + + + + + 0 + 20 + 761 + 411 + + + + + + 0 0 - 761 - 22 + 549 + 20 From 9c53242f86fd9a6e6dd0a2aa4deccdcae415a581 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Thu, 23 May 2024 17:11:38 +0100 Subject: [PATCH 27/46] Minor changes to GUI --- src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui index dc852b42e6..c6b39bff25 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -80,7 +80,7 @@ - Maximum q + Maximum q: @@ -99,6 +99,9 @@ + + 5 + 10000.000000000000000 @@ -125,8 +128,11 @@ + + 5 + - 0.010000000000000 + 0.000010000000000 0.010000000000000 @@ -149,7 +155,7 @@ - A: + Exchange Coefficient (A): @@ -228,6 +234,9 @@ + + perpendicular + perpendicular From f58ece2b7fdca916b8de006218144f5acea678e5 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Fri, 24 May 2024 12:05:50 +0100 Subject: [PATCH 28/46] Enum for experiment geometry --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 34 ++-- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 172 +++++++++--------- .../Utilities/MuMagTool/fit_parameters.py | 10 +- .../qtgui/Utilities/MuMagTool/fit_result.py | 4 +- 4 files changed, 118 insertions(+), 102 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 7ab5482ce3..c695c87d20 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -10,7 +10,7 @@ import matplotlib.pylab as pl import numpy as np -from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters +from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry class MuMag(QtWidgets.QMainWindow, Ui_MuMagTool): @@ -32,15 +32,15 @@ def __init__(self, parent=None): self.PlotDisplayPanel.setLayout(layout) self.fig = plt.figure() #Figure(figsize=(width, height), dpi=dpi) - self.simple_fit_axes = self.fig.add_subplot(111) + self.simple_fit_axes = self.fig.add_subplot(1, 1, 1) self.simple_fit_axes.set_visible(False) - self.chi_squared_axes = self.fig.add_subplot(221) + self.chi_squared_axes = self.fig.add_subplot(2, 2, 1) self.chi_squared_axes.set_visible(False) - self.residuals_axes = self.fig.add_subplot(222) + self.residuals_axes = self.fig.add_subplot(2, 2, 2) self.residuals_axes.set_visible(False) - self.s_h_axes = self.fig.add_subplot(223) + self.s_h_axes = self.fig.add_subplot(2, 2, 3) self.s_h_axes.set_visible(False) - self.longitudinal_scattering_axes = self.fig.add_subplot(224) + self.longitudinal_scattering_axes = self.fig.add_subplot(2, 2, 4) self.longitudinal_scattering_axes.set_visible(False) self.figure_canvas = FigureCanvas(self.fig) @@ -66,13 +66,22 @@ def plot_experimental_data_button_callback(self): self.figure_canvas.draw() def fit_parameters(self) -> FitParameters: + + match self.ScatteringGeometrySelect.currentText().lower(): + case "parallel": + geometry = ExperimentGeometry.PARALLEL + case "perpendicular": + geometry = ExperimentGeometry.PERPENDICULAR + case _: + raise ValueError(f"Unknown experiment geometry: {self.ScatteringGeometrySelect.currentText()}") + return FitParameters( q_max=self.qMaxSpinBox.value(), min_applied_field=self.hMinSpinBox.value(), exchange_A_min=self.aMinSpinBox.value(), exchange_A_max=self.aMaxSpinBox.value(), exchange_A_n=self.aSamplesSpinBox.value(), - experiment_geometry=self.ScatteringGeometrySelect.currentText()) + experiment_geometry=geometry) def simple_fit_button_callback(self): @@ -92,10 +101,13 @@ def simple_fit_button_callback(self): parameters = self.fit_parameters() - if parameters.experiment_geometry == 'perpendicular': - self.longitudinal_scattering_axes.set_visible(True) - else: - self.longitudinal_scattering_axes.set_visible(False) + match parameters.experiment_geometry: + case ExperimentGeometry.PERPENDICULAR: + self.longitudinal_scattering_axes.set_visible(True) + case ExperimentGeometry.PARALLEL: + self.longitudinal_scattering_axes.set_visible(False) + case _: + raise ValueError(f"Unknown Value: {parameters.experiment_geometry}") self.MuMagLib_obj.simple_fit_button_callback( diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 3dec90a405..082cd2863d 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -18,7 +18,7 @@ from sas.qtgui.Utilities.MuMagTool import MuMagParallelGeo from sas.qtgui.Utilities.MuMagTool import MuMagPerpendicularGeo from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters +from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry from sasdata.dataloader.loader import Loader @@ -91,13 +91,6 @@ def nice_log_plot_bounds(self, data: list[np.ndarray]): 10 ** (np.floor(np.log10(upper))) * np.ceil(upper / 10 ** (np.floor(np.log10(upper)))) ) - - - - - - ################################################################################################################ - # def plot_exp_data(self, figure, axes): """ Plot Experimental Data: Generate Figure """ @@ -156,87 +149,88 @@ def simple_fit_button_callback(self, parameters: FitParameters, figure, axes1, a # Least Squares Fit in case of perpendicular SANS geometry - if parameters.experiment_geometry == "perpendicular": - - A_1 = A1 * 1e-12 - A_2 = A2 * 1e-12 - - A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M \ - = MuMagPerpendicularGeo.SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) - - A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = MuMagPerpendicularGeo.LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - - I_opt = MuMagPerpendicularGeo.SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) - - d2chi_dA2 = MuMagPerpendicularGeo.FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - - N_mu = len(I_exp_red[0, :]) - N_nu = len(I_exp_red[:, 0]) - A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) - - MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, - S_H_opt, S_M_opt, A_Uncertainty * 1e12, - figure, axes1, axes2, axes3, axes4) - - # Save to global Variables - self.SimpleFit_q_exp = q - self.SimpleFit_I_exp = I_exp_red - self.SimpleFit_sigma_exp = sigma - self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] - self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] - self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] - self.SimpleFit_I_fit = I_opt - self.SimpleFit_A = A - self.SimpleFit_chi_q = chi_q - self.SimpleFit_S_H_fit = S_H_opt - self.SimpleFit_S_M_fit = S_M_opt - self.SimpleFit_I_res_fit = I_res_opt - self.SimpleFit_A_opt = A_opt - self.SimpleFit_chi_q_opt = chi_q_opt - self.SimpleFit_A_sigma = A_Uncertainty - self.SimpleFit_SANSgeometry = "perpendicular" - - else: - - A_1 = A1 * 1e-12 - A_2 = A2 * 1e-12 - A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ - = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) - - A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = MuMagParallelGeo.LSQ_PAR(q, I_exp_red, sigma, - Ms, H_0, - H_dem, - A_opt) - - I_opt = MuMagParallelGeo.SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) - - d2chi_dA2 = MuMagParallelGeo.FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - N_mu = len(I_exp_red[0, :]) - N_nu = len(I_exp_red[:, 0]) - A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) - - MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, - I_res_opt, S_H_opt, A_Uncertainty * 1e12, - figure, axes1, axes2, axes3, axes4) - - # Save to global Variables - self.SimpleFit_q_exp = q - self.SimpleFit_I_exp = I_exp_red - self.SimpleFit_sigma_exp = sigma - self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] - self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] - self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] - self.SimpleFit_I_fit = I_opt - self.SimpleFit_A = A - self.SimpleFit_chi_q = chi_q - self.SimpleFit_S_H_fit = S_H_opt - self.SimpleFit_I_res_fit = I_res_opt - self.SimpleFit_A_opt = A_opt - self.SimpleFit_chi_q_opt = chi_q_opt - self.SimpleFit_A_sigma = A_Uncertainty - self.SimpleFit_SANSgeometry = "parallel" + match parameters.experiment_geometry: + case ExperimentGeometry.PERPENDICULAR: + + A_1 = A1 * 1e-12 + A_2 = A2 * 1e-12 + + A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M \ + = MuMagPerpendicularGeo.SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + + A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = MuMagPerpendicularGeo.LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + + I_opt = MuMagPerpendicularGeo.SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + + d2chi_dA2 = MuMagPerpendicularGeo.FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + + N_mu = len(I_exp_red[0, :]) + N_nu = len(I_exp_red[:, 0]) + A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + + MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, + S_H_opt, S_M_opt, A_Uncertainty * 1e12, + figure, axes1, axes2, axes3, axes4) + + # Save to global Variables + self.SimpleFit_q_exp = q + self.SimpleFit_I_exp = I_exp_red + self.SimpleFit_sigma_exp = sigma + self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] + self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] + self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] + self.SimpleFit_I_fit = I_opt + self.SimpleFit_A = A + self.SimpleFit_chi_q = chi_q + self.SimpleFit_S_H_fit = S_H_opt + self.SimpleFit_S_M_fit = S_M_opt + self.SimpleFit_I_res_fit = I_res_opt + self.SimpleFit_A_opt = A_opt + self.SimpleFit_chi_q_opt = chi_q_opt + self.SimpleFit_A_sigma = A_Uncertainty + self.SimpleFit_SANSgeometry = "perpendicular" + + case ExperimentGeometry.PARALLEL: + + A_1 = A1 * 1e-12 + A_2 = A2 * 1e-12 + A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ + = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + + A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = MuMagParallelGeo.LSQ_PAR(q, I_exp_red, sigma, + Ms, H_0, + H_dem, + A_opt) + + I_opt = MuMagParallelGeo.SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + + d2chi_dA2 = MuMagParallelGeo.FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + N_mu = len(I_exp_red[0, :]) + N_nu = len(I_exp_red[:, 0]) + A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + + MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, + I_res_opt, S_H_opt, A_Uncertainty * 1e12, + figure, axes1, axes2, axes3, axes4) + + # Save to global Variables + self.SimpleFit_q_exp = q + self.SimpleFit_I_exp = I_exp_red + self.SimpleFit_sigma_exp = sigma + self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] + self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] + self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] + self.SimpleFit_I_fit = I_opt + self.SimpleFit_A = A + self.SimpleFit_chi_q = chi_q + self.SimpleFit_S_H_fit = S_H_opt + self.SimpleFit_I_res_fit = I_res_opt + self.SimpleFit_A_opt = A_opt + self.SimpleFit_chi_q_opt = chi_q_opt + self.SimpleFit_A_sigma = A_Uncertainty + self.SimpleFit_SANSgeometry = "parallel" diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py b/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py index 8fc671bbb9..20b65ff98b 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py +++ b/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py @@ -1,4 +1,11 @@ from dataclasses import dataclass +from enum import Enum + + +class ExperimentGeometry(Enum): + PARALLEL = 1 + PERPENDICULAR = 2 + @dataclass class FitParameters: @@ -7,4 +14,5 @@ class FitParameters: exchange_A_min: float exchange_A_max: float exchange_A_n: int - experiment_geometry: str \ No newline at end of file + experiment_geometry: ExperimentGeometry + diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py index e9d08e9455..b74cad7d46 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py +++ b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py @@ -3,6 +3,7 @@ import numpy as np from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData +from sas.qtgui.Utilities.MuMagTool.fit_parameters import ExperimentGeometry @dataclass @@ -25,4 +26,5 @@ class FitResults: optimal_A_chi_sq: float optimal_A_stdev: float # check - geometry: str \ No newline at end of file + geometry: ExperimentGeometry + From 7c420f7af88a700afb60d9391b9d643ff5f37f8e Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Tue, 4 Jun 2024 18:03:05 +0100 Subject: [PATCH 29/46] Lots of refractoring --- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 66 ++-- .../Utilities/MuMagTool/MuMagParallelGeo.py | 33 +- .../MuMagTool/MuMagPerpendicularGeo.py | 298 ++++++++---------- .../qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 6 +- .../Utilities/MuMagTool/experimental_data.py | 6 +- .../Utilities/MuMagTool/fit_parameters.py | 2 + .../qtgui/Utilities/MuMagTool/fit_result.py | 2 - .../MuMagTool/least_squares_output.py | 18 ++ src/sas/qtgui/Utilities/MuMagTool/models.py | 103 ++++++ .../qtgui/Utilities/MuMagTool/sweep_output.py | 16 + 10 files changed, 315 insertions(+), 235 deletions(-) create mode 100644 src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py create mode 100644 src/sas/qtgui/Utilities/MuMagTool/models.py create mode 100644 src/sas/qtgui/Utilities/MuMagTool/sweep_output.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 082cd2863d..f91825870a 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -140,65 +140,55 @@ def simple_fit_button_callback(self, parameters: FitParameters, figure, axes1, a # Not ideal, would be preferable make sure the data was # compatible, using something like interpolation TODO square_distance_from_qmax = (self.input_data[0].scattering_curve.x - parameters.q_max) ** 2 - max_q_index = np.argmin(square_distance_from_qmax)[0] + max_q_index = int(np.argmin(square_distance_from_qmax)) filtered_inputs = [datum.restrict_by_index(max_q_index) for datum in self.input_data if datum.applied_field > parameters.min_applied_field] - # Least Squares Fit in case of perpendicular SANS geometry match parameters.experiment_geometry: case ExperimentGeometry.PERPENDICULAR: - A_1 = A1 * 1e-12 - A_2 = A2 * 1e-12 - A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M \ - = MuMagPerpendicularGeo.SweepA_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + sweep_data = MuMagPerpendicularGeo.SweepA_PERP(parameters, filtered_inputs) - A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = MuMagPerpendicularGeo.LSQ_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(filtered_inputs, sweep_data.optimal.exchange_A, epsilon=0.0001) - I_opt = MuMagPerpendicularGeo.SANS_Model_PERP(q, S_H_opt, S_M_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + least_squares_fit_at_optimum = MuMagPerpendicularGeo.LSQ_PERP(filtered_inputs, A_opt) - d2chi_dA2 = MuMagPerpendicularGeo.FDM2Ord_PERP(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) + I_opt = least_squares_fit_at_optimum.I_simulated - N_mu = len(I_exp_red[0, :]) - N_nu = len(I_exp_red[:, 0]) - A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + uncertainty = MuMagPerpendicularGeo.uncertainty_perp(filtered_inputs, A_opt) - MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, - S_H_opt, S_M_opt, A_Uncertainty * 1e12, + MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(sweep_data, uncertainty * 1e12, figure, axes1, axes2, axes3, axes4) # Save to global Variables - self.SimpleFit_q_exp = q - self.SimpleFit_I_exp = I_exp_red - self.SimpleFit_sigma_exp = sigma - self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] - self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] - self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] - self.SimpleFit_I_fit = I_opt - self.SimpleFit_A = A - self.SimpleFit_chi_q = chi_q - self.SimpleFit_S_H_fit = S_H_opt - self.SimpleFit_S_M_fit = S_M_opt - self.SimpleFit_I_res_fit = I_res_opt - self.SimpleFit_A_opt = A_opt - self.SimpleFit_chi_q_opt = chi_q_opt - self.SimpleFit_A_sigma = A_Uncertainty - self.SimpleFit_SANSgeometry = "perpendicular" + # self.SimpleFit_q_exp = q + # self.SimpleFit_I_exp = I_exp_red + # self.SimpleFit_sigma_exp = sigma + # self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] + # self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] + # self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] + # self.SimpleFit_I_fit = I_opt + # self.SimpleFit_A = A + # self.SimpleFit_chi_q = chi_q + # self.SimpleFit_S_H_fit = S_H_opt + # self.SimpleFit_S_M_fit = S_M_opt + # self.SimpleFit_I_res_fit = I_res_opt + # self.SimpleFit_A_opt = A_opt + # self.SimpleFit_chi_q_opt = chi_q_opt + # self.SimpleFit_A_sigma = A_Uncertainty + # self.SimpleFit_SANSgeometry = "perpendicular" case ExperimentGeometry.PARALLEL: - A_1 = A1 * 1e-12 - A_2 = A2 * 1e-12 A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ - = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, A_2, A_N) + = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_min, A_max_J, A_N) - A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_1, 0.0001) + A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_min, 0.0001) chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = MuMagParallelGeo.LSQ_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, @@ -207,9 +197,9 @@ def simple_fit_button_callback(self, parameters: FitParameters, figure, axes1, a I_opt = MuMagParallelGeo.SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) d2chi_dA2 = MuMagParallelGeo.FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - N_mu = len(I_exp_red[0, :]) - N_nu = len(I_exp_red[:, 0]) - A_Uncertainty = np.sqrt(2 / (N_mu * N_nu * d2chi_dA2)) + n_field_strengths = len(I_exp_red[0, :]) + n_q = len(I_exp_red[:, 0]) + A_Uncertainty = np.sqrt(2 / (n_field_strengths * n_q * d2chi_dA2)) MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, A_Uncertainty * 1e12, diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py index fb69206e4b..eb14e30e01 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py @@ -3,37 +3,6 @@ import matplotlib.pyplot as plt -#################################################################################################### -# Functions for the analysis of parallel SANS ###################################################### -#################################################################################################### -# Lorentzian Model for the generation of clean synthetic test data for perpendicular SANS geometry -def LorentzianModelPAR(q, A, M_s, H_0, H_dem, a_H, l_c): - - # All inputs in SI-units - # Micromagnetic Model - mu_0 = 4 * np.pi * 1e-7 - H_i = H_0 - H_dem - l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) - H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) - p = M_s / H_eff - R_H = (p ** 2) / 2 - - # Lorentzian functions for S_H, S_M - S_H = a_H**2/(1 + q**2 * l_c**2)**2 - - # Magnetic SANS cross sections - I_M = R_H * S_H - - # Model of I_res - idx = np.argmax(H_0[:, 1]) - I_res = 0.9 * I_M[idx, :] - - # Total SANS cross section - I_sim = I_res + I_M - sigma = 0 * I_sim + 1 - - return I_sim, sigma, S_H, I_res - #################################################################################################### # Least squares method for parallel SANS geometry def LSQ_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A): @@ -115,7 +84,7 @@ def chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A): # Sweep over Exchange Stiffness A for parallel SANS geometry def SweepA_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_1, A_2, A_N): - A = np.linspace(A_1, A_2, A_N) + A = np.linspace(A_1, A_2, A_N) * 1e-12 # pJ/m -> J/m chi_q = np.zeros(len(A)) for k in np.arange(0, len(A)): chi_q[k], I_res, S_H, sigma_I_res, sigma_S_H = LSQ_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A[k]) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py index c031b5a806..ee841b424e 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py @@ -2,178 +2,142 @@ import scipy.optimize as scopt import matplotlib.pyplot as plt +from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData +from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters +from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults +from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutput +from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput +mu_0 = 4 * np.pi * 1e-7 -#################################################################################################### -# Functions for the analysis of perpendicular SANS ################################################# -#################################################################################################### -# Lorentzian Model for the generation of clean synthetic test data for perpendicular SANS geometry -def LorentzianModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c): - - # All inputs in SI-units - # Micromagnetic Model - mu_0 = 4 * np.pi * 1e-7 - H_i = H_0 - H_dem - l_H = np.sqrt((2*A)/(mu_0 * M_s * H_i)) - H_eff = H_i * (1 + l_H**2 * q**2) - p = M_s/H_eff - R_H = p**2 / 4 * (2 + 1/np.sqrt(1 + p)) - R_M = (np.sqrt(1 + p) - 1)/2 +def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: + """ Least squares fitting for a given exchange stiffness, A - # Lorentzian functions for S_H, S_M - S_H = a_H**2/(1 + q**2 * l_c**2)**2 - S_M = a_M**2/(1 + q**2 * l_c**2)**2 + We are fitting the equation: - # Magnetic SANS cross sections - I_M = R_H * S_H + R_M * S_M + I_sim = I_res + response_H * S_H + response_M * S_M + = (I_res, S_H, S_M) . (1, response_H, response_M) + = (I_res, S_H, S_M) . least_squares_x - # Model of I_res - idx = np.argmax(H_0[:, 1]) - print(H_0[idx, 1]*mu_0*1e3) - I_res = 0.9 * I_M[idx, :] + finding I_res, S_H, and S_M for each q value - # Total SANS cross section - I_sim = I_res + I_M - sigma = 0 * I_sim + 1 - return I_sim, sigma, S_H, S_M, I_res + """ -#################################################################################################### -# Lorentzian Model for the generation of noisy synthetic test data for perpendicular SANS geometry -def LorentzianNoisyModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c, beta): + # Get matrices from the input data + n_data = len(data) - # All inputs in SI-units + applied_field = np.array([datum.applied_field for datum in data]) + demagnetising_field = np.array([datum.demagnetising_field for datum in data]) + saturation_magnetisation = np.array([datum.saturation_magnetisation for datum in data]) - # Micromagnetic Model - mu_0 = 4 * np.pi * 1e-7 - H_i = H_0 - H_dem - l_H = np.sqrt((2*A)/(mu_0 * M_s * H_i)) - H_eff = H_i * (1 + l_H**2 * q**2) - p = M_s/H_eff - R_H = p**2 / 4 * (2 + 1/np.sqrt(1 + p)) - R_M = (np.sqrt(1 + p) - 1)/2 + q = np.array([datum.scattering_curve.x for datum in data]) # TODO: Check for transpose + I = np.array([datum.scattering_curve.y for datum in data]) + I_stdev = np.array([datum.scattering_curve.dy for datum in data]) - # Lorentzian functions for S_H, S_M - S_H = a_H**2/(1 + q**2 * l_c**2)**2 - S_M = a_M**2/(1 + q**2 * l_c**2)**2 + n_q = q.shape[0] - # Magnetic SANS cross sections - I_M = R_H * S_H + R_M * S_M + # Micromagnetic Model + internal_field = (applied_field - demagnetising_field).reshape(-1, 1) + magnetic_scattering_length = np.sqrt((2 * A) / (mu_0 * saturation_magnetisation.reshape(-1, 1) * internal_field)) + effective_field = internal_field * (1 + (magnetic_scattering_length ** 2) * (q ** 2)) - # Model of I_res - idx = np.argmax(H_0[:, 1]) - I_res = 0.9 * I_M[idx, :] + # Calculate the response functions + p = saturation_magnetisation.reshape(-1, 1) / effective_field + response_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) + response_M = (np.sqrt(1 + p) - 1) / 2 - # Model of standard deviation - sigma = beta * (I_res + I_M) + print("Shapes:") + print(" I", I.shape) + print(" q", q.shape) + print(" sigma", I_stdev.shape) + print(" response H", response_H.shape) + print(" response M", response_M.shape) - # Total SANS cross section - I_sim = I_res + I_M + sigma * np.random.randn(len(sigma[:, 1]), len(sigma[1, :])) + # Lists for output of calculation + I_residual = [] + S_H = [] + S_M = [] - return I_sim, sigma, S_H, S_M, I_res + I_residual_error_weight = [] + S_M_error_weight = [] + S_H_error_weight = [] -#################################################################################################### -# Least squares method for perpendicular SANS geometry -def LSQ_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A): + for nu in range(n_q): - # Micromagnetic Model - mu_0 = 4 * np.pi * 1e-7 - H_i = H_0 - H_dem - l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) - H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) - p = M_s / H_eff - R_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) - R_M = (np.sqrt(1 + p) - 1) / 2 - # Non-negative least squares loop - L_nu = len(q[1, :]) - S_H = np.zeros((1, L_nu)) - S_M = np.zeros((1, L_nu)) - I_res = np.zeros((1, L_nu)) - sigma_S_H = np.zeros((1, L_nu)) - sigma_S_M = np.zeros((1, L_nu)) - sigma_I_res = np.zeros((1, L_nu)) - for nu in np.arange(0, L_nu): - A = np.array([1/sigma[:, nu], R_H[:, nu]/sigma[:, nu], R_M[:, nu]/sigma[:, nu]]).T - y = I_exp[:, nu]/sigma[:, nu] - c = np.matmul(A.T, y) - H = np.dot(A.T, A) # non-negative linear least squares - x = scopt.nnls(H, c) - I_res[0, nu] = x[0][0] - S_H[0, nu] = x[0][1] - S_M[0, nu] = x[0][2] + least_squares_x = (np.array([np.ones((n_data,)), response_H[:, nu], response_M[:, nu]]) / I_stdev[:, nu]).T + least_squares_y = I[:, nu]/I_stdev[:, nu] - Gamma = np.linalg.inv(np.dot(H.T, H)) - sigma_I_res[0, nu] = Gamma[0, 0] - sigma_S_H[0, nu] = Gamma[1, 1] - sigma_S_M[0, nu] = Gamma[2, 2] + print("Least Squares X", least_squares_x.shape) + print("Least Squares Y", least_squares_y.shape) - I_sim = I_res + R_H * S_H + R_M * S_M - s_q = np.mean(((I_exp - I_sim)/sigma)**2, axis=0) + least_squares_x_squared = np.dot(least_squares_x.T, least_squares_x) - sigma_S_H = np.sqrt(np.abs(sigma_S_H * s_q)) - sigma_S_M = np.sqrt(np.abs(sigma_S_M * s_q)) - sigma_I_res = np.sqrt(np.abs(sigma_I_res * s_q)) + # Non-negative least squares + fit_result = scopt.nnls( + least_squares_x_squared, + np.matmul(least_squares_x.T, least_squares_y)) - chi_q = np.mean(s_q) + I_residual.append(fit_result[0][0]) + S_H.append(fit_result[0][1]) + S_M.append(fit_result[0][2]) - return chi_q, I_res, S_H, S_M, sigma_I_res, sigma_S_H, sigma_S_M + errors = np.linalg.inv(np.dot(least_squares_x_squared.T, least_squares_x_squared)) -#################################################################################################### -# Least squares method for perpendicular SANS geometry -def chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A): + I_residual_error_weight.append(errors[0, 0]) + S_H_error_weight.append(errors[1, 1]) + S_M_error_weight.append(errors[2, 2]) - # Micromagnetic Model - A = abs(A) - mu_0 = 4 * np.pi * 1e-7 - H_i = H_0 - H_dem - l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) - H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) - p = M_s / H_eff - R_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) - R_M = (np.sqrt(1 + p) - 1) / 2 + # Arrayise + S_H = np.array(S_H) + S_M = np.array(S_M) + I_residual = np.array(I_residual) - # Non-negative least squares loop - L_nu = len(q[0, :]) - S_H = np.zeros((1, L_nu)) - S_M = np.zeros((1, L_nu)) - I_res = np.zeros((1, L_nu)) - for nu in np.arange(0, L_nu): - A = np.array([1/sigma[:, nu], R_H[:, nu]/sigma[:, nu], R_M[:, nu]/sigma[:, nu]]).T - y = I_exp[:, nu]/sigma[:, nu] + I_sim = I_residual.reshape(-1, 1) + response_H * S_H.reshape(-1, 1) + response_M * S_M.reshape(-1, 1) - c = np.matmul(A.T, y) - H = np.dot(A.T, A) + s_q = np.mean(((I - I_sim)/I_stdev)**2, axis=1) - # non-negative linear least squares - x = scopt.nnls(H, c) - I_res[0, nu] = x[0][0] - S_H[0, nu] = x[0][1] - S_M[0, nu] = x[0][2] + sigma_I_res = np.sqrt(np.abs(np.array(I_residual_error_weight) * s_q)) + sigma_S_H = np.sqrt(np.abs(np.array(S_H_error_weight) * s_q)) + sigma_S_M = np.sqrt(np.abs(np.array(S_M_error_weight) * s_q)) - I_sim = I_res + R_H * S_H + R_M * S_M - s_q = np.mean(((I_exp - I_sim)/sigma)**2, axis=0) - chi_q = np.mean(s_q) + chi_sq = float(np.mean(s_q)) + + return LeastSquaresOutput( + exchange_A=A, + exchange_A_chi_sq=chi_sq, + q=np.mean(q, axis=1), + I_residual=I_residual, + I_simulated=I_sim, + S_H=S_H, + S_M=S_M, + I_residual_stdev=sigma_I_res, + S_H_stdev=sigma_S_H, + S_M_stdev=sigma_S_M) - return chi_q #################################################################################################### # Sweep over Exchange Stiffness A for perpendicular SANS geometry -def SweepA_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_1, A_2, A_N): +def SweepA_PERP(parameters: FitParameters, data: list[ExperimentalData]): + + a_values = np.linspace( + parameters.exchange_A_min, + parameters.exchange_A_max, + parameters.exchange_A_n) * 1e-12 # From pJ/m to J/m - A = np.linspace(A_1, A_2, A_N) - chi_q = np.zeros(len(A)) - for k in np.arange(0, len(A)): - chi_q[k], I_res, S_H, S_M, sigma_I_res, sigma_S_H, sigma_S_M = LSQ_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A[k]) + least_squared_fits = [LSQ_PERP(data, a) for a in a_values] - min_idx = np.argmin(chi_q) - A_opt = A[min_idx] + optimal_fit = min(least_squared_fits, key=lambda x: x.exchange_A_chi_sq) - chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M = LSQ_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_opt) + chi_sq = np.array([fit.exchange_A_chi_sq for fit in least_squared_fits]) - return A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, sigma_I_res, sigma_S_H, sigma_S_M + return SweepOutput( + exchange_A_checked=a_values, + exchange_A_chi_sq=chi_sq, + optimal=optimal_fit) #################################################################################################### # find optimal Exchange Stiffness A for perpendicular SANS geometry using fsolve function (slow and very accurate) @@ -188,7 +152,7 @@ def func(A): # find optimal Exchange Stiffness A for perpendicular SANS geometry using # successive parabolic interpolation (fast and accurate) # implemented as Jarratt's Method -def OptimA_SPI_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_1, eps): +def OptimA_SPI_PERP(data: list[ExperimentalData], A_1, epsilon): delta = A_1 * 0.1 @@ -196,12 +160,12 @@ def OptimA_SPI_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_1, eps): x_2 = A_1 x_3 = A_1 + delta - y_1 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, x_1) - y_2 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, x_2) - y_3 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, x_3) + y_1 = LSQ_PERP(data, x_1).exchange_A_chi_sq + y_2 = LSQ_PERP(data, x_2).exchange_A_chi_sq + y_3 = LSQ_PERP(data, x_3).exchange_A_chi_sq x_4 = x_3 + 0.5 * ((x_2 - x_3)**2 * (y_3 - y_1) + (x_1 - x_3)**2 * (y_2 - y_3))/((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) - while np.abs(2 * (x_4 - x_3)/(x_4 + x_3)) > eps: + while np.abs(2 * (x_4 - x_3)/(x_4 + x_3)) > epsilon: x_1 = x_2 x_2 = x_3 @@ -209,7 +173,7 @@ def OptimA_SPI_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_1, eps): y_1 = y_2 y_2 = y_3 - y_3 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, x_3) + y_3 = LSQ_PERP(data, x_3).exchange_A_chi_sq x_4 = x_3 + 0.5 * ((x_2 - x_3) ** 2 * (y_3 - y_1) + (x_1 - x_3) ** 2 * (y_2 - y_3)) / ((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) @@ -232,39 +196,47 @@ def SANS_Model_PERP(q, S_H, S_M, I_res, M_s, H_0, H_dem, A): #################################################################################################### # Plot Fitting results of simple fit -def PlotFittingResultsPERP_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, S_M_opt, A_Uncertainty, +def PlotFittingResultsPERP_SimpleFit(z: SweepOutput, A_Uncertainty, figure, axes1, axes2, axes3, axes4): if A_Uncertainty < 1e-4: A_Uncertainty = 0 A_uncertainty_str = str(A_Uncertainty) - A_opt_str = str(A_opt * 1e12) + A_opt_str = str(z.optimal.exchange_A * 1e12) + + q = z.optimal.q * 1e-9 + + # Plot A search data + axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m') - axes1.plot(A * 1e12, chi_q) - axes1.plot(A_opt * 1e12, chi_q_opt, 'o') - axes1.set_xlim([min(A * 1e12), max(A * 1e12)]) + axes1.plot(z.exchange_A_checked * 1e12, z.exchange_A_chi_sq) + axes1.plot(z.optimal.exchange_A * 1e12, z.optimal.exchange_A_chi_sq, 'o') + + axes1.set_xlim([min(z.exchange_A_checked * 1e12), max(z.exchange_A_checked * 1e12)]) axes1.set_xlabel('$A$ [pJ/m]') axes1.set_ylabel('$\chi^2$') - axes2.plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') + # Residual intensity plot + + axes2.plot(q, z.optimal.I_residual, label='fit') axes2.set_yscale('log') axes2.set_xscale('log') - axes2.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axes2.set_xlim([min(q), max(q)]) axes2.set_xlabel('$q$ [1/nm]') axes2.set_ylabel('$I_{\mathrm{res}}$') - axes3.plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') + axes3.plot(q, z.optimal.S_H[0, :], label='fit') axes3.set_yscale('log') axes3.set_xscale('log') - axes3.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axes3.set_xlim([min(q), max(q)]) axes3.set_xlabel('$q$ [1/nm]') axes3.set_ylabel('$S_H$') - axes4.plot(q[0, :] * 1e-9, S_M_opt[0, :], label='fit') + axes4.plot(q, z.optimal.S_M, label='fit') axes4.set_yscale('log') axes4.set_xscale('log') - axes4.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) + axes4.set_xlim([min(q), max(q)]) axes4.set_xlabel('$q$ [1/nm]') axes4.set_ylabel('$S_M$') @@ -283,10 +255,13 @@ def PlotSweepFitResultPERP(q_max_mat, H_min_mat, A_opt_mat): plt.show() #################################################################################################### -# Second Order Derivative of chi-square function via Finite Differences -def FDM2Ord_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_opt): +# +def uncertainty_perp(data: list[ExperimentalData], A_opt: float): + """Calculate the uncertainty for the optimal exchange stiffness A""" + + # Estimate variance from second order derivative of chi-square function via Finite Differences - p = 0.001 + p = 0.001 # fractional gap size for finite differences dA = A_opt * p A1 = A_opt - 2*dA A2 = A_opt - 1*dA @@ -294,12 +269,17 @@ def FDM2Ord_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_opt): A4 = A_opt + 1*dA A5 = A_opt + 2*dA - chi1 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A1) - chi2 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A2) - chi3 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A3) - chi4 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A4) - chi5 = chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A5) + chi1 = LSQ_PERP(data, A1).exchange_A_chi_sq + chi2 = LSQ_PERP(data, A2).exchange_A_chi_sq + chi3 = LSQ_PERP(data, A3).exchange_A_chi_sq + chi4 = LSQ_PERP(data, A4).exchange_A_chi_sq + chi5 = LSQ_PERP(data, A5).exchange_A_chi_sq + + d2chi_dA2 = (-chi1 + 16 * chi2 - 30 * chi3 + 16 * chi4 - chi5)/(12 * dA**2) + + # Scale variance by number of samples and return reciprocal square root - d2_chi_dA2 = (-chi1 + 16 * chi2 - 30 * chi3 + 16 * chi4 - chi5)/(12 * dA**2) + n_field_strengths = len(data) # Number of fields + n_q = len(data[0].scattering_curve.x) # Number of q points - return d2_chi_dA2 \ No newline at end of file + return np.sqrt(2 / (n_field_strengths * n_q * d2chi_dA2)) diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui index c6b39bff25..150f98107e 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -235,16 +235,16 @@ - perpendicular + Perpendicular - perpendicular + Perpendicular - parallel + Parallel diff --git a/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py b/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py index 0aee94cd93..11302de6e4 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py +++ b/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py @@ -22,4 +22,8 @@ def restrict_by_index(self, max_index: int): y = self.scattering_curve.y[:max_index] dy = self.scattering_curve.dy[:max_index] - return Data1D(x=x, y=y, dy=dy) + return ExperimentalData( + scattering_curve=Data1D(x=x, y=y, dy=dy), + applied_field=self.applied_field, + saturation_magnetisation=self.saturation_magnetisation, + demagnetising_field=self.demagnetising_field) diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py b/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py index 20b65ff98b..9828841cf9 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py +++ b/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py @@ -3,12 +3,14 @@ class ExperimentGeometry(Enum): + """ Type of experiment """ PARALLEL = 1 PERPENDICULAR = 2 @dataclass class FitParameters: + """ Input parameters for the fit""" q_max: float min_applied_field: float exchange_A_min: float diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py index b74cad7d46..ad7b800bee 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py +++ b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py @@ -16,7 +16,6 @@ class FitResults: S_H: np.ndarray S_M: np.ndarray - I_residual: np.ndarray # Nuclear + Magnetic cross section at complete magnetic saturation exchange_A: np.ndarray @@ -27,4 +26,3 @@ class FitResults: optimal_A_stdev: float # check geometry: ExperimentGeometry - diff --git a/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py b/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py new file mode 100644 index 0000000000..ec98183b39 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py @@ -0,0 +1,18 @@ +from dataclasses import dataclass + +import numpy as np + + +@dataclass +class LeastSquaresOutput: + """ Output from least squares method""" + exchange_A: float + exchange_A_chi_sq: float + q: np.ndarray + I_simulated: np.ndarray + I_residual: np.ndarray + S_H: np.ndarray + S_M: np.ndarray + I_residual_stdev: np.ndarray + S_H_stdev: np.ndarray + S_M_stdev: np.ndarray \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/models.py b/src/sas/qtgui/Utilities/MuMagTool/models.py new file mode 100644 index 0000000000..49c8781764 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/models.py @@ -0,0 +1,103 @@ + +#################################################################################################### +# Lorentzian Model for the generation of noisy synthetic test data for perpendicular SANS geometry +def LorentzianNoisyModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c, beta): + + # All inputs in SI-units + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2*A)/(mu_0 * M_s * H_i)) + H_eff = H_i * (1 + l_H**2 * q**2) + p = M_s/H_eff + R_H = p**2 / 4 * (2 + 1/np.sqrt(1 + p)) + R_M = (np.sqrt(1 + p) - 1)/2 + + # Lorentzian functions for S_H, S_M + S_H = a_H**2/(1 + q**2 * l_c**2)**2 + S_M = a_M**2/(1 + q**2 * l_c**2)**2 + + # Magnetic SANS cross sections + I_M = R_H * S_H + R_M * S_M + + # Model of I_res + idx = np.argmax(H_0[:, 1]) + I_res = 0.9 * I_M[idx, :] + + # Model of standard deviation + sigma = beta * (I_res + I_M) + + # Total SANS cross section + I_sim = I_res + I_M + sigma * np.random.randn(len(sigma[:, 1]), len(sigma[1, :])) + + return I_sim, sigma, S_H, S_M, I_res + + + + +#################################################################################################### +# Functions for the analysis of parallel SANS ###################################################### +#################################################################################################### +# Lorentzian Model for the generation of clean synthetic test data for perpendicular SANS geometry +def LorentzianModelPAR(q, A, M_s, H_0, H_dem, a_H, l_c): + + # All inputs in SI-units + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 2 + + # Lorentzian functions for S_H, S_M + S_H = a_H**2/(1 + q**2 * l_c**2)**2 + + # Magnetic SANS cross sections + I_M = R_H * S_H + + # Model of I_res + idx = np.argmax(H_0[:, 1]) + I_res = 0.9 * I_M[idx, :] + + # Total SANS cross section + I_sim = I_res + I_M + sigma = 0 * I_sim + 1 + + return I_sim, sigma, S_H, I_res + + +#################################################################################################### +# Functions for the analysis of perpendicular SANS ################################################# +#################################################################################################### +# Lorentzian Model for the generation of clean synthetic test data for perpendicular SANS geometry +def LorentzianModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c): + + # All inputs in SI-units + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2*A)/(mu_0 * M_s * H_i)) + H_eff = H_i * (1 + l_H**2 * q**2) + p = M_s/H_eff + R_H = p**2 / 4 * (2 + 1/np.sqrt(1 + p)) + R_M = (np.sqrt(1 + p) - 1)/2 + + # Lorentzian functions for S_H, S_M + S_H = a_H**2/(1 + q**2 * l_c**2)**2 + S_M = a_M**2/(1 + q**2 * l_c**2)**2 + + # Magnetic SANS cross sections + I_M = R_H * S_H + R_M * S_M + + # Model of I_res + idx = np.argmax(H_0[:, 1]) + print(H_0[idx, 1]*mu_0*1e3) + I_res = 0.9 * I_M[idx, :] + + # Total SANS cross section + I_sim = I_res + I_M + sigma = 0 * I_sim + 1 + + return I_sim, sigma, S_H, S_M, I_res diff --git a/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py b/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py new file mode 100644 index 0000000000..2103579976 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py @@ -0,0 +1,16 @@ +from dataclasses import dataclass + +import numpy as np + +from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutput + + +@dataclass +class SweepOutput: + """ + Results from brute force optimisiation of the chi squared for the exchange A parameter + """ + + exchange_A_checked: np.ndarray + exchange_A_chi_sq: np.ndarray + optimal: LeastSquaresOutput \ No newline at end of file From 717a41951b78b96ee10a4da565bd9ae6a0acbc78 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Thu, 6 Jun 2024 17:05:27 +0100 Subject: [PATCH 30/46] Debugging --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 11 ++++++-- .../MuMagTool/MuMagPerpendicularGeo.py | 26 +++++++++---------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index c695c87d20..5a8da62185 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -66,6 +66,13 @@ def plot_experimental_data_button_callback(self): self.figure_canvas.draw() def fit_parameters(self) -> FitParameters: + """ Get an object containing all the parameters needed for doing the fitting """ + + a_min = self.aMinSpinBox.value() + a_max = self.aMaxSpinBox.value() + + if a_max <= a_min: + raise ValueError(f"minimum A must be less than maximum A") match self.ScatteringGeometrySelect.currentText().lower(): case "parallel": @@ -78,9 +85,9 @@ def fit_parameters(self) -> FitParameters: return FitParameters( q_max=self.qMaxSpinBox.value(), min_applied_field=self.hMinSpinBox.value(), - exchange_A_min=self.aMinSpinBox.value(), - exchange_A_max=self.aMaxSpinBox.value(), exchange_A_n=self.aSamplesSpinBox.value(), + exchange_A_min=a_min, + exchange_A_max=a_max, experiment_geometry=geometry) def simple_fit_button_callback(self): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py index ee841b424e..5fe0a55ebd 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py @@ -47,13 +47,6 @@ def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: response_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) response_M = (np.sqrt(1 + p) - 1) / 2 - print("Shapes:") - print(" I", I.shape) - print(" q", q.shape) - print(" sigma", I_stdev.shape) - print(" response H", response_H.shape) - print(" response M", response_M.shape) - # Lists for output of calculation I_residual = [] S_H = [] @@ -71,15 +64,20 @@ def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: least_squares_x = (np.array([np.ones((n_data,)), response_H[:, nu], response_M[:, nu]]) / I_stdev[:, nu]).T least_squares_y = I[:, nu]/I_stdev[:, nu] - print("Least Squares X", least_squares_x.shape) - print("Least Squares Y", least_squares_y.shape) - least_squares_x_squared = np.dot(least_squares_x.T, least_squares_x) # Non-negative least squares - fit_result = scopt.nnls( - least_squares_x_squared, - np.matmul(least_squares_x.T, least_squares_y)) + try: + fit_result = scopt.nnls( + least_squares_x_squared, + np.matmul(least_squares_x.T, least_squares_y)) + + except ValueError as ve: + print("Value Error:") + print(" A =", A) + + raise ve + I_residual.append(fit_result[0][0]) S_H.append(fit_result[0][1]) @@ -167,6 +165,8 @@ def OptimA_SPI_PERP(data: list[ExperimentalData], A_1, epsilon): x_4 = x_3 + 0.5 * ((x_2 - x_3)**2 * (y_3 - y_1) + (x_1 - x_3)**2 * (y_2 - y_3))/((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) while np.abs(2 * (x_4 - x_3)/(x_4 + x_3)) > epsilon: + print("x1,x2,x3,x4:", x_1, x_2, x_3, x_4) + x_1 = x_2 x_2 = x_3 x_3 = x_4 From 725983373ba3d1cdd99f9ad34df03593de290213 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Fri, 7 Jun 2024 13:36:30 +0100 Subject: [PATCH 31/46] Debugged, starting on parallel case --- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 2 +- .../MuMagTool/MuMagPerpendicularGeo.py | 72 ++++++++++--------- .../MuMagTool/least_squares_output.py | 16 ++++- src/sas/qtgui/Utilities/MuMagTool/models.py | 31 ++++---- .../qtgui/Utilities/MuMagTool/sweep_output.py | 2 +- 5 files changed, 71 insertions(+), 52 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index f91825870a..235ab38c82 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -144,7 +144,7 @@ def simple_fit_button_callback(self, parameters: FitParameters, figure, axes1, a filtered_inputs = [datum.restrict_by_index(max_q_index) for datum in self.input_data - if datum.applied_field > parameters.min_applied_field] + if datum.applied_field >= parameters.min_applied_field] # Least Squares Fit in case of perpendicular SANS geometry diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py index 5fe0a55ebd..45778671a9 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py @@ -1,11 +1,15 @@ +import sys + import numpy as np import scipy.optimize as scopt import matplotlib.pyplot as plt +from sasdata.dataloader import Data1D +from data_util.nxsunit import Converter from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults -from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutput +from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutput, LeastSquaresOutputPerpendicular from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput mu_0 = 4 * np.pi * 1e-7 @@ -24,18 +28,32 @@ def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: """ + + # Get matrices from the input data n_data = len(data) - applied_field = np.array([datum.applied_field for datum in data]) - demagnetising_field = np.array([datum.demagnetising_field for datum in data]) - saturation_magnetisation = np.array([datum.saturation_magnetisation for datum in data]) + # Factor of (1e-3 / mu_0) converts from mT to A/m + applied_field = np.array([datum.applied_field for datum in data]) * (1e-3 / mu_0) + demagnetising_field = np.array([datum.demagnetising_field for datum in data]) * (1e-3 / mu_0) + saturation_magnetisation = np.array([datum.saturation_magnetisation for datum in data]) * (1e-3 / mu_0) + + # TODO: The following is how things should be done in the future, rather than hard-coding + # a scaling factor... + # def data_nanometers(data: Data1D): + # raw_data = data.x + # units = data.x_unit + # converter = Converter(units) + # return converter.scale("1/m", raw_data) + # + # q = np.array([data_nanometers(datum.scattering_curve) for datum in data]) - q = np.array([datum.scattering_curve.x for datum in data]) # TODO: Check for transpose + + q = np.array([datum.scattering_curve.x for datum in data]) * 1e9 I = np.array([datum.scattering_curve.y for datum in data]) I_stdev = np.array([datum.scattering_curve.dy for datum in data]) - n_q = q.shape[0] + n_q = q.shape[1] # Micromagnetic Model internal_field = (applied_field - demagnetising_field).reshape(-1, 1) @@ -47,6 +65,9 @@ def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: response_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) response_M = (np.sqrt(1 + p) - 1) / 2 + # print("Input", q.shape, q[0,10]) + # sys.exit() + # Lists for output of calculation I_residual = [] S_H = [] @@ -89,14 +110,15 @@ def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: S_H_error_weight.append(errors[1, 1]) S_M_error_weight.append(errors[2, 2]) + # Arrayise S_H = np.array(S_H) S_M = np.array(S_M) I_residual = np.array(I_residual) - I_sim = I_residual.reshape(-1, 1) + response_H * S_H.reshape(-1, 1) + response_M * S_M.reshape(-1, 1) + I_sim = I_residual + response_H * S_H + response_M * S_M - s_q = np.mean(((I - I_sim)/I_stdev)**2, axis=1) + s_q = np.mean(((I - I_sim)/I_stdev)**2, axis=0) sigma_I_res = np.sqrt(np.abs(np.array(I_residual_error_weight) * s_q)) sigma_S_H = np.sqrt(np.abs(np.array(S_H_error_weight) * s_q)) @@ -104,10 +126,12 @@ def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: chi_sq = float(np.mean(s_q)) - return LeastSquaresOutput( + output_q_values = np.mean(q, axis=0) + + return LeastSquaresOutputPerpendicular( exchange_A=A, exchange_A_chi_sq=chi_sq, - q=np.mean(q, axis=1), + q=output_q_values, I_residual=I_residual, I_simulated=I_sim, S_H=S_H, @@ -119,7 +143,7 @@ def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: #################################################################################################### # Sweep over Exchange Stiffness A for perpendicular SANS geometry -def SweepA_PERP(parameters: FitParameters, data: list[ExperimentalData]): +def SweepA_PERP(parameters: FitParameters, data: list[ExperimentalData]) -> SweepOutput: a_values = np.linspace( parameters.exchange_A_min, @@ -137,14 +161,6 @@ def SweepA_PERP(parameters: FitParameters, data: list[ExperimentalData]): exchange_A_chi_sq=chi_sq, optimal=optimal_fit) -#################################################################################################### -# find optimal Exchange Stiffness A for perpendicular SANS geometry using fsolve function (slow and very accurate) -def OptimA_fsolve_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A_initial): - - def func(A): - return chi_q_PERP(q, I_exp, sigma, M_s, H_0, H_dem, A) - - return scopt.fsolve(func, A_initial) #################################################################################################### # find optimal Exchange Stiffness A for perpendicular SANS geometry using @@ -165,7 +181,7 @@ def OptimA_SPI_PERP(data: list[ExperimentalData], A_1, epsilon): x_4 = x_3 + 0.5 * ((x_2 - x_3)**2 * (y_3 - y_1) + (x_1 - x_3)**2 * (y_2 - y_3))/((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) while np.abs(2 * (x_4 - x_3)/(x_4 + x_3)) > epsilon: - print("x1,x2,x3,x4:", x_1, x_2, x_3, x_4) + # print("x1,x2,x3,x4:", x_1, x_2, x_3, x_4) x_1 = x_2 x_2 = x_3 @@ -179,20 +195,6 @@ def OptimA_SPI_PERP(data: list[ExperimentalData], A_1, epsilon): return x_4 -#################################################################################################### -# 1D-Cross-Section of the perendicular model -def SANS_Model_PERP(q, S_H, S_M, I_res, M_s, H_0, H_dem, A): - - # Micromagnetic Model - mu_0 = 4 * np.pi * 1e-7 - H_i = H_0 - H_dem - l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) - H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) - p = M_s / H_eff - R_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) - R_M = (np.sqrt(1 + p) - 1) / 2 - - return I_res + R_H * S_H + R_M * S_M #################################################################################################### # Plot Fitting results of simple fit @@ -226,7 +228,7 @@ def PlotFittingResultsPERP_SimpleFit(z: SweepOutput, A_Uncertainty, axes2.set_xlabel('$q$ [1/nm]') axes2.set_ylabel('$I_{\mathrm{res}}$') - axes3.plot(q, z.optimal.S_H[0, :], label='fit') + axes3.plot(q, z.optimal.S_H, label='fit') axes3.set_yscale('log') axes3.set_xscale('log') axes3.set_xlim([min(q), max(q)]) diff --git a/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py b/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py index ec98183b39..16f48b3ff6 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py +++ b/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py @@ -12,7 +12,19 @@ class LeastSquaresOutput: I_simulated: np.ndarray I_residual: np.ndarray S_H: np.ndarray - S_M: np.ndarray I_residual_stdev: np.ndarray S_H_stdev: np.ndarray - S_M_stdev: np.ndarray \ No newline at end of file + + +@dataclass +class LeastSquaresOutputParallel(LeastSquaresOutput): + """ Output from least squares method for parallel case""" + pass + + +@dataclass +class LeastSquaresOutputPerpendicular(LeastSquaresOutput): + """ Output from least squares method for perpendicular case""" + S_M: np.ndarray + S_M_stdev: np.ndarray + diff --git a/src/sas/qtgui/Utilities/MuMagTool/models.py b/src/sas/qtgui/Utilities/MuMagTool/models.py index 49c8781764..f1fee8d004 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/models.py +++ b/src/sas/qtgui/Utilities/MuMagTool/models.py @@ -1,8 +1,7 @@ +import numpy as np -#################################################################################################### -# Lorentzian Model for the generation of noisy synthetic test data for perpendicular SANS geometry def LorentzianNoisyModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c, beta): - + """ Lorentzian Model for the generation of noisy synthetic test data for perpendicular SANS geometry """ # All inputs in SI-units # Micromagnetic Model @@ -34,13 +33,8 @@ def LorentzianNoisyModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c, beta): return I_sim, sigma, S_H, S_M, I_res - - -#################################################################################################### -# Functions for the analysis of parallel SANS ###################################################### -#################################################################################################### -# Lorentzian Model for the generation of clean synthetic test data for perpendicular SANS geometry def LorentzianModelPAR(q, A, M_s, H_0, H_dem, a_H, l_c): + """ Lorentzian Model for the generation of clean synthetic test data for parallel SANS geometry""" # All inputs in SI-units # Micromagnetic Model @@ -68,11 +62,8 @@ def LorentzianModelPAR(q, A, M_s, H_0, H_dem, a_H, l_c): return I_sim, sigma, S_H, I_res -#################################################################################################### -# Functions for the analysis of perpendicular SANS ################################################# -#################################################################################################### -# Lorentzian Model for the generation of clean synthetic test data for perpendicular SANS geometry def LorentzianModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c): + """ Lorentzian Model for the generation of clean synthetic test data for perpendicular SANS geometry""" # All inputs in SI-units # Micromagnetic Model @@ -101,3 +92,17 @@ def LorentzianModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c): sigma = 0 * I_sim + 1 return I_sim, sigma, S_H, S_M, I_res + +def SANS_Model_PERP(q, S_H, S_M, I_res, M_s, H_0, H_dem, A): + """ 1D-Cross-Section of the perendicular model """ + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) + R_M = (np.sqrt(1 + p) - 1) / 2 + + return I_res + R_H * S_H + R_M * S_M diff --git a/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py b/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py index 2103579976..7b33bb41c3 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py +++ b/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py @@ -2,7 +2,7 @@ import numpy as np -from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutput +from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputParallel, LeastSquaresOutputPerpendicular @dataclass From 3068a81159cc807d7ac70e47e6618d50bbdd988f Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Fri, 7 Jun 2024 16:36:06 +0100 Subject: [PATCH 32/46] Calculations now working --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 2 +- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 205 ++++++++++++---- .../Utilities/MuMagTool/MuMagParallelGeo.py | 230 +++++++----------- .../MuMagTool/MuMagPerpendicularGeo.py | 51 ++-- ...1_8000_1600_1.csv => 1_8000_1600_1070.csv} | 0 ...10000_1600_1.csv => 2_10000_1600_1070.csv} | 0 ...12000_1600_1.csv => 3_12000_1600_1070.csv} | 0 ...14000_1600_1.csv => 4_14000_1600_1070.csv} | 0 ...16000_1600_1.csv => 5_16000_1600_1070.csv} | 0 src/sas/qtgui/Utilities/MuMagTool/failure.py | 5 + src/sas/qtgui/Utilities/MuMagTool/models.py | 13 + .../qtgui/Utilities/MuMagTool/sweep_output.py | 10 +- 12 files changed, 290 insertions(+), 226 deletions(-) rename src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/{1_8000_1600_1.csv => 1_8000_1600_1070.csv} (100%) rename src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/{2_10000_1600_1.csv => 2_10000_1600_1070.csv} (100%) rename src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/{3_12000_1600_1.csv => 3_12000_1600_1070.csv} (100%) rename src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/{4_14000_1600_1.csv => 4_14000_1600_1070.csv} (100%) rename src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/{5_16000_1600_1.csv => 5_16000_1600_1070.csv} (100%) create mode 100644 src/sas/qtgui/Utilities/MuMagTool/failure.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 5a8da62185..da3c17ea18 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -117,7 +117,7 @@ def simple_fit_button_callback(self): raise ValueError(f"Unknown Value: {parameters.experiment_geometry}") - self.MuMagLib_obj.simple_fit_button_callback( + self.MuMagLib_obj.do_fit( parameters, self.fig, self.chi_squared_axes, diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 235ab38c82..fb06bf32a6 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -17,8 +17,13 @@ from sas.qtgui.Utilities.MuMagTool import MuMagParallelGeo from sas.qtgui.Utilities.MuMagTool import MuMagPerpendicularGeo +from sas.qtgui.Utilities.MuMagTool.MuMagParallelGeo import LSQ_PAR +from sas.qtgui.Utilities.MuMagTool.MuMagPerpendicularGeo import LSQ_PERP from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry +from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular, \ + LeastSquaresOutputParallel +from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput from sasdata.dataloader.loader import Loader @@ -128,7 +133,8 @@ def plot_exp_data(self, figure, axes): figure.canvas.draw() - def simple_fit_button_callback(self, parameters: FitParameters, figure, axes1, axes2, axes3, axes4): + # @staticmethod + def do_fit(self, parameters: FitParameters, figure, axes1, axes2, axes3, axes4): if self.input_data is None: messagebox.showerror(title="Error!", @@ -152,18 +158,34 @@ def simple_fit_button_callback(self, parameters: FitParameters, figure, axes1, a case ExperimentGeometry.PERPENDICULAR: - sweep_data = MuMagPerpendicularGeo.SweepA_PERP(parameters, filtered_inputs) + sweep_data = MuMagPerpendicularGeo.sweep(parameters, filtered_inputs) - A_opt = MuMagPerpendicularGeo.OptimA_SPI_PERP(filtered_inputs, sweep_data.optimal.exchange_A, epsilon=0.0001) + crude_A = sweep_data.optimal.exchange_A + refined_A = self.refine_exchange_A(filtered_inputs, crude_A, ExperimentGeometry.PERPENDICULAR) - least_squares_fit_at_optimum = MuMagPerpendicularGeo.LSQ_PERP(filtered_inputs, A_opt) + refined = MuMagPerpendicularGeo.LSQ_PERP(filtered_inputs, refined_A) - I_opt = least_squares_fit_at_optimum.I_simulated + uncertainty = self.uncertainty(filtered_inputs, refined_A, ExperimentGeometry.PERPENDICULAR) - uncertainty = MuMagPerpendicularGeo.uncertainty_perp(filtered_inputs, A_opt) + self.plot_results(sweep_data, refined, uncertainty * 1e12, figure, axes1, axes2, axes3, axes4) - MuMagPerpendicularGeo.PlotFittingResultsPERP_SimpleFit(sweep_data, uncertainty * 1e12, - figure, axes1, axes2, axes3, axes4) + + + case ExperimentGeometry.PARALLEL: + + + sweep_data = MuMagPerpendicularGeo.sweep(parameters, filtered_inputs) + + crude_A = sweep_data.optimal.exchange_A + print(crude_A) + refined_A = self.refine_exchange_A(filtered_inputs, parameters.exchange_A_min*1e-12, ExperimentGeometry.PARALLEL) + + refined = MuMagPerpendicularGeo.LSQ_PAR(filtered_inputs, refined_A) + + uncertainty = self.uncertainty(filtered_inputs, refined_A, ExperimentGeometry.PARALLEL) + + self.plot_results(sweep_data, refined, uncertainty * 1e12, + figure, axes1, axes2, axes3, axes4) # Save to global Variables # self.SimpleFit_q_exp = q @@ -176,55 +198,94 @@ def simple_fit_button_callback(self, parameters: FitParameters, figure, axes1, a # self.SimpleFit_A = A # self.SimpleFit_chi_q = chi_q # self.SimpleFit_S_H_fit = S_H_opt - # self.SimpleFit_S_M_fit = S_M_opt # self.SimpleFit_I_res_fit = I_res_opt # self.SimpleFit_A_opt = A_opt # self.SimpleFit_chi_q_opt = chi_q_opt # self.SimpleFit_A_sigma = A_Uncertainty - # self.SimpleFit_SANSgeometry = "perpendicular" + # self.SimpleFit_SANSgeometry = "parallel" + + @staticmethod + def refine_exchange_A( + data: list[ExperimentalData], + exchange_A_initial: float, + geometry: ExperimentGeometry, + epsilon: float = 0.0001): + """ Refines the A parameter using Jarratt's method of successive parabolic interpolation""" + + match geometry: case ExperimentGeometry.PARALLEL: + least_squares_function = LSQ_PAR + case ExperimentGeometry.PERPENDICULAR: + least_squares_function = LSQ_PERP + case _: + raise ValueError(f"Unknown experimental geometry: {geometry}") - A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H \ - = MuMagParallelGeo.SweepA_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_min, A_max_J, A_N) + delta = exchange_A_initial * 0.1 - A_opt = MuMagParallelGeo.OptimA_SPI_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_min, 0.0001) - chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = MuMagParallelGeo.LSQ_PAR(q, I_exp_red, sigma, - Ms, H_0, - H_dem, - A_opt) + x_1 = exchange_A_initial - delta + x_2 = exchange_A_initial + x_3 = exchange_A_initial + delta - I_opt = MuMagParallelGeo.SANS_Model_PAR(q, S_H_opt, I_res_opt, Ms, H_0, H_dem, A_opt) + y_1 = least_squares_function(data, x_1).exchange_A_chi_sq + y_2 = least_squares_function(data, x_2).exchange_A_chi_sq + y_3 = least_squares_function(data, x_3).exchange_A_chi_sq - d2chi_dA2 = MuMagParallelGeo.FDM2Ord_PAR(q, I_exp_red, sigma, Ms, H_0, H_dem, A_opt) - n_field_strengths = len(I_exp_red[0, :]) - n_q = len(I_exp_red[:, 0]) - A_Uncertainty = np.sqrt(2 / (n_field_strengths * n_q * d2chi_dA2)) + x_4 = x_3 + 0.5 * ((x_2 - x_3) ** 2 * (y_3 - y_1) + (x_1 - x_3) ** 2 * (y_2 - y_3)) \ + / ((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) - MuMagParallelGeo.PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, - I_res_opt, S_H_opt, A_Uncertainty * 1e12, - figure, axes1, axes2, axes3, axes4) + for i in range(200): + if np.abs(2 * (x_4 - x_3) / (x_4 + x_3)) < epsilon: + break + + x_1, x_2, x_3 = x_2, x_3, x_4 + y_1, y_2, y_3 = y_2, y_3, least_squares_function(data, x_3).exchange_A_chi_sq + + x_4 = x_3 + 0.5 * ((x_2 - x_3) ** 2 * (y_3 - y_1) + (x_1 - x_3) ** 2 * (y_2 - y_3)) \ + / ((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) + + return x_4 + + @staticmethod + def uncertainty( + data: list[ExperimentalData], + A_opt: float, + geometry: ExperimentGeometry): + """Calculate the uncertainty for the optimal exchange stiffness A""" + + # Estimate variance from second order derivative of chi-square function via Finite Differences + + match geometry: + case ExperimentGeometry.PARALLEL: + least_squares_function = LSQ_PAR + case ExperimentGeometry.PERPENDICULAR: + least_squares_function = LSQ_PERP + case _: + raise ValueError(f"Unknown experimental geometry: {geometry}") + + p = 0.001 # fractional gap size for finite differences + dA = A_opt * p + A1 = A_opt - 2 * dA + A2 = A_opt - 1 * dA + A3 = A_opt + A4 = A_opt + 1 * dA + A5 = A_opt + 2 * dA + + chi1 = least_squares_function(data, A1).exchange_A_chi_sq + chi2 = least_squares_function(data, A2).exchange_A_chi_sq + chi3 = least_squares_function(data, A3).exchange_A_chi_sq + chi4 = least_squares_function(data, A4).exchange_A_chi_sq + chi5 = least_squares_function(data, A5).exchange_A_chi_sq + + d2chi_dA2 = (-chi1 + 16 * chi2 - 30 * chi3 + 16 * chi4 - chi5) / (12 * dA ** 2) + + # Scale variance by number of samples and return reciprocal square root + + n_field_strengths = len(data) # Number of fields + n_q = len(data[0].scattering_curve.x) # Number of q points + + return np.sqrt(2 / (n_field_strengths * n_q * d2chi_dA2)) - # Save to global Variables - self.SimpleFit_q_exp = q - self.SimpleFit_I_exp = I_exp_red - self.SimpleFit_sigma_exp = sigma - self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] - self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] - self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] - self.SimpleFit_I_fit = I_opt - self.SimpleFit_A = A - self.SimpleFit_chi_q = chi_q - self.SimpleFit_S_H_fit = S_H_opt - self.SimpleFit_I_res_fit = I_res_opt - self.SimpleFit_A_opt = A_opt - self.SimpleFit_chi_q_opt = chi_q_opt - self.SimpleFit_A_sigma = A_Uncertainty - self.SimpleFit_SANSgeometry = "parallel" - - - -###################################################################################################################### def save_button_callback(self): SimpleFit_q_exp = self.SimpleFit_q_exp @@ -355,8 +416,60 @@ def save_button_callback(self): else: messagebox.showerror(title="Error!", message="No SimpleFit results available!") + @staticmethod + def plot_results(sweep_data: SweepOutput, + refined: LeastSquaresOutputPerpendicular | LeastSquaresOutputParallel, + A_Uncertainty, + figure, axes1, axes2, axes3, axes4): + + if A_Uncertainty < 1e-4: + A_Uncertainty = 0 + + A_uncertainty_str = str(A_Uncertainty) + A_opt_str = str(refined.exchange_A * 1e12) + + q = refined.q * 1e-9 + + # Plot A search data + + axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m') + axes1.plot(sweep_data.exchange_A_checked * 1e12, sweep_data.exchange_A_chi_sq) + axes1.plot(sweep_data.optimal.exchange_A * 1e12, sweep_data.optimal.exchange_A_chi_sq, 'o') + + axes1.set_xlim([min(sweep_data.exchange_A_checked * 1e12), max(sweep_data.exchange_A_checked * 1e12)]) + axes1.set_xlabel('$A$ [pJ/m]') + axes1.set_ylabel('$\chi^2$') + + # Residual intensity plot + + axes2.plot(q, refined.I_residual, label='fit') + axes2.set_yscale('log') + axes2.set_xscale('log') + axes2.set_xlim([min(q), max(q)]) + axes2.set_xlabel('$q$ [1/nm]') + axes2.set_ylabel('$I_{\mathrm{res}}$') + + # S_H parameter + + axes3.plot(q, refined.S_H, label='fit') + axes3.set_yscale('log') + axes3.set_xscale('log') + axes3.set_xlim([min(q), max(q)]) + axes3.set_xlabel('$q$ [1/nm]') + axes3.set_ylabel('$S_H$') + + # S_M parameter + if isinstance(refined, LeastSquaresOutputPerpendicular): + axes4.plot(q, refined.S_M, label='fit') + axes4.set_yscale('log') + axes4.set_xscale('log') + axes4.set_xlim([min(q), max(q)]) + axes4.set_xlabel('$q$ [1/nm]') + axes4.set_ylabel('$S_M$') + + figure.tight_layout() -################################################################################################################# + ################################################################################################################# def SimpleFit_CompareButtonCallback(self, figure, axes): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py index eb14e30e01..8ce7fbb537 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py @@ -2,185 +2,131 @@ import scipy.optimize as scopt import matplotlib.pyplot as plt +from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData +from sas.qtgui.Utilities.MuMagTool.fit_parameters import ExperimentGeometry +from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputParallel, \ + LeastSquaresOutputPerpendicular +from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput -#################################################################################################### -# Least squares method for parallel SANS geometry -def LSQ_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A): +mu_0 = 4 * np.pi * 1e-7 - # Micromagnetic Model - mu_0 = 4 * np.pi * 1e-7 - H_i = H_0 - H_dem - l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) - H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) - p = M_s / H_eff - R_H = (p ** 2) / 2 - - # Non-negative least squares loop - L_nu = len(q[1, :]) - S_H = np.zeros((1, L_nu)) - I_res = np.zeros((1, L_nu)) - sigma_S_H = np.zeros((1, L_nu)) - sigma_I_res = np.zeros((1, L_nu)) - for nu in np.arange(0, L_nu): - A = np.array([1/sigma[:, nu], R_H[:, nu]/sigma[:, nu]]).T - y = I_exp[:, nu]/sigma[:, nu] - c = np.matmul(A.T, y) - H = np.dot(A.T, A) +def LSQ_PAR(data: list[ExperimentalData], A): - # non-negative linear least squares - x = scopt.nnls(H, c) - I_res[0, nu] = x[0][0] - S_H[0, nu] = x[0][1] + """ Least squares fitting for a given exchange stiffness, A, parallel case - Gamma = np.linalg.inv(np.dot(H.T, H)) - sigma_I_res[0, nu] = Gamma[0, 0] - sigma_S_H[0, nu] = Gamma[1, 1] + We are fitting the equation: - I_sim = I_res + R_H * S_H - s_q = np.mean(((I_exp - I_sim)/sigma)**2, axis=0) + I_sim = I_res + response_H * S_H + = (I_res, S_H) . (1, response_H) + = (I_res, S_H) . least_squares_x - sigma_S_H = np.sqrt(np.abs(sigma_S_H * s_q)) - sigma_I_res = np.sqrt(np.abs(sigma_I_res * s_q)) + finding I_res and S_H for each q value - chi_q = np.mean(s_q) - return chi_q, I_res, S_H, sigma_I_res, sigma_S_H + """ -#################################################################################################### -# Least squares method for parallel SANS geometry -def chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A): + # Get matrices from the input data + n_data = len(data) + + # Factor of (1e-3 / mu_0) converts from mT to A/m + applied_field = np.array([datum.applied_field for datum in data]) * (1e-3 / mu_0) + demagnetising_field = np.array([datum.demagnetising_field for datum in data]) * (1e-3 / mu_0) + saturation_magnetisation = np.array([datum.saturation_magnetisation for datum in data]) * (1e-3 / mu_0) + + # TODO: The following is how things should be done in the future, rather than hard-coding + # a scaling factor... + # def data_nanometers(data: Data1D): + # raw_data = data.x + # units = data.x_unit + # converter = Converter(units) + # return converter.scale("1/m", raw_data) + # + # q = np.array([data_nanometers(datum.scattering_curve) for datum in data]) + + q = np.array([datum.scattering_curve.x for datum in data]) * 1e9 + I = np.array([datum.scattering_curve.y for datum in data]) + I_stdev = np.array([datum.scattering_curve.dy for datum in data]) + + n_q = q.shape[1] # Micromagnetic Model - mu_0 = 4 * np.pi * 1e-7 - H_i = H_0 - H_dem - l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) - H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) - p = M_s / H_eff - R_H = (p ** 2) / 2 - - # Non-negative least squares loop - L_nu = len(q[0, :]) - S_H = np.zeros((1, L_nu)) - I_res = np.zeros((1, L_nu)) - for nu in np.arange(0, L_nu): - A = np.array([1/sigma[:, nu], R_H[:, nu]/sigma[:, nu]]).T - y = I_exp[:, nu]/sigma[:, nu] - - c = np.matmul(A.T, y) - H = np.dot(A.T, A) + internal_field = (applied_field - demagnetising_field).reshape(-1, 1) + magnetic_scattering_length = np.sqrt((2 * A) / (mu_0 * saturation_magnetisation.reshape(-1, 1) * internal_field)) + effective_field = internal_field * (1 + (magnetic_scattering_length ** 2) * (q ** 2)) - # non-negative linear least squares - x = scopt.nnls(H, c) - I_res[0, nu] = x[0][0] - S_H[0, nu] = x[0][1] + # Calculate the response functions + p = saturation_magnetisation.reshape(-1, 1) / effective_field + response_H = (p ** 2) / 2 - I_sim = I_res + R_H * S_H - s_q = np.mean(((I_exp - I_sim)/sigma)**2, axis=0) - chi_q = np.mean(s_q) + # print("Input", q.shape, q[0,10]) + # sys.exit() - return chi_q + # Lists for output of calculation + I_residual = [] + S_H = [] -#################################################################################################### -# Sweep over Exchange Stiffness A for parallel SANS geometry -def SweepA_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_1, A_2, A_N): + I_residual_error_weight = [] + S_H_error_weight = [] - A = np.linspace(A_1, A_2, A_N) * 1e-12 # pJ/m -> J/m - chi_q = np.zeros(len(A)) - for k in np.arange(0, len(A)): - chi_q[k], I_res, S_H, sigma_I_res, sigma_S_H = LSQ_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A[k]) + for nu in range(n_q): - min_idx = np.argmin(chi_q) - A_opt = A[min_idx] + # non-negative linear least squares + least_squares_x = (np.array([np.ones((n_data,)), response_H[:, nu]]) / I_stdev[:, nu]).T + least_squares_y = I[:, nu] / I_stdev[:, nu] - chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H = LSQ_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_opt) + least_squares_x_squared = np.dot(least_squares_x.T, least_squares_x) - return A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, sigma_I_res, sigma_S_H + # Non-negative least squares + try: + fit_result = scopt.nnls( + least_squares_x_squared, + np.matmul(least_squares_x.T, least_squares_y)) -#################################################################################################### -# find optimal Exchange Stiffness A for parallel SANS geometry using fsolve function (slow and very accurate) -def OptimA_fsolve_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_initial): + except ValueError as ve: + print("Value Error:") + print(" A =", A) - def func(A): - return chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A) + raise ve - return scopt.fsolve(func, A_initial) + I_residual.append(fit_result[0][0]) + S_H.append(fit_result[0][1]) -#################################################################################################### -# find optimal Exchange Stiffness A for parallel SANS geometry using successive parabolic interpolation (fast and accurate) -# implemented as Jarratt's Method -def OptimA_SPI_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_1, eps): + errors = np.linalg.inv(np.dot(least_squares_x_squared.T, least_squares_x_squared)) - delta = A_1 * 0.1 + I_residual_error_weight.append(errors[0, 0]) + S_H_error_weight.append(errors[1, 1]) - x_1 = A_1 - delta - x_2 = A_1 - x_3 = A_1 + delta + # Arrayise + S_H = np.array(S_H) + I_residual = np.array(I_residual) - y_1 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, x_1) - y_2 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, x_2) - y_3 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, x_3) + I_sim = I_residual + response_H * S_H - x_4 = x_3 + 0.5 * ((x_2 - x_3)**2 * (y_3 - y_1) + (x_1 - x_3)**2 * (y_2 - y_3))/((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) - while np.abs(2 * (x_4 - x_3)/(x_4 + x_3)) > eps: + s_q = np.mean(((I - I_sim) / I_stdev) ** 2, axis=0) - x_1 = x_2 - x_2 = x_3 - x_3 = x_4 + sigma_I_res = np.sqrt(np.abs(np.array(I_residual_error_weight) * s_q)) + sigma_S_H = np.sqrt(np.abs(np.array(S_H_error_weight) * s_q)) - y_1 = y_2 - y_2 = y_3 - y_3 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, x_3) + chi_sq = float(np.mean(s_q)) - x_4 = x_3 + 0.5 * ((x_2 - x_3) ** 2 * (y_3 - y_1) + (x_1 - x_3) ** 2 * (y_2 - y_3)) / ((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) + output_q_values = np.mean(q, axis=0) - return x_4 + return LeastSquaresOutputParallel( + exchange_A=A, + exchange_A_chi_sq=chi_sq, + q=output_q_values, + I_residual=I_residual, + I_simulated=I_sim, + S_H=S_H, + I_residual_stdev=sigma_I_res, + S_H_stdev=sigma_S_H) -#################################################################################################### -# 1D-Cross-Section of the parallel model -def SANS_Model_PAR(q, S_H, I_res, M_s, H_0, H_dem, A): - # Micromagnetic Model - mu_0 = 4 * np.pi * 1e-7 - H_i = H_0 - H_dem - l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) - H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) - p = M_s / H_eff - R_H = (p ** 2) / 2 +#################################################################################################### - return I_res + R_H * S_H #################################################################################################### # Plot Fitting results of simple fit -def PlotFittingResultsPAR_SimpleFit(q, A, chi_q, A_opt, chi_q_opt, I_res_opt, S_H_opt, A_Uncertainty, - figure, axes1, axes2, axes3, axes4): - - if A_Uncertainty < 1e-4: - A_Uncertainty = 0 - - A_uncertainty_str = str(A_Uncertainty) - A_opt_str = str(A_opt * 1e12) - axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m') - axes1.plot(A * 1e12, chi_q) - axes1.plot(A_opt * 1e12, chi_q_opt, 'o') - axes1.set_xlim([min(A * 1e12), max(A * 1e12)]) - axes1.set_xlabel('$A$ [pJ/m]') - axes1.set_ylabel('$\chi^2$') - - axes2.plot(q[0, :] * 1e-9, I_res_opt[0, :], label='fit') - axes2.set_yscale('log') - axes2.set_xscale('log') - axes2.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axes2.set_xlabel('$q$ [1/nm]') - axes2.set_ylabel('$I_{\mathrm{res}}$') - - axes3.plot(q[0, :] * 1e-9, S_H_opt[0, :], label='fit') - axes3.set_yscale('log') - axes3.set_xscale('log') - axes3.set_xlim([min(q[0, :] * 1e-9), max(q[0, :] * 1e-9)]) - axes3.set_xlabel('$q$ [1/nm]') - axes3.set_ylabel('$S_H$') - - figure.tight_layout() #################################################################################################### def PlotSweepFitResultPAR(q_max_mat, H_min_mat, A_opt_mat): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py index 45778671a9..0ad250d1de 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py @@ -4,18 +4,19 @@ import scipy.optimize as scopt import matplotlib.pyplot as plt +from sas.qtgui.Utilities.MuMagTool.MuMagParallelGeo import LSQ_PAR from sasdata.dataloader import Data1D from data_util.nxsunit import Converter from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters +from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutput, LeastSquaresOutputPerpendicular from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput mu_0 = 4 * np.pi * 1e-7 -def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: - """ Least squares fitting for a given exchange stiffness, A +def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutputPerpendicular: + """ Least squares fitting for a given exchange stiffness, A, perpendicular case We are fitting the equation: @@ -142,15 +143,24 @@ def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutput: #################################################################################################### -# Sweep over Exchange Stiffness A for perpendicular SANS geometry -def SweepA_PERP(parameters: FitParameters, data: list[ExperimentalData]) -> SweepOutput: +# +def sweep(parameters: FitParameters, data: list[ExperimentalData]) -> SweepOutput: + """ Sweep over Exchange Stiffness A for perpendicular SANS geometry to + get an initial estimate which can then be refined""" a_values = np.linspace( parameters.exchange_A_min, parameters.exchange_A_max, parameters.exchange_A_n) * 1e-12 # From pJ/m to J/m - least_squared_fits = [LSQ_PERP(data, a) for a in a_values] + if parameters.experiment_geometry == ExperimentGeometry.PERPENDICULAR: + least_squared_fits = [LSQ_PERP(data, a) for a in a_values] + + elif parameters.experiment_geometry == ExperimentGeometry.PARALLEL: + least_squared_fits = [LSQ_PAR(data, a) for a in a_values] + + else: + raise ValueError(f"Unknown ExperimentGeometry value: {parameters.experiment_geometry}") optimal_fit = min(least_squared_fits, key=lambda x: x.exchange_A_chi_sq) @@ -198,7 +208,7 @@ def OptimA_SPI_PERP(data: list[ExperimentalData], A_1, epsilon): #################################################################################################### # Plot Fitting results of simple fit -def PlotFittingResultsPERP_SimpleFit(z: SweepOutput, A_Uncertainty, +def PlotFittingResultsPERP_SimpleFit(z: SweepOutput, refined: LeastSquaresOutputPerpendicular, A_Uncertainty, figure, axes1, axes2, axes3, axes4): if A_Uncertainty < 1e-4: @@ -258,30 +268,3 @@ def PlotSweepFitResultPERP(q_max_mat, H_min_mat, A_opt_mat): #################################################################################################### # -def uncertainty_perp(data: list[ExperimentalData], A_opt: float): - """Calculate the uncertainty for the optimal exchange stiffness A""" - - # Estimate variance from second order derivative of chi-square function via Finite Differences - - p = 0.001 # fractional gap size for finite differences - dA = A_opt * p - A1 = A_opt - 2*dA - A2 = A_opt - 1*dA - A3 = A_opt - A4 = A_opt + 1*dA - A5 = A_opt + 2*dA - - chi1 = LSQ_PERP(data, A1).exchange_A_chi_sq - chi2 = LSQ_PERP(data, A2).exchange_A_chi_sq - chi3 = LSQ_PERP(data, A3).exchange_A_chi_sq - chi4 = LSQ_PERP(data, A4).exchange_A_chi_sq - chi5 = LSQ_PERP(data, A5).exchange_A_chi_sq - - d2chi_dA2 = (-chi1 + 16 * chi2 - 30 * chi3 + 16 * chi4 - chi5)/(12 * dA**2) - - # Scale variance by number of samples and return reciprocal square root - - n_field_strengths = len(data) # Number of fields - n_q = len(data[0].scattering_curve.x) # Number of q points - - return np.sqrt(2 / (n_field_strengths * n_q * d2chi_dA2)) diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1.csv rename to src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1.csv rename to src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1.csv rename to src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1.csv rename to src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1.csv b/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1.csv rename to src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/failure.py b/src/sas/qtgui/Utilities/MuMagTool/failure.py new file mode 100644 index 0000000000..55a36e635e --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMagTool/failure.py @@ -0,0 +1,5 @@ +class FitFailure(Exception): + pass + +class LoadFailure(Exception): + pass \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/models.py b/src/sas/qtgui/Utilities/MuMagTool/models.py index f1fee8d004..548f22ce2b 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/models.py +++ b/src/sas/qtgui/Utilities/MuMagTool/models.py @@ -106,3 +106,16 @@ def SANS_Model_PERP(q, S_H, S_M, I_res, M_s, H_0, H_dem, A): R_M = (np.sqrt(1 + p) - 1) / 2 return I_res + R_H * S_H + R_M * S_M + +def SANS_Model_PAR(q, S_H, I_res, M_s, H_0, H_dem, A): + """ 1D-Cross-Section of the parallel model""" + + # Micromagnetic Model + mu_0 = 4 * np.pi * 1e-7 + H_i = H_0 - H_dem + l_H = np.sqrt((2 * A) / (mu_0 * M_s * H_i)) + H_eff = H_i * (1 + (l_H ** 2) * (q ** 2)) + p = M_s / H_eff + R_H = (p ** 2) / 2 + + return I_res + R_H * S_H \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py b/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py index 7b33bb41c3..e0644b0365 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py +++ b/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py @@ -2,15 +2,19 @@ import numpy as np -from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputParallel, LeastSquaresOutputPerpendicular +from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutput +from typing import Generic, TypeVar + +T = TypeVar("T", bound=LeastSquaresOutput) @dataclass -class SweepOutput: +class SweepOutput(Generic[T]): """ Results from brute force optimisiation of the chi squared for the exchange A parameter """ exchange_A_checked: np.ndarray exchange_A_chi_sq: np.ndarray - optimal: LeastSquaresOutput \ No newline at end of file + optimal: T + From 384a5da28edb895c7df5bbb98dbdb32ce9427224 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Mon, 10 Jun 2024 13:16:09 +0100 Subject: [PATCH 33/46] Some refactoring --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 125 ++++++++++++++---- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 104 +++++---------- .../Utilities/MuMagTool/SANSData/__init__.py | 0 .../qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 29 ++-- .../qtgui/Utilities/MuMagTool/UI/__init__.py | 0 src/sas/qtgui/Utilities/MuMagTool/__init__.py | 0 src/sas/qtgui/Utilities/MuMagTool/failure.py | 2 + 7 files changed, 145 insertions(+), 115 deletions(-) create mode 100644 src/sas/qtgui/Utilities/MuMagTool/SANSData/__init__.py create mode 100644 src/sas/qtgui/Utilities/MuMagTool/UI/__init__.py create mode 100644 src/sas/qtgui/Utilities/MuMagTool/__init__.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index da3c17ea18..b9200d6a4b 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -10,60 +10,127 @@ import matplotlib.pylab as pl import numpy as np +from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData +from sas.qtgui.Utilities.MuMagTool.failure import LoadFailure from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry +from sas.qtgui.Utilities.MuMagTool.MuMagLib import MuMagLib +from logging import getLogger + +log = getLogger("MuMag") class MuMag(QtWidgets.QMainWindow, Ui_MuMagTool): def __init__(self, parent=None): super().__init__() - self.setupUi(self) - self.MuMagLib_obj = MuMagLib.MuMagLib() + self.setupUi(self) # Callbacks - self.ImportDataButton.clicked.connect(self.import_data_button_callback) - self.PlotDataButton.clicked.connect(self.plot_experimental_data_button_callback) + self.ImportDataButton.clicked.connect(self.importData) self.SimpleFitButton.clicked.connect(self.simple_fit_button_callback) self.CompareResultsButton.clicked.connect(self.compare_data_button_callback) self.SaveResultsButton.clicked.connect(self.save_data_button_callback) - # Plotting - layout = QVBoxLayout() - self.PlotDisplayPanel.setLayout(layout) + # + # Data + # + + self.data: list[ExperimentalData] | None = None - self.fig = plt.figure() #Figure(figsize=(width, height), dpi=dpi) - self.simple_fit_axes = self.fig.add_subplot(1, 1, 1) - self.simple_fit_axes.set_visible(False) - self.chi_squared_axes = self.fig.add_subplot(2, 2, 1) + # + # Plotting + # + + # Data + data_plot_layout = QVBoxLayout() + self.data_tab.setLayout(data_plot_layout) + self.data_figure = plt.figure() #Figure(figsize=(width, height), dpi=dpi) + self.figure_canvas = FigureCanvas(self.data_figure) + self.data_axes = self.data_figure.add_subplot(1, 1, 1) + self.data_axes.set_visible(False) + data_plot_layout.addWidget(self.figure_canvas) + + # Fit results + fit_results_layout = QVBoxLayout() + self.fit_results_tab.setLayout(fit_results_layout) + self.fit_results_figure = plt.figure() + self.fit_results_canvas = FigureCanvas(self.fit_results_figure) + + self.chi_squared_axes = self.fit_results_figure.add_subplot(2, 2, 1) self.chi_squared_axes.set_visible(False) - self.residuals_axes = self.fig.add_subplot(2, 2, 2) + self.residuals_axes = self.fit_results_figure.add_subplot(2, 2, 2) self.residuals_axes.set_visible(False) - self.s_h_axes = self.fig.add_subplot(2, 2, 3) + self.s_h_axes = self.fit_results_figure.add_subplot(2, 2, 3) self.s_h_axes.set_visible(False) - self.longitudinal_scattering_axes = self.fig.add_subplot(2, 2, 4) + self.longitudinal_scattering_axes = self.fit_results_figure.add_subplot(2, 2, 4) self.longitudinal_scattering_axes.set_visible(False) - self.figure_canvas = FigureCanvas(self.fig) - layout.addWidget(self.figure_canvas) + fit_results_layout.addWidget(self.fit_results_canvas) + + def importData(self): + """ Callback for the import data button """ + + # Get the directory from the user + directory = MuMagLib.directory_popup() + + if directory is None: + log.info("No directory selected") + return + + try: + self.data = MuMagLib.import_data(directory) + except LoadFailure as lf: + log.error(repr(lf)) + return + + log.info(f"Loaded {len(self.data)} datasets") + self.plot_data() + self.data_figure.canvas.draw() - def import_data_button_callback(self): - self.MuMagLib_obj.import_data() + def hide_everything(self): - def plot_experimental_data_button_callback(self): - self.simple_fit_axes.set_visible(True) + self.data_axes.set_visible(True) self.chi_squared_axes.set_visible(False) self.residuals_axes.set_visible(False) self.s_h_axes.set_visible(False) self.longitudinal_scattering_axes.set_visible(False) - self.simple_fit_axes.cla() + self.data_axes.cla() self.chi_squared_axes.cla() self.residuals_axes.cla() self.s_h_axes.cla() self.longitudinal_scattering_axes.cla() - self.MuMagLib_obj.plot_exp_data(self.fig, self.simple_fit_axes) - self.figure_canvas.draw() + + + def plot_data(self): + """ Plot Experimental Data: Generate Figure """ + + colors = pl.cm.jet(np.linspace(0, 1, len(self.data))) + + for i, datum in enumerate(self.data): + + self.data_axes.loglog(datum.scattering_curve.x, + datum.scattering_curve.y, + linestyle='-', color=colors[i], linewidth=0.5, + label=r'$B_0 = ' + str(datum.applied_field) + '$ T') + + self.data_axes.loglog(datum.scattering_curve.x, + datum.scattering_curve.y, '.', + color=colors[i], linewidth=0.3, markersize=1) + + # Plot limits + qlim = MuMagLib.nice_log_plot_bounds([datum.scattering_curve.x for datum in self.data]) + ilim = MuMagLib.nice_log_plot_bounds([datum.scattering_curve.y for datum in self.data]) + + self.data_axes.set_xlabel(r'$q$ [1/nm]') + self.data_axes.set_ylabel(r'$I_{\mathrm{exp}}$') + self.data_axes.set_xlim(qlim) + self.data_axes.set_ylim(ilim) + self.data_figure.tight_layout() + self.data_figure.canvas.draw() + self.data_axes.set_visible(True) + def fit_parameters(self) -> FitParameters: """ Get an object containing all the parameters needed for doing the fitting """ @@ -94,14 +161,14 @@ def simple_fit_button_callback(self): # Clear axes - self.simple_fit_axes.cla() + self.data_axes.cla() self.chi_squared_axes.cla() self.residuals_axes.cla() self.s_h_axes.cla() self.longitudinal_scattering_axes.cla() # Set axes visibility - self.simple_fit_axes.set_visible(False) + self.data_axes.set_visible(False) self.chi_squared_axes.set_visible(True) self.residuals_axes.set_visible(True) self.s_h_axes.set_visible(True) @@ -119,7 +186,7 @@ def simple_fit_button_callback(self): self.MuMagLib_obj.do_fit( parameters, - self.fig, + self.data_figure, self.chi_squared_axes, self.residuals_axes, self.s_h_axes, @@ -130,20 +197,20 @@ def simple_fit_button_callback(self): def compare_data_button_callback(self): # Clear axes - self.simple_fit_axes.cla() + self.data_axes.cla() self.chi_squared_axes.cla() self.residuals_axes.cla() self.s_h_axes.cla() self.longitudinal_scattering_axes.cla() # Set visibility - self.simple_fit_axes.set_visible(True) + self.data_axes.set_visible(True) self.chi_squared_axes.set_visible(False) self.residuals_axes.set_visible(False) self.s_h_axes.set_visible(False) self.longitudinal_scattering_axes.set_visible(False) - self.MuMagLib_obj.SimpleFit_CompareButtonCallback(self.fig, self.simple_fit_axes) + self.MuMagLib_obj.SimpleFit_CompareButtonCallback(self.data_figure, self.data_axes) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index fb06bf32a6..30a1e2f805 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -1,25 +1,18 @@ import numpy as np -import math -import matplotlib.pyplot as plt import matplotlib.pylab as pl -import scipy.optimize as scopt -from tkinter import * -from tkinter import filedialog from tkinter import messagebox -from tkinter import ttk import os import os.path from datetime import datetime from PySide6 import QtWidgets from PySide6.QtWidgets import QFileDialog -import string -from sas.qtgui.Utilities.MuMagTool import MuMagParallelGeo from sas.qtgui.Utilities.MuMagTool import MuMagPerpendicularGeo from sas.qtgui.Utilities.MuMagTool.MuMagParallelGeo import LSQ_PAR from sas.qtgui.Utilities.MuMagTool.MuMagPerpendicularGeo import LSQ_PERP from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData +from sas.qtgui.Utilities.MuMagTool.failure import LoadFailure from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular, \ LeastSquaresOutputParallel @@ -28,7 +21,7 @@ from sasdata.dataloader.loader import Loader -class MuMagLib(): +class MuMagLib: def __init__(self): self.input_data: list[ExperimentalData] | None = None @@ -43,46 +36,45 @@ def directory_popup(): return directory - def import_data(self): + @staticmethod + def import_data(directory): """Import experimental data and get information from filenames""" - # Get the directory from the user - directory = MuMagLib.directory_popup() - - if directory is None: - return - - # Load the data - loader = Loader() - input_names = [name for name in os.listdir(directory) if name.lower().endswith(".csv")] - input_paths = [os.path.join(directory, filename) for filename in input_names] + try: + # Load the data + loader = Loader() + input_names = [name for name in os.listdir(directory) if name.lower().endswith(".csv")] + input_paths = [os.path.join(directory, filename) for filename in input_names] - input_data = loader.load(input_paths) + input_data = loader.load(input_paths) - data = [] - for filename, data1d in zip(input_names, input_data): + data = [] + for filename, data1d in zip(input_names, input_data): - # Extract the metadata from the filename - filename_parts = filename.split(".") - filename = ".".join(filename_parts[:-1]) + # Extract the metadata from the filename + filename_parts = filename.split(".") + filename = ".".join(filename_parts[:-1]) - parts = filename.split("_") + parts = filename.split("_") + applied_field = float(parts[1]) # mT + saturation_magnetisation = float(parts[2]) # mT + demagnetising_field = float(parts[3]) # mT - applied_field = float(parts[1]) # mT - saturation_magnetisation = float(parts[2]) # mT - demagnetising_field = float(parts[3]) # mT + # Create input data object + data.append(ExperimentalData( + scattering_curve=data1d, + applied_field=applied_field, + saturation_magnetisation=saturation_magnetisation, + demagnetising_field=demagnetising_field)) - # Create input data object - data.append(ExperimentalData( - scattering_curve=data1d, - applied_field=applied_field, - saturation_magnetisation=saturation_magnetisation, - demagnetising_field=demagnetising_field)) + return sorted(data, key=lambda x: x.applied_field) - self.input_data = sorted(data, key=lambda x: x.applied_field) + except Exception as e: + raise LoadFailure(f"Failed to load from {directory}: " + repr(e)) - def nice_log_plot_bounds(self, data: list[np.ndarray]): + @staticmethod + def nice_log_plot_bounds(data: list[np.ndarray]): """ Get nice bounds for the loglog plots :return: (lower, upper) bounds appropriate to pass to plt.xlim/ylim @@ -96,42 +88,6 @@ def nice_log_plot_bounds(self, data: list[np.ndarray]): 10 ** (np.floor(np.log10(upper))) * np.ceil(upper / 10 ** (np.floor(np.log10(upper)))) ) - def plot_exp_data(self, figure, axes): - """ Plot Experimental Data: Generate Figure """ - - if self.input_data is None: - - messagebox.showerror( - title="Error!", - message="No experimental data available! Please import experimental data!") - - return - - ax = axes - colors = pl.cm.jet(np.linspace(0, 1, len(self.input_data))) - - for i, datum in enumerate(self.input_data): - - ax.loglog(datum.scattering_curve.x, - datum.scattering_curve.y, - linestyle='-', color=colors[i], linewidth=0.5, - label=r'$B_0 = ' + str(datum.applied_field) + '$ T') - - ax.loglog(datum.scattering_curve.x, - datum.scattering_curve.y, '.', - color=colors[i], linewidth=0.3, markersize=1) - - # Plot limits - qlim = self.nice_log_plot_bounds([datum.scattering_curve.x for datum in self.input_data]) - ilim = self.nice_log_plot_bounds([datum.scattering_curve.y for datum in self.input_data]) - - ax.set_xlabel(r'$q$ [1/nm]') - ax.set_ylabel(r'$I_{\mathrm{exp}}$') - ax.set_xlim(qlim) - ax.set_ylim(ilim) - figure.tight_layout() - figure.canvas.draw() - # @staticmethod def do_fit(self, parameters: FitParameters, figure, axes1, axes2, axes3, axes4): diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/__init__.py b/src/sas/qtgui/Utilities/MuMagTool/SANSData/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui index 150f98107e..b9b1254452 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -262,19 +262,24 @@ - - - Display + + + 0 - - - - 0 - 20 - 761 - 411 - - + + + Data + + + + + Fit Results + + + + + Comparison + diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/__init__.py b/src/sas/qtgui/Utilities/MuMagTool/UI/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/sas/qtgui/Utilities/MuMagTool/__init__.py b/src/sas/qtgui/Utilities/MuMagTool/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/sas/qtgui/Utilities/MuMagTool/failure.py b/src/sas/qtgui/Utilities/MuMagTool/failure.py index 55a36e635e..e8dfb573dd 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/failure.py +++ b/src/sas/qtgui/Utilities/MuMagTool/failure.py @@ -1,5 +1,7 @@ class FitFailure(Exception): + """ Fit failed """ pass class LoadFailure(Exception): + """ File loading failed """ pass \ No newline at end of file From a9fc7a3d405b8fd3e3f89791a2883d8f47b40bbb Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Mon, 10 Jun 2024 14:03:47 +0100 Subject: [PATCH 34/46] Much moving --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 25 +- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 344 +++++++++++++++--- .../Utilities/MuMagTool/MuMagParallelGeo.py | 162 --------- .../MuMagTool/MuMagPerpendicularGeo.py | 270 -------------- .../qtgui/Utilities/MuMagTool/fit_result.py | 24 +- 5 files changed, 306 insertions(+), 519 deletions(-) delete mode 100644 src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py delete mode 100644 src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index b9200d6a4b..378bd9da8c 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -17,6 +17,8 @@ from logging import getLogger +from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults + log = getLogger("MuMag") class MuMag(QtWidgets.QMainWindow, Ui_MuMagTool): @@ -36,6 +38,7 @@ def __init__(self, parent=None): # self.data: list[ExperimentalData] | None = None + self.fit_data: FitResults | None = None # # Plotting @@ -84,12 +87,14 @@ def importData(self): return log.info(f"Loaded {len(self.data)} datasets") + + self.hide_everything() self.plot_data() - self.data_figure.canvas.draw() + def hide_everything(self): - self.data_axes.set_visible(True) + self.data_axes.set_visible(False) self.chi_squared_axes.set_visible(False) self.residuals_axes.set_visible(False) self.s_h_axes.set_visible(False) @@ -128,8 +133,9 @@ def plot_data(self): self.data_axes.set_xlim(qlim) self.data_axes.set_ylim(ilim) self.data_figure.tight_layout() - self.data_figure.canvas.draw() + self.data_axes.set_visible(True) + self.data_figure.canvas.draw() def fit_parameters(self) -> FitParameters: @@ -159,6 +165,9 @@ def fit_parameters(self) -> FitParameters: def simple_fit_button_callback(self): + if self.data is None: + log.error("No data loaded") + return None # Clear axes self.data_axes.cla() @@ -184,16 +193,12 @@ def simple_fit_button_callback(self): raise ValueError(f"Unknown Value: {parameters.experiment_geometry}") - self.MuMagLib_obj.do_fit( - parameters, - self.data_figure, - self.chi_squared_axes, - self.residuals_axes, - self.s_h_axes, - self.longitudinal_scattering_axes) + self.fit_data = MuMagLib.do_fit(self.data, parameters) self.figure_canvas.draw() + + def compare_data_button_callback(self): # Clear axes diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 30a1e2f805..8cccaa19c5 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -1,19 +1,18 @@ import numpy as np import matplotlib.pylab as pl -from tkinter import messagebox import os import os.path from datetime import datetime +import scipy.optimize + from PySide6 import QtWidgets from PySide6.QtWidgets import QFileDialog -from sas.qtgui.Utilities.MuMagTool import MuMagPerpendicularGeo -from sas.qtgui.Utilities.MuMagTool.MuMagParallelGeo import LSQ_PAR -from sas.qtgui.Utilities.MuMagTool.MuMagPerpendicularGeo import LSQ_PERP from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData from sas.qtgui.Utilities.MuMagTool.failure import LoadFailure from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry +from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular, \ LeastSquaresOutputParallel from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput @@ -22,9 +21,9 @@ class MuMagLib: - def __init__(self): + """ Library for methods supporting MuMag""" - self.input_data: list[ExperimentalData] | None = None + mu_0 = 4 * np.pi * 1e-7 @staticmethod def directory_popup(): @@ -89,91 +88,312 @@ def nice_log_plot_bounds(data: list[np.ndarray]): ) - # @staticmethod - def do_fit(self, parameters: FitParameters, figure, axes1, axes2, axes3, axes4): + @staticmethod + def do_fit(data: list[ExperimentalData], parameters: FitParameters): + """ Main fitting ("simple fit") """ - if self.input_data is None: - messagebox.showerror(title="Error!", - message="No experimental Data available! Please import experimental data!") - - return None + geometry = parameters.experiment_geometry # Use an index for data upto qmax based on first data set # Not ideal, would be preferable make sure the data was # compatible, using something like interpolation TODO - square_distance_from_qmax = (self.input_data[0].scattering_curve.x - parameters.q_max) ** 2 + square_distance_from_qmax = (data[0].scattering_curve.x - parameters.q_max) ** 2 max_q_index = int(np.argmin(square_distance_from_qmax)) filtered_inputs = [datum.restrict_by_index(max_q_index) - for datum in self.input_data + for datum in data if datum.applied_field >= parameters.min_applied_field] + # Brute force check for something near the minimum + sweep_data = MuMagLib.sweep(parameters, filtered_inputs) - # Least Squares Fit in case of perpendicular SANS geometry - match parameters.experiment_geometry: - case ExperimentGeometry.PERPENDICULAR: + # Refine this result + crude_A = sweep_data.optimal.exchange_A + refined = MuMagLib.refine_exchange_A(filtered_inputs, crude_A, geometry) + # Get uncertainty estimate TODO: Check units + uncertainty = MuMagLib.uncertainty(filtered_inputs, refined.exchange_A, geometry) * 1e12 - sweep_data = MuMagPerpendicularGeo.sweep(parameters, filtered_inputs) + return FitResults( + input_data=data, + sweep_data=sweep_data, + refined_fit_data=refined, + optimal_exchange_A_uncertainty=uncertainty) - crude_A = sweep_data.optimal.exchange_A - refined_A = self.refine_exchange_A(filtered_inputs, crude_A, ExperimentGeometry.PERPENDICULAR) + @staticmethod + def sweep(parameters: FitParameters, data: list[ExperimentalData]) -> SweepOutput: + """ Sweep over Exchange Stiffness A for perpendicular SANS geometry to + get an initial estimate which can then be refined""" - refined = MuMagPerpendicularGeo.LSQ_PERP(filtered_inputs, refined_A) + a_values = np.linspace( + parameters.exchange_A_min, + parameters.exchange_A_max, + parameters.exchange_A_n) * 1e-12 # From pJ/m to J/m - uncertainty = self.uncertainty(filtered_inputs, refined_A, ExperimentGeometry.PERPENDICULAR) + if parameters.experiment_geometry == ExperimentGeometry.PERPENDICULAR: + least_squared_fits = [MuMagLib.LSQ_PERP(data, a) for a in a_values] - self.plot_results(sweep_data, refined, uncertainty * 1e12, figure, axes1, axes2, axes3, axes4) + elif parameters.experiment_geometry == ExperimentGeometry.PARALLEL: + least_squared_fits = [MuMagLib.LSQ_PAR(data, a) for a in a_values] + else: + raise ValueError(f"Unknown ExperimentGeometry value: {parameters.experiment_geometry}") + optimal_fit = min(least_squared_fits, key=lambda x: x.exchange_A_chi_sq) - case ExperimentGeometry.PARALLEL: + chi_sq = np.array([fit.exchange_A_chi_sq for fit in least_squared_fits]) + + return SweepOutput( + exchange_A_checked=a_values, + exchange_A_chi_sq=chi_sq, + optimal=optimal_fit) + + @staticmethod + def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutputPerpendicular: + """ Least squares fitting for a given exchange stiffness, A, perpendicular case + + We are fitting the equation: + + I_sim = I_res + response_H * S_H + response_M * S_M + = (I_res, S_H, S_M) . (1, response_H, response_M) + = (I_res, S_H, S_M) . least_squares_x + + finding I_res, S_H, and S_M for each q value + + + """ + + # Get matrices from the input data + n_data = len(data) + + # Factor of (1e-3 / mu_0) converts from mT to A/m + applied_field = np.array([datum.applied_field for datum in data]) * (1e-3 / MuMagLib.mu_0) + demagnetising_field = np.array([datum.demagnetising_field for datum in data]) * (1e-3 / MuMagLib.mu_0) + saturation_magnetisation = np.array([datum.saturation_magnetisation for datum in data]) * (1e-3 / MuMagLib.mu_0) + # TODO: The following is how things should be done in the future, rather than hard-coding + # a scaling factor... + # def data_nanometers(data: Data1D): + # raw_data = data.x + # units = data.x_unit + # converter = Converter(units) + # return converter.scale("1/m", raw_data) + # + # q = np.array([data_nanometers(datum.scattering_curve) for datum in data]) - sweep_data = MuMagPerpendicularGeo.sweep(parameters, filtered_inputs) + q = np.array([datum.scattering_curve.x for datum in data]) * 1e9 + I = np.array([datum.scattering_curve.y for datum in data]) + I_stdev = np.array([datum.scattering_curve.dy for datum in data]) - crude_A = sweep_data.optimal.exchange_A - print(crude_A) - refined_A = self.refine_exchange_A(filtered_inputs, parameters.exchange_A_min*1e-12, ExperimentGeometry.PARALLEL) + n_q = q.shape[1] - refined = MuMagPerpendicularGeo.LSQ_PAR(filtered_inputs, refined_A) + # Micromagnetic Model + internal_field = (applied_field - demagnetising_field).reshape(-1, 1) + magnetic_scattering_length = np.sqrt( + (2 * A) / (MuMagLib.mu_0 * saturation_magnetisation.reshape(-1, 1) * internal_field)) + effective_field = internal_field * (1 + (magnetic_scattering_length ** 2) * (q ** 2)) - uncertainty = self.uncertainty(filtered_inputs, refined_A, ExperimentGeometry.PARALLEL) + # Calculate the response functions + p = saturation_magnetisation.reshape(-1, 1) / effective_field + response_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) + response_M = (np.sqrt(1 + p) - 1) / 2 - self.plot_results(sweep_data, refined, uncertainty * 1e12, - figure, axes1, axes2, axes3, axes4) + # print("Input", q.shape, q[0,10]) + # sys.exit() + + # Lists for output of calculation + I_residual = [] + S_H = [] + S_M = [] + + I_residual_error_weight = [] + S_M_error_weight = [] + S_H_error_weight = [] + + for nu in range(n_q): + + # non-negative linear least squares + least_squares_x = (np.array([np.ones((n_data,)), response_H[:, nu], response_M[:, nu]]) / I_stdev[:, nu]).T + least_squares_y = I[:, nu] / I_stdev[:, nu] + + least_squares_x_squared = np.dot(least_squares_x.T, least_squares_x) + + # Non-negative least squares + try: + fit_result = scipy.optimize.nnls( + least_squares_x_squared, + np.matmul(least_squares_x.T, least_squares_y)) + + except ValueError as ve: + print("Value Error:") + print(" A =", A) + + raise ve + + I_residual.append(fit_result[0][0]) + S_H.append(fit_result[0][1]) + S_M.append(fit_result[0][2]) + + errors = np.linalg.inv(np.dot(least_squares_x_squared.T, least_squares_x_squared)) + + I_residual_error_weight.append(errors[0, 0]) + S_H_error_weight.append(errors[1, 1]) + S_M_error_weight.append(errors[2, 2]) + + # Arrayise + S_H = np.array(S_H) + S_M = np.array(S_M) + I_residual = np.array(I_residual) + + I_sim = I_residual + response_H * S_H + response_M * S_M + + s_q = np.mean(((I - I_sim) / I_stdev) ** 2, axis=0) + + sigma_I_res = np.sqrt(np.abs(np.array(I_residual_error_weight) * s_q)) + sigma_S_H = np.sqrt(np.abs(np.array(S_H_error_weight) * s_q)) + sigma_S_M = np.sqrt(np.abs(np.array(S_M_error_weight) * s_q)) + + chi_sq = float(np.mean(s_q)) + + output_q_values = np.mean(q, axis=0) + + return LeastSquaresOutputPerpendicular( + exchange_A=A, + exchange_A_chi_sq=chi_sq, + q=output_q_values, + I_residual=I_residual, + I_simulated=I_sim, + S_H=S_H, + S_M=S_M, + I_residual_stdev=sigma_I_res, + S_H_stdev=sigma_S_H, + S_M_stdev=sigma_S_M) - # Save to global Variables - # self.SimpleFit_q_exp = q - # self.SimpleFit_I_exp = I_exp_red - # self.SimpleFit_sigma_exp = sigma - # self.SimpleFit_B_0_exp = self.B_0_exp[K_H:] - # self.SimpleFit_Ms_exp = self.Ms_exp[K_H:] - # self.SimpleFit_Hdem_exp = self.Hdem_exp[K_H:] - # self.SimpleFit_I_fit = I_opt - # self.SimpleFit_A = A - # self.SimpleFit_chi_q = chi_q - # self.SimpleFit_S_H_fit = S_H_opt - # self.SimpleFit_I_res_fit = I_res_opt - # self.SimpleFit_A_opt = A_opt - # self.SimpleFit_chi_q_opt = chi_q_opt - # self.SimpleFit_A_sigma = A_Uncertainty - # self.SimpleFit_SANSgeometry = "parallel" + + @staticmethod + def LSQ_PAR(data: list[ExperimentalData], A): + + """ Least squares fitting for a given exchange stiffness, A, parallel case + + We are fitting the equation: + + I_sim = I_res + response_H * S_H + = (I_res, S_H) . (1, response_H) + = (I_res, S_H) . least_squares_x + + finding I_res and S_H for each q value + + + """ + + # Get matrices from the input data + n_data = len(data) + + # Factor of (1e-3 / mu_0) converts from mT to A/m + applied_field = np.array([datum.applied_field for datum in data]) * (1e-3 / MuMagLib.mu_0) + demagnetising_field = np.array([datum.demagnetising_field for datum in data]) * (1e-3 / MuMagLib.mu_0) + saturation_magnetisation = np.array([datum.saturation_magnetisation for datum in data]) * (1e-3 / MuMagLib.mu_0) + + # TODO: The following is how things should be done in the future, rather than hard-coding + # a scaling factor... + # def data_nanometers(data: Data1D): + # raw_data = data.x + # units = data.x_unit + # converter = Converter(units) + # return converter.scale("1/m", raw_data) + # + # q = np.array([data_nanometers(datum.scattering_curve) for datum in data]) + + q = np.array([datum.scattering_curve.x for datum in data]) * 1e9 + I = np.array([datum.scattering_curve.y for datum in data]) + I_stdev = np.array([datum.scattering_curve.dy for datum in data]) + + n_q = q.shape[1] + + # Micromagnetic Model + internal_field = (applied_field - demagnetising_field).reshape(-1, 1) + magnetic_scattering_length = np.sqrt( + (2 * A) / (MuMagLib.mu_0 * saturation_magnetisation.reshape(-1, 1) * internal_field)) + effective_field = internal_field * (1 + (magnetic_scattering_length ** 2) * (q ** 2)) + + # Calculate the response functions + p = saturation_magnetisation.reshape(-1, 1) / effective_field + response_H = (p ** 2) / 2 + + # Lists for output of calculation + I_residual = [] + S_H = [] + + I_residual_error_weight = [] + S_H_error_weight = [] + + for nu in range(n_q): + + # non-negative linear least squares + least_squares_x = (np.array([np.ones((n_data,)), response_H[:, nu]]) / I_stdev[:, nu]).T + least_squares_y = I[:, nu] / I_stdev[:, nu] + + least_squares_x_squared = np.dot(least_squares_x.T, least_squares_x) + + # Non-negative least squares + try: + fit_result = scipy.optimize.nnls( + least_squares_x_squared, + np.matmul(least_squares_x.T, least_squares_y)) + + except ValueError as ve: + print("Value Error:") + print(" A =", A) + + raise ve + + I_residual.append(fit_result[0][0]) + S_H.append(fit_result[0][1]) + + errors = np.linalg.inv(np.dot(least_squares_x_squared.T, least_squares_x_squared)) + + I_residual_error_weight.append(errors[0, 0]) + S_H_error_weight.append(errors[1, 1]) + + # Arrayise + S_H = np.array(S_H) + I_residual = np.array(I_residual) + + I_sim = I_residual + response_H * S_H + + s_q = np.mean(((I - I_sim) / I_stdev) ** 2, axis=0) + + sigma_I_res = np.sqrt(np.abs(np.array(I_residual_error_weight) * s_q)) + sigma_S_H = np.sqrt(np.abs(np.array(S_H_error_weight) * s_q)) + + chi_sq = float(np.mean(s_q)) + + output_q_values = np.mean(q, axis=0) + + return LeastSquaresOutputParallel( + exchange_A=A, + exchange_A_chi_sq=chi_sq, + q=output_q_values, + I_residual=I_residual, + I_simulated=I_sim, + S_H=S_H, + I_residual_stdev=sigma_I_res, + S_H_stdev=sigma_S_H) @staticmethod def refine_exchange_A( data: list[ExperimentalData], exchange_A_initial: float, geometry: ExperimentGeometry, - epsilon: float = 0.0001): + epsilon: float = 0.0001) -> LeastSquaresOutputPerpendicular | LeastSquaresOutputParallel: """ Refines the A parameter using Jarratt's method of successive parabolic interpolation""" match geometry: case ExperimentGeometry.PARALLEL: - least_squares_function = LSQ_PAR + least_squares_function = MuMagLib.LSQ_PAR case ExperimentGeometry.PERPENDICULAR: - least_squares_function = LSQ_PERP + least_squares_function = MuMagLib.LSQ_PERP case _: raise ValueError(f"Unknown experimental geometry: {geometry}") @@ -183,9 +403,12 @@ def refine_exchange_A( x_2 = exchange_A_initial x_3 = exchange_A_initial + delta + # We want all the least squares fitting data around the final value, so keep that in a variable + refined_least_squared_data = least_squares_function(data, x_3) + y_1 = least_squares_function(data, x_1).exchange_A_chi_sq y_2 = least_squares_function(data, x_2).exchange_A_chi_sq - y_3 = least_squares_function(data, x_3).exchange_A_chi_sq + y_3 = refined_least_squared_data.exchange_A_chi_sq x_4 = x_3 + 0.5 * ((x_2 - x_3) ** 2 * (y_3 - y_1) + (x_1 - x_3) ** 2 * (y_2 - y_3)) \ / ((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) @@ -194,28 +417,30 @@ def refine_exchange_A( if np.abs(2 * (x_4 - x_3) / (x_4 + x_3)) < epsilon: break + refined_least_squared_data = least_squares_function(data, x_3) + x_1, x_2, x_3 = x_2, x_3, x_4 - y_1, y_2, y_3 = y_2, y_3, least_squares_function(data, x_3).exchange_A_chi_sq + y_1, y_2, y_3 = y_2, y_3, refined_least_squared_data.exchange_A_chi_sq x_4 = x_3 + 0.5 * ((x_2 - x_3) ** 2 * (y_3 - y_1) + (x_1 - x_3) ** 2 * (y_2 - y_3)) \ / ((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) - return x_4 + return refined_least_squared_data @staticmethod def uncertainty( data: list[ExperimentalData], A_opt: float, - geometry: ExperimentGeometry): + geometry: ExperimentGeometry) -> float: """Calculate the uncertainty for the optimal exchange stiffness A""" # Estimate variance from second order derivative of chi-square function via Finite Differences match geometry: case ExperimentGeometry.PARALLEL: - least_squares_function = LSQ_PAR + least_squares_function = MuMagLib.LSQ_PAR case ExperimentGeometry.PERPENDICULAR: - least_squares_function = LSQ_PERP + least_squares_function = MuMagLib.LSQ_PERP case _: raise ValueError(f"Unknown experimental geometry: {geometry}") @@ -369,8 +594,7 @@ def save_button_callback(self): np.savetxt(os.path.join(path4, "I_res.csv"), np.array([SimpleFit_q_exp[0, :].T, SimpleFit_I_res_fit[0, :]]).T, delimiter=" ") - else: - messagebox.showerror(title="Error!", message="No SimpleFit results available!") + @staticmethod def plot_results(sweep_data: SweepOutput, diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py deleted file mode 100644 index 8ce7fbb537..0000000000 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagParallelGeo.py +++ /dev/null @@ -1,162 +0,0 @@ -import numpy as np -import scipy.optimize as scopt -import matplotlib.pyplot as plt - -from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.fit_parameters import ExperimentGeometry -from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputParallel, \ - LeastSquaresOutputPerpendicular -from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput - -mu_0 = 4 * np.pi * 1e-7 - -def LSQ_PAR(data: list[ExperimentalData], A): - - """ Least squares fitting for a given exchange stiffness, A, parallel case - - We are fitting the equation: - - I_sim = I_res + response_H * S_H - = (I_res, S_H) . (1, response_H) - = (I_res, S_H) . least_squares_x - - finding I_res and S_H for each q value - - - """ - - # Get matrices from the input data - n_data = len(data) - - # Factor of (1e-3 / mu_0) converts from mT to A/m - applied_field = np.array([datum.applied_field for datum in data]) * (1e-3 / mu_0) - demagnetising_field = np.array([datum.demagnetising_field for datum in data]) * (1e-3 / mu_0) - saturation_magnetisation = np.array([datum.saturation_magnetisation for datum in data]) * (1e-3 / mu_0) - - # TODO: The following is how things should be done in the future, rather than hard-coding - # a scaling factor... - # def data_nanometers(data: Data1D): - # raw_data = data.x - # units = data.x_unit - # converter = Converter(units) - # return converter.scale("1/m", raw_data) - # - # q = np.array([data_nanometers(datum.scattering_curve) for datum in data]) - - q = np.array([datum.scattering_curve.x for datum in data]) * 1e9 - I = np.array([datum.scattering_curve.y for datum in data]) - I_stdev = np.array([datum.scattering_curve.dy for datum in data]) - - n_q = q.shape[1] - - # Micromagnetic Model - internal_field = (applied_field - demagnetising_field).reshape(-1, 1) - magnetic_scattering_length = np.sqrt((2 * A) / (mu_0 * saturation_magnetisation.reshape(-1, 1) * internal_field)) - effective_field = internal_field * (1 + (magnetic_scattering_length ** 2) * (q ** 2)) - - # Calculate the response functions - p = saturation_magnetisation.reshape(-1, 1) / effective_field - response_H = (p ** 2) / 2 - - # print("Input", q.shape, q[0,10]) - # sys.exit() - - # Lists for output of calculation - I_residual = [] - S_H = [] - - I_residual_error_weight = [] - S_H_error_weight = [] - - for nu in range(n_q): - - # non-negative linear least squares - least_squares_x = (np.array([np.ones((n_data,)), response_H[:, nu]]) / I_stdev[:, nu]).T - least_squares_y = I[:, nu] / I_stdev[:, nu] - - least_squares_x_squared = np.dot(least_squares_x.T, least_squares_x) - - # Non-negative least squares - try: - fit_result = scopt.nnls( - least_squares_x_squared, - np.matmul(least_squares_x.T, least_squares_y)) - - except ValueError as ve: - print("Value Error:") - print(" A =", A) - - raise ve - - I_residual.append(fit_result[0][0]) - S_H.append(fit_result[0][1]) - - errors = np.linalg.inv(np.dot(least_squares_x_squared.T, least_squares_x_squared)) - - I_residual_error_weight.append(errors[0, 0]) - S_H_error_weight.append(errors[1, 1]) - - # Arrayise - S_H = np.array(S_H) - I_residual = np.array(I_residual) - - I_sim = I_residual + response_H * S_H - - s_q = np.mean(((I - I_sim) / I_stdev) ** 2, axis=0) - - sigma_I_res = np.sqrt(np.abs(np.array(I_residual_error_weight) * s_q)) - sigma_S_H = np.sqrt(np.abs(np.array(S_H_error_weight) * s_q)) - - chi_sq = float(np.mean(s_q)) - - output_q_values = np.mean(q, axis=0) - - return LeastSquaresOutputParallel( - exchange_A=A, - exchange_A_chi_sq=chi_sq, - q=output_q_values, - I_residual=I_residual, - I_simulated=I_sim, - S_H=S_H, - I_residual_stdev=sigma_I_res, - S_H_stdev=sigma_S_H) - - -#################################################################################################### - - -#################################################################################################### -# Plot Fitting results of simple fit - -#################################################################################################### -def PlotSweepFitResultPAR(q_max_mat, H_min_mat, A_opt_mat): - fig = plt.figure() - ax = plt.axes(projection='3d') - ax.plot_surface(q_max_mat * 1e-9, H_min_mat, A_opt_mat * 1e12) - ax.set(xlabel='q_max [1/nm]', ylabel='H_min [mT]', zlabel='A_opt [pJ/m]') - ax.grid() - - plt.tight_layout() - plt.show() - -#################################################################################################### -# Second Order Derivative of chi-square function via Finite Differences -def FDM2Ord_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A_opt): - - p = 0.01 - dA = A_opt * p - A1 = A_opt - 2*dA - A2 = A_opt - 1*dA - A3 = A_opt - A4 = A_opt + 1*dA - A5 = A_opt + 2*dA - - chi1 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A1) - chi2 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A2) - chi3 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A3) - chi4 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A4) - chi5 = chi_q_PAR(q, I_exp, sigma, M_s, H_0, H_dem, A5) - - d2_chi_dA2 = (-chi1 + 16 * chi2 - 30 * chi3 + 16 * chi4 - chi5)/(12 * dA**2) - - return d2_chi_dA2 \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py deleted file mode 100644 index 0ad250d1de..0000000000 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagPerpendicularGeo.py +++ /dev/null @@ -1,270 +0,0 @@ -import sys - -import numpy as np -import scipy.optimize as scopt -import matplotlib.pyplot as plt - -from sas.qtgui.Utilities.MuMagTool.MuMagParallelGeo import LSQ_PAR -from sasdata.dataloader import Data1D -from data_util.nxsunit import Converter -from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry -from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults -from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutput, LeastSquaresOutputPerpendicular -from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput - -mu_0 = 4 * np.pi * 1e-7 - -def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutputPerpendicular: - """ Least squares fitting for a given exchange stiffness, A, perpendicular case - - We are fitting the equation: - - I_sim = I_res + response_H * S_H + response_M * S_M - = (I_res, S_H, S_M) . (1, response_H, response_M) - = (I_res, S_H, S_M) . least_squares_x - - finding I_res, S_H, and S_M for each q value - - - """ - - - - # Get matrices from the input data - n_data = len(data) - - # Factor of (1e-3 / mu_0) converts from mT to A/m - applied_field = np.array([datum.applied_field for datum in data]) * (1e-3 / mu_0) - demagnetising_field = np.array([datum.demagnetising_field for datum in data]) * (1e-3 / mu_0) - saturation_magnetisation = np.array([datum.saturation_magnetisation for datum in data]) * (1e-3 / mu_0) - - # TODO: The following is how things should be done in the future, rather than hard-coding - # a scaling factor... - # def data_nanometers(data: Data1D): - # raw_data = data.x - # units = data.x_unit - # converter = Converter(units) - # return converter.scale("1/m", raw_data) - # - # q = np.array([data_nanometers(datum.scattering_curve) for datum in data]) - - - q = np.array([datum.scattering_curve.x for datum in data]) * 1e9 - I = np.array([datum.scattering_curve.y for datum in data]) - I_stdev = np.array([datum.scattering_curve.dy for datum in data]) - - n_q = q.shape[1] - - # Micromagnetic Model - internal_field = (applied_field - demagnetising_field).reshape(-1, 1) - magnetic_scattering_length = np.sqrt((2 * A) / (mu_0 * saturation_magnetisation.reshape(-1, 1) * internal_field)) - effective_field = internal_field * (1 + (magnetic_scattering_length ** 2) * (q ** 2)) - - # Calculate the response functions - p = saturation_magnetisation.reshape(-1, 1) / effective_field - response_H = (p ** 2) / 4 * (2 + 1 / np.sqrt(1 + p)) - response_M = (np.sqrt(1 + p) - 1) / 2 - - # print("Input", q.shape, q[0,10]) - # sys.exit() - - # Lists for output of calculation - I_residual = [] - S_H = [] - S_M = [] - - I_residual_error_weight = [] - S_M_error_weight = [] - S_H_error_weight = [] - - for nu in range(n_q): - - - - # non-negative linear least squares - least_squares_x = (np.array([np.ones((n_data,)), response_H[:, nu], response_M[:, nu]]) / I_stdev[:, nu]).T - least_squares_y = I[:, nu]/I_stdev[:, nu] - - least_squares_x_squared = np.dot(least_squares_x.T, least_squares_x) - - # Non-negative least squares - try: - fit_result = scopt.nnls( - least_squares_x_squared, - np.matmul(least_squares_x.T, least_squares_y)) - - except ValueError as ve: - print("Value Error:") - print(" A =", A) - - raise ve - - - I_residual.append(fit_result[0][0]) - S_H.append(fit_result[0][1]) - S_M.append(fit_result[0][2]) - - errors = np.linalg.inv(np.dot(least_squares_x_squared.T, least_squares_x_squared)) - - I_residual_error_weight.append(errors[0, 0]) - S_H_error_weight.append(errors[1, 1]) - S_M_error_weight.append(errors[2, 2]) - - - # Arrayise - S_H = np.array(S_H) - S_M = np.array(S_M) - I_residual = np.array(I_residual) - - I_sim = I_residual + response_H * S_H + response_M * S_M - - s_q = np.mean(((I - I_sim)/I_stdev)**2, axis=0) - - sigma_I_res = np.sqrt(np.abs(np.array(I_residual_error_weight) * s_q)) - sigma_S_H = np.sqrt(np.abs(np.array(S_H_error_weight) * s_q)) - sigma_S_M = np.sqrt(np.abs(np.array(S_M_error_weight) * s_q)) - - chi_sq = float(np.mean(s_q)) - - output_q_values = np.mean(q, axis=0) - - return LeastSquaresOutputPerpendicular( - exchange_A=A, - exchange_A_chi_sq=chi_sq, - q=output_q_values, - I_residual=I_residual, - I_simulated=I_sim, - S_H=S_H, - S_M=S_M, - I_residual_stdev=sigma_I_res, - S_H_stdev=sigma_S_H, - S_M_stdev=sigma_S_M) - - -#################################################################################################### -# -def sweep(parameters: FitParameters, data: list[ExperimentalData]) -> SweepOutput: - """ Sweep over Exchange Stiffness A for perpendicular SANS geometry to - get an initial estimate which can then be refined""" - - a_values = np.linspace( - parameters.exchange_A_min, - parameters.exchange_A_max, - parameters.exchange_A_n) * 1e-12 # From pJ/m to J/m - - if parameters.experiment_geometry == ExperimentGeometry.PERPENDICULAR: - least_squared_fits = [LSQ_PERP(data, a) for a in a_values] - - elif parameters.experiment_geometry == ExperimentGeometry.PARALLEL: - least_squared_fits = [LSQ_PAR(data, a) for a in a_values] - - else: - raise ValueError(f"Unknown ExperimentGeometry value: {parameters.experiment_geometry}") - - optimal_fit = min(least_squared_fits, key=lambda x: x.exchange_A_chi_sq) - - chi_sq = np.array([fit.exchange_A_chi_sq for fit in least_squared_fits]) - - return SweepOutput( - exchange_A_checked=a_values, - exchange_A_chi_sq=chi_sq, - optimal=optimal_fit) - - -#################################################################################################### -# find optimal Exchange Stiffness A for perpendicular SANS geometry using -# successive parabolic interpolation (fast and accurate) -# implemented as Jarratt's Method -def OptimA_SPI_PERP(data: list[ExperimentalData], A_1, epsilon): - - delta = A_1 * 0.1 - - x_1 = A_1 - delta - x_2 = A_1 - x_3 = A_1 + delta - - y_1 = LSQ_PERP(data, x_1).exchange_A_chi_sq - y_2 = LSQ_PERP(data, x_2).exchange_A_chi_sq - y_3 = LSQ_PERP(data, x_3).exchange_A_chi_sq - - x_4 = x_3 + 0.5 * ((x_2 - x_3)**2 * (y_3 - y_1) + (x_1 - x_3)**2 * (y_2 - y_3))/((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) - while np.abs(2 * (x_4 - x_3)/(x_4 + x_3)) > epsilon: - - # print("x1,x2,x3,x4:", x_1, x_2, x_3, x_4) - - x_1 = x_2 - x_2 = x_3 - x_3 = x_4 - - y_1 = y_2 - y_2 = y_3 - y_3 = LSQ_PERP(data, x_3).exchange_A_chi_sq - - x_4 = x_3 + 0.5 * ((x_2 - x_3) ** 2 * (y_3 - y_1) + (x_1 - x_3) ** 2 * (y_2 - y_3)) / ((x_2 - x_3) * (y_3 - y_1) + (x_1 - x_3) * (y_2 - y_3)) - - return x_4 - - -#################################################################################################### -# Plot Fitting results of simple fit -def PlotFittingResultsPERP_SimpleFit(z: SweepOutput, refined: LeastSquaresOutputPerpendicular, A_Uncertainty, - figure, axes1, axes2, axes3, axes4): - - if A_Uncertainty < 1e-4: - A_Uncertainty = 0 - - A_uncertainty_str = str(A_Uncertainty) - A_opt_str = str(z.optimal.exchange_A * 1e12) - - q = z.optimal.q * 1e-9 - - # Plot A search data - - axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m') - axes1.plot(z.exchange_A_checked * 1e12, z.exchange_A_chi_sq) - axes1.plot(z.optimal.exchange_A * 1e12, z.optimal.exchange_A_chi_sq, 'o') - - axes1.set_xlim([min(z.exchange_A_checked * 1e12), max(z.exchange_A_checked * 1e12)]) - axes1.set_xlabel('$A$ [pJ/m]') - axes1.set_ylabel('$\chi^2$') - - # Residual intensity plot - - axes2.plot(q, z.optimal.I_residual, label='fit') - axes2.set_yscale('log') - axes2.set_xscale('log') - axes2.set_xlim([min(q), max(q)]) - axes2.set_xlabel('$q$ [1/nm]') - axes2.set_ylabel('$I_{\mathrm{res}}$') - - axes3.plot(q, z.optimal.S_H, label='fit') - axes3.set_yscale('log') - axes3.set_xscale('log') - axes3.set_xlim([min(q), max(q)]) - axes3.set_xlabel('$q$ [1/nm]') - axes3.set_ylabel('$S_H$') - - axes4.plot(q, z.optimal.S_M, label='fit') - axes4.set_yscale('log') - axes4.set_xscale('log') - axes4.set_xlim([min(q), max(q)]) - axes4.set_xlabel('$q$ [1/nm]') - axes4.set_ylabel('$S_M$') - - figure.tight_layout() - - -#################################################################################################### -def PlotSweepFitResultPERP(q_max_mat, H_min_mat, A_opt_mat): - fig = plt.figure() - ax = plt.axes(projection='3d') - ax.plot_surface(q_max_mat * 1e-9, H_min_mat, A_opt_mat * 1e12) - ax.set(xlabel='q_max [1/nm]', ylabel='H_min [mT]', zlabel='A_opt [pJ/m]') - ax.grid() - - plt.tight_layout() - plt.show() - -#################################################################################################### -# diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py index ad7b800bee..33b0e64e57 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py +++ b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py @@ -4,25 +4,15 @@ from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData from sas.qtgui.Utilities.MuMagTool.fit_parameters import ExperimentGeometry +from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular, \ + LeastSquaresOutputParallel +from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput @dataclass class FitResults: """ Output the MuMag fit """ - truncated_input_data: list[ExperimentalData] - - q: np.ndarray - I_fit: np.ndarray - - S_H: np.ndarray - S_M: np.ndarray - I_residual: np.ndarray # Nuclear + Magnetic cross section at complete magnetic saturation - - exchange_A: np.ndarray - exchange_A_chi_sq: np.ndarray - - optimal_A: float - optimal_A_chi_sq: float - optimal_A_stdev: float # check - - geometry: ExperimentGeometry + input_data: list[ExperimentalData] + sweep_data: SweepOutput + refined_fit_data: LeastSquaresOutputParallel | LeastSquaresOutputPerpendicular + optimal_exchange_A_uncertainty: float From e264f1063e57c4d88f77bf05341e46f437f9d388 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Mon, 10 Jun 2024 14:31:39 +0100 Subject: [PATCH 35/46] GUI work --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 129 +++++++++++++----- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 75 ++-------- 2 files changed, 105 insertions(+), 99 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 378bd9da8c..734e6b9ca3 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -18,6 +18,7 @@ from logging import getLogger from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults +from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular log = getLogger("MuMag") @@ -29,7 +30,7 @@ def __init__(self, parent=None): # Callbacks self.ImportDataButton.clicked.connect(self.importData) - self.SimpleFitButton.clicked.connect(self.simple_fit_button_callback) + self.SimpleFitButton.clicked.connect(self.onFit) self.CompareResultsButton.clicked.connect(self.compare_data_button_callback) self.SaveResultsButton.clicked.connect(self.save_data_button_callback) @@ -60,16 +61,15 @@ def __init__(self, parent=None): self.fit_results_canvas = FigureCanvas(self.fit_results_figure) self.chi_squared_axes = self.fit_results_figure.add_subplot(2, 2, 1) - self.chi_squared_axes.set_visible(False) - self.residuals_axes = self.fit_results_figure.add_subplot(2, 2, 2) - self.residuals_axes.set_visible(False) + self.residual_axes = self.fit_results_figure.add_subplot(2, 2, 2) self.s_h_axes = self.fit_results_figure.add_subplot(2, 2, 3) - self.s_h_axes.set_visible(False) self.longitudinal_scattering_axes = self.fit_results_figure.add_subplot(2, 2, 4) - self.longitudinal_scattering_axes.set_visible(False) fit_results_layout.addWidget(self.fit_results_canvas) + # Set visibility + self.hide_everything() + def importData(self): """ Callback for the import data button """ @@ -89,23 +89,22 @@ def importData(self): log.info(f"Loaded {len(self.data)} datasets") self.hide_everything() + self.plot_tabs.setTabEnabled(0, True) self.plot_data() - def hide_everything(self): - - self.data_axes.set_visible(False) - self.chi_squared_axes.set_visible(False) - self.residuals_axes.set_visible(False) - self.s_h_axes.set_visible(False) - self.longitudinal_scattering_axes.set_visible(False) + """ Hide all plots, disable tabs""" self.data_axes.cla() self.chi_squared_axes.cla() - self.residuals_axes.cla() + self.residual_axes.cla() self.s_h_axes.cla() self.longitudinal_scattering_axes.cla() + self.plot_tabs.setTabEnabled(1, False) + self.plot_tabs.setTabEnabled(2, False) + # weird order because of how the widget behaves when all are not enabled + self.plot_tabs.setTabEnabled(0, False) def plot_data(self): @@ -133,12 +132,12 @@ def plot_data(self): self.data_axes.set_xlim(qlim) self.data_axes.set_ylim(ilim) self.data_figure.tight_layout() - + self.data_axes.set_visible(True) self.data_figure.canvas.draw() - def fit_parameters(self) -> FitParameters: + def get_fit_parameters(self) -> FitParameters: """ Get an object containing all the parameters needed for doing the fitting """ a_min = self.aMinSpinBox.value() @@ -163,26 +162,13 @@ def fit_parameters(self) -> FitParameters: exchange_A_max=a_max, experiment_geometry=geometry) - def simple_fit_button_callback(self): + def onFit(self): if self.data is None: log.error("No data loaded") return None - # Clear axes - self.data_axes.cla() - self.chi_squared_axes.cla() - self.residuals_axes.cla() - self.s_h_axes.cla() - self.longitudinal_scattering_axes.cla() - - # Set axes visibility - self.data_axes.set_visible(False) - self.chi_squared_axes.set_visible(True) - self.residuals_axes.set_visible(True) - self.s_h_axes.set_visible(True) - - parameters = self.fit_parameters() + parameters = self.get_fit_parameters() match parameters.experiment_geometry: case ExperimentGeometry.PERPENDICULAR: @@ -192,11 +178,84 @@ def simple_fit_button_callback(self): case _: raise ValueError(f"Unknown Value: {parameters.experiment_geometry}") + self.fit_data = MuMagLib.simple_fit(self.data, parameters) + + self.show_fit_results() + + + def show_fit_results(self): + """ Show the results of the fit in the widget """ + + # Check for data + if self.fit_data is None: + log.error("No fit data to show") + return + + # Some dereferencing to make things more readable + A_uncertainty = self.fit_data.optimal_exchange_A_uncertainty + refined = self.fit_data.refined_fit_data + sweep_data = self.fit_data.sweep_data + + # Text to show TODO: Replace with field in dialog + if A_uncertainty < 1e-4: + A_uncertainty = 0 - self.fit_data = MuMagLib.do_fit(self.data, parameters) + A_uncertainty_str = str(A_uncertainty) + A_opt_str = str(refined.exchange_A * 1e12) + + q = refined.q * 1e-9 + + # Clear plots + self.chi_squared_axes.cla() + self.residual_axes.cla() + self.s_h_axes.cla() + self.longitudinal_scattering_axes.cla() + + # Plot A search data + self.chi_squared_axes.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m') + self.chi_squared_axes.plot(sweep_data.exchange_A_checked * 1e12, sweep_data.exchange_A_chi_sq) + self.chi_squared_axes.plot(sweep_data.optimal.exchange_A * 1e12, sweep_data.optimal.exchange_A_chi_sq, 'o') + + self.chi_squared_axes.set_xlim([min(sweep_data.exchange_A_checked * 1e12), max(sweep_data.exchange_A_checked * 1e12)]) + self.chi_squared_axes.set_xlabel('$A$ [pJ/m]') + self.chi_squared_axes.set_ylabel('$\chi^2$') + + # Residual intensity plot + self.residual_axes.plot(q, refined.I_residual, label='fit') + self.residual_axes.set_yscale('log') + self.residual_axes.set_xscale('log') + self.residual_axes.set_xlim([min(q), max(q)]) + self.residual_axes.set_xlabel('$q$ [1/nm]') + self.residual_axes.set_ylabel('$I_{\mathrm{res}}$') + + # S_H parameter + self.s_h_axes.plot(q, refined.S_H, label='fit') + self.s_h_axes.set_yscale('log') + self.s_h_axes.set_xscale('log') + self.s_h_axes.set_xlim([min(q), max(q)]) + self.s_h_axes.set_xlabel('$q$ [1/nm]') + self.s_h_axes.set_ylabel('$S_H$') + + # S_M parameter + if isinstance(refined, LeastSquaresOutputPerpendicular): + self.longitudinal_scattering_axes.plot(q, refined.S_M, label='fit') + self.longitudinal_scattering_axes.set_yscale('log') + self.longitudinal_scattering_axes.set_xscale('log') + self.longitudinal_scattering_axes.set_xlim([min(q), max(q)]) + self.longitudinal_scattering_axes.set_xlabel('$q$ [1/nm]') + self.longitudinal_scattering_axes.set_ylabel('$S_M$') + + self.fit_results_figure.tight_layout() + + self.chi_squared_axes.set_visible(True) + self.residual_axes.set_visible(True) + self.s_h_axes.set_visible(True) + self.longitudinal_scattering_axes.set_visible(True) - self.figure_canvas.draw() + self.plot_tabs.setTabEnabled(1, True) + self.plot_tabs.setTabEnabled(2, True) + self.plot_tabs.setCurrentIndex(1) def compare_data_button_callback(self): @@ -204,14 +263,14 @@ def compare_data_button_callback(self): # Clear axes self.data_axes.cla() self.chi_squared_axes.cla() - self.residuals_axes.cla() + self.residual_axes.cla() self.s_h_axes.cla() self.longitudinal_scattering_axes.cla() # Set visibility self.data_axes.set_visible(True) self.chi_squared_axes.set_visible(False) - self.residuals_axes.set_visible(False) + self.residual_axes.set_visible(False) self.s_h_axes.set_visible(False) self.longitudinal_scattering_axes.set_visible(False) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 8cccaa19c5..2811933bef 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -89,7 +89,7 @@ def nice_log_plot_bounds(data: list[np.ndarray]): @staticmethod - def do_fit(data: list[ExperimentalData], parameters: FitParameters): + def simple_fit(data: list[ExperimentalData], parameters: FitParameters): """ Main fitting ("simple fit") """ geometry = parameters.experiment_geometry @@ -105,7 +105,7 @@ def do_fit(data: list[ExperimentalData], parameters: FitParameters): if datum.applied_field >= parameters.min_applied_field] # Brute force check for something near the minimum - sweep_data = MuMagLib.sweep(parameters, filtered_inputs) + sweep_data = MuMagLib.sweep_exchange_A(parameters, filtered_inputs) # Refine this result crude_A = sweep_data.optimal.exchange_A @@ -121,7 +121,7 @@ def do_fit(data: list[ExperimentalData], parameters: FitParameters): optimal_exchange_A_uncertainty=uncertainty) @staticmethod - def sweep(parameters: FitParameters, data: list[ExperimentalData]) -> SweepOutput: + def sweep_exchange_A(parameters: FitParameters, data: list[ExperimentalData]) -> SweepOutput: """ Sweep over Exchange Stiffness A for perpendicular SANS geometry to get an initial estimate which can then be refined""" @@ -131,10 +131,10 @@ def sweep(parameters: FitParameters, data: list[ExperimentalData]) -> SweepOutpu parameters.exchange_A_n) * 1e-12 # From pJ/m to J/m if parameters.experiment_geometry == ExperimentGeometry.PERPENDICULAR: - least_squared_fits = [MuMagLib.LSQ_PERP(data, a) for a in a_values] + least_squared_fits = [MuMagLib.least_squares_perpendicular(data, a) for a in a_values] elif parameters.experiment_geometry == ExperimentGeometry.PARALLEL: - least_squared_fits = [MuMagLib.LSQ_PAR(data, a) for a in a_values] + least_squared_fits = [MuMagLib.least_squares_parallel(data, a) for a in a_values] else: raise ValueError(f"Unknown ExperimentGeometry value: {parameters.experiment_geometry}") @@ -149,7 +149,7 @@ def sweep(parameters: FitParameters, data: list[ExperimentalData]) -> SweepOutpu optimal=optimal_fit) @staticmethod - def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutputPerpendicular: + def least_squares_perpendicular(data: list[ExperimentalData], A) -> LeastSquaresOutputPerpendicular: """ Least squares fitting for a given exchange stiffness, A, perpendicular case We are fitting the equation: @@ -271,7 +271,7 @@ def LSQ_PERP(data: list[ExperimentalData], A) -> LeastSquaresOutputPerpendicular @staticmethod - def LSQ_PAR(data: list[ExperimentalData], A): + def least_squares_parallel(data: list[ExperimentalData], A): """ Least squares fitting for a given exchange stiffness, A, parallel case @@ -391,9 +391,9 @@ def refine_exchange_A( match geometry: case ExperimentGeometry.PARALLEL: - least_squares_function = MuMagLib.LSQ_PAR + least_squares_function = MuMagLib.least_squares_parallel case ExperimentGeometry.PERPENDICULAR: - least_squares_function = MuMagLib.LSQ_PERP + least_squares_function = MuMagLib.least_squares_perpendicular case _: raise ValueError(f"Unknown experimental geometry: {geometry}") @@ -438,9 +438,9 @@ def uncertainty( match geometry: case ExperimentGeometry.PARALLEL: - least_squares_function = MuMagLib.LSQ_PAR + least_squares_function = MuMagLib.least_squares_parallel case ExperimentGeometry.PERPENDICULAR: - least_squares_function = MuMagLib.LSQ_PERP + least_squares_function = MuMagLib.least_squares_perpendicular case _: raise ValueError(f"Unknown experimental geometry: {geometry}") @@ -596,59 +596,6 @@ def save_button_callback(self): - @staticmethod - def plot_results(sweep_data: SweepOutput, - refined: LeastSquaresOutputPerpendicular | LeastSquaresOutputParallel, - A_Uncertainty, - figure, axes1, axes2, axes3, axes4): - - if A_Uncertainty < 1e-4: - A_Uncertainty = 0 - - A_uncertainty_str = str(A_Uncertainty) - A_opt_str = str(refined.exchange_A * 1e12) - - q = refined.q * 1e-9 - - # Plot A search data - - axes1.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m') - axes1.plot(sweep_data.exchange_A_checked * 1e12, sweep_data.exchange_A_chi_sq) - axes1.plot(sweep_data.optimal.exchange_A * 1e12, sweep_data.optimal.exchange_A_chi_sq, 'o') - - axes1.set_xlim([min(sweep_data.exchange_A_checked * 1e12), max(sweep_data.exchange_A_checked * 1e12)]) - axes1.set_xlabel('$A$ [pJ/m]') - axes1.set_ylabel('$\chi^2$') - - # Residual intensity plot - - axes2.plot(q, refined.I_residual, label='fit') - axes2.set_yscale('log') - axes2.set_xscale('log') - axes2.set_xlim([min(q), max(q)]) - axes2.set_xlabel('$q$ [1/nm]') - axes2.set_ylabel('$I_{\mathrm{res}}$') - - # S_H parameter - - axes3.plot(q, refined.S_H, label='fit') - axes3.set_yscale('log') - axes3.set_xscale('log') - axes3.set_xlim([min(q), max(q)]) - axes3.set_xlabel('$q$ [1/nm]') - axes3.set_ylabel('$S_H$') - - # S_M parameter - if isinstance(refined, LeastSquaresOutputPerpendicular): - axes4.plot(q, refined.S_M, label='fit') - axes4.set_yscale('log') - axes4.set_xscale('log') - axes4.set_xlim([min(q), max(q)]) - axes4.set_xlabel('$q$ [1/nm]') - axes4.set_ylabel('$S_M$') - - figure.tight_layout() - ################################################################################################################# def SimpleFit_CompareButtonCallback(self, figure, axes): From 28fb43e3f41596acba6962baae3d9aa1e579083a Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Mon, 10 Jun 2024 17:21:56 +0100 Subject: [PATCH 36/46] Almost done, just need to adjust plots --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 111 ++-- src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py | 293 ++++------- .../qtgui/Utilities/MuMagTool/UI/MuMagUI.ui | 487 +++++++++++------- .../qtgui/Utilities/MuMagTool/fit_result.py | 3 +- 4 files changed, 472 insertions(+), 422 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index 734e6b9ca3..aa7bef2e71 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -1,17 +1,16 @@ from sas.qtgui.Utilities.MuMagTool.UI.MuMagUI import Ui_MuMagTool -from PySide6.QtWidgets import QWidget, QVBoxLayout +from PySide6.QtWidgets import QVBoxLayout from PySide6 import QtWidgets from sas.qtgui.Utilities.MuMagTool import MuMagLib from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas -# from matplotlib.figure import Figure import matplotlib.pyplot as plt import matplotlib.pylab as pl import numpy as np from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.failure import LoadFailure +from sas.qtgui.Utilities.MuMagTool.failure import LoadFailure, FitFailure from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry from sas.qtgui.Utilities.MuMagTool.MuMagLib import MuMagLib @@ -23,6 +22,8 @@ log = getLogger("MuMag") class MuMag(QtWidgets.QMainWindow, Ui_MuMagTool): + """ Main widget for the MuMag tool """ + def __init__(self, parent=None): super().__init__() @@ -31,8 +32,7 @@ def __init__(self, parent=None): # Callbacks self.ImportDataButton.clicked.connect(self.importData) self.SimpleFitButton.clicked.connect(self.onFit) - self.CompareResultsButton.clicked.connect(self.compare_data_button_callback) - self.SaveResultsButton.clicked.connect(self.save_data_button_callback) + self.SaveResultsButton.clicked.connect(self.onSave) # # Data @@ -67,6 +67,16 @@ def __init__(self, parent=None): fit_results_layout.addWidget(self.fit_results_canvas) + # Comparison + comparison_layout = QVBoxLayout() + self.comparison_tab.setLayout(comparison_layout) + self.comparison_figure = plt.figure() + self.comparison_canvas = FigureCanvas(self.comparison_figure) + + self.comparison_axes = self.comparison_figure.add_subplot(1, 1, 1) + + comparison_layout.addWidget(self.comparison_canvas) + # Set visibility self.hide_everything() @@ -90,7 +100,7 @@ def importData(self): self.hide_everything() self.plot_tabs.setTabEnabled(0, True) - self.plot_data() + self.show_input_data() def hide_everything(self): """ Hide all plots, disable tabs""" @@ -107,7 +117,7 @@ def hide_everything(self): self.plot_tabs.setTabEnabled(0, False) - def plot_data(self): + def show_input_data(self): """ Plot Experimental Data: Generate Figure """ colors = pl.cm.jet(np.linspace(0, 1, len(self.data))) @@ -176,9 +186,15 @@ def onFit(self): case ExperimentGeometry.PARALLEL: self.longitudinal_scattering_axes.set_visible(False) case _: - raise ValueError(f"Unknown Value: {parameters.experiment_geometry}") + raise log.error(f"Unknown geometry: {parameters.experiment_geometry}") + + try: + self.fit_data = MuMagLib.simple_fit(self.data, parameters) + + except FitFailure as ff: + log.error("Fitting failed - are the parameters correct? "+repr(ff)) + return - self.fit_data = MuMagLib.simple_fit(self.data, parameters) self.show_fit_results() @@ -192,18 +208,17 @@ def show_fit_results(self): return # Some dereferencing to make things more readable - A_uncertainty = self.fit_data.optimal_exchange_A_uncertainty refined = self.fit_data.refined_fit_data sweep_data = self.fit_data.sweep_data - # Text to show TODO: Replace with field in dialog - if A_uncertainty < 1e-4: - A_uncertainty = 0 + q = refined.q * 1e-9 + + # Update text boxes + + self.exchange_a_display.setText(f"{self.fit_data.refined_fit_data.exchange_A * 1e12 : .5g} pJ/m") + self.exchange_a_std_display.setText(f"{self.fit_data.optimal_exchange_A_uncertainty : .5g} pJ/m") - A_uncertainty_str = str(A_uncertainty) - A_opt_str = str(refined.exchange_A * 1e12) - q = refined.q * 1e-9 # Clear plots self.chi_squared_axes.cla() @@ -212,7 +227,6 @@ def show_fit_results(self): self.longitudinal_scattering_axes.cla() # Plot A search data - self.chi_squared_axes.set_title('$A_{\mathrm{opt}} = (' + A_opt_str[0:5] + ' \pm ' + A_uncertainty_str[0:4] + ')$ pJ/m') self.chi_squared_axes.plot(sweep_data.exchange_A_checked * 1e12, sweep_data.exchange_A_chi_sq) self.chi_squared_axes.plot(sweep_data.optimal.exchange_A * 1e12, sweep_data.optimal.exchange_A_chi_sq, 'o') @@ -252,35 +266,60 @@ def show_fit_results(self): self.s_h_axes.set_visible(True) self.longitudinal_scattering_axes.set_visible(True) - self.plot_tabs.setTabEnabled(1, True) - self.plot_tabs.setTabEnabled(2, True) + # + # Comparison Tab + # - self.plot_tabs.setCurrentIndex(1) + # Plot limits + qlim = MuMagLib.nice_log_plot_bounds([datum.scattering_curve.x for datum in self.data]) + ilim = MuMagLib.nice_log_plot_bounds([datum.scattering_curve.y for datum in self.data]) + # Show the experimental data + # colors = pl.cm.jet(np.linspace(0, 1, len(self.fit_data.input_data))) + # for k, datum in enumerate(self.fit_data.input_data): + # self.comparison_axes.loglog( + # datum.scattering_curve.x, + # datum.scattering_curve.y, + # linestyle='dotted', color=colors[k], linewidth=0.3, markersize=1) + + n_sim = self.fit_data.refined_fit_data.I_simulated.shape[0] + colors = pl.cm.YlGn(np.linspace(0, 1, n_sim)) + for k in range(0, n_sim): + self.comparison_axes.loglog( + self.fit_data.refined_fit_data.q, + self.fit_data.refined_fit_data.I_simulated[k, :], + linestyle='solid', color=colors[k], + linewidth=0.5, label='(fit) B_0 = ' + str(self.fit_data.input_data[k].applied_field) + ' T') + + self.comparison_axes.set_xlabel(r'$q$ [1/nm]') + self.comparison_axes.set_ylabel(r'$I_{\mathrm{exp}}$') + self.comparison_axes.set_xlim(qlim) + self.comparison_axes.set_ylim(ilim) + self.comparison_figure.tight_layout() + self.comparison_figure.canvas.draw() - def compare_data_button_callback(self): - # Clear axes - self.data_axes.cla() - self.chi_squared_axes.cla() - self.residual_axes.cla() - self.s_h_axes.cla() - self.longitudinal_scattering_axes.cla() + # + # Set up tabs + # - # Set visibility - self.data_axes.set_visible(True) - self.chi_squared_axes.set_visible(False) - self.residual_axes.set_visible(False) - self.s_h_axes.set_visible(False) - self.longitudinal_scattering_axes.set_visible(False) + self.plot_tabs.setTabEnabled(1, True) + self.plot_tabs.setTabEnabled(2, True) - self.MuMagLib_obj.SimpleFit_CompareButtonCallback(self.data_figure, self.data_axes) + self.plot_tabs.setCurrentIndex(1) + def onSave(self): + """ Save button pressed """ + if self.fit_data is None: + log.error("Nothing to save!") + return + + directory = MuMagLib.directory_popup() - def save_data_button_callback(self): - self.MuMagLib_obj.save_button_callback() + if directory is not None: + MuMagLib.save_data(self.fit_data, directory) def main(): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py index 2811933bef..63c089996e 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py @@ -10,7 +10,7 @@ from PySide6.QtWidgets import QFileDialog from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.failure import LoadFailure +from sas.qtgui.Utilities.MuMagTool.failure import LoadFailure, FitFailure from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular, \ @@ -115,7 +115,8 @@ def simple_fit(data: list[ExperimentalData], parameters: FitParameters): uncertainty = MuMagLib.uncertainty(filtered_inputs, refined.exchange_A, geometry) * 1e12 return FitResults( - input_data=data, + parameters=parameters, + input_data=filtered_inputs, sweep_data=sweep_data, refined_fit_data=refined, optimal_exchange_A_uncertainty=uncertainty) @@ -225,10 +226,7 @@ def least_squares_perpendicular(data: list[ExperimentalData], A) -> LeastSquares np.matmul(least_squares_x.T, least_squares_y)) except ValueError as ve: - print("Value Error:") - print(" A =", A) - - raise ve + raise FitFailure(f"A = {A} ({repr(ve)})") I_residual.append(fit_result[0][0]) S_H.append(fit_result[0][1]) @@ -342,10 +340,7 @@ def least_squares_parallel(data: list[ExperimentalData], A): np.matmul(least_squares_x.T, least_squares_y)) except ValueError as ve: - print("Value Error:") - print(" A =", A) - - raise ve + raise FitFailure(f"A = {A} ({repr(ve)})") I_residual.append(fit_result[0][0]) S_H.append(fit_result[0][1]) @@ -467,198 +462,102 @@ def uncertainty( return np.sqrt(2 / (n_field_strengths * n_q * d2chi_dA2)) - def save_button_callback(self): - - SimpleFit_q_exp = self.SimpleFit_q_exp - SimpleFit_I_exp = self.SimpleFit_I_exp - SimpleFit_sigma_exp = self.SimpleFit_sigma_exp - SimpleFit_B_0_exp = self.SimpleFit_B_0_exp - SimpleFit_Ms_exp = self.SimpleFit_Ms_exp - SimpleFit_Hdem_exp = self.SimpleFit_Hdem_exp - SimpleFit_I_fit = self.SimpleFit_I_fit - SimpleFit_A = self.SimpleFit_A - SimpleFit_chi_q = self.SimpleFit_chi_q - SimpleFit_S_H_fit = self.SimpleFit_S_H_fit - SimpleFit_S_M_fit = self.SimpleFit_S_M_fit - SimpleFit_I_res_fit = self.SimpleFit_I_res_fit - SimpleFit_A_opt = self.SimpleFit_A_opt - SimpleFit_chi_q_opt = self.SimpleFit_chi_q_opt - SimpleFit_A_sigma = self.SimpleFit_A_sigma - SimpleFit_SANSgeometry = self.SimpleFit_SANSgeometry - - print('hello') - print(np.size(SimpleFit_q_exp)) - - if np.size(SimpleFit_q_exp) > 1: - if SimpleFit_SANSgeometry == 'perpendicular': - DIR = QFileDialog.getExistingDirectory() - - now = datetime.now() - TimeStamp = now.strftime("%d_%m_%Y__%H_%M_%S") - FolderName = "SimpleFitResults_" + TimeStamp - path = os.path.join(DIR, FolderName) - os.mkdir(path) - - InfoFile = open(path + "/InfoFile.txt", "w") - InfoFile.write("FitMagneticSANS Toolbox - SimpleFit Results Info File \n\n") - InfoFile.write("Timestamp: " + TimeStamp + " \n\n") - InfoFile.write("SANS geometry: " + SimpleFit_SANSgeometry + "\n\n") - InfoFile.write("Maximal Scattering Vector: q_max = " + - str(np.amax(SimpleFit_q_exp*1e-9)) + " 1/nm \n") - InfoFile.write("Minimal Applied Field: mu_0*H_min = " + - str(np.around(np.amin(SimpleFit_B_0_exp), 0)) + " mT \n\n") - InfoFile.write("Result for the exchange stiffness constant: A = (" + - str(np.around(SimpleFit_A_opt*1e12, 3)) + " +/- " + - str(np.around(SimpleFit_A_sigma*1e12, 2)) + ") pJ/m \n") - InfoFile.close() - - FolderName2 = "SANS_Intensity_Fit" - path2 = os.path.join(path, FolderName2) - os.mkdir(path2) - - for k in np.arange(0, np.size(SimpleFit_B_0_exp)): - np.savetxt(os.path.join(path2, str(k+1) + "_" + str(SimpleFit_B_0_exp[k]) + "_" - + str(SimpleFit_Ms_exp[k]) + "_" + str(SimpleFit_Hdem_exp[k]) + ".csv"), - np.array([SimpleFit_q_exp[k, :].T, SimpleFit_I_fit[k, :].T]).T, delimiter=" ") - - FolderName3 = "SANS_Intensity_Exp" - path3 = os.path.join(path, FolderName3) - os.mkdir(path3) - - for k in np.arange(0, np.size(SimpleFit_B_0_exp)): - np.savetxt(os.path.join(path3, str(k+1) + "_" + str(SimpleFit_B_0_exp[k]) + "_" - + str(SimpleFit_Ms_exp[k]) + "_" + str(SimpleFit_Hdem_exp[k]) + ".csv"), - np.array([SimpleFit_q_exp[k, :].T, SimpleFit_I_exp[k, :].T, - SimpleFit_sigma_exp[k, :]]).T, delimiter=" ") - - FolderName4 = "Fit_Results" - path4 = os.path.join(path, FolderName4) - os.mkdir(path4) - - np.savetxt(os.path.join(path4, "chi.csv"), np.array([SimpleFit_A, SimpleFit_chi_q]).T, delimiter=" ") - np.savetxt(os.path.join(path4, "S_H.csv"), np.array([SimpleFit_q_exp[0, :].T, - SimpleFit_S_H_fit[0, :]]).T, delimiter=" ") - np.savetxt(os.path.join(path4, "S_M.csv"), np.array([SimpleFit_q_exp[0, :].T, - SimpleFit_S_M_fit[0, :]]).T, delimiter=" ") - np.savetxt(os.path.join(path4, "I_res.csv"), np.array([SimpleFit_q_exp[0, :].T, - SimpleFit_I_res_fit[0, :]]).T, delimiter=" ") - - elif SimpleFit_SANSgeometry == 'parallel': - DIR = QFileDialog.getExistingDirectory() - - now = datetime.now() - TimeStamp = now.strftime("%d_%m_%Y__%H_%M_%S") - FolderName = "SimpleFitResults_" + TimeStamp - path = os.path.join(DIR, FolderName) - os.mkdir(path) - - InfoFile = open(path + "/InfoFile.txt", "w") - InfoFile.write("FitMagneticSANS Toolbox - SimpleFit Results Info File \n\n") - InfoFile.write("Timestamp: " + TimeStamp + " \n\n") - InfoFile.write("SANS geometry: " + SimpleFit_SANSgeometry + "\n\n") - InfoFile.write("Maximal Scattering Vector: q_max = " + - str(np.amax(SimpleFit_q_exp * 1e-9)) + " 1/nm \n") - InfoFile.write("Minimal Applied Field: mu_0*H_min = " + - str(np.around(np.amin(SimpleFit_B_0_exp), 0)) + " mT \n\n") - InfoFile.write("Result for the exchange stiffness constant: A = (" + - str(np.around(SimpleFit_A_opt * 1e12, 3)) + " +/- " + - str(np.around(SimpleFit_A_sigma * 1e12, 2)) + ") pJ/m \n") - InfoFile.close() - - FolderName2 = "SANS_Intensity_Fit" - path2 = os.path.join(path, FolderName2) - os.mkdir(path2) - - for k in np.arange(0, np.size(SimpleFit_B_0_exp)): - np.savetxt(os.path.join(path2, str(k + 1) + "_" + str(int(SimpleFit_B_0_exp[k])) + "_" + str( - int(SimpleFit_Ms_exp[k])) + "_" + str(int(SimpleFit_Hdem_exp[k])) + ".csv"), - np.array([SimpleFit_q_exp[k, :].T, SimpleFit_I_fit[k, :].T]).T, delimiter=" ") - - FolderName3 = "SANS_Intensity_Exp" - path3 = os.path.join(path, FolderName3) - os.mkdir(path3) - - for k in np.arange(0, np.size(SimpleFit_B_0_exp)): - np.savetxt(os.path.join(path3, str(k + 1) + "_" + str(int(SimpleFit_B_0_exp[k])) + "_" + str( - int(SimpleFit_Ms_exp[k])) + "_" + str(int(SimpleFit_Hdem_exp[k])) + ".csv"), - np.array([SimpleFit_q_exp[k, :].T, SimpleFit_I_exp[k, :].T, SimpleFit_sigma_exp[k, :]]).T, - delimiter=" ") - - FolderName4 = "Fit_Results" - path4 = os.path.join(path, FolderName4) - os.mkdir(path4) - - np.savetxt(os.path.join(path4, "chi.csv"), np.array([SimpleFit_A, SimpleFit_chi_q]).T, delimiter=" ") - np.savetxt(os.path.join(path4, "S_H.csv"), np.array([SimpleFit_q_exp[0, :].T, - SimpleFit_S_H_fit[0, :]]).T, delimiter=" ") - np.savetxt(os.path.join(path4, "I_res.csv"), np.array([SimpleFit_q_exp[0, :].T, - SimpleFit_I_res_fit[0, :]]).T, delimiter=" ") - - - - ################################################################################################################# - - def SimpleFit_CompareButtonCallback(self, figure, axes): - - SimpleFit_q_exp = self.SimpleFit_q_exp - SimpleFit_I_exp = self.SimpleFit_I_exp - SimpleFit_sigma_exp = self.SimpleFit_sigma_exp - SimpleFit_B_0_exp = self.SimpleFit_B_0_exp - SimpleFit_Ms_exp = self.SimpleFit_Ms_exp - SimpleFit_Hdem_exp = self.SimpleFit_Hdem_exp - SimpleFit_I_fit = self.SimpleFit_I_fit - SimpleFit_A = self.SimpleFit_A - SimpleFit_chi_q = self.SimpleFit_chi_q - SimpleFit_S_H_fit = self.SimpleFit_S_H_fit - SimpleFit_S_M_fit = self.SimpleFit_S_M_fit - SimpleFit_I_res_fit = self.SimpleFit_I_res_fit - SimpleFit_A_opt = self.SimpleFit_A_opt - SimpleFit_chi_q_opt = self.SimpleFit_chi_q_opt - SimpleFit_A_sigma = self.SimpleFit_A_sigma - SimpleFit_SANSgeometry = self.SimpleFit_SANSgeometry - - if np.size(SimpleFit_q_exp) > 1: - q_exp_min = np.amin(SimpleFit_q_exp) * 1e-9 - q_exp_min = 10 ** (np.floor(np.log10(q_exp_min))) * np.floor(q_exp_min / 10 ** (np.floor(np.log10(q_exp_min)))) - - q_exp_max = np.amax(SimpleFit_q_exp) * 1e-9 - q_exp_max = 10 ** (np.floor(np.log10(q_exp_max))) * np.ceil(q_exp_max / 10 ** (np.floor(np.log10(q_exp_max)))) - - I_exp_min = np.amin(SimpleFit_I_exp) - I_exp_min = 10 ** (np.floor(np.log10(I_exp_min))) * np.floor(I_exp_min / 10 ** (np.floor(np.log10(I_exp_min)))) - - I_exp_max = np.amax(SimpleFit_I_exp) - I_exp_max = 10 ** (np.floor(np.log10(I_exp_max))) * np.ceil(I_exp_max / 10 ** (np.floor(np.log10(I_exp_max)))) - - self.PlotCompareExpFitData(figure, axes, SimpleFit_q_exp * 1e-9, SimpleFit_I_exp, SimpleFit_I_fit, SimpleFit_B_0_exp * 1e-3, q_exp_min, q_exp_max, I_exp_min, I_exp_max) - else: - messagebox.showerror(title="Error!", message="No SimpleFit results available!") + @staticmethod + def _filename_string(datum: ExperimentalData): + """ Get the filename string associated with a bit of experimental data """ + + return f"{datum.applied_field}_{datum.saturation_magnetisation}_{datum.demagnetising_field}" + + @staticmethod + def save_data(data: FitResults, directory: str): + """ Save the data """ + + now = datetime.now() + timestamp = now.strftime("%d-%m-%Y_%H-%M-%S") + output_folder = f"mumag_fit_{timestamp}" + path = os.path.join(directory, output_folder) + + if not os.path.exists(path): + os.mkdir(path) + + with open(os.path.join(path, "fit_info.txt"), "w") as fid: + fid.write(f"FitMagneticSANS Toolbox - SimpleFit Results Info File \n\n") + fid.write(f"Timestamp: {timestamp}\n") + fid.write(f"SANS geometry: {data.parameters.experiment_geometry.name}\n\n") + fid.write(f"Maximal Scattering Vector: q_max = {np.max(data.refined_fit_data.q)} /nm\n") + fid.write(f"Minimal Applied Field: mu_0*H_min = {data.input_data[0].applied_field}\n mT \n") + fid.write(f"Result for the exchange stiffness constant: " + f"A = {data.refined_fit_data.exchange_A} +- {data.optimal_exchange_A_uncertainty} pJ/m \n") + + # + # Save fitted data + # + + subpath = os.path.join(path, "intensity_fit") + + if not os.path.exists(subpath): + os.mkdir(subpath) + + for k, datum in enumerate(data.input_data): + + filename = f"{k}_" + MuMagLib._filename_string(datum) + ".csv" + + q = data.refined_fit_data.q + I = data.refined_fit_data.I_simulated[k, :] + + np.savetxt(os.path.join(subpath, filename), np.array([q, I]).T, delimiter=",") + + # + # Save original data (but truncated) + # + + subpath = os.path.join(path, "input_intensity") + + if not os.path.exists(subpath): + os.mkdir(subpath) + + for k, datum in enumerate(data.input_data): + filename = f"{k}_" + MuMagLib._filename_string(datum) + ".csv" + + q = datum.scattering_curve.x + I = datum.scattering_curve.y + dI = datum.scattering_curve.dy + + np.savetxt(os.path.join(subpath, filename), np.array([q, I, dI]).T, delimiter=",") + + # + # Optimised results + # + + np.savetxt(os.path.join(path, "chi.csv"), + np.array([ + data.sweep_data.exchange_A_checked, + data.sweep_data.exchange_A_chi_sq]).T, + delimiter=",") - def PlotCompareExpFitData(self, figure, axes, q, I_exp, I_fit, B_0, x_min, x_max, y_min, y_max): + np.savetxt(os.path.join(path, "S_H.csv"), + np.array([ + data.refined_fit_data.q, + data.refined_fit_data.S_H, + data.refined_fit_data.S_H_stdev]).T, + delimiter=",") - fig = figure - fig.tight_layout() - ax = axes + np.savetxt(os.path.join(path, "I_res.csv"), + np.array([ + data.refined_fit_data.q, + data.refined_fit_data.I_residual, + data.refined_fit_data.I_residual_stdev]).T, + delimiter=",") - colors = pl.cm.jet(np.linspace(0, 1, len(B_0))) - for k in np.arange(0, len(B_0)): - ax.loglog(q[k, :], I_exp[k, :], '.', color=colors[k], linewidth=0.3, markersize=1) + if data.parameters.experiment_geometry == ExperimentGeometry.PERPENDICULAR: + np.savetxt(os.path.join(path, "S_M.csv"), + np.array([ + data.refined_fit_data.q, + data.refined_fit_data.S_M, + data.refined_fit_data.S_M_stdev]).T, + delimiter=",") - colors = pl.cm.YlGn(np.linspace(0, 1, len(B_0))) - for k in np.arange(0, len(B_0)): - ax.plot(q[k, :], I_fit[k, :], linestyle='solid', color=colors[k], - linewidth=0.5, label='(fit) B_0 = ' + str(B_0[k]) + ' T') - ax.set_xlabel(r'$q$ [1/nm]') - ax.set_ylabel(r'$I_{\mathrm{exp}}$') - ax.set_xlim(x_min, x_max) - ax.set_ylim(y_min, y_max) - figure.tight_layout() - figure.canvas.draw() -if __name__ == "__main__": - app = QtWidgets.QApplication([]) - # app.exec_() - MuMagLib.directory_popup() diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui index b9b1254452..9a6f114fb4 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui @@ -6,255 +6,366 @@ 0 0 - 549 - 481 + 819 + 480 MuMagTool - + - - - Import Data + + + QFrame::StyledPanel - - - - - Import Data - - - - - - - Plot Data - - - - - - - Simple Fit - - - - - - - Compare Results - - - - - - - Save Result - - - - - - - - - - Simple Fit Tool + + QFrame::Raised - + - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 7 - - - + + + GroupBox + + + + - Maximum q: + Import Data - - + + - Applied Field (μ<sub>0</sub> H<sub>min</sub>): + Fit - - - - - 0 + + + + Save Result + + + + + + + + + + Parameters + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - 5 - - - 10000.000000000000000 - - - 75.000000000000000 - - - - - + + 7 + + + - mT + Analysis Method: - - - - - - - - 0 - - - - - 5 - - - 0.000010000000000 - - - 0.010000000000000 - - - 0.600000000000000 - + + + + + 0 + + + + + Perpendicular + + + + Perpendicular + + + + + Parallel + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - + + - nm<sup>-1</sup> + Maximum q: - - - - - - - Exchange Coefficient (A): - - - - - - - - 0 - - - - - 100000.000000000000000 - - - 5.000000000000000 - + + + + + 0 + + + + + 5 + + + 0.000010000000000 + + + 0.010000000000000 + + + 0.600000000000000 + + + + + + + nm<sup>-1</sup> + + + + - - + + - to + Applied Field (μ<sub>0</sub> H<sub>min</sub>): - - - - 100000.000000000000000 - - - 20.000000000000000 - + + + + + 0 + + + + + 5 + + + 10000.000000000000000 + + + 75.000000000000000 + + + + + + + mT + + + + - - + + - pJ/m, + Scan Range for A: - - - - 10000 - - - 200 - + + + + + 0 + + + 0 + + + + + 100000.000000000000000 + + + 5.000000000000000 + + + + + + + to + + + + + + + 100000.000000000000000 + + + 20.000000000000000 + + + + + + + pJ/m + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - - steps - + + + + + 7 + + + 0 + + + 0 + + + 0 + + + + + 10000 + + + 200 + + + + + + + steps + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Results + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + - + + + A value: + + + + + - Analysis Method: + A uncertainty: - - - - 0 - - - - - Perpendicular - - - - Perpendicular - - - - - Parallel - - - - - + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -290,7 +401,7 @@ 0 0 - 549 + 819 20 diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py index 33b0e64e57..e05562ee71 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py +++ b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py @@ -3,7 +3,7 @@ import numpy as np from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.fit_parameters import ExperimentGeometry +from sas.qtgui.Utilities.MuMagTool.fit_parameters import ExperimentGeometry, FitParameters from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular, \ LeastSquaresOutputParallel from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput @@ -12,6 +12,7 @@ @dataclass class FitResults: """ Output the MuMag fit """ + parameters: FitParameters input_data: list[ExperimentalData] sweep_data: SweepOutput refined_fit_data: LeastSquaresOutputParallel | LeastSquaresOutputPerpendicular From c29f5c5f4883c70ae1f44b47202b13a134dcd4e0 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Mon, 10 Jun 2024 17:27:34 +0100 Subject: [PATCH 37/46] Done!!!!! --- src/sas/qtgui/Utilities/MuMagTool/MuMag.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py index aa7bef2e71..6fae9fe3d7 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMagTool/MuMag.py @@ -275,21 +275,22 @@ def show_fit_results(self): ilim = MuMagLib.nice_log_plot_bounds([datum.scattering_curve.y for datum in self.data]) # Show the experimental data - # colors = pl.cm.jet(np.linspace(0, 1, len(self.fit_data.input_data))) - # for k, datum in enumerate(self.fit_data.input_data): - # self.comparison_axes.loglog( - # datum.scattering_curve.x, - # datum.scattering_curve.y, - # linestyle='dotted', color=colors[k], linewidth=0.3, markersize=1) + colors = pl.cm.jet(np.linspace(0, 1, len(self.fit_data.input_data))) + for k, datum in enumerate(self.fit_data.input_data): + self.comparison_axes.loglog( + datum.scattering_curve.x, + datum.scattering_curve.y, + linestyle='dotted', color=colors[k], linewidth=0.3, markersize=1) + # Show the fitted curves n_sim = self.fit_data.refined_fit_data.I_simulated.shape[0] colors = pl.cm.YlGn(np.linspace(0, 1, n_sim)) - for k in range(0, n_sim): + for k in range(n_sim): self.comparison_axes.loglog( - self.fit_data.refined_fit_data.q, + self.fit_data.refined_fit_data.q * 1e-9, self.fit_data.refined_fit_data.I_simulated[k, :], linestyle='solid', color=colors[k], - linewidth=0.5, label='(fit) B_0 = ' + str(self.fit_data.input_data[k].applied_field) + ' T') + label='B_0 = ' + str(self.fit_data.input_data[k].applied_field) + ' T') self.comparison_axes.set_xlabel(r'$q$ [1/nm]') self.comparison_axes.set_ylabel(r'$I_{\mathrm{exp}}$') From cd7db0eb782eb892cfcb080c14ff4e840cec0bf3 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Mon, 10 Jun 2024 17:41:05 +0100 Subject: [PATCH 38/46] Tidying up --- src/sas/qtgui/MainWindow/GuiManager.py | 2 +- .../Utilities/{MuMagTool => MuMag}/MuMag.py | 14 +- .../{MuMagTool => MuMag}/MuMagLib.py | 9 +- .../10_1000_1340_10.csv | 0 .../11_2000_1340_10.csv | 0 .../12_3000_1340_10.csv | 0 .../13_8000_1340_10.csv | 0 .../1_0_1340_10.csv | 0 .../2_20_1340_10.csv | 0 .../3_35_1340_10.csv | 0 .../4_50_1340_10.csv | 0 .../5_75_1340_10.csv | 0 .../6_100_1340_10.csv | 0 .../7_200_1340_10.csv | 0 .../8_300_1340_10.csv | 0 .../9_600_1340_10.csv | 0 .../1_33_1640_22.874115.csv | 0 .../2_42_1640_23.456895.csv | 0 .../3_61_1640_23.748285.csv | 0 .../4_103_1640_24.039675.csv | 0 .../5_312_1640_24.331065.csv | 0 .../6_1270_1640_24.331065.csv | 0 .../1_8000_1600_1070.csv | 0 .../2_10000_1600_1070.csv | 0 .../3_12000_1600_1070.csv | 0 .../4_14000_1600_1070.csv | 0 .../5_16000_1600_1070.csv | 0 .../{MuMagTool => MuMag}/SANSData/__init__.py | 0 .../{MuMagTool => MuMag}/UI/MuMagUI.ui | 0 .../{MuMagTool => MuMag}/UI/__init__.py | 0 .../{MuMagTool => MuMag}/__init__.py | 0 .../qtgui/Utilities/MuMag/datastructures.py | 124 ++++++++++++++++++ .../Utilities/{MuMagTool => MuMag}/models.py | 2 + .../Utilities/MuMagTool/experimental_data.py | 29 ---- src/sas/qtgui/Utilities/MuMagTool/failure.py | 7 - .../Utilities/MuMagTool/fit_parameters.py | 20 --- .../qtgui/Utilities/MuMagTool/fit_result.py | 19 --- .../MuMagTool/least_squares_output.py | 30 ----- .../qtgui/Utilities/MuMagTool/sweep_output.py | 20 --- 39 files changed, 134 insertions(+), 142 deletions(-) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/MuMag.py (95%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/MuMagLib.py (97%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/SANSData/__init__.py (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/UI/MuMagUI.ui (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/UI/__init__.py (100%) rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/__init__.py (100%) create mode 100644 src/sas/qtgui/Utilities/MuMag/datastructures.py rename src/sas/qtgui/Utilities/{MuMagTool => MuMag}/models.py (98%) delete mode 100644 src/sas/qtgui/Utilities/MuMagTool/experimental_data.py delete mode 100644 src/sas/qtgui/Utilities/MuMagTool/failure.py delete mode 100644 src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py delete mode 100644 src/sas/qtgui/Utilities/MuMagTool/fit_result.py delete mode 100644 src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py delete mode 100644 src/sas/qtgui/Utilities/MuMagTool/sweep_output.py diff --git a/src/sas/qtgui/MainWindow/GuiManager.py b/src/sas/qtgui/MainWindow/GuiManager.py index ab701ce215..31043bce1a 100644 --- a/src/sas/qtgui/MainWindow/GuiManager.py +++ b/src/sas/qtgui/MainWindow/GuiManager.py @@ -35,7 +35,7 @@ from sas.qtgui.Utilities.OrientationViewer.OrientationViewer import show_orientation_viewer from sas.qtgui.Utilities.HidableDialog import hidable_dialog -from sas.qtgui.Utilities.MuMagTool.MuMag import MuMag +from sas.qtgui.Utilities.MuMag.MuMag import MuMag from sas.qtgui.Utilities.DocViewWidget import DocViewWindow from sas.qtgui.Utilities.DocRegenInProgess import DocRegenProgress diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py b/src/sas/qtgui/Utilities/MuMag/MuMag.py similarity index 95% rename from src/sas/qtgui/Utilities/MuMagTool/MuMag.py rename to src/sas/qtgui/Utilities/MuMag/MuMag.py index 6fae9fe3d7..907bcdb177 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMag/MuMag.py @@ -1,7 +1,7 @@ -from sas.qtgui.Utilities.MuMagTool.UI.MuMagUI import Ui_MuMagTool +from sas.qtgui.Utilities.MuMag.UI.MuMagUI import Ui_MuMagTool from PySide6.QtWidgets import QVBoxLayout from PySide6 import QtWidgets -from sas.qtgui.Utilities.MuMagTool import MuMagLib +from sas.qtgui.Utilities.MuMag import MuMagLib from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas import matplotlib.pyplot as plt @@ -9,16 +9,12 @@ import matplotlib.pylab as pl import numpy as np -from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.failure import LoadFailure, FitFailure -from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry -from sas.qtgui.Utilities.MuMagTool.MuMagLib import MuMagLib +from sas.qtgui.Utilities.MuMag.datastructures import ExperimentalData, LoadFailure, FitFailure, ExperimentGeometry, \ + FitParameters, FitResults, LeastSquaresOutputPerpendicular +from sas.qtgui.Utilities.MuMag.MuMagLib import MuMagLib from logging import getLogger -from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults -from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular - log = getLogger("MuMag") class MuMag(QtWidgets.QMainWindow, Ui_MuMagTool): diff --git a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py b/src/sas/qtgui/Utilities/MuMag/MuMagLib.py similarity index 97% rename from src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py rename to src/sas/qtgui/Utilities/MuMag/MuMagLib.py index 63c089996e..662e620278 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/MuMagLib.py +++ b/src/sas/qtgui/Utilities/MuMag/MuMagLib.py @@ -9,13 +9,8 @@ from PySide6 import QtWidgets from PySide6.QtWidgets import QFileDialog -from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.failure import LoadFailure, FitFailure -from sas.qtgui.Utilities.MuMagTool.fit_parameters import FitParameters, ExperimentGeometry -from sas.qtgui.Utilities.MuMagTool.fit_result import FitResults -from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular, \ - LeastSquaresOutputParallel -from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput +from sas.qtgui.Utilities.MuMag.datastructures import ExperimentalData, LoadFailure, FitFailure, ExperimentGeometry, \ + FitParameters, FitResults, LeastSquaresOutputParallel, LeastSquaresOutputPerpendicular, SweepOutput from sasdata.dataloader.loader import Loader diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv b/src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv rename to src/sas/qtgui/Utilities/MuMag/SANSData/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv diff --git a/src/sas/qtgui/Utilities/MuMagTool/SANSData/__init__.py b/src/sas/qtgui/Utilities/MuMag/SANSData/__init__.py similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/SANSData/__init__.py rename to src/sas/qtgui/Utilities/MuMag/SANSData/__init__.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMag/UI/MuMagUI.ui similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/UI/MuMagUI.ui rename to src/sas/qtgui/Utilities/MuMag/UI/MuMagUI.ui diff --git a/src/sas/qtgui/Utilities/MuMagTool/UI/__init__.py b/src/sas/qtgui/Utilities/MuMag/UI/__init__.py similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/UI/__init__.py rename to src/sas/qtgui/Utilities/MuMag/UI/__init__.py diff --git a/src/sas/qtgui/Utilities/MuMagTool/__init__.py b/src/sas/qtgui/Utilities/MuMag/__init__.py similarity index 100% rename from src/sas/qtgui/Utilities/MuMagTool/__init__.py rename to src/sas/qtgui/Utilities/MuMag/__init__.py diff --git a/src/sas/qtgui/Utilities/MuMag/datastructures.py b/src/sas/qtgui/Utilities/MuMag/datastructures.py new file mode 100644 index 0000000000..0cf59de57b --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMag/datastructures.py @@ -0,0 +1,124 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Generic + +import numpy as np + +from sas.qtgui.Plotting.PlotterData import Data1D + +from typing import TypeVar + +""" Data structures used in MuMag""" + +# +# Errors +# + + +class LoadFailure(Exception): + """ File loading failed """ + pass + + +class FitFailure(Exception): + """ Fit failed """ + pass + +# +# Enums +# + + +class ExperimentGeometry(Enum): + """ Type of experiment """ + PARALLEL = 1 + PERPENDICULAR = 2 + +# +# Data classes +# + + +@dataclass +class ExperimentalData: + """ Datapoint used as input for the MuMag tool""" + + scattering_curve: Data1D + + applied_field: float + saturation_magnetisation: float + demagnetising_field: float + + def restrict_by_index(self, max_index: int): + """ Remove all points from data up to given index""" + + x = self.scattering_curve.x[:max_index] + y = self.scattering_curve.y[:max_index] + dy = self.scattering_curve.dy[:max_index] + + return ExperimentalData( + scattering_curve=Data1D(x=x, y=y, dy=dy), + applied_field=self.applied_field, + saturation_magnetisation=self.saturation_magnetisation, + demagnetising_field=self.demagnetising_field) + + +@dataclass +class FitParameters: + """ Input parameters for the fit""" + q_max: float + min_applied_field: float + exchange_A_min: float + exchange_A_max: float + exchange_A_n: int + experiment_geometry: ExperimentGeometry + + +@dataclass +class LeastSquaresOutput: + """ Output from least squares method""" + exchange_A: float + exchange_A_chi_sq: float + q: np.ndarray + I_simulated: np.ndarray + I_residual: np.ndarray + S_H: np.ndarray + I_residual_stdev: np.ndarray + S_H_stdev: np.ndarray + + +@dataclass +class LeastSquaresOutputParallel(LeastSquaresOutput): + """ Output from least squares method for parallel case""" + pass + + +@dataclass +class LeastSquaresOutputPerpendicular(LeastSquaresOutput): + """ Output from least squares method for perpendicular case""" + S_M: np.ndarray + S_M_stdev: np.ndarray + + +T = TypeVar("T", bound=LeastSquaresOutput) + + +@dataclass +class SweepOutput(Generic[T]): + """ + Results from brute force optimisiation of the chi squared for the exchange A parameter + """ + + exchange_A_checked: np.ndarray + exchange_A_chi_sq: np.ndarray + optimal: T + + +@dataclass +class FitResults: + """ Output the MuMag fit """ + parameters: FitParameters + input_data: list[ExperimentalData] + sweep_data: SweepOutput + refined_fit_data: LeastSquaresOutputParallel | LeastSquaresOutputPerpendicular + optimal_exchange_A_uncertainty: float diff --git a/src/sas/qtgui/Utilities/MuMagTool/models.py b/src/sas/qtgui/Utilities/MuMag/models.py similarity index 98% rename from src/sas/qtgui/Utilities/MuMagTool/models.py rename to src/sas/qtgui/Utilities/MuMag/models.py index 548f22ce2b..2bd6579064 100644 --- a/src/sas/qtgui/Utilities/MuMagTool/models.py +++ b/src/sas/qtgui/Utilities/MuMag/models.py @@ -1,5 +1,7 @@ import numpy as np +""" Models that are useful for verifying results of MuMag """ + def LorentzianNoisyModelPERP(q, A, M_s, H_0, H_dem, a_H, a_M, l_c, beta): """ Lorentzian Model for the generation of noisy synthetic test data for perpendicular SANS geometry """ # All inputs in SI-units diff --git a/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py b/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py deleted file mode 100644 index 11302de6e4..0000000000 --- a/src/sas/qtgui/Utilities/MuMagTool/experimental_data.py +++ /dev/null @@ -1,29 +0,0 @@ -from dataclasses import dataclass - -import numpy as np - -from sas.qtgui.Plotting.PlotterData import Data1D - - -@dataclass -class ExperimentalData: - """ Datapoint used as input for the MuMag tool""" - - scattering_curve: Data1D - - applied_field: float - saturation_magnetisation: float - demagnetising_field: float - - def restrict_by_index(self, max_index: int): - """ Remove all points from data up to given index""" - - x = self.scattering_curve.x[:max_index] - y = self.scattering_curve.y[:max_index] - dy = self.scattering_curve.dy[:max_index] - - return ExperimentalData( - scattering_curve=Data1D(x=x, y=y, dy=dy), - applied_field=self.applied_field, - saturation_magnetisation=self.saturation_magnetisation, - demagnetising_field=self.demagnetising_field) diff --git a/src/sas/qtgui/Utilities/MuMagTool/failure.py b/src/sas/qtgui/Utilities/MuMagTool/failure.py deleted file mode 100644 index e8dfb573dd..0000000000 --- a/src/sas/qtgui/Utilities/MuMagTool/failure.py +++ /dev/null @@ -1,7 +0,0 @@ -class FitFailure(Exception): - """ Fit failed """ - pass - -class LoadFailure(Exception): - """ File loading failed """ - pass \ No newline at end of file diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py b/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py deleted file mode 100644 index 9828841cf9..0000000000 --- a/src/sas/qtgui/Utilities/MuMagTool/fit_parameters.py +++ /dev/null @@ -1,20 +0,0 @@ -from dataclasses import dataclass -from enum import Enum - - -class ExperimentGeometry(Enum): - """ Type of experiment """ - PARALLEL = 1 - PERPENDICULAR = 2 - - -@dataclass -class FitParameters: - """ Input parameters for the fit""" - q_max: float - min_applied_field: float - exchange_A_min: float - exchange_A_max: float - exchange_A_n: int - experiment_geometry: ExperimentGeometry - diff --git a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py b/src/sas/qtgui/Utilities/MuMagTool/fit_result.py deleted file mode 100644 index e05562ee71..0000000000 --- a/src/sas/qtgui/Utilities/MuMagTool/fit_result.py +++ /dev/null @@ -1,19 +0,0 @@ -from dataclasses import dataclass - -import numpy as np - -from sas.qtgui.Utilities.MuMagTool.experimental_data import ExperimentalData -from sas.qtgui.Utilities.MuMagTool.fit_parameters import ExperimentGeometry, FitParameters -from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutputPerpendicular, \ - LeastSquaresOutputParallel -from sas.qtgui.Utilities.MuMagTool.sweep_output import SweepOutput - - -@dataclass -class FitResults: - """ Output the MuMag fit """ - parameters: FitParameters - input_data: list[ExperimentalData] - sweep_data: SweepOutput - refined_fit_data: LeastSquaresOutputParallel | LeastSquaresOutputPerpendicular - optimal_exchange_A_uncertainty: float diff --git a/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py b/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py deleted file mode 100644 index 16f48b3ff6..0000000000 --- a/src/sas/qtgui/Utilities/MuMagTool/least_squares_output.py +++ /dev/null @@ -1,30 +0,0 @@ -from dataclasses import dataclass - -import numpy as np - - -@dataclass -class LeastSquaresOutput: - """ Output from least squares method""" - exchange_A: float - exchange_A_chi_sq: float - q: np.ndarray - I_simulated: np.ndarray - I_residual: np.ndarray - S_H: np.ndarray - I_residual_stdev: np.ndarray - S_H_stdev: np.ndarray - - -@dataclass -class LeastSquaresOutputParallel(LeastSquaresOutput): - """ Output from least squares method for parallel case""" - pass - - -@dataclass -class LeastSquaresOutputPerpendicular(LeastSquaresOutput): - """ Output from least squares method for perpendicular case""" - S_M: np.ndarray - S_M_stdev: np.ndarray - diff --git a/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py b/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py deleted file mode 100644 index e0644b0365..0000000000 --- a/src/sas/qtgui/Utilities/MuMagTool/sweep_output.py +++ /dev/null @@ -1,20 +0,0 @@ -from dataclasses import dataclass - -import numpy as np - -from sas.qtgui.Utilities.MuMagTool.least_squares_output import LeastSquaresOutput - -from typing import Generic, TypeVar - -T = TypeVar("T", bound=LeastSquaresOutput) - -@dataclass -class SweepOutput(Generic[T]): - """ - Results from brute force optimisiation of the chi squared for the exchange A parameter - """ - - exchange_A_checked: np.ndarray - exchange_A_chi_sq: np.ndarray - optimal: T - From e22e59c7fc03b15ef19aa248291c6d8db9963889 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Wed, 10 Jul 2024 13:31:03 +0100 Subject: [PATCH 39/46] Initial docs --- docs/sphinx-docs/source/user/tools.rst | 3 ++ .../Utilities/MuMag/media/mumag_help.rst | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst diff --git a/docs/sphinx-docs/source/user/tools.rst b/docs/sphinx-docs/source/user/tools.rst index 5559a8e37b..27dac8a98c 100644 --- a/docs/sphinx-docs/source/user/tools.rst +++ b/docs/sphinx-docs/source/user/tools.rst @@ -27,3 +27,6 @@ Tools & Utilities Image Viewer File Converter + + MuMag Tool + diff --git a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst new file mode 100644 index 0000000000..438daa6fd3 --- /dev/null +++ b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst @@ -0,0 +1,41 @@ +.. mumag_help.rst + +MuMag Tool +========== + +format of data files +-------------------- + +The experimental magnetic SANS data is expected to be stored in a separat folder for example named ExperimentalSANSData. Several informations of the experimental data must be given through the file names stored in the folder ExperimentalSANSData, as seen in the following: + + expected filenames: + + - 1_0_1340_10.csv + - 2_20_1340_10.csv + - 3_35_1340_10.csv + - 4_50_1340_10.csv + - ... + + 1. Identifier: Index of the files (e.g. 1, 2, 3, 4, ...) + 2. Identifier: Externally applied magnetic field μ_0 H_0 in mT (e.g. 0, 20, 25, 50, ...) + 3. Identifier: Saturation magnetization μ_0 M_s in mT (e.g. 1340, 1340, 1340, 1340, ...) + 4. Identifier: Demagnetization field μ_0 H_d in mT (e.g. 10, 10, 10, 10, 10, ...) + + (All these values could also be written as float number with dot separator e.g. 10.4345) + +Format of the data files: + ++------------+------------+------------+ +| q [1/nm] | I(q) | std | ++============+============+============+ +|3.62523e-2 |2.85917e+3 |2.28223e+1 | ++------------+------------+------------+ +|4.07000e-2 |1.03769e+3 |1.39076e+1 | ++------------+------------+------------+ +|4.51118e-2 |4.61741e+2 |9.64427e+1 | ++------------+------------+------------+ +|4.95924e-2 |2.83047e+2 |7.65175e+1 | ++------------+------------+------------+ + +Each of the files must have the same length and got to be sorted from the lowest to the highest q-value. In the files only the numerical data is stored, no headers. + From 47a2b05d1933e8f1ae88e1f53c2a33f6ae599145 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Wed, 10 Jul 2024 13:51:55 +0100 Subject: [PATCH 40/46] Help button --- src/sas/qtgui/Utilities/MuMag/MuMag.py | 5 ++++ src/sas/qtgui/Utilities/MuMag/UI/MuMagUI.ui | 26 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/sas/qtgui/Utilities/MuMag/MuMag.py b/src/sas/qtgui/Utilities/MuMag/MuMag.py index 907bcdb177..0479bc8e9d 100644 --- a/src/sas/qtgui/Utilities/MuMag/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMag/MuMag.py @@ -1,3 +1,5 @@ +import webbrowser + from sas.qtgui.Utilities.MuMag.UI.MuMagUI import Ui_MuMagTool from PySide6.QtWidgets import QVBoxLayout from PySide6 import QtWidgets @@ -29,6 +31,7 @@ def __init__(self, parent=None): self.ImportDataButton.clicked.connect(self.importData) self.SimpleFitButton.clicked.connect(self.onFit) self.SaveResultsButton.clicked.connect(self.onSave) + self.helpButton.clicked.connect(self.onHelp) # # Data @@ -318,6 +321,8 @@ def onSave(self): MuMagLib.save_data(self.fit_data, directory) + def onHelp(self): + webbrowser.open("https://www.sasview.org/docs/user/qtgui/Utilities/MuMag/mumag_help.html") def main(): """ Show a demo of the slider """ diff --git a/src/sas/qtgui/Utilities/MuMag/UI/MuMagUI.ui b/src/sas/qtgui/Utilities/MuMag/UI/MuMagUI.ui index 9a6f114fb4..a711e598a3 100644 --- a/src/sas/qtgui/Utilities/MuMag/UI/MuMagUI.ui +++ b/src/sas/qtgui/Utilities/MuMag/UI/MuMagUI.ui @@ -366,6 +366,32 @@ + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Help + + + + + + From f219d139c6480643b764f005f7a17b8da713a636 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Fri, 6 Dec 2024 11:07:22 +0000 Subject: [PATCH 41/46] Some docs --- .../Utilities/MuMag/media/mumag_help.rst | 82 ++++++++++++++----- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst index 438daa6fd3..101ef6e345 100644 --- a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst +++ b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst @@ -3,10 +3,22 @@ MuMag Tool ========== -format of data files --------------------- +Introduction +------------ -The experimental magnetic SANS data is expected to be stored in a separat folder for example named ExperimentalSANSData. Several informations of the experimental data must be given through the file names stored in the folder ExperimentalSANSData, as seen in the following: +Loading data +------------ + +To load data click on the `Import Data` button. This will give you a file chooser that allows you to select a +**directory**. This directory should contain multiple files for measurements take with different applied magnetic fields. + +Currently, *the magnetic field and other information is expected to be in filename with a format as described below* + +Form of Data Files +.................. + +The experimental magnetic SANS data for a given analysis is expected to be stored as CSV files in a single folder. +Information about each SANS scattering curve must be given through the file names, like in the following example: expected filenames: @@ -16,26 +28,56 @@ The experimental magnetic SANS data is expected to be stored in a separat folder - 4_50_1340_10.csv - ... - 1. Identifier: Index of the files (e.g. 1, 2, 3, 4, ...) - 2. Identifier: Externally applied magnetic field μ_0 H_0 in mT (e.g. 0, 20, 25, 50, ...) - 3. Identifier: Saturation magnetization μ_0 M_s in mT (e.g. 1340, 1340, 1340, 1340, ...) - 4. Identifier: Demagnetization field μ_0 H_d in mT (e.g. 10, 10, 10, 10, 10, ...) + The fields separated by underscores have the following meaning + + 1. Identifier: Index of the files (e.g. 1, 2, 3, 4, ...) - (not needed by MuMag) + 2. Identifier: Externally applied magnetic field :math:`μ_0 H_0` in mT (e.g. 0, 20, 25, 50, ...) + 3. Identifier: Saturation magnetization :math:`μ_0 M_s` in mT (e.g. 1340, 1340, 1340, 1340, ...) + 4. Identifier: Demagnetization field :math:`μ_0 H_d` in mT (e.g. 10, 10, 10, 10, 10, ...) (All these values could also be written as float number with dot separator e.g. 10.4345) -Format of the data files: +The CSV files are expected have three columns: momentum transfer :math:`q` in nm:math:`^{-1}`, +scattering intensity :math:`I(q)`, and the standard error corresponding to `I(q)`. + +Each of the files must have the same length and got to be sorted from the lowest to the highest q-value. +In the files only the numerical data is stored, no headers. + +Running MuMag +------------- + +To run MuMag, load the data, set the parameters below, and click `Fit`. + +Parameters +.......... + +* `Analysis method` - This chooses one of two experiment types. Perpendicular is where the applied +field is perpendicular to the beam (e.g. beam in x direction and field in z), and parallel where the applied field is parallel. + +* `Maximum q` - MuMag has the ability to exclude q values beyond a given value, specified here +* `Applied field` - MuMag will use only data with applied field strengths above this value. +MuMag requires the sample to be at (or close to) saturation, use this field to specify where this is. +* `Scan range` - When calculating the exchange stiffness constant A, +MuMag's minimisation step has two components. +(1) A brute for search, then (2) a refinement. +These three connected values that describe the values for which the brute force search will +take place, as well as the values that will appear on any plots. + +Results +....... + +* `A value` - The estimated exchange stiffness constant (A) +* `A uncertainty` - An estimate of the uncertainty associated with it + +Plots +..... -+------------+------------+------------+ -| q [1/nm] | I(q) | std | -+============+============+============+ -|3.62523e-2 |2.85917e+3 |2.28223e+1 | -+------------+------------+------------+ -|4.07000e-2 |1.03769e+3 |1.39076e+1 | -+------------+------------+------------+ -|4.51118e-2 |4.61741e+2 |9.64427e+1 | -+------------+------------+------------+ -|4.95924e-2 |2.83047e+2 |7.65175e+1 | -+------------+------------+------------+ -Each of the files must have the same length and got to be sorted from the lowest to the highest q-value. In the files only the numerical data is stored, no headers. +When you load data the `data` plot will be populated. When you click `fit` the rest will be. +* `Data` - A plot of all the loaded data +* `Fit Results` + * :math:`\chi^2` - figure of merit used by MuMag to calculate the best A value, across different +values of A (currently mean squared). This plot is useful to checking your problem is well conditioned. + * :math:`I_res` - The *residual intensity* - the part of the scattering that doesn't respond to +applied field changes, inferred from the data (see above for details) \ No newline at end of file From f9c999b372ec05020c8fa16a54c2877a0e7a774c Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Fri, 6 Dec 2024 11:28:01 +0000 Subject: [PATCH 42/46] More docs --- src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst index 101ef6e345..323a76f5fa 100644 --- a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst +++ b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst @@ -80,4 +80,7 @@ When you load data the `data` plot will be populated. When you click `fit` the r * :math:`\chi^2` - figure of merit used by MuMag to calculate the best A value, across different values of A (currently mean squared). This plot is useful to checking your problem is well conditioned. * :math:`I_res` - The *residual intensity* - the part of the scattering that doesn't respond to -applied field changes, inferred from the data (see above for details) \ No newline at end of file +applied field changes, inferred from the data (see above for details) + * :math:`S_H` - Anisotropy field scattering function + * :math:`S_M` - Scattering function of the longitudinal magnetization +* `Comparison` - \ No newline at end of file From 3d81f8d7f8c438510092cd58083630b40255e7a8 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Fri, 6 Dec 2024 11:49:34 +0000 Subject: [PATCH 43/46] Plotting update --- src/sas/qtgui/Utilities/MuMag/MuMag.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMag/MuMag.py b/src/sas/qtgui/Utilities/MuMag/MuMag.py index 0479bc8e9d..199ba9d7c3 100644 --- a/src/sas/qtgui/Utilities/MuMag/MuMag.py +++ b/src/sas/qtgui/Utilities/MuMag/MuMag.py @@ -279,11 +279,11 @@ def show_fit_results(self): self.comparison_axes.loglog( datum.scattering_curve.x, datum.scattering_curve.y, - linestyle='dotted', color=colors[k], linewidth=0.3, markersize=1) + linestyle='None', color=colors[k], marker='x') # Show the fitted curves n_sim = self.fit_data.refined_fit_data.I_simulated.shape[0] - colors = pl.cm.YlGn(np.linspace(0, 1, n_sim)) + colors = pl.cm.jet(np.linspace(0, 1, n_sim)) for k in range(n_sim): self.comparison_axes.loglog( self.fit_data.refined_fit_data.q * 1e-9, From 5e41d13fe6954d9f8b9b744a4d987eff66a75561 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Fri, 6 Dec 2024 12:07:43 +0000 Subject: [PATCH 44/46] More docs --- .../Utilities/MuMag/media/mumag_help.rst | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst index 323a76f5fa..1704f653b5 100644 --- a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst +++ b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst @@ -6,6 +6,24 @@ MuMag Tool Introduction ------------ +MuMag is an analysis tool for calculating exchange stiffness constants, residual scattering, anisotropy field +and longitudinal magnetization based on unpolarized 1D SANS experiments with applied magnetic fields. The theory +behind this has been published `here `_. + +Given some scattering curve recorded at different applied field intensities, :math:`I(q, H)`, MuMag will break +the down these curves into two (in the case of parallel magnetic fields) and three, components ( +for perpendicular fields relative to the beam). In the perpendicular case, the resulting linear +decomposition has the following form: + +:math:`I(q, H) = I_res(q) + S_H(q) R_H(q, H) + S_M(q) R_M(q, H)` + +Where :math:`R_H` and :math:`R_M` are known magnetic response functions (see the paper above), and :math:`I_res`, +:math:`S_H` and :math:`S_M` are non-field dependent terms: the residual scattering function, +the anisotropy field scattering function and the longitudinal magnetisation scattering function respectively. + +In the parallel case :math:`S_M` and :math:`R_M` are zero. + + Loading data ------------ @@ -83,4 +101,5 @@ values of A (currently mean squared). This plot is useful to checking your probl applied field changes, inferred from the data (see above for details) * :math:`S_H` - Anisotropy field scattering function * :math:`S_M` - Scattering function of the longitudinal magnetization -* `Comparison` - \ No newline at end of file +* `Comparison` - Crosses show original data, lines show scattering curves reconstructed based on :math:`I_res`, +:math:`S_H` and :math:`S_M` \ No newline at end of file From 68ae63b8d27fa2a6804aabb19c3275a7164c72b8 Mon Sep 17 00:00:00 2001 From: lucas-wilkins Date: Fri, 6 Dec 2024 12:20:31 +0000 Subject: [PATCH 45/46] Docs formatting --- .../Utilities/MuMag/media/mumag_help.rst | 58 ++++++++----------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst index 1704f653b5..e0c13e7d74 100644 --- a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst +++ b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst @@ -38,24 +38,24 @@ Form of Data Files The experimental magnetic SANS data for a given analysis is expected to be stored as CSV files in a single folder. Information about each SANS scattering curve must be given through the file names, like in the following example: - expected filenames: +Example filenames: - - 1_0_1340_10.csv - - 2_20_1340_10.csv - - 3_35_1340_10.csv - - 4_50_1340_10.csv - - ... +- 1_0_1340_10.csv +- 2_20_1340_10.csv +- 3_35_1340_10.csv +- 4_50_1340_10.csv +- ... - The fields separated by underscores have the following meaning +The fields separated by underscores have the following meaning - 1. Identifier: Index of the files (e.g. 1, 2, 3, 4, ...) - (not needed by MuMag) - 2. Identifier: Externally applied magnetic field :math:`μ_0 H_0` in mT (e.g. 0, 20, 25, 50, ...) - 3. Identifier: Saturation magnetization :math:`μ_0 M_s` in mT (e.g. 1340, 1340, 1340, 1340, ...) - 4. Identifier: Demagnetization field :math:`μ_0 H_d` in mT (e.g. 10, 10, 10, 10, 10, ...) +1. Index of the files (e.g. 1, 2, 3, 4, ...) - (not used by SasView's MuMag, but is used by the MATLAB version) +2. Externally applied magnetic field :math:`μ_0 H_0` in mT (e.g. 0, 20, 25, 50, ...) +3. Saturation magnetization :math:`μ_0 M_s` in mT (e.g. 1340, 1340, 1340, 1340, ...) +4. Demagnetization field :math:`μ_0 H_d` in mT (e.g. 10, 10, 10, 10, 10, ...) - (All these values could also be written as float number with dot separator e.g. 10.4345) +(All these values could also be written as float number with dot separator e.g. 10.4345) -The CSV files are expected have three columns: momentum transfer :math:`q` in nm:math:`^{-1}`, +The CSV files are expected have three columns: momentum transfer :math:`q` in nm :math:`^{-1}`, scattering intensity :math:`I(q)`, and the standard error corresponding to `I(q)`. Each of the files must have the same length and got to be sorted from the lowest to the highest q-value. @@ -69,23 +69,16 @@ To run MuMag, load the data, set the parameters below, and click `Fit`. Parameters .......... -* `Analysis method` - This chooses one of two experiment types. Perpendicular is where the applied -field is perpendicular to the beam (e.g. beam in x direction and field in z), and parallel where the applied field is parallel. - -* `Maximum q` - MuMag has the ability to exclude q values beyond a given value, specified here -* `Applied field` - MuMag will use only data with applied field strengths above this value. -MuMag requires the sample to be at (or close to) saturation, use this field to specify where this is. -* `Scan range` - When calculating the exchange stiffness constant A, -MuMag's minimisation step has two components. -(1) A brute for search, then (2) a refinement. -These three connected values that describe the values for which the brute force search will -take place, as well as the values that will appear on any plots. +* **Analysis method** - This chooses one of two experiment types. Perpendicular is where the applied field is perpendicular to the beam (e.g. beam in x direction and field in z), and parallel where the applied field is parallel. +* **Maximum q** - MuMag has the ability to exclude q values beyond a given value, specified here +* **Applied field** - MuMag will use only data with applied field strengths above this value. MuMag requires the sample to be at (or close to) saturation, use this field to specify where this is. +* **Scan range** - When calculating the exchange stiffness constant A, MuMag's minimisation step has two components. (1) A brute for search, then (2) a refinement. These three connected values that describe the values for which the brute force search will take place, as well as the values that will appear on any plots. Results ....... -* `A value` - The estimated exchange stiffness constant (A) -* `A uncertainty` - An estimate of the uncertainty associated with it +* **A value** - The estimated exchange stiffness constant (A) +* **A uncertainty** - An estimate of the uncertainty associated with it Plots ..... @@ -93,13 +86,10 @@ Plots When you load data the `data` plot will be populated. When you click `fit` the rest will be. -* `Data` - A plot of all the loaded data -* `Fit Results` - * :math:`\chi^2` - figure of merit used by MuMag to calculate the best A value, across different -values of A (currently mean squared). This plot is useful to checking your problem is well conditioned. - * :math:`I_res` - The *residual intensity* - the part of the scattering that doesn't respond to -applied field changes, inferred from the data (see above for details) +* **Data** - A plot of all the loaded data +* **Fit Results** + * :math:`\chi^2` - figure of merit used by MuMag to calculate the best A value, across different values of A (currently mean squared). This plot is useful to checking your problem is well conditioned. + * :math:`I_res` - The *residual intensity* - the part of the scattering that doesn't respond to applied field changes, inferred from the data (see above for details) * :math:`S_H` - Anisotropy field scattering function * :math:`S_M` - Scattering function of the longitudinal magnetization -* `Comparison` - Crosses show original data, lines show scattering curves reconstructed based on :math:`I_res`, -:math:`S_H` and :math:`S_M` \ No newline at end of file +* **Comparison** - Crosses show original data, lines show scattering curves reconstructed based on :math:`I_res`, :math:`S_H` and :math:`S_M` \ No newline at end of file From 09f9a8134ecd003935e793dc268792ac4a604f52 Mon Sep 17 00:00:00 2001 From: Lucas Wilkins Date: Thu, 12 Dec 2024 18:30:56 +0000 Subject: [PATCH 46/46] Typos in mumag_help.rst --- src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst index e0c13e7d74..0ff884eb75 100644 --- a/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst +++ b/src/sas/qtgui/Utilities/MuMag/media/mumag_help.rst @@ -11,7 +11,7 @@ and longitudinal magnetization based on unpolarized 1D SANS experiments with app behind this has been published `here `_. Given some scattering curve recorded at different applied field intensities, :math:`I(q, H)`, MuMag will break -the down these curves into two (in the case of parallel magnetic fields) and three, components ( +down these curves into two (in the case of parallel magnetic fields) and three, components ( for perpendicular fields relative to the beam). In the perpendicular case, the resulting linear decomposition has the following form: @@ -72,7 +72,7 @@ Parameters * **Analysis method** - This chooses one of two experiment types. Perpendicular is where the applied field is perpendicular to the beam (e.g. beam in x direction and field in z), and parallel where the applied field is parallel. * **Maximum q** - MuMag has the ability to exclude q values beyond a given value, specified here * **Applied field** - MuMag will use only data with applied field strengths above this value. MuMag requires the sample to be at (or close to) saturation, use this field to specify where this is. -* **Scan range** - When calculating the exchange stiffness constant A, MuMag's minimisation step has two components. (1) A brute for search, then (2) a refinement. These three connected values that describe the values for which the brute force search will take place, as well as the values that will appear on any plots. +* **Scan range** - When calculating the exchange stiffness constant A, MuMag's minimisation step has two components. (1) A brute for search, then (2) a refinement. These three values that describe the values for which the brute force search will take place (start, stop and step), as well as the values used for related plots. Results ....... @@ -92,4 +92,4 @@ When you load data the `data` plot will be populated. When you click `fit` the r * :math:`I_res` - The *residual intensity* - the part of the scattering that doesn't respond to applied field changes, inferred from the data (see above for details) * :math:`S_H` - Anisotropy field scattering function * :math:`S_M` - Scattering function of the longitudinal magnetization -* **Comparison** - Crosses show original data, lines show scattering curves reconstructed based on :math:`I_res`, :math:`S_H` and :math:`S_M` \ No newline at end of file +* **Comparison** - Crosses show original data, lines show scattering curves reconstructed based on :math:`I_res`, :math:`S_H` and :math:`S_M`