BA Emilio Schmidt: Difference between revisions

From Arbeitsgruppe Kuiper
Jump to navigation Jump to search
m (Fehler partial_derivative_dr)
(Fehler d theta)
Line 362: Line 362:
</syntaxhighlight>
</syntaxhighlight>


Dabei durchläuft der Index i die Polarwinkel und der Index j die Radien. Zusätzlich muss jedoch darauf geachtet werden, dass die Transponierten der Geschwindigkeits-Arrays für V eingesetzt werden müssen. Für die spätere Kraftberechnung muss zudem die dynamische Viskosität \(\mu\) berechnet werden. Diese wird gemäß folgender Gleichung bestimmt:
Dabei durchläuft der Index i die Polarwinkel und der Index j die Radien. Zusätzlich muss jedoch darauf geachtet werden, dass die Transponierten der Geschwindigkeits-Arrays für V eingesetzt werden müssen. Um nun die Kraft \(dF_z\) in \(z\)-Richtung auf eine Zelle gemäß obiger Gleichung bestimmen zu können müsste zusätzlich die dynamische Viskosität \(\mu\) bestimmt werden. Werden jedoch zähe Einheiten verwendet, so ist \(\mu=1\). Damit lässt sich nun eine Funktion schreiben, die die Kraft dFz in z-Richtung auf eine Zelle gemäß obiger Gleichung bestimmt:<syntaxhighlight lang="python3">
\begin{align*}
\mu=\frac{\rho_{\text{ext}}v_{\text{ext}}L}{Re}
\end{align*}
 
Dabei ist \(\rho_{\text{ext}}\) die Anfangsdichte des Systems, \(L\) eine charakteristische Länge des Systems, welche hier gleich \(R\) gewählt wird und
vext die Einstromgeschwindigkeit, welche gegeben ist durch:
\begin{align*}
v_{\text{ext}}=Ma\cdot c_s
\end{align*}
 
Dabei sind ρext, R und cs auf \(1\) normiert, wodurch sich die dynamische Viskosität folgendermaßen schreiben lässt:
\begin{align*}
\mu=\frac{Ma R}{Re}
\end{align*}
 
Damit lässt sich eine Funktion definieren, die die dynamische Viskosität, für gegebene Machzahl, Reynoldszahl und gegebenen Radius bestimmt:<syntaxhighlight lang="python3">
def dynamic_viscosity(Ma, Re, R):
   
    mu = (Ma * np.min(R)) / Re
   
    return mu 
</syntaxhighlight>
 
Mit der dynamischen Viskosität und den eingefügten Randbedingungen lässt sich nun die Kraft dFz in z-Richtung auf eine Zelle gemäß obiger Gleichung bestimmen:<syntaxhighlight lang="python3">
def local_force(VR, VTHETA, i, j, Ma, Re, R, P):
def local_force(VR, VTHETA, i, j, Ma, Re, R, P):
      
      
     df = - P[i,j] * np.cos(THETA[i,j]) * np.sin(THETA[i,j])
     df = - P[i,j] * np.cos(THETA[i,j]) * np.sin(THETA[i,j]) * np.pi / (len(THETA[:,0]))
     df += dynamic_viscosity(Ma,Re,R) * (4/3) * partial_derivative_dr(VR,R,i,j) * np.cos(THETA[i,j]) * np.sin(THETA[i,j])
     df += dynamic_viscosity(Ma,Re,R) * (4/3) * partial_derivative_dr(VR,R,i,j) * np.cos(THETA[i,j]) * np.sin(THETA[i,j]) * np.pi / (len(THETA[:,0]))
     df += dynamic_viscosity(Ma,Re,R) * partial_derivative_dr(VTHETA,R,i,j) * np.sin(THETA[i,j]) ** 2
     df += dynamic_viscosity(Ma,Re,R) * partial_derivative_dr(VTHETA,R,i,j) * np.sin(THETA[i,j]) ** 2 * np.pi / (len(THETA[:,0]))
      
      
     return df
     return df
</syntaxhighlight>
</syntaxhighlight>


