Qué hice, qué aprendí y por qué importa, contado para que lo entienda cualquiera. Proyecto final de Ondas gravitacionales e investigación asistida por IA (UBA, 2026).
Esta página es un diario de trabajo. No hace falta saber física para leerla: cada vez que aparece una palabra técnica, está explicada ahí mismo o en el glosario del final. Quien quiera las ecuaciones las encuentra en las páginas técnicas, enlazadas en cada sección.
Las ondas gravitacionales son arrugas en el propio espacio que viajan a la velocidad de la luz. Las producen fenómenos muy violentos, como el choque de dos agujeros negros, y desde 2015 se detectan con instrumentos como LIGO. Algunas de esas ondas podrían venir de los primeros instantes del universo, y traer información de una época de la que no nos llega ninguna luz.
Una de esas épocas es el recalentamiento (en inglés, preheating). Según la idea más aceptada, el universo recién nacido pasó por una inflación: una expansión muy rápida impulsada por un campo llamado inflatón. Cuando la inflación terminó, el inflatón quedó oscilando, y en esas oscilaciones le fue pasando su energía a todas las demás partículas. Esa transferencia fue violenta y desordenada, y un proceso así produce ondas gravitacionales.
Casi todos los estudios de este proceso suponen que el inflatón sólo le pasa energía a campos "simples" (los campos escalares, que en cada punto tienen un solo número). Pero el inflatón también podría estar conectado con campos de gauge, que son los que transmiten fuerzas: el campo electromagnético es el ejemplo más conocido. Un campo de gauge se comporta distinto: tiene dirección, forma líneas de campo y puede armar tubos de flujo.
La pregunta del proyecto es: si al recalentamiento se le agrega un campo de gauge, ¿cuánto cambia la "huella" de ondas gravitacionales que deja? Esa huella es el espectro: cuánta onda hay en cada frecuencia. Cambiar el campo de gauge podría mover el pico del espectro, cambiar su altura o dejar marcas propias que un modelo sin campos de gauge no tiene.
Este proceso es demasiado complicado para resolverlo con lápiz y papel: todo interactúa con todo al mismo tiempo. Lo que se hace es simularlo en una computadora. Se toma un cubo de espacio, se lo divide en una grilla de puntos (una red o lattice) y en cada punto se guarda cuánto vale cada campo. Después se avanza en el tiempo de a pasitos, aplicando las leyes de la física en cada punto.
El programa que uso se llama CosmoLattice. Es público, y lo escribió un grupo de físicos que se especializa en esto. Su gran ventaja es que simula campos de gauge respetando exactamente sus reglas, no de forma aproximada. Trae tres modelos armados que sirven justo para la comparación del proyecto:
| Modelo | Qué tiene | Para qué lo uso |
|---|---|---|
lphi4 | El inflatón y otro campo escalar. Sin campos de gauge. | El control: la versión "sin" contra la que comparar. |
lphi4U1 | El inflatón con carga, conectado a un campo de gauge parecido al electromagnético. | El caso con un campo de gauge. |
lphi4SU2U1 | El inflatón conectado a dos campos de gauge, parecidos a los de la fuerza electrodébil. | Un caso de gauge más rico, si el tiempo alcanza. |
qué ecuaciones resuelve CosmoLattice y cómo pone los campos de gauge en la red está en ¿Qué es CosmoLattice?.
Antes de correr la primera simulación "de verdad" (sección 3.1), primero me aseguré de entender exactamente qué hace el programa, porque si no, cualquier resultado que saliera podría estar mal interpretado. Fue en este orden:
verificar_variables_de_programa.py,
que rehace las cuentas del artículo y las compara con lo que hace el código de
CosmoLattice. Hoy hace 21 comprobaciones y todas dan bien. Así, si mañana
alguien cambia algo, se puede volver a correr y ver si sigue todo en orden.provenance/, con qué programa lo
calculó y qué decisiones hubo que tomar. La idea es que cualquiera pueda
rastrearlo sin tener que preguntarme.Corrí el modelo de control, lphi4, con los parámetros acordados pero en una caja
más chica (128 puntos por lado en lugar de 256), para probar que todo funciona antes de gastar
tiempo en la corrida grande. Tardó 1 hora y 17 minutos en esta computadora (usando sus 8 núcleos) y la
energía se conservó muy bien (el error nunca pasó de 2 en 10 000). Los parámetros están en
code/lphi4_piloto_N128.in y las salidas en
data/lphi4_piloto_N128/.
Para mirar los resultados armé un cuaderno interactivo,
code/analisis_corridas.py (se abre con
marimo edit code/analisis_corridas.py). Muestra cómo se expande el universo, cómo
oscila el inflatón, en qué escalas crece el campo hijo y cuándo aparecen las ondas
gravitacionales. Lo que se ve:
Comparación con lo publicado. Dufaux y colaboradores (2007) simularon este mismo modelo. Al traducir las diferencias (usaron un λ nueve veces menor), nuestro resultado coincide con el de ellos en la altura del pico (3,8×10⁻¹¹ contra ∼3×10⁻¹¹), en su frecuencia (a 20 %), en la forma de la cola de frecuencias bajas y en los momentos en que pasa cada cosa. La única diferencia está en las escalas más chicas: nuestra caja no llega a resolverlas, y ahí el espectro sigue creciendo al final. Para eso hace falta la caja de 256 puntos.
El análisis completo, con todas las figuras, está en El piloto del control.
Cuánto van a tardar los modelos con gauge. Hice pruebas cortas de los tres
modelos con la caja de 128 puntos (data/pruebas_costo_N128/). El control tarda
unos 80 minutos. El de U(1), unas 8 horas y media. El de SU(2)×U(1), unos 3 días y medio: sus
campos son matrices y cada paso cuesta diez veces más. Los tres entran en la memoria, de a uno
por vez. Además apareció una restricción del programa: con campos de gauge y ondas
gravitacionales no se puede usar el integrador del piloto (LF) y hay que usar otro (VV2). Por
eso conviene repetir el control con VV2, para que los tres usen el mismo. La ley de Gauss se
cumple desde el primer instante, con un error de una parte en cien mil millones.
Un integrador es la receta que usa el programa para avanzar el universo de un instante al siguiente. El piloto usó uno llamado LF (leapfrog, "salto de rana"), que calcula los campos y sus velocidades en instantes alternados, medio paso corridos. Los modelos con gauge no pueden usarlo junto con las ondas gravitacionales. La fuente de las ondas necesita el campo eléctrico y el magnético en el mismo instante, y LF los tiene medio paso corridos. Por eso los modelos con gauge van a usar VV2 (velocity Verlet), que sí los sincroniza.
Para que la comparación entre modelos sea justa, los tres tienen que usar el mismo
integrador. Así que repetí el control con VV2: mismos parámetros, misma semilla (el mismo
"ruido" inicial exacto), solo cambia el integrador. Entrada:
code/lphi4_control_N128_VV2.in,
salidas en data/lphi4_control_N128_VV2/ y figuras en
figures/lphi4_control_N128_VV2/ (hechas con el mismo cuaderno). Tardó 1 hora y
32 minutos (el piloto, 1 hora y 17) y usó la misma memoria, 318 MB.
| qué se mide | piloto (LF) | control (VV2) | diferencia |
|---|---|---|---|
| amplitud real del inflatón, A | 1,138 | 1,138 | ninguna |
| velocidad de crecimiento del campo hijo, μ | 0,2002 | 0,2001 | 0,02 % |
| velocidad de crecimiento de las ondas | 0,757 | 0,757 | ninguna |
| los gradientes llegan al 1 % (τ) | 83,9 | 83,9 | ninguna |
| 50 % / 90 % de las ondas hechas (τ) | 130 / 203 | 130 / 201 | < 1 % |
| energía final en ondas, ρ_GW/ρ | 9,87×10⁻⁶ | 9,92×10⁻⁶ | 0,4 % |
| pico del espectro hoy, h²Ω (g★ = 100) | 6,8×10⁻¹¹ a 1,1×10⁸ Hz | 6,9×10⁻¹¹ a 1,1×10⁸ Hz | 2 % en altura, nada en frecuencia |
| pico de (Ω_gw)_p en x ≈ 150 | 2,83×10⁻⁶ | 2,70×10⁻⁶ | 5 % |
| crecimiento del pico entre x ≈ 170 y el final | 22 % | 28 % | 6 puntos |
| error máximo de la energía (Friedmann) | 2,1×10⁻⁴ | 7,7×10⁻⁴ | ver abajo |
Lo que se ve:
Conclusión: el cambio de integrador no afecta los resultados. El control con VV2 pasa a ser la referencia con la que se van a comparar los modelos con gauge, que usan el mismo integrador. El piloto con LF queda como la validación contra Dufaux: da lo mismo.
Los modelos con gauge son caros: con 128 puntos por lado, U(1) tarda unas 8 horas y media y
SU(2)×U(1) unos 3 días y medio. El costo crece como N³, así que con 64 puntos por lado serían
8 veces menos. Antes de hacerlo hay que saber cuánto cambian los resultados. Lo probé con el
control, que es barato: repetí la corrida de la sección 3.2 cambiando solo N (32, 48, 64 y 96),
con la misma caja y la misma semilla. Además hice otra con 64 puntos y la caja a la mitad de
tamaño (kIR = 0,5). Así los puntos quedan igual de juntos que con 128 y la red resuelve las
mismas longitudes de onda cortas. Entradas en code/lphi4_N*_VV2.in, salidas en
data/convergencia_N/, figuras en figures/convergencia_N/, y el script
de la comparación es code/convergencia_N.py.
| corrida | longitud de onda más corta que resuelve (k máximo) | energía final en ondas / la de N = 128 | altura del máximo del espectro / la de N = 128 | tiempo |
|---|---|---|---|---|
| N = 32 | 7 | ×6,0 | ×19 | 1,2 min |
| N = 48 | 10,5 | ×2,5 | ×8,5 | 4,5 min |
| N = 64 | 13,8 | ×1,75 | ×5,1 | 10,5 min |
| N = 96 | 20,8 | ×1,21 | ×2,0 | 37,5 min |
| N = 128 (referencia) | 27,8 | 1 | 1 | 92 min |
| N = 64, caja a la mitad | 27,5 | ×1,003 | ×1,02 | 10,8 min |
| N = 128, caja a la mitad | 55,5 | ×0,84 | ×0,98 | 79 min |
Lo que se ve:
Conclusión: achicar la caja sirve para abaratar las corridas; bajar la resolución con la misma caja, no.
¿Y N = 128, está convergido? Para saberlo corrí también 128 puntos con la caja a la mitad (k máximo ≈ 55, el doble que la referencia; 79 minutos). La respuesta es que no del todo:
Eso explica por qué N = 64 con la caja a la mitad coincidía tan bien con N = 128: las dos llegan al mismo k máximo y tienen el mismo error en el borde. Para comparar modelos, la parte confiable del espectro es el pico y lo que está a su izquierda (k ≲ 4). La meseta a la derecha del pico depende de la resolución.
¿La caja a la mitad alcanza para los campos de gauge? Revisé en qué longitudes
de onda resuena cada modelo (code/analisis_parametros.py::banda_principal, con la
amplitud real del inflatón A = 1,138). En las unidades del control:
Con eso se decidió (24 de septiembre de 2026) correr U(1) con 64 puntos y la caja a la mitad:
code/lphi4U1_N64_kIR0.5_VV2.in.
La primera corrida de U(1) (64 puntos, caja a la mitad, 1 hora y 16 minutos) salió numéricamente bien: la ley de Gauss se cumplió todo el tiempo con un error menor a una parte en mil millones. Pero la resonancia del campo gauge llegó mucho más tarde que la del campo hijo en el control: al 1 % de la energía en τ ≈ 105 en lugar de 68.
La causa es cómo arranca el campo gauge en CosmoLattice. Un campo gauge, como
el electromagnético, tiene dos partes. La parte longitudinal la fijan las cargas, a través
de la ley de Gauss. La parte transversal son las ondas, como la luz. Es la que resuena con
el inflatón y la que produce ondas gravitacionales. CosmoLattice arranca el campo gauge solo con la
parte longitudinal, y la transversal en cero exacto (así lo dicen el código,
u1initializer.h, y el paper del código, arXiv:2102.01031, ecs. 97–102). La parte
transversal solo se enciende después, alimentada por combinaciones de segundo orden de las
fluctuaciones del inflatón, que son muchísimo más chicas. El campo hijo del control, en cambio,
arranca con sus fluctuaciones cuánticas de vacío. La comparación no estaba en igualdad de
condiciones.
Lo que hice: le agregué a CosmoLattice una condición inicial nueva,
ICtype_U1 = RandomWithMatterTransverseVacuum. Hace lo mismo que la original (el
inflatón arranca con el mismo ruido exacto y la parte longitudinal se fija con la ley de Gauss) y
además le da a la parte transversal sus fluctuaciones de vacío, con el mismo criterio que usa el
programa para el campo hijo. El cambio está en code/parches/u1_vacio_transversal.patch,
explicado en code/parches/LEEME.md. Lo probé antes de usarlo: la ley de Gauss sigue
en una parte en cien mil millones, el ruido del inflatón es idéntico, y la energía que se agrega es
la de dos polarizaciones con la energía de vacío del campo hijo.
Midiendo bien el crecimiento. Para ver qué crece hay que mirar el campo magnético, que es puramente transversal. El eléctrico mezcla la parte longitudinal, que no resuena. Mirando el eléctrico me pareció que la resonancia gauge "se frenaba" a mitad de camino. Era un error de lectura: en las dos corridas los modos transversales crecen al ritmo que predice la teoría (Floquet con q = 120: μ ≈ 0,20–0,23 en k de 0,5 a 2), igual que el campo hijo. Lo único que cambia es desde qué tamaño arrancan.
| qué se mide (unidades del control) | control (campo hijo χ) | U(1), como arranca CosmoLattice | U(1), con vacío transversal |
|---|---|---|---|
| el campo hijo/gauge llega al 1 % de la energía (τ) | 68 | 105 | 68 |
| ... al 10 % (τ) | 89 | 148 | 86 |
| fracción máxima de la energía | 49 % | 40 % | 41 % |
| energía final en ondas, ρ_GW/ρ | 9,9×10⁻⁶ | 7,1×10⁻⁶ (−29 %) | 1,5×10⁻⁵ (+53 %) |
| espectro de ondas en k de 0,5 a 2,5 (parte confiable), respecto del control | 1 | 0,3 veces | 0,6–0,7 veces |
| espectro de ondas en k de 3 a 4, respecto del control | 1 | 0,4–0,5 veces | 0,85–1,1 veces |
Lo que se ve:
Cuidado: esto es con una sola semilla y en la red chica. Faltan otras semillas para saber cuánto varía el espectro por puro azar (entre dos integradores, sección 3.2, la fase turbulenta variaba 2–5 %). Actualización del 27 de septiembre: con tres semillas el cociente es 0,56–0,79 (medio 0,68); ver sección 3.6.
Datos en data/lphi4U1_N64_kIR0.5_VV2/ y
data/lphi4U1_vacioT_N64_kIR0.5_VV2/. Figuras en
figures/comparacion_modelos/ (hechas con code/comparar_modelos.py) y el
crecimiento por modo en figures/lphi4U1_*/mu_por_modo_vs_control.png (con
code/crecimiento_por_modo_U1.py).
Antes de largar la corrida larga de SU(2)×U(1) (~11 horas) revisé cómo arranca el campo SU(2).
Tiene el mismo problema que tenía U(1) (sección 3.4): CosmoLattice lo arranca con
el campo en cero exacto y solo la parte longitudinal que fija la ley de Gauss
(su2initializer.h). La parte transversal, la que resuena y produce ondas
gravitacionales, arranca en cero. Así que hacía falta un cambio parecido al de U(1).
Cómo lo armé. Agregué la opción ICtype_SU2 = RandomWithMatterTransverseVacuum
(code/parches/su2_vacio_transversal.patch, explicado en
code/parches/LEEME.md). Para eso tuve que averiguar cómo guarda el programa el campo
SU(2). No guarda el campo directamente: guarda "links", unas matrices que conectan puntos vecinos de
la red. Leyendo cómo calcula la energía y cómo avanza en el tiempo, el campo B entra como
g·dx·B/2 en el link y el campo eléctrico se guarda dividido por 2. Hubo un detalle más: el programa
elige los números al azar a partir del nombre de cada campo auxiliar. Si usaba un solo
auxiliar para todo, los tres "colores" de SU(2) (y el U(1)) habrían recibido exactamente el mismo
ruido.
La primera versión estaba mal, y la prueba lo mostró. Hice dos corridas cortas con la misma semilla, una con el arranque de CosmoLattice y otra con el vacío nuevo, y verifiqué:
Pero al dejar evolucionar un rato, el vacío no se quedaba quieto como debería: la energía iba y venía entre la parte eléctrica y la magnética, y la magnética del U(1) llegó a multiplicarse por 3,6. Eso pasa cuando a un campo se le da el vacío de una masa que no es la que realmente tiene.
La causa: los dos campos gauge se mezclan. En este modelo, el inflatón tiene carga de los dos campos a la vez (U(1) y SU(2)). Eso hace que una combinación del campo U(1) con uno de los colores de SU(2) se comporte como un campo aparte, con su propia masa. Es lo mismo que pasa en el Modelo Estándar de partículas, donde de la mezcla salen el fotón y la partícula Z. Con nuestros parámetros (q_A = q_B = 60) quedan cuatro campos independientes:
| campo | qué combinación es | masa² (unidades del programa) | equivale a |
|---|---|---|---|
| "fotón" | U(1) + color 1, a medias | 0 | no resuena |
| "Z" | U(1) − color 1, a medias | 240 | q = 120, como el campo hijo del control |
| dos "W" | colores 2 y 3 | 120 | q = 60 |
Mi primera versión le daba masa 120 al U(1) y a cada color por separado, sin ver la mezcla. La versión final no escribe las masas a mano: al arrancar, el programa las calcula con las mismas operaciones que usa para mover los campos, verifica que la cuenta sea consistente, separa los cuatro campos independientes y le da a cada uno su vacío con su masa. El resultado fue justo la tabla de arriba.
| cuánto cambia la parte agregada en el primer instante (t de 0 a 0,7) | energía eléctrica | energía magnética |
|---|---|---|
referencia: U(1) solo (lphi4U1, ya validado) | 1,00–1,18 | 0,87–1,00 |
| primera versión, sin mezcla: U(1) | 0,73–1,40 | 1,0–3,6 |
| versión final: U(1) | 1,00–1,16 | 0,87–1,00 |
| versión final: SU(2) | 1,00–1,17 | 0,86–1,00 |
Con la mezcla bien tratada, los dos campos se comportan como la referencia.
Dos cosas a tener en cuenta para el análisis:
Lo que esto dice del modelo: en SU(2)×U(1) no son "dos campos gauge con q = 60 cada uno". Hay uno que resuena como el campo hijo del control (la Z), dos que resuenan más débil (las W) y uno que no resuena (el fotón). Va a ser importante para interpretar las ondas gravitacionales.
Datos de las pruebas en data/prueba_su2_vacioT/ (con su LEEME.md),
verificación con code/validar_vacio_su2.py. La corrida larga usa
code/lphi4SU2U1_vacioT_N64_kIR0.5_VV2.in y guarda en
data/lphi4SU2U1_vacioT_N64_kIR0.5_VV2/.
La "semilla" es el número con el que el programa elige el ruido inicial (las fluctuaciones cuánticas). Cambiarla es como repetir el experimento con otra tirada de dados: la física es la misma, pero los detalles cambian. En la sección 3.4 el espectro de ondas de U(1) salió 0,6–0,7 veces el del control, pero con una sola semilla. Corrí dos semillas más (2345 y 3456) de los dos modelos, con todo lo demás igual.
| semilla | resonancia al 1 % (τ), control / U(1) | espectro U(1) / control en k = 0,5–2,5 | energía total en ondas, U(1) / control |
|---|---|---|---|
| 1234 | 68,3 / 68,1 | 0,61–0,69 (medio 0,66) | 1,53 |
| 2345 | 68,4 / 68,1 | 0,47–0,89 (medio 0,67) | 1,65 |
| 3456 | 68,4 / 68,1 | 0,56–0,85 (medio 0,72) | 1,64 |
| con los promedios de las tres | 0,56–0,79 (medio 0,68) |
Lo que se ve:
Datos en data/semillas/ (con su LEEME.md), análisis con
code/semillas_U1.py, figura en figures/semillas/U1_vs_control_semillas.png.
La corrida larga arrancó a las 23:18 del 27 y terminó bien a las 08:40 del 28 (9 horas y 22 minutos con los 8 núcleos, 249 MB de memoria). La calidad numérica fue buena: la ley de Gauss de SU(2) tuvo un error máximo de una parte en un millón (y al final una en cien mil millones), la de U(1) una en mil millones, y la ecuación de Friedmann (la cuenta de energía del universo) cerró con un error máximo de 0,04 %. Es una sola semilla (1234), la misma que las primeras del control y de U(1).
Cómo separé los campos. El programa guarda la energía de U(1) y la de SU(2) (los tres colores juntos), no la de cada campo de la tabla de la sección 3.5. Pero se pueden despejar: como el fotón y la Z son mitad U(1) y mitad color 1, la energía de "Z + fotón" es el doble de la del U(1), y la de las dos W es la de SU(2) menos la de U(1). Esto vale salvo un término cruzado entre la Z y el fotón, que medí: es ~0,1 % de la energía del U(1), así que no cambia nada. Solo en τ ≈ 75–110 la resta para las W no es confiable, porque ahí las W todavía son muy chicas comparadas con ese término.
| qué se mide (unidades del control) | control (χ) | U(1) (A) | SU(2)×U(1), todos | ... Z + fotón | ... las dos W |
|---|---|---|---|---|---|
| llega al 1 % de la energía (τ) | 68,3 | 68,1 | 68,1 | 68,1 | 117 |
| llega al 10 % (τ) | 88,6 | 86,0 | 85,7 | 85,7 | 130 |
| fracción de la energía al final | 48 % | 40 % | 64 % | 31 % | 32 % |
| ritmo de crecimiento en la fase lineal (μ de la energía, τ 30–70) | 0,16 | 0,16 | 0,16 | 0,07 | |
| ritmo de crecimiento tardío (τ 100–125) | 0,02 | 0,04 | 0,03 | 0,18 |
Lo que se ve:
Las ondas gravitacionales (figura
figures/lphi4SU2U1_vacioT_N64_kIR0.5_VV2/ondas_gravitacionales.png):
| k (unidades del control) | 0,5 | 1 | 1,5 | 2 | 2,5 | promedio |
|---|---|---|---|---|---|---|
| SU(2)×U(1) / control | 0,80 | 1,06 | 1,92 | 1,66 | 0,64 | 1,11 |
| SU(2)×U(1) / U(1) | 1,28 | 1,53 | 3,13 | 2,39 | 0,93 | 1,68 |
| U(1) / control (misma semilla) | 0,63 | 0,69 | 0,61 | 0,69 | 0,69 | 0,66 |
Cuidado: es una sola semilla. Las semillas de la sección 3.6 muestran que el espectro por punto varía hasta un tercio de una tirada a otra. Para afirmar el "más ondas cerca del pico" hacen falta más semillas de SU(2)×U(1) (~9 horas cada una).
Datos en data/lphi4SU2U1_vacioT_N64_kIR0.5_VV2/ (con su LEEME.md), análisis
con code/analisis_SU2U1.py y code/crecimiento_por_modo_U1.py, figuras en
figures/lphi4SU2U1_vacioT_N64_kIR0.5_VV2/.
Como no daba el tiempo para más semillas, hice cuatro análisis con las corridas que ya estaban,
para entender cómo produce ondas gravitacionales cada modelo y no solo cuántas. Todos usan
la semilla 1234 de los tres modelos. El programa guardó el espectro de ondas cada 5 unidades de
tiempo, así que se puede seguir cómo se arma. Código en code/produccion_gws.py, figuras en
figures/produccion_gws/, números en data/produccion_gws.json.
1. ¿Las ondas de SU(2)×U(1) vienen de las W? Las W se disparan tarde (τ ≈ 110–130, sección 3.7), así que parecían las candidatas naturales para explicar el pico más alto. Para averiguarlo miré qué parte de las ondas finales ya existía antes de ese disparo. Una aclaración para poder hacerlo: en estos modelos el universo se expande como si estuviera lleno de radiación, y las ondas también se diluyen como radiación. Por eso, una vez que la fuente se apaga, la cantidad dΩ_GW/d ln k ya no cambia, y comparar el espectro en dos instantes dice cuánto se produjo en el medio.
| qué parte de las ondas finales (k ≤ 4) ya existía | control | U(1) | SU(2)×U(1) |
|---|---|---|---|
| en τ = 100 (antes de que las W crezcan) | 3 % | 2 % | 25 % (33 % en k = 1,5–2) |
| en τ = 120 (las W recién llegan al 1 %) | 48 % | 35 % | 80 % |
| instante en que llega a la mitad de las ondas finales (τ) | 121 | 126 | 112 |
La respuesta es que no. SU(2)×U(1) produce sus ondas antes, no después. El pico
en k = 2 ya está formado en τ ≈ 85–100 (figura espectros_en_el_tiempo.png), y cuando las W
llegan al 10 % de la energía ya está el 80 % de las ondas. En τ = 100, SU(2)×U(1) tenía 10 veces las
ondas del control y 33 veces las de U(1). Al final esa ventaja se achica a 1,24 y 1,86 veces (en
k ≤ 2,5), porque el control y U(1) producen la mayor parte más tarde. El exceso cerca del pico viene del
período en que la resonancia de la Z empieza a saturar, no de las W. Qué lo causa exactamente no lo
sé. Hay dos candidatos: el fotón, que se empieza a llenar en ese momento (se ve en el término cruzado
de la sección 3.7), y las interacciones propias de SU(2). Separarlos requeriría guardar los campos
completos.
2. ¿Crecen las ondas como el cuadrado del campo? Las ondas las produce el "estiramiento" del campo (su tensión), que es cuadrático en el campo. Si el campo crece como eμτ, su energía crece como e2μτ y la energía en ondas como e4μτ: el doble de rápido que la del campo, en escala logarítmica. Medí las dos pendientes en la fase lineal (τ = 35–62):
| control | U(1) | SU(2)×U(1) | |
|---|---|---|---|
| μ del campo que resuena | 0,20 | 0,21 | 0,21 |
| pendiente de las ondas / pendiente de la energía del campo (se espera 2) | 1,88 | 1,78 | 1,76 |
Se cumple en los tres modelos, con un 10 % de diferencia que es razonable, porque la energía total del campo incluye modos que no resuenan. En la fase lineal los tres producen ondas por el mismo mecanismo. Cuidado: en esa fase el nivel de ondas de los modelos gauge está bastante por encima del control (en τ = 60, 30 veces en U(1) y 1000 en SU(2)×U(1)). Pero ahí pesan también las ondas que siembra el vacío de todos los campos, y los modelos gauge tienen más grados de libertad (el control, uno; SU(2)×U(1), ocho polarizaciones). Por eso no tomo esa diferencia como un resultado.
3. ¿Producen menos ondas porque reciben menos energía? La estimación estándar dice que la energía en ondas es proporcional al cuadrado de la fracción de energía que tiene el campo fuente, por un factor que depende de la escala típica de la fuente, (k de esa escala)⁻². Supuse que esa escala es la misma en los tres modelos. Es solo aproximado: la sección 3.9 muestra que SU(2)×U(1) tiene un pico en k = 2, mientras el control tiene una meseta de k = 2 a 4 y U(1) sube hasta el borde de lo confiable. Dividí las ondas en la parte confiable del espectro por el cuadrado de la fracción media de energía en el campo mientras se producen (τ = 70–150):
| respecto del control | ondas (k ≤ 2,5) | (fracción de energía)² | eficiencia |
|---|---|---|---|
| U(1) | 0,66 | 0,70 | 0,94 |
| SU(2)×U(1) | 1,24 | 0,94 | 1,31 |
U(1) produce menos ondas casi solo porque el campo gauge recibe menos energía (eficiencia 0,94, es decir, casi igual que el control). No hace falta invocar algo especial de los campos gauge. SU(2)×U(1), en cambio, produce un 30 % más de ondas de lo que su energía explicaría. Coincide con el punto 1: el pico se forma temprano y de forma más eficiente. Es una estimación de orden de magnitud y con una semilla, pero la diferencia entre 0,94 y 1,31 es más grande que la dispersión entre semillas del cociente de U(1) (0,66–0,72 de medio). Como la escala típica de la fuente no es exactamente la misma (ver arriba), estas eficiencias valen como tendencia y no como número preciso: si la escala del control está algo por encima de k = 2, la ventaja de SU(2)×U(1) sería algo menor.
4. El espectro de hoy. Con la misma cuenta que el piloto (sección 3.1: después de la simulación, el universo se expande como radiación hasta hoy, con g★ = 100), el máximo de la parte confiable (k ≤ 4) queda en la siguiente tabla. En el control es una meseta y en U(1) está en el borde de lo confiable (sección 3.9), así que la frecuencia del máximo solo es precisa en SU(2)×U(1).
| control | U(1) | SU(2)×U(1) | |
|---|---|---|---|
| frecuencia hoy | 6,4×10⁷ Hz | 1,3×10⁸ Hz | 6,4×10⁷ Hz |
| h²Ω_GW hoy | 6,6×10⁻¹¹ | 6,8×10⁻¹¹ | 1,1×10⁻¹⁰ |
Una unidad de k corresponde a 3,2×10⁷ Hz hoy en los tres modelos, como debe ser, porque es la misma
física. Las diferencias entre modelos son factores 0,7–1,9. Todo queda en la zona de ~10⁸ Hz, muy
lejos de las frecuencias de los detectores actuales, que miden de nanohertz a kilohertz. Esto es
propio del preheating a la escala de energía de λφ⁴: los campos gauge cambian la forma del espectro,
pero no lo acercan a algo observable hoy (figura espectro_hoy.png).
En resumen: en la fase lineal los tres modelos producen ondas de la misma manera. U(1) produce menos solo porque se lleva menos energía. SU(2)×U(1) produce más, y antes, en el período en que la resonancia satura; no por las W tardías. Todo esto es con una semilla por modelo.
La pregunta del proyecto es cuánto de la forma del espectro de ondas se debe al campo gauge:
posición y altura del pico, y pendientes a cada lado. Hasta acá había comparado alturas. Medí la forma en
las siete corridas que hay: control y U(1) con tres semillas cada uno, y SU(2)×U(1) con una. Ajusté una
recta en escala logarítmica (dΩ_GW/d ln k ∝ kⁿ) a cada lado del máximo, solo en la parte confiable
(k ≤ 4): del lado de las ondas largas (IR) con k = 0,5–1,5, y del lado de las cortas (UV) con k = 2–4.
Código en code/pendientes_espectro.py, figura en figures/pendientes_espectro.png.
| parte confiable (k ≤ 4) | control (3 semillas) | U(1) (3 semillas) | SU(2)×U(1) (1 semilla) |
|---|---|---|---|
| forma | sube y queda en una meseta de k = 2 a 4 | sube hasta el borde de lo confiable | pico en k = 2 |
| pendiente IR (k = 0,5–1,5) | 1,14 ± 0,34 | 0,85 ± 0,17 | 1,51 |
| pendiente UV cercana (k = 2–4) | 0,09 ± 0,12 | 0,55 ± 0,12 | −1,78 |
| altura máxima (dΩ_GW/d ln k) | 3,9–4,0×10⁻⁶ | 4,1–4,3×10⁻⁶ (en k = 4) | 6,6×10⁻⁶ (en k = 2) |
Lo que se ve:
La respuesta a la pregunta del proyecto, con la red usada (N = 64, parte confiable k ≤ 4):
Anoto todo lo que salió mal o me hizo perder tiempo, para no repetirlo.
Problemas de física y de medición
Problemas con la computadora y las herramientas
pkill -f con un texto que también aparecía en el propio comando, y lo cortó. Parecido: varias
esperas del tipo "esperar mientras el proceso exista" (pgrep -f) nunca terminaban, porque
se encontraban a sí mismas. Hubo que cerrarlas a mano. La solución es esperar por el número de proceso
o por un archivo, no por el texto del comando.provenance/numbers.json lo reescribí con otra sangría, y git lo mostraba como mil líneas
borradas. Lo volví al formato original antes de commitear.date: el script de avance no entendía la zona horaria
("-03") y hubo que ajustarlo.agentPushNotifEnabled). Además, el sistema no manda la notificación si la sesión se usó
hace poco, así que no se podía probar en el momento.code/generar_pdf.py.En este problema aparecen números enormes y diminutos a la vez. Los campos valen alrededor de \(10^{18}\) (un uno con dieciocho ceros) y los acoplamientos alrededor de \(10^{-14}\). Una computadora pierde precisión con números así. La solución de CosmoLattice es cambiar de unidades: elige una unidad de campo y una de tiempo "cómodas" para el problema, de modo que casi todo quede cerca de 1. Son las variables de programa.
dt = 0.01 no significa "una centésima de segundo" sino
"una centésima de la unidad de tiempo del programa". Para interpretar bien
cualquier resultado hay que saber traducir de vuelta a unidades físicas.
Los campos de gauge tienen una regla que se debe cumplir en cada instante y en cada punto: la ley de Gauss. Dice que las líneas de campo eléctrico sólo pueden nacer o terminar donde hay carga. No es algo que "pase con el tiempo": es una condición que tiene que valer siempre.
Por eso importa tanto cómo arranca la simulación. Verifiqué que CosmoLattice prepara el estado inicial de forma que la ley de Gauss se cumpla exactamente, no casi. Eso vuelve útil a la ley de Gauss como alarma durante la simulación: si en algún momento deja de cumplirse, el problema está en el cálculo, no en el punto de partida.
Un campo con carga eléctrica se describe con un número complejo, es decir, con dos números: una "parte real" y una "parte imaginaria". Hay dos maneras habituales de escribirlo, y difieren en un factor \(\sqrt2\) (aproximadamente 1,41). Tenía la sospecha de que el código mezclaba las dos convenciones.
Leí cómo el código calcula la energía de ese campo, cómo lo hace evolucionar y cómo produce las ondas gravitacionales. Las tres partes coinciden: el código es consistente y no hay ningún error. Pero apareció otra cosa, más importante.
Eso pasa con los archivos de ejemplo que trae el programa. El control
(lphi4) y el modelo con gauge (lphi4U1) escriben el
mismo número para el valor inicial del inflatón, pero en cada modelo ese
número significa algo distinto. Resultado: el modelo con gauge arranca
con 4 veces más energía que el control, y con una "intensidad de
resonancia" (el parámetro \(q\)) de 1370 contra 300. Si los hubiera comparado
tal cual, habría atribuido al campo de gauge diferencias que en realidad vienen
de haber arrancado distinto.
El modelo más completo tiene dos campos de gauge, y el inflatón tiene cuatro componentes en lugar de dos. Al arrancar, a cada componente se le agrega un poco de "ruido" que imita las fluctuaciones cuánticas del vacío. El problema es que ese ruido, si se genera al azar, deja en la caja un poco de carga neta. En una caja cerrada la ley de Gauss no tiene solución con carga neta: las líneas de campo no tienen dónde terminar.
El artículo del programa propone generar el ruido con ciertas reglas que cancelan la carga, y comprobé que el código las sigue. Pero encontré un detalle que no está escrito en ningún lado. La fórmula del artículo le da a cada una de las cuatro componentes su propia frecuencia, mientras que el código usa la misma para las cuatro. Hice la cuenta: con frecuencias distintas, la carga no se cancela. El código hace lo correcto y la fórmula del artículo, tomada al pie de la letra, no lo haría. En estos modelos las frecuencias coinciden, así que no cambia nada, pero sí importaría en otros casos.
Al revisar cómo el programa controla la ley de Gauss en el caso SU(2), encontré un comentario que explica una corrección hecha el 3 de agosto de 2026. Antes de esa fecha, el control tenía un error de escala. Su indicador, que debería valer 0 cuando la ley se cumple, marcaba alrededor de 0,6 aun cuando se cumplía perfectamente. La versión que instalé ya tiene la corrección.
Antes de correr, revisé qué valores usan los autores de cada artículo y por qué. Después calculé qué pasa con cada opción. El detalle completo está en Parámetros comparables. Lo principal:
provenance/.El piloto del control ya está corrido y validado contra Dufaux et al. (2007) (sección 3.1 y El piloto del control), y el control definitivo usa el mismo integrador que los modelos con gauge (sección 3.2). Con 256 puntos por lado los modelos con gauge no entran en la memoria de esta computadora. La prueba de la sección 3.3 mostró que 64 puntos con la caja a la mitad dan las mismas ondas que 128 puntos, 8 veces más rápido. Ninguna de las dos resuelve bien las longitudes de onda cortas (k > 4 o 5), así que la comparación entre modelos se apoya en el pico y en las longitudes de onda largas.
Entrega (28 de septiembre de 2026). El curso pidió el repositorio completo y un PDF breve
(5 páginas como máximo) con texto y figuras. Quedaron dos informes: informe-definitivo.pdf (el
pedido, 5 páginas, escrito aparte desde informe-definitivo.html) e
informe-extendido.pdf (la página completa del proyecto). Los dos se generan con
code/generar_pdf.py, que además verifica el límite de páginas. La presentación se prepara
durante la semana.
Los tres modelos ya están corridos con el vacío transversal: U(1) con tres semillas (secciones 3.4 y 3.6) y SU(2)×U(1) con una (sección 3.7). Lo que sigue:
Las tres decisiones sobre los parámetros quedaron tomadas el 22 de septiembre de 2026. Las razones están en Parámetros comparables:
Decisiones confirmadas. La tabla con todos los valores está en Parámetros comparables.
Cuando esté la primera simulación, la primera verificación va a ser justamente lo que aprendí acá: que la ley de Gauss se cumpla desde el primer instante, y que el inflatón del modelo con gauge arranque oscilando igual que el del control.