// ************************************************************************************************ // // BornAgain: simulate and fit reflection and scattering // //! @file Base/Axis/Frame.cpp //! @brief Implements class Frame. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) //! @copyright Forschungszentrum Jülich GmbH 2018 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) // // ************************************************************************************************ #include "Base/Axis/Frame.h" #include "Base/Axis/Scale.h" #include "Base/Util/Assert.h" #include "Base/Util/StringUtil.h" namespace { size_t product_size(const std::vector<const Scale*>& axes) { size_t result = 1; for (const Scale* ax : axes) result *= ax->size(); return result; } } // namespace Frame::Frame(const std::vector<const Scale*>& axes) : m_axes(axes) , m_size(::product_size(axes)) { } Frame::Frame(const Scale* ax0) : Frame(std::vector<const Scale*>{ax0}) { } Frame::Frame(const Scale* ax0, const Scale* ax1) : Frame(std::vector<const Scale*>{ax0, ax1}) { } Frame::Frame(const Frame&) = default; Frame::~Frame() = default; Frame* Frame::clone() const { return new Frame(*this); } size_t Frame::rank() const { return m_axes.size(); } const Scale& Frame::axis(size_t k_axis) const { ASSERT(k_axis < rank()); return *m_axes.at(k_axis); } const Scale& Frame::xAxis() const { return *m_axes.at(0); } const Scale& Frame::yAxis() const { ASSERT(1 < rank()); return *m_axes.at(1); } double Frame::projectedCoord(size_t i_flat, size_t k_axis) const { return projectedBin(i_flat, k_axis).center(); } const Bin1D& Frame::projectedBin(size_t i_flat, size_t k_axis) const { auto axis_index = projectedIndex(i_flat, k_axis); return m_axes[k_axis]->bin(axis_index); } std::vector<int> Frame::allIndices(size_t i_flat) const { std::vector<int> result(rank()); for (size_t k = 0; k < rank(); ++k) result[k] = projectedIndex(i_flat, k); return result; } size_t Frame::projectedIndex(size_t i, size_t k_axis) const { ASSERT(k_axis < rank()); if (rank() == 1) return i; if (rank() == 2) { if (k_axis == 0) return i % m_axes[0]->size(); if (k_axis == 1) return (i / m_axes[0]->size()) % m_axes[1]->size(); } ASSERT_NEVER; } bool Frame::operator==(const Frame& o) const { if (rank() != o.rank()) return false; for (size_t k = 0; k < rank(); ++k) if (!(axis(k) == o.axis(k))) return false; return true; } bool Frame::hasSameSizes(const Frame& o) const { if (rank() != o.rank()) return false; for (size_t k = 0; k < rank(); ++k) if (axis(k).size() != o.axis(k).size()) return false; return true; } Frame Frame::plottableFrame() const { std::vector<const Scale*> outaxes; for (size_t k = 0; k < rank(); ++k) { auto* s = new Scale(axis(k).plottableScale()); outaxes.emplace_back(s); } return Frame(outaxes); } Frame Frame::angularFrame(double lambda, double alpha_i) const { ASSERT(rank() == 2); auto* phi_f_scale = new Scale(xAxis().phi_f_Scale(lambda)); auto* alpha_f_scale = new Scale(yAxis().alpha_f_Scale(lambda, alpha_i)); return Frame(phi_f_scale, alpha_f_scale); } Frame Frame::qSpaceFrame(double lambda, double alpha_i) const { ASSERT(rank() == 2); auto* qy_scale = new Scale(xAxis().qy_Scale(lambda)); auto* qz_scale = new Scale(yAxis().qz_Scale(lambda, alpha_i)); return Frame(qy_scale, qz_scale); } Frame Frame::flat() const { std::vector<const Scale*> outaxes; for (const Scale* s : m_axes) if (s->size() > 1) outaxes.emplace_back(s->clone()); return Frame(outaxes); }