diff --git a/NumLib/Extrapolation/ExtrapolatableElement.h b/NumLib/Extrapolation/ExtrapolatableElement.h new file mode 100644 index 0000000000000000000000000000000000000000..3a24dc3fdbcf6a653e19325bec9f2adaa8f5ed53 --- /dev/null +++ b/NumLib/Extrapolation/ExtrapolatableElement.h @@ -0,0 +1,33 @@ +/** + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef NUMLIB_EXTRAPOLATION_EXTRAPOLATABLEELEMENT_H +#define NUMLIB_EXTRAPOLATION_EXTRAPOLATABLEELEMENT_H + +namespace NumLib +{ +/*! Interface for providing shape matrices and integration point values for + * extrapolation, + * + * Local assemblers that want to have some integration point values extrapolated + * using an Extrapolator have to implement this interface. + */ +class ExtrapolatableElement +{ +public: + //! Provides the shape matrix at the given integration point. + virtual Eigen::Map<const Eigen::VectorXd> getShapeMatrix( + const unsigned integration_point) const = 0; + + virtual ~ExtrapolatableElement() = default; +}; + +} // namespace NumLib + +#endif // NUMLIB_EXTRAPOLATION_EXTRAPOLATABLEELEMENT_H diff --git a/NumLib/Extrapolation/ExtrapolatableElementCollection.h b/NumLib/Extrapolation/ExtrapolatableElementCollection.h new file mode 100644 index 0000000000000000000000000000000000000000..7be326d3faa881d6018cf2d57cb4bb35b62ab9b5 --- /dev/null +++ b/NumLib/Extrapolation/ExtrapolatableElementCollection.h @@ -0,0 +1,121 @@ +/** + * \copyright + * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef NUMLIB_EXTRAPOLATION_EXTRAPOLATABLEELEMENTCOLLECTION_H +#define NUMLIB_EXTRAPOLATION_EXTRAPOLATABLEELEMENTCOLLECTION_H + +#include "ExtrapolatableElement.h" + +namespace NumLib +{ +//! Adaptor to get information needed by an Extrapolator from an "arbitrary" +//! collection of elements (e.g., local assemblers). +class ExtrapolatableElementCollection +{ +public: + //! Returns the shape matrix of the element with the given \c id at the + //! given \c integration_point. + virtual Eigen::Map<const Eigen::VectorXd> getShapeMatrix( + std::size_t const id, unsigned const integration_point) const = 0; + + //! Returns integration point values of some property of the element with + //! the given \c id. + virtual std::vector<double> const& getIntegrationPointValues( + std::size_t const id, std::vector<double>& cache) const = 0; + + //! Returns the number of elements whose properties shall be extrapolated. + virtual std::size_t size() const = 0; + + virtual ~ExtrapolatableElementCollection() = default; +}; + +template <typename LocalAssemblerCollection> +class ExtrapolatableLocalAssemblerCollection + : public ExtrapolatableElementCollection +{ +public: + //! LocalAssemblerCollection contains many LocalAssembler's. + using LocalAssembler = typename std::decay<decltype( + *std::declval<LocalAssemblerCollection>()[static_cast<std::size_t>( + 0)])>::type; + + static_assert(std::is_base_of<ExtrapolatableElement, LocalAssembler>::value, + "Local assemblers used for extrapolation must be derived " + "from Extrapolatable."); + + /*! A method providing integration point values of some property. + * + * \remark + * \parblock + * The vector \c cache can be used to store some derived quantities that + * should be used as integration point values. They can be written to the + * \c cache and a reference to the \c cache can then be returned by the + * implementation of this method. + * Ordinary integration point values can be returned directly (if they are + * stored in the local assembler), and the \c cache can be left untouched. + * + * For usage examples see the processes already implemented or the unit test + * in TestExtrapolation.cpp + * \endparblock + * + * The method must return reference to a vector containing the integration + * point values. + */ + using IntegrationPointValuesMethod = std::vector<double> const& ( + LocalAssembler::*)(std::vector<double>& cache) const; + + /*! Constructs a new instance. + * + * \param local_assemblers a collection of local assemblers whose + * integration point values shall be extrapolated. + * \param integration_point_values_method a LocalAssembler method returning + * integration point values of some property for that local assembler. + */ + ExtrapolatableLocalAssemblerCollection( + LocalAssemblerCollection const& local_assemblers, + IntegrationPointValuesMethod integration_point_values_method) + : _local_assemblers(local_assemblers) + , _integration_point_values_method(integration_point_values_method) + { + } + + Eigen::Map<const Eigen::VectorXd> getShapeMatrix( + std::size_t const id, unsigned const integration_point) const override + { + ExtrapolatableElement const& loc_asm = *_local_assemblers[id]; + return loc_asm.getShapeMatrix(integration_point); + } + + std::vector<double> const& getIntegrationPointValues( + std::size_t const id, std::vector<double>& cache) const override + { + auto const& loc_asm = *_local_assemblers[id]; + return (loc_asm.*_integration_point_values_method)(cache); + } + + std::size_t size() const override { return _local_assemblers.size(); } +private: + LocalAssemblerCollection const& _local_assemblers; + IntegrationPointValuesMethod const _integration_point_values_method; +}; + +//! Creates an ExtrapolatableLocalAssemblerCollection, which can be used to +//! provide information to an Extrapolator. +template <typename LocalAssemblerCollection, + typename IntegrationPointValuesMethod> +ExtrapolatableLocalAssemblerCollection<LocalAssemblerCollection> +makeExtrapolatable(LocalAssemblerCollection const& local_assemblers, + IntegrationPointValuesMethod integration_point_values_method) +{ + return ExtrapolatableLocalAssemblerCollection<LocalAssemblerCollection>{ + local_assemblers, integration_point_values_method}; +} +} // namespace NumLib + +#endif // NUMLIB_EXTRAPOLATION_EXTRAPOLATABLEELEMENTCOLLECTION_H diff --git a/NumLib/Extrapolation/Extrapolator.h b/NumLib/Extrapolation/Extrapolator.h index 1ac340fa0a75ce0e1498522463c9b05d0e9418b7..ee21daa77840a18042fd9e446290d235ed275fa4 100644 --- a/NumLib/Extrapolation/Extrapolator.h +++ b/NumLib/Extrapolation/Extrapolator.h @@ -18,60 +18,14 @@ namespace NumLib { -/*! Interface for providing shape matrices and integration point values for - * extrapolation, - * - * Local assemblers that want to have some integration point values extrapolated - * using Extrapolator have to implement this interface. - * - * \tparam PropertyTag type of the property used to query a specific kind of - * integration point value, usually an enum. - */ -template <typename PropertyTag> -class Extrapolatable -{ -public: - //! Provides the shape matrix at the given integration point. - virtual Eigen::Map<const Eigen::RowVectorXd> - getShapeMatrix(const unsigned integration_point) const = 0; - - /*! Provides integration point values for the given property. - * - * \remark - * The vector \c cache can be used to store some derived quantities that - * should be used as integration point values. They can be written to the - * \c cache and a reference to the \c cache can then be returned by the - * implementation of this method. - * Ordinary integration point values can be returned directly (if they are - * stored in the local assembler), and the \c cache cen be left untouched. - * - * \returns a reference to a vector containing the integration point values. - */ - virtual std::vector<double> const& - getIntegrationPointValues(PropertyTag const property, - std::vector<double>& cache) const = 0; - - virtual ~Extrapolatable() = default; -}; - -/*! Interface for classes that extrapolate integration point values to nodal - * values. - * - * \tparam PropertyTag type of the property used to query a specific kind of - * integration point value, usually an enum. - * \tparam LocalAssembler type of the local assembler being queried for - * integration point values. - */ -template<typename PropertyTag, typename LocalAssembler> +//! Interface for classes that extrapolate integration point values to nodal +//! values. class Extrapolator { public: - //! Vector of local assemblers, the same as is used in the FEM process. - using LocalAssemblers = std::vector<std::unique_ptr<LocalAssembler>>; - //! Extrapolates the given \c property from the given local assemblers. virtual void extrapolate( - LocalAssemblers const& loc_asms, PropertyTag const property) = 0; + ExtrapolatableElementCollection const& extrapolatables) = 0; /*! Computes residuals from the extrapolation of the given \c property. * @@ -80,7 +34,7 @@ public: * \pre extrapolate() must have been called before with the same arguments. */ virtual void calculateResiduals( - LocalAssemblers const& loc_asms, PropertyTag const property) = 0; + ExtrapolatableElementCollection const& extrapolatables) = 0; //! Returns the extrapolated nodal values. //! \todo Maybe write directly to a MeshProperty. diff --git a/NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator-impl.h b/NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator.cpp similarity index 56% rename from NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator-impl.h rename to NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator.cpp index 5e03eece5e3ba05e9c49ec5d82bf2ad31b270eba..2ed625bec24e12eac69166671cc375ba5452d272 100644 --- a/NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator-impl.h +++ b/NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator.cpp @@ -7,24 +7,23 @@ * */ +#include "LocalLinearLeastSquaresExtrapolator.h" + #include <functional> -#include <logog/include/logog.hpp> #include <Eigen/Core> +#include <logog/include/logog.hpp> #include "MathLib/LinAlg/LinAlg.h" -#include "NumLib/Assembler/SerialExecutor.h" #include "MathLib/LinAlg/MatrixVectorTraits.h" +#include "NumLib/Assembler/SerialExecutor.h" #include "NumLib/Function/Interpolation.h" -#include "LocalLinearLeastSquaresExtrapolator.h" +#include "ExtrapolatableElementCollection.h" namespace NumLib { - -template<typename PropertyTag, typename LocalAssembler> -void -LocalLinearLeastSquaresExtrapolator<PropertyTag, LocalAssembler>:: -extrapolate(LocalAssemblers const& local_assemblers, PropertyTag const property) +inline void LocalLinearLeastSquaresExtrapolator::extrapolate( + ExtrapolatableElementCollection const& extrapolatables) { _nodal_values.setZero(); @@ -32,44 +31,39 @@ extrapolate(LocalAssemblers const& local_assemblers, PropertyTag const property) // compute the average afterwards auto counts = MathLib::MatrixVectorTraits<GlobalVector>::newInstance(_nodal_values); - counts->setZero(); // TODO BLAS? - - using Self = LocalLinearLeastSquaresExtrapolator< - PropertyTag, LocalAssembler>; + counts->setZero(); // TODO BLAS? - NumLib::SerialExecutor::executeMemberDereferenced( - *this, &Self::extrapolateElement, local_assemblers, property, *counts); + auto const size = extrapolatables.size(); + for (std::size_t i=0; i<size; ++i) { + extrapolateElement(i, extrapolatables, *counts); + } MathLib::LinAlg::componentwiseDivide(_nodal_values, _nodal_values, *counts); } -template<typename PropertyTag, typename LocalAssembler> -void -LocalLinearLeastSquaresExtrapolator<PropertyTag, LocalAssembler>:: -calculateResiduals(LocalAssemblers const& local_assemblers, - PropertyTag const property) +inline void LocalLinearLeastSquaresExtrapolator::calculateResiduals( + ExtrapolatableElementCollection const& extrapolatables) { - assert(static_cast<std::size_t>(_residuals.size()) == local_assemblers.size()); - - using Self = LocalLinearLeastSquaresExtrapolator< - PropertyTag, LocalAssembler>; + assert(static_cast<std::size_t>(_residuals.size()) == + extrapolatables.size()); - NumLib::SerialExecutor::executeMemberDereferenced( - *this, &Self::calculateResiudalElement, local_assemblers, property); + auto const size = extrapolatables.size(); + for (std::size_t i=0; i<size; ++i) { + calculateResiudalElement(i, extrapolatables); + } } -template<typename PropertyTag, typename LocalAssembler> -void -LocalLinearLeastSquaresExtrapolator<PropertyTag, LocalAssembler>:: -extrapolateElement(std::size_t const element_index, - LocalAssembler const& loc_asm, PropertyTag const property, - GlobalVector& counts) +inline void LocalLinearLeastSquaresExtrapolator::extrapolateElement( + std::size_t const element_index, + ExtrapolatableElementCollection const& extrapolatables, + GlobalVector& counts) { - auto const& integration_point_values = loc_asm.getIntegrationPointValues( - property, _integration_point_values_cache); + auto const& integration_point_values = + extrapolatables.getIntegrationPointValues( + element_index, _integration_point_values_cache); // number of nodes in the element - const auto nn = loc_asm.getShapeMatrix(0).cols(); + const auto nn = extrapolatables.getShapeMatrix(element_index, 0).cols(); // number of integration points in the element const auto ni = integration_point_values.size(); @@ -80,9 +74,9 @@ extrapolateElement(std::size_t const element_index, auto& N = _local_matrix_cache; // TODO make that local? N.resize(ni, nn); // TODO: might reallocate very often - for (auto int_pt=decltype(ni){0}; int_pt<ni; ++int_pt) - { - auto const& shp_mat = loc_asm.getShapeMatrix(int_pt); + for (auto int_pt = decltype(ni){0}; int_pt < ni; ++int_pt) { + auto const& shp_mat = + extrapolatables.getShapeMatrix(element_index, int_pt); assert(shp_mat.cols() == nn); // copy shape matrix to extrapolation matrix columnwise @@ -91,7 +85,7 @@ extrapolateElement(std::size_t const element_index, // TODO make gp_vals an Eigen::VectorXd const& ? Eigen::Map<const Eigen::VectorXd> const integration_point_values_vec( - integration_point_values.data(), integration_point_values.size()); + integration_point_values.data(), integration_point_values.size()); // TODO // optimization: Store decomposition of N*N^T or N^T for reuse? @@ -111,19 +105,18 @@ extrapolateElement(std::size_t const element_index, // TODO: for now always zeroth component is used auto const& global_indices = _local_to_global(element_index, 0).rows; - _nodal_values.add(global_indices, tmp); // TODO does that give rise to PETSc problems? + _nodal_values.add(global_indices, + tmp); // TODO does that give rise to PETSc problems? counts.add(global_indices, std::vector<double>(global_indices.size(), 1.0)); } -template<typename PropertyTag, typename LocalAssembler> -void -LocalLinearLeastSquaresExtrapolator<PropertyTag, LocalAssembler>:: -calculateResiudalElement(std::size_t const element_index, - LocalAssembler const& loc_asm, PropertyTag const property) +inline void LocalLinearLeastSquaresExtrapolator::calculateResiudalElement( + std::size_t const element_index, + ExtrapolatableElementCollection const& extrapolatables) { - auto const& gp_vals = loc_asm.getIntegrationPointValues( - property, _integration_point_values_cache); - const unsigned ni = gp_vals.size(); // number of gauss points + auto const& gp_vals = extrapolatables.getIntegrationPointValues( + element_index, _integration_point_values_cache); + const unsigned ni = gp_vals.size(); // number of gauss points // TODO: for now always zeroth component is used const auto& global_indices = _local_to_global(element_index, 0).rows; @@ -131,7 +124,7 @@ calculateResiudalElement(std::size_t const element_index, // filter nodal values of the current element std::vector<double> nodal_vals_element; nodal_vals_element.resize(global_indices.size()); - for (unsigned i=0; i<global_indices.size(); ++i) { + for (unsigned i = 0; i < global_indices.size(); ++i) { // TODO PETSc negative indices? nodal_vals_element[i] = _nodal_values[global_indices[i]]; } @@ -139,10 +132,11 @@ calculateResiudalElement(std::size_t const element_index, double residual = 0.0; double gp_val_extrapol = 0.0; - for (unsigned gp=0; gp<ni; ++gp) - { + for (unsigned gp = 0; gp < ni; ++gp) { NumLib::shapeFunctionInterpolate( - nodal_vals_element, loc_asm.getShapeMatrix(gp), gp_val_extrapol); + nodal_vals_element, + extrapolatables.getShapeMatrix(element_index, gp), + gp_val_extrapol); auto const& ax_m_b = gp_val_extrapol - gp_vals[gp]; residual += ax_m_b * ax_m_b; } @@ -150,4 +144,4 @@ calculateResiudalElement(std::size_t const element_index, _residuals.set(element_index, std::sqrt(residual / ni)); } -} // namespace ProcessLib +} // namespace NumLib diff --git a/NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator.h b/NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator.h index df3f0ffb093eb3ec788929846ff4e95cf72f7c85..db1154f717cb9134c7bccb7eb6cee06201b51af3 100644 --- a/NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator.h +++ b/NumLib/Extrapolation/LocalLinearLeastSquaresExtrapolator.h @@ -35,14 +35,9 @@ namespace NumLib * system. * \endparblock */ -template <typename PropertyTag, typename LocalAssembler> -class LocalLinearLeastSquaresExtrapolator - : public Extrapolator<PropertyTag, LocalAssembler> +class LocalLinearLeastSquaresExtrapolator : public Extrapolator { public: - using LocalAssemblers = - typename Extrapolator<PropertyTag, LocalAssembler>::LocalAssemblers; - /*! Constructs a new instance * * \note @@ -77,8 +72,8 @@ public: "only one component!"); } - void extrapolate(LocalAssemblers const& local_assemblers, - PropertyTag const property) override; + void extrapolate( + ExtrapolatableElementCollection const& extrapolatables) override; /*! \copydoc Extrapolator::calculateResiduals() * @@ -87,8 +82,8 @@ public: * extrapolation results when interpolated back to the integration points * again. */ - void calculateResiduals(LocalAssemblers const& local_assemblers, - PropertyTag const property) override; + void calculateResiduals( + ExtrapolatableElementCollection const& extrapolatables) override; GlobalVector const& getNodalValues() const override { @@ -108,14 +103,15 @@ public: private: //! Extrapolate one element. - void extrapolateElement(std::size_t const element_index, - LocalAssembler const& local_assembler, - PropertyTag const property, GlobalVector& counts); + void extrapolateElement( + std::size_t const element_index, + ExtrapolatableElementCollection const& extrapolatables, + GlobalVector& counts); //! Compute the residuals for one element - void calculateResiudalElement(std::size_t const element_index, - LocalAssembler const& local_assembler, - PropertyTag const property); + void calculateResiudalElement( + std::size_t const element_index, + ExtrapolatableElementCollection const& extrapolatables); GlobalVector& _nodal_values; //!< extrapolated nodal values GlobalVector _residuals; //!< extrapolation residuals @@ -129,8 +125,7 @@ private: //! Avoids frequent reallocations. std::vector<double> _integration_point_values_cache; }; -} -#include "LocalLinearLeastSquaresExtrapolator-impl.h" +} // namespace NumLib #endif // NUMLIB_LOCAL_LLSQ_EXTRAPOLATOR_H