cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
GridOptimisedGeneratorWorker.cpp
Go to the documentation of this file.
1/*
2 * CepGen: a central exclusive processes event generator
3 * Copyright (C) 2013-2024 Laurent Forthomme
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
28#include "CepGen/Utils/String.h"
30
31namespace cepgen {
33 public:
35 explicit GridOptimisedGeneratorWorker(const ParametersList& params) : GeneratorWorker(params) {}
36
37 void initialise() override;
38 bool next() override;
39
41 auto desc = GeneratorWorker::description();
42 desc.setDescription("Grid-optimised worker");
43 desc.add<int>("binSize", 3);
44 return desc;
45 }
46
47 private:
49 static constexpr int UNASSIGNED_BIN = -999;
50
52 bool correctionCycle(bool&);
54 void computeGenerationParameters();
55
57 std::unique_ptr<GridParameters> grid_;
59 int ps_bin_{UNASSIGNED_BIN};
60 std::vector<double> coords_;
61 };
62
64 grid_.reset(new GridParameters(steer<int>("binSize"), integrand_->size()));
65 coords_ = std::vector<double>(integrand_->size());
66 if (!grid_->prepared())
67 computeGenerationParameters();
68 CG_DEBUG("GridOptimisedGeneratorWorker:initialise")
69 << "Dim-" << integrand_->size() << " " << integrator_->name() << " integrator "
70 << "set for dim-" << grid_->n(0).size() << " grid.";
71 }
72
73 //-----------------------------------------------------------------------------------------------
74 // events generation part
75 //-----------------------------------------------------------------------------------------------
76
78 if (!integrator_)
79 throw CG_FATAL("GridOptimisedGeneratorWorker:next") << "No integrator object handled!";
80 if (!grid_)
81 throw CG_FATAL("GridOptimisedGeneratorWorker:next") << "Grid object was not initialised.";
82
83 CG_TICKER(const_cast<RunParameters*>(params_)->timeKeeper());
84
85 // apply correction cycles if required from previous event
86 if (ps_bin_ != UNASSIGNED_BIN) {
87 bool store = false;
88 while (!correctionCycle(store)) {
89 }
90 if (store)
91 return storeEvent();
92 }
93
94 //--- normal generation cycle
95
96 double weight = 0.;
97 while (true) {
98 double y = -1.;
99 // select a function value and reject if fmax is too small
100 do {
101 // ...
102 ps_bin_ = integrator_->uniform({0., (double)grid_->size()});
103 y = integrator_->uniform({0., grid_->globalMax()});
104 grid_->increment(ps_bin_);
105 } while (y > grid_->maxValue(ps_bin_));
106 // shoot a point x in this bin
107 grid_->shoot(integrator_, ps_bin_, coords_);
108 // get weight for selected x value
109 weight = integrator_->eval(*integrand_, coords_);
110 if (weight > y)
111 break;
112 }
113
114 if (weight > grid_->maxValue(ps_bin_))
115 // if weight is higher than local or global maximum,
116 // init correction cycle for the next event
117 grid_->initCorrectionCycle(ps_bin_, weight);
118 else // no grid correction needed for this bin
119 ps_bin_ = UNASSIGNED_BIN;
120
121 // return with an accepted event
122 return storeEvent();
123 }
124
125 bool GridOptimisedGeneratorWorker::correctionCycle(bool& store) {
126 CG_TICKER(const_cast<RunParameters*>(params_)->timeKeeper());
127
128 CG_DEBUG_LOOP("GridOptimisedGeneratorWorker:correction")
129 << "Correction cycles are started.\n\t"
130 << "bin = " << ps_bin_ << "\n\t"
131 << "correction value = " << grid_->correctionValue() << ".";
132
133 if (grid_->correctionValue() >= 1.)
134 grid_->setCorrectionValue(grid_->correctionValue() - 1.);
135
136 if (integrator_->uniform() < grid_->correctionValue()) {
137 grid_->setCorrectionValue(-1.);
138 // select x values in phase space bin
139 grid_->shoot(integrator_, ps_bin_, coords_);
140 const double weight = integrator_->eval(*integrand_, coords_);
141 // parameter for correction of correction
142 grid_->rescale(ps_bin_, weight);
143 // accept event
144 if (weight >= integrator_->uniform({0., grid_->maxValueDiff()}) + grid_->maxHistValue()) {
145 store = true;
146 return true;
147 }
148 return false;
149 }
150 // correction if too big weight is found while correction
151 // (all your bases are belong to us...)
152 return grid_->correct(ps_bin_);
153 }
154
155 //-----------------------------------------------------------------------------------------------
156 // initial preparation run before the generation of unweighted events
157 //-----------------------------------------------------------------------------------------------
158
159 void GridOptimisedGeneratorWorker::computeGenerationParameters() {
160 if (!params_)
161 throw CG_FATAL("GridOptimisedGeneratorWorker:setGen") << "No steering parameters specified!";
162 if (!integrator_)
163 throw CG_FATAL("GridOptimisedGeneratorWorker:setGen") << "No integrator object specified!";
164
165 integrand_->setStorage(false);
166
167 CG_INFO("GridOptimisedGeneratorWorker:setGen")
168 << "Preparing the grid (" << utils::s("point", params_->generation().numPoints(), true) << "/bin) "
169 << "for the generation of unweighted events.";
170
171 const double inv_num_points = 1. / params_->generation().numPoints();
172 std::vector<double> point_coord(integrand_->size(), 0.);
173 if (point_coord.size() < grid_->n(0).size())
174 throw CG_FATAL("GridParameters:shoot") << "Coordinates vector multiplicity is insufficient!";
175
176 // ...
177 double sum = 0., sum2 = 0., sum2p = 0.;
178
179 utils::ProgressBar prog_bar(grid_->size(), 5);
180
181 //--- main loop
182 for (unsigned int i = 0; i < grid_->size(); ++i) {
183 double fsum = 0., fsum2 = 0.;
184 for (size_t j = 0; j < params_->generation().numPoints(); ++j) {
185 grid_->shoot(integrator_, i, point_coord);
186 const double weight = integrator_->eval(*integrand_, point_coord);
187 grid_->setValue(i, weight);
188 fsum += weight;
189 fsum2 += weight * weight;
190 }
191 const double av = fsum * inv_num_points, av2 = fsum2 * inv_num_points;
192 const double sig2 = av2 - av * av;
193 sum += av;
194 sum2 += av2;
195 sum2p += sig2;
196
197 // per-bin debugging loop
198 CG_DEBUG_LOOP("GridOptimisedGeneratorWorker:setGen").log([&](auto& dbg) {
199 const double sig = sqrt(sig2);
200 const double eff = (grid_->maxValue(i) != 0.) ? av / grid_->maxValue(i) : 0.;
201 dbg << "n-vector for bin " << i << ": " << utils::repr(grid_->n(i)) << "\n\t"
202 << "av = " << av << "\n\t"
203 << "sig = " << sig << "\n\t"
204 << "fmax = " << grid_->maxValue(i) << "\n\t"
205 << "eff = " << eff;
206 });
207 prog_bar.update(i + 1);
208 } // end of main loop
209
210 const double inv_max = 1. / grid_->size();
211 sum *= inv_max;
212 sum2 *= inv_max;
213 sum2p *= inv_max;
214
215 const double sig = sqrt(sum2 - sum * sum), sigp = sqrt(sum2p);
216
217 double eff1 = 0.;
218 for (unsigned int i = 0; i < grid_->size(); ++i)
219 eff1 += sum / grid_->size() * grid_->maxValue(i);
220 const double eff2 = sum / grid_->globalMax();
221
222 CG_DEBUG("GridOptimisedGeneratorWorker:setGen")
223 << "Average function value = " << sum << "\n\t"
224 << "Average squared function value = " << sum2 << "\n\t"
225 << "Overall standard deviation = " << sig << "\n\t"
226 << "Average standard deviation = " << sigp << "\n\t"
227 << "Maximum function value = " << grid_->globalMax() << "\n\t"
228 << "Average inefficiency = " << eff1 << "\n\t"
229 << "Overall inefficiency = " << eff2;
230 grid_->setPrepared(true);
231 //--- from now on events will be stored
232 integrand_->setStorage(true);
233
234 CG_INFO("GridOptimisedGeneratorWorker:setGen")
235 << "Finished the grid preparation. Now launching the unweighted event production.";
236 }
237} // namespace cepgen
238REGISTER_GENERATOR_WORKER("grid_optimised", GridOptimisedGeneratorWorker);
#define CG_FATAL(mod)
Definition Exception.h:61
#define REGISTER_GENERATOR_WORKER(name, obj)
Add a generator worker to the list of handled modules.
#define CG_DEBUG_LOOP(mod)
Definition Message.h:224
#define CG_DEBUG(mod)
Definition Message.h:220
#define CG_INFO(mod)
Definition Message.h:216
#define CG_TICKER(tmr)
Definition TimeKeeper.h:30
Event generator worker instance.
std::unique_ptr< ProcessIntegrand > integrand_
Local event weight evaluator.
const RunParameters * params_
Steering parameters for the event generation.
bool storeEvent()
Store the event in the output file.
static ParametersDescription description()
const Integrator * integrator_
Pointer to the mother-handled integrator instance.
void initialise() override
Initialise the generation parameters.
GridOptimisedGeneratorWorker(const ParametersList &params)
Book the memory slots and structures for the generator.
bool next() override
Generate a single event.
A parameters placeholder for the grid integration helper.
virtual double uniform(const Limits &={0., 1.}) const
Generate a uniformly distributed (between 0 and 1) random number.
virtual double eval(Integrand &, const std::vector< double > &) const
Compute the function value at the given phase space point.
const std::string & name() const
Module unique indexing name.
Definition NamedModule.h:42
A description object for parameters collection.
size_t numPoints() const
Number of points to "shoot" in each integration bin.
List of parameters used to start and run the simulation job.
Generation & generation()
Event generation parameters.
std::string s(const std::string &word, float num, bool show_number)
Add a trailing "s" when needed.
Definition String.cpp:228
std::string repr(const std::vector< T > &vec, const std::function< std::string(const T &)> &printer, const std::string &sep=",")
Helper to print a vector.
Definition String.h:156
Common namespace for this Monte Carlo generator.