Mantid
Loading...
Searching...
No Matches
CreateMonteCarloWorkspace.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2025 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#include <algorithm>
8#include <cmath>
9#include <iostream>
10#include <numbers>
11#include <numeric> // For std::accumulate
12#include <random>
13#include <vector>
14
16#include "MantidAPI/Progress.h"
17#include "MantidAPI/Workspace.h"
20
22#include "MantidKernel/Logger.h"
23
24namespace {
25Mantid::Kernel::Logger g_log("CreateMonteCarloWorkspace");
26}
27namespace Mantid {
28namespace Algorithms {
30using namespace Mantid::API;
31using namespace std;
32
33// Register the algorithm into the AlgorithmFactory
34DECLARE_ALGORITHM(CreateMonteCarloWorkspace)
35
36//----------------------------------------------------------------------------------------------
37
38
39const std::string CreateMonteCarloWorkspace::name() const { return "CreateMonteCarloWorkspace"; }
40
42int CreateMonteCarloWorkspace::version() const { return 1; }
43
45const std::string CreateMonteCarloWorkspace::category() const { return "Simulation"; }
46
48const std::string CreateMonteCarloWorkspace::summary() const {
49 return "Creates a randomly simulated workspace by sampling from the probability distribution of input data.";
50}
51
52//----------------------------------------------------------------------------------------------
56 auto mustBePositive = std::make_shared<Mantid::Kernel::BoundedValidator<int>>();
57 mustBePositive->setLower(0);
58
59 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
60 "Input Workspace containing data to be simulated");
61 declareProperty("Seed", 32, mustBePositive,
62 "Integer seed that initialises the random-number generator, for reproducibility");
63 declareProperty("MonteCarloEvents", 0, mustBePositive,
64 "Number of Monte Carlo events to simulate. Defaults to integral of input workspace if 0.");
65 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
66 "Name of output workspace.");
67}
68
69//----------------------------------------------------------------------------------------------
70
71Mantid::HistogramData::HistogramY CreateMonteCarloWorkspace::fillHistogramWithRandomData(const std::vector<double> &cdf,
72 int numIterations,
73 int seedInput,
74 API::Progress &progress) {
75
76 Mantid::HistogramData::HistogramY outputY(cdf.size(), 0.0);
77 std::mt19937 gen(seedInput);
78 std::uniform_real_distribution<> dis(0.0, 1.0);
79
80 int progressInterval = std::max(1, numIterations / 100); // Update progress every 1%
81
82 for (int i = 0; i < numIterations; ++i) {
83 double randomNum = dis(gen);
84 auto it = std::lower_bound(cdf.begin(), cdf.end(), randomNum);
85 size_t index = std::distance(cdf.begin(), it);
86
87 if (index < outputY.size()) {
88 outputY[index] += 1.0;
89 }
90
91 if (i % progressInterval == 0) {
92 progress.report("Generating random data...");
93 }
94 }
95 return outputY;
96}
97
101std::vector<double> CreateMonteCarloWorkspace::computeNormalizedCDF(const Mantid::HistogramData::HistogramY &yData) {
102 std::vector<double> cdf(yData.size());
103 std::partial_sum(yData.begin(), yData.end(), cdf.begin());
104 double totalCounts = cdf.back();
105
106 if (totalCounts > 0.0) {
107 // Normalize the CDF
108 std::transform(cdf.begin(), cdf.end(), cdf.begin(), [totalCounts](double val) { return val / totalCounts; });
109 } else {
110 g_log.warning("Total counts are zero; normalization skipped.");
111 }
112 return cdf;
113}
114
119int CreateMonteCarloWorkspace::integrateYData(const Mantid::HistogramData::HistogramY &yData) {
120 double totalCounts = std::accumulate(yData.begin(), yData.end(), 0.0);
121 int iterations = static_cast<int>(std::round(totalCounts));
122
123 if (iterations == 0) {
124 g_log.warning("Total counts in the input workspace round to 0. No Monte Carlo events will be generated.");
125 }
126 return iterations;
127}
128
129//----------------------------------------------------------------------------------------------
133 MatrixWorkspace_sptr inputWs = getProperty("InputWorkspace");
134 int seedInput = getProperty("Seed");
135 int userMCEvents = getProperty("MonteCarloEvents");
136
137 const auto &originalYData = inputWs->y(0); // Counts in each bin
138
139 int numIterations = (userMCEvents > 0) ? userMCEvents : integrateYData(originalYData);
140
141 API::Progress progress(this, 0.0, 1.0, 101);
142 progress.report("Computing normalized CDF...");
143 std::vector<double> cdf = computeNormalizedCDF(originalYData);
144
145 MatrixWorkspace_sptr outputWs = WorkspaceFactory::Instance().create(inputWs, 1);
146 outputWs->setSharedX(0, inputWs->sharedX(0));
147
148 // Fill the bins with random data, following the distribution in the CDF
149 Mantid::HistogramData::HistogramY outputY = fillHistogramWithRandomData(cdf, numIterations, seedInput, progress);
150 outputWs->mutableY(0) = outputY;
151
152 // Calculate errors as the square root of the counts
153 Mantid::HistogramData::HistogramE outputE(outputY.size());
154 std::transform(outputY.begin(), outputY.end(), outputE.begin(), [](double count) { return std::sqrt(count); });
155 outputWs->mutableE(0) = std::move(outputE);
156
157 g_log.warning("Only the first spectrum is being plotted.");
158
159 setProperty("OutputWorkspace", outputWs);
160}
161
162} // namespace Algorithms
163} // namespace Mantid
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
std::map< DeltaEMode::Type, std::string > index
int count
counter
Definition Matrix.cpp:37
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:422
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
CreateMonteCarloWorkspace : The algorithm generates a simulated workspace by sampling from the probab...
std::vector< double > computeNormalizedCDF(const Mantid::HistogramData::HistogramY &yData)
Compute a normalized CDF [0..1] from the given histogram data.
int version() const override
Algorithm's version for identification.
const string summary() const override
Algorithm's summary for use in the GUI and help.
Mantid::HistogramData::HistogramY fillHistogramWithRandomData(const std::vector< double > &cdf, int numIterations, int seedInput, API::Progress &progress)
void init() override
Initialize the algorithm's properties.
const string category() const override
Algorithm's category for identification.
int integrateYData(const Mantid::HistogramData::HistogramY &yData)
Determine how many iterations to use for MC sampling.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
Kernel::Logger g_log("DetermineSpinStateOrder")
Helper class which provides the Collimation Length for SANS instruments.
STL namespace.
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54