V. Vigas: Cargas en el Tramo y Ejemplo Completo 🌉#
Hasta ahora, todas las cargas actuaban directamente sobre los nudos. En las vigas reales esto casi nunca ocurre: el peso propio, una losa o un equipo apoyado generan cargas distribuidas o cargas puntuales en medio del tramo. Como el método de la rigidez solo relaciona fuerzas y desplazamientos en los nudos, necesitamos una forma de llevar esas cargas a los nudos sin perder información.
Esta sección presenta las cargas nodales equivalentes, adapta el algoritmo de las Secciones II y III para incluirlas, y resuelve un ejemplo completo de viga continua que se compara con la solución analítica.
1. Superposición: Elemento Empotrado + Nudos Liberados 🧩#
La idea se basa en el principio de superposición. Un elemento con carga en el tramo se analiza como la suma de dos problemas:
- Problema A (nudos bloqueados): Se bloquean todos los GDL de los nudos del elemento (empotramiento perfecto en ambos extremos) y se aplica la carga del tramo. Los apoyos ficticios desarrollan las fuerzas de empotramiento perfecto \(\mathbf{f}_{\text{emp}}\). En este problema los desplazamientos nodales son cero.
- Problema B (nudos liberados): Se quitan los bloqueos aplicando en los nudos las fuerzas contrarias, \(-\mathbf{f}_{\text{emp}}\). Este problema solo tiene cargas en los nudos, así que se resuelve con el método de la rigidez de siempre.
Las fuerzas que se aplican en el Problema B son las cargas nodales equivalentes:
$$\mathbf{f}_{\text{eq}} = -\mathbf{f}_{\text{emp}}$$De la superposición se obtienen dos conclusiones importantes:
- Desplazamientos nodales: Como el Problema A no mueve los nudos, los desplazamientos nodales \(\mathbf{u}\) salen solo del Problema B: basta con sumar \(\mathbf{f}_{\text{eq}}\) al vector de fuerzas \(\mathbf{f}\) y resolver.
- Fuerzas en los extremos del elemento: Son la suma de ambos problemas: $$\mathbf{f}_e = \mathbf{k}' \mathbf{u}_e + \mathbf{f}_{\text{emp}} = \mathbf{k}' \mathbf{u}_e - \mathbf{f}_{\text{eq}}$$ Olvidar el término \(-\mathbf{f}_{\text{eq}}\) es un error muy común: entrega fuerzas internas incorrectas aunque los desplazamientos estén bien.
2. Tabla de Cargas Nodales Equivalentes 📋#
Convención (la misma de la Sección IV): GDL del elemento \([v_1, \theta_1, v_2, \theta_2]\), con \(v\) positivo hacia arriba y \(\theta\) positivo antihorario. Las cargas de la tabla actúan hacia abajo.
| Carga en el tramo | \(f_{v_1}\) | \(f_{\theta_1}\) | \(f_{v_2}\) | \(f_{\theta_2}\) |
|---|---|---|---|---|
| Uniforme \(w\) (N/m) en todo el tramo | \(-\dfrac{wL}{2}\) | \(-\dfrac{wL^2}{12}\) | \(-\dfrac{wL}{2}\) | \(+\dfrac{wL^2}{12}\) |
| Puntual \(P\) en el centro | \(-\dfrac{P}{2}\) | \(-\dfrac{PL}{8}\) | \(-\dfrac{P}{2}\) | \(+\dfrac{PL}{8}\) |
| Puntual \(P\) a distancia \(a\) del nudo 1 (\(b = L - a\)) | \(-\dfrac{P b^2 (3a + b)}{L^3}\) | \(-\dfrac{P a b^2}{L^2}\) | \(-\dfrac{P a^2 (a + 3b)}{L^3}\) | \(+\dfrac{P a^2 b}{L^2}\) |
Notar que no basta con repartir la carga en partes iguales entre los nudos (\(wL/2\) a cada lado): también aparecen momentos nodales, que son los que hacen que la viga se deforme correctamente.
Origen de la Tabla (SymPy)#
Las cargas nodales equivalentes se obtienen integrando la carga \(q(x)\) ponderada por las funciones de forma de Hermite \(\mathbf{N}(x)\), las mismas que describen la deformada cúbica de una viga:
$$\mathbf{f}_{\text{eq}} = \int_0^L \mathbf{N}(x)\, q(x)\, dx$$Con SymPy se puede verificar la primera fila de la tabla y, de paso, la matriz \(\mathbf{k}'_{\text{viga}}\) de la Sección IV:
import sympy as sp
x, L, w, EI = sp.symbols("x L w EI", positive=True)
xi = x / L
# Funciones de forma de Hermite (GDL: v1, θ1, v2, θ2)
N = sp.Matrix([1 - 3*xi**2 + 2*xi**3,
L*(xi - 2*xi**2 + xi**3),
3*xi**2 - 2*xi**3,
L*(-xi**2 + xi**3)])
# Cargas nodales equivalentes: f_eq = ∫ N q dx, con q = -w (hacia abajo)
f_eq = sp.integrate(N * (-w), (x, 0, L))
print("f_eq =", sp.simplify(f_eq.T))
# Verificación: la matriz de rigidez sale de ∫ EI N'' N''^T dx
B = N.diff(x, 2)
k = sp.integrate(EI * B * B.T, (x, 0, L))
print("k =", sp.simplify(k / (EI / L**3)))
3. Algoritmo con Cargas en el Tramo ⚙️#
El algoritmo de las Secciones II y III cambia solo en tres puntos (marcados con ✏️):
- Ensamblar \(\mathbf{K}\) igual que antes.
- ✏️ Ensamblar \(\mathbf{f}\): cargas aplicadas directamente en los nudos más las cargas nodales equivalentes \(\mathbf{f}_{\text{eq}}^{(e)}\) de cada elemento. Se ensamblan con los mismos índices de GDL que su matriz \(\bar{\mathbf{k}}^{(e)}\).
- Reducir y resolver \(\mathbf{K}_{LL} \mathbf{u}_L = \mathbf{f}_L\).
- ✏️ Reacciones: se usa la expresión general de la Sección III, $$\mathbf{R} = \mathbf{K}_{RL} \mathbf{u}_L + \mathbf{K}_{RR} \mathbf{u}_R - \mathbf{f}_R^{\text{ap}}$$ donde ahora \(\mathbf{f}_R^{\text{ap}}\) incluye las cargas nodales equivalentes que caen sobre GDL restringidos. En una viga esto casi siempre ocurre, porque las cargas del tramo llegan a los apoyos.
- ✏️ Fuerzas en los extremos de cada elemento: \(\mathbf{f}_e = \mathbf{k}' \mathbf{u}_e - \mathbf{f}_{\text{eq}}\). En un marco inclinado se trabaja en ejes locales: \(\mathbf{f}'_e = \mathbf{k}' \mathbf{T} \mathbf{U}_e - \mathbf{f}'_{\text{eq}}\).
Resultados Dentro del Elemento#
Para dibujar la deformada y los diagramas de esfuerzos también se suman los dos problemas. Con \(x\) medido desde el nudo 1 del elemento y una carga uniforme \(w\):
- Deformada: la parte nodal (Problema B) se interpola con las funciones de Hermite, y se suma la flecha de la viga empotrada (Problema A): $$v(x) = \mathbf{N}(x)^T \mathbf{u}_e - \frac{w\, x^2 (L - x)^2}{24\, EI}$$
- Momento flector (positivo si tracciona la fibra inferior), a partir de las fuerzas en el extremo 1 del elemento, \(V_1\) y \(M_1\): $$M(x) = -M_1 + V_1\, x - \frac{w\, x^2}{2}$$
4. Ejercicio Demostrativo: Viga Continua de Dos Tramos 💻#
Analicemos una viga continua de dos tramos iguales, con apoyos simples en \(x = 0\), \(x = L\) y \(x = 2L\), y una carga uniforme \(w\) hacia abajo en toda su longitud.
Datos: \(L = 4\) m por tramo, \(w = 10\) kN/m, \(E = 200\) GPa, \(I = 8 \times 10^{-5}\) m\(^4\).
Modelo:
- 3 nudos y 2 elementos. Cada nudo tiene 2 GDL \((v, \theta)\), por lo que \(\mathbf{K}\) es de \(6 \times 6\).
- Nudo \(i\): \(v_i\) es el GDL \(2i - 1\) y \(\theta_i\) es el GDL \(2i\) (en el código, índices \(2i - 2\) y \(2i - 1\)).
- Los tres apoyos impiden el desplazamiento vertical: GDL restringidos 1, 3 y 5 (índices 0, 2 y 4). Las rotaciones quedan libres.
Primero, agrega a tu rigidez.py las funciones de vigas de esta sección (incluida f_eq_puntual, la última fila de la tabla):
# ============================ Sección V ============================
def k_viga(E, I, L):
"""Matriz de rigidez local de una viga (GDL: v1, θ1, v2, θ2)."""
return E * I / L**3 * np.array([
[ 12, 6*L, -12, 6*L],
[6*L, 4*L**2, -6*L, 2*L**2],
[-12, -6*L, 12, -6*L],
[6*L, 2*L**2, -6*L, 4*L**2],
])
def f_eq_uniforme(w, L):
"""Cargas nodales equivalentes de una carga uniforme w (N/m, hacia abajo)."""
return np.array([-w*L/2, -w*L**2/12, -w*L/2, w*L**2/12])
def f_eq_puntual(P, a, L):
"""Cargas nodales equivalentes de una carga puntual P (N, hacia abajo) a una distancia a del nudo 1."""
b = L - a
return np.array([-P*b**2*(3*a + b)/L**3, -P*a*b**2/L**2,
-P*a**2*(a + 3*b)/L**3, P*a**2*b/L**2])
def hermite(xi, L):
"""Funciones de forma de Hermite evaluadas en xi = x/L (filas: v1, θ1, v2, θ2)."""
return np.array([1 - 3*xi**2 + 2*xi**3,
L*(xi - 2*xi**2 + xi**3),
3*xi**2 - 2*xi**3,
L*(-xi**2 + xi**3)])
Las funciones ensamblar, resolver y reacciones de las Secciones II y III sirven sin cambios para vigas: el algoritmo es el mismo, solo cambian la matriz del elemento y el significado de los GDL.
import numpy as np
import matplotlib.pyplot as plt
from rigidez import k_viga, f_eq_uniforme, hermite, ensamblar, resolver, reacciones
# --- Datos ---
E = 200e9 # Pa
I = 8.0e-5 # m^4
L = 4.0 # m (largo de cada tramo)
w = 10e3 # N/m (hacia abajo)
# Índices de GDL de cada elemento (nudo i -> índices 2*(i-1), 2*(i-1)+1)
gdl_elem = [[0, 1, 2, 3], # elemento 1: nudos 1-2
[2, 3, 4, 5]] # elemento 2: nudos 2-3
n_gdl = 6
# --- Ensamblaje de K y del vector de cargas nodales equivalentes ---
K = np.zeros((n_gdl, n_gdl))
f = np.zeros(n_gdl)
for gdl in gdl_elem:
ensamblar(K, k_viga(E, I, L), gdl)
f[gdl] += f_eq_uniforme(w, L)
# --- Apoyos (v = 0 en los tres), solución y reacciones ---
gdl_restringidos = [0, 2, 4]
u = resolver(K, f, gdl_restringidos)
R = reacciones(K, u, f, gdl_restringidos) # R = K_RL u_L - f_R^ap
print("Rotaciones θ1, θ2, θ3 (rad):", u[[1, 3, 5]])
print("Reacciones R1, R2, R3 (N): ", R)
print("Equilibrio vertical (N): ", R.sum() - w * 2 * L)
# --- Fuerzas en los extremos de cada elemento: f_e = k' u_e - f_eq ---
for e, gdl in enumerate(gdl_elem, start=1):
f_e = k_viga(E, I, L) @ u[gdl] - f_eq_uniforme(w, L)
print(f"Elemento {e}: V1={f_e[0]:9.1f} N M1={f_e[1]:9.1f} N·m "
f"V2={f_e[2]:9.1f} N M2={f_e[3]:9.1f} N·m")
# --- Deformada y momento flector dentro de cada elemento ---
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(8, 6))
x_loc = np.linspace(0, L, 51)
for e, gdl in enumerate(gdl_elem):
x = e*L + x_loc
# Deformada: parte nodal (Hermite) + flecha del elemento empotrado
v = hermite(x_loc/L, L).T @ u[gdl] - w*x_loc**2*(L - x_loc)**2/(24*E*I)
f_e = k_viga(E, I, L) @ u[gdl] - f_eq_uniforme(w, L)
M = -f_e[1] + f_e[0]*x_loc - w*x_loc**2/2
ax1.plot(x, v*1e3, "C0")
ax2.plot(x, M/1e3, "C1")
# Solución analítica de cada tramo (s medido desde el apoyo extremo)
s = x_loc if e == 0 else L - x_loc
v_an = -w*s*(L**3 - 3*L*s**2 + 2*s**3)/(48*E*I)
ax1.plot(x[::5], v_an[::5]*1e3, "k.", label="Analítico" if e == 0 else None)
ax1.set_ylabel("v (mm)")
ax1.legend()
ax1.grid(True)
ax2.set_ylabel("M (kN·m)")
ax2.set_xlabel("x (m)")
ax2.grid(True)
plt.show()
Resultados y Verificación#
La viga continua de dos tramos iguales tiene solución analítica conocida, lo que permite verificar cada resultado:
| Resultado | Rigidez (Python) | Analítico | Valor |
|---|---|---|---|
| Rotación en el apoyo extremo \(\theta_1\) | \(-8.333 \times 10^{-4}\) rad | \(-\dfrac{wL^3}{48EI}\) | \(-8.333 \times 10^{-4}\) rad |
| Rotación en el apoyo central \(\theta_2\) | \(\approx 0\) | \(0\) (simetría) | \(0\) |
| Reacciones extremas \(R_1 = R_3\) | 15 000 N | \(\dfrac{3wL}{8}\) | 15 000 N |
| Reacción central \(R_2\) | 50 000 N | \(\dfrac{5wL}{4}\) | 50 000 N |
| Momento en el apoyo central | \(-20\,000\) N·m | \(-\dfrac{wL^2}{8}\) | \(-20\,000\) N·m |
| Momento máximo en el tramo | 11 250 N·m | \(\dfrac{9wL^2}{128}\) | 11 250 N·m |

