Asignatura: Mecánica de Fluidos
Departamento: Ciencia y Tecnología de Materiales y Fluidos
Centro: Escuela Universitaria Politécnica de Teruel
Profesor: Adrián Navas Montilla
El rotor Flettner es un sistema de propulsión de vehículos basado en la generación de fuerzas aerodinámicas producidas por un cilindro en rotación sobre el que incide un flujo de aire. Alrededor del cilindro existe una asimetría en el campo de velocidades y presiones, que se traduce en una fuerza neta en una de las direcciones. A este fenómeno lo llamamos efecto Magnus. La fuerza producida se utiliza para propulsar o sustentar el vehículo en cuestión.
Este sistema se ha aplicado tanto en aeronaves como en barcos:
from IPython.display import YouTubeVideo
YouTubeVideo('kDyBrSW1_Og')
YouTubeVideo('UG2O_GK7-R8')
Para representar el campo de velocidades alrededor de un cilindro en rotación podemos utilizar la superposición de tres flujos elementales: un flujo uniforme, un doblete y un vórtice libre, que luego explicaremos en qué consisten. Además, para facilitar el cálculo trabajaremos bajo la hipótesis de flujo ideal. Esto nos permitirá, conociendo el campo de velocidades alrededor del cilindro, calcular la presión en el mismo, para finalmente calcular las fuerzas sobre el cilindro.
A continuación se detallan los flujos elementales mencionados anteriormente:
Doblete. Corresponde a una pareja de fuente y sumidero que se encuentran muy cerca. Su campo de velocidades viene dado por: $$u_{doublet}\left(x,y\right) = -\frac{\kappa}{2\pi}\frac{x^2-y^2}{\left(x^2+y^2\right)^2}$$ $$v_{doublet}\left(x,y\right) = -\frac{\kappa}{2\pi}\frac{2xy}{\left(x^2+y^2\right)^2}$$ donde $\kappa$ es la intensidad del doblete (a mayor intensidad, mayor será su tamaño y mayores velocidades se alcanzarán en un mismo punto).
Vórtice libre. Corresponde a un flujo en rotación cuya vorticidad es nula (vórtice irrotacional). Su campo de velocidades viene dado por: $$u_{vortex}\left(x,y\right) = \frac{\Gamma}{2\pi}\frac{y}{x^2+y^2}$$ $$v_{vortex}\left(x,y\right) = -\frac{\Gamma}{2\pi}\frac{x}{x^2+y^2}$$ donde $\Gamma$ es la intensidad del vórtice (a mayor intensidad, mayor velocidad de giro).
Puedes encontrar más información sobre estos flujos elementales en el documento de ayuda.
La superposición de estos tres flujos elementales nos permite representar el flujo alrededor de un cilindro en rotación con el siguiente campo de velocidades:
$$ u=u_{doublet}+u_{vortex}+u_{uniform}$$$$ v=v_{doublet}+v_{vortex}+v_{uniform}$$En coordenadas polares, este campo de velocidades se expresa como:
$$u_r\left(r,\theta\right) = \cos\theta \left(U_\infty-\frac{\kappa}{2\pi r^2}\right)$$$$u_\theta\left(r,\theta\right) = -\sin\theta \left(U_\infty +\frac{\kappa}{2\pi r^2}\right) - \frac{\Gamma}{2\pi r}$$Asumiendo que en la superficie del cilindro de radio $R$ la velocidad radial es nula, obtenemos la siguiente expresión para el radio del cilindro:
$$R=\sqrt{\frac{\kappa}{2\pi U_{\infty}}}$$Por otro lado, también asumiremos la siguiente relación para la velocidad angular del cilindro:
$$\omega=\frac{\Gamma}{2\pi R^2}$$Sustituyendo las expresiones anteriores, obtenemos: $$u_r\left(r,\theta\right) = U_\infty \cos\theta \left(1-\frac{R^2}{r^2}\right)$$
$$u_\theta\left(r,\theta\right) = -U_\infty \sin\theta \left(1+\frac{R^2}{r^2}\right) - \frac{\Gamma}{2\pi r}$$Bajo la hipótesis de flujo ideal, es posible relacionar las condiciones del flujo aguas arriba del cilindro con las condiciones del flujo en cualquier otro punto del dominio mediante la ecuación de Bernoulli:
$$p_\infty + \frac{1}{2}\rho U_\infty^2 = p + \frac{1}{2}\rho U^2$$Por ejemplo, podemos utilizar esta relación para conocer la distribución de presiones alrededor del cilindro. En el apartado siguiente, representaremos gráficamente el coeficiente de presión, que se define como:
$$C_p = \frac{p-p_\infty}{\frac{1}{2}\rho U_\infty^2}$$es decir $$C_p = 1 - \left(\frac{U}{U_\infty}\right)^2$$
Para esta parte, nos hemos basado en el trabajo de L. A. Barba (Barba, Lorena A., and Mesnard, Olivier (2019). Aero Python: classical aerodynamics of potential flow using Python. Journal of Open Source Education, 2(15), 45, https://doi.org/10.21105/jose.00045).
Vamos a comenzar importando algunas bibliotecas de Python:
math
proporciona las funciones y constantes matemáticas básicas.import math
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, interactive, fixed, interact_manual
El objetivo es visualizar las líneas de flujo correspondientes a los campos de velocidades que hemos descrito anteriormente. Para ello, necesitamos definir primero un conjunto de puntos donde se calcularán las componentes de la velocidad.
Vamos a definir una malla cartesiana de puntos uniformemente espaciados dentro de un dominio espacial que tiene 4 unidades de longitud de ancho en la dirección $x$ y 2 unidades de longitud de ancho en la dirección $y$, es decir, $x,y\in\left[-2,2\right],\left[-1,1\right]$.
La variable N
será el número de puntos que queremos en cada dirección, y definimos los límites computacionales mediante las variables x_start
, x_end
, y_start
y y_end
.
Utilizamos la función NumPy linspace()
para crear dos matrices que contienen los valores uniformes de las coordenadas $x$ e $y$, correspondientes a nuestros puntos de la cuadrícula. La última línea del bloque de código de abajo llama a la función meshgrid()
, que genera matrices que contienen las coordenadas de los puntos donde se calculará la solución numérica.
N = 50 # numero de puntos en cada direccion
x_start, x_end = -2.0, 2.0 # límites izquierdo y derecho en x
y_start, y_end = -1.0, 1.0 # límites izquierdo y derecho en y
x = np.linspace(x_start, x_end, N) # 1D-array con coordenadas en x
y = np.linspace(y_start, y_end, N) # 1D-array con coordenadas en y
X, Y = np.meshgrid(x, y) # genera las matrices
Ahora definiremos las funciones que nos darán los campos de velocidad del doblete, del vórtice y de la corriente libre:
def get_velocity_doublet(strength, xd, yd, X, Y):
u = (-strength / (2 * math.pi) *
((X - xd)**2 - (Y - yd)**2) /
((X - xd)**2 + (Y - yd)**2)**2)
v = (-strength / (2 * math.pi) *
2 * (X - xd) * (Y - yd) /
((X - xd)**2 + (Y - yd)**2)**2)
return u, v
def get_velocity_vortex(strength, xv, yv, X, Y):
u = +strength / (2 * math.pi) * (Y - yv) / ((X - xv)**2 + (Y - yv)**2)
v = -strength / (2 * math.pi) * (X - xv) / ((X - xv)**2 + (Y - yv)**2)
return u, v
def get_velocity_uniform(strength):
u = strength * np.ones((N, N), dtype=float)
v = np.zeros((N, N), dtype=float)
return u, v
x_c, y_c = 0.0, 0.0 # posición del centro de los elementos
def plot_fields(kappa,gamma,u_inf):
u_doublet, v_doublet = get_velocity_doublet(kappa, x_c, y_c, X, Y)
u_vortex, v_vortex = get_velocity_vortex(gamma, x_c, y_c, X, Y)
u_uniform, v_uniform = get_velocity_uniform(u_inf)
fig,[ax1,ax2,ax3] = plt.subplots(1,3,figsize=(18,4))
ax1.streamplot(X, Y, u_doublet,v_doublet,
density=2, linewidth=1, arrowsize=2, arrowstyle='->')
ax2.streamplot(X, Y, u_vortex,v_vortex,
density=2, linewidth=1, arrowsize=2, arrowstyle='->')
ax3.streamplot(X, Y, u_uniform,v_uniform,
density=2, linewidth=1, arrowsize=2, arrowstyle='->')
ax1.set_title('Doblete')
ax1.set_xlabel("x")
ax1.set_ylabel("y")
ax1.set_aspect('equal', 'box')
ax1.set_xlim([-2,2])
ax1.set_ylim([-1,1])
ax2.set_title('Vórtice')
ax2.set_xlabel("x")
ax2.set_ylabel("y")
ax2.set_aspect('equal', 'box')
ax2.set_xlim([-2,2])
ax2.set_ylim([-1,1])
ax3.set_title('Corriente uniforme')
ax3.set_xlabel("x")
ax3.set_ylabel("y")
ax3.set_aspect('equal', 'box')
ax3.set_xlim([-2,2])
ax3.set_ylim([-1,1])
plot_fields(1,1,1)
xp = np.linspace(0, 2*math.pi, 100)
x_c, y_c = 0.0, 0.0 # posición del centro de los elementos
def cp_angle(alpha,gamma,u_inf,R):
U=-u_inf*np.sin(alpha)*2-gamma/(2*math.pi*R)
cp = 1-(U/u_inf)**2
return cp
def plot_cylinder(R,gamma,u_inf):
kappa = R**2 * (2 * math.pi * u_inf)
u_doublet, v_doublet = get_velocity_doublet(kappa, x_c, y_c, X, Y)
u_vortex, v_vortex = get_velocity_vortex(gamma, x_c, y_c, X, Y)
u_uniform, v_uniform = get_velocity_uniform(u_inf)
u_sum=u_doublet+u_vortex+u_uniform
v_sum=v_doublet+v_vortex+v_uniform
U=np.sqrt(u_sum*u_sum+v_sum*v_sum)
cp = 1.0-(U/u_inf)**2
fig,[ax2,ax] = plt.subplots(1,2,gridspec_kw={'width_ratios': [1, 4]},figsize=(16,4.7))
pt1 = ax.contourf(X, Y, cp, levels=np.linspace(-16, 1, 100))
ax.streamplot(X, Y, u_sum,v_sum,
density=2, linewidth=1, arrowsize=2, arrowstyle='->')
circle = plt.Circle((0, 0), radius=R, color='#CD2305', alpha=1)
ax.add_patch(circle)
arg=gamma/(4.0*math.pi*R*u_inf)
if np.abs(arg)<= 1:
theta = -np.arcsin(gamma/(4*math.pi*R*u_inf))
xpr=R*np.cos(theta)
ypr=R*np.sin(theta)
ax.plot(xpr,ypr,'ob')
ax.plot(-xpr,ypr,'ob')
ax.set_title('Cp')
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_aspect('equal', 'box')
ax.set_xlim([-2,2])
ax.set_ylim([-1,1])
plt.colorbar(pt1)
yp1 = cp_angle(xp,0,u_inf,R)
yp2 = cp_angle(xp,gamma,u_inf,R)
ax2.plot(xp,yp1,"--")
ax2.plot(xp,yp2)
ax2.set_title('Cp en el contorno')
ax2.set_xlabel("α")
ax2.set_ylabel("Cp")
interactive(plot_cylinder, R=(0.25,0.75, 0.05), gamma=(-8,8,0.2), u_inf=(1,2,0.1))