Siru en Simusol · Documentación · Manual

PLAN_DC_RERUN

Plan: sensibilidad, Monte Carlo, peor caso, RERUN y CONTINUE en siru

Pedido del autor, 01/10/2026: que siru haga lo que SCEPTRE hace con SENSITIVITY, MONTE CARLO, WORST CASE, RERUN y CONTINUE. Hoy el lector (slex/d2datdinc/dato.c) reconoce esas secciones y las saltea («sin traducción»), y siru corre solo la parte en el tiempo. La referencia de cada cosa es el manual de SCEPTRE (Simulparser/sceptre-formato-d.md: 2.2.2 y 2.2.3 las cotas, 2.2.7 y 2.2.8 las opciones DC, «Run Controls for DC Options», 2.4 el RERUN) y lo que da SCEPTRE en siru/corpus/sceptre sobre los mismos .d.

OPTIMIZATION no está en el pedido; queda afuera.

Lo que dice SCEPTRE

Lo que hay en el corpus para comparar

opción archivos
sensibilidad solosens.d, a08.d, d04.d
Monte Carlo a07.d, d04.d
peor caso a09.d, d04.d
RERUN 13: a01_*, a03, los tanque_*...
CONTINUE ninguno: hay que escribir uno

Los pasos

Cada paso se commitea al cambiar, antes de probar.

  1. El punto de operación DC (RUN INITIAL CONDITIONS): en libdin, un sistema más del instante con las derivadas como datos en 0 y los estados como incógnitas (las condiciones iniciales del archivo son la semilla); siru lo resuelve al arrancar cuando el archivo lo pide y arranca la corrida desde ahí. Con RUN INITIAL CONDITIONS ONLY escribe el punto y termina (una fila, como el caso 4). Comparar con a03, v030 y los otros «sólo condiciones iniciales» que ya tienen su NOMBRE.sceptre.
  2. Leer. En dato.c, en vez de saltear: las subsecciones DC a GLOBAL.dc (sensibilidad, montecarlo, peorcaso: listas de {dependientes, independientes}), las cotas de cada elemento y parámetro a cotas, los controles a GLOBAL.control, cada RERUN DESCRIPTION a GLOBAL.reruns (lista de cambios por rerun), y CONTINUE a GLOBAL.continue. Pruebas en slex/d2datdinc/probar con un .d chico de cada cosa.
  3. Pasarlo al .din del instante. No hace falta (visto al terminar el paso 1): siru ya tiene el GLOBAL del dato en memoria (Siru::Circuito::caso lo lee con d2datdinc -o -), así que dc, cotas, reruns y continuar los toma de ahí. Lo único que hay que traducir es el nombre de cada variable al del .din: minúsculas (R1 → r1, VC1 → vc1, P1 → p1), y para una rama cuyo valor es un parámetro (L1 = PL) el parámetro es pl; se verifica contra las secciones del instante (# parametros, incógnitas) y lo que no está es un error que lo dice.
  4. Sensibilidad (Siru::DC): sobre el punto DC del paso 0, para cada independiente, por diferencias centradas (paso relativo 1e-6) la derivada de cada dependiente; también la normalizada (∂y/∂x)(x/y), como SCEPTRE. Es la misma derivada que da el adjunto de SCEPTRE, así que tiene que coincidir con solosens, a08.
  5. Monte Carlo: n muestras de los independientes, con la media y σ de SCEPTRE ((máx+mín)/2, (máx−mín)/6), gaussiana N(media, σ) o uniforme como SCEPTRE (ver arriba); el punto DC en cada una; y por dependiente la media, el desvío, el mínimo y el máximo. Con la semilla del archivo y el mismo generador (RANDU, suma de 12 uniformes) se reproduce a SCEPTRE muestra por muestra, y así se compara con a07.
  6. Peor caso: con el signo de cada derivada, cada independiente a la cota que sube (HIGH) o baja (LOW) cada dependiente, y resolver el instante ahí. Con WORST CASE = LOW | HIGH, esos valores quedan para la corrida en el tiempo. Comparar con a09.
  7. RERUN: después de la corrida maestra, una por rerun con los cambios aplicados (elementos y parámetros constantes, condiciones iniciales, tablas, controles), cada una desde el maestro o desde la anterior. Todo en el mismo .simul, en bloques como el .sim de SCEPTRE. Comparar con SCEPTRE en a01_* y los tanque_*, bloque por bloque.
  8. CONTINUE: siru --continuar NOMBRE.d --hasta T sigue desde el estado final de la última corrida hasta el nuevo tiempo, agregando filas al mismo .simul; un .d con CONTINUE se traduce a eso. Escribir un .d de prueba y comparar con la corrida de un tirón.
  9. Salida de lo DC: NOMBRE.dc, una tabla de texto por opción (como las de SCEPTRE), legible por tabular; y lo esencial en el .informe.
  10. Documentar en MANUAL.md y HECHO.md; agregar a siru/corpus/sceptre la comparación de lo DC y de los reruns.

Bitácora

Paso 0, hecho (r1879 a r1881)

RUN INITIAL CONDITIONS y RUN INITIAL CONDITIONS ONLY: d2datdinc los lee como control SCEPTRE_IC=[1|2]; libdin escribe en el instante la sección # puntodc (estado derivada y solo 0|1); siru resuelve el instante en t = 0 con las derivadas como datos (0) y los estados como incógnitas, con las condiciones iniciales del archivo de semilla, arranca desde ahí y con ONLY escribe sólo esa fila. a03 (par Darlington, cuatro capacitores de juntura, diodos) da lo mismo que SCEPTRE en las ocho cifras que imprime: PEC 5.3007344, PEIN 2.7598821e-4, VR3 0.65620879, VR4 0.21082735.

Dos cosas que aparecieron:

Paso 1, hecho (r1893 a r1896)

d2datdinc lee lo que antes salteaba. En el .dat, bajo GLOBAL:

OPTIMIZATION sigue salteada. Prueba: probar sobre pruebas/sceptre/dc-opciones.d y rerun.d (67 bien); prove 222 bien; y el barrido de los 250 .d y .ds del corpus con --din no cambia qué falla.

Paso 3, hecho (r1904 a r1909): la sensibilidad

Siru::DC::sensibilidad: sobre el punto de operación DC (punto_dc, el closure del paso 0, ahora también en el caso 4 sin estados), para cada conjunto de SENSITIVITY la derivada de cada dependiente respecto de cada independiente por diferencias centradas con paso relativo 1e-3 (con 1e-6 la diferencia era del orden del ruido del solver, tolerancia 1e-7), y la normalizada (dy/dx)(x/y). Va a NOMBRE.dc, una tabla legible por tabular. Nombres: minúsculas; una fuente de corriente como dependiente es su corriente (J1T1 → ij1t1); una rama cuyo valor es un parámetro se nombra por él. Los dependientes de GLOBAL.dc se traducen en libdin como las salidas, para que un parámetro por expresión que sólo ellos nombran (PR3 = XR3(R3*IR3*IR3)) sea incógnita del punto. Un independiente que vale una expresión (R1 = X1(10*P1) en solosens) no es un dato y el error lo dice: la sensibilidad se pide respecto de sus parámetros.

Lo que se vio con a08 (par Darlington, 31 derivadas): la tabla de sensibilidad de SCEPTRE no coincide con sus propias corridas. SCEPTRE imprime ∂VCET1/∂P1T1 = 0.2237; siru da 0.0436; y corriendo SCEPTRE dos veces con P1T1 = 0.959 y 0.961 (T1 ... = MODEL 2N706A (CHANGE P1 = ...)) su punto DC se mueve (0.35128338 − 0.35119611)/0.002 = 0.0436, igual que siru, y lo mismo ∂VR4/∂P1T1: SCEPTRE 1.618 (normalizada) contra 0.3147 real, que es la de siru. Los puntos DC de SCEPTRE y siru en esas dos corridas coinciden en ocho cifras. Así que el adjunto de SCEPTRE da otra cosa que la derivada del punto de operación (quizá sin la dependencia de los diodos con su propia tensión); la de siru es la correcta, y NOMBRE.dc no se compara contra la tabla de SCEPTRE sino contra sus reruns.

Paso 4, hecho (r1925 a r1928): Monte Carlo

Siru::DC::montecarlo, calcado de monte.f/random.f de la fase 2 de SCEPTRE (decisión del autor, 01/10/2026: "lo saco de su código de fase 2, hacelo así por ahora"): por independiente media (max+min)/2 y sigma (max−min)/6 (con cotas en porcentaje, nominal·(1 ∓ p/100)); el generador es RANDU (IX ← IX·65539 mod 2³¹, uniforme 0.4656613e-9·IX), semilla 127263527 salvo INITIAL RANDOM NUMBER; la gaussiana es la suma de 12 uniformes menos 6, y la "uniforme" de SCEPTRE es una uniforme en [0,1), así que cae en [media, media+sigma) —defecto de SCEPTRE, reproducido tal cual—. Por muestra un punto de operación (punto_dc con los independientes cambiados); una muestra que no converge se saltea y se avisa, como SCEPTRE. Por variable: nominal, mínimo, máximo, media y sigma muestral con N−1 (sqrt((Σd² − Σd·avg)/(N−1)), d = valor − nominal). Va a NOMBRE.mc. Siru::DC::opciones corre lo que el archivo pide (sensibilidad, Monte Carlo) desde Circuito y UnPunto. d2datdinc lee también RUN MONTE CARLO = n (antes sólo MONTE CARLO = n).

Verificado con a07 (RUN MONTE CARLO = 10, P1 = 0.96 (0.98, 0.9) en los dos 2N706A): mismo generador y misma semilla dan las mismas muestras que SCEPTRE; las 12 filas de a07.mc coinciden con las OBSERVED STATISTICS de SCEPTRE (a07.sceptre-mc) en las ocho cifras que imprime, y la semilla final es la misma (1007121511). siru/corpus/sceptre saca esas estadísticas del listado a NOMBRE.sceptre-mc y las compara fila por fila con NOMBRE.mc. Ojo: tras RUN MONTE CARLO los OUTPUTS que SCEPTRE lista son los de la última muestra, no los nominales (por eso a07 figura "distinto" en SCEPTRE.md).

Paso 5, hecho (r1933 a r1940): el peor caso

Siru::DC::peorcaso, calcado de worst.f (fase 2 de SCEPTRE, 1973). Por cada dependiente del conjunto: el gradiente respecto de los independientes en el punto nominal (diferencias centradas, el mismo de la sensibilidad), u = g/|g|, y por la recta nominal + D·u hasta la primera cota que se toca: DHIGH = min_i (cota_i − nominal_i)/u_i a favor del gradiente, DLOW lo mismo en contra (con las comparaciones estrictas de worst.f). SCEPTRE no pone cada independiente en su cota: sólo la variable más cercana llega a la suya, las demás quedan en un punto intermedio. En cada extremo resuelve el punto de operación y calcula el gradiente otra vez. Gradiente nulo o ninguna cota alcanzada: avisa y saltea el dependiente, como SCEPTRE. Va a NOMBRE.wc: una fila por (dependiente, independiente) con nominal, HIGH, LOW, y el valor y el gradiente de cada independiente en los tres puntos; en comentarios, la distancia y la cota que toca cada extremo. Siru::DC::opciones lo corre con SCEPTRE_WC.

Verificado con a09 (el Darlington, RUN WORST CASE, dos conjuntos): como el gradiente de SCEPTRE es su adjunto, que está mal (paso 3: ∂VCET1/∂P1T1 0.2237 contra 0.0436 real), SCEPTRE va en otra dirección y sus extremos son otros: para VCET1 SCEPTRE da HIGH 0.35394 y LOW 0.34297 (toca P1T1); siru da HIGH 0.36985 y LOW 0.33765 (toca P1T2), más extremos que los de SCEPTRE —el "peor caso" de SCEPTRE no es el peor—. Para verificar los de siru se corrió SCEPTRE con los independientes en los puntos que siru elige (a09wch.d, a09wcl.d: MODEL 2N706A (CHANGE P1 = ...)): da 0.3698499 y 0.33764909, igual que siru en las ocho cifras. siru/corpus/sceptre saca las WORST CASE COMPUTATION del listado a NOMBRE.sceptre-wc, sin compararlas. Otro defecto de SCEPTRE: en el listado nombra mal la variable cuya cota se toca en el segundo conjunto (dice P1T1 donde es P1T2 o R4: usa el índice relativo al conjunto como absoluto).

WORST CASE = LOW | HIGH, hecho (r1966): la corrida en el tiempo sigue con los valores del extremo pedido del último dependiente del último conjunto, desde su punto de operación (DC::opciones los devuelve, Circuito los impone en los parámetros de cada sistema). Comprobado con slex/d2datdinc/pruebas/sceptre/wc-tiempo.d (divisor RC lineal, (VC1, IR1 / R1, R2), RUN WORST CASE = HIGH, STOP TIME = 20) y wc-tiempo-low.d (= LOW): los extremos DC de siru coinciden con los de SCEPTRE (VC1 HIGH 7.1428571, LOW 6.2162162: en un circuito lineal el adjunto de SCEPTRE está bien), pero SCEPTRE integra con los valores contrarios: con HIGH deja R1 = 7, R2 = 13 (los LOW de IR1, VC1 = 6.5) y con LOW deja R1 = 5, R2 = 11 (VC1 = 6.875). Es lo que hace worst.f: calcula HIGH y después LOW salvo que se pida LOW, y queda lo último calculado; restaura el nominal sólo con NOMINAL. siru hace lo que dice el manual, así que wc-tiempo.d figura "distinto" y la corrida de siru con HIGH es la de SCEPTRE con LOW. Otro defecto de SCEPTRE visto acá: con cotas y sin DEFINED PARAMETERS su Fortran no enlaza (pbound_ sin definir: forwrd.f sólo declara COMMON /PLIMIT/ PBOUND si hay parámetros definidos); el mazo lleva un PX = 1 de relleno.

Paso 6, hecho (r1952 a r1959): RERUN

Siru::Rerun::aplicar(dato, rerun, j): los cambios del rerun j sobre una copia del dato —el .dat que lee d2datdinc, el mismo de la maestra—: ELEMENTS a ramas{R1}{valor}, DEFINED PARAMETERS e INITIAL CONDITIONS a defpar (ahí deja d2datdinc las condiciones iniciales), TABLE n = x, y1, y2... y sus filas a tablas{n}{filas} (la abscisa y la columna j), STOP TIME a TIEMPOFINAL, START TIME a T, INTEGRATION ROUTINE a RK con la tabla de d2datdinc (TRAP 12, IMPLICIT 13, RUK 7, XPO 13), IC FOR RERUNS. Lo demás se avisa y no se aplica. Circuito::correr_con_reruns corre la maestra y después cada rerun: escribe su .dat en un temporal al lado de la salida y lo corre entero (d2datdinc, libdin, Calcula) desde el directorio del .d (Preparador acepta directorio); con IC FOR RERUNS = PRECEDING RESULTS el rerun arranca del estado final de la corrida anterior (Integrador lo avisa con al_terminar, correr acepta estado_inicial). Todo en un solo .simul, un bloque por corrida con su cabecera y una línea # RERUN k/N (R1 = 9.3, STOP TIME = 600) antes de la de para Simusol, como lo escribía Simusol (tabular2/data/elementos_parametros_concircuito.simul, decisión del autor: en bloques, no en archivos). Siru::Salida tiene bloque y anexar.

siru/corpus/sceptre compara bloque por bloque: el .sceptre lleva todos los bloques del .sim (en el .sim las filas de cada corrida vienen primero y después su cola #RUN/RERUN NUMBER n, #nam...) o del listado (IC ONLY), cada uno tras una línea # RERUN k/N; el .simul de siru se parte en sus cabeceras; NOMBRE-Sceptre va por bloques y la mayor diferencia de cada variable es sobre todos.

Verificado: a03 (IC ONLY, P1T1 = .96, .93, .9): las cuatro corridas iguales a SCEPTRE en ocho cifras (PEC 5.3007344, 5.1910074, 5.0340188, 4.8854795). tanque_par_1 (PF = 500, 600): tres corridas iguales (VCA 0.0052, el error de integración de SCEPTRE, el mismo de la maestra). El mazo de prueba slex/d2datdinc/pruebas/sceptre/rerun.d (R1, STOP TIME y la rutina por rerun, y un CONTINUE en el mismo mazo): siru corre las tres; SCEPTRE corre las tres pero no escribe el .sim de los reruns ("SIMUL8 DATA GENERATION HAS BEEN DELETED FOR THIS RERUN"), así que sólo la maestra se compara. a01_2 (TABLE 1 por rerun, el inversor con diodos): la maestra y el rerun 2 iguales a SCEPTRE; el rerun 1 (la tabla con pico 1.2) no converge en siru en t = 58.3 con TRAP (SOLVER FAILURE tras 10000 iteraciones) y SCEPTRE sí lo corre: pendiente, es del solver (como a13). siru/corpus/sceptre empareja los bloques por número de rerun, así que un rerun que falta no desplaza a los demás. Falta probar IC FOR RERUNS = PRECEDING RESULTS (ningún .d del corpus lo usa).

Paso 7, hecho (r2001 a r2005): CONTINUE

siru --continuar NOMBRE.d [--hasta T] sigue la corrida terminada: el estado final lo deja bin/siru en NOMBRE.informe (estado final: t=20 qc1=6.87, y parametros impuestos: r1=5 r2=11 si el peor caso dejó valores), y la continuación es otro bloque del mismo NOMBRE.simul, # CONTINUE (desde t = 20, STOP TIME = 40). Rerun::continuacion arma el dato: T = t final, TIEMPOFINAL = T, sin punto de operación ni opciones DC (sigue del estado que dejó la anterior), sin reruns, y con las líneas de la sección CONTINUE del archivo aplicadas como las de un rerun. Circuito::continuar lo corre desde su .dat como un rerun, con estado_inicial, desde (libdin escribe siempre desde 0; START TIME del .d no llega al .din, pendiente) e impuestos heredados. Un .d con CONTINUE en el mismo mazo continúa la última corrida (la maestra o el último rerun), como SCEPTRE continúa lo que quedó guardado. --continuar se puede encadenar: el .informe queda con el nuevo estado final.

Verificado: pruebas/sceptre/rerun.d (maestra, 2 reruns, CONTINUE STOP TIME = 2000): el bloque CONTINUE va de 700 a 2000 sin salto, siguiendo el rerun 2. wc-tiempo.d y --continuar --hasta 40: sigue de t = 20 con R1 = 5, R2 = 11 (los del peor caso HIGH), VC1 constante 6.875. Contra SCEPTRE no se compara: allá CONTINUE es otro mazo sobre datasave, y en el mismo mazo anula el .sim de los reruns.

Después del paso 7 (04/10/2026, r2017 a r2093): lo que pidió d04, y el corpus entero

Para que d04.d (el único .d con RUN WORST CASE = LOW | HIGH en reruns) corriera hizo falta bastante más que los pasos del plan; el detalle está en HECHO.md, secciones 3 nonies a 3 undecies:

d04 contra SCEPTRE: el Monte Carlo coincide (13 filas); la corrida y los dos reruns difieren (VRL1, VRL2), por la ley de la capacidad —no se puede confirmar con una capacidad equivalente porque CC2 = f(VCC1) no la tiene—.

El corpus entero (siru/corpus/SCEPTRE.md, r2093): de 152 .d, 74 iguales, 32 distintos, 46 sin comparar. Queda pendiente una pasada limpia con calcula 6.0-31 instalado, revisar los distintos sin explicación anotada y los que siru no arranca.

Lo que hay que decidir