widget 4: o que é um concentrador de tensão?
#HIDDEN
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from ipywidgets import interactive, widgets
from mpl_toolkits.axisartist import SubplotZero
from matplotlib.patches import Ellipse, Rectangle
import numpy.ma as ma
from matplotlib.ticker import FormatStrFormatter
from IPython.display import display, clear_output
import warnings
warnings.filterwarnings("ignore")
#HIDDEN
def circle(C, R):
t=np.linspace(0,2*np.pi, 200)
return C+R*np.exp(1j*t)
def Juc(z, lam):#Joukowski transformation
return z+(lam**2)/z
def deg2radians(deg):
return deg*np.pi/180
def compute_lines(rho):
'''
Based on the Joukowski transformation of the potential flow past a cylinder.
For reference:
https://people.eng.unimelb.edu.au/asho/PotentialFlow/notes.pdf
https://github.com/luca6331/joukowskiAirfoilVisualization/blob/master/Report.pdf
https://nbviewer.jupyter.org/github/empet/Math/blob/master/Joukowski-airfoil.ipynb
'''
V_inf = 1
R = 1
lam = (R**2 + R*rho/2 - R*(8*R*rho + rho**2)**0.5/2)**0.5
alpha=deg2radians(0) # angle of attack
beta=deg2radians(0) # -beta is the argument of the complex no (Joukovski parameter - circle center)
center_c= 0 # Center of the circle
x=np.arange(-3.5, 3.5, 0.1)
y=np.arange(-5, 5, 0.1)
x,y=np.meshgrid(x,y)
z=x+1j*y
z=ma.masked_where(np.absolute(z-center_c)<=R, z)
Z=z-center_c
Z = -1j*Z
Gamma=-4*np.pi*V_inf*R*np.sin(beta+alpha)
U=np.zeros(Z.shape)
with np.errstate(all='ignore'):#avoid warning when evaluates np.log(0+1jy).
#In this case the arg is arctan(y/0)+cst
for m in range(Z.shape[0]):
for n in range(Z.shape[1]):
#U[m,n]=Gamma*np.log(Z[m,n]/R)/(2*np.pi)#
U[m,n]=Gamma*np.log((Z[m,n]*np.exp(-1j*alpha))/R)/(2*np.pi)
c_flow= V_inf*Z*np.exp(-1j*alpha) + (V_inf*np.exp(1j*alpha)*R**2)/Z - 1j*U #the complex flow
J=Juc(z, lam)
Circle=circle(0, R)
Airfoil=Juc(Circle, lam)# airfoil
return J, c_flow.imag, Airfoil, rho
def get_zone(point, zones):
for i, zone in enumerate(zones):
if zone.get_paths()[0].contains_point(point):
return i, zone
def html_ticks(ticks, id, ticks_pos=None):
html_str = f'''
<style>
.ruler{id} {{
position: relative;
width: 100%;
margin-top: 20px;
height: 0px;
}}
.ruler{id} .cm{id},
.ruler{id} .mm{id} {{
position: absolute;
border-left: 1px solid #555;
height: 0px;
}}
.ruler{id} .cm{id}:after {{
position: absolute;
bottom: -15px;
font: 11px/1 sans-serif;
}}
.ruler{id} .cm{id}:nth-of-type(1) {{
left: 0%;
}}
.ruler{id} .cm{id}:nth-of-type(1):after {{
content: "0.01";
}}
'''
for i, tick in enumerate(ticks[1:]):
if not ticks_pos:
html_str += f'\n .ruler{id} .cm{id}:nth-of-type({i+2}) {{left: {(i+1) * 100 / (len(ticks) - 1)}%;}}'
html_str += f'\n .ruler{id} .cm{id}:nth-of-type({i+2}):after {{content: "{ticks[i+1]}";}}'
else:
html_str += f'\n .ruler{id} .cm{id}:nth-of-type({i+2}) {{left: {ticks_pos[i+1]}%;}}'
html_str += f'\n .ruler{id} .cm{id}:nth-of-type({i+2}):after {{content: "{ticks[i+1]}";}}'
html_str += '\n</style>'
html_str += f"\n<div class='ruler{id}'>"
for i in range(len(ticks)):
html_str += f"\n<div class='cm{id}'></div>"
end_str = '</div>'
html_str += end_str
return html_str
#HIDDEN
np.seterr(all='ignore')
def f(rho, defect, show_lines):
fig, ax = plt.subplots(figsize=(6, 6))
r = Rectangle([-3.5, -4.75], 6.95, 9.5, facecolor='none', edgecolor='k', zorder=10)
if not defect:
if not show_lines:
ax.add_patch(r)
if show_lines:
xcoords = np.linspace(-3.5, 3.5, 50)
ax.add_patch(r)
for xc in xcoords:
perf = plt.axvline(x=xc, c='blue', lw=1)
perf.set_clip_path(r)
if defect:
if not show_lines:
R = 1
lam = (R**2 + R*rho/2 - R*(8*R*rho + rho**2)**0.5/2)**0.5
c = 1
b = c*rho**0.5
Circle=circle(0, R)
Airfoil=Juc(Circle, lam)
ax.plot(Airfoil.real, Airfoil.imag, c='k')
ax.add_patch(r)
if show_lines:
J, stream_func, Airfoil, rho = compute_lines(rho)
cp=ax.contour(J.real, J.imag, stream_func,levels=100, colors='blue', linewidths=1,
linestyles='solid')# this means that the flow is evaluated at Juc(z) since c_flow(Z)=C_flow(csi(Z))
ax.add_patch(r)
for col in cp.collections:
col.set_clip_path(r)
ax.plot(Airfoil.real, Airfoil.imag, c='k')
ax.set_xlim(-5.5, 5.5)
ax.set_ylim(-5.5, 5.5)
plt.annotate('', xy = (0, 4.725), \
xytext = (0, 5.5), fontsize = 20, \
color = '#303030', arrowprops=dict(edgecolor='black', arrowstyle = '<-'))
plt.text(0.25, 5.25, r'$\sigma_{app}$', fontsize=14)
plt.annotate('', xy = (0, -4.725), \
xytext = (0, -5.5), fontsize = 20, \
color = '#303030', arrowprops=dict(edgecolor='black', arrowstyle = '<-'))
plt.text(0.25, -5.5, r'$\sigma_{app}$', fontsize=14)
ax.axis('off')
ax.set_xlim(-5.5, 5.5)
ax.set_ylim(-5.5, 5.5)
fig.patch.set_facecolor((1.0, 0.0, 0.0, 0.0))
plt.show()
rho_slider_base = widgets.FloatSlider(value=0.01,
min=0.01,
max=1,
step=0.01,
description=r'Raio de\nCurvatura do Defeito, 𝜌',
readout=False,
readout_format='.2f',
style= {'description_width': '0px'})
show_lines_button = widgets.ToggleButton(False, description='Linhas de Força')
defect_button = widgets.ToggleButton(True, description='Adicionar o Defeito')
interactive_plot = interactive(f, show_lines=show_lines_button,
rho=rho_slider_base,
defect=defect_button)
rho_slider_title = widgets.HTMLMath(value=r'Raio de Curvatura do Defeito, 𝜌:')
rho_slider_display = widgets.HTMLMath(value=str(rho_slider_base.value))
rho_slider = widgets.VBox([rho_slider_title,
rho_slider_base,
rho_slider_display])
rho_slider.layout = widgets.Layout(align_items='center', width='100%')
def rho_slider_callback(rho_sli):
rho_slider_display.value = r"Raio de Curvatura do Defeito, 𝜌 = " + f'{rho_sli:.2f}'
rho_slider_ticks_HTML_str = html_ticks([0.01, 1], 'x')
rho_slider_ticks = widgets.HTML(rho_slider_ticks_HTML_str)
rho_slider_ticks.layout = widgets.Layout(width='290px', margin='0 0 -45px 0px',
pad='0 0 0 0', position='absolute')
rho_slider_ticked = widgets.VBox([rho_slider_ticks, rho_slider])
# rho_slider_ticked.layout = widgets.Layout(height='100%', position='absolute')
widgets.interactive_output(
rho_slider_callback,
{"rho_sli": rho_slider_base})
output = interactive_plot.children[-1]
# output.layout.height = '660px'
output = widgets.VBox([interactive_plot.children[-1],
show_lines_button,
defect_button,
rho_slider_ticked])
output.layout = widgets.Layout(display='flex',
flex_flow='column',
align_items='center',
align_content='center',
justify_content='center',
width='100%',
height='650px',
overflow='hidden')
interactive_plot.update()
output
comentários: