Siru en Simusol · Documentación · Manual
mdin llama a libdin)30/09/2026. La decisión está en siruviejo/LLAVES.md 13. Esto es el plan para hacerla, escrito después de leer entero slex/din/din.c, Siru::Mdin, Siru::Red, Siru::Circuito y bin/siru. Integración y equilibrio van juntos: siru no se cambia de armador hasta que libdin sepa las dos cosas.
| papel | qué hace |
|---|---|
| el preparador | prepara el modelo de un paso: de la configuración de ese paso, un din |
| el simulador | integra, escribe la salida, y obedece RERUN, CONTINUE, SENSITIVITY, MONTE CARLO |
El preparador prepara el modelo del paso exactamente antes de ejecutarlo. No se sabe de antemano cuántos din va a usar una corrida, y no se prepara ninguno que no se use: con 100 llaves hay 2^100 configuraciones y la corrida pasa por unas pocas. Antes de cada paso se mira la configuración de ese paso; si ya tiene din se usa ese, y si no, se prepara ahí.
Es una sola rutina, la misma para todos los casos, hecha de partes:
| parte | qué pone |
|---|---|
| ramas | las ecuaciones de cada elemento, de su modelo de la biblioteca |
| topológicas | voltajes de rama y corrientes de nodo; con lazos de C o cortes de L, la ley del lazo o del corte en derivadas |
| derivadas | las etapas del método de Runge–Kutta y sus sumas |
| estado | qué variables son estado, su valor inicial, y el equilibrio cuando la configuración tiene lazo o corte |
| propias | las ecuaciones que trae el archivo cuando no hay circuito |
Un sistema sin circuito usa sólo las propias, las derivadas y el estado; un circuito normal, todas menos la variante de lazos y cortes; un punto no usa derivadas. Que una corrida termine con un din o con varios no es algo que el preparador decida: sale de cuántas configuraciones distintas aparecieron.
El código de esas partes está en libdin; siru lo llama antes del paso y guarda lo ya preparado.
En este plan «armador» es el código del preparador que escribe las ecuaciones. Hoy hay dos, uno en C y uno en Perl; tiene que quedar uno.
RERUN y los otros tres no hacen que haya varios din: son del simulador (siruviejo/LLAVES.md 12).
siru le pide a Siru::Mdin tres sistemas por configuración, y los tres los arma el Perl sin pasar por libdin:
| sistema | para qué | quién lo arma hoy | equivalente en libdin |
|---|---|---|---|
integracion(bits, rk) |
un paso de Runge–Kutta | Mdin::_sistema + Butcher |
din_ampliado — existe |
instante(bits) |
evaluar las condiciones de las llaves al empezar el paso | Mdin::_sistema + llave_x = condición |
din_base — existe, sin las llaves |
equilibrio(bits) |
trasvase de carga o de flujo | Mdin::equilibrio |
no existe |
El formato de texto ya es el mismo (variables / ecuaciones, s<i>_, p_, q_). Lo que difiere es lo que sabe cada uno.
Lo que libdin no sabe y Mdin sí (hay que agregarlo a libdin):
libdin rechaza cualquier llave: valor de S1 no constante, porque el valor trae variables declaradas (V:T). Por eso los .tipo de llaves_equilibrio dicen din d2datdinc: NO.Mdin escribe s<i>_t = t + c_i*dt. libdin deja el tiempo como parámetro, el mismo en todas las etapas: una fuente que depende de T la evalúa al comienzo del paso en vez de en t + c_i h.DVOLTAGE), 0 si es constante, numérica si no.Lo que Mdin no sabe y libdin sí (el camino mdin lo gana gratis): funciones del usuario, tablas, parámetros por nombre, salidas res:, SIGN, **, las marcas # @lineal, el chequeo de grados de libertad, las secciones de corrida (paso, adaptación, parada) y el aviso de PENDIENTE. Hoy un circuito con llaves que use una función o una tabla no simula.
Duplicaciones en Perl que desaparecen: el lector del .dat (Red::nuevo), los dos grafos (Red::_grafo_carga, _grafo_flujo), el orden de las ramas por expresión regular (Circuito::_orden), y el lector de las secciones del .din, que está dos veces (bin/siru y Mdin::_sin_ramas).
siru/tests/desde_din.t falla, y lo rompí yo hoy en r1638: espera circuitoB-ED0.csv y ahora la salida es .simul.siru/tests/llaves.t no corre desde que se movió el corpus: busca siru/corpus/llaves_equilibrio, que ahora es siru/corpus/corpus/llaves_equilibrio, y se saltea en silencio. Además lee .csv. Es la prueba de aceptación de todo esto —conservación de carga y de flujo en cada salto— así que tiene que correr antes de tocar nada.d2datdinc, dos opciones nuevas:
--llaves S1=1,S2=0 el estado de cada llave, por nombre
--topologia no escribe nada: dice qué llaves hay y, para el
estado dado, qué lazos y qué cortes
Con --din <N> --llaves ... escribe en --directorio:
NOMBRE-de-d2datdinc.din el instante: el circuito con los estados
como datos, más llave_<x> = condición
NOMBRE-de-d2datdinc-ED<N>.din la integración
NOMBRE-de-d2datdinc-EQ.din el equilibrio, sólo si hay lazo o corte
Todo lo que siru necesita saber de cada archivo va en secciones comentadas, como ya va la corrida: # parametros, # estados, y nuevas # llaves, # entradas, # salidas. siru deja de leer ramas.
Los nombres que ve el usuario no cambian: siru sigue escribiendo NOMBRE-<bits>.mdin y NOMBRE-<bits>E.mdin al lado de la fuente.
Cada paso se commitea solo. Del 1 al 6 son agregados a libdin que no cambian nada de lo que hoy funciona; siru recién cambia de armador en el 8.
0. Red de seguridad. Arreglar desde_din.t y llaves.t para que corran. Guardar en el temporal del trabajo —no en el repositorio— lo que produce hoy el Perl para los 22 archivos de caso 2 que tienen .patron y los 8 de llaves_equilibrio: los tres sistemas de cada configuración y el .simul. Es el oráculo.
1. libdin: la tabla de ramas. din_leer hoy recorre el JSON y emite texto, sin guardar nada por rama. Hace falta una tabla en struct din: nombre, clase (primera letra del tipo), los dos nodos, el índice de su ecuación v = ua - ub, el texto de su x1, su estado y su derivada; y por nodo, el índice de su ecuación de corrientes. Sin cambio de comportamiento: make check de slex tiene que dar igual.
2. libdin: las llaves. Una rama de clase S toma x1 de la configuración (1 o 0, parámetro numérico, como hace Mdin) y guarda su condición aparte. Sin configuración y con llaves, el error dice eso en vez de «valor no constante». De paso, un valor con variables declaradas (V:) deja de ser error: la expresión ya la traduce valor_expresion.
3. libdin: el tiempo de cada etapa. En din_ampliado, si el sistema usa el tiempo: s<i>_t = t + c_i*dt.
4. libdin: lazos y cortes en la integración. Los dos union-find de Red, y el reemplazo de las dos ecuaciones (Mdin::_derivadas_en_degeneraciones): la de voltaje de la rama que cierra el lazo, y la de nodo del supernodo hijo. Con la derivada de las fuentes. La cuenta de grados de libertad no cambia: se reemplaza una por una.
5. libdin: din_equilibrio. El sistema sin DT: potenciales w en la red de capacitores y baterías, potenciales de flujo phi en los supernodos, conservación por nodo. Es Mdin::equilibrio pasado a C.
6. libdin y d2datdinc: el instante, las secciones y las opciones. din_base más llave_<x> = condición; las secciones nuevas; --llaves y --topologia.
7. Paridad, antes de tocar siru. Para cada archivo del oráculo y cada configuración que usó: el sistema de libdin contra el del Perl. No por texto —cambian el orden y las marcas— sino por cantidad de variables y ecuaciones, y resolviendo los dos con los mismos datos. Lo que no coincida se arregla en libdin o se anota acá con el motivo.
8. siru cambia de armador, y queda un solo preparador. Mdin.pm queda en lo que es, la parte del preparador que está en siru: antes de cada paso, si la configuración de ese paso no tiene din, pedírselo a d2datdinc y leer sus secciones; si ya lo tiene, usarlo. Es el mismo para todos los casos, y nunca prepara de antemano. Hoy son dos caminos separados en bin/siru (din_directo y Circuito::correr). Qué llaves hay lo pregunta con --topologia. Un solo lector de secciones del .din (Siru::Din), usado por bin/siru y por Mdin. Y un solo escritor de la salida: UnPunto pasa a usar el de Integrador.
9. Borrar el armador en Perl. De Mdin.pm: _sistema, _derivadas_en_degeneraciones, _camino, _fuente, _derivada_fuente, equilibrio, condiciones, instante, _texto, _numero_rk, _sin_ramas. Red.pm entero. Circuito::_orden. Quedan unas 80 líneas de las 740.
10. Verificar y decir qué anda. prove en siru/tests, make check en slex, y los 53 archivos de caso 2 contra el oráculo, en el temporal. El informe es una tabla por archivo: igual, distinto (con cuánto), o no corre (con el mensaje). Los 31 de caso 2 que hoy no tienen .patron se informan aparte: hoy no andan, y no prometo que anden después.
11. Documentar. LLAVES.md 12 y 13, la cabecera de din.h (que todavía dice «ramas RB, LB, CB y EB con valor constante»), y los README.
din cambian donde hay dependencia del tiempo. Es el punto 3: hoy libdin evalúa el tiempo al comienzo del paso. Con el tiempo de etapa el resultado es más exacto, pero los .simul y .patron de los casos 1 y 3 que usan T van a dar otros números. Es necesario: sin eso el camino mdin empeora respecto de hoy.mdin pasa a ser alfabético, por nombre de rama, que es como ordena libdin (el .dat no trae ordenramas). Hoy es el orden del archivo fuente. Los valores son los mismos; cambia el orden de las columnas del .simul y, con varias llaves, el orden de los dígitos en NOMBRE-<bits>.mdin. Queda igual que el camino din.libdin es más estricto que Mdin: verifica grados de libertad y que todos los nodos lleguen a GND. Puede aparecer algún circuito que hoy corre por mdin y que libdin rechace; sale en el paso 7.Siru::DesdeDat (el puerto en Perl de libdin, su oráculo): no se toca.siru/corpus/clasificar tiene su propia detección de topología para los .tipo: no se toca; después puede usar --topologia.(dq/dt)/C, que vale con C constante. Es la misma limitación de hoy.siru/corpus/PENDIENTE-tipos-por-nombre-y-transformadores.md), funciones a ExprTk (siru/corpus/PENDIENTE-funciones-exprtk.md).Hay otra sesión commiteando en siru/bin/siru y siru/corpus/clasificar (r1640 a r1648). Antes de cada edición de din.c o de bin/siru: svn status y svn diff del archivo; sacar un cambio propio es sacar esas líneas, nunca revertir el archivo.
desde_din.t y llaves.t corren y pasan: 173 pruebas en los cinco archivos.
El oráculo está en el temporal del trabajo: una copia congelada de siru y de d2datdinc en r1655, y lo que dan para 22 archivos de caso 2 (los que tienen .patron; incluye los 8 de llaves_equilibrio). Los 22 corren.
Hallazgo: el camino din hoy rechaza casi todo lo que el Perl dejaba pasar. De los 18 archivos de casos 1, 3 y 4 que tienen un .simul en el corpus, hoy corren 3. Los otros 15 mueren con «El .din no tiene sección estados», porque libdin les encuentra algo sin traducir (# PENDIENTE) y entonces no escribe la corrida. Esos .simul son de cuando todo pasaba por el armador en Perl, que lo que no entiende lo ignora sin avisar.
Lo que libdin marca como pendiente en los 40 archivos mirados, y el Perl ignora:
| qué | cuántas veces | qué es |
|---|---|---|
condicion global: {} |
7 | una condición vacía: no hay nada que traducir |
T<=10, T<=2, T<=7 |
10 | la parada, con <= y un número; libdin sólo entiende T<TIEMPOFINAL y T<número |
TICK<=1000 |
9 | parada por cantidad de pasos |
GLOBAL.constants: {"DT":"0.01"} |
10 | el paso, a la manera de Simusol |
GLOBAL.variables en un circuito con ramas |
11 | |
ecuaciones escritas a mano (IL1+IL4-I3, DIL1-V1/1 * DT) |
5 | un circuito armado a mano, con el Euler escrito |
Esto es el punto 3 de «lo que cambia para afuera», y es más grande de lo que escribí: al pasar a un solo armador, los 22 que hoy corren por mdin van a chocar con lo mismo. No es que el Perl los simule bien: los corre con paso 0.1 ignorando el DT y la parada que dice el archivo. Se resuelve en el paso 7, caso por caso; los dos primeros renglones son arreglos claros de libdin, y DT y TICK necesitan que se decida qué quieren decir.
libdin (r1657 a r1663)| paso | qué | revisión |
|---|---|---|
| 1 y 2 | la tabla de ramas en struct din; las llaves (din_leer_con, --llaves) |
r1657 |
| 3 | el tiempo de cada etapa, (t + c_i*dt) escrito en el lugar |
r1658 |
| 4 | lazos de C y cortes de L: los dos grafos y la ley en derivadas | r1659 |
| 5 y 6 | din_equilibrio, din_instante, din_topologia; --topologia; las secciones |
r1660 |
una condición vacía no queda pendiente; la parada acepta T<=número |
r1661 | |
T es el tiempo también como valor entero de un parámetro |
r1662 | |
d2datdinc acepta un .dat como entrada |
r1663 | |
| dos mensajes de error que decían otra cosa | r1666 |
slex/d2datdinc/probar pasó de 27 a 41 pruebas, todas bien.
Tres cosas que no estaban en el plan y aparecieron:
s<i>_t = t + c_i*dt, como hacía el Perl. Quedó escrito en el lugar, (t + (0.5)*dt): así t y dt siguen siendo datos y no cambia cuáles ecuaciones son lineales.T como valor entero quedaba clavado (r1662). ESIN1, GND-1 = 1,T daba sin(0) toda la corrida: un error de libdin que ya estaba en el camino din y que la paridad sacó a la luz (circuito-S2.d)..dat como entrada (r1663). siru acepta un .dat, y para un circuito con llaves el sistema lo armaba el Perl desde el JSON. Con un solo armador ese camino se perdía; ahora d2datdinc lee el .dat.Y una que no toqué: hay un tercer detector de lazos y cortes, slex/degen (libdegen), que d2datdinc --din usa para escribir un NOMBRE-de-d2datdinc-madre.din. Nadie lo lee: siru no lo usa. Clasifica por lista de tipos (CB, EB, ESIN...) y no por la primera letra, así que un tipo propio como EV o LNL se le escapa. Queda como está.
Contra el armador en Perl congelado en r1655, por nombre de columna. «Igual» es diferencia relativa menor que 1e-9; la peor fue 6e-16.
Los 22 de caso 2 con .patron:
| cuántos | ||
|---|---|---|
| iguales tal cual | 9 | los 8 de llaves_equilibrio y circuitoORI |
no corren por libdin |
13 | tienen cosas sin traducir (abajo) |
| esos 13, sobre una copia sin esas líneas | 13 iguales |
O sea las ecuaciones que arma libdin dan lo mismo que las del Perl en los 22. Lo que cambia es que 13 ya no corren, y es por lo que sigue.
Lo que difiere del plan: la parte del preparador que está en siru no quedó en Mdin.pm sino en un módulo nuevo, Siru::Preparador, y Mdin.pm se borró entero junto con Red.pm. Y aparecieron dos decisiones chicas:
RK=...) se usa el 0, y siru lo dice. Era lo que hacía el camino mdin; el camino din en ese caso no corría.RK=[-1] (circuitoBBBB.ds) se rechaza con un mensaje que lo dice.prove en siru/tests: 173 pruebas bien. make check en slex: probar bien (41); compara-dat y compara-din fallan, como antes de empezar. compara-dat da lo mismo que antes (139 iguales, 55 distintos). Ya no fallan (08/10/2026): lo atrasado eran los congelados, no el código, y se rehicieron con siru/corpus/regenera (r2607). Las dos dan todo igual y el make check de slex pasa entero, 4/4 y 6/6. compara-din compara contra los .din congelados del corpus y ahora encuentra 72 archivos más distintos: miradas las 467 líneas de diferencia, son todas de lo que cambió a propósito —un PENDIENTE que ya no está, la cabecera de lazos y cortes, la ley en derivadas, el tiempo de etapa, la sección de corrida que aparece al irse el pendiente—. Los congelados están desactualizados; no los regeneré.
Lo que corría y ya no corre: 15 archivos. Los 13 de arriba y dos sin .patron (exprtk_varios_exprtkasades2015/circuito-T y circuito-T2). En todos es lo mismo: el archivo dice cosas que libdin no sabe traducir, el Perl las ignoraba en silencio y corría igual, y ahora siru se para y las nombra.
| qué dice el archivo | en cuántos de los 15 | |
|---|---|---|
VARIABLES Z=0 y EQUATIONS Z+T+TICK+DTICK |
9 | una ecuación propia adentro de un circuito |
TICK>1000 como parada |
7 | con TICK=0, DTICK=1 en DEFINED PARAMETERS |
CONSTANTS DT=0.01 |
6 | el paso, a la manera de Simusol |
No es que el Perl los simulara bien: corría con paso 0.1 hasta T=1, sin mirar el DT ni la parada. Hace falta decidir qué quieren decir DT, TICK y DTICK, y si un circuito puede traer ecuaciones propias; con eso libdin los traduce y vuelven a correr.
Lo que no corría y ahora corre: 4 archivos. Simul_varios_Siru_perl_examples/circuitoCSLO4, sceptresimusol_share_sceptresimusol_examples/a06a, Simul_varios_Siru_perl_examples/circuitoBS y Simul_varios_Siru_perl_examples_otros/6elementos.
El resto, que no corría ni corre:
| cuántos | por qué | |
|---|---|---|
caso 2 sin .patron |
27 de 31 | cosas sin traducir (7); en el equilibrio, una capacidad o una fuente que depende de una variable del circuito (7); funciones o símbolos que no están (5); modelo con DT adentro (2); y otros (6: nodos inválidos, un valor complejo, dos valores donde el modelo pide uno, un capacitor sin la carga como estado) |
casos 1, 3 y 4 con .simul |
13 de 18 | cosas sin traducir, las mismas de arriba (12); RK=[-1] (1) |
Lo que mejoró sin buscarlo. stiffloli.ds con RK=[18] daba en T=1 y1 = 0.84133608; ahora da 0.84147098480, y sen(1) = 0.84147098481. El error bajó de 1.3e-4 a 3e-11: es el tiempo de etapa del paso 3.
DT, TICK, DTICK y las ecuaciones propias en un circuito (arriba). Es lo que devuelve los 15..din, .simul y .patron congelados del corpus están desactualizados respecto de este libdin. No se regeneraron.slex/degen y el -madre.din, que nadie lee.siru/corpus/clasificar tiene su propia detección de topología.d2datdinc congelados en r1655, y sus salidas— está en el temporal de esta sesión y se borra con ella.No hacía falta decidir qué «significan» DT y TICK: alcanza con las ecuaciones, más saber que el archivo los recibe del simulador. Cuatro cosas en libdin y siru (r1669, r1670), escritas en siruviejo/LLAVES.md 13:
DT es el paso que usa el simulador, no lo fija el archivo;TICK es la cantidad de pasos dados, y la pone el simulador;TICK>1000) se evalúa al empezar el paso.Y en el corpus (r1671): se sacó DT= de los 53 archivos que lo declaraban sin usarlo, y DTICK de todos lados. Son 58 archivos.
Cómo quedó, con el árbol en r1671:
| corrían con el Perl | corren ahora | |
|---|---|---|
caso 2 con .patron (22) |
22 | 22, y dan lo mismo en las filas que comparten |
caso 2 sin .patron (31) |
2 | 5 |
casos 1, 3 y 4 con .simul (18) |
3 | 15 |
Los 15 que habían dejado de correr, corren. Y ahora llegan hasta la parada que dice el archivo (T>10: 101 filas) en vez de hasta T=1, que era lo que hacía el Perl.
prove: 182 pruebas bien (tests/propias.t es nueva). probar: 48 bien.
Los 29 que no corren, por qué:
| por qué | cuántos |
|---|---|
en el equilibrio, un capacitor cuya capacidad depende de su voltaje (a02 y sus variantes) |
6 |
Calcula no encuentra solución: jacobiano singular (circuito-S, -SE, -SE1, -SERRORRARO, -T3). Con el Perl daba lo mismo |
5 |
una función o un símbolo que no está en el dato (a13, a13plot, g02), o un parámetro que no es un número (a13z, a13zcorto) |
5 |
un modelo de la biblioteca vieja (11elem.ds, cutloop.ds, slex_viejos/circuitoCSLO) |
3 |
un valor con dos partes donde el modelo pide una (circuitoCSLO, circuitoCSLO2) |
2 |
nodos inválidos (circuitoCSLOCLO, circuito-SE2) |
2 |
no cierran los grados de libertad con sus ecuaciones propias (engrane, girator) |
2 |
la ecuación propia nombra una Z que no está en VARIABLES (circuitoBX, circuitoBloli) |
2 |
un valor complejo, (1,0) (d01) |
1 |
RK=[-1] (circuitoBBBB) |
1 |
Para tener presente:
DT en sus ecuaciones lo escribieron pensando en incrementos (DIL1 - V1/1 * DT). Ahora reciben el paso, 0.1, y no el 0.01 que declaraban.2e-14: sumar 0.1 cien veces da 9.99999999999998 y hace falta un paso más para llegar a 10. Por eso una corrida de 0 a 10 tiene 102 filas y no 101. Ya pasaba; no lo toqué..ds2, .dat, .din, .simul, .patron y .tipo del corpus no se regeneraron y están desactualizados.