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

Kynema API: /home/runner/work/kynema-fmb/kynema-fmb/kynema-fmb/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_fmb {
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 (
196 ) {
197 host_base_freedom(constraint) = dof::FreedomSignature::AllComponents;
198 host_target_freedom(constraint) = dof::FreedomSignature::AllComponents;
199
200 host_base_active_dofs(constraint) = 6UL;
201 host_target_active_dofs(constraint) = 6UL;
202 } else if (
205 ) {
206 host_base_freedom(constraint) = dof::FreedomSignature::NoComponents;
207 host_target_freedom(constraint) = dof::FreedomSignature::JustPosition;
208
209 host_base_active_dofs(constraint) = 0UL;
210 host_target_active_dofs(constraint) = 3UL;
212 host_base_freedom(constraint) = dof::FreedomSignature::AllComponents;
213 host_target_freedom(constraint) = dof::FreedomSignature::JustPosition;
214
215 host_base_active_dofs(constraint) = 6UL;
216 host_target_active_dofs(constraint) = 3UL;
217 }
218
219 control_signal[constraint] = c.control;
220
221 // Set base and target node index
222 host_base_node_index(constraint) = base_node_id;
223 host_target_node_index(constraint) = target_node_id;
224
225 // Set constraint rows
226 auto n_rows = NumRowsForConstraint(host_type(constraint));
227 host_row_range(constraint) = Kokkos::make_pair(start_row, start_row + n_rows);
228 start_row += n_rows;
229
230 // Calculate initial relative position (X0)
231 std::array<double, 3> x0{0., 0., 0.};
234 x0 = CalculateX0(c, nodes[target_node_id], nodes[base_node_id]);
235 }
236 for (auto component : std::views::iota(0U, 3U)) {
237 host_X0(constraint, component) = x0[component];
238 }
239
240 // Calculate rotation axes
241 const auto rotation_matrix = CalculateAxes(c, x0);
242 for (auto component_1 : std::views::iota(0U, 3U)) {
243 for (auto component_2 : std::views::iota(0U, 3U)) {
244 host_axes(constraint, component_1, component_2) =
245 rotation_matrix[component_1][component_2];
246 }
247 }
248
249 // Initialize displacement to provided displacement if prescribed BC
252 for (auto component : std::views::iota(0U, 7U)) {
253 host_input(constraint, component) = c.initial_displacement[component];
254 }
255 }
256 }
257
258 deep_copy(type, host_type);
259 deep_copy(row_range, host_row_range);
260 deep_copy(base_node_index, host_base_node_index);
261 deep_copy(target_node_index, host_target_node_index);
262 deep_copy(base_node_freedom_signature, host_base_freedom);
263 deep_copy(target_node_freedom_signature, host_target_freedom);
264 deep_copy(base_active_dofs, host_base_active_dofs);
265 deep_copy(target_active_dofs, host_target_active_dofs);
266 deep_copy(X0, host_X0);
267 deep_copy(axes, host_axes);
268
269 deep_copy(subview(this->input, ALL, 3), 1.);
270 }
271
273 static std::array<double, 3> CalculateX0(
274 const constraints::Constraint& constraint, const Node& target_node, const Node& base_node
275 ) {
276 std::array<double, 3> x0{0., 0., 0.};
277 // Set X0 to the prescribed displacement for fixed and prescribed BCs i.e. constraints
278 // with 1 node
279 if (GetNumberOfNodes(constraint.type) == 1) {
280 x0[0] = target_node.x0[0] - constraint.axis_vector[0];
281 x0[1] = target_node.x0[1] - constraint.axis_vector[1];
282 x0[2] = target_node.x0[2] - constraint.axis_vector[2];
283 return x0;
284 }
285
286 // Default: set X0 to the relative position between nodes
287 x0[0] = target_node.x0[0] - base_node.x0[0];
288 x0[1] = target_node.x0[1] - base_node.x0[1];
289 x0[2] = target_node.x0[2] - base_node.x0[2];
290 return x0;
291 }
292
294 static std::array<std::array<double, 3>, 3> CalculateAxes(
295 const constraints::Constraint& constraint, const std::array<double, 3>& x0
296 ) {
297 std::array<std::array<double, 3>, 3> rotation_matrix{};
299 const auto x = Eigen::Matrix<double, 3, 1>::Unit(0);
300 const auto axis_vector = Eigen::Matrix<double, 3, 1>(constraint.axis_vector.data());
301 const auto x_hat = (axis_vector.norm() != 0.)
302 ? axis_vector.normalized()
303 : Eigen::Matrix<double, 3, 1>(x0.data()).normalized();
304
305 // Create rotation matrix to rotate x to match vector
306 const auto cross_product = x.cross(x_hat);
307 const auto dot_product = x_hat.dot(x);
308 const auto k = 1. / (1. + dot_product);
309
310 // Set orthogonal unit vectors from the rotation matrix
314
318
322
323 return rotation_matrix;
324 }
325
326 // Set rotation_matrix to the unit vector of the constraint axis for rotation control
328 const auto unit_vector =
329 Eigen::Matrix<double, 3, 1>(constraint.axis_vector.data()).normalized();
330 rotation_matrix[0][0] = unit_vector(0);
331 rotation_matrix[0][1] = unit_vector(1);
332 rotation_matrix[0][2] = unit_vector(2);
333 return rotation_matrix;
334 }
335
336 // If not a revolute/hinge joint, set rotation_matrix to the input vector
337 rotation_matrix[0][0] = constraint.axis_vector[0];
338 rotation_matrix[0][1] = constraint.axis_vector[1];
339 rotation_matrix[0][2] = constraint.axis_vector[2];
340 return rotation_matrix;
341 }
342
344 template <typename ArrayType>
345 void UpdateDisplacement(size_t constraint_id, const ArrayType& disp) const {
346 for (auto component : std::views::iota(0U, 7U)) {
347 host_input(constraint_id, component) = disp[component];
348 }
349 }
350
352 void UpdateViews() {
353 for (auto constraint : std::views::iota(0U, this->num_constraints)) {
354 if (control_signal[constraint] != nullptr) {
355 host_input(constraint, 0) = *control_signal[constraint];
356 }
357 }
358 Kokkos::deep_copy(this->input, host_input);
359 }
360};
361
362} // namespace kynema_fmb
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
Definition calculate_constraint_output.hpp:8
Container class for managing multiple constraints in a simulation.
Definition constraints.hpp:29
View< double *[3]>::HostMirror host_output
Definition constraints.hpp:64
View< double *[6]> system_residual_terms
Definition constraints.hpp:70
size_t num_dofs
Definition constraints.hpp:36
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:345
View< size_t * > target_active_dofs
Definition constraints.hpp:49
View< double *[6][6]> base_gradient_terms
Definition constraints.hpp:71
std::vector< double * > control_signal
Definition constraints.hpp:40
View< double *[3]> X0
Definition constraints.hpp:54
View< double *[6]> residual_terms
Definition constraints.hpp:67
View< dof::FreedomSignature * > target_node_freedom_signature
Definition constraints.hpp:47
View< double *[6]> lambda
Definition constraints.hpp:60
View< double *[7]> input
Definition constraints.hpp:58
View< size_t * > target_node_index
Definition constraints.hpp:42
View< dof::FreedomSignature * > base_node_freedom_signature
Definition constraints.hpp:46
View< double *[3][3]> axes
Definition constraints.hpp:55
void UpdateViews()
Transfers new prescribed displacements and control signals to Views.
Definition constraints.hpp:352
View< size_t *[6]> target_node_freedom_table
Definition constraints.hpp:51
View< constraints::ConstraintType * > type
Definition constraints.hpp:39
View< size_t * > base_node_index
Definition constraints.hpp:41
Constraints(std::span< const constraints::Constraint > constraints, std::span< const Node > nodes)
Definition constraints.hpp:76
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:294
View< double *[6][6]> base_gradient_transpose_terms
Definition constraints.hpp:73
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:273
View< double *[6][6]> target_gradient_transpose_terms
Definition constraints.hpp:74
View< double *[6]> target_lambda_residual_terms
Definition constraints.hpp:69
View< size_t * > base_active_dofs
Definition constraints.hpp:48
View< double *[6][6]> target_gradient_terms
Definition constraints.hpp:72
View< double *[6]> base_lambda_residual_terms
Definition constraints.hpp:68
View< double *[7]>::HostMirror host_input
Definition constraints.hpp:63
View< size_t *[6]> base_node_freedom_table
Definition constraints.hpp:50
size_t num_constraints
Definition constraints.hpp:35
Kokkos::View< ValueType, DeviceType > View
Definition constraints.hpp:31
View< Kokkos::pair< size_t, size_t > * > row_range
Definition constraints.hpp:45
View< double *[3]> output
Definition constraints.hpp:59
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
std::array< double, 3 > axis_vector
Vector for rotation/control axis.
Definition constraint.hpp:21
ConstraintType type
Type of constraint.
Definition constraint.hpp:19