|
10 | 10 | merge_calibration, |
11 | 11 | normalize_by_monitor_histogram, |
12 | 12 | normalize_by_monitor_integrated, |
| 13 | + normalize_by_vanadium_dspacing, |
| 14 | + normalize_by_vanadium_dspacing_and_two_theta, |
13 | 15 | ) |
14 | 16 | from ess.powder.types import ( |
15 | 17 | CaveMonitor, |
16 | 18 | CorrectedDspacing, |
| 19 | + FocussedDataDspacing, |
| 20 | + FocussedDataDspacingTwoTheta, |
17 | 21 | NormalizedDspacing, |
18 | 22 | SampleRun, |
19 | 23 | UncertaintyBroadcastMode, |
| 24 | + VanadiumRun, |
20 | 25 | WavelengthMonitor, |
21 | 26 | ) |
22 | 27 |
|
@@ -454,3 +459,181 @@ def test_normalize_by_monitor_integrated_assigns_mask_if_monitor_range_too_narro |
454 | 459 | monitor=WavelengthMonitor[SampleRun, CaveMonitor](monitor), |
455 | 460 | uncertainty_broadcast_mode=UncertaintyBroadcastMode.fail, |
456 | 461 | ) |
| 462 | + |
| 463 | + |
| 464 | +class TestNormalizeByVanadium: |
| 465 | + def random_variable( |
| 466 | + self, |
| 467 | + rng: np.random.Generator, |
| 468 | + dim: str, |
| 469 | + n: int, |
| 470 | + unit: str, |
| 471 | + with_variances: bool = False, |
| 472 | + ) -> sc.Variable: |
| 473 | + values = rng.uniform(0.1, 2.0, n) |
| 474 | + variances = values * rng.uniform(0.1, 0.5, n) if with_variances else None |
| 475 | + return sc.array(dims=[dim], values=values, variances=variances, unit=unit) |
| 476 | + |
| 477 | + def random_binned_data( |
| 478 | + self, |
| 479 | + rng: np.random.Generator, |
| 480 | + n_events: int, |
| 481 | + unit: str, |
| 482 | + with_variances: bool = False, |
| 483 | + *coords: tuple[str, int, str], |
| 484 | + ) -> sc.DataArray: |
| 485 | + return sc.DataArray( |
| 486 | + self.random_variable( |
| 487 | + rng, 'event', n_events, unit, with_variances=with_variances |
| 488 | + ), |
| 489 | + coords={ |
| 490 | + dim: self.random_variable(rng, 'event', n_events, coord_unit) |
| 491 | + for (dim, _, coord_unit) in coords |
| 492 | + }, |
| 493 | + ).bin({dim: n_bins for (dim, n_bins, _) in coords}) |
| 494 | + |
| 495 | + def make_sample_and_vanadium_1d(self) -> tuple[sc.DataArray, sc.DataArray]: |
| 496 | + rng = np.random.default_rng(seed=495) |
| 497 | + sample = self.random_binned_data(rng, 84, 'count', True, ('dspacing', 35, 'Å')) |
| 498 | + vanadium = self.random_binned_data( |
| 499 | + rng, 146, 'count', True, ('dspacing', 79, 'Å') |
| 500 | + ) |
| 501 | + return sample, vanadium |
| 502 | + |
| 503 | + def make_sample_and_vanadium_2d(self) -> tuple[sc.DataArray, sc.DataArray]: |
| 504 | + rng = np.random.default_rng(seed=3193) |
| 505 | + sample = self.random_binned_data( |
| 506 | + rng, 138, 'count', True, ('dspacing', 35, 'Å'), ('two_theta', 13, 'rad') |
| 507 | + ) |
| 508 | + vanadium = self.random_binned_data( |
| 509 | + rng, 170, 'count', True, ('dspacing', 79, 'Å'), ('two_theta', 14, 'rad') |
| 510 | + ) |
| 511 | + return sample, vanadium |
| 512 | + |
| 513 | + def test_1d_binned_vanadium(self) -> None: |
| 514 | + sample, vanadium = self.make_sample_and_vanadium_1d() |
| 515 | + normed = normalize_by_vanadium_dspacing( |
| 516 | + FocussedDataDspacing[SampleRun](sample), |
| 517 | + FocussedDataDspacing[VanadiumRun](vanadium), |
| 518 | + UncertaintyBroadcastMode.drop, |
| 519 | + ) |
| 520 | + # we test masks separately |
| 521 | + normed = normed.drop_masks(list(normed.masks.keys())) |
| 522 | + |
| 523 | + norm = vanadium.hist(dspacing=sample.coords['dspacing']) |
| 524 | + expected = sample / sc.values(norm) |
| 525 | + sc.testing.assert_allclose(normed, expected) |
| 526 | + |
| 527 | + def test_1d_histogrammed_vanadium(self) -> None: |
| 528 | + sample, vanadium = self.make_sample_and_vanadium_1d() |
| 529 | + vanadium = vanadium.hist() |
| 530 | + normed = normalize_by_vanadium_dspacing( |
| 531 | + FocussedDataDspacing[SampleRun](sample), |
| 532 | + FocussedDataDspacing[VanadiumRun](vanadium), |
| 533 | + UncertaintyBroadcastMode.drop, |
| 534 | + ) |
| 535 | + # we test masks separately |
| 536 | + normed = normed.drop_masks(list(normed.masks.keys())) |
| 537 | + |
| 538 | + norm = vanadium.rebin(dspacing=sample.coords['dspacing']) |
| 539 | + expected = sample / sc.values(norm) |
| 540 | + sc.testing.assert_allclose(normed, expected) |
| 541 | + |
| 542 | + def test_1d_binned_vanadium_binning_has_no_effect(self) -> None: |
| 543 | + sample, vanadium = self.make_sample_and_vanadium_1d() |
| 544 | + vana_binned_like_sample = vanadium.bin(dspacing=sample.coords['dspacing']) |
| 545 | + normed_a = normalize_by_vanadium_dspacing( |
| 546 | + FocussedDataDspacing[SampleRun](sample), |
| 547 | + FocussedDataDspacing[VanadiumRun](vanadium), |
| 548 | + UncertaintyBroadcastMode.drop, |
| 549 | + ) |
| 550 | + normed_b = normalize_by_vanadium_dspacing( |
| 551 | + FocussedDataDspacing[SampleRun](sample), |
| 552 | + FocussedDataDspacing[VanadiumRun](vana_binned_like_sample), |
| 553 | + UncertaintyBroadcastMode.drop, |
| 554 | + ) |
| 555 | + sc.testing.assert_allclose(normed_a, normed_b) |
| 556 | + |
| 557 | + def test_1d_masks_zero_vanadium_bins(self) -> None: |
| 558 | + sample, vanadium = self.make_sample_and_vanadium_1d() |
| 559 | + vanadium['dspacing', 5] = sc.scalar(0.0, variance=0.0, unit='counts') |
| 560 | + normed = normalize_by_vanadium_dspacing( |
| 561 | + FocussedDataDspacing[SampleRun](sample), |
| 562 | + FocussedDataDspacing[VanadiumRun](vanadium), |
| 563 | + UncertaintyBroadcastMode.drop, |
| 564 | + ) |
| 565 | + |
| 566 | + norm = vanadium.hist(dspacing=sample.coords['dspacing']) |
| 567 | + |
| 568 | + sc.testing.assert_allclose( |
| 569 | + normed.masks['zero_vanadium'], norm.data == sc.scalar(0.0, unit='counts') |
| 570 | + ) |
| 571 | + |
| 572 | + def test_2d_binned_vanadium(self) -> None: |
| 573 | + sample, vanadium = self.make_sample_and_vanadium_2d() |
| 574 | + normed = normalize_by_vanadium_dspacing_and_two_theta( |
| 575 | + FocussedDataDspacingTwoTheta[SampleRun](sample), |
| 576 | + FocussedDataDspacingTwoTheta[VanadiumRun](vanadium), |
| 577 | + UncertaintyBroadcastMode.drop, |
| 578 | + ) |
| 579 | + # we test masks separately |
| 580 | + normed = normed.drop_masks(list(normed.masks.keys())) |
| 581 | + |
| 582 | + norm = vanadium.hist( |
| 583 | + dspacing=sample.coords['dspacing'], two_theta=sample.coords['two_theta'] |
| 584 | + ) |
| 585 | + expected = sample / sc.values(norm) |
| 586 | + sc.testing.assert_allclose(normed, expected) |
| 587 | + |
| 588 | + def test_2d_histogrammed_vanadium(self) -> None: |
| 589 | + sample, vanadium = self.make_sample_and_vanadium_2d() |
| 590 | + vanadium = vanadium.hist() |
| 591 | + normed = normalize_by_vanadium_dspacing_and_two_theta( |
| 592 | + FocussedDataDspacingTwoTheta[SampleRun](sample), |
| 593 | + FocussedDataDspacingTwoTheta[VanadiumRun](vanadium), |
| 594 | + UncertaintyBroadcastMode.drop, |
| 595 | + ) |
| 596 | + # we test masks separately |
| 597 | + normed = normed.drop_masks(list(normed.masks.keys())) |
| 598 | + |
| 599 | + norm = vanadium.rebin( |
| 600 | + dspacing=sample.coords['dspacing'], two_theta=sample.coords['two_theta'] |
| 601 | + ) |
| 602 | + expected = sample / sc.values(norm) |
| 603 | + sc.testing.assert_allclose(normed, expected) |
| 604 | + |
| 605 | + def test_2d_binned_vanadium_binning_has_no_effect(self) -> None: |
| 606 | + sample, vanadium = self.make_sample_and_vanadium_2d() |
| 607 | + vana_binned_like_sample = vanadium.bin( |
| 608 | + dspacing=sample.coords['dspacing'], two_theta=sample.coords['two_theta'] |
| 609 | + ) |
| 610 | + normed_a = normalize_by_vanadium_dspacing_and_two_theta( |
| 611 | + FocussedDataDspacingTwoTheta[SampleRun](sample), |
| 612 | + FocussedDataDspacingTwoTheta[VanadiumRun](vanadium), |
| 613 | + UncertaintyBroadcastMode.drop, |
| 614 | + ) |
| 615 | + normed_b = normalize_by_vanadium_dspacing_and_two_theta( |
| 616 | + FocussedDataDspacingTwoTheta[SampleRun](sample), |
| 617 | + FocussedDataDspacingTwoTheta[VanadiumRun](vana_binned_like_sample), |
| 618 | + UncertaintyBroadcastMode.drop, |
| 619 | + ) |
| 620 | + sc.testing.assert_allclose(normed_a, normed_b) |
| 621 | + |
| 622 | + def test_2d_masks_zero_vanadium_bins(self) -> None: |
| 623 | + sample, vanadium = self.make_sample_and_vanadium_2d() |
| 624 | + vanadium['dspacing', 5]['two_theta', 7] = sc.scalar( |
| 625 | + 0.0, variance=0.0, unit='counts' |
| 626 | + ) |
| 627 | + normed = normalize_by_vanadium_dspacing_and_two_theta( |
| 628 | + FocussedDataDspacingTwoTheta[SampleRun](sample), |
| 629 | + FocussedDataDspacingTwoTheta[VanadiumRun](vanadium), |
| 630 | + UncertaintyBroadcastMode.drop, |
| 631 | + ) |
| 632 | + |
| 633 | + norm = vanadium.hist( |
| 634 | + dspacing=sample.coords['dspacing'], two_theta=sample.coords['two_theta'] |
| 635 | + ) |
| 636 | + |
| 637 | + sc.testing.assert_allclose( |
| 638 | + normed.masks['zero_vanadium'], norm.data == sc.scalar(0.0, unit='counts') |
| 639 | + ) |
0 commit comments