Skip to content

Commit

Permalink
Merge pull request #300 from Exawind/add_vfc_data_structures
Browse files Browse the repository at this point in the history
Added initial data structures and algorithms to support different element types
  • Loading branch information
ddement authored Nov 6, 2024
2 parents 61963ac + afae9f8 commit 0c23929
Show file tree
Hide file tree
Showing 12 changed files with 464 additions and 1 deletion.
9 changes: 8 additions & 1 deletion src/beams/beams.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <Kokkos_Core.hpp>

#include "src/dof_management/freedom_signature.hpp"
#include "src/types.hpp"

namespace openturbine {
Expand All @@ -26,6 +27,8 @@ struct Beams {
Kokkos::View<size_t*> num_nodes_per_element;
Kokkos::View<size_t*> num_qps_per_element;
Kokkos::View<size_t**> node_state_indices; // State row index for each node
Kokkos::View<FreedomSignature**> element_freedom_signature;
Kokkos::View<size_t** [6]> element_freedom_table;

View_3 gravity;

Expand Down Expand Up @@ -95,6 +98,8 @@ struct Beams {
num_nodes_per_element("num_nodes_per_element", num_elems),
num_qps_per_element("num_qps_per_element", num_elems),
node_state_indices("node_state_indices", num_elems, max_elem_nodes),
element_freedom_signature("element_freedom_signature", num_elems, max_elem_nodes),
element_freedom_table("element_freedom_table", num_elems, max_elem_nodes),
gravity("gravity"),
// Node Data
node_x0("node_x0", num_elems, max_elem_nodes),
Expand Down Expand Up @@ -150,7 +155,9 @@ struct Beams {
inertia_matrix_terms("inertia_matrix_terms", num_elems, max_elem_nodes, max_elem_nodes),
// Shape Function data
shape_interp("shape_interp", num_elems, max_elem_nodes, max_elem_qps),
shape_deriv("deriv_interp", num_elems, max_elem_nodes, max_elem_qps) {}
shape_deriv("deriv_interp", num_elems, max_elem_nodes, max_elem_qps) {
Kokkos::deep_copy(element_freedom_signature, FreedomSignature::AllComponents);
}
};

} // namespace openturbine
30 changes: 30 additions & 0 deletions src/dof_management/assemble_node_freedom_allocation_table.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <Kokkos_Core.hpp>

#include "freedom_signature.hpp"

#include "src/beams/beams.hpp"
#include "src/state/state.hpp"

namespace openturbine {

inline void assemble_node_freedom_allocation_table(State& state, const Beams& beams) {
Kokkos::parallel_for(
"Assemble Node Freedom Map Table", 1,
KOKKOS_LAMBDA(size_t) {
for (auto i = 0U; i < beams.num_elems; ++i) {
const auto num_nodes = beams.num_nodes_per_element(i);
for (auto j = 0U; j < num_nodes; ++j) {
const auto node_index = beams.node_state_indices(i, j);
const auto current_signature = state.node_freedom_allocation_table(node_index);
const auto contributed_signature = beams.element_freedom_signature(i, j);
state.node_freedom_allocation_table(node_index) =
current_signature | contributed_signature;
}
}
}
);
}

} // namespace openturbine
25 changes: 25 additions & 0 deletions src/dof_management/compute_node_freedom_map_table.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <Kokkos_Core.hpp>

#include "freedom_signature.hpp"

#include "src/beams/beams.hpp"
#include "src/state/state.hpp"

namespace openturbine {

inline void compute_node_freedom_map_table(State& state) {
Kokkos::parallel_for(
"Compute Node Freedom Map Table", 1,
KOKKOS_LAMBDA(size_t) {
state.node_freedom_map_table(0) = 0U;
for (auto i = 1U; i < state.num_system_nodes; ++i) {
const auto num_dof = count_active_dofs(state.node_freedom_allocation_table(i - 1));
state.node_freedom_map_table(i) = state.node_freedom_map_table(i - 1) + num_dof;
}
}
);
}

} // namespace openturbine
30 changes: 30 additions & 0 deletions src/dof_management/create_element_freedom_table.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <Kokkos_Core.hpp>

#include "freedom_signature.hpp"

#include "src/beams/beams.hpp"
#include "src/state/state.hpp"

namespace openturbine {

inline void create_element_freedom_table(Beams& beams, const State& state) {
Kokkos::parallel_for(
"Create Element Freedom Table", 1,
KOKKOS_LAMBDA(size_t) {
for (auto i = 0U; i < beams.num_elems; ++i) {
const auto num_nodes = beams.num_nodes_per_element(i);
for (auto j = 0U; j < num_nodes; ++j) {
const auto node_index = beams.node_state_indices(i, j);
for (auto k = 0U; k < 6U; ++k) {
beams.element_freedom_table(i, j, k) =
state.node_freedom_map_table(node_index) + k;
}
}
}
}
);
}

} // namespace openturbine
34 changes: 34 additions & 0 deletions src/dof_management/freedom_signature.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include <type_traits>

#include <Kokkos_Core.hpp>

namespace openturbine {

enum class FreedomSignature : std::uint8_t {
AllComponents = 0b00111111,
JustPosition = 0b00111000,
JustRotation = 0b00000111,
NoComponents = 0b00000000
};

KOKKOS_INLINE_FUNCTION
FreedomSignature operator|(FreedomSignature x, FreedomSignature y) {
using T = std::underlying_type_t<FreedomSignature>;
return static_cast<FreedomSignature>(static_cast<T>(x) | static_cast<T>(y));
}

KOKKOS_INLINE_FUNCTION
size_t count_active_dofs(FreedomSignature x) {
using T = std::underlying_type_t<FreedomSignature>;
auto count = 0UL;
constexpr auto zero = T{0};
constexpr auto one = T{1};
for (auto value = static_cast<T>(x); value > zero; value = value >> 1) {
count += value & one;
}
return count;
}

} // namespace openturbine
6 changes: 6 additions & 0 deletions src/state/state.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "src/dof_management/freedom_signature.hpp"
#include "src/types.hpp"

namespace openturbine {
Expand All @@ -10,6 +11,9 @@ namespace openturbine {
struct State {
size_t num_system_nodes; //< Number of system nodes
Kokkos::View<size_t*> ID;
Kokkos::View<FreedomSignature*> node_freedom_allocation_table;
Kokkos::View<size_t*> node_freedom_map_table;

View_Nx7 x0; //< Initial global position/rotation
View_Nx7 x; //< Current global position/rotation
View_Nx6 q_delta; //< Displacement increment
Expand All @@ -23,6 +27,8 @@ struct State {
explicit State(size_t num_system_nodes_)
: num_system_nodes(num_system_nodes_),
ID("ID", num_system_nodes),
node_freedom_allocation_table("node_freedom_allocation_table", num_system_nodes),
node_freedom_map_table("node_freedom_map_table", num_system_nodes),
x0("x0", num_system_nodes),
x("x", num_system_nodes),
q_delta("q_delta", num_system_nodes),
Expand Down
1 change: 1 addition & 0 deletions tests/unit_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_executable(openturbine_unit_tests)

# Add subdirectories for additional components
add_subdirectory(beams)
add_subdirectory(dof_management)
add_subdirectory(math)
add_subdirectory(model)
add_subdirectory(solver)
Expand Down
9 changes: 9 additions & 0 deletions tests/unit_tests/dof_management/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Specify the source files for the unit test executable
target_sources(
openturbine_unit_tests
PRIVATE
test_assemble_node_freedom_allocation_table.cpp
test_compute_node_freedom_map_table.cpp
test_create_element_freedom_table.cpp
test_freedom_signature.cpp
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <gtest/gtest.h>

#include "src/dof_management/assemble_node_freedom_allocation_table.hpp"

namespace openturbine::tests {

TEST(TestAssembleNodeFreedomAllocationTable, OneBeamOneNode) {
auto state = State(1U);

auto beams = Beams(1U, 1U, 1U);
Kokkos::deep_copy(beams.node_state_indices, 0U);
Kokkos::deep_copy(beams.num_nodes_per_element, 1U);

assemble_node_freedom_allocation_table(state, beams);

const auto host_node_freedom_allocation_table =
Kokkos::create_mirror(state.node_freedom_allocation_table);
Kokkos::deep_copy(host_node_freedom_allocation_table, state.node_freedom_allocation_table);

EXPECT_EQ(host_node_freedom_allocation_table(0), FreedomSignature::AllComponents);
}

TEST(TestAssembleNodeFreedomAllocationTable, OneBeamTwoNodes) {
auto state = State(2U);

auto beams = Beams(1U, 2U, 1U);
constexpr auto host_node_state_indices_data = std::array{0UL, 1UL};
const auto host_node_state_indices =
Kokkos::View<size_t[1][2], Kokkos::HostSpace>::const_type(host_node_state_indices_data.data()
);
const auto mirror_node_state_indices = Kokkos::create_mirror(beams.node_state_indices);
Kokkos::deep_copy(mirror_node_state_indices, host_node_state_indices);
Kokkos::deep_copy(beams.node_state_indices, mirror_node_state_indices);
Kokkos::deep_copy(beams.num_nodes_per_element, 2U);

assemble_node_freedom_allocation_table(state, beams);

const auto host_node_freedom_allocation_table =
Kokkos::create_mirror(state.node_freedom_allocation_table);
Kokkos::deep_copy(host_node_freedom_allocation_table, state.node_freedom_allocation_table);

EXPECT_EQ(host_node_freedom_allocation_table(0), FreedomSignature::AllComponents);
EXPECT_EQ(host_node_freedom_allocation_table(1), FreedomSignature::AllComponents);
}

TEST(TestAssembleNodeFreedomAllocationTable, TwoBeamsOneNode) {
auto state = State(2U);

auto beams = Beams(2U, 1U, 1U);
constexpr auto host_node_state_indices_data = std::array{0UL, 1UL};
const auto host_node_state_indices =
Kokkos::View<size_t[2][1], Kokkos::HostSpace>::const_type(host_node_state_indices_data.data()
);
const auto mirror_node_state_indices = Kokkos::create_mirror(beams.node_state_indices);
Kokkos::deep_copy(mirror_node_state_indices, host_node_state_indices);
Kokkos::deep_copy(beams.node_state_indices, mirror_node_state_indices);
Kokkos::deep_copy(beams.num_nodes_per_element, 1U);

assemble_node_freedom_allocation_table(state, beams);

const auto host_node_freedom_allocation_table =
Kokkos::create_mirror(state.node_freedom_allocation_table);
Kokkos::deep_copy(host_node_freedom_allocation_table, state.node_freedom_allocation_table);

EXPECT_EQ(host_node_freedom_allocation_table(0), FreedomSignature::AllComponents);
EXPECT_EQ(host_node_freedom_allocation_table(1), FreedomSignature::AllComponents);
}

} // namespace openturbine::tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include <gtest/gtest.h>

#include "src/dof_management/compute_node_freedom_map_table.hpp"

namespace openturbine::tests {

TEST(TestComputeNodeFreedomMapTable, OneNode) {
auto state = State(1U);
Kokkos::deep_copy(state.node_freedom_allocation_table, FreedomSignature::AllComponents);

compute_node_freedom_map_table(state);

const auto host_node_freedom_map_table = Kokkos::create_mirror(state.node_freedom_map_table);
Kokkos::deep_copy(host_node_freedom_map_table, state.node_freedom_map_table);

EXPECT_EQ(host_node_freedom_map_table(0), 0);
}

TEST(TestComputeNodeFreedomMapTable, FourNodes) {
auto state = State(4U);
constexpr auto host_node_freedom_allocation_table_data = std::array{
FreedomSignature::AllComponents, FreedomSignature::JustPosition,
FreedomSignature::JustRotation, FreedomSignature::NoComponents
};
const auto host_node_freedom_allocation_table =
Kokkos::View<FreedomSignature[4], Kokkos::HostSpace>::const_type(
host_node_freedom_allocation_table_data.data()
);
const auto mirror_node_freedom_allocation_table =
Kokkos::create_mirror(state.node_freedom_allocation_table);
Kokkos::deep_copy(mirror_node_freedom_allocation_table, host_node_freedom_allocation_table);
Kokkos::deep_copy(state.node_freedom_allocation_table, mirror_node_freedom_allocation_table);

compute_node_freedom_map_table(state);

const auto host_node_freedom_map_table = Kokkos::create_mirror(state.node_freedom_map_table);
Kokkos::deep_copy(host_node_freedom_map_table, state.node_freedom_map_table);

EXPECT_EQ(host_node_freedom_map_table(0), 0);
EXPECT_EQ(host_node_freedom_map_table(1), 6);
EXPECT_EQ(host_node_freedom_map_table(2), 9);
EXPECT_EQ(host_node_freedom_map_table(3), 12);
}

} // namespace openturbine::tests
Loading

0 comments on commit 0c23929

Please sign in to comment.