-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Made a few optimizations for running OpenTurbine on GPU. #350
Changes from 3 commits
21ed592
c908e22
f86d219
031d7e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,48 +7,35 @@ | |
|
||
namespace openturbine { | ||
|
||
/** | ||
* @brief Populates Views with beam element data for numerical integration | ||
* | ||
* @param elem The beam element containing node, quadrature, and section data | ||
* @param node_x0 View for initial nodal positions and orientations (size = num_nodes x num_dofs) | ||
* @param qp_weight View for quadrature point weights (size = num_qps) | ||
* @param qp_Mstar View for interpolated mass matrices at quadrature points (size = num_qps x 6 x 6) | ||
* @param qp_Cstar View for interpolated stiffness matrices at quadrature points | ||
* (size = num_qps x 6 x 6) | ||
* @param shape_interp View for shape function interpolation weights (size = num_nodes x num_qps) | ||
* @param shape_deriv View for shape function derivative weights (size = num_nodes x num_qps) | ||
* | ||
* This function transforms element data into a format suitable for numerical integration: | ||
* - Maps node and section positions from [0,1] to [-1,1] | ||
* - Computes shape function weights for interpolation and derivatives using Lagrange polynomials | ||
* - Interpolates section properties (mass and stiffness) at quadrature points using | ||
* linear interpolation | ||
*/ | ||
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> | ||
inline void PopulateElementViews( | ||
const BeamElement& elem, const std::vector<Node>& nodes, T1 node_x0, T2 qp_weight, T3 qp_Mstar, | ||
T4 qp_Cstar, T5 shape_interp, T6 shape_deriv | ||
inline void PopulateNodeX0( | ||
const BeamElement& elem, const std::vector<Node>& nodes, | ||
const Kokkos::View<double* [7], Kokkos::LayoutStride, Kokkos::HostSpace>& node_x0 | ||
) { | ||
// Map node positions from [0,1] to [-1,1] | ||
std::vector<double> node_xi(elem.node_ids.size()); | ||
for (size_t i = 0; i < elem.node_ids.size(); ++i) { | ||
node_xi[i] = 2 * nodes[elem.node_ids[i]].s - 1; | ||
} | ||
|
||
// Populate node initial position and orientation | ||
for (size_t j = 0; j < elem.node_ids.size(); ++j) { | ||
for (size_t k = 0U; k < kLieGroupComponents; ++k) { | ||
node_x0(j, k) = nodes[elem.node_ids[j]].x[k]; | ||
} | ||
} | ||
} | ||
|
||
// Populate quadrature weights | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's keep the comment like so
|
||
inline void PopulateQPWeight( | ||
const BeamElement& elem, | ||
const Kokkos::View<double*, Kokkos::LayoutStride, Kokkos::HostSpace>& qp_weight | ||
) { | ||
for (size_t j = 0; j < elem.quadrature.size(); ++j) { | ||
qp_weight(j) = elem.quadrature[j][1]; | ||
} | ||
} | ||
|
||
inline void PopulateShapeFunctionValues( | ||
const BeamElement& elem, const std::vector<Node>& nodes, | ||
const Kokkos::View<double**, Kokkos::LayoutStride, Kokkos::HostSpace>& shape_interp | ||
) { | ||
std::vector<double> node_xi(elem.node_ids.size()); | ||
for (size_t i = 0; i < elem.node_ids.size(); ++i) { | ||
node_xi[i] = 2 * nodes[elem.node_ids[i]].s - 1; | ||
} | ||
|
||
// Populate shape interpolation and derivative weights (Lagrange polynomial) | ||
std::vector<double> weights; | ||
for (size_t j = 0; j < elem.quadrature.size(); ++j) { | ||
auto qp_xi = elem.quadrature[j][0]; | ||
|
@@ -57,35 +44,82 @@ inline void PopulateElementViews( | |
for (size_t k = 0; k < node_xi.size(); ++k) { | ||
shape_interp(k, j) = weights[k]; | ||
} | ||
} | ||
} | ||
|
||
inline void PopulateShapeFunctionDerivatives( | ||
const BeamElement& elem, const std::vector<Node>& nodes, | ||
const Kokkos::View<double**, Kokkos::LayoutStride, Kokkos::HostSpace>& shape_deriv | ||
) { | ||
std::vector<double> node_xi(elem.node_ids.size()); | ||
for (size_t i = 0; i < elem.node_ids.size(); ++i) { | ||
node_xi[i] = 2 * nodes[elem.node_ids[i]].s - 1; | ||
} | ||
|
||
std::vector<double> weights; | ||
for (size_t j = 0; j < elem.quadrature.size(); ++j) { | ||
auto qp_xi = elem.quadrature[j][0]; | ||
|
||
LagrangePolynomialDerivWeights(qp_xi, node_xi, weights); | ||
for (size_t k = 0; k < node_xi.size(); ++k) { | ||
shape_deriv(k, j) = weights[k]; | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could remove the duplicate code here (Lines 30-68) by doing the following. There might be more optimization possible by combining the shape + shape deriv functions into one however I suppose you wanted to keep them separate.
|
||
|
||
// Map section positions from [0,1] to [-1,1] | ||
inline void PopulateQPMstar( | ||
const BeamElement& elem, | ||
const Kokkos::View<double* [6][6], Kokkos::LayoutStride, Kokkos::HostSpace>& qp_Mstar | ||
) { | ||
std::vector<double> weights(elem.sections.size()); | ||
std::vector<double> section_xi(elem.sections.size()); | ||
for (size_t i = 0; i < elem.sections.size(); ++i) { | ||
section_xi[i] = 2 * elem.sections[i].position - 1; | ||
} | ||
|
||
// Populate section mass and stiffness matrices at quadrature points by | ||
// linearly interpolating between section values | ||
Kokkos::deep_copy(qp_Mstar, 0.); | ||
Kokkos::deep_copy(qp_Cstar, 0.); | ||
for (size_t i = 0; i < elem.quadrature.size(); ++i) { | ||
auto qp_xi = elem.quadrature[i][0]; | ||
LinearInterpWeights(qp_xi, section_xi, weights); | ||
for (size_t m = 0; m < 6; ++m) { | ||
for (size_t n = 0; n < 6; ++n) { | ||
qp_Mstar(i, m, n) = 0.; | ||
} | ||
} | ||
for (size_t j = 0; j < section_xi.size(); ++j) { | ||
for (size_t m = 0; m < 6; ++m) { | ||
for (size_t n = 0; n < 6; ++n) { | ||
qp_Mstar(i, m, n) += elem.sections[j].M_star[m][n] * weights[j]; | ||
qp_Cstar(i, m, n) += elem.sections[j].C_star[m][n] * weights[j]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
inline void PopulateQPCstar( | ||
const BeamElement& elem, | ||
const Kokkos::View<double* [6][6], Kokkos::LayoutStride, Kokkos::HostSpace>& qp_Cstar | ||
) { | ||
std::vector<double> weights(elem.sections.size()); | ||
std::vector<double> section_xi(elem.sections.size()); | ||
for (size_t i = 0; i < elem.sections.size(); ++i) { | ||
section_xi[i] = 2 * elem.sections[i].position - 1; | ||
} | ||
|
||
for (size_t i = 0; i < elem.quadrature.size(); ++i) { | ||
auto qp_xi = elem.quadrature[i][0]; | ||
LinearInterpWeights(qp_xi, section_xi, weights); | ||
for (size_t m = 0; m < 6; ++m) { | ||
for (size_t n = 0; n < 6; ++n) { | ||
qp_Cstar(i, m, n) = 0.; | ||
} | ||
} | ||
for (size_t j = 0; j < section_xi.size(); ++j) { | ||
for (size_t m = 0; m < 6; ++m) { | ||
for (size_t n = 0; n < 6; ++n) { | ||
qp_Cstar(i, m, n) += elem.sections[j].C_star[m][n] * weights[j]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On a similar vein to my previous comment, we could modularize as follows to remove redundant code in M* and C* population. And I wonder if we could write a lambda-like function to consolidate the sectional matrix creation logic since they look awfully similar -- I leave that to your judgement.
|
||
} // namespace openturbine |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose the following readability improvement: