Diferencia entre revisiones de «Ecuación del Calor LÁJ»

De MateWiki
Saltar a: navegación, buscar
(Página creada con «{{ TrabajoED | Ecuación del calor. Grupo LÁJ| EDP|2025-26 | Luis García Suárez Álvaro Moreno Cisneros Juan Pérez Guerra...»)
 
Línea 6: Línea 6:
  
 
[[Archivo:Ecuación del calor LÁJ.jpeg||800px]]
 
[[Archivo:Ecuación del calor LÁJ.jpeg||800px]]
[[Medio:Ecuación del calor LÁJ.pdf | PDF del póster]]
+
[[Medio:Ecuación del calor LÁJ.png | PDF del póster]]
  
  

Revisión del 08:41 8 abr 2026

Trabajo realizado por estudiantes
Título Ecuación del calor. Grupo LÁJ
Asignatura EDP
Curso 2025-26
Autores Luis García Suárez

Álvaro Moreno Cisneros

Juan Pérez Guerra

Este artículo ha sido escrito por estudiantes como parte de su evaluación en la asignatura


800px PDF del póster


Abajo se puede ver el código que se ha utilizado para conseguir las gráficas.

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import trapezoid
from matplotlib import cm

# Ecuación del calor acotada-----------------------------------------------------------------------
def Eca_Acotada(L,alpha,n_terms,f):

    """
    Aproxima la solución de la ecuación del calor u_t -alpha * u_xx = 0, con 
    condición inicial f(x) y condiciones frontera dirichlet homogéneas

    Inputs: 
        L: longitud de la barra
        alpha: constante
        n_terms: número de términos para la serie de Fourier
        f: condición inicial
    """

    # 1. Preparar la malla con T en el eje "X" y X en el eje "Y"
    t_plot = np.linspace(0, 0.1, 100)
    x_plot = np.linspace(0, L, 100)
    T, X = np.meshgrid(t_plot, x_plot)

    # 2. Cálculo de coeficientes a_n con la fórmula del trapecio
    x_fine = np.linspace(0, L, 1000)
    y_init = f(x_fine)
    a = np.zeros(n_terms + 1)
    for n in range(1, n_terms + 1):
        integrando = y_init * np.sin(n * np.pi * x_fine / L)
        a[n] = (2/L) * trapezoid(integrando, x=x_fine)

    # 3. Calcular la solución U(T, X)
    U = np.zeros_like(T)
    for n in range(1, n_terms + 1):
        term_exp = np.exp(-alpha * (n * np.pi / L)**2 * T)
        term_sin = np.sin(n * np.pi * X / L)
        U += a[n] * term_exp * term_sin

    # 4. Graficar
    fig = plt.figure(figsize=(12, 8))
    ax = fig.add_subplot(111, projection='3d')

    # Ahora graficamos T en el primer eje y X en el segundo
    surf = ax.plot_surface(T, X, U, cmap=cm.inferno, linewidth=0, antialiased=True)

    ax.set_xlabel('Tiempo (t)')
    ax.set_ylabel('Posición (x)')
    ax.set_zlabel('Temperatura (u)')
    ax.set_title('Visualización: Tiempo vs Posición')
    fig.colorbar(surf, shrink=0.5, aspect=5)

    ax.view_init(elev=30, azim=-120)

    plt.show()


# Parámetros 
L = 1.0        
alpha = 1.0    
n_terms = 50   

# Dato inicial
def f(x):
    return np.where((x >= 0.3) & (x <= 0.7), 10.0, 0.0)
# def f(x):
#     return 1.0 - 2.0 * np.abs(0.5 - x)


# LLamamos a la función
Eca_Acotada(L,alpha,n_terms,f)


# Ecuación del calor no acotada-----------------------------------------------------------------------
# Visualizar como la solución fundamental tiende a la delta de Dirac------------------------
# Parámetros
alpha = 1.0  # Difusividad térmica

# Definición de la solución fundamental
def solucion_fundamental(x, t, alpha):
    """
    Calcula el valor de la solución fundamental en (x, t).
    Representa la distribución de calor partiendo de una masa puntual en x=0.
    """
    # Evitamos división por cero si t=0
    if t <= 0:
        return np.zeros_like(x)
    
    coeficiente = 1.0 / np.sqrt(4 * np.pi * alpha * t)
    exponente = - (x**2) / (4 * alpha * t)
    return coeficiente * np.exp(exponente)

# Configuración de la visualización
x = np.linspace(-2, 2, 1000)
# Tiempos que se acercan a cero para ver la Delta de Dirac
tiempos = [0.1, 0.05, 0.01, 0.005, 0.001] 

plt.figure(figsize=(10, 6))

for t in tiempos:
    u = solucion_fundamental(x, t, alpha)
    plt.plot(x, u, label=f't = {t}')

plt.title('Convergencia de la Solución Fundamental a la Delta de Dirac')
plt.xlabel('Posición (x)')
plt.ylabel('Temperatura (u)')
plt.legend()
plt.grid(True, linestyle=':')
plt.show()


#Visualizar la solución fundamental en 3D----------------
# Parámetros
alpha = 1.0

# 1. Crear malla de puntos (T en el primer eje, X en el segundo)
t_plot = np.linspace(0.005, 0.1, 100)
x_plot = np.linspace(-2, 2, 100)
T, X = np.meshgrid(t_plot, x_plot) # Invertimos el orden para el intercambio

# 2. Calcular la solución fundamental
U = (1.0 / np.sqrt(4 * np.pi * alpha * T)) * np.exp(-(X**2) / (4 * alpha * T))

# 3. Graficar
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')

# Graficamos T en el eje X del gráfico, X en el eje Y
surf = ax.plot_surface(T, X, U, cmap=cm.viridis, linewidth=0, antialiased=True)

# Etiquetas corregidas
ax.set_xlabel('Tiempo (t)')
ax.set_ylabel('Posición (x)')
ax.set_zlabel('Temperatura (u)')
ax.set_title('Núcleo de Calor: Evolución del Pico (t -> 0)')

fig.colorbar(surf, shrink=0.5, aspect=5)

ax.view_init(elev=30, azim=-120)

plt.show()


#Visualizar solución de la ecuación del calor no acotada----------------

# 1. Definición del núcleo y dato inicial
def kernel(x, t, alpha=1.0):
    return (1.0 / np.sqrt(4 * np.pi * alpha * t)) * np.exp(-(x**2) / (4 * alpha * t))

def u0(y):
    # Dato inicial
    return np.where((y >= 0) & (y <= 1), 1.0, 0.0)

# 2. Configuración de la malla
t_range = np.linspace(0.001, 1, 50)  # Eje T
x_range = np.linspace(-2, 3, 60)      # Eje X
T, X = np.meshgrid(t_range, x_range)

# Espacio de integración para la convolución (eje y)
y_int = np.linspace(-4, 5, 500)
u_initial_values = u0(y_int)

# 3. Cálculo de la superficie U(T, X)
U = np.zeros_like(X)

for i in range(len(x_range)):
    for j in range(len(t_range)):
        curr_x = X[i, j]
        curr_t = T[i, j]
        # Realizamos la convolución numérica para cada punto (x, t)
        integrando = kernel(curr_x - y_int, curr_t) * u_initial_values
        U[i, j] = trapezoid(integrando, x=y_int)

# 4. Graficar en 3D
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')

# Graficamos con Tiempo en el primer eje y Posición en el segundo
surf = ax.plot_surface(T, X, U, cmap=cm.plasma, linewidth=0, antialiased=True)

ax.set_xlabel('Tiempo (t)')
ax.set_ylabel('Posición (x)')
ax.set_zlabel('Temperatura (u)')
ax.set_title('Solución por Convolución: Disipación de un bloque de calor')

fig.colorbar(surf, shrink=0.5, aspect=5)
ax.view_init(elev=30, azim=-130)

plt.show()

#Ver como el máximo va disminuyendo a lo largo del tiempo
maximos = [np.max(U[:, j]) for j in range(len(t_range))]

plt.figure(figsize=(8, 4))
plt.plot(t_range, maximos, color='red', linewidth=2)
plt.axhline(y=1.0, color='black', linestyle='--', label='Máximo Inicial (t=0)')
plt.title('Validación del Principio del Máximo')
plt.xlabel('Tiempo (t)')
plt.ylabel('Temperatura Máxima alcanzada')
plt.legend()
plt.grid(True)
plt.show()