Dabei ist P der Durck, welcher von der jeweiligen Zelle aus auf die Kugel ausgeübt wird. Dieser lässt sich ebenfalls aus den Daten laden. Für die Gesamtkraft Fz in z-Richtung auf die Kugel müssen die dFz für alle Zellen um die Kugel aufsummiert werden und anschließend mit dem Faktor 2πR2 gewichtet werden. Außerdem muss das Endergebnis zusätzlich mit einem Faktor 2 multipliziert werden, da aus Symmetriegründen nur die Hälfte der Kugel simuliert wird. Damit lässt sich folgende Funktion definieren:<syntaxhighlight lang="python3">
Dabei ist P der Durck, welcher von der jeweiligen Zelle aus auf die Kugel ausgeübt wird. Dieser lässt sich ebenfalls aus den Daten laden. Der Faktor <code> np.pi / (len(THETA[:,0])) </code> entspricht hierbei dem dθ in obiger Gleichung. Für die Gesamtkraft Fz in z-Richtung auf die Kugel müssen die dFz für alle Zellen um die Kugel aufsummiert werden und anschließend mit dem Faktor 2πR2 gewichtet werden. Außerdem muss das Endergebnis zusätzlich mit einem Faktor 2 multipliziert werden, da aus Symmetriegründen nur die Hälfte der Kugel simuliert wird. Damit lässt sich folgende Funktion definieren:<syntaxhighlight lang="python3">
def net_force(VR, VTHETA, j, Ma, Re, R, P):  
def net_force(VR, VTHETA, j, Ma, Re, R, P):  
      
      

Revision as of 16:27, 3 May 2024

(Der Echtzeit-Previewer rendert leider keine Formeln. Am besten stets mit "edit source" statt dem visual "edit" arbeiten und bitte ausgiebig den Knopf "Show preview" benutzen anstatt zig mal abzuspeichern. Diskussionen sollten unter Discussion geführt werden. -- Lothar)

Stokes-Fluss um eine Kugel

Kraftberechnung

F=KσdSundFz=ezKσdS=KezσdS=KugelKezσerdS Bei Zylindersymmetrie und Verwendung von KK wird daraus Fz=0π02π(ercosθeθsinθ)σ(r=R,θ)erR2sinθdϕdθ=2πR20π(σrr(r=R,θ)cosθsinθσθr(r=R,θ)sin2θ)dθ

Dabei lautet der Spannungstensor (s. auch Wikipedia) σ=1(pζu)+μ(u+(u)T123u) und bei der Formulierung von u und u in KK hilft ebenfalls die Wikipedia. Die Komponenten des Einheitstensors 1 schließlich bilden in jeder Basis die Einheitsmatrix.


Kraftberechnung (Emilio)

Die Kraft, welche auf die umströmte Kugel wirkt, ist gegeben durch folgendes Oberflächenintegral: F=VσdA

Dabei gilt für ein Oberflächenelement dA einer Kugel mit Radius r=R, in Kugelkoordinaten: dA=R2sin(θ)dφdθer

Einsetzen und weitere Berechnung in Kugelkoordinaten liefert: F=0π02πσ(r=R,θ,φ)erR2sin(θ)dφdθ

Auswerten des Matrix-Vektor-Produktes liefert, dass nur die rr-, θr- und φr-Komponenten des Spannungstensors multipliziert mit entsprechenden Basisvektoren übrig bleiben. Es gilt also: F=0π02π[σrrer+σθreΘ+σφreφ]|r=RR2sin(θ)dφdθ

Um nun die Integrale ausrechnen zu können, wird die explizite Form des Spannungstensors für dieses Problem benötigt. Im Allgemeinen ist der Spannungstensor für reale, newtonsche Fluide gegeben durch: σ=[pζ(u)]1+μ[u+(u)T23(u)1]

Mit der Volumenviskosität ζ, welche jedoch aufgrund der Stokes'schen Hypothese vernachlässigt werden kann. Damit folgt: σ=p1+μ[u+(u)T23(u)1]

Dabei ist 1 der Einheitstensor, μ die dynamische Viskosität und u die Geschwindigkeit des Fluides. Aufgrund dessen, dass bei der Kraftberechnung in Kugelkoordinaten nur die rr-, φr- und θr-Komponente des Spannungstensors eingehen, werden im Folgenden auch nur diese bestimmt. Die rr-Komponente ist dabei gegeben durch: σrr=p+μ[2urr23u]

