26 std::vector<std::vector<double>>
27 extractValues(std::vector<std::vector<ParameterSample>> samples,
30 std::vector<std::vector<double>> result;
31 result.resize(samples.size());
32 for (
size_t i = 0, size = result.size(); i < size; ++i) {
33 const auto& sample_row = samples[i];
34 auto& result_row = result[i];
35 result_row.reserve(sample_row.size());
36 std::for_each(sample_row.begin(), sample_row.end(),
38 result_row.push_back(extractor(sample));
46 AngularSpecScan::AngularSpecScan(
double wl, std::vector<double> inc_angle)
48 m_inc_angle(std::make_unique<
PointwiseAxis>(
"inc_angles", std::move(inc_angle))),
52 checkInitialization();
55 AngularSpecScan::AngularSpecScan(
double wl,
const IAxis& inc_angle)
56 : m_wl(wl), m_inc_angle(inc_angle.clone()),
60 checkInitialization();
63 AngularSpecScan::AngularSpecScan(
double wl,
int nbins,
double alpha_i_min,
double alpha_i_max)
65 m_inc_angle(std::make_unique<
FixedBinAxis>(
"inc_angles", nbins, alpha_i_min, alpha_i_max)),
69 checkInitialization();
75 result->setFootprintFactor(m_footprint.get());
76 result->setWavelengthResolution(*m_wl_resolution);
77 result->setAngleResolution(*m_inc_resolution);
81 AngularSpecScan::~AngularSpecScan() =
default;
85 const auto wls = extractValues(applyWlResolution(),
87 const auto incs = extractValues(applyIncResolution(),
90 std::vector<SpecularSimulationElement> result;
92 for (
size_t i = 0; i < m_inc_angle->size(); ++i) {
93 for (
size_t k = 0, size_incs = incs[i].size(); k < size_incs; ++k) {
94 const double inc = incs[i][k];
95 for (
size_t j = 0, size_wls = wls[i].size(); j < size_wls; ++j) {
96 const double wl = wls[i][j];
107 m_footprint.reset(f_factor ? f_factor->clone() :
nullptr);
112 m_wl_resolution.reset(resolution.clone());
113 m_wl_res_cache.clear();
114 m_wl_res_cache.shrink_to_fit();
117 void AngularSpecScan::setRelativeWavelengthResolution(
const RangedDistribution& distr,
120 std::unique_ptr<ScanResolution> resolution(
121 ScanResolution::scanRelativeResolution(distr, rel_dev));
126 const std::vector<double>& rel_dev)
128 std::unique_ptr<ScanResolution> resolution(
129 ScanResolution::scanRelativeResolution(distr, rel_dev));
133 void AngularSpecScan::setAbsoluteWavelengthResolution(
const RangedDistribution& distr,
136 std::unique_ptr<ScanResolution> resolution(
137 ScanResolution::scanAbsoluteResolution(distr, std_dev));
142 const std::vector<double>& std_dev)
144 std::unique_ptr<ScanResolution> resolution(
145 ScanResolution::scanAbsoluteResolution(distr, std_dev));
151 m_inc_resolution.reset(resolution.clone());
152 m_inc_res_cache.clear();
153 m_inc_res_cache.shrink_to_fit();
156 void AngularSpecScan::setRelativeAngularResolution(
const RangedDistribution& distr,
double rel_dev)
158 std::unique_ptr<ScanResolution> resolution(
159 ScanResolution::scanRelativeResolution(distr, rel_dev));
164 const std::vector<double>& rel_dev)
166 std::unique_ptr<ScanResolution> resolution(
167 ScanResolution::scanRelativeResolution(distr, rel_dev));
171 void AngularSpecScan::setAbsoluteAngularResolution(
const RangedDistribution& distr,
double std_dev)
173 std::unique_ptr<ScanResolution> resolution(
174 ScanResolution::scanAbsoluteResolution(distr, std_dev));
179 const std::vector<double>& std_dev)
181 std::unique_ptr<ScanResolution> resolution(
182 ScanResolution::scanAbsoluteResolution(distr, std_dev));
189 throw std::runtime_error(
"Error in AngularSpecScan::footprint: given index exceeds the "
190 "number of simulation elements");
192 std::vector<double> result(n_elements, 1.0);
196 const size_t n_wl_samples = m_wl_resolution->nSamples();
197 const size_t n_inc_samples = m_inc_resolution->nSamples();
199 const auto sample_values = extractValues(
200 applyIncResolution(), [](
const ParameterSample& sample) {
return sample.value; });
202 const size_t pos_out = start / (n_wl_samples * n_inc_samples);
203 size_t pos_inc = (start - pos_out * n_wl_samples * n_inc_samples) / n_wl_samples;
204 size_t pos_wl = (start - pos_inc * n_wl_samples);
205 int left =
static_cast<int>(n_elements);
207 for (
size_t i = pos_out; left > 0; ++i)
208 for (
size_t k = pos_inc; k < n_inc_samples && left > 0; ++k) {
210 const double angle = sample_values[i][k];
212 (angle >= 0 && angle <= M_PI_2) ? m_footprint->calculate(angle) : 1.0;
213 for (
size_t j = pos_wl; j < n_wl_samples && left > 0; ++j) {
225 return m_inc_angle->size() * m_wl_resolution->nSamples() * m_inc_resolution->nSamples();
231 const size_t axis_size = m_inc_angle->size();
232 std::vector<double> result(axis_size, 0.0);
234 const auto wl_weights = extractValues(
235 applyWlResolution(), [](
const ParameterSample& sample) {
return sample.weight; });
236 const auto inc_weights = extractValues(
237 applyIncResolution(), [](
const ParameterSample& sample) {
return sample.weight; });
240 for (
size_t i = 0; i < axis_size; ++i) {
241 double& current = result[i];
242 for (
size_t k = 0, size_incs = inc_weights[i].size(); k < size_incs; ++k) {
243 const double inc_weight = inc_weights[i][k];
244 for (
size_t j = 0, size_wls = wl_weights[i].size(); j < size_wls; ++j) {
245 current += sim_elements[elem_pos].getIntensity() * inc_weight * wl_weights[i][j];
255 std::stringstream result;
256 result <<
"\n" <<
pyfmt::indent() <<
"# Defining specular scan:\n";
258 result << axis_def <<
coordinateAxis()->pyString(
"rad", axis_def.size()) <<
"\n";
261 result <<
"ba.AngularSpecScan(" << pyfmt::printDouble(m_wl) <<
", axis)\n";
264 result << *m_footprint <<
"\n";
265 result <<
pyfmt::indent() <<
"scan.setFootprintFactor(footprint)\n";
267 if (!m_inc_resolution->empty()) {
268 result <<
"\n" <<
pyfmt::indent() <<
"# Defining angular resolution\n";
269 result << *m_inc_resolution <<
"\n";
270 result <<
pyfmt::indent() <<
"scan.setAngleResolution(resolution)\n";
272 if (!m_wl_resolution->empty()) {
273 result <<
"\n" <<
pyfmt::indent() <<
"# Defining wavelength resolution\n";
274 result << *m_wl_resolution <<
"\n";
275 result <<
pyfmt::indent() <<
"scan.setWavelengthResolution(resolution)\n";
280 void AngularSpecScan::checkInitialization()
283 throw std::runtime_error(
284 "Error in AngularSpecScan::checkInitialization: wavelength shell be positive");
286 const std::vector<double> axis_values = m_inc_angle->getBinCenters();
287 if (!std::is_sorted(axis_values.begin(), axis_values.end()))
288 throw std::runtime_error(
"Error in AngularSpecScan::checkInitialization: q-vector values "
289 "shall be sorted in ascending order.");
294 AngularSpecScan::DistrOutput AngularSpecScan::applyWlResolution()
const
296 if (m_wl_res_cache.empty())
297 m_wl_res_cache = m_wl_resolution->generateSamples(m_wl, m_inc_angle->size());
298 return m_wl_res_cache;
301 AngularSpecScan::DistrOutput AngularSpecScan::applyIncResolution()
const
303 if (m_inc_res_cache.empty())
304 m_inc_res_cache = m_inc_resolution->generateSamples(m_inc_angle->getBinCenters());
305 return m_inc_res_cache;
Declares AngularSpecScan class.
Defines class FixedBinAxis.
Defines class PointwiseAxis.
Defines functions in namespace pyfmt.
Defines classes representing ranged one-dimensional distributions.
Defines scan resolution class.
Declares the class SpecularSimulationElement.
Scan type with inclination angles as coordinate values and a unique wavelength.
void setAngleResolution(const ScanResolution &resolution)
Sets angle resolution values via ScanResolution object.
std::vector< double > footprint(size_t i, size_t n_elements) const override
Returns footprint correction factor for a range of simulation elements of size n_elements and startin...
size_t numberOfSimulationElements() const override
Returns the number of simulation elements.
virtual const IAxis * coordinateAxis() const override
Returns coordinate axis assigned to the data holder.
std::vector< double > createIntensities(const std::vector< SpecularSimulationElement > &sim_elements) const override
Returns intensity vector corresponding to convolution of given simulation elements.
void setFootprintFactor(const IFootprintFactor *f_factor)
Sets footprint correction factor.
void setWavelengthResolution(const ScanResolution &resolution)
Sets wavelength resolution values via ScanResolution object.
std::string print() const override
Print scan definition in python format.
std::vector< SpecularSimulationElement > generateSimulationElements() const override
Generates simulation elements for specular simulations.
Axis with fixed bin size.
Interface for one-dimensional axes.
A parameter value with a weight, as obtained when sampling from a distribution.
Axis containing arbitrary (non-equidistant) coordinate values.
Interface for one-dimensional ranged distributions.
Container for reflectivity resolution data.
Data stucture containing both input and output of a single image pixel for specular simulation.
std::string indent(size_t width)
Returns a string of blanks with given width.