Visión general
Una Programación es lo que ancla una simulación al tiempo real. Sin una programación, un modelo corre en tiempo abstracto con llegadas sintéticas, útil para trabajo exploratorio, pero no para comparar contra tu piso real. Con una programación, la simulación queda anclada a fechas reales, patrones de turno reales y planes de producción reales. El material entra cuando tu plan dice que entra, las transiciones de turno se disparan en momentos de reloj específicos, y los resultados son directamente comparables con lo que produjo tu piso. Todo uso serio de ProDex involucra al menos una programación. La mayoría de los modelos tienen varias: una para el plan “normal”, algunas para escenarios alternativos que estás comparando. Si te estás orientando primero en el flujo de trabajo de simulación, empieza por Resumen de la simulación: esta página es la referencia profunda de la capa de tiempos. El modelo mental que hace que las programaciones tengan sentido es la división en dos planos: la programación lleva cuándo cambian las cosas (se disparan liberaciones, cambian los turnos), mientras que el modelo lleva qué hace cada componente en cada cambio. Un patrón de tres turnos que afecta a cinco recursos necesita tres emisiones programadas y repetitivas más 15 event listeners definidos una sola vez en el modelo, no cientos de entradas de capacidad individuales.Elegir una programación
El selector de programación está en el riel del Modelador, junto al selector de modelo. Lista todas las programaciones de la fábrica, más:- Predeterminado (sin programación): cuando se selecciona, el modelo corre en tiempo abstracto con las llegadas estocásticas que definan las Fuentes. No hay ningún objeto de programación detrás de esto.
- Nuevo Programa: crea una programación nueva y vacía y cambia a ella.
- Editar: abre el Editor de Programación para la programación actualmente seleccionada.
- Eliminar: elimina la programación actualmente seleccionada, después de confirmar en un diálogo Eliminar Programa.
El Editor de Programación
El Editor de Programación es un diálogo titulado Editar {nombre de la programación} donde escribes los tiempos y eventos de una programación. La parte superior del diálogo tiene cuatro campos que definen la programación:- Nombre de Programación: corto, descriptivo. Es lo que se muestra en el selector de programación.
- Descripción: texto libre opcional que explica qué representa esta programación.
- Hora de Inicio: el momento de reloj en que empieza la simulación. Cada marca de tiempo de evento en esta programación debe caer en o después de la Hora de Inicio.
- Hora de Finalización: el momento de reloj en que termina la simulación. Si se deja en blanco, la simulación corre durante la Duración configurada del modelo a partir de la Hora de Inicio. Si se define, la Hora de Finalización sobrescribe la Duración.
- Liberación de Material: entidades que entran al modelo en un momento específico
- Asignar Variable: define una variable de estado en un momento específico
- Emitir Evento: publica un tema en un momento específico
Qué contiene una programación
Una programación es una secuencia de liberaciones de material y acciones programadas, cada una marcada con un momento de reloj absoluto específico. La simulación corre desde la Hora de Inicio hasta la Hora de Finalización (o durante la Duración configurada del modelo si no se define la Hora de Finalización), y cada evento se dispara cuando el tiempo de simulación en reloj llega a su marca de tiempo. Cada marca de tiempo de evento es absoluta, no un desfase relativo desde la Hora de Inicio.Liberaciones de material
Una liberación de material le indica a una Fuente o Búfer que emita una o más entidades en un momento de reloj específico. Cada liberación tiene:- Objetivo: la Fuente o Búfer desde la que se libera, y el tipo de Entidad a liberar. Los componentes dentro de un Nodo de modelo se listan después de un divisor; de ellos, solo los Búferes son objetivos válidos, porque una Fuente dentro de un submodelo recibe entidades a través de su Nodo de modelo padre. Las Fuentes y los Búferes solo aceptan liberaciones de su propio tipo de entidad; cualquier otro emparejamiento falla la validación.
- Valor: la cantidad, un número entero de al menos 1.
- Cuándo: el momento de reloj en que se dispara la liberación (UTC). Una liberación marcada exactamente en la Hora de Inicio de la programación siembra el WIP inicial: material que ya está en el piso cuando comienza la corrida.
- Repeticiones (opcional): libera la misma cantidad de nuevo en un intervalo fijo (ver Eventos recurrentes).
- Atributos: valores para asignar a las entidades recién creadas, mediante Editar Atributos. El Editor de Programación fija un valor por atributo. Dexter también puede usar las demás estrategias de asignación aquí; una Expresión DSL en una liberación corre en contexto sin entidad: puede leer constantes, tablas de búsqueda y variables de estado, pero todavía no hay ninguna entidad en alcance.
priority="rush" y due_priority=5; el 1 de nov. de 2024 a las 9:00 AM UTC libera 30 unidades del Producto B; y así sucesivamente.
La lógica de llegada de una Fuente y las liberaciones de material corren en paralelo. No son mutuamente excluyentes. Una Fuente puede seguir produciendo llegadas estocásticas mientras una programación inyecta simultáneamente lotes específicos en momentos programados, y las acciones
release_entity disparadas por eventos pueden dispararse encima de ambas. Si quieres una Fuente que dependa solo de la programación, deja su lógica de llegada vacía.Acciones programadas
Una acción programada se dispara en un momento de reloj específico (Cuándo) sin estar atada al evento de ciclo de vida de ningún componente. Los dos tipos de acción son:- Asignar Variable: escribe un valor en una Variable de Estado.
- Emitir Evento: publica en un Tema.
- Un Emitir Evento programado se dispara en el límite del turno: por ejemplo, publica el tema
shift_start_night. - Un Event Listener en el recurso se suscribe a ese tema y define la capacidad al valor nocturno.
Las acciones programadas corren en contexto sin entidad y sin componente.
SELF no está disponible (está restringido a event hooks y event listeners), y no hay ninguna entidad en alcance. Las expresiones aquí pueden alcanzar variables de estado, constantes, tablas de búsqueda, el estado de la simulación (SIM_TIME, SIM_DURATION) y las funciones de consulta de componentes con ids de componente explícitos.Eventos recurrentes
Los límites de turno y las órdenes permanentes se repiten, y no deberías tener que escribir a mano docenas de eventos idénticos. Tanto las acciones programadas como las liberaciones de material pueden repetirse en un intervalo fijo: el evento vence en su momento Cuándo, y luego otra vez en cada intervalo, hasta el momento Hasta (inclusive). Deja Hasta vacío y se repite hasta la hora de finalización de la programación, o hasta la duración del modelo cuando la programación no tiene una. La programación guarda una sola entrada sin importar cuánto dure la corrida. En el Editor de Programación esto es la columna Repeticiones: activa Repetir este evento, define Cada como un número entero y una unidad (Segundos, Minutos, Horas, Días o Semanas), y opcionalmente un momento Hasta.- El intervalo es una duración fija, así que un evento diario mantiene su hora UTC todo el año; no sigue los cambios de horario de verano.
- Un patrón solo de días laborables es un evento por día laborable, cada uno repitiéndose cada 1 semana.
- Una condición en una acción repetitiva se revisa en cada ocurrencia, y una ocurrencia que cae exactamente en el final de la corrida está planificada pero no se dispara.
Direccionamiento jerárquico
Una liberación puede apuntar a un Búfer dentro de un Nodo de modelo (no a una Fuente; consulta Objetivo más arriba). En los datos de resultados (como la columnaelement_id de schedule_definition), ese tipo de objetivo se identifica con el separador ::. Ejemplos:
source_1: una Fuente de nivel superiormodel_node_1::buffer_1: un Búfer dentro de un Nodo de modeloouter_node::inner_node::buffer_2: anidado profundamente
:: está reservado, así que ningún id de componente puede contenerlo.
El patrón de programación por turnos
La mayoría de las fábricas tienen capacidad basada en turnos que cambia a lo largo del día y la semana. La forma idiomática de modelar esto en ProDex combina programaciones, temas, variables de estado y event listeners:- Una variable de estado de turno:
CURRENT_SHIFT, tipo Texto, valor inicial"day". - Acciones Emitir Evento repetitivas en los límites de turno: publica el tema
shift_dayal inicio del primer turno diurno yshift_nightal inicio del primer turno nocturno, cada una repitiéndose cada día. - Un Event Listener en cada recurso afectado suscrito a los temas de turno: cuando se publica
shift_night, define la capacidad de la máquina CNC al valor nocturno y actualizaCURRENT_SHIFTa"night". - Las expresiones referencian
CURRENT_SHIFT: las tasas de llegada, la puntuación de prioridad y cualquier otra cosa que varíe por turno lee la variable de estado y se ramifica según corresponda.
Reutilizar programaciones entre modelos
Las programaciones pertenecen a la fábrica y pueden reutilizarse entre modelos. Cada una es un conjunto completo de liberaciones de material y acciones programadas con su propia Hora de Inicio y Hora de Finalización; eliges cuál usar desde el selector al correr una simulación. Sus referencias a componentes, entidades, variables y temas deben ser válidas para el modelo que ejecutes. Usos típicos:- Escenarios base vs. de estrés: una programación “normal” y una programación de “aumento de demanda”, ejecutadas por separado y comparadas.
- Repetición histórica: la demanda real del mes pasado como una programación, un pronóstico de demanda planificada como otra.
- Variaciones de turno: una programación estándar de cinco días y una programación alternativa de siete días con cobertura de fin de semana.
Hora de Inicio y Hora de Finalización
- La Hora de Inicio es el momento de reloj en que empieza la simulación. Cada marca de tiempo de liberación de material y de acción programada debe caer en o después de la Hora de Inicio.
- La Hora de Finalización, si se define, es cuándo termina la simulación: sobrescribe la duración configurada del modelo. Útil para correr la misma programación contra una ventana más corta o más larga sin editar los eventos de la programación.
- Si la Hora de Finalización se deja en blanco, la simulación corre durante la Duración configurada del modelo a partir de la Hora de Inicio.
- Los eventos marcados después de la Hora de Finalización (o después de Hora de Inicio + Duración si no se define Hora de Finalización) quedan fuera de la ventana de la corrida y nunca se alcanzan.
Z) y los límites de turno se quedan exactamente donde los pusiste.
Formas de crear una programación
Hay dos formas de que una programación llegue a existir, ambas produciendo la misma programación:- El Editor de Programación: el diálogo descrito arriba, mejor para ediciones pequeñas y revisión.
- Dexter: el camino más rápido para datos reales. Sube el material crudo (un CSV de órdenes, un calendario de turnos, un extracto de ERP) y pídele a Dexter que construya la programación; perfila los datos y genera las liberaciones y acciones por ti. Así es como conviertes un archivo operativo en una programación sin escribir a mano cada liberación.
Programaciones en los datos de resultados
Cada corrida contra una programación materializa una tablaschedule_definition en los dataframes de resultados, una fila por entrada atómica:
- Una acción programada con N acciones internas se expande a N filas, discriminadas por
action_index; las liberaciones de material son una fila cada una. entry_typees uno dematerial_release,scheduled_assignoscheduled_emit.- Las columnas están tipadas por entrada: las liberaciones llevan
element_id,entity_type_id,quantityyattributes_json(el diccionario de asignación codificado en JSON, poblado solo en liberaciones con sobrescrituras por liberación); las asignaciones programadas llevanvariable_nameyvalue_expr; las emisiones programadas llevantopic.condition_expr(la condición DSL sin evaluar, nula cuando no hay condición) aplica solo a acciones, yaction_indexes nulo en las filas de liberación. - Cada entrada se registra por adelantado, así que una acción condicionada aparece en la tabla incluso si su condición nunca evalúa como verdadera en tiempo de ejecución: la fila registra lo que declaró el plan, no lo que se disparó.
Consejos
- Todo modelo serio necesita una programación. Las llegadas sintéticas están bien para la primera pasada; las programaciones reales son necesarias para resultados comparables.
- Usa marcas de tiempo de reloj absolutas de forma consistente. Es tentador pensar en desfases relativos (“libera en +3600s”), pero cada evento necesita una marca de tiempo absoluta. Si estás bosquejando una programación en papel, calcula las marcas de tiempo absolutas a partir de tu Hora de Inicio base antes de ingresarlas.
- Condiciona las acciones programadas con una condición (pídeselo a Dexter) para depender del estado en tiempo de ejecución, por ejemplo, emitir un tema solo si una variable de estado está en un modo particular.
- Mantén la lógica a nivel de programación en la programación, y la lógica a nivel de componente en los Event Listeners. La programación emite la señal; el listener maneja los efectos secundarios.
- Usa varias programaciones para comparar escenarios. Patrones de turno, demanda estacional, casos de carga hipotéticos, planificación de capacidad bajo distintos supuestos: las programaciones son un eje de variación, la configuración del modelo el otro.
- El orden de eventos simultáneos no está especificado: no confíes en él. Si el orden importa entre dos eventos en la misma marca de tiempo, escalónalos por un segundo o encadénalos mediante un tema.
- Revisa la procedencia en los números de planificación. Las cantidades de liberación, los pesos de asignación y las condiciones de acción que Dexter escribe llevan una marca Datos / Indicado / Asumido en el panel de Evidencia: una revisión de supuestos hará salir a la superficie cualquier suposición en el plan.