Skip to content

Commit 264ee02

Browse files
authored
Merge pull request #7 from Fuad-HH/stiffnessMatrixLoad
Element Stiffness Matrix Calculation
2 parents dadfc43 + 0ac526d commit 264ee02

12 files changed

Lines changed: 552 additions & 8 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ build-*
88
*.o
99
*.obj
1010

11+
*.sh
1112
# Precompiled Headers
1213
*.gch
1314
*.pch

openmp-scorec-config.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ cmake -B build -S . \
33
-DCMAKE_INSTALL_PREFIX=build/install \
44
-DCMAKE_CXX_COMPILER=`which mpicxx` \
55
-DCMAKE_C_COMPILER=`which mpicc` \
6-
-DKokkos_ROOT=../assignment2_deps/kokkos/build/install/ \
6+
-DKokkos_ROOT=/lore/paudea/build/ADA89/kokkos/install/ \
77
-DAssignment_ENABLE_CUDA=OFF \
88
-DCatch2_ROOT=/lore/hasanm4/practice_projects/advanced_comp/assignment2_deps/Catch2/build/install/
99

src/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@
33
set(Assignment2_SOURCES
44
main.cpp
55
Mesh.cpp
6+
CalculateStiffnessMatrixAndLoadVector.cpp
67
StiffnessMatrix.cpp
78
MatVecMult.cpp
89
)
910

