Skip to content

Commit 3467c72

Browse files
Add initial Bayesian analysis implementation with BUMPS DREAM (#170)
* Add Bayesian analysis design note * Add arviz for Bayesian analysis * Remove old package structure documentation * Update package structure docs with refln reorganization * Plan Bayesian DREAM implementation * Register BUMPS DREAM minimizer * Add Bayesian fit result models * Thread random seed through fitting * Implement DREAM sampling * Add Bayesian fit result display * Plot Bayesian parameter correlations * Add posterior ArviZ plots * Add posterior predictive plots * Refine Bayesian fit UX * Fix DREAM sampler progress reporting * Fix posterior pair plot axis sharing * Improve Bayesian demo parameter choices * Expose DREAM sampler settings * Render posterior marginals as KDE curves * Add posterior pair density contours * Switch Bayesian demo to correlated pair * Add Bayesian tracking and posterior plot updates * Add posterior draws and log-posterior tracking * Use population mean log-posterior for progress tracking * Polish Bayesian progress and posterior plots * Fix DREAM diagnostics and posterior KDEs * Refine posterior plot styling * Improve posterior pair plot UX * Add uncertainty-based fit bounds method * Tighten posterior pair plot layout * Make fit bounds helper a setter * Refine posterior contour layering * Fix posterior contour layering * Preserve pair plot sample hover * Enforce pair plot trace z-order * Restore pair plot axis frames * Split posterior diagnostic warnings * Strengthen pair plot axis borders * Free broad_gauss and set bounds from uncertainty * Draw explicit pair plot borders * Align pair plot y-axis titles * Unify plot axis border colors * Lock posterior pair axis ranges * Align pair plot title with modebar * Update diagonal subplot axis styling * Expose DREAM init and align pair labels * Tighten fit bounds multiplier from 5 to 4 * Match pair plot axis title font sizes * Disable Rich highlighting in Bayesian summaries * Tune DREAM and model parameters in fit * Expand Bayesian tutorial walkthrough * Apply linting rules and formatting * Add LBCO Bayesian tutorial * Make posterior pair plots responsive * Add DREAM bound validation and flexible parameter selection * Adopt fixed-aspect CSS for posterior pair plots * Add posterior pair plot rendering modes * Add multiline axis titles to posterior pair plots * Redesign correlation heatmap display * Simplify tutorial parameter loops and bounds * Improve hover template readability * Improve posterior plot binning and styling * Refactor posterior x-axis range to static method * Change posterior predictive default style to band * Add separate caching for band summaries * Reduce sampling steps and adjust plot ranges * Update posterior pair plot marker and background * Update notebooks * Fix docstring errors in Plotter class * Standardize axis title font size * Improve Bayesian fit summary display * Improve Bayesian fit result display * Adjust posterior and band fill transparency * Update fit bounds and plot range in ed-21 * Improve posterior table diagnostic notes * Add parallel DREAM sampling * Add parallel=0 description to DREAM tutorial * Fix test expectations for r-hat and parallel=0 * Add Bayesian DREAM to architecture * Clean up * Fix Bayesian diagnostics and DREAM cleanup edge cases * Fix square matrix plot spacing and aspect ratio * Apply the latest templates * Bump setup-pixi to v0.9.5 * Bump dependencies * Bump pixi.lock from v6 to v7 * Add correlation-based limits to posterior pair plots * Improve posterior summary plot styling * Add single-crystal posterior predictive scatter plot * Add Tb2TiO7 Bayesian tutorial * Set default correlation and pair-plot limit to six * Bump copier template to v0.11.3 * Update tutorials * Adjust posterior pair plot margins and title shift * Generalize pair-plot layout to square matrix * Switch DREAM defaults and refine Bayesian fit displays * Show uncertainty multiplier in pair plot titles * Refine Bayesian tutorial examples * Shorten fit-bounds multiplier constant name * Bump dependencies * Add ADR documents * Improve CI and codecov settings * Fix structure factor support for X-ray * Increase integration coverage for Bayesian fit helpers * Remove unused benchmark dependency and track serial benchmarks * Normalize styled console output in Windows integration tests
1 parent 2a48780 commit 3467c72

69 files changed

Lines changed: 25035 additions & 11639 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.codecov.yml‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Codecov configuration
2+
# https://docs.codecov.com/docs/codecov-yaml
3+
4+
github_checks:
5+
annotations: true
6+
7+
comment:
8+
layout: 'reach, diff, flags, files'
9+
behavior: default
10+
require_changes: false
11+
require_base: false
12+
require_head: true
13+
14+
coverage:
15+
status:
16+
project:
17+
default:
18+
target: auto
19+
threshold: 1%
20+
# Make project coverage informational (won't block PR)
21+
informational: true
22+
patch:
23+
default:
24+
target: auto
25+
# Require patch coverage but with threshold
26+
threshold: 1%

‎.copier-answers.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# WARNING: Do not edit this file manually.
22
# Any changes will be overwritten by Copier.
3-
_commit: v0.11.1-12-gbb9bb30
3+
_commit: v0.11.4
44
_src_path: gh:easyscience/templates
55
app_docs_url: https://easyscience.github.io/diffraction-app
66
app_doi: 10.5281/zenodo.18163581

‎.github/actions/setup-pixi/action.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ inputs:
3333
runs:
3434
using: 'composite'
3535
steps:
36-
- uses: prefix-dev/setup-pixi@v0.9.4
36+
- uses: prefix-dev/setup-pixi@v0.9.5
3737
with:
3838
environments: ${{ inputs.environments }}
3939
activate-environment: ${{ inputs.activate-environment }}

‎.github/copilot-instructions.md‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
## Testing
7878

7979
- Every new module, class, or bug fix ships with tests. See
80-
`docs/architecture/architecture.md` §10 for the full strategy.
80+
`docs/dev/architecture.md` §10 for the full strategy.
8181
- Unit tests mirror the source tree:
8282
`src/easydiffraction/<pkg>/<mod>.py` →
8383
`tests/unit/easydiffraction/<pkg>/test_<mod>.py`. Verify with
@@ -102,8 +102,8 @@
102102

103103
- Before any structural/design change (new categories, factories,
104104
switchable-category wiring, datablocks, CIF serialisation), read
105-
`docs/architecture/architecture.md` and follow documented patterns.
106-
Localised bug fixes or test updates need only this file.
105+
`docs/dev/architecture.md` and follow documented patterns. Localised
106+
bug fixes or test updates need only this file.
107107
- Project is in beta: no legacy shims, no deprecation warnings — update
108108
tests and tutorials to the current API.
109109
- Minimal diffs; don't reformat working code. Fix only what's asked;
@@ -146,13 +146,12 @@ Non-trivial changes use a two-phase workflow:
146146

147147
Notes:
148148

149-
- `pixi run fix` regenerates `docs/architecture/package-structure-*.md`
149+
- `pixi run fix` regenerates `docs/dev/package-structure-*.md`
150150
automatically — never edit those by hand. Don't review auto-fixes;
151151
accept and move on. Then `pixi run check` until clean.
152152
- Open issues / design questions / planned improvements live in
153-
`docs/architecture/issues_open.md` (priority-ordered). On resolution,
154-
move to `docs/architecture/issues_closed.md` and update
155-
`architecture.md` if affected.
153+
`docs/dev/issues_open.md` (priority-ordered). On resolution, move to
154+
`docs/dev/issues_closed.md` and update `architecture.md` if affected.
156155

157156
### Planning
158157

‎.github/workflows/coverage.yml‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ on:
55
push:
66
branches:
77
- develop
8-
# Do not run on version tags (those are handled by other workflows)
9-
tags-ignore: ['v*']
108
# Trigger the workflow on pull request
119
pull_request:
1210
# Allows you to run this workflow manually from the Actions tab

‎.github/workflows/dashboard.yml‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@ jobs:
3232
- name: Set up pixi
3333
uses: ./.github/actions/setup-pixi
3434

35+
# Install badgery into the active Pixi environment without modifying
36+
# pixi.toml/pixi.lock. Using `pixi add` here re-solves the whole project
37+
# and rebuilds the local editable package, which can cause intermittent
38+
# Linux CI failures (`Text file busy`, os error 26).
3539
- name: Install badgery
3640
shell: bash
37-
run: pixi add --pypi --git https://github.com/enhantica/badgery badgery
41+
run: pixi run python -m pip install git+https://github.com/enhantica/badgery
3842

3943
- name: Run docstring coverage and code complexity/maintainability checks
4044
run: |
Lines changed: 20 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
# Verifies if the current issue has at least one real `[scope]` label and one
2-
# real `[priority]` label. If either is missing, the workflow adds a reminder
3-
# label with a warning emoji.
1+
# Verifies if the current issue has at least one `[scope]` label and one
2+
# `[priority]` label. If either is missing, the workflow adds a reminder label.
43

54
name: Issue labels check
65

@@ -20,130 +19,22 @@ jobs:
2019
cancel-in-progress: true
2120

2221
steps:
23-
- name: Checkout repository
24-
uses: actions/checkout@v6
25-
26-
- name: Sync missing-label reminders
27-
uses: ./.github/actions/github-script
22+
- name: Ensure [scope] label
23+
uses: Rindrics/expect-label-prefix@v1.2.1
2824
with:
29-
script: |
30-
const fs = require('fs');
31-
32-
const issueNumber = context.issue.number;
33-
const action = context.payload.action;
34-
const changedLabel = context.payload.label?.name ?? null;
35-
const labels = context.payload.issue.labels.map(({ name }) => name);
36-
const requirements = [
37-
{
38-
prefix: '[scope] ',
39-
reminder: '[scope] ⚠️ label needed',
40-
},
41-
{
42-
prefix: '[priority] ',
43-
reminder: '[priority] ⚠️ label needed',
44-
},
45-
];
46-
47-
const labelsToAdd = [];
48-
const labelsToRemove = [];
49-
const evaluations = [];
50-
51-
console.log(`::group::Issue label check for #${issueNumber}`);
52-
console.log(`Event action: ${action}`);
53-
if (changedLabel) {
54-
console.log(`Event label: ${changedLabel}`);
55-
}
56-
console.log(
57-
`Current labels: ${labels.length > 0 ? labels.join(', ') : '(none)'}`,
58-
);
59-
60-
for (const { prefix, reminder } of requirements) {
61-
const matchingRealLabels = labels.filter(
62-
(name) => name.startsWith(prefix) && name !== reminder,
63-
);
64-
const hasRealLabel = matchingRealLabels.length > 0;
65-
const hasReminderLabel = labels.includes(reminder);
66-
67-
evaluations.push({
68-
prefix,
69-
reminder,
70-
matchingRealLabels,
71-
hasReminderLabel,
72-
});
73-
74-
if (hasRealLabel && hasReminderLabel) {
75-
labelsToRemove.push(reminder);
76-
} else if (!hasRealLabel && !hasReminderLabel) {
77-
labelsToAdd.push(reminder);
78-
}
79-
}
80-
81-
for (const evaluation of evaluations) {
82-
if (evaluation.matchingRealLabels.length > 0) {
83-
console.log(
84-
`Found required ${evaluation.prefix}label(s): ${evaluation.matchingRealLabels.join(', ')}`,
85-
);
86-
} else {
87-
console.log(`Missing required ${evaluation.prefix}label.`);
88-
}
89-
90-
if (evaluation.hasReminderLabel) {
91-
console.log(`Reminder label already present: ${evaluation.reminder}`);
92-
}
93-
}
94-
95-
if (labelsToAdd.length > 0) {
96-
console.log(`Adding reminder labels: ${labelsToAdd.join(', ')}`);
97-
await github.rest.issues.addLabels({
98-
owner: context.repo.owner,
99-
repo: context.repo.repo,
100-
issue_number: context.issue.number,
101-
labels: labelsToAdd,
102-
});
103-
}
104-
105-
for (const name of labelsToRemove) {
106-
console.log(`Removing reminder label: ${name}`);
107-
await github.rest.issues.removeLabel({
108-
owner: context.repo.owner,
109-
repo: context.repo.repo,
110-
issue_number: context.issue.number,
111-
name,
112-
});
113-
}
114-
115-
if (labelsToAdd.length === 0 && labelsToRemove.length === 0) {
116-
console.log('No label changes required.');
117-
}
118-
119-
console.log('::endgroup::');
120-
121-
if (process.env.GITHUB_STEP_SUMMARY) {
122-
const summaryLines = [
123-
'### Issue Label Check',
124-
`- Issue: #${issueNumber}`,
125-
`- Event: ${action}`,
126-
`- Trigger label: ${changedLabel ?? '(none)'}`,
127-
`- Current labels: ${labels.length > 0 ? labels.join(', ') : '(none)'}`,
128-
'',
129-
'#### Requirement status',
130-
...evaluations.map((evaluation) => {
131-
const status =
132-
evaluation.matchingRealLabels.length > 0
133-
? `found ${evaluation.matchingRealLabels.join(', ')}`
134-
: 'missing';
135-
const reminder = evaluation.hasReminderLabel
136-
? `reminder present: ${evaluation.reminder}`
137-
: `reminder absent: ${evaluation.reminder}`;
138-
return `- ${evaluation.prefix}: ${status}; ${reminder}`;
139-
}),
140-
'',
141-
`- Labels to add: ${labelsToAdd.length > 0 ? labelsToAdd.join(', ') : '(none)'}`,
142-
`- Labels to remove: ${labelsToRemove.length > 0 ? labelsToRemove.join(', ') : '(none)'}`,
143-
];
144-
145-
fs.appendFileSync(
146-
process.env.GITHUB_STEP_SUMMARY,
147-
`${summaryLines.join('\n')}\n`,
148-
);
149-
}
25+
repository_full_name: ${{ github.repository }}
26+
token: ${{ github.token }}
27+
label_prefix: '[scope]'
28+
label_separator: ' '
29+
add_label: 'true'
30+
default_label: '[scope] ⚠️ label needed'
31+
32+
- name: Ensure [priority] label
33+
uses: Rindrics/expect-label-prefix@v1.2.1
34+
with:
35+
repository_full_name: ${{ github.repository }}
36+
token: ${{ github.token }}
37+
label_prefix: '[priority]'
38+
label_separator: ' '
39+
add_label: 'true'
40+
default_label: '[priority] ⚠️ label needed'

‎.github/workflows/pr-labels.yml‎

Lines changed: 28 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,45 @@
11
# Verifies if a pull request has at least one label from a set of valid
22
# labels before it can be merged.
33
#
4-
# NOTE:
5-
# This workflow may be triggered twice in quick succession when a PR is
6-
# created:
7-
# 1) `opened` — when the pull request is initially created
8-
# 2) `labeled` — if labels are added immediately after creation
9-
# (e.g. by manual labeling, another workflow, or GitHub App).
10-
#
11-
# These are separate GitHub events, so two workflow runs can be started.
12-
# The `concurrency` configuration below ensures that only the latest run
13-
# for the same PR remains active, canceling any previous in-progress
14-
# run.
4+
# The label validation is delegated to `mheap/github-action-required-labels`,
5+
# which checks the current PR labels via the GitHub API and can add or update a
6+
# PR comment when the required label set is missing.
157

168
name: PR labels check
179

1810
on:
1911
pull_request_target:
2012
types: [opened, labeled, unlabeled, synchronize]
2113

22-
concurrency:
23-
group: pr-labels-${{ github.event.pull_request.number }}
24-
cancel-in-progress: true
25-
2614
permissions:
27-
pull-requests: read
15+
issues: write
16+
pull-requests: write
2817

2918
jobs:
3019
check-labels:
3120
runs-on: ubuntu-latest
3221

3322
steps:
34-
- name: Check for valid labels
35-
run: |
36-
PR_LABELS=$(echo '${{ toJson(github.event.pull_request.labels.*.name) }}' | jq -r '.[]')
37-
38-
echo "Current PR labels: $PR_LABELS"
39-
VALID_LABELS=(
40-
"[bot] release"
41-
"[scope] bug"
42-
"[scope] documentation"
43-
"[scope] enhancement"
44-
"[scope] maintenance"
45-
"[scope] significant"
46-
)
47-
48-
found=false
49-
for label in "${VALID_LABELS[@]}"; do
50-
if echo "$PR_LABELS" | grep -Fxq "$label"; then
51-
echo "✅ Found valid label: $label"
52-
found=true
53-
break
54-
fi
55-
done
56-
57-
if [ "$found" = false ]; then
58-
echo "ERROR: PR must have at least one of the following labels:"
59-
for label in "${VALID_LABELS[@]}"; do
60-
echo " - $label"
61-
done
62-
exit 1
63-
fi
23+
- name: Checkout repository
24+
uses: actions/checkout@v6
25+
26+
- name: Setup easyscience[bot]
27+
id: bot
28+
uses: ./.github/actions/setup-easyscience-bot
29+
with:
30+
app-id: ${{ vars.EASYSCIENCE_APP_ID }}
31+
private-key: ${{ secrets.EASYSCIENCE_APP_KEY }}
32+
33+
- uses: mheap/github-action-required-labels@v5
34+
with:
35+
token: ${{ steps.bot.outputs.token }}
36+
add_comment: true
37+
mode: minimum
38+
count: 1
39+
labels: |
40+
[bot] release
41+
[scope] bug
42+
[scope] documentation
43+
[scope] enhancement
44+
[scope] maintenance
45+
[scope] significant

‎.github/workflows/test.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,10 @@ jobs:
248248
exit 1
249249
fi
250250
251-
whl_url="file://$(python -c 'import os,sys; print(os.path.abspath(sys.argv[1]))' "${whl_path[0]}")"
251+
whl_abs_path="$(python -c 'import os,sys; print(os.path.abspath(sys.argv[1]))' "${whl_path[0]}")"
252252
253-
echo "Adding easydiffraction from: $whl_url"
254-
pixi add --pypi "easydiffraction[dev] @ ${whl_url}"
253+
echo "Adding easydiffraction from: $whl_abs_path"
254+
pixi add --pypi "easydiffraction[dev] @ ${whl_abs_path}"
255255
256256
echo "Exiting pixi project directory"
257257
cd ..

‎CONTRIBUTING.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,12 @@ or to run only Python linting checks:
249249
pixi run py-lint-check
250250
```
251251

252+
To add missing license headers:
253+
254+
```bash
255+
pixi run spdx-add
256+
```
257+
252258
Some formatting issues can be fixed automatically:
253259

254260
```bash

0 commit comments

Comments
 (0)