134 lines
3.7 KiB
C++
134 lines
3.7 KiB
C++
#include <fesa/fem/dof_manager.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <cstddef>
|
|
#include <stdexcept>
|
|
|
|
namespace fesa::fem {
|
|
|
|
void DofManager::define_node_dofs(core::NodeId node_id, std::vector<model::DofComponent> components)
|
|
{
|
|
for (const auto component : components) {
|
|
DofKey key{node_id, component};
|
|
if (find_record(key) == records_.end()) {
|
|
records_.push_back({key});
|
|
}
|
|
}
|
|
}
|
|
|
|
void DofManager::apply_boundary_condition(const model::BoundaryCondition& bc)
|
|
{
|
|
auto record = find_record({bc.node_id(), bc.component()});
|
|
if (record == records_.end()) {
|
|
throw std::invalid_argument("boundary condition references undefined dof");
|
|
}
|
|
record->constrained = true;
|
|
}
|
|
|
|
void DofManager::number_equations()
|
|
{
|
|
std::sort(records_.begin(), records_.end(), [](const Record& lhs, const Record& rhs) {
|
|
if (lhs.key.node_id.value != rhs.key.node_id.value) {
|
|
return lhs.key.node_id.value < rhs.key.node_id.value;
|
|
}
|
|
return static_cast<int>(lhs.key.component) < static_cast<int>(rhs.key.component);
|
|
});
|
|
|
|
int free_id = 0;
|
|
for (int equation_id = 0; equation_id < static_cast<int>(records_.size()); ++equation_id) {
|
|
records_[equation_id].equation_id = equation_id;
|
|
if (records_[equation_id].constrained) {
|
|
records_[equation_id].free_equation_id = std::nullopt;
|
|
} else {
|
|
records_[equation_id].free_equation_id = free_id++;
|
|
}
|
|
}
|
|
|
|
sparse_pattern_.clear();
|
|
for (int row = 0; row < free_id; ++row) {
|
|
for (int column = 0; column < free_id; ++column) {
|
|
sparse_pattern_.push_back({row, column});
|
|
}
|
|
}
|
|
}
|
|
|
|
int DofManager::total_dof_count() const
|
|
{
|
|
return static_cast<int>(records_.size());
|
|
}
|
|
|
|
int DofManager::free_dof_count() const
|
|
{
|
|
return static_cast<int>(
|
|
std::count_if(records_.begin(), records_.end(), [](const Record& record) {
|
|
return !record.constrained;
|
|
})
|
|
);
|
|
}
|
|
|
|
int DofManager::constrained_dof_count() const
|
|
{
|
|
return total_dof_count() - free_dof_count();
|
|
}
|
|
|
|
bool DofManager::is_constrained(DofKey key) const
|
|
{
|
|
return require_record(key).constrained;
|
|
}
|
|
|
|
int DofManager::equation_id(DofKey key) const
|
|
{
|
|
return require_record(key).equation_id;
|
|
}
|
|
|
|
std::optional<int> DofManager::free_equation_id(DofKey key) const
|
|
{
|
|
return require_record(key).free_equation_id;
|
|
}
|
|
|
|
std::vector<double> DofManager::expand_free_vector(const std::vector<double>& free_values) const
|
|
{
|
|
if (free_values.size() != static_cast<std::size_t>(free_dof_count())) {
|
|
throw std::invalid_argument("free vector size does not match dof manager");
|
|
}
|
|
|
|
std::vector<double> full(records_.size(), 0.0);
|
|
for (const auto& record : records_) {
|
|
if (record.free_equation_id.has_value()) {
|
|
full[static_cast<std::size_t>(record.equation_id)] =
|
|
free_values[static_cast<std::size_t>(*record.free_equation_id)];
|
|
}
|
|
}
|
|
return full;
|
|
}
|
|
|
|
const std::vector<std::pair<int, int>>& DofManager::sparse_pattern() const
|
|
{
|
|
return sparse_pattern_;
|
|
}
|
|
|
|
std::vector<DofManager::Record>::iterator DofManager::find_record(DofKey key)
|
|
{
|
|
return std::find_if(records_.begin(), records_.end(), [key](const Record& record) {
|
|
return record.key == key;
|
|
});
|
|
}
|
|
|
|
std::vector<DofManager::Record>::const_iterator DofManager::find_record(DofKey key) const
|
|
{
|
|
return std::find_if(records_.begin(), records_.end(), [key](const Record& record) {
|
|
return record.key == key;
|
|
});
|
|
}
|
|
|
|
const DofManager::Record& DofManager::require_record(DofKey key) const
|
|
{
|
|
const auto record = find_record(key);
|
|
if (record == records_.end()) {
|
|
throw std::invalid_argument("dof is not defined");
|
|
}
|
|
return *record;
|
|
}
|
|
|
|
} // namespace fesa::fem
|