Autor: Edison Del Rosario

  • 1Eva_2023PAOII_T2 Trayectoria de buque en puerto

    1ra Evaluación 2023-2024 PAO II. 21/Noviembre/2023

    Tema 2. (40 puntos) El DPS (Dynamic Positioning System) controla automáticamente la posición y el rumbo de un barco usando propulsión activa mediante un ordenador y una variedad de sistemas y funciones.

    trayectoria buque 01En el caso de entradas a puertos comerciales de alto tráfico y limitado espacio se convierten el una herramienta indispensable para gestionar las recorridos de ingreso o salida.

    Suponga que como primer paso para planificar una ruta de un barco de contenedores, minimizando el gasto de energía usando la inercia del barco se planifica una ruta siguiendo los puntos de marca indicados en la tabla.

    Puntos referenciales para la ruta
    x 0.1 2.0 4.0 5.0 7.0
    y 1.0 8.0 0.0 -1.0 3.0

    a. Plantee el ejercicio usando un polinomio de interpolación y un sistema de ecuaciones.

    b. Establezca la forma matricial del sistema de ecuaciones (Vandermonde) y como matriz aumentada

    c. De ser necesario realice el pivoteo parcial por filas

    d. Use el método directo Gauss, desarrolle todas las expresiones de las operaciones que realiza el algoritmo numérico. Estime la tolerancia y justifique.

    e. Comente sobre la convergencia del método si usara un método iterativo. (número de condición)

    f. Adjunte los archivos: algoritmos.py, resultados.txt y gráfica.png del polinomio.

    x = [0.1,2.0,4.0,5.0,7.0]
    y = [1.0,8.0,0.0,-1.0,3.0]

    Rúbrica: literal a (5 puntos), literal b (5 puntos), literal c (5 puntos), literal d (15 puntos), literal e (5 puntos), literal f (5 puntos).

    Referencia: [1] Gigante buque ingresa a las terminales portuarias de Guayaquil. El Universo. 18 Ene 2020. https://youtu.be/X5S9x53Z_mY?
    [2] Reportan congestión de buques de carga en puertos de EE.UU. Noticias Telemundo. 22 sept 2021.

    [3] Colisiones y errores de barcos jamás capturados en cámara. 21 oct 2023.

     

  • 1Eva_2023PAOII_T1 GPR Radar penetrante de suelo

    1ra Evaluación 2023-2024 PAO II. 21/Noviembre/2023

    Tema 1. (30 puntos) Radar penetrante o GPR (Ground Penetrating Radar) es el término general aplicado para mapear o cartografiar estructuras enterradas en el suelo. radar penetrante de suelo
    El GPR se utiliza en muchas áreas como la localización de tuberías enterradas para servicios públicos, la evaluación del sitio en minas, excavaciones arqueológicas, medición del espesor de nieve o hielo para la gestión de pistas de esquí, etc.
    Al emitir un pulso de radio hacia el suelo, la señal rebota al cambiar de medio y puede ser detectada en la superficie. Por lo que la distancia recorrida por la señal es de dos veces d.
    Simplificando el ejercicio, considere la potencia de la señal recibida en el receptor en dB se expresa como:

    RSSI(d)=-10\alpha log_{10}(d)+ P_0 ; d\gt0

    Suponga que el coeficiente de atenuación del medio α = 4.5, P0 = - 20 y Rssi = -90, que la composición del suelo es uniforme y no existen pérdidas al rebotar sobre el material de la tubería mostrada en la gráfica.

    a. Plantear el ejercicio para encontrar la profundidad a la que se encontraría la tubería usando el método de Newton-Raphson.

    b. Describa el criterio para seleccionar un valor inicial de búsqueda y la tolerancia a usar en la solución.

    c. Realice al menos tres iteraciones para el método indicado.

    d. Realice observaciones sobre la convergencia del método.

    e. Adjunte los archivos: algoritmos.py, resultados.txt y gráfica.png

    Rúbrica: literal a (5 puntos), literal b (3 puntos), literal c (12 puntos), literal d (5 puntos), literal e (5 puntos)

    Referencia: [1] ¿Puedo predecir la profundidad de exploración?. Sensors&Software. https://www.sensoft.ca/es/blog/what-is-gpr/
    [2] Te mostramos en realidad aumentada cómo son los túneles. Univisión Noticias. 16 oct 2023.

  • 7.4 EDP con gráficos animados en Python

    Solo para fines didácticos, y como complemento para los ejercicios presentados en la unidad para Ecuaciones Diferenciales Parciales, se presentan las instrucciones para las animaciones usadas en la presentación de los conceptos y ejercicios. Los algoritmos para animación NO son necesarios para realizar los ejercicios, que requieren una parte analítica con al menos tres iteraciones en papel y lápiz. Se lo adjunta como una herramienta didáctica de asistencia para las clases.


    EDP Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]
    ..


    1. EDP Parabólicas método explícito

    EDP_Parabolica Ani 01
    resultados del algoritmo

    Método explícito EDP Parabólica
    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] ... 1.0
    Tabla de resultados en malla EDP Parabólica
    j, U[:,: 5 ], primeras iteraciones de  100
    5 [60.   44.21 32.93 27.29 25.41 25.05 25.18 25.98 28.4  33.23 40.  ]
    4 [60.   42.77 31.29 26.37 25.14 25.   25.06 25.59 27.7  32.62 40.  ]
    3 [60.   40.86 29.38 25.55 25.   25.   25.   25.23 26.88 31.8  40.  ]
    2 [60.   38.12 27.19 25.   25.   25.   25.   25.   25.94 30.62 40.  ]
    1 [60.   33.75 25.   25.   25.   25.   25.   25.   25.   28.75 40.  ]
    0 [60. 25. 25. 25. 25. 25. 25. 25. 25. 25. 40.]
    

    Algoritmo en Python

    # EDP parabólicas d2u/dx2  = K du/dt
    # método explícito,usando diferencias divididas
    import numpy as np
    
    # INGRESO
    # Valores de frontera
    Ta = 60  # izquierda de barra
    Tb = 40  # derecha de barra
    #Tc = 25 # estado inicial de barra en x
    fxc = lambda x: 25 + 0*x # f(x) en tiempo inicial
    
    # dimensiones de la barra
    a = 0  # longitud en x
    b = 1
    t0 = 0 # tiempo inicial, aumenta con dt en n iteraciones
    
    K = 4     # Constante K
    dx = 0.1  # muestreo en x, tamaño de paso
    dt = dx/10
    
    n = 100  # iteraciones en tiempo
    verdigitos = 2   # decimales a mostrar en tabla de resultados
    
    # coeficientes de U[x,t]. factores P,Q,R, 
    lamb = dt/(K*dx**2)
    P = lamb       # izquierda P*U[i-1,j]
    Q = 1 - 2*lamb # centro Q*U[i,j]
    R = lamb       # derecha R*U[i+1,j]
    
    # PROCEDIMIENTO
    # iteraciones en x, longitud
    xi = np.arange(a,b+dx/2,dx)
    m = len(xi) 
    ultimox = m-1
    ultimot = n-1
    
    # u[xi,tj], tabla de resultados
    u = np.zeros(shape=(m,n+1), dtype=float)
    
    # u[i,j], valores iniciales
    u[0,:] = Ta  # Izquierda
    u[ultimox,:] = Tb  # derecha
    # estado inicial de barra en x, Tc
    fic = fxc(xi) # f(x) en tiempo inicial
    u[1:ultimox,0] = fic[1:ultimox]
    
    # Calcula U para cada tiempo + dt
    tj = np.arange(t0,(n+1)*dt,dt)
    for j  in range(0,n,1):
        for i in range(1,ultimox,1):
            # ecuacion discreta, entre [1,ultimox]
            u[i,j+1] = P*u[i-1,j] + Q*u[i,j] + R*u[i+1,j]
    
    # SALIDA
    j_mostrar = 5
    np.set_printoptions(precision=verdigitos)
    print('Método explícito EDP Parabólica')
    print('lambda: ',np.around(lamb,verdigitos))
    print('x:',xi)
    print('t:',tj[0:j_mostrar],'...',tj[-1])
    print('Tabla de resultados en malla EDP Parabólica')
    print('j, U[:,:',j_mostrar,'], primeras iteraciones de ',n)
    for j in range(j_mostrar,-1,-1):
        print(j,u[:,j])
    

    EDP Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]
    ..


    1.1 Gráficas 2D, EDP Parabólica, método explícito

    # GRAFICA 2D ------------
    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()
    

    EDP Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]
    ..


    1.3 Gráficas 3D,  EDP Parabólica, método explícito

    Esta sección es la base para la generación de las animaciones siguientes, por lo que debe ser incluida antes de las dos siguientes animaciones 2D o 3D. Al menos hasta la parte donde se realiza la transpuesta de U.

    # GRAFICA 3D -----------
    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=(m,tramos),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)
    U = np.transpose(U)
    
    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[0],tk[1],U[1,0],'o',color ='orange')
    graf_3D.plot(xi[1],tk[1],U[1,1],'o',color ='green')
    graf_3D.plot(xi[2],tk[1],U[1,2],'o',color ='green')
    graf_3D.plot(xi[1],tk[2],U[2,1],'o',color ='salmon',
                 label='U[i,j+1]')
    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()
    

    EDP Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]
    ..


    1.4 Gráficas 2D animada, EDP Parabólica, método explícito

    La animación en 2D para la EDP parabólica método explícito se añade, luego de comentar el #plt.show() anterior

    EDP Parabolica Ani 01

    # GRAFICA 2D ANIMADA --------
    # import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    unmetodo = 'EDP Parabólica - Método explícito'
    narchivo = 'EdpParabolica' # nombre archivo GIF
    
    # Parametros de trama/foto
    retardo = 500   # milisegundos entre tramas
    
    # GRAFICA animada en fig_ani
    fig_ani, graf_ani = plt.subplots()
    
    # Lineas y puntos base
    linea_f, = graf_ani.plot(xi,u[:,0])
    graf_ani.axhline(0, color='k')  # Eje en x=0
    
    maximoy = np.max(u) 
    txt_y = maximoy*(1-0.1)
    txt_f = graf_ani.text(xi[0],txt_y,'tiempo:',
                          horizontalalignment='left')
    # Configura gráfica
    graf_ani.set_xlim([xi[0],xi[ultimox]])
    graf_ani.set_ylim([ np.min(u),maximoy])
    graf_ani.set_title(unmetodo)
    graf_ani.set_xlabel('x')
    graf_ani.set_ylabel('u')
    #graf_ani.legend()
    graf_ani.grid()
    
    # Nueva Trama
    def unatrama(i,xi,u):
        # actualiza cada linea
        linea_f.set_ydata(u[:,i])
        linea_f.set_xdata(xi)
        linea_f.set_label('tiempo linea: '+str(i))
        if (i<=9): # color de la línea
            lineacolor = 'C'+str(i)
        else:
            numcolor = i%10
            lineacolor = 'C'+str(numcolor)
        linea_f.set_color(lineacolor)
        txt_f.set_text('tiempo['+str(i)+'] = ' + str(i*dt))
        return linea_f, txt_f,
    
    # Limpia Trama anterior
    def limpiatrama(): 
        linea_f.set_ydata(np.ma.array(xi, mask=True))
        linea_f.set_label('')
        txt_f.set_text('')
        return linea_f, txt_f,
    
    # contador de tramas
    i = np.arange(0,len(tk),1)
    ani = animation.FuncAnimation(fig_ani, unatrama,
                                  i, fargs=(xi,u),
                                  init_func=limpiatrama,
                                  interval=retardo,
                                  blit=False)
    # Graba Archivo GIFAnimado y video
    ani.save(narchivo+'_animado.gif',writer='pillow')
    #ani.save(narchivo+'.mp4')
    plt.draw()
    plt.show()
    

    EDP Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]
    ..


    1.5 Gráficas 3D animada, EDP Parabólica, método explícito

    Ecuación diferencial parcial Parabolica animado

    Para el caso de animación 3D, se cambia la sección de animación del algoritmo anterior por:

    # GRAFICA 3D ANIMADA --------
    # import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    unmetodo = 'EDP Parabólica - Método explícito'
    narchivo = 'EdpParabolica2' # nombre archivo GIF
    
    # Parametros de trama/foto
    retardo = 500   # milisegundos entre tramas
    
    # GRAFICA animada en fig_ani
    fig_ani3D = plt.figure()
    graf_ani3 = fig_ani3D.add_subplot(projection='3d')
    
    # Lineas y puntos base
    ##graf_ani3.plot_wireframe(Xi,Yi,U,
    ##                         color ='blue',label='EDP Parabólica')
    punto_a, = graf_ani3.plot(xi[0],tk[0],U[1,0],'o',color ='green')
    punto_b, = graf_ani3.plot(xi[0],tk[0],U[1,0],'o',
                              color ='salmon',label='U[i,j+1]')
    linea_c, = graf_ani3.plot(xi[0],tk[0],U[1,0],'-',color ='blue')
    # Configura gráfica
    graf_ani3.set_xlim(min(xi),max(xi))
    graf_ani3.set_ylim(min(tk),max(tk))
    graf_ani3.set_title(unmetodo)
    graf_ani3.set_xlabel('x')
    graf_ani3.set_ylabel('t')
    graf_ani3.set_zlabel('U')
    graf_ani3.legend()
    graf_ani3.grid()
    graf_ani3.view_init(35, -45)
    
    mallaEDP = None
    # Nueva Trama
    def unatrama(i,xi,tk,U,k):
        f = i//k
        c = i%k
        # actualiza cada punto
        punto_a.set_data([[xi[c],xi[c+1],xi[c+2]],
                          [tk[f],tk[f],tk[f]]])
        punto_a.set_3d_properties([U[f,c],U[f,c+1],U[f,c+2]])
        punto_b.set_data([xi[c+1]],[tk[f+1]])
        punto_b.set_3d_properties([U[f+1,c+1]])
        linea_c.set_data(xi[0:c+2],[tk[f+1]]*(c+2))
        linea_c.set_3d_properties([U[f+1,0:c+2]])
        
        global mallaEDP
        if mallaEDP:
            mallaEDP.remove()
        mallaEDP = graf_ani3.plot_wireframe(Xi[0:f+1,:],
                                            Yi[0:f+1,:],
                                            U[0:f+1,:],
                                            color ='blue',
                                            label='EDP Parabólica')
        return (punto_a,punto_b,linea_c)
    
    
    # contador de tramas
    k = len(xi)-2
    k2 = k*(len(tk)-1)
    i = np.arange(0,k2,1)
    ani = animation.FuncAnimation(fig_ani3D, unatrama,
                                  i ,
                                  fargs=(xi,tk,U,k),
                                  interval=retardo,
                                  blit=False)
    # Graba Archivo GIFAnimado y video
    ani.save(narchivo+'_animado.gif', writer='pillow')
    #ani.save(narchivo+'.mp4')
    #plt.draw()
    plt.show()
    

    EDP Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]

    ..


    1.6 Gráfica 3D, EDP Parabólicas método implícito

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

    Puesto que la solución de la tabla de resultados en U es la misma que el los dos métodos explícito e implícito, solo se adjunta la parte de la animación.

    Para el caso del la gráfica 3D del método implícito se cambia la sección de gráfica animada por:

    # GRAFICA 3D ANIMADA --------
    # import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    unmetodo = 'EDP Parabólica - Método explícito'
    narchivo = 'EdpParabolica2' # nombre archivo GIF
    
    # Parametros de trama/foto
    retardo = 500   # milisegundos entre tramas
    
    # GRAFICA animada en fig_ani
    fig_ani3D = plt.figure()
    graf_ani3 = fig_ani3D.add_subplot(projection='3d')
    
    # Lineas y puntos base
    ##graf_ani3.plot_wireframe(Xi,Yi,U,
    ##                         color ='blue',label='EDP Parabólica')
    punto_a, = graf_ani3.plot(xi[0],tk[0],U[1,0],'o',color ='green')
    punto_b, = graf_ani3.plot(xi[0],tk[0],U[1,0],'o',
                              color ='salmon',label='U[i,j+1]')
    linea_c, = graf_ani3.plot(xi[0],tk[0],U[1,0],'-',color ='blue')
    # Configura gráfica
    graf_ani3.set_xlim(min(xi),max(xi))
    graf_ani3.set_ylim(min(tk),max(tk))
    graf_ani3.set_title(unmetodo)
    graf_ani3.set_xlabel('x')
    graf_ani3.set_ylabel('t')
    graf_ani3.set_zlabel('U')
    graf_ani3.legend()
    graf_ani3.grid()
    graf_ani3.view_init(35, -45)
    
    mallaEDP = None
    # Nueva Trama
    def unatrama(i,xi,tk,U,k):
        f = i//k
        c = i%k
        # actualiza cada punto
        punto_a.set_data([[xi[c],xi[c+1],xi[c+2]],
                          [tk[f],tk[f],tk[f]]])
        punto_a.set_3d_properties([U[f,c],U[f,c+1],U[f,c+2]])
        punto_b.set_data([xi[c+1]],[tk[f+1]])
        punto_b.set_3d_properties([U[f+1,c+1]])
        linea_c.set_data(xi[0:c+2],[tk[f+1]]*(c+2))
        linea_c.set_3d_properties([U[f+1,0:c+2]])
        
        global mallaEDP
        if mallaEDP:
            mallaEDP.remove()
        mallaEDP = graf_ani3.plot_wireframe(Xi[0:f+1,:],
                                            Yi[0:f+1,:],
                                            U[0:f+1,:],
                                            color ='blue',
                                            label='EDP Parabólica')
        return (punto_a,punto_b,linea_c)
    
    
    # contador de tramas
    k = len(xi)-2
    k2 = k*(len(tk)-1)
    i = np.arange(0,k2,1)
    ani = animation.FuncAnimation(fig_ani3D, unatrama,
                                  i ,
                                  fargs=(xi,tk,U,k),
                                  interval=retardo,
                                  blit=False)
    # Graba Archivo GIFAnimado y video
    ani.save(narchivo+'_animado.gif', writer='pillow')
    #ani.save(narchivo+'.mp4')
    #plt.draw()
    plt.show()
    

    EDP Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]
    ..


    2. EDP Elípticas método iterativo

    Edp Eliptica Itera animado

    Al algoritmo desarrollado en EDP Elípticas método iterativo, se crean una lista para almacenar los valores de la matriz U por cada iteración, se usan para graficar cada iteración.

    # Ecuaciones Diferenciales Parciales
    # Elipticas. Método iterativo
    import numpy as np
    
    # INGRESO
    # Condiciones iniciales en los bordes
    Ta = 60     # izquierda
    Tb = 25     # derecha
    #Tc = 50    # inferior 
    fxc = lambda x: 50+0*x # función inicial inferior
    # Td = 70   # superior
    fxd = lambda x: 70+0*x # función 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
    tolera = 0.0001
    verdigitos = 2   # decimales a mostrar en tabla de resultados
    
    # PROCEDIMIENTO
    xi = np.arange(x0,xn+dx/2,dx)
    yj = np.arange(y0,yn+dy/2,dy)
    n = len(xi)
    m = len(yj)
    
    # Matriz u
    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)
    u[:,0]   = fic  # Tc inferior
    fid = fxd(xi)
    u[:,m-1] = fid  # Td superior
    # valor inicial de iteración dentro de u
    # promedio = (Ta+Tb+Tc+Td)/4
    promedio = (Ta+Tb+np.max(fic)+np.max(fid))/4
    u[1:n-1,1:m-1] = promedio
    np.set_printoptions(precision=verdigitos)
    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] = (u[i-1,j]+u[i+1,j]+u[i,j-1]+u[i,j+1])/4
        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 itera<=3:
            np.set_printoptions(precision=verdigitos)
            print('itera:',itera-1,'  ; ','u:')
            print(np.transpose(u))
            print('errado_u: ', errado_u)
        if itera==4:
            print('... continua')
            
    # SALIDA
    print('Método Iterativo EDP Elíptica')
    print('iteraciones:',itera,' converge = ', converge)
    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])
    

    EDP Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]
    ..


    2.1 Gráfica 3D, EDP Elípticas método iterativo

    # GRAFICA en 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 Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]
    ..


    2.2 Gráfica 3D animada, EDP Elípticas método iterativo

    # GRAFICA CON ANIMACION 3D--------
    # import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    unmetodo = 'EDP Eliptica - Método iterativo'
    narchivo = 'EdpElipticaItera' # nombre archivo GIF
    
    # Parametros de trama/foto
    retardo = 500   # milisegundos entre tramas
    
    # GRAFICA animada en fig_ani
    fig_ani3D = plt.figure()
    graf_ani3 = fig_ani3D.add_subplot(projection='3d')
    
    # Lineas y puntos base
    punto_a, = graf_ani3.plot(xi[0],yj[0],U[0,0],'.',color ='blue')
    
    # Configura gráfica
    graf_ani3.set_xlim(min(xi),max(xi))
    graf_ani3.set_ylim(min(yj),max(yj))
    graf_ani3.set_title(unmetodo)
    graf_ani3.set_xlabel('x')
    graf_ani3.set_ylabel('t')
    graf_ani3.set_zlabel('U')
    # graf_ani3.legend()
    graf_ani3.grid()
    graf_ani3.view_init(35, -45)
    
    etiqueta_i ='itera: '+str(0)
    etiqueta_err = 'errado['+str(0)+']: '+str(U_error[0]) 
    txt_i = graf_ani3.text2D(0.05, 0.95, etiqueta_i,
                             transform=graf_ani3.transAxes)
    txt_errado = graf_ani3.text2D(0.05, 0.90, etiqueta_err,
                                  transform=graf_ani3.transAxes)
    
    mallaEDP = None
    # Nueva Trama
    def unatrama(i,xi,yj,U_3D,U_error):
    
        etiqueta_i ='itera: '+str(i)
        txt_i.set_text(etiqueta_i)
        etiqueta_err = 'errado['+str(i)+']: '+str(U_error[i])
        txt_errado.set_text(etiqueta_err)
        global mallaEDP
        if mallaEDP:
            graf_ani3.collections.remove(mallaEDP)
        mallaEDP = graf_ani3.plot_wireframe(Xi,Yi,
                                            np.transpose(U_3D[i]),
                                            color ='blue')
        return (txt_i,txt_errado,)
    
    
    # contador de tramas
    k = 11 #len(U_3D)
    i = np.arange(0,k,1)
    ani = animation.FuncAnimation(fig_ani3D, unatrama,
                                  i ,
                                  fargs=(xi,yj,U_3D,U_error),
                                  interval=retardo,
                                  blit=False)
    # Graba Archivo GIFAnimado y video
    ani.save(narchivo+'_animado.gif', writer='pillow')
    #ani.save(narchivo+'.mp4')
    #plt.draw()
    plt.show()
    

    EDP Parabólica [ concepto ] [ ejercicio ] || explícito [ algoritmo ] gráfica [ 2D ] [ 3D ] animada [ 2D ] [ 3D ] || implícito gráfica [ 3D animada ] ||
    EDP Elípticas [ concepto ] [ ejercicio ] iterativo [ algoritmo ] [ 3D ] [ 3D animada ]

  • 7.2.4EDP Elípticas - analítico implícito con Sympy-Python

    EDP Elípticas [ contínua a discreta ] || Sympy [ iterativo ] [ implícito ] [ gráfica_3D ]
    ..


    4. EDP Elípticas - Método Implícito con Sympy-Python

    Desarrollo analítico del método implicito para una ecuación diferencial parcial elíptica usando Sympy. El algoritmo reutiliza el algoritmo para la EDP Elíptica de contínua a discreta, la creación de la matriz de valores u_xy, y la función
    edp_sustituyeValorU() para buscar los valores conocidos de la u(x,y).

    El algoritmo usa la ecuación discreta para en cada iteración i,j reemplazar los valores de U conocidos. Los valores de U se escriben en una matriz u_xy, para diferenciar si el valor existe se usa la matriz de estados u_mask.

    Con las ecuaciones de cada iteración se llena la matriz A de coeficientes y el vector B de las constantes. Al resolver el sistema de ecuaciones se obtienen todos los valores de la matriz U, completando el ejercicio. Se desarrola la solución al sistema de ecuaciones usando Sympy como alternativa a usar numpy con np.linalg.solve(A.B) que se encuentra como comentario entre las instrucciones.

     discreta :
    -4⋅U(i, j) + U(i, j - 1) + U(i, j + 1) + U(i - 1, j) + U(i + 1, j) = 0
    
    Método Implícito - EDP Elíptica
    j: 1 ; i: 1 ; ecuacion: 0
    U(0, 1) + U(1, 0) - 4⋅U(1, 1) + U(1, 2) + U(2, 1) = 0
    -4⋅U(1, 1) + U(1, 2) + U(2, 1) = -110.0
    j: 1 ; i: 2 ; ecuacion: 1
    U(1, 1) + U(2, 0) - 4⋅U(2, 1) + U(2, 2) + U(3, 1) = 0
    U(1, 1) - 4⋅U(2, 1) + U(2, 2) + U(3, 1) = -50.0
    j: 1 ; i: 3 ; ecuacion: 2
    U(2, 1) + U(3, 0) - 4⋅U(3, 1) + U(3, 2) + U(4, 1) = 0
    U(2, 1) - 4⋅U(3, 1) + U(3, 2) + U(4, 1) = -50.0
    j: 1 ; i: 4 ; ecuacion: 3
    U(3, 1) + U(4, 0) - 4⋅U(4, 1) + U(4, 2) + U(5, 1) = 0
    U(3, 1) - 4⋅U(4, 1) + U(4, 2) + U(5, 1) = -50.0
    j: 1 ; i: 5 ; ecuacion: 4
    U(4, 1) + U(5, 0) - 4⋅U(5, 1) + U(5, 2) + U(6, 1) = 0
    U(4, 1) - 4⋅U(5, 1) + U(5, 2) + U(6, 1) = -50.0
    j: 1 ; i: 6 ; ecuacion: 5
    U(5, 1) + U(6, 0) - 4⋅U(6, 1) + U(6, 2) + U(7, 1) = 0
    U(5, 1) - 4⋅U(6, 1) + U(6, 2) + U(7, 1) = -50.0
    j: 1 ; i: 7 ; ecuacion: 6
    U(6, 1) + U(7, 0) - 4⋅U(7, 1) + U(7, 2) + U(8, 1) = 0
    U(6, 1) - 4⋅U(7, 1) + U(7, 2) = -75.0
    j: 2 ; i: 1 ; ecuacion: 7
    U(0, 2) + U(1, 1) - 4⋅U(1, 2) + U(1, 3) + U(2, 2) = 0
    U(1, 1) - 4⋅U(1, 2) + U(1, 3) + U(2, 2) = -60.0
    j: 2 ; i: 2 ; ecuacion: 8
    U(1, 2) + U(2, 1) - 4⋅U(2, 2) + U(2, 3) + U(3, 2) = 0
    j: 2 ; i: 3 ; ecuacion: 9
    U(2, 2) + U(3, 1) - 4⋅U(3, 2) + U(3, 3) + U(4, 2) = 0
    j: 2 ; i: 4 ; ecuacion: 10
    U(3, 2) + U(4, 1) - 4⋅U(4, 2) + U(4, 3) + U(5, 2) = 0
    j: 2 ; i: 5 ; ecuacion: 11
    U(4, 2) + U(5, 1) - 4⋅U(5, 2) + U(5, 3) + U(6, 2) = 0
    j: 2 ; i: 6 ; ecuacion: 12
    U(5, 2) + U(6, 1) - 4⋅U(6, 2) + U(6, 3) + U(7, 2) = 0
    j: 2 ; i: 7 ; ecuacion: 13
    U(6, 2) + U(7, 1) - 4⋅U(7, 2) + U(7, 3) + U(8, 2) = 0
    U(6, 2) + U(7, 1) - 4⋅U(7, 2) + U(7, 3) = -25.0
    j: 3 ; i: 1 ; ecuacion: 14
    U(0, 3) + U(1, 2) - 4⋅U(1, 3) + U(1, 4) + U(2, 3) = 0
    U(1, 2) - 4⋅U(1, 3) + U(1, 4) + U(2, 3) = -60.0
    j: 3 ; i: 2 ; ecuacion: 15
    U(1, 3) + U(2, 2) - 4⋅U(2, 3) + U(2, 4) + U(3, 3) = 0
    j: 3 ; i: 3 ; ecuacion: 16
    U(2, 3) + U(3, 2) - 4⋅U(3, 3) + U(3, 4) + U(4, 3) = 0
    j: 3 ; i: 4 ; ecuacion: 17
    U(3, 3) + U(4, 2) - 4⋅U(4, 3) + U(4, 4) + U(5, 3) = 0
    j: 3 ; i: 5 ; ecuacion: 18
    U(4, 3) + U(5, 2) - 4⋅U(5, 3) + U(5, 4) + U(6, 3) = 0
    j: 3 ; i: 6 ; ecuacion: 19
    U(5, 3) + U(6, 2) - 4⋅U(6, 3) + U(6, 4) + U(7, 3) = 0
    j: 3 ; i: 7 ; ecuacion: 20
    U(6, 3) + U(7, 2) - 4⋅U(7, 3) + U(7, 4) + U(8, 3) = 0
    U(6, 3) + U(7, 2) - 4⋅U(7, 3) + U(7, 4) = -25.0
    j: 4 ; i: 1 ; ecuacion: 21
    U(0, 4) + U(1, 3) - 4⋅U(1, 4) + U(1, 5) + U(2, 4) = 0
    U(1, 3) - 4⋅U(1, 4) + U(1, 5) + U(2, 4) = -60.0
    j: 4 ; i: 2 ; ecuacion: 22
    U(1, 4) + U(2, 3) - 4⋅U(2, 4) + U(2, 5) + U(3, 4) = 0
    j: 4 ; i: 3 ; ecuacion: 23
    U(2, 4) + U(3, 3) - 4⋅U(3, 4) + U(3, 5) + U(4, 4) = 0
    j: 4 ; i: 4 ; ecuacion: 24
    U(3, 4) + U(4, 3) - 4⋅U(4, 4) + U(4, 5) + U(5, 4) = 0
    j: 4 ; i: 5 ; ecuacion: 25
    U(4, 4) + U(5, 3) - 4⋅U(5, 4) + U(5, 5) + U(6, 4) = 0
    j: 4 ; i: 6 ; ecuacion: 26
    U(5, 4) + U(6, 3) - 4⋅U(6, 4) + U(6, 5) + U(7, 4) = 0
    j: 4 ; i: 7 ; ecuacion: 27
    U(6, 4) + U(7, 3) - 4⋅U(7, 4) + U(7, 5) + U(8, 4) = 0
    U(6, 4) + U(7, 3) - 4⋅U(7, 4) + U(7, 5) = -25.0
    j: 5 ; i: 1 ; ecuacion: 28
    U(0, 5) + U(1, 4) - 4⋅U(1, 5) + U(1, 6) + U(2, 5) = 0
    U(1, 4) - 4⋅U(1, 5) + U(2, 5) = -130.0
    j: 5 ; i: 2 ; ecuacion: 29
    U(1, 5) + U(2, 4) - 4⋅U(2, 5) + U(2, 6) + U(3, 5) = 0
    U(1, 5) + U(2, 4) - 4⋅U(2, 5) + U(3, 5) = -70.0
    j: 5 ; i: 3 ; ecuacion: 30
    U(2, 5) + U(3, 4) - 4⋅U(3, 5) + U(3, 6) + U(4, 5) = 0
    U(2, 5) + U(3, 4) - 4⋅U(3, 5) + U(4, 5) = -70.0
    j: 5 ; i: 4 ; ecuacion: 31
    U(3, 5) + U(4, 4) - 4⋅U(4, 5) + U(4, 6) + U(5, 5) = 0
    U(3, 5) + U(4, 4) - 4⋅U(4, 5) + U(5, 5) = -70.0
    j: 5 ; i: 5 ; ecuacion: 32
    U(4, 5) + U(5, 4) - 4⋅U(5, 5) + U(5, 6) + U(6, 5) = 0
    U(4, 5) + U(5, 4) - 4⋅U(5, 5) + U(6, 5) = -70.0
    j: 5 ; i: 6 ; ecuacion: 33
    U(5, 5) + U(6, 4) - 4⋅U(6, 5) + U(6, 6) + U(7, 5) = 0
    U(5, 5) + U(6, 4) - 4⋅U(6, 5) + U(7, 5) = -70.0
    j: 5 ; i: 7 ; ecuacion: 34
    U(6, 5) + U(7, 4) - 4⋅U(7, 5) + U(7, 6) + U(8, 5) = 0
    U(6, 5) + U(7, 4) - 4⋅U(7, 5) = -95.0
    
     A : 
     [[-4.  1.  0. ...  0.  0.  0.]
     [ 1. -4.  1. ...  0.  0.  0.]
     [ 0.  1. -4. ...  0.  0.  0.]
     ...
     [ 0.  0.  0. ... -4.  1.  0.]
     [ 0.  0.  0. ...  1. -4.  1.]
     [ 0.  0.  0. ...  0.  1. -4.]]
    
     B : 
     [-110.  -50.  -50.  -50.  -50.  -50.  -75.  -60.    0.    0.    0.    0.
        0.  -25.  -60.    0.    0.    0.    0.    0.  -25.  -60.    0.    0.
        0.    0.    0.  -25. -130.  -70.  -70.  -70.  -70.  -70.  -95.]
    Resultados para U(x,y)
    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 ]
     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.81 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.]
    

    Instrucciones en Python

    Las instrucciones completas con Sympy-Python son:

    # Ecuaciones Diferenciales Parciales Elipticas
    # EDP Elípticas contínua a discreta con Sympy
    import numpy as np
    import sympy as sym
    
    # u(x,y) funciones continuas y variables simbólicas usadas
    x = sym.Symbol('x',real=True)
    y = sym.Symbol('y',real=True)
    u = sym.Function('u')(x,y) # funcion
    f = sym.Function('f')(x,y) # funcion complemento
    # U[i,j] funciones discretas y variables simbólicas usadas
    i  = sym.Symbol('i',integer=True,positive=True)
    j  = sym.Symbol('j',integer=True,positive=True)
    Dx = sym.Symbol('Dx',real=True,positive=True)
    Dy = sym.Symbol('Dy',real=True,positive=True)
    L  = sym.Symbol('L',real=True)
    U  = sym.Function('U')(i,j)
    
    # INGRESO
    fxy = 0*x+0*y  # f(x,y) = 0 , ecuacion de Poisson
    # ecuacion edp : LHS=RHS
    LHS = sym.diff(u,x,2) + sym.diff(u,y,2)
    RHS = fxy
    edp = sym.Eq(LHS-RHS,0)
    
    # centrada, centrada, atras
    dif_dividida ={sym.diff(u,x,2): (U.subs(i,i-1)-2*U+U.subs(i,i+1))/(Dx**2),
                   sym.diff(u,y,2): (U.subs(j,j-1)-2*U+U.subs(j,j+1))/(Dy**2),
                   sym.diff(u,y,1): (U - U.subs(j,j-1))/Dy}
    
    # Condiciones iniciales en los bordes
    fya = lambda y: 60 +0*y  # izquierda
    fyb = lambda y: 25 +0*y  # derecha
    fxc = lambda x: 50 +0*x  # inferior 
    fxd = lambda x: 70 +0*x  # superior 
    
    # dimensiones de la placa
    x0 = 0    # longitud en x
    xn = 2
    y0 = 0    # longitud en y
    yn = 1.5
    # muestreo en ejes, discreto, supone dx=dy
    dx = 0.25  # Tamaño de paso
    dy = dx # supone dx=dy
    iteramax = 100 # revisa convergencia
    tolera = 0.0001
    
    verdigitos = 2      # para mostrar en tabla de resultados
    casicero = 1e-15    # para redondeo de términos en ecuacion
    
    # PROCEDIMIENTO
    def edp_discreta(edp,dif_dividida,x,y,u):
        ''' EDP contínua a discreta, usa diferencias divididas
            proporcionadas en parámetros, indica las variables x,y
            con función u de (x,y)
        '''
        resultado={}
        # expresión todo a la izquierda LHS (Left Hand side)
        LHS = edp.lhs
        RHS = edp.rhs
        if not(edp.rhs==0):
            LHS = LHS-RHS
            RHS = 0
            edp = sym.Eq(LHS,RHS)
        # orden de derivada por x, y
        edp_x = edp.subs(x,0)
        edp_y = edp.subs(y,0)
        ordenDx = sym.ode_order(edp_x,u)
        ordenDy = sym.ode_order(edp_y,u)
        resultado['ordenDx'] = ordenDx  # guarda en resultados
        resultado['ordenDy'] = ordenDy
        # coeficiente derivada orden mayor a 1 (d2u/dx2)
        coeff_x = edp_coef_Dx(edp,x,ordenDx)
        if not(coeff_x==1):
            LHS = LHS/coeff_x
            RHS = RHS/coeff_x
        edp = sym.Eq(LHS,RHS)
        K_ = edp_coef_Dx(edp,y,ordenDy)
        if abs(K_)%1<casicero: # si es entero
            K_ = int(K_)
        resultado['edp=0']  = edp
        resultado['K_']  = K_
        
        discreta = edp.lhs  # EDP discreta
        for derivada in dif_dividida: # reemplaza diferencia dividida
            discreta = discreta.subs(derivada,dif_dividida[derivada])
        resultado['discreta=0'] = discreta
        return (resultado)
    
    def edp_coef_Dx(edp,x,ordenx):
        ''' Extrae el coeficiente de la derivada Dx de ordenx
        edp es la ecuación como lhs=rhs
        '''
        coeff_x = 1.0 # valor inicial
        # separa cada término de suma
        term_suma = sym.Add.make_args(edp.lhs)
        for term_k in term_suma:
            if term_k.is_Mul: # mas de un factor
                factor_Mul = sym.Mul.make_args(term_k)
                coeff_temp = 1; coeff_usar=False
                # separa cada factor de término 
                for factor_k in factor_Mul:
                    if not(factor_k.is_Derivative):
                        coeff_temp = coeff_temp*factor_k
                    else: # factor con derivada de ordenx
                        partes = factor_k.args
                        if partes[1]==(x,ordenx):
                            coeff_usar = 1
                if coeff_usar==True:
                    coeff_x = coeff_x*coeff_temp
        return(coeff_x)
    
    def redondea_coef(ecuacion, precision=6,casicero = 1e-15):
        ''' redondea coeficientes de términos suma de una ecuacion
        ecuación como lhs=rhs
        '''
        tipo = type(ecuacion)
        tipo_eq = False
        if tipo == sym.core.relational.Equality:
            RHS = ecuacion.rhs
            ecuacion = ecuacion.lhs
            tipo = type(ecuacion)
            tipo_eq = True
    
        if tipo == sym.core.add.Add: # términos suma de ecuacion
            term_sum = sym.Add.make_args(ecuacion)
            ecuacion = sym.S.Zero # vacia
            for term_k in term_sum:
                # factor multiplicativo de termino suma
                term_mul = sym.Mul.make_args(term_k)
                producto = sym.S.One
                for factor in term_mul:
                    if not(factor.has(sym.Symbol)): # es numerico
                        factor = np.around(float(factor),precision)
                        if (abs(factor)%1)<casicero: # si es entero
                            factor = int(factor)
                    producto = producto*factor
                ecuacion = ecuacion + producto
        
        if tipo == sym.core.mul.Mul: # termino único, busca factores
            term_mul = sym.Mul.make_args(ecuacion)
            producto = sym.S.One
            for factor in term_mul:
                if not(factor.has(sym.Symbol)): # es numerico
                    factor = np.around(float(factor),precision)
                    if (abs(factor)%1)<casicero: # si es entero
                        factor = int(factor)
                producto = producto*factor
            ecuacion = producto
        
        if tipo == float: # # solo un numero
            if (abs(ecuacion)%1)<casicero: 
                ecuacion = int(ecuacion)
        if tipo_eq==True: # era igualdad, integra lhs=rhs
            ecuacion = sym.Eq(ecuacion,RHS)
        
        return(ecuacion)
    
    def edp_simplificaLamba(resultado,dx,dy):
        '''simplifica ecuacion con valores de lambda, dx y dy
        entregando la edp discreta simplificada
        '''
        discreta = resultado['discreta=0']
        ordenDy = resultado['ordenDy']
        ordenDx = resultado['ordenDx']
        K_ = resultado['K_']
        lamb = (Dy**ordenDy)/(Dx**ordenDx)
        if ordenDy==1 and ordenDx==2:
            lamb = lamb/K_
        resultado['Lambda_L'] = lamb
        # valor de Lambda en ecuacion edp
        L_k = lamb.subs([(Dx,dx),(Dy,dy)])
        if abs(L_k)%1<casicero: # si es entero
            L_k = int(L_k)
        resultado['Lambda L_k'] = L_k
        # simplifica con lambda L
        discreta_L = sym.expand(discreta*(Dy**ordenDy),mul=True)
        resultado['(discreta=0)*Dy**ordeny'] = discreta_L
        discreta_L = edp_sustituye_L(resultado)
        discreta_L = discreta_L.subs(lamb,L)
        discreta_L = sym.collect(discreta_L,U)
        discreta_L = sym.Eq(discreta_L,0)
        resultado['discreta_L = 0'] = discreta_L
        # sustituye constantes en ecuación a iterar
        discreta_L = discreta_L.subs([(Dx,dx),(Dy,dy),(L,L_k)])
        discreta_L = redondea_coef(discreta_L)
        resultado['discreta'] = discreta_L
        return(resultado)
    
    def edp_sustituye_L(resultado):
        ''' sustituye lambda con Dy**ordeny/Dx**x/K_
        por L, al simplificar Lambda
        '''
        discreta = resultado['(discreta=0)*Dy**ordeny']
        ordenDy = resultado['ordenDy']
        ordenDx = resultado['ordenDx']
        discreta_L = 0
        # separa cada término de suma
        term_suma = sym.Add.make_args(discreta)
        for term_k in term_suma:
            # busca partes de L y cambia por valor L
            cambiar = 0 # por orden de derivada
            if term_k.has(Dx) and term_k.has(Dy):
                partes = term_k.args
                ordeny=1
                ordenx=1
                for unaparte in partes:    
                    if unaparte.has(Dy):
                        if unaparte.is_Pow:
                            partey = unaparte.args
                            ordeny = partey[1]
                    if unaparte.has(Dx):
                        if unaparte.is_Pow:
                            partey = unaparte.args
                            ordenx = partey[1]
                if (ordeny<=ordenDy and ordenx<=-ordenDx):
                    cambiar=1
            if cambiar:
                term_k = term_k*L/resultado['Lambda_L']
            discreta_L = discreta_L + term_k
            # simplifica unos con decimal a entero 
            discreta_L = discreta_L.subs(1.0,1)
        return(discreta_L)
    
    def edp_sustituyeValorU(discreta,xi,yj,u_xy,u_mask):
        '''Sustituye en edp discreta los valores conocidos de U[i,j]
        tomados desde u_xy, marcados con u_mask
        u_mask indica si el valor se ha calculado con edp.
        '''
        LHS = discreta.lhs # lado izquierdo de ecuacion
        RHS = discreta.rhs # lado derecho
        # sustituye U[i,j] con valores conocidos
        A_diagonal = [] # lista de i,j para matriz de coeficientes A
        # Separa términos suma
        term_suma = sym.Add.make_args(LHS)
        for term_k in term_suma:
            # busca U[i,j] y cambia por valor uxt[i,j]
            cambiar = 0 ; cambiar_valor = 0 ; cambiar_factor = 0
            # separa cada factor de término
            factor_Mul = sym.Mul.make_args(term_k)
            for factor_k in factor_Mul:
                # busca U[i,j] en matriz uxt[i,j]
                if factor_k.is_Function:
                    [i_k,j_k] = factor_k.args
                    if not(np.isnan(u_xy[i_k,j_k])):
                        cambiar = u_mask[i_k,j_k]
                        cambiar_factor = factor_k
                        cambiar_valor = u_xy[i_k,j_k]
                    else:
                        A_diagonal.append([i_k,j_k,term_k/factor_k])
            # encontró valor U[i,j],term_k va a la derecha de ecuación
            if cambiar:
                LHS = LHS - term_k
                term_ki = term_k.subs(cambiar_factor,cambiar_valor)
                RHS = RHS - term_ki
        discreta = sym.Eq(LHS,RHS)
        B_diagonal = RHS
        resultado = [discreta,A_diagonal,B_diagonal]
        return (resultado)
    
    # PROCEDIMIENTO
    # transforma edp continua a discreta
    resultado = edp_discreta(edp,dif_dividida,x,y,u)
    resultado = edp_simplificaLamba(resultado,dx,dy)
    discreta = resultado['discreta']
    
    # SALIDA
    np.set_printoptions(precision=verdigitos)
    algun_numero = [int,float,str,'Lambda L_k']
    print('EDP Elíptica contínua a discreta')
    for entrada in resultado:
        tipo = type(resultado[entrada])
        if tipo in algun_numero or entrada in algun_numero:
            print('',entrada,':',resultado[entrada])
        else:
            print('\n',entrada,':')
            sym.pprint(resultado[entrada])
    
    # ITERAR para cada i,j dentro de U ------------
    # x[i] , y[j]  valor en posición en cada eje
    xi = np.arange(x0,xn+dx/2,dx)
    yj = np.arange(y0,yn+dy/2,dy)
    n = len(xi)
    m = len(yj)
    
    # Matriz U
    u_xy = np.zeros(shape=(n,m),dtype = float)
    u_xy = u_xy*np.nan # valor inicial dentro de u
    # llena u con valores en fronteras
    u_xy[0,:]   = fya(yj)  # izquierda Ta
    u_xy[n-1,:] = fyb(yj)  # derecha   Tb
    u_xy[:,0]   = fxc(xi)  # inferior  Tc
    u_xy[:,m-1] = fxd(xi)  # superior  Td
    u0 = np.copy(u_xy)     # matriz u inicial
    
    # u_mask[i,j] con valores iniciales o calculados:True
    u_mask = np.zeros(shape=(n,m),dtype=bool)
    u_mask[0,:]  = True # izquierda
    u_mask[-1,:] = True # derecha
    u_mask[:,0]  = True # inferior
    u_mask[:,-1] = True # superior
    
    # Método implícito para EDP Elíptica
    # ITERAR para plantear las ecuaciones en [i,j]
    resultado = {}
    eq_itera = [] ; tamano = (n-2)*(m-2)
    A = np.zeros(shape=(tamano,tamano),dtype=float)
    B = np.zeros(tamano,dtype=float)
    for j_k in range(1,m-1,1): # no usar valores en bordes
        for i_k in range(1,n-1,1): 
            eq_conteo = (j_k - 1)*(n-2)+(i_k-1)
            discreta_ij = discreta.subs({i:i_k,j:j_k,
                                         x:xi[i_k],y:yj[j_k]})
            resultado[eq_conteo]= {'j':j_k, 'i':i_k,
                                     'discreta_ij': discreta_ij}
            # usa valores de frontera segun u_mask con True
            discreta_k = edp_sustituyeValorU(discreta_ij,
                                            xi,yj,u_xy,u_mask)
            discreta_ij = discreta_k[0]
            A_diagonal  = discreta_k[1] # lista de (i,j,coeficiente) 
            B_diagonal  = discreta_k[2]
            resultado[eq_conteo]['discreta_k'] = discreta_k[0]
            # añade ecuacion a resolver
            eq_itera.append(discreta_ij)
            # Aplica coeficientes de ecuacion en A y B:
            # A_diagonal tiene lista de (i,j,coeficiente) 
            for uncoeff in A_diagonal:
                columna = (uncoeff[1]-1)*(n-2)+(uncoeff[0]-1)
                fila = (j_k - 1)*(n-2)+(i_k-1)
                A[fila,columna] = uncoeff[2]
            B[eq_conteo] = float(B_diagonal) # discreta_ij.rhs
    resultado['A'] = np.copy(A)
    resultado['B'] = np.copy(B)
    
    # resuelve el sistema de ecuaciones en eq_itera en Sympy
    X_k = sym.solve(eq_itera)[0]
    # actualiza uxt[i,j] , u_mask segun X_k en Sympy
    for nodo_Uij in X_k: 
        [i_k,j_k] = nodo_Uij.args
        u_xy[i_k,j_k] = X_k[nodo_Uij]
        u_mask[i_k,j_k] = True
    # resuelve el sistema A.X=B en Numpy
    #X = np.linalg.solve(A,B)
    # tarea: llevar valores X a u_xy
    
    # SALIDA
    np.set_printoptions(precision=verdigitos)
    algun_numero = [int,float,str,'Lambda L_k']
    print('\nMétodo Implícito - EDP Elíptica')
    for entrada in resultado:
        tipo = type(resultado[entrada])
        if tipo in algun_numero or entrada in algun_numero:
            print('',entrada,':',resultado[entrada])
        elif (tipo==dict):
            print('j:',resultado[entrada]['j'],'; '
                  'i:',resultado[entrada]['i'],'; '
                  'ecuacion:',entrada)
            sym.pprint(resultado[entrada]['discreta_ij'])
            if resultado[entrada]['discreta_k'].rhs!=0:
                sym.pprint(resultado[entrada]['discreta_k'])
        else:
            print('\n',entrada,': \n',resultado[entrada])
    print('Resultados para U(x,y)')
    print('xi:',xi)
    print('yj:',yj)
    print(' j, U[i,j]')
    for j_k in range(m-1,-1,-1):
        print(j_k, (u_xy[:,j_k]))
    

    EDP Elípticas [ contínua a discreta ] || Sympy [ iterativo ] [ implícito ] [ gráfica_3D ]

  • 7.2.3 EDP Elípticas - analítico iterativo con Sympy-Python

    EDP Elípticas [ contínua a discreta ] || Sympy [ iterativo ] [ implícito ] [ gráfica_3D ]
    ..


    1. Ejercicio

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

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

    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

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

    EDP Elípticas [ contínua a discreta ] || Sympy [ iterativo ] [ implícito ] [ gráfica_3D ]

    ..


    2. EDP Elípticas contínua a discreta

    El resultado de las operaciones en la expresión usando el algoritmo es:

    EDP Elíptica contínua a discreta
     ordenDx : 2
     ordenDy : 2
    
     edp=0 :
      2              2             
     ∂              ∂              
    ───(u(x, y)) + ───(u(x, y)) = 0
      2              2             
    ∂x             ∂y              
     K_ : 1
    
     discreta=0 :
    -2⋅U(i, j) + U(i, j - 1) + U(i, j + 1)   -2⋅U(i, j) + U(i - 1, j) + U(i + 1, j)
    ────────────────────────────────────── + ──────────────────────────────────────
                       2                                        2                 
                     Dy                                       Dx                  
     Lambda_L :
      2
    Dy 
    ───
      2
    Dx 
     Lambda L_k : 1
    
     (discreta=0)*Dy**ordeny :
                                                 2             2                 2
                                             2⋅Dy ⋅U(i, j)   Dy ⋅U(i - 1, j)   Dy ⋅ U(i + 1, j)
    -2⋅U(i, j) + U(i, j - 1) + U(i, j + 1) - ───────────── + ─────────────── + ───────────────
                                                    2                2                 2   
                                                  Dx               Dx                Dx  
    
     discreta_L = 0 :
    L⋅U(i - 1, j) + L⋅U(i + 1, j) + (-2⋅L - 2)⋅U(i, j) + U(i, j - 1) + U(i, j + 1) = 0
    
     discreta :
    -4⋅U(i, j) + U(i, j - 1) + U(i, j + 1) + U(i - 1, j) + U(i + 1, j) = 0
    
    discreta_iterativa
              U(i, j - 1) + U(i, j + 1) + U(i - 1, j) + U(i + 1, j)
    U(i, j) = ─────────────────────────────────────────────────────
                                        4    
    

    El desarrollo analítico inicia convirtiendo la ecuación diferencial parcial elíptica de la forma contínua a su representación discreta usando las expresiones de derivadas en  diferencias divididas. El cambio de la expresión se realiza usando  Sympy.

    La EDP se escribe en formato Sympy en el bloque de ingreso.  La ecuación EDP se compone del lado izquierdo (LHS) y lado derecho (RHS), indicando u como una función de las variables x,y.

    # INGRESO
    fxy = 0*x+0*y # f(x,y) = 0 , ecuacion de Poisson
    # ecuacion: LHS=RHS
    LHS = sym.diff(u,x,2) + sym.diff(u,y,2)
    RHS = fxy
    EDP = sym.Eq(LHS-RHS,0)
    

    las diferencias divididas se ingresan como un diccionario:

    # centrada, centrada, atras
    dif_dividida ={sym.diff(u,x,2): (U.subs(i,i-1)-2*U+U.subs(i,i+1))/(Dx**2),
                   sym.diff(u,y,2): (U.subs(j,j-1)-2*U+U.subs(j,j+1))/(Dy**2),
                   sym.diff(u,y,1): (U - U.subs(j,j-1))/Dy}
    

    las condiciones iniciales en los bordes, pueden ser funciones matemáticas, por lo que se usa el formato lambda. En el ejercicio básico presentado en la parte teórica, los bordes tienen temperaturas constantes, por lo que en ésta sección se escriben las condiciones como la constante mas cero por la variable independiente, facilitando la evaluación de un vector xi por ejemplo.

    # Condiciones iniciales en los bordes
    fya = lambda y: 60 +0*y  # izquierda
    fyb = lambda y: 25 +0*y  # derecha
    fxc = lambda x: 50 +0*x  # inferior, función inicial 
    fxd = lambda x: 70 +0*x  # superior, función inicial 
    

    los demás parámetros del ejercicio se ingresan más adelante de forma semejante al ejercicio con Numpy.

    Todas las expresiones se escriben al lado izquierdo (LHS) de la igualdad, la parte del lado derecho(RHS) se la prefiere mantener en cero. La expresión se organiza manteniendo el coeficiente en 1 para el termino de Dx de mayor orden. Se sustituyen las derivadas por diferencias divididas, para luego simplificar la expresión usando λ como referencia.

    Instrucciones en Python

    Los resultados al aplicar una operación a la expresión se guardan en un diccionario, para revisar cada paso intermedio al final

    # Ecuaciones Diferenciales Parciales Elipticas
    # EDP Elípticas contínua a discreta con Sympy
    import numpy as np
    import sympy as sym
    
    # u(x,y) funciones continuas y variables simbólicas usadas
    x = sym.Symbol('x',real=True)
    y = sym.Symbol('y',real=True)
    u = sym.Function('u')(x,y) # funcion
    f = sym.Function('f')(x,y) # funcion complemento
    # U[i,j] funciones discretas y variables simbólicas usadas
    i  = sym.Symbol('i',integer=True,positive=True) # indices
    j  = sym.Symbol('j',integer=True,positive=True)
    Dx = sym.Symbol('Dx',real=True,positive=True)
    Dy = sym.Symbol('Dy',real=True,positive=True)
    L  = sym.Symbol('L',real=True)
    U  = sym.Function('U')(i,j)
    
    # INGRESO
    fxy = 0*x+0*y  # f(x,y) = 0 , ecuacion de Poisson
    # ecuacion edp : LHS=RHS
    LHS = sym.diff(u,x,2) + sym.diff(u,y,2)
    RHS = fxy
    edp = sym.Eq(LHS-RHS,0)
    
    # centrada, centrada, atras
    dif_dividida ={sym.diff(u,x,2): (U.subs(i,i-1)-2*U+U.subs(i,i+1))/(Dx**2),
                   sym.diff(u,y,2): (U.subs(j,j-1)-2*U+U.subs(j,j+1))/(Dy**2),
                   sym.diff(u,y,1): (U - U.subs(j,j-1))/Dy}
    
    # Condiciones iniciales en los bordes
    fya = lambda y: 60 +0*y  # izquierda
    fyb = lambda y: 25 +0*y  # derecha
    fxc = lambda x: 50 +0*x  # inferior 
    fxd = lambda x: 70 +0*x  # superior 
    
    # dimensiones de la placa
    x0 = 0    # longitud en x
    xn = 2
    y0 = 0    # longitud en y
    yn = 1.5
    # muestreo en ejes, discreto, supone dx=dy
    dx = 0.25  # Tamaño de paso
    dy = dx # supone dx=dy
    iteramax = 100 # revisa convergencia
    tolera = 0.0001
    
    verdigitos = 2      # para mostrar en tabla de resultados
    casicero = 1e-15    # para redondeo de términos en ecuacion
    
    # PROCEDIMIENTO
    def edp_discreta(edp,dif_dividida,x,y,u):
        ''' EDP contínua a discreta, usa diferencias divididas
            proporcionadas en parámetros, indica las variables x,y
            con función u de (x,y)
        '''
        resultado={}
        # expresión todo a la izquierda LHS (Left Hand side)
        LHS = edp.lhs
        RHS = edp.rhs
        if not(edp.rhs==0):
            LHS = LHS-RHS
            RHS = 0
            edp = sym.Eq(LHS,RHS)
        # orden de derivada por x, y
        edp_x = edp.subs(x,0)
        edp_y = edp.subs(y,0)
        ordenDx = sym.ode_order(edp_x,u)
        ordenDy = sym.ode_order(edp_y,u)
        resultado['ordenDx'] = ordenDx  # guarda en resultados
        resultado['ordenDy'] = ordenDy
        # coeficiente derivada orden mayor a 1 (d2u/dx2)
        coeff_x = edp_coef_Dx(edp,x,ordenDx)
        if not(coeff_x==1):
            LHS = LHS/coeff_x
            RHS = RHS/coeff_x
        edp = sym.Eq(LHS,RHS)
        K_ = edp_coef_Dx(edp,y,ordenDy)
        if abs(K_)%1<casicero: # si es entero
            K_ = int(K_)
        resultado['edp=0']  = edp
        resultado['K_']  = K_
        
        discreta = edp.lhs  # EDP discreta
        for derivada in dif_dividida: # reemplaza diferencia dividida
            discreta = discreta.subs(derivada,dif_dividida[derivada])
        resultado['discreta=0'] = discreta
        return (resultado)
    
    def edp_coef_Dx(edp,x,ordenx):
        ''' Extrae el coeficiente de la derivada Dx de ordenx
        edp es la ecuación como lhs=rhs
        '''
        coeff_x = 1.0 # valor inicial
        # separa cada término de suma
        term_suma = sym.Add.make_args(edp.lhs)
        for term_k in term_suma:
            if term_k.is_Mul: # mas de un factor
                factor_Mul = sym.Mul.make_args(term_k)
                coeff_temp = 1; coeff_usar=False
                # separa cada factor de término 
                for factor_k in factor_Mul:
                    if not(factor_k.is_Derivative):
                        coeff_temp = coeff_temp*factor_k
                    else: # factor con derivada de ordenx
                        partes = factor_k.args
                        if partes[1]==(x,ordenx):
                            coeff_usar = 1
                if coeff_usar==True:
                    coeff_x = coeff_x*coeff_temp
        return(coeff_x)
    
    def redondea_coef(ecuacion, precision=6,casicero = 1e-15):
        ''' redondea coeficientes de términos suma de una ecuacion
        ecuación como lhs=rhs
        '''
        tipo = type(ecuacion)
        tipo_eq = False
        if tipo == sym.core.relational.Equality:
            RHS = ecuacion.rhs
            ecuacion = ecuacion.lhs
            tipo = type(ecuacion)
            tipo_eq = True
    
        if tipo == sym.core.add.Add: # términos suma de ecuacion
            term_sum = sym.Add.make_args(ecuacion)
            ecuacion = sym.S.Zero # vacia
            for term_k in term_sum:
                # factor multiplicativo de termino suma
                term_mul = sym.Mul.make_args(term_k)
                producto = sym.S.One
                for factor in term_mul:
                    if not(factor.has(sym.Symbol)): # es numerico
                        factor = np.around(float(factor),precision)
                        if (abs(factor)%1)<casicero: # si es entero
                            factor = int(factor)
                    producto = producto*factor
                ecuacion = ecuacion + producto
        
        if tipo == sym.core.mul.Mul: # termino único, busca factores
            term_mul = sym.Mul.make_args(ecuacion)
            producto = sym.S.One
            for factor in term_mul:
                if not(factor.has(sym.Symbol)): # es numerico
                    factor = np.around(float(factor),precision)
                    if (abs(factor)%1)<casicero: # si es entero
                        factor = int(factor)
                producto = producto*factor
            ecuacion = producto
        
        if tipo == float: # # solo un numero
            if (abs(ecuacion)%1)<casicero: 
                ecuacion = int(ecuacion)
        if tipo_eq==True: # era igualdad, integra lhs=rhs
            ecuacion = sym.Eq(ecuacion,RHS)
        
        return(ecuacion)
    
    def edp_simplificaLamba(resultado,dx,dy):
        '''simplifica ecuacion con valores de lambda, dx y dy
        entregando la edp discreta simplificada
        '''
        discreta = resultado['discreta=0']
        ordenDy = resultado['ordenDy']
        ordenDx = resultado['ordenDx']
        K_ = resultado['K_']
        lamb = (Dy**ordenDy)/(Dx**ordenDx)
        if ordenDy==1 and ordenDx==2:
            lamb = lamb/K_
        resultado['Lambda_L'] = lamb
        # valor de Lambda en ecuacion edp
        L_k = lamb.subs([(Dx,dx),(Dy,dy)])
        if abs(L_k)%1<casicero: # si es entero
            L_k = int(L_k)
        resultado['Lambda L_k'] = L_k
        # simplifica con lambda L
        discreta_L = sym.expand(discreta*(Dy**ordenDy),mul=True)
        resultado['(discreta=0)*Dy**ordeny'] = discreta_L
        discreta_L = edp_sustituye_L(resultado)
        discreta_L = discreta_L.subs(lamb,L)
        discreta_L = sym.collect(discreta_L,U)
        discreta_L = sym.Eq(discreta_L,0)
        resultado['discreta_L = 0'] = discreta_L
        # sustituye constantes en ecuación a iterar
        discreta_L = discreta_L.subs([(Dx,dx),(Dy,dy),(L,L_k)])
        discreta_L = redondea_coef(discreta_L)
        resultado['discreta'] = discreta_L
        return(resultado)
    
    def edp_sustituye_L(resultado):
        ''' sustituye lambda con Dy**ordeny/Dx**x/K_
        por L, al simplificar Lambda
        '''
        discreta = resultado['(discreta=0)*Dy**ordeny']
        ordenDy = resultado['ordenDy']
        ordenDx = resultado['ordenDx']
        discreta_L = 0
        # separa cada término de suma
        term_suma = sym.Add.make_args(discreta)
        for term_k in term_suma:
            # busca partes de L y cambia por valor L
            cambiar = False # por orden de derivada
            if term_k.has(Dx) and term_k.has(Dy):
                partes = term_k.args
                ordeny=1
                ordenx=1
                for unaparte in partes:    
                    if unaparte.has(Dy):
                        if unaparte.is_Pow:
                            partey = unaparte.args
                            ordeny = partey[1]
                    if unaparte.has(Dx):
                        if unaparte.is_Pow:
                            partey = unaparte.args
                            ordenx = partey[1]
                if (ordeny<=ordenDy and ordenx<=-ordenDx):
                    cambiar=True
            if cambiar==True:
                term_k = term_k*L/resultado['Lambda_L']
            discreta_L = discreta_L + term_k
            # simplifica unos con decimal a entero 
            discreta_L = redondea_coef(discreta_L)
        return(discreta_L)
    
    # PROCEDIMIENTO -------------------------------
    # transforma edp continua a discreta
    resultado = edp_discreta(edp,dif_dividida,x,y,u)
    resultado = edp_simplificaLamba(resultado,dx,dy)
    discreta = resultado['discreta']
    
    # SALIDA
    np.set_printoptions(precision=verdigitos)
    algun_numero = [int,float,str,'Lambda L_k']
    print('EDP Elíptica contínua a discreta')
    for entrada in resultado:
        tipo = type(resultado[entrada])
        if tipo in algun_numero or entrada in algun_numero:
            print('',entrada,':',resultado[entrada])
        else:
            print('\n',entrada,':')
            sym.pprint(resultado[entrada])
    

    EDP Elípticas [ contínua a discreta ] || Sympy [ iterativo ] [ implícito ] [ gráfica_3D ]
    ..


    3. EDP Elípticas - Método iterativo con Sympy-Python

    El desarrollo del método iterativo para una ecuación diferencial parcial elíptica usando Sympy, sigue a continuación del anterior.

    Se añaden las instrucciones para iterar la expresión discreta para cada i,j dentro de la matriz U creada para el ejercicio. Se aplican las condiciones iniciales a los bordes, para luego proceder a iterar.

    Como en las actividades del curso se requiere realizar al menos 3 iteraciones para las expresiones del algoritmo con papel y lápiz, solo se presentarán los resultados para la primera fila en j=0

    Los resultados del algoritmo  luego del resultado del algoritmo anterior se presentan como:

    discreta_iterativa
              U(i, j - 1) + U(i, j + 1) + U(i - 1, j) + U(i + 1, j)
    U(i, j) = ─────────────────────────────────────────────────────
                                        4                          
    
     iterar i,j:
    j:  1  ;  i:  1
              U(0, 1)   U(1, 0)   U(1, 2)   U(2, 1)
    U(1, 1) = ─────── + ─────── + ─────── + ───────
                 4         4         4         4   
    U(1, 1) = 53.125
    j:  1  ;  i:  2
              U(1, 1)   U(2, 0)   U(2, 2)   U(3, 1)
    U(2, 1) = ─────── + ─────── + ─────── + ───────
                 4         4         4         4   
    U(2, 1) = 51.40625
    j:  1  ;  i:  3
              U(2, 1)   U(3, 0)   U(3, 2)   U(4, 1)
    U(3, 1) = ─────── + ─────── + ─────── + ───────
                 4         4         4         4   
    U(3, 1) = 50.9765625
    j:  1  ;  i:  4
              U(3, 1)   U(4, 0)   U(4, 2)   U(5, 1)
    U(4, 1) = ─────── + ─────── + ─────── + ───────
                 4         4         4         4   
    U(4, 1) = 50.869140625
    j:  1  ;  i:  5
              U(4, 1)   U(5, 0)   U(5, 2)   U(6, 1)
    U(5, 1) = ─────── + ─────── + ─────── + ───────
                 4         4         4         4   
    U(5, 1) = 50.84228515625
    j:  1  ;  i:  6
              U(5, 1)   U(6, 0)   U(6, 2)   U(7, 1)
    U(6, 1) = ─────── + ─────── + ─────── + ───────
                 4         4         4         4   
    U(6, 1) = 50.8355712890625
    j:  1  ;  i:  7
              U(6, 1)   U(7, 0)   U(7, 2)   U(8, 1)
    U(7, 1) = ─────── + ─────── + ─────── + ───────
                 4         4         4         4   
    U(7, 1) = 44.271392822265625
    
    Método iterativo EDP Elíptica
    continuar el desarrollo con: 
    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 ]
     j, U[i,j]
    2 [60.   51.25 51.25 51.25 51.25 51.25 51.25 51.25 25.  ]
    1 [60.   53.12 51.41 50.98 50.87 50.84 50.84 44.27 25.  ]
    0 [50. 50. 50. 50. 50. 50. 50. 50. 50.]
    

    Se pueden sustituir los valores de las expresiones, evaluando cada u[i,j] y completando la matriz y para la gráfica. Esta parte queda como tarea.

    Instrucciones en Python

    Las instrucciones adicionales al algoritmo de EDP elíptica contínua a discreta empiezan con la creación de la matriz u_xy para los valores, los vectores xi,yj y una matriz u_mask que indica si se dispone de  un valor calculado o conocido en ese punto (x,y) . Para el método iterativo, la matriz se rellena con el promedio de los valores máximos de las funciones dadas para los bordes de la placa.

    Tarea: El algoritmo desarrolla el cálculo para j_k=1, solo la primera fila. Se deja como tarea desarrollar para toda la matriz.

    # ITERAR para cada i,j dentro de U ------------
    # x[i] , y[j]  valor en posición en cada eje
    xi = np.arange(x0,xn+dx/2,dx)
    yj = np.arange(y0,yn+dy/2,dy)
    n = len(xi)
    m = len(yj)
    
    # Matriz U 
    u_xy = np.zeros(shape=(n,m),dtype = float)
    u_xy = u_xy*np.nan # valor inicial dentro de u
    # llena u con valores en fronteras
    u_xy[0,:]   = fya(yj)  # izquierda Ta
    u_xy[n-1,:] = fyb(yj)  # derecha   Tb
    u_xy[:,0]   = fxc(xi)  # inferior  Tc
    u_xy[:,m-1] = fxd(xi)  # superior  Td
    u0 = np.copy(u_xy)     # matriz u inicial
    
    # u_mask[i,j] con valores iniciales o calculados:True
    u_mask = np.zeros(shape=(n,m),dtype=bool)
    u_mask[0,:]  = True # izquierda
    u_mask[-1,:] = True # derecha
    u_mask[:,0]  = True # inferior
    u_mask[:,-1] = True # superior
    
    # valor inicial de iteración dentro de u
    # promedio = (Ta+Tb+Tc+Td)/4
    promedio = (np.max(fya(yj))+np.max(fyb(yj))+\
                np.max(fxc(xi))+np.max(fxd(xi)))/4
    u_xy[1:n-1,1:m-1]   = promedio
    u_mask[1:n-1,1:m-1] = True
    u0 = np.copy(u_xy) # copia para revisión
    
    def edp_sustituyeValorU(discreta,xi,yj,u_xy,u_mask):
        '''Sustituye en edp discreta los valores conocidos de U[i,j]
        tomados desde u_xy, marcados con u_mask
        u_mask indica si el valor se ha calculado con edp.
        '''
        LHS = discreta.lhs # lado izquierdo de ecuacion
        RHS = discreta.rhs # lado derecho
        # sustituye U[i,j] con valores conocidos
        A_diagonal = [] # lista de i,j para matriz de coeficientes A
        # Separa términos suma
        term_suma = sym.Add.make_args(LHS)
        for term_k in term_suma:
            # busca U[i,j] y cambia por valor uxt[i,j]
            cambiar = False ; cambiar_valor = 0 ; cambiar_factor = 0
            # separa cada factor de término
            factor_Mul = sym.Mul.make_args(term_k)
            for factor_k in factor_Mul:
                # busca U[i,j] en matriz uxt[i,j]
                if factor_k.is_Function:
                    [i_k,j_k] = factor_k.args
                    if not(np.isnan(u_xy[i_k,j_k])):
                        cambiar = u_mask[i_k,j_k]
                        cambiar_factor = factor_k
                        cambiar_valor = u_xy[i_k,j_k]
                    else:
                        A_diagonal.append([i_k,j_k,term_k/factor_k])
            # encontró valor U[i,j],term_k va a la derecha de ecuación
            if cambiar==True:
                LHS = LHS - term_k
                term_ki = term_k.subs(cambiar_factor,cambiar_valor)
                RHS = RHS - term_ki
        discreta = sym.Eq(LHS,RHS)
        B_diagonal = RHS
        resultado = [discreta,A_diagonal,B_diagonal]
        return (resultado)
    
    # Método iterativo para EDP Elíptica
    # separa término U[j,j] del centro,con valor no conocido
    buscar = U.subs(j,j)
    discreta = sym.solve(discreta,buscar)
    discreta = sym.factor_terms(discreta[0])
    discreta = sym.Eq(buscar,discreta)
    resultado['discreta_iterativa'] = discreta
    
    print('\ndiscreta_iterativa')
    sym.pprint(discreta)
    
    # Desarrollo de iteraciones en cada nodo i,j, para la fila j_k
    # genera el valor en cada punto
    # Nota: Solo la primera fila, Tarea desarrollar para la matriz
    print('\n iterar i,j:')
    j_k = 1
    for i_k in range(1,n-1,1):
        print('j: ',j_k,' ; ','i: ',i_k)
        discreta_ij = discreta.subs({i:i_k,j:j_k,
                                     x:xi[i_k],y:yj[j_k]})
        sym.pprint(discreta_ij)
        RHS = discreta_ij.rhs
        discreta_ij = sym.Eq(RHS,0)
        # usa valores de frontera segun u_mask con True
        discreta_k = edp_sustituyeValorU(discreta_ij,
                                        xi,yj,u_xy,u_mask)
        u_xy[i_k,j_k] = sym.Float(-discreta_k[2])
        print(buscar.subs({i:i_k,j:j_k}),
              '=',u_xy[i_k,j_k])
        
    # SALIDA
    np.set_printoptions(precision=verdigitos)
    print('\nMétodo iterativo EDP Elíptica')
    print('continuar el desarrollo con: ')
    print('xi:',xi)
    print('yj:',yj)
    print(' j, U[i,j]')
    for j_k in range(2,-1,-1):
        print(j_k, (u_xy[:,j_k]))
    

    EDP Elípticas [ contínua a discreta ] || Sympy [ iterativo ] [ implícito ] [ gráfica_3D ]
    ..


    Grafica en 3D para EDP Elípticas

    A partir de la solución en matriz U_xy, Xi, Yi

    # GRAFICA en 3D ------
    import matplotlib.pyplot as plt
    # Malla para cada eje X,Y
    Xi, Yi = np.meshgrid(xi, yj)
    U_xy = np.transpose(u_xy) # 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_xy,
                           color ='blue')
    graf_3D.plot(Xi[1,0],Yi[1,0],U_xy[1,0],'o',color ='orange')
    graf_3D.plot(Xi[1,1],Yi[1,1],U_xy[1,1],'o',color ='red',
                 label='U[i,j]')
    graf_3D.plot(Xi[1,2],Yi[1,2],U_xy[1,2],'o',color ='salmon')
    graf_3D.plot(Xi[0,1],Yi[0,1],U_xy[0,1],'o',color ='green')
    graf_3D.plot(Xi[2,1],Yi[2,1],U_xy[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 [ contínua a discreta ] || Sympy [ iterativo ] [ implícito ] [ gráfica_3D ]

  • 7.1.4 EDP Parabólica - analítico implícito con Sympy-Python

    EDP Parabólica [ contínua a discreta ] || sympy: [ explícito ] [ implícito ]
    ..


    4. EDP Parabólica - Método implícito con Sympy

    Para el ejercicio presentado en el numeral 1, se desarrolla el método implícito.

    Las diferencias finitas centradas y hacia atrás se definen en el diccionario dif_dividida.

    Para desarrollar la expresión discreta, se incorpora la función edp_sustituye_L(), que busca el en cada término de la suma los componentes de λ y los sustituye por la variable L.

    Para cada valor de j, se crean las ecuaciones desde la forma discreta de la EDP, moviendo a la derecha los valores conocidos para generar un sistema de ecuaciones A.X=B. Se resuelve el sistema de ecuaciones  y se actualiza la matriz u[i,j] de resultados.

    Por la extensión de los pasos a mostrar, para las iteraciones en cada fila, solo se presentan para la primera fila. En caso de requerir observar más filas, puede cambiar el parámetro en el bloque de salida, en el condicional:

        elif (tipo==dict):
            if entrada<2
    

    Los resultados para el algoritmo son:

    EDP Parabólica contínua a discreta
     ordenDx : 2
     ordenDy : 1
    
     edp=0 :
      2                             
     ∂               ∂              
    ───(u(x, y)) - 4⋅──(u(x, y)) = 0
      2              ∂y             
    ∂x                              
     K_ : 4
    
     Lambda_L :
      Dy 
    ─────
        2
    4⋅Dx 
     Lambda L_k : 0.250000000000000
    
     (discreta=0)*Dy**ordeny :
                                 2⋅Dy⋅U(i, j)   Dy⋅U(i - 1, j)   Dy⋅U(i + 1, j)
    -4⋅U(i, j) + 4⋅U(i, j - 1) - ──────────── + ────────────── + ──────────────
                                       2               2                2      
                                     Dx              Dx               Dx       
    
     discreta_L=0 :
    4⋅L⋅U(i - 1, j) + 4⋅L⋅U(i + 1, j) + (-8⋅L - 4)⋅U(i, j) + 4⋅U(i, j - 1) = 0
    
     discreta :
    -6⋅U(i, j) + 4⋅U(i, j - 1) + U(i - 1, j) + U(i + 1, j) = 0
    
    Método implícito EDP Parabólica
    j: 1 ; i: 1
    U(0, 1) + 4⋅U(1, 0) - 6⋅U(1, 1) + U(2, 1) = 0
    -6⋅U(1, 1) + U(2, 1) = -160.0
    j: 1 ; i: 2
    U(1, 1) + 4⋅U(2, 0) - 6⋅U(2, 1) + U(3, 1) = 0
    U(1, 1) - 6⋅U(2, 1) + U(3, 1) = -100.0
    j: 1 ; i: 3
    U(2, 1) + 4⋅U(3, 0) - 6⋅U(3, 1) + U(4, 1) = 0
    U(2, 1) - 6⋅U(3, 1) + U(4, 1) = -100.0
    j: 1 ; i: 4
    U(3, 1) + 4⋅U(4, 0) - 6⋅U(4, 1) + U(5, 1) = 0
    U(3, 1) - 6⋅U(4, 1) + U(5, 1) = -100.0
    j: 1 ; i: 5
    U(4, 1) + 4⋅U(5, 0) - 6⋅U(5, 1) + U(6, 1) = 0
    U(4, 1) - 6⋅U(5, 1) + U(6, 1) = -100.0
    j: 1 ; i: 6
    U(5, 1) + 4⋅U(6, 0) - 6⋅U(6, 1) + U(7, 1) = 0
    U(5, 1) - 6⋅U(6, 1) + U(7, 1) = -100.0
    j: 1 ; i: 7
    U(6, 1) + 4⋅U(7, 0) - 6⋅U(7, 1) + U(8, 1) = 0
    U(6, 1) - 6⋅U(7, 1) + U(8, 1) = -100.0
    j: 1 ; i: 8
    U(7, 1) + 4⋅U(8, 0) - 6⋅U(8, 1) + U(9, 1) = 0
    U(7, 1) - 6⋅U(8, 1) + U(9, 1) = -100.0
    j: 1 ; i: 9
    U(8, 1) + 4⋅U(9, 0) - 6⋅U(9, 1) + U(10, 1) = 0
    U(8, 1) - 6⋅U(9, 1) = -140.0
    A :
    [[-6.  1.  0.  0.  0.  0.  0.  0.  0.]
     [ 1. -6.  1.  0.  0.  0.  0.  0.  0.]
     [ 0.  1. -6.  1.  0.  0.  0.  0.  0.]
     [ 0.  0.  1. -6.  1.  0.  0.  0.  0.]
     [ 0.  0.  0.  1. -6.  1.  0.  0.  0.]
     [ 0.  0.  0.  0.  1. -6.  1.  0.  0.]
     [ 0.  0.  0.  0.  0.  1. -6.  1.  0.]
     [ 0.  0.  0.  0.  0.  0.  1. -6.  1.]
     [ 0.  0.  0.  0.  0.  0.  0.  1. -6.]]
    B :
    [-160. -100. -100. -100. -100. -100. -100. -100. -140.]
    X :
    [31.01 26.03 25.18 25.03 25.01 25.01 25.08 25.44 27.57]
    Resultados para U(x,y)
    xi: [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]
    yj: [0.   0.01 0.02 0.03 0.04]
     j, U[i,j]
    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

    Para el método implícito se añade la sección donde se reemplazan los valores en los bordes y en la barra en la matriz U(x,y) en el algoritmo identificada como  u_xy . Para diferenciar si el valor existe se usa la matriz de estados u_mask con estados True/False.

    También se incorpora la función edp_sustituyeValorU() que para cada término suma de la ecuación busca en la matriz u_xy si el valor U(i,j) existe y lo cambia. Luego pasa el valor al lado derecho de la ecuación par formar el sistema de ecuaciones.

    Con los valores existentes antes de la iteración, se obtienen las ecuaciones por cada punto i,j de una fila para el sistema de ecuaciones en la forma A.x=B. El sistema se resuelve con las instrucciones de Numpy. El resultado se actualiza en la matriz u_xy y la matriz  u_mask para indicar que el valor ya está disponible.

    Compare los resultados con el método numérico y mida los tiempos de ejecución de cada algoritmo para escribir sus observaciones.

    # Ecuaciones Diferenciales Parciales Parabólicas
    # EDP Parabólicas contínua a discreta con Sympy
    import numpy as np
    import sympy as sym
    
    # u(x,y) funciones continuas y variables simbólicas usadas
    t = sym.Symbol('t',real=True) # independiente
    x = sym.Symbol('x',real=True)
    y = sym.Symbol('y',real=True) 
    u = sym.Function('u')(x,y) # funcion
    f = sym.Function('f')(x,y) # funcion complemento
    K = sym.Symbol('K',real=True)
    # U[i,j] funciones discretas y variables simbólicas usadas
    i  = sym.Symbol('i',integer=True,positive=True) # indices
    j  = sym.Symbol('j',integer=True,positive=True)
    Dt = sym.Symbol('Dt',real=True,positive=True)
    Dx = sym.Symbol('Dx',real=True,positive=True)
    Dy = sym.Symbol('Dy',real=True,positive=True)
    L  = sym.Symbol('L',real=True)
    U  = sym.Function('U')(i,j)
    
    # INGRESO
    fxy = 0*x+0*y  # f(x,y) = 0 , ecuacion complementaria
    # ecuacion edp : LHS=RHS
    LHS = sym.diff(u,x,2) 
    RHS = 4*sym.diff(u,y,1) + fxy
    edp = sym.Eq(LHS-RHS,0)
    
    # centrada, atras
    dif_dividida ={sym.diff(u,x,2): (U.subs(i,i-1)-2*U+U.subs(i,i+1))/(Dx**2),
                   sym.diff(u,y,1): (U - U.subs(j,j-1))/Dy}
    
    buscar = U.subs(j,j+1) # U[i,j+1] método explícito
    
    # Valores de frontera
    fya = lambda y: 60 +0*y  # izquierda
    fyb = lambda y: 40 +0*y  # derecha
    fxc = lambda x: 25 +0*x  # inferior, función inicial
    
    # [a,b] dimensiones de la barra
    a = 0  # longitud en x
    b = 1
    y0 = 0 # tiempo inicial, aumenta con dt en n iteraciones
    
    # muestreo en ejes, discreto
    x_tramos = 10
    dx  = (b-a)/x_tramos
    dy  = dx/10
    n_iteraciones = 4 # iteraciones en tiempo
    
    verdigitos = 2      # para mostrar en tabla de resultados
    casicero = 1e-15    # para redondeo de términos en ecuacion
    
    # PROCEDIMIENTO
    
    def edp_coef_Dx(edp,x,ordenx):
        ''' Extrae el coeficiente de la derivada Dx de ordenx,
        edp es la ecuación como lhs=rhs
        '''
        coeff_x = 1.0 # valor inicial
        # separa cada término de suma
        term_suma = sym.Add.make_args(edp.lhs)
        for term_k in term_suma:
            if term_k.is_Mul: # mas de un factor
                factor_Mul = sym.Mul.make_args(term_k)
                coeff_temp = 1; coeff_usar = False
                # separa cada factor de término 
                for factor_k in factor_Mul:
                    if not(factor_k.is_Derivative):
                        coeff_temp = coeff_temp*factor_k
                    else: # factor con derivada de ordenx
                        partes = factor_k.args
                        if partes[1]==(x,ordenx):
                            coeff_usar = True
                if coeff_usar==True:
                    coeff_x = coeff_x*coeff_temp
        return(coeff_x)
    
    def redondea_coef(ecuacion, precision=6,casicero = 1e-15):
        ''' redondea coeficientes de términos suma de una ecuacion
        ecuación como lhs=rhs
        '''
        tipo = type(ecuacion)
        tipo_eq = False
        if tipo == sym.core.relational.Equality:
            RHS = ecuacion.rhs  # separa lado derecho
            ecuacion = ecuacion.lhs # analiza lado izquierdo
            tipo = type(ecuacion)
            tipo_eq = True
    
        if tipo == sym.core.add.Add: # términos suma de ecuacion
            term_sum = sym.Add.make_args(ecuacion)
            ecuacion = sym.S.Zero  # vacia
            for term_k in term_sum:
                # factor multiplicativo de termino suma
                term_mul = sym.Mul.make_args(term_k)
                producto = sym.S.One
                for factor in term_mul:
                    if not(factor.has(sym.Symbol)): # es numerico
                        factor = np.around(float(factor),precision)
                        if (abs(factor)%1)<casicero: # si es entero
                            factor = int(factor)
                    producto = producto*factor
                ecuacion = ecuacion + producto
                
        if tipo == sym.core.mul.Mul: # termino único, busca factores
            term_mul = sym.Mul.make_args(ecuacion)
            producto = sym.S.One
            for factor in term_mul:
                if not(factor.has(sym.Symbol)): # es numerico
                    factor = np.around(float(factor),precision)
                    if (abs(factor)%1)<casicero: # si es entero
                        factor = int(factor)
                producto = producto*factor
            ecuacion = producto
            
        if tipo == float: # solo un numero
            if (abs(ecuacion)%1)<casicero: 
                ecuacion = int(ecuacion)
                
        if tipo_eq==True: # era igualdad, integra lhs=rhs
            ecuacion = sym.Eq(ecuacion,RHS)
    
        return(ecuacion)
    
    def edp_sustituye_L(resultado):
        ''' sustituye lambda con Dy**ordeny/Dx**x/K_
        por L, al simplificar Lambda
        '''
        discreta = resultado['(discreta=0)*Dy**ordeny']
        ordenDy = resultado['ordenDy']
        ordenDx = resultado['ordenDx']
        discreta_L = 0
        # separa cada término de suma
        term_suma = sym.Add.make_args(discreta)
        for term_k in term_suma:
            # busca partes de L y cambia por valor L
            cambiar = False # por orden de derivada
            if term_k.has(Dx) and term_k.has(Dy):
                partes = term_k.args
                ordeny = 1
                ordenx = 1
                for unaparte in partes:    
                    if unaparte.has(Dy):
                        if unaparte.is_Pow:
                            partey = unaparte.args
                            ordeny = partey[1]
                    if unaparte.has(Dx):
                        if unaparte.is_Pow:
                            partey = unaparte.args
                            ordenx = partey[1]
                if (ordeny<=ordenDy and ordenx<=-ordenDx):
                    cambiar = True
            if cambiar==True:
                term_k = term_k*L/resultado['Lambda_L']
            discreta_L = discreta_L + term_k
            # simplifica unos con decimal a entero 
            discreta_L = redondea_coef(discreta_L)
        return(discreta_L)
    
    
    resultado = {} # resultados en diccionario
    # orden de derivada por x, y
    edp_x = edp.subs(x,0)
    edp_y = edp.subs(y,0)
    ordenDx = sym.ode_order(edp_x,u)
    ordenDy = sym.ode_order(edp_y,u)
    resultado['ordenDx'] = ordenDx  # guarda en resultados
    resultado['ordenDy'] = ordenDy
    # coeficiente derivada orden mayor a 1 (d2u/dx2)
    coeff_x = edp_coef_Dx(edp,x,ordenDx)
    LHS = edp.lhs  # lado izquierdo de edp
    RHS = edp.rhs  # lado derecho de edp
    if not(coeff_x==1):
        LHS = LHS/coeff_x
        RHS = RHS/coeff_x
    # toda la expresión a la izquierda
    edp = sym.Eq(LHS-RHS,0)
    K_ = -edp_coef_Dx(edp,y,ordenDy)
    if abs(K_)%1<casicero: # si es entero
        K_ = int(K_)
    resultado['edp=0']  = edp
    resultado['K_']  = K_
    
    # lambda en ecuacion edp
    lamb = (Dy**ordenDy)/(Dx**ordenDx)
    if ordenDy==1 and ordenDx==2:
            lamb = lamb/K_
    resultado['Lambda_L'] = lamb
    # valor de Lambda en ecuacion edp
    L_k = lamb.subs([(Dx,dx),(Dy,dy)])
    if abs(L_k)%1<casicero: # si es entero
        L_k = int(L_k)
    resultado['Lambda L_k'] = L_k
    
    discreta = edp.lhs # EDP discreta
    for derivada in dif_dividida:
        discreta = discreta.subs(derivada,dif_dividida[derivada])
    
    # simplifica con Lambda L
    discreta_L = sym.expand(discreta*(Dy**ordenDy),mul=True)
    resultado['(discreta=0)*Dy**ordeny'] = discreta_L
    
    discreta_L = edp_sustituye_L(resultado)
    discreta_L = sym.collect(discreta_L,U) # agrupa u[,]
    discreta_L = sym.Eq(discreta_L,0)
    resultado['discreta_L=0'] = discreta_L
            
    # sustituye constantes en ecuación a iterar
    discreta_L = discreta_L.subs([(Dx,dx),(Dy,dy),(L,L_k)])
    discreta_L = redondea_coef(discreta_L)
    resultado['discreta'] = discreta_L
    
    # SALIDA
    np.set_printoptions(precision=verdigitos)
    algun_numero = [int,float,str,'Lambda L_k']
    print('EDP Parabólica contínua a discreta')
    for entrada in resultado:
        tipo = type(resultado[entrada])
        if tipo in algun_numero or entrada in algun_numero:
            print('',entrada,':',resultado[entrada])
        else:
            print('\n',entrada,':')
            sym.pprint(resultado[entrada])
    
    # Método implícito EDP Parabólica ------------
    # ITERAR para cada i,j dentro de U 
    # x[i] , y[j]  valor en posición en cada eje
    xi = np.arange(a,b+dx/2,dx)
    yj = np.arange(y0,n_iteraciones*dy+dy/2,dy)
    n = len(xi)
    m = len(yj)
    # Matriz U
    u_xy = np.zeros(shape=(n,m),dtype = float)
    u_xy = u_xy*np.nan # valor inicial dentro de u
    # llena u con valores en fronteras
    u_xy[:,0]   = fxc(xi)  # inferior  Tc
    u_xy[0,:]   = fya(yj)  # izquierda Ta
    u_xy[n-1,:] = fyb(yj)  # derecha   Tb
    u0 = np.copy(u_xy)     # matriz u inicial
    
    # u_mask[i,j] con valores iniciales o calculados:True
    u_mask = np.zeros(shape=(n,m),dtype=bool)
    u_mask[0,:]  = True # izquierda Ta
    u_mask[-1,:] = True # derecha   Tb
    u_mask[:,0]  = True # inferior  Tc
    
    # Método implícito para EDP Parabólica
    # a usar en iteraciones
    discreta = resultado['discreta']
    
    def edp_sustituyeValorU(discreta,xi,yj,u_xy,u_mask):
        '''Sustituye en edp discreta los valores conocidos de U[i,j]
        tomados desde u_xy, marcados con u_mask
        u_mask indica si el valor se ha calculado con edp.
        '''
        LHS = discreta.lhs # lado izquierdo de ecuacion
        RHS = discreta.rhs # lado derecho
        # sustituye U[i,j] con valores conocidos
        A_diagonal = [] # lista de i,j para matriz de coeficientes A
        # Separa términos suma
        term_suma = sym.Add.make_args(LHS)
        for term_k in term_suma:
            # busca U[i,j] y cambia por valor uxt[i,j]
            cambiar = False ; cambiar_valor = 0 ; cambiar_factor = 0
            # separa cada factor de término
            factor_Mul = sym.Mul.make_args(term_k)
            for factor_k in factor_Mul:
                # busca U[i,j] en matriz uxt[i,j]
                if factor_k.is_Function:
                    [i_k,j_k] = factor_k.args
                    if not(np.isnan(u_xy[i_k,j_k])):
                        cambiar = u_mask[i_k,j_k]
                        cambiar_factor = factor_k
                        cambiar_valor = u_xy[i_k,j_k]
                    else:
                        A_diagonal.append([i_k,j_k,term_k/factor_k])
            # encontró valor U[i,j],term_k va a la derecha de ecuación
            if cambiar == True:
                LHS = LHS - term_k
                term_ki = term_k.subs(cambiar_factor,cambiar_valor)
                RHS = RHS - term_ki
        discreta = sym.Eq(LHS,RHS)
        B_diagonal = RHS
        resultado = [discreta,A_diagonal,B_diagonal]
        return (resultado)
    
    # ITERAR para plantear las ecuaciones en [i,j]
    resultado = {} # resultados en diccionario
    eq_itera = [] ; tamano = (n-2)
    A = np.zeros(shape=(tamano,tamano),dtype=float)
    B = np.zeros(tamano,dtype=float)
    for j_k in range(1,m,1): # no usar valores en bordes
        resultado[j_k] ={}
        for i_k in range(1,n-1,1): 
            eq_conteo = i_k-1
            discreta_ij = discreta.subs({i:i_k,j:j_k,
                                         x:xi[i_k],y:yj[j_k]})
            resultado[j_k][eq_conteo]= {'j':j_k, 'i':i_k,
                                     'discreta_ij': discreta_ij}
            # usa valores de frontera segun u_mask con True
            discreta_k = edp_sustituyeValorU(discreta_ij,
                                            xi,yj,u_xy,u_mask)
            discreta_ij = discreta_k[0]
            A_diagonal  = discreta_k[1] # lista de (i,j,coeficiente) 
            B_diagonal  = discreta_k[2] # constante para B
            resultado[j_k][eq_conteo]['discreta_k'] = discreta_k[0]
            # añade ecuacion a resolver
            eq_itera.append(discreta_ij)
            # Aplica coeficientes de ecuacion en A y B:
            # A_diagonal tiene lista de (i,j,coeficiente) 
            for uncoeff in A_diagonal:
                columna = uncoeff[0]-1
                fila = eq_conteo
                A[fila,columna] = uncoeff[2]
            B[eq_conteo] = float(B_diagonal) # discreta_ij.rhs
        # resuelve el sistema A.X=B en Numpy
        X_k = np.linalg.solve(A,B)
        # actualiza uxt[i,j] , u_mask segun X_k
        u_xy[1:n-1,j_k] = X_k
        u_mask[1:n-1,j_k] = True
        # almacena resultados
        resultado[j_k]['A'] = np.copy(A)
        resultado[j_k]['B'] = np.copy(B)
        resultado[j_k]['X'] = np.copy(X_k)
    
    # SALIDA
    np.set_printoptions(precision=verdigitos)
    algun_numero = [int,float,str,'Lambda L_k']
    print('\nMétodo implícito EDP Parabólica')
    for entrada in resultado:
        tipo = type(resultado[entrada])
        if tipo in algun_numero or entrada in algun_numero:
            print('',entrada,':',resultado[entrada])
        elif (tipo==dict):
            if entrada<2:
                eq_conteo = resultado[entrada].keys()
                for una_eq in eq_conteo:
                    if una_eq=='A' or una_eq=='B' or una_eq=='X':
                        print(una_eq,':')
                        print(resultado[entrada][una_eq])
                    else:
                        print('j:',resultado[entrada][una_eq]['j'],'; '
                              'i:',resultado[entrada][una_eq]['i'])
                        sym.pprint(resultado[entrada][una_eq]['discreta_ij'])
                        sym.pprint(resultado[entrada][una_eq]['discreta_k'])
        else:
            print('\n',entrada,': \n',resultado[entrada])
    print('Resultados para U(x,y)')
    print('xi:',xi)
    print('yj:',yj)
    print(' j, U[i,j]')
    for j_k in range(m-1,-1,-1):
        print(j_k, (u_xy[:,j_k]))
    

    EDP Parabólica [ contínua a discreta ] || sympy: [ explícito ] [ implícito ]

  • 7.1.3 EDP Parabólica - analítico explícito con Sympy-Python

    EDP Parabólica [ contínua a discreta ] || sympy: [ explícito ] [ implícito ]
    ..


    1. Ejercicio

    Referencia:  Chapra 30.2 p888 pdf912, Burden 9Ed 12.2 p725, Rodríguez 10.2 p406

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

    Valores de frontera: Ta = 60, Tb = 40, T0 = 25
    Longitud en x a = 0, b = 1,  Constante K= 4
    Tamaño de paso dx = 0.1, dt = dx/10

    EDP Parabólica [ contínua a discreta ] || [ sympy_explícito ] [sympy_ implícito ]
    ..


    2. EDP Parabólica contínua a discreta

    El resultado del algoritmo para el ejercicio propuesto es:

    EDP Parabólica contínua a discreta
     ordenDx : 2
     ordenDy : 1
    
     edp=0 :
      2                             
     ∂               ∂              
    ───(u(x, y)) - 4⋅──(u(x, y)) = 0
      2              ∂y             
    ∂x                              
     K_ : 4
    
     Lambda_L :
      Dy 
    ─────
        2
    4⋅Dx 
     Lambda L_k : 0.250000000000000
    
     (discreta=0)*Dy**ordeny :
                                2⋅Dy⋅U(i, j)   Dy⋅U(i - 1, j)   Dy⋅U(i + 1, j)
    4⋅U(i, j) - 4⋅U(i, j + 1) - ──────────── + ────────────── + ──────────────
                                      2               2                2      
                                    Dx              Dx               Dx       
    
     discreta_L=0 :
    ⎛    2⋅Dy⎞                           Dy⋅U(i - 1, j)   Dy⋅U(i + 1, j)    
    ⎜4 - ────⎟⋅U(i, j) - 4⋅U(i, j + 1) + ────────────── + ────────────── = 0
    ⎜      2 ⎟                                  2                2          
    ⎝    Dx  ⎠                                Dx               Dx           
    
     discreta :
    2⋅U(i, j) - 4⋅U(i, j + 1) + U(i - 1, j) + U(i + 1, j) = 0
    

    El desarrollo analítico comienza en escribir la ecuación diferencial parcial parabólica de la forma contínua a la representación discreta, siguiendo los criterios indicados en la parte teórica usando derivadas expresadas en diferencias divididas.

    La EDP se escribe en formato Sympy en el bloque de ingreso en dos partes: lado izquierdo (LHS) de la ecuación y lado derecho (RHS), definiendo u como una función de variables x,y.

    # INGRESO
    fxy = 0*x+0*y  # f(x,y) = 0 , ecuacion complementaria
    # ecuacion edp : LHS=RHS
    LHS = sym.diff(u,x,2) 
    RHS = 4*sym.diff(u,y,1) + fxy
    edp = sym.Eq(LHS-RHS,0)
    

    La ecuación f(x,y) se añade para ser usada con otros ejercicios que puede revisar en la sección de Evaluaciones.

    Las expresiones para diferencias divididas seleccionadas se ingresan como un diccionario:

    # centrada, adelante 
    dif_dividida ={sym.diff(u,x,2): (U.subs(i,i-1)-2*U+U.subs(i,i+1))/(Dx**2),
                   sym.diff(u,y,1): (U.subs(j,j+1)-U)/Dy}
    

    Las condiciones iniciales en los extremos a y b, y la temperatura en la barra, pueden ser funciones matemáticas, por lo que se propone usar el formato lambda de las variables x o y. En el ejercicio básico presentado en la parte teórica, la barra tiene temperatura constante, por lo que escribe como una  constante mas cero por la variable independiente, esta forma facilita la evaluación de un vector xi por ejemplo, en caso de disponer una expresión diferente.

    # Valores de frontera
    fya = lambda y: 60 +0*y  # izquierda
    fyb = lambda y: 40 +0*y  # derecha
    fxc = lambda x: 25 +0*x  # inferior, función inicial
    

    los demás parámetros del ejercicio se ingresan más adelante de forma semejante al ejercicio con Numpy.

    Todas las expresiones se escriben al lado izquierdo (LHS) de la igualdad, la parte del lado derecho(RHS) se la prefiere mantener en cero. La expresión se organiza manteniendo el coeficiente en 1 para el termino de Dx de mayor orden. Se sustituyen las derivadas por diferencias divididas, para luego simplificar la expresión usando λ como referencia.

    Al desarrollar el método explícito se requiere indicar el nodo u(i,j+1) a buscar

    buscar = U.subs(j,j+1) # U[i,j+1] método explícito
    

    El valor de K se puede determinar en la expresión al reordenar para que el término de Dx de mayor grado sea la unidad. El valor de K será el del término Dy con signo negativo, al encontrarse en el lado izquierdo (LHS) de la expresión, en la propuesta teórica se encontraba como positivo del lado derecho.

    El término de mayor grado se puede obtener al revisar la expresión por cada término de la suma, buscando el factor que contiene Dx o Dy en cada caso. Por ser un poco ordenado se añade la función edp_coef_Dx().

    Instrucciones en Python

    Para revisar los resultados de algunos pasos para obtener la expresión discreta de EDP, se usa un diccionario a ser usado en el bloque de salida. Para las expresiones de ecuación se usa sym.pprint().

    # Ecuaciones Diferenciales Parciales Parabólicas
    # EDP Parabólicas contínua a discreta con Sympy
    import numpy as np
    import sympy as sym
    
    # u(x,y) funciones continuas y variables simbólicas usadas
    t = sym.Symbol('t',real=True) # independiente
    x = sym.Symbol('x',real=True)
    y = sym.Symbol('y',real=True) 
    u = sym.Function('u')(x,y) # funcion 
    f = sym.Function('f')(x,y) # funcion complemento
    K = sym.Symbol('K',real=True)
    # U[i,j] funciones discretas y variables simbólicas usadas
    i  = sym.Symbol('i',integer=True,positive=True) # indices
    j  = sym.Symbol('j',integer=True,positive=True)
    Dt = sym.Symbol('Dt',real=True,positive=True)
    Dx = sym.Symbol('Dx',real=True,positive=True)
    Dy = sym.Symbol('Dy',real=True,positive=True)
    L  = sym.Symbol('L',real=True)
    U  = sym.Function('U')(i,j)
    
    # INGRESO
    fxy = 0*x+0*y  # f(x,y) = 0 , ecuacion complementaria
    # ecuacion edp : LHS=RHS
    LHS = sym.diff(u,x,2) 
    RHS = 4*sym.diff(u,y,1) + fxy
    edp = sym.Eq(LHS-RHS,0)
    
    # centrada, adelante 
    dif_dividida ={sym.diff(u,x,2): (U.subs(i,i-1)-2*U+U.subs(i,i+1))/(Dx**2),
                   sym.diff(u,y,1): (U.subs(j,j+1)-U)/Dy}
    
    buscar = U.subs(j,j+1) # U[i,j+1] método explícito
    
    # Valores de frontera
    fya = lambda y: 60 +0*y  # izquierda
    fyb = lambda y: 40 +0*y  # derecha
    fxc = lambda x: 25 +0*x  # inferior, función inicial
    
    # [a,b] dimensiones de la barra
    a = 0  # longitud en x
    b = 1
    y0 = 0 # tiempo inicial, aumenta con dt en n iteraciones
    
    # muestreo en ejes, discreto
    x_tramos = 10
    dx  = (b-a)/x_tramos
    dy  = dx/10
    n_iteraciones = 4 # iteraciones en tiempo
    
    verdigitos = 2      # para mostrar en tabla de resultados
    casicero = 1e-15    # para redondeo de términos en ecuacion
    
    # PROCEDIMIENTO --------------------------------------
    
    def edp_coef_Dx(edp,x,ordenx):
        ''' Extrae el coeficiente de la derivada Dx de ordenx,
        edp es la ecuación como lhs=rhs
        '''
        coeff_x = 1.0 # valor inicial
        # separa cada término de suma
        term_suma = sym.Add.make_args(edp.lhs)
        for term_k in term_suma:
            if term_k.is_Mul: # mas de un factor
                factor_Mul = sym.Mul.make_args(term_k)
                coeff_temp = 1; coeff_usar = False
                # separa cada factor de término 
                for factor_k in factor_Mul:
                    if not(factor_k.is_Derivative):
                        coeff_temp = coeff_temp*factor_k
                    else: # factor con derivada de ordenx
                        partes = factor_k.args
                        if partes[1]==(x,ordenx):
                            coeff_usar = True
                if coeff_usar==True:
                    coeff_x = coeff_x*coeff_temp
        return(coeff_x)
    
    def redondea_coef(ecuacion, precision=6,casicero = 1e-15):
        ''' redondea coeficientes de términos suma de una ecuacion
        ecuación como lhs=rhs
        '''
        tipo = type(ecuacion)
        tipo_eq = False
        if tipo == sym.core.relational.Equality:
            RHS = ecuacion.rhs  # separa lado derecho
            ecuacion = ecuacion.lhs # analiza lado izquierdo
            tipo = type(ecuacion)
            tipo_eq = True
    
        if tipo == sym.core.add.Add: # términos suma de ecuacion
            term_sum = sym.Add.make_args(ecuacion)
            ecuacion = sym.S.Zero  # vacia
            for term_k in term_sum:
                # factor multiplicativo de termino suma
                term_mul = sym.Mul.make_args(term_k)
                producto = sym.S.One
                for factor in term_mul:
                    if not(factor.has(sym.Symbol)): # es numerico
                        factor = np.around(float(factor),precision)
                        if (abs(factor)%1)<casicero: # si es entero
                            factor = int(factor)
                    producto = producto*factor
                ecuacion = ecuacion + producto
                
        if tipo == sym.core.mul.Mul: # termino único, busca factores
            term_mul = sym.Mul.make_args(ecuacion)
            producto = sym.S.One
            for factor in term_mul:
                if not(factor.has(sym.Symbol)): # es numerico
                    factor = np.around(float(factor),precision)
                    if (abs(factor)%1)<casicero: # si es entero
                        factor = int(factor)
                producto = producto*factor
            ecuacion = producto
            
        if tipo == float: # solo un numero
            if (abs(ecuacion)%1)<casicero: 
                ecuacion = int(ecuacion)
                
        if tipo_eq==True: # era igualdad, integra lhs=rhs
            ecuacion = sym.Eq(ecuacion,RHS)
    
        return(ecuacion)
    
    
    resultado = {} # resultados en diccionario
    # orden de derivada por x, y
    edp_x = edp.subs(x,0)
    edp_y = edp.subs(y,0)
    ordenDx = sym.ode_order(edp_x,u)
    ordenDy = sym.ode_order(edp_y,u)
    resultado['ordenDx'] = ordenDx  # guarda en resultados
    resultado['ordenDy'] = ordenDy
    # coeficiente derivada orden mayor a 1 (d2u/dx2)
    coeff_x = edp_coef_Dx(edp,x,ordenDx)
    LHS = edp.lhs  # lado izquierdo de edp
    RHS = edp.rhs  # lado derecho de edp
    if not(coeff_x==1):
        LHS = LHS/coeff_x
        RHS = RHS/coeff_x
    # toda la expresión a la izquierda
    edp = sym.Eq(LHS-RHS,0) 
    K_ = -edp_coef_Dx(edp,y,ordenDy)
    if abs(K_)%1<casicero: # si es entero
        K_ = int(K_)
    resultado['edp=0']  = edp
    resultado['K_']  = K_
    
    # lambda en ecuacion edp
    lamb = (Dy**ordenDy)/(Dx**ordenDx)
    if ordenDy==1 and ordenDx==2:
            lamb = lamb/K_
    resultado['Lambda_L'] = lamb
    # valor de Lambda en ecuacion edp
    L_k = lamb.subs([(Dx,dx),(Dy,dy)])
    if abs(L_k)%1<casicero:
        L_k = int(L_k)
    resultado['Lambda L_k'] = L_k
    
    discreta = edp.lhs # EDP discreta
    for derivada in dif_dividida: # reemplaza diferencia dividida
        discreta = discreta.subs(derivada,dif_dividida[derivada])
    
    # simplifica con Lambda_L
    discreta_L = sym.expand(discreta*(Dy**ordenDy),mul=True)
    resultado['(discreta=0)*Dy**ordeny'] = discreta_L
    
    discreta_L = discreta_L.subs(lamb,L)
    discreta_L = sym.collect(discreta_L,U) #agrupa u[,]
    discreta_L = sym.Eq(discreta_L,0)
    resultado['discreta_L=0'] = discreta_L
            
    # sustituye constantes en ecuación a iterar
    discreta_L = discreta_L.subs([(Dx,dx),(Dy,dy),(L,L_k)])
    discreta_L = redondea_coef(discreta_L)
    resultado['discreta'] = discreta_L
    
    # SALIDA
    np.set_printoptions(precision=verdigitos)
    algun_numero = [int,float,str,'Lambda L_k']
    print('EDP Parabólica contínua a discreta')
    for entrada in resultado:
        tipo = type(resultado[entrada])
        if tipo in algun_numero or entrada in algun_numero:
            print('',entrada,':',resultado[entrada])
        else:
            print('\n',entrada,':')
            sym.pprint(resultado[entrada])
    

    EDP Parabólica [ contínua a discreta ] || sympy: [ explícito ] [ implícito ]

    ..


    3. EDP Parabólica - Método explícito con Sympy

    El desarrollo del método explícito para una ecuación diferencial parcial parabólica usando Sympy, requiere añadir instrucciones para procesar la expresión obtenida en el algoritmo anterior con los valores de i,j.

    Se añaden las instrucciones para iterar la expresión discreta para cada i,j dentro de la matriz U creada para el ejercicio. Se aplican las condiciones iniciales a los bordes de la matriz, para luego proceder a iterar.

    Como en las actividades del curso se requiere realizar al menos 3 iteraciones para las expresiones del algoritmo con papel y lápiz, solo se presentarán los resultados de las expresiones para la primera fila en j=0.

    El algoritmo para la EDP del ejemplo muestra el siguiente resultado:

    Método explícito EDP Parabólica
    discreta_itera:
                  U(i, j)   U(i - 1, j)   U(i + 1, j)
    U(i, j + 1) = ─────── + ─────────── + ───────────
                     2           4             4     
    
     iterar i,j:
    j:  0  ;  i:  1  ;  ecuacion: 0
              U(0, 0)   U(1, 0)   U(2, 0)
    U(1, 1) = ─────── + ─────── + ───────
                 4         2         4   
    U(1, 1) = 33.75
    j:  0  ;  i:  2  ;  ecuacion: 1
              U(1, 0)   U(2, 0)   U(3, 0)
    U(2, 1) = ─────── + ─────── + ───────
                 4         2         4   
    U(2, 1) = 25.0
    j:  0  ;  i:  3  ;  ecuacion: 2
              U(2, 0)   U(3, 0)   U(4, 0)
    U(3, 1) = ─────── + ─────── + ───────
                 4         2         4   
    U(3, 1) = 25.0
    j:  0  ;  i:  4  ;  ecuacion: 3
              U(3, 0)   U(4, 0)   U(5, 0)
    U(4, 1) = ─────── + ─────── + ───────
                 4         2         4   
    U(4, 1) = 25.0
    j:  0  ;  i:  5  ;  ecuacion: 4
              U(4, 0)   U(5, 0)   U(6, 0)
    U(5, 1) = ─────── + ─────── + ───────
                 4         2         4   
    U(5, 1) = 25.0
    j:  0  ;  i:  6  ;  ecuacion: 5
              U(5, 0)   U(6, 0)   U(7, 0)
    U(6, 1) = ─────── + ─────── + ───────
                 4         2         4   
    U(6, 1) = 25.0
    j:  0  ;  i:  7  ;  ecuacion: 6
              U(6, 0)   U(7, 0)   U(8, 0)
    U(7, 1) = ─────── + ─────── + ───────
                 4         2         4   
    U(7, 1) = 25.0
    j:  0  ;  i:  8  ;  ecuacion: 7
              U(7, 0)   U(8, 0)   U(9, 0)
    U(8, 1) = ─────── + ─────── + ───────
                 4         2         4   
    U(8, 1) = 25.0
    j:  0  ;  i:  9  ;  ecuacion: 8
              U(8, 0)   U(9, 0)   U(10, 0)
    U(9, 1) = ─────── + ─────── + ────────
                 4         2         4    
    U(9, 1) = 28.75
    ... continua calculando
    
    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]
     j, U[i,j]
    4 [60.   42.77 31.29 26.37 25.14 25.   25.06 25.59 27.7  32.62 40.  ]
    3 [60.   40.86 29.38 25.55 25.   25.   25.   25.23 26.88 31.8  40.  ]
    2 [60.   38.12 27.19 25.   25.   25.   25.   25.   25.94 30.62 40.  ]
    1 [60.   33.75 25.   25.   25.   25.   25.   25.   25.   28.75 40.  ]
    0 [60. 25. 25. 25. 25. 25. 25. 25. 25. 25. 40.]
    

    Instrucciones en Python

    # Método explícito EDP Parabólica ------------
    # ITERAR para cada i,j dentro de U 
    # x[i] , y[j]  valor en posición en cada eje
    xi = np.arange(a,b+dx/2,dx)
    yj = np.arange(y0,n_iteraciones*dy+dy,dy)
    n = len(xi)
    m = len(yj)
    # Matriz U
    u_xy = np.zeros(shape=(n,m),dtype = float)
    u_xy = u_xy*np.nan # valor inicial dentro de u
    # llena u con valores en fronteras
    u_xy[:,0]   = fxc(xi)  # inferior  Tc
    u_xy[0,:]   = fya(yj)  # izquierda Ta
    u_xy[n-1,:] = fyb(yj)  # derecha   Tb
    u0 = np.copy(u_xy)     # matriz u inicial
    
    # busca el término no conocido
    u_explicito = sym.solve(discreta_L,buscar)
    u_explicito = sym.Eq(buscar,u_explicito[0])
    resultado['discreta_itera'] = u_explicito
    
    print('\nMétodo explícito EDP Parabólica')
    print('discreta_itera:')
    sym.pprint(u_explicito)
    
    # iterando
    print('\n iterar i,j:')
    j_k = 0
    for j_k in range(0,m-1,1):
        for i_k in range(1,n-1,1):
            eq_conteo = j_k*(n-2)+(i_k-1)
            discreta_ij = u_explicito.subs({i:i_k,j:j_k})
            valorij = 0 # calcula valor de nodo ij
            # separa cada término de suma
            term_suma = sym.Add.make_args(discreta_ij.rhs)
            for term_k in term_suma:
                term_ki = 1
                if term_k.is_Function:
                    [i_f,j_f] = term_k.args
                    term_ki = u_xy[i_f,j_f]
                elif term_k.is_Mul: # mas de un factor
                    factor_Mul = sym.Mul.make_args(term_k)
                    # separa cada factor de término 
                    for factor_k in factor_Mul:
                        if factor_k.is_Function:
                            [i_f,j_f] = factor_k.args
                            term_ki = term_ki*u_xy[i_f,j_f]
                        else:
                            term_ki = term_ki*factor_k
                else:
                    term_ki = term_k
                valorij = valorij + term_ki
            [i_f,j_f] = discreta_ij.lhs.args
            u_xy[i_f,j_f] = float(valorij) # actualiza matriz u
            # muestra las primeras m iteraciones
            if eq_conteo<(n-2):
                print('j: ',j_k,' ; ','i: ',i_k,
                      ' ; ','ecuacion:',eq_conteo)
                sym.pprint(discreta_ij)
                print(discreta_ij.lhs,'=',float(valorij))
    print('... continua calculando')
    
    # SALIDA
    np.set_printoptions(precision=verdigitos)
    print('\nx:',xi)
    print('t:',yj)
    print(' j, U[i,j]')
    for j_k in range(m-1,-1,-1):
        print(j_k, (u_xy[:,j_k]))
    

    EDP Parabólica [ contínua a discreta ] || sympy: [ explícito ] [ implícito ]

  • 3Eva_2023PAOI_T4 EDO Especies en competencia por recursos

    3ra Evaluación 2023-2024 PAO I. 12/Septiembre/2023

    Tema 4. (30 puntos) especies en competencia por recursosConsidere dos especies de animales que ocupan el mismo ecosistema, en competencia por los recursos de alimentos y espacio definidas por:

    \frac{dx}{dt} = x(2 - 0.4 x - 0.3 y) \frac{dy}{dt} = y( 1 - 0.1 y - 0.3 x)

    Donde las poblaciones de x(t) y y(t) se miden en miles y t en años. Use un método numérico para analizar las poblaciones en un periodo largo para el caso que:  x(0)=1.5, y(0)=3.5

    a. Realice el planteamiento del ejercicio usando Runge-Kutta de 2do Orden

    b. Desarrolle tres iteraciones para x(t), y(t) con tamaño de paso h=0.5.

    c. Usando el algoritmo, aproxime la solución entre t=0 a t=10 años, adjunte sus resultados en la evaluación.

    d. Realice una observación sobre el crecimiento de la población de las especies y(t) a lo largo del tiempo.

    Rúbrica: literal a (5 puntos), literal b (15 puntos), literal c (5 puntos), literal d (5 puntos)

    Referencia: [1] Modelos de competencia ejercicio 10. Zill, Dennis G. Ecuaciones diferenciales con aplicaciones de modelado. Edición 9. P109. p111.

    [2] Competition in ecosystems. Stile Education. 11 septiembre 2019.

  • 3Eva_2023PAOI_T3 Perfil de área devastada por incendios

    3ra Evaluación 2023-2024 PAO I. 12/Septiembre/2023

    3Eva_2023PAOI_T2 Área devastada por incendios

    Tema 3. (20 puntos) Continuando con el ejercicio del área devastada por el incendio, con el objetivo de simplificar el registro de datos se propone describir los perfiles usando polinomios.

    area devastada por incendio perfil

    Frontera superior

    X 350 300 350 420 444 484 504 534 568 620 660 720 780 740 800 800
    Y 0 315 315 315 320 336 400 415 462 510 550 550 490 390 390 150

    Frontera inferior

    X 350 459 666 800
    Y 0 63 130 150

    a. Plantear el ejercicio para realizar interpolación polinómica. Describa criterios, intervalos, método.

    b. Desarrolle el o los polinomios para la frontera superior, siguiendo el método propuesto en el literal a.

    c. Desarrolle el o los polinomios para la frontera inferior, con un método diferente al literal a.

    d. Usando un algoritmo, graficar al menos un resultado del literal b y c.

    Rúbrica: literal a (5 puntos), literal b (5 puntos), literal c (5 puntos), literal d (5 puntos)

     

  • 3Eva_2023PAOI_T2 Área devastada por incendios

    3ra Evaluación 2023-2024 PAO I. 12/Septiembre/2023

    Tema 2 (25 puntos) Se requiere determinar el área urbana a restaurar, que devastada por incendios en una isla del océano Pacífico, se encuentra delimitada por la playa y los puntos mostrados en la figura.

    area devastada por incendio perfil

    Se dispone de algunos puntos de referencia tomados desde imágenes de satélites mostrados en la tabla.

    a. Plantear el ejercicio indicando el método de integración numérica a usar. Justifique su selección.

    b. Desarrolle el método para los datos de la frontera superior

    c. Realice los cálculos para la frontera inferior delimitada por playa

    d. Estime la cota de error en los cálculos.

    Frontera superior

    X 350 300 350 420 444 484 504 534 568 620 660 720 780 740 800 800
    Y 0 315 315 315 320 336 400 415 462 510 550 550 490 390 390 150

    Frontera inferior

    X 350 459 666 800
    Y 0 63 130 150

    Rúbrica: literal a (5 puntos), literal b (10 puntos), literal c (5 puntos), literal d (5 puntos)

    xs = [350, 300, 350, 420, 444, 484, 504, 534, 568, 620, 660, 720, 780, 740, 800, 800]
    fs = [0, 315, 315, 315, 320, 336, 400, 415, 462, 510, 550, 550, 490, 390, 390, 150]
    xi = [350, 459, 666, 800]
    fi = [0, 63, 130, 150]

    Referencia: Incendios forestales devastan partes de la isla de Maui. DW español. 11 agosto 2023.