urr ist hier die $rr$-Komponente des Vektorgradienten u, welche gegeben ist durch: urr=urr

Für die Divergenz des Geschwindigkeitsfeldes gilt allgemein in Kugelkoordinaten: u=1r2r2urr+1rsin(θ)sin(θ)uθθ+1rsin(θ)uφφ

Aufgrund dessen, dass das Fluid homogen einströmt und eine Kugel umströmt, hat das Geschwindigkeitsfeld um die Kugel Zylindersymmetrie. Daher fällt die azimutale Ableitung bei Betrachtung des Geschwindigkeitsfeldes um die Kugel weg. Außerdem folgt aus der vorgegebenen Anfangsbedingung, dass das Fluid entlang der z-Achse einströmt, zusammen mit der Kugelsymmetrie der Kugel, dass das Geschwindigkeitsfeld und auch sämtliche anderen relevanten Vektorfelder, die dieses Problem beschreiben, keine azimutale Komponente aufweisen können. Damit folgt für die Divergenz des Geschwindigkeitsfeldes: u=1r2r2urr+1rsin(θ)sin(θ)uθθ

Einsetzen in die rr-Komponente und auswerten an der Kugeloberfläche liefert: σrr|r=R=p(R,θ)+μ(R,θ)[2urr|r=R231R2r2urr|r=R+1Rsin(θ)sin(θ)uθθ|r=R]

Die Ableitungen lassen sich zusätzlich mittels der Produktregel vereinfachen. Es folgt: σrr|r=R=p(R,θ)+μ(R,θ)[43urr|r=R43Rur|r=R23Rcot(θ)uθ|r=R23Ruθθ|r=R]

Die Verwendung der No-Slip-RB bedeutet, dass sowohl die normale als auch die tangentiale Komponente des Geschwindigkeitsvektors auf der Oberfläche eines festen Körpers verschwinden müssen. Damit folgt: ur|r=R=uθ|r=R=0

Außerdem impliziert das Verschwinden des Geschwindigkeitsvektors auf der Kugeloberfläche und dessen Kugelsymmetrie, dass zusätzlich die polaren Ableitungen auf der Oberfläche verschwinden: urθ|r=R=uθθ|r=R=0

Damit folgt für die rr-Komponente des Spannungstensors, ausgewertet an der Kugeloberfläche: σrr|r=R=p(R,θ)+43μ(R,θ)urr|r=R

Für die θr-Komponente gilt dann gemäß obiger Gleichung: σθr=μ[uθr+urθ]

Einsetzen der jeweiligen Komponenten des Vektorgradienten und auswerten an der Kugeloberfläche liefert: σθr|r=R=μ(R,θ)[uθr|r=R+1Rurθ|r=RuθR|r=R]

Mit den Randbedingungen folgt dann final für die θr-Komponente: σθr|r=R=μ(R,θ)uθr|r=R

Für die φr-Komponente gilt gemäß obiger Gleichung: σφr=μ[uφr+urφ]

Die jeweiligen Komponenten des Vektorgradienten sind im Allgemeinen gegeben durch: uφr=uφrurφ=1rsin(θ)urφuφr

Analog zu oben fallen hier auch sowohl die azimutalen Komponenten als auch die azimutalen Ableitungen weg, weshalb für die φr-Komponente des Spannungstensors folgt: σφr=0

Einsetzen in das Integral zur Kraftberechnung und auswerten des Integrals über φ liefert: ,,F=2πR20π[(p(R,θ)+43μ(R,θ)urr|r=R)er+μ(R,θ)uθr|r=ReΘ]sin(Θ)dΘF=2πR2[0πp(R,θ)ersin(θ)dθ+430πμ(R,θ)urr|r=Rersin(θ)dθ+0πμ(R,θ)uθr|r=ReΘsin(θ)dθ]

Da im vorliegenden Problem insbesondere die Kraft auf die Kugel in z-Richtung von Interesse ist, wird nun die Projektion des Kraftvektors auf die z-Achse bestimmt: Fz=ezF

