Capítulo 6
Los grados de libertad
Cada barra tiene ya su matriz de rigidez de , escrita en función de los desplazamientos de sus dos nodos. Para unirlas en una sola matriz de la armadura necesitamos un sistema de referencia común: una numeración de todos los desplazamientos posibles de la estructura, sus grados de libertad. En este capítulo los numeramos, los separamos en libres y restringidos según los apoyos y hacemos una primera revisión de la estabilidad. Por el camino, enfrentamos una diferencia incómoda entre la ingeniería y Python: nosotros contamos desde 1, y Python, desde 0.
6.1 Los grados de libertad de la armadura
En una armadura plana, cada nodo puede desplazarse en dos direcciones, e . Una armadura de nodos tiene, por lo tanto, grados de libertad. Los numeramos nodo por nodo, siempre en el mismo orden: primero y después . Así, el nodo tiene los grados de libertad
Cada grado de libertad es de uno de dos tipos (figura 6.1):
- Libre. El nodo puede desplazarse en esa dirección. El desplazamiento es una incógnita y la fuerza, la carga aplicada, es un dato.
- Restringido. Un apoyo impide el desplazamiento. El desplazamiento es un dato (nulo, salvo asentamientos) y la fuerza, la reacción, es una incógnita.
Grados de libertad del ejemplo A. El nodo 1 (articulado) tiene ambos restringidos; el nodo 2 (rodillo), solo el vertical.
Para cada barra necesitamos además saber a qué grados de libertad de la armadura corresponden sus cuatro grados de libertad locales: los dos de su nodo inicial y los dos de su nodo final. Esta lista, que algunos textos llaman vector de correspondencia (code numbers), es la que nos permitirá colocar cada matriz de en el lugar correcto de la matriz de la armadura en el capítulo 7.
6.2 Decisiones con if
Para clasificar un grado de libertad debemos preguntar si el nodo tiene un
apoyo en esa dirección y actuar según la respuesta. Las preguntas se escriben
con comparaciones (comparisons): > y <, >= y <=,
== (igual a, con dos signos) y != (distinto de). Su resultado es un
booleano:
area = barras[1]["area"]
print(area > 0.001, len(barras) == 3, len(nodos) != 3)
True True False
La instrucción if ejecuta un bloque solo si la condición es verdadera,
y else, el bloque alternativo. Como en los bucles y las funciones, los
bloques van sangrados debajo de una línea que termina en dos puntos:
apoyo = apoyos[2]
if apoyo["x"]:
print("El nodo 2 no puede moverse en x")
else:
print("El nodo 2 puede moverse en x")
El nodo 2 puede moverse en x
Cuando hay más de dos casos, elif (contracción de else if)
agrega condiciones intermedias. Lo usaremos en el apartado 6.6.
6.3 La numeración de los grados de libertad
La ecuación clave se traduce en una función de una línea. Una función puede devolver varios valores separados por comas, y quien la llama los recibe en varias variables:
def gdl_del_nodo(nodo):
"""Grados de libertad (x, y) del nodo, desde 1."""
return 2 * nodo - 1, 2 * nodo
gdl_x, gdl_y = gdl_del_nodo(3)
print(f"Nodo 3: x → {gdl_x}, y → {gdl_y}")
Nodo 3: x → 5, y → 6
Con ella obtenemos el vector de correspondencia de una barra: los grados de libertad de su nodo inicial seguidos de los de su nodo final, en el mismo orden que en la figura 5.1.
def gdl_de_barra(barra):
"""Grados de libertad de los extremos de una barra."""
xi, yi = gdl_del_nodo(barra["nodo_inicial"])
xj, yj = gdl_del_nodo(barra["nodo_final"])
return [xi, yi, xj, yj]
for numero, barra in barras.items():
print(f"Barra {numero}: {gdl_de_barra(barra)}")
Barra 1: [1, 2, 3, 4] Barra 2: [3, 4, 5, 6] Barra 3: [1, 2, 5, 6]
Verificación. La barra 2 va del nodo 2 al nodo 3, cuyos grados de libertad son y , como se ve en la figura 6.1.
6.4 Grados de libertad libres y restringidos
Para clasificar, recorremos los nodos y preguntamos, en cada dirección, si
hay un apoyo. Un nodo sin apoyo no aparece en el diccionario apoyos:
el método get, que vimos en el capítulo 3, nos
permite tratarlo como un nodo «sin restricciones». Cada grado de
libertad se agrega con append a la lista que le corresponde:
def clasificar_gdl(nodos, apoyos):
"""Grados de libertad libres y restringidos."""
libres = []
restringidos = []
sin_apoyo = {"x": False, "y": False}
for nodo in nodos:
gdl_x, gdl_y = gdl_del_nodo(nodo)
apoyo = apoyos.get(nodo, sin_apoyo)
if apoyo["x"]:
restringidos.append(gdl_x)
else:
libres.append(gdl_x)
if apoyo["y"]:
restringidos.append(gdl_y)
else:
libres.append(gdl_y)
return libres, restringidos
libres, restringidos = clasificar_gdl(nodos, apoyos)
print(f"Libres: {libres}")
print(f"Restringidos: {restringidos}")
Libres: [3, 5, 6] Restringidos: [1, 2, 4]
Verificación. El nodo 1 aporta sus dos grados de libertad, 1 y 2, a los restringidos, y el rodillo del nodo 2, el vertical (4). Los libres son el horizontal del nodo 2 y los dos del nodo 3. La suma, , da todos los grados de libertad.
6.5 De la numeración desde 1 a los índices de Python
En el capítulo 3 vimos que Python cuenta las posiciones desde cero. En los próximos capítulos guardaremos fuerzas, desplazamientos y rigideces en arreglos de NumPy, cuya primera posición es la 0: el grado de libertad 1 estará en la posición 0, el 2 en la posición 1, y así sucesivamente.
Podríamos restar 1 cada vez que accedemos a un arreglo, pero sería peligroso: bastaría con olvidarlo una vez para que el programa use el grado de libertad equivocado, sin dar ningún error. Por eso concentramos la traducción en una sola función, que convierte una lista de grados de libertad en la lista de índices correspondiente:
def indices(gdl):
"""Traduce grados de libertad (desde 1) a índices
de NumPy (desde 0). Es el único lugar del libro donde
se hace esta traducción."""
resultado = []
for g in gdl:
resultado.append(g - 1)
return resultado
NumPy permite además seleccionar varios elementos de un arreglo a la vez, indicando la lista de sus índices entre corchetes. Por ejemplo, los valores que ocupan los grados de libertad libres:
# Un valor por cada grado de libertad del ejemplo A
valores = np.array([10.0, 20.0, 30.0, 40.0, 50.0, 60.0])
print(indices(libres))
valores[indices(libres)]
[2, 4, 5] array([30., 50., 60.])
Los grados de libertad libres 3, 5 y 6 ocupan las posiciones 2, 4 y 5, y seleccionan los valores 30, 50 y 60. Este mecanismo es la base del ensamblaje y de la partición de los próximos capítulos.
6.6 Una revisión previa de la estabilidad
Una armadura de barras y reacciones tiene fuerzas desconocidas, y el equilibrio de sus nodos aporta ecuaciones. La diferencia es el grado de indeterminación (degree of indeterminacy):
Si , faltan barras o apoyos y la armadura es inestable; si , es estáticamente determinada (isostática); si , es hiperestática de grado . Como cada grado de libertad restringido corresponde a una reacción, es la cantidad de grados de libertad restringidos:
def indeterminacion(nodos, barras, restringidos):
"""b + r - 2n: incógnitas menos ecuaciones."""
b, r, n = len(barras), len(restringidos), len(nodos)
return b + r - 2 * n
Para interpretar el resultado usamos if, elif y else:
grado = indeterminacion(nodos, barras, restringidos)
if grado < 0:
print(f"Inestable: faltan {-grado} barras o apoyos")
elif grado == 0:
print("Estáticamente determinada (isostática)")
else:
print(f"Hiperestática de grado {grado}")
Estáticamente determinada (isostática)
Problema resuelto 6.1 · Los grados de libertad del ejemplo B
Obtener los vectores de correspondencia de las barras del ejemplo B (figura 3.2), clasificar sus grados de libertad y calcular su grado de indeterminación.
Solución
Las funciones del capítulo sirven sin cambios para cualquier armadura:
for numero, barra in barras_b.items():
print(f"Barra {numero}: {gdl_de_barra(barra)}")
libres_b, restringidos_b = clasificar_gdl(
nodos_b, apoyos_b)
print(f"Libres: {libres_b}")
print(f"Restringidos: {restringidos_b}")
grado_b = indeterminacion(nodos_b, barras_b,
restringidos_b)
print(f"Grado de indeterminación: {grado_b}")
Barra 1: [1, 2, 3, 4] Barra 2: [3, 4, 7, 8] Barra 3: [5, 6, 7, 8] Barra 4: [1, 2, 5, 6] Barra 5: [1, 2, 7, 8] Barra 6: [3, 4, 5, 6] Libres: [3, 5, 6, 7, 8] Restringidos: [1, 2, 4] Grado de indeterminación: 1
Verificación. El ejemplo B tiene 4 nodos y 8 grados de libertad: 3 restringidos (el apoyo articulado del nodo 1 y el rodillo del nodo 2) y 5 libres. Con 6 barras, : una barra más de las necesarias, la segunda diagonal. Por eso el método de los nudos no basta para resolverlo, y el método de rigidez sí.
Repaso y resumen del capítulo
- Una armadura plana de nodos tiene grados de libertad; el nodo tiene los grados de libertad () y ().
- En un grado de libertad libre, el desplazamiento es la incógnita; en uno restringido, la incógnita es la reacción.
- El vector de correspondencia de una barra son los grados de libertad de sus dos nodos, en el orden .
if,elifyelseejecutan un bloque u otro según una condición; las comparaciones usan==,!=,<,>,<=y>=.- La función
indiceses el único lugar donde la numeración desde 1 se traduce a los índices de NumPy, que empiezan en 0. - El grado de indeterminación clasifica la armadura; es necesario, pero no suficiente, para la estabilidad.
Ejercicios
Ejercicio 6.1
Obtener el vector de correspondencia de la barra 6 del ejemplo B y comprobarlo en la figura 3.2.
Ver la solución
# La barra 6 va del nodo 2 al nodo 3
gdl_de_barra(barras_b[6])
[3, 4, 5, 6]
Los grados de libertad del nodo 2 son 3 y 4, y los del nodo 3, 5 y 6.
Ejercicio 6.2
Si el rodillo del nodo 2 del ejemplo A se reemplaza por un apoyo articulado, ¿cuáles son los grados de libertad libres y restringidos? Calcular el nuevo grado de indeterminación.
Ver la solución
apoyos_articulados = {
1: {"x": True, "y": True},
2: {"x": True, "y": True},
}
libres_2, restringidos_2 = clasificar_gdl(
nodos, apoyos_articulados)
print(f"Libres: {libres_2}")
print(f"Restringidos: {restringidos_2}")
grado = indeterminacion(nodos, barras, restringidos_2)
print(f"Grado de indeterminación: {grado}")
Libres: [5, 6] Restringidos: [1, 2, 3, 4] Grado de indeterminación: 1
Con dos apoyos articulados hay 4 reacciones, y : la armadura pasa a ser hiperestática. Solo el nodo 3 puede desplazarse.
Ejercicio 6.3
Calcular el grado de indeterminación del ejemplo A sin su barra 1 e interpretar el resultado. ¿Qué movimiento puede hacer la armadura?
Ver la solución
barras_sin_1 = {2: barras[2], 3: barras[3]}
grado = indeterminacion(nodos, barras_sin_1, restringidos)
print(f"Grado de indeterminación: {grado}")
Grado de indeterminación: -1
Con la armadura es inestable: sin la barra 1, nada impide que el rodillo del nodo 2 se deslice horizontalmente y que las barras 2 y 3 giren como un mecanismo.
Ejercicio 6.4
Construir la correspondencia entre la numeración natural del ejemplo A y la
de los textos que renumeran primero los grados de libertad libres. La función
enumerate(lista, 1) recorre una lista y entrega, además de cada elemento,
su posición contando desde 1.
Ver la solución
nueva_numeracion = libres + restringidos
for nuevo, original in enumerate(nueva_numeracion, 1):
print(f"GDL {original} → {nuevo}")
GDL 3 → 1 GDL 5 → 2 GDL 6 → 3 GDL 1 → 4 GDL 2 → 5 GDL 4 → 6
Los grados de libertad libres 3, 5 y 6 pasan a ser los primeros (1, 2 y 3), y los restringidos 1, 2 y 4, los últimos (4, 5 y 6).