5.4 Fórmulas compuestas con Δx segmentos desiguales con Python

[ Concepto ] [ Algoritmo /función ] [ Gráfica ] [ diferencias entre tramos ]

..


Referencia: Chapra 21.3 p640

En la práctica, existen muchas situaciones con segmentos o tramos de tamaños desiguales. Por ejemplo, los datos obtenidos en experimentos frecuentemente son de este tipo. Para integración numérica, se busca identificar los segmentos de igual tamaño y aplicar: Simpson 3/8, Simpson 1/3  o trapecio.

Integral Fórrmula Compuesta Simpson 3/8, Simpson 1/3, Trapecio

El algoritmo se desarrolla al incorporar cada método como integral numérico de "fórmulas compuestas".

[ Concepto ] [ Algoritmo /función ] [ Gráfica ] [ diferencias entre tramos ]


1. Ejercicio

Los datos de ejemplo son:

xi = [1.        , 1.22222222, 1.44444444, 1.66666667,
      1.88888889, 2.11111111, 2+1/3, 2+1/3+0.2,
      2+1/3+0.4, 3.        ]
fi = [0.84147098, 1.03905509, 1.19226953, 1.28506615,
      1.30542157, 1.24598661, 1.10453193, 0.90952929,
      0.65637234, 0.24442702]

[ Concepto ] [ Algoritmo /función ] [ Gráfica ] [ diferencias entre tramos ]
..


2. Algoritmo como función en Python

Los resultados del algoritmo muestran los detalles parciales al aplicar cada método acorde a los requisitos de cada uno en el siguiente orden: Tres tramos iguales permiten aplicar Simpson de 3/8, Dos tramos iguales permiten aplicar Simpson de 1/3, Un tramo desigual le aplica trapecio.

Los métodos usados de identifican por el arreglo de tramos iguales:

Fórmulas compuestas, tramos: 9
métodos 3:Simpson3/8, 2:Simpson1/3, 1:Trapecio, 0:usado
tramos iguales en xi: [3 0 0 3 0 0 2 0 1 0]
 Simpson 3/8 : 0.7350425751495739
 Simpson 3/8 : 0.8369852099634817
 Simpson 1/3 : 0.3599347620000003
 trapecio : 0.1201065813333333
tramos iguales en xi: [3 0 0 3 0 0 2 0 1 0]
Integral: 2.0520691284463894

Instrucciones en Python

# Integración Simpson 3/8, Simpson 1/3 y trapecio
# tramos no iguales, formulas compuestas
import numpy as np

# INGRESO
xi = [1.        , 1.22222222, 1.44444444, 1.66666667,
      1.88888889, 2.11111111, 2+1/3, 2+1/3+0.2,
      2+1/3+0.4, 3.        ]
fi = [0.84147098, 1.03905509, 1.19226953, 1.28506615,
      1.30542157, 1.24598661, 1.10453193, 0.90952929,
      0.65637234, 0.24442702]