Aufgrund dessen, dass die z-Achse eine feste Richtung hat und der Linearität der Integrationsoperation, kann der Basisvektor ez in das Integral hineingezogen werden. Damit folgt für Fz: Fz=2πR2[0πp(R,θ)erezsin(θ)dθ+430πμ(R,θ)urr|r=Rerezsin(θ)dθ+0πμ(R,θ)uθr|r=ReΘezsin(θ)dθ]

Für die Berechnung der jeweiligen Skalarprodukte ist es praktisch den Basisvektor ez in der hier genutzten sphärischen Basis darzustellen: ez=cos(θ)ersin(θ)eθ

Damit folgt für Fz: Fz=2πR2[0πp(R,θ)cos(θ)sin(θ)dθ+430πμ(R,θ)urr|r=Rcos(θ)sin(θ)dθ0πμ(R,θ)uθr|r=Rsin2(θ)dθ]

Die Kraft in x- bzw. y-Richtung lässt sich analog berechnen. Da jedoch die Basisvektoren ex bzw. ey in sphärischer Darstellung eine φ-Abhängigkeit aufweisen, kann die Integration über φ nicht so leicht durchgeführt werden, wie es oben geschehen ist. Für die Kraft in x-Richtung muss dann folgendes Integral ausgewertet werden: Fx=R2[0π02πp(R,θ)sin2(θ)cos(φ)dφdθ+430π02πμ(R,θ)urr|r=Rsin2(θ)cos(φ)dφdθ+0π02πμ(R,θ)uθr|r=Rsin(θ)cos(θ)cos(φ)dφdθ]

Auswerten der Integrale über φ liefert jedoch, wie zu erwarten war, für Fx: Fx=0

Analoges Vorgehen liefert für Fy: Fy=0

Natürliche Einheiten

Aus den vier System-Parametern v, R, ρ und μ lassen sich zwei sinnvolle Einheitensätze bilden:

"zähe" Einheiten

Damit ist der Satz R, ρ und μ gemeint, Basiseinheiten sind ρR3 ,R ,R2ρμ für Masse, Länge und Zeit; und μ/(ρR) bzw. μ2/ρ die Geschwindigkeits- bzw. Krafteinheit. Die Reynoldszahl stellt dann gemäß vμ/(ρR)=Re2 die Geschwindigkeit ein, und im Stokes-Regime gilt Fμ2/ρ=3πRe .

"träge" Einheiten

Damit ist der Satz R, v und ρ gemeint, Basiseinheiten sind dann ρR3 ,R ,Rv für Masse, Länge und Zeit; und ρvR bzw. ρv2R2 die Viskositäts- bzw. Krafteinheit. Die Reynoldszahl stellt dann gemäß μρvR=2Re die Viskosität ein, und im Stokes-Regime gilt Fρv2R2=6π2Re .

NB: Die Zahlenwerte der einheitenbildenden Parameter sind 1 und sollten auch im Code so gewählt werden.

Viskosität, dynamisch vs. kinematisch

Von den beiden, μ=νρ, ist keine ein wirklicher Materialparameter, doch die dynamische Viskosität hängt nur von der Temperatur (und von WW-Details der Fluid-Partikel) ab. Da im Stokes-Regime die Temperatur-Änderung klein sein sollte, ist es also sinnvoller, μ als "Materialparameter" vorzugeben.

Die Viskosität wird in der Funktion Visc_nu() in visc_nu.c berechnet, ein Aufruf pro Zelle. Trotz der Namen nu1 (Scherv.) und nu2 (Volumenv.) handelt es sich um die dynamischen Viskositäten. Beim Vorgeben von μ sollte ρ (im Code v[RHO]) also gar nicht auftauchen. Verwendet man obige "zähe Einheiten", so wird die Funktion besonders einfach:

void Visc_nu(double *v, double x1, double x2, double x3, double *nu1, double *nu2)
/* ... */
{
  *nu1 = 1.0;  *nu2 = 0.0;
}

Implementierung in Python

Nachdem die Daten mittels der Bibliothek pyPLUTO geladen wurden, wurde zunächst ein Meshgrid für die Radien und die Winkel erstellt:

RS, THETAS = np.meshgrid(D.x1, D.x2)

Hierbei wurde verwendet:

