diff --git a/docs/instrument_and_reduction.rst b/docs/instrument_and_reduction.rst deleted file mode 100644 index 468283269..000000000 --- a/docs/instrument_and_reduction.rst +++ /dev/null @@ -1,24 +0,0 @@ -# Instrument Geometry - -## Mantid - -## PyRS-instrument - -It is assumed that for HB2B, - -1. sample position is always at (0, 0, 0) -2. source (moderator) position is always at (0, 0, -???) -3. detector can be configured to - - 1024, 1024 - - 2048, 2048 -4. detector pixels' size can be defined flexibly. - -# Reduction Workflow - -## Mantid - -## PyRS-reduction - -This is a reduction algorithm based on pure python programming. -It is supposed to be equivalent to the reduction Mantid algorithms, -which are practically slower. diff --git a/docs/pole_figure.pdf b/docs/pole_figure.pdf deleted file mode 100644 index 863c15647..000000000 Binary files a/docs/pole_figure.pdf and /dev/null differ diff --git a/docs/pole_figure.tex b/docs/pole_figure.tex deleted file mode 100644 index 83b07efbb..000000000 --- a/docs/pole_figure.tex +++ /dev/null @@ -1,81 +0,0 @@ -\documentclass[12pt,bezier,amstex]{report} % include bezier curves -\renewcommand\baselinestretch{1.0} % single space -%\pagestyle{empty} % no headers and page numbers -\oddsidemargin -10 true pt % Left margin on odd-numbered pages. -\evensidemargin 10 true pt % Left margin on even-numbered pages. -\marginparwidth 0.75 true in % Width of marginal notes. -\oddsidemargin 0 true in % Note that \oddsidemargin=\evensidemargin -\evensidemargin 0 true in -\topmargin 0.25 true in % Nominal distance from top of page to top of -\textheight 9.0 true in % Height of text (including footnotes and figures) -\textwidth 6.375 true in % Width of text line. -\parindent=0pt % Do not indent paragraphs -\parskip=0.15 true in -\usepackage{color} % Need the color package -\usepackage{epsfig} - -\usepackage{algorithmic} - - -\title{NRSF2 Design Document Appendix} - -\begin{document} - -\maketitle - -Construct 2 orthogonal {\it q} vectors from y-direction and x-direction respectively with rotation by $\theta$ along z-axis -\begin{eqnarray*} -\vec{q}_1 &=& - R_z (- \frac{2\theta}{2}) (010) \\ -\vec{q}_2 &=& - R_z(-\frac{2\theta}{2}) (100) -\end{eqnarray*} - -where -\begin{itemize} -\item $2\theta_{peak}$ = position of peak (which is in plane) -%\item $\omega$ = incident angle -%\item $\chi$ = $\chi$ rotation about (100) of sample -%\item $\phi$ = $\phi$ rotation about sample normal -\end{itemize} - -In order to convert $\vec{q}$ from instrument coordinate to sample coordinate, the ration will be done on -$\omega$, $\chi$ and $\phi$ respectively. - -The rotation matrix $R_p$ is defined as -\begin{eqnarray*} -R_p &=& R_x(\phi + 90^o) \times R_y(\chi) \times R_z(-\omega) -\end{eqnarray*} - -where -\begin{itemize} -\item $\omega$ = incident angle -\item $\chi$ = $\chi$ rotation about (100) of sample -\item $\phi$ = $\phi$ rotation about sample normal -\end{itemize} - -Thus, $\vec{q}_1$ and $\vec{q}_2$ are rotated by $R_p$ such as -\begin{eqnarray*} -\vec{q\prime}_1 &=& R_p\times \vec{q}_1 \\ -\vec{q\prime}_2 &=& R_p\times \vec{q}_2 -\end{eqnarray*} - -Finally angle $\alpha$ and $\beta$ are between $\vec{q}_1$, $\vec{q\prime}_1$, $\vec{q}_2$ and $\vec{q\prime}_2$. -Such that -\begin{eqnarray*} -\alpha &=& \cos^{-1}(\vec{q\prime}_2\cdot\vec{q}_2) -\end{eqnarray*} - -It is a little complicated for $\beta$: -\begin{itemize} -\item If $(\vec{q}_1)_z >= 0$: $beta = 360^o - \cos^{-1}(\vec{q\prime}_1\cdot\vec{q}_1)$; -\item if $(\vec{q}_1)_z < 0$: $beta = \cos^{-1}(\vec{q\prime}_1\cdot\vec{q}_1)$ -\end{itemize} -Then -\begin{itemize} -\item If $\beta <= 90^o$: $beta = 360^o + (\beta - 90^o)$; -\item if $\beta > 90^o$: $beta = (\beta - 90^o)$ -\end{itemize} -Such that $\beta$ is between $0^o$ and $360^o$. - -\end{document} diff --git a/docs/source/project_file.rst b/docs/source/project_file.rst deleted file mode 100644 index 1e09884ee..000000000 --- a/docs/source/project_file.rst +++ /dev/null @@ -1,68 +0,0 @@ -HB2B Project File ------------------ - -Definition -========== - -The HIDRA project file contains reduced data, which may contain multiple runs. -There are several levels reduced data for an engineering diffraction experiment project, such as -diffraction patterns, fitted peaks and calculated strains/stresses. -This project file shall store information about measured diffraction patterns (intensity vs :math:`2\theta`) and results from single peak fitting. -Strain/stress results are not stored in individual project files because these calculations rely on information from addition project files (d0 and additional strain components). - -Here is a list of reduced data that will be stored in project file - -- Raw experimental data presented as neutron intensity on each pixel (not by default) -- Histogram data vectors - - :math:`2\theta` - - intensity - - estimated intensity uncertainty -- Instrument geometry parameters -- Calibrated instrument geometry parameters -- Fitted peaks' parameters - -File Structure -============== - -HiDRA project file utilizes an HDF file format with the following organizational tree structure. - -- Instrument - - Geometry parameters: table of parameters - - Geometry calibration: - - Calibration file - - Calibration run - - Calibration date - - Table of calibrated parameters -- Mask - - detector - - default detector masked used to exclude pixels near the edge of the detector - -- Peaks - - HKL_0 - - chi2 - - d reference - - d reference error - - fitting error - - parameters - - sub-runs - - - HKL_1 - - ... ... - -- Raw Data - - logs - - logs for motor positions and metadata information for each sub-run - - sub-runs - - intensity count vs pixel vectors (by default not saved) - -- reduced diffraction data - - 2theta - - :math:`2\theta` vectors for each sub-run - - main - - count vectors for each sub-run - - main_var - - estimated error in counts for each sub-run - - main_XANG - - count vectors for each sub-run for a given out-of-plane angle (X) - - main_XANG_var - - estimated error in counts for each sub-run for a given out-of-plane angle (X) diff --git a/docs/stress_strain.pdf b/docs/stress_strain.pdf deleted file mode 100644 index 0f5a57e44..000000000 Binary files a/docs/stress_strain.pdf and /dev/null differ diff --git a/docs/stress_strain.tex b/docs/stress_strain.tex deleted file mode 100644 index 404c482bc..000000000 --- a/docs/stress_strain.tex +++ /dev/null @@ -1,85 +0,0 @@ -\documentclass[12pt]{report} % include bezier curves -\renewcommand\baselinestretch{1.0} % single space -%\pagestyle{empty} % no headers and page numbers -\oddsidemargin -10 true pt % Left margin on odd-numbered pages. -\evensidemargin 10 true pt % Left margin on even-numbered pages. -\marginparwidth 0.75 true in % Width of marginal notes. -\oddsidemargin 0 true in % Note that \oddsidemargin=\evensidemargin -\evensidemargin 0 true in -\topmargin 0.25 true in % Nominal distance from top of page to top of -\textheight 9.0 true in % Height of text (including footnotes and figures) -\textwidth 6.375 true in % Width of text line. -\parindent=0pt % Do not indent paragraphs -\parskip=0.15 true in -\usepackage{color} % Need the color package -\usepackage{epsfig} - -\usepackage{algorithmic} - - -\title{NRSF2 Design Document Appendix: Strain and Stress Calculation} - -\begin{document} - -%\maketitle - -{\bf Strain}, aka, unconstrained strain, is measured as the fraction change from a reference state ($d_0$). -\begin{eqnarray} -\epsilon_{ij} &=& \frac{d_{ij} - d_0}{d_0} -\end{eqnarray} - -{\bf Residual stress} is determined by measuring stress along {\bf\it 3} orthogonal directions -\begin{eqnarray} -\sigma_{ij} &=& - \frac{E}{(1 + \nu)}\left[\epsilon_{ij} + \frac{\nu}{1-2\nu}(\epsilon_{11} + \epsilon_{22} + \epsilon_{33})\right] -\end{eqnarray} - -where -\begin{itemize} -\item $\nu$ is {\it Poisson's Ratio}. -\item $E$ is {\it Young's Modulus}. -\item $\epsilon_{ij}$ are strains. Be noted that - \begin{itemize} - \item $\epsilon_{ij}$ with $i = j$ are principle strains. But not all all three orthogonal strains are equivalent to principle strains. - \item The off-diagonal strain component, i.e., $\epsilon_{ij}$ with $i\neq j$ are all set to {\bf zero}. It is very hard to measure these values in HB2B's setup. - \end{itemize} -\end{itemize} - -Therefore the stress that is calculated is -% -\begin{equation} -\sigma_{ii} = - \frac{E}{(1 + \nu)}\left[\epsilon_{ii} + \frac{\nu}{1-2\nu}(\epsilon_{11} + \epsilon_{22} + \epsilon_{33})\right] -\end{equation} -% -where the second term in the sum is the same between all 3 principle strain directions, ($\sigma_{11}$, $\sigma_{22}$, and $\sigma_{33}$). - -There are also two simplified cases when only two strain components are measured. The first is {\bf in-plane strain}, where $\epsilon_{33}=0$. Then the strain equations become -% -\begin{eqnarray} -\sigma_{11} &=& - \frac{E}{(1 + \nu)}\left[\epsilon_{11} + \frac{\nu}{1-2\nu}(\epsilon_{11} + \epsilon_{22})\right] \\ -\sigma_{22} &=& - \frac{E}{(1 + \nu)}\left[\epsilon_{22} + \frac{\nu}{1-2\nu}(\epsilon_{11} + \epsilon_{22})\right] \\ -\sigma_{33} &=& - \frac{E \nu (\epsilon_{11} + \epsilon_{22})}{(1 + \nu)(1-2\nu)} -\end{eqnarray} - -The {\bf in-plane stress}, assumes $\sigma_{33} = 0$. -Therefore, $\epsilon_{33}$ can be calculated from $\epsilon_{11}$ and $\epsilon_{22}$ from $\sigma_{33} = 0$. Then the missing strain can be determined to be -% -\begin{equation} -\epsilon_{33} = \frac{\nu}{\nu-1}(\epsilon_{11} + \epsilon_{22}) -\end{equation} -% -With that relation, the stresses (with the in-plane stress assumption) are -% -\begin{eqnarray} -\sigma_{11} &=& - \frac{E}{(1 + \nu)}\left[\epsilon_{11} + \frac{\nu (\epsilon_{11} + \epsilon_{22})}{1-\nu}\right] \\ -\sigma_{22} &=& - \frac{E}{(1 + \nu)}\left[\epsilon_{22} + \frac{\nu (\epsilon_{11} + \epsilon_{22})}{1-\nu}\right] \\ -\sigma_{33} &=& 0 -\end{eqnarray} - -\end{document} diff --git a/pixi.lock b/pixi.lock index 16f53e513..2719deafc 100644 --- a/pixi.lock +++ b/pixi.lock @@ -23,8 +23,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.4.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-1.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.15.3-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.1-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-client-1.14.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda @@ -38,7 +38,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.18.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhcf101f3_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py312h90b7ffd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.4.0-py312h90b7ffd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.14.3-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda @@ -49,35 +49,35 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.23.1-hc31b594_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cachecontrol-0.14.3-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-he90730b_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py312h460c074_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/chardet-5.2.0-pyhd8ed1ab_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/chardet-7.4.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cli11-2.6.2-h54a6638_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-2024.11.20-py312h4c3975b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/comm-0.2.3-pyhe01879c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.7.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.3.2-py312h7900ff3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-26.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312h0a2e395_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.13.5-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.0-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.13-py312hd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-46.0.5-py312ha4b625e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-48.0.0-py312ha4b625e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cyclonedx-python-lib-11.7.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.10.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.11.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.28-hac629b4_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-h24cb091_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.20-py312h8285ef7_0.conda @@ -88,15 +88,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/docstring_parser-0.17.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.4.0-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.6-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-abi-5.0.1.80-hf414acd_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/epoxy-1.5.10-hb03c661_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/euphonic-1.6.0-py312h4f23490_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/euphonic-1.6.1-py312h4f23490_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/evalidate-2.0.5-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexcache-0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexparser-0.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda @@ -107,8 +107,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.0-py312h8a5da7c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-ha6d2627_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.1-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-h215f996_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/freeimage-3.18.0-h49ef1fa_24.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.3-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.16-hb03c661_0.conda @@ -117,26 +117,26 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/future-1.0.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.44.6-h2b0a6b4_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-h36e74d4_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.2.0-h3abd4de_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.86.4-h5192d8d_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.86.4-hf516916_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.3.0-h71661d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.88.1-hd810c12_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.88.1-hee1de02_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.11-h18acefa_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gsl-2.8-hbf7d49c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.10-h0363672_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.10-h17cb667_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.11-h6d08254_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.11-h29cf534_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gtest-1.17.0-h84d6215_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gtk3-3.24.52-ha5ea40c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.16.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h5glance-0.9-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py312ha4f8f14_101.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-13.2.1-h6083320_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py312ha4f8f14_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-14.2.0-h6083320_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hatch-1.16.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hatchling-1.29.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_108.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_109.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5plugin-6.0.0-py312hb944afc_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hicolor-icon-theme-0.17-ha770c72_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda @@ -148,20 +148,19 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/hyperlink-21.0.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/id-1.6.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/imageio-2.37.0-pyhfb79c49_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-2.0.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.2.2-hde8ca8f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.5.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-7.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-7.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-7.2.0-pyha191276_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.12.0-pyhecfbec7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.13.0-pyh53cf698_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhcf101f3_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.4.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/jasper-4.2.9-h1588d4d_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda @@ -181,23 +180,23 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.0-py312h0a2e395_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.7-gpl_hc2c16d8_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-7_h4a7cf45_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.88.0-hd24cca6_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-python-1.88.0-py312hf890105_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcap-2.77-hd0affe5_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.0-default_h99862b1_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-7_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.5-default_h99862b1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.5-default_h746c552_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda @@ -205,71 +204,71 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-devel-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.0-hecca717_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libflac-1.5.0-he200343_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.4-h6548e54_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.1-h0d30a3d_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.3-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.12.2-default_hafda6a7_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-7_h47877c9_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblief-0.17.6-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.8-hf7376ad_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.2-hf7376ad_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py312h1ca65c7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.5-hf7376ad_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.6.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.6.0-hf859cbd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.6.0-py312h5ee1301_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.2-hc2fc477_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmsgpack-c-6.1.0-h54a6638_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_104.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.5-hd0c01bc_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopus-1.6.1-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.56-h421ea60_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.3-h9abb657_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libraw-0.21.5-h074291d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/librdkafka-2.13.2-he5e3081_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.62.1-h4c96295_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc7d488a_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.36-h9463b59_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.37-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-hd0affe5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h4ab18f5_1006.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.341.0-h5279c79_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.13.1-hca5e8e5_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.3-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.43-h711ed8c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.2-h6991a6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda @@ -277,73 +276,73 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-4.4.5-py312h3d67a73_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda - - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantid-6.15.20260331.2253-np21py312h62f99c1_0.conda - - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidqt-6.15.20260331.2253-py312he48a509_0.conda - - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidworkbench-6.15.20260331.2253-py312hc9b079f_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantid-6.15.20260501.2109-np21py312h68643e6_0.conda + - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidqt-6.15.20260501.2109-py312he137b73_0.conda + - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidworkbench-6.15.20260501.2109-py312h0a96521_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.4-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.4-py312hd3ec401_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.9-py312h7900ff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.9-py312he3d6523_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mbedtls-3.6.3.1-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-25.0.5-h57bcd07_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-26.0.3-h8cca3c9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-11.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py312hd9148b4_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/multidict-6.7.1-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/muparser-2.3.4-h27087fc_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.19.1-py312h4c3975b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.20.2-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nbformat-5.10.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nexusformat-1.0.8-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.4-py310h6de7dc8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.5-py310hd8a072f_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.1.3-py312h58c1407_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.8-h40f6f1d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.11-h9f1635d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.26.3-h8d634f6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.27.2-h8d634f6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.13-hbde042b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/orsopy-1.2.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.2-h3435931_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packageurl-python-0.17.6-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.2-py312h8ecdadd_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pango-1.56.4-hda50119_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.6-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.7-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patch-2.8-hb03c661_1002.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.1.1-py312h50c33e8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py312h50c33e8_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pint-0.25.3-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.1-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-api-0.0.34-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-audit-2.10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-requirements-parser-32.0.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkce-1.0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.6-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/poco-1.15.1-hbea8664_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/poco-1.15.2-hc403b36_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pooch-1.9.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.6.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prettytable-3.17.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.0-he0df7b0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.1-he0df7b0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/propcache-0.3.1-py312h178313f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h5253ce2_0.conda @@ -359,58 +358,58 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pyconify-0.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py312h4c3975b_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py312h868fb18_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.14.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyjwt-2.12.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject_hooks-1.2.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.11-py312h82c0db2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.17.0-py312h1289d80_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.11.0-py312h50ac2ff_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pystack-1.6.0-py312hb682716_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-qt-4.5.0-pyhdecd6ff_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-build-1.4.2-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-build-1.5.0-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.13-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-libarchive-c-5.3-pyhe01879c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.8.1-py312h5253ce2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.11.0-py312h5253ce2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.1.post1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.47.1-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.3-pyhdecd6ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.48.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.4-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hda471dd_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qscintilla2-2.14.1-py312h82c0db2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-gtk-platformtheme-5.15.15-h4e19bd6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.15-h0c412b5_8.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.10.2-pl5321h16c4a6b_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.11.0-pl5321h16c4a6b_4.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtconsole-5.7.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtconsole-base-5.7.2-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtpy-2.4.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/quasielasticbayes-0.3.0-py312hfc6b132_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/quickbayes-1.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rapidjson-1.1.0.post20240409-h3f2d84a_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.61.4-ha759004_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.1-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.64.1-ha759004_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.7.post0-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.7.post0-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/rich-rst-1.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ripgrep-15.1.0-hdab8a38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/roman-numerals-4.1.0-pyhd8ed1ab_0.conda @@ -419,13 +418,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py312h5253ce2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py312h5253ce2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.3-py312h54fa4ab_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.4.1-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.2.1-pyhcf101f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/semver-3.0.4-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.6.4-hb700be7_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/sip-6.10.0-py312h1289d80_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda @@ -442,51 +441,51 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jquery-4.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-programoutput-0.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2025.5-hb700be7_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2026.1-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/superqt-0.8.0-pyh9208f05_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2022.3.0-hb700be7_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2023.0.0-h51de99f_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhcf101f3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.15.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.5-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.1.14.14-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.5.7.17-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/twine-6.2.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.24.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20250915-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20251009-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.25.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20260510-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20260408-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py312hd9148b4_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uncertainties-3.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unixodbc-2.3.14-h69e2008_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/utfcpp-4.09-ha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.2-h0f56927_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.13-h29f5ae7_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.3.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.0-hca82ae8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.0-py312h64f160b_4.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.3.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.1-cpu_hc82bd48_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.1-py312hb8f95c7_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.7.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-pyhd8ed1ab_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.6-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.6-hb03c661_0.conda @@ -519,13 +518,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.23.0-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.1-h909a3a2_5.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py312h5253ce2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - pypi: https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0a/fe/661043d1c263b0d9d10c6ff4e9c9745f3df9641c62b51f96a3473638e7ce/regex-2026.3.32-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/cc/1e/3fbe2fa1e8cebd62f3bb7d3321cff1640aca2e240b51d9bd624aad949260/regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d2/b8/f0b9b880c03a3db8eaff63d76ca751ac7d8e45483fb7a0bb9f8e5c6ce433/toml_cli-0.8.2-py3-none-any.whl - pypi: ./ dev: @@ -551,8 +550,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.4.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-1.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.15.3-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.1-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-client-1.14.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda @@ -566,7 +565,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.18.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhcf101f3_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py312h90b7ffd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.4.0-py312h90b7ffd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.14.3-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda @@ -576,32 +575,32 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.23.1-hc31b594_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-he90730b_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py312h460c074_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/chardet-5.2.0-pyhd8ed1ab_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/chardet-7.4.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cli11-2.6.2-h54a6638_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-2024.11.20-py312h4c3975b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/comm-0.2.3-pyhe01879c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.7.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.3.2-py312h7900ff3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-26.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312h0a2e395_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.13.5-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.0-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.13-py312hd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-46.0.5-py312ha4b625e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-48.0.0-py312ha4b625e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.10.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.11.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.28-hac629b4_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-h24cb091_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.20-py312h8285ef7_0.conda @@ -612,15 +611,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/docstring_parser-0.17.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.4.0-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.6-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-abi-5.0.1.80-hf414acd_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/epoxy-1.5.10-hb03c661_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/euphonic-1.6.0-py312h4f23490_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/euphonic-1.6.1-py312h4f23490_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/evalidate-2.0.5-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexcache-0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexparser-0.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda @@ -631,8 +630,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.0-py312h8a5da7c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-ha6d2627_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.1-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-h215f996_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/freeimage-3.18.0-h49ef1fa_24.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.3-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.16-hb03c661_0.conda @@ -641,26 +640,26 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/future-1.0.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.44.6-h2b0a6b4_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-h36e74d4_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.2.0-h3abd4de_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.86.4-h5192d8d_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.86.4-hf516916_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.3.0-h71661d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.88.1-hd810c12_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.88.1-hee1de02_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.11-h18acefa_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gsl-2.8-hbf7d49c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.10-h0363672_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.10-h17cb667_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.11-h6d08254_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.11-h29cf534_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gtest-1.17.0-h84d6215_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gtk3-3.24.52-ha5ea40c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.16.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h5glance-0.9-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py312ha4f8f14_101.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-13.2.1-h6083320_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py312ha4f8f14_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-14.2.0-h6083320_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hatch-1.16.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hatchling-1.29.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_108.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_109.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5plugin-6.0.0-py312hb944afc_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hicolor-icon-theme-0.17-ha770c72_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda @@ -671,19 +670,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/hyperlink-21.0.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/id-1.6.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/imageio-2.37.0-pyhfb79c49_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-2.0.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.2.2-hde8ca8f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.5.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-7.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-7.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-7.2.0-pyha191276_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.12.0-pyhecfbec7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.13.0-pyh53cf698_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhcf101f3_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.4.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/jasper-4.2.9-h1588d4d_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda @@ -703,23 +701,23 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.0-py312h0a2e395_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.7-gpl_hc2c16d8_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-7_h4a7cf45_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.88.0-hd24cca6_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-python-1.88.0-py312hf890105_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcap-2.77-hd0affe5_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.0-default_h99862b1_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-7_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.5-default_h99862b1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.5-default_h746c552_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda @@ -727,138 +725,138 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-devel-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.0-hecca717_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libflac-1.5.0-he200343_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.4-h6548e54_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.1-h0d30a3d_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.3-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.12.2-default_hafda6a7_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-7_h47877c9_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblief-0.17.6-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.8-hf7376ad_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.2-hf7376ad_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py312h1ca65c7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.5-hf7376ad_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.6.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.6.0-hf859cbd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.6.0-py312h5ee1301_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.2-hc2fc477_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmsgpack-c-6.1.0-h54a6638_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_104.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.5-hd0c01bc_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopus-1.6.1-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.56-h421ea60_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.3-h9abb657_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libraw-0.21.5-h074291d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/librdkafka-2.13.2-he5e3081_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.62.1-h4c96295_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc7d488a_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.36-h9463b59_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.37-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-hd0affe5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h4ab18f5_1006.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.341.0-h5279c79_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.13.1-hca5e8e5_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.3-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.43-h711ed8c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.2-h6991a6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-4.4.5-py312h3d67a73_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda - - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantid-6.15.20260331.2253-np21py312h62f99c1_0.conda - - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidqt-6.15.20260331.2253-py312he48a509_0.conda - - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidworkbench-6.15.20260331.2253-py312hc9b079f_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantid-6.15.20260501.2109-np21py312h68643e6_0.conda + - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidqt-6.15.20260501.2109-py312he137b73_0.conda + - conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidworkbench-6.15.20260501.2109-py312h0a96521_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.4-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.4-py312hd3ec401_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.9-py312h7900ff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.9-py312he3d6523_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mbedtls-3.6.3.1-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-25.0.5-h57bcd07_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-26.0.3-h8cca3c9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-11.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py312hd9148b4_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/multidict-6.7.1-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/muparser-2.3.4-h27087fc_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.19.1-py312h4c3975b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.20.2-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nbformat-5.10.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nexusformat-1.0.8-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.4-py310h6de7dc8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.5-py310hd8a072f_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.1.3-py312h58c1407_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.8-h40f6f1d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.11-h9f1635d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.26.3-h8d634f6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.27.2-h8d634f6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.13-hbde042b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/orsopy-1.2.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.2-h3435931_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.2-py312h8ecdadd_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pango-1.56.4-hda50119_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.6-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.7-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patch-2.8-hb03c661_1002.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.1.1-py312h50c33e8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py312h50c33e8_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pint-0.25.3-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.1-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkce-1.0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.6-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/poco-1.15.1-hbea8664_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/poco-1.15.2-hc403b36_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pooch-1.9.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prettytable-3.17.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.0-he0df7b0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.1-he0df7b0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/propcache-0.3.1-py312h178313f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h5253ce2_0.conda @@ -873,57 +871,57 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pyconify-0.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py312h4c3975b_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py312h868fb18_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.14.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyjwt-2.12.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject_hooks-1.2.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.11-py312h82c0db2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.17.0-py312h1289d80_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.11.0-py312h50ac2ff_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pystack-1.6.0-py312hb682716_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-qt-4.5.0-pyhdecd6ff_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.13-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-libarchive-c-5.3-pyhe01879c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.8.1-py312h5253ce2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.11.0-py312h5253ce2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.1.post1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.47.1-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.3-pyhdecd6ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.48.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.4-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hda471dd_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qscintilla2-2.14.1-py312h82c0db2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-gtk-platformtheme-5.15.15-h4e19bd6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.15-h0c412b5_8.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.10.2-pl5321h16c4a6b_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.11.0-pl5321h16c4a6b_4.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtconsole-5.7.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtconsole-base-5.7.2-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtpy-2.4.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/quasielasticbayes-0.3.0-py312hfc6b132_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/quickbayes-1.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rapidjson-1.1.0.post20240409-h3f2d84a_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.61.4-ha759004_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.1-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.64.1-ha759004_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.7.post0-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.7.post0-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/rich-rst-1.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ripgrep-15.1.0-hdab8a38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/roman-numerals-4.1.0-pyhd8ed1ab_0.conda @@ -932,13 +930,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py312h5253ce2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py312h5253ce2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.3-py312h54fa4ab_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.4.1-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.2.1-pyhcf101f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/semver-3.0.4-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.6.4-hb700be7_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/sip-6.10.0-py312h1289d80_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda @@ -954,49 +952,49 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jquery-4.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-programoutput-0.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2025.5-hb700be7_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2026.1-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/superqt-0.8.0-pyh9208f05_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2022.3.0-hb700be7_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2023.0.0-h51de99f_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhcf101f3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.15.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.5-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.1.14.14-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.5.7.17-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/twine-6.2.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.24.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20250915-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20251009-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.25.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20260510-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20260408-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uncertainties-3.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unixodbc-2.3.14-h69e2008_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/utfcpp-4.09-ha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.2-h0f56927_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.13-h29f5ae7_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.3.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.0-hca82ae8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.0-py312h64f160b_4.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.3.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.1-cpu_hc82bd48_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.1-py312hb8f95c7_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.7.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.6-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.6-hb03c661_0.conda @@ -1029,13 +1027,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.23.0-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.1-h909a3a2_5.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py312h5253ce2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - pypi: https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0a/fe/661043d1c263b0d9d10c6ff4e9c9745f3df9641c62b51f96a3473638e7ce/regex-2026.3.32-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/cc/1e/3fbe2fa1e8cebd62f3bb7d3321cff1640aca2e240b51d9bd624aad949260/regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d2/b8/f0b9b880c03a3db8eaff63d76ca751ac7d8e45483fb7a0bb9f8e5c6ce433/toml_cli-0.8.2-py3-none-any.whl - pypi: ./ prod: @@ -1061,8 +1059,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.4.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-1.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.15.3-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.1-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-client-1.14.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda @@ -1076,7 +1074,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.18.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhcf101f3_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py311h6b1f9c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.4.0-py311h6b1f9c4_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.14.3-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda @@ -1086,32 +1084,32 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.23.1-hc31b594_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-he90730b_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py311h03d9500_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/chardet-5.2.0-pyhd8ed1ab_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/chardet-7.4.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cli11-2.6.2-h54a6638_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-2024.11.20-py311h49ec1c0_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/comm-0.2.3-pyhe01879c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py311h38be061_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.7.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.3.2-py311h38be061_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-26.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py311h724c32c_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.13.5-py311h3778330_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.0-py311h3778330_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.11.15-py311hd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-46.0.5-py311h2005dd1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-48.0.0-py311h2005dd1_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.10.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.11.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.28-hac629b4_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-h24cb091_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.20-py311hc665b79_0.conda @@ -1122,7 +1120,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/docstring_parser-0.17.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.4.0-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.6-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-abi-5.0.1.80-hf414acd_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/epoxy-1.5.10-hb03c661_2.conda @@ -1130,7 +1128,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/evalidate-2.0.5-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexcache-0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexparser-0.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda @@ -1141,8 +1139,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.0-py311h3778330_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-ha6d2627_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.1-py311h3778330_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-h215f996_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/freeimage-3.18.0-h49ef1fa_24.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.3-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.16-hb03c661_0.conda @@ -1152,26 +1150,26 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.44.6-h2b0a6b4_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-h36e74d4_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.2.0-h3abd4de_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.86.4-h5192d8d_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.86.4-hf516916_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.3.0-h71661d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.88.1-hd810c12_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.88.1-hee1de02_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.11-h18acefa_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gsl-2.8-hbf7d49c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.10-h0363672_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.10-h17cb667_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.11-h6d08254_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.11-h29cf534_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gtest-1.17.0-h84d6215_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gtk3-3.24.52-ha5ea40c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.16.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h5glance-0.9-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py311h0b2f468_101.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-13.2.1-h6083320_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py311h0b2f468_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-14.2.0-h6083320_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hatch-1.16.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hatchling-1.29.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_108.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_109.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5plugin-6.0.0-py311h60fd0ea_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hicolor-icon-theme-0.17-ha770c72_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda @@ -1182,19 +1180,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/hyperlink-21.0.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/id-1.6.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/imageio-2.37.0-pyhfb79c49_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-2.0.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.2.2-hde8ca8f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.5.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-7.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-7.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-7.2.0-pyha191276_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.10.1-pyh53cf698_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.13.0-pyh53cf698_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhcf101f3_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.4.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/jasper-4.2.9-h1588d4d_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda @@ -1215,23 +1212,23 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.0-py311h724c32c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.7-gpl_hc2c16d8_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-7_h4a7cf45_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.88.0-hd24cca6_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-python-1.88.0-py311h1d5f577_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcap-2.77-hd0affe5_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.0-default_h99862b1_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-7_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.5-default_h99862b1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.5-default_h746c552_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda @@ -1239,63 +1236,63 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-devel-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.0-hecca717_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libflac-1.5.0-he200343_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.4-h6548e54_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.1-h0d30a3d_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.3-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.12.2-default_hafda6a7_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-7_h47877c9_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblief-0.17.6-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.8-hf7376ad_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.2-hf7376ad_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py311hc5d5c7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.5-hf7376ad_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.6.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.6.0-hf859cbd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.6.0-py311he982024_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.2-hc2fc477_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmsgpack-c-6.1.0-h54a6638_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_104.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.5-hd0c01bc_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopus-1.6.1-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.56-h421ea60_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.3-h9abb657_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libraw-0.21.5-h074291d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/librdkafka-2.13.2-he5e3081_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.62.1-h4c96295_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc7d488a_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.36-h9463b59_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.37-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-hd0affe5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h4ab18f5_1006.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.341.0-h5279c79_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.6.0-h9635ea4_0.conda @@ -1303,8 +1300,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.13.1-hca5e8e5_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.3-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.43-h711ed8c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.2-h6991a6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda @@ -1314,64 +1311,64 @@ environments: - conda: https://conda.anaconda.org/mantid/label/main/linux-64/mantid-6.15.0-np21py311h131b964_0.conda - conda: https://conda.anaconda.org/mantid/label/main/linux-64/mantidqt-6.15.0-py311he66f075_0.conda - conda: https://conda.anaconda.org/mantid/label/main/linux-64/mantidworkbench-6.15.0-py311h3ec3e80_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py311h3778330_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.4-py311h38be061_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.4-py311h2b939e6_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mbedtls-3.6.3.1-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py311h38be061_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-25.0.5-h57bcd07_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-26.0.3-h8cca3c9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-11.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py311hdf67eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/multidict-6.7.1-py311h3778330_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/muparser-2.3.4-h27087fc_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.19.1-py311h49ec1c0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.20.2-py311h49ec1c0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nbformat-5.10.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nexusformat-1.0.8-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.4-py310h6de7dc8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.5-py310hd8a072f_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.1.3-py311h71ddf71_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.8-h40f6f1d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.11-h9f1635d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.26.3-h8d634f6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.27.2-h8d634f6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.13-hbde042b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/orsopy-1.2.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.2-h3435931_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.2-py311h8032f78_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pango-1.56.4-hda50119_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.6-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.7-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patch-2.8-hb03c661_1002.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-11.3.0-py311h98278a2_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pint-0.25.3-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.1-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkce-1.0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.6-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/poco-1.14.2-h0a6e815_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pooch-1.9.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prettytable-3.17.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.0-he0df7b0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.1-he0df7b0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/propcache-0.3.1-py311h2dc5d0c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py311haee01d2_0.conda @@ -1386,9 +1383,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pyconify-0.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py311h49ec1c0_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py311h902ca64_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py311h902ca64_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.14.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyjwt-2.12.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda @@ -1396,24 +1393,24 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.9-py311hf0fb5b6_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.12.2-py311hb755f60_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqtwebengine-5.15.9-py311hd529140_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py311hf27b23e_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.11.0-py311hf27b23e_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pystack-1.6.0-py311h67e06ae_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-qt-4.5.0-pyhdecd6ff_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.11.15-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-libarchive-c-5.3-pyhe01879c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.8.1-py311haee01d2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.11.0-py311haee01d2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.1.post1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.47.1-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.3-pyhdecd6ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.48.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.4-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py311h3778330_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py311h57d2397_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda @@ -1421,24 +1418,24 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-gtk-platformtheme-5.15.15-h4e19bd6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.15-h0c412b5_8.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-webengine-5.15.15-h5dcc908_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.10.2-pl5321h16c4a6b_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.11.0-pl5321h16c4a6b_4.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtconsole-5.7.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtconsole-base-5.7.2-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtpy-2.4.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/quasielasticbayes-0.3.0-py311h7bc6544_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/quickbayes-1.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rapidjson-1.1.0.post20240409-h3f2d84a_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.61.4-ha759004_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.1-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.64.1-ha759004_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.7.post0-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.7.post0-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/rich-rst-1.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ripgrep-15.1.0-hdab8a38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/roman-numerals-4.1.0-pyhd8ed1ab_0.conda @@ -1447,13 +1444,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py311haee01d2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py311haee01d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.3-py311hbe70eeb_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.4.1-py311h38be061_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.1.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/semver-3.0.4-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.6.4-hb700be7_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.12-py311hb755f60_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda @@ -1469,49 +1466,49 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jquery-4.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-programoutput-0.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2025.5-hb700be7_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2026.1-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/superqt-0.8.0-pyh9208f05_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2022.3.0-hb700be7_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2023.0.0-h51de99f_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhcf101f3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.15.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.5-py311h49ec1c0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.1.14.14-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.5.7.17-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/twine-6.2.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.24.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20250915-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20251009-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.25.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20260510-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20260408-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uncertainties-3.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py311h49ec1c0_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unixodbc-2.3.14-h69e2008_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/utfcpp-4.09-ha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.2-h0f56927_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.13-h29f5ae7_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.3.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.0-hca82ae8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.0-py311h37e4f33_4.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.3.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.1-cpu_hc82bd48_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.1-py311h0f46057_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.7.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.6-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.6-hb03c661_0.conda @@ -1544,13 +1541,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.23.0-py311h3778330_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.1-h909a3a2_5.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py311haee01d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - pypi: https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e7/26/46673bb18448c51222c6272c850484a0092f364fae8d0315be9aa1e4baa7/regex-2026.3.32-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/33/6f/1481597e859ef19508b345eec4afd1416ed6e6b459c75a64026ef193aecf/regex-2026.5.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d2/b8/f0b9b880c03a3db8eaff63d76ca751ac7d8e45483fb7a0bb9f8e5c6ce433/toml_cli-0.8.2-py3-none-any.whl - pypi: ./ qa: @@ -1576,8 +1573,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.4.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-1.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.15.3-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.1-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-client-1.14.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda @@ -1591,7 +1588,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.18.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhcf101f3_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py312h90b7ffd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.4.0-py312h90b7ffd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.14.3-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda @@ -1601,32 +1598,32 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.23.1-hc31b594_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-he90730b_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py312h460c074_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/chardet-5.2.0-pyhd8ed1ab_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/chardet-7.4.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cli11-2.6.2-h54a6638_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-2024.11.20-py312h4c3975b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/comm-0.2.3-pyhe01879c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.7.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.3.2-py312h7900ff3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-26.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312h0a2e395_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.13.5-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.0-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.13-py312hd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-46.0.5-py312ha4b625e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-48.0.0-py312ha4b625e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.10.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.11.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.28-hac629b4_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-h24cb091_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.20-py312h8285ef7_0.conda @@ -1637,15 +1634,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/docstring_parser-0.17.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.4.0-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.6-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-abi-5.0.1.80-hf414acd_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/epoxy-1.5.10-hb03c661_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/euphonic-1.6.0-py312h4f23490_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/euphonic-1.6.1-py312h4f23490_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/evalidate-2.0.5-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexcache-0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/flexparser-0.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda @@ -1656,8 +1653,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.0-py312h8a5da7c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-ha6d2627_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.1-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-h215f996_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/freeimage-3.18.0-h49ef1fa_24.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.3-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.16-hb03c661_0.conda @@ -1665,28 +1662,27 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.7.0-py312h447239a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/future-1.0.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.44.6-h2b0a6b4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-h36e74d4_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.2.0-h3abd4de_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.86.4-h5192d8d_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.86.4-hf516916_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.3.0-h71661d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.88.1-hd810c12_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.88.1-hee1de02_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.11-h18acefa_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gsl-2.8-hbf7d49c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.10-h0363672_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.10-h17cb667_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.11-h6d08254_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.11-h29cf534_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gtest-1.17.0-h84d6215_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gtk3-3.24.52-ha5ea40c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.16.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h5glance-0.9-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py312ha4f8f14_101.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-13.2.1-h6083320_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py312ha4f8f14_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-14.2.0-h6083320_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hatch-1.16.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hatchling-1.29.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_108.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_109.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5plugin-6.0.0-py312hb944afc_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hicolor-icon-theme-0.17-ha770c72_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda @@ -1697,19 +1693,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/hyperlink-21.0.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/id-1.6.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/imageio-2.37.0-pyhfb79c49_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-2.0.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.2.2-hde8ca8f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.5.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-7.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-7.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-7.2.0-pyha191276_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.12.0-pyhecfbec7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.13.0-pyh53cf698_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhcf101f3_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.4.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/jasper-4.2.9-h1588d4d_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda @@ -1729,23 +1724,23 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.0-py312h0a2e395_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.7-gpl_hc2c16d8_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-7_h4a7cf45_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.88.0-hd24cca6_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-python-1.88.0-py312hf890105_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcap-2.77-hd0affe5_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.0-default_h99862b1_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-7_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.5-default_h99862b1_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.5-default_h746c552_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda @@ -1753,139 +1748,138 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-devel-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.0-hecca717_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libflac-1.5.0-he200343_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.4-h6548e54_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.1-h0d30a3d_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.3-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.12.2-default_hafda6a7_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-7_h47877c9_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblief-0.17.6-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.8-hf7376ad_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.2-hf7376ad_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py312h1ca65c7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.5-hf7376ad_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.6.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.6.0-hf859cbd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.6.0-py312h5ee1301_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.2-hc2fc477_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmsgpack-c-6.1.0-h54a6638_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_104.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.5-hd0c01bc_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libopus-1.6.1-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.56-h421ea60_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.3-h9abb657_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libraw-0.21.5-h074291d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/librdkafka-2.13.2-he5e3081_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.62.1-h4c96295_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc7d488a_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.36-h9463b59_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.37-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-hd0affe5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h4ab18f5_1006.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.341.0-h5279c79_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.6.0-h9635ea4_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.13.1-hca5e8e5_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.3-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.43-h711ed8c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.2-h6991a6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-4.4.5-py312h3d67a73_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda - - conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantid-6.15.0.2rc4-np21py312h62f99c1_0.conda - - conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantidqt-6.15.0.2rc4-py312he48a509_0.conda - - conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantidworkbench-6.15.0.2rc4-py312hea17ed9_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantid-6.15.0.4rc1-np21py312h68643e6_0.conda + - conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantidqt-6.15.0.4rc1-py312he137b73_0.conda + - conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantidworkbench-6.15.0.4rc1-py312h0a96521_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.4-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.4-py312hd3ec401_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.9-py312h7900ff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.9-py312he3d6523_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mbedtls-3.6.3.1-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-25.0.5-h57bcd07_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-26.0.3-h8cca3c9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-11.0.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py312hd9148b4_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/multidict-6.7.1-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/muparser-2.3.4-h27087fc_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.19.1-py312h4c3975b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.20.2-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nbformat-5.10.4-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nexusformat-1.0.8-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.4-py310h6de7dc8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.5-py310hd8a072f_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.1.3-py312h58c1407_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.8-h40f6f1d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.11-h9f1635d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.26.3-h8d634f6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.27.2-h8d634f6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.13-hbde042b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/orsopy-1.2.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.2-h3435931_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.2-py312h8ecdadd_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pango-1.56.4-hda50119_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.6-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.7-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patch-2.8-hb03c661_1002.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.1.1-py312h50c33e8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py312h50c33e8_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pint-0.25.3-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.1-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkce-1.0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.6-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/poco-1.15.1-hbea8664_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/poco-1.15.2-hc403b36_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pooch-1.9.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prettytable-3.17.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.0-he0df7b0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.1-he0df7b0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/propcache-0.3.1-py312h178313f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h5253ce2_0.conda @@ -1900,59 +1894,57 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pyconify-0.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py312h4c3975b_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py312h868fb18_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.14.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyjwt-2.12.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject_hooks-1.2.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.11-py312h82c0db2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.17.0-py312h1289d80_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqtwebengine-5.15.11-py312hf963f02_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.11.0-py312h50ac2ff_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pystack-1.6.0-py312hb682716_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-qt-4.5.0-pyhdecd6ff_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.3.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.13-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-libarchive-c-5.3-pyhe01879c_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.8.1-py312h5253ce2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.11.0-py312h5253ce2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.1.post1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.47.1-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.3-pyhdecd6ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.48.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.4-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hda471dd_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qscintilla2-2.14.1-py312h82c0db2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-gtk-platformtheme-5.15.15-h4e19bd6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.15-h0c412b5_8.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-webengine-5.15.15-h5dcc908_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.10.2-pl5321h16c4a6b_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.11.0-pl5321h16c4a6b_4.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtconsole-5.7.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtconsole-base-5.7.2-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/qtpy-2.4.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/quasielasticbayes-0.3.0-py312hfc6b132_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/quickbayes-1.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rapidjson-1.1.0.post20240409-h3f2d84a_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.61.4-ha759004_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.1-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.64.1-ha759004_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.7.post0-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.7.post0-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/rich-rst-1.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ripgrep-15.1.0-hdab8a38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/roman-numerals-4.1.0-pyhd8ed1ab_0.conda @@ -1961,13 +1953,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py312h5253ce2_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py312h5253ce2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.3-py312h54fa4ab_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.4.1-py312h7900ff3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.2.1-pyhcf101f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/semver-3.0.4-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.6.4-hb700be7_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/sip-6.10.0-py312h1289d80_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda @@ -1983,49 +1975,49 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jquery-4.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-programoutput-0.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2025.5-hb700be7_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2026.1-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/superqt-0.8.0-pyh9208f05_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2022.3.0-hb700be7_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2023.0.0-h51de99f_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhcf101f3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.15.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.5-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.1.14.14-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.5.7.17-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/twine-6.2.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.24.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20250915-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20251009-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.25.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20260510-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20260408-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uncertainties-3.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unixodbc-2.3.14-h69e2008_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/utfcpp-4.09-ha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.2-h0f56927_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.13-h29f5ae7_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.3.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.0-hca82ae8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.0-py312h64f160b_4.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.3.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.1-cpu_hc82bd48_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.1-py312hb8f95c7_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.7.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.6-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.6-hb03c661_0.conda @@ -2058,13 +2050,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.23.0-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.1-h909a3a2_5.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py312h5253ce2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - pypi: https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0a/fe/661043d1c263b0d9d10c6ff4e9c9745f3df9641c62b51f96a3473638e7ce/regex-2026.3.32-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/cc/1e/3fbe2fa1e8cebd62f3bb7d3321cff1640aca2e240b51d9bd624aad949260/regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d2/b8/f0b9b880c03a3db8eaff63d76ca751ac7d8e45483fb7a0bb9f8e5c6ce433/toml_cli-0.8.2-py3-none-any.whl - pypi: ./ packages: @@ -2193,9 +2185,9 @@ packages: purls: [] size: 584660 timestamp: 1768327524772 -- conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.0-pyhd8ed1ab_0.conda - sha256: 402e5433ecc3d3ae06a9b43c3e45e769de86985ffd60e8355190802bba7ca3bb - md5: a60066d23ca609efbb14ada3e57fa98c +- conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-auth-0.14.4-pyhd8ed1ab_0.conda + sha256: 9365229ee90c2fab3cedf91ecdad4f2954eb18a33f1a6837ceb1a22ea0b57893 + md5: f28c911b16449d4d3b4b92a55f2579db depends: - anaconda-cli-base >=0.8.1 - cryptography >=3.4.0 @@ -2209,18 +2201,18 @@ packages: - requests - semver <4 constrains: + - anaconda-cloud-auth >=0.8 - conda >=23.9.0 - conda-token >=0.7.0 - - anaconda-cloud-auth >=0.8 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/anaconda-auth?source=hash-mapping - size: 52672 - timestamp: 1774323340657 -- conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.1-pyhc364b38_1.conda - sha256: 6ba3551f9085546106b23b980c8a71b884bf580c9a03245c0d3fa7fbff44c479 - md5: 7c77aad42e8687238c52e72b4ecf09b0 + size: 53713 + timestamp: 1777928666873 +- conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-cli-base-0.8.2-pyhc364b38_0.conda + sha256: a15e57650690f37bbe54f18e4ff429530b3bb54aa582ff9e3a9155921fec2804 + md5: af12e48f4d16dce2d160e3067930ad93 depends: - python >=3.10 - click @@ -2241,8 +2233,8 @@ packages: license_family: BSD purls: - pkg:pypi/anaconda-cli-base?source=hash-mapping - size: 29565 - timestamp: 1772639433841 + size: 29631 + timestamp: 1775090496005 - conda: https://conda.anaconda.org/conda-forge/noarch/anaconda-client-1.14.1-pyhcf101f3_0.conda sha256: 15f36a27ba72fcce0cc19023d55c2bc23cfa78940622df8e0d8d75c6c14b671a md5: 69a7f22cff99ab4b87aa2c5b729b00f8 @@ -2312,7 +2304,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/anyio?source=compressed-mapping + - pkg:pypi/anyio?source=hash-mapping size: 146764 timestamp: 1774359453364 - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda @@ -2390,7 +2382,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/attrs?source=compressed-mapping + - pkg:pypi/attrs?source=hash-mapping size: 64927 timestamp: 1773935801332 - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.18.0-pyhcf101f3_1.conda @@ -2404,7 +2396,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/babel?source=compressed-mapping + - pkg:pypi/babel?source=hash-mapping size: 7684321 timestamp: 1772555330347 - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda @@ -2430,9 +2422,9 @@ packages: - pkg:pypi/backports-tarfile?source=hash-mapping size: 35739 timestamp: 1767290467820 -- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py311h6b1f9c4_0.conda - sha256: 246e50ec7fc222875c6ecfa3feab77f5661dc43e26397bc01d9e0310e3cd48a0 - md5: adda5ef2a74c9bdb338ff8a51192898a +- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.4.0-py311h6b1f9c4_0.conda + sha256: a23717f9dc06924b988b92ba8dca0f4cb9154cac954457a40adb2f19d57896de + md5: aa8c3009fd8903bebdcb22fbcb4c0dea depends: - python - __glibc >=2.17,<3.0.a0 @@ -2442,22 +2434,22 @@ packages: license: BSD-3-Clause AND MIT AND EPL-2.0 purls: - pkg:pypi/backports-zstd?source=hash-mapping - size: 244920 - timestamp: 1767044984647 -- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py312h90b7ffd_0.conda - sha256: d77a24be15e283d83214121428290dbe55632a6e458378205b39c550afa008cf - md5: 5b8c55fed2e576dde4b0b33693a4fdb1 + size: 245341 + timestamp: 1777848716685 +- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.4.0-py312h90b7ffd_0.conda + sha256: e8c83696e6529ac1909a96690c58624bb376312fd0768409380cd9b05e248c9b + md5: 542da724e75cdeef19e29cca23935c25 depends: - python - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - python_abi 3.12.* *_cp312 - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.12.* *_cp312 license: BSD-3-Clause AND MIT AND EPL-2.0 purls: - pkg:pypi/backports-zstd?source=hash-mapping - size: 237970 - timestamp: 1767045004512 + size: 238360 + timestamp: 1777848717715 - conda: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.14.3-pyha770c72_0.conda sha256: bf1e71c3c0a5b024e44ff928225a0874fc3c3356ec1a0b6fe719108e6d1288f6 md5: 5267bef8efea4127aacd1f4e1f149b6e @@ -2567,7 +2559,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/brotli?source=compressed-mapping + - pkg:pypi/brotli?source=hash-mapping size: 368300 timestamp: 1764017300621 - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda @@ -2607,15 +2599,15 @@ packages: purls: [] size: 353899 timestamp: 1772620395951 -- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda - sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc - md5: 4492fd26db29495f0ba23f146cd5638d +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.4.22-hbd8a1cb_0.conda + sha256: c9dbcc8039a52023660d6d1bbf87594a93dd69c6ac5a2a44323af2c92976728d + md5: e18ad67cf881dcadee8b8d9e2f8e5f73 depends: - __unix license: ISC purls: [] - size: 147413 - timestamp: 1772006283803 + size: 131039 + timestamp: 1776865545798 - conda: https://conda.anaconda.org/conda-forge/noarch/cachecontrol-0.14.3-pyha770c72_0.conda sha256: ec791bb6f1ef504411f87b28946a7ae63ed1f3681cefc462cf1dfdaf0790b6a9 md5: 241ef6e3db47a143ac34c21bfba510f1 @@ -2678,16 +2670,16 @@ packages: purls: [] size: 989514 timestamp: 1766415934926 -- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda - sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 - md5: 765c4d97e877cdbbb88ff33152b86125 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda + sha256: 989db6e5957c4b44fa600c68c681ec2f36a55e48f7c7f1c073d5e91caa8cd878 + md5: 929471569c93acefb30282a22060dcd5 depends: - python >=3.10 license: ISC purls: - - pkg:pypi/certifi?source=compressed-mapping - size: 151445 - timestamp: 1772001170301 + - pkg:pypi/certifi?source=hash-mapping + size: 135656 + timestamp: 1776866680878 - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py311h03d9500_1.conda sha256: 3ad13377356c86d3a945ae30e9b8c8734300925ef81a3cb0a9db0d755afbe7bb md5: 3912e4373de46adafd8f1e97e4bd166b @@ -2731,28 +2723,28 @@ packages: - pkg:pypi/cfgv?source=hash-mapping size: 13589 timestamp: 1763607964133 -- conda: https://conda.anaconda.org/conda-forge/noarch/chardet-5.2.0-pyhd8ed1ab_3.conda - sha256: cfca3959d2bec9fcfec98350ecdd88b71dac6220d1002c257d65b40f6fbba87c - md5: 56bfd153e523d9b9d05e4cf3c1cfe01c +- conda: https://conda.anaconda.org/conda-forge/noarch/chardet-7.4.3-pyhcf101f3_0.conda + sha256: d307dcdba7498fadeeeed616ad0fc9e1cfd6061f5d83f64fbd20be4968f1bfb9 + md5: 7dd72a4c857cd652a1e23c13099a15d2 depends: - - python >=3.9 - license: LGPL-2.1-only - license_family: GPL + - python >=3.10 + - python + license: 0BSD purls: - pkg:pypi/chardet?source=hash-mapping - size: 132170 - timestamp: 1741798023836 -- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda - sha256: d86dfd428b2e3c364fa90e07437c8405d635aa4ef54b25ab51d9c712be4112a5 - md5: 49ee13eb9b8f44d63879c69b8a40a74b + size: 627453 + timestamp: 1776140819080 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda + sha256: 3f9483d62ce24ecd063f8a5a714448445dc8d9e201147c46699fc0033e824457 + md5: a9167b9571f3baa9d448faa2139d1089 depends: - python >=3.10 license: MIT license_family: MIT purls: - - pkg:pypi/charset-normalizer?source=compressed-mapping - size: 58510 - timestamp: 1773660086450 + - pkg:pypi/charset-normalizer?source=hash-mapping + size: 58872 + timestamp: 1775127203018 - conda: https://conda.anaconda.org/conda-forge/linux-64/cli11-2.6.2-h54a6638_0.conda sha256: 1d635e8963e094d95d35148df4b46e495f93bb0750ad5069f4e0e6bbb47ac3bf md5: 83dae3dfadcfec9b37a9fbff6f7f7378 @@ -2765,19 +2757,19 @@ packages: purls: [] size: 99051 timestamp: 1772207728613 -- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda - sha256: 38cfe1ee75b21a8361c8824f5544c3866f303af1762693a178266d7f198e8715 - md5: ea8a6c3256897cc31263de9f455e25d9 +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda + sha256: 37a5d8b10ea3516e2c42f870c9c351b9f7b31ff48c66d83490039f417e1e5228 + md5: 2266262ce8a425ecb6523d765f79b303 depends: - - python >=3.10 - __unix - python + - python >=3.10 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/click?source=hash-mapping - size: 97676 - timestamp: 1764518652276 + size: 100048 + timestamp: 1777219902525 - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-2024.11.20-py311h49ec1c0_1.conda sha256: 447b65e534b3104cbd55d98fcf06607d7d136f54be30577fbd654d9647717950 md5: 59ff48e89b1a32ddfbe0d73de2498ec8 @@ -2831,14 +2823,14 @@ packages: - pkg:pypi/comm?source=hash-mapping size: 14690 timestamp: 1753453984907 -- conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py311h38be061_0.conda - sha256: 9cd790637fcab45938ad49753d15b0cfbe847f9f0d4a1b7213d30b6fb412fede - md5: 52f7c28c287da1a28cb9cabda1f5d0cf +- conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.3.2-py311h38be061_1.conda + sha256: 9e48d9da9d7a6542a467b2d0526468e7918fb11544beb371fc210df943989751 + md5: 727fa88cd88480f8c17fc868cb0b9beb depends: - archspec >=0.2.3 - boltons >=23.0.0 - charset-normalizer - - conda-libmamba-solver >=25.4.0 + - conda-libmamba-solver >=25.11.0 - conda-package-handling >=2.2.0 - distro >=1.5.0 - frozendict >=2.4.2 @@ -2846,7 +2838,7 @@ packages: - menuinst >=2 - packaging >=23.0 - platformdirs >=3.10.0 - - pluggy >=1.0.0 + - pluggy >=1.6.0 - pycosat >=0.6.3 - python >=3.11,<3.12.0a0 - python_abi 3.11.* *_cp311 @@ -2858,22 +2850,22 @@ packages: - zstandard >=0.19.0 constrains: - conda-env >=2.6 + - conda-content-trust >=0.3.0 - conda-build >=25.9 - - conda-content-trust >=0.1.1 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/conda?source=hash-mapping - size: 1286583 - timestamp: 1772191375962 -- conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py312h7900ff3_0.conda - sha256: 375f17f645dfb7e995acaf0bfadd9ad0e591d8b63f8c2e6875d7a8c7b84ce1bf - md5: 32e3a7c6278d6f3993241ea4e4689ba8 + size: 1263294 + timestamp: 1777457739858 +- conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.3.2-py312h7900ff3_1.conda + sha256: 791dd5e4f9f317ccd53fcce74a59a2de9a1e11ced12abfc06c812d6c7644317f + md5: bfee51fc1b2eaf5e3e699c8b1353be55 depends: - archspec >=0.2.3 - boltons >=23.0.0 - charset-normalizer - - conda-libmamba-solver >=25.4.0 + - conda-libmamba-solver >=25.11.0 - conda-package-handling >=2.2.0 - distro >=1.5.0 - frozendict >=2.4.2 @@ -2881,7 +2873,7 @@ packages: - menuinst >=2 - packaging >=23.0 - platformdirs >=3.10.0 - - pluggy >=1.0.0 + - pluggy >=1.6.0 - pycosat >=0.6.3 - python >=3.12,<3.13.0a0 - python_abi 3.12.* *_cp312 @@ -2893,17 +2885,17 @@ packages: - zstandard >=0.19.0 constrains: - conda-env >=2.6 - - conda-content-trust >=0.1.1 + - conda-content-trust >=0.3.0 - conda-build >=25.9 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/conda?source=hash-mapping - size: 1257328 - timestamp: 1772191366983 -- conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_0.conda - sha256: 81ce7618c6d9dd0fb7861519ebf381839384e13715095a796463fb72b197322f - md5: 315159e27cb872b7c0141681a69dba3a + size: 1235591 + timestamp: 1777457739191 +- conda: https://conda.anaconda.org/conda-forge/noarch/conda-build-26.3.0-pyh31ec981_1.conda + sha256: 584ea91cfede78020876f75c864726fb96743e1424461b0ff86fa2a49f37d15d + md5: 47c7f3c52fb50f7699147ff3b9a2d987 depends: - __linux - beautifulsoup4 @@ -2925,7 +2917,6 @@ packages: - py-lief - python >=3.11 - python-libarchive-c - - pytz - pyyaml - rattler-build - requests @@ -2937,16 +2928,16 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/conda-build?source=compressed-mapping - size: 319776 - timestamp: 1774990297702 -- conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.7.0-pyhd8ed1ab_0.conda - sha256: c69f458bc0bd2af464288b2b9f5f8d014b408c0a72e12b6049f385f6d30f970f - md5: 70ba3b97a9a5afc8a8ce3d65260c9b44 + - pkg:pypi/conda-build?source=hash-mapping + size: 319592 + timestamp: 1776077171656 +- conda: https://conda.anaconda.org/conda-forge/noarch/conda-index-0.11.0-pyhd8ed1ab_0.conda + sha256: b4ca0bd410b8e3bff5dfb317431aaae7fb2d02f0d349a1320de6949922990a5a + md5: 8cc4a08be7f6235df245a345c77ca97c depends: - click >=8 - - conda >=4.14.0 - - conda-package-streaming >=0.7.0 + - conda >=25 + - conda-package-streaming >=0.12.0 - filelock - jinja2 - msgpack-python >=1.0.2 @@ -2957,11 +2948,11 @@ packages: license_family: BSD purls: - pkg:pypi/conda-index?source=hash-mapping - size: 199096 - timestamp: 1760661907193 -- conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda - sha256: 001812b000c9791db53a85b0f215952b7497ca1fd6e3070314e20f707556765b - md5: 1d545b8b06123889395de8a3674fc0e7 + size: 204825 + timestamp: 1776455505773 +- conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-26.4.1-pyhd8ed1ab_0.conda + sha256: 3c0513a2c32240f7d3c01af45623fa02950b96c2d74bd98f25882711c53a2978 + md5: 7fb0416c7841b65a087b466abd3dc28f depends: - boltons >=23.0.0 - libmambapy >=2.0.0 @@ -2975,8 +2966,8 @@ packages: license_family: BSD purls: - pkg:pypi/conda-libmamba-solver?source=hash-mapping - size: 56969 - timestamp: 1770137431666 + size: 59598 + timestamp: 1777712721201 - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda sha256: 8b2b1c235b7cbfa8488ad88ff934bdad25bac6a4c035714681fbff85b602f3f0 md5: 32c158f481b4fd7630c565030f7bc482 @@ -3016,7 +3007,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/contourpy?source=compressed-mapping + - pkg:pypi/contourpy?source=hash-mapping size: 320553 timestamp: 1769155975008 - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312h0a2e395_4.conda @@ -3035,9 +3026,9 @@ packages: - pkg:pypi/contourpy?source=hash-mapping size: 320386 timestamp: 1769155979897 -- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.13.5-py311h3778330_0.conda - sha256: 3b6e6e0d4c46c4e7664a4baef5b1b4a8142bd0f9521534211e934e59773e533c - md5: e32c4e7639b1c1b5680fabdaa6081e56 +- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.0-py311h3778330_0.conda + sha256: 865202b90e5c9af7f39aa9f84ffc0d6d561c4757f010eacbf2e43efdee05bfd7 + md5: f566275adc487ec7b8dfaf9257967fcf depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -3045,14 +3036,13 @@ packages: - python_abi 3.11.* *_cp311 - tomli license: Apache-2.0 - license_family: APACHE purls: - - pkg:pypi/coverage?source=compressed-mapping - size: 399687 - timestamp: 1773761044419 -- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.13.5-py312h8a5da7c_0.conda - sha256: 9e88f91f85f0049686796fd25b20001bfbe9e4367714bb5d258849abcf54a705 - md5: c4d858e15305e70b255e756a4dc96e58 + - pkg:pypi/coverage?source=hash-mapping + size: 400114 + timestamp: 1778444963541 +- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.0-py312h8a5da7c_0.conda + sha256: 6ed9b689e92c5e202d834d5a4eeba990ecbfda104ef40ac455f3d006d439a926 + md5: c78de13127e71cb1e581f473ac76f360 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -3060,11 +3050,10 @@ packages: - python_abi 3.12.* *_cp312 - tomli license: Apache-2.0 - license_family: APACHE purls: - - pkg:pypi/coverage?source=compressed-mapping - size: 387585 - timestamp: 1773761191371 + - pkg:pypi/coverage?source=hash-mapping + size: 390409 + timestamp: 1778444934285 - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda sha256: 0d9405d9f2de5d4b15d746609d87807aac10e269072d6408b769159762ed113d md5: d17488e343e4c5c0bd0db18b3934d517 @@ -3098,14 +3087,14 @@ packages: purls: [] size: 46463 timestamp: 1772728929620 -- conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-46.0.5-py311h2005dd1_0.conda - sha256: 0b427b0f353ccf66a926360b6544ea18566e13099e661dcd35c61ffc9c0924e9 - md5: f9c47968555906c9fe918f447d9abf1f +- conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-48.0.0-py311h2005dd1_0.conda + sha256: 838cde68e70f4e0dc6458613316fa0e50eee5cf86cafb1cee4b7ca1a701a8436 + md5: 96f6e551c7ff30c95c1c8b4d2d1c5c9f depends: - __glibc >=2.17,<3.0.a0 - - cffi >=1.14 + - cffi >=2.0 - libgcc >=14 - - openssl >=3.5.5,<4.0a0 + - openssl >=3.5.6,<4.0a0 - python >=3.11,<3.12.0a0 - python_abi 3.11.* *_cp311 constrains: @@ -3114,16 +3103,16 @@ packages: license_family: BSD purls: - pkg:pypi/cryptography?source=hash-mapping - size: 1714583 - timestamp: 1770772534804 -- conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-46.0.5-py312ha4b625e_0.conda - sha256: 3a20020b7c9efbabfbfdd726ff303df81159e0c3a41a40ef8b37c3ce161a7849 - md5: 4c69182866fcdd2fc335885b8f0ac192 + size: 1913519 + timestamp: 1777966158377 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-48.0.0-py312ha4b625e_0.conda + sha256: 16d3d1e8df34a36430a28f423380fbd93abe5670ca7b52e9f4a64c091fd3ddd9 + md5: c5a8e173200adf567dc2818d8bf1325f depends: - __glibc >=2.17,<3.0.a0 - - cffi >=1.14 + - cffi >=2.0 - libgcc >=14 - - openssl >=3.5.5,<4.0a0 + - openssl >=3.5.6,<4.0a0 - python >=3.12,<3.13.0a0 - python_abi 3.12.* *_cp312 constrains: @@ -3132,8 +3121,8 @@ packages: license_family: BSD purls: - pkg:pypi/cryptography?source=hash-mapping - size: 1712251 - timestamp: 1770772759286 + size: 1912222 + timestamp: 1777966300032 - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda sha256: bb47aec5338695ff8efbddbc669064a3b10fe34ad881fb8ad5d64fbfa6910ed1 md5: 4c2a8fef270f6c69591889b93f9f55c1 @@ -3163,9 +3152,9 @@ packages: - pkg:pypi/cyclonedx-python-lib?source=hash-mapping size: 185680 timestamp: 1773761822976 -- conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.10.1-pyhcf101f3_0.conda - sha256: aae95f265ed767d3ba490259bf9e14ec984f15aedf7e85a67da122a327f760ea - md5: 3718be965507e15f8c815e35b755600c +- conda: https://conda.anaconda.org/conda-forge/noarch/cyclopts-4.11.2-pyhcf101f3_0.conda + sha256: a8c8c87add7547efc02b3b4273ca03b65b2c757afd63dab0c04b322da8985782 + md5: 94238d5e6b8a19177d39e21663de27c9 depends: - python >=3.10 - attrs >=23.1.0 @@ -3179,8 +3168,8 @@ packages: license_family: APACHE purls: - pkg:pypi/cyclopts?source=hash-mapping - size: 163722 - timestamp: 1774283230806 + size: 171294 + timestamp: 1777904956128 - conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.28-hac629b4_1.conda sha256: 7684da83306bb69686c0506fb09aa7074e1a55ade50c3a879e4e5df6eebb1009 md5: af491aae930edc096b58466c51c4126c @@ -3318,17 +3307,18 @@ packages: purls: [] size: 71809 timestamp: 1765193127016 -- conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_1.conda - sha256: 8d4f908e670be360617d418c328213bc46e7100154c3742db085148141712f60 - md5: 2cf824fe702d88e641eec9f9f653e170 +- conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.6-pyhcf101f3_0.conda + sha256: bb826ff403b8195467e7cd5f504bc14767b424dac27bb225508ca2c1852554b2 + md5: 86b177231eecb011fe00e2117dbc3348 depends: - - python >=3.9 + - python >=3.10 + - python license: MIT license_family: MIT purls: - pkg:pypi/editables?source=hash-mapping - size: 10828 - timestamp: 1733208220327 + size: 13160 + timestamp: 1776172429816 - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-abi-5.0.1.80-hf414acd_0.conda sha256: acde70d55f7dbbc043d733427fd6f1ec6ca49db7cbabcf7a656dd29a952b8ad8 md5: a85c1768af7780d67c6446c17848b76f @@ -3406,9 +3396,9 @@ packages: - pkg:pypi/euphonic?source=hash-mapping size: 317596 timestamp: 1767781349165 -- conda: https://conda.anaconda.org/conda-forge/linux-64/euphonic-1.6.0-py312h4f23490_0.conda - sha256: 6d82e6b7b259a337a31427c2880ac983479d955b5254b4f77c78c97381b9fa14 - md5: 98e201681f3f75a6750b82b7285cfe45 +- conda: https://conda.anaconda.org/conda-forge/linux-64/euphonic-1.6.1-py312h4f23490_0.conda + sha256: c5902e19ba36741a970b61eceecad9875e2f8854ab19eb085d7a61ee478940b5 + md5: 40d94395d8ceac2e0201bf717891a7bc depends: - __glibc >=2.17,<3.0.a0 - _openmp_mutex >=4.5 @@ -3428,8 +3418,8 @@ packages: license_family: GPL purls: - pkg:pypi/euphonic?source=hash-mapping - size: 312625 - timestamp: 1770757368164 + size: 312551 + timestamp: 1776193760939 - conda: https://conda.anaconda.org/conda-forge/noarch/evalidate-2.0.5-pyhe01879c_0.conda sha256: e98899cec440273341378bcff0e47bc10a5dbdffc0e77a7bc7010ca9189e3b4f md5: 202726f0a6ffa85897273591c4b32b0e @@ -3464,16 +3454,16 @@ packages: - pkg:pypi/executing?source=hash-mapping size: 30753 timestamp: 1756729456476 -- conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda - sha256: dddea9ec53d5e179de82c24569d41198f98db93314f0adae6b15195085d5567f - md5: f58064cec97b12a7136ebb8a6f8a129b +- conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.0-pyhd8ed1ab_0.conda + sha256: 6b471a18372bbd52bdf32fc965f71de3bc1b5219418b8e6b3875a67a7b08c483 + md5: 8fa8358d022a3a9bd101384a808044c6 depends: - python >=3.10 license: Unlicense purls: - - pkg:pypi/filelock?source=compressed-mapping - size: 25845 - timestamp: 1773314012590 + - pkg:pypi/filelock?source=hash-mapping + size: 34211 + timestamp: 1776621506566 - conda: https://conda.anaconda.org/conda-forge/noarch/flexcache-0.3-pyhd8ed1ab_1.conda sha256: acdb7b73d84268773fcc8192965994554411edc488ec3447925a62154e9d3baa md5: f1e618f2f783427019071b14a111b30d @@ -3582,9 +3572,9 @@ packages: purls: [] size: 4059 timestamp: 1762351264405 -- conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.0-py311h3778330_0.conda - sha256: f97e434344eefb9af8a5892a831b53a276c26fbabec3d2f1261064a819e8bbc9 - md5: bd4aa764c1b2f877aff5049f26cbffde +- conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.1-py311h3778330_0.conda + sha256: ce164bc99128b8fb0e47f45af8946ba53a6630280d6cc240b3faa17453424890 + md5: dd214022a8f01bc2ebed383dfdc8deea depends: - __glibc >=2.17,<3.0.a0 - brotli @@ -3596,12 +3586,12 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/fonttools?source=compressed-mapping - size: 3018805 - timestamp: 1773137226454 -- conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.0-py312h8a5da7c_0.conda - sha256: 777c80a1aa0889e6b637631c31f95d0b048848c5ba710f89ed7cedd3ad318227 - md5: 526f7ffd63820e55d7992cc1cf931a36 + - pkg:pypi/fonttools?source=hash-mapping + size: 3005683 + timestamp: 1776708364796 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.62.1-py312h8a5da7c_0.conda + sha256: e81f6e1ddadbc81ce56b158790148835256d2a3d5762016d389daaa06decfeab + md5: 2396fee22e84f69dffc6e23135905ce8 depends: - __glibc >=2.17,<3.0.a0 - brotli @@ -3614,25 +3604,29 @@ packages: license_family: MIT purls: - pkg:pypi/fonttools?source=hash-mapping - size: 2935817 - timestamp: 1773137546716 -- conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-ha6d2627_3.conda - sha256: 676540a8e7f73a894cb1fcb870e7bec623ec1c0a2d277094fd713261a02d8d56 - md5: 84ec3f5b46f3076be49f2cf3f1cfbf02 + size: 2953293 + timestamp: 1776708606358 +- conda: https://conda.anaconda.org/conda-forge/linux-64/freeglut-3.2.2-h215f996_4.conda + sha256: f94040a0d7c449038811097e145f223bd3b2ab4c5181870c6e27e1b9dd777d48 + md5: b39dccf5af984bcb68ee2aa0f3213ea6 depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libxcb >=1.16,<2.0.0a0 - - xorg-libx11 >=1.8.9,<2.0a0 - - xorg-libxau >=1.0.11,<2.0a0 - - xorg-libxext >=1.3.4,<2.0a0 - - xorg-libxfixes - - xorg-libxi + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libgl >=1.7.0,<2.0a0 + - libglu >=9.0.3,<9.1.0a0 + - libstdcxx >=14 + - libxcb >=1.17.0,<2.0a0 + - xorg-libx11 >=1.8.13,<2.0a0 + - xorg-libxau >=1.0.12,<2.0a0 + - xorg-libxext >=1.3.7,<2.0a0 + - xorg-libxfixes >=6.0.2,<7.0a0 + - xorg-libxi >=1.8.2,<2.0a0 + - xorg-libxxf86vm >=1.1.7,<2.0a0 license: MIT license_family: MIT purls: [] - size: 144010 - timestamp: 1719014356708 + size: 146159 + timestamp: 1776928018299 - conda: https://conda.anaconda.org/conda-forge/linux-64/freeimage-3.18.0-h49ef1fa_24.conda sha256: 42a16cc6d4521d8b596d533be088f828afb390cb4b9ebba265f9ed22a91c2bdf md5: 14ccdbaf6fcf27563ac43e522559a79b @@ -3784,9 +3778,9 @@ packages: purls: [] size: 75835 timestamp: 1773985381918 -- conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.2.0-h3abd4de_0.conda - sha256: fe1232f1a00b671091eff53388ef4dffc1e0e0efeb1c3e7c8ee4cbbbda968c80 - md5: 6ea943ca4f0d01d6eec6a60d24415dc5 +- conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.3.0-h71661d4_0.conda + sha256: 535d152ee06e3d3015a5ab410dfea9574e1678e226fa166f859a0b9e1153e597 + md5: 7eefecda1c71c380bfc406d16e78bbee depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -3797,32 +3791,32 @@ packages: license: BSD-3-Clause license_family: BSD purls: [] - size: 544416 - timestamp: 1760370322297 -- conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.86.4-h5192d8d_1.conda - sha256: 5439dc9c3f3ac84b5f637b31e0480b721d686da21927f6fc3f0e7b6944e53012 - md5: 61272bde04aeccf919351b92fbb96a53 + size: 492673 + timestamp: 1766373546677 +- conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.88.1-hd810c12_2.conda + sha256: 6a97b61cfb30a85c2f4a95f1f7525a873eea0b540f9f11b9cf31ad70d6635fce + md5: 9add1716591862a115c885dda4fcbeb5 depends: - - glib-tools 2.86.4 hf516916_1 - - libglib 2.86.4 h6548e54_1 - - packaging - python * + - packaging + - libglib ==2.88.1 h0d30a3d_2 + - glib-tools ==2.88.1 hee1de02_2 license: LGPL-2.1-or-later purls: [] - size: 79208 - timestamp: 1771863362595 -- conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.86.4-hf516916_1.conda - sha256: 441586fc577c5a3f2ad7bf83578eb135dac94fb0cb75cc4da35f8abb5823b857 - md5: b52b769cd13f7adaa6ccdc68ef801709 + size: 85268 + timestamp: 1778508800134 +- conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.88.1-hee1de02_2.conda + sha256: ae41fd5c867bc4e713a8cc1dc06f5b418026fec116cc222abe33e94235c6b241 + md5: e5a459d2bb98edb88de5a44bfad66b9d depends: - - __glibc >=2.17,<3.0.a0 + - libglib ==2.88.1 h0d30a3d_2 - libffi - libgcc >=14 - - libglib 2.86.4 h6548e54_1 + - __glibc >=2.17,<3.0.a0 license: LGPL-2.1-or-later purls: [] - size: 214712 - timestamp: 1771863307416 + size: 236955 + timestamp: 1778508800134 - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda sha256: 309cf4f04fec0c31b6771a5809a1909b4b3154a2208f52351e1ada006f4c750c md5: c94a5994ef49749880a8139cf9afcbe1 @@ -3833,9 +3827,9 @@ packages: purls: [] size: 460055 timestamp: 1718980856608 -- conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.11-h18acefa_1.conda - sha256: c1e0ec25221c132fcee81098a23f956f3c26302739086d99e9119ab5546b05fe - md5: 334367662a82dfe67945438e373a1d3b +- conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda + sha256: dbdbb714064914281c755650bc54e1855412e7e2f4c99ad171b5123ed704b2b1 + md5: 7c3de21891993e89aabdadaa603ed835 depends: - __glibc >=2.17,<3.0.a0 - gmp >=6.3.0,<7.0a0 @@ -3844,12 +3838,12 @@ packages: - libstdcxx >=14 - libtasn1 >=4.21.0,<5.0a0 - nettle >=3.10.1,<3.11.0a0 - - p11-kit >=0.26.0,<0.27.0a0 + - p11-kit >=0.26.2,<0.27.0a0 license: LGPL-2.1-or-later license_family: LGPL purls: [] - size: 2030992 - timestamp: 1768686277371 + size: 2054535 + timestamp: 1778044634746 - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda sha256: 25ba37da5c39697a77fce2c9a15e48cf0a84f1464ad2aafbe53d8357a9f6cc8c md5: 2cd94587f3a401ae05e03a6caf09539d @@ -3875,56 +3869,57 @@ packages: purls: [] size: 2486744 timestamp: 1737621160295 -- conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.10-h0363672_0.conda - sha256: f43bc8fd2c8b0c4317cf771f2cf8a9e7eee47105c233bfed00158f6579e41340 - md5: fd9738c3189541787bd967e19587de26 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.26.11-h6d08254_0.conda + sha256: 5a227ac457b9cc7a70b14008df1f91fd5dd2b3fda9641e5445c950b06d04be9e + md5: 971da16e7fc43161329213557688d315 depends: + - gstreamer ==1.26.11 h29cf534_0 - __glibc >=2.17,<3.0.a0 - - alsa-lib >=1.2.15.1,<1.3.0a0 - - gstreamer 1.26.10 h17cb667_0 - - libdrm >=2.4.125,<2.5.0a0 - - libegl >=1.7.0,<2.0a0 - - libexpat >=2.7.3,<3.0a0 - - libgcc >=14 - - libgl >=1.7.0,<2.0a0 - - libglib >=2.86.3,<3.0a0 - - libogg >=1.3.5,<1.4.0a0 - - libopus >=1.5.2,<2.0a0 - - libpng >=1.6.53,<1.7.0a0 - libstdcxx >=14 - - libvorbis >=1.3.7,<1.4.0a0 - - libxcb >=1.17.0,<2.0a0 - - libzlib >=1.3.1,<2.0a0 - - pango >=1.56.4,<2.0a0 - - xorg-libx11 >=1.8.12,<2.0a0 + - libgcc >=14 - xorg-libxau >=1.0.12,<2.0a0 + - libogg >=1.3.5,<1.4.0a0 + - xorg-libxshmfence >=1.3.3,<2.0a0 - xorg-libxdamage >=1.1.6,<2.0a0 - - xorg-libxext >=1.3.6,<2.0a0 - - xorg-libxfixes >=6.0.2,<7.0a0 + - libexpat >=2.7.5,<3.0a0 + - pango >=1.56.4,<2.0a0 - xorg-libxrender >=0.9.12,<0.10.0a0 - - xorg-libxshmfence >=1.3.3,<2.0a0 - - xorg-libxxf86vm >=1.1.6,<2.0a0 + - libxcb >=1.17.0,<2.0a0 + - xorg-libxfixes >=6.0.2,<7.0a0 + - libopus >=1.6.1,<2.0a0 + - libglib >=2.86.4,<3.0a0 + - libegl >=1.7.0,<2.0a0 + - alsa-lib >=1.2.15.3,<1.3.0a0 + - libgl >=1.7.0,<2.0a0 + - libvorbis >=1.3.7,<1.4.0a0 + - libpng >=1.6.57,<1.7.0a0 + - libdrm >=2.4.125,<2.5.0a0 + - gstreamer >=1.26.11,<1.27.0a0 + - libzlib >=1.3.2,<2.0a0 + - xorg-libxext >=1.3.7,<2.0a0 + - xorg-libxxf86vm >=1.1.7,<2.0a0 + - xorg-libx11 >=1.8.13,<2.0a0 license: LGPL-2.0-or-later license_family: LGPL purls: [] - size: 2928142 - timestamp: 1766699713774 -- conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.10-h17cb667_0.conda - sha256: 35044ecb0b08cd61f32b18f0c0c60f8d4aa610352eee4c5902e171a3decc0eba - md5: 0c38cdf4414540aae129822f961b5636 + size: 3199241 + timestamp: 1776268376145 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.26.11-h29cf534_0.conda + sha256: 6b9f6c7de3207b7d3a76741713587dd9f7fe2f00720f9ba047632f0900cfa5e5 + md5: 1e0e854b77451ac918b4a68f28932b1d depends: - - __glibc >=2.17,<3.0.a0 - - glib >=2.86.3,<3.0a0 + - glib >=2.86.4,<3.0a0 + - libstdcxx >=14 - libgcc >=14 - - libglib >=2.86.3,<3.0a0 + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.2,<2.0a0 + - libglib >=2.86.4,<3.0a0 - libiconv >=1.18,<2.0a0 - - libstdcxx >=14 - - libzlib >=1.3.1,<2.0a0 license: LGPL-2.0-or-later license_family: LGPL purls: [] - size: 2059388 - timestamp: 1766699555877 + size: 2281638 + timestamp: 1776268376145 - conda: https://conda.anaconda.org/conda-forge/linux-64/gtest-1.17.0-h84d6215_1.conda sha256: 1f738280f245863c5ac78bcc04bb57266357acda45661c4aa25823030c6fb5db md5: 55e29b72a71339bc651f9975492db71f @@ -3992,7 +3987,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/h11?source=compressed-mapping + - pkg:pypi/h11?source=hash-mapping size: 39069 timestamp: 1767729720872 - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda @@ -4022,9 +4017,9 @@ packages: - pkg:pypi/h5glance?source=hash-mapping size: 22140 timestamp: 1732029278587 -- conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py311h0b2f468_101.conda - sha256: bc6f3f698839e83f594dee629b53c506de3a37595f4571c9b85d7464fe8e23e9 - md5: 208b162b7be10f8398a88055190900f7 +- conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py311h0b2f468_102.conda + sha256: 61e3adb8218d57a2e7a91c7b4b4d338c3c0d23432ef0f2ed5bfc8d51f73735f3 + md5: f476161e215ecee68daf16efbf209731 depends: - __glibc >=2.17,<3.0.a0 - cached-property @@ -4036,12 +4031,12 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/h5py?source=compressed-mapping - size: 1356892 - timestamp: 1774712270994 -- conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py312ha4f8f14_101.conda - sha256: ea129e82173ea5841bc6ecf898ed03505252a7c0912c632d09c1b5ccffea6ca0 - md5: 00cda48b891eb5189ec4ce1a469df0f6 + - pkg:pypi/h5py?source=hash-mapping + size: 1353682 + timestamp: 1775581279300 +- conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py312ha4f8f14_102.conda + sha256: de9ec9b1b01b90f2da2d896a5835a2fd8049859aff0c6331ca4594327ec79a8b + md5: b270340809d19ae40ff9913f277b803a depends: - __glibc >=2.17,<3.0.a0 - cached-property @@ -4054,19 +4049,19 @@ packages: license_family: BSD purls: - pkg:pypi/h5py?source=hash-mapping - size: 1334426 - timestamp: 1774712279148 -- conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-13.2.1-h6083320_0.conda - sha256: 477f2c553f72165020d3c56740ba354be916c2f0b76fd9f535e83d698277d5ec - md5: 14470902326beee192e33719a2e8bb7f + size: 1335314 + timestamp: 1775581269364 +- conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-14.2.0-h6083320_0.conda + sha256: 232c95b56d16d33d8256026a3b1ad34f7f9a75c179d388854be0fd624ddba9e3 + md5: e194f6a2f498f0c7b1e6498bd0b12645 depends: - __glibc >=2.17,<3.0.a0 - cairo >=1.18.4,<2.0a0 - graphite2 >=1.3.14,<2.0a0 - icu >=78.3,<79.0a0 - - libexpat >=2.7.4,<3.0a0 - - libfreetype >=2.14.2 - - libfreetype6 >=2.14.2 + - libexpat >=2.7.5,<3.0a0 + - libfreetype >=2.14.3 + - libfreetype6 >=2.14.3 - libgcc >=14 - libglib >=2.86.4,<3.0a0 - libstdcxx >=14 @@ -4074,8 +4069,8 @@ packages: license: MIT license_family: MIT purls: [] - size: 2384060 - timestamp: 1774276284520 + size: 2333599 + timestamp: 1776778392713 - conda: https://conda.anaconda.org/conda-forge/noarch/hatch-1.16.5-pyhcf101f3_0.conda sha256: e298f93e25d98f5b90f231cf9cd6467773fc3fd242a9a0dce2b82fcfa1b38971 md5: 3191c464a2222e8af63e57926da9315c @@ -4121,7 +4116,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/hatchling?source=compressed-mapping + - pkg:pypi/hatchling?source=hash-mapping size: 61052 timestamp: 1773194193187 - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda @@ -4137,24 +4132,24 @@ packages: purls: [] size: 756742 timestamp: 1695661547874 -- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_108.conda - sha256: 795c3a34643aa766450b8363b8c5dd6e65ad40e5cc64d138c3678d05068a380a - md5: cbb2d15a6e9aeb85f18f1a8f01c29b81 +- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_109.conda + sha256: 9d2ea00599e2874b295baa7e719c79823ed61fec885e25c55e7dad666fb1cf50 + md5: c0ca97fff3fff46f837c69efedf838b1 depends: - __glibc >=2.17,<3.0.a0 - libaec >=1.1.5,<2.0a0 - - libcurl >=8.19.0,<9.0a0 + - libcurl >=8.20.0,<9.0a0 - libgcc >=14 - libgfortran - libgfortran5 >=14.3.0 - libstdcxx >=14 - libzlib >=1.3.2,<2.0a0 - - openssl >=3.5.5,<4.0a0 + - openssl >=3.5.6,<4.0a0 license: BSD-3-Clause license_family: BSD purls: [] - size: 3719931 - timestamp: 1774406907641 + size: 3719822 + timestamp: 1777518369641 - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5plugin-6.0.0-py311h60fd0ea_5.conda sha256: 5bbb95e68fe40468d1f55df0494c932bc025c662931e6fcdc5956f16ccd94234 md5: 25623058b0001eb8d5c5a1398f5c3aac @@ -4325,9 +4320,9 @@ packages: - pkg:pypi/id?source=hash-mapping size: 27972 timestamp: 1770237711404 -- conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda - sha256: 3bae1b612ccc71e49c5795a369a82c4707ae6fd4e63360e8ecc129f9539f779b - md5: 635d1a924e1c55416fce044ed96144a2 +- conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda + sha256: 381cedccf0866babfc135d65ee40b778bd20e927d2a5ec810f750c5860a7c5b8 + md5: 84a3233b709a289a4ddd7a2fd27dd988 depends: - python >=3.10 - ukkonen @@ -4335,32 +4330,20 @@ packages: license_family: MIT purls: - pkg:pypi/identify?source=hash-mapping - size: 79749 - timestamp: 1774239544252 -- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - sha256: ae89d0299ada2a3162c2614a9d26557a92aa6a77120ce142f8e0109bbf0342b0 - md5: 53abe63df7e10a6ba605dc5f9f961d36 + size: 79757 + timestamp: 1776455344188 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda + sha256: 9ab620e6f64bb67737bd7bc1ad6f480770124e304c6710617aba7fe60b089f48 + md5: fb7130c190f9b4ec91219840a05ba3ac depends: - python >=3.10 + - python license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/idna?source=hash-mapping - size: 50721 - timestamp: 1760286526795 -- conda: https://conda.anaconda.org/conda-forge/noarch/imageio-2.37.0-pyhfb79c49_0.conda - sha256: 8ef69fa00c68fad34a3b7b260ea774fda9bd9274fd706d3baffb9519fd0063fe - md5: b5577bc2212219566578fd5af9993af6 - depends: - - numpy - - pillow >=8.3.2 - - python >=3.9 - license: BSD-2-Clause - license_family: BSD - purls: - - pkg:pypi/imageio?source=hash-mapping - size: 293226 - timestamp: 1738273949742 + size: 59038 + timestamp: 1776947141407 - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-2.0.0-pyhd8ed1ab_0.conda sha256: 5a047f9eac290e679b4e6f6f4cbfcc5acdfbf031a4f06824d4ddb590cdbb850b md5: 92617c2ba2847cca7a6ed813b6f4ab79 @@ -4395,34 +4378,34 @@ packages: license: Apache-2.0 license_family: APACHE purls: - - pkg:pypi/importlib-metadata?source=compressed-mapping + - pkg:pypi/importlib-metadata?source=hash-mapping size: 34387 timestamp: 1773931568510 -- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.5.2-pyhd8ed1ab_0.conda - sha256: a99a3dafdfff2bb648d2b10637c704400295cb2ba6dc929e2d814870cf9f6ae5 - md5: e376ea42e9ae40f3278b0f79c9bf9826 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-7.1.0-pyhd8ed1ab_0.conda + sha256: 6a2f86ef0965605d742b5b94229bf8b829258d0a9f640e3651901cc72ef9a0a5 + md5: e3bffa82b874f8b9a2631bddb3869529 depends: - - importlib_resources >=6.5.2,<6.5.3.0a0 - - python >=3.9 + - importlib_resources >=7.1.0,<7.1.1.0a0 + - python >=3.10 license: Apache-2.0 license_family: APACHE purls: [] - size: 9724 - timestamp: 1736252443859 -- conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - sha256: acc1d991837c0afb67c75b77fdc72b4bf022aac71fedd8b9ea45918ac9b08a80 - md5: c85c76dc67d75619a92f51dfbce06992 + size: 10354 + timestamp: 1776068852701 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-7.1.0-pyhd8ed1ab_0.conda + sha256: a563a51aa522998172838e867e6dedcf630bc45796e8612f5a1f6d73e9c8125a + md5: 0ba6225c279baf7ea9473a62ea0ec9ae depends: - - python >=3.9 + - python >=3.10 - zipp >=3.1.0 constrains: - - importlib-resources >=6.5.2,<6.5.3.0a0 + - importlib-resources >=7.1.0,<7.1.1.0a0 license: Apache-2.0 license_family: APACHE purls: - pkg:pypi/importlib-resources?source=hash-mapping - size: 33781 - timestamp: 1736252433366 + size: 34809 + timestamp: 1776068839274 - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda sha256: e1a9e3b1c8fe62dc3932a616c284b5d8cbe3124bbfbedcf4ce5c828cb166ee19 md5: 9614359868482abba1bd15ce465e3c42 @@ -4461,32 +4444,9 @@ packages: - pkg:pypi/ipykernel?source=hash-mapping size: 133644 timestamp: 1770566133040 -- conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.10.1-pyh53cf698_0.conda - sha256: 31a2051c65320221ee9d69faa4482f6b0e930d501a59ce31f299d8c35ef1dae7 - md5: 6c1b4639872bdd4b6954b2c20fe2411a - depends: - - __unix - - decorator >=4.3.2 - - ipython_pygments_lexers >=1.0.0 - - jedi >=0.18.1 - - matplotlib-inline >=0.1.5 - - prompt-toolkit >=3.0.41,<3.1.0 - - pygments >=2.11.0 - - python >=3.11 - - stack_data >=0.6.0 - - traitlets >=5.13.0 - - typing_extensions >=4.6 - - pexpect >4.3 - - python - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/ipython?source=hash-mapping - size: 647233 - timestamp: 1774631599657 -- conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.12.0-pyhecfbec7_0.conda - sha256: 932044bd893f7adce6c9b384b96a72fd3804cc381e76789398c2fae900f21df7 - md5: b293210beb192c3024683bf6a998a0b8 +- conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.13.0-pyh53cf698_0.conda + sha256: a0af49948a1842dfd15a0b0b2fd56c94ddbd07e07a6c8b4bc70d43015eafaff0 + md5: 73e9657cd19605740d21efb14d8d0cb9 depends: - __unix - decorator >=5.1.0 @@ -4494,18 +4454,20 @@ packages: - jedi >=0.18.2 - matplotlib-inline >=0.1.6 - prompt-toolkit >=3.0.41,<3.1.0 + - psutil >=7 - pygments >=2.14.0 - - python >=3.12 + - python >=3.11 - stack_data >=0.6.0 - traitlets >=5.13.0 + - typing_extensions >=4.6 - pexpect >4.6 - python license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/ipython?source=compressed-mapping - size: 649967 - timestamp: 1774609994657 + - pkg:pypi/ipython?source=hash-mapping + size: 651632 + timestamp: 1777038396606 - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda sha256: 894682a42a7d659ae12878dbcb274516a7031bbea9104e92f8e88c1f2765a104 md5: bd80ba060603cc228d9d81c257093119 @@ -4531,9 +4493,9 @@ packages: - pkg:pypi/jaraco-classes?source=hash-mapping size: 14831 timestamp: 1767294269456 -- conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.1-pyhcf101f3_0.conda - sha256: 49c3e2e9aa4930734badfcbb31543406ed1b5531cb833f595cf57baf628dea7d - md5: 5ed60de12f1673398943262371667f79 +- conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.1.2-pyhcf101f3_0.conda + sha256: 108b3919db8ef81b5585b38a3fedbe9eeccdf8fa576c250a13559a1188f597cc + md5: b9d2b1ffa307961f6bb7d83c8ba8a8be depends: - python >=3.10 - backports.tarfile @@ -4542,8 +4504,8 @@ packages: license_family: MIT purls: - pkg:pypi/jaraco-context?source=hash-mapping - size: 15368 - timestamp: 1773131463776 + size: 16222 + timestamp: 1776862415793 - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.4.0-pyhcf101f3_1.conda sha256: 6a91447b3bb4d7ae94cc0d77ed12617796629aee11111efe7ea43cbd0e113bda md5: aa83cc08626bf6b613a3103942be8951 @@ -4615,7 +4577,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/jinja2?source=compressed-mapping + - pkg:pypi/jinja2?source=hash-mapping size: 120685 timestamp: 1764517220861 - pypi: https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl @@ -4667,7 +4629,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/jsonpointer?source=compressed-mapping + - pkg:pypi/jsonpointer?source=hash-mapping size: 14190 timestamp: 1774311356147 - conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda @@ -4713,7 +4675,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/jupyter-client?source=compressed-mapping + - pkg:pypi/jupyter-client?source=hash-mapping size: 112785 timestamp: 1767954655912 - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_core-5.9.1-pyhc90fa1f_0.conda @@ -4800,7 +4762,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/kiwisolver?source=compressed-mapping + - pkg:pypi/kiwisolver?source=hash-mapping size: 77120 timestamp: 1773067050308 - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda @@ -4829,19 +4791,19 @@ packages: purls: [] size: 508258 timestamp: 1664996250081 -- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda - sha256: 836ec4b895352110335b9fdcfa83a8dcdbe6c5fb7c06c4929130600caea91c0a - md5: 6f2e2c8f58160147c4d1c6f4c14cbac4 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_0.conda + sha256: eb89c6c39f2f6a93db55723dbb2f6bba8c8e63e6312bf1abf13e6e9ff45849c8 + md5: f92f984b558e6e6204014b16d212b271 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - - libjpeg-turbo >=3.1.2,<4.0a0 + - libjpeg-turbo >=3.1.4.1,<4.0a0 - libtiff >=4.7.1,<4.8.0a0 license: MIT license_family: MIT purls: [] - size: 249959 - timestamp: 1768184673131 + size: 251086 + timestamp: 1778079286384 - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c md5: 18335a698559cdbcd86150a48bf54ba6 @@ -4879,44 +4841,43 @@ packages: purls: [] size: 36544 timestamp: 1769221884824 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda - sha256: 69ea8da58658ad26cb64fb0bfccd8a3250339811f0b57c6b8a742e5e51bacf70 - md5: 981d372c31a23e1aa9965d4e74d085d5 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.7-gpl_hc2c16d8_101.conda + sha256: 78dd3d493d72c7d7c7647912fe383a3545a2695ee308037b64e9d0752ccedbe9 + md5: bb1483d91797dae0b466cab86ceb59a7 depends: - __glibc >=2.17,<3.0.a0 - bzip2 >=1.0.8,<2.0a0 - libgcc >=14 - - liblzma >=5.8.2,<6.0a0 + - liblzma >=5.8.3,<6.0a0 - libxml2 - libxml2-16 >=2.14.6 - - libzlib >=1.3.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 - lz4-c >=1.10.0,<1.11.0a0 - lzo >=2.10,<3.0a0 - - openssl >=3.5.5,<4.0a0 + - openssl >=3.5.6,<4.0a0 - zstd >=1.5.7,<1.6.0a0 license: BSD-2-Clause license_family: BSD purls: [] - size: 887139 - timestamp: 1773243188979 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda - build_number: 6 - sha256: 7bfe936dbb5db04820cf300a9cc1f5ee8d5302fc896c2d66e30f1ee2f20fbfd6 - md5: 6d6d225559bfa6e2f3c90ee9c03d4e2e + size: 890218 + timestamp: 1778486345922 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-7_h4a7cf45_openblas.conda + build_number: 7 + sha256: 081c850f99bc355821fac9c6e3727d40b3f8ce3beb50a5437cf03726b611ff39 + md5: 955b44e8b00b7f7ef4ce0130cef12394 depends: - - libopenblas >=0.3.32,<0.3.33.0a0 - - libopenblas >=0.3.32,<1.0a0 + - libopenblas >=0.3.33,<0.3.34.0a0 + - libopenblas >=0.3.33,<1.0a0 constrains: - - blas 2.306 openblas - - liblapack 3.11.0 6*_openblas - - liblapacke 3.11.0 6*_openblas - - libcblas 3.11.0 6*_openblas - - mkl <2026 + - libcblas 3.11.0 7*_openblas + - blas 2.307 openblas + - liblapack 3.11.0 7*_openblas + - liblapacke 3.11.0 7*_openblas + - mkl <2027 license: BSD-3-Clause - license_family: BSD purls: [] - size: 18621 - timestamp: 1774503034895 + size: 18716 + timestamp: 1778489854108 - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.88.0-hd24cca6_7.conda sha256: dd489228e1916c7720c925248d0ba12803d1dc8b9898be0c51f4ab37bab6ffa5 md5: d70e4dc6a847d437387d45462fe60cf9 @@ -5017,47 +4978,46 @@ packages: purls: [] size: 124432 timestamp: 1774333989027 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda - build_number: 6 - sha256: 57edafa7796f6fa3ebbd5367692dd4c7f552be42109c2dd1a7c89b55089bf374 - md5: 36ae340a916635b97ac8a0655ace2a35 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-7_h0358290_openblas.conda + build_number: 7 + sha256: 956ae0bb1ec8b0c3663d75b151aceb0521b54e513bf97f621a035f9c87037970 + md5: 0675639dc24cb0032f199e7ff68e4633 depends: - - libblas 3.11.0 6_h4a7cf45_openblas + - libblas 3.11.0 7_h4a7cf45_openblas constrains: - - blas 2.306 openblas - - liblapack 3.11.0 6*_openblas - - liblapacke 3.11.0 6*_openblas + - liblapacke 3.11.0 7*_openblas + - blas 2.307 openblas + - liblapack 3.11.0 7*_openblas license: BSD-3-Clause - license_family: BSD purls: [] - size: 18622 - timestamp: 1774503050205 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.0-default_h99862b1_0.conda - sha256: 914da94dbf829192b2bb360a7684b32e46f047a57de96a2f5ab39a011aeae6ea - md5: d966a23335e090a5410cc4f0dec8d00a + size: 18675 + timestamp: 1778489861559 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp22.1-22.1.5-default_h99862b1_1.conda + sha256: 20319f075f7dc77270ec9a1696c5264b4ea06788105a1dd592a37bf0d544bfc7 + md5: 8d6a3213512f06865c389a43b781f837 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - - libllvm22 >=22.1.0,<22.2.0a0 + - libllvm22 >=22.1.5,<22.2.0a0 - libstdcxx >=14 license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 21661249 - timestamp: 1772101075353 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.0-default_h746c552_0.conda - sha256: 4a9dd814492a129f2ff40cd4ab0b942232c9e3c6dbc0d0aaf861f1f65e99cc7d - md5: 140459a7413d8f6884eb68205ce39a0d + size: 21678235 + timestamp: 1778479708847 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.5-default_h746c552_1.conda + sha256: 7f479f796ba05f22324fb484f53da6f9948395499d7558cc4ff5ec24e91448b1 + md5: af8c5fb71cb5aa4861365af2784fc9ce depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - - libllvm22 >=22.1.0,<22.2.0a0 + - libllvm22 >=22.1.5,<22.2.0a0 - libstdcxx >=14 license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 12817500 - timestamp: 1772101411287 + size: 12827971 + timestamp: 1778479852868 - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda sha256: 205c4f19550f3647832ec44e35e6d93c8c206782bdd620c1d7cf66237580ff9c md5: 49c553b47ff679a6a1e9fc80b9c5a2d4 @@ -5072,23 +5032,23 @@ packages: purls: [] size: 4518030 timestamp: 1770902209173 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda - sha256: a0390fd0536ebcd2244e243f5f00ab8e76ab62ed9aa214cd54470fe7496620f4 - md5: d50608c443a30c341c24277d28290f76 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda + sha256: 75963a5dd913311f59a35dbd307592f4fa754c4808aff9c33edb430c415e38eb + md5: c3cc2864f82a944bc90a7beb4d3b0e88 depends: - __glibc >=2.17,<3.0.a0 - krb5 >=1.22.2,<1.23.0a0 - libgcc >=14 - - libnghttp2 >=1.67.0,<2.0a0 + - libnghttp2 >=1.68.1,<2.0a0 - libssh2 >=1.11.1,<2.0a0 - - libzlib >=1.3.1,<2.0a0 - - openssl >=3.5.5,<4.0a0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 - zstd >=1.5.7,<1.6.0a0 license: curl license_family: MIT purls: [] - size: 466704 - timestamp: 1773218522665 + size: 468706 + timestamp: 1777461492876 - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda sha256: aa8e8c4be9a2e81610ddf574e05b64ee131fab5e0e3693210c9d6d2fba32c680 md5: 6c77a605a7a689d17d4819c0f8ac9a00 @@ -5168,19 +5128,19 @@ packages: purls: [] size: 427426 timestamp: 1685725977222 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda - sha256: e8c2b57f6aacabdf2f1b0924bd4831ce5071ba080baa4a9e8c0d720588b6794c - md5: 49f570f3bc4c874a06ea69b7225753af +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.0-hecca717_0.conda + sha256: ea33c40977ea7a2c3658c522230058395bc2ee0d89d99f0711390b6a1ee80d12 + md5: a3b390520c563d78cc58974de95a03e5 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 constrains: - - expat 2.7.5.* + - expat 2.8.0.* license: MIT license_family: MIT purls: [] - size: 76624 - timestamp: 1774719175983 + size: 77241 + timestamp: 1777846112704 - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6 md5: a360c33a5abe61c07959e449fa1453eb @@ -5229,45 +5189,45 @@ packages: purls: [] size: 384575 timestamp: 1774298162622 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda - sha256: faf7d2017b4d718951e3a59d081eb09759152f93038479b768e3d612688f83f5 - md5: 0aa00f03f9e39fb9876085dee11a85d4 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + sha256: 8e0a3b5e41272e5678499b5dfc4cddb673f9e935de01eb0767ce857001229f46 + md5: 57736f29cc2b0ec0b6c2952d3f101b6a depends: - __glibc >=2.17,<3.0.a0 - _openmp_mutex >=4.5 constrains: - - libgcc-ng ==15.2.0=*_18 - - libgomp 15.2.0 he0feb66_18 + - libgcc-ng ==15.2.0=*_19 + - libgomp 15.2.0 he0feb66_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 1041788 - timestamp: 1771378212382 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda - sha256: e318a711400f536c81123e753d4c797a821021fb38970cebfb3f454126016893 - md5: d5e96b1ed75ca01906b3d2469b4ce493 + size: 1041084 + timestamp: 1778269013026 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + sha256: 9dcf54adfaa5e861123c2da4f2f0451a685464ea7e5a41ad91cf67b31d658d98 + md5: 331ee9b72b9dff570d56b1302c5ab37d depends: - - libgcc 15.2.0 he0feb66_18 + - libgcc 15.2.0 he0feb66_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 27526 - timestamp: 1771378224552 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda - sha256: d2c9fad338fd85e4487424865da8e74006ab2e2475bd788f624d7a39b2a72aee - md5: 9063115da5bc35fdc3e1002e69b9ef6e + size: 27694 + timestamp: 1778269016987 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + sha256: 561a42758ef25b9ce308c4e2cf56daee4f06138385a17e29a492cd928e00be6f + md5: 42bf7eca1a951735fa06c0e3c0d5c8e6 depends: - - libgfortran5 15.2.0 h68bc16d_18 + - libgfortran5 15.2.0 h68bc16d_19 constrains: - - libgfortran-ng ==15.2.0=*_18 + - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 27523 - timestamp: 1771378269450 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda - sha256: 539b57cf50ec85509a94ba9949b7e30717839e4d694bc94f30d41c9d34de2d12 - md5: 646855f357199a12f02a87382d429b75 + size: 27655 + timestamp: 1778269042954 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda + sha256: 057978bb69fea29ed715a9b98adf71015c31baecc4aeb2bfc20d4fd5d83579d4 + md5: 85072b0ad177c966294f129b7c04a2d5 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=15.2.0 @@ -5276,8 +5236,8 @@ packages: license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 2482475 - timestamp: 1771378241063 + size: 2483673 + timestamp: 1778269025089 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda sha256: dc2752241fa3d9e40ce552c1942d0a4b5eeb93740c9723873f6fcf8d39ef8d2d md5: 928b8be80851f5d8ffb016f9c81dae7a @@ -5300,22 +5260,22 @@ packages: purls: [] size: 113911 timestamp: 1731331012126 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.4-h6548e54_1.conda - sha256: a27e44168a1240b15659888ce0d9b938ed4bdb49e9ea68a7c1ff27bcea8b55ce - md5: bb26456332b07f68bf3b7622ed71c0da +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.1-h0d30a3d_2.conda + sha256: 33eb5d5310a5c2c0a4707a0afa644801c2e08c8f70c45e1f62f354116dfe0970 + md5: 17d484ab9c8179c6a6e5b7dbb5065afc depends: - __glibc >=2.17,<3.0.a0 - - libffi >=3.5.2,<3.6.0a0 - libgcc >=14 - - libiconv >=1.18,<2.0a0 - - libzlib >=1.3.1,<2.0a0 + - libffi >=3.5.2,<3.6.0a0 - pcre2 >=10.47,<10.48.0a0 + - libzlib >=1.3.2,<2.0a0 + - libiconv >=1.18,<2.0a0 constrains: - - glib 2.86.4 *_1 + - glib >2.66 license: LGPL-2.1-or-later purls: [] - size: 4398701 - timestamp: 1771863239578 + size: 4754097 + timestamp: 1778508800134 - conda: https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.3-h5888daf_1.conda sha256: a0105eb88f76073bbb30169312e797ed5449ebb4e964a756104d6e54633d17ef md5: 8422fcc9e5e172c91e99aef703b3ce65 @@ -5360,16 +5320,16 @@ packages: purls: [] size: 26388 timestamp: 1731331003255 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda - sha256: 21337ab58e5e0649d869ab168d4e609b033509de22521de1bfed0c031bfc5110 - md5: 239c5e9546c38a1e884d69effcf4c882 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + sha256: 5abe4ab9d93f6c9757d654f1969ae2267d4505315c1f2f8fe705fd60af084f1b + md5: faac990cb7aedc7f3a2224f2c9b0c26c depends: - __glibc >=2.17,<3.0.a0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 603262 - timestamp: 1771378117851 + size: 603817 + timestamp: 1778268942614 - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.12.2-default_hafda6a7_1000.conda sha256: 2cf160794dda62cf93539adf16d26cfd31092829f2a2757dbdd562984c1b110a md5: 0ed3aa3e3e6bc85050d38881673a692f @@ -5406,9 +5366,9 @@ packages: purls: [] size: 139036 timestamp: 1760385590993 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda - sha256: cc9aba923eea0af8e30e0f94f2ad7156e2984d80d1e8e7fe6be5a1f257f0eb32 - md5: 8397539e3a0bbd1695584fb4f927485a +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda + sha256: 10056646c28115b174de81a44e23e3a0a3b95b5347d2e6c45cc6d49d35294256 + md5: 6178c6f2fb254558238ef4e6c56fb782 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -5416,23 +5376,22 @@ packages: - jpeg <0.0.0a license: IJG AND BSD-3-Clause AND Zlib purls: [] - size: 633710 - timestamp: 1762094827865 -- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda - build_number: 6 - sha256: 371f517eb7010b21c6cc882c7606daccebb943307cb9a3bf2c70456a5c024f7d - md5: 881d801569b201c2e753f03c84b85e15 + size: 633831 + timestamp: 1775962768273 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-7_h47877c9_openblas.conda + build_number: 7 + sha256: 96962084921f197c9ad13fb7f8b324f2351d50ff3d8d962148751ad532f54a01 + md5: 6569b4f273740e25dc0dc7e3232c2a6c depends: - - libblas 3.11.0 6_h4a7cf45_openblas + - libblas 3.11.0 7_h4a7cf45_openblas constrains: - - blas 2.306 openblas - - liblapacke 3.11.0 6*_openblas - - libcblas 3.11.0 6*_openblas + - liblapacke 3.11.0 7*_openblas + - libcblas 3.11.0 7*_openblas + - blas 2.307 openblas license: BSD-3-Clause - license_family: BSD purls: [] - size: 18624 - timestamp: 1774503065378 + size: 18694 + timestamp: 1778489869038 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblief-0.17.6-hecca717_0.conda sha256: 7508b34b3748704978e2ef3527e042ff173775527d22b4fa1f6d611210a6841e md5: 787cf305cdb5aa4797b845062458742a @@ -5446,25 +5405,9 @@ packages: purls: [] size: 2193217 timestamp: 1773833605974 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.8-hf7376ad_1.conda - sha256: bd2981488f63afbc234f6c7759f8363c63faf38dd0f4e64f48ef5a06541c12b4 - md5: eafa8fd1dfc9a107fe62f7f12cabbc9c - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - libstdcxx >=14 - - libxml2 - - libxml2-16 >=2.14.5 - - libzlib >=1.3.1,<2.0a0 - - zstd >=1.5.7,<1.6.0a0 - license: Apache-2.0 WITH LLVM-exception - license_family: Apache - purls: [] - size: 43977914 - timestamp: 1757353652788 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.2-hf7376ad_0.conda - sha256: eda0013a9979d142f520747e3621749c493f5fbc8f9d13a52ac7a2b699338e7c - md5: 7147b0792a803cd5b9929ce5d48f7818 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.5-hf7376ad_1.conda + sha256: 094198dc5c7fbd85e3719d192d5b77c3f0dccf657dfd9ba0c79e391f11f7ace2 + md5: 6adc0202fa7fcf0a5fce8c31ef2ed866 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -5476,108 +5419,109 @@ packages: license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 44217146 - timestamp: 1774480335347 -- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda - sha256: 755c55ebab181d678c12e49cced893598f2bab22d582fbbf4d8b83c18be207eb - md5: c7c83eecbb72d88b940c249af56c8b17 + size: 44241856 + timestamp: 1778417624650 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + sha256: ec30e52a3c1bf7d0425380a189d209a52baa03f22fb66dd3eb587acaa765bd6d + md5: b88d90cad08e6bc8ad540cb310a761fb depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 constrains: - - xz 5.8.2.* + - xz 5.8.3.* license: 0BSD purls: [] - size: 113207 - timestamp: 1768752626120 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda - sha256: ca2d384f30e1582b7c6ae9f1406fb51f993e44c92799e3cabf2130f69c7261d5 - md5: a24532d0660b8a58ca2955301281f71e + size: 113478 + timestamp: 1775825492909 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.6.0-hd28c85e_0.conda + sha256: 554aca39e3e6999259e692c67bd86fa6d600430ce397136f5450369c5cf1723d + md5: 09ee8a6272898ad6616b2f9635359087 depends: - cpp-expected >=1.3.1,<1.3.2.0a0 - __glibc >=2.17,<3.0.a0 - libstdcxx >=14 - libgcc >=14 - - zstd >=1.5.7,<1.6.0a0 + - libsolv >=0.7.37,<0.8.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - simdjson >=4.6.3,<4.7.0a0 + - openssl >=3.5.6,<4.0a0 - reproc >=14.2,<15.0a0 - - spdlog >=1.17.0,<1.18.0a0 - - libarchive >=3.8.5,<3.9.0a0 - - openssl >=3.5.4,<4.0a0 + - reproc-cpp >=14.2,<15.0a0 - nlohmann_json-abi ==3.12.0 + - spdlog >=1.17.0,<1.18.0a0 + - libarchive >=3.8.7,<3.9.0a0 + - libmsgpack-c >=6.1.0,<7.0a0 - fmt >=12.1.0,<12.2.0a0 - - simdjson >=4.2.4,<4.3.0a0 - - libsolv >=0.7.35,<0.8.0a0 - - reproc-cpp >=14.2,<15.0a0 - - libcurl >=8.18.0,<9.0a0 - - yaml-cpp >=0.8.0,<0.9.0a0 + - libcurl >=8.20.0,<9.0a0 + - zstd >=1.5.7,<1.6.0a0 license: BSD-3-Clause license_family: BSD purls: [] - size: 2567543 - timestamp: 1767884157869 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda - sha256: 75deca8004690aed0985845f734927e48aa49a683ee09b3d9ff4e22ace9e4a8e - md5: c866cdca3b16b5c7a0fd9916d5d64577 + size: 2796472 + timestamp: 1777466067862 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.6.0-hf859cbd_0.conda + sha256: cc9395f4bc67871d5dfe60f6c521c97c50cb3ad3d5af7459893e822864956d2a + md5: d4f1f94f6ddb5c494f09f8a7b200aacc depends: - libstdcxx >=14 - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - libmamba >=2.5.0,<2.6.0a0 + - libmamba >=2.6.0,<2.7.0a0 license: BSD-3-Clause license_family: BSD purls: [] - size: 20396 - timestamp: 1767884157870 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py311hc5d5c7c_0.conda - sha256: ebd16f6685bdc2f0cf595f0f441b638b378a43e76e2124763c35d548df09084b - md5: f72a2daebdd84c968828602bfa081ae5 + size: 20290 + timestamp: 1777466067862 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.6.0-py311he982024_0.conda + sha256: faf6d1785deac06351e9dc4a98744d25314a4cd3b614e934fc0a96564db565da + md5: 3dc8d10fd186675277fbf564b9589e00 depends: - python - - libmamba ==2.5.0 hd28c85e_0 - - libmamba-spdlog ==2.5.0 h12fcf84_0 - - __glibc >=2.17,<3.0.a0 + - libmamba ==2.6.0 hd28c85e_0 + - libmamba-spdlog ==2.6.0 hf859cbd_0 - libstdcxx >=14 - libgcc >=14 - - zstd >=1.5.7,<1.6.0a0 + - __glibc >=2.17,<3.0.a0 + - nlohmann_json-abi ==3.12.0 - fmt >=12.1.0,<12.2.0a0 - - python_abi 3.11.* *_cp311 - - openssl >=3.5.4,<4.0a0 - yaml-cpp >=0.8.0,<0.9.0a0 - - spdlog >=1.17.0,<1.18.0a0 - - nlohmann_json-abi ==3.12.0 + - libmamba >=2.6.0,<2.7.0a0 - pybind11-abi ==11 - - libmamba >=2.5.0,<2.6.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - openssl >=3.5.6,<4.0a0 + - python_abi 3.11.* *_cp311 + - zstd >=1.5.7,<1.6.0a0 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/libmambapy?source=hash-mapping - size: 944797 - timestamp: 1767884157872 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py312h1ca65c7_0.conda - sha256: 6dbcc988eb061add6fa16fc3145259fcae54b98d1361ae28a216324bba12ca15 - md5: 56537f56fd84dc81106fed56a705022c + size: 963295 + timestamp: 1777466067862 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.6.0-py312h5ee1301_0.conda + sha256: b355b08441e34026e73fb9fae90a295e906ffa47d327332f9fa81ec57617c3fe + md5: 23270bf128896a4375dd4d9abe0d33d3 depends: - python - - libmamba ==2.5.0 hd28c85e_0 - - libmamba-spdlog ==2.5.0 h12fcf84_0 + - libmamba ==2.6.0 hd28c85e_0 + - libmamba-spdlog ==2.6.0 hf859cbd_0 - libstdcxx >=14 - libgcc >=14 - __glibc >=2.17,<3.0.a0 + - python_abi 3.12.* *_cp312 - pybind11-abi ==11 - - openssl >=3.5.4,<4.0a0 - - spdlog >=1.17.0,<1.18.0a0 - zstd >=1.5.7,<1.6.0a0 - - python_abi 3.12.* *_cp312 - - nlohmann_json-abi ==3.12.0 - - yaml-cpp >=0.8.0,<0.9.0a0 - - libmamba >=2.5.0,<2.6.0a0 - fmt >=12.1.0,<12.2.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - nlohmann_json-abi ==3.12.0 + - spdlog >=1.17.0,<1.18.0a0 + - openssl >=3.5.6,<4.0a0 + - libmamba >=2.6.0,<2.7.0a0 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/libmambapy?source=hash-mapping - size: 947154 - timestamp: 1767884157873 + size: 966414 + timestamp: 1777466067862 - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.2-hc2fc477_0.conda sha256: 6b21e0f3d1577bbe10f27003212f0b8c9a881d99faa01a83476311730aed5c9d md5: a02cb80c806b7b768e1d60170f63375d @@ -5590,9 +5534,22 @@ packages: purls: [] size: 286166 timestamp: 1752566614604 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_103.conda - sha256: 657a4eaf5b9dfb3e8ef76bb4c5a682951ae8dcc9d35cd73c4ff62c144b356d13 - md5: 737fd40c9bfa4076d007f6ff7fa405e3 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmsgpack-c-6.1.0-h54a6638_6.conda + sha256: 79a75422873cb4107fb731d3794402eda063fcc9a809f4bb0b5738a6b3d46dee + md5: fde05e07c2a9c96ad09216f0d5fda9a1 + depends: + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + constrains: + - msgpack-c ==6.1.0 *_6 + license: BSL-1.0 + purls: [] + size: 40340 + timestamp: 1770807484162 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.10.0-nompi_hb6f1874_104.conda + sha256: 7deab19f51934a5bfdf8eec10721d91a02c6a27632471527b07ece8f0d2c7a8e + md5: e9e60f617e5545e1a7de60c2d01f8029 depends: - __glibc >=2.17,<3.0.a0 - blosc >=1.21.6,<2.0a0 @@ -5607,13 +5564,13 @@ packages: - libxml2-16 >=2.14.6 - libzip >=1.11.2,<2.0a0 - libzlib >=1.3.2,<2.0a0 - - openssl >=3.5.5,<4.0a0 + - openssl >=3.5.6,<4.0a0 - zstd >=1.5.7,<1.6.0a0 license: MIT license_family: MIT purls: [] - size: 861141 - timestamp: 1774633364108 + size: 862900 + timestamp: 1776686244733 - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda sha256: 663444d77a42f2265f54fb8b48c5450bfff4388d9c0f8253dd7855f0d993153f md5: 2a45e7f8af083626f009645a6481f12d @@ -5663,21 +5620,21 @@ packages: purls: [] size: 218500 timestamp: 1745825989535 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda - sha256: 6dc30b28f32737a1c52dada10c8f3a41bc9e021854215efca04a7f00487d09d9 - md5: 89d61bc91d3f39fda0ca10fcd3c68594 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda + sha256: 3d9aa85648e5e18a6d66db98b8c4317cc426721ad7a220aa86330d1ccedc8903 + md5: 2d3278b721e40468295ca755c3b84070 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - libgfortran - libgfortran5 >=14.3.0 constrains: - - openblas >=0.3.32,<0.3.33.0a0 + - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD purls: [] - size: 5928890 - timestamp: 1774471724897 + size: 5931919 + timestamp: 1776993658641 - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda sha256: 215086c108d80349e96051ad14131b751d17af3ed2cb5a34edd62fa89bfe8ead md5: 7df50d44d4a14d6c31a2c54f2cd92157 @@ -5710,17 +5667,17 @@ packages: purls: [] size: 28424 timestamp: 1749901812541 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.56-h421ea60_0.conda - sha256: 4f9fca3bc21e485ec0b3eb88db108b6cf9ab9a481cdf7d2ac6f9d30350b45ead - md5: 97169784f0775c85683c3d8badcea2c3 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda + sha256: 377cfe037f3eeb3b1bf3ad333f724a64d32f315ee1958581fc671891d63d3f89 + md5: eba48a68a1a2b9d3c0d9511548db85db depends: - - libgcc >=14 - __glibc >=2.17,<3.0.a0 + - libgcc >=14 - libzlib >=1.3.2,<2.0a0 license: zlib-acknowledgement purls: [] - size: 317540 - timestamp: 1774513272700 + size: 317729 + timestamp: 1776315175087 - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.3-h9abb657_0.conda sha256: c7e61b86c273ec1ce92c0e087d1a0f3ed3b9485507c6cd35e03bc63de1b6b03f md5: 405ec206d230d9d37ad7c2636114cbf4 @@ -5817,31 +5774,30 @@ packages: purls: [] size: 277661 timestamp: 1772479381288 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.36-h9463b59_0.conda - sha256: 2a336d83e25e67b69548ee233188fa612cbce6809b3e2d45dd0b6520d75b3870 - md5: e6e2535fc6b69b08cdbaeab01aa1c277 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.37-h9463b59_0.conda + sha256: 40bf68965389a011a6522fe3fed3e5b798fa9e880f7b840e0e6cb96343c2b511 + md5: 994f869ff76bfefdfc3b3877bffe27c9 depends: - libstdcxx >=14 - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - libzlib >=1.3.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 license: BSD-3-Clause license_family: BSD purls: [] - size: 519098 - timestamp: 1773328331358 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda - sha256: d716847b7deca293d2e49ed1c8ab9e4b9e04b9d780aea49a97c26925b28a7993 - md5: fd893f6a3002a635b5e50ceb9dd2c0f4 + size: 519303 + timestamp: 1776950236789 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda + sha256: 54cdcd3214313b62c2a8ee277e6f42150d9b748264c1b70d958bf735e420ef8d + md5: 7dc38adcbf71e6b38748e919e16e0dce depends: - __glibc >=2.17,<3.0.a0 - - icu >=78.2,<79.0a0 - libgcc >=14 - - libzlib >=1.3.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 license: blessing purls: [] - size: 951405 - timestamp: 1772818874251 + size: 954962 + timestamp: 1777986471789 - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda sha256: fa39bfd69228a13e553bd24601332b7cfeb30ca11a3ca50bb028108fe90a7661 md5: eecce068c7e4eddeb169591baac20ac4 @@ -5855,29 +5811,29 @@ packages: purls: [] size: 304790 timestamp: 1745608545575 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - sha256: 78668020064fdaa27e9ab65cd2997e2c837b564ab26ce3bf0e58a2ce1a525c6e - md5: 1b08cd684f34175e4514474793d44bcb +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + sha256: dff1058c76ec6b8759e41cefa2508162d00e4a5e6721aa68ec3fd10094e702dc + md5: 5794b3bdc38177caf969dabd3af08549 depends: - __glibc >=2.17,<3.0.a0 - - libgcc 15.2.0 he0feb66_18 + - libgcc 15.2.0 he0feb66_19 constrains: - - libstdcxx-ng ==15.2.0=*_18 + - libstdcxx-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 5852330 - timestamp: 1771378262446 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - sha256: 3c902ffd673cb3c6ddde624cdb80f870b6c835f8bf28384b0016e7d444dd0145 - md5: 6235adb93d064ecdf3d44faee6f468de + size: 5852044 + timestamp: 1778269036376 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda + sha256: 0672b6b6e1791c92e8eccad58081a99d614fcf82bca5841f9dfa3c3e658f83b9 + md5: e5ce228e579726c07255dbf90dc62101 depends: - - libstdcxx 15.2.0 h934c35e_18 + - libstdcxx 15.2.0 h934c35e_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 27575 - timestamp: 1771378314494 + size: 27776 + timestamp: 1778269074600 - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-hd0affe5_0.conda sha256: c5008b602cb5c819f7b52d418b3ed17e1818cbbf6705b189e7ab36bb70cce3d8 md5: 8ee3cb7f64be0e8c4787f3a4dbe024e6 @@ -5940,17 +5896,17 @@ packages: purls: [] size: 1433436 timestamp: 1626955018689 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda - sha256: 1a7539cfa7df00714e8943e18de0b06cceef6778e420a5ee3a2a145773758aee - md5: db409b7c1720428638e7c0d509d3e1b5 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda + sha256: bc1b08c92626c91500fd9f26f2c797f3eb153b627d53e9c13cd167f1e12b2829 + md5: 38ffe67b78c9d4de527be8315e5ada2c depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: BSD-3-Clause license_family: BSD purls: [] - size: 40311 - timestamp: 1766271528534 + size: 40297 + timestamp: 1775052476770 - conda: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda sha256: ca494c99c7e5ecc1b4cd2f72b5584cef3d4ce631d23511184411abcbb90a21a5 md5: b4ecbefe517ed0157c37f8182768271c @@ -6052,39 +6008,39 @@ packages: purls: [] size: 837922 timestamp: 1764794163823 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_0.conda - sha256: 275c324f87bda1a3b67d2f4fcc3555eeff9e228a37655aa001284a7ceb6b0392 - md5: e49238a1609f9a4a844b09d9926f2c3d +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_0.conda + sha256: 3bc5551720c58591f6ea1146f7d1539c734ed1c40e7b9f5cb8cb7e900c509aba + md5: 995d8c8bad2a3cc8db14675a153dec2b depends: - __glibc >=2.17,<3.0.a0 - - icu >=78.2,<79.0a0 + - icu >=78.3,<79.0a0 - libgcc >=14 - libiconv >=1.18,<2.0a0 - - liblzma >=5.8.2,<6.0a0 - - libxml2-16 2.15.2 hca6bf5a_0 - - libzlib >=1.3.1,<2.0a0 + - liblzma >=5.8.3,<6.0a0 + - libxml2-16 2.15.3 hca6bf5a_0 + - libzlib >=1.3.2,<2.0a0 license: MIT license_family: MIT purls: [] - size: 45968 - timestamp: 1772704614539 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda - sha256: 08d2b34b49bec9613784f868209bb7c3bb8840d6cf835ff692e036b09745188c - md5: f3bc152cb4f86babe30f3a4bf0dbef69 + size: 46810 + timestamp: 1776376751152 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.3-hca6bf5a_0.conda + sha256: 3d44f737c5ae52d5af32682cc1530df433f401f8e58a7533926536244127572a + md5: e79d2c2f24b027aa8d5ab1b1ba3061e7 depends: - __glibc >=2.17,<3.0.a0 - - icu >=78.2,<79.0a0 + - icu >=78.3,<79.0a0 - libgcc >=14 - libiconv >=1.18,<2.0a0 - - liblzma >=5.8.2,<6.0a0 - - libzlib >=1.3.1,<2.0a0 + - liblzma >=5.8.3,<6.0a0 + - libzlib >=1.3.2,<2.0a0 constrains: - - libxml2 2.15.2 + - libxml2 2.15.3 license: MIT license_family: MIT purls: [] - size: 557492 - timestamp: 1772704601644 + size: 559775 + timestamp: 1776376739004 - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.43-h711ed8c_1.conda sha256: 0694760a3e62bdc659d90a14ae9c6e132b525a7900e59785b18a08bb52a5d7e5 md5: 87e6096ec6d542d1c1f8b33245fe8300 @@ -6192,9 +6148,9 @@ packages: purls: [] size: 191060 timestamp: 1753889274283 -- conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantid-6.15.0.2rc4-np21py312h62f99c1_0.conda - sha256: a4947c0a4756dfa9e10aca44a6dae52a4f99232c8c3219d59eab63fe503326f0 - md5: 7a16750aebb4f1f8dab75eb98ff1265a +- conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantid-6.15.0.4rc1-np21py312h68643e6_0.conda + sha256: 205033cafec9d0469fcbf01275a11001218c93d35377bd2f171de20652c53a3a + md5: b2877131facda63b9e9086e52cab861c depends: - gsl >=2.8,<2.9.0a0 - hdf4 >=4.2.15,<4.3.0a0 @@ -6223,33 +6179,33 @@ packages: - libstdcxx >=13 - libgcc >=13 - __glibc >=2.17,<3.0.a0 - - libboost >=1.88.0,<1.89.0a0 - - libzlib >=1.3.2,<2.0a0 + - libglu >=9.0.3,<9.1.0a0 + - xorg-libx11 >=1.8.13,<2.0a0 + - tbb >=2021.13.0 + - librdkafka >=2.13.2,<2.14.0a0 - muparser >=2.3.4,<2.4.0a0 - hdf4 >=4.2.15,<4.2.16.0a0 - - libgl >=1.7.0,<2.0a0 - - libopenblas >=0.3.27,<1.0a0 - occt >=7.9.3,<7.9.4.0a0 - - numpy >=1.21,<3 - jsoncpp >=1.9.6,<1.9.7.0a0 - - poco >=1.15.1,<1.15.2.0a0 - - librdkafka >=2.13.2,<2.14.0a0 - - libboost-python >=1.88.0,<1.89.0a0 - - gsl >=2.8,<2.9.0a0 - - tbb >=2021.13.0 + - libzlib >=1.3.2,<2.0a0 + - libboost >=1.88.0,<1.89.0a0 - gtest >=1.17.0,<1.17.1.0a0 - - xorg-libx11 >=1.8.13,<2.0a0 - - xorg-libxxf86vm >=1.1.7,<2.0a0 + - poco >=1.15.2,<1.15.3.0a0 - python_abi 3.12.* *_cp312 + - gsl >=2.8,<2.9.0a0 + - libgl >=1.7.0,<2.0a0 - hdf5 >=1.14.6,<1.14.7.0a0 - - libglu >=9.0.3,<9.1.0a0 + - xorg-libxxf86vm >=1.1.7,<2.0a0 + - libopenblas >=0.3.27,<1.0a0 + - numpy >=1.21,<3 + - libboost-python >=1.88.0,<1.89.0a0 constrains: - - matplotlib-base 3.9.* + - matplotlib-base 3.10.* - pyparsing <3.3.0 - - pystog >=0.5.0 + - pystog >=0.6.3 license: GPL-3.0-or-later - size: 39393439 - timestamp: 1774620141154 + size: 37931812 + timestamp: 1776697073871 - conda: https://conda.anaconda.org/mantid/label/main/linux-64/mantid-6.15.0-np21py311h131b964_0.conda sha256: 5f4c0be8882e335acbeece1276935360af90354868ff89da7f2ac3dc19a2411e md5: da573e5a88e2d6d9869d298ebf9c1137 @@ -6311,9 +6267,9 @@ packages: license: GPL-3.0-or-later size: 39771829 timestamp: 1771534620695 -- conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantid-6.15.20260331.2253-np21py312h62f99c1_0.conda - sha256: a550059b89d56687742fa0a586fe24fc4a942d060898a82a573a5772c06805ca - md5: 31614e9b3f99fc527394c390707b36d7 +- conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantid-6.15.20260501.2109-np21py312h68643e6_0.conda + sha256: 3c50bcb5f650fd23f4a437bccd7a65fb828518444f50771e1bab3e1afa4e4fcc + md5: 2e4ea4b962302c98f96cf0bb937f6c5d depends: - gsl >=2.8,<2.9.0a0 - hdf4 >=4.2.15,<4.3.0a0 @@ -6337,70 +6293,67 @@ packages: - libboost >=1.88.0,<1.89.0a0 - libboost-python >=1.88.0,<1.89.0a0 - libglu >=9.0 - - __glibc >=2.17,<3.0.a0 - libgcc >=13 - _openmp_mutex >=4.5 - libstdcxx >=13 - libgcc >=13 - - libopenblas >=0.3.27,<1.0a0 + - __glibc >=2.17,<3.0.a0 - gsl >=2.8,<2.9.0a0 - - numpy >=1.21,<3 - - jsoncpp >=1.9.6,<1.9.7.0a0 - - muparser >=2.3.4,<2.4.0a0 - - hdf5 >=1.14.6,<1.14.7.0a0 - - tbb >=2021.13.0 - - python_abi 3.12.* *_cp312 - - libzlib >=1.3.2,<2.0a0 - - libgl >=1.7.0,<2.0a0 - - xorg-libx11 >=1.8.13,<2.0a0 - - gtest >=1.17.0,<1.17.1.0a0 - librdkafka >=2.13.2,<2.14.0a0 - - poco >=1.15.1,<1.15.2.0a0 - - libboost >=1.88.0,<1.89.0a0 + - poco >=1.15.2,<1.15.3.0a0 - libglu >=9.0.3,<9.1.0a0 - - xorg-libxxf86vm >=1.1.7,<2.0a0 + - libboost >=1.88.0,<1.89.0a0 - libboost-python >=1.88.0,<1.89.0a0 - - occt >=7.9.3,<7.9.4.0a0 + - libzlib >=1.3.2,<2.0a0 - hdf4 >=4.2.15,<4.2.16.0a0 - constrains: - - matplotlib-base 3.9.* - - pyparsing <3.3.0 - - pystog >=0.5.0 + - xorg-libx11 >=1.8.13,<2.0a0 + - occt >=7.9.3,<7.9.4.0a0 + - muparser >=2.3.4,<2.4.0a0 + - tbb >=2021.13.0 + - jsoncpp >=1.9.6,<1.9.7.0a0 + - libgl >=1.7.0,<2.0a0 + - gtest >=1.17.0,<1.17.1.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - python_abi 3.12.* *_cp312 + - xorg-libxxf86vm >=1.1.7,<2.0a0 + - numpy >=1.21,<3 + - libopenblas >=0.3.27,<1.0a0 + constrains: + - matplotlib-base 3.10.* + - pyparsing <3.3.0 + - pystog >=0.6.3 license: GPL-3.0-or-later - size: 39408032 - timestamp: 1775002946655 -- conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantidqt-6.15.0.2rc4-py312he48a509_0.conda - sha256: 5cfdfe9ce8277d0484282487e542e6af8ed744d207bd6d4176098071e06c1402 - md5: 9aba3983cd075e50b33c483728f35e3c - depends: - - mantid ==6.15.0.2rc4 - - matplotlib 3.9.* + size: 38030814 + timestamp: 1777681352759 +- conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantidqt-6.15.0.4rc1-py312he137b73_0.conda + sha256: 7ebc406fd1b2e6a3845eea91a2400b57380c395bc1ec7b191ad0b8b555088a8d + md5: 2a19a9b736a484055eed692fe1492379 + depends: + - mantid ==6.15.0.4rc1 + - matplotlib 3.10.* - qscintilla2 >=2.14.1,<2.15.0a0 - qt-main >=5.15.15,<5.16.0a0 - qtpy >=2.4,!=2.4.2 - python - qt-gtk-platformtheme - __glibc >=2.17,<3.0.a0 - - libstdcxx >=13 - - libgcc >=13 - _openmp_mutex >=4.5 + - libstdcxx >=13 - libgcc >=13 + - libgl >=1.7.0,<2.0a0 + - python_abi 3.12.* *_cp312 - xorg-libx11 >=1.8.13,<2.0a0 - - pyqtwebengine >=5.15.9,<5.16.0a0 - - pyqt >=5.15.9,<5.16.0a0 + - qt-main >=5.15.15,<5.16.0a0 - libboost >=1.88.0,<1.89.0a0 - - libboost-python >=1.88.0,<1.89.0a0 - - qt-webengine >=5.15.15,<5.16.0a0 - libopenblas >=0.3.27,<1.0a0 - - python_abi 3.12.* *_cp312 - - tbb >=2021.13.0 - - qt-main >=5.15.15,<5.16.0a0 - xorg-libxxf86vm >=1.1.7,<2.0a0 - - mantid ==6.15.0.2rc4 np21py312h62f99c1_0 - - libgl >=1.7.0,<2.0a0 + - libboost-python >=1.88.0,<1.89.0a0 + - tbb >=2021.13.0 + - pyqt >=5.15.9,<5.16.0a0 + - mantid ==6.15.0.4rc1 np21py312h68643e6_0 license: GPL-3.0-or-later - size: 10366781 - timestamp: 1774620663514 + size: 10370437 + timestamp: 1776697540907 - conda: https://conda.anaconda.org/mantid/label/main/linux-64/mantidqt-6.15.0-py311he66f075_0.conda sha256: 79fe73916925a41c0585ec95751ed71037e0b43ab21024e4fabda2e83cc341ae md5: 111da43f2835d1c1264bda9a05cc422c @@ -6433,44 +6386,45 @@ packages: license: GPL-3.0-or-later size: 10151421 timestamp: 1771535073359 -- conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidqt-6.15.20260331.2253-py312he48a509_0.conda - sha256: 09e5ebcdb2e1659c0dc5890d42e3f40bd0630eb53c800c3f603bed97cebd8a43 - md5: 4d1a43942f357594722938c1712e4164 +- conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidqt-6.15.20260501.2109-py312he137b73_0.conda + sha256: fb561c583147f66c2adb4f79a6c109980c70b37007c05393e9f21283f4846e1f + md5: d28668c11e63da1490b356c2496d33e9 depends: - - mantid ==6.15.20260331.2253 - - matplotlib 3.9.* + - mantid ==6.15.20260501.2109 + - matplotlib 3.10.* - qscintilla2 >=2.14.1,<2.15.0a0 - qt-main >=5.15.15,<5.16.0a0 - qtpy >=2.4,!=2.4.2 - python - qt-gtk-platformtheme + - libgcc >=13 - _openmp_mutex >=4.5 + - __glibc >=2.17,<3.0.a0 - libstdcxx >=13 - libgcc >=13 - - __glibc >=2.17,<3.0.a0 - - tbb >=2021.13.0 - - libopenblas >=0.3.27,<1.0a0 - - qt-main >=5.15.15,<5.16.0a0 - libboost-python >=1.88.0,<1.89.0a0 - - python_abi 3.12.* *_cp312 - - mantid ==6.15.20260331.2253 np21py312h62f99c1_0 + - qt-main >=5.15.15,<5.16.0a0 + - libopenblas >=0.3.27,<1.0a0 + - tbb >=2021.13.0 + - pyqt >=5.15.9,<5.16.0a0 - libboost >=1.88.0,<1.89.0a0 - - libgl >=1.7.0,<2.0a0 - xorg-libx11 >=1.8.13,<2.0a0 - - pyqt >=5.15.9,<5.16.0a0 + - python_abi 3.12.* *_cp312 - xorg-libxxf86vm >=1.1.7,<2.0a0 + - libgl >=1.7.0,<2.0a0 + - mantid ==6.15.20260501.2109 np21py312h68643e6_0 license: GPL-3.0-or-later - size: 10434757 - timestamp: 1775003408710 -- conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantidworkbench-6.15.0.2rc4-py312hea17ed9_0.conda - sha256: cf03107605ae4fb8a2913feb32acbd715c64373b081b5149b94fea21b9cd0eb7 - md5: 5355fff9d62151163b7860de27d02a74 + size: 10476161 + timestamp: 1777681823143 +- conda: https://conda.anaconda.org/mantid-ornl/label/rc/linux-64/mantidworkbench-6.15.0.4rc1-py312h0a96521_0.conda + sha256: 17df9244f9da2e86234af69536e24b818f53f3792c1c9162cd7c82a62f5c2d3f + md5: e5922f20c2e96e07e00aceace4e8a82c depends: - ipykernel - - mantidqt ==6.15.0.2rc4 + - mantidqt ==6.15.0.4rc1 - psutil >=5.8.0 - python >=3.12.13,<3.13.0a0 - - matplotlib 3.9.* + - matplotlib 3.10.* - pyvista >=0.46 - pyvistaqt - superqt @@ -6478,18 +6432,18 @@ packages: - setuptools >=82.0.1,<82.1.0a0 - pystack - lz4 - - python_abi 3.12.* *_cp312 - xorg-libx11 >=1.8.13,<2.0a0 - - tbb >=2021.13.0 - - libgl >=1.7.0,<2.0a0 - - mantidqt ==6.15.0.2rc4 py312he48a509_0 + - python_abi 3.12.* *_cp312 - xorg-libxxf86vm >=1.1.7,<2.0a0 + - libgl >=1.7.0,<2.0a0 + - mantidqt ==6.15.0.4rc1 py312he137b73_0 + - tbb >=2021.13.0 constrains: - - mslice 2.14.* - - mantiddocs ==6.15.0.2rc4 + - mslice >=2.14 + - mantiddocs ==6.15.0.4rc1 license: GPL-3.0-or-later - size: 2802612 - timestamp: 1774626903114 + size: 2801826 + timestamp: 1776704786369 - conda: https://conda.anaconda.org/mantid/label/main/linux-64/mantidworkbench-6.15.0-py311h3ec3e80_0.conda sha256: dd25484b2a69713abd6945d38a42990967d7c900f09774e45d2e2fc3e4d530ed md5: 65c5fccbd99e0dd71c2252c539b635fc @@ -6517,15 +6471,15 @@ packages: license: GPL-3.0-or-later size: 2818970 timestamp: 1771553287757 -- conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidworkbench-6.15.20260331.2253-py312hc9b079f_0.conda - sha256: 2541ca57bc7071c9d176b196b005cd9bc520de372c29a0127b4b92af25644fb7 - md5: ed08da3a52cb07570c98273ef54e13c6 +- conda: https://conda.anaconda.org/mantid/label/nightly/linux-64/mantidworkbench-6.15.20260501.2109-py312h0a96521_0.conda + sha256: 4b324e686075dae029595f7e2bb5d3d212e517388e3896175c4d6645a44cadff + md5: 85b5e597f93583c4f56d4194a1ecf338 depends: - ipykernel - - mantidqt ==6.15.20260331.2253 + - mantidqt ==6.15.20260501.2109 - psutil >=5.8.0 - python >=3.12.13,<3.13.0a0 - - matplotlib 3.9.* + - matplotlib 3.10.* - pyvista >=0.46 - pyvistaqt - superqt @@ -6533,21 +6487,21 @@ packages: - setuptools >=82.0.1,<82.1.0a0 - pystack - lz4 - - python_abi 3.12.* *_cp312 - - tbb >=2021.13.0 - - xorg-libx11 >=1.8.13,<2.0a0 - libgl >=1.7.0,<2.0a0 - - mantidqt ==6.15.20260331.2253 py312he48a509_0 + - xorg-libx11 >=1.8.13,<2.0a0 - xorg-libxxf86vm >=1.1.7,<2.0a0 + - python_abi 3.12.* *_cp312 + - tbb >=2021.13.0 + - mantidqt ==6.15.20260501.2109 py312he137b73_0 constrains: - - mslice 2.15.* - - mantiddocs ==6.15.20260331.2253 + - mslice >=2.14 + - mantiddocs ==6.15.20260501.2109 license: GPL-3.0-or-later - size: 2802074 - timestamp: 1775017974649 -- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda - sha256: 7b1da4b5c40385791dbc3cc85ceea9fad5da680a27d5d3cb8bfaa185e304a89e - md5: 5b5203189eb668f042ac2b0826244964 + size: 2802204 + timestamp: 1777697004184 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + sha256: 0c4c35376fe920714390d46e4b8d31c876d65f18e1655899e0763ec25f2a902f + md5: 6d03368f2b2b0a5fb6839df53b2eb5e0 depends: - mdurl >=0.1,<1 - python >=3.10 @@ -6555,8 +6509,8 @@ packages: license_family: MIT purls: - pkg:pypi/markdown-it-py?source=hash-mapping - size: 64736 - timestamp: 1754951288511 + size: 69017 + timestamp: 1778169663339 - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py311h3778330_1.conda sha256: 710e207b2e91308a34bcfe547c60ad86c1fa294827266ba18548c1fe1a9d8333 md5: f9efdf9b0f3d0cc309d56af6edf2a6b0 @@ -6570,7 +6524,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/markupsafe?source=compressed-mapping + - pkg:pypi/markupsafe?source=hash-mapping size: 26756 timestamp: 1772445078834 - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda @@ -6586,9 +6540,23 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/markupsafe?source=compressed-mapping + - pkg:pypi/markupsafe?source=hash-mapping size: 26057 timestamp: 1772445297924 +- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.9-py312h7900ff3_0.conda + sha256: cdd59bb1a52b09979f11c68909d53120b2e749edd1992853a74e1604db19c8b0 + md5: 579c6a324b197594fabc9240bddf2d8b + depends: + - matplotlib-base >=3.10.9,<3.10.10.0a0 + - pyside6 >=6.7.2 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - tornado >=5 + license: PSF-2.0 + license_family: PSF + purls: [] + size: 17831 + timestamp: 1777000588302 - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.4-py311h38be061_0.conda sha256: 359eb83bbb0c111ad0e3acd1ac23259aad3f7b29af67b2addb89d5be919c1d13 md5: a3ec05065e1d66c691e357ab6c88f50d @@ -6603,52 +6571,39 @@ packages: purls: [] size: 16887 timestamp: 1734120550368 -- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.4-py312h7900ff3_0.conda - sha256: c191931cfad4048c4a31911ea0242679ddb240963df0b85f13a380108033c7f0 - md5: 2b1df96ad1f394cb0d3e67a930ac19c0 - depends: - - matplotlib-base >=3.9.4,<3.9.5.0a0 - - pyside6 >=6.7.2 - - python >=3.12,<3.13.0a0 - - python_abi 3.12.* *_cp312 - - tornado >=5 - license: PSF-2.0 - license_family: PSF - purls: [] - size: 16942 - timestamp: 1734120430188 -- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.4-py311h2b939e6_0.conda - sha256: ba6f0739f9aafb73ffc5ba74f9e3ccf9642665719cca37087f302d593e7c7571 - md5: f84bdd171a75a47bdb991827d2e5fb06 +- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.9-py312he3d6523_0.conda + sha256: c7e133837376e53e6a52719c205a3067c42f05769bc3e8307417f8d817dfc63e + md5: 7d499b5b6d150f133800dc3a582771c7 depends: - __glibc >=2.17,<3.0.a0 - - certifi >=2020.06.20 - contourpy >=1.0.1 - cycler >=0.10 - fonttools >=4.22.0 - - freetype >=2.12.1,<3.0a0 + - freetype - kiwisolver >=1.3.1 - - libgcc >=13 - - libstdcxx >=13 - - numpy >=1.19,<3 + - libfreetype >=2.14.3 + - libfreetype6 >=2.14.3 + - libgcc >=14 + - libstdcxx >=14 - numpy >=1.23 + - numpy >=1.23,<3 - packaging >=20.0 - pillow >=8 - pyparsing >=2.3.1 - - python >=3.11,<3.12.0a0 + - python >=3.12,<3.13.0a0 - python-dateutil >=2.7 - - python_abi 3.11.* *_cp311 + - python_abi 3.12.* *_cp312 - qhull >=2020.2,<2020.3.0a0 - tk >=8.6.13,<8.7.0a0 license: PSF-2.0 license_family: PSF purls: - pkg:pypi/matplotlib?source=hash-mapping - size: 7918459 - timestamp: 1734120522524 -- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.4-py312hd3ec401_0.conda - sha256: aaa7f459f89c9dcd5bb6a8189d35e5d959c898cdb5ea200374fe2172703560cd - md5: b39b563d1a75c7b9b623e2a2b42d9e6d + size: 8336056 + timestamp: 1777000573501 +- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.4-py311h2b939e6_0.conda + sha256: ba6f0739f9aafb73ffc5ba74f9e3ccf9642665719cca37087f302d593e7c7571 + md5: f84bdd171a75a47bdb991827d2e5fb06 depends: - __glibc >=2.17,<3.0.a0 - certifi >=2020.06.20 @@ -6664,29 +6619,29 @@ packages: - packaging >=20.0 - pillow >=8 - pyparsing >=2.3.1 - - python >=3.12,<3.13.0a0 + - python >=3.11,<3.12.0a0 - python-dateutil >=2.7 - - python_abi 3.12.* *_cp312 + - python_abi 3.11.* *_cp311 - qhull >=2020.2,<2020.3.0a0 - tk >=8.6.13,<8.7.0a0 license: PSF-2.0 license_family: PSF purls: - pkg:pypi/matplotlib?source=hash-mapping - size: 7893167 - timestamp: 1734120409482 -- conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda - sha256: 9d690334de0cd1d22c51bc28420663f4277cfa60d34fa5cad1ce284a13f1d603 - md5: 00e120ce3e40bad7bfc78861ce3c4a25 + size: 7918459 + timestamp: 1734120522524 +- conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.2-pyhd8ed1ab_0.conda + sha256: 35b43d7343f74452307fd018a1cca92b8f68961ff8e2ab6a81ce0a703c9a3764 + md5: 9acc1c385be401d533ff70ef5b50dae6 depends: - python >=3.10 - traitlets license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/matplotlib-inline?source=hash-mapping - size: 15175 - timestamp: 1761214578417 + - pkg:pypi/matplotlib-inline?source=compressed-mapping + size: 15725 + timestamp: 1778264403247 - conda: https://conda.anaconda.org/conda-forge/linux-64/mbedtls-3.6.3.1-h5888daf_0.conda sha256: 6736158b195d9163adfcdd97e4e80a7a3c166ed534efa2efa27a4b83359b4b1f md5: dd2974918f8e2534850866eddd42ee3c @@ -6732,33 +6687,31 @@ packages: - pkg:pypi/menuinst?source=hash-mapping size: 181675 timestamp: 1765733217223 -- conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-25.0.5-h57bcd07_2.conda - sha256: b2c88c95088db3dd3048242a48e957cf53ac852047ebaafc3a822bd083ad9858 - md5: 9b6b685b123906eb4ef270b50cbe826c +- conda: https://conda.anaconda.org/conda-forge/linux-64/mesalib-26.0.3-h8cca3c9_0.conda + sha256: 3e6385e04e5a8f62599a5eb72b9a8c65ac143f0621d57f24688f103276d686eb + md5: 823e4ae1d60e97845773f7358585fc56 depends: - __glibc >=2.17,<3.0.a0 - - libdrm >=2.4.125,<2.5.0a0 - - libexpat >=2.7.1,<3.0a0 - libgcc >=14 - - libllvm20 >=20.1.8,<20.2.0a0 - libstdcxx >=14 - - libxcb >=1.17.0,<2.0a0 - - libzlib >=1.3.1,<2.0a0 - - spirv-tools >=2025,<2026.0a0 - - xorg-libx11 >=1.8.12,<2.0a0 - - xorg-libxrandr >=1.5.4,<2.0a0 - xorg-libxshmfence >=1.3.3,<2.0a0 - zstd >=1.5.7,<1.6.0a0 - track_features: - - mesalib + - xorg-libx11 >=1.8.13,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - xorg-libxrandr >=1.5.5,<2.0a0 + - libexpat >=2.7.4,<3.0a0 + - spirv-tools >=2026,<2027.0a0 + - libllvm22 >=22.1.1,<22.2.0a0 + - libxcb >=1.17.0,<2.0a0 + - libdrm >=2.4.125,<2.5.0a0 license: MIT license_family: MIT purls: [] - size: 6350427 - timestamp: 1755729794084 -- conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhcf101f3_1.conda - sha256: 449609f0d250607a300754474350a3b61faf45da183d3071e9720e453c765b8a - md5: 32f78e9d06e8593bc4bbf1338da06f5f + size: 2964576 + timestamp: 1773867966762 +- conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-11.0.2-pyhcf101f3_0.conda + sha256: 74f7b461e0f0e0709a0c8abb018de9ad885258b74790ffda1e750ac5ddde0a85 + md5: b874955758a30a37c78b82ea5cf78fdb depends: - python >=3.10 - python @@ -6766,8 +6719,8 @@ packages: license_family: MIT purls: - pkg:pypi/more-itertools?source=hash-mapping - size: 69210 - timestamp: 1764487059562 + size: 71254 + timestamp: 1775762492525 - conda: https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda sha256: 39c4700fb3fbe403a77d8cc27352fa72ba744db487559d5d44bf8411bb4ea200 md5: c7f302fd11eeb0987a6a5e1f3aed6a21 @@ -6860,44 +6813,44 @@ packages: purls: [] size: 216720 timestamp: 1668542554576 -- conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.19.1-py311h49ec1c0_0.conda - sha256: fcabeb938ff98570856e7904494fb1bf478125e35570d1517bb9abe54bea1e1e - md5: 30b022a5f4a6a48c384257e8141960b8 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.20.2-py311h49ec1c0_0.conda + sha256: 2e3d545aeccb15779b648ada9315cf13cd13d8fd8cc7230a392936f12a19902d + md5: 3969d0b9e13b629f1ce6846ac2bf896b depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - mypy_extensions >=1.0.0 - - pathspec >=0.9.0 + - pathspec >=1.0.0 - psutil >=4.0 - python >=3.11,<3.12.0a0 - - python-librt >=0.6.2 + - python-librt >=0.8.0 - python_abi 3.11.* *_cp311 - typing_extensions >=4.6.0 license: MIT license_family: MIT purls: - pkg:pypi/mypy?source=hash-mapping - size: 19960163 - timestamp: 1765795816180 -- conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.19.1-py312h4c3975b_0.conda - sha256: d0e0765e5ec08141b10da9e03ef620d2e3e571d81cc2bc14025c52a48bb01856 - md5: c3ad8cc29400fe5ca1b6a6e5ae46538e + size: 21759130 + timestamp: 1776802253855 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.20.2-py312h4c3975b_0.conda + sha256: 2c03499b0f267a29321ce198a86285449eca2bb685e883703ef564a2ce641802 + md5: e3174d3f01d539ffd867a85639a8d9b5 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - mypy_extensions >=1.0.0 - - pathspec >=0.9.0 + - pathspec >=1.0.0 - psutil >=4.0 - python >=3.12,<3.13.0a0 - - python-librt >=0.6.2 + - python-librt >=0.8.0 - python_abi 3.12.* *_cp312 - typing_extensions >=4.6.0 license: MIT license_family: MIT purls: - pkg:pypi/mypy?source=hash-mapping - size: 20301935 - timestamp: 1765795520217 + size: 22035539 + timestamp: 1776802000447 - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda sha256: 6ed158e4e5dd8f6a10ad9e525631e35cee8557718f83de7a4e3966b1f772c4b1 md5: e9c622e0d00fa24a6292279af3ab6d06 @@ -6924,16 +6877,16 @@ packages: - pkg:pypi/nbformat?source=hash-mapping size: 100945 timestamp: 1733402844974 -- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586 - md5: 47e340acb35de30501a76c7c799c41d7 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + sha256: fc89f74bbe362fb29fa3c037697a89bec140b346a2469a90f7936d1d7ea4d8a3 + md5: fc21868a1a5aacc937e7a18747acb8a5 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 + - libgcc >=14 license: X11 AND BSD-3-Clause purls: [] - size: 891641 - timestamp: 1738195959188 + size: 918956 + timestamp: 1777422145199 - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda sha256: bb7b21d7fd0445ddc0631f64e66d91a179de4ba920b8381f29b9d006a42788c0 md5: 598fd7d4d0de2455fb74f56063969a97 @@ -6971,10 +6924,10 @@ packages: - pkg:pypi/nexusformat?source=hash-mapping size: 69038 timestamp: 1743367584974 -- conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.4-py310h6de7dc8_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.3.5-py310hd8a072f_1.conda noarch: python - sha256: 772ec92277b60a19ccebdd2c8ea8875086a8fe7742e1b3db233c5a6b04367fa0 - md5: 8f94b4cd2c1a0ad78d34c076112d269f + sha256: 3bb2aa2bf8758f4f1269fa36d67020e4f25199366773e2b73164456ce9286dc3 + md5: 8719dd226e9a128bd10033746e2418c6 depends: - python - libgcc >=14 @@ -6987,8 +6940,8 @@ packages: license_family: MIT purls: - pkg:pypi/nh3?source=hash-mapping - size: 677091 - timestamp: 1774451928026 + size: 678701 + timestamp: 1777219093168 - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda sha256: fd2cbd8dfc006c72f45843672664a8e4b99b2f8137654eaae8c3d46dca776f63 md5: 16c2a0e9c4a166e53632cfca4f68d020 @@ -7086,17 +7039,17 @@ packages: - pkg:pypi/numpy?source=hash-mapping size: 8388631 timestamp: 1730588649810 -- conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_102.conda - sha256: 098c858df0b0ae80f73d40d2ac131dbfebda4b8320bfb6522338320b878fd259 - md5: 0d096f211457b401d66cb4f22b4887f1 +- conda: https://conda.anaconda.org/conda-forge/linux-64/occt-7.9.3-novtk_hb176d5c_103.conda + sha256: cf6eb5894a9aa0074623fb14c7c364d89b3da63bee5ab932f0542f6a4866acfa + md5: 7355fcbd4cd8efece256c81f0e751f6d depends: - __glibc >=2.17,<3.0.a0 - fontconfig >=2.17.1,<3.0a0 - fonts-conda-ecosystem - freeimage >=3.18.0,<3.19.0a0 - freetype - - libfreetype >=2.14.2 - - libfreetype6 >=2.14.2 + - libfreetype >=2.14.3 + - libfreetype6 >=2.14.3 - libgcc >=14 - libgl >=1.7.0,<2.0a0 - libstdcxx >=14 @@ -7108,24 +7061,24 @@ packages: license: LGPL-2.1-only license_family: LGPL purls: [] - size: 25344065 - timestamp: 1773784031947 -- conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.8-h40f6f1d_0.conda - sha256: 67cbe0dfa060e03a0abd32daacfcb4c7b861d39fbc5378a394021072e742b4c9 - md5: 494f0051343d095d4bf99f6fb31fb7cf + size: 25385099 + timestamp: 1776668879469 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.4.11-h9f1635d_0.conda + sha256: 97b4570eaa1589d54160f64cc1074523a25a02582752ce3c6a9cd714052045ec + md5: c09d36f2fca535bc2f4f89e13d60696a depends: - - __glibc >=2.17,<3.0.a0 - libstdcxx >=14 - libgcc >=14 - - openjph >=0.26.3,<0.27.0a0 - - libdeflate >=1.25,<1.26.0a0 + - __glibc >=2.17,<3.0.a0 - libzlib >=1.3.2,<2.0a0 + - libdeflate >=1.25,<1.26.0a0 + - openjph >=0.27.0,<0.28.0a0 - imath >=3.2.2,<3.2.3.0a0 license: BSD-3-Clause license_family: BSD purls: [] - size: 1217976 - timestamp: 1774561006856 + size: 1218919 + timestamp: 1777531700890 - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda sha256: 3900f9f2dbbf4129cf3ad6acf4e4b6f7101390b53843591c53b00f034343bc4d md5: 11b3379b191f63139e29c0d19dee24cd @@ -7141,37 +7094,36 @@ packages: purls: [] size: 355400 timestamp: 1758489294972 -- conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.26.3-h8d634f6_0.conda - sha256: 4587e7762f27cad93619de77fa0573e2e17a899892d4bed3010196093e343533 - md5: 792d5b6e99677177f5527a758a02bc07 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjph-0.27.2-h8d634f6_0.conda + sha256: f88a521cd891475ac2bbfd8fb657774f2d1d0777c9316bcd55f55c397d1301c9 + md5: ac7564cac998d4df2f030de2e532291d depends: - __glibc >=2.17,<3.0.a0 - - libstdcxx >=14 - libgcc >=14 + - libstdcxx >=14 - libtiff >=4.7.1,<4.8.0a0 license: BSD-2-Clause - license_family: BSD purls: [] - size: 279846 - timestamp: 1771349499024 -- conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda - sha256: 2e185a3dc2bdc4525dd68559efa3f24fa9159a76c40473e320732b35115163b2 - md5: 3c40a106eadf7c14c6236ceddb267893 + size: 283187 + timestamp: 1778381714549 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.13-hbde042b_0.conda + sha256: 21c4f6c7f41dc9bec2ea2f9c80440d9a4d45a6f2ac13243e658f10dcf1044146 + md5: 680608784722880fbfe1745067570b00 depends: - __glibc >=2.17,<3.0.a0 - cyrus-sasl >=2.1.28,<3.0a0 - krb5 >=1.22.2,<1.23.0a0 - libgcc >=14 - libstdcxx >=14 - - openssl >=3.5.5,<4.0a0 + - openssl >=3.5.6,<4.0a0 license: OLDAP-2.8 license_family: BSD purls: [] - size: 785570 - timestamp: 1771970256722 -- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda - sha256: 44c877f8af015332a5d12f5ff0fb20ca32f896526a7d0cdb30c769df1144fb5c - md5: f61eb8cd60ff9057122a3d338b99c00f + size: 786149 + timestamp: 1775741359582 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda + sha256: c0ef482280e38c71a08ad6d71448194b719630345b0c9c60744a2010e8a8e0cb + md5: da1b85b6a87e141f5140bb9924cecab0 depends: - __glibc >=2.17,<3.0.a0 - ca-certificates @@ -7179,8 +7131,8 @@ packages: license: Apache-2.0 license_family: Apache purls: [] - size: 3164551 - timestamp: 1769555830639 + size: 3167099 + timestamp: 1775587756857 - conda: https://conda.anaconda.org/conda-forge/noarch/orsopy-1.2.1-pyhd8ed1ab_1.conda sha256: ab2e2c8cac273488028874c3eb29064907814c06c2154495584d69353fbd73b8 md5: 7793211c1838805e0e19af038fa132ab @@ -7218,18 +7170,18 @@ packages: - pkg:pypi/packageurl-python?source=hash-mapping size: 33897 timestamp: 1764001202900 -- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda - sha256: c1fc0f953048f743385d31c468b4a678b3ad20caffdeaa94bed85ba63049fd58 - md5: b76541e68fea4d511b1ac46a28dcd2c6 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890 + md5: 4c06a92e74452cfa53623a81592e8934 depends: - python >=3.8 - python license: Apache-2.0 license_family: APACHE purls: - - pkg:pypi/packaging?source=compressed-mapping - size: 72010 - timestamp: 1769093650580 + - pkg:pypi/packaging?source=hash-mapping + size: 91574 + timestamp: 1777103621679 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.2-py311h8032f78_0.conda sha256: f8aefe73a0d0863a92ad09688dbb65b2b746202f93733016c4db671f977c63ab md5: 138e5d98884407fcc8ccc6088574b1c7 @@ -7282,8 +7234,9 @@ packages: - xlsxwriter >=3.2.0 - zstandard >=0.23.0 license: BSD-3-Clause + license_family: BSD purls: - - pkg:pypi/pandas?source=compressed-mapping + - pkg:pypi/pandas?source=hash-mapping size: 15154211 timestamp: 1774916583619 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.2-py312h8ecdadd_0.conda @@ -7338,8 +7291,9 @@ packages: - xlsxwriter >=3.2.0 - zstandard >=0.23.0 license: BSD-3-Clause + license_family: BSD purls: - - pkg:pypi/pandas?source=compressed-mapping + - pkg:pypi/pandas?source=hash-mapping size: 14849233 timestamp: 1774916580467 - conda: https://conda.anaconda.org/conda-forge/linux-64/pango-1.56.4-hda50119_1.conda @@ -7363,9 +7317,9 @@ packages: purls: [] size: 458036 timestamp: 1774281947855 -- conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.6-pyhcf101f3_0.conda - sha256: 42b2d77ccea60752f3aa929a6413a7835aaacdbbde679f2f5870a744fa836b94 - md5: 97c1ce2fffa1209e7afb432810ec6e12 +- conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.7-pyhcf101f3_0.conda + sha256: 611882f7944b467281c46644ffde6c5145d1a7730388bcde26e7e86819b0998e + md5: 39894c952938276405a1bd30e4ce2caf depends: - python >=3.10 - python @@ -7373,8 +7327,8 @@ packages: license_family: MIT purls: - pkg:pypi/parso?source=hash-mapping - size: 82287 - timestamp: 1770676243987 + size: 82472 + timestamp: 1777722955579 - conda: https://conda.anaconda.org/conda-forge/linux-64/patch-2.8-hb03c661_1002.conda sha256: 61d3a3ef79952014bf536ffd84828d3558fc58b332adb89ed198b77fb301c2c5 md5: eaa73c6e5aff5b28675147abc350d49a @@ -7397,17 +7351,17 @@ packages: purls: [] size: 94048 timestamp: 1673473024463 -- conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda - sha256: 29ea20d0faf20374fcd61c25f6d32fb8e9a2c786a7f1473a0c3ead359470fbe1 - md5: 2908273ac396d2cd210a8127f5f1c0d6 +- conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda + sha256: 6eaee417d33f298db79bc7185ab1208604c0e6cf51dade34cd513c6f9db9c6f3 + md5: 11adc78451c998c0fd162584abfa3559 depends: - python >=3.10 license: MPL-2.0 license_family: MOZILLA purls: - pkg:pypi/pathspec?source=hash-mapping - size: 53739 - timestamp: 1769677743677 + size: 56559 + timestamp: 1777271601895 - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda sha256: 5e6f7d161356fefd981948bea5139c5aa0436767751a6930cb1ca801ebb113ff md5: 7a3bff861a6583f1889021facefc08b1 @@ -7455,29 +7409,29 @@ packages: - pkg:pypi/pillow?source=hash-mapping size: 1045029 timestamp: 1758208668856 -- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.1.1-py312h50c33e8_0.conda - sha256: 782b6b578a0e61f6ef5cca5be993d902db775a2eb3d0328a3c4ff515858e7f2c - md5: c5eff3ada1a829f0bdb780dc4b62bbae +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py312h50c33e8_0.conda + sha256: fa291f8915114733dc1df9f1627b8c63c517217c1eee1a6ede2ceb5e368cf27a + md5: 9e5609720e31213d4f39afe377f6217e depends: - python - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - libjpeg-turbo >=3.1.2,<4.0a0 - - tk >=8.6.13,<8.7.0a0 + - lcms2 >=2.18,<3.0a0 - libxcb >=1.17.0,<2.0a0 + - libjpeg-turbo >=3.1.2,<4.0a0 + - libtiff >=4.7.1,<4.8.0a0 - libwebp-base >=1.6.0,<2.0a0 - - libfreetype >=2.14.1 - - libfreetype6 >=2.14.1 - - lcms2 >=2.18,<3.0a0 + - openjpeg >=2.5.4,<3.0a0 - python_abi 3.12.* *_cp312 + - tk >=8.6.13,<8.7.0a0 + - libfreetype >=2.14.3 + - libfreetype6 >=2.14.3 - zlib-ng >=2.3.3,<2.4.0a0 - - libtiff >=4.7.1,<4.8.0a0 - - openjpeg >=2.5.4,<3.0a0 license: HPND purls: - pkg:pypi/pillow?source=hash-mapping - size: 1029755 - timestamp: 1770794002406 + size: 1039561 + timestamp: 1775060059882 - conda: https://conda.anaconda.org/conda-forge/noarch/pint-0.25.3-pyhc364b38_0.conda sha256: f58a03dd2908c15dc65fab7e03a0212c69043466f7f85a4e345470492841782f md5: 293c4719f6d62778ffecd18e024a8fcd @@ -7493,12 +7447,12 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/pint?source=compressed-mapping + - pkg:pypi/pint?source=hash-mapping size: 245230 timestamp: 1773969991837 -- conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda - sha256: 8e1497814a9997654ed7990a79c054ea5a42545679407acbc6f7e809c73c9120 - md5: 67bdec43082fd8a9cffb9484420b39a2 +- conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.1-pyh8b19718_0.conda + sha256: 1bd94ef1ae08fd811ef3b26857e46ba460c7430bf1f3ccd94a4d6614fd619bd5 + md5: 35870d32aed92041d31cbb15e822dca3 depends: - python >=3.10,<3.13.0a0 - setuptools @@ -7506,9 +7460,9 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/pip?source=compressed-mapping - size: 1181790 - timestamp: 1770270305795 + - pkg:pypi/pip?source=hash-mapping + size: 1201616 + timestamp: 1777924080196 - conda: https://conda.anaconda.org/conda-forge/noarch/pip-api-0.0.34-pyhd8ed1ab_0.conda sha256: 2d0a1dc9695eb260400496c038e8a467d37d2fd04ecf9ec2e205a921d5adfa45 md5: 8ea39496190b1a0f92f049685f97e8c7 @@ -7592,18 +7546,18 @@ packages: - pkg:pypi/pkginfo?source=hash-mapping size: 30536 timestamp: 1739984682585 -- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda - sha256: 0289f0a38337ee201d984f8f31f11f6ef076cfbbfd0ab9181d12d9d1d099bf46 - md5: 82c1787f2a65c0155ef9652466ee98d6 +- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.6-pyhcf101f3_0.conda + sha256: 8f29915c172f1f7f4f7c9391cd5dac3ebf5d13745c8b7c8006032615246345a5 + md5: 89c0b6d1793601a2a3a3f7d2d3d8b937 depends: - python >=3.10 - python license: MIT license_family: MIT purls: - - pkg:pypi/platformdirs?source=compressed-mapping - size: 25646 - timestamp: 1773199142345 + - pkg:pypi/platformdirs?source=hash-mapping + size: 25862 + timestamp: 1775741140609 - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e md5: d7585b6550ad04c8c5e21097ada2888e @@ -7641,20 +7595,20 @@ packages: purls: [] size: 5190425 timestamp: 1747060027562 -- conda: https://conda.anaconda.org/conda-forge/linux-64/poco-1.15.1-hbea8664_0.conda - sha256: 0aa58b3d3b9b67a4c421cd3f78b3b9d2f70a29ed5816255bdab9b3bd7f1f6ad3 - md5: 81f3753c84a4dca35bef3a6f6e5c02ef +- conda: https://conda.anaconda.org/conda-forge/linux-64/poco-1.15.2-hc403b36_0.conda + sha256: 72bd41eae70c79b1eda3607968c3c4e45b497dadc67a6bd44d97f6671354c4a8 + md5: 5e193512eaa09875e2c2d894f677c762 depends: - __glibc >=2.28,<3.0.a0 - libgcc >=14 - libstdcxx >=14 - - openssl >=3.5.5,<4.0a0 + - openssl >=3.5.6,<4.0a0 - unixodbc >=2.3.14,<2.4.0a0 license: BSL-1.0 license_family: OTHER purls: [] - size: 5451307 - timestamp: 1774358312988 + size: 5495343 + timestamp: 1776377861553 - conda: https://conda.anaconda.org/conda-forge/noarch/pooch-1.9.0-pyhd8ed1ab_0.conda sha256: 081e52c4612830bf1fd4a9c78eebaf335d1385d74ddfd328b1b2f26b983848eb md5: dd4b6337bf8886855db6905b336db3c8 @@ -7669,9 +7623,9 @@ packages: - pkg:pypi/pooch?source=hash-mapping size: 56833 timestamp: 1769816568869 -- conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda - sha256: 5b81b7516d4baf43d0c185896b245fa7384b25dc5615e7baa504b7fa4e07b706 - md5: 7f3ac694319c7eaf81a0325d6405e974 +- conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.6.0-pyha770c72_0.conda + sha256: 716960bf0a9eb334458a26b3bdcb17b8d0786062138a4f48c7f335c8418c5d0b + md5: 7859736b4f8ebe6c8481bf48d91c9a1e depends: - cfgv >=2.0.0 - identify >=1.0.0 @@ -7683,8 +7637,8 @@ packages: license_family: MIT purls: - pkg:pypi/pre-commit?source=hash-mapping - size: 200827 - timestamp: 1765937577534 + size: 201606 + timestamp: 1776858157327 - conda: https://conda.anaconda.org/conda-forge/noarch/prettytable-3.17.0-pyhd8ed1ab_0.conda sha256: a1cc667bd683f26c319ccab257cd3e17b33f34ef90ff4f548a811a342358c952 md5: 9a12c482f559d39f3ed9550ba9e0eeb0 @@ -7699,26 +7653,26 @@ packages: - pkg:pypi/prettytable?source=hash-mapping size: 35808 timestamp: 1763199361018 -- conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.0-he0df7b0_0.conda - sha256: 89f28d4ab8abea4bca124cf37b757cf24b64f2e5efa287727ab24ce0ff2208d1 - md5: 3732388938fc3decf65b90884c2d8198 +- conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.8.1-he0df7b0_0.conda + sha256: dff6f355025b9a510d9093e29fd970fa1091e758b848c9dec814d96ae63a09ba + md5: b23619e5e9009eaa070ead0342034027 depends: - sqlite - libtiff - libcurl - - libgcc >=14 - __glibc >=2.17,<3.0.a0 + - libgcc >=14 - libstdcxx >=14 - - libcurl >=8.18.0,<9.0a0 - - libsqlite >=3.51.2,<4.0a0 - libtiff >=4.7.1,<4.8.0a0 + - libsqlite >=3.53.0,<4.0a0 + - libcurl >=8.19.0,<9.0a0 constrains: - proj4 ==999999999999 license: MIT license_family: MIT purls: [] - size: 3670889 - timestamp: 1772446870068 + size: 3652144 + timestamp: 1775840249166 - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda sha256: 4817651a276016f3838957bfdf963386438c70761e9faec7749d411635979bae md5: edb16f14d920fb3faf17f5ce582942d6 @@ -7786,7 +7740,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/psutil?source=compressed-mapping + - pkg:pypi/psutil?source=hash-mapping size: 225545 timestamp: 1769678155334 - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda @@ -7991,31 +7945,30 @@ packages: - pkg:pypi/pycparser?source=hash-mapping size: 110100 timestamp: 1733195786147 -- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.5-pyhcf101f3_1.conda - sha256: 868569d9505b7fe246c880c11e2c44924d7613a8cdcc1f6ef85d5375e892f13d - md5: c3946ed24acdb28db1b5d63321dbca7d +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda + sha256: 69700e31165df070e9716315e042196aa92525dae5deb5107785847ab9f4189f + md5: 729843edafc0899b3348bd3f19525b9d depends: - typing-inspection >=0.4.2 - typing_extensions >=4.14.1 - python >=3.10 - - typing-extensions >=4.6.1 - annotated-types >=0.6.0 - - pydantic-core ==2.41.5 + - pydantic-core ==2.46.4 - python license: MIT license_family: MIT purls: - pkg:pypi/pydantic?source=hash-mapping - size: 340482 - timestamp: 1764434463101 -- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py311h902ca64_1.conda - sha256: da6e2060a91de065031214f9ca56e24906785ea412cd274d1f32128992dc0d43 - md5: 08d407f0331ff8e871db23bec7eef83c + size: 346511 + timestamp: 1778103405862 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py311h902ca64_0.conda + sha256: ac3faa31154a85f4b1a4618957b4a06623ff2c6a85f8eac20efe9dbac5757d91 + md5: b6cfa054aec29586d383f9e666bd0e9a depends: - python - typing-extensions >=4.6.0,!=4.7.0 - - libgcc >=14 - __glibc >=2.17,<3.0.a0 + - libgcc >=14 - python_abi 3.11.* *_cp311 constrains: - __glibc >=2.17 @@ -8023,11 +7976,11 @@ packages: license_family: MIT purls: - pkg:pypi/pydantic-core?source=hash-mapping - size: 1938184 - timestamp: 1762988992467 -- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py312h868fb18_1.conda - sha256: 07f899d035e06598682d3904d55f1529fac71b15e12b61d44d6a5fbf8521b0fe - md5: 56a776330a7d21db63a7c9d6c3711a04 + size: 1884122 + timestamp: 1778084220486 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py312h868fb18_0.conda + sha256: b8260660d064fb947f4b573ec4a782696bc8b19042452eaa4e9bb1152b540555 + md5: dfb9a57535eb8c35c6744da7043063f0 depends: - python - typing-extensions >=4.6.0,!=4.7.0 @@ -8040,30 +7993,32 @@ packages: license_family: MIT purls: - pkg:pypi/pydantic-core?source=hash-mapping - size: 1935221 - timestamp: 1762989004359 -- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.13.1-pyhd8ed1ab_0.conda - sha256: 343988d65c08477a87268d4fbeba59d0295514143965d2755ac4519b73155479 - md5: cc0da73801948100ae97383b8da12993 + size: 1895409 + timestamp: 1778084226169 +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.14.1-pyhcf101f3_0.conda + sha256: a4ad48b01e5e2640561011d8d48ac038fec66670f24e22c370097747bd9200d2 + md5: 3b05fc4bb3e31efd3498136b3221c18f depends: - - pydantic >=2.7.0 + - typing-inspection >=0.4.0 - python >=3.10 + - pydantic >=2.7.0 - python-dotenv >=0.21.0 - - typing-inspection >=0.4.0 + - python license: MIT license_family: MIT purls: - pkg:pypi/pydantic-settings?source=hash-mapping - size: 49319 - timestamp: 1771527313149 + size: 52280 + timestamp: 1778254612174 - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda sha256: cf70b2f5ad9ae472b71235e5c8a736c9316df3705746de419b59d442e8348e86 md5: 16c18772b340887160c79a6acc022db0 depends: - python >=3.10 license: BSD-2-Clause + license_family: BSD purls: - - pkg:pypi/pygments?source=compressed-mapping + - pkg:pypi/pygments?source=hash-mapping size: 893031 timestamp: 1774796815820 - conda: https://conda.anaconda.org/conda-forge/noarch/pyjwt-2.12.1-pyhcf101f3_0.conda @@ -8190,40 +8145,6 @@ packages: - pkg:pypi/pyqt5-sip?source=hash-mapping size: 85800 timestamp: 1759495565076 -- conda: https://conda.anaconda.org/conda-forge/linux-64/pyqtwebengine-5.15.11-py312hf963f02_2.conda - sha256: 76a0da8ad525467e9fd47b640c7cb8f8455034a2c51b2b5b47b5efa9ddcff8e9 - md5: 72a43a000533277f63cb2739d641b7b9 - depends: - - __glibc >=2.17,<3.0.a0 - - libegl >=1.7.0,<2.0a0 - - libgcc >=14 - - libgl >=1.7.0,<2.0a0 - - libopengl >=1.7.0,<2.0a0 - - libstdcxx >=14 - - pyqt >=5.15.11,<5.16.0a0 - - python >=3.12,<3.13.0a0 - - python_abi 3.12.* *_cp312 - - qt-main >=5.15.15,<5.16.0a0 - - qt-webengine >=5.15.15,<5.16.0a0 - - sip >=6.10.0,<6.11.0a0 - - xcb-util >=0.4.1,<0.5.0a0 - - xcb-util-image >=0.4.0,<0.5.0a0 - - xcb-util-keysyms >=0.4.1,<0.5.0a0 - - xcb-util-renderutil >=0.3.10,<0.4.0a0 - - xcb-util-wm >=0.4.2,<0.5.0a0 - - xorg-libice >=1.1.2,<2.0a0 - - xorg-libsm >=1.2.6,<2.0a0 - - xorg-libx11 >=1.8.12,<2.0a0 - - xorg-libxcomposite >=0.4.6,<1.0a0 - - xorg-libxdamage >=1.1.6,<2.0a0 - - xorg-libxext >=1.3.6,<2.0a0 - - xorg-libxxf86vm >=1.1.6,<2.0a0 - license: GPL-3.0-only - license_family: GPL - purls: - - pkg:pypi/pyqtwebengine?source=hash-mapping - size: 158496 - timestamp: 1759498270983 - conda: https://conda.anaconda.org/conda-forge/linux-64/pyqtwebengine-5.15.9-py311hd529140_5.conda sha256: d286ad8e7a8949dfe12092a4af250845477689d7a1235b2b5f3d8e8ea2e5cf6a md5: d4d71c140e9588f47e46387eaca50143 @@ -8244,61 +8165,58 @@ packages: timestamp: 1695420780098 - pypi: ./ name: pyrs - version: 1.9.0.dev20 - sha256: c05df128cdfc5deca37699901d69a944010855d7eea23ff2d671ec996502bcb2 + version: 1.9.0.dev22 + sha256: 962870db7993c7888e02fbdda0bd365dad45dc2aa2cc58d05ea3ea0522d12626 requires_python: '>=3.11' -- conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py311hf27b23e_1.conda - sha256: af32f0f281233d5822b389a38a7ff22652db45f794a9baa227a7c12e9223fa56 - md5: 69d2caeedece7a008151c6917525403d +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.11.0-py311hf27b23e_3.conda + sha256: 9d0fe9fc928a1eafdce5632fe348025707f8048755c56f181ad4552fb262face + md5: 5252465ce4c160c84e9294803a50782b depends: - python - - qt6-main 6.10.2.* - - __glibc >=2.17,<3.0.a0 + - qt6-main 6.11.0.* - libstdcxx >=14 - libgcc >=14 - - libvulkan-loader >=1.4.341.0,<2.0a0 + - __glibc >=2.17,<3.0.a0 - libclang13 >=21.1.8 + - python_abi 3.11.* *_cp311 + - libvulkan-loader >=1.4.341.0,<2.0a0 + - libxslt >=1.1.43,<2.0a0 + - libegl >=1.7.0,<2.0a0 + - libgl >=1.7.0,<2.0a0 - libopengl >=1.7.0,<2.0a0 + - qt6-main >=6.11.0,<6.12.0a0 - libxml2 - libxml2-16 >=2.14.6 - - libegl >=1.7.0,<2.0a0 - - qt6-main >=6.10.2,<6.11.0a0 - - libgl >=1.7.0,<2.0a0 - - libxslt >=1.1.43,<2.0a0 - - python_abi 3.11.* *_cp311 license: LGPL-3.0-only - license_family: LGPL purls: - - pkg:pypi/pyside6?source=hash-mapping - - pkg:pypi/shiboken6?source=hash-mapping - size: 13113375 - timestamp: 1773742512309 -- conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.2-py312h50ac2ff_1.conda - sha256: 18c8ffaca3d33e8617d600a79a1781b6de8e022039827254772a85651f4cebe6 - md5: 08452854f86c3190c3b0d4df1ae28555 + - pkg:pypi/pyside6?source=compressed-mapping + size: 13658580 + timestamp: 1778540469441 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.11.0-py312h50ac2ff_3.conda + sha256: c30432bb07d396600db971a775cd54506c8cb9e3fe494a4df3f169b8c1d15a1e + md5: 3cc6b6c3dce5070ae78f106bb3840e7b depends: - python - - qt6-main 6.10.2.* + - qt6-main 6.11.0.* - __glibc >=2.17,<3.0.a0 - libgcc >=14 - libstdcxx >=14 - - libopengl >=1.7.0,<2.0a0 - - qt6-main >=6.10.2,<6.11.0a0 - - libclang13 >=21.1.8 - - libxslt >=1.1.43,<2.0a0 + - libvulkan-loader >=1.4.341.0,<2.0a0 - libxml2 - libxml2-16 >=2.14.6 - - libegl >=1.7.0,<2.0a0 + - qt6-main >=6.11.0,<6.12.0a0 - libgl >=1.7.0,<2.0a0 + - libxslt >=1.1.43,<2.0a0 - python_abi 3.12.* *_cp312 - - libvulkan-loader >=1.4.341.0,<2.0a0 + - libegl >=1.7.0,<2.0a0 + - libclang13 >=21.1.8 + - libopengl >=1.7.0,<2.0a0 license: LGPL-3.0-only - license_family: LGPL purls: - pkg:pypi/pyside6?source=hash-mapping - pkg:pypi/shiboken6?source=hash-mapping - size: 13096913 - timestamp: 1773742520312 + size: 13642640 + timestamp: 1778540462882 - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8 md5: 461219d1a5bd61342293efa2c0c90eac @@ -8343,17 +8261,17 @@ packages: - pkg:pypi/pystack?source=hash-mapping size: 427218 timestamp: 1769431112708 -- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.2-pyhcf101f3_0.conda - sha256: 9e749fb465a8bedf0184d8b8996992a38de351f7c64e967031944978de03a520 - md5: 2b694bad8a50dc2f712f5368de866480 +- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + sha256: 960f59442173eee0731906a9077bd5ccf60f4b4226f05a22d1728ab9a21a879c + md5: 6a991452eadf2771952f39d43615bb3e depends: + - colorama >=0.4 - pygments >=2.7.2 - python >=3.10 - iniconfig >=1.0.1 - packaging >=22 - pluggy >=1.5,<2 - tomli >=1 - - colorama >=0.4 - exceptiongroup >=1 - python constrains: @@ -8362,8 +8280,8 @@ packages: license_family: MIT purls: - pkg:pypi/pytest?source=hash-mapping - size: 299581 - timestamp: 1765062031645 + size: 299984 + timestamp: 1775644472530 - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda sha256: 44e42919397bd00bfaa47358a6ca93d4c21493a8c18600176212ec21a8d25ca5 md5: 67d1790eefa81ed305b89d8e314c7923 @@ -8376,7 +8294,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/pytest-cov?source=compressed-mapping + - pkg:pypi/pytest-cov?source=hash-mapping size: 29559 timestamp: 1774139250481 - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-qt-4.5.0-pyhdecd6ff_0.conda @@ -8447,11 +8365,11 @@ packages: purls: [] size: 31608571 timestamp: 1772730708989 -- conda: https://conda.anaconda.org/conda-forge/noarch/python-build-1.4.2-pyhc364b38_1.conda - sha256: 3f76a55e524728cd4092d78dd01107c8c3e91a66842317b49c7c8209a332c4f1 - md5: 09971b38d49f16c47a8769aeb171ef3d +- conda: https://conda.anaconda.org/conda-forge/noarch/python-build-1.5.0-pyhc364b38_0.conda + sha256: eb8d5e44fddee9033eb7cfdd5ea584b7594b50e31c7602bef553af0fd4ee9266 + md5: fa587158c0d768127faa1a3b4df01e5d depends: - - python >=3.9 + - python >=3.10 - colorama - importlib-metadata >=4.6 - packaging >=24.0 @@ -8464,8 +8382,8 @@ packages: license_family: MIT purls: - pkg:pypi/build?source=hash-mapping - size: 28291 - timestamp: 1774469084833 + size: 28946 + timestamp: 1778048948266 - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664 md5: 5b8d21249ff20967101ffa321cab24e8 @@ -8479,9 +8397,9 @@ packages: - pkg:pypi/python-dateutil?source=hash-mapping size: 233310 timestamp: 1751104122689 -- conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda - sha256: 5a70a9cbcf48be522c2b82df8c7a57988eed776f159142b0d30099b61f31a35e - md5: f2e88fc463b249bc1f40d9ca969d9b5e +- conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.3.0-pyhcf101f3_0.conda + sha256: ae70eb1c16970f2317e71dd2dee7d3a41abd26a47298ca8d9163a94b6579517b + md5: 696db6f25e56c0fafdccb0a7426fffb6 depends: - python >=3.10 - filelock >=3.15.4 @@ -8490,9 +8408,9 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/python-discovery?source=compressed-mapping - size: 34137 - timestamp: 1774605818480 + - pkg:pypi/python-discovery?source=hash-mapping + size: 35030 + timestamp: 1778013338579 - conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda sha256: 74e417a768f59f02a242c25e7db0aa796627b5bc8c818863b57786072aeb85e5 md5: 130584ad9f3a513cdd71b1fdc1244e9c @@ -8501,7 +8419,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/python-dotenv?source=compressed-mapping + - pkg:pypi/python-dotenv?source=hash-mapping size: 27848 timestamp: 1772388605021 - conda: https://conda.anaconda.org/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda @@ -8548,34 +8466,32 @@ packages: - pkg:pypi/libarchive-c?source=hash-mapping size: 29627 timestamp: 1754663558440 -- conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.8.1-py311haee01d2_0.conda - sha256: 05f57e25a2cafc9c9c6803d775307a55a310992b8a2563610f47d9691db9a701 - md5: 02d9d935e9270742d7a6ab7b28b9e92e +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.11.0-py311haee01d2_0.conda + sha256: be4672e9a1c5c052529767b3675f766e10cca5ef207c76ddb21a8927f84fe1ac + md5: 5211fbc1a437503e8df1f8bcadd86651 depends: - python - libgcc >=14 - __glibc >=2.17,<3.0.a0 - python_abi 3.11.* *_cp311 license: MIT - license_family: MIT purls: - pkg:pypi/librt?source=hash-mapping - size: 77144 - timestamp: 1771423012220 -- conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.8.1-py312h5253ce2_0.conda - sha256: 41a3f2541952ee521c867ada76da02a43a919beeb46da8fee99284d161273a50 - md5: e2cc29a3786c42455a70263a8bf6813e + size: 156372 + timestamp: 1778511625319 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.11.0-py312h5253ce2_0.conda + sha256: 6aa36a62db36c2aa144640a3fba1cd3c61dd679a979288eae2fd3b9f89ef4eac + md5: 0a73899771633857390eac009995e5f9 depends: - python - - __glibc >=2.17,<3.0.a0 - libgcc >=14 + - __glibc >=2.17,<3.0.a0 - python_abi 3.12.* *_cp312 license: MIT - license_family: MIT purls: - pkg:pypi/librt?source=hash-mapping - size: 77475 - timestamp: 1771423012370 + size: 157857 + timestamp: 1778511616936 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda build_number: 8 sha256: fddf123692aa4b1fc48f0471e346400d9852d96eeed77dbfdd746fa50a8ff894 @@ -8598,21 +8514,21 @@ packages: purls: [] size: 6958 timestamp: 1752805918820 -- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.1.post1-pyhcf101f3_0.conda - sha256: d35c15c861d5635db1ba847a2e0e7de4c01994999602db1f82e41b5935a9578a - md5: f8a489f43a1342219a3a4d69cecc6b25 +- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda + sha256: 5020863d629f584b5c057333a67a7aed43e3ed013ba15dd70f353501ccb5aff6 + md5: 03cb60f505ad3ada0a95277af5faeb1a depends: - python >=3.10 - python license: MIT license_family: MIT purls: - - pkg:pypi/pytz?source=compressed-mapping - size: 201725 - timestamp: 1773679724369 -- conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.47.1-pyhd8ed1ab_1.conda - sha256: 1257ccb38525cdef1f1b10da8e5d3bd7c36992359a96462e2130f9562e6bcee7 - md5: c2f767478b4deb9f5a381ca7b9ebff3b + - pkg:pypi/pytz?source=hash-mapping + size: 201747 + timestamp: 1777892201250 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyvista-0.48.2-pyhd8ed1ab_0.conda + sha256: 1b888022034b884921c239c0467275f6b4973b65350435a9e323b0795d5f9bfb + md5: d90d43289d75931f7be528f8eb4ffe3d depends: - cyclopts >=4.0.0 - matplotlib-base >=3.0.1 @@ -8626,23 +8542,22 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/pyvista?source=hash-mapping - size: 2176679 - timestamp: 1773418651859 -- conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.3-pyhdecd6ff_0.conda - sha256: 075537f9a638979dcdfaa63af45109b74331404150ab6a8c99423bc79cf36794 - md5: a8210cd7dd52b5e285b713f710a8d7c4 + - pkg:pypi/pyvista?source=compressed-mapping + size: 2259790 + timestamp: 1778405078289 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyvistaqt-0.11.4-pyhd8ed1ab_0.conda + sha256: 2735312d6860b567d0d29df0fd14b010b89fe8d6d4b8a46758b7d8ba1c07131f + md5: 9455f6d735e4a7709e3bb13b2c237837 depends: - - imageio >=2.5.0 - - python >=3.9 - - pyvista >=0.32.0 + - python >=3.10 + - pyvista >=0.39.0 - qtpy >=1.9.0 license: MIT license_family: MIT purls: - pkg:pypi/pyvistaqt?source=hash-mapping - size: 134743 - timestamp: 1753429881433 + size: 135726 + timestamp: 1775235295414 - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py311h3778330_1.conda sha256: c9a6cd2c290d7c3d2b30ea34a0ccda30f770e8ddb2937871f2c404faf60d0050 md5: a24add9a3bababee946f3bc1c829acfe @@ -8655,7 +8570,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/pyyaml?source=compressed-mapping + - pkg:pypi/pyyaml?source=hash-mapping size: 206190 timestamp: 1770223702917 - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda @@ -8908,9 +8823,9 @@ packages: purls: [] size: 51532169 timestamp: 1769499727503 -- conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.10.2-pl5321h16c4a6b_6.conda - sha256: dd2fdde2cfecd29d4acd2bacbb341f00500d8b3b1c0583a8d92e07fc1e4b1106 - md5: 3a00bff44c15ee37bfd5eb435e1b2a51 +- conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.11.0-pl5321h16c4a6b_4.conda + sha256: d2cb212a4abd66c13df44771c22ee23c0b013ba1d5dbb5e10e8a13e261a47c6b + md5: c81127acb50fdc7760682495fc9ab088 depends: - libxcb - xcb-util @@ -8919,69 +8834,68 @@ packages: - xcb-util-image - xcb-util-renderutil - xcb-util-cursor - - __glibc >=2.17,<3.0.a0 + - libgl-devel + - libegl-devel - libgcc >=14 + - __glibc >=2.17,<3.0.a0 - libstdcxx >=14 - - xorg-libice >=1.1.2,<2.0a0 - - icu >=78.3,<79.0a0 - - libllvm22 >=22.1.0,<22.2.0a0 - - krb5 >=1.22.2,<1.23.0a0 - - xorg-libx11 >=1.8.13,<2.0a0 - - xorg-libxtst >=1.2.5,<2.0a0 - - libfreetype >=2.14.2 - - libfreetype6 >=2.14.2 - - libxml2 - - libxml2-16 >=2.14.6 - - libtiff >=4.7.1,<4.8.0a0 - - libegl >=1.7.0,<2.0a0 - - xorg-libxxf86vm >=1.1.7,<2.0a0 - - libdrm >=2.4.125,<2.5.0a0 - - xcb-util >=0.4.1,<0.5.0a0 - - libbrotlicommon >=1.2.0,<1.3.0a0 - - libbrotlienc >=1.2.0,<1.3.0a0 - - libbrotlidec >=1.2.0,<1.3.0a0 - libvulkan-loader >=1.4.341.0,<2.0a0 - - libclang-cpp22.1 >=22.1.0,<22.2.0a0 - - double-conversion >=3.4.0,<3.5.0a0 - - dbus >=1.16.2,<2.0a0 - - xcb-util-renderutil >=0.3.10,<0.4.0a0 - - alsa-lib >=1.2.15.3,<1.3.0a0 - - wayland >=1.24.0,<2.0a0 - - xcb-util-cursor >=0.1.6,<0.2.0a0 - - libpng >=1.6.55,<1.7.0a0 - - libclang13 >=22.1.0 - libwebp-base >=1.6.0,<2.0a0 - - zstd >=1.5.7,<1.6.0a0 + - libgl >=1.7.0,<2.0a0 + - libegl >=1.7.0,<2.0a0 + - openssl >=3.5.6,<4.0a0 + - dbus >=1.16.2,<2.0a0 + - libxkbcommon >=1.13.1,<2.0a0 - pcre2 >=10.47,<10.48.0a0 - - xorg-libxrandr >=1.5.5,<2.0a0 - - libcups >=2.3.3,<2.4.0a0 - - libpq >=18.3,<19.0a0 - - libjpeg-turbo >=3.1.2,<4.0a0 - - xorg-libxcomposite >=0.4.7,<1.0a0 - - xcb-util-keysyms >=0.4.1,<0.5.0a0 - - xorg-libxcursor >=1.2.3,<2.0a0 - - harfbuzz >=13.1.1 - - openssl >=3.5.5,<4.0a0 + - krb5 >=1.22.2,<1.23.0a0 - fontconfig >=2.17.1,<3.0a0 - fonts-conda-ecosystem - libxcb >=1.17.0,<2.0a0 - - libzlib >=1.3.1,<2.0a0 - - libsqlite >=3.52.0,<4.0a0 - - xorg-libsm >=1.2.6,<2.0a0 - - libgl >=1.7.0,<2.0a0 - - libglib >=2.86.4,<3.0a0 - - xorg-libxext >=1.3.7,<2.0a0 - - libxkbcommon >=1.13.1,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + - xcb-util >=0.4.1,<0.5.0a0 + - xorg-libxcomposite >=0.4.7,<1.0a0 + - xorg-libxxf86vm >=1.1.7,<2.0a0 + - icu >=78.3,<79.0a0 - xorg-libxdamage >=1.1.6,<2.0a0 + - xcb-util-renderutil >=0.3.10,<0.4.0a0 - xcb-util-image >=0.4.0,<0.5.0a0 + - wayland >=1.25.0,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - xcb-util-keysyms >=0.4.1,<0.5.0a0 + - xorg-libxcursor >=1.2.3,<2.0a0 + - double-conversion >=3.4.0,<3.5.0a0 + - alsa-lib >=1.2.15.3,<1.3.0a0 + - xorg-libxext >=1.3.7,<2.0a0 + - harfbuzz >=14.1.0 + - libsqlite >=3.53.0,<4.0a0 + - libfreetype >=2.14.3 + - libfreetype6 >=2.14.3 + - libtiff >=4.7.1,<4.8.0a0 + - libdrm >=2.4.125,<2.5.0a0 + - libjpeg-turbo >=3.1.4.1,<4.0a0 - xcb-util-wm >=0.4.2,<0.5.0a0 + - libcups >=2.3.3,<2.4.0a0 + - xorg-libx11 >=1.8.13,<2.0a0 + - libpng >=1.6.58,<1.7.0a0 + - xorg-libxtst >=1.2.5,<2.0a0 + - xorg-libice >=1.1.2,<2.0a0 + - xorg-libxrandr >=1.5.5,<2.0a0 + - libbrotlicommon >=1.2.0,<1.3.0a0 + - libbrotlienc >=1.2.0,<1.3.0a0 + - libbrotlidec >=1.2.0,<1.3.0a0 + - xcb-util-cursor >=0.1.6,<0.2.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - xorg-libsm >=1.2.6,<2.0a0 + - libpq >=18.3,<19.0a0 + - libglib >=2.86.4,<3.0a0 constrains: - - qt ==6.10.2 + - qt ==6.11.0 license: LGPL-3.0-only license_family: LGPL purls: [] - size: 58118322 - timestamp: 1773865930316 + size: 59928585 + timestamp: 1776322501700 - conda: https://conda.anaconda.org/conda-forge/noarch/qtconsole-5.7.2-pyhd8ed1ab_0.conda sha256: 890fdf416cb1cb29bfe502fb1b038b60a87a6cdffc0a78db6b9688d8ae75f0c8 md5: 506f8b95ef2554db6160f0e8b8994313 @@ -9085,33 +8999,34 @@ packages: purls: [] size: 156074 timestamp: 1742820732296 -- conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.61.4-ha759004_0.conda - sha256: 75c7fc60c42363b681cb52d589597b504cbf6679eb8103973803fdab170fc39b - md5: e2a723aea7b00504af01bb424f87b7f1 +- conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.64.1-ha759004_0.conda + sha256: 2d9511bf7019e392dfc7c03b7f619c1a7d3db6f230c0adb0a6f2dc042c1d0c4a + md5: 711e3d00097aaf617c8a665edc87a6d1 depends: - patchelf - - libstdcxx >=14 - - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - openssl >=3.5.5,<4.0a0 + - libgcc >=14 + - libstdcxx >=14 + - openssl >=3.5.6,<4.0a0 constrains: - __glibc >=2.17 license: BSD-3-Clause + license_family: BSD purls: [] - size: 18962901 - timestamp: 1774984405950 -- conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.1-pyhe01879c_0.conda - sha256: e8eb7be6d307f1625c6e6c100270a2eea92e6e7cc45277cd26233ce107ea9f73 - md5: 7f24e776b0f2ffac7516e51e9d2c1e52 + size: 19269945 + timestamp: 1777910751216 +- conda: https://conda.anaconda.org/conda-forge/noarch/readchar-4.2.2-pyhcf101f3_0.conda + sha256: ea85cacf3cc5bcd472622e58592a1966fdb196fe62facb7de9a30133dec46ff6 + md5: b71e7f9e2ba9425275f7318f4461877f depends: - - python >=3.9 + - python >=3.10 - python license: MIT license_family: MIT purls: - pkg:pypi/readchar?source=hash-mapping - size: 15139 - timestamp: 1750461053332 + size: 15624 + timestamp: 1775509908875 - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 md5: d7d95fc8287ea7bf33e0e7116d2b95ec @@ -9154,43 +9069,43 @@ packages: - pkg:pypi/referencing?source=hash-mapping size: 51788 timestamp: 1760379115194 -- pypi: https://files.pythonhosted.org/packages/0a/fe/661043d1c263b0d9d10c6ff4e9c9745f3df9641c62b51f96a3473638e7ce/regex-2026.3.32-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl +- pypi: https://files.pythonhosted.org/packages/33/6f/1481597e859ef19508b345eec4afd1416ed6e6b459c75a64026ef193aecf/regex-2026.5.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl name: regex - version: 2026.3.32 - sha256: f54840bea73541652f1170dc63402a5b776fc851ad36a842da9e5163c1f504a0 + version: 2026.5.9 + sha256: 2a661a7d270a61f7cf460caee8b9fa2d5ef9e5c681234bcb9e0fe14f488e7dfc requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/e7/26/46673bb18448c51222c6272c850484a0092f364fae8d0315be9aa1e4baa7/regex-2026.3.32-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl +- pypi: https://files.pythonhosted.org/packages/cc/1e/3fbe2fa1e8cebd62f3bb7d3321cff1640aca2e240b51d9bd624aad949260/regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl name: regex - version: 2026.3.32 - sha256: c5e0fdb5744caf1036dec5510f543164f2144cb64932251f6dfd42fa872b7f9c + version: 2026.5.9 + sha256: dd2810d22146b6d838acc5ec15602cb6b47920aa4e33015df3868eedfd20bab8 requires_python: '>=3.10' -- conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda - sha256: a1973f41a6b956f1305f9aaefdf14b2f35a8c9615cfe5f143f1784ed9aa6bf47 - md5: 69fbc0a9e42eb5fe6733d2d60d818822 +- conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.7.post0-hb03c661_0.conda + sha256: ee62a35f1e63791a7d62bfde35920feb225b7a42cbd0675db1d23791314a3c09 + md5: c29ecc627d4d8e2416b6cc67e2a85987 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 + - libgcc >=14 license: MIT license_family: MIT purls: [] - size: 34194 - timestamp: 1731925834928 -- conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda - sha256: 568485837b905b1ea7bdb6e6496d914b83db57feda57f6050d5a694977478691 - md5: 828302fca535f9cfeb598d5f7c204323 + size: 34819 + timestamp: 1776257913113 +- conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.7.post0-hecca717_0.conda + sha256: 6856d7ff1ad8eea8b90c3047dd8d21baefd9525e39e611310567c4f0c29c7fbf + md5: 6671b0f9402a3bfbff38bde336d141ec depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - libstdcxx >=13 - - reproc 14.2.5.post0 hb9d3cd8_0 + - libgcc >=14 + - libstdcxx >=14 + - reproc 14.2.7.post0 hb03c661_0 license: MIT license_family: MIT purls: [] - size: 25665 - timestamp: 1731925852714 -- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda - sha256: c0249bc4bf4c0e8e06d0e7b4d117a5d593cc4ab2144d5006d6d47c83cb0af18e - md5: 10afbb4dbf06ff959ad25a92ccee6e59 + size: 26676 + timestamp: 1776257951002 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.0-pyhcf101f3_0.conda + sha256: 4487fdb341537e2df47159ed8e546add99080974c52d5b2dc2a710910619115a + md5: a5985537dab1ba7034b5ff4ea22e2fa9 depends: - python >=3.10 - certifi >=2023.5.7 @@ -9199,12 +9114,12 @@ packages: - urllib3 >=1.26,<3 - python constrains: - - chardet >=3.0.2,<6 + - chardet >=3.0.2,<8 license: Apache-2.0 purls: - pkg:pypi/requests?source=compressed-mapping - size: 63712 - timestamp: 1774894783063 + size: 68658 + timestamp: 1778534036810 - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_1.conda sha256: c0b815e72bb3f08b67d60d5e02251bbb0164905b5f72942ff5b6d2a339640630 md5: 66de8645e324fda0ea6ef28c2f99a2ab @@ -9228,9 +9143,9 @@ packages: - pkg:pypi/rfc3986?source=hash-mapping size: 38028 timestamp: 1733921806657 -- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda - sha256: b06ce84d6a10c266811a7d3adbfa1c11f13393b91cc6f8a5b468277d90be9590 - md5: 7a6289c50631d620652f5045a63eb573 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda + sha256: 3d6ba2c0fcdac3196ba2f0615b4104e532525ffa1335b50a2878be5ff488814a + md5: 0242025a3c804966bf71aa04eee82f66 depends: - markdown-it-py >=2.2.0 - pygments >=2.13.0,<3.0.0 @@ -9240,9 +9155,9 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/rich?source=compressed-mapping - size: 208472 - timestamp: 1771572730357 + - pkg:pypi/rich?source=hash-mapping + size: 208577 + timestamp: 1775991661559 - conda: https://conda.anaconda.org/conda-forge/noarch/rich-rst-1.3.2-pyhd8ed1ab_0.conda sha256: 202e90d6624abc924e185166f6fcfdd29c6749ec26d60480a0a34c898c0b67fd md5: cbd84dbdb3f5a7d762b5fb2b0d49e7cd @@ -9426,17 +9341,17 @@ packages: - pkg:pypi/scipy?source=hash-mapping size: 16666973 timestamp: 1766108740332 -- conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.0-pyhd8ed1ab_0.conda - sha256: 9a952a8e1af64f012b85b3dc69c049b6a48dfa4f2c8ac347d1e59a6634058305 - md5: 2d707ed62f63d72f4a0141b818e9c7b6 +- conda: https://conda.anaconda.org/conda-forge/noarch/scooby-0.11.2-pyhd8ed1ab_0.conda + sha256: f9c82b8e992963b8c61e20536d7009a6675d3136fcdd737dfc6b60e000d57d3f + md5: c5b13fecbbd3984f12a70599973c6551 depends: - python >=3.10 license: MIT license_family: MIT purls: - pkg:pypi/scooby?source=hash-mapping - size: 24029 - timestamp: 1762031716091 + size: 24816 + timestamp: 1776995060561 - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.4.1-py311h38be061_0.conda sha256: 47f28b12e760ae3ce8a1e616c5b56f5e874e0e4a036bdd09516ebf263c19521f md5: ec955e67147942a68469a46d0bdf0a7b @@ -9480,20 +9395,21 @@ packages: - pkg:pypi/seekpath?source=hash-mapping size: 56120 timestamp: 1755759152086 -- conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.2.1-pyhd8ed1ab_0.conda - sha256: a432fa507ec1afbfa820234e00add0bb1109a1960e0d8ab9eb7081e6ea39851c - md5: 9047925cffa6fd304e441477107b4909 +- conda: https://conda.anaconda.org/conda-forge/noarch/seekpath-2.2.1-pyhcf101f3_2.conda + sha256: 0c31fc514e782eb67fa9e7100389466994773ac0431d35e86c5629151abf9500 + md5: 910e60de5711de260de6b00a3b4e6be5 depends: - - numpy >=1.0 - python >=3.10 - - scipy + - numpy >=1.0 - spglib >=1.9.4 + - scipy + - python license: MIT license_family: MIT purls: - pkg:pypi/seekpath?source=hash-mapping - size: 57092 - timestamp: 1769869874842 + size: 57143 + timestamp: 1777477135226 - conda: https://conda.anaconda.org/conda-forge/noarch/semver-3.0.4-pyhcf101f3_1.conda sha256: bea67173ed67c73cf16691ef72e58059492ac1ed1c880cfbeb6f1295c5add7d6 md5: 8e7be844ccb9706a999a337e056606ab @@ -9528,9 +9444,9 @@ packages: - pkg:pypi/shellingham?source=hash-mapping size: 15018 timestamp: 1762858315311 -- conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda - sha256: ffe0c49e65486b485e66c7e116b1782189c970c16cb2fe9710a568e44bb9ede3 - md5: da6caa4c932708d447fb80eed702cb4e +- conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.6.4-hb700be7_0.conda + sha256: 7a1f81823ec7d5ad659024de878ec34ea90205743cd685790621d7c013cc0a75 + md5: a0a159ba93ca0018f3d3e333470b045f depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -9538,8 +9454,8 @@ packages: license: Apache-2.0 license_family: APACHE purls: [] - size: 294996 - timestamp: 1766034103379 + size: 317505 + timestamp: 1778109124630 - conda: https://conda.anaconda.org/conda-forge/linux-64/sip-6.10.0-py312h1289d80_1.conda sha256: 65224ec231bb938a720897d75fb76f20a2376bded01a438f5220f6fa43195e4f md5: f96baa9ba899d5d30578675fe28b3473 @@ -9609,7 +9525,7 @@ packages: license: Apache-2.0 license_family: Apache purls: - - pkg:pypi/sniffio?source=compressed-mapping + - pkg:pypi/sniffio?source=hash-mapping size: 15698 timestamp: 1762941572482 - conda: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-3.0.1-pyhd8ed1ab_0.conda @@ -9798,9 +9714,9 @@ packages: - pkg:pypi/sphinxcontrib-jsmath?source=hash-mapping size: 10462 timestamp: 1733753857224 -- conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.1-pyhd8ed1ab_0.conda - sha256: 282edd719ea1b904aa5b10f3c45fd349400b30d9d06d4439bcd326cfe7701d39 - md5: 393bd25222decb075f05036fbdd5905d +- conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-mermaid-2.0.2-pyhd8ed1ab_0.conda + sha256: 7c46723e034abe7faeb8e8e9c5a5671fee7bdb63394d04437b014d792f747883 + md5: 1893e7b70d99972de59259b4e32c276a depends: - python >=3.10 - pyyaml @@ -9809,8 +9725,8 @@ packages: license_family: BSD purls: - pkg:pypi/sphinxcontrib-mermaid?source=hash-mapping - size: 19817 - timestamp: 1772753857998 + size: 20031 + timestamp: 1778054700470 - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-programoutput-0.19-pyhd8ed1ab_0.conda sha256: a0ffae2b63de1e48d8b3a59219fc57d486f58e7a470cc981ccc819319b546fdb md5: 4e214c97d3722dc82f3556fb359df92e @@ -9847,35 +9763,34 @@ packages: - pkg:pypi/sphinxcontrib-serializinghtml?source=hash-mapping size: 28669 timestamp: 1733750596111 -- conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2025.5-hb700be7_0.conda - sha256: 7547142ab1352132adf98d555ed955badd96c9f277cbd054ae52f7edd6cf6cb8 - md5: 058d5f16eaa3018be91aa3508df00d7c +- conda: https://conda.anaconda.org/conda-forge/linux-64/spirv-tools-2026.1-hb700be7_0.conda + sha256: 003180b3a2e0c6490b1f3461cf9e0ed740b1bbf88ee4b73ee177b94bea0dc95d + md5: 8809e0bd5ec279bfe4bb6651c3ed2730 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - libstdcxx >=14 constrains: - - spirv-headers >=1.4.335.0,<1.4.335.1.0a0 + - spirv-headers >=1.4.341.0,<1.4.341.1.0a0 license: Apache-2.0 license_family: APACHE purls: [] - size: 2595788 - timestamp: 1769406054481 -- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda - sha256: c9af81e7830d9c4b67a7f48e512d060df2676b29cac59e3b31f09dbfcee29c58 - md5: 7d9d7efe9541d4bb71b5934e8ee348ea + size: 2296977 + timestamp: 1770089626195 +- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda + sha256: d167fa92781bcdcd3b9aaa6bb1cd50c5b108f6190c170098a118b5cf5df2f881 + md5: 8e0b8654ead18e50af552e54b5a08a61 depends: - __glibc >=2.17,<3.0.a0 - - icu >=78.2,<79.0a0 - libgcc >=14 - - libsqlite 3.52.0 hf4e2dac_0 - - libzlib >=1.3.1,<2.0a0 - - ncurses >=6.5,<7.0a0 + - libsqlite 3.53.1 h0c1763c_0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 - readline >=8.3,<9.0a0 license: blessing purls: [] - size: 203641 - timestamp: 1772818888368 + size: 205399 + timestamp: 1777986477546 - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda sha256: 570da295d421661af487f1595045760526964f41471021056e993e73089e9c41 md5: b1b505328da7a6b246787df4b5a49fbc @@ -9905,9 +9820,9 @@ packages: - pkg:pypi/superqt?source=hash-mapping size: 81580 timestamp: 1772747657990 -- conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2022.3.0-hb700be7_2.conda - sha256: 975710e4b7f1b13c3c30b7fbf21e22f50abe0463b6b47a231582fdedcc45c961 - md5: 8f7278ca5f7456a974992a8b34284737 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2023.0.0-h51de99f_1.conda + sha256: 131a764e9c890bbe0b6c4d36e5349a6a873e09cbfc494549dd6cc85815b88ab2 + md5: 6383c1684badc0d94408b12850cf07f1 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -9916,8 +9831,8 @@ packages: license: Apache-2.0 license_family: APACHE purls: [] - size: 181329 - timestamp: 1767886632911 + size: 181400 + timestamp: 1777976294854 - conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda sha256: 6016672e0e72c4cf23c0cf7b1986283bd86a9c17e8d319212d78d8e9ae42fdfd md5: 9d64911b31d57ca443e9f1e36b04385f @@ -9974,7 +9889,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/tomli?source=compressed-mapping + - pkg:pypi/tomli?source=hash-mapping size: 21561 timestamp: 1774492402955 - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda @@ -9988,17 +9903,17 @@ packages: - pkg:pypi/tomli-w?source=hash-mapping size: 12680 timestamp: 1736962345843 -- conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda - sha256: b35082091c8efd084e51bc3a4a2d3b07897eff232aaf58cbc0f959b6291a6a93 - md5: 385dca77a8b0ec6fa9b92cb62d09b43b +- conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.15.0-pyha770c72_0.conda + sha256: 1cd52f9ccb4854c4d731438afe0e833b6b71edaf5ede661152aa98efb3a7cc70 + md5: 42ef10a8f7f5d55a2e267c0d5daa6387 depends: - python >=3.10 license: MIT license_family: MIT purls: - pkg:pypi/tomlkit?source=hash-mapping - size: 39224 - timestamp: 1768476626454 + size: 41169 + timestamp: 1778423744478 - conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda sha256: 4e379e1c18befb134247f56021fdf18e112fb35e64dd1691858b0a0f3bea9a45 md5: c07a6153f8306e45794774cf9b13bd32 @@ -10021,7 +9936,7 @@ packages: license: Apache-2.0 license_family: Apache purls: - - pkg:pypi/tornado?source=compressed-mapping + - pkg:pypi/tornado?source=hash-mapping size: 876817 timestamp: 1774358035290 - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.5-py312h4c3975b_0.conda @@ -10035,7 +9950,7 @@ packages: license: Apache-2.0 license_family: Apache purls: - - pkg:pypi/tornado?source=compressed-mapping + - pkg:pypi/tornado?source=hash-mapping size: 859665 timestamp: 1774358032165 - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda @@ -10047,31 +9962,32 @@ packages: - python license: MPL-2.0 and MIT purls: - - pkg:pypi/tqdm?source=compressed-mapping + - pkg:pypi/tqdm?source=hash-mapping size: 94132 timestamp: 1770153424136 -- conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda - sha256: f39a5620c6e8e9e98357507262a7869de2ae8cc07da8b7f84e517c9fd6c2b959 - md5: 019a7385be9af33791c989871317e1ed +- conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda + sha256: dfb681579be59c2e790c95f7f49b7529a9b0511d6385ad276e3c8988cbd54d2c + md5: 4bada6a6d908a27262af8ebddf4f7492 depends: - - python >=3.9 + - python >=3.10 + - python license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/traitlets?source=hash-mapping - size: 110051 - timestamp: 1733367480074 -- conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.1.14.14-pyhd8ed1ab_0.conda - sha256: 302d576f7e44fa13d2849b901772a04f1c2aabc5d6b6c7dcdc5a271bcffd50fe - md5: f5793a97363a42fd6a98f31f29537bbc + size: 115165 + timestamp: 1778074251714 +- conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2026.5.7.17-pyhd8ed1ab_0.conda + sha256: b06931edfab2f6bde64fae1e7323216b74389b5a27242bf2b54b401246efb04d + md5: 58ad6f35e45eca7db0fd5da95aafc693 depends: - python >=3.10 license: Apache-2.0 license_family: Apache purls: - pkg:pypi/trove-classifiers?source=hash-mapping - size: 19707 - timestamp: 1768550221435 + size: 20076 + timestamp: 1778229720640 - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda sha256: eece5be81588c39a855a0b70da84e0febb878a6d91dd27d6d21370ce9e5c5a46 md5: c2db35b004913ec69bcac64fb0783de0 @@ -10106,42 +10022,43 @@ packages: - pkg:pypi/twine?source=hash-mapping size: 42488 timestamp: 1757013705407 -- conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.24.0-pyhcf101f3_0.conda - sha256: e1116d08e6a55b2b42a090130c268f75211ad8e6a8e7749e977924de3864d487 - md5: 10870929f587540c5802cd9b071cba5c +- conda: https://conda.anaconda.org/conda-forge/noarch/typer-0.25.1-pyhcf101f3_0.conda + sha256: 18fc3a27bc995318d09142fe16d01ea454e76f377bf8f68db03b8b18f11085ed + md5: ef114c2eb2ff19f6bf616c81f4710841 depends: - annotated-doc >=0.0.2 - click >=8.2.1 - python >=3.10 - - rich >=12.3.0 + - rich >=13.8.0 - shellingham >=1.3.0 - python license: MIT license_family: MIT purls: - pkg:pypi/typer?source=hash-mapping - size: 117860 - timestamp: 1771292312899 -- conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20250915-pyhd8ed1ab_1.conda - sha256: ba565f80b5dc5d88f34587b391f21807efd54099516f11beae5cb29a7925fd3d - md5: 0fcb42ddc8e8ba6f906274108e6d891d + size: 118013 + timestamp: 1777583624586 +- conda: https://conda.anaconda.org/conda-forge/noarch/types-pyyaml-6.0.12.20260510-pyhcf101f3_0.conda + sha256: 5cdf41d2b0917682de9b3abab396f6786bea55ad77e8c2983b5913c7af830f91 + md5: 861a0152a30bbf78c64e993ef37b8d55 depends: - python >=3.10 + - python license: Apache-2.0 AND MIT purls: - pkg:pypi/types-pyyaml?source=hash-mapping - size: 22060 - timestamp: 1762942278334 -- conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20251009-pyhd8ed1ab_0.conda - sha256: a52ccb2911bbd8f33f21b556cd541fccc21158e375a1079302800ca98d621ed6 - md5: 79dc12ee42f2ab1ed6df2b7ad1a7f8ec + size: 26884 + timestamp: 1778395529048 +- conda: https://conda.anaconda.org/conda-forge/noarch/types-six-1.17.0.20260408-pyhd8ed1ab_0.conda + sha256: f79c5c87dab85928764ff37d4e6d92cc669e0072e20d881253ec8c408f3042e9 + md5: f95e48faf730b074e4bb9643be736901 depends: - python >=3.10 license: Apache-2.0 AND MIT purls: - pkg:pypi/types-six?source=hash-mapping - size: 26048 - timestamp: 1759983060635 + size: 26590 + timestamp: 1775652207617 - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c md5: edd329d7d3a4ab45dcf905899a7a6115 @@ -10152,18 +10069,19 @@ packages: purls: [] size: 91383 timestamp: 1756220668932 -- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhd8ed1ab_1.conda - sha256: 70db27de58a97aeb7ba7448366c9853f91b21137492e0b4430251a1870aa8ff4 - md5: a0a4a3035667fc34f29bfbd5c190baa6 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda + sha256: 8b90d2f19f9458b8c58a55e1fcdc1d90c1603a847a47654d8a454549413ba60a + md5: 53f5409c5cfd6c5a66417d68e3f0a864 depends: - python >=3.10 - typing_extensions >=4.12.0 + - python license: MIT license_family: MIT purls: - pkg:pypi/typing-inspection?source=hash-mapping - size: 18923 - timestamp: 1764158430324 + size: 20935 + timestamp: 1777105465795 - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 md5: 0caa1af407ecff61170c9437a808404d @@ -10223,7 +10141,7 @@ packages: license: Apache-2.0 license_family: Apache purls: - - pkg:pypi/unicodedata2?source=compressed-mapping + - pkg:pypi/unicodedata2?source=hash-mapping size: 409682 timestamp: 1770909108616 - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda @@ -10237,7 +10155,7 @@ packages: license: Apache-2.0 license_family: Apache purls: - - pkg:pypi/unicodedata2?source=compressed-mapping + - pkg:pypi/unicodedata2?source=hash-mapping size: 410641 timestamp: 1770909099497 - conda: https://conda.anaconda.org/conda-forge/linux-64/unixodbc-2.3.14-h69e2008_0.conda @@ -10253,9 +10171,9 @@ packages: purls: [] size: 307887 timestamp: 1764772751439 -- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda - sha256: af641ca7ab0c64525a96fd9ad3081b0f5bcf5d1cbb091afb3f6ed5a9eee6111a - md5: 9272daa869e03efe68833e3dc7a02130 +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda + sha256: feff959a816f7988a0893201aa9727bbb7ee1e9cec2c4f0428269b489eb93fb4 + md5: cbb88288f74dbe6ada1c6c7d0a97223e depends: - backports.zstd >=1.0.0 - brotli-python >=1.2.0 @@ -10266,8 +10184,8 @@ packages: license_family: MIT purls: - pkg:pypi/urllib3?source=hash-mapping - size: 103172 - timestamp: 1767817860341 + size: 103560 + timestamp: 1778188657149 - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda sha256: 26e53b42f7fa1127e6115a35b91c20e15f75984648b88f115136f27715d4a440 md5: 946e3571aaa55e0870fec0dea13de3bf @@ -10287,19 +10205,19 @@ packages: purls: [] size: 14226 timestamp: 1767012219987 -- conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.2-h0f56927_0.conda - sha256: 3eccb34638bb0b098cd80fda1373e1c36c4558cd46f2c247ad606a3dfeaca042 - md5: b2abfeb6b60fa2d5c55acb56d44accfc +- conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.11.13-h29f5ae7_0.conda + sha256: 935f3da1d65e8e6b5072d301e6dad162b1496539551aa97315692d570d3e2804 + md5: 80539aee0f21ffab72cf662ffcc9d005 depends: + - libstdcxx >=14 - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - libstdcxx >=14 constrains: - __glibc >=2.17 license: Apache-2.0 OR MIT purls: [] - size: 19158475 - timestamp: 1774572345053 + size: 19133005 + timestamp: 1778474103544 - conda: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.3.0-pyhd8ed1ab_0.conda sha256: 4b9a3f6738ab6e241b12b2fe9258f7e051678b911ca0f0ab042becc29096ff51 md5: 57b96d99ac0f5a548f7001618db6a561 @@ -10314,9 +10232,9 @@ packages: - pkg:pypi/versioningit?source=hash-mapping size: 167034 timestamp: 1751113901223 -- conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda - sha256: b83246d145ba0e6814d2ed0b616293e56924e6c7d6649101f5a4f97f9e757ed1 - md5: 704c22301912f7e37d0a92b2e7d5942d +- conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.3.1-pyhcf101f3_0.conda + sha256: 8888b4725d4166ab54435ba4b6a24e9f089578301a88f8157d012dd38a88ac43 + md5: dd6a1f3ce9d1cfa8b5b1b32953a80a55 depends: - python >=3.10 - distlib >=0.3.7,<1 @@ -10329,29 +10247,31 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/virtualenv?source=compressed-mapping - size: 4647775 - timestamp: 1773133660203 -- conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.0-hca82ae8_0.conda - sha256: 33155bc8ab60dd47e5fae160c355912e130add71109cd73604adc4117325a137 - md5: 5b4d69a15107ebad71ee9aaf76c4b09e + - pkg:pypi/virtualenv?source=hash-mapping + size: 5154970 + timestamp: 1777964652524 +- conda: https://conda.anaconda.org/conda-forge/linux-64/viskores-1.1.1-cpu_hc82bd48_0.conda + sha256: 2ebe8d6ae8c302ca5bf4aec532cd75ebfb00240db1c14dad9a91bace65aa083d + md5: 24676eb7fd23ea3d8d69417f5f1224e0 depends: - libstdcxx >=14 - libgcc >=14 - __glibc >=2.17,<3.0.a0 - _openmp_mutex >=4.5 - - zfp >=1.0.1,<2.0a0 - - glew >=2.2.0,<2.3.0a0 - - mesalib >=25.0.5,<25.1.0a0 - hdf5 >=1.14.6,<1.14.7.0a0 + - mesalib >=26.0.3,<26.1.0a0 + - glew >=2.3.0,<2.4.0a0 + - zfp >=1.0.1,<2.0a0 + track_features: + - viskores-p-0 license: BSD-3-Clause license_family: BSD purls: [] - size: 25057909 - timestamp: 1765513310183 -- conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.0-py311h37e4f33_4.conda - sha256: aec90d42e4c7da4262cd08d80fa30129f341bf50e3fc66e2e8acd2f49a2c2b1d - md5: 1813d4cd35b75500ac5a4008d9166bc8 + size: 25058279 + timestamp: 1777494673829 +- conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.1-py311h0f46057_4.conda + sha256: 63d67e6313743b6f9147935f9213b05664ef4f85b52146d1ddc1c630b016f397 + md5: 90b75797aa2125e99b3f1a4ac7eac495 depends: - python - utfcpp @@ -10363,50 +10283,50 @@ packages: - __glibc >=2.17,<3.0.a0 - libstdcxx >=14 - libgcc >=14 - - libopengl >=1.7.0,<2.0a0 - - libfreetype >=2.14.2 - - libfreetype6 >=2.14.2 - - double-conversion >=3.4.0,<3.5.0a0 - - fmt >=12.1.0,<12.2.0a0 + - proj >=9.8.1,<9.9.0a0 + - qt6-main >=6.11.0,<6.12.0a0 + - libfreetype >=2.14.3 + - libfreetype6 >=2.14.3 + - libglvnd >=1.7.0,<2.0a0 - hdf5 >=1.14.6,<1.14.7.0a0 - - libnetcdf >=4.10.0,<4.10.1.0a0 - - lz4-c >=1.10.0,<1.11.0a0 - - libtiff >=4.7.1,<4.8.0a0 - - libxml2 - - libxml2-16 >=2.14.6 - - pugixml >=1.15,<1.16.0a0 - - viskores >=1.1.0,<1.2.0a0 + - gl2ps >=1.4.2,<1.4.3.0a0 + - libjpeg-turbo >=3.1.4.1,<4.0a0 - python_abi 3.11.* *_cp311 - - libogg >=1.3.5,<1.4.0a0 + - libtiff >=4.7.1,<4.8.0a0 + - libzlib >=1.3.2,<2.0a0 + - jsoncpp >=1.9.6,<1.9.7.0a0 - tbb >=2022.3.0 + - eigen-abi >=5.0.1.80,<5.0.1.81.0a0 - xorg-libxcursor >=1.2.3,<2.0a0 + - libsqlite >=3.53.1,<4.0a0 + - libnetcdf >=4.10.0,<4.10.1.0a0 + - libopengl >=1.7.0,<2.0a0 - libtheora >=1.1.1,<1.2.0a0 - - libjpeg-turbo >=3.1.2,<4.0a0 - - liblzma >=5.8.2,<6.0a0 - - jsoncpp >=1.9.6,<1.9.7.0a0 + - libexpat >=2.8.0,<3.0a0 + - pugixml >=1.15,<1.16.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - viskores >=1.1.1,<1.2.0a0 + - double-conversion >=3.4.0,<3.5.0a0 + - libpng >=1.6.58,<1.7.0a0 + - fmt >=12.1.0,<12.2.0a0 - xorg-libx11 >=1.8.13,<2.0a0 - - libpng >=1.6.55,<1.7.0a0 - - libglvnd >=1.7.0,<2.0a0 - - proj >=9.8.0,<9.9.0a0 + - liblzma >=5.8.3,<6.0a0 + - libogg >=1.3.5,<1.4.0a0 - libglx >=1.7.0,<2.0a0 - - libexpat >=2.7.4,<3.0a0 - - eigen-abi >=5.0.1.80,<5.0.1.81.0a0 - - libsqlite >=3.52.0,<4.0a0 - - libzlib >=1.3.1,<2.0a0 - libglu >=9.0.3,<9.1.0a0 - - qt6-main >=6.10.2,<6.11.0a0 - - gl2ps >=1.4.2,<1.4.3.0a0 constrains: - - libboost-headers >=1.88.0,<1.89.0a0 + - libboost-headers >=1.90.0,<1.91.0a0 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/vtk?source=hash-mapping - size: 85559557 - timestamp: 1773872703615 -- conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.0-py312h64f160b_4.conda - sha256: b39b8d46aae8caff5e6eb9de93023e3738cf6381fce6bfb2e1da4e2e3f03c8a2 - md5: 8a400b17fbc6066f0fee409886eb04ad + size: 85636724 + timestamp: 1778024922852 +- conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.6.1-py312hb8f95c7_4.conda + sha256: a662c9e086c2d40aecc900d93e1b2a22ba193fe15c262f6001da3015a8ce3f8e + md5: 0910787812203a454f4a48bce5a6f331 depends: - python - utfcpp @@ -10415,50 +10335,50 @@ packages: - numpy - wslink - matplotlib-base >=2.0.0 + - __glibc >=2.17,<3.0.a0 - libstdcxx >=14 - libgcc >=14 - - __glibc >=2.17,<3.0.a0 - - eigen-abi >=5.0.1.80,<5.0.1.81.0a0 - - libglvnd >=1.7.0,<2.0a0 - - hdf5 >=1.14.6,<1.14.7.0a0 - - viskores >=1.1.0,<1.2.0a0 - - libtheora >=1.1.1,<1.2.0a0 - - libzlib >=1.3.1,<2.0a0 - - gl2ps >=1.4.2,<1.4.3.0a0 - - lz4-c >=1.10.0,<1.11.0a0 - - libxml2 - - libxml2-16 >=2.14.6 - - libexpat >=2.7.4,<3.0a0 - - fmt >=12.1.0,<12.2.0a0 - - jsoncpp >=1.9.6,<1.9.7.0a0 - tbb >=2022.3.0 - - libopengl >=1.7.0,<2.0a0 - - xorg-libx11 >=1.8.13,<2.0a0 - - libsqlite >=3.52.0,<4.0a0 - - xorg-libxcursor >=1.2.3,<2.0a0 - - liblzma >=5.8.2,<6.0a0 + - fmt >=12.1.0,<12.2.0a0 - libtiff >=4.7.1,<4.8.0a0 - - libfreetype >=2.14.2 - - libfreetype6 >=2.14.2 - - libpng >=1.6.55,<1.7.0a0 - - libogg >=1.3.5,<1.4.0a0 - - pugixml >=1.15,<1.16.0a0 - - proj >=9.8.0,<9.9.0a0 - - libjpeg-turbo >=3.1.2,<4.0a0 + - proj >=9.8.1,<9.9.0a0 - libglu >=9.0.3,<9.1.0a0 + - libexpat >=2.8.0,<3.0a0 + - libxml2 + - libxml2-16 >=2.14.6 - python_abi 3.12.* *_cp312 - - double-conversion >=3.4.0,<3.5.0a0 + - libogg >=1.3.5,<1.4.0a0 + - libsqlite >=3.53.1,<4.0a0 + - libfreetype >=2.14.3 + - libfreetype6 >=2.14.3 + - liblzma >=5.8.3,<6.0a0 + - gl2ps >=1.4.2,<1.4.3.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - viskores >=1.1.1,<1.2.0a0 - libnetcdf >=4.10.0,<4.10.1.0a0 - - qt6-main >=6.10.2,<6.11.0a0 + - libjpeg-turbo >=3.1.4.1,<4.0a0 + - double-conversion >=3.4.0,<3.5.0a0 + - libglvnd >=1.7.0,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - libopengl >=1.7.0,<2.0a0 + - eigen-abi >=5.0.1.80,<5.0.1.81.0a0 + - jsoncpp >=1.9.6,<1.9.7.0a0 + - xorg-libx11 >=1.8.13,<2.0a0 + - pugixml >=1.15,<1.16.0a0 + - hdf5 >=1.14.6,<1.14.7.0a0 + - libpng >=1.6.58,<1.7.0a0 + - qt6-main >=6.11.0,<6.12.0a0 + - xorg-libxcursor >=1.2.3,<2.0a0 - libglx >=1.7.0,<2.0a0 + - libtheora >=1.1.1,<1.2.0a0 constrains: - - libboost-headers >=1.88.0,<1.89.0a0 + - libboost-headers >=1.90.0,<1.91.0a0 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/vtk?source=hash-mapping - size: 85577217 - timestamp: 1773872746186 + size: 85627117 + timestamp: 1778024918008 - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda sha256: ea374d57a8fcda281a0a89af0ee49a2c2e99cc4ac97cf2e2db7064e74e764bdb md5: 996583ea9c796e5b915f7d7580b51ea6 @@ -10473,17 +10393,17 @@ packages: purls: [] size: 334139 timestamp: 1773959575393 -- conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - sha256: e298b508b2473c4227206800dfb14c39e4b14fd79d4636132e9e1e4244cdf4aa - md5: c3197f8c0d5b955c904616b716aca093 +- conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.7.0-pyhd8ed1ab_0.conda + sha256: 1ee2d8384972ecbf8630ce8a3ea9d16858358ad3e8566675295e66996d5352da + md5: eb9538b8e55069434a18547f43b96059 depends: - python >=3.10 license: MIT license_family: MIT purls: - pkg:pypi/wcwidth?source=hash-mapping - size: 71550 - timestamp: 1770634638503 + size: 82917 + timestamp: 1777744489106 - conda: https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-pyhd8ed1ab_3.conda sha256: 19ff205e138bb056a46f9e3839935a2e60bd1cf01c8241a5e172a422fed4f9c6 md5: 2841eb5bfc75ce15e9a0054b98dcd64d @@ -10495,9 +10415,9 @@ packages: - pkg:pypi/webencodings?source=hash-mapping size: 15496 timestamp: 1733236131358 -- conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda - sha256: d6cf2f0ebd5e09120c28ecba450556ce553752652d91795442f0e70f837126ae - md5: bdbd7385b4a67025ac2dba4ef8cb6a8f +- conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda + sha256: 9e156ffaefb8463437144326ada4b85d1de17961b9997ac5f1cbbaf747bd8bed + md5: d0e3b2f0030cf4fca58bde71d246e94c depends: - packaging >=24.0 - python >=3.10 @@ -10505,8 +10425,8 @@ packages: license_family: MIT purls: - pkg:pypi/wheel?source=hash-mapping - size: 31858 - timestamp: 1769139207397 + size: 33491 + timestamp: 1776878563806 - conda: https://conda.anaconda.org/conda-forge/noarch/wslink-2.5.6-pyhd8ed1ab_0.conda sha256: 0754558be231485ee835b0db11bace246ecd5465143a355029b039803ea716b0 md5: d34454e27bb9ec7025cefccfa92908ad @@ -10882,7 +10802,7 @@ packages: license: Apache-2.0 license_family: Apache purls: - - pkg:pypi/yarl?source=compressed-mapping + - pkg:pypi/yarl?source=hash-mapping size: 149070 timestamp: 1772409506948 - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.23.0-py312h8a5da7c_0.conda @@ -10929,9 +10849,9 @@ packages: purls: [] size: 277694 timestamp: 1766549572069 -- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda - sha256: b4533f7d9efc976511a73ef7d4a2473406d7f4c750884be8e8620b0ce70f4dae - md5: 30cd29cb87d819caead4d55184c1d115 +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.1-pyhcf101f3_0.conda + sha256: 523616c0530d305d2216c2b4a8dfd3872628b60083255b89c5e0d8c42e738cca + md5: e1c36c6121a7c9c76f2f148f1e83b983 depends: - python >=3.10 - python @@ -10939,8 +10859,8 @@ packages: license_family: MIT purls: - pkg:pypi/zipp?source=hash-mapping - size: 24194 - timestamp: 1764460141901 + size: 24461 + timestamp: 1776131454755 - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.conda sha256: 245c9ee8d688e23661b95e3c6dd7272ca936fabc03d423cdb3cdee1bbcf9f2f2 md5: c2a01a08fc991620a74b32420e97868a diff --git a/pyproject.toml b/pyproject.toml index 16867f996..09c9032b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -302,6 +302,9 @@ pyrs = { cmd = "pyrsplot", description = "Start the pyrs application" } ignore_missing_imports = true namespace_packages = true +[tool.pytest.ini_options] +norecursedirs = ["tests/scripts/cis_tests"] + [tool.ruff] line-length = 119 target-version = "py311" @@ -310,5 +313,9 @@ exclude = ["pyrs/icons", "scripts"] [tool.ruff.lint] select = ["E4", "E7", "E9", "F"] +[tool.ruff.lint.per-file-ignores] +# WARNING: there are multiple `conftest.py` files! +"**/conftest.py" = ["F401"] + [tool.ruff.format] line-ending = "lf" diff --git a/pyrs/calibration/mantid_peakfit_calibration.py b/pyrs/calibration/mantid_peakfit_calibration.py index 57c5c513b..5b9cc31d9 100644 --- a/pyrs/calibration/mantid_peakfit_calibration.py +++ b/pyrs/calibration/mantid_peakfit_calibration.py @@ -65,7 +65,7 @@ def __init__( else: self._hidra_ws = reduction_engine - self.initalize_calib_arrays() + self.initialize_calib_arrays() # Initalize calibration status to -1 self._calibstatus = -1 @@ -217,7 +217,7 @@ def get_powder_lines(self): self._diff_peaks["BCC"] = np.sqrt(np.array([2, 4, 6, 8, 10, 12])) self._diff_peaks["FCC"] = np.sqrt(np.array([3, 4, 8, 11, 12, 19])) - def initalize_calib_arrays(self): + def initialize_calib_arrays(self): # calibration: numpy array. size as 7 for ... [6] for wave length self._calib = np.array(8 * [0], dtype=np.float64) # calibration error: numpy array. size as 7 for ... diff --git a/pyrs/core/instrument_geometry.py b/pyrs/core/instrument_geometry.py index c3b1f3f5c..b2f1574df 100644 --- a/pyrs/core/instrument_geometry.py +++ b/pyrs/core/instrument_geometry.py @@ -41,6 +41,11 @@ def get_instrument_geometry(self, calibrated): :param calibrated: Bool :return GeometrySetup: Geometry setup parameters """ + # TODO: this next `if calibrated...` clause has some serious issues: + # (1) `apply_shift` returns `None`. + # (2) Potentially, shift will be applied multiple times. + # (3) Non-calibrated _geometry_setup is modified: + # what happens if the next call has `calibrated = False`? if calibrated and self._geometry_shift is not None: return self._geometry_setup.apply_shift(self._geometry_shift) diff --git a/pyrs/core/peak_profile_utility.py b/pyrs/core/peak_profile_utility.py index 15ff1918a..aebd3f16b 100644 --- a/pyrs/core/peak_profile_utility.py +++ b/pyrs/core/peak_profile_utility.py @@ -43,8 +43,8 @@ def native_parameters(self): class BackgroundFunction(Enum): - LINEAR = "Linear" # so far, one and only supported - QUADRATIC = "Quadratic" # so far, one and only supported + LINEAR = "Linear" + QUADRATIC = "Quadratic" def __str__(self): return self.value @@ -72,7 +72,7 @@ def native_parameters(self): def get_parameter_dtype(peak_shape=None, background_function=None, effective=False): - """Convert the peak parameters into a dtype to ge used in numpy constructors + """Convert the peak parameters into a dtype to be used in numpy constructors ``np.zeros(NUM_SUBRUN, dtype=get_parameter_dtype('Gaussian'))`` """ @@ -115,7 +115,7 @@ def get_effective_parameters_converter(peak_profile): class PeakParametersConverter: - """Virtual base class to convert peak parameters from native to effective""" + """Virtual base class to convert peak parameters from native to effective or vice versa""" def __init__(self, peak_shape): """Initialization""" @@ -147,6 +147,25 @@ def calculate_effective_parameters(self, param_value_array, param_error_array): """ raise NotImplementedError("Virtual") + def calculate_native_parameters(self, eff_value_array, eff_error_array): + """Calculate native peak parameter values from effective parameters. + + This is the inverse of calculate_effective_parameters. + + Parameters + ---------- + eff_value_array : numpy.ndarray + structured array with effective parameter values + eff_error_array : numpy.ndarray + structured array with effective parameter errors + + Returns + ------- + np.ndarray, np.ndarray + structured arrays for native parameter values and errors + """ + raise NotImplementedError("Virtual") + class Gaussian(PeakParametersConverter): """ @@ -238,6 +257,62 @@ def calculate_effective_parameters(self, param_value_array, param_error_array): return eff_value_array, eff_error_array + def calculate_native_parameters(self, eff_value_array, eff_error_array): + """Inverse of calculate_effective_parameters for Gaussian. + + Effective → Native mapping: + PeakCentre = Center + Height = Height + Sigma = FWHM / (2 * sqrt(2 * ln(2))) + + Intensity is discarded (it was derived from Height and Sigma). + + Error propagation: + σ(PeakCentre) = σ(Center) + σ(Height) = σ(Height) + σ(Sigma) = σ(FWHM) / (2 * sqrt(2 * ln(2))) + """ + # Input validation + if eff_value_array.dtype != eff_error_array.dtype: + raise RuntimeError( + "dtype of values and errors do not match: {} and {}".format( + eff_value_array.dtype, eff_error_array.dtype + ) + ) + if eff_value_array.size != eff_error_array.size: + raise RuntimeError( + "size of values and errors do not match: {} and {}".format(eff_value_array.size, eff_error_array.size) + ) + + # Determine background type + has_quadratic = np.any(np.abs(eff_value_array["A2"]) > 1e-20) + bg_func = BackgroundFunction.QUADRATIC if has_quadratic else BackgroundFunction.LINEAR + + native_dtype = get_parameter_dtype(peak_shape=PeakShape.GAUSSIAN, background_function=bg_func) + native_values = np.zeros(eff_value_array.size, dtype=native_dtype) + native_errors = np.zeros(eff_value_array.size, dtype=native_dtype) + + # Invert FWHM → Sigma + native_values["Sigma"] = self.cal_sigma(eff_value_array["FWHM"]) + native_errors["Sigma"] = self.cal_sigma(eff_error_array["FWHM"]) # linear, same scale factor + + # Direct mappings + native_values["Height"] = eff_value_array["Height"] + native_values["PeakCentre"] = eff_value_array["Center"] + native_errors["Height"] = eff_error_array["Height"] + native_errors["PeakCentre"] = eff_error_array["Center"] + + # Background + native_values["A0"] = eff_value_array["A0"] + native_values["A1"] = eff_value_array["A1"] + native_errors["A0"] = eff_error_array["A0"] + native_errors["A1"] = eff_error_array["A1"] + if has_quadratic: + native_values["A2"] = eff_value_array["A2"] + native_errors["A2"] = eff_error_array["A2"] + + return native_values, native_errors + @staticmethod def cal_intensity(height, sigma): """Calculate peak intensity (intensities) @@ -441,6 +516,61 @@ def calculate_effective_parameters(self, param_value_array, param_error_array): return eff_value_array, eff_error_array + def calculate_native_parameters(self, eff_value_array, eff_error_array): + """Inverse of calculate_effective_parameters for PseudoVoigt. + + Effective → Native mapping: + PeakCentre = Center + FWHM = FWHM + Mixing = Mixing + Intensity = Intensity + + Height is discarded (it was derived from Intensity, FWHM, Mixing). + + Error propagation: all identity (direct copy). + """ + # Input validation + if eff_value_array.dtype != eff_error_array.dtype: + raise RuntimeError( + "dtype of values and errors do not match: {} and {}".format( + eff_value_array.dtype, eff_error_array.dtype + ) + ) + if eff_value_array.size != eff_error_array.size: + raise RuntimeError( + "size of values and errors do not match: {} and {}".format(eff_value_array.size, eff_error_array.size) + ) + + # Determine background type + has_quadratic = np.any(np.abs(eff_value_array["A2"]) > 1e-20) + bg_func = BackgroundFunction.QUADRATIC if has_quadratic else BackgroundFunction.LINEAR + + native_dtype = get_parameter_dtype(peak_shape=PeakShape.PSEUDOVOIGT, background_function=bg_func) + native_values = np.zeros(eff_value_array.size, dtype=native_dtype) + native_errors = np.zeros(eff_value_array.size, dtype=native_dtype) + + # All native PseudoVoigt params are direct from effective + native_values["Mixing"] = eff_value_array["Mixing"] + native_values["Intensity"] = eff_value_array["Intensity"] + native_values["PeakCentre"] = eff_value_array["Center"] + native_values["FWHM"] = eff_value_array["FWHM"] + + native_errors["Mixing"] = eff_error_array["Mixing"] + native_errors["Intensity"] = eff_error_array["Intensity"] + native_errors["PeakCentre"] = eff_error_array["Center"] + native_errors["FWHM"] = eff_error_array["FWHM"] + + # Background + native_values["A0"] = eff_value_array["A0"] + native_values["A1"] = eff_value_array["A1"] + native_errors["A0"] = eff_error_array["A0"] + native_errors["A1"] = eff_error_array["A1"] + if has_quadratic: + native_values["A2"] = eff_value_array["A2"] + native_errors["A2"] = eff_error_array["A2"] + + return native_values, native_errors + @staticmethod def cal_height(intensity, fwhm, mixing): """Calculate peak height from I(intensity), Gamma (fwhm) and eta (mixing) @@ -494,7 +624,6 @@ def cal_height_error(intensity, intensity_error, fwhm, fwhm_error, mixing, mixin mixing_factor = np.sqrt(np.pi * np.log(2)) - 1 two_inv_pi = 2.0 / np.pi - # FIXME - all the terms shall get SQUARED! # Partial derivative to intensity # partial h()/partial I = 2. * (1 + (np.sqrt(np.pi * np.log(2)) - 1) * mixing) / (np.pi * fwhm) # = (2 / np.pi) * (1 + F1 * mixing) / fwhm @@ -640,7 +769,9 @@ def gaussian(x, a, sigma, x0): :param x0: :return: """ - return a * np.exp(-(((x - x0) / sigma) ** 2)) + # THIS WAS corrected (11.02.2026) so that it matches the convention used in the rest of this module, + # and throughout the Mantid codebase. + return a * np.exp(-0.5 * ((x - x0) / sigma) ** 2) def pseudo_voigt(x, intensity, fwhm, mixing, x0): diff --git a/pyrs/core/workspaces.py b/pyrs/core/workspaces.py index e075d61e5..729485fd5 100644 --- a/pyrs/core/workspaces.py +++ b/pyrs/core/workspaces.py @@ -420,9 +420,9 @@ def get_wavelength(self, calibrated, throw_if_not_set, sub_run=None): calibrated : bool whether the wave length is calibrated or raw throw_if_not_set : bool - throw an exception if wave length is not set to workspace + throw an exception if wave length is not set on the workspace sub_run : None or int - sub run number for the wave length associated with + sub run number for the wave length Returns ------- @@ -1190,6 +1190,73 @@ def set_wavelength(self, wave_length, calibrated): else: self._wave_length_dict = wl_dict + def set_sample_logs_from_object(self, sample_logs): + """Replace the current sample logs with the provided SampleLogs object. + + Parameters + ---------- + sample_logs : SampleLogs + Complete SampleLogs object to set + + Returns + ------- + None + """ + self._sample_logs = sample_logs + + def set_wavelength_from_value(self, wavelength): + """Set the universal wavelength (not per-subrun). + + Parameters + ---------- + wavelength : float + Wavelength value to set + + Returns + ------- + None + """ + self._wave_length = wavelength + + def set_reduced_diffraction_data_set(self, two_theta_matrix, diff_data_set, var_data_set): + """Set the full reduced diffraction data matrices directly. + + Parameters + ---------- + two_theta_matrix : np.ndarray + 2D array, shape (n_subruns, n_2theta) + diff_data_set : dict + {mask_id: np.ndarray} intensity matrices + var_data_set : dict + {mask_id: np.ndarray} variance matrices + + Returns + ------- + None + """ + self._2theta_matrix = np.copy(two_theta_matrix) + self._diff_data_set = {k: np.copy(v) for k, v in diff_data_set.items()} + self._var_data_set = {k: np.copy(v) for k, v in var_data_set.items()} + + def set_masks_from_dict(self, default_mask, mask_dict): + """Set detector masks from explicit arrays. + + Parameters + ---------- + default_mask : np.ndarray or None + Default mask array, or None if no default + mask_dict : dict + {mask_name: mask_array} + + Returns + ------- + None + """ + if default_mask is not None: + self.set_detector_mask(default_mask, True) + for name, arr in mask_dict.items(): + self.set_detector_mask(arr, False, name) + def reset_diffraction_data(self): """Reset the data structures to store the diffraction data set diff --git a/pyrs/dataobjects/constants.py b/pyrs/dataobjects/constants.py index 1e496016d..b262fd405 100644 --- a/pyrs/dataobjects/constants.py +++ b/pyrs/dataobjects/constants.py @@ -57,3 +57,9 @@ class HidraConstants: # Special sample logs SUB_RUN_DURATION = "sub-run duration" # units in seconds SAMPLE_COORDINATE_NAMES = ("vx", "vy", "vz") + SAMPLE_NAME = "SampleName" + SAMPLE_DESCRIPTION = "SampleDescription" + CHEMICAL_FORMULA = "chemical formula" + TEMPERATURE = "temperature" + STRESS_FIELD = "stress field" + STRESS_FIELD_DIRECTION = "stress field direction" diff --git a/pyrs/dataobjects/sample_logs.py b/pyrs/dataobjects/sample_logs.py index d57559884..42ccb572f 100644 --- a/pyrs/dataobjects/sample_logs.py +++ b/pyrs/dataobjects/sample_logs.py @@ -348,24 +348,25 @@ def __setitem__( r""" Initialize/update the subruns instance, or insert/update the value of a log entry - `value` is coerced into a numpy array, which could be a one-item array if passing an int of float. + `value` is coerced into a numpy array, which could be a one-item array if passing an int or float. Parameters ---------- key: str, tuple - If `str`, then name of the log value, or dedicated string 'sub-runs'. It `tuple`, then the - first item is the same as previously, and the second item is a string representing the log units. - value: int, flat, list, np.ndarray, ~pyrs.dataobjects.sample_logs.Subruns - A list of subrun numbers of the values of a log entry + If `str`, then name of the log entry, or dedicated string 'sub-runs'. If `tuple`, then the + first item is the same as previously, and the second item is a string representing the units + of the log entry's value. + value: int, float, list, np.ndarray, ~pyrs.dataobjects.sample_logs.Subruns + A list, in subrun order, of the values of a log entry Raises ------ ValueError Attempt to insert/update the value of a log entry prior to initialization of the - selected subruns list + number of subruns ValueError - Attempt to insert/update the value of a log entry with a list of different size - then the selected subruns list + Attempt to insert/update the value of a log entry with a list of different length + then the number of subruns """ if isinstance(key, str): log_name = key @@ -379,10 +380,13 @@ def __setitem__( if self._subruns.size == 0: raise RuntimeError("Must set subruns first") elif isinstance(value, np.ndarray): - if value.size != self.subruns.size: + # 17.02.2026: Modified this to allow log entries to be non-scalar: + # this seemed to be consistent with what was intended by the original design. + # For a `numpy.ndarray` `len` returns the number of rows (i.e. the length of the first axis). + if len(value) != self.subruns.size: raise ValueError( - "Number of values[{}] isn't the same as number of subruns[{}]".format( - value.size, self.subruns.size + "Number of values (or value rows)[{}] isn't the same as number of subruns[{}]".format( + len(value), self.subruns.size ) ) else: diff --git a/pyrs/interface/ui/mplfitplottingwidget.py b/pyrs/interface/ui/mplfitplottingwidget.py index 0a098f3ef..8d1b43a6c 100644 --- a/pyrs/interface/ui/mplfitplottingwidget.py +++ b/pyrs/interface/ui/mplfitplottingwidget.py @@ -138,8 +138,14 @@ def _validate_second_point(self, x=np.nan): if _working_range[0] == x: # remove this range self.list_peak_ranges.remove([_working_range[0], np.nan]) [left_peak, right_peak] = self.list_peak_ranges_matplotlib_id[self._working_with_range_index] - left_peak.remove() - right_peak.remove() + try: + left_peak.remove() + except NotImplementedError: + pass + try: + right_peak.remove() + except NotImplementedError: + pass self.list_peak_ranges_matplotlib_id.remove([left_peak, right_peak]) _peak_label = self.list_fit_peak_labels[self._working_with_range_index] self.list_fit_peak_labels.remove(_peak_label) @@ -272,11 +278,20 @@ def plot_diff_data(self, data_set, color=None, line_label=""): def plot_data_with_fitting_ranges(self): for _peak_label in self.list_peak_labels_matplotlib_id: - _peak_label.remove() + try: + _peak_label.remove() + except NotImplementedError: + pass for [_left_line, _right_line] in self.list_peak_ranges_matplotlib_id: - _left_line.remove() - _right_line.remove() + try: + _left_line.remove() + except NotImplementedError: + pass + try: + _right_line.remove() + except NotImplementedError: + pass data_set = self._data_set line_label = self._line_label @@ -308,11 +323,20 @@ def plot_data_fitting_ranges(self): # self.clear_canvas() for _peak_label in self.list_peak_labels_matplotlib_id: - _peak_label.remove() + try: + _peak_label.remove() + except NotImplementedError: + pass for [_left_line, _right_line] in self.list_peak_ranges_matplotlib_id: - _left_line.remove() - _right_line.remove() + try: + _left_line.remove() + except NotImplementedError: + pass + try: + _right_line.remove() + except NotImplementedError: + pass x_min = self._data_set[0].min() x_max = self._data_set[0].max() diff --git a/pyrs/peaks/peak_collection.py b/pyrs/peaks/peak_collection.py index 843a66c55..24c0be6f9 100644 --- a/pyrs/peaks/peak_collection.py +++ b/pyrs/peaks/peak_collection.py @@ -8,6 +8,7 @@ BackgroundFunction, ) from pyrs.dataobjects import SubRuns # type: ignore +from pyrs.dataobjects.constants import HidraConstants from typing import Tuple, Union from uncertainties import unumpy from uncertainties import ufloat @@ -242,6 +243,8 @@ def __init__( d_reference_error: Union[float, np.ndarray] = 0.0, projectfilename: str = "", runnumber: int = -1, + *, + mask: str = HidraConstants.DEFAULT_MASK, ) -> None: """Initialization @@ -257,6 +260,7 @@ def __init__( """ # Init variables from input self._tag = peak_tag + self._mask = mask self._filename: str = "" self.projectfilename = projectfilename # use the setter self._runnumber: int = runnumber @@ -299,6 +303,18 @@ def peak_tag(self) -> str: """ return self._tag + @property + def mask(self) -> str: + """Mask name + + Returns + ------- + str + Mask name + + """ + return self._mask + @property def peak_profile(self) -> str: """Get peak profile name @@ -373,7 +389,10 @@ def __convertParameters(self, parameters): raise RuntimeError(msg) converted = np.zeros(parameters.size, get_parameter_dtype(self._peak_profile, self._background_type)) for name in converted.dtype.names: - converted[name] = parameters[name] + # Only copy fields that exist in the input parameters + if name in supplied_names: + converted[name] = parameters[name] + # Fields not in input (e.g., A2 for Linear background) remain zero return converted @@ -468,7 +487,7 @@ def get_strain(self, units: str = "strain") -> Tuple[np.ndarray, np.ndarray]: d_reference_errors, ) - # multiplying by 1e6 converts to micro + # multiplying by 1.0e6 converts to micro strain = conversion_factor * (d_fitted - safe_d_reference) / safe_d_reference # unpack the values to return diff --git a/pyrs/projectfile/file_object.py b/pyrs/projectfile/file_object.py index 9bd518bb2..49ca2d438 100644 --- a/pyrs/projectfile/file_object.py +++ b/pyrs/projectfile/file_object.py @@ -80,6 +80,18 @@ def __init__( if self._io_mode == HidraProjectFileMode.OVERWRITE: self._init_project() + ###################################### + ## Context-manager support methods: ## + ###################################### + def __enter__(self) -> "HidraProjectFile": + return self + + def __exit__(self, exc_type, exc, tb): + self.close() + return False # do not suppress exceptions + + ###################################### + def _checkFileAccess(self): """Verify the file has the correct acces permissions and set the value of ``self._is_writable``""" # prepare the call to check the file permissions @@ -484,12 +496,18 @@ def read_diffraction_masks(self): if "2Theta" in masks: masks.remove("2Theta") + # Variance datasets are stored alongside intensity datasets with a '_var' suffix + # (e.g. 'main_var' alongside 'main'). They are not masks and must be excluded so + # that _load_reduced_diffraction_data does not treat them as intensity entries. + masks = [m for m in masks if not m.endswith("_var")] + return masks def read_instrument_geometry(self): """ Get instrument geometry parameters :return: an instance of instrument_geometry.InstrumentSetup + *** TODO: actually this returns an instance of `DENEXDetectorGeometry`! *** """ # Get group geometry_group = self._project_h5[HidraConstants.INSTRUMENT][HidraConstants.GEOMETRY_SETUP] diff --git a/pyrs/utilities/NXstress/NXstress.py b/pyrs/utilities/NXstress/NXstress.py new file mode 100644 index 000000000..38267a11b --- /dev/null +++ b/pyrs/utilities/NXstress/NXstress.py @@ -0,0 +1,336 @@ +""" +pyrs/utilities/NXstress/NXstress.py + +Primary service class for NeXus NXstress-compatible I/O. +""" + +from datetime import datetime +from nexusformat.nexus import NXdata, NXentry, NXfield, NXFile, nxopen +from pathlib import Path + +from pyrs.core.workspaces import HidraWorkspace +from pyrs.peaks.peak_collection import PeakCollection +from pyrs.utilities.pydantic_transition import validate_call_ + +from ._definitions import ( + DEFAULT_TAG, + GROUP_NAME, + group_naming_scheme, + NO_LOG, + suffix_from_group_name, + logger, + REQUIRED_LOGS, +) +from ._input_data import _InputData +from ._instrument import _Instrument, _Masks +from ._sample import _Sample +from ._fit import _Fit, _Diffractogram +from ._peaks import _Peaks + + +""" +REQUIRED PARAMETERS FOR NXstress: +--------------------------------- + +/ (NXentry, group) +│ +├─ definition (dataset: "NXstress") +├─ start_time (dataset: ISO8601 string) +├─ end_time (dataset: ISO8601 string) +├─ processingtype (dataset: string) +│ +├─ instrument (NXinstrument, group) +│ ├─ name (dataset: string) +│ ├─ source (NXsource, group) +│ ├─ detector (NXdetector, group) +│ └─ mask (optional) (NXcollection, group) +│ +├─ sample (NXsample, group) +│ ├─ name (dataset: string) +│ ├─ chemical_formula (optional) (dataset: string) +│ ├─ temperature (optional) (dataset: string) +│ ├─ stress_field (optional) (dataset: string) +│ └─ gauge_volume (optional) (NXparameters, group) +│ +├─ fit (NXprocess, group) +│ ├─ @date (attribute: ISO8601 string) +│ ├─ @program (attribute: string) +│ ├─ description (NXnote, group) +│ ├─ peakparameters (NXparameters, group) +│ └─ diffractogram (NXdata, group) +│ ├─ diffractogram (dataset) +│ ├─ diffractogram_errors (dataset) +│ ├─ daxis/xaxis (dataset) +│ ├─ @axes (attribute: string) +│ └─ @signal (attribute: string) +│ +├─ peaks (NXreflections, group) +│ ├─ h (dataset) +│ ├─ k (dataset) +│ ├─ l (dataset) +│ └─ phase_name (dataset) +""" + + +class NXstress: + ################################################################## + ## Service class to write NXstress-compliant NXentries: ## + ## the `write` method writes the next `NXentry` to the file. ## + ################################################################## + + ## Context-manager related methods: + def __init__(self, file_path: Path, mode: str = "r"): + self._path = str(file_path) + self._mode = mode + self._nx = NXFile(self._path, self._mode) # low-level handle + self._root = None # will *ONLY* be set in __enter__ + + def __enter__(self) -> "NXstress": + self._root = nxopen(self._path, self._mode) + if self._root is None: + raise RuntimeError( + f"Unexpected `nexusformat` error opening '{self._path}' " + f"for {'read' if 'r' in self._mode else 'write'}." + ) + self._root.__enter__() + + return self + + def __exit__(self, exc_type, exc, tb): + if self._root: + self._root.__exit__(exc_type, exc, tb) + self._root = None + + # Do not suppress exceptions + return False + + def write(self, ws: HidraWorkspace, peakss: list[PeakCollection]): + # Write the _next_ NXentry to the file: + # + # -- multiple NXentry are allowed by the NXstress schema. + # -- each NXentry includes: + # + # -- [optional] input_data: raw detector counts, indexed by 'scan_point' (aka: 'subrun'); + # -- the `NXinstrument`, including its `NXdetector`, applicable `NXtransformations` + # and detector and solid-angle masks; + # -- a canonical PEAKS instance: + # + # -- peaks are indexed by: phase, (h, k, l), mask, + # (no duplicate entries are allowed) + # + # -- reduced 'diffraction_data' sections corresponding to the PEAKS entries: + # + # -- peak-fit details, indexed as for the PEAKS indices; + # -- normalized and reduced data for each mask, indexed by 'scan_point'; + # -- a calculated model spectrum: this section is still in progress. + # + + ###################################################### + ## Recommended usage: ## + ## -------------------------------------------------## + ## from pyrs/utilities/NXstress import NXstress ## + ## ... ## + ## ws: HidraWorkspace ## + ## peakss: list[PeakCollection] ## + ## ... ## + ## # To write the first (, or only) entry: ## + ## with NXstress(.nxs, 'w') as nxS: ## + ## nxS.write(f, ws, peaks) ## + ## -------------------------------------------------## + ## # To write an additional entry: ## + ## # alternatively, this could have been done ## + ## # in the first `with` clause above. ## + ## with NXfile(.nxs, 'a') as nxS: ## + ## nxS.write(f, ws, peaks) ## + ###################################################### + + if self._root is None: + raise RuntimeError("Usage error: only usage as context manager is supported!") + entry_number = len(self._root.NXentry) + 1 + entry_name = group_naming_scheme(GROUP_NAME.ENTRY, entry_number) + if entry_name in self._root: + raise RuntimeError(f"Not implemented: overwriting existing `NXentry` '/{entry_name}'.") + + entry = self.init_group(ws, peakss) + self._root[entry_name] = entry + + def read(self, entry_number: int = 1): + """Read back a (HidraWorkspace, list[PeakCollection]) from the NXstress file. + + Parameters + ---------- + entry_number : int + Which NXentry to read (1-based). Default is 1. + + Returns + ------- + tuple + (HidraWorkspace, list[PeakCollection]) + """ + # Verify context manager is active + if self._root is None: + raise RuntimeError("Usage error: only usage as context manager is supported!") + + # Resolve entry name + entry_name = group_naming_scheme(GROUP_NAME.ENTRY, entry_number) + + # Access entry + entry = self._root[entry_name] + + # Read sample logs + sample_logs = _Sample.sampleLogsFromNexus(entry[GROUP_NAME.SAMPLE_DESCRIPTION]) + + # Read instrument + geometry, shift, wavelength = _Instrument.instrumentFromNexus(entry[GROUP_NAME.INSTRUMENT]) + is_calibrated = shift is not None + + # Read masks + default_mask, mask_dict = _Masks.masksFromNexus(entry[GROUP_NAME.INSTRUMENT][GROUP_NAME.MASKS]) + + # Build workspace + ws = HidraWorkspace() + ws.set_sample_logs_from_object(sample_logs) + # `set_wavelength` expects `dict[int, float]` + ws.set_wavelength( + {subrun_index: wavelength[n] for n, subrun_index in enumerate(ws.get_sub_runs())}, is_calibrated + ) + ws.set_instrument_geometry(geometry) + if shift is not None: + ws.set_detector_shift(shift) + ws.set_masks_from_dict(default_mask, mask_dict) + + # Read raw counts if present + if GROUP_NAME.INPUT_DATA in entry: + _InputData.readSubruns(ws, entry[GROUP_NAME.INPUT_DATA]) + + # Read reduced diffraction data from FIT group's DIFFRACTOGRAM subgroups + if GROUP_NAME.FIT in entry: + fit_group = entry[GROUP_NAME.FIT] + diff_data = {} + var_data = {} + two_theta_matrix = None + + for child_name in fit_group: + child = fit_group[child_name] + if not isinstance(child, NXdata): + continue + mask_name = suffix_from_group_name(child_name, GROUP_NAME.DIFFRACTOGRAM) + scan_pts, two_theta, data, errors = _Diffractogram.diffractogramFromNexus(child) + + # Map DEFAULT_TAG to None for workspace dict keys + ws_mask_key = None if mask_name == DEFAULT_TAG else mask_name + diff_data[ws_mask_key] = data + + # NOTE: Despite the field name 'diffractogram_errors', + # variance values (not standard errors) are stored in this field. + var_data[ws_mask_key] = errors + + if two_theta_matrix is None: + two_theta_matrix = two_theta + + if two_theta_matrix is not None: + ws.set_reduced_diffraction_data_set(two_theta_matrix, diff_data, var_data) + + # Read peak collections + peak_collections = [] + if GROUP_NAME.PEAKS in entry: + peaks_group = entry[GROUP_NAME.PEAKS] + if GROUP_NAME.FIT in entry: + fit_group = entry[GROUP_NAME.FIT] + peak_collections = _Peaks.peakCollectionsFromNexus(peaks_group, fit_group) + + return ws, peak_collections + + ############################################ + # ALL non-context-manager related methods ## + # must be `classmethod`. ## + ############################################ + + @classmethod + @validate_call_ + def _validateWorkspaceAndPeaksData(cls, ws: HidraWorkspace, peakss: list[PeakCollection]): + # VERIFY that all required logs are present. + logs = ws.sample_log_names + for k in REQUIRED_LOGS: + if k not in logs: + raise ValueError(f"NXstress requires log '{k}', which is not present") + + # VERIFY that no duplicate PeakCollections exist + _Peaks.validateNoDuplicatePeaks(peakss) + + # VERIFY that any or referenced by any `PeakCollection` is included in the workspace. + _Fit.validateWorkspaceAndPeaksData(ws, peakss) + + @classmethod + @validate_call_ + def _init(cls, ws: HidraWorkspace) -> NXentry: + # Create the NXentry and initialize any required attributes. + + """ + ├─ definition (dataset: "NXstress") + ├─ start_time (dataset: ISO8601 string) + ├─ end_time (dataset: ISO8601 string) + ├─ processing_type (dataset: string) + :: apart from 'definition', these fields may also be + lists by subrun. + """ + entry = NXentry() + entry["definition"] = "NXstress" + + # lists of 'start_time', 'end_time' for all subruns + try: + start_times: list[str] = [ + datetime.fromisoformat(t.decode("utf-8")).astimezone().isoformat() + for t in ws.get_sample_log_values("start_time") + ] + end_times: list[str] = [ + datetime.fromisoformat(t.decode("utf-8")).astimezone().isoformat() + for t in ws.get_sample_log_values("end_time") + ] + except ValueError as e: + if "Invalid isoformat string" not in str(e): + raise + logger.warning( + f"Log entries for sub-run start and end times are not in ISO-8601 format:\n" + f" in order to continue writing, a value of '{NO_LOG}' will be used for all time entries!" + ) + start_times = end_times = [NO_LOG for n in ws._sample_logs.subruns] + entry["start_time"] = NXfield(start_times) + entry["end_time"] = NXfield(end_times) + + # the type of the primary strain calculation: + # this might also be 'two-theta', but 'd-spacing' seems more likely + entry["processing_type"] = "d-spacing" + + return entry + + @classmethod + @validate_call_ + def init_group(cls, ws: HidraWorkspace, peakss: list[PeakCollection]) -> NXentry: + # Create and initialize a single NXstress-compatible NXentry tree: + # _multiple_ NXentry can exist within an NXstress-compatible HDF5 file. + # For example, distinct entries might be added for each set of + # data-reduction or sample conditions. + + # Verify that all data required by NXstress are present. + cls._validateWorkspaceAndPeaksData(ws, peakss) + + # Initialize this NXentry, and add required attributes. + entry = cls._init(ws) + + # 'input_data' group + entry[GROUP_NAME.INPUT_DATA] = _InputData.init_group(ws) + + # 'instrument' group + entry[GROUP_NAME.INSTRUMENT] = _Instrument.init_group(ws) + + # 'SAMPLE_DESCRIPTION' group + entry[GROUP_NAME.SAMPLE_DESCRIPTION] = _Sample.init_group(ws._sample_logs) + + # 'FIT' group + entry[GROUP_NAME.FIT] = _Fit.init_group(ws, peakss, ws._sample_logs) + + # 'PEAKS' group + entry[GROUP_NAME.PEAKS] = _Peaks.init_group(peakss, ws._sample_logs) + + return entry diff --git a/pyrs/utilities/NXstress/__init__.py b/pyrs/utilities/NXstress/__init__.py new file mode 100644 index 000000000..98f367c85 --- /dev/null +++ b/pyrs/utilities/NXstress/__init__.py @@ -0,0 +1,10 @@ +""" +pyrs/utilities/NXstress/__init__.py + +This package implements NeXus NXstress-schema compatible I/O for PyRS. +""" +# pyrs/utilities/NXstress/__init__.py + +from .NXstress import NXstress + +__all__ = ["NXstress"] diff --git a/pyrs/utilities/NXstress/_definitions.py b/pyrs/utilities/NXstress/_definitions.py new file mode 100644 index 000000000..4c2f6e265 --- /dev/null +++ b/pyrs/utilities/NXstress/_definitions.py @@ -0,0 +1,242 @@ +""" +pyrs/utilities/NXstress/_definitions.py + +Constants and definitions used by NeXus NXstress-compatible I/O. +""" + +from enum import Enum, StrEnum +from datetime import datetime +import h5py +import logging +from nexusformat.nexus import ( + NXbeam, + NXcollection, + NXdata, + NXdetector, + NXentry, + NXfield, + NXgroup, + NXinstrument, + NXmonochromator, + NXnote, + NXparameters, + NXprocess, + NXreflections, + NXsample, + NXsource, + NXtransformations, +) +import numpy as np +from typing import List, Tuple + +from pyrs.dataobjects.constants import HidraConstants + + +logger = logging.getLogger("pyrs.utilities.NXstress") +REQUIRED_LOGS: List[str] = [] + + +class _TypeBehavior: + # Avoid metaclass conflict if mixin were derived from `type` directly. + + def __call__(self, *args, **kwargs): + # Allow calling the enum member to construct via the underlying type + return self.value(*args, **kwargs) + + def is_instance(self, obj): + return isinstance(obj, self.value) + + def is_subclass(self, cls): + return issubclass(cls, self.value) + + def __str__(self): + return self.value.__name__ + + +class FIELD_DTYPE(_TypeBehavior, Enum): + # HDF5 dataset types for various fields + FLOAT_CONSTANT = np.float64 + FLOAT_DATA = np.float32 + INT_DATA = np.int32 + STRING = h5py.string_dtype(encoding="utf-8") + + +def CHUNK_SHAPE(rank: int) -> Tuple[int, ...]: + # chunk fast-axis only + return (1,) * (rank - 1) + (100,) + + +class REQUIRED_NAME(StrEnum): + # These are *required* group or dataset names, as specified in the `NXstress` schema. + + # FIT/DIFFRACTOGRAM sub-fields: + PEAK_PARAMETERS = "peak_parameters" + BACKGROUND_PARAMETERS = "background_parameters" + DGRAM_DIFFRACTOGRAM = "diffractogram" + DGRAM_DIFFRACTOGRAM_ERRORS = "diffractogram_errors" + DGRAM_FIT = "fit" + DGRAM_FIT_ERRORS = "fit_errors" + + INSTRUMENT = "instrument" + BEAM = "beam_intensity_profile" + PEAKS = "peaks" + + +class GROUP_NAME(StrEnum): + # Group names: ordered by their appearance in the NXstress schema: + # + # -- Unless initialized from a `REQUIRED_NAME`, these may be modified as necessary. + # -- In case of multiple group instances, the enum value here becomes the , + # with the or becoming a name suffix (see `group_naming_scheme` below). + # + + # --- mypy: --- + allowMultiple: bool + nxClass: type[NXgroup] + # ------------- + + # Multiple NXentry are allowed in case there are multiple reduced data sets: + # e.g. from the same input data set, using different optimal peak-fit combinations. + ENTRY = ("entry", True, NXentry) + + INSTRUMENT = (REQUIRED_NAME.INSTRUMENT, False, NXinstrument) + CALIBRATION = ("calibration", False, NXnote) + + # SOURCE = ('source', False, NXsource) + SOURCE = ("SOURCE", False, NXsource) # *** DEBUG *** validator bug + + # DETECTOR = ('detector', True, NXdetector) + DETECTOR = ("DETECTOR", True, NXdetector) # *** DEBUG *** validator bug + + TRANSFORMATIONS = ("transformations", False, NXtransformations) + BEAM = (REQUIRED_NAME.BEAM, False, NXbeam) + MONOCHROMATOR = ("monochromator", False, NXmonochromator) + + # SAMPLE_DESCRIPTION = ('sample', False, NXsample) + SAMPLE_DESCRIPTION = ("SAMPLE_DESCRIPTION", False, NXsample) # *** DEBUG *** validator bug + + # FIT (NXprocess) groups contain the reduced data (and associated metadata): + # there should be one FIT group corresponding to each detector mask. + + # FIT = ('fit', True, NXprocess) + FIT = ("FIT", True, NXprocess) # *** DEBUG *** validator bug + + # input NXparameters subgroup in 'NXprocess' + INPUT = ("input", False, NXparameters) + + # DESCRIPTION = ('description', False, NXnote) # *** DEBUG *** validator bug + DESCRIPTION = ("DESCRIPTION", False, NXnote) + + PEAK_PARAMETERS = (REQUIRED_NAME.PEAK_PARAMETERS, False, NXparameters) + BACKGROUND_PARAMETERS = (REQUIRED_NAME.BACKGROUND_PARAMETERS, False, NXparameters) + + # DIFFRACTOGRAM = ('diffractogram', False, NXdata) # *** DEBUG *** validator bug + DIFFRACTOGRAM = ("DIFFRACTOGRAM", False, NXdata) + DGRAM_TWO_THETA_NAME = ("XAXIS", False, NXfield) # *** DEBUG *** validator bug: normally would be just 'two_theta' + + # DIFFRACTOGRAM sub-fields: + DGRAM_DIFFRACTOGRAM = (REQUIRED_NAME.DGRAM_DIFFRACTOGRAM, False, NXfield) + DGRAM_DIFFRACTOGRAM_ERRORS = (REQUIRED_NAME.DGRAM_DIFFRACTOGRAM_ERRORS, False, NXfield) + DGRAM_FIT = (REQUIRED_NAME.DGRAM_FIT, False, NXfield) + DGRAM_FIT_ERRORS = (REQUIRED_NAME.DGRAM_FIT_ERRORS, False, NXfield) + + # PEAKS (NXreflections) presents the canonical reduction result: there is only one per NXentry. + PEAKS = (REQUIRED_NAME.PEAKS, False, NXreflections) + + ## OPTIONAL GROUPS, allowed by but not specified by the schema: ## + + # Including the input data allows all of the information for a reduction to be contained in one file. + INPUT_DATA = ("input_data", False, NXdata) + + # Masks are added as a subgroup under the `INSTRUMENT` group: + # both and are currently recognized, + # however the mask names must be distinct, because they're used as suffix tags + # when creating other group names. + MASKS = ("masks", False, NXcollection) + + def __new__(cls, value, allowMultiple: bool, nxClass: type[NXgroup]): + obj = str.__new__(cls, value) + obj._value_ = value + obj.allowMultiple = allowMultiple + obj.nxClass = nxClass + return obj + + +# `NXstress` records `peak_parameters` and `background_parameters` in distinct groups. +EFFECTIVE_BACKGROUND_PARAMETERS = ["A0", "A1", "A2"] + +# Name or suffix corresponding to the default dataset: +# -- when a group name uses this as a suffix tag (e.g. multiple FIT (NXprocess) groups, one for each mask) +# this default tag should be _omitted_ from the group name. +# -- presently this is only used for masks, to allow multiple FIT.diffractogram groups. +DEFAULT_TAG = HidraConstants.DEFAULT_MASK + +UNDEFINED_PEAK_TAG = "_undefined_" + +NO_LOG = "_no_log_" + + +def group_naming_scheme(base_name: str, suffix: int | str) -> str: + # Generate the name for an HDF5 group, allowing for multiple group instances: + # instance: + # int: enumerated group names: '_1' is omitted; + # str: group names (e.g. 'DIFFRACTOGRAM' (NXdata)), delineated using a tag suffix: '__DEFAULT_' is omitted. + if not isinstance(suffix, (int, str)): + raise RuntimeError(f"`group_naming_scheme`: not implemented for suffix '{suffix}'") + + tag = "" + if isinstance(suffix, int) and suffix > 1 or isinstance(suffix, str) and suffix != DEFAULT_TAG: + tag = f"_{suffix}" + + return f"{base_name}{tag}" + + +def suffix_from_group_name(group_name: str, base_name: str) -> str: + """Reverse of `group_naming_scheme`: extract the suffix from a group name. + + 'DIFFRACTOGRAM' -> DEFAULT_TAG + 'DIFFRACTOGRAM_mask_A' -> 'mask_A' + + Parameters + ---------- + group_name : str + The group name to parse + base_name : str + The base name used to form the group name + + Returns + ------- + str + The appended suffix (or DEFAULT_TAG for the default case) + """ + prefix = str(base_name) + if group_name == prefix: + return DEFAULT_TAG + elif group_name.startswith(prefix + "_"): + return group_name[len(prefix) + 1 :] + else: + raise RuntimeError(f"Cannot extract suffix (e.g. mask name) from '{group_name}'") + + +def allowed_identifier(s: str) -> str: + # Convert PV-log name to NeXus-compliant identifier + + # This function is simplified, for the moment (making several assumptions about the input string): + # + # -- ':' characters are not allowed, and are replaced by '_'; + # -- '.' are allowed, and are assumed to be in the interior + # of string; + # -- TODO: check for other disallowed chars, such as "$"? + + return s.replace(":", "_") + + +def is_ISO_8601(s: str) -> bool: + scannable = True + try: + datetime.fromisoformat(s) + except ValueError as e: + if "Invalid isoformat string" not in str(e): + raise + scannable = False + return scannable diff --git a/pyrs/utilities/NXstress/_fit.py b/pyrs/utilities/NXstress/_fit.py new file mode 100644 index 000000000..66b6ac1ed --- /dev/null +++ b/pyrs/utilities/NXstress/_fit.py @@ -0,0 +1,598 @@ +""" +pyrs/utilities/NXstress/_fit.py + +Private service class for NeXus NXstress-compatible I/O. +This class provides I/O for the `fit` `NXprocess` subgroup: + this subgroup includes the reduced output data as a 'diffraction_data' `NXdata` group. +""" + +import logging + +from datetime import datetime +from nexusformat.nexus import NXdata, NXfield, NXnote, NXparameters, NXprocess +import numpy as np +from typing import Tuple + +from pyrs.peaks.peak_collection import PeakCollection +from pyrs.core.peak_profile_utility import BackgroundFunction +from pyrs.core.workspaces import HidraWorkspace +from pyrs.dataobjects.sample_logs import SampleLogs +from pyrs.utilities.pydantic_transition import validate_call_ + +from ._definitions import FIELD_DTYPE, CHUNK_SHAPE, DEFAULT_TAG, GROUP_NAME, group_naming_scheme, UNDEFINED_PEAK_TAG +from ._peaks import _Peaks + +""" +REQUIRED PARAMETERS FOR NXstress: +--------------------------------- + +├─ fit (NXprocess, group) +│ ├─ date (dataset: ISO8601 string) +│ ├─ program (dataset: string) +│ ├─ description (NXnote, group) +│ ├─ peakparameters (NXparameters, group) +│ └─ diffractogram (NXdata, group) +│ ├─ diffractogram (dataset) +│ ├─ diffractogram_errors (dataset) +│ ├─ daxis/xaxis (dataset) +│ ├─ @axes (attribute: string) +│ └─ @signal (attribute: string) +""" + + +class _PeakParameters: + @classmethod + def _init(cls, peakss: list[PeakCollection]) -> NXparameters: + # required 'peak_parameters' subgroup + pp = NXparameters() + peak_profile = str(peakss[0].peak_profile).lower() if peakss else UNDEFINED_PEAK_TAG + + # To be compliant with `NXstress` schema: + # this cannot be tiled: all `PeakCollection` must share the same `peak_profile`. + pp["title"] = NXfield(peak_profile, dtype=FIELD_DTYPE.STRING.value) + + pp["center"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="degree" + ) + pp["center_errors"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="degree" + ) + pp["height"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="counts" + ) + pp["height_errors"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="counts" + ) + pp["fwhm"] = NXfield(np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="degree") + pp["fwhm_errors"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="degree" + ) + + # Voigt or Pseudo-Voigt: Lorentzian fraction + pp["form_factor"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="1" + ) + pp["form_factor_errors"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="1" + ) + + return pp + + @classmethod + @validate_call_ + def init_group(cls, peakss: list[PeakCollection]) -> NXparameters: + # required 'peak_parameters' subgroup + pp = cls._init(peakss) + + for peak_collection in sorted(peakss, key=_Peaks.PeakIndex.sort_key): + cls._append_peak(pp, peak_collection) + + return pp + + @classmethod + @validate_call_ + def _append_peak(cls, pp: NXparameters, peaks: PeakCollection) -> NXparameters: + # Append the peak parameters from a single `PeakCollection` instance. + + # Verify the `PeakCollection` peak-profile type. + peak_profile = str(peaks.peak_profile).lower() + if pp["title"] == UNDEFINED_PEAK_TAG: + pp["title"].replace(peak_profile) + elif peak_profile != pp["title"]: + raise ValueError( + f"All `PeakCollection` must share the same peak profile ''{pp['title']}'', not ''{peak_profile}''." + ) + + # Use _effective_ peak parameters here: all peaks will then have the same number of parameter, + # and all parameter values will be in the expected column. + # We have one new parameter value for each of 'N_scan' subruns. + + N_scan = len(peaks.sub_runs) + cur_rows = pp["center"].shape[0] + new_rows = cur_rows + N_scan + + ## In the following, make sure to include _only_ the peak-function parameters. + params_value, params_error = peaks.get_effective_params() + + pp["center"].resize((new_rows,)) + pp["center_errors"].resize((new_rows,)) + pp["height"].resize((new_rows,)) + pp["height_errors"].resize((new_rows,)) + pp["fwhm"].resize((new_rows,)) + pp["fwhm_errors"].resize((new_rows,)) + pp["form_factor"].resize((new_rows,)) + pp["form_factor_errors"].resize((new_rows,)) + + pp["center"][cur_rows:] = params_value["Center"].astype(np.float64) + pp["center_errors"][cur_rows:] = params_error["Center"].astype(np.float64) + pp["height"][cur_rows:] = params_value["Height"].astype(np.float64) + pp["height_errors"][cur_rows:] = params_error["Height"].astype(np.float64) + pp["fwhm"][cur_rows:] = params_value["FWHM"].astype(np.float64) + pp["fwhm_errors"][cur_rows:] = params_error["FWHM"].astype(np.float64) + + # Voigt or Pseudo-Voigt: Lorentzian fraction + pp["form_factor"][cur_rows:] = (1.0 - params_value["Mixing"]).astype(np.float64) + pp["form_factor_errors"][cur_rows:] = params_error["Mixing"].astype(np.float64) + + return pp + + @classmethod + def peakParametersForRange(cls, pp, start: int, end: int) -> tuple: + """Extract peak parameters for a specific range and convert to native parameters. + + Reads effective parameters from the NXparameters group, slices to the specified range, + and converts to native parameters using the appropriate converter. + + CRITICAL: form_factor is stored as (1 - Mixing), so we invert: Mixing = 1 - form_factor + + Parameters + ---------- + pp : NXparameters + Peak parameters group + start : int + Starting index (inclusive) + end : int + Ending index (exclusive) + + Returns + ------- + tuple[np.ndarray, np.ndarray] + (native_values, native_errors) structured arrays + """ + from pyrs.core.peak_profile_utility import PeakShape, get_parameter_dtype, get_effective_parameters_converter + + # Get peak profile type and converter (needed for both Intensity reconstruction and native conversion) + peak_shape = PeakShape.getShape(pp["title"].nxdata) + converter = get_effective_parameters_converter(peak_shape) + + # Build effective parameter structured arrays + N = end - start + eff_values = np.zeros(N, dtype=get_parameter_dtype(effective=True)) + eff_errors = np.zeros(N, dtype=get_parameter_dtype(effective=True)) + + # Slice datasets and populate effective arrays + eff_values["Center"] = pp["center"].nxdata[start:end] + eff_values["Height"] = pp["height"].nxdata[start:end] + eff_values["FWHM"] = pp["fwhm"].nxdata[start:end] + + # CRITICAL: Invert form_factor to Mixing + eff_values["Mixing"] = 1.0 - pp["form_factor"].nxdata[start:end] + + eff_errors["Center"] = pp["center_errors"].nxdata[start:end] + eff_errors["Height"] = pp["height_errors"].nxdata[start:end] + eff_errors["FWHM"] = pp["fwhm_errors"].nxdata[start:end] + eff_errors["Mixing"] = pp["form_factor_errors"].nxdata[start:end] + + # Intensity is not stored -- reconstruct it and its error from the stored (h, fwhm, eta). + # The reconstruction is shape-dependent because each peak profile has a different + # native parameterisation and a different write-path error propagation. + h = eff_values["Height"] + fwhm = eff_values["FWHM"] + eta = eff_values["Mixing"] + s_h = eff_errors["Height"] + s_fwhm = eff_errors["FWHM"] + s_eta = eff_errors["Mixing"] + + if peak_shape == PeakShape.PSEUDOVOIGT: + # PseudoVoigt: $I = h \pi \Gamma / (2 (1 + F \eta))$ where $F = \sqrt{\pi \ln 2} - 1$ + eff_values["Intensity"] = converter.cal_intensity(h, fwhm, eta) + + # Error propagation: exact inversion of the write-path cal_height_error formula. + # On the write path s_h was derived from (s_I, s_fwhm, s_eta) treated as independent: + # $s_h^2 = (\partial h/\partial I)^2 s_I^2 + # + (\partial h/\partial \Gamma)^2 s_\Gamma^2 + # + (\partial h/\partial \eta)^2 s_\eta^2$ + # Solving for $s_I^2$: + # $s_I^2 = (\partial I/\partial h)^2 s_h^2 + # - (\partial I/\partial \Gamma)^2 s_\Gamma^2 + # - (\partial I/\partial \eta)^2 s_\eta^2$ + # The subtraction removes the correlation terms that would otherwise be double-counted. + # The guard below handles the case where floating-point noise makes $s_I^2$ slightly negative. + _F = np.sqrt(np.pi * np.log(2)) - 1.0 + I_val = eff_values["Intensity"] + dI_dh = np.where(h != 0, I_val / h, 0.0) + dI_dfwhm = np.where(fwhm != 0, I_val / fwhm, 0.0) + dI_deta = -I_val * _F / (1.0 + _F * eta) + sigma_I_sq = (dI_dh * s_h) ** 2 - (dI_dfwhm * s_fwhm) ** 2 - (dI_deta * s_eta) ** 2 + if np.any(sigma_I_sq < 0) or np.any(~np.isfinite(sigma_I_sq)): + logging.getLogger(__name__).warning( + "peakParametersForRange: first-order s_Intensity approximation failed " + "(negative or non-finite variance); setting s_Intensity = NaN." + ) + eff_errors["Intensity"] = np.nan + else: + eff_errors["Intensity"] = np.sqrt(sigma_I_sq) + + else: + # Gaussian (and any other shape): Height is a native parameter, so s_h comes + # directly from the fit and is independent of s_fwhm -- no double-counting. + # $I = \sqrt{2\pi} \cdot h \cdot \sigma$ where $\sigma = \Gamma / (2\sqrt{2 \ln 2})$ + sigma_g = converter.cal_sigma(fwhm) + s_sigma_g = converter.cal_sigma(s_fwhm) # linear, same scale factor + I_val = converter.cal_intensity(h, sigma_g) + eff_values["Intensity"] = I_val + eff_errors["Intensity"] = converter.cal_intensity_error(I_val, h, s_h, sigma_g, s_sigma_g) + + # A0, A1, A2 will be populated from backgroundParametersForRange + # Initialize to 0.0 as they are part of the effective parameter dtype + eff_values["A0"] = 0.0 + eff_values["A1"] = 0.0 + eff_values["A2"] = 0.0 + eff_errors["A0"] = 0.0 + eff_errors["A1"] = 0.0 + eff_errors["A2"] = 0.0 + + # Convert to native parameters + native_values, native_errors = converter.calculate_native_parameters(eff_values, eff_errors) + + return native_values, native_errors + + +class _BackgroundParameters: + @classmethod + def _init(cls, peakss: list[PeakCollection]) -> NXparameters: + # required 'background_parameters' subgroup + bp = NXparameters() + + # To be compliant with `NXstress` schema: + # this cannot be tiled: all `PeakCollection` must share the same `background_type`. + background_function = ( + str(BackgroundFunction.getFunction(peakss[0].background_type)).lower() if peakss else UNDEFINED_PEAK_TAG + ) + bp["title"] = NXfield(background_function, dtype=FIELD_DTYPE.STRING.value) + + bp["A0"] = NXfield(np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="counts") + bp["A0_errors"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="counts" + ) + + bp["A1"] = NXfield(np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="counts") + bp["A1_errors"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="counts" + ) + + bp["A2"] = NXfield(np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="counts") + bp["A2_errors"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="counts" + ) + + return bp + + @classmethod + @validate_call_ + def init_group(cls, peakss: list[PeakCollection]) -> NXparameters: + # required 'background_parameters' subgroup + bp = cls._init(peakss) + + for peak_collection in sorted(peakss, key=_Peaks.PeakIndex.sort_key): + cls._append_peak(bp, peak_collection) + + return bp + + @classmethod + @validate_call_ + def _append_peak(cls, bp: NXparameters, peaks: PeakCollection) -> NXparameters: + # Append the background parameters from a single `PeakCollection` instance. + + # Verify the `PeakCollection` background type. + background_title = str(BackgroundFunction.getFunction(peaks.background_type)).lower() + if bp["title"] == UNDEFINED_PEAK_TAG: + bp["title"].replace(background_title) + elif background_title != bp["title"]: + raise ValueError( + f"All `PeakCollection` must share the same background type ''{bp['title']}'', not ''{background_title}''." + ) + + ## In the following, make sure to include _only_ the background parameters. + params_value, params_error = peaks.get_effective_params() + + N_scan = len(peaks.sub_runs) + cur_rows = bp["A0"].shape[0] + new_rows = cur_rows + N_scan + + bp["A0"].resize((new_rows,)) + bp["A0_errors"].resize((new_rows,)) + bp["A1"].resize((new_rows,)) + bp["A1_errors"].resize((new_rows,)) + bp["A2"].resize((new_rows,)) + bp["A2_errors"].resize((new_rows,)) + + bp["A0"][cur_rows:,] = params_value["A0"].astype(np.float64) + bp["A0_errors"][cur_rows:,] = params_error["A0"].astype(np.float64) + bp["A1"][cur_rows:,] = params_value["A1"].astype(np.float64) + bp["A1_errors"][cur_rows:,] = params_error["A1"].astype(np.float64) + bp["A2"][cur_rows:,] = params_value["A2"].astype(np.float64) + bp["A2_errors"][cur_rows:,] = params_error["A2"].astype(np.float64) + + return bp + + @classmethod + def backgroundParametersForRange(cls, bp, start: int, end: int) -> tuple: + """Extract background parameters for a specific range. + + Reads background coefficients from the NXparameters group and slices to the specified range. + + Parameters + ---------- + bp : NXparameters + Background parameters group + start : int + Starting index (inclusive) + end : int + Ending index (exclusive) + + Returns + ------- + tuple[np.ndarray, np.ndarray] + (eff_bg_values, eff_bg_errors) structured arrays with A0, A1, A2 fields + """ + from pyrs.core.peak_profile_utility import get_parameter_dtype + + # Build effective background parameter arrays + N = end - start + eff_bg_values = np.zeros(N, dtype=get_parameter_dtype(effective=True)) + eff_bg_errors = np.zeros(N, dtype=get_parameter_dtype(effective=True)) + + # Slice datasets and populate arrays + eff_bg_values["A0"] = bp["A0"].nxdata[start:end] + eff_bg_values["A1"] = bp["A1"].nxdata[start:end] + eff_bg_values["A2"] = bp["A2"].nxdata[start:end] + + eff_bg_errors["A0"] = bp["A0_errors"].nxdata[start:end] + eff_bg_errors["A1"] = bp["A1_errors"].nxdata[start:end] + eff_bg_errors["A2"] = bp["A2_errors"].nxdata[start:end] + + return eff_bg_values, eff_bg_errors + + +class _Diffractogram: + @classmethod + def _get_diffraction_data(cls, ws: HidraWorkspace, mask_name: str) -> Tuple[np.ndarray, np.ndarray]: + # Workaround for PyRS codebase use of `None` as the default key. + data_key = cls._diffraction_data_key(mask_name) + if data_key not in ws._diff_data_set: + raise RuntimeError( + f"NXstress._fit._Diffractogram: usage error: diffraction data '{data_key}' is not present in the workspace" + ) + if data_key not in ws._var_data_set: + raise RuntimeError( + f"NXstress._fit._Diffractogram: variance for diffraction data '{mask_name}' is not present in the workspace:\n" + " how was this workspace initialized?" + ) + return ws._diff_data_set[data_key], ws._var_data_set[data_key] + + @classmethod + def _diffraction_data_key(cls, mask_name: str) -> str | None: + # Workaround for PyRS codebase use of `None` as the default key. + return mask_name if mask_name != DEFAULT_TAG else None + + @classmethod + def _init(cls, ws: HidraWorkspace) -> NXdata: + if ws._2theta_matrix is None: + raise RuntimeError("Usage error: cannot write NXstress file: workspace doesn't include any reduced data.") + dg = NXdata() + return dg + + @classmethod + @validate_call_ + def init_group(cls, ws: HidraWorkspace, maskName: str, peakss: list[PeakCollection]) -> NXdata: + # required DIFFRACTOGRAM (NXdata) subgroup: + + dg = cls._init(ws) + dg.attrs["signal"] = GROUP_NAME.DGRAM_DIFFRACTOGRAM + dg.attrs["auxiliary_signals"] = [ + GROUP_NAME.DGRAM_DIFFRACTOGRAM_ERRORS, + GROUP_NAME.DGRAM_FIT, + GROUP_NAME.DGRAM_FIT_ERRORS, + ] + dg.attrs["axes"] = ["scan_point", "."] # do _not_ specify a 2-D theta in 'axes' + dg.attrs["two_theta_indices"] = [0, 1] # two-theta has shape (, ) + dg["scan_point"] = NXfield(ws.get_sub_runs()) + dg["scan_point"].attrs["units"] = "" + + two_theta = ws._2theta_matrix + dg[GROUP_NAME.DGRAM_TWO_THETA_NAME] = NXfield( # *** DEBUG *** validator bug + two_theta, units="degree" + ) + + data, errors = cls._get_diffraction_data(ws, maskName) + dg[GROUP_NAME.DGRAM_DIFFRACTOGRAM] = NXfield( + data, dtype=FIELD_DTYPE.FLOAT_DATA.value, interpretation="spectrum", units="counts" + ) + + dg[GROUP_NAME.DGRAM_DIFFRACTOGRAM_ERRORS] = NXfield(errors, dtype=FIELD_DTYPE.FLOAT_DATA.value, units="counts") + + ## + ## ENTRY/FIT/DIFFRACTOGRAM/fit, fit_errors: required datasets under `NXstress`: + ## these should contain the spectrum reconstructed from the fitted model. + ## For the moment, these will be initialized to NaN. + ## + dg[GROUP_NAME.DGRAM_FIT] = NXfield( + np.empty((0, 0), dtype=np.float64), maxshape=(None, None), chunks=CHUNK_SHAPE(2), fillvalue=np.nan + ) + dg[GROUP_NAME.DGRAM_FIT].attrs["interpretation"] = "spectrum" + dg[GROUP_NAME.DGRAM_FIT].attrs["units"] = "counts" + dg[GROUP_NAME.DGRAM_FIT_ERRORS] = NXfield( + np.empty((0, 0), dtype=np.float64), maxshape=(None, None), chunks=CHUNK_SHAPE(2), fillvalue=np.nan + ) + dg[GROUP_NAME.DGRAM_FIT_ERRORS].attrs["units"] = "counts" + + return dg + + @classmethod + @validate_call_ + def diffractogramFromNexus(cls, dg): + """Read diffractogram data from NXdata group. + + Parameters + ---------- + dg : NXdata + The DIFFRACTOGRAM NXdata group from the HDF5 file + + Returns + ------- + tuple + (scan_points, two_theta, diffractogram, diffractogram_errors) + + Note + ---- + The write side stores variance in 'diffractogram_errors', so this is + returned directly without conversion. + """ + # Read scan_point array + scan_points = dg["scan_point"].nxdata + + # Read two_theta array (using the correct field name from GROUP_NAME) + two_theta = dg[GROUP_NAME.DGRAM_TWO_THETA_NAME].nxdata + + # Read diffractogram and diffractogram_errors (which stores variance) + diffractogram = dg[GROUP_NAME.DGRAM_DIFFRACTOGRAM].nxdata + diffractogram_errors = dg[GROUP_NAME.DGRAM_DIFFRACTOGRAM_ERRORS].nxdata + + return scan_points, two_theta, diffractogram, diffractogram_errors + + +class _Fit: + ######################################## + # ALL methods must be `classmethod`. ## + ######################################## + + ## + ## Notes: + ## -- Under 'NXstress', there can be multiple FIT (NXprocess) groups in the NXentry, but the results from only + ## one of these should be promoted to the canonical fit results in the PEAKS (NXreflections) group. + ## -- FIT (NXprocess) contains the as-fit peak and background parameters, including any information associated + ## with the fitting process. In this section, any appropriate coordinate system may be used. + ## -- Not yet in PyRS: FIT/DIFFRACTOGRAM/fit, fit_errors: these datasets should contain the reconstructed spectrum + # from the fitted model. We don't seem to have methods to do this yet, so these are initialized to NaN. + ## -- The canonical fit results in PEAKS (NXreflections) should contain the final results, converted to the final + ## coordinate system (e.g. usually `d-spacing`). + ## + @classmethod + @validate_call_ + def _init(cls, logs: SampleLogs, *, processing_description: str, processing_time) -> NXprocess: + # Initialize the 'FIT' (NXprocess) group: + + fit = NXprocess() + + input_ = NXparameters() + input_["description"] = "Peak fits and reduced diffractogram data" + fit[GROUP_NAME.INPUT] = input_ + + # Required information fields: + fit["date"] = NXfield(processing_time) + fit["program"] = NXfield("PyRS") + fit["raw_data_file"] = NXfield(logs["Filename"][0].decode("utf-8")) + + note = NXnote( + type="text/plain", + description="Processing description", + # author='', + # date='', + data=processing_description, + ) + fit[GROUP_NAME.DESCRIPTION] = note + + return fit + + @classmethod + @validate_call_ + def init_group( + cls, + ws: HidraWorkspace, + peakss: list[PeakCollection], + logs: SampleLogs, + processing_description: str = "", + processing_time: str | None = None, + ): + # Initialize a new 'FIT' (NXprocess) group: + # (see `_definitions.group_naming_scheme`). + + ## Under `NXstress`: `FIT` (NXprocess) groups contain peak and background-fit results, including any + ## information relevant to the fitting process used. + fit = cls._init( + logs, + processing_description=processing_description, + processing_time=processing_time if bool(processing_time) else datetime.now().astimezone().isoformat(), + ) + fit[GROUP_NAME.PEAK_PARAMETERS] = _PeakParameters.init_group(peakss) + fit[GROUP_NAME.BACKGROUND_PARAMETERS] = _BackgroundParameters.init_group(peakss) + + # Add one DIFFRACTOGRAM group for each reduced diffraction dataset present in the workspace. + mask_keys = set(ws._diff_data_set.keys()) + mask_keys.discard(None) + mask_keys.add(DEFAULT_TAG) + for mask in mask_keys: + ## TODO: mask naming (and storage) is messed up. They all need to be accessed the same way, + ## regardless of whether or not the "default" mask is being accessed. + ## Here we assume that this loop also accesses data for the _DEFAULT_ mask, and that the default + ## mask has the '_DEFAULT_' name, and not some other name, such as 'main' or `None`?! + dgram_name = group_naming_scheme(GROUP_NAME.DIFFRACTOGRAM, mask) + if dgram_name in fit.NXdata: + raise RuntimeError( + f"Usage error: DIFFRACTOGRAM (NXdata) group '{dgram_name}' already exists in the current (NXprocess) group." + ) + fit[dgram_name] = _Diffractogram.init_group(ws, mask, peakss) + + return fit + + @classmethod + def validateWorkspaceAndPeaksData(cls, ws: HidraWorkspace, peakss: list[PeakCollection]): + # VERIFY that scan_point[s] and mask[s] reference by any `PeakCollection` are present in the workspace. + scan_point = set(ws.get_sub_runs().raw_copy()) + + diff_data_keys = set(ws._diff_data_set.keys()) + var_data_keys = set(ws._var_data_set.keys()) + if diff_data_keys != var_data_keys: + raise ValueError( + f"Diffraction-data keys '{diff_data_keys}' and variance keys '{var_data_keys}' are not the same." + ) + + mask_keys = set(ws._mask_dict.keys()) + mask_keys.discard(None) + mask_keys.add(DEFAULT_TAG) + + for peaks in peakss: + # VERIFY that any referenced by any `PeakCollection` is included in the workspace. + + # Note: `PeakCollection.get_sub_runs()` is *broken*: + # it does not actually return a `SubRuns` instance! + peaks_scan_point = set(peaks._sub_run_array.raw_copy()) + if not peaks_scan_point.issubset(scan_point): + raise ValueError( + f"Scan points {peaks_scan_point}, required by `PeakCollection`,\n" + f" are not present in workspace scan points {scan_point}." + ) + + # VERIFY that any referenced by any `PeakCollection` is included in the workspace. + peaks_mask = peaks.mask + if peaks_mask not in mask_keys: + raise ValueError( + f"Mask '{peaks_mask}' required by `PeakCollection`,\n is not present in the workspace." + ) + data_key = _Diffractogram._diffraction_data_key(peaks_mask) + if data_key not in ws._diff_data_set: + raise ValueError( + f"Reduced data required for mask '{peaks_mask}', required by `PeakCollection`,\n" + " is not present in the workspace." + ) diff --git a/pyrs/utilities/NXstress/_input_data.py b/pyrs/utilities/NXstress/_input_data.py new file mode 100644 index 000000000..cb420f342 --- /dev/null +++ b/pyrs/utilities/NXstress/_input_data.py @@ -0,0 +1,76 @@ +""" +pyrs/utilities/NXstress/_input_data.py + +Private service class for NeXus NXstress-compatible I/O. +This class provides I/O for the `input_data` `NXdata` subgroup. +""" + +from nexusformat.nexus import NXdata, NXfield +import numpy as np + +from pyrs.core.workspaces import HidraWorkspace +from pyrs.utilities.pydantic_transition import validate_call_ + +from ._definitions import CHUNK_SHAPE, FIELD_DTYPE + + +""" +REQUIRED PARAMETERS FOR NXstress: +--------------------------------- + +NONE: 'input_data' (NXdata, group) is allowed by the NXstress schema, but it is optional. +""" + + +class _InputData: + ######################################## + # ALL methods must be `classmethod`. ## + ######################################## + + @classmethod + @validate_call_ + def init_group(cls, ws: HidraWorkspace, data: NXdata = None): + # Initialize the input-data group. + + # Raw data may not actually be loaded in the `HidraWorkspace`: + # in that case, just initialize an empty NXdata group. + scan_points = ws._raw_counts.keys() + scans = ( + np.stack([ws.get_detector_counts(p).astype(FIELD_DTYPE.FLOAT_DATA.value) for p in scan_points]) + if len(scan_points) + else np.empty((0, 0), dtype=FIELD_DTYPE.FLOAT_DATA.value) + ) + + # TODO: append to the group, if it already exists. + if data is not None: + raise RuntimeError("not implemented: append detector_counts data to NXstress file") + else: + data = NXdata() + data["detector_counts"] = NXfield(scans, maxshape=(None, None), chunks=CHUNK_SHAPE(2)) + data["scan_point"] = scan_points + + # Set attributes for axes and signal + data.attrs["signal"] = "detector_counts" + data.attrs["axes"] = ["scan_point", "."] + + return data + + @classmethod + @validate_call_ + def readSubruns(cls, ws: HidraWorkspace, data: NXdata): + # Initialize `HidraWorkspace` detector_counts from input-data group. + + # TODO: append to the `HidraWorkspace`, if any detector_counts data already exists. + scan_points = data["scan_point"].nxdata + + # An empty group means raw counts were not available when the file was written — nothing to load. + if len(scan_points) == 0: + return + + # `HidraWorkspace` must already contain its `SampleLogs`, and scan-points must match. + if ws.get_sub_runs() != scan_points: + raise RuntimeError("not implemented: append or change detector_counts data on existing workspace") + + scans = data["detector_counts"].nxdata + for n, p in enumerate(scan_points): + ws.set_raw_counts(p, scans[n]) diff --git a/pyrs/utilities/NXstress/_instrument.py b/pyrs/utilities/NXstress/_instrument.py new file mode 100644 index 000000000..e75fa5780 --- /dev/null +++ b/pyrs/utilities/NXstress/_instrument.py @@ -0,0 +1,487 @@ +""" +pyrs/utilities/NXstress/_instrument.py + +Private service class for NeXus NXstress-compatible I/O. +This class provides I/O for the `instrument` `NXinstrument` subgroup. +""" + +import logging +from nexusformat.nexus import ( + NXbeam, + NXcollection, + NXdetector, + NXdetector_module, + NXfield, + NXinstrument, + NXlink, + NXmonochromator, + NXnote, + NXsource, + NXtransformations, +) +import numpy as np +import json + +from pyrs.core.instrument_geometry import DENEXDetectorGeometry, DENEXDetectorShift +from pyrs.core.workspaces import HidraWorkspace +from pyrs.utilities.pydantic_transition import validate_call_ + +from ._definitions import CHUNK_SHAPE, DEFAULT_TAG, FIELD_DTYPE, GROUP_NAME + + +_logger = logging.getLogger(__name__) + +""" +REQUIRED PARAMETERS FOR NXstress: +--------------------------------- + +├─ instrument (NXinstrument, group) +│ ├─ name (dataset) +│ ├─ source (NXsource, group) +│ ├─ detector (NXdetector, group) +│ └─ masks (optional) (NXcollection, group) +""" + + +class _Instrument: + ######################################## + # ALL methods must be `classmethod`. ## + ######################################## + + @classmethod + def _init(cls, name: str, short_name: str) -> NXinstrument: + inst = NXinstrument() # WARNING: cannot assign 'name' field via kwarg! + inst["name"] = name + inst["name"].attrs["short_name"] = short_name + return inst + + @classmethod + @validate_call_ + def init_group(cls, ws: HidraWorkspace) -> NXinstrument: + """ + Create a new NXinstrument group subtree. + Conventions: + - Array datasets use explicit NumPy dtypes (np.int64 / np.float64). + - Python native int/float are used for scalars. + - DENEXDetectorGeometry.detectorsize -> (rows, cols) + - DENEXDetectorGeometry.pixeldimension -> (px, py) (meters) + - If present, setup._geometryshift is DENEXDetectorShift. + """ + inst = cls._init("HB2B", "HB2B") + + N_scan_point = len(ws.get_sub_runs()) + + # Detector base geometry and transformations + geom: DENEXDetectorGeometry = ws.get_instrument_setup() + shift: DENEXDetectorShift | None = ws.get_detector_shift() + is_calibrated = shift is not None + + # Wavelength (`get_wavelength` returns either a single `float` or a `dict` keyed by subrun) + wavelength = ws.get_wavelength(is_calibrated, False) + if isinstance(wavelength, dict): + # `dict` order should be the same as the sorted subruns order + wavelength = [l_ for l_ in wavelength.values()] + elif isinstance(wavelength, float): + wavelength = list((wavelength,) * N_scan_point) + elif wavelength is None: + wavelength = list((np.nan,) * N_scan_point) + else: + raise RuntimeError(f"unable to parse wavelength from `HidraWorkspace.get_wavelength`: {wavelength}") + if len(wavelength) != N_scan_point: + raise ValueError( + "Workspace must have either a single wavelength value,\n" + " or one wavelength value for each of {N_scan_point} subruns." + ) + + # Construct required NeXus subgroups: + # NXsource, NXmonochromator, NXdetector, NXtransformations. + src = NXsource() + src["type"] = NXfield("Reactor Neutron Source") + src["probe"] = NXfield("neutron") + + mono = NXmonochromator() + # `wavelength` by ? + mono["wavelength"] = NXfield(wavelength, units="angstrom", calibrated=is_calibrated) + + det = NXdetector() + det["type"] = "He_3 PSD" + # Detector size (in rows and columns) and pixel size (in meters) + nrows, ncols = geom.detector_size + px_m, py_m = geom.pixel_dimension # meters + + # det['data_size'] = NXfield(np.array([nrows, ncols], dtype=np.int64), dtype=np.int64) + # det['x_pixel_size'] = NXfield(np.array(px_m, dtype=np.float64), dtype=np.float64, units='m') + # det['y_pixel_size'] = NXfield(np.array(py_m, dtype=np.float64), dtype=np.float64, units='m') + + # Note: moving these fields to a subgroup `NXdetector_module` allows us to use scalars here, + # otherwise, the strict-mode validators require that we enter one value for each pixel! + det["detector_bank"] = NXdetector_module( + data_size=NXfield(np.array([nrows, ncols], dtype=np.int64), dtype=np.int64), + fast_pixel_direction=NXfield(np.array(px_m, dtype=np.float64), dtype=np.float64, units="m"), + slow_pixel_direction=NXfield(np.array(py_m, dtype=np.float64), dtype=np.float64, units="m"), + depends_on=".", + ) + + # Beam intensity profile + beam = NXbeam() + # TODO: fill in the beam-intensity profile. + + # Transformations chain (values as native floats; axis vectors as float64 arrays) + trans = NXtransformations() + + if is_calibrated and shift is not None: + tx = float(shift.center_shift_x) # meters + ty = float(shift.center_shift_y) # meters + tz = float(shift.center_shift_z) # meters + + # Sample-to-detector distance: + # TODO: RE `L2`: At present there seems no way to determine if the `DENEXDetectorGeometry` + # already has had the _arm_ shift applied to it -- this issue needs to be fixed! + distance = float(geom.arm_length) # meters + + rotx = float(shift.rotation_x) # degrees + roty = float(shift.rotation_y) # degrees + rotz = float(shift.rotation_z) # degrees + tth0 = float(shift.two_theta_0) # degrees + else: + tx = ty = tz = 0.0 + # Always write the actual arm_length, not 0.0 + distance = float(geom.arm_length) # meters + rotx = roty = rotz = tth0 = 0.0 + + ex = np.array([1.0, 0.0, 0.0], dtype=np.float64) + ey = np.array([0.0, 1.0, 0.0], dtype=np.float64) + ez = np.array([0.0, 0.0, 1.0], dtype=np.float64) + + depends = "." + for name, val, vec, units, trtype in [ + ("translation_x", tx, ex, "m", "translation"), + ("translation_y", ty, ey, "m", "translation"), + ("translation_z", tz, ez, "m", "translation"), + ("distance", distance, ez, "m", "translation"), + ("rotation_x", rotx, ex, "deg", "rotation"), + ("rotation_y", roty, ey, "deg", "rotation"), + ("rotation_z", rotz, ez, "deg", "rotation"), + # TODO: check order of rotations here!!! + ("two_theta_zero", tth0, ex, "deg", "rotation"), + ]: + f = NXfield(val, units=units) + f.attrs["transformation_type"] = trtype + f.attrs["vector"] = vec + # each transformation depends on the previous one in the chain + f.attrs["depends_on"] = depends + trans[name] = f + depends = f"./transformations/{name}" + + det["transformations"] = trans + # detector depends on the first transformation in the chain + det["depends_on"] = "./transformations/translation_x" + + # Add a calibrated flag as extra metadata + det["transformations"].attrs["calibrated"] = bool(is_calibrated) + + # Optional calibration provenance + if is_calibrated and shift is not None: + try: + caldict = shift.convert_to_dict() + except Exception: + caldict = { + "center_shift_x": tx, + "center_shift_y": ty, + "center_shift_z": tz, + "rotation_x": rotx, + "rotation_y": roty, + "rotation_z": rotz, + } + note = NXnote() + note["type"] = NXfield("text/plain") + # Note: calibration_file may not be available on all shift objects + try: + note["file_name"] = shift.calibration_file + except AttributeError: + note["file_name"] = "" + note["data"] = NXfield(json.dumps(caldict, indent=2)) + else: + note = None + + inst[GROUP_NAME.SOURCE] = src + inst[GROUP_NAME.BEAM] = beam + inst[GROUP_NAME.MONOCHROMATOR] = mono + inst[GROUP_NAME.DETECTOR] = det + if note is not None: + inst["detector_calibration"] = note + + # Add an optional 'masks' subgroup, to contain any detector or solid-angle masks. + # For the moment, we only write detector masks -- the `HidraWorkspace` doesn't + # yet seem to provide a way to distinguish between a detector and a solid-angle mask. + inst[GROUP_NAME.MASKS] = _Masks.init_group(ws) + + return inst + + @classmethod + @validate_call_ + def instrumentFromNexus(cls, instrument): + """Read instrument geometry, detector shift, and wavelength from NXinstrument group. + + Parameters + ---------- + instrument : NXinstrument + The NXinstrument group from the HDF5 file + + Returns + ------- + tuple + (DENEXDetectorGeometry, DENEXDetectorShift | None, wavelength: np.ndarray) + """ + + # Read detector geometry from detector/detector_bank + detector = instrument[GROUP_NAME.DETECTOR] + detector_bank = detector["detector_bank"] + + # data_size: (nrows, ncols) + data_size = detector_bank["data_size"].nxdata + nrows, ncols = int(data_size[0]), int(data_size[1]) + + # Pixel sizes in meters + px_m = float(detector_bank["fast_pixel_direction"].nxdata) + py_m = float(detector_bank["slow_pixel_direction"].nxdata) + + # Read transformations + trans = detector["transformations"] + calibrated = bool(trans.attrs.get("calibrated", False)) + + # Read distance (arm_length) + distance = float(trans["distance"].nxdata) if "distance" in trans else 0.0 + arm_length = distance + + # Create geometry object + geometry = DENEXDetectorGeometry(nrows, ncols, px_m, py_m, arm_length, calibrated) + + # If calibrated, read shift parameters + shift = None + if calibrated: + tx = float(trans["translation_x"].nxdata) if "translation_x" in trans else 0.0 + ty = float(trans["translation_y"].nxdata) if "translation_y" in trans else 0.0 + tz = float(trans["translation_z"].nxdata) if "translation_z" in trans else 0.0 + rotx = float(trans["rotation_x"].nxdata) if "rotation_x" in trans else 0.0 + roty = float(trans["rotation_y"].nxdata) if "rotation_y" in trans else 0.0 + rotz = float(trans["rotation_z"].nxdata) if "rotation_z" in trans else 0.0 + tth0 = float(trans["two_theta_zero"].nxdata) if "two_theta_zero" in trans else 0.0 + + shift = DENEXDetectorShift(tx, ty, tz, rotx, roty, rotz, tth0) + + # Read wavelength from monochromator: + # we don't have access to the scan-point indices at this level, + # so we just return an `np.ndarray` in scan-point order. + wavelength = None + if GROUP_NAME.MONOCHROMATOR in instrument: + mono = instrument[GROUP_NAME.MONOCHROMATOR] + if "wavelength" in mono: + wavelength = mono["wavelength"].nxdata + + return geometry, shift, wavelength + + +class _Masks: + # `INSTRUMENT/masks` (NXcollection) is allowed by the `NXstress` schema, + # but is not specified by the schema. + + # + # * Masks are stored by name. + # + # * Mask names must be distinct over both and : + # this allows us to successfully use the mask name as a suffix tag on other groups, + # without requiring the same sub-categorization for those groups. + # + # * Throughout the PyRS codebase `None` is used to indicate that the default mask is + # being used. For the purposes of the NXstress-compliant output, `None` will be + # mapped to `_definitions.DEFAULT_TAG`. For this key *only*, the mask-name suffix + # is _omitted_ from gener + # + + @classmethod + @validate_call_ + def _init(cls) -> NXcollection: + # initialize the `masks` (NXcollection) group + masks = NXcollection() + masks["names"] = NXfield( + np.empty((0,), dtype=FIELD_DTYPE.STRING.value), maxshape=(None,), chunks=CHUNK_SHAPE(1) + ) + masks["detector"] = NXcollection() + masks["solid_angle"] = NXcollection() + + return masks + + @classmethod + @validate_call_ + def init_group(cls, ws: HidraWorkspace, *, masks: NXcollection = None): + # Write or append masks to the `NXcollection` + + # Allow append: both 'detector' and 'solid_angle' masks may exist, + # and if so, the masks will need to be added in separate steps. + masks = masks if masks is not None else cls._init() + names = masks["names"].nxvalue + + appending = len(names) > 0 + detector_masks = masks["detector"] + solid_angle_masks = masks["solid_angle"] + + # Unify the `_mask_dict` to a standard Python `dict`. + _mask_dict = ws._mask_dict.copy() + if not appending: + # There is only *one* default detector-mask, and for output purposes, + # the default mask *must* be initialized. + default_mask = ws.get_detector_mask(True) + if default_mask is None: + _logger.warning( + "NXstress._instrument: no default " + " detector-mask is defined;\n" + " for output purposes, a default mask will be created." + ) + _mask_dict[DEFAULT_TAG] = ( + default_mask if default_mask is not None else cls._generate_default_mask(ws, detector_mask=True) + ) + + # Write the default-mask *once* to the masks group: + # this must happen first, as we may re-use it below as an `NXlink`. + detector_masks[DEFAULT_TAG] = NXfield(_mask_dict[DEFAULT_TAG], units="") + names.append(DEFAULT_TAG) + + # Check key correspondance in order to generate warning messages: + # here we do NOT replace the `None` key with `_definitions.DEFAULT_TAG`! + ws_data_keys = set(ws._diff_data_set.keys()) + ws_mask_keys = set(ws._mask_dict.keys()) + + for mask in cls.mask_keys(ws): + if mask == DEFAULT_TAG: + # WARNING: the default-mask should have been written before this point. + continue + + if mask in names: + raise RuntimeError( + f'Usage error: mask "{mask}" has already been written;\n' + + " names must be distinct over both detector and solid-angle masks." + ) + if mask in ws_data_keys and mask not in ws_mask_keys: + _logger.warning( + f"NXstress._instrument: no mask entry exists corresponding to diffraction data '{mask}';\n" + " for output purposes, the *default* mask will be written for this mask." + ) + + # WARNING: this section assumes that `detector_masks[DEFAULT_TAG]` already exists: + # it should have been written above. + mask_array = _mask_dict.get(mask) + units = "degrees" if (mask_array is not None and cls._is_solid_angle_mask(mask_array)) else "" + + # If no specific mask is present corresponding to a reduced diffraction dataset, + # a link will be created to the default detector-mask. + if mask_array is not None: + ds = NXfield(mask_array, units=units) + else: + # WORKAROUND to create an `NXlink` within an *unattached* group: + # this bypasses `NXlink.__init__` attempt to dereferene the parent group. + ds = NXlink(target=DEFAULT_TAG, name=f"link_to_{DEFAULT_TAG}") + ds._group = detector_masks + + if cls._is_solid_angle_mask(ds.nxdata): + solid_angle_masks[mask] = ds + else: + detector_masks[mask] = ds + + # append the mask's name to the `names` list + names.append(mask) + + masks["names"].resize((len(names),)) + masks["names"] = names + + return masks + + @classmethod + def mask_keys(cls, ws: HidraWorkspace): + # The complete set of mask names to be used for the `NXstress`-format file: + # + # * The default mask is a detector-mask and will use `_definitions.DEFAULT_TAG` as a key; + # for output purposes, a default-mask will be generated, if not present. + # + # * mask entries may be either detector or solid-angle masks, but they must have distinct names; + # + # * There may be more mask entries than entries in `ws._diff_data_set`. + # For example, if the reduction process may not have been completed for all mask entries. + # + # * Each entry in `ws._diff_data_set` *must* have a corresponding mask. + # When a corresponding entry is not present in `ws._mask_dict`, + # this will be logged (as a warning), and then such an entry will be *linked* + # to the default mask, if not present. + # + # * Any entry in `ws._var_data_set` that does not have a corresponding + # entry in `ws._diff_data_set` will be logged (as a warning) and skipped. + # + # * At present, there's no special name for any default solid-angle mask. + # + + keys = set(ws._mask_dict.keys()).union(ws._diff_data_set.keys()) + keys.discard(None) + # a key for the default detector-mask must always be present + keys.add(DEFAULT_TAG) + return keys + + @classmethod + def _generate_default_mask(cls, ws: HidraWorkspace, *, detector_mask: bool) -> np.ndarray | list[float]: + # Generate an unmasked default mask. + if not detector_mask: + _logger.warning( + "NXstress._instrument: *generating* a default solid-angle mask as `[-180.0, 180.0]`;\n" + " if this is not correct for your usage, please contact the developers." + ) + return [-180.0, 180.0] + + if not ws._instrument_setup: + raise RuntimeError("`_Masks._generate_default_mask`: workspace must have an instrument") + return np.ones(ws._instrument_setup.detector_size, dtype=np.int64) + + @classmethod + def _is_solid_angle_mask(cls, mask: np.ndarray) -> bool: + # Check if a mask is a solid-angle mask + + # Solid-angle masks are comprised of pairs of + # azimuthal *inclusion* zones. + return len(mask.shape) == 1 and mask.shape[0] % 2 == 0 and np.issubdtype(mask.dtype, np.floating) + + @classmethod + @validate_call_ + def masksFromNexus(cls, masks): + """Read masks from NXcollection group. + + Parameters + ---------- + masks : NXcollection + The masks NXcollection group from the HDF5 file + + Returns + ------- + tuple + (default_mask_or_None, {mask_name: np.ndarray}) + """ + # Read mask names + mask_names = masks["names"].nxdata + if isinstance(mask_names, np.ndarray): + mask_names = [name.decode("utf-8") if isinstance(name, bytes) else name for name in mask_names] + else: + mask_names = [mask_names.decode("utf-8") if isinstance(mask_names, bytes) else mask_names] + + default_mask = None + mask_dict = {} + + # Check both detector and solid_angle collections + for collection_name in ["detector", "solid_angle"]: + if collection_name in masks: + collection = masks[collection_name] + for name in mask_names: + if name in collection: + mask_array = collection[name].nxdata + if name == DEFAULT_TAG: + default_mask = mask_array + else: + mask_dict[name] = mask_array + + return default_mask, mask_dict diff --git a/pyrs/utilities/NXstress/_peaks.py b/pyrs/utilities/NXstress/_peaks.py new file mode 100644 index 000000000..9498be126 --- /dev/null +++ b/pyrs/utilities/NXstress/_peaks.py @@ -0,0 +1,457 @@ +# ruff: noqa: E741 # use `l` for `l` in `(h, k, l)`! +""" +pyrs/utilities/NXstress/_peaks.py + +Private service class for NeXus NXstress-compatible I/O. +This class provides I/O for the `peaks` `NXreflections` subgroup: + this subgroup includes fitted peak data, as used in reduction. +""" + +import numpy as np +from nexusformat.nexus import NXreflections, NXfield +import re +from typing import NamedTuple + +from pyrs.peaks.peak_collection import PeakCollection +from pyrs.dataobjects.sample_logs import SampleLogs +from pyrs.utilities.pydantic_transition import validate_call_ + +from ._definitions import CHUNK_SHAPE, FIELD_DTYPE + + +""" +REQUIRED PARAMETERS FOR NXstress: +--------------------------------- + +├─ peaks (NXreflections, group) +│ ├─ h (dataset) +│ ├─ k (dataset) +│ ├─ l (dataset) +│ └─ phase_name (dataset) + +`PeakCollection` to `peaks` (NXreflections), `FIT` (NXprocess) mapping: +----------------------------------------------------------------------- + +1. `peaks` provides the `n_Peaks` index which identifies `FIT` entries, with the exception of the `diffractogram` which are indexed separately. + +- A flattened index is used `(, h, k, l, , )`: all may not be present, and to support legacy code specifying the is optional, + and it will default to the key '_DEFAULT_'; Note that was not retained as a `PeakCollection` field prior to this implementation, but it does seem to be required; + +- This flattened index allows appending (not yet implemented), however each index value must identify a *unique* entry (i.e. there can be no duplicates); + +- Each combination of `(, h, k, l, , ...)` corresponds to *one* `PeakCollection` instance; + +- For input and output purposes (to and from HDF5), the entire index set will be sorted lexographically prior to output. This makes the append operation more complicated, + but provides robustness against duplicates (or overwrites). + +2. `diffractogram` are stored as 'diffractogram_', and indexed by . Any single that does not have an entry will be filled in with `NaN`. + +""" + + +class _Peaks: + ######################################## + # ALL methods must be `classmethod`. ## + ######################################## + + class PeakIndex(NamedTuple): + # Corresponds to the `n_Peaks` index in the `NXstress` schema. + # Each `PeakCollection` instance provides + # `(, h, k, l, , ...)`, i.e. multiple scan_point; + # `scan_point` are distinct, but are not required to be contiguous, nor complete. + phase_name: str + h: int + k: int + l: int # noqa: E741 + mask: str + scan_point: int + + @classmethod + def sort_key(cls, peaks: PeakCollection) -> tuple[str, int, int, int, str]: + # Define an ordering for `PeakCollection` instances + phase_name, (h, k, l) = _Peaks._parse_peak_tag(peaks.peak_tag) + mask = peaks.mask + return (phase_name, h, k, l, mask) + + @classmethod + def _parse_peak_tag(cls, tag: str) -> tuple[str, tuple[int, int, int]]: + # Parse a peak-tag string into its and Miller indices (h, k, l). + match: re.Match[str] | None = max( + re.finditer(r"\d+", tag), + key=lambda m: len(m.group(0)), + default=None, + ) + if match is None or len(match.group(0)) % 3 != 0: + raise RuntimeError(f"Unable to parse peak tag '{tag}' into its and Miller indices (h, k, l).") + # Extract as the rest of the tag. + i, j = match.span() + phase = (tag[:i] + tag[j:]).strip() + if not bool(phase): + raise RuntimeError(f"Unable to parse from peak tag '{tag}'.") + + # Extract (h, k, l) + maybeHKL = match.group(0) + N_d = len(maybeHKL) // 3 + h, k, l_ = int(maybeHKL[0:N_d]), int(maybeHKL[N_d : 2 * N_d]), int(maybeHKL[2 * N_d : 3 * N_d]) + + return phase, (h, k, l_) + + @classmethod + def _init(cls, logs: SampleLogs) -> NXreflections: + # Initialize the 'PEAKS' group + peaks = NXreflections() + + peaks["scan_point"] = NXfield(np.empty((0,), dtype=np.int32), maxshape=(None,), chunks=CHUNK_SHAPE(1)) + + peaks["h"] = NXfield(np.empty((0,), dtype=np.int32), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="") + peaks["k"] = NXfield(np.empty((0,), dtype=np.int32), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="") + peaks["l"] = NXfield(np.empty((0,), dtype=np.int32), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="") + + peaks["phase_name"] = NXfield( + np.empty((0,), dtype=FIELD_DTYPE.STRING.value), maxshape=(None,), chunks=CHUNK_SHAPE(1) + ) + + peaks["mask"] = NXfield( + np.empty((0,), dtype=FIELD_DTYPE.STRING.value), maxshape=(None,), chunks=CHUNK_SHAPE(1) + ) + + ## Components of the normalized scattering vector Q in the sample reference frame + ## 'qx', 'qy', and 'qz' are *required* by NXstress, but it looks as if PyRS doesn't + ## use these -- initialize to `NaN`. + peaks["qx"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), fillvalue=np.nan + ) + peaks["qx"].attrs["units"] = "1" + peaks["qy"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), fillvalue=np.nan + ) + peaks["qy"].attrs["units"] = "1" + peaks["qz"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), fillvalue=np.nan + ) + peaks["qz"].attrs["units"] = "1" + ## + + peaks["center"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="angstrom" + ) + peaks["center_errors"] = NXfield( + np.empty((0,), dtype=np.float64), maxshape=(None,), chunks=CHUNK_SHAPE(1), units="angstrom" + ) + peaks["center_type"] = NXfield("d-spacing") + + # Sample position for each subrun -- initialize to `NaN`. + ss_units = { + ## work around: units may be an empty string + "sx": logs.units("sx") if bool(logs.units("sx")) else "mm", + "sy": logs.units("sy") if bool(logs.units("sy")) else "mm", + "sz": logs.units("sz") if bool(logs.units("sz")) else "mm", + } + peaks["sx"] = NXfield( + np.empty((0,), dtype=np.float64), + maxshape=(None,), + chunks=CHUNK_SHAPE(1), + fillvalue=np.nan, + units=ss_units["sx"], + ) + peaks["sy"] = NXfield( + np.empty((0,), dtype=np.float64), + maxshape=(None,), + chunks=CHUNK_SHAPE(1), + fillvalue=np.nan, + units=ss_units["sy"], + ) + peaks["sz"] = NXfield( + np.empty((0,), dtype=np.float64), + maxshape=(None,), + chunks=CHUNK_SHAPE(1), + fillvalue=np.nan, + units=ss_units["sz"], + ) + + return peaks + + @classmethod + def init_group(cls, peakss: list[PeakCollection], logs: SampleLogs) -> NXreflections: + # Initialize the PEAKS group: + # according to the NXstress schema, this group contains the canonical reduction data, + # in a form usable for stress / strain calculations. + + # TODO: these code sections are implemented in a form that allows new scan-point data to be appended + # However, at present, appending data is not yet supported. + peaks = cls._init(logs) + + for peak_collection in sorted(peakss, key=_Peaks.PeakIndex.sort_key): + cls._append_peak(peaks, peak_collection, logs) + + return peaks + + @classmethod + def _append_peak(cls, peaks: NXreflections, peak_collection: PeakCollection, logs: SampleLogs) -> NXreflections: + # Append a `PeakCollection` to an initialized PEAKS group. + scan_point = peak_collection.sub_runs.raw_copy() + N_scan = len(scan_point) + phase_name, (h, k, l_) = cls._parse_peak_tag(peak_collection.peak_tag) + mask = peak_collection.mask + + # Each dataset has scan point as its first index. + phase_name_arr = np.array((phase_name,) * N_scan) + h_arr = np.array((h,) * N_scan) + k_arr = np.array((k,) * N_scan) + l_arr = np.array((l_,) * N_scan) + mask_arr = np.array((mask,) * N_scan) + + d_reference_arr, d_reference_error_arr = peak_collection.get_d_reference() + + curr_len = peaks["h"].shape[0] + new_len = curr_len + N_scan + + peaks["scan_point"].resize((new_len,)) + + peaks["h"].resize((new_len,)) + peaks["k"].resize((new_len,)) + peaks["l"].resize((new_len,)) + peaks["phase_name"].resize((new_len,)) + peaks["mask"].resize((new_len,)) + + # For `PEAKS` (NXreflections) group: 'center' means `d_reference`. + peaks["center"].resize((new_len,)) + peaks["center_errors"].resize((new_len,)) + + peaks["sx"].resize((new_len,)) + peaks["sy"].resize((new_len,)) + peaks["sz"].resize((new_len,)) + + peaks["scan_point"][curr_len:] = scan_point + peaks["h"][curr_len:] = h_arr + peaks["k"][curr_len:] = k_arr + peaks["l"][curr_len:] = l_arr + peaks["phase_name"][curr_len:] = phase_name_arr + peaks["mask"][curr_len:] = mask_arr + + peaks["center"][curr_len:] = d_reference_arr.ravel() + peaks["center_errors"][curr_len:] = d_reference_error_arr.ravel() + + """ # This doesn't make sense! + peaks['sx'][curr_len:] = logs['sx'] + peaks['sy'][curr_len:] = logs['sy'] + peaks['sz'][curr_len:] = logs['sz'] + """ # TODO: fix this! + peaks["sx"][curr_len:] = np.full((N_scan,), np.nan) + peaks["sy"][curr_len:] = np.full((N_scan,), np.nan) + peaks["sz"][curr_len:] = np.full((N_scan,), np.nan) + + return peaks + + @classmethod + def peakCollectionRanges(cls, peaks) -> list[tuple[tuple[str, int, int, int, str], int, int]]: + """Identify contiguous blocks of PeakCollection data in NXreflections group. + + Each PeakCollection corresponds to a unique 5-tuple (phase_name, h, k, l, mask) + with multiple scan-points written as a contiguous block in increasing order. + + Parameters + ---------- + peaks : NXreflections + The peaks group from which to read the flattened index + + Returns + ------- + list[tuple[tuple[str, int, int, int, str], int, int]] + List of (key, start, end) where: + - key is (phase_name, h, k, l, mask) + - start is the first index (inclusive) + - end is the last index (exclusive) + + Raises + ------ + RuntimeError + If scan_point values are not strictly increasing within a block + RuntimeError + If interleaved blocks are detected for the same sub-index key + """ + # Read index arrays via .nxdata + phase_name = peaks["phase_name"].nxdata[:] + h = peaks["h"].nxdata[:] + k = peaks["k"].nxdata[:] + l_ = peaks["l"].nxdata[:] + mask = peaks["mask"].nxdata[:] + scan_point = peaks["scan_point"].nxdata[:] + + if len(phase_name) == 0: + return [] + + # Decode bytes to strings if necessary + if phase_name.dtype.kind == "S" or phase_name.dtype.kind == "O": + phase_name = np.array([p.decode("utf-8") if isinstance(p, bytes) else str(p) for p in phase_name]) + if mask.dtype.kind == "S" or mask.dtype.kind == "O": + mask = np.array([m.decode("utf-8") if isinstance(m, bytes) else str(m) for m in mask]) + + ranges = [] + seen_keys = set() + + # Track current block + current_key = (str(phase_name[0]), int(h[0]), int(k[0]), int(l_[0]), str(mask[0])) + start_idx = 0 + + for i in range(1, len(phase_name)): + key = (str(phase_name[i]), int(h[i]), int(k[i]), int(l_[i]), str(mask[i])) + + if key != current_key: + # Block boundary - validate and record current block + end_idx = i + + # Check for strictly increasing scan_point within block + block_scan_points = scan_point[start_idx:end_idx] + if not np.all(block_scan_points[1:] > block_scan_points[:-1]): + raise RuntimeError( + f"scan_point values are not strictly increasing within PeakCollection block " + f"at {current_key}, indices [{start_idx}, {end_idx})" + ) + + # Check for interleaved blocks + if current_key in seen_keys: + raise RuntimeError(f"Interleaved blocks detected for sub-index {current_key}") + + seen_keys.add(current_key) + ranges.append((current_key, start_idx, end_idx)) + + # Start new block + current_key = key + start_idx = i + + # Handle last block + end_idx = len(phase_name) + block_scan_points = scan_point[start_idx:end_idx] + if not np.all(block_scan_points[1:] > block_scan_points[:-1]): + raise RuntimeError( + f"scan_point values are not strictly increasing within PeakCollection block " + f"at {current_key}, indices [{start_idx}, {end_idx})" + ) + + if current_key in seen_keys: + raise RuntimeError(f"Interleaved blocks detected for sub-index {current_key}") + + seen_keys.add(current_key) + ranges.append((current_key, start_idx, end_idx)) + + return ranges + + @classmethod + def validateNoDuplicatePeaks(cls, peakss: list[PeakCollection]) -> None: + """Validate that no duplicate PeakCollections exist in the list. + + Each PeakCollection must have a unique 5-tuple key (phase_name, h, k, l, mask). + + Parameters + ---------- + peakss : list[PeakCollection] + List of PeakCollection instances to validate + + Raises + ------ + ValueError + If any duplicate keys are found + """ + seen_keys = {} + for peaks in peakss: + key = cls.PeakIndex.sort_key(peaks) + if key in seen_keys: + raise ValueError( + f"Duplicate PeakCollection detected in output list at {key} " + f"-- did you forget to initialize the `mask` key?" + ) + seen_keys[key] = peaks + + @classmethod + @validate_call_ + def peakCollectionsFromNexus(cls, peaks, fit) -> list[PeakCollection]: + """Read PeakCollections from NXreflections and NXprocess groups. + + Note: This implementation assumes positive Miller indices. Negative indices + are not supported by the current _parse_peak_tag implementation. + + Parameters + ---------- + peaks : NXreflections + The peaks (NXreflections) group containing d-spacing and Miller indices + fit : NXprocess + The FIT (NXprocess) group containing peak_parameters and background_parameters + + Returns + ------- + list[PeakCollection] + List of reconstructed PeakCollection instances + """ + from ._fit import _PeakParameters, _BackgroundParameters + from ._definitions import GROUP_NAME + + # Get the parameter groups + pp = fit[GROUP_NAME.PEAK_PARAMETERS] + bp = fit[GROUP_NAME.BACKGROUND_PARAMETERS] + + # Get peak profile and background function from titles + from pyrs.core.peak_profile_utility import PeakShape, BackgroundFunction + + peak_profile = PeakShape.getShape(pp["title"].nxdata) + background_function = BackgroundFunction.getFunction(bp["title"].nxdata) + + # Get ranges for each PeakCollection + ranges = cls.peakCollectionRanges(peaks) + + peak_collections = [] + for (phase_name, h, k, l_, mask), start, end in ranges: + # Extract scan points for this range + sub_runs_array = peaks["scan_point"].nxdata[start:end] + + # Get peak parameters + native_peak_values, native_peak_errors = _PeakParameters.peakParametersForRange(pp, start, end) + + # Get background parameters + bg_values, bg_errors = _BackgroundParameters.backgroundParametersForRange(bp, start, end) + + # Merge background into native peak arrays + # A0 and A1 are always present, A2 only for Quadratic background + native_peak_values["A0"] = bg_values["A0"] + native_peak_values["A1"] = bg_values["A1"] + native_peak_errors["A0"] = bg_errors["A0"] + native_peak_errors["A1"] = bg_errors["A1"] + # A2 only exists if background is Quadratic + if "A2" in native_peak_values.dtype.names: + native_peak_values["A2"] = bg_values["A2"] + native_peak_errors["A2"] = bg_errors["A2"] + + param_values = native_peak_values + param_errors = native_peak_errors + + # Reconstruct peak_tag with zero-padded Miller indices + # Use max absolute value to ensure all indices have the same digit count + max_val = max(abs(h), abs(k), abs(l_)) + N_d = len(str(max_val)) + peak_tag = f"{phase_name}{str(h).zfill(N_d)}{str(k).zfill(N_d)}{str(l_).zfill(N_d)}" + + # Extract d_reference and errors + d_reference = peaks["center"].nxdata[start] + d_reference_error = peaks["center_errors"].nxdata[start] + + # Construct PeakCollection with mask keyword + pc = PeakCollection( + peak_tag=peak_tag, + peak_profile=peak_profile, + background_type=background_function, + wavelength=np.nan, # Will be set by workspace if needed + projectfilename="", + runnumber=0, + d_reference=d_reference, + d_reference_error=d_reference_error, + mask=mask, + ) + + # Set peak fitting values + N = len(sub_runs_array) + fit_costs = np.full(N, np.nan) + pc.set_peak_fitting_values(sub_runs_array, param_values, param_errors, fit_costs) + + peak_collections.append(pc) + + return peak_collections diff --git a/pyrs/utilities/NXstress/_sample.py b/pyrs/utilities/NXstress/_sample.py new file mode 100644 index 000000000..91d09a7ce --- /dev/null +++ b/pyrs/utilities/NXstress/_sample.py @@ -0,0 +1,211 @@ +""" +pyrs/utilities/NXstress/_sample.py + +Private service class for NeXus NXstress-compatible I/O. +This class provides I/O for the `sample` `NXsample` subgroup. +""" + +import numpy as np +from nexusformat.nexus import NXcollection, NXsample, NXfield + +from pyrs.dataobjects.constants import HidraConstants +from pyrs.dataobjects.sample_logs import SampleLogs, SubRuns +from pyrs.utilities.pydantic_transition import validate_call_ + +from ._definitions import allowed_identifier, CHUNK_SHAPE, FIELD_DTYPE + + +""" +REQUIRED PARAMETERS FOR NXstress: +--------------------------------- + +├─ sample (NXsample, group) +│ ├─ name (dataset) +│ ├─ chemical_formula (optional) (dataset) +│ ├─ temperature (optional) (dataset) +│ ├─ stress_field (optional) (dataset) +│ └─ gauge_volume (optional) (NXparameters, group) +""" + + +class _Sample: + ######################################## + # ALL methods must be `classmethod`. ## + ######################################## + + # Log keys included in the NXstress schema. + NXstress_logs = { + HidraConstants.SAMPLE_NAME, + *HidraConstants.SAMPLE_COORDINATE_NAMES, + HidraConstants.CHEMICAL_FORMULA, + HidraConstants.TEMPERATURE, + HidraConstants.STRESS_FIELD, + HidraConstants.STRESS_FIELD_DIRECTION, + } + + @classmethod + def init_group(cls, sampleLogs: SampleLogs) -> NXsample: + """ + Create SAMPLE_DESCRIPTION (NXsample) group following NXstress schema: + - subrun[nP]: link to the scanpoint axis + - vx[nP], vy[nP], vz[nP]: sample positions in mm (from SampleLogs, converted via PointList) + - name: sample descriptive name if present in logs; otherwise 'unknown' + - chemical_formula: sample formula if present in logs; otherwise 'unknown' + - [optional fields, only if present in the logs]: 'temperature', 'stress_field' + """ + # Create SAMPLE_DESCRIPTION as an NXsample + sd = NXsample() + + # Name of sample (required): try the expected log key; fall back to 'unknown'. + sd["name"] = NXfield(sampleLogs.get(HidraConstants.SAMPLE_NAME, ("unknown",))[0]) + + # Link scanpoints to subruns: subrun[nP] (unitless) + # SampleLogs.subruns is a SubRuns object; use .raw_copy() to get a NumPy array + scan_points = sampleLogs.subruns.raw_copy() + sd["scan_point"] = NXfield( + scan_points.astype(FIELD_DTYPE.INT_DATA.value), chunks=CHUNK_SHAPE(1), maxshape=(None,), units="" + ) + N_scan = len(scan_points) + + # 3) Sample positions per scanpoint (mm). Use SampleLogs.get_pointlist(). + # PointList returns vx, vy, vz arrays in millimeters. + try: + pl = sampleLogs.get_pointlist() + vv = (pl.vx, pl.vy, pl.vz) + except AssertionError as e: + if "some coordinates do not have finite values" in str(e): + vv = (np.full((N_scan,), np.nan),) * 3 + else: + raise + for axis_name, axis_values in zip(HidraConstants.SAMPLE_COORDINATE_NAMES, vv): + vs = np.asarray(axis_values, dtype=FIELD_DTYPE.FLOAT_DATA.value) + if vs.shape[0] != N_scan: + raise RuntimeError( + f"NXstress required log '{axis_name}' has unexpected shape.\n" + f" First axis should be (== {N_scan}), not {vs.shape[0]}" + ) + f = NXfield(vs, name=axis_name, units="mm") + sd[axis_name] = f + + # Optionally, add other NXstress SAMPLE_DESCRIPTION fields if available in logs: + # - `HidraConstants.CHEMICAL_FORMULA` (NXCHAR) + # - `HidraConstants.TEMPERATURE`[nTemp] (NXTEMPERATURE) + # - `HidraConstants.STRESS_FIELD`[nsField] (with `@direction` attr = 'x'|'y'|'z') + # The lines below are safe no-ops if the corresponding logs are not present. + sd["chemical_formula"] = NXfield(sampleLogs.get(HidraConstants.CHEMICAL_FORMULA, ("unknown",))[0]) + + # Example of temperature if present (stored as numeric array and units carried separately) + if HidraConstants.TEMPERATURE in sampleLogs: + tkey = HidraConstants.TEMPERATURE + tvals = np.asarray(sampleLogs[tkey], dtype=FIELD_DTYPE.FLOAT_DATA.value) + tf = NXfield(tvals, name="temperature") + tf.attrs["units"] = sampleLogs.units(tkey) or "K" + sd["temperature"] = tf + + # Example of stress_field if present (values + direction attribute) + if HidraConstants.STRESS_FIELD in sampleLogs: + # TODO: we don't have an example of these entries, so the dimensions may not be correct! + # -- Assuming: + # :: (, ...) + # :: {'x', 'y', 'z'}: scalar + # + sf = np.asarray(sampleLogs[HidraConstants.STRESS_FIELD], dtype=FIELD_DTYPE.FLOAT_DATA.value) + if sf.shape[0] != N_scan: + raise RuntimeError( + f"NXstress required log '{HidraConstants.STRESS_FIELD}' has unexpected shape.\n" + f" First axis should be (== {N_scan}), not {sf.shape[0]}" + ) + sff = NXfield(sf, name="stress_field") + # If a direction log exists, attach it; otherwise default to 'x' + direction_key = HidraConstants.STRESS_FIELD_DIRECTION + direction = sampleLogs[direction_key] if direction_key in sampleLogs else "x" + sff.attrs["direction"] = direction + sd["stress_field"] = sff + + # Retain any additional logs that happen to be present. + sd["logs"] = NXcollection() + for key in sampleLogs: + # convert ':' to '_': + name = allowed_identifier(key) + if key not in cls.NXstress_logs: + sd["logs"][name] = NXfield( + sampleLogs[key], + # source PV-log name as attribute + local_name=key, + # 'units' as attribute + units=sampleLogs.units(key), + ) + + return sd + + @classmethod + @validate_call_ + def sampleLogsFromNexus(cls, sample) -> SampleLogs: + """Read SampleLogs from an NXsample group. + + Parameters + ---------- + sample : NXsample + The NXsample group from the HDF5 file + + Returns + ------- + SampleLogs + Populated SampleLogs object + """ + + # Read scan_point array + scan_point = sample["scan_point"].nxdata + + # Initialize SampleLogs and set subruns + logs = SampleLogs() + logs.subruns = SubRuns(scan_point) + + # Read vx, vy, vz coordinates (stored at top level of NXsample) + for coord_name in HidraConstants.SAMPLE_COORDINATE_NAMES: + if coord_name in sample: + coord_field = sample[coord_name] + values = coord_field.nxdata + units = coord_field.attrs.get("units", "mm") + logs[coord_name, units] = values + + # Read extra logs from the 'logs' NXcollection (if present) + if "logs" in sample: + logs_collection = sample["logs"] + for field_name in logs_collection: + field = logs_collection[field_name] + # Get the original PV-log key from local_name attribute + original_key = field.attrs.get("local_name", field_name) + units = field.attrs.get("units", "") + values = field.nxdata + logs[original_key, units] = values + + # Read optional scalar fields + if "name" in sample: + sample_name = sample["name"].nxdata + if isinstance(sample_name, (bytes, np.bytes_)): + sample_name = sample_name.decode("utf-8") + logs[HidraConstants.SAMPLE_NAME, ""] = np.array([sample_name] * len(scan_point)) + + if "chemical_formula" in sample: + chem_formula = sample["chemical_formula"].nxdata + if isinstance(chem_formula, (bytes, np.bytes_)): + chem_formula = chem_formula.decode("utf-8") + logs[HidraConstants.CHEMICAL_FORMULA, ""] = np.array([chem_formula] * len(scan_point)) + + if "temperature" in sample: + temp_field = sample["temperature"] + temp_values = temp_field.nxdata + temp_units = temp_field.attrs.get("units", "K") + logs[HidraConstants.TEMPERATURE, temp_units] = temp_values + + if "stress_field" in sample: + stress_field = sample["stress_field"] + stress_values = stress_field.nxdata + logs[HidraConstants.STRESS_FIELD, ""] = stress_values + # Read direction attribute if present + if "direction" in stress_field.attrs: + direction = stress_field.attrs["direction"] + logs[HidraConstants.STRESS_FIELD_DIRECTION, ""] = np.array([direction] * len(scan_point)) + + return logs diff --git a/pyrs/utilities/pydantic_transition.py b/pyrs/utilities/pydantic_transition.py new file mode 100644 index 000000000..9290b7210 --- /dev/null +++ b/pyrs/utilities/pydantic_transition.py @@ -0,0 +1,8 @@ +from pydantic import ConfigDict, validate_call + + +# Use Pydantic's `validate_call` decorator with arbitrary types: +# name with trailing-underscore to avoid conflicts if `pydantic.validate_call` +# is itself ever used anywhere in the code-base. +def validate_call_(func): + return validate_call(config=ConfigDict(arbitrary_types_allowed=True))(func) diff --git a/tests/conftest.py b/tests/conftest.py index bb332bcfe..0ba239f8c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,6 @@ import numpy as np import os import pytest -import sys from pyrs.dataobjects.fields import StrainField, StrainFieldSingle, StressField from pyrs.dataobjects.sample_logs import _coerce_to_ndarray, PointList @@ -16,10 +15,11 @@ @pytest.fixture(scope="session") -def test_data_dir(): - this_module_path = sys.modules[__name__].__file__ - this_module_directory = os.path.dirname(this_module_path) - return os.path.join(this_module_directory, "data") +def test_data_dir(request): + # WARNING, there may be multiple `conftest.py`, + # and pytest often screws with the import sequence: + # do _not_ use `sys.modules[__name__].__file__` here! + return str(request.config.rootpath / "tests" / "data") @pytest.fixture(scope="session") @@ -142,7 +142,7 @@ def wrapped_function(peaks_data): ) # Back-calculate the peak centers from supplied lattice spacings - centers = 2 * np.rad2deg(np.arcsin(peaks_data["wavelength"] / (2 * peaks_data["d_spacing"]))) + centers = 2.0 * np.rad2deg(np.arcsin(peaks_data["wavelength"] / (2.0 * peaks_data["d_spacing"]))) # Enter the native parameters in the peak collection subruns_count = len(peaks_data["subruns"]) diff --git a/tests/data/HB2B_1017_w_mask.h5 b/tests/data/HB2B_1017_w_mask.h5 new file mode 100644 index 000000000..9a3600c5f Binary files /dev/null and b/tests/data/HB2B_1017_w_mask.h5 differ diff --git a/tests/scripts/cis_tests/NXstress_demo_script.py b/tests/scripts/cis_tests/NXstress_demo_script.py new file mode 100644 index 000000000..c5c6489d5 --- /dev/null +++ b/tests/scripts/cis_tests/NXstress_demo_script.py @@ -0,0 +1,478 @@ +""" +tests/scripts/cis_tests/NXstress_demo_script.py + +Smoke-test / "by hand" demo script for the NXstress I/O implementation. + +Features demonstrated +--------------------- +1. Loading a ``HidraWorkspace`` from an existing HiDRA project file + (``tests/data/3393_PWHT-TD.h5``). + +2. Fitting two diffraction peaks with + ``tests.util.peak_collection_helpers.generate_PeakCollection_from_workspace`` + to produce a ``list[PeakCollection]``. + + The ``fit_dic`` below mirrors the starting point given in the docstring of + that helper, but with ``peak_label`` values adjusted to follow the + ``peak_tag`` convention required by ``NXstress``: + + " " e.g. "Fe 311" + + where ```` is a string of 3 N digits that encodes the Miller indices + (h, k, l) as N-digit zero-padded integers. The two peaks present in the + data file are the austenitic-iron reflections "Fe 311" and "Fe 222", as + confirmed by the ``hklPhase`` log stored in the file. + +3. Writing the workspace and fitted peak collections to a new + NXstress-compatible NeXus file via ``NXstress`` used as a context manager. + +4. Reading the data back from the NXstress file and printing a short summary + to confirm that the round-trip succeeded. + +Usage +----- +Run this script directly (not via pytest):: + + python tests/scripts/cis_tests/NXstress_demo_script.py + +The output NXstress file is written to the current working directory as +``NXstress_demo_output.nxs``. +""" + +from datetime import date +from pathlib import Path + +import numpy as np + +from pyrs.core.instrument_geometry import HidraSetup +from pyrs.core.workspaces import HidraWorkspace +from pyrs.dataobjects.constants import HidraConstants +from pyrs.projectfile.file_object import HidraProjectFile, HidraProjectFileMode +from pyrs.utilities.NXstress import NXstress + +from tests.util.input_data_helpers import ensure_input_data +from tests.util.instrument_helpers import ensure_instrument_geometry +from tests.util.peak_collection_helpers import generate_FitResults_from_workspace + +# --------------------------------------------------------------------------- +# Paths +# --------------------------------------------------------------------------- + +# Repository root is two levels above the directory of this script: +# tests/scripts/cis_tests/ -> tests/scripts/ -> tests/ -> +_REPO_ROOT = Path(__file__).resolve().parents[3] + +# DATA_FILE is the baseline HiDRA project file shipped with the repository. +# Once a "--complete.h5" file has been generated on a machine with /HFIR +# mounted (see Step 1 below), DATA_FILE can be pointed at that file instead; +# the complete file includes instrument geometry and raw detector counts, so +# ensure_instrument_geometry / ensure_input_data become no-ops and the script +# runs correctly even without a live HFIR archive connection. +# ------ +DATA_FILE = _REPO_ROOT / "tests" / "data" / "3393_PWHT-TD.h5" ## *** ORIGINAL DATA SOURCE *** +# DATA_FILE = _REPO_ROOT / "tests" / "data" / "3393_PWHT-TD-2026-05-08-complete.h5" + +INPUT_DATA_PRESENT = False # set to `True` if loading from `...complete.h5` +# ------ + +OUTPUT_FILE = Path("NXstress_demo_output.nxs") + +# Workspace name is derived from the stem of DATA_FILE so that it tracks +# automatically if DATA_FILE is changed to a "-complete" variant. +WORKSPACE_NAME = DATA_FILE.stem + +# HB2B run number corresponding to DATA_FILE -- used to fetch raw counts from the archive. +DATA_RUN_NUMBER = 3393 + +# --------------------------------------------------------------------------- +# Round-trip verification helpers +# --------------------------------------------------------------------------- + +_REL_TOL = 0.01 # 1 % relative tolerance for aggregate (mean / variance) comparisons +_GEO_TOL = 1e-5 # tight tolerance for stored scalar geometry values +_WL_TOL = 1e-4 # tolerance for wavelength (stored as float32) + +_POSITION_LOGS = list(HidraConstants.SAMPLE_COORDINATE_NAMES) # ("vx", "vy", "vz") + + +def _check_approx(label: str, orig: float, back: float, rtol: float = _REL_TOL) -> None: + """Assert the two scalars agree to within *rtol* and print the result.""" + orig, back = float(orig), float(back) + rel_diff = abs(orig - back) / (abs(orig) + 1e-10) + status = "OK" if rel_diff <= rtol else "FAIL" + print(f" [{status}] {label}: orig={orig:.6g} back={back:.6g} rel_diff={rel_diff:.2e}") + assert rel_diff <= rtol, ( + f"Round-trip mismatch for '{label}': {orig} vs {back} (rtol={rtol})" + ) + + +def _to_wavelength_array(wl_raw, n: int) -> np.ndarray: + """Normalise a wavelength value (float, dict, or None) to a 1-D ndarray of length *n*.""" + if wl_raw is None: + return np.full(n, np.nan) + if isinstance(wl_raw, float): + return np.full(n, wl_raw) + if isinstance(wl_raw, dict): + return np.array(list(wl_raw.values()), dtype=float) + return np.asarray(wl_raw, dtype=float) + + +def verify_sample_group(ws: HidraWorkspace, ws_back: HidraWorkspace) -> None: + """Verify the round-tripped SAMPLE_DESCRIPTION (NXsample) group.""" + print(" [sample] log names present ...") + log_names_back = set(ws_back.sample_log_names) + assert len(log_names_back) > 0, "Read-back workspace has no sample logs" + for coord in _POSITION_LOGS: + assert coord in log_names_back, ( + f"Expected position log '{coord}' not found in read-back workspace" + ) + + n = len(ws.get_sub_runs()) + print(f" [sample] position log shapes (expected n={n}) ...") + for coord in _POSITION_LOGS: + arr = ws_back._sample_logs[coord] + assert arr.shape == (n,), ( + f"Log '{coord}': expected shape ({n},), got {arr.shape}" + ) + + print(" [sample] position log mean / variance ...") + for coord in _POSITION_LOGS: + orig_arr = ws._sample_logs[coord].astype(float) + back_arr = ws_back._sample_logs[coord].astype(float) + _check_approx(f"{coord} mean", np.nanmean(orig_arr), np.nanmean(back_arr)) + if np.nanvar(orig_arr) > 0: + _check_approx(f"{coord} var", np.nanvar(orig_arr), np.nanvar(back_arr)) + + +def verify_instrument_group(ws: HidraWorkspace, ws_back: HidraWorkspace) -> None: + """Verify the round-tripped INSTRUMENT (NXinstrument) group.""" + geom_orig = ws.get_instrument_setup() + geom_back = ws_back.get_instrument_setup() + assert geom_back is not None, "Read-back workspace has no instrument geometry" + + print(" [instrument] geometry scalars ...") + _check_approx("arm_length", geom_orig.arm_length, geom_back.arm_length, rtol=_GEO_TOL) + orig_rows, orig_cols = geom_orig.detector_size + back_rows, back_cols = geom_back.detector_size + _check_approx("detector nrows", orig_rows, back_rows, rtol=_GEO_TOL) + _check_approx("detector ncols", orig_cols, back_cols, rtol=_GEO_TOL) + orig_px, orig_py = geom_orig.pixel_dimension + back_px, back_py = geom_back.pixel_dimension + _check_approx("pixel_size_x", orig_px, back_px, rtol=_GEO_TOL) + _check_approx("pixel_size_y", orig_py, back_py, rtol=_GEO_TOL) + + print(" [instrument] wavelength ...") + n = len(ws.get_sub_runs()) + # `get_wavelength` always returns `_wave_length` first (regardless of the calibrated flag) + # when it is set, so use calibrated=False which matches how NXstress stored it. + wl_orig = _to_wavelength_array(ws.get_wavelength(calibrated=False, throw_if_not_set=False), n) + wl_back = _to_wavelength_array(ws_back.get_wavelength(calibrated=False, throw_if_not_set=False), n) + assert wl_back.shape == (n,), f"Wavelength shape: expected ({n},), got {wl_back.shape}" + assert not np.all(np.isnan(wl_back)), "All read-back wavelength values are NaN" + _check_approx("wavelength mean", np.nanmean(wl_orig), np.nanmean(wl_back), rtol=_WL_TOL) + + +def verify_input_data_group(ws: HidraWorkspace, ws_back: HidraWorkspace) -> None: + """Verify the round-tripped INPUT_DATA (NXdata / detector_counts) group. + + If *ws* has raw counts (loaded via ``ensure_input_data``), confirm that the + read-back workspace contains the same number of sub-runs with counts and + that the per-sub-run pixel arrays agree to within floating-point precision. + + If *ws* has no raw counts (the project file was loaded without them and + ``ensure_input_data`` was not called), just confirm that no counts were + spuriously created on the read-back. + """ + n_orig = len(ws._raw_counts) + n_back = len(ws_back._raw_counts) + print(f" [input_data] raw_counts entries: orig={n_orig} back={n_back}") + + if n_orig == 0: + assert n_back == 0, ( + f"Expected no raw counts in read-back workspace (none were written), got {n_back}" + ) + print(" [--] no raw counts written -- skipping pixel comparison") + return + + assert n_back == n_orig, ( + f"raw_counts sub-run count mismatch: orig={n_orig} back={n_back}" + ) + + sub_runs = sorted(ws._raw_counts.keys()) + for sr in sub_runs: + orig_counts = ws._raw_counts[sr].astype(float) + back_counts = ws_back._raw_counts[sr].astype(float) + assert orig_counts.shape == back_counts.shape, ( + f"sub_run={sr}: detector_counts shape mismatch: " + f"{orig_counts.shape} vs {back_counts.shape}" + ) + _check_approx( + f"sub_run={sr} detector_counts mean", + float(np.nanmean(orig_counts)), + float(np.nanmean(back_counts)), + rtol=_REL_TOL, + ) + print(f" pixel arrays compared for {len(sub_runs)} sub-run(s)") + + +def verify_diffraction_group(ws: HidraWorkspace, ws_back: HidraWorkspace) -> None: + """Verify the round-tripped FIT / diffractogram (NXdata) group.""" + assert ws_back._2theta_matrix is not None, "Read-back workspace has no 2θ matrix" + + orig_shape = ws._2theta_matrix.shape + back_shape = ws_back._2theta_matrix.shape + print(f" [diffraction] 2θ matrix shape: orig={orig_shape} back={back_shape}") + assert orig_shape == back_shape, ( + f"2θ matrix shape mismatch: {orig_shape} vs {back_shape}" + ) + + orig_masks = set(ws._diff_data_set.keys()) + back_masks = set(ws_back._diff_data_set.keys()) + print(f" [diffraction] mask keys: orig={orig_masks} back={back_masks}") + assert orig_masks == back_masks, ( + f"Diffraction mask key mismatch: {orig_masks} vs {back_masks}" + ) + + for mask_id in orig_masks: + orig_data = ws._diff_data_set[mask_id] + back_data = ws_back._diff_data_set[mask_id] + assert orig_data.shape == back_data.shape, ( + f"Diffraction data shape mismatch for mask={mask_id!r}: " + f"{orig_data.shape} vs {back_data.shape}" + ) + finite_back = back_data[np.isfinite(back_data)] + assert len(finite_back) > 0, ( + f"All diffraction data for mask={mask_id!r} is non-finite" + ) + assert np.any(finite_back != 0), ( + f"All diffraction data for mask={mask_id!r} is zero" + ) + _check_approx( + f"mask={mask_id!r} intensity mean", + np.nanmean(orig_data), np.nanmean(back_data), + ) + if np.nanvar(orig_data) > 0: + _check_approx( + f"mask={mask_id!r} intensity var", + np.nanvar(orig_data), np.nanvar(back_data), + ) + + +def verify_peaks_group(peak_collections: list, peaks_back: list) -> None: + """Verify the round-tripped PEAKS (NXreflections) and FIT/peak_parameters groups.""" + assert len(peaks_back) == len(peak_collections), ( + f"PeakCollection count: expected {len(peak_collections)}, got {len(peaks_back)}" + ) + + def _sort_key(pc): + # Normalise tag so "Fe 311" and "Fe311" both become "Fe311" for matching. + return pc.peak_tag.replace(" ", "") + + orig_sorted = sorted(peak_collections, key=_sort_key) + back_sorted = sorted(peaks_back, key=_sort_key) + + for orig, back in zip(orig_sorted, back_sorted): + tag = orig.peak_tag + print(f" [peaks] '{tag}' ...") + + assert orig.peak_profile == back.peak_profile, ( + f"peak_profile mismatch for '{tag}': {orig.peak_profile!r} vs {back.peak_profile!r}" + ) + assert orig.background_type == back.background_type, ( + f"background_type mismatch for '{tag}': {orig.background_type!r} vs {back.background_type!r}" + ) + + orig_runs = orig.sub_runs.raw_copy() + back_runs = back.sub_runs.raw_copy() + assert len(orig_runs) == len(back_runs), ( + f"sub_runs length mismatch for '{tag}': {len(orig_runs)} vs {len(back_runs)}" + ) + assert np.array_equal(orig_runs, back_runs), ( + f"sub_runs values mismatch for '{tag}'" + ) + + orig_dref, _ = orig.get_d_reference() + back_dref, _ = back.get_d_reference() + orig_dref_is_nan = np.all(np.isnan(orig_dref)) + assert orig_dref_is_nan == np.all(np.isnan(back_dref)), ( + f"d_reference NaN status mismatch for '{tag}': " + f"orig all-NaN={orig_dref_is_nan}, back all-NaN={np.all(np.isnan(back_dref))}" + ) + assert not orig_dref_is_nan, ( + f"d_reference is all-NaN for '{tag}' — was 'd0' set in fit_dic?" + ) + _check_approx(f"'{tag}' d_reference mean", np.nanmean(orig_dref), np.nanmean(back_dref), rtol=1e-5) + + orig_vals, orig_errs = orig.get_native_params() + back_vals, back_errs = back.get_native_params() + assert orig_vals.shape == back_vals.shape, ( + f"Native param array shape mismatch for '{tag}': {orig_vals.shape} vs {back_vals.shape}" + ) + for field in orig_vals.dtype.names: + o_mean = float(np.nanmean(orig_vals[field].astype(float))) + b_mean = float(np.nanmean(back_vals[field].astype(float))) + _check_approx(f"'{tag}' param '{field}' mean", o_mean, b_mean) + + # Error comparison: all fields (including Intensity for PseudoVoigt) round-trip + # exactly now that the sigma_I inversion in peakParametersForRange is correct. + for field in orig_errs.dtype.names: + o_err = orig_errs[field].astype(float) + b_err = back_errs[field].astype(float) + _check_approx( + f"'{tag}' error '{field}' mean", + float(np.nanmean(o_err)), float(np.nanmean(b_err)), + ) + + print(f" fit_costs length: {len(back.fitting_costs)} (expected {len(orig_runs)})") + assert len(back.fitting_costs) == len(orig_runs), ( + f"fitting_costs length mismatch for '{tag}': " + f"{len(back.fitting_costs)} vs {len(orig_runs)}" + ) + + +# --------------------------------------------------------------------------- +# Peak-fit configuration +# --------------------------------------------------------------------------- +# ``peak_label`` values MUST follow the ``peak_tag`` convention so that +# ``_Peaks._parse_peak_tag`` can extract a phase name and Miller indices. +# The data file records "Fe 311, Fe 222" in its ``hklPhase`` log. +# +# fit_dic format: +# key – arbitrary string used as an ordered loop index +# value – dict with: +# "peak_range" : [x_min, x_max] (2θ in degrees) +# "peak_label" : peak_tag string (" ") +# "d0" : reference d-spacing in Å (for strain calculation) +FIT_DIC = { + "0": {"peak_range": [87.599, 91.569], "peak_label": "Fe 311", "d0": 1.08}, + "1": {"peak_range": [93.544, 95.890], "peak_label": "Fe 222", "d0": 1.03}, +} + +# --------------------------------------------------------------------------- +# Step 1 – Load the HidraWorkspace +# --------------------------------------------------------------------------- +print("=" * 60) +print("Step 1: Loading HidraWorkspace") +print(f" file: {DATA_FILE}") + +ws = HidraWorkspace(WORKSPACE_NAME) +with HidraProjectFile(DATA_FILE, mode=HidraProjectFileMode.READONLY) as project_file: + ws.load_hidra_project(project_file, load_raw_counts=INPUT_DATA_PRESENT, load_reduced_diffraction=True) + +# Track whether anything was added to the workspace beyond what DATA_FILE +# already contained, so we know whether to write a "-complete" project file. +_geometry_added = ws._instrument_setup is None +_had_raw_counts = bool(ws._raw_counts) # True when the file already contained them +_raw_counts_added = False + +# Most Hidra project files have no instrument section; NXstress requires one. +# Install the nominal HB2B engineering geometry if none was stored in the file. +ensure_instrument_geometry(ws) + +# Load the raw detector counts from the HFIR archive so that the NXstress +# input_data group is written and can be verified on read-back. +# This requires a live connection to the HFIR archive; if the run is not +# accessible, ensure_input_data is a no-op and the input_data group will +# simply be empty (the rest of the demo continues normally). +try: + ensure_input_data(ws, DATA_RUN_NUMBER) + _raw_counts_added = bool(ws._raw_counts) and not _had_raw_counts + print(f" raw counts loaded : {len(ws._raw_counts)} sub-run(s)") +except Exception as _exc: # noqa: BLE001 + print(f" [WARN] could not load raw counts from archive: {_exc}") + print(" input_data group will be empty -- continuing.") + +print(f" sub-runs loaded : {len(ws.get_sub_runs())}") +print(f" wavelength : {ws.get_wavelength(calibrated=True, throw_if_not_set=False)} Angstrom") + +# --------------------------------------------------------------------------- +# Step 1b -- Persist a "-complete" HiDRA project file when new data was added +# --------------------------------------------------------------------------- +# If geometry or raw counts were loaded that were absent from DATA_FILE, save a +# self-contained project file next to DATA_FILE. On subsequent runs (with or +# without /HFIR mounted) DATA_FILE can be pointed at this file directly. +if _geometry_added or _raw_counts_added: + _today = date.today().isoformat() # e.g. "2026-05-08" + _complete_file = DATA_FILE.with_name(f"{WORKSPACE_NAME}-{_today}-complete.h5") + print() + print(f" Saving complete HiDRA project file -> {_complete_file}") + with HidraProjectFile(_complete_file, mode=HidraProjectFileMode.OVERWRITE) as _hf: + if ws._instrument_setup is not None: + _hf.write_instrument_geometry(HidraSetup(ws.get_instrument_setup())) + ws.save_experimental_data(_hf, ignore_raw_counts=not _raw_counts_added) + # save_experimental_data only writes raw counts + sample logs; the reduced + # diffraction data lives in a separate HDF5 group and must be written explicitly. + if ws._2theta_matrix is not None: + _hf.write_reduced_diffraction_data_set( + ws._2theta_matrix, + ws._diff_data_set, + ws._var_data_set, + ) + print(f" Written: {_complete_file.resolve()}") + +# --------------------------------------------------------------------------- +# Step 2 – Fit peaks and build list[PeakCollection] +# --------------------------------------------------------------------------- +print() +print("=" * 60) +print("Step 2: Fitting peaks with generate_FitResults_from_workspace") + +fit_results = generate_FitResults_from_workspace(ws, FIT_DIC) +peak_collections = [pc for result in fit_results for pc in result.peakcollections] + +print(f" PeakCollections fitted: {len(peak_collections)}") +for pc in peak_collections: + print(f" peak_tag : {pc.peak_tag!r}") + print(f" peak_profile : {pc.peak_profile}") + print(f" background : {pc.background_type}") + +# --------------------------------------------------------------------------- +# Step 3 – Write to NXstress file +# --------------------------------------------------------------------------- +print() +print("=" * 60) +print(f"Step 3: Writing NXstress file -> {OUTPUT_FILE}") + +with NXstress(OUTPUT_FILE, mode="w") as nxs: + nxs.write(ws, peak_collections) + +print(f" Written: {OUTPUT_FILE.resolve()}") + +# --------------------------------------------------------------------------- +# Step 4 – Read back and verify round-trip +# --------------------------------------------------------------------------- +print() +print("=" * 60) +print("Step 4: Reading back from NXstress file") + +with NXstress(OUTPUT_FILE, mode="r") as nxs: + ws_back, peaks_back = nxs.read(entry_number=1) + +print(f" sub-runs read back : {len(ws_back.get_sub_runs())}") +print(f" PeakCollections read : {len(peaks_back)}") +for pc in peaks_back: + print(f" peak_tag (read back): {pc.peak_tag!r}") + +print() +print("Verifying SAMPLE group ...") +verify_sample_group(ws, ws_back) + +print() +print("Verifying INSTRUMENT group ...") +verify_instrument_group(ws, ws_back) + +print() +print("Verifying INPUT_DATA group ...") +verify_input_data_group(ws, ws_back) + +print() +print("Verifying DIFFRACTION group ...") +verify_diffraction_group(ws, ws_back) + +print() +print("Verifying PEAKS group ...") +verify_peaks_group(peak_collections, peaks_back) + +print() +print("=" * 60) +print("Demo completed successfully.") diff --git a/tests/scripts/cis_tests/README.rst b/tests/scripts/cis_tests/README.rst new file mode 100644 index 000000000..3e8d059e0 --- /dev/null +++ b/tests/scripts/cis_tests/README.rst @@ -0,0 +1,3 @@ +This directory contains scripts used for by hand smoke-tests to verify the implementation of PyRS features. + +All scripts in this directory will be automatically ignored by the pytest collection system. diff --git a/tests/unit/pyrs/projectfile/test_file_object.py b/tests/unit/pyrs/projectfile/test_file_object.py index e647ac45f..ec2d202c4 100644 --- a/tests/unit/pyrs/projectfile/test_file_object.py +++ b/tests/unit/pyrs/projectfile/test_file_object.py @@ -145,6 +145,82 @@ def test_detector_efficiency(self): # Clean os.remove("test_efficient.hdf") + def test_reduced_diffraction_masks_excludes_variance_datasets(self, tmpdir): + """read_diffraction_masks must not return variance datasets (those ending in '_var'). + + write_reduced_diffraction_data_set stores intensity data under 'main' (or a named + mask key) and variance data under 'main_var'. Before the fix, read_diffraction_masks + returned both, causing _load_reduced_diffraction_data to load 'main_var' as a second + intensity mask and populate _diff_data_set with a spurious 'main_var' entry. + + This test: + 1. Writes a project file with one default-mask intensity + variance dataset. + 2. Reads back the mask list and asserts '_var' keys are absent. + 3. Loads the workspace and confirms _diff_data_set has exactly one key (None), + while _var_data_set also has exactly one key (None) with the correct variance values. + """ + from pyrs.core.workspaces import HidraWorkspace + + test_file = str(tmpdir.join("test_diffraction_masks.h5")) + + n_subruns = 3 + n_bins = 50 + two_theta = np.tile(np.linspace(80.0, 95.0, n_bins), (n_subruns, 1)) + intensity = np.random.default_rng(0).uniform(0.0, 1000.0, (n_subruns, n_bins)) + variance = intensity * 0.01 # distinct from sqrt(intensity) so we can tell them apart + + # --- write --- + pf_write = HidraProjectFile(test_file, HidraProjectFileMode.OVERWRITE) + + # write_reduced_diffraction_data_set requires sub-run entries in the file + for sr in range(1, n_subruns + 1): + pf_write.append_raw_counts(sr, np.zeros(4)) + + # populate the subruns log so load_hidra_project can read the spectrum map + # pf_write.write_sub_runs(np.arange(1, n_subruns + 1)) + pf_write.append_experiment_log(HidraConstants.SUB_RUNS, np.arange(1, n_subruns + 1)) + + pf_write.write_reduced_diffraction_data_set( + two_theta, + {None: intensity}, + {None: variance}, + ) + pf_write.save(verbose=False) + + # --- read masks --- + pf_read = HidraProjectFile(test_file, HidraProjectFileMode.READONLY) + masks = pf_read.read_diffraction_masks() + + # Only the intensity mask ('main') should be visible -- no '_var' entries. + assert "main_var" not in masks, "read_diffraction_masks returned a variance dataset as a mask: {}".format( + masks + ) + # The default mask is stored as 'main'; read_diffraction_masks should keep it. + assert "main" in masks, "Expected 'main' in masks, got: {}".format(masks) + + # --- load into a workspace and verify both dicts --- + ws = HidraWorkspace("test") + ws.load_hidra_project(pf_read, load_raw_counts=False, load_reduced_diffraction=True) + + # _diff_data_set must have exactly one key: None (the default mask) + assert set(ws._diff_data_set.keys()) == {None}, "Expected {{None}} in _diff_data_set, got: {}".format( + set(ws._diff_data_set.keys()) + ) + # _var_data_set must also have exactly one key: None + assert set(ws._var_data_set.keys()) == {None}, "Expected {{None}} in _var_data_set, got: {}".format( + set(ws._var_data_set.keys()) + ) + + # Intensity values must round-trip exactly (stored as float64) + np.testing.assert_array_equal(ws._diff_data_set[None], intensity) + + # Variance values must round-trip exactly and must NOT equal sqrt(intensity), + # confirming the stored variance was used rather than the fallback. + np.testing.assert_array_equal(ws._var_data_set[None], variance) + assert not np.allclose(ws._var_data_set[None], np.sqrt(intensity)), ( + "Variance readback matches sqrt(intensity) -- the stored variance was not used" + ) + def test_wave_length_rw(self): """Test writing and reading for wave length diff --git a/tests/unit/pyrs/utilities/NXstress/conftest.py b/tests/unit/pyrs/utilities/NXstress/conftest.py new file mode 100644 index 000000000..9d6b8027a --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/conftest.py @@ -0,0 +1,28 @@ +from collections.abc import Callable, Generator +from pathlib import Path + + +from pyrs.core.workspaces import HidraWorkspace +from pyrs.projectfile.file_object import HidraProjectFile, HidraProjectFileMode + +import pytest +from tests.util.peak_collection_helpers import createPeakCollection + + +@pytest.fixture +def load_HidraWorkspace(test_data_dir) -> Generator[Callable[..., HidraWorkspace]]: + # This fixture loads a `HidraWorkspace` instance from a `HidraProject`-format file. + + def _init(*, file_name: str, name: str, load_raw_counts=True, load_reduced_diffraction=True) -> HidraWorkspace: + file_path = Path(test_data_dir) / file_name + ws = HidraWorkspace(name) + with HidraProjectFile(file_path, mode=HidraProjectFileMode.READONLY) as project_file: + ws.load_hidra_project( + project_file, load_raw_counts=load_raw_counts, load_reduced_diffraction=load_reduced_diffraction + ) + return ws + + yield _init + + # teardown follows + pass diff --git a/tests/unit/pyrs/utilities/NXstress/test_NXstress.py b/tests/unit/pyrs/utilities/NXstress/test_NXstress.py new file mode 100644 index 000000000..39bb5e0d9 --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_NXstress.py @@ -0,0 +1,759 @@ +# ruff: noqa: E741 # use `l` for `l` in `(h, k, l)`! +from collections.abc import Callable +from nexusformat.nexus import ( + NXbeam, + NXcollection, + NXdata, + NXdetector, + NXentry, + NXinstrument, + NXmonochromator, + NXnote, + NXparameters, + NXprocess, + NXreflections, + NXsample, + NXsource, +) +from pathlib import Path + +from pyrs.core.workspaces import HidraWorkspace +from pyrs.peaks.peak_collection import PeakCollection +from pyrs.utilities.NXstress._definitions import FIELD_DTYPE, GROUP_NAME +from pyrs.utilities.NXstress._fit import _Diffractogram, _Fit, _PeakParameters, _BackgroundParameters +from pyrs.utilities.NXstress._input_data import _InputData +from pyrs.utilities.NXstress._instrument import _Instrument, _Masks +from pyrs.utilities.NXstress._peaks import _Peaks +from pyrs.utilities.NXstress._sample import _Sample +from pyrs.utilities.NXstress.NXstress import NXstress + +import pytest + + +class TestNXstress: + # instrument, input data, reduced data, no mask + PROJECT_FILE_A = "HB2B_1017.h5" + + # instrument, mask, reduced data, but no input data + PROJECT_FILE_B = "HB2B_1628.h5" + + # instrument, mask (from '1628'), input data, reduced data + PROJECT_FILE_C = "HB2B_1017_w_mask.h5" + + @pytest.fixture(autouse=True) + def setUp(self, load_HidraWorkspace, createPeakCollection): + """ + self.sampleLogs = self.ws._sample_logs + self.subruns = self.ws._sample_logs.subruns.raw_copy() + + N_subrun = len(self.subruns) + self.peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun + ) + self.peak1 = createPeakCollection( + peak_tag="111 Si", + peak_profile="PseudoVoigt", + background_type="Linear", + wavelength=10.1, + projectfilename="/does/not/exist2.h5", + runnumber=12346, + N_subrun=N_subrun + ) + """ + # Unfortunately, no available project file actually includes + # all of the necessary data to initialize the NXstress file. + # The tests below, use different files to verify different sections. + yield + + # teardown follows ... + pass + + def test_NXstress_context_manager( + self, + tmp_path: Path, + load_HidraWorkspace: Callable[..., HidraWorkspace], + createPeakCollection: Callable[..., PeakCollection], + ): + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, + name="test_workspace", + # raw-counts load => instrument load + load_raw_counts=True, + load_reduced_diffraction=True, + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + file_path = tmp_path / "test_NXstress_context_manager.nxs" + assert not file_path.exists() + + with NXstress(file_path, "w") as nx: + nx.write(ws, [peak0]) + assert nx._root is not None + assert file_path.exists() + + def test_NXentry_fields( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + # Verify that all required datasets, and attributes are present + # on the `NXentry` + + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, + name="test_workspace", + # raw-counts load => instrument load + load_raw_counts=True, + load_reduced_diffraction=True, + ) + + required_datasets = ("definition", "start_time", "end_time", "processing_type") + + entry = NXstress._init(ws) + assert isinstance(entry, NXentry) + for key in required_datasets: + assert key in entry + + def test_NXentry_subgroups( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + # Verify that all required subgroups are present + # on the `NXentry` + + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, + name="test_workspace", + # raw-counts load => instrument load + load_raw_counts=True, + load_reduced_diffraction=True, + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + required_groups = ( + (GROUP_NAME.SAMPLE_DESCRIPTION, NXsample), + (GROUP_NAME.FIT, NXprocess), + (GROUP_NAME.PEAKS, NXreflections), + ) + + entry = NXstress.init_group(ws, [peak0]) + assert isinstance(entry, NXentry) + for key, NXclass_ in required_groups: + assert key in entry + assert isinstance(entry[key], NXclass_) + + def test_NXentry_input_data( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + # Verify that an optional `input_data` `NXdata` group will be created on the `NXentry` + # when detector-counts data is attached to the source workspace. + + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, + name="test_workspace", + # raw-counts load => instrument load + load_raw_counts=True, + load_reduced_diffraction=True, + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + entry = NXstress.init_group(ws, [peak0]) + assert isinstance(entry, NXentry) + key, NXclass_ = GROUP_NAME.INPUT_DATA, NXdata + assert key in entry + assert isinstance(entry[key], NXclass_) + + def test_NXentry_input_data_optional( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + # When no input data is attached to the source workspace: + # verify that an empty (i.e. no scan-points) `input_data` `NXdata` group is created on the `NXentry`. + + # Notes: + # -- A successful instrument load is required; this is keyed to detector-counts data load. + # So we need to fudge the workspace after the load in order to _remove_ the attached input data. + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, + name="test_workspace", + # raw-counts load => instrument load + load_raw_counts=True, + load_reduced_diffraction=True, + ) + # remove the input data: + ws._raw_counts = dict() + + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + entry = NXstress.init_group(ws, [peak0]) + assert isinstance(entry, NXentry) + key, NXclass_ = GROUP_NAME.INPUT_DATA, NXdata + assert key in entry + assert isinstance(entry[key], NXclass_) + assert len(entry[key]["scan_point"]) == 0 + + def test_NXentry_multiple( + self, + tmp_path: Path, + load_HidraWorkspace: Callable[..., HidraWorkspace], + createPeakCollection: Callable[..., PeakCollection], + ): + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, + name="test_workspace", + # raw-counts load => instrument load + load_raw_counts=True, + load_reduced_diffraction=True, + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + peak1 = createPeakCollection( + peak_tag="Si 111", + peak_profile="PseudoVoigt", + background_type="Quadratic", + wavelength=20.6, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + file_path = tmp_path / "test_NXstress_multiple_NXentry.nxs" + with NXstress(file_path, "w") as nx: + nx.write(ws, [peak0]) + nx.write(ws, [peak1]) + root = nx._root + + assert root is not None + assert len(root.NXentry) == 2 + assert "entry" in root + assert "entry_2" in root + + assert file_path.exists() + + # *** DEBUG *** : for validation: + # shutil.copy2(file_path, Path('${workspaces}/ORNL-work/PyRS/tmp/validation')) + + def test__Instrument_fields_and_subgroups( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_A, + name="test_workspace", + # raw-counts load => instrument load + load_raw_counts=True, + load_reduced_diffraction=True, + ) + + required_fields = ("name",) + required_subgroups = ( + (GROUP_NAME.SOURCE, NXsource), + (GROUP_NAME.BEAM, NXbeam), + (GROUP_NAME.MONOCHROMATOR, NXmonochromator), + (GROUP_NAME.DETECTOR, NXdetector), + # Optional field for NXstress: + (GROUP_NAME.MASKS, NXcollection), + ) + + inst = _Instrument.init_group(ws) + assert isinstance(inst, NXinstrument) + for key in required_fields: + assert key in inst + for key, NXclass_ in required_subgroups: + assert key in inst + assert isinstance(inst[key], NXclass_) + + def test__Masks_fields_and_subgroups( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_A, + name="test_workspace", + # raw-counts load => instrument load + load_raw_counts=True, + load_reduced_diffraction=True, + ) + + required_fields = ("names",) + required_subgroups = (("detector", NXcollection), ("solid_angle", NXcollection)) + + masks = _Masks.init_group(ws) + assert isinstance(masks, NXcollection) + for key in required_fields: + assert key in masks + for key, NXclass_ in required_subgroups: + assert key in masks + assert isinstance(masks[key], NXclass_) + + def test__Sample_fields_and_subgroups( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + required_fields = ( + "name", + # not required by `NXstress`, but _possibly_ required by PyRS: + "vx", + "vy", + "vz", + ) + required_subgroups: list[tuple[str, type[object]]] = [] + + sample = _Sample.init_group(ws._sample_logs) + assert isinstance(sample, NXsample) + for key in required_fields: + assert key in sample + # Placeholder: no required subgroups yet: + for key, NXclass_ in required_subgroups: + assert key in sample + assert isinstance(sample[key], NXclass_) + + def test__Fit_fields_and_subgroups( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + required_fields = ("date", "program") + required_subgroups = ( + (GROUP_NAME.DESCRIPTION, NXnote), + (GROUP_NAME.INPUT, NXparameters), + (GROUP_NAME.PEAK_PARAMETERS, NXparameters), + (GROUP_NAME.BACKGROUND_PARAMETERS, NXparameters), + (GROUP_NAME.DIFFRACTOGRAM, NXdata), + ) + + fit = _Fit.init_group(ws, [peak0], sampleLogs) + assert isinstance(fit, NXprocess) + for key in required_fields: + assert key in fit + for key, NXclass_ in required_subgroups: + assert key in fit + assert isinstance(fit[key], NXclass_) + + def test_write_without_context_manager( + self, + tmp_path: Path, + load_HidraWorkspace: Callable[..., HidraWorkspace], + createPeakCollection: Callable[..., PeakCollection], + ): + """Verify RuntimeError when write() is called without context manager""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + file_path = tmp_path / "test_no_context.nxs" + nx = NXstress(file_path, "w") + + with pytest.raises(RuntimeError, match=r".*only usage as context manager is supported.*"): + nx.write(ws, [peak0]) + + def test_NXentry_init_fallback_timestamps( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify NXstress._init succeeds when timestamps are not valid ISO-8601""" + # Load workspace and deliberately corrupt the timestamps + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + # Corrupt the timestamps to trigger the fallback path + bad_timestamps = [b"not-valid-iso8601" for _ in ws._sample_logs.subruns] + ws._sample_logs["start_time"] = bad_timestamps + ws._sample_logs["end_time"] = bad_timestamps + + # Should not raise - fallback path handles this + entry = NXstress._init(ws) + assert isinstance(entry, NXentry) + assert "start_time" in entry + assert "end_time" in entry + + def test_validateWorkspaceAndPeaksData_valid( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify _validateWorkspaceAndPeaksData completes without error for valid data""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + # Should not raise + NXstress._validateWorkspaceAndPeaksData(ws, [peak0]) + + def test_NXentry_definition_value( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify entry['definition'] is 'NXstress' and processing_type is 'd-spacing'""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + entry = NXstress._init(ws) + assert entry["definition"] == "NXstress" + assert entry["processing_type"] == "d-spacing" + + def test__PeakParameters_fields_and_subgroups( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + # Load a workspace in order to get a realistic axis. + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="PseudoVoigt", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + peak0_params_value, peak0_params_error = peak0.get_effective_params() + + required_fields = ( + "title", + "center", + # Not all of these fields are required by `NXstress`, but + # as these are available in PyRS, they will be used here. + "center_errors", + "height", + "height_errors", + "fwhm", + "fwhm_errors", + "form_factor", + "form_factor_errors", + ) + + peak_parameters = _PeakParameters.init_group([peak0]) + assert isinstance(peak_parameters, NXparameters) + for key in required_fields: + assert key in peak_parameters + + # Verify mixing to form factor conversion. + assert pytest.approx(peak_parameters["form_factor"], 1.0e-6) == (1.0 - peak0_params_value["Mixing"]).astype( + FIELD_DTYPE.FLOAT_DATA.value + ) + + def test__BackgroundParameters_fields_and_subgroups( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + # Load a workspace in order to get a realistic axis. + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="PseudoVoigt", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + peak0_params_value, peak0_params_error = peak0.get_effective_params() + + required_fields = ( + "title", + # Not all of these fields are required by `NXstress`, but + # as PyRS uses polynomial background functions, they will be used here. + "A0", + "A0_errors", + "A1", + "A1_errors", + "A2", + "A2_errors", + ) + + background_parameters = _BackgroundParameters.init_group([peak0]) + assert isinstance(background_parameters, NXparameters) + for key in required_fields: + assert key in background_parameters + + def test__Diffractogram_fields_and_subgroups( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + required_attributes = ("signal", "auxiliary_signals", "axes") + required_fields = ( + "scan_point", + GROUP_NAME.DGRAM_TWO_THETA_NAME, + GROUP_NAME.DGRAM_DIFFRACTOGRAM, + GROUP_NAME.DGRAM_DIFFRACTOGRAM_ERRORS, + GROUP_NAME.DGRAM_FIT, + GROUP_NAME.DGRAM_FIT_ERRORS, + ) + required_subgroups: list[tuple[str, type[object]]] = [] + + dgram = _Diffractogram.init_group(ws, "_DEFAULT_", [peak0]) + assert isinstance(dgram, NXdata) + for key in required_attributes: + assert key in dgram.attrs + for key in required_fields: + assert key in dgram + # Placeholder: there are currently no required subgroups: + for key, NXclass_ in required_subgroups: + assert key in dgram + assert isinstance(dgram[key], NXclass_) + + def test__Peaks_fields_and_subgroups( + self, + tmp_path: Path, + load_HidraWorkspace: Callable[..., HidraWorkspace], + createPeakCollection: Callable[..., PeakCollection], + ): + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + sampleLogs = ws._sample_logs + subruns = sampleLogs.subruns.raw_copy() + + N_subrun = len(subruns) + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + required_fields = ( + "h", + "k", + "l", + "phase_name", + "qx", + "qy", + "qz", + "center", + "center_errors", + "center_type", + "sx", + "sy", + "sz", + ) + required_subgroups: list[tuple[str, type[object]]] = [] + + peaks = _Peaks.init_group([peak0], sampleLogs) + assert isinstance(peaks, NXreflections) + for key in required_fields: + assert key in peaks + # Placeholder: no required subgroups yet: + for key, NXclass_ in required_subgroups: + assert key in peaks + assert isinstance(peaks[key], NXclass_) + + def test__parse_peak_tag(self): + phase, (h, k, l) = _Peaks._parse_peak_tag("Al 452411") + assert phase == "Al" + assert (45, 24, 11) == (h, k, l) + + phase, (h, k, l) = _Peaks._parse_peak_tag("111 Al2O3") + assert phase == "Al2O3" + assert (1, 1, 1) == (h, k, l) + + phase, (h, k, l) = _Peaks._parse_peak_tag("010203 Silicon") + assert phase == "Silicon" + assert (1, 2, 3) == (h, k, l) + + # Behavior check: takes longest digits substring. + # This would not be a "real" peak tag! + phase, (h, k, l) = _Peaks._parse_peak_tag("321 010203 Silicon") + assert phase == "321 Silicon" + assert (1, 2, 3) == (h, k, l) + + with pytest.raises(RuntimeError, match=r".*Unable to parse peak tag.*"): + # substrings must have length divisible by 3 + _phase, (_h, _k, _l) = _Peaks._parse_peak_tag("0102 Silicon") + + with pytest.raises(RuntimeError, match=r".*Unable to parse peak tag.*"): + # must contain an (h, k, l) substring + _phase, (_h, _k, _l) = _Peaks._parse_peak_tag("Silicon") + + with pytest.raises(RuntimeError, match=r".*Unable to parse from peak tag.*"): + # must contain a phase substring + _phase, (_h, _k, _l) = _Peaks._parse_peak_tag("102030") + + def test__InputData_fields_and_subgroups( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_A, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + required_attributes = ("axes", "signal") + required_fields = ("scan_point", "detector_counts") + required_subgroups: list[tuple[str, type[object]]] = [] + + data = _InputData.init_group(ws) + assert isinstance(data, NXdata) + for key in required_attributes: + assert key in data.attrs + for key in required_fields: + assert key in data + # Placeholder: no required subgroups yet: + for key, NXclass_ in required_subgroups: + assert key in data + assert isinstance(data[key], NXclass_) + + def test__InputData_omitted( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + # When input-data is not attached to the source workspace, + # the structure of the input-data group should still be filled in. + ws = load_HidraWorkspace( + # PROJECT_B doesn't include any raw-counts data. + file_name=self.PROJECT_FILE_B, + name="test_workspace", + load_raw_counts=False, + load_reduced_diffraction=True, + ) + + required_attributes = ("axes", "signal") + required_fields = ("scan_point", "detector_counts") + required_subgroups: list[tuple[str, type[object]]] = [] + + data = _InputData.init_group(ws) + assert isinstance(data, NXdata) + for key in required_attributes: + assert key in data.attrs + for key in required_fields: + assert key in data + # Placeholder: no required subgroups yet: + for key, NXclass_ in required_subgroups: + assert key in data + assert isinstance(data[key], NXclass_) diff --git a/tests/unit/pyrs/utilities/NXstress/test_definitions.py b/tests/unit/pyrs/utilities/NXstress/test_definitions.py new file mode 100644 index 000000000..02cecc411 --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_definitions.py @@ -0,0 +1,117 @@ +""" +Tests for pyrs/utilities/NXstress/_definitions.py +""" + +import numpy as np +import pytest + +from pyrs.utilities.NXstress._definitions import ( + CHUNK_SHAPE, + FIELD_DTYPE, + GROUP_NAME, + group_naming_scheme, + allowed_identifier, + is_ISO_8601, + DEFAULT_TAG, +) + + +class TestDefinitions: + """Test suite for _definitions.py utility functions and enums""" + + def test_CHUNK_SHAPE(self): + """Verify CHUNK_SHAPE returns correct tuples for ranks 1-3""" + assert CHUNK_SHAPE(1) == (100,) + assert CHUNK_SHAPE(2) == (1, 100) + assert CHUNK_SHAPE(3) == (1, 1, 100) + + def test_FIELD_DTYPE_call(self): + """Verify calling a FIELD_DTYPE enum member returns expected NumPy dtype""" + # Test that calling enum members constructs values of the expected type + float_val = FIELD_DTYPE.FLOAT_DATA(3.14) + assert isinstance(float_val, np.float32) + assert float_val == np.float32(3.14) + + int_val = FIELD_DTYPE.INT_DATA(42) + assert isinstance(int_val, np.int32) + assert int_val == np.int32(42) + + def test_FIELD_DTYPE_is_instance(self): + """Verify FIELD_DTYPE.is_instance correctly identifies instances""" + assert FIELD_DTYPE.FLOAT_DATA.is_instance(np.float32(1.0)) is True + assert FIELD_DTYPE.INT_DATA.is_instance(np.float32(1.0)) is False + + assert FIELD_DTYPE.INT_DATA.is_instance(np.int32(42)) is True + assert FIELD_DTYPE.FLOAT_DATA.is_instance(np.int32(42)) is False + + def test_FIELD_DTYPE_is_subclass(self): + """Verify FIELD_DTYPE.is_subclass correctly identifies subclasses""" + assert FIELD_DTYPE.FLOAT_DATA.is_subclass(np.float32) is True + assert FIELD_DTYPE.FLOAT_DATA.is_subclass(np.int32) is False + + assert FIELD_DTYPE.INT_DATA.is_subclass(np.int32) is True + assert FIELD_DTYPE.INT_DATA.is_subclass(np.float32) is False + + def test_FIELD_DTYPE_str(self): + """Verify str(FIELD_DTYPE) returns the underlying type's __name__""" + assert str(FIELD_DTYPE.FLOAT_DATA) == "float32" + assert str(FIELD_DTYPE.INT_DATA) == "int32" + assert str(FIELD_DTYPE.FLOAT_CONSTANT) == "float64" + + def test_GROUP_NAME_attributes(self): + """Verify GROUP_NAME enum members have allowMultiple and nxClass attributes""" + # Check that all enum members have the required attributes + for group in GROUP_NAME: + assert hasattr(group, "allowMultiple") + assert hasattr(group, "nxClass") + assert isinstance(group.allowMultiple, bool) + + # Verify specific known members + assert GROUP_NAME.ENTRY.allowMultiple is True + assert GROUP_NAME.DETECTOR.allowMultiple is True + assert GROUP_NAME.FIT.allowMultiple is True + + assert GROUP_NAME.INSTRUMENT.allowMultiple is False + assert GROUP_NAME.SAMPLE_DESCRIPTION.allowMultiple is False + + def test_group_naming_scheme_int_first(self): + """Verify group_naming_scheme with int suffix=1 omits suffix""" + assert group_naming_scheme("entry", 1) == "entry" + + def test_group_naming_scheme_int_second(self): + """Verify group_naming_scheme with int suffix>1 adds suffix""" + assert group_naming_scheme("entry", 2) == "entry_2" + assert group_naming_scheme("entry", 3) == "entry_3" + + def test_group_naming_scheme_str_default(self): + """Verify group_naming_scheme with DEFAULT_TAG omits suffix""" + assert group_naming_scheme("DIFFRACTOGRAM", DEFAULT_TAG) == "DIFFRACTOGRAM" + + def test_group_naming_scheme_str_nondefault(self): + """Verify group_naming_scheme with non-default string adds suffix""" + assert group_naming_scheme("DIFFRACTOGRAM", "custom_mask") == "DIFFRACTOGRAM_custom_mask" + assert group_naming_scheme("FIT", "mask_2") == "FIT_mask_2" + + def test_group_naming_scheme_invalid_suffix(self): + """Verify group_naming_scheme raises RuntimeError for invalid suffix type""" + with pytest.raises(RuntimeError, match=r".*not implemented for suffix.*"): + group_naming_scheme("entry", 3.14) + + def test_allowed_identifier(self): + """Verify allowed_identifier replaces : with _ and leaves other chars unchanged""" + assert allowed_identifier("HB2B:CS:Wavelength") == "HB2B_CS_Wavelength" + assert allowed_identifier("simple_name") == "simple_name" + assert allowed_identifier("name.with.dots") == "name.with.dots" + assert allowed_identifier("A:B:C:D") == "A_B_C_D" + + def test_is_ISO_8601_valid(self): + """Verify is_ISO_8601 returns True for valid ISO 8601 strings""" + assert is_ISO_8601("2024-01-15T10:30:00") is True + assert is_ISO_8601("2024-12-31T23:59:59") is True + assert is_ISO_8601("2024-01-01T00:00:00") is True + + def test_is_ISO_8601_invalid(self): + """Verify is_ISO_8601 returns False for invalid date strings""" + assert is_ISO_8601("not-a-date") is False + assert is_ISO_8601("2024/01/15 10:30:00") is False + assert is_ISO_8601("invalid") is False diff --git a/tests/unit/pyrs/utilities/NXstress/test_fit.py b/tests/unit/pyrs/utilities/NXstress/test_fit.py new file mode 100644 index 000000000..ebfb10459 --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_fit.py @@ -0,0 +1,557 @@ +""" +Tests for pyrs/utilities/NXstress/_fit.py +""" + +from collections.abc import Callable +import numpy as np +from nexusformat.nexus import NXdata, NXnote, NXparameters, NXprocess +import pytest + +from pyrs.core.workspaces import HidraWorkspace +from pyrs.peaks.peak_collection import PeakCollection +from pyrs.utilities.NXstress._fit import _BackgroundParameters, _Diffractogram, _Fit, _PeakParameters +from pyrs.utilities.NXstress._definitions import DEFAULT_TAG + + +class TestFit: + """Test suite for _fit.py""" + + PROJECT_FILE_B = "HB2B_1628.h5" # instrument, mask, reduced data, but no input data + PROJECT_FILE_C = "HB2B_1017_w_mask.h5" # instrument, mask, input data, reduced data + + def test_PeakParameters_data_values( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify numeric values in peak parameters match get_effective_params()""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="PseudoVoigt", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + params_value, params_error = peak0.get_effective_params() + + peak_params = _PeakParameters.init_group([peak0]) + + assert isinstance(peak_params, NXparameters) + + # Verify all required fields exist + assert "center" in peak_params + assert "center_errors" in peak_params + assert "height" in peak_params + assert "height_errors" in peak_params + assert "fwhm" in peak_params + assert "fwhm_errors" in peak_params + assert "form_factor" in peak_params + assert "form_factor_errors" in peak_params + + # Verify data values match + np.testing.assert_array_almost_equal(peak_params["center"].nxdata, params_value["Center"].astype(np.float64)) + np.testing.assert_array_almost_equal(peak_params["height"].nxdata, params_value["Height"].astype(np.float64)) + np.testing.assert_array_almost_equal(peak_params["fwhm"].nxdata, params_value["FWHM"].astype(np.float64)) + + # Form factor is (1.0 - Mixing) + expected_form_factor = (1.0 - params_value["Mixing"]).astype(np.float64) + np.testing.assert_array_almost_equal(peak_params["form_factor"].nxdata, expected_form_factor) + + def test_PeakParameters_multiple_peaks( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify two PeakCollections create 2×N_scan rows in sort order""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peak1 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peak_params = _PeakParameters.init_group([peak0, peak1]) + + # Should have 2 * N_subrun rows + assert peak_params["center"].shape[0] == 2 * N_subrun + + def test_PeakParameters_mismatched_profile_raises( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify ValueError when PeakCollections have different peak_profile""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peak1 = createPeakCollection( + peak_tag="Si 111", + peak_profile="PseudoVoigt", # Different! + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + with pytest.raises(ValueError, match=r".*must share the same peak profile.*"): + _PeakParameters.init_group([peak0, peak1]) + + def test_BackgroundParameters_data_values( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify A0, A1, A2 (and errors) match get_effective_params()""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + params_value, params_error = peak0.get_effective_params() + + bg_params = _BackgroundParameters.init_group([peak0]) + + assert isinstance(bg_params, NXparameters) + + # Verify all background parameters + for param in ["A0", "A1", "A2"]: + assert param in bg_params + assert f"{param}_errors" in bg_params + + np.testing.assert_array_almost_equal(bg_params[param].nxdata, params_value[param].astype(np.float64)) + np.testing.assert_array_almost_equal( + bg_params[f"{param}_errors"].nxdata, params_error[param].astype(np.float64) + ) + + def test_BackgroundParameters_multiple_peaks( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify two PeakCollections create 2×N_scan rows""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peak1 = createPeakCollection( + peak_tag="Al 222", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + bg_params = _BackgroundParameters.init_group([peak0, peak1]) + + # Should have 2 * N_subrun rows + assert bg_params["A0"].shape[0] == 2 * N_subrun + + def test_BackgroundParameters_mismatched_type_raises( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify ValueError when PeakCollections have different background_type""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peak1 = createPeakCollection( + peak_tag="Si 111", + peak_profile="Gaussian", + background_type="Linear", # Different! + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + with pytest.raises(ValueError, match=r".*must share the same background type.*"): + _BackgroundParameters.init_group([peak0, peak1]) + + def test_Diffractogram_data_key_default(self): + """Verify _diffraction_data_key returns `None` for DEFAULT_TAG""" + data_key = _Diffractogram._diffraction_data_key(DEFAULT_TAG) + + assert data_key is None + + def test_Diffractogram_data_keys_named(self): + """Verify _diffraction_data_keys returns proper keys for named mask""" + data_key = _Diffractogram._diffraction_data_key("my_mask") + + assert data_key == "my_mask" + + def test_Diffractogram_init_no_reduced_data_raises( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify RuntimeError when workspace._2theta_matrix is None""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Set _2theta_matrix to None to simulate no reduced data + ws._2theta_matrix = None + + with pytest.raises(RuntimeError, match=r".*doesn't include any reduced data.*"): + _Diffractogram._init(ws) + + def test_Diffractogram_init_group_missing_mask_raises( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify RuntimeError when mask data not in workspace""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + # Try to create diffractogram for non-existent mask + with pytest.raises(RuntimeError, match=r".*is not present in the workspace.*"): + _Diffractogram.init_group(ws, "non_existent_mask", [peak0]) + + def test_Diffractogram_data_values( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify diffractogram/diffractogram_errors match workspace arrays""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + dgram = _Diffractogram.init_group(ws, DEFAULT_TAG, [peak0]) + + assert isinstance(dgram, NXdata) + + # Verify required fields + assert "diffractogram" in dgram + assert "diffractogram_errors" in dgram + assert "fit" in dgram + assert "fit_errors" in dgram + + # Verify data matches workspace (use allclose for float32 comparison) + data_key = _Diffractogram._diffraction_data_key(DEFAULT_TAG) + expected_data = ws._diff_data_set[data_key] + expected_errors = ws._var_data_set[data_key] + + np.testing.assert_allclose(dgram["diffractogram"].nxdata, expected_data, rtol=1e-6, equal_nan=True) + np.testing.assert_allclose(dgram["diffractogram_errors"].nxdata, expected_errors, rtol=1e-6, equal_nan=True) + + # fit and fit_errors should be empty + assert dgram["fit"].shape == (0, 0) + assert dgram["fit_errors"].shape == (0, 0) + + def test_Fit_init_fields( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify _Fit._init creates fields: date, program, raw_data_file, DESCRIPTION""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + logs = ws._sample_logs + fit = _Fit._init(logs, processing_description="Test description", processing_time="2024-01-15T10:30:00") + + assert isinstance(fit, NXprocess) + assert "date" in fit + assert "program" in fit + assert "raw_data_file" in fit + assert "DESCRIPTION" in fit + + assert fit["program"] == "PyRS" + assert fit["date"] == "2024-01-15T10:30:00" + assert isinstance(fit["DESCRIPTION"], NXnote) + + def test_Fit_multiple_masks( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify workspace with multiple masks creates one DIFFRACTOGRAM per mask""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + fit = _Fit.init_group(ws, [peak0], ws._sample_logs) + + # Count NXdata groups (diffractograms) + diffractogram_count = sum(1 for key in fit.keys() if isinstance(fit[key], NXdata)) + + # Should have at least one diffractogram + assert diffractogram_count >= 1 + + def test_Fit_duplicate_diffractogram_raises( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify RuntimeError when diffractogram name collision occurs""" + # This test checks the internal logic - would need to manipulate + # workspace to have duplicate mask names, which is prevented elsewhere + # For now, we'll skip this as it's hard to trigger in practice + pass + + def test_validateWorkspaceAndPeaksData_valid( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify validation passes for matching workspace and peaks data""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + # Should not raise + _Fit.validateWorkspaceAndPeaksData(ws, [peak0]) + + def test_validateWorkspaceAndPeaksData_missing_scan_points( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify ValueError when PeakCollection references missing scan points""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + # Add a non-existent scan point to the peak collection + import numpy as np + from pyrs.dataobjects.sample_logs import SubRuns + + # Create sub_runs with extra scan points not in workspace + extra_subruns = np.append(subruns, [9999, 10000]) + peak0._sub_run_array = SubRuns(extra_subruns) + + with pytest.raises(ValueError, match=r".*not present in workspace.*"): + _Fit.validateWorkspaceAndPeaksData(ws, [peak0]) + + def test_validateWorkspaceAndPeaksData_missing_mask_data( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify ValueError when PeakCollection references missing mask data""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + # Set a mask that doesn't exist in the workspace + peak0._mask = "non_existent_mask" + + with pytest.raises(ValueError, match=r".*not present in the workspace.*"): + _Fit.validateWorkspaceAndPeaksData(ws, [peak0]) + + def test_peakParametersForRange_intensity_error_roundtrip( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """σ_Intensity survives a write→read round-trip for PseudoVoigt; Gaussian does not crash. + + PseudoVoigt write path converts Intensity → Height (storing σ_h derived from σ_I, σ_Γ, σ_η). + The read path must invert that exactly via algebraic cancellation of the correlated terms; + naive addition would over-estimate σ_I by ≈ √2 for the σ_Γ / σ_η contributions. + + Gaussian stores Height as a native parameter, so Intensity is not in the native output of + peakParametersForRange. For Gaussian we verify that the call succeeds and that Height and + Sigma (the actual native parameters) round-trip correctly. + """ + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + # --- PseudoVoigt: full σ_I round-trip --- + peak_pv = createPeakCollection( + peak_tag="Fe 311", + peak_profile="PseudoVoigt", + background_type="Linear", + wavelength=1.5, + projectfilename="/does/not/exist.h5", + runnumber=99, + N_subrun=N_subrun, + ) + + _, orig_errors_pv = peak_pv.get_effective_params() + sigma_I_orig = orig_errors_pv["Intensity"].astype(np.float64) + + pp_pv = _PeakParameters.init_group([peak_pv]) + native_values_pv, native_errors_pv = _PeakParameters.peakParametersForRange(pp_pv, 0, N_subrun) + + # For PseudoVoigt, Intensity is a native parameter — verify exact round-trip. + # A factor-of-two over-count would produce errors ~√2× too large and fail here. + np.testing.assert_allclose( + native_errors_pv["Intensity"].astype(np.float64), + sigma_I_orig, + rtol=1e-6, + err_msg="PseudoVoigt σ_Intensity round-trip failed: check peakParametersForRange", + ) + + # --- Gaussian: native Height / Sigma round-trip (Intensity is not a native parameter) --- + peak_g = createPeakCollection( + peak_tag="Fe 311", + peak_profile="Gaussian", + background_type="Linear", + wavelength=1.5, + projectfilename="/does/not/exist.h5", + runnumber=99, + N_subrun=N_subrun, + ) + + orig_values_g, orig_errors_g = peak_g.get_effective_params() + + pp_g = _PeakParameters.init_group([peak_g]) + native_values_g, native_errors_g = _PeakParameters.peakParametersForRange(pp_g, 0, N_subrun) + + # Height is stored directly on the write path — must survive exactly. + np.testing.assert_allclose( + native_values_g["Height"].astype(np.float64), + orig_values_g["Height"].astype(np.float64), + rtol=1e-6, + err_msg="Gaussian Height round-trip failed", + ) + np.testing.assert_allclose( + native_errors_g["Height"].astype(np.float64), + orig_errors_g["Height"].astype(np.float64), + rtol=1e-6, + err_msg="Gaussian σ_Height round-trip failed", + ) diff --git a/tests/unit/pyrs/utilities/NXstress/test_helper_util.py b/tests/unit/pyrs/utilities/NXstress/test_helper_util.py new file mode 100644 index 000000000..1b68318b7 --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_helper_util.py @@ -0,0 +1,32 @@ +# ruff: noqa: F841 +from pathlib import Path + +from pyrs.projectfile.file_object import HidraProjectFile + + +PROJECT_FILE = "HB2B_1628.h5" + + +def test_createPeakCollection(createPeakCollection): + peaks = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=25, + ) + + +def test_load_HidraWorkspace(load_HidraWorkspace): + ws = load_HidraWorkspace( + file_name=PROJECT_FILE, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + assert ws.name == "test_workspace" + + +def test_HidraProjectFile_context_manager(test_data_dir): + project_file_path = Path(test_data_dir) / PROJECT_FILE + with HidraProjectFile(project_file_path) as project_file: + assert project_file.name == str(project_file_path) diff --git a/tests/unit/pyrs/utilities/NXstress/test_input_data.py b/tests/unit/pyrs/utilities/NXstress/test_input_data.py new file mode 100644 index 000000000..1d9a2ba84 --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_input_data.py @@ -0,0 +1,137 @@ +""" +Tests for pyrs/utilities/NXstress/_input_data.py +""" + +from collections.abc import Callable +import numpy as np +from nexusformat.nexus import NXdata, nxopen +from pathlib import Path +import pytest + +from pyrs.core.workspaces import HidraWorkspace +from pyrs.utilities.NXstress._input_data import _InputData + + +class TestInputData: + """Test suite for _input_data.py""" + + PROJECT_FILE_A = "HB2B_1017.h5" # instrument, input data, reduced data, no mask + PROJECT_FILE_C = "HB2B_1017_w_mask.h5" # instrument, mask, input data, reduced data + + def test_InputData_init_group_raises_on_existing_data( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify RuntimeError when trying to append detector_counts data""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_A, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + # Create an existing NXdata group + existing_data = NXdata() + + with pytest.raises(RuntimeError, match=r".*not implemented: append detector_counts data to NXstress file.*"): + _InputData.init_group(ws, data=existing_data) + + def test_InputData_init_group_data_values( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify detector_counts shape and scan_point values match workspace""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_A, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + data = _InputData.init_group(ws) + + # Verify structure + assert isinstance(data, NXdata) + assert "detector_counts" in data + assert "scan_point" in data + + # Verify data shape + scan_points = list(ws._raw_counts.keys()) + N_scan = len(scan_points) + + # Get detector size from first scan point + first_counts = ws.get_detector_counts(scan_points[0]) + N_pixels = len(first_counts) + + assert data["detector_counts"].shape == (N_scan, N_pixels) + assert len(data["scan_point"]) == N_scan + + # Verify scan_point values match + np.testing.assert_array_equal(data["scan_point"], scan_points) + + def test_InputData_readSubruns( + self, + tmp_path: Path, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify readSubruns round-trip: write then read back""" + # Load workspace with raw counts + ws_write = load_HidraWorkspace( + file_name=self.PROJECT_FILE_A, + name="test_workspace_write", + load_raw_counts=True, + load_reduced_diffraction=True, + ) + + # Create input data + data = _InputData.init_group(ws_write) + + # Write to file + file_path = tmp_path / "test_readSubruns.nxs" + with nxopen(str(file_path), "w") as nx: + nx["input_data"] = data + + # Create empty workspace for reading + ws_read = HidraWorkspace("test_workspace_read") + # `SampleLogs` must already be attached: + # otherwise the workspace will have no `Subruns`! + ws_read._sample_logs = ws_write._sample_logs + + # Read back + with nxopen(str(file_path), "r") as nx: + _InputData.readSubruns(ws_read, nx["input_data"]) + + # Verify round-trip + assert len(ws_read.get_sub_runs()) == len(ws_write.get_sub_runs()) + + # Check that all scan points are present + original_scan_points = list(ws_write._raw_counts.keys()) + read_scan_points = list(ws_write._raw_counts.keys()) + + for scan_point in original_scan_points: + assert scan_point in read_scan_points + original_counts = ws_write.get_detector_counts(scan_point) + read_counts = ws_read.get_detector_counts(scan_point) + np.testing.assert_array_equal(read_counts, original_counts) + + def test_InputData_readSubruns_raises_on_scanpoint_mismatch( + self, + tmp_path: Path, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify RuntimeError when workspace has subruns that don't match those from input data""" + # Load workspace with data + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_A, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + # Create input data and write to file + data = _InputData.init_group(ws) + file_path = tmp_path / "test_existing_subruns.nxs" + with nxopen(str(file_path), "w") as nx: + nx["input_data"] = data + + # Try to read into workspace that has subruns that do not match + existing_subruns = ws._sample_logs._subruns._value + ws._sample_logs._subruns._value = np.append( + existing_subruns, [max(existing_subruns) + 1, max(existing_subruns) + 2] + ) + with nxopen(str(file_path), "r") as nx: + with pytest.raises( + RuntimeError, match=r".*not implemented: append or change detector_counts data on existing workspace.*" + ): + _InputData.readSubruns(ws, nx["input_data"]) diff --git a/tests/unit/pyrs/utilities/NXstress/test_instrument.py b/tests/unit/pyrs/utilities/NXstress/test_instrument.py new file mode 100644 index 000000000..ef25ca45b --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_instrument.py @@ -0,0 +1,189 @@ +# ruff: noqa: F841 +""" +Tests for pyrs/utilities/NXstress/_instrument.py +""" + +from collections.abc import Callable +import numpy as np +from nexusformat.nexus import NXcollection, NXinstrument, NXdetector_module +import pytest + +from pyrs.core.workspaces import HidraWorkspace +from pyrs.utilities.NXstress._instrument import _Instrument, _Masks +from pyrs.utilities.NXstress._definitions import DEFAULT_TAG +from tests.util.mask_helpers import add_named_detector_mask + + +class TestInstrument: + """Test suite for _instrument.py""" + + PROJECT_FILE_A = "HB2B_1017.h5" # instrument, input data, reduced data, no mask + PROJECT_FILE_B = "HB2B_1628.h5" # instrument, mask, reduced data, but no input data + PROJECT_FILE_C = "HB2B_1017_w_mask.h5" # instrument, mask, input data, reduced data + + def test_Masks_init(self): + """Verify _Masks._init creates empty NXcollection with required fields""" + masks = _Masks._init() + + assert isinstance(masks, NXcollection) + assert "names" in masks + assert "detector" in masks + assert "solid_angle" in masks + + # Verify empty structure + assert len(masks["names"]) == 0 + assert isinstance(masks["detector"], NXcollection) + assert isinstance(masks["solid_angle"], NXcollection) + + def test_Masks_init_group_with_default_mask( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify default mask appears in masks with DEFAULT_TAG name""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + masks = _Masks.init_group(ws) + + assert isinstance(masks, NXcollection) + assert DEFAULT_TAG in masks["names"] + assert DEFAULT_TAG in masks["detector"] + + def test_Masks_init_group_append( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify calling init_group twice (detector then solid_angle) populates both""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + # First call for detector masks + masks = _Masks.init_group(ws) + initial_count = len(masks["names"]) + + # Second call for solid angle masks (appending) + # For this test, we'll use the same workspace but we'll just change the names. + defaults = ws._diff_data_set[None], ws._var_data_set[None], ws._mask_dict.get(None, None) + ws._diff_data_set = {f"{k}_2nd": v for k, v in ws._diff_data_set.items() if k is not None} + ws._var_data_set = {f"{k}_2nd": v for k, v in ws._var_data_set.items() if k is not None} + ws._mask_dict = {f"{k}_2nd": v for k, v in ws._mask_dict.items() if k is not None} + # Re-add the default items: + ws._diff_data_set[None], ws._var_data_set[None] = defaults[0:2] + if defaults[2]: + ws._mask_dict[None] = defaults[2] + + # In real usage, solid angle masks would be different data + masks = _Masks.init_group(ws, masks=masks) + + # Names should have been appended + assert len(masks["names"]) >= initial_count + + def test_Masks_init_group_duplicate_raises( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify behavior when attempting to add duplicate masks + + A non-default named mask is added to the workspace. The first call to + `init_group` writes it; the second call must raise because the same + name is already present in the masks group. + """ + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_C, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + # Add a non-default named mask so that `mask_keys(ws)` contains a + # name other than DEFAULT_TAG. The first `init_group` call will write + # it; the second call will find it already in `names` and raise. + add_named_detector_mask(ws, "test_mask") + + masks = _Masks.init_group(ws) + + with pytest.raises(RuntimeError, match=r".*Usage error: mask .* has already been written.*"): + masks2 = _Masks.init_group(ws, masks=masks) + + def test_Instrument_init(self): + """Verify _Instrument._init creates NXinstrument with name and short_name""" + inst = _Instrument._init("HB2B", "HB2B") + + assert isinstance(inst, NXinstrument) + assert "name" in inst + assert inst["name"] == "HB2B" + assert inst["name"].attrs["short_name"] == "HB2B" + + def test_Instrument_detector_module_fields( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify NXdetector_module contains required fields""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_A, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + inst = _Instrument.init_group(ws) + + assert "DETECTOR" in inst + detector = inst["DETECTOR"] + assert "detector_bank" in detector + + det_module = detector["detector_bank"] + assert isinstance(det_module, NXdetector_module) + + # Verify required fields + assert "data_size" in det_module + assert "fast_pixel_direction" in det_module + assert "slow_pixel_direction" in det_module + assert "depends_on" in det_module + + # Verify data_size is 2D array [rows, cols] + assert len(det_module["data_size"]) == 2 + assert det_module["data_size"].dtype == np.int64 + + def test_Instrument_transformations_chain( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify all 8 transformations exist and depends_on chain is correct""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_A, name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + inst = _Instrument.init_group(ws) + + detector = inst["DETECTOR"] + assert "transformations" in detector + + trans = detector["transformations"] + + # Verify all 8 transformations exist + expected_transforms = [ + "translation_x", + "translation_y", + "translation_z", + "distance", + "rotation_x", + "rotation_y", + "rotation_z", + "two_theta_zero", + ] + + for name in expected_transforms: + assert name in trans + # Each transformation should have required attributes + assert "transformation_type" in trans[name].attrs + assert "vector" in trans[name].attrs + assert "depends_on" in trans[name].attrs + + # Verify depends_on chain + # First transformation depends on '.' + assert trans["translation_x"].attrs["depends_on"] == "." + + # Subsequent transformations form a chain + assert trans["translation_y"].attrs["depends_on"] == "./transformations/translation_x" + assert trans["translation_z"].attrs["depends_on"] == "./transformations/translation_y" + assert trans["distance"].attrs["depends_on"] == "./transformations/translation_z" + + # Detector depends on first transformation + assert detector["depends_on"] == "./transformations/translation_x" diff --git a/tests/unit/pyrs/utilities/NXstress/test_peaks.py b/tests/unit/pyrs/utilities/NXstress/test_peaks.py new file mode 100644 index 000000000..7d025f102 --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_peaks.py @@ -0,0 +1,280 @@ +# ruff: noqa: E741, F841 +""" +Tests for pyrs/utilities/NXstress/_peaks.py +""" + +from collections.abc import Callable +import numpy as np +from nexusformat.nexus import NXreflections + +from pyrs.core.workspaces import HidraWorkspace +from pyrs.peaks.peak_collection import PeakCollection +from pyrs.utilities.NXstress._peaks import _Peaks + + +class TestPeaks: + """Test suite for _peaks.py""" + + PROJECT_FILE_B = "HB2B_1628.h5" # instrument, mask, reduced data, but no input data + + def test_Peaks_init_empty( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify _Peaks._init creates empty datasets with correct dtypes/units""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + logs = ws._sample_logs + peaks = _Peaks._init(logs) + + assert isinstance(peaks, NXreflections) + + # Verify all required fields exist and array fields are empty + array_fields = [ + "scan_point", + "h", + "k", + "l", + "phase_name", + "mask", + "qx", + "qy", + "qz", + "center", + "center_errors", + "sx", + "sy", + "sz", + ] + + for field in array_fields: + assert field in peaks + assert peaks[field].shape[0] == 0 + + # Verify scalar field + assert "center_type" in peaks + assert peaks["center_type"].nxdata == "d-spacing" + + def test_Peaks_init_group_data_values( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify one PeakCollection creates N_scan rows with correct values""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 251540", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peaks = _Peaks.init_group([peak0], ws._sample_logs) + + assert isinstance(peaks, NXreflections) + + # Verify shape + assert peaks["h"].shape[0] == N_subrun + assert peaks["k"].shape[0] == N_subrun + assert peaks["l"].shape[0] == N_subrun + assert peaks["phase_name"].shape[0] == N_subrun + assert peaks["mask"].shape[0] == N_subrun + assert peaks["scan_point"].shape[0] == N_subrun + assert peaks["center"].shape[0] == N_subrun + assert peaks["center_errors"].shape[0] == N_subrun + + # Verify values + # Parse peak tag to get expected h, k, l + phase, (h, k, l) = _Peaks._parse_peak_tag(peak0.peak_tag) + + # All rows should have same h, k, l + assert all(peaks["h"].nxdata == h) + assert all(peaks["k"].nxdata == k) + assert all(peaks["l"].nxdata == l) + + # All rows should have same phase_name + assert all(p == phase for p in peaks["phase_name"].nxdata) + + # scan_point should match subruns + np.testing.assert_array_equal(peaks["scan_point"].nxdata, subruns) + + def test_Peaks_init_group_multiple_peaks( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify two PeakCollections create 2×N_scan rows in lexicographic sort order""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + # Create two peaks - they will be sorted by PeakIndex.sort_key + peak0 = createPeakCollection( + peak_tag="Al 251540", # (2, 5, 1540) -> (25, 15, 40) after parsing "251540" + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peak1 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peaks = _Peaks.init_group([peak0, peak1], ws._sample_logs) + + # Should have 2 * N_subrun rows + assert peaks["h"].shape[0] == 2 * N_subrun + + # Verify sorting - first N_subrun rows should be from peak with lower sort key + # Sort key is (phase_name, h, k, l, mask) + # Both are "Al", so it's sorted by (h, k, l) + phase0, hkl0 = _Peaks._parse_peak_tag(peak0.peak_tag) + phase1, hkl1 = _Peaks._parse_peak_tag(peak1.peak_tag) + + # Determine which peak should come first + key0 = (phase0, *hkl0, peak0.mask) + key1 = (phase1, *hkl1, peak1.mask) + + if key0 < key1: + first_peak = peak0 + first_hkl = hkl0 + else: + first_peak = peak1 + first_hkl = hkl1 + + # Verify first N_subrun rows match the first peak in sort order + h, k, l = first_hkl + assert all(peaks["h"].nxdata[:N_subrun] == h) + assert all(peaks["k"].nxdata[:N_subrun] == k) + assert all(peaks["l"].nxdata[:N_subrun] == l) + + def test_PeakIndex_sort_key( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify PeakIndex.sort_key returns correct tuple for sorting""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peak1 = createPeakCollection( + peak_tag="Si 222", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + # Get sort keys + key0 = _Peaks.PeakIndex.sort_key(peak0) + key1 = _Peaks.PeakIndex.sort_key(peak1) + + # Keys should be tuples (phase_name, h, k, l, mask) + assert len(key0) == 5 + assert len(key1) == 5 + + # Verify they can be compared for sorting + assert key0 != key1 + assert (key0 < key1) or (key0 > key1) + + def test_Peaks_qxyz_nan( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify qx, qy, qz fields exist but remain empty after init_group since implementation doesn't populate them""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peaks = _Peaks.init_group([peak0], ws._sample_logs) + + # qx, qy, qz exist but remain empty (implementation doesn't populate them) + assert "qx" in peaks + assert "qy" in peaks + assert "qz" in peaks + + assert peaks["qx"].shape[0] == 0 + assert peaks["qy"].shape[0] == 0 + assert peaks["qz"].shape[0] == 0 + + def test_Peaks_sxyz_nan( + self, load_HidraWorkspace: Callable[..., HidraWorkspace], createPeakCollection: Callable[..., PeakCollection] + ): + """Verify sx, sy, sz are filled with NaN after init_group""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak0 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/does/not/exist.h5", + runnumber=12345, + N_subrun=N_subrun, + ) + + peaks = _Peaks.init_group([peak0], ws._sample_logs) + + # sx, sy, sz should exist and be filled with NaN + assert "sx" in peaks + assert "sy" in peaks + assert "sz" in peaks + + assert peaks["sx"].shape[0] == N_subrun + assert peaks["sy"].shape[0] == N_subrun + assert peaks["sz"].shape[0] == N_subrun + + # All values should be NaN + assert all(np.isnan(peaks["sx"].nxdata)) + assert all(np.isnan(peaks["sy"].nxdata)) + assert all(np.isnan(peaks["sz"].nxdata)) diff --git a/tests/unit/pyrs/utilities/NXstress/test_peaks_read.py b/tests/unit/pyrs/utilities/NXstress/test_peaks_read.py new file mode 100644 index 000000000..ec292cbf6 --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_peaks_read.py @@ -0,0 +1,522 @@ +# ruff: noqa: E741, F841 +""" +Tests for NXstress read functionality in pyrs/utilities/NXstress/_peaks.py and _fit.py +""" + +import numpy as np +from nexusformat.nexus import NXparameters, NXfield +import pytest +from pathlib import Path +import tempfile + +from pyrs.utilities.NXstress._peaks import _Peaks +from pyrs.utilities.NXstress._fit import _PeakParameters, _BackgroundParameters +from pyrs.utilities.NXstress.NXstress import NXstress +from pyrs.utilities.NXstress._definitions import FIELD_DTYPE, GROUP_NAME + + +class TestPeakCollectionRanges: + """Test suite for _Peaks.peakCollectionRanges""" + + def test_peakCollectionRanges_happy_path(self, load_HidraWorkspace, createPeakCollection): + """Write 3 PeakCollections with distinct keys, read ranges, verify count and span""" + ws = load_HidraWorkspace( + file_name="HB2B_1628.h5", name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + # Create 3 distinct PeakCollections + peak1 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=N_subrun, + ) + + peak2 = createPeakCollection( + peak_tag="Si 200", + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=N_subrun, + ) + + peak3 = createPeakCollection( + peak_tag="Fe 110", + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=N_subrun, + ) + + # Write to NXreflections group + peaks_group = _Peaks.init_group([peak1, peak2, peak3], ws._sample_logs) + + # Read ranges + ranges = _Peaks.peakCollectionRanges(peaks_group) + + # Verify we got 3 ranges + assert len(ranges) == 3 + + # Verify each range spans N_subrun entries + for (phase_name, h, k, l, mask), start, end in ranges: + assert end - start == N_subrun + + # Verify ranges are contiguous + expected_start = 0 + for (phase_name, h, k, l, mask), start, end in ranges: + assert start == expected_start + expected_start = end + + def test_peakCollectionRanges_interleaved_blocks(self, load_HidraWorkspace): + """Construct NXreflections with non-contiguous blocks for same key → RuntimeError""" + ws = load_HidraWorkspace( + file_name="HB2B_1628.h5", name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Manually create NXreflections with interleaved blocks + peaks = _Peaks._init(ws._sample_logs) + + # Create data for interleaved pattern: Al-111, Si-200, Al-111 (duplicate) + phase_names = np.array(["Al", "Si", "Al"]) + h_vals = np.array([1, 2, 1]) + k_vals = np.array([1, 0, 1]) + l_vals = np.array([1, 0, 1]) + masks = np.array(["_DEFAULT_", "_DEFAULT_", "_DEFAULT_"]) + scan_points = np.array([1, 1, 2]) + + # Resize and fill datasets + peaks["phase_name"].resize((3,)) + peaks["h"].resize((3,)) + peaks["k"].resize((3,)) + peaks["l"].resize((3,)) + peaks["mask"].resize((3,)) + peaks["scan_point"].resize((3,)) + peaks["center"].resize((3,)) + peaks["center_errors"].resize((3,)) + + peaks["phase_name"][:] = phase_names + peaks["h"][:] = h_vals + peaks["k"][:] = k_vals + peaks["l"][:] = l_vals + peaks["mask"][:] = masks + peaks["scan_point"][:] = scan_points + peaks["center"][:] = [1.0, 2.0, 1.5] + peaks["center_errors"][:] = [0.01, 0.02, 0.015] + + # Should raise RuntimeError about interleaved blocks + with pytest.raises(RuntimeError, match="Interleaved blocks detected"): + _Peaks.peakCollectionRanges(peaks) + + def test_peakCollectionRanges_scan_point_order_violation(self, load_HidraWorkspace): + """Non-increasing scan points within block → RuntimeError""" + ws = load_HidraWorkspace( + file_name="HB2B_1628.h5", name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Manually create NXreflections with non-increasing scan_point + peaks = _Peaks._init(ws._sample_logs) + + # Create data with scan_point not strictly increasing: 1, 3, 2 (wrong!) + phase_names = np.array(["Al", "Al", "Al"]) + h_vals = np.array([1, 1, 1]) + k_vals = np.array([1, 1, 1]) + l_vals = np.array([1, 1, 1]) + masks = np.array(["_DEFAULT_", "_DEFAULT_", "_DEFAULT_"]) + scan_points = np.array([1, 3, 2]) # Not strictly increasing! + + # Resize and fill datasets + peaks["phase_name"].resize((3,)) + peaks["h"].resize((3,)) + peaks["k"].resize((3,)) + peaks["l"].resize((3,)) + peaks["mask"].resize((3,)) + peaks["scan_point"].resize((3,)) + peaks["center"].resize((3,)) + peaks["center_errors"].resize((3,)) + + peaks["phase_name"][:] = phase_names + peaks["h"][:] = h_vals + peaks["k"][:] = k_vals + peaks["l"][:] = l_vals + peaks["mask"][:] = masks + peaks["scan_point"][:] = scan_points + peaks["center"][:] = [1.0, 1.0, 1.0] + peaks["center_errors"][:] = [0.01, 0.01, 0.01] + + # Should raise RuntimeError about scan_point not strictly increasing + with pytest.raises(RuntimeError, match="scan_point values are not strictly increasing"): + _Peaks.peakCollectionRanges(peaks) + + +class TestValidateNoDuplicatePeaks: + """Test suite for _Peaks.validateNoDuplicatePeaks""" + + def test_validateNoDuplicatePeaks_no_duplicates(self, createPeakCollection): + """3 distinct PeakCollections → no error""" + peak1 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=5, + ) + + peak2 = createPeakCollection( + peak_tag="Si 200", + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=5, + ) + + peak3 = createPeakCollection( + peak_tag="Fe 110", + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=5, + ) + + # Should not raise any error + _Peaks.validateNoDuplicatePeaks([peak1, peak2, peak3]) + + def test_validateNoDuplicatePeaks_with_duplicates(self, createPeakCollection): + """2 PeakCollections with same key → ValueError with 'Duplicate PeakCollection detected'""" + peak1 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=5, + ) + + # Create another with same peak_tag and mask (duplicate!) + peak2 = createPeakCollection( + peak_tag="Al 111", # Same as peak1 + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=5, + ) + + # Should raise ValueError + with pytest.raises(ValueError, match="Duplicate PeakCollection detected"): + _Peaks.validateNoDuplicatePeaks([peak1, peak2]) + + +class TestPeakParametersForRange: + """Test suite for _PeakParameters.peakParametersForRange""" + + def test_peakParametersForRange(self): + """Manual NXparameters with known data, slice, verify native params including form_factor→Mixing inversion""" + # Create manual NXparameters group for Gaussian peak + pp = NXparameters() + pp["title"] = NXfield("gaussian", dtype=FIELD_DTYPE.STRING.value) + + # Create datasets with known values + N = 10 + centers = np.linspace(10.0, 20.0, N) + heights = np.linspace(100.0, 200.0, N) + fwhms = np.linspace(0.5, 1.5, N) + form_factors = np.linspace(0.2, 0.8, N) # Will be inverted to Mixing + + pp["center"] = NXfield(centers) + pp["center_errors"] = NXfield(centers * 0.01) + pp["height"] = NXfield(heights) + pp["height_errors"] = NXfield(heights * 0.01) + pp["fwhm"] = NXfield(fwhms) + pp["fwhm_errors"] = NXfield(fwhms * 0.01) + pp["form_factor"] = NXfield(form_factors) + pp["form_factor_errors"] = NXfield(form_factors * 0.01) + + # Slice range [2:5] + start, end = 2, 5 + native_values, native_errors = _PeakParameters.peakParametersForRange(pp, start, end) + + # Verify we got 3 entries + assert len(native_values) == 3 + assert len(native_errors) == 3 + + # Verify native parameter fields exist (Gaussian: Height, PeakCentre, Sigma, A0, A1) + assert "Height" in native_values.dtype.names + assert "PeakCentre" in native_values.dtype.names + assert "Sigma" in native_values.dtype.names + + # Verify values match sliced data (account for float32 precision) + np.testing.assert_allclose(native_values["Height"], heights[start:end], rtol=1e-6) + np.testing.assert_allclose(native_values["PeakCentre"], centers[start:end], rtol=1e-6) + + # Verify errors match (account for float32 precision) + np.testing.assert_allclose(native_errors["Height"], heights[start:end] * 0.01, rtol=1e-6) + np.testing.assert_allclose(native_errors["PeakCentre"], centers[start:end] * 0.01, rtol=1e-6) + + # CRITICAL: Verify form_factor was inverted to Mixing (not directly visible in native Gaussian) + # For Gaussian, we converted via effective parameters where Mixing=1-form_factor + # Then converted back to native Sigma = FWHM / (2*sqrt(2*ln(2))) + expected_sigma = fwhms[start:end] / (2.0 * np.sqrt(2.0 * np.log(2.0))) + np.testing.assert_array_almost_equal(native_values["Sigma"], expected_sigma, decimal=5) + + +class TestBackgroundParametersForRange: + """Test suite for _BackgroundParameters.backgroundParametersForRange""" + + def test_backgroundParametersForRange(self): + """Manual NXparameters, slice, verify A0/A1/A2""" + # Create manual NXparameters group for background + bp = NXparameters() + bp["title"] = NXfield("quadratic", dtype=FIELD_DTYPE.STRING.value) + + # Create datasets with known values + N = 10 + A0_vals = np.linspace(1.0, 10.0, N) + A1_vals = np.linspace(0.1, 1.0, N) + A2_vals = np.linspace(0.01, 0.1, N) + + bp["A0"] = NXfield(A0_vals) + bp["A0_errors"] = NXfield(A0_vals * 0.05) + bp["A1"] = NXfield(A1_vals) + bp["A1_errors"] = NXfield(A1_vals * 0.05) + bp["A2"] = NXfield(A2_vals) + bp["A2_errors"] = NXfield(A2_vals * 0.05) + + # Slice range [3:7] + start, end = 3, 7 + bg_values, bg_errors = _BackgroundParameters.backgroundParametersForRange(bp, start, end) + + # Verify we got 4 entries + assert len(bg_values) == 4 + assert len(bg_errors) == 4 + + # Verify A0, A1, A2 fields exist + assert "A0" in bg_values.dtype.names + assert "A1" in bg_values.dtype.names + assert "A2" in bg_values.dtype.names + + # Verify values match sliced data + np.testing.assert_array_almost_equal(bg_values["A0"], A0_vals[start:end]) + np.testing.assert_array_almost_equal(bg_values["A1"], A1_vals[start:end]) + np.testing.assert_array_almost_equal(bg_values["A2"], A2_vals[start:end]) + + # Verify errors match + np.testing.assert_array_almost_equal(bg_errors["A0"], A0_vals[start:end] * 0.05) + np.testing.assert_array_almost_equal(bg_errors["A1"], A1_vals[start:end] * 0.05) + np.testing.assert_array_almost_equal(bg_errors["A2"], A2_vals[start:end] * 0.05) + + +class TestPeakCollectionsFromNexus: + """Test suite for full round-trip read/write""" + + def test_peakCollectionsFromNexus_roundtrip(self, load_HidraWorkspace, createPeakCollection): + """Write PeakCollections via NXstress.write(), read back via peakCollectionsFromNexus, verify match""" + ws = load_HidraWorkspace( + file_name="HB2B_1017_w_mask.h5", + name="test_workspace", + load_raw_counts=True, # Required to load instrument geometry + load_reduced_diffraction=True, + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + # Create test PeakCollections (must use same peak profile) + peak1 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Quadratic", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=N_subrun, + ) + + peak2 = createPeakCollection( + peak_tag="Si 200", + peak_profile="Gaussian", # Must match peak1 + background_type="Quadratic", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=N_subrun, + ) + + original_peaks = [peak1, peak2] + + # Write to temporary file + with tempfile.TemporaryDirectory() as tmpdir: + file_path = Path(tmpdir) / "test_roundtrip.nxs" + + with NXstress(file_path, mode="w") as nxs: + nxs.write(ws, original_peaks) + + # Read back + with NXstress(file_path, mode="r") as nxs: + # Access the first entry + entry_name = "entry" + entry = nxs._root[entry_name] + + peaks_group = entry[GROUP_NAME.PEAKS] + fit_group = entry[GROUP_NAME.FIT] + + # Read PeakCollections + reconstructed_peaks = _Peaks.peakCollectionsFromNexus(peaks_group, fit_group) + + # Verify we got 2 PeakCollections back + assert len(reconstructed_peaks) == 2 + + # Match by sub-index key (not by list position) + original_by_key = {_Peaks.PeakIndex.sort_key(p): p for p in original_peaks} + reconstructed_by_key = {_Peaks.PeakIndex.sort_key(p): p for p in reconstructed_peaks} + + assert set(original_by_key.keys()) == set(reconstructed_by_key.keys()) + + # Verify each PeakCollection + for key in original_by_key: + orig = original_by_key[key] + recon = reconstructed_by_key[key] + + # Verify peak_tag parses to same (phase, h, k, l) + # Exact string match is not required (spaces are not significant) + orig_phase, orig_hkl = _Peaks._parse_peak_tag(orig.peak_tag) + recon_phase, recon_hkl = _Peaks._parse_peak_tag(recon.peak_tag) + assert orig_phase == recon_phase + assert orig_hkl == recon_hkl + + # Verify mask + assert orig.mask == recon.mask + + # Verify sub_runs match + np.testing.assert_array_equal(orig.sub_runs.raw_copy(), recon.sub_runs.raw_copy()) + + # Verify d_reference (should be constant for all subruns) + orig_d, orig_d_err = orig.get_d_reference() + recon_d, recon_d_err = recon.get_d_reference() + np.testing.assert_almost_equal(orig_d, recon_d, decimal=5) + np.testing.assert_almost_equal(orig_d_err, recon_d_err, decimal=5) + + # Verify effective parameters match (within tolerance) + orig_eff_vals, orig_eff_errs = orig.get_effective_params() + recon_eff_vals, recon_eff_errs = recon.get_effective_params() + + # Check all effective parameter fields + for field in ["Center", "Height", "FWHM", "Mixing"]: + np.testing.assert_allclose( + orig_eff_vals[field], recon_eff_vals[field], atol=1e-5, err_msg=f"Mismatch in {field} values" + ) + np.testing.assert_allclose( + orig_eff_errs[field], recon_eff_errs[field], atol=1e-5, err_msg=f"Mismatch in {field} errors" + ) + + def test_peak_tag_roundtrip_multidigit_miller(self, load_HidraWorkspace, createPeakCollection): + """PeakCollection with peak_tag='Fe120100' (h=12,k=1,l=0) round-trips correctly""" + ws = load_HidraWorkspace( + file_name="HB2B_1017_w_mask.h5", + name="test_workspace", + load_raw_counts=True, # Required to load instrument geometry + load_reduced_diffraction=True, + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + # Create PeakCollection with multi-digit Miller indices + peak = createPeakCollection( + peak_tag="Fe120100", # h=12, k=1, l=0 → N_d=2, each index is 2 digits + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=N_subrun, + ) + + original_peaks = [peak] + + # Write and read back + with tempfile.TemporaryDirectory() as tmpdir: + file_path = Path(tmpdir) / "test_multidigit.nxs" + + with NXstress(file_path, mode="w") as nxs: + nxs.write(ws, original_peaks) + + with NXstress(file_path, mode="r") as nxs: + entry = nxs._root["entry"] + peaks_group = entry[GROUP_NAME.PEAKS] + fit_group = entry[GROUP_NAME.FIT] + + reconstructed_peaks = _Peaks.peakCollectionsFromNexus(peaks_group, fit_group) + + # Verify peak_tag matches + assert len(reconstructed_peaks) == 1 + assert reconstructed_peaks[0].peak_tag == "Fe120100" + + # Verify parsing produces correct Miller indices + phase, (h, k, l) = _Peaks._parse_peak_tag(reconstructed_peaks[0].peak_tag) + assert phase == "Fe" + assert h == 12 + assert k == 1 + assert l == 0 + + +class TestValidateNoDuplicatePeaksIntegration: + """Test validateNoDuplicatePeaks integration in NXstress.write()""" + + def test_validateNoDuplicatePeaks_integration_in_write(self, load_HidraWorkspace, createPeakCollection): + """NXstress.write() with duplicates → ValueError before any file content written""" + ws = load_HidraWorkspace( + file_name="HB2B_1628.h5", name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + subruns = ws._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + # Create duplicate PeakCollections + peak1 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=N_subrun, + ) + + peak2 = createPeakCollection( + peak_tag="Al 111", # Duplicate! + peak_profile="Gaussian", + background_type="Linear", + wavelength=25.4, + projectfilename="/tmp/test.h5", + runnumber=1, + N_subrun=N_subrun, + ) + + duplicate_peaks = [peak1, peak2] + + # Attempt to write should raise ValueError + with tempfile.TemporaryDirectory() as tmpdir: + file_path = Path(tmpdir) / "test_duplicate_check.nxs" + + # The validation happens before any writes, so the error is raised early + with pytest.raises(ValueError, match="Duplicate PeakCollection detected"): + with NXstress(file_path, mode="w") as nxs: + nxs.write(ws, duplicate_peaks) diff --git a/tests/unit/pyrs/utilities/NXstress/test_sample.py b/tests/unit/pyrs/utilities/NXstress/test_sample.py new file mode 100644 index 000000000..0a966eb87 --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_sample.py @@ -0,0 +1,232 @@ +""" +Tests for pyrs/utilities/NXstress/_sample.py +""" + +from collections.abc import Callable +import numpy as np +from nexusformat.nexus import NXsample, NXcollection +import pytest + +from pyrs.core.workspaces import HidraWorkspace +from pyrs.dataobjects.constants import HidraConstants +from pyrs.utilities.NXstress._sample import _Sample +from pyrs.utilities.NXstress._definitions import FIELD_DTYPE + + +class TestSample: + """Test suite for _sample.py""" + + PROJECT_FILE_A = "HB2B_1017.h5" # instrument, input data, reduced data, no mask + PROJECT_FILE_B = "HB2B_1628.h5" # instrument, mask, reduced data, but no input data + PROJECT_FILE_C = "HB2B_1017_w_mask.h5" # instrument, mask, input data, reduced data + + def test_Sample_scan_point_and_coordinates( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify scan_point matches subruns and vx,vy,vz have correct shape/dtype""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + sample = _Sample.init_group(ws._sample_logs) + + assert isinstance(sample, NXsample) + assert "scan_point" in sample + assert "vx" in sample + assert "vy" in sample + assert "vz" in sample + + # Verify scan_point matches subruns + subruns = ws._sample_logs.subruns.raw_copy() + N_scan = len(subruns) + + np.testing.assert_array_equal(sample["scan_point"].nxdata, subruns.astype(FIELD_DTYPE.INT_DATA.value)) + + # Verify coordinate arrays have correct shape and dtype + for coord in ["vx", "vy", "vz"]: + assert sample[coord].shape == (N_scan,) + assert sample[coord].dtype == FIELD_DTYPE.FLOAT_DATA.value + + def test_Sample_chemical_formula_present( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify chemical_formula field when CHEMICAL_FORMULA log is present""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Add chemical formula to logs - must match number of subruns + subruns = ws._sample_logs.subruns.raw_copy() + N_scan = len(subruns) + ws._sample_logs[HidraConstants.CHEMICAL_FORMULA] = ["Fe3O4"] * N_scan + + sample = _Sample.init_group(ws._sample_logs) + + assert "chemical_formula" in sample + # _Sample takes the first value from the log + assert sample["chemical_formula"] == "Fe3O4" + + def test_Sample_chemical_formula_absent( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify chemical_formula defaults to 'unknown' when not in logs""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Ensure chemical formula is not in logs + if HidraConstants.CHEMICAL_FORMULA in ws._sample_logs: + del ws._sample_logs[HidraConstants.CHEMICAL_FORMULA] + + sample = _Sample.init_group(ws._sample_logs) + + assert "chemical_formula" in sample + assert sample["chemical_formula"] == "unknown" + + def test_Sample_temperature_present(self, load_HidraWorkspace: Callable[..., HidraWorkspace]): + """Verify temperature field and units when TEMPERATURE log is present""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Add temperature data to logs with units using tuple syntax + subruns = ws._sample_logs.subruns.raw_copy() + N_scan = len(subruns) + temp_values = np.linspace(300, 400, N_scan) + + # Use tuple (key, units) to set value with units + ws._sample_logs[(HidraConstants.TEMPERATURE, "K")] = temp_values + + sample = _Sample.init_group(ws._sample_logs) + + assert "temperature" in sample + assert sample["temperature"].shape == (N_scan,) + assert sample["temperature"].dtype == FIELD_DTYPE.FLOAT_DATA.value + assert sample["temperature"].attrs["units"] == "K" + + def test_Sample_temperature_absent( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify no temperature field when TEMPERATURE log is absent""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Ensure temperature is not in logs + if HidraConstants.TEMPERATURE in ws._sample_logs: + del ws._sample_logs[HidraConstants.TEMPERATURE] + + sample = _Sample.init_group(ws._sample_logs) + + assert "temperature" not in sample + + def test_Sample_stress_field_present( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify stress_field field, shape, and direction attr when present""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Add stress field data to logs + subruns = ws._sample_logs.subruns.raw_copy() + N_scan = len(subruns) + stress_values = np.random.randn(N_scan, 3) + + ws._sample_logs[HidraConstants.STRESS_FIELD] = stress_values + # Direction is stored as array with same value for each subrun + ws._sample_logs[HidraConstants.STRESS_FIELD_DIRECTION] = np.array(["z"] * N_scan) + + sample = _Sample.init_group(ws._sample_logs) + + assert "stress_field" in sample + assert sample["stress_field"].shape[0] == N_scan + assert sample["stress_field"].dtype == FIELD_DTYPE.FLOAT_DATA.value + # The direction attribute gets the array value + direction_val = sample["stress_field"].attrs["direction"] + # Using `nexusformat`, for a string attribute it will return a list, check first element + if isinstance(direction_val, list): + assert direction_val[0] == "z" + else: + assert direction_val == "z" + + def test_Sample_stress_field_shape_mismatch(self, load_HidraWorkspace: Callable[..., HidraWorkspace]): + """Verify RuntimeError when stress_field first axis != N_scan""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Add stress field with wrong shape + subruns = ws._sample_logs.subruns.raw_copy() + N_scan = len(subruns) + wrong_shape_stress = np.random.randn(N_scan + 5, 3) # Wrong first dimension + + # Set `_data` dict directly, otherwise `SampleLogs.__setitem__` itself will raise an exception. + ws._sample_logs._data[HidraConstants.STRESS_FIELD] = wrong_shape_stress + + with pytest.raises(RuntimeError, match=r".*unexpected shape.*"): + _Sample.init_group(ws._sample_logs) + + def test_Sample_coordinate_shape_mismatch( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify RuntimeError when coordinate array axis != N_scan""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Corrupt vx to have wrong size by directly manipulating the logs + subruns = ws._sample_logs.subruns.raw_copy() + N_scan = len(subruns) + + # Create bad coordinate data with wrong length + # Set `_data` dict directly, otherwise `SampleLogs.__setitem__` itself will raise an exception. + ws._sample_logs._data["vx"] = np.zeros(N_scan + 5) # Wrong size + ws._sample_logs._data["vy"] = np.zeros(N_scan + 5) + ws._sample_logs._data["vz"] = np.zeros(N_scan + 5) + + with pytest.raises(RuntimeError, match=r".*unexpected shape.*"): + _Sample.init_group(ws._sample_logs) + + def test_Sample_extra_logs( + self, + load_HidraWorkspace: Callable[..., HidraWorkspace], + ): + """Verify logs not in NXstress_logs go to logs NXcollection with local_name""" + ws = load_HidraWorkspace( + file_name=self.PROJECT_FILE_B, name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Add a custom log with ':' in the name and units using tuple syntax + custom_log_name = "HB2B:CS:CustomValue" + subruns = ws._sample_logs.subruns.raw_copy() + N_scan = len(subruns) + custom_log_value = np.full(N_scan, 42.0) + ws._sample_logs[(custom_log_name, "mm")] = custom_log_value + + sample = _Sample.init_group(ws._sample_logs) + + assert "logs" in sample + assert isinstance(sample["logs"], NXcollection) + + # The ':' should be replaced by '_' + expected_field_name = "HB2B_CS_CustomValue" + assert expected_field_name in sample["logs"] + + # Verify attributes + assert sample["logs"][expected_field_name].attrs["local_name"] == custom_log_name + assert sample["logs"][expected_field_name].attrs["units"] == "mm" + + # The ':' should be replaced by '_' + expected_field_name = "HB2B_CS_CustomValue" + assert expected_field_name in sample["logs"] + + # Verify attributes + assert sample["logs"][expected_field_name].attrs["local_name"] == custom_log_name + assert sample["logs"][expected_field_name].attrs["units"] == "mm" diff --git a/tests/unit/pyrs/utilities/NXstress/test_workspace_read.py b/tests/unit/pyrs/utilities/NXstress/test_workspace_read.py new file mode 100644 index 000000000..bf0d54818 --- /dev/null +++ b/tests/unit/pyrs/utilities/NXstress/test_workspace_read.py @@ -0,0 +1,426 @@ +""" +Tests for NXstress workspace read functionality (Part 2) +""" + +import numpy as np +from nexusformat.nexus import ( + NXsample, + NXinstrument, + NXcollection, + NXfield, + NXdetector, + NXdetector_module, + NXmonochromator, + NXsource, + NXtransformations, +) +from nexusformat.nexus.tree import NeXusError + +from pyrs.dataobjects.constants import HidraConstants +from pyrs.utilities.NXstress.NXstress import NXstress +from pyrs.utilities.NXstress._sample import _Sample +from pyrs.utilities.NXstress._instrument import _Instrument, _Masks +from pyrs.utilities.NXstress._definitions import DEFAULT_TAG, FIELD_DTYPE +from pyrs.utilities.NXstress._peaks import _Peaks + +import pytest + + +@pytest.fixture +def roundtrip_nxstress(load_HidraWorkspace, createPeakCollection, tmp_path): + """Fixture that writes and reads back a workspace with peaks""" + + # Load a workspace with instrument geometry + ws_original = load_HidraWorkspace( + file_name="HB2B_1017_w_mask.h5", name="test_workspace", load_raw_counts=True, load_reduced_diffraction=True + ) + + # Set up instrument geometry if not present + if ws_original._instrument_setup is None: + from pyrs.core.instrument_geometry import DENEXDetectorGeometry, DENEXDetectorShift + + geometry = DENEXDetectorGeometry( + num_rows=512, + num_columns=512, + pixel_size_x=0.001, # 1 mm in meters + pixel_size_y=0.001, # 1 mm in meters + arm_length=2.0, # 2 meters + calibrated=True, + ) + ws_original.set_instrument_geometry(geometry) + + # Set detector shift for calibrated geometry + shift = DENEXDetectorShift( + shift_x=0.01, shift_y=0.02, shift_z=0.03, rotation_x=1.0, rotation_y=2.0, rotation_z=3.0, tth_0=0.5 + ) + ws_original.set_detector_shift(shift) + + # Set wavelength if not present (test data may lack monochromator settings) + if ws_original.get_wavelength(calibrated=True, throw_if_not_set=False) is None: + ws_original.set_wavelength(1.486, calibrated=True) + + # Create 2 PeakCollection objects + subruns = ws_original._sample_logs.subruns.raw_copy() + N_subrun = len(subruns) + + peak1 = createPeakCollection( + peak_tag="Al 111", + peak_profile="Gaussian", + background_type="Linear", + wavelength=1.486, + projectfilename="test.h5", + runnumber=1017, + N_subrun=N_subrun, + ) + + peak2 = createPeakCollection( + peak_tag="Si 220", + peak_profile="Gaussian", + background_type="Linear", + wavelength=1.486, + projectfilename="test.h5", + runnumber=1017, + N_subrun=N_subrun, + ) + + peaks_original = [peak1, peak2] + + # Write to NXstress file + nxstress_file = tmp_path / "test_roundtrip.nxs" + with NXstress(nxstress_file, mode="w") as nxs: + nxs.write(ws_original, peaks_original) + + # Re-open and read back + with NXstress(nxstress_file, mode="r") as nxs: + ws_readback, peaks_readback = nxs.read() + + yield ws_original, peaks_original, ws_readback, peaks_readback + + +class TestWorkspaceRoundtrip: + """Test suite for workspace reading via roundtrip""" + + def test_workspace_roundtrip_sample_logs(self, roundtrip_nxstress): + """Verify sample log names and values match between original and readback""" + ws_original, _, ws_readback, _ = roundtrip_nxstress + + # Verify sample log names match + original_logs = set(ws_original.get_sample_log_names()) + readback_logs = set(ws_readback.get_sample_log_names()) + + # All original logs should be present in readback + assert original_logs.issubset(readback_logs), f"Missing logs: {original_logs - readback_logs}" + + # Verify sample log values for vx, vy, vz + for coord_name in HidraConstants.SAMPLE_COORDINATE_NAMES: + if coord_name in ws_original.get_sample_log_names(): + orig_values = ws_original.get_sample_log_values(coord_name) + read_values = ws_readback.get_sample_log_values(coord_name) + np.testing.assert_allclose( + orig_values, read_values, atol=1e-5, err_msg=f"Mismatch in {coord_name} values" + ) + + # Verify subruns match + assert np.array_equal(ws_original.get_sub_runs().raw_copy(), ws_readback.get_sub_runs().raw_copy()) + + def test_workspace_roundtrip_wavelength(self, roundtrip_nxstress): + """Verify wavelength round-trips correctly""" + ws_original, _, ws_readback, _ = roundtrip_nxstress + + # here `get_wavelength` returns `float | dict[int, float]` + wl_original = ws_original.get_wavelength(calibrated=True, throw_if_not_set=False) + wl_readback = ws_readback.get_wavelength(calibrated=True, throw_if_not_set=False) + + if wl_original is not None: + # `HidraWorkspace` *may* hold its wavelength as a `float`, + # so here we just normalize it over all scan-points. + # Readback from NeXus will always return a non-scalar. + if not isinstance(wl_original, dict): + wl_original = {n: wl_original for n in ws_original.get_sub_runs()} + assert wl_readback is not None + np.testing.assert_allclose(list(wl_original.values()), list(wl_readback.values()), rtol=1e-6) + + def test_workspace_roundtrip_instrument(self, roundtrip_nxstress): + """Verify instrument geometry and detector shift round-trip""" + ws_original, _, ws_readback, _ = roundtrip_nxstress + + geom_original = ws_original.get_instrument_setup() + geom_readback = ws_readback.get_instrument_setup() + + # Verify detector size + assert geom_original.detector_size == geom_readback.detector_size + + # Verify pixel dimensions + orig_px = geom_original.pixel_dimension + read_px = geom_readback.pixel_dimension + np.testing.assert_allclose(orig_px, read_px, rtol=1e-6) + + # Verify arm length + np.testing.assert_allclose(geom_original.arm_length, geom_readback.arm_length, rtol=1e-6) + + # Verify detector shift (if present) + shift_original = ws_original.get_detector_shift() + shift_readback = ws_readback.get_detector_shift() + + if shift_original is not None: + assert shift_readback is not None + np.testing.assert_allclose(shift_original.center_shift_x, shift_readback.center_shift_x, rtol=1e-6) + np.testing.assert_allclose(shift_original.center_shift_y, shift_readback.center_shift_y, rtol=1e-6) + np.testing.assert_allclose(shift_original.center_shift_z, shift_readback.center_shift_z, rtol=1e-6) + else: + assert shift_readback is None + + def test_workspace_roundtrip_masks(self, roundtrip_nxstress): + """Verify masks round-trip correctly""" + ws_original, _, ws_readback, _ = roundtrip_nxstress + + # Verify default mask + default_orig = ws_original.get_detector_mask(is_default=True) + default_read = ws_readback.get_detector_mask(is_default=True) + + if default_orig is not None: + assert default_read is not None + assert np.array_equal(default_orig, default_read) + + # Verify user masks + for mask_id in ws_original._mask_dict.keys(): + mask_orig = ws_original.get_detector_mask(is_default=False, mask_id=mask_id) + mask_read = ws_readback.get_detector_mask(is_default=False, mask_id=mask_id) + assert np.array_equal(mask_orig, mask_read), f"Mask {mask_id} doesn't match" + + def test_workspace_roundtrip_reduced_data(self, roundtrip_nxstress): + """Verify reduced diffraction data round-trips correctly""" + ws_original, _, ws_readback, _ = roundtrip_nxstress + + # Verify 2theta matrix + if ws_original._2theta_matrix is not None: + assert ws_readback._2theta_matrix is not None + assert ws_original._2theta_matrix.shape == ws_readback._2theta_matrix.shape + np.testing.assert_allclose(ws_original._2theta_matrix, ws_readback._2theta_matrix, atol=1e-5) + + # Verify diff_data_set and var_data_set for each mask + for mask_id in ws_original._diff_data_set.keys(): + assert mask_id in ws_readback._diff_data_set, f"Mask {mask_id} missing in readback diff_data_set" + + orig_data = ws_original._diff_data_set[mask_id] + read_data = ws_readback._diff_data_set[mask_id] + assert orig_data.shape == read_data.shape + np.testing.assert_allclose(orig_data, read_data, atol=1e-5) + + for mask_id in ws_original._var_data_set.keys(): + assert mask_id in ws_readback._var_data_set, f"Mask {mask_id} missing in readback var_data_set" + + orig_var = ws_original._var_data_set[mask_id] + read_var = ws_readback._var_data_set[mask_id] + assert orig_var.shape == read_var.shape + np.testing.assert_allclose(orig_var, read_var, atol=1e-5) + + def test_workspace_roundtrip_raw_counts(self, roundtrip_nxstress): + """Verify raw counts round-trip correctly""" + ws_original, _, ws_readback, _ = roundtrip_nxstress + + # Verify all subruns have raw counts + for subrun in ws_original._raw_counts.keys(): + assert subrun in ws_readback._raw_counts, f"Subrun {subrun} missing in readback raw_counts" + + orig_counts = ws_original.get_detector_counts(subrun) + read_counts = ws_readback.get_detector_counts(subrun) + assert orig_counts.shape == read_counts.shape + np.testing.assert_allclose(orig_counts, read_counts, atol=1e-5) + + def test_full_roundtrip(self, roundtrip_nxstress): + """Comprehensive test: verify workspace and peaks together""" + ws_original, peaks_original, ws_readback, peaks_readback = roundtrip_nxstress + + # Verify peak collection count + assert len(peaks_original) == len(peaks_readback) + + # Verify each peak collection + for peak_orig, peak_read in zip(peaks_original, peaks_readback): + # we don't care about small changes to the format (e.g. omitted spaces), we only care + # that they parse to the same `(, h, k, l)` tuples + assert _Peaks._parse_peak_tag(peak_orig.peak_tag) == _Peaks._parse_peak_tag(peak_read.peak_tag) + assert peak_orig.peak_profile == peak_read.peak_profile + assert peak_orig.background_type == peak_read.background_type + + # Verify subruns match + assert np.array_equal(peak_orig._sub_run_array.raw_copy(), peak_read._sub_run_array.raw_copy()) + + +class TestReadErrors: + """Test error handling in read operations""" + + def test_read_nonexistent_entry(self, load_HidraWorkspace, tmp_path): + """Attempt to read non-existent entry → KeyError""" + ws = load_HidraWorkspace( + file_name="HB2B_1017.h5", name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Set up instrument geometry if not present + if ws._instrument_setup is None: + from pyrs.core.instrument_geometry import DENEXDetectorGeometry + + geometry = DENEXDetectorGeometry( + num_rows=512, num_columns=512, pixel_size_x=0.001, pixel_size_y=0.001, arm_length=2.0, calibrated=False + ) + ws.set_instrument_geometry(geometry) + + nxstress_file = tmp_path / "test_nonexistent.nxs" + with NXstress(nxstress_file, mode="w") as nxs: + nxs.write(ws, []) + + with pytest.raises(NeXusError, match=r".*Invalid path.*"): + with NXstress(nxstress_file, mode="r") as nxs: + nxs.read(entry_number=99) + + def test_read_outside_context_manager(self, load_HidraWorkspace, tmp_path): + """Call read() outside context manager → RuntimeError""" + # First create a valid NXstress file + ws = load_HidraWorkspace( + file_name="HB2B_1017.h5", name="test_workspace", load_raw_counts=False, load_reduced_diffraction=True + ) + + # Set up instrument geometry if not present + if ws._instrument_setup is None: + from pyrs.core.instrument_geometry import DENEXDetectorGeometry + + geometry = DENEXDetectorGeometry( + num_rows=512, num_columns=512, pixel_size_x=0.001, pixel_size_y=0.001, arm_length=2.0, calibrated=False + ) + ws.set_instrument_geometry(geometry) + + nxstress_file = tmp_path / "test_outside_context.nxs" + with NXstress(nxstress_file, mode="w") as nxs: + nxs.write(ws, []) + + # Now try to read without context manager + nxs = NXstress(nxstress_file, mode="r") + with pytest.raises(RuntimeError, match="context manager"): + nxs.read() + + +class TestStandaloneMethods: + """Test standalone read methods""" + + def test_sampleLogsFromNexus_standalone(self): + """Build NXsample manually, read with sampleLogsFromNexus""" + # Create NXsample group manually + sample = NXsample() + + scan_points = np.array([1, 2, 3], dtype=np.int32) + sample["scan_point"] = NXfield(scan_points, units="") + + # Add coordinates + sample["vx"] = NXfield(np.array([0.0, 1.0, 2.0], dtype=np.float32), units="mm") + sample["vy"] = NXfield(np.array([0.0, 0.0, 0.0], dtype=np.float32), units="mm") + sample["vz"] = NXfield(np.array([0.0, 0.0, 0.0], dtype=np.float32), units="mm") + + # Add name and formula + sample["name"] = NXfield("TestSample") + sample["chemical_formula"] = NXfield("H2O") + + # Add logs collection + logs_coll = NXcollection() + logs_coll["test_log"] = NXfield(np.array([10.0, 20.0, 30.0]), local_name="test:log:pv", units="V") + sample["logs"] = logs_coll + + # Read back + sample_logs = _Sample.sampleLogsFromNexus(sample) + + # Verify + assert np.array_equal(sample_logs.subruns.raw_copy(), scan_points) + assert "vx" in sample_logs + assert "test:log:pv" in sample_logs + np.testing.assert_array_equal(sample_logs["vx"], np.array([0.0, 1.0, 2.0])) + np.testing.assert_array_equal(sample_logs["test:log:pv"], np.array([10.0, 20.0, 30.0])) + + def test_instrumentFromNexus_standalone(self): + """Build NXinstrument manually, read with instrumentFromNexus""" + # Create NXinstrument group manually + inst = NXinstrument() + inst["name"] = "HB2B" + + # Add source + inst["SOURCE"] = NXsource(type="Reactor Neutron Source", probe="neutron") + + # Add monochromator with wavelength + mono = NXmonochromator() + mono["wavelength"] = NXfield(1.486, units="angstrom") + inst["monochromator"] = mono + + # Add detector + det = NXdetector() + det["type"] = "He_3 PSD" + + # Detector bank + det["detector_bank"] = NXdetector_module( + data_size=NXfield(np.array([512, 512], dtype=np.int64)), + fast_pixel_direction=NXfield(np.array(0.001, dtype=np.float64), units="m"), + slow_pixel_direction=NXfield(np.array(0.001, dtype=np.float64), units="m"), + ) + + # Transformations + trans = NXtransformations() + trans.attrs["calibrated"] = True + trans["distance"] = NXfield(2.0, units="m") + trans["translation_x"] = NXfield(0.01, units="m") + trans["translation_y"] = NXfield(0.02, units="m") + trans["translation_z"] = NXfield(0.03, units="m") + trans["rotation_x"] = NXfield(1.0, units="deg") + trans["rotation_y"] = NXfield(2.0, units="deg") + trans["rotation_z"] = NXfield(3.0, units="deg") + trans["two_theta_zero"] = NXfield(0.5, units="deg") + + det["transformations"] = trans + inst["DETECTOR"] = det + + # Read back + geometry, shift, wavelength = _Instrument.instrumentFromNexus(inst) + + # Verify geometry + assert geometry.detector_size == (512, 512) + np.testing.assert_allclose(geometry.pixel_dimension, (0.001, 0.001)) + np.testing.assert_allclose(geometry.arm_length, 2.0) + + # Verify shift + assert shift is not None + np.testing.assert_allclose(shift.center_shift_x, 0.01) + np.testing.assert_allclose(shift.center_shift_y, 0.02) + np.testing.assert_allclose(shift.center_shift_z, 0.03) + np.testing.assert_allclose(shift.rotation_x, 1.0) + np.testing.assert_allclose(shift.rotation_y, 2.0) + np.testing.assert_allclose(shift.rotation_z, 3.0) + np.testing.assert_allclose(shift.two_theta_0, 0.5) + + # Verify wavelength + np.testing.assert_allclose(wavelength, 1.486) + + def test_masksFromNexus_standalone(self): + """Build masks NXcollection manually, read with masksFromNexus""" + # Create masks collection manually + masks = NXcollection() + + # Add mask names + mask_names = np.array([DEFAULT_TAG, "mask_A", "mask_B"], dtype=FIELD_DTYPE.STRING.value) + masks["names"] = NXfield(mask_names) + + # Add detector masks + det_coll = NXcollection() + det_coll[DEFAULT_TAG] = NXfield(np.ones(100, dtype=bool), units="") + det_coll["mask_A"] = NXfield(np.zeros(100, dtype=bool), units="") + masks["detector"] = det_coll + + # Add solid_angle mask + sa_coll = NXcollection() + sa_coll["mask_B"] = NXfield(np.ones(100, dtype=bool), units="") + masks["solid_angle"] = sa_coll + + # Read back + default_mask, mask_dict = _Masks.masksFromNexus(masks) + + # Verify + assert default_mask is not None + assert len(default_mask) == 100 + assert "mask_A" in mask_dict + assert "mask_B" in mask_dict + assert len(mask_dict) == 2 diff --git a/tests/util/__init__.py b/tests/util/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/util/input_data_helpers.py b/tests/util/input_data_helpers.py new file mode 100644 index 000000000..b0f22310d --- /dev/null +++ b/tests/util/input_data_helpers.py @@ -0,0 +1,50 @@ +""" +tests/util/input_data_helpers.py + +Helper for ensuring a HidraWorkspace has its raw detector counts (_raw_counts) +populated, for use in smoke-test scripts that load HiDRA project files which do +not retain the raw pixel data. + +NOTE: this module imports from ``pyrs.core.nexus_conversion`` which depends on +Mantid. It should only be used from smoke-test scripts or integration tests +that run in a Mantid-enabled environment, *not* from pure-Python unit tests. +""" + +from pyrs.core.nexus_conversion import NeXusConvertingApp +from pyrs.core.workspaces import HidraWorkspace +from pyrs.utilities.file_util import get_nexus_file + + +def ensure_input_data(ws: HidraWorkspace, run_number: int) -> None: + """Populate *ws._raw_counts* from the HFIR archive if not already loaded. + + Locates the raw NeXus event file for *run_number* via Mantid's + ``FileFinder`` (with ``finddata`` as a fallback), converts the pixel + event data with ``NeXusConvertingApp.convert()``, and copies the resulting + per-sub-run detector counts into *ws* using ``ws.set_raw_counts()``. + + This is a no-op when *ws._raw_counts* is already non-empty (e.g. the + project file was loaded with ``load_raw_counts=True``). + + The sample logs, reduced diffraction data, peak fits, and instrument + geometry already present in *ws* are not touched. + + Parameters + ---------- + ws: + ``HidraWorkspace`` to populate in-place. + run_number: + HB2B run number (integer) whose raw NeXus file should be loaded. + The IPTS directory is resolved automatically via Mantid's archive + search, which looks under ``/HFIR/HB2B/IPTS-*/nexus/HB2B_{run}.nxs.h5``. + """ + if ws._raw_counts: + # Already populated -- nothing to do. + return + + nexus_path = get_nexus_file(run_number) + converter = NeXusConvertingApp(nexus_path) + converted = converter.convert() + + for sub_run, counts in converted._raw_counts.items(): + ws.set_raw_counts(sub_run, counts) diff --git a/tests/util/instrument_helpers.py b/tests/util/instrument_helpers.py new file mode 100644 index 000000000..52497d3de --- /dev/null +++ b/tests/util/instrument_helpers.py @@ -0,0 +1,53 @@ +""" +tests/util/instrument_helpers.py + +Helpers for ensuring a HidraWorkspace has instrument geometry set, +for use in tests and demo scripts that load Hidra project files which +may not contain an instrument section. +""" + +from pyrs.core.instrument_geometry import DENEXDetectorGeometry +from pyrs.core.workspaces import HidraWorkspace + +# Import the canonical HB2B engineering constants from the one place they +# are defined, so there is no duplication. +from pyrs.core.nexus_conversion import NUM_PIXEL_1D, PIXEL_SIZE, ARM_LENGTH + + +def default_hb2b_geometry() -> DENEXDetectorGeometry: + """Return the standard HB2B DENEX detector geometry using nominal engineering values. + + These are the same hardcoded values used by ``NeXusConvertingApp`` when it + initialises a fresh ``HidraWorkspace`` from a NeXus file. The geometry is + *not* calibrated (``calibrated=False``) and carries no detector shift, i.e. + it represents the as-built instrument with no alignment corrections applied. + """ + return DENEXDetectorGeometry( + NUM_PIXEL_1D, + NUM_PIXEL_1D, + PIXEL_SIZE, + PIXEL_SIZE, + ARM_LENGTH, + False, # not calibrated — nominal engineering values, no shift applied + ) + + +def ensure_instrument_geometry(ws: HidraWorkspace) -> None: + """Set the default HB2B geometry on *ws* if none is already present. + + Most Hidra project files do not include an instrument section, but + ``NXstress`` requires one. Calling this function after + ``ws.load_hidra_project(...)`` guarantees the workspace has a geometry + without overwriting one that was stored in the file. + + The geometry installed here is the nominal (uncalibrated) HB2B engineering + geometry; no ``DENEXDetectorShift`` is applied, so + ``ws._instrument_geometry_shift`` is left untouched. + + Parameters + ---------- + ws: + The ``HidraWorkspace`` to patch in-place. + """ + if ws._instrument_setup is None: + ws.set_instrument_geometry(default_hb2b_geometry()) diff --git a/tests/util/mask_helpers.py b/tests/util/mask_helpers.py new file mode 100644 index 000000000..0b1724fbe --- /dev/null +++ b/tests/util/mask_helpers.py @@ -0,0 +1,34 @@ +""" +tests/util/mask_helpers.py + +Helpers for adding masks to a HidraWorkspace in tests. +""" + +import numpy as np + +from pyrs.core.workspaces import HidraWorkspace + + +def add_named_detector_mask(ws: HidraWorkspace, mask_name: str) -> np.ndarray: + """Add a named (non-default) all-pass detector mask to a workspace and return it. + + The mask array is shaped to match the workspace's instrument detector size. + All pixels are set to 1 (unmasked). + + Parameters + ---------- + ws : HidraWorkspace + The workspace to add the mask to. + mask_name : str + A non-empty, non-default name for the mask. + + Returns + ------- + np.ndarray + The mask array that was added. + """ + setup = ws.get_instrument_setup() + nrows, ncols = setup.detector_size + mask_array = np.ones(nrows * ncols, dtype=np.int64) + ws.set_detector_mask(mask_array, False, mask_name) + return mask_array diff --git a/tests/util/peak_collection_helpers.py b/tests/util/peak_collection_helpers.py new file mode 100644 index 000000000..53eeebe8d --- /dev/null +++ b/tests/util/peak_collection_helpers.py @@ -0,0 +1,120 @@ +from collections.abc import Callable, Generator +import numpy as np + +from pyrs.core.peak_profile_utility import get_parameter_dtype +from pyrs.core.workspaces import HidraWorkspace +from pyrs.peaks import FitEngineFactory as PeakFitEngineFactory # type: ignore +from pyrs.peaks.peak_collection import PeakCollection +from pyrs.peaks.peak_fit_engine import FitResult + +import pytest + +RNG = np.random.default_rng(seed=0x923F109B1D944AF5) + + +@pytest.fixture +def createPeakCollection() -> Generator[Callable[..., PeakCollection]]: + # This fixture generates a `PeakCollection` instance initialized using random values. + + def _init( + *, + peak_tag: str, + peak_profile: str, + background_type: str, + wavelength: float, + projectfilename: str, + runnumber: int, + N_subrun: int, + exclude_list=None, + N_counts=1000, # range for random counts + N_span=10000.0, # domain for random axes + error_fraction=0.01, # fractional error for various initializations + ) -> PeakCollection: + peaks = PeakCollection( + peak_tag, + peak_profile, + background_type, + wavelength=wavelength, + projectfilename=projectfilename, + runnumber=runnumber, + ) + + """ + # Grab some random indices from somewhere in the middle of the permutations sequence. + all_runs = [n for n in range(3 * N_subrun)] + subruns = next(islice(permutations((n for n in range(3 * N_subrun)), N_subrun), 2 * N_subrun, 2 * N_subrun + 1)) + """ + # Assume subruns are supposed to be in order. Why would that be the case? + subruns = [n + 1 for n in range(N_subrun)] + + # Ensure that the parameter values are somewhat physically meaningful: + # for example, no negative peak widths or out-of-range mixing fractions. + params = peaks._peak_profile.native_parameters + dtypes = dict(get_parameter_dtype(peaks._peak_profile, peaks._background_type)) + param_values = np.zeros(N_subrun, list(dtypes.items())) + param_errors = np.zeros(N_subrun, list(dtypes.items())) + for param in params: + dtype = dtypes[param] + match param: + case "Height" | "Intensity": + vs = RNG.uniform(0.0, N_counts, size=(N_subrun,)).astype(dtype) + es = RNG.uniform(0.0, error_fraction * N_counts, size=(N_subrun,)).astype(dtype) + case "PeakCentre": + vs = RNG.uniform(0.0, N_span, size=(N_subrun,)).astype(dtype) + es = RNG.uniform(0.0, error_fraction * N_span, size=(N_subrun,)).astype(dtype) + case "Sigma" | "FWHM": + vs = RNG.uniform(0.0, N_span / 10.0, size=(N_subrun,)).astype(dtype) + es = RNG.uniform(0.0, error_fraction * N_span / 10.0, size=(N_subrun,)).astype(dtype) + case "Mixing": + vs = RNG.uniform(0.0, 1.0, size=(N_subrun,)).astype(dtype) + es = RNG.uniform(0.0, error_fraction * 1.0, size=(N_subrun,)).astype(dtype) + case _: + raise RuntimeError(f"`createPeakCollection`: unexpected param '{param}'") + + param_values[param] = vs + param_errors[param] = es + + fit_costs = RNG.uniform(0.0, 100.0, size=(N_subrun,)).astype(dtype) + + peaks.set_peak_fitting_values(subruns, param_values, param_errors, fit_costs, exclude_list) + return peaks + + yield _init + + # teardown follows + pass + + +def generate_FitResults_from_workspace(hidra_ws: HidraWorkspace, fit_dic: dict = {}) -> list[FitResult]: + """ + You can use file tests/data/3393_PWHT-TD.h5 with fit_dic={"0": {"peak_range": [87.599, 91.569], "peak_label": "Peak0", "d0": 1.08}, "1": {"peak_range": [93.544, 95.89], "peak_label": "Peak1", "d0": 1.03}} + """ + fit_results = [] + fit_engine = PeakFitEngineFactory.getInstance( + hidraworkspace=hidra_ws, + peak_function_name="PseudoVoigt", + background_function_name="Linear", + wavelength=hidra_ws.get_wavelength(True, True), + ) + + for peak in fit_dic.keys(): + print("Fitting data") + print("peak_tag: {}".format(fit_dic[peak]["peak_label"])) + print("x_min: {}".format(fit_dic[peak]["peak_range"][0])) + print("x_max: {}".format(fit_dic[peak]["peak_range"][1])) + print("") + + result = fit_engine.fit_peaks( + peak_tag=fit_dic[peak]["peak_label"], + x_min=fit_dic[peak]["peak_range"][0], + x_max=fit_dic[peak]["peak_range"][1], + ) + + d0 = fit_dic[peak].get("d0") + if d0 is not None: + for pc in result.peakcollections: + pc.set_d_reference(values=float(d0), errors=0.0) + + fit_results.append(result) + + return fit_results