Repository navigation
Use each bin's width in dndm_from_sample - #427
Conversation
dndm_from_sample() took the width of every bin from the first one, so dn/dm was wrong in all other bins when bins were given as non-uniform edges, which the bins parameter allows.
Reviewer's guide (collapsed on small PRs)Reviewer's GuideFix dndm_from_sample so each bin is normalized by its own width in log10 mass, and add a regression test confirming correct dn/dm values for non-uniform bin edges. Flow diagram for per-bin dndm normalizationflowchart LR
M["Sample masses m"] --> H["np.histogram(np.log10(m), bins, weights=nm)"]
H --> E["Bin edges"]
E --> D["np.diff(edges)"]
E --> C["Bin centres"]
D --> N["Normalize each bin by its own width"]
C --> N
N --> R["dndm_from_sample result"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/hmf/helpers/sample.py" line_range="108" />
<code_context>
hist, edges = np.histogram(np.log10(m), bins, weights=nm)
centres = (edges[1:] + edges[:-1]) / 2
- dx = centres[1] - centres[0]
+ dx = np.diff(edges)
hist = hist.astype("float") / (10**centres * float(V) * dx * np.log(10))
</code_context>
<issue_to_address>
**Concurrent bin changes skew normalization**
When another thread mutates the ndarray passed as `bins` between the `centres` calculation and `np.diff(edges)`, `np.histogram` returns the supplied edge array, so `dx` can read newly mutated widths while `hist` and `centres` reflect the earlier edges, producing a misnormalized result.
Copy caller-provided bin edges before passing them to `np.histogram`, and use that snapshot throughout the calculation.
</issue_to_address>
### Comment 2
<location path="tests/test_sample.py" line_range="71" />
<code_context>
+ centres, hist = dndm_from_sample(m, volume, bins=bins)
+
+ expected = n / (volume * 3 * 10**centres * np.log(10))
+ assert np.allclose(hist, expected, rtol=1e-10)
</code_context>
<issue_to_address>
**Uneven-bin test misses the bug**
When the old equal-width normalization is used, `np.allclose` uses its default `atol=1e-8`, much larger than the expected histogram values in the higher-mass bins (about `1e-10`). The old equal-width normalization therefore still satisfies this assertion, so the regression test passes with the bug present.
Set an explicit `atol` small enough for these values (or zero) so the test detects the incorrect bin normalization.
</issue_to_address>Sourcery assessment
Approval pending. 2 findings to address first.
Blocking findings: src/hmf/helpers/sample.py:108, tests/test_sample.py:71
| hist, edges = np.histogram(np.log10(m), bins, weights=nm) | ||
| centres = (edges[1:] + edges[:-1]) / 2 | ||
| dx = centres[1] - centres[0] | ||
| dx = np.diff(edges) |
There was a problem hiding this comment.
🟡 Medium · Concurrent bin changes skew normalization
When another thread mutates the ndarray passed as bins between the centres calculation and np.diff(edges), np.histogram returns the supplied edge array, so dx can read newly mutated widths while hist and centres reflect the earlier edges, producing a misnormalized result.
Copy caller-provided bin edges before passing them to np.histogram, and use that snapshot throughout the calculation.
Prompt for AI agents
In `src/hmf/helpers/sample.py` at line 108:
**Concurrent bin changes skew normalization**
When another thread mutates the ndarray passed as `bins` between the `centres` calculation and `np.diff(edges)`, `np.histogram` returns the supplied edge array, so `dx` can read newly mutated widths while `hist` and `centres` reflect the earlier edges, producing a misnormalized result.
Copy caller-provided bin edges before passing them to `np.histogram`, and use that snapshot throughout the calculation.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #427 +/- ##
=======================================
Coverage 99.60% 99.60%
=======================================
Files 62 62
Lines 7819 7819
=======================================
Hits 7788 7788
Misses 31 31 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
np.allclose defaults to atol=1e-8, larger than the expected dn/dm in the upper bins (about 1e-10), so those bins were not effectively checked.
akashdeshmukh-git
left a comment
There was a problem hiding this comment.
Tolerance: fixed in 200473c with an explicit atol=0. Thread safety: not applicable. The function only uses the edges array returned by np.histogram, never bins after that call.
steven-murray
left a comment
There was a problem hiding this comment.
Thank you @akashdeshmukh-git !
dndm_from_sample() took the width of every bin from the first one, so dn/dm was wrong in all other bins when bins were given as non-uniform edges, which the bins parameter allows.
Summary
Type of change
Linked issues
Checklist
I have
Summary by Sourcery
Fix dndm_from_sample to calculate mass functions correctly for non-uniform bins.
Bug Fixes: