Etiqueta: análisis numérico

  • s1Eva_IIIT2007_T2 Función Cobb-Douglas

    Ejercicio: 1Eva_IIIT2007_T2 Función Cobb-Douglas

    [ a1 interpola filas ] [a2 interpola punto Y] [ b1 interpola columnas ] [ b2 raíz Newton-Raphson]  [ Algoritmo ]
    ..


    literal a.1 Interpola tabla por filas

    Se usa la tabla para plantear los polinomios usando los datos de cada fila. Se evalúa el polinomio con el valor de K=25 (en miles) para completar los datos de la columna K=25

     L\K (miles $) 10 20 25 30 40
    0 0 0 0 0
    10 11.0000 13.0813 14.4768 15.5563
    20 18.4997 22.0000 24.3470 26.1626
    25 Y
    30 25.0746 29.8189 33.0000 35.4608

    Para la fila L=0 no es necesario realizar un polinomio, pues se observa que para 0 trabajadores la producción es nula, no existe producción p(K)=0  y pK(25)=0.

    Para la fila L=10, se disponen de 4 puntos, por lo que se plantea un polinomio de grado 3:

    P_{L10}(K) = 11\frac{(K-20)(K-30)(K-40)}{(10-20)(10-30)(10-40)} + + 13.0813\frac{(K-10)(K-30)(K-40)}{(20-10)(20-30)(20-40)} + + 14.4768\frac{(K-10)(K-20)(K-40)}{(30-10)(30-20)(30-40)} + + 15.5563\frac{(k-10)(k-20)(k-30)}{(40-10)(40-20)(40-30)}

    Con el algoritmo se simplifica la expresión:

    P_{L10}(K) =0.0000616335 K^3 - 0.0071269*K^2 + 0.378796 K + 7.8630

    Se evalúa el polinomio con K=25

    P_{L10}(K) =0.0000616335 (25)^3 - 0.0071269*(25)^2 + 0.378796 (25) + 7.8630 P_{L10}(25) = 13.84166

    Se observan los resultados encontrados en la primera gráfica:

    Cobb Douglas

    Se continua el ejercicio usando los algoritmos para encontrar los polinomios de Lagrange obteniendo:

     **** literal a:
    Polinomio de Lagrange por fila de L
    fila: 0 , li[fila]: 0  , polinomio pk :
    0
     pk[25]: 0
    ___
    fila: 1 , li[fila]: 10  , polinomio pk :
                         3                        2                               
    6.16333333333342e-5*K  - 0.00712699999999999*K  + 0.378796666666668*K + 7.86309999999999
     pk[25]: 13.8416625000000
    ___
    fila: 2 , li[fila]: 20  , polinomio pk :
                          3              2                                
    0.000103649999999999*K  - 0.0119855*K  + 0.637039999999995*K + 13.2242
     pk[25]: 23.2787937499999
    ___
    fila: 3 , li[fila]: 30  , polinomio pk :
                         3                       2                                
    0.00014048333333333*K  - 0.0162449999999998*K  + 0.863441666666663*K + 17.9242
     pk[25]: 31.5521687500000
    ___
     Datos para el polinomio de L
    li:
    [ 0 10 20 30]
    k_buscado:
    [0, 13.8416625000000, 23.2787937499999, 31.5521687500000]
    

    [ a1 interpola filas ] [a2 interpola punto Y] [ b1 interpola columnas ] [ b2 raíz Newton-Raphson]  [ Algoritmo ]

    ..


    literal a.2 Interpola un punto en Y con K=25

    Con los datos obtenidos se genera el siguiente polinomio P(L), que corresponde a la parte derecha de la gráfica mostrada.

    P_{k=25}(L) = 0\frac{(L-10)(L-20)(L-30)}{(0-10)(0-20)(0-30)} + + 13.84166\frac{(L-0)(L-20)(L-30)}{(10-0)(10-20)(10-30)} + + 23.27879\frac{(L-0)(L-10)(L-30)}{(20-0)(20-10)(20-30)} + + 31.55216\frac{(L-0)(L-10)(L-20)}{(30-0)(30-10)(30-20)}

    simplificando con el algoritmo se tiene:

    P_{k=25}(L) = 00.00054012 L^3 - 0.038226 L^2 + 1.71241 L

    evaluando el polinomio con L=25

    P_{k=25}(L) = 00.00054012 (25)^3 - 0.038226 (25)^2 + 1.71241 (25) P_{k=25}(L) = 27.358402

    Con los datos obtenidos se realiza la gráfica en 3D marcando los puntos calculados con los polinomios.

    Cobb Douglas Y[L,K]

    [ a1 interpola filas ] [a2 interpola punto Y] [ b1 interpola columnas ] [ b2 raíz Newton-Raphson]  [ Algoritmo ]

    ..


    literal b.1 Interpola tabla por columnas

     L\K (miles $) 10 20 K=? 30 40
    0 0 0 0 0
    10 11.0000 13.0813 14.4768 15.5563
    20 18.4997 22.0000 24.3470 26.1626
    25 Y=30
    30 25.0746 29.8189 33.0000 35.4608

    Se repite el ejercicio del literal a, con el mismo algoritmo para no rescribir todo por las filas por columnas. En el algoritmo se intercambian las filas por columnas y se transpone la matriz.

    # INGRESO 
    
    ...
    # Se intercambian los valores de fila columna para repetir el algoritmo
    # obteniendo Y(L=25,k)
    M = np.transpose(M)
    kj = [0, 10, 20, 30]
    li = [10, 20, 30, 40]
    
    l_busca = 25 # trabajadores
    k_busca = 25 # inversión en miles de $
    

    Se ajustan las etiquetas de las gráficas y se obtiene el polinomio a usar, que es la producción Y(k) para un capital K dado:

    Y(K) = P_{L=25}(K) = 
    0.000121812500000016*K**3 - 0.0140857812500013*K**2 +
     0.748676562500027*K + 15.5417812499999
    Y(K) = 0.00012181 K^3 - 0.014085 K^2 + 0.74867 K + 15.54178

    [ a1 interpola filas ] [a2 interpola punto Y] [ b1 interpola columnas ] [ b2 raíz Newton-Raphson]  [ Algoritmo ]

    ..


    literal b.2 raíz con Newton-Raphson

    Para el algoritmo de Newton- Raphson, el ejercicio se plantea igualando el polinomio al valor buscado de producción Y=30. Se escribe luego la expresión en como f(x)=0 y f'(x):.

    0.00012181 K^3 - 0.014085 K^2 + 0.74867 K + 15.54178 = 30 f(K) = 0.00012181 K^3 - 0.014085 K^2 + 0.74867 K + 15.54178 - 30 f'(K) = 0.0001218(3) K^2 - 0.014085(2) K+ 0.74867 f'(K) = 0.00036543 K^2 - 0.02817 K+ 0.74867

    Usando la gráfica se inicia con K0=30, por ser el valor mas cercano de los puntos conocidos a Y=30, se obtienen los siguientes resultados:

    itera = 0

    f(30) = 0.00012181 (30)^3 - 0.014085 (30)^2 + 0.74867 (30) + + 15.54178 - 30 = -1.3862 f'(30) = 0.00036543 (30)^2 - 0.02817 (30)+ 0.74867 = 0.2325 K_{1} = 30 -\frac{-1.3862}{0.2325} = 35.963 errado = |35.963 -30| = 5.963

    itera = 1

    f(35.963) = 0.00012181 (35.963)^3 - 0.014085 (35.963)^2 + + 0.74867 (35.963) + 15.54178 - 30 = -0.0854 f'(35.963) = 0.00036543 (35.963)^2 - 0.02817 (35.963) + 0.74867 = 0.2082 K_{2} = 35.963 -\frac{-0.0854}{0.2082} = 36.3734 errado = |36.3734 -35.963| = 0.4104

    itera = 2

    f( 36.3734) = 0.00012181 ( 36.3734)^3 - 0.014085 ( 36.3734)^2 + + 0.74867 ( 36.3734) + 15.54178 - 30 = -0.00016955 f'( 36.3734) = 0.00036543 ( 36.3734)^2 - 0.02817 ( 36.3734)+ + 0.74867 = 0.20751 K_{3} = 36.3734 -\frac{-0.00016955}{0.20751} = 36.374 errado = |36.374 - 36.3734| = 0.00081705

    Se observa que el error disminuye en cada iteración, por lo que el método converge.

    Se sigue con las iteraciones usando el algoritmo:

    método de Newton-Raphson
    i ['xi', 'fi', 'dfi', 'xnuevo', 'tramo']
    0 [30.     -1.3862  0.2325 35.963   5.963 ]
    1 [35.963  -0.0854  0.2082 36.3734  0.4104]
    2 [ 3.6373e+01 -1.6955e-04  2.0751e-01  3.6374e+01  8.1705e-04]
    3 [ 3.6374e+01 -3.8858e-08  2.0751e-01  3.6374e+01  1.8726e-07]
    raíz en:  36.3742052500759
    

    Se encuentra la raíz en 36.3741, que corresponde a una inversión K un poco mas de 36 mil dólares para una producción Y de 30 mil unidades.

    Cobb Douglas K para Y-30[ a1 interpola filas ] [a2 interpola punto Y] [ b1 interpola columnas ] [ b2 raíz Newton-Raphson]  [ Algoritmo ]

    ..


    Instrucciones en Python. literal a

    #1Eva_IIIT2007_T2 Función Cobb-Douglas
    # Interpolacion de Lagrange
    import numpy as np
    import matplotlib.pyplot as plt
    import sympy as sym
    
    def interpola_lagrange(xi,yi):
        '''
        Interpolación con método de Lagrange
        resultado: polinomio en forma simbólica
        '''
        # PROCEDIMIENTO
        n = len(xi)
        x=sym.Symbol('x')
        # Polinomio
        polinomio = 0*x # inicializa con cero
        for i in range(0,n,1):
            # Termino de Lagrange
            termino = 1
            for j  in range(0,n,1):
                if (j!=i):
                    termino = termino*(x-xi[j])/(xi[i]-xi[j])
            polinomio = polinomio + termino*yi[i]
        # Expande el polinomio
        polinomio = polinomio.expand()
        return(polinomio)
    
    # INGRESO
    M = [[ 0,       0,       0,       0     ],
         [11.0000, 13.0813, 14.4768, 15.5563],
         [18.4997, 22.0000, 24.3470, 26.1626],
         [25.0746, 29.8189, 33.0000, 35.4608]]
    li = [0, 10, 20, 30]
    kj = [10, 20, 30, 40]
    
    l_busca = 25 # trabajadores
    k_busca = 25 # inversion en miles de $
    
    # PROCEDIMIENTO
    M = np.array(M)
    tamano = np.shape(M)
    n = tamano[0]
    m = tamano[1]
    x,K,L = sym.symbols('x,K,L')
    
    # Literal a.1 Interpola polinomio pk
    # por fila de trabajadores L
    # evalua en k_busca, inversiones en miles
    poli_fila = []
    pk_columna =[]
    for fila in range(0,n,1):
        pk = interpola_lagrange(kj,M[fila,:])
        pk = pk.subs(x,K)
        poli_fila.append(pk)
        pk_busca = poli_fila[fila].subs(K,k_busca)
        pk_columna.append(pk_busca)
    
    # Interpola un polinomio en columna de inversiones pk_columna
    # evalua en l_busca
    pkl_busca = interpola_lagrange(li,pk_columna)
    pkl_busca = pkl_busca.subs(x,L)
    Ykl_busca = pkl_busca.subs(L,l_busca)
    
    # SALIDA
    np.set_printoptions(precision=4)
    print(' **** literal a:')
    print('___ Polinomio por fila de trabajadores L')
    for fila in range(0,n,1):
        print(fila,', L['+str(fila)+']=',li[fila], ', pk(K) :')
        print(poli_fila[fila])
        print(' pk['+str(k_busca)+']:',pk_columna[fila])
        print('___')
    print('\n Datos para el polinomio de L')
    print('     Li: ',li)
    print('k_busca: ',pk_columna)
    print('Polinomio p(L):')
    print(pkl_busca)
    print('Y[l_busca,k_busca]: ',Ykl_busca)
    
    # Grafica de P(k) por cada L
    muestras = 20
    xk = np.linspace(min(kj),max(kj),muestras)
    
    plt.subplot(121)
    for fila in range(0,n,1):
        pk = poli_fila[fila]
        if pk.has(K):
            pk_lambda = sym.lambdify(K,pk)
            pkx = pk_lambda(xk)
        else:
            nk = len(xk)
            pkx = np.ones(nk)*float(pk)
        plt.plot(xk,pkx, label='pk(K);li='+str(li[fila]))
        plt.plot(k_busca,pk_columna[fila],'o')
    plt.ylabel('p(K)')
    plt.xlabel('K inversiones en miles')
    plt.axvline(k_busca, linestyle ='dashed')
    plt.title('Polinomios pk(K)')
    plt.legend()
    
    # Grafica de p(L) en k_busca 
    xl = np.linspace(min(li),max(li),muestras)
    pl_lambda = sym.lambdify(L,pkl_busca)
    plx = pl_lambda(xl)
    
    plt.subplot(122)
    plt.plot(xl,plx, label='p(L)')
    plt.plot(li,pk_columna,'o', label='[li,pk(K)]')
    plt.axvline(l_busca, linestyle ='dashed')
    plt.plot(l_busca,Ykl_busca,'o')
    plt.ylabel('p(L)')
    plt.xlabel('L trabajadores')
    plt.title('Polinomio pl(L)')
    plt.legend()
    # plt.show()
    
    # Grafica 3D
    from mpl_toolkits.mplot3d import axes3d
    X, Y = np.meshgrid(kj,li)
    figura = plt.figure()
    ax = figura.add_subplot(111, projection = '3d')
    ax.plot_wireframe(X,Y,M)
    ax.plot(k_busca,l_busca,Ykl_busca,'o',label='(25,25,Y)')
    ax.plot(k_busca*np.ones(len(li)),li,pk_columna,'o')
    ax.set_xlabel('K inversion')
    ax.set_ylabel('L trabajadores')
    ax.set_zlabel('Y producción')
    ax.set_title('Cobb-Douglas')
    plt.show()
    

    [ a1 interpola filas ] [a2 interpola punto Y] [ b1 interpola columnas ] [ b2 raíz Newton-Raphson]  [ Algoritmo ]

    Instrucciones en Python. literal b

    #1Eva_IIIT2007_T2 Función Cobb-Douglas
    # Interpolacion de Lagrange # Newton-Raphson
    import numpy as np
    import matplotlib.pyplot as plt
    
    def newton_raphson(fx,dfx,xi, tolera, iteramax=100, vertabla=False, precision=4):
        '''
        funciónx y fxderiva en forma numérica lambda
        xi es el punto inicial de búsqueda
        '''
        itera=0
        tramo = abs(2*tolera)
        if vertabla==True:
            print('i', ['xi','fi','dfi', 'xnuevo', 'tramo'])
            np.set_printoptions(precision)
        while (tramo>=tolera and itera<iteramax):
            fi = fx(xi)
            dfi = dfx(xi)
            xnuevo = xi - fi/dfi
            tramo = abs(xnuevo-xi)
            if vertabla==True:
                print(itera,np.array([xi,fi,dfi,xnuevo,tramo]))
            xi = xnuevo
            itera = itera + 1
        if itera>=iteramax:
            xi = np.nan
            print('itera: ',itera, 'No converge,se alcanzó el máximo de iteraciones')
        return(xi)
    
    # INGRESO
    y_busca = 30
    fx  = lambda K: 0.0001218125*K**3 - 0.0140857812500013*K**2 + 0.748676562500027*K + 15.5417812499999 -y_busca
    dfx = lambda K: 0.00036543*K**2 - 0.02817*K + 0.748676562500027
    
    x0 = 30
    tolera = 0.00001
    muestras = 20
    
    # PROCEDIMIENTO
    respuesta = newton_raphson(fx,dfx,x0, tolera, vertabla=True)
    # SALIDA
    print('raíz en: ', respuesta)
    
    # Grafica
    xl = np.linspace(0,40,muestras)
    plx = fx(xl)
    plt.plot(xl,plx, label='Y(k)')
    plt.axhline(0,linestyle='dotted')
    plt.ylabel('f(K)')
    plt.xlabel('K inversiones en miles')
    plt.title('f(K) = Y(K)-'+str(y_busca))
    plt.show()
    

    [ a1 interpola filas ] [a2 interpola punto Y] [ b1 interpola columnas ] [ b2 raíz Newton-Raphson]  [ Algoritmo ]

  • s1Eva_IIIT2007_T1_AN Container: Refrigeradoras y Cocinas

    Ejercicio: 1Eva_IIIT2007_T1 Container: Cocinas y Refrigeradoras

    literal a

    Considerando  como  x la cantidad de refrigeradoras, y cantidad de cocinas, las ecuaciones a plantear son:

    \begin{cases} 200 x + 100 y = 1000 \\ 2 x + 1.05 y = 10.4 \end{cases}

    La forma matricial del ejercicio se convierte a:

    \begin{pmatrix} 200 & 100 \\ 2 & 1.05\end{pmatrix} \begin{pmatrix}x \\ y \end{pmatrix} = \begin{pmatrix} 1000 \\10.4 \end{pmatrix}

    la matriz aumentada es

    \begin{pmatrix} 200 & 100 & 1000\\ 2 & 1.05 & 10.4\end{pmatrix}

    Para el pivoteo parcial por filas, dado que el mayor valor de la primera columna se encuentra en la diagonal, no se requiere y la matriz aumentada se mantiene igual.

    Para el proceso de eliminación hacia adelante, se incia con el pivote=200

    factor = \frac{2}{200} = 0.01

    que se aplica a la segunda fila

             [ 200.  100.     1000  ]
    -(2/200)*[   2.    1.05     10.4]
    _________________________________
           = [   0.     0.05     0.4]

    con lo que la matriz queda:

    \begin{pmatrix} 200 & 100 & 1000\\ 0 & 0.05 & 0.4\end{pmatrix}

    Se aplica sustitución hacia atrás, desde la última fila:

    0.05 y = 0.4 y = \frac{0.4}{0.05 } = 8

    para la primera fila:

    200 x+100(8)=1000 200 x=1000-100 (8) x=\frac{1000 - 100 (8)}{200} = 1

    siendo la respuesta [1,8]

    Con el algoritmo se obtiene:

    Matriz aumentada
    [[ 200.    100.   1000.  ]
     [   2.      1.05   10.4 ]]
    Pivoteo parcial:
      Pivoteo por filas NO requerido
    Elimina hacia adelante:
      factor:  0.01  para fila:  1
    [[2.e+02 1.e+02 1.e+03]
     [0.e+00 5.e-02 4.e-01]]
    solución: 
    [1. 8.]
    >>>

    literal b

    Matriz aumentada
    [[ 200.   100.  1000. ]
     [   2.     1.1   10.4]]
    Pivoteo parcial:
      Pivoteo por filas NO requerido
    Elimina hacia adelante:
     fila 0 pivote:  200
       factor:  0.01  para fila:  1
    [[2.e+02 1.e+02 1.e+03]
     [0.e+00 1.e-01 4.e-01]]
    solución: 
    [3. 4.]
    >>> 
    

    literal c

    Observación: el pequeño cambio de volumen de la cocina no es consistente con los resultados.

    El asunto es que la forma de la refrigeradora o cocina no se adapta al volumen disponible, pues son objetos rígidos. Por lo que el sistema de ecuaciones estaría mal planteado.
    Las ecuaciones tendrían sentido si esta diseñando el mejor "tamaño" para que entren la mayor cantidad dentro de un container, sin embargo los tamaños de las refrigeradoras y cocinas se encuentran estandarizados.

    Revisamos el número de condición, que resulta ser del orden de 104, lo que confirma que el sistema está mal condicionado.

    Usando la el valor de 1.05

    >>> C = np.concatenate((A,B),axis=1)
    >>> C
    array([[  200. ,   100. ,  1000.  ],
           [    2. ,     1.05,    10.4]])
    >>> np.linalg.cond(C)
    12926.000640466344
    

    Algoritmo en Python

    # 1Eva_IIIT2007_T1 Container: Cocinas y Refrigeradoras
    import numpy as np
    
    def pivoteafila(A,B,vertabla=False):
        '''
        Pivotea parcial por filas
        Si hay ceros en diagonal es matriz singular,
        Tarea: Revisar si diagonal tiene ceros
        '''
        A = np.array(A,dtype=float)
        B = np.array(B,dtype=float)
        # Matriz aumentada
        nB = len(np.shape(B))
        if nB == 1:
            B = np.transpose([B])
        AB  = np.concatenate((A,B),axis=1)
        
        if vertabla==True:
            print('Matriz aumentada')
            print(AB)
            print('Pivoteo parcial:')
        
        # Pivoteo por filas AB
        tamano = np.shape(AB)
        n = tamano[0]
        m = tamano[1]
        
        # Para cada fila en AB
        pivoteado = 0
        for i in range(0,n-1,1):
            # columna desde diagonal i en adelante
            columna = np.abs(AB[i:,i])
            dondemax = np.argmax(columna)
            
            # dondemax no es en diagonal
            if (dondemax != 0):
                # intercambia filas
                temporal = np.copy(AB[i,:])
                AB[i,:] = AB[dondemax+i,:]
                AB[dondemax+i,:] = temporal
    
                pivoteado = pivoteado + 1
                if vertabla==True:
                    print(' ',pivoteado, 'intercambiar filas: ',i,'y', dondemax)
        if vertabla==True:
            if pivoteado==0:
                print('  Pivoteo por filas NO requerido')
            else:
                print(AB)
        return(AB)
    
    def gauss_eliminaAdelante(AB,vertabla=False, casicero = 1e-15):
        ''' Gauss elimina hacia adelante
        tarea: verificar términos cero
        '''
        tamano = np.shape(AB)
        n = tamano[0]
        m = tamano[1]
        if vertabla==True:
            print('Elimina hacia adelante:')
        for i in range(0,n,1):
            pivote = AB[i,i]
            adelante = i+1
            if vertabla==True:
                print(' fila',i,'pivote: ', pivote)
            for k in range(adelante,n,1):
                if (np.abs(pivote)>=casicero):
                    factor = AB[k,i]/pivote
                    AB[k,:] = AB[k,:] - factor*AB[i,:]
                    if vertabla==True:
                        print('   factor: ',factor,' para fila: ',k)
                else:
                    print('  pivote:', pivote,'en fila:',i,
                          'genera division para cero')
        if vertabla==True:
            print(AB)
        return(AB)
    
    def gauss_sustituyeAtras(AB,vertabla=False, casicero = 1e-15):
        ''' Gauss sustituye hacia atras
        '''
        tamano = np.shape(AB)
        n = tamano[0]
        m = tamano[1]
        # Sustitución hacia atras
        X = np.zeros(n,dtype=float) 
        ultfila = n-1
        ultcolumna = m-1
        for i in range(ultfila,0-1,-1):
            suma = 0
            for j in range(i+1,ultcolumna,1):
                suma = suma + AB[i,j]*X[j]
            X[i] = (AB[i,ultcolumna]-suma)/AB[i,i]
        return(X)
    
    # INGRESO
    A = [[200, 100   ],
         [  2,   1.05]]
    
    B = [1000, 10.4]
    
    # PROCEDIMIENTO
    AB = pivoteafila(A,B,vertabla=True)
    
    AB = gauss_eliminaAdelante(AB,vertabla=True)
    
    X = gauss_sustituyeAtras(AB,vertabla=True)
    
    # SALIDA
    print('solución: ')
    print(X)
    
  • s1Eva_IIT2007_T3 Interpolación inversa, encontrar xi para fi dado

    Ejercicio: 1Eva_IIT2007_T3 Interpolación inversa

    Para determinar el valor de x, usando interpolación inversa.interpola inversa

    f(0.50) = 1.648
    f(0.65) = 1.915
    f( x  ) = 2.117
    f(0.80) = 2.225
    f(0.95) = 2.5857

    Para el algoritmo se intercambian las variables previo a usarlo.

    fi = [0.50 , 0.65 , 0.80,  0.95   ]
    xi = [1.648, 1.915, 2.225, 2.5857 ]
    

    Luego se evalúa en el punto buscado, en éste caso: fi=2.117, obteniendo que x es: 0.750321134121361

    Para obtener el polinomio se usa el método de Lagrange:

    término 1

    L_{0} (x) = \frac{(x-1.915)(x-2.225)(x-2.5857)}{(1.648-1.915)(1.648-2.225)(1.648-2.5857)}

    término 2

    L_{1} (x) = \frac{(x-1.648)(x-2.225)(x-2.5857)}{(1.915-1.648)(1.915-2.225)(1.915-2.5857)}

    término 3

    L_{2} (x) = \frac{(x-1.648)(x-1.915)(x-2.5857)}{(2.225-1.648)(2.225-1.915)(2.225-2.5857)}

    término 4

    L_{3} (x) = \frac{(x-1.648)(x-1.915)(x-2.225)}{(2.5857-1.648)(2.5857-1.915)(2.5857-2.225)}

    se construye el polinomio usando la fórmula para fn(x) para cada valor fi,

    p_3(x) = 0.5 L_{0} (x) + 0.65 L_{1} (x) + 0.8 L_{2} (x) + 0.95 L_{3} (x) p_3(x) = 0.5 \frac{(x-1.915)(x-2.225)(x-2.5857)}{-0.14446112} + +0.65 \frac{(x-1.648)(x-2.225)(x-2.5857)}{0.05551384 } + + 0.8 \frac{(x-1.648)(x-1.915)(x-2.5857)}{-0.06451841} + +0.95 \frac{(x-1.648)(x-1.915)(x-2.225)}{0.22684978} p_3(x) = 0.03588 x^3 - 0.34275 x^2 + 1.44073 x - 1.10404

    A partir del resultado del algoritmo se puede evaluar p(2.117)

        valores de fi:  [0.5  0.65 0.8  0.95]
    divisores en L(i):  [-0.14446112  0.05551384 -0.06451841  0.22684978]
    
    Polinomio de Lagrange, expresiones
    -3.46113878334255*(x - 2.5857)*(x - 2.225)*(x - 1.915) 
    + 11.7087921085767*(x - 2.5857)*(x - 2.225)*(x - 1.648) 
    - 12.3995618056856*(x - 2.5857)*(x - 1.915)*(x - 1.648) 
    + 4.18779332775953*(x - 2.225)*(x - 1.915)*(x - 1.648)
    
    Polinomio de Lagrange: 
    0.0358848473081546*x**3 - 0.342756582990933*x**2 
    + 1.44073214117569*x - 1.10404634485234
    >>> polisimple.subs(x,2.117)
    0.750321134121178
    >>> polisimple
    0.0358848473081546*x**3 - 0.342756582990933*x**2 
    + 1.44073214117569*x - 1.10404634485234
    >>> 
    

    Algoritmo en Python

    # 1Eva_IIT2007_T3 Interpolación inversa
    # Interpolacion de Lagrange
    # divisoresL solo para mostrar valores
    import numpy as np
    import matplotlib.pyplot as plt
    import sympy as sym
    
    # INGRESO , Datos de prueba
    fi = [0.50 , 0.65 , 0.80,  0.95   ]
    xi = [1.648, 1.915, 2.225, 2.5857 ]
    
    # PROCEDIMIENTO
    xi = np.array(xi,dtype=float)
    fi = np.array(fi,dtype=float)
    # Polinomio de Lagrange
    n = len(xi)
    x = sym.Symbol('x')
    polinomio = 0
    divisorL = np.zeros(n, dtype = float)
    for i in range(0,n,1):
        
        # Termino de Lagrange
        numerador = 1
        denominador = 1
        for j  in range(0,n,1):
            if (j!=i):
                numerador = numerador*(x-xi[j])
                denominador = denominador*(xi[i]-xi[j])
        terminoLi = numerador/denominador
    
        polinomio = polinomio + terminoLi*fi[i]
        divisorL[i] = denominador
    
    # simplifica el polinomio
    polisimple = polinomio.expand()
    
    # Salida
    print('    valores de fi: ',fi)
    print('divisores en L(i): ',divisorL)
    print()
    print('Polinomio de Lagrange, expresiones')
    print(polinomio)
    print()
    print('Polinomio de Lagrange: ')
    print(polisimple)

    para revisar con la gráfica, se añaden las líneas,

    # GRAFICA
    polinomio = sym.lambdify(x,polisimple)
    y = np.linspace(1,3,100)
    pyi= polinomio(y)
    plt.plot(pyi,y,label='p(x)')
    plt.plot(fi,xi,'o')
    plt.axhline(2.117,linestyle='dashed',
                label='f(x)=2.117', color='green')
    plt.legend()
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.show()
    
  • s1Eva_IIT2007_T2 Aplicar Gauss-Seidel 6x6

    Ejercicio: 1Eva_IIT2007_T2 Aplicar Gauss-Seidel 6x6

    1. Desarrollo Analítico

    - Verificar que la matriz es diagonal dominante

    No es necesario realizar el pivoteo por filas, ya la matriz tiene la diagonal dominante.

    A = [[7.63, 0.30, 0.15,  0.50, 0.34, 0.84],
         [0.38, 6.40, 0.70,  0.90, 0.29, 0.57],
         [0.83, 0.19, 8.33,  0.82, 0.34, 0.37],
         [0.50, 0.68, 0.86, 10.21, 0.53, 0.70],
         [0.71, 0.30, 0.85,  0.82, 5.95, 0.55],
         [0.43, 0.54, 0.59,  0.66, 0.31, 9.25]]
    
    B = [ -9.44, 25.27, -48.01, 19.76, -23.63, 62.59]
    

    - revisar el número de condición

    cond(A) = || A||.||A-1||

    El número de condición no es "muy alto",  los valores de la diagonal son los mayores en toda la fila, por lo que el sistema converge.

    >>> np.linalg.cond(A)
    2.04518539662910119
    

    - realizar iteraciones con las expresiones:

    x_0 = \Big(-9.44 -0.3 x_1 -0.15x_2 -0.50 x_3 -0.34 x_4 -0.84 x_5\Big)\frac{1}{7.63} x_1 = \Big( 25.27 -0.38 x_0 -0.70 x_2 -0.90 x_3 -0.29 x_4 -0.57 x_5 \Big) \frac{1}{6.40} x_2 = \Big(-48.01 -0.83x_0 -0.19 x_1 -0.82x_3 -0.34x_4 -0.37x_5 \Big)\frac{1}{8.33} x_3 = \Big(19.76 -0.50 x_0 -0.68 x_1 -0.86 x_2 -0.53 x_4 -0.70x_5 \Big)\frac{1}{10.21} x_4 = \Big( -23.63 - 0.71 x_0 -0.30 x_1 -0.85 x_2 -0.82 x_3 -0.55x_5 \Big)\frac{1}{5.95} x_5 = \Big( 62.59 - 0.43x_0 -0.54x_1 - 0.59 x_2 -0.66 x_3 -0.31 x_4 \Big)\frac{1}{9.25}

    Dado que no se establece en el enunciado el vector inicial, se usará el vector cero. La tolerancia requerida es 10-5
    X0 = [ 0. 0. 0. 0. 0. 0.] = [x0,x1,x2,x3,x4,x5]

    iteración 0

    x_0 = \Big(-9.44 -0.3 (0) -0.15(0) -0.50 (0) -0.34(0) -0.84 (0)\Big)\frac{1}{7.63} = -1.23722 x_1 = \Big( 25.27 -0.38 (-1.23722) -0.70 (0) -0.90 (0) -0.29 (0) -0.57 (0) \Big) \frac{1}{6.40} = 4.0219 x_2 = \Big(-48.01 -0.83 (-1.23722) -0.19 (4.0219) -0.82(0) -0.34(0) -0.37(0) \Big)\frac{1}{8.33} = -5.73196 x_3 = \Big( 19.76 -0.50 (-1.23722) -0.68 (4.0219) -0.86 (-5.73196) -0.53 (0) -0.70(0) \Big)\frac{1}{10.21} = 2.21089 x_4 = \Big( -23.63 - 0.71 (-1.23722) -0.30 (4.0219) -0.85 (-5.73196) -0.82 (2.21089) -0.55(0) \Big)\frac{1}{5.95} = -3.51242 x_5 = \Big( 62.59 - 0.43(-1.23722) -0.54(4.0219) - 0.59 (-5.73196) -0.66 (2.21089) -0.31 (-3.51242) \Big)\frac{1}{9.25} = 6.91478 X_1 = [-1.23722, 4.0219, -5.73196, 2.21089, -3.51242, 6.91478 ] diferencia = X1 - [0,0,0,0,0,0] errado = max(|diferencia|) = 6.91478

    iteración 1

    x_0 = \Big(-9.44 -0.3 (4.0219) -0.15(4.0219) -0.50 (2.21089) -0.34 (-3.51242) -0.84(6.91478) \Big)\frac{1}{7.63} = -2.0323 x_1 = \Big( 25.27 -0.38 (-2.0323) -0.70 ( -5.73196) -0.90 (2.21089) -0.29 (-3.51242) -0.57 (6.91478) \Big) \frac{1}{6.40} = 3.92844 x_2 = \Big(-48.01 -0.83(-2.0323) -0.19 (3.92844) -0.82(2.21089) -0.34(-3.51242) -0.37(6.91478) \Big)\frac{1}{8.33} = -6.03203 x_3 = \Big(19.76 -0.50 (-2.0323) -0.68 (3.92844) -0.86 (-6.03203) -0.53 (-3.51242) -0.70(6.91478) \Big)\frac{1}{10.21} = 1.98958 x_4 = \Big( -23.63 - 0.71 (-2.0323) -0.30 (3.92844) -0.85 (-6.03203) -0.82 (1.98958) -0.55(6.91478) \Big)\frac{1}{5.95} = -3.97865 x_5 = \Big( 62.59 - 0.43(-2.0323) -0.54(3.92844) - 0.59 (-6.03203) -0.66 (1.98958) -0.31 (-3.97865) \Big)\frac{1}{9.25} = 7.00775 X_2 = [-2.0323, 3.92844, -6.03203, 1.98958, -3.97865, 7.00775] diferencia = X2 - [-1.23722, 4.0219, -5.73196, 2.21089, -3.51242, 6.91478 ] errado = max(|diferencia|) = 0.79507

    iteración 2

    Desarrollar como tarea.


    2. Algoritmo en Python

    La tabla de aproximaciones sucesivas para el vector X es:

    Pivoteo por filas NO requerido
    Iteraciones Gauss-Seidel
    itera,[X],[errado]
    0 [0. 0. 0. 0. 0. 0.] [1.]
    1 [-1.23722  4.0219  -5.73196  2.21089 -3.51242  6.91478] [6.91478]
    2 [-2.0323   3.92844 -6.03203  1.98958 -3.97865  7.00775] [0.79507]
    3 [-1.99768  4.00317 -6.00049  1.99808 -4.00082  6.9999 ] [0.07473]
    4 [-1.99994  4.00037 -5.99979  2.      -4.00005  6.99996] [0.00281]
    5 [-2.00001  3.99998 -6.       2.00001 -4.       7.     ] [0.00038]
    6 [-2.  4. -6.  2. -4.  7.] [1.60155e-05]
    7 [-2.  4. -6.  2. -4.  7.] [1.74554e-06]
    Matriz aumentada y pivoteada:
    [[  7.63   0.3    0.15   0.5    0.34   0.84  -9.44]
     [  0.38   6.4    0.7    0.9    0.29   0.57  25.27]
     [  0.83   0.19   8.33   0.82   0.34   0.37 -48.01]
     [  0.5    0.68   0.86  10.21   0.53   0.7   19.76]
     [  0.71   0.3    0.85   0.82   5.95   0.55 -23.63]
     [  0.43   0.54   0.59   0.66   0.31   9.25  62.59]]
    Vector Xi: 
    [-2.  4. -6.  2. -4.  7.]
    >>> 
    

    el gráfico de los iteraciones vs errores es:

    Gauss-Seidel errado_1EIIT2007T2

    La tabla obtiene aplicando la función de Gauss-Seidel, tomando como vector inicial el vector de ceros.

    Tarea: X=TX+C

    Instrucciones en Python

    # 1Eva_IIT2007_T2 Aplicar Gauss-Seidel
    # Algoritmo Gauss-Seidel
    import numpy as np
    
    def pivoteafila(A,B,vertabla=False):
        '''
        Pivotea parcial por filas
        Si hay ceros en diagonal es matriz singular,
        Tarea: Revisar si diagonal tiene ceros
        '''
        # Matriz aumentada
        nB = len(np.shape(B))
        if nB == 1:
            B = np.transpose([B])
        AB  = np.concatenate((A,B),axis=1)
        M = np.copy(AB)
        
        # Pivoteo por filas AB
        tamano = np.shape(M)
        n = tamano[0]
        m = tamano[1]
        
        # Para cada fila en AB
        pivoteado = 0
        for i in range(0,n-1,1):
            # columna desde diagonal i en adelante
            columna = np.abs(M[i:,i])
            dondemax = np.argmax(columna)
            
            # dondemax no es en diagonal
            if (dondemax != 0):
                # intercambia filas
                temporal = np.copy(M[i,:])
                M[i,:] = M[dondemax+i,:]
                M[dondemax+i,:] = temporal
    
                pivoteado = pivoteado + 1
                if vertabla==True:
                    print(pivoteado, 'intercambiar: ',i,dondemax)
        if vertabla==True and pivoteado==0:
            print('Pivoteo por filas NO requerido')
        return(M)
    
    def gauss_seidel(A,B,tolera,X0, iteramax=100, vertabla=False, precision=5):
        ''' Método de Gauss Seidel, tolerancia, vector inicial X0
            para mostrar iteraciones: vertabla=True
        '''
        tamano = np.shape(A)
        n = tamano[0]
        m = tamano[1]
        diferencia = 2*tolera*np.ones(n, dtype=float)
        errado = np.max(diferencia)
        X = np.copy(X0)
    
        itera = 0
        if vertabla==True:
            print('Iteraciones Gauss-Seidel')
            print('itera,[X],[errado]')
            np.set_printoptions(precision)
            print(itera, X, np.array([errado]))
        while (errado>tolera and itera<iteramax):
            for i in range(0,n,1):
                xi = B[i]
                for j in range(0,m,1):
                    if (i!=j):
                        xi = xi-A[i,j]*X[j]
                xi = xi/A[i,i]
                diferencia[i] = np.abs(xi-X[i])
                X[i] = xi
            errado = np.max(diferencia)
            itera = itera + 1
            if vertabla==True:
                print(itera, X, np.array([errado]))        
        
        if (itera>iteramax): # No converge
            X = itera
            print('iteramax superado, No converge')
        return(X)
    
    # Programa de prueba #######
    # INGRESO
    A = np.array([[7.63, 0.30, 0.15,  0.50, 0.34, 0.84],
                  [0.38, 6.40, 0.70,  0.90, 0.29, 0.57],
                  [0.83, 0.19, 8.33,  0.82, 0.34, 0.37],
                  [0.50, 0.68, 0.86, 10.21, 0.53, 0.70],
                  [0.71, 0.30, 0.85,  0.82, 5.95, 0.55],
                  [0.43, 0.54, 0.59,  0.66, 0.31, 9.25]])
    
    B = np.array([-9.44,25.27,-48.01,19.76,-23.63,62.59])
    
    tolera = 0.00001
    X = np.zeros(len(A), dtype=float)
    
    # PROCEDIMIENTO
    n = len(A)
    A = np.array(A,dtype=float)
    B = np.array(B,dtype=float)
    
    
    AB = pivoteafila(A,B, vertabla=True)
    A = AB[:,:n]
    B = AB[:,n]
    respuesta = gauss_seidel(A,B, tolera, X, vertabla=True)
    
    # SALIDA
    print('Matriz aumentada y pivoteada:')
    print(AB)
    print('Vector Xi: ')
    print(respuesta)
    
    

    En el caso de la norma infinito, para la matriz A, se puede usar el algoritmo desarrollado en clase.
    Como valor para verificar su algoritmo, se obtuvo:

    >>> np.linalg.norm(A, np.inf)
    13.479999999999999
    

    Tarea: incluir la norma infinito para T

  • s1Eva_IIT2007_T1 Distribución binomial acumulada

    Ejercicio: 1Eva_IIT2007_T1 Distribución binomial acumulada

    Dado F=0.4, dado que n=5 y k=1

    F = \sum_{t=0}^{k} \binom{n}{t} p^t (1-p)^{n-t}

    La fórmula para el ejercicio se convierte en:

    F = \Bigg( \begin{array}{c} 5 \\ 0 \end{array} \Bigg) p ^0 (1-p)^{(5-0)} + \Bigg( \begin{array}{c} 5 \\ 1 \end{array} \Bigg) p ^1 (1-p)^{(5-1)} = 0.4

    Los valores de las combinatorias se calculan como:

    >>> import scipy.special as sts
    >>> sts.comb(5,0,repetition=False)
    1.0
    >>> sts.comb(5,1,repetition=False)
    5.0
    >>> 
    
    (1-p)^{5} + 5p (1-p)^{4} = 0.4

    La expresión para el ejercicio se convierte en:

    f(p) = (1-p)^{5} + 5p (1-p)^{4} - 0.4

    como referencia se revisa la gráfica para f(p)

    f(p) = (1-p)^5 + 5p(1-p)^4 - 0.4 = (1-p)^4 (1 - p + 5p) - 0.4 = (1-p)^4 (1 + 4p) - 0.4 = (1-p)^2 (1-p)^2 (1 + 4p) - 0.4 = (1-2p+p^2) (1-2p+p^2) (1 + 4p) - 0.4 = (1 - 4p + 6p^2 - 4p^3 +p^4 ) (1 + 4p) - 0.4 = 1 - 10p^2 + 20p^3 + 15p^4 + 4p^5 - 0.4 f(p) = 0.6 - 10p^2 + 20p^3 + 15p^4 + 4p^5

    y su derivada:

    f'(p) = - 20p + 60p^2 + 60p^3 +20p^4

    con lo que se puede desarrollar el método Newton-Raphson.

    Verificando el polinomio  obtenido a partir de la expresión inicial usando Sympy:

    >>> import sympy as sp
    >>> p = sp.Symbol('p')
    >>> poli = (1-p)**5 + 5*p*((1-p)**4) - 0.4
    >>> pol = poli.expand()
    >>> pol
    4*p**5 - 15*p**4 + 20*p**3 - 10*p**2 + 0.6
    >>> pol.diff(p,1)
    20*p**4 - 60*p**3 + 60*p**2 - 20*p
    

    A partir de la gráfica, un punto inicial cercano a la raíz es X0 = 0.2

    itera = 0

    f(0.2) = 0.6 - 10(0.2)^2 + 20(0.2)^3 + 15(0.2)^4 + 4(0.2)^5 = 0.3373 f'(0.2) = - 20(0.2) + 60(0.2)^2 + 60(0.2)^3 +20(0.2)^4 = -2.048 x_1 = 0.2 -\frac{0.3373}{-2.048} = 0.3647 errado = |0.2 - 0.36469| = 0.1647

    itera = 1

    f(0.36469) = 0.6 - 10(0.36469)^2 + 20(0.36469)^3 + 15(0.36469)^4 + 4(0.36469)^5 = 0.0005566 f'(0.36469) = - 20(0.36469) + 60(0.36469)^2 + 60(0.36469)^3 +20(0.36469)^4 = -1.8703 x_1 = 0.36469 -\frac{0.0005566}{-1.8703} = 0.36499 errado = |0.36469 - 0.36499| = 0.000297

    itera = 3

    f(0.36499) = 0.6 - 10(0.36499)^2 + 20(0.36499)^3 + 15(0.36499)^4 + 4(0.36499)^5 = 1.6412291237166698e-07 f'(0.36499) = - 20(0.36499) + 60(0.36499)^2 + 60(0.36499)^3 +20(0.36499)^4 = -1.869204616112814 x_1 = 0.36469 -\frac{1.6412291237166698e-07}{ -1.8692} = 0.36499 errado = |0.36499 - 0.36499| = 8.7804e-08

    verificar con raíz: 0.3649852264049102

    Instrucciones para la gráfica

    # 1ra Eval II Término 2007
    # Tema 1. Distribución binomial acumulada
    import numpy as np
    import matplotlib.pyplot as plt
    import scipy.special as sts
    
    fp = lambda p: (1-p)**5 + 5*p*((1-p)**4) - 0.4
    
    a = 0
    b = 1
    pasos = 100
    
    # PROCEDIMIENTO
    xi = np.linspace(a,b,pasos+1)
    p_i = fp(xi)
    
    # SALIDA
    plt.plot(xi,p_i)
    plt.axhline(0)
    plt.show()
    

    Algoritmo en Python

    el resultado usando el algoritmo es:

    i ['xi', 'fi', 'dfi', 'xnuevo', 'tramo']
    0 [ 0.2     0.3373 -2.048   0.3647  0.1647]
    1 [ 3.6469e-01  5.5668e-04 -1.8703e+00  3.6499e-01  2.9764e-04]
    2 [ 3.6499e-01  1.6412e-07 -1.8692e+00  3.6499e-01  8.7804e-08]
    raiz en:  0.3649852264049102
    

    con error de: 8.780360960525257e-08

    Instrucciones en Python para Newton-Raphson

    # 1Eva_IIT2007_T1 Distribución binomial acumulada
    # Método de Newton-Raphson
    
    import numpy as np
    import matplotlib.pyplot as plt
    
    def newton_raphson(fx,dfx,xi, tolera, iteramax=100, vertabla=False, precision=4):
        '''
        fx y dfx en forma numérica lambda
        xi es el punto inicial de búsqueda
        '''
        itera=0
        tramo = abs(2*tolera)
        if vertabla==True:
            print('método de Newton-Raphson')
            print('i', ['xi','fi','dfi', 'xnuevo', 'tramo'])
            np.set_printoptions(precision)
        while (tramo>=tolera):
            fi = fx(xi)
            dfi = dfx(xi)
            xnuevo = xi - fi/dfi
            tramo = abs(xnuevo-xi)
            if vertabla==True:
                print(itera,np.array([xi,fi,dfi,xnuevo,tramo]))
            xi = xnuevo
            itera = itera + 1
    
        if itera>=iteramax:
            xi = np.nan
            print('itera: ',itera, 'No converge,se alcanzó el máximo de iteraciones')
    
        return(xi)
    
    # INGRESO
    fx  = lambda p: 4*p**5 - 15*p**4 + 20*p**3 - 10*p**2 + 0.6
    dfx = lambda p: 20*p**4 - 60*p**3 + 60*p**2 - 20*p
    
    x0 = 0.2
    tolera = 0.0000001
    
    # PROCEDIMIENTO
    respuesta = newton_raphson(fx,dfx,x0, tolera, vertabla=True)
    # SALIDA
    print('raiz en: ', respuesta)
    
    # GRAFICA
    a = 0
    b = 1
    muestras = 21
    
    xi = np.linspace(a,b,muestras)
    fi = fx(xi)
    plt.plot(xi,fi, label='f(x)')
    plt.axhline(0)
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.grid()
    plt.legend()
    plt.show()
    
  • 7.3 EDP hiperbólicas con Python

    [ concepto ] [ analítico ] [ algoritmo ]
    ..


    1. Concepto y ejercicio

    Referencia:  Chapra PT8.1 p860,  Rodríguez 10.4 p435

    Las Ecuaciones Diferenciales Parciales tipo hiperbólicas semejantes a la mostrada, para un ejemplo en particular, representa la ecuación de onda de una dimensión u[x,t], que representa el desplazamiento vertical de una cuerda.

    \frac{\partial ^2 u}{\partial t^2}=c^2\frac{\partial ^2 u}{\partial x^2}

    EDP Cuerda 01

    Los extremos de la cuerda de longitud unitaria están sujetos y referenciados a una posición 0 a la izquierda y 1 a la derecha.

    u[x,t] , 0<x<1, t≥0
    u(0,t) = 0 , t≥0
    u(1,t) = 0 , t≥0

    Al inicio, la cuerda está estirada por su punto central:

    u(x,0) = \begin{cases} -0.5x &, 0\lt x\leq 0.5 \\ 0.5(x-1) &, 0.5\lt x \lt 1 \end{cases}

    Se suelta la cuerda, con velocidad cero desde la posición inicial:

    \frac{\partial u(x,0)}{\partial t} = 0

    [ concepto ] [ analítico ] [ algoritmo ]
    ..


    2. Desarrollo analítico

    La solución se realiza de forma semejante al procedimiento para EDP parabólicas y elípticas. Se cambia a la forma discreta  usando diferencias finitas divididas:

    \frac{u_{i,j+1}-2u_{i,j}+u_{i,j-1}}{(\Delta t)^2} =c^2 \frac{u_{i+1,j}-2u_{i,j}+u_{i-1,j}}{(\Delta x)^2}

    El error es del orden O(\Delta x)^2 + O(\Delta t)^2.
    se reagrupa de la forma:

    u_{i,j+1}-2u_{i,j}+u_{i,j-1} = \frac{c^2 (\Delta t)^2}{(\Delta x)^2} \big( u_{i+1,j}-2u_{i,j}+u_{i-1,j} \big)

    El término constante, por facilidad se simplifica con el valor de 1

    \lambda = \frac{c^2 (\Delta t)^2}{(\Delta x)^2} =1

    si c = 2 y Δx = 0.2, se deduce que Δt = 0.1

    que al sustituir en la ecuación, se simplifica anulando el término u[i,j]:

    u_{i,j+1}+u_{i,j-1} = u_{i+1,j}+u_{i-1,j}

    EDP Cuerda 02

    en los que intervienen solo los puntos extremos. Despejando el punto superior del rombo:

    u_{i,j+1} = u_{i+1,j}-u_{i,j-1}+u_{i-1,j}

    Convergencia:

    \lambda = \frac{c^2 (\Delta t)^2}{(\Delta x)^2} \leq 1

    para simplificar aún más el problema, se usa la condición velocidad inicial de la cuerda igual a cero

    \frac{\delta u_{i,0}}{\delta t}=\frac{u_{i,1}-u_{i,-1}}{2\Delta t} = 0 u_{i,-1}=u_{i,1}

    que se usa para cuando el tiempo es cero, permite calcular los puntos para t[1]:

    j=0

    u_{i,1} = u_{i+1,0}-u_{i,-1}+u_{i-1,0} u_{i,1} = u_{i+1,0}-u_{i,1}+u_{i-1,0} 2 u_{i,1} = u_{i+1,0}+u_{i-1,0} u_{i,1} = \frac{u_{i+1,0}+u_{i-1,0}}{2}

    Aplicando solo cuando j = 0

    EDP Cuerda 03

    que al ponerlos en la malla se logra un sistema explícito para cada u[i,j], con lo que se puede resolver con un algoritmo:

    EDP hiperbolica 01

    [ concepto ] [ analítico ] [ algoritmo ]
    ..


    3. Algoritmo con Python

    # Ecuaciones Diferenciales Parciales
    # Hiperbólica. Método explicito
    import numpy as np
    
    def cuerdainicio(xi):
        n = len(xi)
        y = np.zeros(n,dtype=float)
        for i in range(0,n,1):
            if (xi[i]<=0.5):
                y[i]=-0.5*xi[i]
            else:
                y[i]=0.5*(xi[i]-1)
        return(y)
    
    # INGRESO
    x0 = 0 # Longitud de cuerda
    xn = 1
    y0 = 0 # Puntos de amarre
    yn = 0
    t0 = 0 # tiempo inicial
    c = 2  # constante EDP
    # discretiza
    tramosx = 16
    tramost = 32
    dx = (xn-x0)/tramosx 
    dt = dx/c
    
    # PROCEDIMIENTO
    xi = np.arange(x0,xn+dx/2,dx)
    tj = np.arange(0,tramost*dt+dt/2,dt)
    n = len(xi)
    m = len(tj)
    
    u = np.zeros(shape=(n,m),dtype=float)
    u[:,0] = cuerdainicio(xi)
    u[0,:] = y0
    u[n-1,:] = yn
    # Aplicando condición inicial
    j = 0
    for i in range(1,n-1,1):
        u[i,j+1] = (u[i+1,j]+u[i-1,j])/2
    # Para los otros puntos
    for j in range(1,m-1,1):
        for i in range(1,n-1,1):
            u[i,j+1] = u[i+1,j]-u[i,j-1]+u[i-1,j]
    
    # SALIDA
    np.set_printoptions(precision=2)
    print('xi =')
    print(xi)
    print('tj =')
    print(tj)
    print('matriz u =')
    print(u)
    

    con lo que se obtienen los resultados numéricos, que para mejor interpretación se presentan en una gráfica estática y otra animada.

    # GRAFICA
    import matplotlib.pyplot as plt
    
    for j in range(0,m,1):
        y = u[:,j]
        plt.plot(xi,y)
    
    plt.title('EDP hiperbólica')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()
    
    # **** GRÁFICO CON ANIMACION ***********
    import matplotlib.animation as animation
    
    # Inicializa parametros de trama/foto
    retardo = 70   # milisegundos entre tramas
    tramas  = m
    maximoy = np.max(np.abs(u))
    figura, ejes = plt.subplots()
    plt.xlim([x0,xn])
    plt.ylim([-maximoy,maximoy])
    
    # lineas de función y polinomio en gráfico
    linea_poli, = ejes.plot(xi,u[:,0], '-')
    plt.axhline(0, color='k')  # Eje en x=0
    
    plt.title('EDP hiperbólica')
    # plt.legend()
    # txt_x = (x0+xn)/2
    txt_y = maximoy*(1-0.1)
    texto = ejes.text(x0,txt_y,'tiempo:',
                      horizontalalignment='left')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.grid()
    
    # Nueva Trama
    def unatrama(i,xi,u):
        # actualiza cada linea
        linea_poli.set_ydata(u[:,i])
        linea_poli.set_xdata(xi)
        linea_poli.set_label('tiempo linea: '+str(i))
        texto.set_text('tiempo['+str(i)+']')
        # color de la línea
        if (i<=9):
            lineacolor = 'C'+str(i)
        else:
            numcolor = i%10
            lineacolor = 'C'+str(numcolor)
        linea_poli.set_color(lineacolor)
        return linea_poli, texto
    
    # Limpia Trama anterior
    def limpiatrama():
        linea_poli.set_ydata(np.ma.array(xi, mask=True))
        linea_poli.set_label('')
        texto.set_text('')
        return linea_poli, texto
    
    # Trama contador
    i = np.arange(0,tramas,1)
    ani = animation.FuncAnimation(figura,
                                  unatrama,
                                  i ,
                                  fargs=(xi,u),
                                  init_func=limpiatrama,
                                  interval=retardo,
                                  blit=True)
    # Graba Archivo video y GIFAnimado :
    # ani.save('EDP_hiperbólica.mp4')
    ani.save('EDP_hiperbolica.gif', writer='imagemagick')
    plt.draw()
    plt.show()
    

    Una vez realizado el algoritmo, se pueden cambiar las condiciones iniciales de la cuerda y se observan los resultados.

    Se recomienda realizar otros ejercicios de la sección de evaluaciones para EDP Hiperbólicas y observar los resultados con el algoritmo modificado.

    [ concepto ] [ analítico ] [ algoritmo ]

  • 7.2.2 EDP Elípticas método implícito con Python

    EDP Elípticas [ concepto ] Método implícito: [ Analítico ] [ Algoritmo ]
    ..


    1. EDP Elípticas: Método Implícito – Desarrollo Analítico

    con el resultado desarrollado en EDP elípticas para:

    \frac{\partial ^2 u}{\partial x^2} + \frac{\partial ^2 u}{ \partial y^2} = 0

    y con el supuesto que: \lambda = \frac{(\Delta y)^2}{(\Delta x)^2} = 1

    se puede plantear que:

    u_{i+1,j}-4u_{i,j}+u_{i-1,j} + u_{i,j+1} +u_{i,j-1} = 0

    EDP Elipticas Iterativo

    con lo que para el método implícito, se plantea un sistema de ecuaciones para determinar los valores en cada punto desconocido.

    j=1, i =1

    u_{2,1}-4u_{1,1}+u_{0,1} + u_{1,2} +u_{1,0} = 0 u_{2,1}-4u_{1,1}+Ta + u_{1,2} +Tc= 0 -4u_{1,1}+u_{2,1}+u_{1,2} = -(Tc+Ta)

    j=1, i =2

    u_{3,1}-4u_{2,1}+u_{1,1} + u_{2,2} +u_{2,0} = 0 u_{3,1}-4u_{2,1}+u_{1,1} + u_{2,2} +Tc = 0 u_{1,1}-4u_{2,1}+u_{3,1}+ u_{2,2}= -Tc

    j=1, i=3

    u_{4,1}-4u_{3,1}+u_{2,1} + u_{3,2} +u_{3,0} = 0 Tb-4u_{3,1}+u_{2,1} + u_{3,2} +Tc = 0 u_{2,1} -4u_{3,1} + u_{3,2} = -(Tc+Tb)

    j=2, i=1

    u_{2,2}-4u_{1,2}+u_{0,2} + u_{1,3} +u_{1,1} = 0 u_{2,2}-4u_{1,2}+Ta + u_{1,3} +u_{1,1} = 0 -4u_{1,2}+u_{2,2}+u_{1,1}+u_{1,3} = -Ta

    j = 2, i = 2

    u_{1,2}-4u_{2,2}+u_{3,2} + u_{2,3} +u_{2,1} = 0

    j = 2, i = 3

    u_{4,2}-4u_{3,2}+u_{2,2} + u_{3,3} +u_{3,1} = 0 Tb-4u_{3,2}+u_{2,2} + u_{3,3} +u_{3,1} = 0 u_{2,2} -4u_{3,2}+ u_{3,3} +u_{3,1} = -Tb

    j=3, i = 1

    u_{2,3}-4u_{1,3}+u_{0,3} + u_{1,4} +u_{1,2} = 0 u_{2,3}-4u_{1,3}+Ta + Td +u_{1,2} = 0 -4u_{1,3}+u_{2,3}+u_{1,2} = -(Td+Ta)

    j=3, i = 2

    u_{3,3}-4u_{2,3}+u_{1,3} + u_{2,4} +u_{2,2} = 0 u_{3,3}-4u_{2,3}+u_{1,3} + Td +u_{2,2} = 0 +u_{1,3} -4u_{2,3}+u_{3,3} +u_{2,2} = -Td

    j=3, i=3

    u_{4,3}-4u_{3,3}+u_{2,3} + u_{3,4} +u_{3,2} = 0 Tb-4u_{3,3}+u_{2,3} + Td +u_{3,2} = 0 u_{2,3}-4u_{3,3}+u_{3,2} = -(Td+Tb)

    con las ecuaciones se arma una matriz:

    A = np.array([
        [-4, 1, 0, 1, 0, 0, 0, 0, 0],
        [ 1,-4, 1, 0, 1, 0, 0, 0, 0],
        [ 0, 1,-4, 0, 0, 1, 0, 0, 0],
        [ 1, 0, 0,-4, 1, 0, 1, 0, 0],
        [ 0, 1, 0, 1,-4, 1, 0, 1, 0],
        [ 0, 0, 1, 0, 1,-4, 0, 0, 1],
        [ 0, 0, 0, 1, 0, 0,-4, 1, 0],
        [ 0, 0, 0, 0, 1, 0, 1,-4, 1],
        [ 0, 0, 0, 0, 0, 1, 0, 1,-4],
        ])
    B = np.array([-(Tc+Ta),-Tc,-(Tc+Tb),
                      -Ta,   0,    -Tb,
                  -(Td+Ta),-Td,-(Td+Tb)])
    

    que al resolver el sistema de ecuaciones se obtiene:

    >>> Xu
    array([ 56.43,  55.71,  56.43,  60.  ,  60.  ,  60.  ,  63.57,  64.29,
            63.57])
    

    ingresando los resultados a la matriz u:

    xi=
    [ 0.   0.5  1.   1.5  2. ]
    yj=
    [ 0.    0.38  0.75  1.12  1.5 ]
    matriz u
    [[ 60.    60.    60.    60.    60.  ]
     [ 50.    56.43  60.    63.57  70.  ]
     [ 50.    55.71  60.    64.29  70.  ]
     [ 50.    56.43  60.    63.57  70.  ]
     [ 60.    60.    60.    60.    60.  ]]
    >>>
    

    EDP Elípticas [ concepto ] Método implícito: [ Analítico ] [ Algoritmo ]

    ..


    2. EDP Elípticas: Método Implícito – Desarrollo con algoritmo

    Instrucciones en Python

    # Ecuaciones Diferenciales Parciales
    # Elipticas. Método implícito
    import numpy as np
    
    # INGRESO
    # Condiciones iniciales en los bordes
    Ta = 60
    Tb = 60
    Tc = 50
    Td = 70
    # dimensiones de la placa
    x0 = 0
    xn = 2
    y0 = 0
    yn = 1.5
    # discretiza, supone dx=dy
    tramosx = 4
    tramosy = 4
    dx = (xn-x0)/tramosx 
    dy = (yn-y0)/tramosy 
    maxitera = 100
    tolera = 0.0001
    
    A = np.array([
        [-4, 1, 0, 1, 0, 0, 0, 0, 0],
        [ 1,-4, 1, 0, 1, 0, 0, 0, 0],
        [ 0, 1,-4, 0, 0, 1, 0, 0, 0],
        [ 1, 0, 0,-4, 1, 0, 1, 0, 0],
        [ 0, 1, 0, 1,-4, 1, 0, 1, 0],
        [ 0, 0, 1, 0, 1,-4, 0, 0, 1],
        [ 0, 0, 0, 1, 0, 0,-4, 1, 0],
        [ 0, 0, 0, 0, 1, 0, 1,-4, 1],
        [ 0, 0, 0, 0, 0, 1, 0, 1,-4],
        ])
    B = np.array([-(Tc+Ta),-Tc,-(Tc+Tb),
                  -Ta,0,-Tb,
                  -(Td+Ta),-Td,-(Td+Tb)])
    
    
    # PROCEDIMIENTO
    # Resuelve sistema ecuaciones
    Xu = np.linalg.solve(A,B)
    [nx,mx] = np.shape(A)
    
    xi = np.arange(x0,xn+dx/2,dx)
    yj = np.arange(y0,yn+dy/2,dy)
    n = len(xi)
    m = len(yj)
    
    u = np.zeros(shape=(n,m),dtype=float)
    u[:,0]   = Tc
    u[:,m-1] = Td
    u[0,:]   = Ta
    u[n-1,:] = Tb
    u[1:1+3,1] = Xu[0:0+3]
    u[1:1+3,2] = Xu[3:3+3]
    u[1:1+3,3] = Xu[6:6+3]
    
    # SALIDA
    np.set_printoptions(precision=2)
    print('xi=')
    print(xi)
    print('yj=')
    print(yj)
    print('matriz u')
    print(u)
    

    La gráfica de resultados se obtiene de forma semejante al ejercicio con método iterativo.

    Se podría estandarizar un poco más el proceso para que sea realizado por el algoritmo y sea más sencillo generar la matriz con más puntos. Tarea.

  • 7.2.1 EDP Elípticas método iterativo con Python

    EDP Elípticas [ concepto ] [ ejercicio ]
    Método iterativo: [ Analítico ] [ Algoritmo ]

    ..


    1. Ejercicio

    Referencia: Chapra 29.1 p866, Rodríguez 10.3 p425, Burden 12.1 p694

    Siguiendo el tema anterior en EDP Elípticas, para resolver la parte numérica asuma como:

    Valores de frontera: Ta = 60 , Tb = 25 , Tc = 50, Td = 70
    Longitud en:  x0 = 0, xn = 2 , y0 = 0, yn = 1.5
    Tamaño de paso dx = 0.25 dy = dx
    iteramax = 100 tolera = 0.0001

    Para la ecuación diferencial parcial Elíptica

    \frac{\partial ^2 u}{\partial x^2} + \frac{\partial ^2 u}{ \partial y^2} = 0


    EDP Elípticas [ concepto ] [ ejercicio ]
    Método iterativo: [ Analítico ] [ Algoritmo ]
    ..


    2. EDP Elípticas: Método iterativo - Desarrollo Analítico

    A partir del resultado desarrollado en EDP elípticas:

    \frac{(\Delta y)^2}{(\Delta x)^2} \Big( u_{i+1,j}-2u_{i,j} +u_{i-1,j} \Big)+ u_{i,j+1}-2u_{i,j}+u_{i,j-1}=0 \lambda \Big( u_{i+1,j}-2u_{i,j} +u_{i-1,j} \Big)+ u_{i,j+1}-2u_{i,j}+u_{i,j-1}=0 \lambda u_{i+1,j} +(-2\lambda-2) u_{i,j} +\lambda u_{i-1,j} + u_{i,j+1} +u_{i,j-1}=0

    y con el supuesto que: \lambda = \frac{(\Delta y)^2}{(\Delta x)^2} = 1

    se puede plantear que:

    u_{i+1,j}-4u_{i,j}+u_{i-1,j} + u_{i,j+1} +u_{i,j-1} = 0

    que reordenando para un punto central desconocido se convierte a:

    u_{i,j} = \frac{1}{4} \big[ u_{i+1,j}+u_{i-1,j} + u_{i,j+1} +u_{i,j-1} \big]

    con lo que se interpreta que cada punto central es el resultado del promedio de los puntos alrededor del rombo formado en la malla.

    El cálculo numérico se puede realizar de forma iterativa haciendo varias pasadas en la matriz, promediando cada punto. Para revisar las iteraciones se controla la convergencia junto con un máximo de iteraciones.

    EDP Elípticas [ concepto ] [ ejercicio ]
    Método iterativo: [ Analítico ] [ Algoritmo ]

    ..


    3. Algoritmo en Python

    Para el ejercicio dado, se presenta el resultado para tres iteraciones y el resultado final con un gráfico en 3D:

    u inicial:
    [[50.   50.   50.   50.   50.   50.   50.   50.   50.  ]
     [60.   51.25 51.25 51.25 51.25 51.25 51.25 51.25 25.  ]
     [60.   51.25 51.25 51.25 51.25 51.25 51.25 51.25 25.  ]
     [60.   51.25 51.25 51.25 51.25 51.25 51.25 51.25 25.  ]
     [60.   51.25 51.25 51.25 51.25 51.25 51.25 51.25 25.  ]
     [60.   51.25 51.25 51.25 51.25 51.25 51.25 51.25 25.  ]
     [70.   70.   70.   70.   70.   70.   70.   70.   70.  ]]
    itera: 0   ;  u:
    [[50.   50.   50.   50.   50.   50.   50.   50.   50.  ]
     [60.   53.12 51.41 50.98 50.87 50.84 50.84 44.27 25.  ]
     [60.   53.91 51.95 51.36 51.18 51.13 51.12 42.91 25.  ]
     [60.   54.1  52.14 51.5  51.3  51.23 51.21 42.59 25.  ]
     [60.   54.15 52.2  51.55 51.34 51.27 51.24 42.52 25.  ]
     [60.   58.85 58.07 57.72 57.58 57.52 57.5  48.76 25.  ]
     [70.   70.   70.   70.   70.   70.   70.   70.   70.  ]]
    errado_u:  8.728094100952148
    itera: 1   ;  u:
    [[50.   50.   50.   50.   50.   50.   50.   50.   50.  ]
     [60.   53.83 51.69 50.98 50.75 50.68 49.02 41.73 25.  ]
     [60.   54.97 52.54 51.55 51.18 51.05 48.55 39.47 25.  ]
     [60.   55.31 52.89 51.82 51.39 51.23 48.4  38.85 25.  ]
     [60.   56.59 54.78 53.91 53.54 53.38 50.45 40.76 25.  ]
     [60.   61.17 60.91 60.6  60.42 60.33 57.38 48.29 25.  ]
     [70.   70.   70.   70.   70.   70.   70.   70.   70.  ]]
    errado_u:  3.7443900108337402
    itera: 2   ;  u:
    [[50.   50.   50.   50.   50.   50.   50.   50.   50.  ]
     [60.   54.17 51.92 51.06 50.73 50.2  47.62 40.52 25.  ]
     [60.   55.5  52.97 51.76 51.23 50.3  46.45 37.7  25.  ]
     [60.   56.25 53.95 52.75 52.19 51.07 46.71 37.54 25.  ]
     [60.   58.05 56.71 55.9  55.47 54.33 49.8  40.16 25.  ]
     [60.   62.24 62.39 62.18 61.99 60.93 57.25 48.1  25.  ]
     [70.   70.   70.   70.   70.   70.   70.   70.   70.  ]]
    errado_u:  2.0990657806396484
    ... continua
    Método Iterativo EDP Elíptica
    iteraciones: 41  converge =  True
    xi: [0.   0.25 0.5  0.75 1.   1.25 1.5  1.75 2.  ]
    yj: [0.   0.25 0.5  0.75 1.   1.25 1.5 ]
    Tabla de resultados en malla EDP Elíptica
    j, U[i,j]
    6 [70. 70. 70. 70. 70. 70. 70. 70. 70.]
    5 [60.   64.02 64.97 64.71 63.62 61.44 57.16 47.96 25.  ]
    4 [60.   61.1  61.14 60.25 58.35 54.98 49.23 39.67 25.  ]
    3 [60.   59.23 58.25 56.8  54.53 50.89 45.13 36.48 25.  ]
    2 [60.   57.56 55.82 54.19 52.09 48.92 43.91 36.14 25.  ]
    1 [60.   55.21 53.27 52.05 50.73 48.78 45.46 39.15 25.  ]
    0 [50. 50. 50. 50. 50. 50. 50. 50. 50.]
    >>>
    

    cuyos valores se interpretan mejor en una gráfica, en este caso 3D:

    EDP Elipticas Iterativo

    Instrucciones en Python

    # Ecuaciones Diferenciales Parciales
    # Elipticas. Método iterativo
    # d2u/dx2  + du/dt = f(x,y)
    import numpy as np
    
    # INGRESO
    fxy = lambda x,y: 0*x+0*y # f(x,y) = 0 , ecuacion de Poisson
    # Condiciones iniciales en los bordes, valores de frontera
    Ta = 60     # izquierda de la placa
    Tb = 25     # derecha de la placa
    #Tc = 50    # inferior 
    fxc = lambda x: 50+0*x #  f(x) inicial inferior
    # Td = 70   # superior
    fxd = lambda x: 70+0*x #  f(x) inicial superior
    
    # dimensiones de la placa
    x0 = 0    # longitud en x
    xn = 2
    y0 = 0    # longitud en y
    yn = 1.5
    # discretiza, supone dx=dy
    dx = 0.25  # Tamaño de paso
    dy = dx
    
    iteramax = 100  # maximo de iteraciones
    tolera = 0.0001
    verdigitos = 2   # decimales a mostrar en tabla de resultados
    vertabla = True  # ver iteraciones
    
    # coeficientes de U[x,t]. factores P,Q,R
    lamb = (dy**2)/(dx**2)
    P = lamb       # izquierda P*U[i-1,j]
    Q = -2*lamb-2  # centro Q*U[i,j]
    R = lamb       # derecha R*U[i+1,j]
    
    # PROCEDIMIENTO
    # iteraciones en xi,yj ancho,profundidad
    xi = np.arange(x0,xn+dx/2,dx)
    yj = np.arange(y0,yn+dy/2,dy)
    n = len(xi)
    m = len(yj)
    
    # Matriz u[xi,yj], tabla de resultados
    u = np.zeros(shape=(n,m),dtype=float)
    
    # llena u con valores en fronteras
    u[0,:]   = Ta   # izquierda
    u[n-1,:] = Tb   # derecha
    fic = fxc(xi)   # Tc inferior
    u[:,0]   = fic
    fid = fxd(xi)   # Td superior
    u[:,m-1] = fid  
    # estado inicial dentro de la placa
    # promedio = (Ta+Tb+Tc+Td)/4
    promedio = (Ta+Tb+np.max(fic)+np.max(fid))*(1/-Q)
    u[1:n-1,1:m-1] = promedio
    
    np.set_printoptions(precision=verdigitos)
    if vertabla == True:
        print('u inicial:')
        print(np.transpose(u))
    
    # iterar puntos interiores
    U_3D = [np.copy(u)]
    U_error = ['--']
    itera = 0
    converge = False
    while (itera<=iteramax and converge==False):
        itera = itera +1
        Uantes = np.copy(u)
        for i in range(1,n-1):
            for j in range(1,m-1):
                u[i,j] = P*u[i-1,j]+R*u[i+1,j]+u[i,j-1]+u[i,j+1]
                u[i,j] = u[i,j] - fxy(xi[i],yj[j])*(dy**2)
                u[i,j] = (1/-Q)*u[i,j]
        diferencia = u - Uantes
        errado_u = np.max(np.abs(diferencia))
        if (errado_u<tolera):
            converge=True
        U_3D.append(np.copy(u))
        U_error.append(np.around(errado_u,verdigitos))
        
        if (vertabla==True) and (itera<=3):
            np.set_printoptions(precision=verdigitos)
            print('itera:',itera-1,'  ; ','u:')
            print(np.transpose(u))
            print('errado_u: ', errado_u)
        if (vertabla==True) and (itera==4):
            print('... continua')
            
    # SALIDA
    print('Método Iterativo EDP Elíptica')
    print('iteraciones:',itera,' converge = ', converge)
    print('errado_u: ', errado_u)
    print('xi:', xi)
    print('yj:', yj)
    print('Tabla de resultados en malla EDP Elíptica')
    print('j, U[i,j]')
    for j in range(m-1,-1,-1):
        print(j,u[:,j])
    

    La gráfica de resultados requiere ajuste de ejes, pues el índice de filas es el eje x, y las columnas es el eje y. La matriz y sus datos en la gráfica se obtiene como la transpuesta de u

    # GRAFICA 3D ------
    import matplotlib.pyplot as plt
    # Malla para cada eje X,Y
    Xi, Yi = np.meshgrid(xi, yj)
    U = np.transpose(u) # ajuste de índices fila es x
    
    fig_3D = plt.figure()
    graf_3D = fig_3D.add_subplot(111, projection='3d')
    graf_3D.plot_wireframe(Xi,Yi,U,
                           color ='blue')
    graf_3D.plot(Xi[1,0],Yi[1,0],U[1,0],'o',color ='orange')
    graf_3D.plot(Xi[1,1],Yi[1,1],U[1,1],'o',color ='red',
                 label='U[i,j]')
    graf_3D.plot(Xi[1,2],Yi[1,2],U[1,2],'o',color ='salmon')
    graf_3D.plot(Xi[0,1],Yi[0,1],U[0,1],'o',color ='green')
    graf_3D.plot(Xi[2,1],Yi[2,1],U[2,1],'o',color ='salmon')
    
    graf_3D.set_title('EDP elíptica')
    graf_3D.set_xlabel('x')
    graf_3D.set_ylabel('y')
    graf_3D.set_zlabel('U')
    graf_3D.legend()
    graf_3D.view_init(35, -45)
    plt.show()
    

    EDP Elípticas [ concepto ] [ ejercicio ]
    Método iterativo: [ Analítico ] [ Algoritmo ]

     

  • 7.2 EDP Elípticas

    EDP Elípticas [ concepto ] Método [ iterativo ] [ implícito ]
    ..


    1. EDP Elípticas

    Referencia: Chapra 29.1 p866, Rodríguez 10.3 p425, Burden 12.1 p694

    Las Ecuaciones Diferenciales Parciales tipo elípticas semejantes a la mostrada:

    \frac{\partial ^2 u}{\partial x^2} + \frac{\partial ^2 u}{ \partial y^2} = 0

    (ecuación de Laplace, Ecuación de Poisson con f(x,y)=0)

    se interpreta como una placa metálica de dimensiones Lx y Ly, delgada con aislante que recubren las caras de la placa, y sometidas a condiciones en las fronteras:

    Lx = dimensión x de placa metálica
    Ly = dimensión y de placa metálica
    u[0,y]  = Ta
    u[Lx,y] = Tb
    u[x,0]  = Tc
    u[x,Ly] = Td

    Placa Metalica 01

    Para el planteamiento se usa una malla en la que cada nodo corresponden a los valores u[xi,yj]. Para simplificar la nomenclatura se usan los subíndices i para el eje de las x,  j para el eje t, quedando u[i,j].

    EDP Elipticas Iterativo

    vista superior, plano xy:

    Placa Metalica 02

    La ecuación se cambia a la forma discreta, usando diferencias divididas que se sustituyen en la ecuación, por ejemplo:

    \frac{u_{i+1,j}-2u_{i,j}+u_{i-1,j}}{(\Delta x)^2} + \frac{u_{i,j+1}-2u_{i,j}+u_{i,j-1}}{(\Delta y)^2}=0

    Se agrupan los términos de los diferenciales:

    \frac{(\Delta y)^2}{(\Delta x)^2} \Big( u_{i+1,j}-2u_{i,j} +u_{i-1,j} \Big)+ u_{i,j+1}-2u_{i,j}+u_{i,j-1}=0 \lambda \Big( u_{i+1,j}-2u_{i,j} +u_{i-1,j} \Big)+ u_{i,j+1}-2u_{i,j}+u_{i,j-1}=0 \lambda u_{i+1,j} - 2\lambda u_{i,j} + \lambda u_{i-1,j} + u_{i,j+1} - 2 u_{i,j} + u_{i,j-1} = 0 \lambda u_{i+1,j} + (-2\lambda-2) u_{i,j} +\lambda u_{i-1,j} + u_{i,j+1} +u_{i,j-1}=0

    Obteniendo así la solución numérica conceptual. La forma de resolver el problema determina el nombre del método a seguir.

    Una forma de simplificar la expresión, es hacer λ=1, es decir  \lambda = \frac{(\Delta y)^2}{(\Delta x)^2} = 1, se determina que los tamaño de paso Δx, Δy son iguales.

    u_{i+1,j}-4u_{i,j}+u_{i-1,j} + u_{i,j+1} +u_{i,j-1} = 0

    EDP Elípticas [ concepto ] Método [ iterativo ] [ implícito ]

  • 7.1.2 EDP Parabólicas método implícito con Python

    EDP Parabólica [ concepto ] [ ejercicio ]
    Método implícito: [ Analítico ] [ Algoritmo ]

    ..


    1. Ejercicio

    Referencia:  Chapra 30.3 p893 pdf917, Burden 9Ed 12.2 p729, Rodríguez 10.2.4 p415

    Siguiendo el tema anterior en EDP Parabólicas, se tiene que:

    \frac{\partial ^2 u}{\partial x ^2} = K\frac{\partial u}{\partial t}

    Ecuación Diferencial Parcial Parabólica método Implicito animado

    EDP Parabólica [ concepto ] [ ejercicio ]
    Método implícito: [ Analítico ] [ Algoritmo ]

    ..


    2. Desarrollo Analítico

    En éste caso se usan diferencias finitas centradas y hacia atrás; la línea de referencia es t1:

    \frac{\partial^2 u}{\partial x^2} = \frac{u_{i+1,j} - 2 u_{i,j} + u_{i-1,j}}{(\Delta x)^2} \frac{\partial u}{\partial t} = \frac{u_{i,j} - u_{i,j-1} }{\Delta t}

    La selección de las diferencias divididas corresponden a los puntos que se quieren usar para el cálculo, se observan mejor en la gráfica de la malla.

    Barra Metalica 04

    Luego se sustituyen en la ecuación del problema, obteniendo:

    \frac{u_{i+1,j}-2u_{i,j}+u_{i-1,j}}{(\Delta x)^2} = K\frac{u_{i,j}-u_{i,j-1}}{\Delta t}

    De la gráfica se destaca que en la fórmula, dentro del triángulo solo hay DOS valores desconocidos, destacados por los punto en amarillo.
    En la ecuación se representa por U[i,j] y U[i+1,j]. Por lo que será necesario crear un sistema de ecuaciones sobre toda la línea de tiempo t1 para resolver el problema.

    EDP M Implicito 02

    Despejando la ecuación, se agrupan términos constantes: λ = \frac{\Delta t}{K (\Delta x)^2} .

    \lambda u_{i-1,j} + (-1-2\lambda) u_{i,j} + \lambda u_{i+1,j} = -u_{i,j-1}

    Los parámetro P, Q y R se determinan de forma semejante al método explícito:

    P = \lambda Q = -1-2\lambda R = \lambda Pu_{i-1,j} + Qu_{i,j} + Ru_{i+1,j} = -u_{i,j-1}

    Los valores en los extremos son conocidos, para los puntos intermedios  se crea un sistema de ecuaciones para luego usar la forma Ax=B y resolver los valores para cada u(xi,tj).

    Por ejemplo con cuatro tramos entre extremos se tiene que:
    indice de tiempo es 1 e índice de x es 1.

    i=1,j=1

    Pu_{0,1} + Qu_{1,1} + Ru_{2,1} = -u_{1,0}

    i=2,j=1

    Pu_{1,1} + Qu_{2,1} + Ru_{3,1} = -u_{2,0}

    i=3,j=1

    Pu_{2,1} + Qu_{3,1} + Ru_{4,1} = -u_{3,0}

    agrupando ecuaciones y sustituyendo valores conocidos:
    \begin{cases} Qu_{1,1} + Ru_{2,1} + 0 &= -T_{0}-PT_{A}\\Pu_{1,1} + Qu_{2,1} + Ru_{3,1} &= -T_{0}\\0+Pu_{2,1}+Qu_{3,1}&=-T_{0}-RT_{B}\end{cases}

    que genera la matriz a resolver:

    \begin{bmatrix} Q && R && 0 && -T_{0}-PT_{A}\\P && Q && R && -T_{0}\\0 && P && Q && -T_{0}-RT_{B}\end{bmatrix}

    Use alguno de los métodos de la unidad 3 para resolver el sistema y obtener los valores correspondientes.

    Por la extensión de la solución es conveniente usar un algoritmo y convertir los pasos o partes pertinentes a funciones.

    Tarea: Revisar y comparar con el método explícito.

    EDP Parabólica [ concepto ] [ ejercicio ]
    Método implícito: [ Analítico ] [ Algoritmo ]

    ..


    Algoritmos en Python

    Para la solución con el método implícito, se obtiene el mismo resultado en la gráfica y tabla. Aunque el algoritmo es diferente.

    EDP Parabolica
    algunos valores:

    iteración j: 1
    A:
     [[-1.5   0.25  0.    0.    0.    0.    0.    0.    0.  ]
     [ 0.25 -1.5   0.25  0.    0.    0.    0.    0.    0.  ]
     [ 0.    0.25 -1.5   0.25  0.    0.    0.    0.    0.  ]
     [ 0.    0.    0.25 -1.5   0.25  0.    0.    0.    0.  ]
     [ 0.    0.    0.    0.25 -1.5   0.25  0.    0.    0.  ]
     [ 0.    0.    0.    0.    0.25 -1.5   0.25  0.    0.  ]
     [ 0.    0.    0.    0.    0.    0.25 -1.5   0.25  0.  ]
     [ 0.    0.    0.    0.    0.    0.    0.25 -1.5   0.25]
     [ 0.    0.    0.    0.    0.    0.    0.    0.25 -1.5 ]]
    B:
     [-40. -25. -25. -25. -25. -25. -25. -25. -35.]
    resultado en j: 1 
     [31.01 26.03 25.18 25.03 25.01 25.01 25.08 25.44 27.57]
    iteración j: 2
    A:
     [[-1.5   0.25  0.    0.    0.    0.    0.    0.    0.  ]
     [ 0.25 -1.5   0.25  0.    0.    0.    0.    0.    0.  ]
     [ 0.    0.25 -1.5   0.25  0.    0.    0.    0.    0.  ]
     [ 0.    0.    0.25 -1.5   0.25  0.    0.    0.    0.  ]
     [ 0.    0.    0.    0.25 -1.5   0.25  0.    0.    0.  ]
     [ 0.    0.    0.    0.    0.25 -1.5   0.25  0.    0.  ]
     [ 0.    0.    0.    0.    0.    0.25 -1.5   0.25  0.  ]
     [ 0.    0.    0.    0.    0.    0.    0.25 -1.5   0.25]
     [ 0.    0.    0.    0.    0.    0.    0.    0.25 -1.5 ]]
    B:
     [-46.01 -26.03 -25.18 -25.03 -25.01 -25.01 -25.08 -25.44 -37.57]
    resultado en j: 2 
     [35.25 27.49 25.55 25.12 25.03 25.05 25.24 26.07 29.39]
    iteración j: 3
    A:
     [[-1.5   0.25  0.    0.    0.    0.    0.    0.    0.  ]
     [ 0.25 -1.5   0.25  0.    0.    0.    0.    0.    0.  ]
     [ 0.    0.25 -1.5   0.25  0.    0.    0.    0.    0.  ]
     [ 0.    0.    0.25 -1.5   0.25  0.    0.    0.    0.  ]
     [ 0.    0.    0.    0.25 -1.5   0.25  0.    0.    0.  ]
     [ 0.    0.    0.    0.    0.25 -1.5   0.25  0.    0.  ]
     [ 0.    0.    0.    0.    0.    0.25 -1.5   0.25  0.  ]
     [ 0.    0.    0.    0.    0.    0.    0.25 -1.5   0.25]
     [ 0.    0.    0.    0.    0.    0.    0.    0.25 -1.5 ]]
    B:
     [-50.25 -27.49 -25.55 -25.12 -25.03 -25.05 -25.24 -26.07 -39.39]
    resultado en j: 3 
     [38.34 29.06 26.09 25.28 25.09 25.13 25.47 26.74 30.72]
    EDP Parabólica - Método implícito 
    lambda:  0.25
    x: [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]
    t: [0.   0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 ] ... 1.0
    Tabla de resultados en malla EDP Parabólica
    j, U[:,: 10 ], primeras iteraciones
    10 [60.   47.43 37.58 31.3  27.98 26.64 26.63 27.83 30.43 34.63 40.  ]
    9 [60.   46.75 36.68 30.56 27.48 26.3  26.33 27.47 30.04 34.33 40.  ]
    8 [60.   45.96 35.69 29.8  27.01 26.   26.06 27.12 29.6  33.99 40.  ]
    7 [60.   45.01 34.6  29.02 26.57 25.73 25.81 26.76 29.13 33.58 40.  ]
    6 [60.   43.87 33.39 28.24 26.16 25.51 25.58 26.41 28.6  33.09 40.  ]
    5 [60.   42.45 32.06 27.48 25.8  25.32 25.39 26.07 28.03 32.48 40.  ]
    4 [60.   40.67 30.61 26.75 25.51 25.18 25.24 25.76 27.41 31.71 40.  ]
    3 [60.   38.34 29.06 26.09 25.28 25.09 25.13 25.47 26.74 30.72 40.  ]
    2 [60.   35.25 27.49 25.55 25.12 25.03 25.05 25.24 26.07 29.39 40.  ]
    1 [60.   31.01 26.03 25.18 25.03 25.01 25.01 25.08 25.44 27.57 40.  ]
    0 [60. 25. 25. 25. 25. 25. 25. 25. 25. 25. 40.]
    >>> 
    

    Instrucciones en Python

    # EDP parabólicas d2u/dx2  = K du/dt
    # método implícito
    # Referencia: Chapra 30.3 p.895 pdf.917
    #       Rodriguez 10.2.5 p.417
    import numpy as np
    
    # INGRESO
    # Valores de frontera
    Ta = 60
    Tb = 40
    #T0 = 25 # estado inicial de barra
    fx = lambda x: 25 + 0*x # función inicial para T0
    a = 0  # longitud en x
    b = 1
    
    K = 4     # Constante K
    dx = 0.1  # Tamaño de paso
    dt = dx/10
    
    n = 100 # iteraciones en tiempo
    verdigitos = 2   # decimales a mostrar en tabla de resultados
    
    # PROCEDIMIENTO
    # iteraciones en longitud
    xi = np.arange(a,b+dx/2,dx)
    fi = fx(xi)
    m  = len(xi)
    ultimox = m-1
    ultimot = n-1
    # Resultados en tabla u[x,t]
    u = np.zeros(shape=(m,n), dtype=float)
    
    # valores iniciales de u[:,j]
    j = 0
    u[0,:]= Ta
    u[1:ultimox,j] = fi[1:ultimox]
    u[ultimox,:] = Tb
    
    # factores P,Q,R
    lamb = dt/(K*dx**2)
    P = lamb
    Q = -1 -2*lamb
    R = lamb
    
    # Calcula U para cada tiempo + dt
    tj = np.arange(0,(n+1)*dt,dt)
    j = 1
    while not(j>=n):
        # Matriz de ecuaciones
        k = m-2
        A = np.zeros(shape=(k,k), dtype = float)
        B = np.zeros(k, dtype = float)
        for f in range(0,k,1):
            if (f>0):
                A[f,f-1]=P
            A[f,f] = Q
            if (f<(k-1)):
                A[f,f+1]=R
            B[f] = -u[f+1,j-1]
        B[0] = B[0]-P*u[0,j]
        B[k-1] = B[k-1]-R*u[m-1,j]
        # Resuelve sistema de ecuaciones
        C = np.linalg.solve(A, B)
    
        # copia resultados a u[i,j]
        for f in range(0,k,1):
            u[f+1,j] = C[f]
    
        # siguiente iteración
        j = j + 1
    
        # muestra 3 primeras iteraciones
        np.set_printoptions(precision=verdigitos)
        if j<(3+2): 
            print('iteración j:',j-1)
            print('A:\n',A)
            print('B:\n',B)
            print('resultado en j:',j-1,'\n',C)
            
    # SALIDA
    print('EDP Parabólica - Método implícito ')
    print('lambda: ',np.around(lamb,verdigitos))
    print('x:',xi)
    print('t:',tj[0:len(xi)],'...',tj[-1])
    print('Tabla de resultados en malla EDP Parabólica')
    print('j, U[:,:',ultimox,'], primeras iteraciones')
    for j in range(ultimox,-1,-1):
        print(j,u[:,j])
    

    Para realizar la gráfica se aplica lo mismo que en el método explícito

    # GRAFICA ------------
    import matplotlib.pyplot as plt
    tramos = 10
    salto = int(n/tramos) # evita muchas líneas
    if (salto == 0):
        salto = 1
    for j in range(0,n,salto):
        vector = u[:,j]
        plt.plot(xi,vector)
        plt.plot(xi,vector, '.',color='red')
    plt.xlabel('x[i]')
    plt.ylabel('u[j]')
    plt.title('Solución EDP parabólica')
    plt.show()
    

    Sin embargo para la gráfica en 3D se ajustan los puntos de referencia agregados por las diferencias finitas.

    # GRAFICA en 3D
    # vector de tiempo, simplificando en tramos
    tramos = 10
    salto = int(n/tramos)
    if (salto == 0):
        salto = 1
    tj = np.arange(0,n*dt,dt)
    tk = np.zeros(tramos,dtype=float)
    
    # Extrae parte de la matriz U,acorde a los tramos
    U = np.zeros(shape=(tramos,m),dtype=float)
    for k in range(0,tramos,1):
        U[k,:] = u[:,k*salto]
        tk[k] = tj[k*salto]
    # Malla para cada eje X,Y
    Xi, Yi = np.meshgrid(xi,tk)
    
    fig_3D = plt.figure()
    graf_3D = fig_3D.add_subplot(111, projection='3d')
    graf_3D.plot_wireframe(Xi,Yi,U,
                           color ='blue',label='EDP Parabólica')
    graf_3D.plot(Xi[2,0],Yi[2,0],U[2,0],'o',color ='orange')
    graf_3D.plot(Xi[2,1],Yi[2,1],U[2,1],'o',color ='salmon')
    graf_3D.plot(Xi[2,2],Yi[2,2],U[2,2],'o',color ='salmon')
    graf_3D.plot(Xi[1,1],Yi[1,1],U[1,1],'o',color ='green')
    graf_3D.set_title('EDP Parabólica')
    graf_3D.set_xlabel('x')
    graf_3D.set_ylabel('t')
    graf_3D.set_zlabel('U')
    graf_3D.legend()
    graf_3D.view_init(35, -45)
    plt.show()
    

    Queda por revisar la convergencia y estabilidad de la solución a partir de los O(h) de cada aproximación usada. Revisar los criterios en Chapra 30.2.1 p891, Burden 9Ed 12.2 p727, Rodríguez 10.2.2 p409 .

    Tarea o proyecto: Realizar la comparación de tiempos de ejecución entre los métodos explícitos e implícitos. La parte de animación funciona igual en ambos métodos.  Los tiempos de ejecución se determinan usando las instrucciones descritas en el enlace: Tiempos de Ejecución en Python


    EDP Parabólica [ concepto ] [ ejercicio ]
    Método implícito: [ Analítico ] [ Algoritmo ]