diff --git a/CHANGELOG b/CHANGELOG index d848223c3354482777be4ff30276f410997731a4..34f8c85ea3e60f94c369df663d4ca8dd1b2573b8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,8 @@ BornAgain-22.0, in preparation > GUI changes: * Examples DepthProfile, Transmission: flattened DepthProbeSimulation > Examples and documentation: + > Bug fixes: + * Fix intensity background (#328) > Internal refactoring: * Simplified coordinate names and units, now both in Scale::name (#487, #614) * Remove ICoordSystem and children; functionality provided by Frame diff --git a/GUI/Model/Device/InstrumentItems.cpp b/GUI/Model/Device/InstrumentItems.cpp index 6417a82cce81380844eab720ed478ef969686427..557621905ab9358c60c6b7ddaf6b8c3a03917982 100644 --- a/GUI/Model/Device/InstrumentItems.cpp +++ b/GUI/Model/Device/InstrumentItems.cpp @@ -355,7 +355,7 @@ void ScanningFunctionality::readScanFrom(QXmlStreamReader* r) // ************************************************************************************************ SpecularInstrumentItem::SpecularInstrumentItem() - : ScanningFunctionality(1) + : ScanningFunctionality(1e6) { } diff --git a/Sim/Simulation/DepthprobeSimulation.cpp b/Sim/Simulation/DepthprobeSimulation.cpp index e24a6a81ec280c9f1bc5688d939c0a0be1e02d2c..df52d32e2ca226ed7d7b830a3351570942aee517 100644 --- a/Sim/Simulation/DepthprobeSimulation.cpp +++ b/Sim/Simulation/DepthprobeSimulation.cpp @@ -150,9 +150,6 @@ void DepthprobeSimulation::runComputation(const ReSample& re_sample, size_t i, d for (double& v : intensities) v *= intensity_factor; - if (background()) - throw std::runtime_error("nonzero background is not supported by DepthprobeSimulation"); - const size_t N1 = m_z_axis->size(); for (size_t j = 0; j < N1; ++j) m_cache[i * N1 + j] += intensities[j] * weight; @@ -177,5 +174,8 @@ Datafield DepthprobeSimulation::packResult() std::vector<const Scale*> axes{m_scan->coordinateAxis()->clone(), m_z_axis->clone()}; auto data = std::make_unique<Datafield>(std::move(axes), m_cache); + if (background()) + throw std::runtime_error("nonzero background is not supported by DepthprobeSimulation"); + return {*data}; } diff --git a/Sim/Simulation/OffspecSimulation.cpp b/Sim/Simulation/OffspecSimulation.cpp index 673e65e47d9fe9e0b23a12005807afd392316bb4..1c4625671c525d9cc7374485b7920dc10c6c000f 100644 --- a/Sim/Simulation/OffspecSimulation.cpp +++ b/Sim/Simulation/OffspecSimulation.cpp @@ -108,9 +108,6 @@ void OffspecSimulation::runComputation(const ReSample& re_sample, size_t i, doub intensity *= m_scan->intensity() * solid_angle / sin_alpha_i; } - if (background()) - intensity = background()->addBackground(intensity); - m_cache[i] += intensity * weight; progress().incrementDone(1); @@ -130,14 +127,13 @@ size_t OffspecSimulation::nElements() const Datafield OffspecSimulation::packResult() { - // update intensity map Datafield intensity_map({m_scan->coordinateAxis()->clone(), m_detector->axis(1).clone()}); intensity_map.setAllTo(0.); size_t ny = m_detector->axis(1).size(); - // Normalize, apply detector resolution and transfer detector image + // Apply detector resolution and transfer detector image for (size_t j = 0; j < m_scan->coordinateAxis()->size(); ++j) { Datafield detector_image({m_detector->axis(0).clone(), m_detector->axis(1).clone()}); size_t N = detector_image.size(); @@ -146,6 +142,11 @@ Datafield OffspecSimulation::packResult() // TODO restore resolution m_detector->applyDetectorResolution(&detector_image); for (size_t i = 0; i < N; ++i) intensity_map[j * ny + i % ny] += detector_image[i]; + + if (background()) + for (size_t i = 0; i < N; ++i) + intensity_map[j * ny + i % ny] = + background()->addBackground(intensity_map[j * ny + i % ny]); } return {intensity_map}; diff --git a/Sim/Simulation/ScatteringSimulation.cpp b/Sim/Simulation/ScatteringSimulation.cpp index 47047909b0b417cdb2b0e3dd705e0d046ec3dbc2..0366c05d0e2c9860a3e19a50847c93818cbc3123 100644 --- a/Sim/Simulation/ScatteringSimulation.cpp +++ b/Sim/Simulation/ScatteringSimulation.cpp @@ -100,9 +100,6 @@ void ScatteringSimulation::runComputation(const ReSample& re_sample, size_t i, d intensity *= m_beam->intensity() * solid_angle / sin_alpha_i; } - if (background()) - intensity = background()->addBackground(intensity); - m_cache[i] += intensity * weight; progress().incrementDone(1); @@ -128,5 +125,10 @@ Datafield ScatteringSimulation::packResult() [&](const auto it) { result[it.roiIndex()] = m_cache[elementIndex++]; }); m_detector->applyDetectorResolution(&result); + if (background()) + m_detector->iterateOverNonMaskedPoints([&](const auto it) { + result[it.roiIndex()] = background()->addBackground(result[it.roiIndex()]); + }); + return result; } diff --git a/Sim/Simulation/SpecularSimulation.cpp b/Sim/Simulation/SpecularSimulation.cpp index d96f8985ac8f3f00caba8b3ca926af39e40b9c98..75c3d8451e7b9bce20bc4011507884d265d4bbe5 100644 --- a/Sim/Simulation/SpecularSimulation.cpp +++ b/Sim/Simulation/SpecularSimulation.cpp @@ -75,12 +75,7 @@ void SpecularSimulation::runComputation(const ReSample& re_sample, size_t iEleme } } - double intensity = refl * ele.footprint(); - - if (background()) - intensity = background()->addBackground(intensity); - - m_cache[iElement] += intensity * weight; + m_cache[iElement] += refl * ele.footprint() * weight; progress().incrementDone(1); } @@ -104,6 +99,9 @@ Datafield SpecularSimulation::packResult() const SpecularElement& ele = m_eles.at(i); vec.at(ele.i_out()) += m_scan->intensity() * m_cache.at(i) * ele.weight(); } + if (background()) + for (size_t i = 0; i < m_scan->nScan(); i++) + vec[i] = background()->addBackground(vec[i]) / m_scan->intensity(); Datafield data({m_scan->coordinateAxis()->clone()}, vec); return {data}; diff --git a/hugo/content/ref/sim/setup/bg/index.md b/hugo/content/ref/sim/setup/bg/index.md index 1eff36a66cfe8c25cd0d74f76a33877e6e231c63..4d197c0d0ff83ad39779a114114a569239ffd7e4 100644 --- a/hugo/content/ref/sim/setup/bg/index.md +++ b/hugo/content/ref/sim/setup/bg/index.md @@ -1,8 +1,21 @@ +++ -title = "Constant background" +title = "Background" weight = 80 +++ +### Poisson background + +To add a Poisson background to a `Simulation` instance, use + +```python +bg = ba.PoissonBackground() +simulation.setBackground(bg) +``` + +In this case, the output intensity is randomly distributed around the exact value with discrete Poisson statistics. + +The lower the intensity of the probing beam, the lower the signal-to-noise ratio. + ### Constant background To add a constant background to a `Simulation` instance, use @@ -12,6 +25,8 @@ bg = ba.ConstantBackground(1e3) simulation.setBackground(bg) ``` +Background is applied before the [specular simulation](/ref/sim/class/specular) is normalized, so the threshold value will also be divided by the probe beam intensity. + {{< galleryscg >}} {{< figscg src="/img/auto/scatter2d/ConstantBackground.png" width="450px" caption="Intensity image">}} {{< /galleryscg >}}