# PROCEDIMIENTO
def simpson_compuesto(xi,fi,vertabla=False,casicero=1e-7):
    '''Método compuesto Simpson 3/8, Simpson 1/3 y trapecio
    salida: integral,cuenta_h
    '''
    # vectores como arreglo, numeros reales
    xi = np.array(xi,dtype=float)
    fi = np.array(fi,dtype=float)
    n = len(xi)

    # Método compuesto Simpson 3/8, Simpson 1/3 y trapecio
    cuenta_h = (-1)*np.ones(n,dtype=int) # sin usar
    suma = 0 # integral total
    suma_parcial =[] # integral por cada método
    i = 0
    while i<(n-1): # i<tramos, al menos un tramo
        tramo_usado = False
        h = xi[i+1]-xi[i] # tamaño de paso, supone constante
        
        # tres tramos iguales
        if (tramo_usado==False) and (i+3)<n:
            d2x = np.diff(xi[i:i+4],2) # diferencias entre tramos
            errado = np.max(np.abs(d2x))
            if errado<casicero: # Simpson 3/8
                S38 = (3/8)*h*(fi[i]+3*fi[i+1]+3*fi[i+2]+fi[i+3])
                suma = suma + S38
                cuenta_h[i:i+3] = [3,0,0] # Simpson 3/8
                suma_parcial.append(['Simpson 3/8',S38])
                i = i+3
                tramo_usado = True

        # dos tramos iguales
        if (tramo_usado==False) and (i+2)<n:
            d2x = np.diff(xi[i:i+3],2) # diferencias entre tramos
            errado = np.max(np.abs(d2x))
            if errado<casicero: # Simpson 1/3
                S13 = (h/3)*(fi[i]+4*fi[i+1]+fi[i+2])
                suma = suma + S13
                cuenta_h[i:i+2] = [2,0]
                suma_parcial.append(['Simpson 1/3',S13])
                i = i+2
                tramo_usado = True
                
        # un tramo igual
        if (tramo_usado == False) and (i+1)<n:
            trapecio = (h/2)*(fi[i]+fi[i+1])
            suma = suma + trapecio
            cuenta_h[i:i+1] = [1] # usar trapecio
            suma_parcial.append(['trapecio',trapecio])
            i = i+1
            tramo_usado = True
            
    cuenta_h[n-1] = 0 # ultima casilla
    
    if vertabla==True: #mostrar datos parciales
        print('Fórmulas compuestas, tramos:',n-1)
        print('métodos 3:Simpson3/8, 2:Simpson1/3, 1:Trapecio, 0:usado')
        print('tramos iguales en xi:',cuenta_h)
        for unparcial in suma_parcial:
            print('',unparcial[0],':',unparcial[1])
    
    return(suma,cuenta_h)

# usa función
area,cuenta_h = simpson_compuesto(xi,fi,vertabla=True)

# SALIDA
print('tramos iguales en xi:',cuenta_h)
print('Integral:',area)

[ Concepto ] [ Algoritmo /función ] [ Gráfica ] [ diferencias entre tramos ]
..


3. Gráfica de segmentos desiguales

En la gráfica se diferencian los métodos aplicados por colores.

Se añaden al algoritmo anterior las siguientes instrucciones,

# GRAFICA ---------------------
import matplotlib.pyplot as plt
n = len(xi) # muestras
tramos = n-1
metodotipo = [['na','grey'],
              ['Trapecio','lightblue'],
              ['Simpson 1/3','lightgreen'],
              ['Simpson 3/8','cyan']]
# etiquetas linea
plt.plot(xi[0],fi[0],'o', label=metodotipo[1][0],
         color=metodotipo[1][1])
plt.plot(xi[0],fi[0],'o', label=metodotipo[2][0],
         color=metodotipo[2][1])
plt.plot(xi[0],fi[0],'o', label=metodotipo[3][0],
         color=metodotipo[3][1])

# relleno y bordes
tipo = 0
for i in range(0,tramos,1):
    if cuenta_h[i]>0:
        tipo = cuenta_h[i]
    plt.fill_between([xi[i],xi[i+1]],
                     [fi[i],fi[i+1]],[0,0],
                     color=metodotipo[tipo][1])        
# Divisiones entre tramos
for i in range(0,n,1):
    tipolinea = 'dashed' # inicia un método
    if cuenta_h[i]==0: 
        tipolinea = 'dotted' # dentro de un método
    plt.vlines(xi[i],0,fi[i],linestyle=tipolinea,
               color='orange')

# puntos de xi,fi
plt.plot(xi,fi,marker='o',linestyle='dashed',
         color='orange',label='f(xi)')

plt.axhline(0,color='black') # eje x
plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('Integral numérico xi,fi con Fórmulas Compuestas')
plt.legend()
plt.tight_layout()
plt.show()

[ Concepto ] [ Algoritmo /función ] [ Gráfica ] [ diferencias entre tramos ]
..


