forked from hombit/freddi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnonlinear_diffusion.cpp
More file actions
152 lines (136 loc) · 5.73 KB
/
nonlinear_diffusion.cpp
File metadata and controls
152 lines (136 loc) · 5.73 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "nonlinear_diffusion.hpp"
double mean_square_rel(const vecd &A, const vecd &B, int first, int last){
double rv = 0;
double odds;
for ( int i = first; i <= last; ++i ){
odds = ( A.at(i) - B.at(i) ) / A.at(i);
rv += odds*odds;
}
return sqrt(rv) / (last-first+1);
}
double max_dif_rel(const vecd &A, const vecd &B, int first, int last){
double max = 0.;
for ( int i = first; i <= last; ++i ){
double x = fabs ( ( A.at(i) - B.at(i) ) / A.at(i) );
if ( x > max )
max = x;
}
return max;
}
// \frac{dw}{dt}=\frac{d^2y}{dx^2}, y=y(x,t) — ?, w = w (x,y)
void nonlenear_diffusion_nonuniform_1_2 (const double tau,
const double eps, // reletive error for w
const double left_bounder_cond, // y(left_border,Time+tau) = left_bounder_cond
const double right_bounder_cond, // \frac{y(right_border,Time+tau)}{dx} = right_bounder_cond
std::function<vecd (const vecd &, const vecd &, unsigned int, unsigned int)> wunc, // first argument is array of x_i, second — array of y(x_i,t); return value — array of w(x_i,y_i)
const vecd &x, // array with (non)uniform grid
vecd &y// array with initial coundition and for results
){
vecd y_init(y);
const int N = fmin(x.size(), y.size()); // N_x+1
const auto W = wunc(x, y, 1, N-1);
vecd K_0(N), K_1(N), CC(N), frac(N), a(N), b(N), f(N);
for ( int i = 1; i < N-1; ++i ){
a.at(i) = 2. * ( x.at(i+1) - x.at(i) ) / ( x.at(i+1) - x.at(i-1) );
b.at(i) = 2. * ( x.at(i) - x.at(i-1) ) / ( x.at(i+1) - x.at(i-1) );
frac.at(i) = ( x.at(i+1) - x.at(i) ) * ( x.at(i) - x.at(i-1) ) / tau;
}
frac.at(N-1) = ( x.at(N-1) - x.at(N-2) ) * ( x.at(N-1) - x.at(N-2) ) * 0.5 / tau;
for ( int i = 1; i < N; ++i ){
f.at(i) = frac.at(i) * W.at(i);
K_1.at(i) = frac.at(i) * W.at(i) / y.at(i);
CC.at(i) = K_0.at(i) = K_1.at(i) * (1. + 2.*eps);
}
auto iteration = [&](vecd &K) -> void{
vecd alpha(N), beta(N);
alpha.at(1) = 0.;
beta.at(1) = left_bounder_cond;
for ( int i = 1; i < N-1; ++i ){
double c = 2. + K.at(i);
alpha.at(i+1) = b.at(i) / ( c - alpha.at(i) * a.at(i) );
beta.at(i+1) = ( beta.at(i) * a.at(i) + f.at(i) ) / ( c - alpha.at(i) * a.at(i) );
}
y.at(N-1) = ( (x.at(N-1) - x.at(N-2) ) * right_bounder_cond + f.at(N-1) + beta.at(N-1) ) / ( 1. + K.at(N-1) - alpha.at(N-1) );
for ( int i = N-2; i > 0; --i )
y.at(i) = alpha.at(i+1) * y.at(i+1) + beta.at(i+1);
y.at(0) = left_bounder_cond;
auto WW = wunc(x, y, 1, N-1);
for ( int i = 1; i < N-1; ++i )
K.at(i) = frac.at(i) * WW.at(i) / y.at(i);
};
bool flag = false; int j = 0; double delta; vecd D_1(N), D_2(N);
while( max_dif_rel(K_1, K_0, 1, N-2) > eps ){
K_0 = K_1;
vecd alpha(N), beta(N);
alpha.at(1) = 0.;
beta.at(1) = left_bounder_cond;
for ( int i = 1; i < N-1; ++i ){
double c = 2. + K_1.at(i);
alpha.at(i+1) = b.at(i) / ( c - alpha.at(i) * a.at(i) );
beta.at(i+1) = ( beta.at(i) * a.at(i) + f.at(i) ) / ( c - alpha.at(i) * a.at(i) );
}
y.at(N-1) = ( (x.at(N-1) - x.at(N-2) ) * right_bounder_cond + f.at(N-1) + beta.at(N-1) ) / ( 1. + K_1.at(N-1) - alpha.at(N-1) );
for ( int i = N-2; i > 0; --i )
y.at(i) = alpha.at(i+1) * y.at(i+1) + beta.at(i+1);
y.at(0) = left_bounder_cond;
auto WW = wunc(x, y, 1, N-1);
for ( int i = 1; i < N-1; ++i ){
K_1.at(i) = frac.at(i) * WW.at(i) / y.at(i);
}
}
}
void nonlenear_diffusion_nonuniform_2_2 (const double tau,
const double eps, // reletive error for w
const double left_bounder_cond, // // \frac{y(left_border,Time+tau)}{dx} = left_bounder_cond
const double right_bounder_cond, // \frac{y(right_border,Time+tau)}{dx} = right_bounder_cond
std::function<vecd (const vecd &, const vecd &, unsigned int, unsigned int)> wunc, // first argument is array of x_i, second — array of y(x_i,t); return value — array of w(x_i,y_i)
const vecd &x, // array with (non)uniform grid
vecd &y// array with initial coundition and for results
){
vecd y_init(y);
const int N = fmin(x.size(), y.size()); // N_x+1
const auto W = wunc(x, y, 1, N-1);
vecd K_0(N), K_1(N), CC(N), frac(N), a(N), b(N), f(N);
for ( int i = 1; i < N-1; ++i ){
frac.at(i) = ( x.at(i+1) - x.at(i) ) * ( x.at(i) - x.at(i-1) ) / tau;
a.at(i) = 2. * ( x.at(i+1) - x.at(i) ) / ( x.at(i+1) - x.at(i-1) );
b.at(i) = 2. * ( x.at(i) - x.at(i-1) ) / ( x.at(i+1) - x.at(i-1) );
f.at(i) = frac.at(i) * W.at(i);
K_1.at(i) = frac.at(i) * W.at(i) / y.at(i);
CC.at(i) = K_0.at(i) = K_1.at(i) * 2. + 10.*eps;
}
auto iteration = [&](vecd &K) -> void{ // [&] <-> [&wunc, &x, &y, &frac, &a, &b, &f, N, left_bounder_cond, right_bounder_cond]
vecd alpha(N), beta(N);
alpha.at(1) = 1.;
beta.at(1) = - (x.at(1) - x.at(0)) * left_bounder_cond;
for ( int i = 1; i < N-1; ++i ){
double c = 2. + K.at(i);
alpha.at(i+1) = b.at(i) / ( c - alpha.at(i) * a.at(i) );
beta.at(i+1) = ( beta.at(i) * a.at(i) + f.at(i) ) / ( c - alpha.at(i) * a.at(i) );
}
y.at(N-1) = ( (x.at(N-1) - x.at(N-2) ) * right_bounder_cond + beta.at(N-1) ) / ( 1. - alpha.at(N-1) );
for ( int i = N-2; i > 0; --i )
y.at(i) = alpha.at(i+1) * y.at(i+1) + beta.at(i+1);
y.at(0) = left_bounder_cond;
auto WW = wunc(x, y, 1, N-1);
for ( int i = 1; i < N-1; ++i )
K.at(i) = frac.at(i) * WW.at(i) / y.at(i);
};
bool flag = false; int j = 0; double delta; vecd D_1(N), D_2(N);
while( max_dif_rel(K_1, K_0, 1, N-2) > eps ){
if ( max_dif_rel(K_1, CC, 1, N-2) > 0. and flag == false ){
K_0 = K_1;
iteration(K_1);
j++;
if ( j % 2 == 0 )
CC = K_0;
if ( j % 4 == 1 )
delta = max_dif_rel (K_1, K_0, 1, N-2);
if ( j % 4 == 3 and max_dif_rel (K_1, K_0, 1, N-2) >= delta ){
flag = true;
}
} else{
throw std::runtime_error("Divergence in nonlinear_diffusion");
}
}
}