Skip to content
Snippets Groups Projects
Commit 3748bf56 authored by Philipp Wissmann's avatar Philipp Wissmann
Browse files

Add more concepts

parent a9d113fb
No related branches found
No related tags found
No related merge requests found
// © 2025 ETH Zurich, Mechanics and Materials Lab
//
// This file is part of ae108.
//
// ae108 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or any
// later version.
//
// ae108 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ae108. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "PluginBase.h"
#include <ae108/elements/ElementConcept.h>
namespace ae108::assembly {
template <typename Mesh, ae108::elements::ElementConcept Element>
class AssembleForceVectorPlugin : public PluginBase<Mesh, Element> {
public:
using mesh_type = Mesh;
using vector_type = typename mesh_type::vector_type;
using element_type = Element;
void assemble(const cpppetsc::local<vector_type> &displacements,
const double time,
cpppetsc::local<vector_type> *const output) const {
typename element_type::NodalDisplacements elementInput;
for (const auto &meshElement : this->meshElements()) {
ae108::assembly::utilities::groupElementDataPerVertex(
meshElement.meshView(), displacements, &elementInput);
const auto forces =
meshElement.instance().computeForces(elementInput, time);
ae108::assembly::utilities::ungroupElementDataPerVertex(
meshElement.meshView(), forces, output);
}
}
};
} // namespace ae108::assembly
\ No newline at end of file
......@@ -19,44 +19,21 @@
#include "PluginBase.h"
namespace ae108::assembly {
template <typename Mesh, ElementConcept Element>
class AssembleForceVectorPluginSimplified : public PluginBase<Mesh, Element> {
public:
using vector_type = typename Mesh::vector_type;
using element_type = Element;
#include <ae108/elements/ElementConcept.h>
void assembleForceVector(const cpppetsc::local<vector_type> &displacements,
const double time,
cpppetsc::local<vector_type> *const output) const {
typename element_type::NodalDisplacements elementInput;
for (const auto &meshElement : this->meshElements()) {
ae108::assembly::utilities::groupElementDataPerVertex(
meshElement.meshView(), displacements, &elementInput);
const auto forces =
meshElement.instance().computeForces(elementInput, time);
ae108::assembly::utilities::ungroupElementDataPerVertex(
meshElement.meshView(), forces, output);
}
}
};
namespace ae108::assembly {
template <typename Mesh, ElementConcept Element>
class AssembleStiffnessMatrixPluginSimplified
: public PluginBase<Mesh, Element> {
template <typename Mesh, ae108::elements::ElementConcept Element>
class AssembleStiffnessMatrixPlugin : public PluginBase<Mesh, Element> {
public:
using vector_type = typename Mesh::vector_type;
using matrix_type = typename Mesh::matrix_type;
using value_type = typename Mesh::value_type;
using mesh_type = Mesh;
using vector_type = typename mesh_type::vector_type;
using matrix_type = typename mesh_type::matrix_type;
using value_type = typename mesh_type::value_type;
using element_type = Element;
void
assembleStiffnessMatrix(const cpppetsc::local<vector_type> &displacements,
const double time, matrix_type *const output) const {
void assemble(const cpppetsc::local<vector_type> &displacements,
const double time, matrix_type *const output) const {
typename element_type::NodalDisplacements elementInput;
std::vector<value_type> outputBuffer;
......
......@@ -17,71 +17,67 @@
#pragma once
#include "ConceptHelpers.h"
#include "PluginBase.h"
namespace ae108::assembly {
/// Concept for all Plugins used in Assemblers
template <typename P>
concept PluginLike = requires(P p) {
{std::is_base_of_v<
PluginBase<typename P::mesh_type, typename P::element_type>, P>};
};
/// Concept for plugins that can calulculate stiffness matrix
template <typename P>
concept StiffnessMatrixPluginLike = PluginLike<P> && requires(P p) {
p.assembleStiffnessMatrix(
std::add_const_t<cpppetsc::local<typename P::vector_type>>{}, double(0),
std::add_pointer_t<typename P::matrix_type>{});
};
/// Assembler base class using PluginLike concept
template <PluginLike... Plugins> struct AssemblerBase {
/**
* @brief Base class for assemblers
*
* Stores plugins and allows invoking the plugins 'assemble' function
*/
template <PluginLike... Plugins>
requires(same_nested_mesh_type<Plugins...>
&&same_plugin_concept<Plugins...>) class AssemblerBase {
public:
explicit AssemblerBase() : _plugins(Plugins{}...) {}
std::tuple<Plugins...> _plugins;
/** @brief Return stored plugins
* @remark std::tuple<> allows for decying into structured bindings:
* @code
* auto &[plugin1, plugin2] = assembler.plugins();
* @endcode
*/
std::tuple<Plugins...> &plugins() { return _plugins; }
const std::tuple<Plugins...> &plugins() const { return _plugins; }
template <int N> auto &getPlugin() { return std::get<N>(_plugins); }
};
/// ForceVectorAssembler
template <typename Mesh, PluginLike... Plugins>
struct ForceVectorAssembler : public AssemblerBase<Plugins...> {
using vector_type = typename Mesh::vector_type;
explicit ForceVectorAssembler() : AssemblerBase<Plugins...>() {}
void assembleForceVector(const cpppetsc::local<vector_type> &displacements,
const double time,
cpppetsc::local<vector_type> *const output) const {
protected:
/** @brief Function to dispatch assembly call to all plugins
*
* Calls the assembly function on all plugins and uses a constraint to verify
* that a member function exists on all the plugins.
* Derived classes can call this function to invoke the plugins.
*
*/
template <typename... Args>
requires((std::is_invocable_v<decltype(&Plugins::assemble), Plugins &,
Args &&...> &&
...)) void dispatchAssembly(Args &&...args) const {
std::apply(
[&](const auto &...plugin) {
(plugin.assembleForceVector(displacements, time, output), ...);
(plugin.assemble(std::forward<Args>(args)...), ...);
},
this->_plugins);
}
private:
/// Plugin container
std::tuple<Plugins...> _plugins;
};
template <typename Mesh, StiffnessMatrixPluginLike... Plugins>
class StiffnessMatrixAssembler : public AssemblerBase<Plugins...> {
template <typename... Plugins>
class UnifiedAssembler : public AssemblerBase<Plugins...> {
public:
using mesh_type = Mesh;
using vector_type = typename Mesh::vector_type;
using matrix_type = typename Mesh::matrix_type;
using mesh_type = typename first<Plugins...>::mesh_type;
using vector_type = typename mesh_type::vector_type;
using matrix_type = typename mesh_type::matrix_type;
explicit StiffnessMatrixAssembler() : AssemblerBase<Plugins...>() {}
explicit UnifiedAssembler() : AssemblerBase<Plugins...>() {}
void
assembleStiffnessMatrix(const cpppetsc::local<vector_type> &displacements,
const double time, matrix_type *const output) const {
std::apply(
[&](const auto &...plugin) {
(plugin.assembleStiffnessMatrix(displacements, time, output), ...);
},
this->_plugins);
template <typename... Args> void assemble(Args &&...args) const {
this->dispatchAssembly(std::forward<Args>(args)...);
}
};
} // namespace ae108::assembly
\ No newline at end of file
// © 2025 ETH Zurich, Mechanics and Materials Lab
//
// This file is part of ae108.
//
// ae108 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or any
// later version.
//
// ae108 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ae108. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "PluginBase.h"
#include <type_traits>
namespace ae108 {
/// Return the first type of types in a parameter pack
template <typename... Types>
using first = typename std::tuple_element<0, std::tuple<Types...>>::type;
/// Concept to ensure having the same nested type 'mesh_type'
template <typename... Types>
concept same_nested_mesh_type =
std::conjunction_v < std::is_same < typename first<Types...>::mesh_type,
typename Types::mesh_type > ... > ;
/// Concept for all Plugins used in Assemblers
template <typename P>
concept PluginLike = requires(P p) {
{std::is_base_of_v<
assembly::PluginBase<typename P::mesh_type, typename P::element_type>,
P>};
};
/// Concept for plugins that can calulculate a force vector
template <typename Plugin>
concept ForceVectorPluginLike = PluginLike<Plugin> && requires(Plugin p) {
p.assemble(
std::add_const_t<cpppetsc::local<typename Plugin::vector_type>>{},
double(0),
std::add_pointer_t<cpppetsc::local<typename Plugin::vector_type>>{});
};
/// Concept for plugins that can calulculate stiffness matrix
template <typename Plugin>
concept StiffnessMatrixPluginLike = PluginLike<Plugin> && requires(Plugin p) {
p.assemble(std::add_const_t<cpppetsc::local<typename Plugin::vector_type>>{},
double(0), std::add_pointer_t<typename Plugin::matrix_type>{});
};
/// Concept to verify that all plugin types are of the same concept
template <typename... Plugins>
concept same_plugin_concept = (StiffnessMatrixPluginLike<Plugins> && ...) ||
(ForceVectorPluginLike<Plugins> && ...);
} // namespace ae108
\ No newline at end of file
......@@ -22,7 +22,12 @@
#include <type_traits>
namespace ae108::assembly {
template <typename Mesh, ElementConcept Element> class AnnotatedElement {
namespace detail {
/**
* @brief A class that is essentially a pair of an ElementView and an Element
* instance.
*/
template <typename Mesh, ElementConcept Element> class AnnotatedElement final {
public:
using ElementView = typename cpppetsc::LocalElementView<Mesh>;
/**
......@@ -41,8 +46,13 @@ public:
private:
ElementView _meshView;
Element _instance;
}; // namespace AnnotatedElement
};
} // namespace detail
/**
* @brief Base class of assembler plugins. Provides element storage and
* construction methods.
*/
template <typename Mesh, ElementConcept Element> class PluginBase {
public:
using mesh_type = Mesh;
......@@ -62,6 +72,17 @@ public:
return std::ranges::subrange(_elements.begin(), _elements.end());
}
/**
* @brief Emplace (i.e. construct directly into the internal container without
* moving) a local Element instance.
*
* @remark Use methods of the mesh to know which elements are local, and their
* vertices.
*
* @param view A view of the mesh element. A copy of this view will be stored.
* @param constructorArguments The parameters that are passed to the Element
* constructor.
*/
using ElementView = typename cpppetsc::LocalElementView<Mesh>;
template <class... Args>
requires(std::is_constructible_v<Element, Args...>) void emplaceElement(
......@@ -70,7 +91,8 @@ public:
std::forward<Args>(constructorArguments)...);
}
using ElementContainer = std::deque<AnnotatedElement<Mesh, Element>>;
private:
using ElementContainer = std::deque<detail::AnnotatedElement<Mesh, Element>>;
ElementContainer _elements;
};
} // namespace ae108::assembly
\ No newline at end of file
......@@ -41,7 +41,7 @@ concept StiffnessAssemblerLike = AssemblerLike<Assembler> &&
requires(const Assembler a) {
typename Assembler::vector_type;
typename Assembler::matrix_type;
a.assembleStiffnessMatrix(
a.assemble(
std::add_const_t<cpppetsc::local<typename Assembler::vector_type>>{},
double(0), std::add_pointer_t<typename Assembler::matrix_type>{});
};
......@@ -50,7 +50,7 @@ template <typename Assembler>
concept ForceVectorAssemblerLike = AssemblerLike<Assembler> &&
requires(const Assembler a) {
typename Assembler::vector_type;
a.assembleForceVector(
a.assemble(
std::add_const_t<cpppetsc::local<typename Assembler::vector_type>>{},
double(0),
std::add_pointer_t<cpppetsc::local<typename Assembler::vector_type>>{});
......
......@@ -184,8 +184,7 @@ NonlinearSolver<Mesh>::computeSolution(
mesh.copyToLocalVector(input, &localDisplacements);
localForces.unwrap().setZero();
forceAssembler.assembleForceVector(localDisplacements, time,
&localForces);
forceAssembler.assemble(localDisplacements, time, &localForces);
mesh.addToGlobalVector(localForces, output);
};
......@@ -195,8 +194,7 @@ NonlinearSolver<Mesh>::computeSolution(
const double time, matrix_type *const output) {
mesh.copyToLocalVector(input, &localDisplacements);
stiffnessAssembler.assembleStiffnessMatrix(localDisplacements, time,
output);
stiffnessAssembler.assemble(localDisplacements, time, output);
output->finalize();
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment