El desarrollo se realiza por partes, en el mismo orden del planteamiento de los literales
# 3ra Evaluación I Término 2018# Tema 1. Intersección de círculosimport numpy as np
import matplotlib.pyplot as plt
# literal a
fx1 = lambda x: np.sqrt(5-(x-4)**2)+4
fx2 = lambda x: -np.sqrt(5-(x-4)**2)+4
gx1 = lambda x: np.sqrt(16-x**2)
gx2 = lambda x: -np.sqrt(16-x**2)
# Rango inicial de análisis (visual)
a = -5; b = 7
muestras = 501
# PROCEDIMIENTO# Evalua los puntos en el rango
xi = np.linspace(a,b,muestras)
fx1i = fx1(xi)
fx2i = fx2(xi)
gx1i = gx1(xi)
gx2i = gx2(xi)
# SALIDA - Gráfica
plt.plot(xi,fx1i)
plt.plot(xi,fx2i)
plt.plot(xi,gx1i)
plt.plot(xi,gx2i)
plt.xlabel('x')
plt.ylabel('y')
plt.title('Intersección de círculos')
plt.grid()
plt.show()
# GRAFICAR las diferencias
a = 4 - np.sqrt(5)
b = 4 + np.sqrt(5)
# PROCEDIMIENTO
xi = np.linspace(a,b,muestras)
diferencia = fx2(xi) - gx1(xi)
# GRAFICA
plt.plot(xi,diferencia)
plt.axhline(0)
plt.xlabel('x')
plt.ylabel('y')
plt.title('diferencia entre círculos')
plt.grid()
plt.show()
# literal b -----------------------defnewton_raphson(funcionx, fxderiva, xi, tolera):
# funciónx y fxderiva en forma numérica# xi es el punto inicial de búsqueda
tramo = abs(2*tolera)
while (tramo>=tolera):
xnuevo = xi - funcionx(xi)/fxderiva(xi)
tramo = abs(xnuevo-xi)
xi = xnuevo
return(xi)
funcionx = lambda x: fx2(x) - gx1(x)
fxderiva = lambda x: (x-4)/np.sqrt(5-(x-4)**2)+x/np.sqrt(16-x**2)
tolera = 0.001
xi1 = a + tolera
xi2 = 3.5
raiz1 = newton_raphson(funcionx, fxderiva, xi1, tolera)
raiz2 = newton_raphson(funcionx, fxderiva, xi2, tolera)
# SALIDAprint('\n usando Newton-Raphson')
print('raices en: ', raiz1,raiz2)
_
2. Solución General de intersección de círculos
Una solución más general de la intersección de círculos, considerada como para una actividad de mayor duración, revisa previamente si existe un cruce de áreas entre los dos círculos y estima el intervalo donde se encuentran las raíces [xa,xb].
De existir esa posibilidad, con el intervalo anterior [xa,xb] busca por un método de búsqueda de raíces las coordenadas de la intersección de las circunferencias.
2.1 Buscar cruce de áreas entre dos círculos
El cruce de áreas entre dos círculos se determina comparando si la distancia entre la suma de los radios es mayor o igual a la distancia entre los centros de los círculos.
De cumplirse la condición anterior, es posible encontrar las intersecciones de los círculos. El valor xa se obtiene como el mayor entre los límites x hacia la izquierda de cada círculo, mientras que xb se obtiene como el límite x hacia la derecha entre los círculos.
Lo siguiente que hay que reconocer es cuál de las partes (superior e inferior) de cada círculo es necesario usar para encontrar las intersecciones. Esta sección es necesaria puesto que la fórmula que describe el círculo contiene una raiz cuadrada que puede se positiva o negativa, generando dos segmentos en cada círculo.
Por ejemplo, partiendo de la fórmula general de un círculo con centro en [x1,y1] y radio r1:
Con lo que se muestra la necesidad de identificar para cada círculo el sector arriba y abajo que interviene para encontrar las intersecciones. El orden del sector se establece con las posibles combinaciones de:
tabla de signos en raíz cuadrada para círculo
círculo 2 abajo
círculo2 arriba
círculo 1 abajo
[-1,-1]
[-1,1]
círculo 1 arriba
[ 1,-1]
[ 1,1]
El uso de cada combinación se estrablece en el vector de 1 y 0 con el siguiente orden:
2.2 Raíces como coordenadas de intersección entre dos círculos
Las coordenadas de intersección entre dos círculos se obtienen aplicando un método de búsqueda de raíces. Por ejemplo bisección, que para esta parte se usa el algoritmo de SciPy con la instrucción sp.bisect(fx,xa,xb,xtol=2e-12).
Para el caso más general, donde existen dos raíces que buscar, se divide el intervalo de busqueda [xa,xb] en dos medios segmentos [xa,xc] y [xc,xb]. Se aplica un método de búsqueda de raíces para cada subintervalo. Para minimizar errores de truncamiento, en cada busqueda de desplaza dx/10 cada xc hacia el lado que amplia el subintervalo de búsqueda.
Para el caso donde los círculos solo tienen un punto de contacto, se realiza una revisión considerando que el intervalo de búsqueda podría ser menor al valor de tolerancia del radio.
Por ejemplo, cuando la linea que une los centros de los círculos resulta paralelos al eje de las x, adicionalmete se topan en un solo punto, el algoritmo anterior indica que se usan todos los sectores de los círculos, dando como resultado cuatro raices iguales. El caso se corrige realizando la parte de sectores solo cuando la distancia entre [xa,xb] es mayor a cero.
El resultado se presenta como los vectores raizx y raizy.
Las intrucciones en Python para esta sección se describen a continuación:
defraices2circulos(x1,y1,r1,x2,y2,r2,tolera=2e-12):
''' busca las intersección entre 2 circulos
de centro y radio: x1,y1,r1 || x2,y2,r2
revisa con cruce2circulos()
'''
uncruce = cruce2circulos(x1,y1,r1,x2,y2,r2)
raizx = []; raizy = []
# si hay cruce de circulosiflen(uncruce)>0:
sectores = [[-1,-1],[-1,1],
[ 1,-1],[ 1,1]]
[xa,xb,ya,yb,sector] = uncruce
xc = (xa+xb)/2
dx = np.abs(xb-xa)
dy = np.abs(yb-ya)
k = 1 # se tocan en un puntoif dx>0: # se tocan en mas de un punto
k = len(sector)
for j inrange(0,k,1):
if sector[j]==1:
s1 = sectores[j][0]
s2 = sectores[j][1]
fx1 = lambda x: s1*np.sqrt(r1**2-(x-x1)**2)+y1
fx2 = lambda x: s2*np.sqrt(r2**2-(x-x2)**2)+y2
fx = lambda x: fx1(x)-fx2(x)
fa = fx(xa)
fb = fx(xb)
raiz1 = np.nan
raiz2 = np.nan
# intervalo/2 izquierda
xc = xc + dx/10
fc = fx(xc)
cambio = np.sign(fa)*np.sign(fc)
if cambio<0:
raiz1 = sp.bisect(fx,xa,xc,xtol=tolera)
# intervalo/2 derecha
xc = xc - 2*dx/10
fc = fx(xc)
cambio = np.sign(fc)*np.sign(fb)
if cambio<0:
raiz2 = sp.bisect(fx,xc,xb,xtol=tolera)
# si hay contacto en un bordeif dx<tolera*r1 and dy>0:
raiz1 = xa
if dy<tolera*r1 and dx>0:
raiz1 = x1
# Añade si existe raizifnot(np.isnan(raiz1)):
raizx.append(raiz1)
raizy.append(fx1(raiz1))
ifnot(np.isnan(raiz2)):
raizx.append(raiz2)
raizy.append(fx1(raiz2))
raices = [raizx,raizy]
return(raices)
Se utiliza una matriz de ceros para la iteración inicial. En el ejercicio se muestran cálculos para 3 nodos, el resto se realiza con el algoritmo en Python.
Para varias iteraciones se usa Δx =Δy = 1/4 = 0.25
y las ecuaciones para los valores en las fronteras o bordes de la placa
# 3Eva_IT2017_T4 EDP elíptica, placa desplazada# método iterativoimport numpy as np
# INGRESO# longitud en x
a = 1
b = 2
# longitud en y
c = 1
d = 2
# tamaño de paso
dx = 0.25
dy = 0.25
# funciones en los bordes de la placa
abajo = lambda x,y: x*np.log(x)
arriba = lambda x,y: x*np.log(4*(x**2))
izquierda = lambda x,y: y*np.log(y)
derecha = lambda x,y: 2*y*np.log(2*y)
# función de la ecuación
fxy = lambda x,y: x/y + y/x
# control de iteraciones
maxitera = 100
tolera = 0.0001
# PROCEDIMIENTO# tamaño de la matriz
n = int((b-a)/dx)+1
m = int((d-c)/dy)+1
# vectores con valore de ejes
xi = np.linspace(a,b,n)
yj = np.linspace(c,d,m)
# matriz de puntos muestra
u = np.zeros(shape=(n,m),dtype=float)
# valores en los bordes
u[:,0] = abajo(xi,yj[0])
u[:,m-1] = arriba(xi,yj[m-1])
u[0,:] = izquierda(xi[0],yj)
u[n-1,:] = derecha(xi[n-1],yj)
# valores interiores# para menos iteraciones
mitadx = int(n/2)
mitady = int(m/2)
promedio = (u[mitadx,0]+u[mitadx,m-1]+u[0,mitady]+u[n-1,mitady])/4
u[1:n-1,1:m-1] = promedio
# método iterativo
itera = 0
converge = 0
whilenot(itera>=maxitera or converge==1):
itera = itera +1
# copia u para calcular errores entre iteraciones
nueva = np.copy(u)
for i inrange(1,n-1):
for j inrange(1,m-1):
# usar fórmula desarrollada para algoritmo
u[i,j] = (u[i-1,j]+u[i+1,j]+u[i,j-1]+u[i,j+1]-(dy**2)*fxy(xi[i],yj[j]))/4
diferencia = nueva-u
erroru = np.linalg.norm(np.abs(diferencia))
if (erroru<tolera):
converge=1
# SALIDAprint('iteraciones: ',itera)
print('error entre iteraciones: ',erroru)
print('solución para u: ')
print(u)
# Gráficaimport matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
# matrices de ejes para la gráfica 3D
X, Y = np.meshgrid(xi, yj)
U = np.transpose(u) # ajuste de índices fila es x
figura = plt.figure()
grafica = Axes3D(figura)
grafica.plot_surface(X, Y, U, rstride=1, cstride=1, cmap=cm.Reds)
plt.title('EDP elíptica')
plt.xlabel('x')
plt.ylabel('y')
plt.show()