diff --git a/src/core/grid.hh b/src/core/grid.hh index 75db563..333fd01 100644 --- a/src/core/grid.hh +++ b/src/core/grid.hh @@ -1,230 +1,233 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2022 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * Copyright (©) 2020-2022 Lucas Frérot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef GRID_HH #define GRID_HH /* -------------------------------------------------------------------------- */ #include "grid_base.hh" #include "tamaas.hh" #include #include #include #include /* -------------------------------------------------------------------------- */ namespace tamaas { /** * @brief Multi-dimensional & multi-component array class * * This class is a container for multi-component data stored on a multi- * dimensional grid. * * The access function is the parenthesis operator. For a grid of dimension d, * the operator takes d+1 arguments: the first d arguments are the position on * the grid and the last one is the component of the stored data. * * It is also possible to use the access operator with only one argument, it is * then considering the grid as a flat array, accessing the given cell of the * array. */ template class Grid : public GridBase { template using is_valid_index = fold_trait; public: /* ------------------------------------------------------------------------ */ /* Types */ /* ------------------------------------------------------------------------ */ using value_type = T; using reference = value_type&; static constexpr UInt dimension = dim; /* ------------------------------------------------------------------------ */ /* Constructors */ /* ------------------------------------------------------------------------ */ public: /// Constructor by default (empty array) Grid(); /// Constructor from iterators template Grid(RandomAccessIterator begin, RandomAccessIterator end, UInt nb_components); + template + Grid(RandomAccessIterator begin, RandomAccessIterator end, + UInt nb_components, value_type* data); /// Constructor Grid(const std::array& n, UInt nb_components) : Grid(std::begin(n), std::end(n), nb_components) {} /// Wrap on given data Grid(const std::array& n, UInt nb_components, value_type* data); /// Constructor with vectors Grid(const std::vector& n, UInt nb_components) : Grid(std::begin(n), std::end(n), nb_components) {} /// Constructor with initializer list Grid(const std::initializer_list& n, UInt nb_components) : Grid(std::begin(n), std::end(n), nb_components) {} /// Copy constructor Grid(const Grid& o); /// Move constructor (transfers data ownership) Grid(Grid&& o) noexcept; /// Destructor ~Grid() override = default; private: /// Init from standard container template void init(const Container& n, UInt nb_components); public: /* ------------------------------------------------------------------------ */ /* Common operations */ /* ------------------------------------------------------------------------ */ /// Resize array void resize(const std::array& n); /// Resize array (from std::vector) void resize(const std::vector& n); /// Resize array (from initializer list) void resize(std::initializer_list n); /// Resize array (from iterators) template void resize(ForwardIt begin, ForwardIt end); /// Compute size inline UInt computeSize() const; /// Get grid dimension inline UInt getDimension() const override { return dim; } /// Compute strides void computeStrides(); /// Print virtual void printself(std::ostream& str) const; /// Get sizes const std::array& sizes() const { return n; } /// Get strides const std::array& getStrides() const { return this->strides; } /* ------------------------------------------------------------------------ */ /* Access operators (these cannot be moved outside the class) */ /* ------------------------------------------------------------------------ */ /// Variadic access operator (non-const) template inline std::enable_if_t::value, T&> operator()(T1... args) { /// Checking access integrity constexpr UInt nargs = sizeof...(T1); static_assert(nargs == dim + 1 || nargs == 1 || nargs == dim, "number of arguments in operator() does not match dimension"); constexpr UInt start = (nargs == 1) ? dim : 0; UInt offset = unpackOffset(0, start, args...); return this->data[offset]; } /// Variadic access operator template inline std::enable_if_t::value, const T&> operator()(T1... args) const { /// Checking access integrity constexpr UInt nargs = sizeof...(T1); static_assert(nargs == dim + 1 || nargs == 1 || nargs == dim, "number of arguments in operator() does not match dimension"); constexpr UInt start = (nargs == 1) ? dim : 0; UInt offset = unpackOffset(0, start, args...); return this->data[offset]; } /// Tuple index access operator template inline T& operator()(std::array tuple); template inline const T& operator()(std::array tuple) const; private: /// Unpacking the arguments of variadic () template inline UInt unpackOffset(UInt offset, UInt index_pos, UInt index, T1... rest) const; /// End case for recursion template inline UInt unpackOffset(UInt offset, UInt index_pos, UInt index) const; /// Computing offset for a tuple index template inline UInt computeOffset(std::array tuple) const; /* ------------------------------------------------------------------------ */ /* Move/Copy operators */ /* ------------------------------------------------------------------------ */ public: using GridBase::operator=; // = operator Grid& operator=(const Grid& other); // = operator (move) Grid& operator=(Grid&& other) noexcept; // Copy data from another grid template void copy(const Grid& other); // Move data from another grid template void move(Grid&& other) noexcept; template void wrap(GridBase & other, Container&& n) { GridBase::wrap(other); std::copy(n.begin(), n.end(), this->n.begin()); this->computeStrides(); } template void wrap(const GridBase & other, Container&& n) { GridBase::wrap(other); std::copy(n.begin(), n.end(), this->n.begin()); this->computeStrides(); } // Wrap memory (non-const) void wrap(Grid& other) { wrap(other, other.n); } // Wrap memory void wrap(const Grid& other) { wrap(other, other.n); } /* ------------------------------------------------------------------------ */ /* Member variables */ /* ------------------------------------------------------------------------ */ protected: std::array n; ///< shape of grid: size per dimension std::array strides; ///< strides for access }; } // namespace tamaas /* -------------------------------------------------------------------------- */ /* Inline/template function definitions */ /* -------------------------------------------------------------------------- */ #include "grid_tmpl.hh" /* -------------------------------------------------------------------------- */ #endif // GRID_HH diff --git a/src/core/grid_tmpl.hh b/src/core/grid_tmpl.hh index 12293b7..69aee35 100644 --- a/src/core/grid_tmpl.hh +++ b/src/core/grid_tmpl.hh @@ -1,153 +1,171 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2022 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * Copyright (©) 2020-2022 Lucas Frérot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef GRID_TMPL_HH #define GRID_TMPL_HH /* -------------------------------------------------------------------------- */ #include "grid.hh" #include "tamaas.hh" namespace tamaas { template template Grid::Grid(RandomAccessIterator begin, RandomAccessIterator end, UInt nb_components) : GridBase() { if (end - begin != dim) { TAMAAS_EXCEPTION("Provided sizes (" << end - begin << ") for grid do not match dimension (" << dim << ")"); } this->nb_components = nb_components; this->resize(begin, end); } /* -------------------------------------------------------------------------- */ +template +template +Grid::Grid(RandomAccessIterator begin, RandomAccessIterator end, + UInt nb_components, value_type* data) + : GridBase() { + if (end - begin != dim) { + TAMAAS_EXCEPTION("Provided sizes (" << end - begin + << ") for grid do not match dimension (" + << dim << ")"); + } + + std::copy(begin, end, this->n.begin()); + this->nb_components = nb_components; + this->data.wrap(data, this->computeSize()); +} + +/* -------------------------------------------------------------------------- */ + template inline UInt Grid::computeSize() const { UInt size = 1; for (UInt i = 0; i < dim; i++) size *= n[i]; size *= this->nb_components; return size; } /* -------------------------------------------------------------------------- */ template template void Grid::resize(ForwardIt begin, ForwardIt end) { std::copy(begin, end, this->n.begin()); UInt size = this->computeSize(); GridBase::resize(size); this->computeStrides(); } /* -------------------------------------------------------------------------- */ template template inline UInt Grid::unpackOffset(UInt offset, UInt index_pos, UInt index, T1... rest) const { offset += index * strides[index_pos]; return unpackOffset(offset, index_pos + 1, rest...); // tail-rec bb } template template inline UInt Grid::unpackOffset(UInt offset, UInt index_pos, UInt index) const { return offset + index * strides[index_pos]; } /* -------------------------------------------------------------------------- */ template template inline UInt Grid::computeOffset(std::array tuple) const { static_assert(tdim == dim or tdim == dim + 1, "Tuple dimension is invalid"); return std::inner_product(tuple.begin(), tuple.end(), strides.begin(), 0); } template template inline T& Grid::operator()(std::array tuple) { UInt offset = computeOffset(tuple); return this->data[offset]; } template template inline const T& Grid::operator()(std::array tuple) const { UInt offset = computeOffset(tuple); return this->data[offset]; } /* -------------------------------------------------------------------------- */ template Grid& Grid::operator=(const Grid& other) { this->copy(other); return *this; } template Grid& Grid::operator=(Grid&& other) noexcept { this->move(std::move(other)); return *this; } /* -------------------------------------------------------------------------- */ template template void Grid::copy(const Grid& other) { GridBase::copy(other); this->n = other.n; this->strides = other.strides; } template template void Grid::move(Grid&& other) noexcept { GridBase::move(std::move(other)); this->n = std::move(other.n); this->strides = std::move(other.strides); } /* -------------------------------------------------------------------------- */ /* Stream operator */ /* -------------------------------------------------------------------------- */ template inline std::ostream& operator<<(std::ostream& stream, const Grid& _this) { _this.printself(stream); return stream; } } // namespace tamaas /* -------------------------------------------------------------------------- */ #endif // GRID_TMPL_HH diff --git a/src/model/kelvin.cpp b/src/model/kelvin.cpp index fdf2bad..a286c6d 100644 --- a/src/model/kelvin.cpp +++ b/src/model/kelvin.cpp @@ -1,161 +1,161 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2022 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * Copyright (©) 2020-2022 Lucas Frérot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "kelvin.hh" #include "logger.hh" /* -------------------------------------------------------------------------- */ namespace tamaas { /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* Constructors */ /* -------------------------------------------------------------------------- */ template Kelvin::Kelvin(Model* model) : VolumePotential(model) { setIntegrationMethod(integration_method::linear, 1e-12); } template void Kelvin::setIntegrationMethod(integration_method method, Real cutoff) { this->method = method; this->cutoff = cutoff; Logger logger; if (this->method == integration_method::linear) { logger.get(LogLevel::debug) << TAMAAS_DEBUG_MSG("Setting linear integration method"); this->initialize(dtrait::template source_components, dtrait::template out_components, this->model->getDiscretization()[0]); } else { logger.get(LogLevel::debug) << TAMAAS_DEBUG_MSG( "Setting cutoff integration method (cutoff " << this->cutoff << ')'); this->initialize(dtrait::template source_components, dtrait::template out_components, 1); } auto max_q = Loop::reduce( [] CUDA_LAMBDA(VectorProxy qv) { return qv.l2norm(); }, range>( this->wavevectors)); if (this->method == integration_method::linear and not std::isfinite(std::exp(max_q * this->model->getSystemSize()[0]))) logger.get(LogLevel::warning) << "Probable overflow of integral computation (consider " "changing integration method to integration_method::cutoff or " "compiling with real_type='long double')\n"; } /* -------------------------------------------------------------------------- */ /* Operator implementation */ /* -------------------------------------------------------------------------- */ template void Kelvin::applyIf(GridBase& source, GridBase& out, filter_t pred) const { KelvinInfluence kelvin(this->model->getShearModulus(), this->model->getPoissonRatio()); parent::transformSource(source, pred); // Reset buffer values for (auto&& layer : this->out_buffer) layer = 0; if (method == integration_method::linear) { linearIntegral(out, kelvin); } else { cutoffIntegral(out, kelvin); } } template void Kelvin::linearIntegral(GridBase& out, KelvinInfluence& kelvin) const { detail::KelvinHelper helper; helper.applyIntegral(this->source_buffer, this->out_buffer, this->wavevectors, this->model->getSystemSize().front(), kelvin); helper.applyFreeTerm(this->source_buffer, this->out_buffer, kelvin); helper.makeFundamentalGreatAgain(this->out_buffer); parent::transformOutput( [](auto&& out_buffer, auto layer) -> typename parent::BufferType& { return out_buffer[layer]; }, out); } template void Kelvin::cutoffIntegral(GridBase& out, KelvinInfluence& kelvin) const { detail::KelvinHelper helper; auto func = [&](auto&& out_buffer, auto layer) -> typename parent::BufferType& { auto&& out = out_buffer.front(); out = 0; helper.applyIntegral(this->source_buffer, out, layer, this->wavevectors, this->model->getSystemSize().front(), cutoff, kelvin); helper.applyFreeTerm(this->source_buffer[layer], out, kelvin); helper.makeFundamentalGreatAgain(out); return out; }; parent::transformOutput(func, out); } /* -------------------------------------------------------------------------- */ template std::pair Kelvin::matvecShape() const { const auto N = (*this->model)["displacement"].getGlobalNbPoints(); return std::make_pair(dtrait::template out_components * N, dtrait::template source_components * N); } /* -------------------------------------------------------------------------- */ template GridBase Kelvin::matvec(GridBase& X) const { const auto dim = trait::dimension; - Grid x; - Grid y{this->model->getDiscretization(), - dtrait::template out_components}; - X.setNbComponents(dtrait::template source_components); - x.wrap(X, this->model->getDiscretization()); + const auto shape = this->model->getDiscretization(); + Grid x{shape.begin(), shape.end(), + dtrait::template source_components, + X.getInternalData()}, + y{shape, dtrait::template out_components}; this->apply(x, y); return y; } /* -------------------------------------------------------------------------- */ /* Template instanciation */ /* -------------------------------------------------------------------------- */ template class Kelvin; template class Kelvin; template class Kelvin; /* -------------------------------------------------------------------------- */ } // namespace tamaas