{"id":22418903,"url":"https://github.com/radi0sus/fit-mb","last_synced_at":"2025-06-17T03:06:55.153Z","repository":{"id":209404758,"uuid":"723972807","full_name":"radi0sus/fit-mb","owner":"radi0sus","description":"Python 3 script for (hassle-free) fitting of Mößbauer (MB) spectra","archived":false,"fork":false,"pushed_at":"2024-11-13T06:26:51.000Z","size":25353,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-27T04:32:01.541Z","etag":null,"topics":["fit","fitting","least-squares-optimization","levenberg-marquardt","lmfit","lorentz","lorentzian","mossbauer","mossbauer-spectroscopy","non-linear-optimization","python","python3","spectrum"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/radi0sus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-27T06:14:11.000Z","updated_at":"2024-11-13T06:26:54.000Z","dependencies_parsed_at":"2024-11-13T07:23:06.263Z","dependency_job_id":"dcd3665d-dd0e-40ce-9744-9b1825d604e2","html_url":"https://github.com/radi0sus/fit-mb","commit_stats":null,"previous_names":["radi0sus/fit-mb"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/radi0sus/fit-mb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radi0sus%2Ffit-mb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radi0sus%2Ffit-mb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radi0sus%2Ffit-mb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radi0sus%2Ffit-mb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/radi0sus","download_url":"https://codeload.github.com/radi0sus/fit-mb/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radi0sus%2Ffit-mb/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260281568,"owners_count":22985629,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fit","fitting","least-squares-optimization","levenberg-marquardt","lmfit","lorentz","lorentzian","mossbauer","mossbauer-spectroscopy","non-linear-optimization","python","python3","spectrum"],"created_at":"2024-12-05T16:13:17.740Z","updated_at":"2025-06-17T03:06:55.126Z","avatar_url":"https://github.com/radi0sus.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fit-MB\n\nA Python 3 script for (hassle-free) fitting of Mößbauer (MB) spectra. \n\nIt is easy to use but has some limitations. The script is limited to doublets \n(with no intensity differences) and singlets, cannot handle magnetic properties and is \nrestricted to Lorentzian lines shapes. \n\n\n## External modules\n\n`lmfit`\n`numpy` \n`scipy` \n`matplotlib`\n`tabulate`\n\n## Quick start\n\n1. Edit or create a parameter file (e.g. `mb-param.text`) with a text editor:\n\n    ```\n    #...\n    #\n    MB-data = example_data.dat\n    # \n    # ⇦ just a comment\n    #...\n    #----------------------------------------\n    # label |   δ    |  ΔEQ  | fwhm  | ratio\n    #----------------------------------------\n    L1Fe      -0.12    2.92    \n    L2Fe      -0.09    2.21   \n    # adjust    ⇧       ⇧\n    ```\n    `example_data.dat` is the file that contains data from measurement. \n    First column should contain velocity, second intensity. Recognized delimiters \n    are `,` or space(s).\n\n    The script can also process WissEl data (`.ws5`) directly. Three additional parameters\n    from a calibration (folding point: `FP`, channel in which the velocity is zero: `v0`,\n    and maximum velocity: `vmax`) must be included in the parameter file. It is also necessary\n    to change the number of channels directly in the script under `N_chan`, if the number\n    of channels is different from 512. You can obtain these parameters with `mcal` or\n    [cal-mb](https://github.com/radi0sus/cal-mb), for example.\n\n    ```\n    #...\n    # Note that FP, v0 and vmax must be specified. \n    MB-data = example_data.ws5\n    FP = 256.621\n    v0 = 125.282\n    vmax = -4.2622 \n    # \n    # ⇦ just a comment\n    #...\n    #----------------------------------------\n    # label |   δ    |  ΔEQ  | fwhm  | ratio\n    #----------------------------------------\n    L1Fe      -0.12    2.92    \n    L2Fe      -0.09    2.21   \n    # adjust    ⇧       ⇧\n    ```\n    The number of labels (e.g. `L1Fe`) is equivalent to the number of MB active species. \n    Furthermore rough estimates of $δ$ (isomer shift) and $ΔE_Q$ (quadrupol splitting) \n    are required.\n    \n    \u003e If the number of species is insufficient add or remove (or comment `#`) them\n    \u003e in the parameter file (e.g. `mb-param.text`) and restart the script as described\n    \u003e under **2**.\n\n3. Start the script with:\n\n    ```console\n    python3 mb-fit.py mb-param.txt\n    ```\n    \n    After the `matplotlib` window has opened, select a species in the upper legend. Simply \n    click on the **label** or the **radio button**. Adjust parameters for each species \n    with the **sliders** at the bottom of the window.  It should roughly agree with what \n    you expect. You can also **fix** some of the parameters, but in general this is not \n    necessary. Then press the **Fit button**.  \n    \n    \u003e You can also try to fit the data without adjusting any parameters. Simply click \n    \u003e **Fit**. In this example no alteration of the start parameters was necessary.\n       \n\u003cimg src='examples\\start-mod.png' alt='Start' width=600 align='center'\u003e    \n\n3. The result of the fit is displayed in the lower area, parameters and statistics are \n   also displayed in the terminal (console, cmd, std.out). Check if the results are okay. \n   Otherwise adjust the **sliders**  and click the **Fit button** again.\n   \n   \u003cimg src='examples\\fit.png' alt='Fit' width=600 align='center'\u003e   \n \n   Terminal output:\n   \n   ```\n   # Fit report for example_data\n   ## File statistics:\n   MB data     : example_data.dat\n   data points : 256\n   variables   : 9\n   \n   χ²          : 8.3411e-05\n   red. χ²     : 3.3770e-07\n   R²          : 0.9952\n\n   ## Fit results:\n   data in 1σ  : 30\n   data in 3σ  : 101\n   y0          : 0.9995±0.0001\n   \n   |   species |    δ /mm·s⁻¹ |   ΔEQ /mm·s⁻¹ |   fwhm /mm·s⁻¹ |   r (area)/% |   r (int)/% |\n   |-----------|--------------|---------------|----------------|--------------|-------------|\n   |      L1Fe |  0.669±0.016 |   1.637±0.026 |    0.877±0.049 |   20.26±0.93 |       19.85 |\n   |      L2Fe | -0.170±0.002 |   2.240±0.003 |    0.519±0.006 |   79.74±0.93 |       80.15 |\n   ```\n\n5. Finally save the results by clicking on the **Save** button. The optimized parameters \n   will be saved in `mb-param-fit.txt`, a fit report in `example_data-report.txt` \n   (similar to the last console output), raw data and the fitted curves in\n   `example_data-fit.dat` (a file which you can open in Gnuplot, Excel or Origin \n   for example) and the content of the lower plot area in `example_data-fit.png`.\n\u003cimg src='examples\\fit.png' alt='Fit' width=600 align='center'\u003e    \n   Terminal output:\n\n   ```\n   mb-param-fit.txt saved.\n   example_data-report.txt saved.\n   example_data-fit.dat saved.\n   example_data-fit.png saved.\n   ```\n   In the case of WissEl data, the folded spectrum is also saved (same output as above, plus):\n   ```\n   example_data-fold.dat saved.\n   ```  \n\n7. Exit.\n\n## Command-line options\n\n- filename, required: filename, e.g. `mb-param.txt`. A file, that contains the name (and\n  location) of the file that contains MB data and start parameters for the fit.\n  \n## Parameter file\n\nBelow is a sample parameter file with all necessary information. Important are the \nname (and location) of the file that contains MB data (`MB-data = example_data.dat`) \nand start parameters for the fit. The term `MB-data = ` must not be changed. In case \nof raw data from a multi-channel analyzer (WissEl .ws5 files for example), the terms \n`FP = `, `v0 = ` and `vmax = ` must not be changed. You can obtain these parameters \nfrom a calibration with `mcal` or [cal-mb](https://github.com/radi0sus/cal-mb), \nfor example.\n\nOnly label, $δ$ and $ΔE_Q$ are essential and the labeling must be unique. Every time \nsomething has changed in the parameter file, the script must be restarted.    \n\n\u003e Simply add or remove `#` before a label, to include or exclude a MB active species.\n\n\u003e It is strongly recommended to have the parameter file and the data file in the \n\u003e same directory. \n\n```\n#==============================================================================\n# Example of a MB parameter file for fit-mb.py\n#==============================================================================\n# This is a comment.\n# Lines starting with '#' are ignored by the script.\n#\n# The MB (raw) data file should contain 'velocity' (1st column) and \n# 'intensity' (2nd column). Further columns and lines starting with '#' \n# are ignored. Recognized delimiters are ',' or ' ' (whitespace(s)).\n# WissEl files '.ws5' are also accepted. \n# For WissEl '.ws5' files, 'FP' (folding point), 'v0' (channel in which \n# the velocity is zero) and 'vmax' (maximum velocity) must also be specified.\n#\n# The terms 'MB-data = ', FP =  ', 'v0 = ', and 'vmax = ' must not \n# be changed since they are recognized by the script. \n#\nMB-data = example_data.dat\nFP = 256.621\nv0 = 125.282\nvmax = -4.2622 \n#\n# The start parameters for the fit must be entered in the following order:\n#\n# label_1 δ_1 ΔEQ_1 fwhm_1 ratio_1\n# label_2 δ_2 ΔEQ_2 fwhm_2 ratio_2\n# label_3 δ_3 ΔEQ_3 fwhm_3 ratio_3\n# ...\n# \n# label =  unique atom / compound name\n# δ     =  isomeric shift in mm/s\n# ΔEQ   =  quadrupole splitting in mm/s; should be positive\n# fwhm  =  full width at half maximum; line width for broadening\n# ratio =  ratio of the MB active compound / nucleus\n#\n# At least one species with label, δ, ΔEQ must be defined.\n# The labeling must be unique (e.g. 'Fe1', 'Fe2', ...). Identical labels\n# (e.g. 'Fe1', 'Fe1', ...) lead to errors. Labels should be without\n# spaces (e.g. 'LFe1' or 'LFe_1' instead of 'LFe 1').\n#\n# 'fwhm' and 'ratio' are optional. If there is no value for 'fwhm', \n# but there is a value for 'ratio', 'ratio' is considered to be 'fwhm', \n# because the third parameter in the line is assumed to be 'fwhm'.\n# \n# If 'fwhm' is not specified it is set to 0.1. If 'fwhm' is not specified \n# then 'ratio' cannot be specified (see above remark).\n# \n# If 'ratio' is not specified it is set to 0.1.\n# Defining a ratio different from 1 or 100% can be useful if there is \n# a main component and an impurity which is also MB active\n# or a mixture of two or more compounds with MB active nuclei. \n# However, setting a 'ratio' as start parameter is just for orientation,\n# since the fit starts with a fixed value.\n#\n#----------------------------------------\n# label |   δ    |  ΔEQ  | fwhm  | ratio\n#----------------------------------------\n#L1Fe      0.24    1.51    0.33    0.40\n#L2Fe      0.25    3.12    0.39    0.35\n#L3Fe     -0.03    1.24    0.44    0.12\n#L4Fe     -0.06    0.61    0.37    0.13\nL1Fe       0.264   2.321   0.434   0.492\nL2Fe       0.279   1.551   0.427   0.508\n```\n\n## MB data file\n\nBelow is a sample data file. Lines starting with `#` are ignored. Only the first two \ncolumns are considered. The first column must contain the velocity, the second column\nmust contain the intensity data. Recognized delimiters are `,` and spaces.\n\n```\n# filename\n# sample: sample name\n# 80 K : temperature\n# 0 T  : field\n# 125.69, -4.693\n# ---------------------------\n -4.5893,   587126.4,       1\n -4.5525,   588314.7,       2\n -4.5157,   586286.4,       3\n -4.4789,   586907.1,       4\n -4.4421,   587216.4,       5\n -4.4052,   586408.4,       6\n....\n```\n\n## WissEl ws5 file\n\nBelow is a sample WissEl ws5 file. Lines starting with `\u003c` are ignored. It is necessary \nto change the number of channels directly in the script under `N_chan`, if the number of \nchannels is different from 512.\n\n\u003e In principle any raw data (not only WissEl) can be processed, as long as `FP`,\n\u003e `v0`, `vmax` are included in the parameter file.\n\n```\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?\u003e\n\u003cwissoft version=\"1.1\"\u003e\n\u003ccomment\u003ehttp://www.wissel-gmbh.de\u003c/comment\u003e\n\u003cdata channels=\"512\" time=\"0\"\u003e\n132130\n132207\n131879\n132294\n132142\n....\n```\n\n## Pre-fit plot \n\nThe pre-fit plot is in the upper part of the `matplotlib` window. The active species\nis selected in the **legend** of plot. The plot is updated if any of the parameters is \nchanged using the **sliders** at the bottom of the window. \nThe purpose of the pre-fit plot in combination with the **sliders** is to set the fitting \nparameters so that they roughly reflect the shape of the measured data.    \n\nIf `errbar_ws5 = True` is set in the script, error bars are displayed for folded raw \ndata (e.g. WissEl .ws5).\n\n\u003e The most important parameters to be changed are **$δ$** and **$ΔE_Q$**. **Fwhm** is \n\u003e recognized by the fitting procedure, but is less important. The **ratio** is only for \n\u003e orientation and is ignored as a start parameter for the fit.\n\n\u003cimg src='examples\\pre-fit.png' alt='Pre-fit' width=600 align='center'\u003e\n\n## Adjustment sliders and check (fix) buttons\n\nThere are four separate **sliders** for **$δ$** (isomer shift), **$ΔE_Q$** (quadropule \nsplitting), **fwhm** (full width at half maximum), and **ratio** (ratio of the species / \ncomponent). For the fit, the start value for **ratio** is always set to 0.1 regardless \nof the slider value. Changing the **ratio** is therefore only for orientation.     \n\nThree parameters can be fixed at a certain value with the check buttons **fix $δ$**, \n**fix $ΔE_Q$**, and **fix fwhm**. Fixed values are not changed during fit.      \n\nSelect the species/component in the **legend** of the diagram at the top and change the \nparameters for each component individually.\n\n\u003e The most important parameters to be changed are **$δ$** and **$ΔE_Q$**. **Fwhm** is \n\u003e recognized by the fitting procedure, but is less important. The **ratio** is only for \n\u003e orientation and is ignored as a start parameter for the fit.    \n\n\u003e If **$ΔE_Q$** is zero or close to zero and the fit fails, **$ΔE_Q$** should be \n\u003e **fixed** around **0**. In a subsequent fit, this **fix** can often be removed.     \n\n\u003cimg src='examples\\sliders.png' alt='Sliders' width=600 align='center'\u003e\n\n## Curve fitting\n\nAfter clicking on the **Fit button**, (raw) data, the fitted curves for each component, \nthe resulting curve and the residuals are displayed in the lower area of the plot window.\n\nThe **ratio** of the components (in %),  **$δ$** and **$ΔE_Q$** (in mm/s) and **$R^2$** \nare given in the legend. \n\nOptionally, the **3σ** uncertainty band can be displayed (set `plot_3s_band = True` in the \nscript). \n\nIf the result is not suitable, the parameters should be adjusted with the **sliders** \nand the **Fit** should be restarted.\n\n\u003e If a fit fails or is poor, try changing the number of species \n\u003e (components), **$δ$**, **$ΔE_Q$** and **fwhm** in that order. \n\n\u003cimg src='examples\\fit-detail.png' alt='Fit detail' width=600 align='center'\u003e\n\nThe terminal provides a more detailed fit report.\n\n```\n# Fit report for example_data\n## File statistics: \nMB data     : example_data.dat     ⇦ name of the file that contains the (raw) data\ndata points : 256                  ⇦ number of data points\nvariables   : 9                    ⇦ number of variables\n\nmean σ data : 9.2035e-04           ⇦ in case of .ws5 data (`weights` for χ² and red. χ²)\nχ²          : 8.3411e-05           ⇦ Chi square(d); close to the numer of data in case of .ws5 \nred. χ²     : 3.3770e-07           ⇦ reduced Chi square(d); close to 1 in case of .ws5 \nR²          : 0.9952               ⇦ R square(d)\n\n## Fit results:\ndata in 1σ  : 30                   ⇦ data points in 1σ (optional)\ndata in 3σ  : 101                  ⇦ data points in 3σ (optional)\ny0          : 0.9995±0.0001        ⇦ y0±error (offset)\n\n|   species |    δ /mm·s⁻¹ |   ΔEQ /mm·s⁻¹ |   fwhm /mm·s⁻¹ |   r (area)/% |   r (int)/% |\n|-----------|--------------|---------------|----------------|--------------|-------------|\n|      L1Fe |  0.669±0.016 |   1.637±0.026 |    0.877±0.049 |   20.26±0.93 |       19.85 |\n|      L2Fe | -0.170±0.002 |   2.240±0.003 |    0.519±0.006 |   79.74±0.93 |       80.15 |\n      ⇧             ⇧               ⇧                ⇧               ⇧              ⇧\n    label        δ±error       ΔEQ±error         fwhm±error     ratio from      ratio from  \n                                                                  area          integral \n```\n\n\u003e A good fit result has a **$R²$** close to **1** (\u003e 0.98) and a **χ²** below 1e⁻³ \n\u003e or less. But this strongly depends on the quality of the measured data.\n\n\u003e In case of unfolded data, uncertainties (standard deviations)\n\u003e are calculated from the difference of the intensities from the left-hand side and\n\u003e the right-hand side of the unfolded spectrum. **χ²** and **red. χ²** a are then weigthed by\n\u003e the mean standard deviation (or square root of the mean variance of all data pairs).\n\u003e **χ²** should be close to the number of data and **red. χ²** should be close to 1 for\n\u003e a good fit result.\n\n**χ²** from `lmfit`:   \n$$\\chi^2 = \\sum_{i}^N [\\rm Residuals_i]^2$$  \n(weighted in case of .ws5 files)\n   \n**red. χ²** from `lmfit` \n$$\\chi^2_\\nu = \\chi^2 / (N-N_{\\rm varys})$$   \n$N$ is the number of data points and $N_{varys}$ is number of variable parameters.    \n(weighted in case of .ws5 files)\n\n **$R²$**: coefficient of determination \n\nData points in **1σ** or **3σ** are optional (set `print_in_sigma = True` in the script).\n\n**r (area)** in % is the ratio of a component calculated by the area of the individual \ncomponent divided by the sum of all components.    \n**r (int)** in % is the ratio of a component calculated by the integral (area under \nthe curve) of an individual component divided by the total area / integral of all \ncomponents. Integrals or areas under curves are calculated with the trapezoidal rule. \n**r (int)** is often closer to the values calculated by the `mfit2` program. \n\nThe errors are calculated by the `lmfit` module.\n\n## Saving results\n\nAfter clicking the **Save button** the following files are saved:\n\n```\nparameterfile-fit.txt          ⇦ new parameter file with fitted parameters\ndata_filename-report.txt       ⇦ fit report; similar to the last terminal output\ndata_filename-fit.dat          ⇦ a file that contains all data from fit and raw data\ndata_filename-fit.png          ⇦ exactly the plot (as PNG) in the lower window\ndata_filename-fold.dat         ⇦ folded spectrum (only if a WissEl ws5 file has been processed)\n```\n\nIn case of the **parameter file** `-fit` is added to the filename of the new parameter-file. \nThe filename (without extension) of the file that contains the measured data is the prefix\nfor the **report**, **data** and **plot** files. `-fit` is added to the prefix in case of\nthe latter two files. The **folded** spectrum is saved, if if a WissEl ws5 file has been processed \n(`-fold` is added to the filename).\n\nThe file `data_filename-fit.dat` contains the following data:\n\n```\n#velocity   data       residuals  fit        L1Fe       L2Fe      \n-4.58930    0.99832    1.00224    0.99917    0.99924    0.99942\n-4.55250    0.99906    1.00149    0.99916    0.99923    0.99942\n-4.51570    0.99900    1.00154    0.99916    0.99923    0.99942\n-4.47890    0.99909    1.00145    0.99915    0.99922    0.99942\n-4.44210    0.99952    1.00101    0.99914    0.99922    0.99942\n...\n   ⇧          ⇧           ⇧          ⇧          ⇧          ⇧\nvelocity   raw data   residuals   best-fit   single fit curves \n                      (+ extra)   curve      for each component\n```\nTo the `residuals` some extra in `y` is added to display them above data and fit curves. \n\n## Exit\n\nTo exit the script, klick on the **Exit button** or close the `matplotlib` window.\n\n## Known Issues\n\n- If $ΔE_Q$ is 0 or close to 0, the fitting procedure has sometimes problems finding the correct solution.\n  In this case **fix $ΔE_Q$** at a value close to zero, **Fit**, remove **fix $ΔE_Q$** and **Fit** again.\n- If $ΔE_Q$ is 0 or close to 0, the error is very large. This results from the calculation of errors in\n  `lmfit`. There is no solution for this behaviour.\n- The script has not been tested with raw data from 1024 channel multi-channel analyzers.\n\n## Remarks\n\n- The script is benchmarked against the `mfit2` program from Dr. Eckhard Bill. Within the given restrictions, \n  the results for  $δ$ and $ΔE_Q$ match down to the second decimal place. \n- Raw spectra (WissEl .ws5 for example) are expected to start at channel 1 and be folded to the right.\n- χ² and red. χ² are rather meaningless in case of files that contain only velocity and intensity. However, if\n  the fit is good both values get smaller.\n- In case of unfolded data, the error can be estimated from the differences in the intensities of the left-hand\n  side and right-hand side sub-spectra. The weighting for χ² and red. χ² is 1 / (mean standard deviation). \n  The mean standard deviation is the square root of the mean variance of two times the intensities of the left-hand\n  side and right-hand side data pairs which are supposed to be equal. χ² is close to the number of data points and\n  red. χ² is close to 1 in case of a good fit. All values are normalized.    \n  Please note that parameters like $δ$ or $ΔE_Q$ are mainly derived from channel or velocity data (x-values),\n  while only errors from transmission or intensity data (y-values) are taken into account for the weigths of χ² and red. χ².\n- R² is calculated by 1 - variance(residual * mean standard deviation) / variance(intensities), because\n  R² is calculated wrongly by `lmfit` in case of weights.\n\n## Example\n\n\u003cimg src='examples\\show-use3.gif' alt='Show use' width=900 align='center'\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fradi0sus%2Ffit-mb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fradi0sus%2Ffit-mb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fradi0sus%2Ffit-mb/lists"}