Algunas observaciones:
- Los resultados coinciden exactamente con la solución analítica, incluso dentro de los tramos. Esto ocurre porque, para vigas de Euler-Bernoulli, las funciones de Hermite más la flecha de empotramiento reproducen la solución exacta.
- \(\theta_2 = 0\) por simetría: es una verificación gratuita que conviene aprovechar siempre que exista.
- El momento máximo en valor absoluto está sobre el apoyo central (momento negativo, tracción en la fibra superior). Es el punto que gobierna el diseño de la viga.
5. Ejercicios Propuestos 📝#
- Concepto: ¿Por qué no basta con repartir una carga uniforme como \(wL/2\) en cada nudo? ¿Qué parte de la respuesta de la viga se perdería?
- Cálculo: Escribe el vector \(\mathbf{f}_{\text{eq}}\) para un tramo de \(L = 5\) m con una carga uniforme de \(8\) kN/m.
- SymPy: Modifica el código de SymPy para una carga puntual \(P\) a una distancia \(a\) del nudo 1 (pista: la integral con una carga puntual se reduce a evaluar \(-P\,\mathbf{N}(a)\)). Verifica la última fila de la tabla.
- SymPy: Calcula \(\mathbf{f}_{\text{eq}}\) para una carga triangular \(q(x) = -w_0\, x / L\) (cero en el nudo 1 y máxima en el nudo 2).
- Programación: La función
reaccionesresta las cargas nodales equivalentes que caen sobre los apoyos (\(\mathbf{f}_R^{\text{ap}}\)). En el ejemplo demostrativo, calcula las reacciones sin ese término, con(K @ u)[gdl_restringidos]. ¿Qué valores obtienes? ¿Se cumple el equilibrio vertical? - Programación: Elimina el término de la flecha de empotramiento en el cálculo de
v. ¿Por qué la deformada sigue coincidiendo en los nudos pero no dentro de los tramos? - Programación: Cambia el apoyo del nudo 1 por un empotramiento (restringe también \(\theta_1\)). ¿Cómo cambian las reacciones y el momento sobre el apoyo central?
- Programación: Agrega una carga puntual \(P = 20\) kN en el centro del segundo tramo (además de \(w\)). Usa la tabla para ensamblar sus cargas nodales equivalentes y verifica el equilibrio vertical.
- Programación: Escribe una función
viga_continua(L_tramos, w, E, I)que resuelva una viga continua con cualquier número de tramos (apoyos simples en todos los nudos) y devuelva las rotaciones y las reacciones. Pruébala con 3 tramos. - Interpretación: En el gráfico de momento flector, ¿dónde se tracciona la fibra superior de la viga y dónde la inferior? ¿Dónde pondrías la armadura de refuerzo si fuera una viga de hormigón armado?