/home/runner/work/kynema/kynema/kynema/src/constraints/constraints.hpp Source File

Kynema API: /home/runner/work/kynema/kynema/kynema/src/constraints/constraints.hpp Source File
Kynema API
A flexible multibody structural dynamics code for wind turbines
Loading...
Searching...
No Matches
constraints.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <numeric>
5#include <ranges>
6#include <span>
7#include <vector>
8
9#include <Kokkos_Core.hpp>
10
11#include "constraint.hpp"
13#include "model/node.hpp"
14
15namespace kynema {
16
28template <typename DeviceType>
30 template <typename ValueType>
31 using View = Kokkos::View<ValueType, DeviceType>;
32 template <typename ValueType>
34
35 size_t num_constraints; //< Total number of constraints in the system
36 size_t num_dofs; //< Total number of degrees of freedom controlled by constraints
37
38 // Constraint properties
39 View<constraints::ConstraintType*> type; //< Type of each constraint
40 std::vector<double*> control_signal; //< Control signal for each constraint
41 View<size_t*> base_node_index; //< Index of the base node for each constraint
42 View<size_t*> target_node_index; //< Index of the target node for each constraint
43
44 // DOF management
52
53 // Geometric configuration
54 View<double* [3]> X0; //< Initial relative position
55 View<double* [3][3]> axes; //< Rotation axes
56
57 // State variables
58 View<double* [7]> input; //< Current state input
59 View<double* [3]> output; //< Current state output
61
62 // Host mirrors for CPU access
65
66 // System contributions
75
76 explicit Constraints(
77 std::span<const constraints::Constraint> constraints, std::span<const Node> nodes
78 )
79 : num_constraints{constraints.size()},
81 std::begin(constraints), std::end(constraints), 0U, std::plus{},
82 [](auto c) {
83 return NumRowsForConstraint(c.type);
84 }
85 )},
86 type(Kokkos::view_alloc("type", Kokkos::WithoutInitializing), num_constraints),
87 control_signal(num_constraints),
88 base_node_index(
89 Kokkos::view_alloc("base_node_index", Kokkos::WithoutInitializing), num_constraints
90 ),
91 target_node_index(
92 Kokkos::view_alloc("target_node_index", Kokkos::WithoutInitializing), num_constraints
93 ),
94 row_range(Kokkos::view_alloc("row_range", Kokkos::WithoutInitializing), num_constraints),
95 base_node_freedom_signature(
96 Kokkos::view_alloc("base_node_freedom_signature", Kokkos::WithoutInitializing),
97 num_constraints
98 ),
99 target_node_freedom_signature(
100 Kokkos::view_alloc("target_node_freedom_signature", Kokkos::WithoutInitializing),
101 num_constraints
102 ),
103 base_active_dofs(
104 Kokkos::view_alloc("base_active_dofs", Kokkos::WithoutInitializing), num_constraints
105 ),
106 target_active_dofs(
107 Kokkos::view_alloc("target_active_dofs", Kokkos::WithoutInitializing), num_constraints
108 ),
109 base_node_freedom_table(
110 Kokkos::view_alloc("base_node_freedom_table", Kokkos::WithoutInitializing),
111 num_constraints
112 ),
113 target_node_freedom_table(
114 Kokkos::view_alloc("target_node_freedom_table", Kokkos::WithoutInitializing),
115 num_constraints
116 ),
117 X0(Kokkos::view_alloc("X0", Kokkos::WithoutInitializing), num_constraints),
118 axes(Kokkos::view_alloc("axes", Kokkos::WithoutInitializing), num_constraints),
119 input(Kokkos::view_alloc("inputs", Kokkos::WithoutInitializing), num_constraints),
120 output(Kokkos::view_alloc("outputs", Kokkos::WithoutInitializing), num_constraints),
121 lambda(Kokkos::view_alloc("lambda", Kokkos::WithoutInitializing), num_constraints),
122 host_input(Kokkos::view_alloc("host_input", Kokkos::WithoutInitializing), num_constraints),
123 host_output(
124 Kokkos::view_alloc("host_output", Kokkos::WithoutInitializing), num_constraints
125 ),
126 residual_terms(
127 Kokkos::view_alloc("residual_terms", Kokkos::WithoutInitializing), num_constraints
128 ),
129 base_lambda_residual_terms(
130 Kokkos::view_alloc("base_lambda_residual_terms", Kokkos::WithoutInitializing),
131 num_constraints
132 ),
133 target_lambda_residual_terms(
134 Kokkos::view_alloc("target_lambda_residual_terms", Kokkos::WithoutInitializing),
135 num_constraints
136 ),
137 system_residual_terms(
138 Kokkos::view_alloc("system_residual_terms", Kokkos::WithoutInitializing),
139 num_constraints
140 ),
141 base_gradient_terms(
142 Kokkos::view_alloc("base_gradient_terms", Kokkos::WithoutInitializing), num_constraints
143 ),
144 target_gradient_terms(
145 Kokkos::view_alloc("target_gradient_terms", Kokkos::WithoutInitializing),
146 num_constraints
147 ),
148 base_gradient_transpose_terms(
149 Kokkos::view_alloc("base_gradient_transpose_terms", Kokkos::WithoutInitializing),
150 num_constraints
151 ),
152 target_gradient_transpose_terms(
153 Kokkos::view_alloc("target_gradient_transpose_terms", Kokkos::WithoutInitializing),
154 num_constraints
155 ) {
156 using Kokkos::ALL;
157 using Kokkos::create_mirror_view;
158 using Kokkos::deep_copy;
159 using Kokkos::subview;
160 using Kokkos::WithoutInitializing;
161
162 auto host_type = create_mirror_view(WithoutInitializing, type);
163 auto host_row_range = create_mirror_view(WithoutInitializing, row_range);
164 auto host_base_node_index = create_mirror_view(WithoutInitializing, base_node_index);
165 auto host_target_node_index = create_mirror_view(WithoutInitializing, target_node_index);
166 auto host_base_freedom =
167 create_mirror_view(WithoutInitializing, base_node_freedom_signature);
168 auto host_target_freedom =
169 create_mirror_view(WithoutInitializing, target_node_freedom_signature);
170 auto host_base_active_dofs = create_mirror_view(WithoutInitializing, base_active_dofs);
171 auto host_target_active_dofs = create_mirror_view(WithoutInitializing, target_active_dofs);
172 auto host_X0 = create_mirror_view(WithoutInitializing, X0);
173 auto host_axes = create_mirror_view(WithoutInitializing, axes);
174
175 auto start_row = size_t{0U};
176 for (auto constraint : std::views::iota(0U, num_constraints)) {
177 const auto& c = constraints[constraint];
178 const auto base_node_id = c.node_ids[0];
179 const auto target_node_id = c.node_ids[1];
180
181 // Set constraint properties
182 host_type(constraint) = c.type;
183
184 // Set the freedom signature from the constraint types
187 host_base_freedom(constraint) = dof::FreedomSignature::NoComponents;
188 host_target_freedom(constraint) = dof::FreedomSignature::AllComponents;
189
190 host_base_active_dofs(constraint) = 0UL;
191 host_target_active_dofs(constraint) = 6UL;
192 } else if (c.type == constraints::ConstraintType::RigidJoint ||
195 host_base_freedom(constraint) = dof::FreedomSignature::AllComponents;
196 host_target_freedom(constraint) = dof::FreedomSignature::AllComponents;
197
198 host_base_active_dofs(constraint) = 6UL;
199 host_target_active_dofs(constraint) = 6UL;
200 } else if (c.type == constraints::ConstraintType::FixedBC3DOFs ||
202 host_base_freedom(constraint) = dof::FreedomSignature::NoComponents;
203 host_target_freedom(constraint) = dof::FreedomSignature::JustPosition;
204
205 host_base_active_dofs(constraint) = 0UL;
206 host_target_active_dofs(constraint) = 3UL;
208 host_base_freedom(constraint) = dof::FreedomSignature::AllComponents;
209 host_target_freedom(constraint) = dof::FreedomSignature::JustPosition;
210
211 host_base_active_dofs(constraint) = 6UL;
212 host_target_active_dofs(constraint) = 3UL;
213 }
214
215 control_signal[constraint] = c.control;
216
217 // Set base and target node index
218 host_base_node_index(constraint) = base_node_id;
219 host_target_node_index(constraint) = target_node_id;
220
221 // Set constraint rows
222 auto n_rows = NumRowsForConstraint(host_type(constraint));
223 host_row_range(constraint) = Kokkos::make_pair(start_row, start_row + n_rows);
224 start_row += n_rows;
225
226 // Calculate initial relative position (X0)
227 std::array<double, 3> x0{0., 0., 0.};
230 x0 = CalculateX0(c, nodes[target_node_id], nodes[base_node_id]);
231 }
232 for (auto component : std::views::iota(0U, 3U)) {
233 host_X0(constraint, component) = x0[component];
234 }
235
236 // Calculate rotation axes
237 const auto rotation_matrix = CalculateAxes(c, x0);
238 for (auto component_1 : std::views::iota(0U, 3U)) {
239 for (auto component_2 : std::views::iota(0U, 3U)) {
240 host_axes(constraint, component_1, component_2) =
241 rotation_matrix[component_1][component_2];
242 }
243 }
244
245 // Initialize displacement to provided displacement if prescribed BC
248 for (auto component : std::views::iota(0U, 7U)) {
249 host_input(constraint, component) = c.initial_displacement[component];
250 }
251 }
252 }
253
254 deep_copy(type, host_type);
255 deep_copy(row_range, host_row_range);
256 deep_copy(base_node_index, host_base_node_index);
257 deep_copy(target_node_index, host_target_node_index);
258 deep_copy(base_node_freedom_signature, host_base_freedom);
259 deep_copy(target_node_freedom_signature, host_target_freedom);
260 deep_copy(base_active_dofs, host_base_active_dofs);
261 deep_copy(target_active_dofs, host_target_active_dofs);
262 deep_copy(X0, host_X0);
263 deep_copy(axes, host_axes);
264
265 deep_copy(subview(this->input, ALL, 3), 1.);
266 }
267
269 static std::array<double, 3> CalculateX0(
270 const constraints::Constraint& constraint, const Node& target_node, const Node& base_node
271 ) {
272 std::array<double, 3> x0{0., 0., 0.};
273 // Set X0 to the prescribed displacement for fixed and prescribed BCs i.e. constraints
274 // with 1 node
275 if (GetNumberOfNodes(constraint.type) == 1) {
276 x0[0] = target_node.x0[0] - constraint.axis_vector[0];
277 x0[1] = target_node.x0[1] - constraint.axis_vector[1];
278 x0[2] = target_node.x0[2] - constraint.axis_vector[2];
279 return x0;
280 }
281
282 // Default: set X0 to the relative position between nodes
283 x0[0] = target_node.x0[0] - base_node.x0[0];
284 x0[1] = target_node.x0[1] - base_node.x0[1];
285 x0[2] = target_node.x0[2] - base_node.x0[2];
286 return x0;
287 }
288
290 static std::array<std::array<double, 3>, 3> CalculateAxes(
291 const constraints::Constraint& constraint, const std::array<double, 3>& x0
292 ) {
293 std::array<std::array<double, 3>, 3> rotation_matrix{};
295 constexpr std::array<double, 3> x = {1., 0., 0.};
296 const std::array<double, 3> x_hat = math::Norm(constraint.axis_vector) != 0.
297 ? math::UnitVector(constraint.axis_vector)
298 : math::UnitVector(x0);
299
300 // Create rotation matrix to rotate x to match vector
301 const auto cross_product = math::CrossProduct(x, x_hat);
302 const auto dot_product = math::DotProduct(x_hat, x);
303 const auto k = 1. / (1. + dot_product);
304
305 // Set orthogonal unit vectors from the rotation matrix
309
313
317
318 return rotation_matrix;
319 }
320
321 // Set rotation_matrix to the unit vector of the constraint axis for rotation control
323 const auto unit_vector = math::UnitVector(constraint.axis_vector);
324 rotation_matrix[0][0] = unit_vector[0];
325 rotation_matrix[0][1] = unit_vector[1];
326 rotation_matrix[0][2] = unit_vector[2];
327 return rotation_matrix;
328 }
329
330 // If not a revolute/hinge joint, set rotation_matrix to the input vector
331 rotation_matrix[0][0] = constraint.axis_vector[0];
332 rotation_matrix[0][1] = constraint.axis_vector[1];
333 rotation_matrix[0][2] = constraint.axis_vector[2];
334 return rotation_matrix;
335 }
336
338 template <typename ArrayType>
339 void UpdateDisplacement(size_t constraint_id, const ArrayType& disp) const {
340 for (auto component : std::views::iota(0U, 7U)) {
341 host_input(constraint_id, component) = disp[component];
342 }
343 }
344
346 void UpdateViews() {
347 for (auto constraint : std::views::iota(0U, this->num_constraints)) {
348 if (control_signal[constraint] != nullptr) {
349 host_input(constraint, 0) = *control_signal[constraint];
350 }
351 }
352 Kokkos::deep_copy(this->input, host_input);
353 }
354};
355
356} // namespace kynema
KOKKOS_INLINE_FUNCTION constexpr size_t NumRowsForConstraint(ConstraintType type)
Returns the number of degrees of freedom prescribed/fixed by the constraint type.
Definition constraint_type.hpp:63
KOKKOS_INLINE_FUNCTION void CrossProduct(const VectorType &a, const VectorType &b, const VectorType &c)
Calculate the cross product between two vector views.
Definition vector_operations.hpp:40
KOKKOS_INLINE_FUNCTION double DotProduct(const AVectorType &a, const BVectorType &b)
Calculate the dot product between two vector views.
Definition vector_operations.hpp:25
constexpr double Norm(const std::array< double, 3 > &v)
Calculate the norm of a given vector.
Definition vector_operations.hpp:60
constexpr std::array< double, 3 > UnitVector(const std::array< double, 3 > &v)
UnitVector returns the unit vector of the given vector.
Definition vector_operations.hpp:65
Definition calculate_constraint_output.hpp:8
Container class for managing multiple constraints in a simulation.
Definition constraints.hpp:29
View< size_t * > target_active_dofs
Definition constraints.hpp:49
View< size_t * > base_node_index
Definition constraints.hpp:41
View< double *[6]> lambda
Definition constraints.hpp:60
View< double *[3]> output
Definition constraints.hpp:59
View< dof::FreedomSignature * > base_node_freedom_signature
Definition constraints.hpp:46
Kokkos::View< ValueType, DeviceType > View
Definition constraints.hpp:31
static std::array< double, 3 > CalculateX0(const constraints::Constraint &constraint, const Node &target_node, const Node &base_node)
Calculates the initial relative position (X0) based on constraint type and nodes.
Definition constraints.hpp:269
std::vector< double * > control_signal
Definition constraints.hpp:40
typename View< ValueType >::const_type ConstView
Definition constraints.hpp:33
void UpdateDisplacement(size_t constraint_id, const ArrayType &disp) const
Sets the new displacement for the given constraint.
Definition constraints.hpp:339
View< size_t * > target_node_index
Definition constraints.hpp:42
View< double *[6]> residual_terms
Definition constraints.hpp:67
View< double *[6][6]> base_gradient_transpose_terms
Definition constraints.hpp:73
View< double *[6]> base_lambda_residual_terms
Definition constraints.hpp:68
View< double *[7]> input
Definition constraints.hpp:58
View< double *[6]> system_residual_terms
Definition constraints.hpp:70
View< double *[6][6]> base_gradient_terms
Definition constraints.hpp:71
void UpdateViews()
Transfers new prescribed displacements and control signals to Views.
Definition constraints.hpp:346
View< double *[3]> X0
Definition constraints.hpp:54
View< Kokkos::pair< size_t, size_t > * > row_range
Definition constraints.hpp:45
View< dof::FreedomSignature * > target_node_freedom_signature
Definition constraints.hpp:47
View< size_t *[6]> base_node_freedom_table
Definition constraints.hpp:50
View< double *[3][3]> axes
Definition constraints.hpp:55
View< double *[6][6]> target_gradient_terms
Definition constraints.hpp:72
size_t num_constraints
Definition constraints.hpp:35
static std::array< std::array< double, 3 >, 3 > CalculateAxes(const constraints::Constraint &constraint, const std::array< double, 3 > &x0)
Calculates the rotation axes for a constraint based on its type and configuration.
Definition constraints.hpp:290
View< double *[6][6]> target_gradient_transpose_terms
Definition constraints.hpp:74
View< constraints::ConstraintType * > type
Definition constraints.hpp:39
View< double *[6]> target_lambda_residual_terms
Definition constraints.hpp:69
Constraints(std::span< const constraints::Constraint > constraints, std::span< const Node > nodes)
Definition constraints.hpp:76
View< double *[3]>::HostMirror host_output
Definition constraints.hpp:64
size_t num_dofs
Definition constraints.hpp:36
View< size_t * > base_active_dofs
Definition constraints.hpp:48
View< size_t *[6]> target_node_freedom_table
Definition constraints.hpp:51
View< double *[7]>::HostMirror host_input
Definition constraints.hpp:63
Represents a node in the finite element model.
Definition node.hpp:26
Defines a constraint between two nodes or enforces a boundary condition at a single node.
Definition constraint.hpp:17
ConstraintType type
Type of constraint.
Definition constraint.hpp:19
std::array< double, 3 > axis_vector
Vector for rotation/control axis.
Definition constraint.hpp:21