1011
set (Assignment2_HEADERS
1112
Mesh.h
13+
Element.hpp
14+
TriElement.hpp
15+
QuadElement.hpp
16+
CalculateStiffnessMatrixAndLoadVector.hpp
1217
StriffnessMatrix.h
1318
MatVecMult.h
1419
)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include "CalculateStiffnessMatrixAndLoadVector.hpp"
2+
3+
4+
Results calculateAllElementStiffnessMatrixAndLoadVector(const Mesh& mesh, double k) {
5+
6+
int numElements = mesh.GetNumElements();
7+
8+
int numNodes = mesh.GetNumNodesPerElement();
9+
10+
int sizePerElement = numNodes * numNodes;
11+
12+
View1D allElementStiffnessMatrix("stores all element stiffness matrix", numElements * sizePerElement);
13+
View1D allElementLoadVector("stores all element load vector", numElements * numNodes);
14+
15+
Kokkos::parallel_for("CalculateStiffness", numElements,
16+
KOKKOS_LAMBDA(const int elemIdx) {
17+
18+
double stiffnessMatrixPerElement[MAX_STIFFNESS_MATRIX_SIZE] = {};
19+
double loadVectorPerElement[MAX_LOAD_VECTOR_SIZE] = {};
20+
if (numNodes == 3) { // Triangle element
21+
TriElement triElem(mesh, elemIdx);
22+
triElem.setMaterialProperty(k);
23+
triElem.computeElementStiffnessMatrix(stiffnessMatrixPerElement);
24+
triElem.computeElementLoadVector(loadVectorPerElement);
25+
} else { // Quad element
26+
QuadElement quadElem(mesh, elemIdx);
27+
quadElem.setMaterialProperty(k);
28+
quadElem.computeElementStiffnessMatrix(stiffnessMatrixPerElement);
29+
quadElem.computeElementLoadVector(loadVectorPerElement);
30+
}
31+
32+
int base_stiffness_idx = elemIdx * sizePerElement;
33+
for (int i = 0; i < sizePerElement; ++i){
34+
allElementStiffnessMatrix(base_stiffness_idx + i) = stiffnessMatrixPerElement[i];
35+
}
36+
37+
int base_load_idx = elemIdx * numNodes;
38+
39+
for (int i = 0; i < numNodes; ++i){
40+
allElementLoadVector(base_load_idx + i) = loadVectorPerElement[i];
41+
}
42+
43+
});
44+
45+
return Results{allElementStiffnessMatrix, allElementLoadVector};
46+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef COMPUTING_AT_SCALE_ASSIGNMENT_CALCULATE_STIFFNESS_MATRIX_AND_LOAD_VECTOR_HPP
2+
#define COMPUTING_AT_SCALE_ASSIGNMENT_CALCULATE_STIFFNESS_MATRIX_AND_LOAD_VECTOR_HPP
3+
4+
#include "TriElement.hpp"
5+
#include "QuadElement.hpp"
6+
7+
constexpr static int MAX_STIFFNESS_MATRIX_SIZE = 16;
8+
constexpr static int MAX_LOAD_VECTOR_SIZE = 4;
9+
10+
11+
struct Results {
12+
View1D allElementStiffnessMatrix;
13+
View1D allElementLoadVector;
14+
15+
};
16+
17+
18+
Results calculateAllElementStiffnessMatrixAndLoadVector(const Mesh& mesh, double k = 1.0);
19+
20+
#endif

src/Element.hpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#ifndef COMPUTING_AT_SCALE_ASSIGNMENT_ELEMENT_HPP
2+
#define COMPUTING_AT_SCALE_ASSIGNMENT_ELEMENT_HPP
3+
4+
#include <Kokkos_Core.hpp>
5+
#include "Mesh.h"
6+
7+
using View1D = Kokkos::View<double*>;
8+
9+
class Element {
10+
protected:
11+
const Mesh& mesh_;
12+
int elemIdx_;
13+
double k_;
14+
15+
public:
16+
KOKKOS_INLINE_FUNCTION
17+
Element(const Mesh& mesh, int elemIdx, double k = 1.0) : mesh_(mesh), elemIdx_(elemIdx), k_(k) {}
18+
19+
KOKKOS_INLINE_FUNCTION
20+
virtual ~Element() {}
21+
22+
// Get number of nodes per element
23+
KOKKOS_INLINE_FUNCTION
24+
virtual int getNumNodes() const = 0;
25+
26+
// Compute local basis function
27+
KOKKOS_INLINE_FUNCTION
28+
virtual double computeLocalBasisFunction(const int node, const double xi, const double eta) const = 0;
29+
30+
// Compute jacobian for an element
31+
KOKKOS_INLINE_FUNCTION
32+
virtual double computeJacobian(const double xi, const double eta) const = 0;
33+
34+
// Compute element stiffness matrix
35+
KOKKOS_INLINE_FUNCTION
36+
virtual void computeElementStiffnessMatrix(double* stiffness) const = 0;
37+
38+
// Compute element load vector
39+
KOKKOS_INLINE_FUNCTION
40+
virtual void computeElementLoadVector(double* load) const = 0;
41+
42+
// Set material property k
43+
KOKKOS_INLINE_FUNCTION
44+
void setMaterialProperty(double k) {k_ = k;}
45+
46+
// Get material property k
47+
KOKKOS_INLINE_FUNCTION
48+
void getMaterialProperty(double k) {k_ = k;}
49+
50+
51+
};
52+
53+
#endif // COMPUTING_AT_SCALE_ASSIGNMENT_ELEMENT_HPP

src/Mesh.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ class Mesh {
5959
KOKKOS_INLINE_FUNCTION
6060
MeshType GetMeshType() const { return meshType_; }
6161

62+
[[nodiscard]] size_t GetNumNodesPerElement() const {
63+
return static_cast<int>(GetMeshType());
64+
}
65+
6266
private:
6367
// ***************************** Private Attributes
6468
// ***************************** //

src/QuadElement.hpp

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#ifndef COMPUTING_AT_SCALE_ASSIGNMENT_QUAD_ELEMENT_HPP
2+
#define COMPUTING_AT_SCALE_ASSIGNMENT_QUAD_ELEMENT_HPP
3+
4+
#include "Element.hpp"
5+
6+
class QuadElement : public Element {
7+
private:
8+
// Gauss quadrature points and weights for quads
9+
static constexpr int numQuadPoints_ = 4;
10+
static constexpr int numNodes_ = 4;
11+
static constexpr double gaussPoint_ = 0.57735026919; // 1/sqrt(3)
12+
13+
// Get quadrature point coordinates and weight
14+
KOKKOS_INLINE_FUNCTION
15+
void getQuadPoint(int q, double& xi, double& eta, double& weight) const {
16+
if (q == 0) {
17+
xi = -gaussPoint_; eta = -gaussPoint_; weight = 1.0;
18+
} else if (q == 1) {
19+
xi = gaussPoint_; eta = -gaussPoint_; weight = 1.0;
20+
} else if (q == 2) {
21+
xi = gaussPoint_; eta = gaussPoint_; weight = 1.0;
22+
} else if (q == 3) {
23+
xi = -gaussPoint_; eta = gaussPoint_; weight = 1.0;
24+
}
25+
}
26+
27+
public:
28+
KOKKOS_INLINE_FUNCTION
29+
QuadElement(const Mesh& mesh, int elemIdx) : Element(mesh, elemIdx) {}
30+
31+
KOKKOS_INLINE_FUNCTION
32+
int getNumNodes() const override { return numNodes_; }
33+
34+
KOKKOS_INLINE_FUNCTION
35+
double computeLocalBasisFunction(const int node, const double xi, const double eta) const override {
36+
switch(node) {
37+
case 0: return 0.25 * (1.0 - xi) * (1.0 - eta);
38+
case 1: return 0.25 * (1.0 + xi) * (1.0 - eta);
39+
case 2: return 0.25 * (1.0 + xi) * (1.0 + eta);
40+
case 3: return 0.25 * (1.0 - xi) * (1.0 + eta);
41+
default: return 0.0;
42+
}
43+
}
44+
45+
KOKKOS_INLINE_FUNCTION
46+
void computeBasisGradient(const int node, const double xi, const double eta,
47+
double& dN_dxi, double& dN_deta) const {
48+
switch(node) {
49+
case 0:
50+
dN_dxi = -0.25 * (1.0 - eta);
51+
dN_deta = -0.25 * (1.0 - xi);
52+
break;
53+
case 1:
54+
dN_dxi = 0.25 * (1.0 - eta);
55+
dN_deta = -0.25 * (1.0 + xi);
56+
break;
57+
case 2:
58+
dN_dxi = 0.25 * (1.0 + eta);
59+
dN_deta = 0.25 * (1.0 + xi);
60+
break;
61+
case 3:
62+
dN_dxi = -0.25 * (1.0 + eta);
63+
dN_deta = 0.25 * (1.0 - xi);
64+
break;
65+
default:
66+
dN_dxi = 0.0;
67+
dN_deta = 0.0;
68+
}
69+
}
70+
71+
KOKKOS_INLINE_FUNCTION
72+
double computeJacobian(const double xi, const double eta) const override {
73+
// For quads, the Jacobian varies by position
74+
double x[4], y[4];
75+
for (int i = 0; i < 4; i++) {
76+
x[i] = mesh_.GetCoordinate(elemIdx_, i, 0);
77+
y[i] = mesh_.GetCoordinate(elemIdx_, i, 1);
78+
}
79+
80+
// Compute derivatives of x and y w.r.t. local coordinates
81+
double dxdxi = 0.0, dxdeta = 0.0, dydxi = 0.0, dydeta = 0.0;
82+
83+
for (int i = 0; i < 4; i++) {
84+
double dN_dxi, dN_deta;
85+
computeBasisGradient(i, xi, eta, dN_dxi, dN_deta);
86+
87+
dxdxi += x[i] * dN_dxi;
88+
dxdeta += x[i] * dN_deta;
89+
dydxi += y[i] * dN_dxi;
90+
dydeta += y[i] * dN_deta;
91+
}
92+
93+
return dxdxi * dydeta - dxdeta * dydxi;
94+
}
95+
96+
KOKKOS_INLINE_FUNCTION
97+
void computeElementStiffnessMatrix(double* stiffness) const override {
98+
99+
// Initialize stiffness matrix
100+
for (int i = 0; i < numNodes_ * numNodes_; i++) {
101+
stiffness[i] = 0.0;
102+
}
103+
104+
// Get coordinates of quadrilateral vertices
105+
double x[4], y[4];
106+
for (int i = 0; i < 4; i++) {
107+
x[i] = mesh_.GetCoordinate(elemIdx_, i, 0);
108+
y[i] = mesh_.GetCoordinate(elemIdx_, i, 1);
109+
}
110+
111+
// Integrate using Gauss quadrature
112+
for (int q = 0; q < numQuadPoints_; q++) {
113+
double xi, eta, weight;
114+
getQuadPoint(q, xi, eta, weight);
115+
116+
// Compute Jacobian at this quadrature point
117+
double dxdxi = 0.0, dxdeta = 0.0, dydxi = 0.0, dydeta = 0.0;
118+
119+
for (int n = 0; n < numNodes_; n++) {
120+
double dN_dxi, dN_deta;
121+
computeBasisGradient(n, xi, eta, dN_dxi, dN_deta);
122+
123+
dxdxi += x[n] * dN_dxi;
124+
dxdeta += x[n] * dN_deta;
125+
dydxi += y[n] * dN_dxi;
126+
dydeta += y[n] * dN_deta;
127+
}
128+
129+
double det_J = dxdxi * dydeta - dxdeta * dydxi;
130+
double abs_det_J = det_J > 0 ? det_J : -det_J;
131+
132+
// compute inverse of the jacobian
133+
double invJ = 1/abs_det_J;
134+
135+
// Compute contribution to stiffness matrix
136+
for (int i = 0; i < numNodes_; i++) {
137+
double dNi_dxi, dNi_deta;
138+
computeBasisGradient(i, xi, eta, dNi_dxi, dNi_deta);
139+
140+
double dNi_dx = dydeta * dNi_dxi - dydxi * dNi_deta ;
141+
double dNi_dy = -dxdeta * dNi_dxi + dxdxi * dNi_deta;
142+
143+
for (int j = 0; j < numNodes_; j++) {
144+
double dNj_dxi, dNj_deta;
145+
computeBasisGradient(j, xi, eta, dNj_dxi, dNj_deta);
146+
147+
double dNj_dx = dydeta * dNj_dxi - dydxi * dNj_deta ;
148+
double dNj_dy = dydeta * dNj_dxi + dxdxi * dNj_deta ;
149+
150+
stiffness[i * numNodes_ + j] += (dNi_dx * dNj_dx + dNi_dy * dNj_dy) * invJ * weight;
151+
}
152+
}
153+
}
154+
155+
}
156+
157+
KOKKOS_INLINE_FUNCTION
158+
void computeElementLoadVector(double* load) const override {
159+
// Create load vector (4 entries)
160+
161+
// Initialize load vector
162+
for (int i = 0; i < numNodes_; i++) {
163+
load[i] = 0.0;
164+
}
165+
166+
double f = 1.0;
167+
168+
// Integrate load using quadrature
169+
for (int q = 0; q < numQuadPoints_; q++) {
170+
double xi, eta, weight;
171+
getQuadPoint(q, xi, eta, weight);
172+
173+
double det_J = computeJacobian(xi, eta);
174+
double abs_det_J = det_J > 0 ? det_J : -det_J;
175+
176+
for (int i = 0; i < numNodes_; i++) {
177+
double phi = computeLocalBasisFunction(i, xi, eta);
178+
load[i] += phi * f * weight * abs_det_J;
179+
}
180+
}
181+
}
182+
};
183+
184+
#endif // COMPUTING_AT_SCALE_ASSIGNMENT_QUAD_ELEMENT_HPP

src/StiffnessMatrix.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,38 @@ void StiffnessMatrix::printStiffnessMatrix() const {
138138
}
139139
printf("\n");
140140
}
141+
142+
std::vector<std::vector<double>> StiffnessMatrix::getDenseMatrix() const {
143+
std::vector<std::vector<double>> denseMatrix(nDof_,
144+
std::vector<double>(nDof_, 0.0));
145+
146+
auto csr_row_host = Kokkos::create_mirror_view(csrRowIds_);
147+
auto csr_col_host = Kokkos::create_mirror_view(csrColIds_);
148+
auto csr_val_host = Kokkos::create_mirror_view(csrValues_);
149+
Kokkos::deep_copy(csr_row_host, csrRowIds_);
150+
Kokkos::deep_copy(csr_col_host, csrColIds_);
151+
Kokkos::deep_copy(csr_val_host, csrValues_);
152+
153+
for (int row = 0; row < nDof_; ++row) {
154+
auto row_start = csr_row_host(row);
155+
auto row_end = csr_row_host(row + 1);
156+
for (int i = row_start; i < row_end; ++i) {
157+
int col = csr_col_host(i);
158+
double value = csr_val_host(i);
159+
denseMatrix[row][col] += value;
160+
}
161+
}
162+
163+
return denseMatrix;
164+
}
165+
166+
void StiffnessMatrix::printDenseMatrix() const {
167+
auto denseMatrix = getDenseMatrix();
168+
printf("Dense Matrix:\n");
169+
for (const auto &row : denseMatrix) {
170+
for (const auto &val : row) {
171+
printf("%5.1f ", val);
172+
}
173+
printf("\n");
174+
}
175+
}

0 commit comments

Comments
 (0)