-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHyperbolicEquationSolverDDTest.java
More file actions
131 lines (114 loc) · 4.51 KB
/
HyperbolicEquationSolverDDTest.java
File metadata and controls
131 lines (114 loc) · 4.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package io.github.andreipunko.math.pde.solver;
import io.github.andreipunko.math.pde.border.DirichletBorderCondition;
import io.github.andreipunko.math.pde.equation.HyperbolicEquation;
import io.github.andreipunko.util.FileUtil;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import static java.lang.Math.PI;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static org.assertj.core.api.Assertions.assertThat;
/**
* <pre>
* Test for HyperbolicEquationSolver with Dirichlet border conditions on both sides.
*
* Solution of wave equation: Utt = c^2*Uxx
* - constant displacement U=0 on the left & right borders
* - initial displacement with triangle profile (see method getU0(x))
* - constant coefficient c
* </pre>
*
* @see <a href="https://math.libretexts.org/Bookshelves/Differential_Equations/Differential_Equations_(Chasnov)/09%3A_Partial_Differential_Equations/9.06%3A_Solution_of_the_Wave_Equation">article</a>
*/
class HyperbolicEquationSolverDDTest {
private final double U_MAX = 0.005; // Max displacement, m
private final double L = 0.100; // Length of string, m
private final double TIME = 25; // Investigated time, sec
private final double C_coeff = 1e-2; // Wave speed c (so Utt = c²Uxx via gK() = c²). Or “c²=T/ρ” in physics.
private final double h = L / 2000.0; // Space step
private final double tau = TIME / 2000.0; // Time step
private final double EPSILON = U_MAX / 80.;
@Test
void solve() throws IOException {
var waveEquation = buildHyperbolicEquation();
// Solve equation
var solution = new HyperbolicEquationSolver()
.solve(waveEquation, h, tau);
// Save numeric solution to file
var numericU = solution.gUt(TIME);
FileUtil.save(numericU, "./build/hyperbolic11-numeric.txt", true);
// Save analytic solution to file
FileUtil.saveFunc(solution.area().x(), (x) -> analyticSolution(x, TIME), "./build/hyperbolic11-analytic.txt");
// Compare numeric & analytic solutions
double maxAbsErr = 0d;
for (var i = 0; i < numericU.getN(); i++) {
var x = numericU.x(i);
var numericY = numericU.y(i);
var analyticY = analyticSolution(x, TIME);
maxAbsErr = Math.max(maxAbsErr, Math.abs(numericY - analyticY));
}
assertThat(maxAbsErr).isLessThanOrEqualTo(EPSILON);
}
private HyperbolicEquation buildHyperbolicEquation() {
var leftBorderCondition = new DirichletBorderCondition();
var rightBorderCondition = new DirichletBorderCondition();
return new HyperbolicEquation(0, L, TIME, leftBorderCondition, rightBorderCondition) {
@Override
public double gK(double x, double t, double U) {
return C_coeff * C_coeff;
}
@Override
public double gU0(double x) {
return getU0(x);
}
};
}
/**
* Initial displacement profile
*
* @param x space coordinate
* @return displacement U_0(x)
*/
private double getU0(double x) {
x /= L;
if (0 <= x && x <= 0.2) {
return U_MAX * 5 * x;
}
return U_MAX * 1.25 * (1 - x);
}
/**
* <pre>
* Analytic solution:
* U(x,t) = Sum( b_n*u_n(x,t) ) = Sum( b_n*sin(n*PI*x/L)*cos(n*PI*C*t/L) )
*
* According to <a href="https://math.libretexts.org/Bookshelves/Differential_Equations/Differential_Equations_(Chasnov)/09%3A_Partial_Differential_Equations/9.06%3A_Solution_of_the_Wave_Equation">article</a>
* </pre>
*
* @param x space coordinate
* @param t time
* @return displacement U(x,t)
*/
private double analyticSolution(double x, double t) {
var result = 0d;
for (int n = 1; n <= 100; n++) {
result += b_n(n) * sin(n * PI * x / L) * cos(n * PI * C_coeff * t / L);
}
return result;
}
/**
* Coefficient b_n of a Fourier sine series
*
* @param n number of coefficient
* @return b_n value
*/
private double b_n(int n) {
var integral = 0d;
var N = 100d;
var dx = L / N;
for (int i = 0; i < N; i++) {
var x = dx * (i + 0.5);
integral += getU0(x) * sin(n * PI * x / L) * dx;
}
return 2. / L * integral;
}
}