Je voudrais résumer (en plusieurs articles) les connaissances nécessaires pour construire un code d'analyse numérique des fluides pour l'eau, tout en étudiant également la dynamique numérique des fluides (CFD), qui est une étude liée à la simulation de fluides tels que l'air et l'eau.
Je voudrais l'écrire pour que même les débutants puissent facilement le comprendre. Il semble qu'il y ait beaucoup d'erreurs, alors veuillez nous contacter si vous le trouvez. Je vous serais également reconnaissant de bien vouloir commenter ce qui est difficile à comprendre. Nous le mettrons à jour de temps en temps.
Comme étape préliminaire pour traiter les équations de base du fluide requises pour la simulation de l'eau, nous résumerons brièvement et implémenterons les équations de transfert.
Nous résoudrons l '[équation de transfert] unidimensionnelle (http://zellij.hatenablog.com/entry/20140805/p1) par la méthode des différences finies.
Équation avancée
Ce que signifie cette équation, c'est qu'une fonction u se déplace à la vitesse c. En bref, c'est une équation qui exprime que la quantité physique se déplace le long du flux de vitesse c.
Dispersez ceci et résolvez l'équation. Cette fois, nous allons le résoudre par une méthode appelée Positive Solution. La méthode explicite est simplement une méthode de recherche de valeurs futures en utilisant uniquement les valeurs de temps actuelles. En plus de la méthode explicite, il existe également une méthode appelée méthode implicite, qui est une méthode de calcul basée sur la valeur actuelle et la valeur future.
La méthode explicite à mettre en œuvre cette fois est la suivante. J'ai choisi les quatre suivants à volonté.
Pour chacun, j'écrirai les expressions discrètes. Dans la formule, l'indice j signifie le lieu et n le temps. Par conséquent, $ f_j ^ n $ signifie la valeur de la fonction f située à l'emplacement $ x_j $ au moment $ n $.
FTCS(Forward in Time and Central Difference in Space)
2.
Upwind differencing
3.
Lax-Wendroff scheme
4.
CIP(Constrained Interpolation Profile scheme) method
Les détails seront décrits plus tard. Vous pouvez également vous reporter à Introduction à la loi CIP.
Je voudrais mentionner brièvement les conditions de stabilité importantes lors de l'utilisation de la méthode explicite. Numériquement, la vitesse de propagation de l'information $ \ frac {\ Delta t} {\ Delta x} $ (la vitesse obtenue en divisant la largeur de la grille par le temps) doit être supérieure ou égale à la vitesse physique du signal $ c
Le langage utilisé est Python. Je vais l'écrire sans utiliser de nombreuses fonctions Numpy pour que la formule de calcul soit facile à comprendre.
Calculez le transfert d'une onde rectangulaire. La largeur de la grille $ \ Delta x $, la vitesse physique du signal $ c $ et la largeur du pas de temps $ \ Delta t $ sont toutes calculées comme des constantes. Cette fois, il est calculé comme $ \ Delta x = 1 $, $ c = 1 $, $ \ Delta t = 0,2 $ selon la référence. Par conséquent, il est fixé à $ CFL = 0,2 $ et la condition CFL est satisfaite.
# Creat square wave
Num_stencil_x = 101
x_array = np.arange(Num_stencil_x)
u_array = np.where(((x_array >= 30) |(x_array < 10)), 0.0, 1.0)
u_lower_boundary = 0.0
u_upper_boundary = 0.0
Time_step = 200
Delta_x = max(x_array) / (Num_stencil_x-1)
C = 1
Delta_t = 0.2
CFL = C * Delta_t / Delta_x
total_movement = C * Delta_t * (Time_step+1)
exact_u_array = np.where(((x_array >= 30 + total_movement) |(x_array < 10 + total_movement)), 0.0, 1.0)
plt.plot(x_array, u_array, label="Initial condition")
plt.plot(x_array, exact_u_array, label="Answer")
plt.legend(loc="upper right")
plt.xlabel("x")
plt.ylabel("u")
plt.xlim(0, max(x_array))
plt.ylim(-0.5,1.5)
La solution vibre. Je n'ai pas du tout de réponse
u_ftcs = u_array.copy()
#Définir le pas de temps
for n in range(Time_step):
u_old = u_ftcs.copy()
u_ftcs[0] = u_old[0] - CFL / 2 * (u_old[1] - u_lower_boundary)
u_ftcs[-1] = u_old[-1] - CFL / 2 * (u_upper_boundary - u_old[-1])
for j in range(1,Num_stencil_x-1, 1):
u_ftcs[j] = u_old[j] - CFL / 2 * (u_old[j+1] - u_old[j-1])
plt.plot(x_array, exact_u_array, label="Answer")
plt.plot(x_array, u_ftcs, label="FTCS")
plt.legend(loc="upper right")
plt.xlabel("x")
plt.ylabel("u(FTCS)")
plt.xlim(0, max(x_array))
plt.ylim(-0.5,1.5)
La diffusion numérique est grande et la solution devient lisse.
u_upwind = u_array.copy()
#Définir le pas de temps
for n in range(Time_step):
u_old = u_upwind.copy()
u_upwind[0:1] = u_old[0] - CFL * (u_old[1] - u_lower_boundary)
for j in range(1,Num_stencil_x):
u_upwind[j:j+1] = u_old[j] - CFL * (u_old[j] - u_old[j-1])
plt.plot(x_array, exact_u_array, label="Answer")
plt.plot(x_array, u_upwind, label="Upwind differencing")
plt.legend(loc="upper right")
plt.xlabel("x")
plt.ylabel("u(Upwind differencing)")
plt.xlim(0, max(x_array))
plt.ylim(-0.5,1.5)
Il y a une vibration numérique et une solution terne.
u_lw= u_array.copy()
#Définir le pas de temps
for n in range(Time_step):
u_old = u_lw.copy()
u_lw[0:1] = u_old[0] - CFL / 2 * (u_old[1] - u_lower_boundary) \
+ CFL**2 / 2 * (u_old[1] - 2 * u_old[0] + u_lower_boundary)
u_lw[-1] = u_old[-1] - CFL / 2 * (u_upper_boundary - u_old[-1]) \
+ CFL**2 / 2 * (u_upper_boundary - 2 * u_old[-1] + u_old[-2])
for j in range(1,Num_stencil_x-1, 1):
u_lw[j] = u_old[j] - CFL / 2 * (u_old[j+1] - u_old[j-1]) \
+ CFL**2 / 2 * (u_old[j+1] - 2 * u_old[j] + u_old[j-1])
plt.plot(x_array, exact_u_array, label="Answer")
plt.plot(x_array, u_lw, label="Lax-Wendroff scheme")
plt.legend(loc="upper right")
plt.xlabel("x")
plt.ylabel("u(Lax-Wendroff scheme)")
plt.xlim(0, max(x_array))
plt.ylim(-0.5,1.5)
L'idée de base de la méthode CIP est que lorsqu'une fonction f est d'abord discrétisée, les quantités physiques d'un point $ x_j $ et d'un point $ x_ {j-1} $ à côté d'elle sont reliées en douceur. En faisant cela, les valeurs différentielles des grandeurs physiques respectives $ f_j $ et $ f_ {j-1} $ peuvent être utilisées pour l'évolution temporelle sans diverger l'inclinaison entre les réseaux.
En d'autres termes, à condition que la ** valeur de la fonction et la valeur différentielle soient continues sur les points de la grille **, la relation entre les deux points de la grille peut être exprimée par la fonction complémentaire cubique $ F (x) $.
Dans la zone de $ x_ {j-1} <= x <x_j $
Est satisfait, donc si vous remplacez ceci dans la formule de $ F (x) $ et trouvez $ a, b, c, d $
a = \frac{\partial f_j^n / \partial x + \partial f_{j+1}^n / \partial x }{\Delta x^2} + \frac{2 (f_j^n - f_{j+1}^n)}{\Delta x^3} \\
b = \frac{3 (f_{j+1}^n - f_j^n)}{\Delta x^2} - \frac{2( \partial f_j^n / \partial x + \partial f_{j+1}^n / \partial x )}{\Delta x} \\
c = \frac{\partial f_j^n}{\partial x}\\
d = f_j^n
D'après ce qui précède, lorsque la vitesse c est constante, $ \ frac {\ partial u} {\ partial t} + c \ frac {\ partial u} {\ partial x} = 0 $ satisfait également la valeur différentielle, donc la largeur du pas de temps $ \ Delta t (n + 1 pas) La valeur et la valeur différentielle après $ secondes sont
u_j^{n+1} = F(x_j - c \Delta t)= a \xi^3 + b \xi^2 + c\xi + d \\
\frac{\partial u_j^{n+1}}{\partial x} = \frac{d F(x_j - c \Delta t)}{d x} = 3 a \xi^2 + 2 b \xi + c \\
, where \quad \xi = - c \Delta t
La diffusion numérique et les vibrations sont extrêmement plus petites que les trois autres méthodes. ~~ Cependant, le transfert n'était pas aussi bon que Références. ~~ (2020/02/20 Après avoir apporté les corrections que j'ai reçues dans les commentaires, cela s'est considérablement amélioré.)
u_cip= u_array.copy()
partial_u_cip = ((np.append(u_cip[1:], u_upper_boundary) + u_cip)/2 - (np.append(u_lower_boundary, u_cip[:-1]) + u_cip)/2)/ Delta_x
#Développer le temps
for n in range(Time_step):
u_old = u_cip.copy()
partial_u_old = partial_u_cip.copy()
u_cip[0] = 0
partial_u_cip[0] = 0
for j in range(1, Num_stencil_x):
a = (partial_u_old[j] + partial_u_old[j-1]) / Delta_x**2 - 2.0 * (u_old[j] - u_old[j-1]) / Delta_x**3
b = 3 * (u_old[j-1] - u_cip[j]) / Delta_x**2 + (2.0*partial_u_old[j] + partial_u_old[j-1]) / Delta_x
c = partial_u_old[j]
d = u_old[j]
xi = - C * Delta_t # C > 0
u_cip[j:j+1] = a * xi**3 + b * xi**2 + c * xi + d
partial_u_cip[j:j+1] = 3 * a * xi**2 + 2 * b * xi + c
plt.plot(x_array, exact_u_array, label="Answer")
plt.plot(x_array, u_cip, label="CIP method")
plt.legend(loc="upper right")
plt.xlabel("x")
plt.ylabel("u(CIP)")
plt.xlim(0, max(x_array))
plt.ylim(-0.5,1.5)
Les bases des équations de translocation qui composent l'équation de fluide sont résumées avec une brève mise en œuvre. Les quatre suivants ont été mis en œuvre.
La prochaine fois, je parlerai de Équation de diffusion.
Recommended Posts