Skip to content

Commit 0d1ddfe

Browse files
authored
Merge pull request #8 from Fuad-HH/test_elem_stiff
Fix Element Stiffness and Regression Testing
2 parents 264ee02 + ea7c76b commit 0d1ddfe

4 files changed

Lines changed: 256 additions & 169 deletions

File tree

src/QuadElement.hpp

Lines changed: 177 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -4,181 +4,190 @@
44
#include "Element.hpp"
55

66
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-
}
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_;
18+
eta = -gaussPoint_;
19+
weight = 1.0;
20+
} else if (q == 1) {
21+
xi = gaussPoint_;
22+
eta = -gaussPoint_;
23+
weight = 1.0;
24+
} else if (q == 2) {
25+
xi = gaussPoint_;
26+
eta = gaussPoint_;
27+
weight = 1.0;
28+
} else if (q == 3) {
29+
xi = -gaussPoint_;
30+
eta = gaussPoint_;
31+
weight = 1.0;
2532
}
33+
}
2634

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-
}
35+
public:
36+
KOKKOS_INLINE_FUNCTION
37+
QuadElement(const Mesh& mesh, int elemIdx) : Element(mesh, elemIdx) {}
38+
39+
KOKKOS_INLINE_FUNCTION
40+
int getNumNodes() const override { return numNodes_; }
41+
42+
KOKKOS_INLINE_FUNCTION
43+
double computeLocalBasisFunction(const int node, const double xi,
44+
const double eta) const override {
45+
switch (node) {
46+
case 0:
47+
return 0.25 * (1.0 - xi) * (1.0 - eta);
48+
case 1:
49+
return 0.25 * (1.0 + xi) * (1.0 - eta);
50+
case 2:
51+
return 0.25 * (1.0 + xi) * (1.0 + eta);
52+
case 3:
53+
return 0.25 * (1.0 - xi) * (1.0 + eta);
54+
default:
55+
return -10000.0; // Error case
4356
}
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-
}
57+
}
58+
59+
KOKKOS_INLINE_FUNCTION
60+
void computeBasisGradient(const int node, const double xi, const double eta,
61+
double& dN_dxi, double& dN_deta) const {
62+
switch (node) {
63+
case 0:
64+
dN_dxi = -0.25 * (1.0 - eta);
65+
dN_deta = -0.25 * (1.0 - xi);
66+
break;
67+
case 1:
68+
dN_dxi = 0.25 * (1.0 - eta);
69+
dN_deta = -0.25 * (1.0 + xi);
70+
break;
71+
case 2:
72+
dN_dxi = 0.25 * (1.0 + eta);
73+
dN_deta = 0.25 * (1.0 + xi);
74+
break;
75+
case 3:
76+
dN_dxi = -0.25 * (1.0 + eta);
77+
dN_deta = 0.25 * (1.0 - xi);
78+
break;
6979
}
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;
80+
}
81+
82+
KOKKOS_INLINE_FUNCTION
83+
double computeJacobian(const double xi, const double eta) const override {
84+
// For quads, the Jacobian varies by position
85+
double x[4], y[4];
86+
for (int i = 0; i < 4; i++) {
87+
x[i] = mesh_.GetCoordinate(elemIdx_, i, 0);
88+
y[i] = mesh_.GetCoordinate(elemIdx_, i, 1);
9489
}
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-
90+
91+
// Compute derivatives of x and y w.r.t. local coordinates
92+
double dxdxi = 0.0, dxdeta = 0.0, dydxi = 0.0, dydeta = 0.0;
93+
94+
for (int i = 0; i < 4; i++) {
95+
double dN_dxi, dN_deta;
96+
computeBasisGradient(i, xi, eta, dN_dxi, dN_deta);
97+
98+
dxdxi += x[i] * dN_dxi;
99+
dxdeta += x[i] * dN_deta;
100+
dydxi += y[i] * dN_dxi;
101+
dydeta += y[i] * dN_deta;
155102
}
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-
}
103+
104+
return dxdxi * dydeta - dxdeta * dydxi;
105+
}
106+
107+
KOKKOS_INLINE_FUNCTION
108+
void computeElementStiffnessMatrix(double* stiffness) const override {
109+
// Initialize stiffness matrix
110+
for (int i = 0; i < numNodes_ * numNodes_; i++) {
111+
stiffness[i] = 0.0;
112+
}
113+
114+
// Get coordinates of quadrilateral vertices
115+
double x[4], y[4];
116+
for (int i = 0; i < 4; i++) {
117+
x[i] = mesh_.GetCoordinate(elemIdx_, i, 0);
118+
y[i] = mesh_.GetCoordinate(elemIdx_, i, 1);
119+
}
120+
121+
// Integrate using Gauss quadrature
122+
for (int q = 0; q < numQuadPoints_; q++) {
123+
double xi, eta, weight;
124+
getQuadPoint(q, xi, eta, weight);
125+
126+
// Compute Jacobian at this quadrature point
127+
double dxdxi = 0.0, dxdeta = 0.0, dydxi = 0.0, dydeta = 0.0;
128+
129+
for (int n = 0; n < numNodes_; n++) {
130+
double dN_dxi, dN_deta;
131+
computeBasisGradient(n, xi, eta, dN_dxi, dN_deta);
132+
133+
dxdxi += x[n] * dN_dxi;
134+
dxdeta += x[n] * dN_deta;
135+
dydxi += y[n] * dN_dxi;
136+
dydeta += y[n] * dN_deta;
137+
}
138+
139+
double det_J = dxdxi * dydeta - dxdeta * dydxi;
140+
141+
// compute inverse of the jacobian
142+
double invJ = 1 / det_J;
143+
144+
// Compute contribution to stiffness matrix
145+
for (int i = 0; i < numNodes_; i++) {
146+
double dNi_dxi, dNi_deta;
147+
computeBasisGradient(i, xi, eta, dNi_dxi, dNi_deta);
148+
149+
double dNi_dx = dydeta * dNi_dxi - dydxi * dNi_deta;
150+
double dNi_dy = -dxdeta * dNi_dxi + dxdxi * dNi_deta;
151+
152+
for (int j = 0; j < numNodes_; j++) {
153+
double dNj_dxi, dNj_deta;
154+
computeBasisGradient(j, xi, eta, dNj_dxi, dNj_deta);
155+
156+
double dNj_dx = dydeta * dNj_dxi - dydxi * dNj_deta;
157+
double dNj_dy = -dxdeta * dNj_dxi + dxdxi * dNj_deta;
158+
159+
stiffness[i * numNodes_ + j] +=
160+
(dNi_dx * dNj_dx + dNi_dy * dNj_dy) * invJ * weight;
180161
}
162+
}
163+
}
164+
}
165+
166+
KOKKOS_INLINE_FUNCTION
167+
void computeElementLoadVector(double* load) const override {
168+
// Create load vector (4 entries)
169+
170+
// Initialize load vector
171+
for (int i = 0; i < numNodes_; i++) {
172+
load[i] = 0.0;
173+
}
174+
175+
double f = 1.0;
176+
177+
// Integrate load using quadrature
178+
for (int q = 0; q < numQuadPoints_; q++) {
179+
double xi, eta, weight;
180+
getQuadPoint(q, xi, eta, weight);
181+
182+
double det_J = computeJacobian(xi, eta);
183+
double abs_det_J = det_J > 0 ? det_J : -det_J;
184+
185+
for (int i = 0; i < numNodes_; i++) {
186+
double phi = computeLocalBasisFunction(i, xi, eta);
187+
load[i] += phi * f * weight * abs_det_J;
188+
}
181189
}
190+
}
182191
};
183192

