Mercurial > repos > muon-spectroscopy-computational-project > larch_lcf
changeset 0:f59731986b61 draft
planemo upload for repository https://github.com/MaterialsGalaxy/larch-tools/tree/main/larch_lcf commit 5be486890442dedfb327289d597e1c8110240735
author | muon-spectroscopy-computational-project |
---|---|
date | Tue, 14 Nov 2023 15:35:22 +0000 |
parents | |
children | 6c28339b73f7 |
files | common.py larch_lcf.py larch_lcf.xml macros.xml test-data/PtSn_OCO_Abu_1.prj test-data/SnO2_extracted.prj test-data/Sn_foil_extracted.prj |
diffstat | 7 files changed, 217 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common.py Tue Nov 14 15:35:22 2023 +0000 @@ -0,0 +1,46 @@ +from typing import Iterable + +from larch.io import extract_athenagroup, read_athena +from larch.io.athena_project import AthenaGroup +from larch.symboltable import Group +from larch.xafs import autobk, pre_edge, xftf + + +def get_group(athena_group: AthenaGroup, key: str = None) -> Group: + if key is None: + group_keys = list(athena_group._athena_groups.keys()) + key = group_keys[0] + return extract_athenagroup(athena_group._athena_groups[key]) + + +def read_group(dat_file: str, key: str = None, xftf_params: dict = None): + athena_group = read_athena(dat_file) + group = get_group(athena_group, key) + bkg_parameters = group.athena_params.bkg + print(group.athena_params.fft) + print(group.athena_params.fft.__dict__) + pre_edge( + group, + e0=bkg_parameters.e0, + pre1=bkg_parameters.pre1, + pre2=bkg_parameters.pre2, + norm1=bkg_parameters.nor1, + norm2=bkg_parameters.nor2, + nnorm=bkg_parameters.nnorm, + make_flat=bkg_parameters.flatten, + ) + autobk(group) + if xftf_params is None: + xftf(group) + else: + print(xftf_params) + xftf(group, **xftf_params) + xftf_details = Group() + setattr(xftf_details, "call_args", xftf_params) + group.xftf_details = xftf_details + return group + + +def read_groups(dat_files: "list[str]", key: str = None) -> Iterable[Group]: + for dat_file in dat_files: + yield read_group(dat_file=dat_file, key=key)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/larch_lcf.py Tue Nov 14 15:35:22 2023 +0000 @@ -0,0 +1,82 @@ +import json +import sys + +from common import read_group + +from larch.math.lincombo_fitting import get_label, lincombo_fit +from larch.symboltable import Group + +import matplotlib +import matplotlib.pyplot as plt + + +def plot( + group_to_fit: Group, + fit_group: Group, + energy_min: float, + energy_max: float, +): + formatted_label = "" + for label, weight in fit_group.weights.items(): + formatted_label += f"{label}: {weight:.3%}\n" + + plt.figure() + plt.plot( + group_to_fit.energy, + group_to_fit.norm, + label=group_to_fit.filename, + linewidth=4, + color="blue", + ) + plt.plot( + fit_group.xdata, + fit_group.ydata, + label=formatted_label[:-1], + linewidth=2, + color="orange", + linestyle="--", + ) + plt.grid(color="black", linestyle=":", linewidth=1) # show and format grid + plt.xlim(energy_min, energy_max) + plt.xlabel("Energy (eV)") + plt.ylabel("normalised x$\mu$(E)") # noqa: W605 + plt.legend() + plt.savefig("plot.png", format="png") + plt.close("all") + + +def set_label(component_group, label): + if label is not None: + component_group.filename = label + else: + component_group.filename = get_label(component_group) + + +if __name__ == "__main__": + # larch imports set this to an interactive backend, so need to change it + matplotlib.use("Agg") + prj_file = sys.argv[1] + input_values = json.load(open(sys.argv[2], "r", encoding="utf-8")) + + group_to_fit = read_group(prj_file) + set_label(group_to_fit, input_values["label"]) + + component_groups = [] + for component in input_values["components"]: + component_group = read_group(component["component_file"]) + set_label(component_group, component["label"]) + component_groups.append(component_group) + + fit_group = lincombo_fit(group_to_fit, component_groups) + print(f"Goodness of fit (rfactor): {fit_group.rfactor:.6%}") + + energy_min = input_values["energy_min"] + energy_max = input_values["energy_max"] + if input_values["energy_format"] == "relative": + e0 = group_to_fit.e0 + if energy_min is not None: + energy_min += e0 + if energy_max is not None: + energy_max += e0 + + plot(group_to_fit, fit_group, energy_min, energy_max)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/larch_lcf.xml Tue Nov 14 15:35:22 2023 +0000 @@ -0,0 +1,63 @@ +<tool id="larch_lcf" name="Larch LCF" version="@TOOL_VERSION@+galaxy@WRAPPER_VERSION@" python_template_version="3.5" profile="22.05" license="MIT"> + <description>perform linear combination fit on XAS data</description> + <macros> + <!-- version of underlying tool (PEP 440) --> + <token name="@TOOL_VERSION@">0.9.71</token> + <!-- version of this tool wrapper (integer) --> + <token name="@WRAPPER_VERSION@">0</token> + <!-- citation should be updated with every underlying tool version --> + <!-- typical fields to update are version, month, year, and doi --> + <token name="@TOOL_CITATION@">10.1088/1742-6596/430/1/012007</token> + <import>macros.xml</import> + </macros> + <creator> + <person givenName="Patrick" familyName="Austin" url="https://github.com/patrick-austin" identifier="https://orcid.org/0000-0002-6279-7823"/> + </creator> + <requirements> + <requirement type="package" version="@TOOL_VERSION@">xraylarch</requirement> + <requirement type="package" version="3.5.2">matplotlib</requirement> + </requirements> + <required_files> + <include type="literal" path="larch_lcf.py"/> + </required_files> + <command detect_errors="exit_code"><![CDATA[ + python '${__tool_directory__}/larch_lcf.py' '$prj_file' '$inputs' + ]]></command> + <configfiles> + <inputs name="inputs" data_style="paths"/> + </configfiles> + <inputs> + <param name="label" type="text" optional="true" label="Main data label" help="The label to use for the main data (target of the fit). If unset, the label will be taken from the Athena project metadata."/> + <param name="prj_file" type="data" format="prj" label="Athena project to fit" help="Normalised X-ray Absorption Fine Structure (XAFS) data, in Athena project format, to be fit."/> + <repeat name="components" title="Fit components"> + <param name="label" type="text" optional="true" label="Component label" help="The label to use for this component. If unset, the label will be taken from the Athena project metadata."/> + <param name="component_file" type="data" format="prj" label="Athena project to fit" help="Reference X-ray Absorption Fine Structure (XAFS) data, in Athena project format, to be used as components in the fit."/> + </repeat> + <expand macro="energy_limits"/> + </inputs> + <outputs> + <data name="plot" format="png" from_work_dir="plot.png" label="Larch LCF ${label} ${on_string}"/> + </outputs> + <tests> + <test expect_num_outputs="1"> + <param name="prj_file" value="PtSn_OCO_Abu_1.prj"/> + <param name="component_file" value="Sn_foil_extracted.prj"/> + <param name="component_file" value="SnO2_extracted.prj"/> + <param name="energy_format" value="relative"/> + <param name="energy_max" value="10"/> + <output name="plot"> + <assert_contents> + <has_size value="55100" delta="100"/> + </assert_contents> + </output> + </test> + </tests> + <help><![CDATA[ + Performs a Linear Combination Fit (LCF) on an Athena project, using a number of other projects as components to the fit. + The extent to which each component contributes to the target is recorded in the output plot of the normalised absorption co-efficient. + ]]></help> + <citations> + <citation type="doi">@TOOL_CITATION@</citation> + <citation type="doi">10.1107/S0909049505012719</citation> + </citations> +</tool> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/macros.xml Tue Nov 14 15:35:22 2023 +0000 @@ -0,0 +1,26 @@ +<macros> + <xml name="energy_limits"> + <param name="energy_format" type="select" display="radio" label="Energy limits" help="Whether to limit the energy relative to the absorption edge or with absolute values."> + <option value="relative" selected="true">Relative</option> + <option value="absolute">Absolute</option> + </param> + <param name="energy_min" type="float" label="Minimum energy (eV)" optional="true" help="If set, data will be cropped below this value in electron volts."/> + <param name="energy_max" type="float" label="Maximum energy (eV)" optional="true" help="If set, data will be cropped above this value in electron volts."/> + </xml> + <xml name="xftf_params"> + <param argument="kmin" type="float" value="0" min="0.0" help="Minimum k value."/> + <param argument="kmax" type="float" value="20" min="0.0" help="Maximum k value."/> + <param argument="kweight" type="float" value="2" help="Exponent for weighting spectra by raising k to this power."/> + <param argument="dk" type="float" value="4" help="Tapering parameter for Fourier Transform window."/> + <param argument="window" type="select" help="Fourier Transform window type."> + <option value="hanning">Hanning (cosine-squared taper)</option> + <option value="parzen">Parzen (linear taper)</option> + <option value="welch">Welch (quadratic taper)</option> + <option value="gaussian">Gaussian function window</option> + <option value="sine">Sine function window</option> + <option value="kaiser" selected="true">Kaiser-Bessel function-derived window</option> + </param> + <param argument="rmin" type="float" value="0.0" min="0.0" help="Minimum radial distance."/> + <param argument="rmax" type="float" value="10.0" min="0.0" help="Maximum radial distance."/> + </xml> +</macros> \ No newline at end of file