D = pp.pload(500, w_dir="C:/Users/...")

Die oben beschriebenen Randbedingungen sind jedoch nicht in den Daten für Radien und den Winkeln bzw. für die jeweiligen Geschwindigkeitskomponenten enthalten. Daher müssen sie manuell in die Datensätze eingefügt werden. Dafür sorgt folgende Funktion:

def before_first_value_line(array, value):
    
    new_arr = np.hstack((np.full((array.shape[0], 1), value), array))
    
    return new_arr

np.hstack() ist dabei eine Funktion, um zwei Arrays nebeneinander zu setzen, sodass zwei Arrays der Form (n,m) und (n,p) zu einem Array der Form (n,m+p) zusammengefügt werden. np.full() erstellt hierbei ein Array mit der selben Anzahl an Zeilen, wie das zu übergebende Array, jedoch nur mit einer Spalte.

Mit dieser Funktion lassen sich jetzt die Randbedingungen in die Datensätze einfügen:

R = before_first_value_line(RS,1) 
THETA = THETAS

VR = before_first_value_line(D.vx1.T,0) 
VTHETA = before_first_value_line(D.vx2.T,0)

Um nun Fz gemäß der obigen Gleichung bestimmen zu können, müssen zunächst die partiellen Ableitungen der Geschwindigkeitskomponenten nach Radius und Polarwinkel numerisch bestimmt werden. Dafür erweist sich die Numpy-Funktion np.gradient() als nützlich. Mit dieser lässt sich eine Funktion definieren, die die Ableitung nach dem Radius durchführt:

def partial_derivative_dr(V, R, i, j):
    
    dvdr = np.gradient(V[i,:], R[i,:])
    
    return dvdr[j]

Dabei durchläuft der Index i die Polarwinkel und der Index j die Radien. Zusätzlich muss jedoch darauf geachtet werden, dass die Transponierten der Geschwindigkeits-Arrays für V eingesetzt werden müssen. Um nun die Kraft dFz in z-Richtung auf eine Zelle gemäß obiger Gleichung bestimmen zu können müsste zusätzlich die dynamische Viskosität μ bestimmt werden. Werden jedoch zähe Einheiten verwendet, so ist μ=1. Damit lässt sich nun eine Funktion schreiben, die die Kraft dFz in z-Richtung auf eine Zelle gemäß obiger Gleichung bestimmt:

def local_force(VR, VTHETA, i, j, Ma, Re, R, P):
    
    df = - P[i,j] * np.cos(THETA[i,j]) * np.sin(THETA[i,j]) * np.pi / (len(THETA[:,0]))
    df += dynamic_viscosity(Ma,Re,R) * (4/3) * partial_derivative_dr(VR,R,i,j) * np.cos(THETA[i,j]) * np.sin(THETA[i,j]) * np.pi / (len(THETA[:,0]))
    df += dynamic_viscosity(Ma,Re,R) * partial_derivative_dr(VTHETA,R,i,j) * np.sin(THETA[i,j]) ** 2 * np.pi / (len(THETA[:,0]))
    
    return df

Dabei ist P der Durck, welcher von der jeweiligen Zelle aus auf die Kugel ausgeübt wird. Dieser lässt sich ebenfalls aus den Daten laden. Der Faktor np.pi / (len(THETA[:,0])) entspricht hierbei dem dθ in obiger Gleichung. Für die Gesamtkraft Fz in z-Richtung auf die Kugel müssen die dFz für alle Zellen um die Kugel aufsummiert werden und anschließend mit dem Faktor 2πR2 gewichtet werden. Außerdem muss das Endergebnis zusätzlich mit einem Faktor 2 multipliziert werden, da aus Symmetriegründen nur die Hälfte der Kugel simuliert wird. Damit lässt sich folgende Funktion definieren:

def net_force(VR, VTHETA, j, Ma, Re, R, P): 
    
    df_arr = np.zeros(len(THETA[:,0])) 
    
    for i in np.arange(0,len(THETA[:,0])):
        
        df_arr[i] = local_force(VR, VTHETA, i, j, Ma, Re, R, P)
        
    f = 2 * np.pi * np.min(R) ** 2 * 2 * np.sum(df_arr) 

    return f