184-
#endif // COMPUTING_AT_SCALE_ASSIGNMENT_QUAD_ELEMENT_HPP
193+
#endif // COMPUTING_AT_SCALE_ASSIGNMENT_QUAD_ELEMENT_HPP

src/TriElement.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ class TriElement : public Element {
4444
return xi;
4545
case 2:
4646
return eta;
47-
// TODO: Handle with error flag
47+
default:
48+
return 100000.0; // Error case
4849
}
4950
}
5051

tests/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,10 @@ add_executable(test_matvecmult test_matvec_mult.cpp ${CMAKE_SOURCE_DIR}/src/MatV
3939
target_link_libraries(test_matvecmult PRIVATE Catch2::Catch2WithMain Kokkos::kokkos)
4040
target_include_directories(test_matvecmult PRIVATE ${CMAKE_SOURCE_DIR}/src)
4141
catch_discover_tests(test_matvecmult WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
42+
43+
44+
# Test Element Stiffness Matrix
45+
add_executable(test_element_stiffness test_element_stiffness.cpp ${CMAKE_SOURCE_DIR}/src/CalculateStiffnessMatrixAndLoadVector.cpp ${CMAKE_SOURCE_DIR}/src/Mesh.cpp ${CMAKE_SOURCE_DIR}/src/StiffnessMatrix.cpp)
46+
target_link_libraries(test_element_stiffness PRIVATE Catch2::Catch2WithMain Kokkos::kokkos)
47+
target_include_directories(test_element_stiffness PRIVATE ${CMAKE_SOURCE_DIR}/src)
48+
catch_discover_tests(test_element_stiffness WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

0 commit comments

Comments
 (0)