4. Diferencias entre tramos xi

Las diferencias entre tramos pueden ser analizadas con una gráfica, usando operaciones de diferencias finitas.

Diferencias Tramos XiResultado del algoritmo:

d1xi: [0.22222222 0.22222222 0.22222223 0.22222222 0.22222222 0.22222222
 0.2        0.2        0.26666667]
d2xi: [ 2.22044605e-16  9.99999972e-09 -9.99999972e-09 -2.22044605e-16
  3.33333361e-09 -2.22222233e-02 -4.44089210e-16  6.66666667e-02]
diferencia máxima: 4.440892098500626e-16  en i: 7
tramos iguales en xi: [3 0 0 2 0 1 2 0 1 0]

Instrucciones en Python

# revisa xi por
# tramos equidistantes y no iguales
import numpy as np

# INGRESO
xi = [1.        , 1.22222222, 1.44444444, 1.66666667,
      1.88888889, 2.11111111, 2+1/3, 2+1/3+0.2,
      2+1/3+0.4, 3.        ]

# PROCEDIMIENTO
casicero=1e-7
# vectores como arreglo, números reales
xi = np.array(xi,dtype=float)
n = len(xi)

# diferencias finitas en xi
d1xi = np.diff(xi,1) # magnitud de tramos
d2xi = np.diff(xi,2) # diferencia entre tramos
errado = np.max(np.abs(d2xi)) # error mayor
donde = np.argmax(np.abs(d2xi)) # donde es error mayor

# revisa tramos iguales
cuenta_h = -1*np.ones(n,dtype=int)
i = 0
while i<(n-1): # i<tramos, al menos un tramo
    tramo_usado = False
    
    # tres tramos iguales
    if (tramo_usado==False) and (i+3)<n:
        d2x = np.diff(xi[i:i+4],2) # diferencias entre tramos
        errado = np.max(np.abs(d2x))
        if errado<casicero: # Simpson 3/8
            cuenta_h[i:i+3] = [3,0,0]
            i = i+3
            tramo_usado==True
            
    # dos tramos iguales
    if (tramo_usado==False) and (i+2)<n:
        d2x = np.diff(xi[i:i+3],2) # diferencias entre tramos
        errado = np.max(np.abs(d2x))
        if errado<casicero: # Simpson 1/3
            cuenta_h[i:i+2] = [2,0]
            i = i+2
            tramo_usado = True
            
    # un tramo igual
    if (tramo_usado == False) and (i+1)<n:
        cuenta_h[i:i+1] = [1] # usar trapecio
        i = i+1
        tramo_usado = True

    cuenta_h[n-1] = 0 # ultima casilla

# SALIDA
print('d1xi:',d1xi)
print('d2xi:',d2xi)
print('diferencia máxima:',errado,' en i:',donde)

print('tramos iguales en xi:',cuenta_h)

# GRAFICA
import matplotlib.pyplot as plt
m = len(xi)-1

plt.subplot(311) # diferencia entre tramos
plt.stem(d2xi,linefmt=':',markerfmt ='C03')
plt.plot(np.ones(n)*casicero,color='red',linestyle='dotted')
plt.xlim(-0.1,m+0.1)
plt.ylabel('diferencia tramos')
plt.title('Diferencia entre tramos, muestras:'+str(n))

plt.subplot(312) # tramos
plt.stem(d1xi,linefmt=':',markerfmt ='C02')
plt.xlim(-0.1,m+0.1)
plt.ylabel('|tramo|')

plt.subplot(313) # muestras
plt.stem(xi,linefmt=':',markerfmt ='C01')
plt.xlim(-0.1,m+0.1)
plt.ylabel('xi')
plt.xlabel('muestra i')

plt.tight_layout()
plt.show()

[ Concepto ] [ Algoritmo /función ] [ Gráfica ] [ diferencias entre tramos ]


Unidades