-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathParabolicEquationSolver22Test.java
132 lines (115 loc) · 4.48 KB
/
ParabolicEquationSolver22Test.java
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
132
package by.andd3dfx.math.pde.solver;
import by.andd3dfx.math.pde.border.BorderConditionType2;
import by.andd3dfx.math.pde.equation.ParabolicEquation;
import by.andd3dfx.util.FileUtil;
import org.junit.jupiter.api.Test;
import static java.lang.Math.PI;
import static java.lang.Math.cos;
import static java.lang.Math.exp;
import static org.assertj.core.api.Assertions.assertThat;
/**
* <pre>
* Test for ParabolicEquationSolver with type 2 of border conditions on both sides.
*
* Solution of diffusion equation: Ut = D*Uxx
* - sealed pipe ends, so no diffusion through the ends
* - initial concentration with triangle profile: most mass concentrated in the center (see method getU0(x))
* - constant diffusion coefficient
* </pre>
*
* @see <a href="https://math.libretexts.org/Bookshelves/Differential_Equations/Differential_Equations_(Chasnov)/09%3A_Partial_Differential_Equations/9.05%3A_Solution_of_the_Diffusion_Equation">article</a>
*/
class ParabolicEquationSolver22Test {
private final double C_MAX = 100.0;
private final double L = 0.001; // Thickness of plate, m
private final double TIME = 1; // Investigated time, sec
private final double D = 1e-9; // Diffusion coefficient
private final double h = L / 100.0;
private final double tau = TIME / 100.0;
// We allow difference between numeric & analytic solution no more than 1% of max concentration value
private final double EPSILON = C_MAX / 100.;
@Test
void solve() {
var diffusionEquation = buildParabolicEquation();
// Solve equation
var solution = new ParabolicEquationSolver()
.solve(diffusionEquation, h, tau);
// Save numeric solution to file
var numericU = solution.gUt(TIME);
FileUtil.save(numericU, "./build/parabolic22-numeric.txt", true);
// Save analytic solution to file
FileUtil.saveFunc(solution.area().x(), (x) -> analyticSolution(x, TIME), "./build/parabolic22-analytic.txt");
// Compare numeric & analytic solutions
for (var i = 0; i < numericU.getN(); i++) {
var x = numericU.x(i);
var numericY = numericU.y(i);
var analyticY = analyticSolution(x, TIME);
assertThat(Math.abs(numericY - analyticY)).isLessThanOrEqualTo(EPSILON);
}
}
private ParabolicEquation buildParabolicEquation() {
var leftBorderCondition = new BorderConditionType2();
var rightBorderCondition = new BorderConditionType2();
return new ParabolicEquation(0, L, TIME, leftBorderCondition, rightBorderCondition) {
@Override
public double gK(double x, double t, double U) {
return D;
}
@Override
public double gU0(double x) {
return getU0(x);
}
};
}
/**
* Initial concentration profile
*
* @param x space coordinate
* @return concentration C_0(x)
*/
private double getU0(double x) {
x /= L;
if (0.4 <= x && x <= 0.5) {
return C_MAX * (10 * x - 4);
}
if (0.5 <= x && x <= 0.6) {
return C_MAX * (-10 * x + 6);
}
return 0;
}
/**
* <pre>
* Analytic solution:
* U(x,t) = a_0/2 + Sum(a_n*u_n(x,t)) = a_0/2 + Sum(a_n*cos(n*PI*x/L))*exp(-(n*PI/L)^2 * D*t)
*
* According to <a href="https://math.libretexts.org/Bookshelves/Differential_Equations/Differential_Equations_(Chasnov)/09%3A_Partial_Differential_Equations/9.05%3A_Solution_of_the_Diffusion_Equation">article</a>
* </pre>
*
* @param x space coordinate
* @param t time
* @return concentration C(x,t)
*/
private double analyticSolution(double x, double t) {
var result = 0d;
for (int n = 1; n <= 100; n++) {
result += a_n(n) * cos(n * PI * x / L) * exp(-Math.pow(n * PI / L, 2.) * D * t);
}
return a_n(0) / 2. + result;
}
/**
* Coefficient a_n of a Fourier sine series
*
* @param n number of coefficient
* @return b_n value
*/
private double a_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) * cos(n * PI * x / L) * dx;
}
return 2. / L * integral;
}
}