├── simulation ├── __init__.py ├── gym │ ├── __init__.py │ ├── sample_envs.py │ ├── E.py │ └── environment.py ├── plugins │ ├── __init__.py │ ├── cost_plugin.py │ ├── interface.py │ ├── visualization_template.html │ ├── chart_plugin.py │ └── wandb_plugin.py ├── dispatching │ ├── __init__.py │ ├── dm_lot_for_machine.py │ ├── dispatcher.py │ └── dm_machine_for_lot.py ├── randomizer.py ├── dataset_preprocess.py ├── tools.py ├── read.py ├── event_queue.py ├── events.py ├── generator_instance.py ├── stats.py ├── file_instance.py ├── greedy.py ├── classes.py └── instance.py ├── .gitignore ├── docs ├── favicon.ico └── assets │ ├── img │ ├── logo_xs.png │ ├── bg │ │ ├── bg-home.jpg │ │ ├── bg-action.jpg │ │ ├── bg-client.jpg │ │ ├── bg-quote.jpg │ │ ├── bg-milestone.jpg │ │ └── bg-corporate.svg │ ├── logo_small.png │ ├── user │ │ ├── user-1.jpg │ │ ├── user-2.jpg │ │ └── user-3.jpg │ ├── carousel │ │ ├── carousel-1.jpg │ │ ├── carousel-2.jpg │ │ └── carousel-3.jpg │ └── portfolio │ │ ├── asmc_paper.png │ │ ├── wsc_paper.png │ │ ├── es_preprint.png │ │ ├── asmc_2023_poster.pdf │ │ ├── asmc_2023_poster.png │ │ ├── asmc_presentation.pdf │ │ ├── asmc_presentation.png │ │ ├── wsc_presentation.pdf │ │ └── wsc_presentation.png │ └── css │ ├── webfonts │ ├── fa-brands-400.ttf │ ├── fa-solid-900.ttf │ ├── fa-brands-400.woff2 │ ├── fa-regular-400.ttf │ ├── fa-regular-400.woff2 │ ├── fa-solid-900.woff2 │ ├── fa-v4compatibility.ttf │ └── fa-v4compatibility.woff2 │ └── one-page-parallax │ ├── fonts │ ├── bootstrap-icons.woff │ └── bootstrap-icons.woff2 │ └── images │ └── bg-content-cover.png ├── datasets ├── SMT2020_HVLM │ ├── fromto.txt │ ├── part.txt │ ├── setupgrp.txt │ ├── setup.txt │ ├── order.txt │ ├── downcal.txt │ ├── attach.txt │ └── tool.txt.1l └── SMT2020_LVHM │ ├── fromto.txt │ ├── setupgrp.txt │ ├── setup.txt │ ├── part.txt │ ├── downcal.txt │ ├── order.txt │ ├── attach.txt │ └── tool.txt.1l ├── reproduce_dispatcher_experiments.sh ├── gui.html ├── env_test.py ├── main.py ├── README.md ├── test_rl_agents.py ├── greedy_runner.py ├── requirements.txt ├── exp_set_gen.py ├── rl_train.py ├── rl_test.py └── eval_results.py /simulation/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | venv/ -------------------------------------------------------------------------------- /simulation/gym/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /simulation/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /simulation/dispatching/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/favicon.ico -------------------------------------------------------------------------------- /datasets/SMT2020_HVLM/fromto.txt: -------------------------------------------------------------------------------- 1 | FROMLOC TOLOC DDIST DTIME DTIME2 DUNITS 2 | Fab Fab uniform 7.5 2.5 min 3 | -------------------------------------------------------------------------------- /datasets/SMT2020_LVHM/fromto.txt: -------------------------------------------------------------------------------- 1 | FROMLOC TOLOC DDIST DTIME DTIME2 DUNITS 2 | Fab Fab uniform 7.5 2.5 min 3 | -------------------------------------------------------------------------------- /docs/assets/img/logo_xs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/logo_xs.png -------------------------------------------------------------------------------- /docs/assets/img/bg/bg-home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/bg/bg-home.jpg -------------------------------------------------------------------------------- /docs/assets/img/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/logo_small.png -------------------------------------------------------------------------------- /docs/assets/img/bg/bg-action.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/bg/bg-action.jpg -------------------------------------------------------------------------------- /docs/assets/img/bg/bg-client.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/bg/bg-client.jpg -------------------------------------------------------------------------------- /docs/assets/img/bg/bg-quote.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/bg/bg-quote.jpg -------------------------------------------------------------------------------- /docs/assets/img/user/user-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/user/user-1.jpg -------------------------------------------------------------------------------- /docs/assets/img/user/user-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/user/user-2.jpg -------------------------------------------------------------------------------- /docs/assets/img/user/user-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/user/user-3.jpg -------------------------------------------------------------------------------- /reproduce_dispatcher_experiments.sh: -------------------------------------------------------------------------------- 1 | mkdir greedy 2 | python3 greedy_runner.py 3 | python3 eval_results.py > greedy/_greedy_sum.txt -------------------------------------------------------------------------------- /docs/assets/img/bg/bg-milestone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/bg/bg-milestone.jpg -------------------------------------------------------------------------------- /docs/assets/img/carousel/carousel-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/carousel/carousel-1.jpg -------------------------------------------------------------------------------- /docs/assets/img/carousel/carousel-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/carousel/carousel-2.jpg -------------------------------------------------------------------------------- /docs/assets/img/carousel/carousel-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/carousel/carousel-3.jpg -------------------------------------------------------------------------------- /docs/assets/img/portfolio/asmc_paper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/portfolio/asmc_paper.png -------------------------------------------------------------------------------- /docs/assets/img/portfolio/wsc_paper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/portfolio/wsc_paper.png -------------------------------------------------------------------------------- /docs/assets/css/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /docs/assets/css/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /docs/assets/img/portfolio/es_preprint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/portfolio/es_preprint.png -------------------------------------------------------------------------------- /docs/assets/css/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /docs/assets/css/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /docs/assets/css/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /docs/assets/css/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /datasets/SMT2020_HVLM/part.txt: -------------------------------------------------------------------------------- 1 | PARTGRP PARTFAM PART ROUTEFILE ROUTE 2 | Saleable product_3 part_3 route_3.txt r_3 3 | Saleable product_4 part_4 route_4.txt r_4 4 | -------------------------------------------------------------------------------- /docs/assets/css/webfonts/fa-v4compatibility.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/webfonts/fa-v4compatibility.ttf -------------------------------------------------------------------------------- /docs/assets/img/portfolio/asmc_2023_poster.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/portfolio/asmc_2023_poster.pdf -------------------------------------------------------------------------------- /docs/assets/img/portfolio/asmc_2023_poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/portfolio/asmc_2023_poster.png -------------------------------------------------------------------------------- /docs/assets/img/portfolio/asmc_presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/portfolio/asmc_presentation.pdf -------------------------------------------------------------------------------- /docs/assets/img/portfolio/asmc_presentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/portfolio/asmc_presentation.png -------------------------------------------------------------------------------- /docs/assets/img/portfolio/wsc_presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/portfolio/wsc_presentation.pdf -------------------------------------------------------------------------------- /docs/assets/img/portfolio/wsc_presentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/img/portfolio/wsc_presentation.png -------------------------------------------------------------------------------- /docs/assets/css/webfonts/fa-v4compatibility.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/webfonts/fa-v4compatibility.woff2 -------------------------------------------------------------------------------- /docs/assets/css/one-page-parallax/fonts/bootstrap-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/one-page-parallax/fonts/bootstrap-icons.woff -------------------------------------------------------------------------------- /docs/assets/css/one-page-parallax/fonts/bootstrap-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/one-page-parallax/fonts/bootstrap-icons.woff2 -------------------------------------------------------------------------------- /docs/assets/css/one-page-parallax/images/bg-content-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prosysscience/PySCFabSim-release/HEAD/docs/assets/css/one-page-parallax/images/bg-content-cover.png -------------------------------------------------------------------------------- /datasets/SMT2020_HVLM/setupgrp.txt: -------------------------------------------------------------------------------- 1 | SETUPGRP SETUP MINRUN IGNORE 2 | Implant_Gas SU128_1 7 Implant_128 3 | SU128_2 7 Implant_128 4 | SU128_3 7 Implant_128 5 | SU132_1 7 Implant_132 6 | SU132_2 7 Implant_132 7 | SU132_3 7 Implant_132 8 | SU91_1 7 Implant_91 9 | SU91_2 7 Implant_91 10 | SU91_3 7 Implant_91 11 | -------------------------------------------------------------------------------- /datasets/SMT2020_LVHM/setupgrp.txt: -------------------------------------------------------------------------------- 1 | SETUPGRP SETUP MINRUN IGNORE 2 | Implant_Gas SU128_1 7 Implant_128 3 | SU128_2 7 Implant_128 4 | SU128_3 7 Implant_128 5 | SU132_1 7 Implant_132 6 | SU132_2 7 Implant_132 7 | SU132_3 7 Implant_132 8 | SU91_1 7 Implant_91 9 | SU91_2 7 Implant_91 10 | SU91_3 7 Implant_91 11 | -------------------------------------------------------------------------------- /gui.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simulator gui 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /env_test.py: -------------------------------------------------------------------------------- 1 | import gym 2 | import simulation.gym 3 | from simulation.gym.environment import DynamicSCFabSimulationEnvironment 4 | 5 | env = gym.make('DynamicSCFabSimulation-10days-v0') 6 | state, done = env.reset(), False 7 | ret = 0 8 | steps = 0 9 | while not done: 10 | action = env.action_space.sample() 11 | state, reward, done, info = env.step(action) 12 | ret += reward 13 | steps += 1 14 | 15 | print(f"Return {ret} steps {steps}") 16 | 17 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from simulation.greedy import run_greedy 2 | import sys 3 | 4 | sys.path.insert(0, '.') 5 | 6 | 7 | def main(): 8 | profile = False 9 | if profile: 10 | from pyinstrument import Profiler 11 | 12 | p = Profiler() 13 | p.start() 14 | 15 | run_greedy() 16 | print() 17 | print() 18 | 19 | if profile: 20 | p.stop() 21 | p.open_in_browser() 22 | 23 | 24 | if __name__ == '__main__': 25 | main() 26 | -------------------------------------------------------------------------------- /datasets/SMT2020_HVLM/setup.txt: -------------------------------------------------------------------------------- 1 | CURSETUP NEWSETUP STIME STUNITS IGNORE 2 | DE_BE_13_1 DE_BE_13_2 7 min DE_BE_13 3 | DE_BE_13_2 DE_BE_13_1 12 min DE_BE_13 4 | DE_BE_66_1 DE_BE_66_2 15 min DE_BE_66 5 | DE_BE_66_2 DE_BE_66_1 10 min DE_BE_66 6 | SU128_1 72 min Implant_128 7 | SU128_2 72 min Implant_128 8 | SU128_3 72 min Implant_128 9 | SU132_1 60 min Implant_132 10 | SU132_2 60 min Implant_132 11 | SU132_3 60 min Implant_132 12 | SU91_1 80 min Implant_91 13 | SU91_2 80 min Implant_91 14 | SU91_3 80 min Implant_91 15 | -------------------------------------------------------------------------------- /datasets/SMT2020_LVHM/setup.txt: -------------------------------------------------------------------------------- 1 | CURSETUP NEWSETUP STIME STUNITS IGNORE 2 | DE_BE_13_1 DE_BE_13_2 7 min DE_BE_13 3 | DE_BE_13_2 DE_BE_13_1 12 min DE_BE_13 4 | DE_BE_66_1 DE_BE_66_2 15 min DE_BE_66 5 | DE_BE_66_2 DE_BE_66_1 10 min DE_BE_66 6 | SU128_1 72 min Implant_128 7 | SU128_2 72 min Implant_128 8 | SU128_3 72 min Implant_128 9 | SU132_1 60 min Implant_132 10 | SU132_2 60 min Implant_132 11 | SU132_3 60 min Implant_132 12 | SU91_1 80 min Implant_91 13 | SU91_2 80 min Implant_91 14 | SU91_3 80 min Implant_91 15 | -------------------------------------------------------------------------------- /datasets/SMT2020_LVHM/part.txt: -------------------------------------------------------------------------------- 1 | PARTGRP PARTFAM PART ROUTEFILE ROUTE 2 | Saleable product_1 part_1 route_1.txt r_1 3 | Saleable product_2 part_2 route_2.txt r_2 4 | Saleable product_3 part_3 route_3.txt r_3 5 | Saleable product_4 part_4 route_4.txt r_4 6 | Saleable product_5 part_5 route_5.txt r_5 7 | Saleable product_6 part_6 route_6.txt r_6 8 | Saleable product_7 part_7 route_7.txt r_7 9 | Saleable product_8 part_8 route_8.txt r_8 10 | Saleable product_9 part_9 route_9.txt r_9 11 | Saleable product_10 part_10 route_10.txt r_10 12 | -------------------------------------------------------------------------------- /simulation/randomizer.py: -------------------------------------------------------------------------------- 1 | import os 2 | from random import Random 3 | 4 | 5 | class Singleton(type): 6 | _instances = {} 7 | 8 | def __call__(cls, *args, **kwargs): 9 | if cls not in cls._instances: 10 | cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) 11 | return cls._instances[cls] 12 | 13 | 14 | class Randomizer(metaclass=Singleton): 15 | def __init__(self): 16 | random_seed = int(os.environ['SEED']) if 'SEED' in os.environ else None 17 | self.random = Random(random_seed) 18 | -------------------------------------------------------------------------------- /datasets/SMT2020_HVLM/order.txt: -------------------------------------------------------------------------------- 1 | LOT PART PRIOR PIECES START RDIST REPEAT RUNITS RPT# LOTSPERRPT DUE ORDER HOTLOT 2 | Lot_3 part_3 10 25 01/01/18 00:00:00 constant 51.69 min 200000 1 02/23/18 20:07:47 O_Lot_3 no 3 | Lot_4 part_4 10 25 01/01/18 00:00:00 constant 51.69 min 200000 1 01/31/18 07:29:20 O_Lot_4 no 4 | HotLot_3 part_3 20 25 01/01/18 00:00:00 constant 2016 min 20000 1 02/03/18 07:59:15 O_HotLot_3 no 5 | HotLot_4 part_4 20 25 01/01/18 00:00:00 constant 2016 min 20000 1 01/20/18 13:17:36 O_HotLot_4 no 6 | SuperHotLot_3 part_3 30 25 01/01/18 00:00:00 constant 27397.61 min 2000 1 02/03/18 05:13:01 O_SuperHotLot_3 no 7 | -------------------------------------------------------------------------------- /simulation/gym/sample_envs.py: -------------------------------------------------------------------------------- 1 | from simulation.gym.E import E 2 | 3 | DEMO_ENV_1 = { 4 | 'action': E.A.CHOOSE_LOT_FOR_FREE_MACHINE, 5 | 'state_components': ( 6 | E.A.L4M.S.MACHINE.SETUP_PROCESSING_RATIO, 7 | E.A.L4M.S.MACHINE.IDLE_RATIO, 8 | E.A.L4M.S.MACHINE.MAINTENANCE.NEXT, 9 | E.A.L4M.S.OPERATION_TYPE.NO_LOTS_PER_BATCH, 10 | E.A.L4M.S.OPERATION_TYPE.CR.MAX, 11 | E.A.L4M.S.OPERATION_TYPE.FREE_SINCE.MAX, 12 | E.A.L4M.S.OPERATION_TYPE.SETUP.MIN_RUNS_OK, 13 | E.A.L4M.S.OPERATION_TYPE.SETUP.NEEDED, 14 | E.A.L4M.S.OPERATION_TYPE.SETUP.LAST_SETUP_TIME, 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reproduction of experiments 2 | 3 | ## Install requirements (suggested to run in a new virtual environment) 4 | 5 | ```shell 6 | pip install -r requirements.txt 7 | ``` 8 | 9 | 10 | ## Test FIFO and CR dispatching startegies 11 | 12 | ```shell 13 | ./reproduce_dispatcher_experiments.sh 14 | ``` 15 | 16 | ## Dataset 17 | 18 | Our simulator uses the SMT2020 dataset. It is available on https://p2schedgen.fernuni-hagen.de/index.php/downloads/simulation 19 | 20 | Kopp, Denny & Hassoun, Michael & Kalir, Adar & Mönch, Lars. (2020). SMT2020—A Semiconductor Manufacturing Testbed. IEEE Transactions on Semiconductor Manufacturing. PP. 1-1. 10.1109/TSM.2020.3001933. -------------------------------------------------------------------------------- /simulation/plugins/cost_plugin.py: -------------------------------------------------------------------------------- 1 | from simulation.plugins.interface import IPlugin 2 | 3 | 4 | class CostPlugin(IPlugin): 5 | 6 | def on_sim_done(self, instance): 7 | super().on_sim_done(instance) 8 | self.cost = 0 9 | for lot in instance.done_lots: 10 | self.cost += 25 if lot.deadline_at < lot.done_at else 0 11 | self.cost += max(0, lot.done_at - lot.deadline_at) / 3600 / 24 12 | self.cost += len(instance.active_lots) * 200 13 | self.done_lots = len(instance.done_lots) 14 | 15 | def get_output_name(self): 16 | super().get_output_name() 17 | return 'cost' 18 | 19 | def get_output_value(self): 20 | return self.cost 21 | -------------------------------------------------------------------------------- /test_rl_agents.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os 3 | import subprocess 4 | import time 5 | from os import listdir, path, mkdir 6 | 7 | root = 'experiments' 8 | 9 | dirs = listdir(root) 10 | while True: 11 | for d in sorted(dirs): 12 | for checkpoint in [50000, 100000, 150000, 200000, 300000, 400000, 500000, 600000, 800000, 1000000, 1200000, 1400000, 1600000, 1800000, 2000000]: 13 | report_loc = path.join(root, d, f'report_{checkpoint}.txt') 14 | weights_loc = f'checkpoint__{checkpoint}_steps.zip' 15 | if path.exists(path.join(root, d, weights_loc)) and not path.exists(report_loc): 16 | print(d) 17 | with io.open(report_loc, 'w') as f: 18 | subprocess.call(['python3', 'rl_test.py', path.join(root, d), weights_loc], 19 | stdout=f) 20 | 21 | 22 | print('No more experiments to run.') 23 | time.sleep(10) 24 | 25 | -------------------------------------------------------------------------------- /datasets/SMT2020_HVLM/downcal.txt: -------------------------------------------------------------------------------- 1 | DOWNCALNAME DOWNCALTYPE MTTFDIST MTTF MTTFUNITS MTTRDIST MTTR MTTRUNITS IGNORE 2 | BREAK_Def_Met mttf_by_cal exponential 10080 min exponential 35.28 min Def_Met 3 | BREAK_Dielectric mttf_by_cal exponential 10080 min exponential 604.8 min Dielectric 4 | BREAK_Diffusion mttf_by_cal exponential 10080 min exponential 151.2 min Diffusion 5 | BREAK_Dry_Etch mttf_by_cal exponential 10080 min exponential 231.84 min Dry_Etch 6 | BREAK_Implant mttf_by_cal exponential 10080 min exponential 604.8 min Implant 7 | BREAK_Litho mttf_by_cal exponential 10080 min exponential 705.59 min Litho 8 | BREAK_Litho_Met mttf_by_cal exponential 10080 min exponential 35.28 min Litho_Met 9 | BREAK_Planar mttf_by_cal exponential 10080 min exponential 201.6 min Planar 10 | BREAK_TF mttf_by_cal exponential 10080 min exponential 453.6 min TF 11 | BREAK_TF_Met mttf_by_cal exponential 10080 min exponential 35.28 min TF_Met 12 | BREAK_Wet_Etch mttf_by_cal exponential 10080 min exponential 221.76 min Wet_Etch 13 | -------------------------------------------------------------------------------- /datasets/SMT2020_LVHM/downcal.txt: -------------------------------------------------------------------------------- 1 | DOWNCALNAME DOWNCALTYPE MTTFDIST MTTF MTTFUNITS MTTRDIST MTTR MTTRUNITS IGNORE 2 | BREAK_Def_Met mttf_by_cal exponential 10080 min exponential 35.28 min Def_Met 3 | BREAK_Dielectric mttf_by_cal exponential 10080 min exponential 604.8 min Dielectric 4 | BREAK_Diffusion mttf_by_cal exponential 10080 min exponential 151.2 min Diffusion 5 | BREAK_Dry_Etch mttf_by_cal exponential 10080 min exponential 231.84 min Dry_Etch 6 | BREAK_Implant mttf_by_cal exponential 10080 min exponential 604.8 min Implant 7 | BREAK_Litho mttf_by_cal exponential 10080 min exponential 705.59 min Litho 8 | BREAK_Litho_Met mttf_by_cal exponential 10080 min exponential 35.28 min Litho_Met 9 | BREAK_Planar mttf_by_cal exponential 10080 min exponential 201.6 min Planar 10 | BREAK_TF mttf_by_cal exponential 10080 min exponential 453.6 min TF 11 | BREAK_TF_Met mttf_by_cal exponential 10080 min exponential 35.28 min TF_Met 12 | BREAK_Wet_Etch mttf_by_cal exponential 10080 min exponential 221.76 min Wet_Etch 13 | -------------------------------------------------------------------------------- /greedy_runner.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os 3 | import subprocess 4 | import threading 5 | import time 6 | 7 | threads = [] 8 | 9 | if not os.path.exists('greedy'): 10 | os.mkdir('greedy') 11 | 12 | for seed in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]: 13 | for day in [365*2]: 14 | for dataset, dispatcher in [('HVLM', 'fifo'), ('LVHM', 'cr')]: 15 | def s(day_, dataset_, dispatcher_): 16 | name_ = f'greedy/greedy_seed{seed}_{day}days_{dataset}_{dispatcher}.txt' 17 | with io.open(name_, 'w') as f: 18 | print(name_) 19 | subprocess.call(['pypy3', 'main.py', '--days', str(day_), 20 | '--dataset', dataset_, '--dispatcher', dispatcher_, '--seed', str(seed), 21 | '--alg', 'l4m'], stdout=f) 22 | 23 | 24 | t = threading.Thread(target=s, args=(day, dataset, dispatcher)) 25 | t.start() 26 | time.sleep(2) 27 | threads.append(t) 28 | 29 | for t in threads: 30 | t.join() 31 | 32 | print('Done') 33 | -------------------------------------------------------------------------------- /simulation/plugins/interface.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod, ABCMeta 2 | 3 | 4 | class IPlugin(metaclass=ABCMeta): 5 | def on_sim_init(self, instance): 6 | pass 7 | 8 | def on_sim_done(self, instance): 9 | pass 10 | 11 | def on_lots_release(self, instance, lots): 12 | pass 13 | 14 | def on_lot_done(self, instance, lot): 15 | pass 16 | 17 | def on_step_done(self, instance, lot, step): 18 | pass 19 | 20 | def on_dispatch(self, instance, machine, lots, machine_end_time, lot_end_time): 21 | pass 22 | 23 | def on_machine_free(self, instance, machine): 24 | pass 25 | 26 | def on_lot_free(self, instance, lot): 27 | pass 28 | 29 | def on_breakdown(self, machine, breakdown_event): 30 | pass 31 | 32 | def on_preventive_maintenance(self, machine, preventive_maintenance_event): 33 | pass 34 | 35 | def get_output_name(self): 36 | return None 37 | 38 | def get_output_value(self): 39 | raise NotImplementedError() 40 | 41 | def on_cqt_violated(self, instance, machine, lot): 42 | pass 43 | -------------------------------------------------------------------------------- /simulation/dataset_preprocess.py: -------------------------------------------------------------------------------- 1 | class RemoveBreakdowns: 2 | 3 | def preprocess(self, files): 4 | files['attach.txt'] = [r for r in files['attach.txt'] if r['CALTYPE'] != 'down'] 5 | files['downcal.txt'] = [] 6 | return files 7 | 8 | 9 | class RemovePreventiveMaintenance: 10 | 11 | def preprocess(self, files): 12 | files['attach.txt'] = [r for r in files['attach.txt'] if r['CALTYPE'] != 'pm'] 13 | files['pmcal.txt'] = [] 14 | return files 15 | 16 | 17 | class RemoveWIP: 18 | 19 | def preprocess(self, files): 20 | files['WIP.txt'] = [] 21 | return files 22 | 23 | 24 | class RemoveRework: 25 | 26 | def preprocess(self, files): 27 | for name, val in files.items(): 28 | if 'route' in name: 29 | for v in val: 30 | v['REWORK'] = None 31 | return files 32 | 33 | 34 | class RemoveSampling: 35 | 36 | def preprocess(self, files): 37 | for name, val in files.items(): 38 | if 'route' in name: 39 | for v in val: 40 | v['StepPercent'] = None 41 | return files 42 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | absl-py==1.0.0 2 | atari-py==0.2.9 3 | cachetools==4.2.4 4 | certifi==2021.10.8 5 | charset-normalizer==2.0.9 6 | click==8.0.3 7 | cloudpickle==1.6.0 8 | configparser==5.2.0 9 | cycler==0.11.0 10 | docker-pycreds==0.4.0 11 | fonttools==4.28.4 12 | gitdb==4.0.9 13 | GitPython==3.1.24 14 | google-auth==2.3.3 15 | google-auth-oauthlib==0.4.6 16 | grpcio==1.43.0 17 | gym==0.19.0 18 | idna==3.3 19 | importlib-metadata==4.9.0 20 | kiwisolver==1.3.2 21 | Markdown==3.3.6 22 | matplotlib==3.5.1 23 | numpy==1.21.4 24 | oauthlib==3.1.1 25 | opencv-python==4.5.4.60 26 | packaging==21.3 27 | pandas==1.3.5 28 | pathtools==0.1.2 29 | Pillow==8.4.0 30 | promise==2.3 31 | protobuf==3.19.1 32 | psutil==5.8.0 33 | pyasn1==0.4.8 34 | pyasn1-modules==0.2.8 35 | pyparsing==3.0.6 36 | python-dateutil==2.8.2 37 | pytz==2021.3 38 | PyYAML==6.0 39 | requests==2.26.0 40 | requests-oauthlib==1.3.0 41 | rsa==4.8 42 | sentry-sdk==1.5.1 43 | shortuuid==1.0.8 44 | six==1.16.0 45 | smmap==5.0.0 46 | stable-baselines3==1.3.0 47 | subprocess32==3.5.4 48 | tensorboard==2.7.0 49 | tensorboard-data-server==0.6.1 50 | tensorboard-plugin-wit==1.8.0 51 | termcolor==1.1.0 52 | torch==1.10.1 53 | typing-extensions==4.0.1 54 | urllib3==1.26.7 55 | wandb==0.12.9 56 | Werkzeug==2.0.2 57 | yaspin==2.1.0 58 | zipp==3.6.0 59 | 60 | pyinstrument~=4.1.1 -------------------------------------------------------------------------------- /simulation/plugins/visualization_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Chart 4 | 5 | 6 | 7 | 8 | 34 | 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /exp_set_gen.py: -------------------------------------------------------------------------------- 1 | import io 2 | import json 3 | import os.path 4 | from os import mkdir, path 5 | 6 | root = 'experiments' 7 | if not os.path.exists(root): 8 | mkdir(root) 9 | 10 | stngrps = [ 11 | '', 12 | ] 13 | 14 | for seed in [0]: 15 | for dataset, dispatcher in [('HVLM', 'fifo')]: 16 | for action_count in [9]: 17 | for training_period in [365 * 2]: 18 | for reward in [2]: 19 | for stngrp in stngrps: 20 | case_name = f'{seed}_ds_{dataset}_a{action_count}_tp{training_period}_reward{reward}_di_{dispatcher}_{str(stngrp)[:2]}' 21 | d = path.join(root, case_name) 22 | mkdir(d) 23 | with io.open(path.join(d, 'config.json'), 'w') as f: 24 | case = { 25 | 'name': case_name, 26 | 'params': { 27 | 'seed': seed, 28 | 'dataset': dataset, 29 | 'action_count': action_count, 30 | 'training_period': training_period, 31 | 'dispatcher': dispatcher, 32 | 'reward': reward, 33 | 'station_group': stngrp, 34 | } 35 | } 36 | json.dump(case, f, indent=2) 37 | -------------------------------------------------------------------------------- /simulation/tools.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from simulation.randomizer import Randomizer 4 | 5 | r = Randomizer() 6 | 7 | 8 | def get_interval(num, unit): 9 | units = {'sec': 1, 's': 1, 'min': 60, 'hr': 3600, 'day': 86400, 'pieces': 1, '': 1} 10 | if num is None: 11 | return None 12 | if unit in units: 13 | return num * units[unit] 14 | else: 15 | raise ValueError(f'Unit {unit} not known.') 16 | 17 | 18 | class UniformDistribution: 19 | 20 | def __init__(self, m, l): 21 | self.m, self.l = m, l 22 | 23 | def sample(self): 24 | return r.random.uniform(self.m - self.l / 2, self.m + self.l / 2) 25 | 26 | def avg(self): 27 | return self.m 28 | 29 | 30 | class ConstantDistribution: 31 | 32 | def __init__(self, c): 33 | self.c = c 34 | 35 | def sample(self): 36 | return self.c 37 | 38 | def avg(self): 39 | return self.c 40 | 41 | 42 | class ExponentialDistribution: 43 | 44 | def __init__(self, p): 45 | self.p = p 46 | 47 | def sample(self): 48 | return r.random.expovariate(1 / self.p) 49 | 50 | 51 | def get_distribution(typ, unit, *args, multiplier=1): 52 | arr = [multiplier * get_interval(a, unit) for a in args if a is not None] 53 | if typ == 'uniform': 54 | return UniformDistribution(*arr) 55 | if typ == 'constant': 56 | return ConstantDistribution(*arr) 57 | if typ == 'exponential': 58 | return ExponentialDistribution(*arr) 59 | 60 | 61 | def date_time_parse(st): 62 | return datetime.datetime.strptime(st, '%m/%d/%y %H:%M:%S') 63 | -------------------------------------------------------------------------------- /simulation/dispatching/dm_lot_for_machine.py: -------------------------------------------------------------------------------- 1 | 2 | class LotForMachineDispatchManager: 3 | 4 | @staticmethod 5 | def init(self): 6 | self.free_machines = [False for _ in self.machines] 7 | self.usable_machines = set() 8 | 9 | @staticmethod 10 | def free_up_lots(self, lot): 11 | for machine in self.family_machines[lot.actual_step.family]: 12 | di = lot.actual_step.order 13 | if di not in lot.dedications or machine.idx == lot.dedications[di]: 14 | machine.waiting_lots.append(lot) 15 | lot.waiting_machines.append(machine) 16 | if self.free_machines[machine.idx]: 17 | self.usable_machines.add(machine) 18 | 19 | @staticmethod 20 | def free_up_machine(self, machine): 21 | assert not self.free_machines[machine.idx] 22 | self.free_machines[machine.idx] = True 23 | if len(machine.waiting_lots) > 0: 24 | self.usable_machines.add(machine) 25 | 26 | @staticmethod 27 | def reserve(self, lots, machine): 28 | self.free_machines[machine.idx] = False 29 | self.usable_machines.remove(machine) 30 | for lot in lots: 31 | for mx in lot.waiting_machines: 32 | mx.waiting_lots.remove(lot) 33 | if len(mx.waiting_lots) == 0 and mx in self.usable_machines: 34 | self.usable_machines.remove(mx) 35 | lot.waiting_machines.clear() 36 | 37 | @staticmethod 38 | def next_decision_point(self): 39 | while len(self.usable_machines) == 0 and not self.done: 40 | self.next_step() 41 | return self.done 42 | 43 | -------------------------------------------------------------------------------- /simulation/read.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os 3 | from collections import defaultdict 4 | from os import environ 5 | 6 | from simulation.dataset_preprocess import RemoveBreakdowns, RemoveWIP, RemoveRework, RemoveSampling, \ 7 | RemovePreventiveMaintenance 8 | 9 | 10 | def try_to_num(inp: str): 11 | try: 12 | return int(inp) 13 | except Exception: 14 | try: 15 | return float(inp) 16 | except Exception: 17 | return inp 18 | 19 | 20 | def read_txt(path): 21 | with io.open(path, 'r') as f: 22 | lines = f.read().split('\n') 23 | headers, lines = lines[0].split('\t'), lines[1:] 24 | dicts = [] 25 | for line in lines: 26 | cols = line.split('\t') 27 | d = defaultdict(lambda: None) 28 | all_none = True 29 | for header, col in zip(headers, cols): 30 | if header.upper() != 'IGNORE': 31 | col = try_to_num(col) 32 | d[header] = col 33 | if col is not None: 34 | all_none = False 35 | if len(line) > 0 and len(d) > 0 and not all_none: 36 | dicts.append(d) 37 | return dicts 38 | 39 | 40 | def read_all(d, preprocessors=None): 41 | files = defaultdict(lambda: []) 42 | for file in os.listdir(d): 43 | if '.txt' in file: 44 | files[file] = read_txt(os.path.join(d, file)) 45 | if preprocessors is None: 46 | preprocessors = [] 47 | if 'NOWIP' in environ: 48 | preprocessors.append(RemoveWIP()) 49 | if 'NOBREAKDOWN' in environ: 50 | preprocessors.append(RemoveBreakdowns()) 51 | if 'NOPM' in environ: 52 | preprocessors.append(RemovePreventiveMaintenance()) 53 | if 'NOREWORK' in environ: 54 | preprocessors.append(RemoveRework()) 55 | if 'NOSAMPLING' in environ: 56 | preprocessors.append(RemoveSampling()) 57 | if preprocessors is not None: 58 | for p in preprocessors: 59 | files = p.preprocess(files) 60 | return files 61 | -------------------------------------------------------------------------------- /simulation/gym/E.py: -------------------------------------------------------------------------------- 1 | class E: 2 | class A: 3 | CHOOSE_LOT_FOR_FREE_MACHINE = 100001 4 | CHOOSE_MACHINE_FOR_FREE_LOT = 100002 5 | CHOOSE_LOT_TO_DISPATCH = 100003 6 | 7 | class L4M: 8 | class S: 9 | class GLOBAL: 10 | pass 11 | 12 | class MACHINE: 13 | class MAINTENANCE: 14 | NEXT = 4010101 15 | 16 | SETUP_PROCESSING_RATIO = 4010010 17 | IDLE_RATIO = 4010020 18 | MACHINE_CLASS = 4010030 19 | 20 | class OPERATION_TYPE: 21 | NO_LOTS = 4030010 22 | NO_LOTS_PER_BATCH = 4030020 23 | 24 | class STEPS_LEFT: 25 | MIN = 4030101 26 | MEAN = 4030102 27 | MEDIAN = 4030103 28 | MAX = 4030104 29 | 30 | class FREE_SINCE: 31 | MIN = 4030201 32 | MEAN = 4030202 33 | MEDIAN = 4030203 34 | MAX = 4030204 35 | 36 | class PRIORITY: 37 | MIN = 4030401 38 | MEAN = 4030402 39 | MEDIAN = 4030403 40 | MAX = 4030404 41 | 42 | class PROCESSING_TIME: 43 | AVERAGE = 4030501 44 | 45 | class BATCH: 46 | MIN = 4030601 47 | MAX = 4030602 48 | FULLNESS = 4030603 49 | 50 | class CR: 51 | MIN = 4030701 52 | MEAN = 4030703 53 | MEDIAN = 4030703 54 | MAX = 4030704 55 | 56 | class SETUP: 57 | NEEDED = 4030801 58 | MIN_RUNS_LEFT = 4030802 59 | MIN_RUNS_OK = 4030803 60 | LAST_SETUP_TIME = 4030804 61 | -------------------------------------------------------------------------------- /rl_train.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import json 3 | import os 4 | import sys 5 | import time 6 | 7 | import wandb 8 | 9 | from stable_baselines3 import PPO 10 | 11 | from wandb.integration.sb3 import WandbCallback 12 | 13 | from simulation.gym.environment import DynamicSCFabSimulationEnvironment 14 | from stable_baselines3.common.callbacks import CheckpointCallback 15 | 16 | from sys import argv 17 | 18 | from simulation.gym.sample_envs import DEMO_ENV_1 19 | 20 | 21 | def main(): 22 | to_train = 1000000 23 | t = time.time() 24 | 25 | class MyCallBack(CheckpointCallback): 26 | 27 | def on_step(self) -> bool: 28 | if self.num_timesteps % 100 == 0: 29 | ratio = self.num_timesteps / to_train 30 | perc = round(ratio * 100) 31 | remaining = (time.time() - t) / ratio * (1 - ratio) if ratio > 0 else 9999999999999 32 | remaining /= 3600 33 | 34 | sys.stderr.write(f'\r{self.num_timesteps} / {to_train} {perc}% {round(remaining, 2)} hours left {env.instance.current_time_days} ') 35 | return super().on_step() 36 | 37 | fn = argv[1] 38 | with open(fn, 'r') as config: 39 | p = json.load(config)['params'] 40 | args = dict(num_actions=p['action_count'], active_station_group=p['station_group'], 41 | days=p['training_period'], dataset='SMT2020_' + p['dataset'], 42 | dispatcher=p['dispatcher']) 43 | env = DynamicSCFabSimulationEnvironment(**DEMO_ENV_1, **args, seed=p['seed'], max_steps=1000000, reward_type=p['reward']) 44 | eval_env = DynamicSCFabSimulationEnvironment(**DEMO_ENV_1, **args, seed=777, max_steps=10000, reward_type=p['reward']) 45 | model = PPO("MlpPolicy", env, verbose=1) 46 | 47 | p = os.path.dirname(os.path.realpath(fn)) 48 | checkpoint_callback = MyCallBack(save_freq=100000, save_path=p, name_prefix='checkpoint_') 49 | model.learn( 50 | total_timesteps=to_train, eval_freq=4000000, eval_env=eval_env, n_eval_episodes=1, 51 | callback=checkpoint_callback 52 | ) 53 | model.save(os.path.join(p, 'trained.weights')) 54 | 55 | 56 | if __name__ == '__main__': 57 | main() 58 | -------------------------------------------------------------------------------- /datasets/SMT2020_LVHM/order.txt: -------------------------------------------------------------------------------- 1 | LOT PART PRIOR PIECES START RDIST REPEAT RUNITS RPT# LOTSPERRPT DUE ORDER HOTLOT 2 | Lot_1 part_1 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 02/19/18 18:41:46 O_Lot_1 no 3 | Lot_2 part_2 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 02/22/18 11:05:59 O_Lot_2 no 4 | Lot_3 part_3 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 02/26/18 08:27:35 O_Lot_3 no 5 | Lot_4 part_4 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 02/02/18 04:30:02 O_Lot_4 no 6 | Lot_5 part_5 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 01/24/18 18:49:41 O_Lot_5 no 7 | Lot_6 part_6 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 01/30/18 23:03:00 O_Lot_6 no 8 | Lot_7 part_7 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 02/05/18 00:53:39 O_Lot_7 no 9 | Lot_8 part_8 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 02/07/18 22:42:05 O_Lot_8 no 10 | Lot_9 part_9 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 02/09/18 00:24:20 O_Lot_9 no 11 | Lot_10 part_10 10 25 01/01/18 00:00:00 constant 258.46 min 200000 1 02/10/18 02:18:05 O_Lot_10 no 12 | HotLot_1 part_1 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 02/03/18 22:41:51 O_HotLot_1 no 13 | HotLot_2 part_2 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 02/06/18 05:43:47 O_HotLot_2 no 14 | HotLot_3 part_3 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 02/08/18 07:05:01 O_HotLot_3 no 15 | HotLot_4 part_4 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 01/24/18 01:49:09 O_HotLot_4 no 16 | HotLot_5 part_5 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 01/17/18 20:54:20 O_HotLot_5 no 17 | HotLot_6 part_6 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 01/21/18 22:30:42 O_HotLot_6 no 18 | HotLot_7 part_7 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 01/25/18 00:45:18 O_HotLot_7 no 19 | HotLot_8 part_8 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 01/26/18 09:57:25 O_HotLot_8 no 20 | HotLot_9 part_9 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 01/27/18 18:09:27 O_HotLot_9 no 21 | HotLot_10 part_10 20 25 01/01/18 00:00:00 constant 10080 min 20000 1 01/28/18 18:30:14 O_HotLot_10 no 22 | SuperHotLot_3 part_3 30 25 01/01/18 00:00:00 constant 28258.37 min 2000 1 02/08/18 07:05:01 O_SuperHotLot_3 no 23 | -------------------------------------------------------------------------------- /simulation/event_queue.py: -------------------------------------------------------------------------------- 1 | class EventQueue: 2 | def __init__(self): 3 | self.arr = [] 4 | 5 | @property 6 | def first(self): 7 | return self.arr[0] 8 | 9 | @property 10 | def empty(self): 11 | return len(self.arr) == 0 12 | 13 | def pop_first(self): 14 | return self.arr.pop(0) 15 | 16 | def push(self, item): 17 | self.arr.append(item) 18 | 19 | def ordered_insert(self, item): 20 | if len(self.arr) == 0 or item.timestamp < self.arr[0].timestamp: 21 | self.arr.insert(0, item) 22 | elif item.timestamp > self.arr[-1].timestamp: 23 | self.arr.append(item) 24 | else: 25 | lo = 0 26 | hi = len(self.arr) 27 | while lo < hi: 28 | mid = (lo + hi) // 2 29 | if item.timestamp < self.arr[mid].timestamp: 30 | hi = mid 31 | else: 32 | lo = mid + 1 33 | self.arr.insert(lo, item) 34 | 35 | def remove(self, remove): 36 | self.arr.remove(remove) 37 | 38 | 39 | class LNode: 40 | def __init__(self, value, nx): 41 | self.value = value 42 | self.next: LNode = nx 43 | 44 | 45 | class LinkedList: 46 | def __init__(self): 47 | self.f = None 48 | 49 | @property 50 | def first(self): 51 | return self.f.value 52 | 53 | @property 54 | def empty(self): 55 | return self.f is None 56 | 57 | def pop_first(self): 58 | val = self.f.value 59 | self.f = self.f.next 60 | return val 61 | 62 | def ordered_insert(self, item): 63 | for i, ev in enumerate(self.arr): 64 | if item.timestamp < ev.timestamp: 65 | ins = True 66 | break 67 | if ins: 68 | self.arr.insert(i, item) 69 | else: 70 | self.push(item) 71 | pass 72 | 73 | def remove(self, item): 74 | if item == self.f.value: 75 | return self.pop_first() 76 | else: 77 | pointer = self.f 78 | while pointer is not None: 79 | if pointer.next.value == item.value: 80 | item = pointer.next.item 81 | pointer.next = pointer.next.next 82 | return item 83 | raise ValueError('not found') 84 | -------------------------------------------------------------------------------- /simulation/dispatching/dispatcher.py: -------------------------------------------------------------------------------- 1 | from simulation.classes import Lot, Machine 2 | from simulation.randomizer import Randomizer 3 | 4 | r = Randomizer() 5 | 6 | 7 | class Dispatchers: 8 | 9 | @staticmethod 10 | def get_setup(new_setup, machine, actual_step_setup_time, setups): 11 | if new_setup != '' and machine.current_setup != new_setup: 12 | if actual_step_setup_time is not None: 13 | return actual_step_setup_time 14 | elif (machine.current_setup, new_setup) in setups: 15 | return setups[(machine.current_setup, new_setup)] 16 | elif ('', new_setup) in setups: 17 | return setups[('', new_setup)] 18 | return 0 19 | 20 | @staticmethod 21 | def fifo_ptuple_for_lot(lot: Lot, time, machine: Machine = None, setups=None): 22 | if machine is not None: 23 | lot.ptuple = ( 24 | 0 if machine.min_runs_left is None or machine.min_runs_setup == lot.actual_step.setup_needed else 1, 25 | 0 if lot.cqt_waiting is not None else 1, 26 | Dispatchers.get_setup(lot.actual_step.setup_needed, machine, lot.actual_step.setup_time, setups), 27 | -lot.priority, lot.free_since, lot.deadline_at, 28 | ) 29 | return lot.ptuple 30 | else: 31 | return -lot.priority, lot.free_since, lot.deadline_at, 32 | 33 | @staticmethod 34 | def cr_ptuple_for_lot(lot: Lot, time, machine: Machine = None, setups=None): 35 | if machine is not None: 36 | lot.ptuple = ( 37 | 0 if machine.min_runs_left is None or machine.min_runs_setup == lot.actual_step.setup_needed else 1, 38 | 0 if lot.cqt_waiting is not None else 1, 39 | Dispatchers.get_setup(lot.actual_step.setup_needed, machine, lot.actual_step.setup_time, setups), 40 | -lot.priority, lot.cr(time), 41 | ) 42 | return lot.ptuple 43 | else: 44 | return -lot.priority, lot.cr(time), 45 | 46 | @staticmethod 47 | def random_ptuple_for_lot(lot: Lot, time, machine: Machine = None, setups=None): 48 | if machine is not None: 49 | return ( 50 | 0 if machine.min_runs_left is None or machine.min_runs_setup == lot.actual_step.setup_needed else 1, 51 | 0 if lot.cqt_waiting is not None else 1, 52 | r.random.uniform(0, 99999), 53 | ) 54 | else: 55 | return r.random.uniform(0, 99999), 56 | 57 | 58 | dispatcher_map = { 59 | 'fifo': Dispatchers.fifo_ptuple_for_lot, 60 | 'cr': Dispatchers.cr_ptuple_for_lot, 61 | 'random': Dispatchers.random_ptuple_for_lot, 62 | } 63 | -------------------------------------------------------------------------------- /simulation/events.py: -------------------------------------------------------------------------------- 1 | class MachineDoneEvent: 2 | 3 | def __init__(self, timestamp, machines): 4 | self.timestamp = timestamp 5 | self.machines = machines 6 | self.lots = [] 7 | 8 | def handle(self, instance): 9 | instance.free_up_machines(self.machines) 10 | 11 | 12 | class LotDoneEvent: 13 | 14 | def __init__(self, timestamp, machines, lots): 15 | self.timestamp = timestamp 16 | self.machines = machines 17 | self.lots = lots 18 | 19 | def handle(self, instance): 20 | instance.free_up_lots(self.lots) 21 | 22 | 23 | class ReleaseEvent: 24 | 25 | @staticmethod 26 | def handle(instance, to_time): 27 | if to_time is None or ( 28 | len(instance.dispatchable_lots) > 0 and instance.dispatchable_lots[0].release_at <= to_time): 29 | instance.current_time = max(0, instance.dispatchable_lots[0].release_at, instance.current_time) 30 | lots_released = [] 31 | while len(instance.dispatchable_lots) > 0 and max(0, instance.dispatchable_lots[ 32 | 0].release_at) <= instance.current_time: 33 | lots_released.append(instance.dispatchable_lots[0]) 34 | instance.dispatchable_lots = instance.dispatchable_lots[1:] 35 | instance.active_lots += lots_released 36 | instance.free_up_lots(lots_released) 37 | for plugin in instance.plugins: 38 | plugin.on_lots_release(instance, lots_released) 39 | return True 40 | else: 41 | return False 42 | 43 | 44 | class BreakdownEvent: 45 | 46 | def __init__(self, timestamp, length, repeat_interval, machine, is_breakdown): 47 | self.timestamp = timestamp 48 | self.machine = machine 49 | self.machines = [] 50 | self.lots = [] 51 | self.is_breakdown = is_breakdown 52 | self.repeat_interval = repeat_interval 53 | self.length = length 54 | if not is_breakdown: 55 | machine.next_preventive_maintenance = timestamp 56 | 57 | def handle(self, instance): 58 | length = self.length.sample() 59 | if self.is_breakdown: 60 | self.machine.bred_time += length 61 | else: 62 | self.machine.pmed_time += length 63 | instance.handle_breakdown(self.machine, length) 64 | for plugin in instance.plugins: 65 | if self.is_breakdown: 66 | plugin.on_breakdown(instance, self) 67 | else: 68 | plugin.on_preventive_maintenance(instance, self) 69 | instance.add_event(BreakdownEvent( 70 | self.timestamp + length + self.repeat_interval.sample(), 71 | self.length, 72 | self.repeat_interval, 73 | self.machine, 74 | self.is_breakdown, 75 | )) 76 | -------------------------------------------------------------------------------- /simulation/dispatching/dm_machine_for_lot.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | class MachineForLotDispatchManager: 5 | 6 | @staticmethod 7 | def init(self): 8 | self.lots_waiting_for_family = defaultdict(lambda: set()) 9 | self.usable_lots = list() 10 | self.lot_in_usable = defaultdict(lambda: False) 11 | self.free_machines = [False for _ in self.machines] 12 | 13 | @staticmethod 14 | def free_up_lots(self, lot): 15 | self.lots_waiting_for_family[lot.actual_step.family].add(lot) 16 | for machine in self.family_machines[lot.actual_step.family]: 17 | if self.free_machines[machine.idx]: 18 | MachineForLotDispatchManager.assign_lot_if_dedication_ok(self, lot, machine) 19 | 20 | @staticmethod 21 | def assign_lot_if_dedication_ok(self, lot, machine): 22 | di = lot.actual_step.order 23 | if di not in lot.dedications or machine.idx == lot.dedications[di]: 24 | if machine not in lot.waiting_machines: 25 | lot.waiting_machines.append(machine) 26 | if lot not in machine.waiting_lots: 27 | machine.waiting_lots.append(lot) 28 | if not self.lot_in_usable[lot.idx]: 29 | self.lot_in_usable[lot.idx] = True 30 | assert lot not in self.usable_lots 31 | assert len(lot.waiting_machines) > 0 32 | self.usable_lots.append(lot) 33 | 34 | @staticmethod 35 | def free_up_machine(self, machine): 36 | self.free_machines[machine.idx] = True 37 | for lot in self.lots_waiting_for_family[machine.family]: 38 | MachineForLotDispatchManager.assign_lot_if_dedication_ok(self, lot, machine) 39 | 40 | @staticmethod 41 | def reserve(self, lots, machine): 42 | self.free_machines[machine.idx] = False 43 | for lot in machine.waiting_lots: 44 | lot.waiting_machines.remove(machine) 45 | if len(lot.waiting_machines) == 0 and self.lot_in_usable[lot.idx]: 46 | self.lot_in_usable[lot.idx] = False 47 | self.usable_lots.remove(lot) 48 | machine.waiting_lots.clear() 49 | for lot in lots: 50 | self.lots_waiting_for_family[lot.actual_step.family].remove(lot) 51 | for m in lot.waiting_machines: 52 | m.waiting_lots.remove(lot) 53 | lot.waiting_machines.clear() 54 | for lot in lots: 55 | if self.lot_in_usable[lot.idx]: 56 | self.lot_in_usable[lot.idx] = False 57 | self.usable_lots.remove(lot) 58 | assert lot not in self.usable_lots 59 | 60 | @staticmethod 61 | def next_decision_point(self): 62 | while len(self.usable_lots) == 0 and not self.done: 63 | self.next_step() 64 | return self.done 65 | -------------------------------------------------------------------------------- /rl_test.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import io 3 | import json 4 | import os 5 | from sys import argv, stdout 6 | 7 | from stable_baselines3 import PPO 8 | 9 | from simulation.gym.environment import DynamicSCFabSimulationEnvironment 10 | from simulation.gym.sample_envs import DEMO_ENV_1 11 | from simulation.stats import print_statistics 12 | 13 | 14 | def main(): 15 | t = datetime.datetime.now() 16 | ranag = 'random' in argv[2] 17 | if not ranag: 18 | model = PPO.load(os.path.join(argv[1], argv[2])) 19 | with io.open(os.path.join(argv[1], "config.json"), "r") as f: 20 | config = json.load(f)['params'] 21 | 22 | args = dict(seed=0, num_actions=config['action_count'], active_station_group=config['station_group'], days=365 * 2, 23 | dataset='SMT2020_' + config['dataset'], dispatcher=config['dispatcher'], reward_type=config['reward']) 24 | env = DynamicSCFabSimulationEnvironment(**DEMO_ENV_1, **args, max_steps=1000000000) 25 | obs = env.reset() 26 | reward = 0 27 | 28 | checkpoints = [180, 365] 29 | current_checkpoint = 0 30 | 31 | steps = 0 32 | shown_days = 0 33 | deterministic = True 34 | while True: 35 | if not ranag: 36 | action, _states = model.predict(obs, deterministic=deterministic) 37 | if ranag: 38 | if argv[2] == 'random': 39 | action = env.action_space.sample() 40 | else: 41 | state = obs[4:] 42 | actions = config['action_count'] 43 | one_length = len(state) // actions 44 | descending = True 45 | index = 0 46 | sortable = [] 47 | for i in range(actions): 48 | sortable.append((state[one_length * i + index], i)) 49 | sortable.sort(reverse=descending) 50 | action = sortable[0][1] 51 | obs, r, done, info = env.step(action) 52 | if r < 0: 53 | deterministic = False 54 | else: 55 | deterministic = True 56 | reward += r 57 | steps += 1 58 | di = int(env.instance.current_time_days) 59 | 60 | if di % 10 == 0 and di > shown_days: 61 | print(f'Step {steps} day {shown_days}') 62 | shown_days = di 63 | stdout.flush() 64 | 65 | chp = checkpoints[current_checkpoint] 66 | if env.instance.current_time_days > chp: 67 | print(f'{checkpoints[current_checkpoint]} days') 68 | print_statistics(env.instance, chp, config['dataset'], config['dispatcher'], method=f'rl{chp}', dir=argv[1]) 69 | print('=================') 70 | stdout.flush() 71 | current_checkpoint += 1 72 | if len(checkpoints) == current_checkpoint: 73 | break 74 | 75 | if done: 76 | print('Exiting with DONE') 77 | break 78 | 79 | print(f'Reward is {reward}') 80 | dt = datetime.datetime.now() - t 81 | print('Elapsed', str(dt)) 82 | env.close() 83 | 84 | 85 | if __name__ == '__main__': 86 | main() 87 | -------------------------------------------------------------------------------- /simulation/plugins/chart_plugin.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os 3 | from collections import defaultdict 4 | import random 5 | 6 | from simulation.plugins.interface import IPlugin 7 | 8 | CHART_INTERVAL = 10 9 | 10 | 11 | def random_color(): 12 | r = lambda: random.randint(0, 255) 13 | return '#%02X%02X%02X' % (r(), r(), r()) 14 | 15 | 16 | class ChartPlugin(IPlugin): 17 | def on_sim_init(self, instance): 18 | self.debug_step_count = 0 19 | self.visualization_data_jobs = defaultdict(lambda: []) 20 | self.visualization_data_jobs_colors = defaultdict(lambda: []) 21 | self.visualization_data_tools = defaultdict(lambda: []) 22 | self.visualization_data_tools_colors = defaultdict(lambda: []) 23 | self.visualization_task_colors = defaultdict(random_color) 24 | self.visualization_tool_colors = defaultdict(random_color) 25 | 26 | def on_dispatch(self, instance, machine, lots, machine_end_time, lot_end_time): 27 | machine_name = f"{machine.idx}_{machine.family}" 28 | self.add_chart_tools(machine_name, ','.join([lot.name + ' ' + str(lot.idx) for lot in lots]), 29 | ','.join([lot.actual_step.step_name for lot in lots]), instance.current_time, 30 | machine_end_time) 31 | for lot in lots: 32 | self.add_chart_jobs(lot.name + ' ' + str(lot.idx), machine_name, lot.actual_step.order, 33 | instance.current_time, lot_end_time) 34 | 35 | if self.debug_step_count % CHART_INTERVAL == 0: 36 | self.print_html() 37 | 38 | @property 39 | def act_dir(self): 40 | return os.path.dirname(os.path.realpath(__file__)) 41 | 42 | def print_html(self): 43 | d = os.path.join(self.act_dir, 'visualization_template.html') 44 | with io.open(d, 'r') as f: 45 | template = f.read() 46 | for name, li, colors in [('tools', self.visualization_data_tools, self.visualization_data_tools_colors), 47 | ('jobs', self.visualization_data_jobs, self.visualization_data_jobs_colors)]: 48 | vis_data = [] 49 | color_data = [] 50 | keyss = sorted(li.keys()) 51 | for k in keyss: 52 | vis_data += li[k] 53 | color_data += colors[k] 54 | data = template.replace('["DATA"]', ',\n'.join(vis_data)) 55 | with io.open(f'chart_{name}.html', 'w') as f: 56 | f.write(data) 57 | 58 | def add_chart_tools(self, tool_name, job_name, task_name, t_from: int, t_to: int): 59 | self.visualization_data_tools[tool_name].append( 60 | f"['{tool_name}', '{task_name}', 'fill-color: {self.visualization_task_colors[job_name]}', " + 61 | f"new Date({t_from * 1000}), new Date({t_to * 1000})]") 62 | self.visualization_data_tools_colors[tool_name].append(f"'{self.visualization_task_colors[job_name]}'") 63 | 64 | def add_chart_jobs(self, job_name, tool_name, step, t_from, t_to): 65 | self.visualization_data_jobs[tool_name].append( 66 | f"['{job_name}', '{tool_name} s{step}', 'fill-color: {self.visualization_tool_colors[tool_name]}', " + 67 | f"new Date({t_from * 1000}), new Date({t_to * 1000})]") 68 | self.visualization_data_jobs_colors[tool_name].append(f"'{self.visualization_tool_colors[tool_name]}'") 69 | -------------------------------------------------------------------------------- /simulation/generator_instance.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import Dict, List 3 | 4 | from simulation.classes import Machine, FileRoute, Lot, Step, Route 5 | from simulation.events import BreakdownEvent 6 | from simulation.instance import Instance 7 | from simulation.randomizer import Randomizer 8 | from simulation.tools import get_interval, get_distribution, UniformDistribution, date_time_parse 9 | 10 | r = Randomizer() 11 | 12 | 13 | class GeneratorRoute(Route): 14 | def __init__(self, idx, steps: int): 15 | fams = [r.random.choice(['S1', 'S2', 'S3', 'S4', 'B1', 'B2', 'B3', 16 | 'C1', 'C2']) for i in range(steps)] 17 | steps = [Step(i, { 18 | 'STEP': i + 1, 19 | 'DESC': f'Step {i} for route {idx}', 20 | 'STNFAM': fam, 21 | 'SETUP': r.random.choice(['', '', '', '', 'Setup1', 'Setup2']), 22 | 'STIME': 20, 23 | 'STUNITS': 'min', 24 | 'RWKSTEP': '', 25 | 'PTPER': 'per_batch', 26 | 'PDIST': 'uniform', 27 | 'PTUNITS': 'min', 28 | 'PTIME': r.random.choice([25, 45, 120, 10]), 29 | 'PTIME2': 5, 30 | 'BATCHMN': 75 if fam.startswith('B') else '', 31 | 'BATCHMX': 125 if fam.startswith('B') else '', 32 | 'StepPercent': '', 33 | 'REWORK': '', 34 | 'PartInterval': '', 35 | 'BatchInterval': '', 36 | }) for i, fam in enumerate(fams)] 37 | super().__init__(idx, steps) 38 | 39 | 40 | class GeneratorInstance(Instance): 41 | 42 | def __init__(self, run_to): 43 | print('New instance generated') 44 | machines = [] 45 | machine_id = 0 46 | r = Randomizer() 47 | family_locations = {} 48 | for group, family, quantity, cascading in [ 49 | ('Simple', 'S1', 4, 1), 50 | ('Simple', 'S2', 2, 1), 51 | ('Simple', 'S3', 3, 1), 52 | ('Simple', 'S4', 2, 1), 53 | ('Batching', 'B1', 5, 1), 54 | ('Batching', 'B2', 3, 1), 55 | ('Batching', 'B3', 2, 1), 56 | ('Cascading', 'C1', 3, 2), 57 | ('Cascading', 'C2', 1, 2), 58 | ]: 59 | for i in range(quantity): 60 | speed = r.random.uniform(0.7, 1.3) 61 | m = Machine(idx=machine_id, d={ 62 | 'LTIME': 1, 63 | 'LTUNITS': 'min', 64 | 'ULTIME': 1, 65 | 'ULTUNITS': 'min', 66 | 'STNGRP': group, 67 | 'STNFAMLOC': 'Fab', 68 | 'STNFAM': family, 69 | 'STNCAP': cascading, 70 | }, speed=speed) 71 | family_locations[m.family] = m.loc 72 | machines.append(m) 73 | machine_id += 1 74 | 75 | from_to = {('Fab', 'Fav'): get_distribution('uniform', 'min', 5, 1)} 76 | 77 | routes = {} 78 | for rk in range(5): 79 | route = GeneratorRoute(rk, 10) 80 | last_loc = None 81 | for s in route.steps: 82 | s.family_location = family_locations[s.family] 83 | key = (last_loc, s.family_location) 84 | if last_loc is not None and key in from_to: 85 | s.transport_time = from_to[key] 86 | last_loc = s.family_location 87 | routes[str(rk)] = route 88 | 89 | parts = {str(p): str(p) for p in range(5)} 90 | 91 | lots = [] 92 | idx = 0 93 | lot_pre = {} 94 | for order in range(5): 95 | first_release = 0 96 | release_interval = 36000 97 | 98 | for i in range(10000): 99 | rel_time = first_release + i * release_interval 100 | 101 | route = routes[str(order)] 102 | 103 | relative_deadline = sum([s.processing_time.avg() for s in route.steps]) * 2 104 | 105 | lot = Lot(idx, route, 10, rel_time, relative_deadline, {'LOT': f'Lot {order}'}) 106 | lots.append(lot) 107 | lot_pre[lot.name] = relative_deadline 108 | idx += 1 109 | if rel_time > run_to * 1.5: 110 | break 111 | 112 | setups = {('Setup1', 'Setup2'): 1200, ('Setup1', 'Setup2'): 2400} 113 | 114 | super().__init__(machines, routes, lots, setups, []) 115 | -------------------------------------------------------------------------------- /simulation/stats.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import io 3 | import json 4 | import statistics 5 | from collections import defaultdict 6 | 7 | from simulation.classes import Lot, Step 8 | 9 | 10 | def print_statistics(instance, days, dataset, disp, method='greedy', dir='greedy'): 11 | from simulation.instance import Instance 12 | instance: Instance 13 | lot: Lot 14 | lots = defaultdict(lambda: {'ACT': [], 'throughput': 0, 'on_time': 0, 'tardiness': 0, 'waiting_time': 0, 15 | 'processing_time': 0, 'transport_time': 0, 'waiting_time_batching': 0}) 16 | apt = {} 17 | dl = {} 18 | for lot in instance.done_lots: 19 | lots[lot.name]['ACT'].append(lot.done_at - lot.release_at) 20 | lots[lot.name]['throughput'] += 1 21 | lots[lot.name]['tardiness'] += max(0, lot.done_at - lot.deadline_at) 22 | lots[lot.name]['waiting_time'] += lot.waiting_time 23 | lots[lot.name]['waiting_time_batching'] += lot.waiting_time_batching 24 | lots[lot.name]['processing_time'] += lot.processing_time 25 | lots[lot.name]['transport_time'] += lot.transport_time 26 | if lot.done_at <= lot.deadline_at: 27 | lots[lot.name]['on_time'] += 1 28 | if lot.name not in apt: 29 | apt[lot.name] = sum([s.processing_time.avg() for s in lot.processed_steps]) 30 | dl[lot.name] = lot.deadline_at - lot.release_at 31 | print('Lot', 'APT', 'DL', 'ACT', 'TH', 'ONTIME', 'tardiness', 'wa', 'pr', 'tr') 32 | acts = [] 33 | ths = [] 34 | ontimes = [] 35 | for lot_name in sorted(list(lots.keys())): 36 | l = lots[lot_name] 37 | avg = statistics.mean(l['ACT']) / 3600 / 24 38 | lots[lot_name]['ACT'] = avg 39 | acts += [avg] 40 | th = lots[lot_name]['throughput'] 41 | ths += [th] 42 | ontime = round(l['on_time'] / l['throughput'] * 100) 43 | ontimes += [ontime] 44 | wa = lots[lot_name]['waiting_time'] / l['throughput'] / 3600 / 24 45 | wab = lots[lot_name]['waiting_time_batching'] / l['throughput'] / 3600 / 24 46 | pr = lots[lot_name]['processing_time'] / l['throughput'] / 3600 / 24 47 | tr = lots[lot_name]['transport_time'] / l['throughput'] / 3600 / 24 48 | print(lot_name, round(apt[lot_name] / 3600 / 24, 1), round(dl[lot_name] / 3600 / 24, 1), round(avg, 1), th, 49 | ontime, l['tardiness'], wa, wab, pr, tr) 50 | print('---------------') 51 | print(round(statistics.mean(acts), 2), statistics.mean(ths), statistics.mean(ontimes)) 52 | print(round(sum(acts), 2), sum(ths), sum(ontimes)) 53 | 54 | utilized_times = defaultdict(lambda: []) 55 | setup_times = defaultdict(lambda: []) 56 | pm_times = defaultdict(lambda: []) 57 | br_times = defaultdict(lambda: []) 58 | for machine in instance.machines: 59 | utilized_times[machine.family].append(machine.utilized_time) 60 | setup_times[machine.family].append(machine.setuped_time) 61 | pm_times[machine.family].append(machine.pmed_time) 62 | br_times[machine.family].append(machine.bred_time) 63 | 64 | print('Machine', 'Cnt', 'avail' 'util', 'br', 'pm', 'setup') 65 | machines = defaultdict(lambda: {}) 66 | for machine_name in sorted(list(utilized_times.keys())): 67 | av = (instance.current_time - statistics.mean(pm_times[machine_name]) - statistics.mean(br_times[machine_name])) 68 | machines[machine_name]['avail'] = av / instance.current_time 69 | machines[machine_name]['util'] = statistics.mean(utilized_times[machine_name]) / av 70 | machines[machine_name]['pm'] = statistics.mean(pm_times[machine_name]) / instance.current_time 71 | machines[machine_name]['br'] = statistics.mean(br_times[machine_name]) / instance.current_time 72 | machines[machine_name]['setup'] = statistics.mean(setup_times[machine_name]) / instance.current_time 73 | r = instance.lot_waiting_at_machine[machine_name] 74 | machines[machine_name]['waiting_time'] = r[1] / r[0] / 3600 / 24 75 | print(machine_name, len(utilized_times[machine_name]), 76 | round(machines[machine_name]['avail'] * 100, 2), 77 | round(machines[machine_name]['util'] * 100, 2), 78 | round(machines[machine_name]['br'] * 100, 2), 79 | round(machines[machine_name]['pm'] * 100, 2), 80 | round(machines[machine_name]['setup'] * 100, 2)) 81 | 82 | plugins = {} 83 | 84 | for plugin in instance.plugins: 85 | if plugin.get_output_name() is not None: 86 | plugins[plugin.get_output_name()] = plugin.get_output_value() 87 | 88 | with io.open(f'{dir}/{method}_{days}days_{dataset}_{disp}.json', 'w') as f: 89 | json.dump({ 90 | 'lots': lots, 91 | 'machines': machines, 92 | 'plugins': plugins, 93 | }, f) 94 | -------------------------------------------------------------------------------- /simulation/file_instance.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List 2 | 3 | from simulation.classes import Machine, FileRoute, Lot 4 | from simulation.events import BreakdownEvent 5 | from simulation.instance import Instance 6 | from simulation.randomizer import Randomizer 7 | from simulation.tools import get_interval, get_distribution, UniformDistribution, date_time_parse 8 | 9 | 10 | class FileInstance(Instance): 11 | 12 | def __init__(self, files: Dict[str, List[Dict]], run_to, lot_for_machine, plugins): 13 | machines = [] 14 | machine_id = 0 15 | r = Randomizer() 16 | family_locations = {} 17 | for d_m in files['tool.txt.1l']: 18 | for i in range(int(d_m['STNQTY'])): 19 | speed = 1 # r.random.uniform(0.7, 1.3) 20 | m = Machine(idx=machine_id, d=d_m, speed=speed) 21 | family_locations[m.family] = m.loc 22 | machines.append(m) 23 | machine_id += 1 24 | 25 | from_to = {(a['FROMLOC'], a['TOLOC']): get_distribution(a['DDIST'], a['DUNITS'], a['DTIME'], a['DTIME2']) for a 26 | in files['fromto.txt']} 27 | 28 | pieces = max([a['PIECES'] for a in files['order.txt'] + files['WIP.txt']]) 29 | routes = {} 30 | route_keys = [key for key in files.keys() if 'route' in key] 31 | for rk in route_keys: 32 | route = FileRoute(rk, pieces, files[rk]) 33 | last_loc = None 34 | for s in route.steps: 35 | s.family_location = family_locations[s.family] 36 | key = (last_loc, s.family_location) 37 | if last_loc is not None and key in from_to: 38 | s.transport_time = from_to[key] 39 | last_loc = s.family_location 40 | routes[rk] = route 41 | 42 | parts = {p['PART']: p['ROUTEFILE'] for p in files['part.txt']} 43 | 44 | lots = [] 45 | idx = 0 46 | lot_pre = {} 47 | for order in files['order.txt']: 48 | assert pieces == order['PIECES'] 49 | first_release = 0 50 | release_interval = get_interval(order['REPEAT'], order['RUNITS']) 51 | relative_deadline = (date_time_parse(order['DUE']) - date_time_parse(order['START'])).total_seconds() 52 | 53 | for i in range(order['RPT#']): 54 | rel_time = first_release + i * release_interval 55 | lot = Lot(idx, routes[parts[order['PART']]], order['PRIOR'], rel_time, relative_deadline, order) 56 | lots.append(lot) 57 | lot_pre[lot.name] = relative_deadline 58 | idx += 1 59 | if rel_time > run_to: 60 | break 61 | 62 | for wip in files['WIP.txt']: 63 | assert pieces == wip['PIECES'] 64 | first_release = 0 65 | relative_deadline = (date_time_parse(wip['DUE']) - date_time_parse(wip['START'])).total_seconds() 66 | if wip['CURSTEP'] < len(routes[parts[wip['PART']]].steps) - 1: 67 | lot = Lot(idx, routes[parts[wip['PART']]], wip['PRIOR'], first_release, relative_deadline, wip) 68 | lots.append(lot) 69 | lot.release_at = lot.deadline_at - lot_pre[lot.name] 70 | idx += 1 71 | 72 | setups = {(s['CURSETUP'], s['NEWSETUP']): get_interval(s['STIME'], s['STUNITS']) for s in files['setup.txt']} 73 | setup_min_run = {s['SETUP']: s['MINRUN'] for s in files['setupgrp.txt']} 74 | 75 | downcals = {} 76 | for dc in files['downcal.txt']: 77 | downcals[dc['DOWNCALNAME']] = (get_distribution(dc['MTTFDIST'], dc['MTTFUNITS'], dc['MTTF']), 78 | get_distribution(dc['MTTRDIST'], dc['MTTRUNITS'], dc['MTTR'])) 79 | pmcals = {} 80 | for dc in files['pmcal.txt']: 81 | pmcals[dc['PMCALNAME']] = (get_distribution('constant', dc['MTBPMUNITS'], dc['MTBPM']), 82 | get_distribution(dc['MTTRDIST'], dc['MTTRUNITS'], dc['MTTR'], dc['MTTR2'])) 83 | 84 | breakdowns = [] 85 | for a in files['attach.txt']: 86 | if a['RESTYPE'] == 'stngrp': 87 | m_break = [m for m in machines if m.group == a['RESNAME']] 88 | else: 89 | m_break = [m for m in machines if m.family == a['RESNAME']] 90 | distribution = get_distribution(a['FOADIST'], a['FOAUNITS'], a['FOA']) 91 | if a['CALTYPE'] == 'down': 92 | is_breakdown = True 93 | ne, le = downcals[a['CALNAME']] 94 | else: 95 | is_breakdown = False 96 | ne, le = pmcals[a['CALNAME']] 97 | if distribution is None: 98 | distribution = ne 99 | if a['FOAUNITS'] == '': 100 | for m in m_break: 101 | m.piece_per_maintenance.append(ne.c) 102 | m.pieces_until_maintenance.append(a['FOA']) 103 | m.maintenance_time.append(le) 104 | else: 105 | for m in m_break: 106 | br = BreakdownEvent(distribution.sample(), le, ne, m, is_breakdown) 107 | if not is_breakdown: 108 | m.pms.append(br) 109 | breakdowns.append(br) 110 | 111 | super().__init__(machines, routes, lots, setups, setup_min_run, breakdowns, lot_for_machine, plugins) 112 | -------------------------------------------------------------------------------- /eval_results.py: -------------------------------------------------------------------------------- 1 | import io 2 | import json 3 | import statistics 4 | from collections import defaultdict 5 | from os import listdir, path 6 | 7 | 8 | def read_references(): 9 | out = {} 10 | for t in ['lots', 'machines']: 11 | out[t] = {} 12 | for ds in ['HVLM', 'LVHM']: 13 | out[t][ds] = defaultdict(lambda: 0) 14 | file_name = f'datasets/{t}_SMT2020_{ds}.txt' 15 | with io.open(file_name, 'r') as f: 16 | lines = f.read().split('\n') 17 | headers = lines[0].split(' ') 18 | rows = [a.split(' ') for a in lines[1:]] 19 | for row in rows: 20 | for h, c in zip(headers[1:], row[1:]): 21 | out[t][ds][(h, row[0])] = c 22 | return out 23 | 24 | 25 | def handle_obj(datas): 26 | o = {} 27 | for k, v in datas[0].items(): 28 | its = [d[k] for d in datas] 29 | if type(v) is dict: 30 | o[k] = handle_obj(its) 31 | elif type(v) in [int, float]: 32 | o[k] = (statistics.mean(its), statistics.stdev(its)) 33 | else: 34 | assert False 35 | return o 36 | 37 | 38 | def loadfile(f): 39 | with io.open(f, 'r') as q: 40 | return q.read() 41 | 42 | 43 | def main(): 44 | dirs = ['greedy'] 45 | 46 | results = {} 47 | names = set() 48 | 49 | runs = 10 50 | 51 | lots = defaultdict(lambda: defaultdict(lambda: defaultdict(int))) 52 | machines = defaultdict(lambda: defaultdict(lambda: defaultdict(int))) 53 | 54 | for d in dirs: 55 | subs = listdir(d) 56 | for s in subs: 57 | if path.isfile(d + '/' + s) and 'seed0' in s and s.endswith('.json'): 58 | file_locs = [d + '/' + s.replace('seed0_', f'seed{r}_') for r in range(runs)] 59 | name = f'{len(file_locs)}x {s.replace("seed0_", "")}' 60 | results[name] = {'files': file_locs} 61 | elif path.isdir(d + '/' + s) and s.startswith('0_'): 62 | s = s[2:] 63 | ds = 'HVLM' if 'HVLM' in s else 'LVHM' 64 | dispatcher = 'fifo' if 'fifo' in s else 'cr' 65 | y2n = f'rl2y_730days_{ds}_{dispatcher}.json' 66 | d180n = f'rl180_180days_{ds}_{dispatcher}.json' 67 | file_locs_2y = [path.join(d, str(r) + '_' + s, y2n) for r in range(runs)] 68 | file_locs_180d = [path.join(d, str(r) + '_' + s, d180n) for r in range(runs)] 69 | name180 = f'{len(file_locs_2y)}x {d}_180days_{s}' 70 | name730 = f'{len(file_locs_2y)}x {d}_730days_{s}' 71 | results[name180] = {'files': file_locs_180d} 72 | results[name730] = {'files': file_locs_2y} 73 | 74 | for name in results.keys(): 75 | names.add(name) 76 | d = results[name] 77 | files = d['files'] 78 | datas = [json.loads(loadfile(f)) for f in files] 79 | r = d['avgs'] = handle_obj(datas) 80 | for k, v in sorted(r['lots'].items(), key=lambda k: k[0]): 81 | lots[k][name] = dict( 82 | act=round(v["ACT"][0], 2), 83 | th=round(v["throughput"][0], 2), 84 | on_time=round(v["on_time"][0] / v["throughput"][0] * 100), 85 | tardiness=round(v["tardiness"][0] / v["throughput"][0] / 24), 86 | ) 87 | 88 | for k, v in sorted(r['machines'].items(), key=lambda k: k[0]): 89 | machines[k][name] = dict( 90 | avail=round(v["avail"][0] * 100, 2), 91 | util=round(v["util"][0] * 100, 2), 92 | pm=round(v["pm"][0] * 100, 2), 93 | br=round(v["br"][0] * 100, 2), 94 | setup=round(v["setup"][0] * 100, 2), 95 | waiting_time=round(v["waiting_time"][0], 2), 96 | ) 97 | 98 | print('\t', end='') 99 | names = sorted(list(names)) 100 | for name in names: 101 | print(name.replace(':', '').replace('\t', ''), '\t\t', end='') 102 | print() 103 | 104 | print('', end='\t') 105 | for name in names: 106 | print('act\tth\ton_time\ttardiness', end='\t') 107 | print() 108 | 109 | ref = read_references() 110 | 111 | for lot in sorted(lots.keys()): 112 | t = lots[lot] 113 | print(lot, end='\t') 114 | for name in names: 115 | i = ref['lots']['HVLM' if 'HVLM' in name else 'LVHM'] 116 | for x in ['act', 'th', 'on_time']: 117 | i[(x, lot)] = float(i[(x, lot)]) 118 | print(f"{i[(x, lot)]}->{t[name][x]} ({round(t[name][x] - i[(x, lot)], 2)})", end='\t') 119 | print(t[name]['tardiness'], end='\t') 120 | print() 121 | 122 | print('', end='\t') 123 | for name in names: 124 | print('avail\t\t\tutil\t\t\tpm\t\t\tbr\t\t\tsetup\t\t\twaiting_time_before', end='\t') 125 | print() 126 | print('', end='\t') 127 | for name in names: 128 | print('old\tnew\tdelta\told\tnew\tdelta\told\tnew\tdelta\told\tnew\tdelta\told\tnew\tdelta\tnew', end='\t') 129 | print() 130 | for machine in sorted(machines.keys()): 131 | t = machines[machine] 132 | print(machine, end='\t') 133 | for name in names: 134 | i = ref['machines']['HVLM' if 'HVLM' in name else 'LVHM'] 135 | for x in ['avail', 'util', 'pm', 'br', 'setup']: 136 | i[(x, machine)] = float(i[(x, machine)]) 137 | print(f"{i[(x, machine)]}\t{t[name][x]}\t{round(t[name][x] - i[(x, machine)], 2)}", end='\t') 138 | # print(f"{round(t[name][x] - i[(x, machine)], 2)}", end='\t') 139 | print(t[name]['waiting_time'], end='\t') 140 | print() 141 | 142 | 143 | if __name__ == '__main__': 144 | main() 145 | -------------------------------------------------------------------------------- /simulation/plugins/wandb_plugin.py: -------------------------------------------------------------------------------- 1 | import statistics 2 | import time 3 | from collections import defaultdict 4 | from typing import List 5 | 6 | from simulation.classes import Machine, Lot 7 | from simulation.plugins.interface import IPlugin 8 | 9 | import wandb 10 | 11 | WANDB_LOG_INTERVAL = 5000 12 | 13 | 14 | def meanor0(li): 15 | if len(li) > 0: 16 | return statistics.mean(li) 17 | else: 18 | return 0 19 | 20 | 21 | class WandBPlugin(IPlugin): 22 | def on_sim_init(self, instance): 23 | wandb.init() 24 | self.wandb_start = time.time() 25 | self.wandb_machine_free_count = [] 26 | self.wandb_machine_usable_count = [] 27 | self.wandb_steps_performed = 0 28 | self.wandb_lots_already_done = 0 29 | self.wandb_time_done = 0 30 | self.wandb_initial_waiting_lots = len(instance.dispatchable_lots) 31 | self.wandb_batch_util = [] 32 | self.wandb_step_count = 0 33 | 34 | self.wandb_last_setup = defaultdict(lambda: None) 35 | self.wandb_same_setup_count = defaultdict(lambda: 0) 36 | self.wandb_avg_steps_after_setup = [0] 37 | self.wandb_avg_steps_after_setup_1 = [0] 38 | self.wandb_avg_steps_after_setup_2 = [0] 39 | self.wandb_resetups = 0 40 | self.wandb_setup_machines = set() 41 | self.wandb_cqt_violations = 0 42 | 43 | def on_sim_done(self, instance): 44 | self.step(instance, force=True) 45 | columns = ['lot name', 'in progress', 'completed', 'completed on time', 'on time percent', 'average cycle time', 46 | 'theoretical processing time'] 47 | 48 | groups = defaultdict(lambda: defaultdict(lambda: 0)) 49 | for lot in instance.active_lots: 50 | groups[lot.name]['in progress'] += 1 51 | for lot in instance.done_lots: 52 | groups[lot.name]['completed'] += 1 53 | if lot.done_at <= lot.deadline_at: 54 | groups[lot.name]['completed on time'] += 1 55 | groups[lot.name]['on time percent'] = round( 56 | groups[lot.name]['completed on time'] / groups[lot.name]['completed'] * 100, 2) 57 | groups[lot.name]['act_sum'] += lot.done_at - lot.release_at 58 | groups[lot.name]['average cycle time'] = round( 59 | groups[lot.name]['act_sum'] / groups[lot.name]['completed'] / 3600 / 24, 2) 60 | groups[lot.name]['theoretical processing time'] = round(lot.full_time / 3600 / 24, 2) 61 | 62 | rows = [] 63 | for k, v in groups.items(): 64 | r = [k] 65 | for c in columns[1:]: 66 | r.append(v[c]) 67 | rows.append(r) 68 | rows.sort(key=lambda k: k[0]) 69 | 70 | html = '' + \ 71 | ''.join([f'' for c in columns]) + \ 72 | '' + \ 73 | ''.join(['' + ''.join([f'' for c in row]) + '' for row in rows]) + \ 74 | '
{c}
{c}
' 75 | wandb.log({ 76 | 'lot_stats': wandb.Html(html) 77 | }) 78 | wandb.finish() 79 | 80 | def on_dispatch(self, instance, machine, lots, machine_end_time, lot_end_time): 81 | machine: Machine 82 | lots: List[Lot] 83 | s = lots[0].actual_step.setup_needed 84 | if s not in [None, '']: 85 | if machine.last_setup != machine.current_setup: 86 | self.wandb_setup_machines.add(machine.idx) 87 | self.wandb_resetups += 1 88 | if self.wandb_same_setup_count[machine.idx] != 0: 89 | self.wandb_avg_steps_after_setup.append(self.wandb_same_setup_count[machine.idx]) 90 | if machine.has_min_runs: 91 | self.wandb_avg_steps_after_setup_2.append(self.wandb_same_setup_count[machine.idx]) 92 | else: 93 | self.wandb_avg_steps_after_setup_1.append(self.wandb_same_setup_count[machine.idx]) 94 | self.wandb_same_setup_count[machine.idx] = 1 95 | else: 96 | self.wandb_same_setup_count[machine.idx] += 1 97 | self.wandb_last_setup[machine.idx] = s 98 | self.wandb_step_count += 1 99 | self.wandb_machine_free_count.append(sum(instance.free_machines)) 100 | self.wandb_machine_usable_count.append(len(instance.usable_machines)) 101 | self.wandb_steps_performed += len(lots) 102 | if lots[0].actual_step.batch_max > 1: 103 | self.wandb_batch_util.append(len(lots) / lots[0].actual_step.batch_max) 104 | self.step(instance) 105 | 106 | def step(self, instance, force=False): 107 | if self.wandb_step_count % WANDB_LOG_INTERVAL == 0 or force: 108 | now_done = len(instance.done_lots) - self.wandb_lots_already_done 109 | elapsed_time = instance.current_time_days - self.wandb_time_done 110 | wandb.log({ 111 | 'lots/wip': len(instance.active_lots), 112 | 'lots/done': len(instance.done_lots), 113 | 'machines/free': meanor0(self.wandb_machine_free_count), 114 | 'machines/free_with_lots_waiting': meanor0(self.wandb_machine_usable_count), 115 | 'lots/steps_performed': self.wandb_steps_performed, 116 | 'lots/now_done': now_done, 117 | 'sim/simulated_time_seconds': instance.current_time, 118 | 'sim/simulated_time_days': instance.current_time_days, 119 | 'sim/running_time_minutes': (time.time() - self.wandb_start) / 60, 120 | 'sim/running_time_hours': (time.time() - self.wandb_start) / 3600, 121 | 'sim/speed': instance.current_time / (time.time() - self.wandb_start), 122 | 'lots/throughput_per_day': now_done / elapsed_time, 123 | 'lots/released': self.wandb_initial_waiting_lots - len(instance.dispatchable_lots), 124 | 'machines/batch_util': meanor0(self.wandb_batch_util), 125 | 'machines/setups_executed': self.wandb_resetups / max(1, len(self.wandb_setup_machines)), 126 | 'machines/avg_run_per_setup': statistics.mean(self.wandb_avg_steps_after_setup), 127 | 'machines/avg_run_per_setup_for_enforced': statistics.mean(self.wandb_avg_steps_after_setup_2), 128 | 'machines/avg_run_per_setup_NOT_enforced': statistics.mean(self.wandb_avg_steps_after_setup_1), 129 | 'lots/done_in_time': len([l for l in instance.done_lots if l.done_at <= l.deadline_at]), 130 | 'lots/done_late': len([l for l in instance.done_lots if l.done_at > l.deadline_at]), 131 | 'lots/cqt_violations': self.wandb_cqt_violations, 132 | }) 133 | self.wandb_lots_already_done = len(instance.done_lots) 134 | self.wandb_machine_free_count.clear() 135 | self.wandb_machine_usable_count.clear() 136 | self.wandb_batch_util.clear() 137 | self.wandb_steps_performed = 0 138 | self.wandb_time_done = instance.current_time_days 139 | 140 | def on_cqt_violated(self, instance, machine, lot): 141 | super().on_cqt_violated(instance, machine, lot) 142 | self.wandb_cqt_violations += 1 143 | 144 | -------------------------------------------------------------------------------- /simulation/greedy.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from collections import defaultdict 4 | from datetime import datetime 5 | from typing import List 6 | 7 | from simulation.classes import Lot, Machine 8 | from simulation.dispatching.dispatcher import dispatcher_map 9 | from simulation.file_instance import FileInstance 10 | from simulation.plugins.cost_plugin import CostPlugin 11 | from simulation.randomizer import Randomizer 12 | from simulation.read import read_all 13 | from simulation.stats import print_statistics 14 | 15 | import argparse 16 | 17 | last_sort_time = -1 18 | 19 | 20 | def dispatching_combined_permachine(ptuple_fcn, machine, time, setups): 21 | for lot in machine.waiting_lots: 22 | lot.ptuple = ptuple_fcn(lot, time, machine, setups) 23 | 24 | 25 | def get_lots_to_dispatch_by_machine(instance, ptuple_fcn, machine=None): 26 | time = instance.current_time 27 | if machine is None: 28 | for machine in instance.usable_machines: 29 | break 30 | dispatching_combined_permachine(ptuple_fcn, machine, time, instance.setups) 31 | wl = sorted(machine.waiting_lots, key=lambda k: k.ptuple) 32 | # select lots to dispatch 33 | lot = wl[0] 34 | if lot.actual_step.batch_max > 1: 35 | # construct batch 36 | lot_m = defaultdict(lambda: []) 37 | for w in wl: 38 | lot_m[w.actual_step.step_name].append(w) # + '_' + w.part_name 39 | lot_l = sorted(list(lot_m.values()), 40 | key=lambda l: ( 41 | l[0].ptuple[0], # cqt 42 | l[0].ptuple[1], # min run setup is the most important 43 | -min(1, len(l) / l[0].actual_step.batch_max), # then maximize the batch size 44 | 0 if len(l) >= l[0].actual_step.batch_min else 1, # then take min batch size into account 45 | *(l[0].ptuple[2:]), # finally, order based on prescribed priority rule 46 | )) 47 | lots: List[Lot] = lot_l[0] 48 | if len(lots) > lots[0].actual_step.batch_max: 49 | lots = lots[:lots[0].actual_step.batch_max] 50 | if len(lots) < lots[0].actual_step.batch_max: 51 | lots = None 52 | else: 53 | # dispatch single lot 54 | lots = [lot] 55 | if lots is not None and machine.current_setup != lots[0].actual_step.setup_needed: 56 | m: Machine 57 | for m in instance.family_machines[machine.family]: 58 | if m in instance.usable_machines and m.current_setup == lots[0].actual_step.setup_needed: # TODO: check instance.free_machines[m.idx] bug 59 | machine = m 60 | break 61 | if machine.dispatch_failed < 5 and machine.min_runs_left is not None and machine.min_runs_setup != lots[0].actual_step.setup_needed: 62 | machine.dispatch_failed += 1 63 | lots = None 64 | if lots is not None: 65 | machine.dispatch_failed = 0 66 | return machine, lots 67 | 68 | 69 | def build_batch(lot, nexts): 70 | batch = [lot] 71 | if lot.actual_step.batch_max > 1: 72 | for bo_lot in nexts: 73 | if lot.actual_step.step_name == bo_lot.actual_step.step_name: 74 | batch.append(bo_lot) 75 | if len(batch) == lot.actual_step.batch_max: 76 | break 77 | return batch 78 | 79 | 80 | def get_lots_to_dispatch_by_lot(instance, current_time, dispatcher): 81 | global last_sort_time 82 | if last_sort_time != current_time: 83 | for lot in instance.usable_lots: 84 | lot.ptuple = dispatcher(lot, current_time, None) 85 | last_sort_time = current_time 86 | instance.usable_lots.sort(key=lambda k: k.ptuple) 87 | lots = instance.usable_lots 88 | setup_machine, setup_batch = None, None 89 | min_run_break_machine, min_run_break_batch = None, None 90 | family_lock = None 91 | for i in range(len(lots)): 92 | lot: Lot = lots[i] 93 | if family_lock is None or family_lock == lot.actual_step.family: 94 | family_lock = lot.actual_step.family 95 | assert len(lot.waiting_machines) > 0 96 | for machine in lot.waiting_machines: 97 | if lot.actual_step.setup_needed == '' or lot.actual_step.setup_needed == machine.current_setup: 98 | return machine, build_batch(lot, lots[i + 1:]) 99 | else: 100 | if setup_machine is None and machine.min_runs_left is None: 101 | setup_machine = machine 102 | setup_batch = i 103 | if min_run_break_machine is None: 104 | min_run_break_machine = machine 105 | min_run_break_batch = i 106 | if setup_machine is not None: 107 | return setup_machine, build_batch(lots[setup_batch], lots[setup_batch + 1:]) 108 | return min_run_break_machine, build_batch(lots[min_run_break_batch], lots[min_run_break_batch + 1:]) 109 | 110 | 111 | def run_greedy(): 112 | p = argparse.ArgumentParser() 113 | p.add_argument('--dataset', type=str) 114 | p.add_argument('--days', type=int) 115 | p.add_argument('--dispatcher', type=str) 116 | p.add_argument('--seed', type=int) 117 | p.add_argument('--wandb', action='store_true', default=False) 118 | p.add_argument('--chart', action='store_true', default=False) 119 | p.add_argument('--alg', type=str, default='l4m', choices=['l4m', 'm4l']) 120 | a = p.parse_args() 121 | 122 | sys.stderr.write('Loading ' + a.dataset + ' for ' + str(a.days) + ' days, using ' + a.dispatcher + '\n') 123 | sys.stderr.flush() 124 | 125 | start_time = datetime.now() 126 | 127 | files = read_all('datasets/' + a.dataset) 128 | 129 | run_to = 3600 * 24 * a.days 130 | Randomizer().random.seed(a.seed) 131 | l4m = a.alg == 'l4m' 132 | plugins = [] 133 | if a.wandb: 134 | from simulation.plugins.wandb_plugin import WandBPlugin 135 | plugins.append(WandBPlugin()) 136 | if a.chart: 137 | from simulation.plugins.chart_plugin import ChartPlugin 138 | plugins.append(ChartPlugin()) 139 | plugins.append(CostPlugin()) 140 | instance = FileInstance(files, run_to, l4m, plugins) 141 | 142 | dispatcher = dispatcher_map[a.dispatcher] 143 | 144 | sys.stderr.write('Starting simulation with dispatching rule\n\n') 145 | sys.stderr.flush() 146 | 147 | while not instance.done: 148 | done = instance.next_decision_point() 149 | instance.print_progress_in_days() 150 | if done or instance.current_time > run_to: 151 | break 152 | 153 | if l4m: 154 | machine, lots = get_lots_to_dispatch_by_machine(instance, dispatcher) 155 | if lots is None: 156 | instance.usable_machines.remove(machine) 157 | else: 158 | instance.dispatch(machine, lots) 159 | else: 160 | machine, lots = get_lots_to_dispatch_by_lot(instance, instance.current_time, dispatcher) 161 | if lots is None: 162 | instance.usable_lots.clear() 163 | instance.lot_in_usable.clear() 164 | instance.next_step() 165 | else: 166 | instance.dispatch(machine, lots) 167 | 168 | instance.finalize() 169 | interval = datetime.now() - start_time 170 | print(instance.current_time_days, ' days simulated in ', interval) 171 | print_statistics(instance, a.days, a.dataset, a.dispatcher, method='greedy_seed' + str(a.seed)) 172 | -------------------------------------------------------------------------------- /simulation/classes.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict 2 | 3 | from simulation.events import BreakdownEvent 4 | from simulation.randomizer import Randomizer 5 | from simulation.tools import get_interval, get_distribution, date_time_parse, ConstantDistribution 6 | 7 | r = Randomizer() 8 | 9 | machine_classes = {} 10 | 11 | 12 | def alt(d, a1, a2): 13 | return d[a1] if a1 in d else (d[a2] if a2 is not None else None) 14 | 15 | 16 | def default(d, a1, de): 17 | return d[a1] if a1 in d else de 18 | 19 | 20 | def none_is_0(v): 21 | return 0 if v is None else v 22 | 23 | 24 | class Machine: 25 | 26 | def __init__(self, idx, d, speed): 27 | self.idx = idx 28 | self.load_time = none_is_0(get_interval(d['LTIME'], d['LTUNITS'])) 29 | self.unload_time = none_is_0(get_interval(d['ULTIME'], d['ULTUNITS'])) 30 | self.group = d['STNGRP'] 31 | if self.group not in machine_classes: 32 | machine_classes[self.group] = len(machine_classes) 33 | self.machine_class = machine_classes[self.group] 34 | self.loc = d['STNFAMLOC'] 35 | self.family = d['STNFAM'] 36 | self.cascading = True if type(d['STNCAP']) in [int, float] and int(d['STNCAP']) == 2 else False 37 | self.speed = speed 38 | self.minimize_setup_time = d['WAKERESRANK'] == 'wake_LeastSetupTime' 39 | 40 | self.available_from = None 41 | self.available_to = None 42 | 43 | self.piece_per_maintenance = [] 44 | self.pieces_until_maintenance = [] 45 | self.maintenance_time = [] 46 | 47 | self.waiting_lots: List[Lot] = [] 48 | 49 | self.utilized_time = 0 50 | self.setuped_time = 0 51 | self.pmed_time = 0 52 | self.bred_time = 0 53 | 54 | self.current_setup = '' 55 | 56 | self.events = [] 57 | self.min_runs_left = None 58 | self.min_runs_setup = None 59 | 60 | # RL state space features 61 | self.pms: List[BreakdownEvent] = [] 62 | self.last_actions = 4 * [999] 63 | 64 | self.last_setup_time = 0 65 | self.dispatch_failed = 0 66 | 67 | self.has_min_runs = False 68 | 69 | self.next_preventive_maintenance = None 70 | 71 | def __hash__(self): 72 | return self.idx 73 | 74 | def __repr__(self): 75 | return f'Machine {self.idx}' 76 | 77 | 78 | class Product: 79 | def __init__(self, route, priority): 80 | self.route = route 81 | self.priority = priority 82 | 83 | 84 | class Step: 85 | 86 | def __init__(self, idx, pieces_per_lot, d): 87 | self.idx = idx 88 | self.order = d['STEP'] 89 | self.step_name = d['DESC'] 90 | self.family = d['STNFAM'] 91 | self.setup_needed = d['SETUP'] 92 | self.setup_time = get_interval(d['STIME'], d['STUNITS']) if type(d['STIME']) is int else None 93 | self.rework_step = d['RWKSTEP'] 94 | assert len(self.family) > 0 95 | self.cascading = False 96 | if type(d['PartInterval']) in [float, int]: 97 | assert d['PTPER'] == 'per_piece' 98 | per_piece = get_interval(d['PartInterval'], d['PartIntUnits']) 99 | self.processing_time = get_distribution(d['PDIST'], d['PTUNITS'], d['PTIME'], d['PTIME2']) 100 | self.processing_time.m += per_piece * (pieces_per_lot - 1) 101 | self.cascading_time = ConstantDistribution(per_piece * pieces_per_lot) 102 | self.cascading = True 103 | else: 104 | if d['PTPER'] == 'per_piece': 105 | m = pieces_per_lot 106 | else: 107 | m = 1 108 | self.processing_time = get_distribution(default(d, 'PDIST', 'constant'), d['PTUNITS'], d['PTIME'], 109 | d['PTIME2'], multiplier=m) 110 | if type(d['BatchInterval']) in [float, int]: 111 | self.cascading_time = get_distribution('constant', d['BatchIntUnits'], d['BatchInterval']) 112 | self.cascading = True 113 | else: 114 | self.cascading_time = self.processing_time 115 | self.batching = d['PTPER'] == 'per_batch' 116 | self.batch_min = 1 if d['BATCHMN'] == '' else int(d['BATCHMN'] / pieces_per_lot) 117 | self.batch_max = 1 if d['BATCHMX'] == '' else int(d['BATCHMX'] / pieces_per_lot) 118 | self.sampling_percent = 100 if d['StepPercent'] in ['', None] else float(d['StepPercent']) 119 | self.rework_percent = 0 if d['REWORK'] in ['', None] else float(d['REWORK']) 120 | 121 | self.cqt_for_step = d['STEP_CQT'] if 'STEP_CQT' in d else None 122 | self.cqt_time = get_interval(d['CQT'], d['CQTUNITS']) if self.cqt_for_step is not None else None 123 | 124 | self.lot_to_lens_dedication = d['FORSTEP'] if d['SVESTN'] == 'yes' else None 125 | 126 | self.family_location = '' 127 | self.transport_time = ConstantDistribution(0) 128 | 129 | self.reworked = {} 130 | 131 | def has_to_perform(self): 132 | if self.sampling_percent == 100: 133 | return True 134 | return r.random.uniform(0, 100) <= self.sampling_percent 135 | 136 | def has_to_rework(self, lot_id): 137 | if self.rework_percent == 0 or lot_id in self.reworked: 138 | return False 139 | self.reworked[lot_id] = True 140 | return r.random.uniform(0, 100) <= self.rework_percent 141 | 142 | 143 | class Lot: 144 | def __init__(self, idx, route, priority, release, relative_deadline, d): 145 | self.idx = idx 146 | self.remaining_steps = [step for step in route.steps] 147 | self.actual_step: Step = None 148 | self.processed_steps = [] 149 | self.priority = priority 150 | self.release_at = release 151 | self.deadline_at = self.release_at + relative_deadline 152 | self.name: str = d['LOT'] 153 | self.part_name: str = d['PART'] 154 | if 'Init_' in self.name: 155 | self.name = self.name[self.name.index('_') + 1:self.name.rindex('_')] 156 | 157 | if 'CURSTEP' in d: 158 | cs = d['CURSTEP'] 159 | self.processed_steps, self.remaining_steps = self.remaining_steps[:cs - 1], self.remaining_steps[cs - 1:] 160 | 161 | self.pieces = d['PIECES'] 162 | 163 | self.waiting_machines = [] 164 | 165 | self.done_at = None 166 | self.free_since = None 167 | 168 | self.remaining_steps_last = -1 169 | self.remaining_time_last = 0 170 | 171 | self.dedications = {} 172 | 173 | self.waiting_time = 0 174 | self.waiting_time_batching = 0 175 | self.processing_time = 0 176 | self.transport_time = 0 177 | 178 | self.cqt_waiting = None 179 | self.cqt_deadline = None 180 | 181 | self.ft = None 182 | 183 | def __hash__(self): 184 | return self.idx 185 | 186 | def __repr__(self): 187 | return f'Lot {self.idx}' 188 | 189 | def cr(self, time): 190 | rt = self.remaining_time 191 | return (self.deadline_at - time) / rt if rt > 0 else 1 192 | 193 | @property 194 | def full_time(self): 195 | if self.ft is None: 196 | self.ft = sum( 197 | [s.processing_time.avg() for s in self.processed_steps + 198 | ([self.actual_step] if self.actual_step is not None else []) + self.remaining_steps]) 199 | return self.ft 200 | 201 | @property 202 | def remaining_time(self): 203 | if self.remaining_steps_last != len(self.remaining_steps): 204 | if self.remaining_steps_last - 1 == len(self.remaining_steps): 205 | self.remaining_time_last -= self.processed_steps[-1].processing_time.avg() 206 | else: 207 | self.remaining_time_last = sum( 208 | [s.processing_time.avg() for s in self.remaining_steps]) + self.actual_step.processing_time.avg() 209 | self.remaining_steps_last = len(self.remaining_steps) 210 | return self.remaining_time_last 211 | 212 | 213 | class Route: 214 | 215 | def __init__(self, idx, steps: List[Step]): 216 | self.idx = idx 217 | self.steps = steps 218 | 219 | 220 | class FileRoute(Route): 221 | 222 | def __init__(self, idx, pieces_per_lot, steps: List[Dict]): 223 | steps = [Step(i, pieces_per_lot, d) for i, d in enumerate(steps)] 224 | super().__init__(idx, steps) 225 | -------------------------------------------------------------------------------- /simulation/gym/environment.py: -------------------------------------------------------------------------------- 1 | import statistics 2 | from collections import defaultdict 3 | from typing import List 4 | 5 | import gym 6 | from gym import Env 7 | 8 | from simulation.classes import Machine, Lot 9 | from simulation.file_instance import FileInstance 10 | from simulation.greedy import get_lots_to_dispatch_by_machine 11 | from simulation.dispatching.dispatcher import Dispatchers, dispatcher_map 12 | from simulation.gym.E import E 13 | from simulation.randomizer import Randomizer 14 | from simulation.read import read_all 15 | 16 | r = Randomizer() 17 | 18 | STATE_COMPONENTS_DEMO = ( 19 | E.A.L4M.S.OPERATION_TYPE.NO_LOTS_PER_BATCH, 20 | E.A.L4M.S.OPERATION_TYPE.CR.MAX, 21 | E.A.L4M.S.OPERATION_TYPE.FREE_SINCE.MAX, 22 | E.A.L4M.S.OPERATION_TYPE.SETUP.MIN_RUNS_OK, 23 | E.A.L4M.S.OPERATION_TYPE.SETUP.NEEDED, 24 | E.A.L4M.S.OPERATION_TYPE.SETUP.LAST_SETUP_TIME, 25 | ) 26 | 27 | 28 | class DynamicSCFabSimulationEnvironment(Env): 29 | 30 | def __init__(self, num_actions, active_station_group, days, dataset, dispatcher, seed, max_steps, 31 | reward_type, action, state_components): 32 | self.did_reset = False 33 | self.files = read_all('datasets/' + dataset) 34 | self.instance = None 35 | self.num_actions = num_actions 36 | self.days = days 37 | self.action_space = gym.spaces.Discrete(num_actions) 38 | self.action = action 39 | self.observation_space = gym.spaces.Box(low=-100, high=1000000, 40 | shape=(4 + num_actions * len(state_components),)) 41 | self._state = None 42 | self.station_group = active_station_group 43 | self.lots_done = 0 44 | self.seed_val = seed 45 | self.dispatcher = dispatcher_map[dispatcher] 46 | self.max_steps = max_steps 47 | self.reward_type = reward_type 48 | self.mavg = 0 49 | self.state_components = state_components 50 | self.reset() 51 | 52 | def seed(self, seed=None): 53 | if seed is None: 54 | seed = 0 55 | self.seed_val = seed 56 | self.reset() 57 | 58 | def step(self, action): 59 | self.did_reset = False 60 | self.actual_step += 1 61 | # apply_priority_rule(self._machine) 62 | waiting_lots = self._machine.actions 63 | lot_index = action 64 | if lot_index < len(waiting_lots) and waiting_lots[lot_index] is not None: 65 | lot_group = waiting_lots[lot_index] 66 | lot = lot_group[0] 67 | lots = lot_group[:min(len(lot_group), lot.actual_step.batch_max)] 68 | violated_minruns = self._machine.min_runs_left is not None and self._machine.min_runs_setup == lot.actual_step.setup_needed 69 | self.instance.dispatch(self._machine, lots) 70 | done = self.next_step() or self.max_steps < self.actual_step 71 | reward = 0 72 | if self.reward_type in [1, 2]: 73 | for i in range(self.lots_done, len(self.instance.done_lots)): 74 | lot = self.instance.done_lots[i] 75 | reward += 1000 76 | if self.reward_type == 2: 77 | reward += 1000 if lot.deadline_at >= lot.done_at else 0 78 | else: 79 | reward += 1000 if lot.deadline_at >= lot.done_at else -min(500, ( 80 | lot.done_at - lot.deadline_at) / 3600) 81 | elif self.reward_type == 3: 82 | reward += statistics.mean( 83 | [min(1, j.cr(self.instance.current_time) - 1) for j in self.instance.active_lots]) 84 | elif self.reward_type == 7: 85 | reward += statistics.mean( 86 | [l.notlateness(self.instance.current_time) for l in self.instance.active_lots]) 87 | else: 88 | pass 89 | if violated_minruns: 90 | reward += -10 91 | self.lots_done = len(self.instance.done_lots) 92 | return self.state, reward, done, {} 93 | else: 94 | return self.state, -100, self.max_steps < self.actual_step, {} 95 | 96 | def reset(self): 97 | if not self.did_reset: 98 | self.did_reset = True 99 | self.actual_step = 0 100 | self.lots_done = 0 101 | run_to = 3600 * 24 * self.days 102 | self.instance = FileInstance(self.files, run_to, True, []) 103 | Randomizer().random.seed(self.seed_val) 104 | self.seed_val += 1 105 | self.next_step() 106 | return self.state 107 | 108 | def next_step(self): 109 | found = False 110 | while not found: 111 | done = self.instance.next_decision_point() 112 | if done or self.instance.current_time > 3600 * 24 * self.days: 113 | return True 114 | for machine in self.instance.usable_machines: 115 | break 116 | if self.station_group is None or \ 117 | f'[{machine.group}]' in self.station_group or \ 118 | f'<{machine.family}>' in self.station_group: 119 | found = True 120 | else: 121 | machine, lots = get_lots_to_dispatch_by_machine(self.instance, machine=machine, 122 | ptuple_fcn=self.dispatcher) 123 | if lots is None: 124 | self.instance.usable_machines.remove(machine) 125 | else: 126 | self.instance.dispatch(machine, lots) 127 | 128 | self._machine = machine 129 | actions = defaultdict(lambda: []) 130 | for lot in machine.waiting_lots: 131 | actions[lot.actual_step.step_name].append(lot) 132 | self.mavg = self.mavg * 0.99 + len(actions) * 0.01 133 | if len(actions) > self.num_actions: 134 | self._machine.actions = r.random.sample(list(actions.values()), self.num_actions) 135 | else: 136 | self._machine.actions = list(actions.values()) 137 | while len(self._machine.actions) < self.num_actions: 138 | self._machine.actions.append(None) 139 | r.random.shuffle(self._machine.actions) 140 | self._state = None 141 | return False 142 | 143 | @property 144 | def state(self): 145 | if self._state is None: 146 | m: Machine = self._machine 147 | t = self.instance.current_time 148 | self._state = [ 149 | m.pms[0].timestamp - t if len(m.pms) > 0 else 999999, # next maintenance 150 | m.utilized_time / m.setuped_time if m.setuped_time > 0 else 0, # ratio of setup time / processing time 151 | (m.setuped_time + m.utilized_time) / t if t > 0 else 0, # ratio of non idle time 152 | m.machine_class, # type of machine 153 | ] 154 | from statistics import mean, median 155 | for action in self._machine.actions: 156 | if action is None: 157 | self._state += [-1000] * len(self.state_components) 158 | else: 159 | action: List[Lot] 160 | free_since = [self.instance.current_time - l.free_since for l in action] 161 | work_rem = [len(l.remaining_steps) for l in action] 162 | cr = [l.cr(self.instance.current_time) for l in action] 163 | priority = [l.priority for l in action] 164 | l0 = action[0] 165 | 166 | self._machine: Machine 167 | action_type_state_lambdas = { 168 | E.A.L4M.S.OPERATION_TYPE.NO_LOTS: lambda: len(action), 169 | E.A.L4M.S.OPERATION_TYPE.NO_LOTS_PER_BATCH: lambda: len(action) / l0.actual_step.batch_max, 170 | E.A.L4M.S.OPERATION_TYPE.STEPS_LEFT.MEAN: lambda: mean(work_rem), 171 | E.A.L4M.S.OPERATION_TYPE.STEPS_LEFT.MEDIAN: lambda: median(work_rem), 172 | E.A.L4M.S.OPERATION_TYPE.STEPS_LEFT.MAX: lambda: max(work_rem), 173 | E.A.L4M.S.OPERATION_TYPE.STEPS_LEFT.MIN: lambda: min(work_rem), 174 | E.A.L4M.S.OPERATION_TYPE.FREE_SINCE.MEAN: lambda: mean(free_since), 175 | E.A.L4M.S.OPERATION_TYPE.FREE_SINCE.MEDIAN: lambda: median(free_since), 176 | E.A.L4M.S.OPERATION_TYPE.FREE_SINCE.MAX: lambda: max(free_since), 177 | E.A.L4M.S.OPERATION_TYPE.FREE_SINCE.MIN: lambda: min(free_since), 178 | E.A.L4M.S.OPERATION_TYPE.PROCESSING_TIME.AVERAGE: lambda: l0.actual_step.processing_time.avg(), 179 | E.A.L4M.S.OPERATION_TYPE.BATCH.MIN: lambda: l0.actual_step.batch_min, 180 | E.A.L4M.S.OPERATION_TYPE.BATCH.MAX: lambda: l0.actual_step.batch_max, 181 | E.A.L4M.S.OPERATION_TYPE.BATCH.FULLNESS: lambda: min(1, len(action) / l0.actual_step.batch_max), 182 | E.A.L4M.S.OPERATION_TYPE.PRIORITY.MEAN: lambda: mean(priority), 183 | E.A.L4M.S.OPERATION_TYPE.PRIORITY.MEDIAN: lambda: median(priority), 184 | E.A.L4M.S.OPERATION_TYPE.PRIORITY.MAX: lambda: max(priority), 185 | E.A.L4M.S.OPERATION_TYPE.PRIORITY.MIN: lambda: min(priority), 186 | E.A.L4M.S.OPERATION_TYPE.CR.MEAN: lambda: mean(cr), 187 | E.A.L4M.S.OPERATION_TYPE.CR.MEDIAN: lambda: median(cr), 188 | E.A.L4M.S.OPERATION_TYPE.CR.MAX: lambda: max(cr), 189 | E.A.L4M.S.OPERATION_TYPE.CR.MIN: lambda: min(cr), 190 | E.A.L4M.S.OPERATION_TYPE.SETUP.NEEDED: lambda: 0 if l0.actual_step.setup_needed == '' or l0.actual_step.setup_needed == m.current_setup else 1, 191 | E.A.L4M.S.OPERATION_TYPE.SETUP.MIN_RUNS_LEFT: lambda: 0 if self._machine.min_runs_left is None else self._machine.min_runs_left, 192 | E.A.L4M.S.OPERATION_TYPE.SETUP.MIN_RUNS_OK: lambda: 1 if l0.actual_step.setup_needed == '' or l0.actual_step.setup_needed == self._machine.min_runs_setup else 0, 193 | E.A.L4M.S.OPERATION_TYPE.SETUP.LAST_SETUP_TIME: lambda: self._machine.last_setup_time, 194 | E.A.L4M.S.MACHINE.MAINTENANCE.NEXT: lambda: 0, 195 | E.A.L4M.S.MACHINE.IDLE_RATIO: lambda: 1 - ( 196 | self._machine.utilized_time / self.instance.current_time) if self._machine.utilized_time > 0 else 1, 197 | E.A.L4M.S.MACHINE.SETUP_PROCESSING_RATIO: lambda: ( 198 | self._machine.setuped_time / self._machine.utilized_time) if self._machine.utilized_time > 0 else 1, 199 | E.A.L4M.S.MACHINE.MACHINE_CLASS: lambda: 0, 200 | } 201 | self._state += [ 202 | action_type_state_lambdas[s]() 203 | for s in self.state_components 204 | ] 205 | return self._state 206 | 207 | def render(self, mode="human"): 208 | pass 209 | -------------------------------------------------------------------------------- /simulation/instance.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from typing import Dict, List, Set, Tuple 3 | 4 | from simulation.classes import Machine, Route, Lot 5 | from simulation.dispatching.dm_lot_for_machine import LotForMachineDispatchManager 6 | from simulation.dispatching.dm_machine_for_lot import MachineForLotDispatchManager 7 | from simulation.event_queue import EventQueue 8 | from simulation.events import MachineDoneEvent, LotDoneEvent, BreakdownEvent, ReleaseEvent 9 | from simulation.plugins.interface import IPlugin 10 | 11 | 12 | class Instance: 13 | 14 | def __init__(self, machines: List[Machine], routes: Dict[str, Route], lots: List[Lot], 15 | setups: Dict[Tuple, int], setup_min_run: Dict[str, int], breakdowns: List[BreakdownEvent], 16 | lot_for_machine, plugins): 17 | self.plugins: List[IPlugin] = plugins 18 | self.lot_waiting_at_machine = defaultdict(lambda: (0, 0)) 19 | 20 | self.free_machines: List[bool] = [] 21 | self.usable_machines: Set[Machine] = set() 22 | self.usable_lots: List[Lot] = list() 23 | 24 | self.machines: List[Machine] = [m for m in machines] 25 | self.family_machines = defaultdict(lambda: []) 26 | for m in self.machines: 27 | self.family_machines[m.family].append(m) 28 | self.routes: Dict[str, Route] = routes 29 | self.setups: Dict[Tuple, int] = setups 30 | self.setup_min_run: Dict[str, int] = setup_min_run 31 | 32 | self.dm = LotForMachineDispatchManager() if lot_for_machine else MachineForLotDispatchManager() 33 | self.dm.init(self) 34 | 35 | self.dispatchable_lots: List[Lot] = lots 36 | self.dispatchable_lots.sort(key=lambda k: k.release_at) 37 | self.active_lots: List[Lot] = [] 38 | self.done_lots: List[Lot] = [] 39 | 40 | self.events = EventQueue() 41 | 42 | self.current_time = 0 43 | 44 | for plugin in self.plugins: 45 | plugin.on_sim_init(self) 46 | 47 | self.next_step() 48 | 49 | self.free_up_machines(self.machines) 50 | 51 | for br in breakdowns: 52 | self.add_event(br) 53 | 54 | self.printed_days = -1 55 | 56 | @property 57 | def current_time_days(self): 58 | return self.current_time / 3600 / 24 59 | 60 | def next_step(self): 61 | process_until = [] 62 | if len(self.events.arr) > 0: 63 | process_until.append(max(0, self.events.first.timestamp)) 64 | process_until.append(max(0, self.dispatchable_lots[0].release_at)) 65 | process_until = min(process_until) 66 | while len(self.events.arr) > 0 and self.events.first.timestamp <= process_until: 67 | ev = self.events.pop_first() 68 | self.current_time = max(0, ev.timestamp, self.current_time) 69 | # print(f'Time stamp {self.current_time}') 70 | ev.handle(self) 71 | ReleaseEvent.handle(self, process_until) 72 | 73 | def free_up_machines(self, machines): 74 | # add machine to list of available machines 75 | for machine in machines: 76 | machine.events.clear() 77 | self.dm.free_up_machine(self, machine) 78 | 79 | for plugin in self.plugins: 80 | plugin.on_machine_free(self, machine) 81 | 82 | def free_up_lots(self, lots: List[Lot]): 83 | # add lot to lists, make it available 84 | for lot in lots: 85 | lot.free_since = self.current_time 86 | step_found = False 87 | while len(lot.remaining_steps) > 0: 88 | old_step = None 89 | if lot.actual_step is not None: 90 | lot.processed_steps.append(lot.actual_step) 91 | old_step = lot.actual_step 92 | if lot.actual_step is not None and lot.actual_step.has_to_rework(lot.idx): 93 | rw_step = lot.actual_step.rework_step 94 | removed = lot.processed_steps[rw_step - 1:] 95 | lot.processed_steps = lot.processed_steps[:rw_step - 1] 96 | lot.remaining_steps = removed + lot.remaining_steps 97 | lot.actual_step, lot.remaining_steps = lot.remaining_steps[0], lot.remaining_steps[1:] 98 | if lot.actual_step.has_to_perform(): 99 | # print(f'Lot {lot.idx} step {len(lot.processed_steps)} / {len(lot.remaining_steps)}') 100 | self.dm.free_up_lots(self, lot) 101 | step_found = True 102 | for plugin in self.plugins: 103 | plugin.on_step_done(self, lot, old_step) 104 | break 105 | if not step_found: 106 | assert len(lot.remaining_steps) == 0 107 | lot.actual_step = None 108 | lot.done_at = self.current_time 109 | # print(f'Lot {lot.idx} is done {len(self.active_lots)} {len(self.done_lots)} {self.current_time_days}') 110 | self.active_lots.remove(lot) 111 | self.done_lots.append(lot) 112 | for plugin in self.plugins: 113 | plugin.on_lot_done(self, lot) 114 | 115 | for plugin in self.plugins: 116 | plugin.on_lot_free(self, lot) 117 | 118 | def dispatch(self, machine: Machine, lots: List[Lot]): 119 | # remove machine and lot from active sets 120 | self.reserve_machine_lot(lots, machine) 121 | lwam = self.lot_waiting_at_machine[machine.family] 122 | self.lot_waiting_at_machine[machine.family] = (lwam[0] + len(lots), 123 | lwam[1] + sum([self.current_time - l.free_since for l in lots])) 124 | for lot in lots: 125 | lot.waiting_time += self.current_time - lot.free_since 126 | if lot.actual_step.batch_max > 1: 127 | lot.waiting_time_batching += self.current_time - lot.free_since 128 | if lot.actual_step.cqt_for_step is not None: 129 | lot.cqt_waiting = lot.actual_step.cqt_for_step 130 | lot.cqt_deadline = lot.actual_step.cqt_time 131 | if lot.actual_step.order == lot.cqt_waiting: 132 | if lot.cqt_deadline < self.current_time: 133 | for plugin in self.plugins: 134 | plugin.on_cqt_violated(self, machine, lot) 135 | lot.cqt_waiting = None 136 | lot.cqt_deadline = None 137 | # compute times for lot and machine 138 | lot_time, machine_time, setup_time = self.get_times(self.setups, lots, machine) 139 | # compute per-piece preventive maintenance requirement 140 | for i in range(len(machine.pieces_until_maintenance)): 141 | machine.pieces_until_maintenance[i] -= sum([l.pieces for l in lots]) 142 | if machine.pieces_until_maintenance[i] <= 0: 143 | s = machine.maintenance_time[i].sample() 144 | machine_time += s 145 | machine.pieces_until_maintenance[i] = machine.piece_per_maintenance[i] 146 | machine.pmed_time += s 147 | # if there is ltl dedication, dedicate lot for selected step 148 | for lot in lots: 149 | if lot.actual_step.lot_to_lens_dedication is not None: 150 | lot.dedications[lot.actual_step.lot_to_lens_dedication] = machine.idx 151 | # decrease / eliminate min runs required before next setup 152 | if machine.min_runs_left is not None: 153 | machine.min_runs_left -= len(lots) 154 | if machine.min_runs_left <= 0: 155 | machine.min_runs_left = None 156 | machine.min_runs_setup = None 157 | # add events 158 | machine_done = self.current_time + machine_time + setup_time 159 | lot_done = self.current_time + lot_time + setup_time 160 | ev1 = MachineDoneEvent(machine_done, [machine]) 161 | ev2 = LotDoneEvent(lot_done, [machine], lots) 162 | self.add_event(ev1) 163 | self.add_event(ev2) 164 | machine.events += [ev1, ev2] 165 | 166 | for plugin in self.plugins: 167 | plugin.on_dispatch(self, machine, lots, machine_done, lot_done) 168 | return machine_done, lot_done 169 | 170 | def get_times(self, setups, lots, machine): 171 | proc_t_samp = lots[0].actual_step.processing_time.sample() 172 | lot_time = proc_t_samp + machine.load_time + machine.unload_time 173 | for lot in lots: 174 | lot.processing_time += lot_time 175 | if len(lots[0].remaining_steps) > 0: 176 | tt = lots[0].remaining_steps[0].transport_time.sample() 177 | lot_time += tt 178 | for lot in lots: 179 | lot.transport_time += tt 180 | if lots[0].actual_step.processing_time == lots[0].actual_step.cascading_time: 181 | cascade_t_samp = proc_t_samp 182 | else: 183 | cascade_t_samp = lots[0].actual_step.cascading_time.sample() 184 | machine_time = cascade_t_samp + (machine.load_time + machine.unload_time if not machine.cascading else 0) 185 | new_setup = lots[0].actual_step.setup_needed 186 | if new_setup != '' and machine.current_setup != new_setup: 187 | if lots[0].actual_step.setup_time is not None: 188 | setup_time = lots[0].actual_step.setup_time 189 | elif (machine.current_setup, new_setup) in setups: 190 | setup_time = setups[(machine.current_setup, new_setup)] 191 | elif ('', new_setup) in setups: 192 | setup_time = setups[('', new_setup)] 193 | else: 194 | setup_time = 0 195 | else: 196 | setup_time = 0 197 | if new_setup in self.setup_min_run: 198 | machine.min_runs_left = self.setup_min_run[new_setup] 199 | machine.min_runs_setup = new_setup 200 | machine.has_min_runs = True 201 | if setup_time > 0: 202 | machine.last_setup_time = setup_time 203 | machine.utilized_time += machine_time 204 | machine.setuped_time += setup_time 205 | machine.last_setup = machine.current_setup 206 | machine.current_setup = new_setup 207 | return lot_time, machine_time, setup_time 208 | 209 | def reserve_machine_lot(self, lots, machine): 210 | self.dm.reserve(self, lots, machine) 211 | 212 | def add_event(self, to_insert): 213 | # insert event to the correct place in the array 214 | self.events.ordered_insert(to_insert) 215 | 216 | def next_decision_point(self): 217 | return self.dm.next_decision_point(self) 218 | 219 | def handle_breakdown(self, machine, delay): 220 | ta = [] 221 | for ev in machine.events: 222 | if ev in self.events.arr: 223 | ta.append(ev) 224 | self.events.remove(ev) 225 | for ev in ta: 226 | ev.timestamp += delay 227 | self.add_event(ev) 228 | 229 | @property 230 | def done(self): 231 | return len(self.dispatchable_lots) == 0 and len(self.active_lots) == 0 232 | 233 | def finalize(self): 234 | for plugin in self.plugins: 235 | plugin.on_sim_done(self) 236 | 237 | def print_progress_in_days(self): 238 | import sys 239 | if int(self.current_time_days) > self.printed_days: 240 | self.printed_days = int(self.current_time_days) 241 | if self.printed_days > 0: 242 | sys.stderr.write( 243 | f'\rDay {self.printed_days}===Throughput: {round(len(self.done_lots) / self.printed_days)}/day=') 244 | sys.stderr.flush() 245 | -------------------------------------------------------------------------------- /datasets/SMT2020_LVHM/attach.txt: -------------------------------------------------------------------------------- 1 | CALNAME CALTYPE RESTYPE RESNAME FOADIST FOA FOAUNITS 2 | BREAK_Def_Met down stngrp Def_Met exponential 10080 min 3 | BREAK_Dielectric down stngrp Dielectric exponential 10080 min 4 | BREAK_Diffusion down stngrp Diffusion exponential 10080 min 5 | BREAK_Dry_Etch down stngrp Dry_Etch exponential 10080 min 6 | BREAK_Implant down stngrp Implant exponential 10080 min 7 | BREAK_Litho down stngrp Litho exponential 10080 min 8 | BREAK_Litho_Met down stngrp Litho_Met exponential 10080 min 9 | BREAK_Planar down stngrp Planar exponential 10080 min 10 | BREAK_TF down stngrp TF exponential 10080 min 11 | BREAK_TF_Met down stngrp TF_Met exponential 10080 min 12 | BREAK_Wet_Etch down stngrp Wet_Etch exponential 10080 min 13 | DefMet_BE_33_MN pm stnfam DefMet_BE_33 constant 29.1 day 14 | DefMet_BE_33_QT pm stnfam DefMet_BE_33 constant 88.3 day 15 | DefMet_BE_42_MN pm stnfam DefMet_BE_42 constant 25.8 day 16 | DefMet_BE_42_QT pm stnfam DefMet_BE_42 constant 78.3 day 17 | DefMet_FE_10_MN pm stnfam DefMet_FE_10 constant 27 day 18 | DefMet_FE_10_QT pm stnfam DefMet_FE_10 constant 81.9 day 19 | DefMet_FE_106_MN pm stnfam DefMet_FE_106 constant 25.5 day 20 | DefMet_FE_106_QT pm stnfam DefMet_FE_106 constant 77.4 day 21 | DefMEt_FE_118_MN pm stnfam DefMEt_FE_118 constant 28.2 day 22 | DefMEt_FE_118_QT pm stnfam DefMEt_FE_118 constant 85.5 day 23 | DefMet_FE_34_MN pm stnfam DefMet_FE_34 constant 33 day 24 | DefMet_FE_34_QT pm stnfam DefMet_FE_34 constant 100.1 day 25 | DefMet_FE_43_MN pm stnfam DefMet_FE_43 constant 28.8 day 26 | DefMet_FE_43_QT pm stnfam DefMet_FE_43 constant 87.4 day 27 | Diffusion_BE_123_MN pm stnfam Diffusion_BE_123 constant 28.5 day 28 | Diffusion_BE_123_QT pm stnfam Diffusion_BE_123 constant 86.5 day 29 | Diffusion_FE_100_MN pm stnfam Diffusion_FE_100 constant 29.7 day 30 | Diffusion_FE_100_QT pm stnfam Diffusion_FE_100 constant 90.1 day 31 | Diffusion_FE_101_MN pm stnfam Diffusion_FE_101 constant 31.5 day 32 | Diffusion_FE_101_QT pm stnfam Diffusion_FE_101 constant 95.6 day 33 | Diffusion_FE_120_MN pm stnfam Diffusion_FE_120 constant 27.9 day 34 | Diffusion_FE_120_QT pm stnfam Diffusion_FE_120 constant 84.6 day 35 | Diffusion_FE_122_MN pm stnfam Diffusion_FE_122 constant 27.9 day 36 | Diffusion_FE_122_QT pm stnfam Diffusion_FE_122 constant 84.6 day 37 | Diffusion_FE_125_MN pm stnfam Diffusion_FE_125 constant 28.5 day 38 | Diffusion_FE_125_QT pm stnfam Diffusion_FE_125 constant 86.5 day 39 | Diffusion_FE_126_MN pm stnfam Diffusion_FE_126 constant 30.6 day 40 | Diffusion_FE_126_QT pm stnfam Diffusion_FE_126 constant 92.8 day 41 | Diffusion_FE_127_MN pm stnfam Diffusion_FE_127 constant 31.8 day 42 | Diffusion_FE_127_QT pm stnfam Diffusion_FE_127 constant 96.5 day 43 | Diffusion_FE_44_MN pm stnfam Diffusion_FE_44 constant 30.3 day 44 | Diffusion_FE_44_QT pm stnfam Diffusion_FE_44 constant 91.9 day 45 | Diffusion_FE_94_MN pm stnfam Diffusion_FE_94 constant 30 day 46 | Diffusion_FE_94_QT pm stnfam Diffusion_FE_94 constant 91 day 47 | Litho_BE_110_WK pm stnfam Litho_BE_110 constant 7 day 48 | Litho_BE_110_MN pm stnfam Litho_BE_110 constant 30 day 49 | Litho_BE_110_QT pm stnfam Litho_BE_110 constant 91 day 50 | Litho_BE_93_WK pm stnfam Litho_BE_93 constant 7.1 day 51 | Litho_BE_93_MN pm stnfam Litho_BE_93 constant 30.3 day 52 | Litho_BE_93_QT pm stnfam Litho_BE_93 constant 91.9 day 53 | Litho_BE_99_WK pm stnfam Litho_BE_99 constant 6.6 day 54 | Litho_BE_99_MN pm stnfam Litho_BE_99 constant 28.2 day 55 | Litho_BE_99_QT pm stnfam Litho_BE_99 constant 85.5 day 56 | Litho_FE_111_WK pm stnfam Litho_FE_111 constant 6.7 day 57 | Litho_FE_111_MN pm stnfam Litho_FE_111 constant 28.8 day 58 | Litho_FE_111_QT pm stnfam Litho_FE_111 constant 87.4 day 59 | Litho_FE_35_WK pm stnfam Litho_FE_35 constant 6.4 day 60 | Litho_FE_35_MN pm stnfam Litho_FE_35 constant 27.3 day 61 | Litho_FE_35_QT pm stnfam Litho_FE_35 constant 82.8 day 62 | Litho_FE_92_WK pm stnfam Litho_FE_92 constant 7.2 day 63 | Litho_FE_92_MN pm stnfam Litho_FE_92 constant 30.9 day 64 | Litho_FE_92_QT pm stnfam Litho_FE_92 constant 93.7 day 65 | Litho_FE_98_WK pm stnfam Litho_FE_98 constant 7.7 day 66 | Litho_FE_98_MN pm stnfam Litho_FE_98 constant 33 day 67 | Litho_FE_98_QT pm stnfam Litho_FE_98 constant 100.1 day 68 | Litho_REG_BE_63_MN pm stnfam Litho_REG_BE_63 constant 29.1 day 69 | Litho_REG_BE_63_QT pm stnfam Litho_REG_BE_63 constant 88.3 day 70 | Litho_REG_FE_64_MN pm stnfam Litho_REG_FE_64 constant 29.7 day 71 | Litho_REG_FE_64_QT pm stnfam Litho_REG_FE_64 constant 90.1 day 72 | LithoMet_BE_18_MN pm stnfam LithoMet_BE_18 constant 31.8 day 73 | LithoMet_BE_18_QT pm stnfam LithoMet_BE_18 constant 96.5 day 74 | LithoMet_FE_19_MN pm stnfam LithoMet_FE_19 constant 31.2 day 75 | LithoMet_FE_19_QT pm stnfam LithoMet_FE_19 constant 94.6 day 76 | LithoTrack_BE_117_WK pm stnfam LithoTrack_BE_117 constant 7.5 day 77 | LithoTrack_BE_117_MN pm stnfam LithoTrack_BE_117 constant 32.1 day 78 | LithoTrack_BE_117_QT pm stnfam LithoTrack_BE_117 constant 97.4 day 79 | LithoTrack_FE_115_WK pm stnfam LithoTrack_FE_115 constant 7 day 80 | LithoTrack_FE_115_MN pm stnfam LithoTrack_FE_115 constant 30 day 81 | LithoTrack_FE_115_QT pm stnfam LithoTrack_FE_115 constant 91 day 82 | LithoTrack_FE_95_WK pm stnfam LithoTrack_FE_95 constant 6.9 day 83 | LithoTrack_FE_95_MN pm stnfam LithoTrack_FE_95 constant 29.7 day 84 | LithoTrack_FE_95_QT pm stnfam LithoTrack_FE_95 constant 90.1 day 85 | LithoTrack_FE_96_WK pm stnfam LithoTrack_FE_96 constant 6.4 day 86 | LithoTrack_FE_96_MN pm stnfam LithoTrack_FE_96 constant 27.6 day 87 | LithoTrack_FE_96_QT pm stnfam LithoTrack_FE_96 constant 83.7 day 88 | TF_Met_FE_45_MN pm stnfam TF_Met_FE_45 constant 32.7 day 89 | TF_Met_FE_45_QT pm stnfam TF_Met_FE_45 constant 99.2 day 90 | TF_Met_FE_61_MN pm stnfam TF_Met_FE_61 constant 30.9 day 91 | TF_Met_FE_61_QT pm stnfam TF_Met_FE_61 constant 93.7 day 92 | DE_BE_11_WK pm stnfam DE_BE_11 constant 2244 93 | DE_BE_11_MN pm stnfam DE_BE_11 constant 9764 94 | DE_BE_11_QT pm stnfam DE_BE_11 constant 29290 95 | DE_BE_12_WK pm stnfam DE_BE_12 constant 1200 96 | DE_BE_12_MN pm stnfam DE_BE_12 constant 5250 97 | DE_BE_12_QT pm stnfam DE_BE_12 constant 15750 98 | DE_BE_13_WK pm stnfam DE_BE_13 constant 1942 99 | DE_BE_13_MN pm stnfam DE_BE_13 constant 8391 100 | DE_BE_13_QT pm stnfam DE_BE_13 constant 25172 101 | DE_BE_48_WK pm stnfam DE_BE_48 constant 1542 102 | DE_BE_48_MN pm stnfam DE_BE_48 constant 6649 103 | DE_BE_48_QT pm stnfam DE_BE_48 constant 19947 104 | DE_BE_50_WK pm stnfam DE_BE_50 constant 1800 105 | DE_BE_50_MN pm stnfam DE_BE_50 constant 7800 106 | DE_BE_50_QT pm stnfam DE_BE_50 constant 23400 107 | DE_BE_65_WK pm stnfam DE_BE_65 constant 1710 108 | DE_BE_65_MN pm stnfam DE_BE_65 constant 7380 109 | DE_BE_65_QT pm stnfam DE_BE_65 constant 22140 110 | DE_BE_66_WK pm stnfam DE_BE_66 constant 1486 111 | DE_BE_66_MN pm stnfam DE_BE_66 constant 6417 112 | DE_BE_66_QT pm stnfam DE_BE_66 constant 19250 113 | DE_BE_67_WK pm stnfam DE_BE_67 constant 1782 114 | DE_BE_67_MN pm stnfam DE_BE_67 constant 7751 115 | DE_BE_67_QT pm stnfam DE_BE_67 constant 23252 116 | DE_BE_69_WK pm stnfam DE_BE_69 constant 2180 117 | DE_BE_69_MN pm stnfam DE_BE_69 constant 9447 118 | DE_BE_69_QT pm stnfam DE_BE_69 constant 28340 119 | DE_FE_1_WK pm stnfam DE_FE_1 constant 1302 120 | DE_FE_1_MN pm stnfam DE_FE_1 constant 5580 121 | DE_FE_1_QT pm stnfam DE_FE_1 constant 16740 122 | DE_FE_51_WK pm stnfam DE_FE_51 constant 1504 123 | DE_FE_51_MN pm stnfam DE_FE_51 constant 6499 124 | DE_FE_51_QT pm stnfam DE_FE_51 constant 19497 125 | DE_FE_53_WK pm stnfam DE_FE_53 constant 900 126 | DE_FE_53_MN pm stnfam DE_FE_53 constant 3960 127 | DE_FE_53_QT pm stnfam DE_FE_53 constant 11880 128 | DE_FE_54_WK pm stnfam DE_FE_54 constant 1650 129 | DE_FE_54_MN pm stnfam DE_FE_54 constant 7260 130 | DE_FE_54_QT pm stnfam DE_FE_54 constant 21780 131 | DE_FE_56_WK pm stnfam DE_FE_56 constant 2825 132 | DE_FE_56_MN pm stnfam DE_FE_56 constant 12430 133 | DE_FE_56_QT pm stnfam DE_FE_56 constant 37290 134 | DE_FE_58_WK pm stnfam DE_FE_58 constant 2240 135 | DE_FE_58_MN pm stnfam DE_FE_58 constant 9520 136 | DE_FE_58_QT pm stnfam DE_FE_58 constant 28560 137 | DE_FE_59_WK pm stnfam DE_FE_59 constant 1750 138 | DE_FE_59_MN pm stnfam DE_FE_59 constant 7625 139 | DE_FE_59_QT pm stnfam DE_FE_59 constant 22875 140 | DE_FE_62_WK pm stnfam DE_FE_62 constant 1427 141 | DE_FE_62_MN pm stnfam DE_FE_62 constant 6162 142 | DE_FE_62_QT pm stnfam DE_FE_62 constant 18487 143 | DE_FE_70_WK pm stnfam DE_FE_70 constant 2028 144 | DE_FE_70_MN pm stnfam DE_FE_70 constant 8818 145 | DE_FE_70_QT pm stnfam DE_FE_70 constant 26455 146 | DE_FE_71_WK pm stnfam DE_FE_71 constant 1485 147 | DE_FE_71_MN pm stnfam DE_FE_71 constant 6435 148 | DE_FE_71_QT pm stnfam DE_FE_71 constant 19305 149 | DE_FE_72_WK pm stnfam DE_FE_72 constant 1814 150 | DE_FE_72_MN pm stnfam DE_FE_72 constant 7859 151 | DE_FE_72_QT pm stnfam DE_FE_72 constant 23577 152 | DE_FE_86_WK pm stnfam DE_FE_86 constant 1556 153 | DE_FE_86_MN pm stnfam DE_FE_86 constant 6744 154 | DE_FE_86_QT pm stnfam DE_FE_86 constant 20231 155 | Dielectric_BE_20_WK pm stnfam Dielectric_BE_20 constant 3604 156 | Dielectric_BE_20_MN pm stnfam Dielectric_BE_20 constant 15688 157 | Dielectric_BE_20_QT pm stnfam Dielectric_BE_20 constant 47064 158 | Dielectric_BE_21_WK pm stnfam Dielectric_BE_21 constant 4680 159 | Dielectric_BE_21_MN pm stnfam Dielectric_BE_21 constant 20340 160 | Dielectric_BE_21_QT pm stnfam Dielectric_BE_21 constant 61020 161 | Dielectric_BE_27_WK pm stnfam Dielectric_BE_27 constant 3986 162 | Dielectric_BE_27_MN pm stnfam Dielectric_BE_27 constant 17246 163 | Dielectric_BE_27_QT pm stnfam Dielectric_BE_27 constant 51740 164 | Dielectric_BE_28_WK pm stnfam Dielectric_BE_28 constant 4420 165 | Dielectric_BE_28_MN pm stnfam Dielectric_BE_28 constant 19040 166 | Dielectric_BE_28_QT pm stnfam Dielectric_BE_28 constant 57120 167 | Dielectric_BE_60_WK pm stnfam Dielectric_BE_60 constant 4000 168 | Dielectric_BE_60_MN pm stnfam Dielectric_BE_60 constant 17280 169 | Dielectric_BE_60_QT pm stnfam Dielectric_BE_60 constant 51840 170 | Dielectric_FE_112_WK pm stnfam Dielectric_FE_112 constant 3547 171 | Dielectric_FE_112_MN pm stnfam Dielectric_FE_112 constant 15336 172 | Dielectric_FE_112_QT pm stnfam Dielectric_FE_112 constant 46007 173 | Dielectric_FE_130_WK pm stnfam Dielectric_FE_130 constant 3500 174 | Dielectric_FE_130_MN pm stnfam Dielectric_FE_130 constant 15250 175 | Dielectric_FE_130_QT pm stnfam Dielectric_FE_130 constant 45750 176 | Dielectric_FE_29_WK pm stnfam Dielectric_FE_29 constant 2730 177 | Dielectric_FE_29_MN pm stnfam Dielectric_FE_29 constant 11830 178 | Dielectric_FE_29_QT pm stnfam Dielectric_FE_29 constant 35490 179 | Dielectric_FE_30_WK pm stnfam Dielectric_FE_30 constant 3150 180 | Dielectric_FE_30_MN pm stnfam Dielectric_FE_30 constant 13500 181 | Dielectric_FE_30_QT pm stnfam Dielectric_FE_30 constant 40500 182 | Dielectric_FE_31_WK pm stnfam Dielectric_FE_31 constant 4360 183 | Dielectric_FE_31_MN pm stnfam Dielectric_FE_31 constant 18803 184 | Dielectric_FE_31_QT pm stnfam Dielectric_FE_31 constant 56408 185 | EPI_36_WK pm stnfam EPI_36 constant 2675 186 | EPI_36_MN pm stnfam EPI_36 constant 11770 187 | EPI_36_QT pm stnfam EPI_36 constant 35310 188 | EPI_38_WK pm stnfam EPI_38 constant 3480 189 | EPI_38_MN pm stnfam EPI_38 constant 14790 190 | EPI_38_QT pm stnfam EPI_38 constant 44370 191 | Implant_119_WK pm stnfam Implant_119 constant 4895 192 | Implant_119_MN pm stnfam Implant_119 constant 21360 193 | Implant_119_QT pm stnfam Implant_119 constant 64080 194 | Implant_128_WK pm stnfam Implant_128 constant 7438 195 | Implant_128_MN pm stnfam Implant_128 constant 32228 196 | Implant_128_QT pm stnfam Implant_128 constant 96684 197 | Implant_132_WK pm stnfam Implant_132 constant 6143 198 | Implant_132_MN pm stnfam Implant_132 constant 26571 199 | Implant_132_QT pm stnfam Implant_132 constant 79714 200 | Implant_74_WK pm stnfam Implant_74 constant 3465 201 | Implant_74_MN pm stnfam Implant_74 constant 14850 202 | Implant_74_QT pm stnfam Implant_74 constant 44550 203 | Implant_88_WK pm stnfam Implant_88 constant 3570 204 | Implant_88_MN pm stnfam Implant_88 constant 15300 205 | Implant_88_QT pm stnfam Implant_88 constant 45900 206 | Implant_90_WK pm stnfam Implant_90 constant 5610 207 | Implant_90_MN pm stnfam Implant_90 constant 24480 208 | Implant_90_QT pm stnfam Implant_90 constant 73440 209 | Implant_91_WK pm stnfam Implant_91 constant 6879 210 | Implant_91_MN pm stnfam Implant_91 constant 29807 211 | Implant_91_QT pm stnfam Implant_91 constant 89421 212 | Planar_BE_75_WK pm stnfam Planar_BE_75 constant 3189 213 | Planar_BE_75_MN pm stnfam Planar_BE_75 constant 13842 214 | Planar_BE_75_QT pm stnfam Planar_BE_75 constant 41528 215 | Planar_FE_76_WK pm stnfam Planar_FE_76 constant 3815 216 | Planar_FE_76_MN pm stnfam Planar_FE_76 constant 16350 217 | Planar_FE_76_QT pm stnfam Planar_FE_76 constant 49050 218 | Planar_FE_77_WK pm stnfam Planar_FE_77 constant 3955 219 | Planar_FE_77_MN pm stnfam Planar_FE_77 constant 16950 220 | Planar_FE_77_QT pm stnfam Planar_FE_77 constant 50850 221 | Planar_FE_78_WK pm stnfam Planar_FE_78 constant 2275 222 | Planar_FE_78_MN pm stnfam Planar_FE_78 constant 10010 223 | Planar_FE_78_QT pm stnfam Planar_FE_78 constant 30030 224 | Planar_FE_79_WK pm stnfam Planar_FE_79 constant 3300 225 | Planar_FE_79_MN pm stnfam Planar_FE_79 constant 14300 226 | Planar_FE_79_QT pm stnfam Planar_FE_79 constant 42900 227 | Planar_FE_80_WK pm stnfam Planar_FE_80 constant 3395 228 | Planar_FE_80_MN pm stnfam Planar_FE_80 constant 14550 229 | Planar_FE_80_QT pm stnfam Planar_FE_80 constant 43650 230 | TF_BE_2_WK pm stnfam TF_BE_2 constant 2325 231 | TF_BE_2_MN pm stnfam TF_BE_2 constant 9998 232 | TF_BE_2_QT pm stnfam TF_BE_2 constant 29993 233 | TF_BE_23_WK pm stnfam TF_BE_23 constant 2786 234 | TF_BE_23_MN pm stnfam TF_BE_23 constant 12071 235 | TF_BE_23_QT pm stnfam TF_BE_23 constant 36214 236 | TF_BE_24_WK pm stnfam TF_BE_24 constant 2160 237 | TF_BE_24_MN pm stnfam TF_BE_24 constant 9450 238 | TF_BE_24_QT pm stnfam TF_BE_24 constant 28350 239 | TF_BE_26_WK pm stnfam TF_BE_26 constant 2777 240 | TF_BE_26_MN pm stnfam TF_BE_26 constant 12057 241 | TF_BE_26_QT pm stnfam TF_BE_26 constant 36173 242 | TF_BE_40_WK pm stnfam TF_BE_40 constant 2682 243 | TF_BE_40_MN pm stnfam TF_BE_40 constant 11640 244 | TF_BE_40_QT pm stnfam TF_BE_40 constant 34920 245 | TF_FE_103_WK pm stnfam TF_FE_103 constant 2240 246 | TF_FE_103_MN pm stnfam TF_FE_103 constant 9660 247 | TF_FE_103_QT pm stnfam TF_FE_103 constant 28980 248 | TF_FE_104_WK pm stnfam TF_FE_104 constant 2968 249 | TF_FE_104_MN pm stnfam TF_FE_104 constant 12932 250 | TF_FE_104_QT pm stnfam TF_FE_104 constant 38796 251 | TF_FE_113_WK pm stnfam TF_FE_113 constant 2100 252 | TF_FE_113_MN pm stnfam TF_FE_113 constant 9000 253 | TF_FE_113_QT pm stnfam TF_FE_113 constant 27000 254 | TF_FE_131_WK pm stnfam TF_FE_131 constant 2356 255 | TF_FE_131_MN pm stnfam TF_FE_131 constant 10269 256 | TF_FE_131_QT pm stnfam TF_FE_131 constant 30805 257 | TF_FE_3_WK pm stnfam TF_FE_3 constant 2403 258 | TF_FE_3_MN pm stnfam TF_FE_3 constant 10300 259 | TF_FE_3_QT pm stnfam TF_FE_3 constant 30900 260 | TF_FE_5_WK pm stnfam TF_FE_5 constant 2100 261 | TF_FE_5_MN pm stnfam TF_FE_5 constant 9000 262 | TF_FE_5_QT pm stnfam TF_FE_5 constant 27000 263 | WE_BE_14_WK pm stnfam WE_BE_14 constant 9828 264 | WE_BE_14_MN pm stnfam WE_BE_14 constant 42588 265 | WE_BE_14_QT pm stnfam WE_BE_14 constant 127764 266 | WE_BE_16_WK pm stnfam WE_BE_16 constant 10010 267 | WE_BE_16_MN pm stnfam WE_BE_16 constant 43420 268 | WE_BE_16_QT pm stnfam WE_BE_16 constant 130260 269 | WE_BE_17_WK pm stnfam WE_BE_17 constant 10200 270 | WE_BE_17_MN pm stnfam WE_BE_17 constant 44370 271 | WE_BE_17_QT pm stnfam WE_BE_17 constant 133110 272 | WE_BE_7_WK pm stnfam WE_BE_7 constant 6840 273 | WE_BE_7_MN pm stnfam WE_BE_7 constant 29640 274 | WE_BE_7_QT pm stnfam WE_BE_7 constant 88920 275 | WE_BE_81_WK pm stnfam WE_BE_81 constant 9630 276 | WE_BE_81_MN pm stnfam WE_BE_81 constant 41730 277 | WE_BE_81_QT pm stnfam WE_BE_81 constant 125190 278 | WE_BE_82_WK pm stnfam WE_BE_82 constant 11550 279 | WE_BE_82_MN pm stnfam WE_BE_82 constant 50050 280 | WE_BE_82_QT pm stnfam WE_BE_82 constant 150150 281 | WE_BE_9_WK pm stnfam WE_BE_9 constant 9100 282 | WE_BE_9_MN pm stnfam WE_BE_9 constant 39494 283 | WE_BE_9_QT pm stnfam WE_BE_9 constant 118482 284 | WE_FE_108_WK pm stnfam WE_FE_108 constant 11163 285 | WE_FE_108_MN pm stnfam WE_FE_108 constant 48373 286 | WE_FE_108_QT pm stnfam WE_FE_108 constant 145120 287 | WE_FE_41_WK pm stnfam WE_FE_41 constant 11880 288 | WE_FE_41_MN pm stnfam WE_FE_41 constant 51480 289 | WE_FE_41_QT pm stnfam WE_FE_41 constant 154440 290 | WE_FE_47_WK pm stnfam WE_FE_47 constant 10400 291 | WE_FE_47_MN pm stnfam WE_FE_47 constant 45000 292 | WE_FE_47_QT pm stnfam WE_FE_47 constant 135000 293 | WE_FE_8_WK pm stnfam WE_FE_8 constant 5280 294 | WE_FE_8_MN pm stnfam WE_FE_8 constant 22880 295 | WE_FE_8_QT pm stnfam WE_FE_8 constant 68640 296 | WE_FE_83_WK pm stnfam WE_FE_83 constant 11158 297 | WE_FE_83_MN pm stnfam WE_FE_83 constant 48410 298 | WE_FE_83_QT pm stnfam WE_FE_83 constant 145230 299 | WE_FE_84_WK pm stnfam WE_FE_84 constant 10608 300 | WE_FE_84_MN pm stnfam WE_FE_84 constant 45944 301 | WE_FE_84_QT pm stnfam WE_FE_84 constant 137834 302 | WE_FE_85_WK pm stnfam WE_FE_85 constant 7560 303 | WE_FE_85_MN pm stnfam WE_FE_85 constant 32940 304 | WE_FE_85_QT pm stnfam WE_FE_85 constant 98820 305 | -------------------------------------------------------------------------------- /datasets/SMT2020_HVLM/attach.txt: -------------------------------------------------------------------------------- 1 | CALNAME CALTYPE RESTYPE RESNAME FOADIST FOA FOAUNITS 2 | BREAK_Def_Met down stngrp Def_Met exponential 10080 min 3 | BREAK_Dielectric down stngrp Dielectric exponential 10080 min 4 | BREAK_Diffusion down stngrp Diffusion exponential 10080 min 5 | BREAK_Dry_Etch down stngrp Dry_Etch exponential 10080 min 6 | BREAK_Implant down stngrp Implant exponential 10080 min 7 | BREAK_Litho down stngrp Litho exponential 10080 min 8 | BREAK_Litho_Met down stngrp Litho_Met exponential 10080 min 9 | BREAK_Planar down stngrp Planar exponential 10080 min 10 | BREAK_TF down stngrp TF exponential 10080 min 11 | BREAK_TF_Met down stngrp TF_Met exponential 10080 min 12 | BREAK_Wet_Etch down stngrp Wet_Etch exponential 10080 min 13 | DefMet_BE_33_MN pm stnfam DefMet_BE_33 constant 27.3 day 14 | DefMet_BE_33_QT pm stnfam DefMet_BE_33 constant 82.8 day 15 | DefMet_BE_42_MN pm stnfam DefMet_BE_42 constant 27 day 16 | DefMet_BE_42_QT pm stnfam DefMet_BE_42 constant 81.9 day 17 | DefMet_FE_10_MN pm stnfam DefMet_FE_10 constant 33.3 day 18 | DefMet_FE_10_QT pm stnfam DefMet_FE_10 constant 101 day 19 | DefMet_FE_106_MN pm stnfam DefMet_FE_106 constant 27.3 day 20 | DefMet_FE_106_QT pm stnfam DefMet_FE_106 constant 82.8 day 21 | DefMEt_FE_118_MN pm stnfam DefMEt_FE_118 constant 27.3 day 22 | DefMEt_FE_118_QT pm stnfam DefMEt_FE_118 constant 82.8 day 23 | DefMet_FE_34_MN pm stnfam DefMet_FE_34 constant 30.6 day 24 | DefMet_FE_34_QT pm stnfam DefMet_FE_34 constant 92.8 day 25 | DefMet_FE_43_MN pm stnfam DefMet_FE_43 constant 29.4 day 26 | DefMet_FE_43_QT pm stnfam DefMet_FE_43 constant 89.2 day 27 | Diffusion_BE_123_MN pm stnfam Diffusion_BE_123 constant 28.5 day 28 | Diffusion_BE_123_QT pm stnfam Diffusion_BE_123 constant 86.5 day 29 | Diffusion_FE_100_MN pm stnfam Diffusion_FE_100 constant 26.1 day 30 | Diffusion_FE_100_QT pm stnfam Diffusion_FE_100 constant 79.2 day 31 | Diffusion_FE_101_MN pm stnfam Diffusion_FE_101 constant 31.5 day 32 | Diffusion_FE_101_QT pm stnfam Diffusion_FE_101 constant 95.6 day 33 | Diffusion_FE_120_MN pm stnfam Diffusion_FE_120 constant 28.2 day 34 | Diffusion_FE_120_QT pm stnfam Diffusion_FE_120 constant 85.5 day 35 | Diffusion_FE_122_MN pm stnfam Diffusion_FE_122 constant 29.1 day 36 | Diffusion_FE_122_QT pm stnfam Diffusion_FE_122 constant 88.3 day 37 | Diffusion_FE_125_MN pm stnfam Diffusion_FE_125 constant 30.9 day 38 | Diffusion_FE_125_QT pm stnfam Diffusion_FE_125 constant 93.7 day 39 | Diffusion_FE_126_MN pm stnfam Diffusion_FE_126 constant 26.4 day 40 | Diffusion_FE_126_QT pm stnfam Diffusion_FE_126 constant 80.1 day 41 | Diffusion_FE_127_MN pm stnfam Diffusion_FE_127 constant 29.4 day 42 | Diffusion_FE_127_QT pm stnfam Diffusion_FE_127 constant 89.2 day 43 | Diffusion_FE_44_MN pm stnfam Diffusion_FE_44 constant 29.4 day 44 | Diffusion_FE_44_QT pm stnfam Diffusion_FE_44 constant 89.2 day 45 | Diffusion_FE_94_MN pm stnfam Diffusion_FE_94 constant 30.9 day 46 | Diffusion_FE_94_QT pm stnfam Diffusion_FE_94 constant 93.7 day 47 | Litho_BE_110_WK pm stnfam Litho_BE_110 constant 6.9 day 48 | Litho_BE_110_MN pm stnfam Litho_BE_110 constant 29.4 day 49 | Litho_BE_110_QT pm stnfam Litho_BE_110 constant 89.2 day 50 | Litho_BE_93_WK pm stnfam Litho_BE_93 constant 7.6 day 51 | Litho_BE_93_MN pm stnfam Litho_BE_93 constant 32.4 day 52 | Litho_BE_93_QT pm stnfam Litho_BE_93 constant 98.3 day 53 | Litho_BE_99_WK pm stnfam Litho_BE_99 constant 6.8 day 54 | Litho_BE_99_MN pm stnfam Litho_BE_99 constant 29.1 day 55 | Litho_BE_99_QT pm stnfam Litho_BE_99 constant 88.3 day 56 | Litho_FE_111_WK pm stnfam Litho_FE_111 constant 6.8 day 57 | Litho_FE_111_MN pm stnfam Litho_FE_111 constant 29.1 day 58 | Litho_FE_111_QT pm stnfam Litho_FE_111 constant 88.3 day 59 | Litho_FE_35_WK pm stnfam Litho_FE_35 constant 7.6 day 60 | Litho_FE_35_MN pm stnfam Litho_FE_35 constant 32.4 day 61 | Litho_FE_35_QT pm stnfam Litho_FE_35 constant 98.3 day 62 | Litho_FE_92_WK pm stnfam Litho_FE_92 constant 6.9 day 63 | Litho_FE_92_MN pm stnfam Litho_FE_92 constant 29.4 day 64 | Litho_FE_92_QT pm stnfam Litho_FE_92 constant 89.2 day 65 | Litho_FE_98_WK pm stnfam Litho_FE_98 constant 7.5 day 66 | Litho_FE_98_MN pm stnfam Litho_FE_98 constant 32.1 day 67 | Litho_FE_98_QT pm stnfam Litho_FE_98 constant 97.4 day 68 | Litho_REG_BE_63_MN pm stnfam Litho_REG_BE_63 constant 29.7 day 69 | Litho_REG_BE_63_QT pm stnfam Litho_REG_BE_63 constant 90.1 day 70 | Litho_REG_FE_64_MN pm stnfam Litho_REG_FE_64 constant 30.3 day 71 | Litho_REG_FE_64_QT pm stnfam Litho_REG_FE_64 constant 91.9 day 72 | LithoMet_BE_18_MN pm stnfam LithoMet_BE_18 constant 30.6 day 73 | LithoMet_BE_18_QT pm stnfam LithoMet_BE_18 constant 92.8 day 74 | LithoMet_FE_19_MN pm stnfam LithoMet_FE_19 constant 29.7 day 75 | LithoMet_FE_19_QT pm stnfam LithoMet_FE_19 constant 90.1 day 76 | LithoTrack_BE_117_WK pm stnfam LithoTrack_BE_117 constant 7.1 day 77 | LithoTrack_BE_117_MN pm stnfam LithoTrack_BE_117 constant 30.6 day 78 | LithoTrack_BE_117_QT pm stnfam LithoTrack_BE_117 constant 92.8 day 79 | LithoTrack_FE_115_WK pm stnfam LithoTrack_FE_115 constant 7.1 day 80 | LithoTrack_FE_115_MN pm stnfam LithoTrack_FE_115 constant 30.3 day 81 | LithoTrack_FE_115_QT pm stnfam LithoTrack_FE_115 constant 91.9 day 82 | LithoTrack_FE_95_WK pm stnfam LithoTrack_FE_95 constant 7.1 day 83 | LithoTrack_FE_95_MN pm stnfam LithoTrack_FE_95 constant 30.3 day 84 | LithoTrack_FE_95_QT pm stnfam LithoTrack_FE_95 constant 91.9 day 85 | LithoTrack_FE_96_WK pm stnfam LithoTrack_FE_96 constant 6.5 day 86 | LithoTrack_FE_96_MN pm stnfam LithoTrack_FE_96 constant 27.9 day 87 | LithoTrack_FE_96_QT pm stnfam LithoTrack_FE_96 constant 84.6 day 88 | TF_Met_FE_45_MN pm stnfam TF_Met_FE_45 constant 26.1 day 89 | TF_Met_FE_45_QT pm stnfam TF_Met_FE_45 constant 79.2 day 90 | TF_Met_FE_61_MN pm stnfam TF_Met_FE_61 constant 33.9 day 91 | TF_Met_FE_61_QT pm stnfam TF_Met_FE_61 constant 102.8 day 92 | DE_BE_11_WK pm stnfam DE_BE_11 constant 1880 93 | DE_BE_11_MN pm stnfam DE_BE_11 constant 8178 94 | DE_BE_11_QT pm stnfam DE_BE_11 constant 24534 95 | DE_BE_12_WK pm stnfam DE_BE_12 constant 1100 96 | DE_BE_12_MN pm stnfam DE_BE_12 constant 4730 97 | DE_BE_12_QT pm stnfam DE_BE_12 constant 14190 98 | DE_BE_13_WK pm stnfam DE_BE_13 constant 1905 99 | DE_BE_13_MN pm stnfam DE_BE_13 constant 8238 100 | DE_BE_13_QT pm stnfam DE_BE_13 constant 24714 101 | DE_BE_48_WK pm stnfam DE_BE_48 constant 1560 102 | DE_BE_48_MN pm stnfam DE_BE_48 constant 6760 103 | DE_BE_48_QT pm stnfam DE_BE_48 constant 20280 104 | DE_BE_50_WK pm stnfam DE_BE_50 constant 1667 105 | DE_BE_50_MN pm stnfam DE_BE_50 constant 7222 106 | DE_BE_50_QT pm stnfam DE_BE_50 constant 21667 107 | DE_BE_65_WK pm stnfam DE_BE_65 constant 1765 108 | DE_BE_65_MN pm stnfam DE_BE_65 constant 7647 109 | DE_BE_65_QT pm stnfam DE_BE_65 constant 22941 110 | DE_BE_66_WK pm stnfam DE_BE_66 constant 1579 111 | DE_BE_66_MN pm stnfam DE_BE_66 constant 6842 112 | DE_BE_66_QT pm stnfam DE_BE_66 constant 20526 113 | DE_BE_67_WK pm stnfam DE_BE_67 constant 1980 114 | DE_BE_67_MN pm stnfam DE_BE_67 constant 8613 115 | DE_BE_67_QT pm stnfam DE_BE_67 constant 25839 116 | DE_BE_69_WK pm stnfam DE_BE_69 constant 2700 117 | DE_BE_69_MN pm stnfam DE_BE_69 constant 11880 118 | DE_BE_69_QT pm stnfam DE_BE_69 constant 35640 119 | DE_FE_1_WK pm stnfam DE_FE_1 constant 1529 120 | DE_FE_1_MN pm stnfam DE_FE_1 constant 6573 121 | DE_FE_1_QT pm stnfam DE_FE_1 constant 19719 122 | DE_FE_51_WK pm stnfam DE_FE_51 constant 1579 123 | DE_FE_51_MN pm stnfam DE_FE_51 constant 6842 124 | DE_FE_51_QT pm stnfam DE_FE_51 constant 20526 125 | DE_FE_53_WK pm stnfam DE_FE_53 constant 970 126 | DE_FE_53_MN pm stnfam DE_FE_53 constant 4268 127 | DE_FE_53_QT pm stnfam DE_FE_53 constant 12804 128 | DE_FE_54_WK pm stnfam DE_FE_54 constant 1980 129 | DE_FE_54_MN pm stnfam DE_FE_54 constant 8514 130 | DE_FE_54_QT pm stnfam DE_FE_54 constant 25542 131 | DE_FE_56_WK pm stnfam DE_FE_56 constant 2550 132 | DE_FE_56_MN pm stnfam DE_FE_56 constant 11220 133 | DE_FE_56_QT pm stnfam DE_FE_56 constant 33660 134 | DE_FE_58_WK pm stnfam DE_FE_58 constant 1534 135 | DE_FE_58_MN pm stnfam DE_FE_58 constant 6746 136 | DE_FE_58_QT pm stnfam DE_FE_58 constant 20240 137 | DE_FE_59_WK pm stnfam DE_FE_59 constant 1584 138 | DE_FE_59_MN pm stnfam DE_FE_59 constant 6840 139 | DE_FE_59_QT pm stnfam DE_FE_59 constant 20520 140 | DE_FE_62_WK pm stnfam DE_FE_62 constant 1415 141 | DE_FE_62_MN pm stnfam DE_FE_62 constant 6152 142 | DE_FE_62_QT pm stnfam DE_FE_62 constant 18457 143 | DE_FE_70_WK pm stnfam DE_FE_70 constant 2019 144 | DE_FE_70_MN pm stnfam DE_FE_70 constant 8723 145 | DE_FE_70_QT pm stnfam DE_FE_70 constant 26169 146 | DE_FE_71_WK pm stnfam DE_FE_71 constant 1415 147 | DE_FE_71_MN pm stnfam DE_FE_71 constant 6117 148 | DE_FE_71_QT pm stnfam DE_FE_71 constant 18351 149 | DE_FE_72_WK pm stnfam DE_FE_72 constant 2222 150 | DE_FE_72_MN pm stnfam DE_FE_72 constant 9667 151 | DE_FE_72_QT pm stnfam DE_FE_72 constant 29000 152 | DE_FE_86_WK pm stnfam DE_FE_86 constant 1519 153 | DE_FE_86_MN pm stnfam DE_FE_86 constant 6578 154 | DE_FE_86_QT pm stnfam DE_FE_86 constant 19733 155 | Dielectric_BE_20_WK pm stnfam Dielectric_BE_20 constant 4200 156 | Dielectric_BE_20_MN pm stnfam Dielectric_BE_20 constant 18270 157 | Dielectric_BE_20_QT pm stnfam Dielectric_BE_20 constant 54810 158 | Dielectric_BE_21_WK pm stnfam Dielectric_BE_21 constant 4594 159 | Dielectric_BE_21_MN pm stnfam Dielectric_BE_21 constant 19950 160 | Dielectric_BE_21_QT pm stnfam Dielectric_BE_21 constant 59850 161 | Dielectric_BE_27_WK pm stnfam Dielectric_BE_27 constant 4000 162 | Dielectric_BE_27_MN pm stnfam Dielectric_BE_27 constant 17333 163 | Dielectric_BE_27_QT pm stnfam Dielectric_BE_27 constant 52000 164 | Dielectric_BE_28_WK pm stnfam Dielectric_BE_28 constant 4163 165 | Dielectric_BE_28_MN pm stnfam Dielectric_BE_28 constant 18038 166 | Dielectric_BE_28_QT pm stnfam Dielectric_BE_28 constant 54113 167 | Dielectric_BE_60_WK pm stnfam Dielectric_BE_60 constant 3900 168 | Dielectric_BE_60_MN pm stnfam Dielectric_BE_60 constant 16900 169 | Dielectric_BE_60_QT pm stnfam Dielectric_BE_60 constant 50700 170 | Dielectric_FE_112_WK pm stnfam Dielectric_FE_112 constant 3920 171 | Dielectric_FE_112_MN pm stnfam Dielectric_FE_112 constant 16954 172 | Dielectric_FE_112_QT pm stnfam Dielectric_FE_112 constant 50862 173 | Dielectric_FE_130_WK pm stnfam Dielectric_FE_130 constant 3563 174 | Dielectric_FE_130_MN pm stnfam Dielectric_FE_130 constant 15438 175 | Dielectric_FE_130_QT pm stnfam Dielectric_FE_130 constant 46313 176 | Dielectric_FE_29_WK pm stnfam Dielectric_FE_29 constant 2933 177 | Dielectric_FE_29_MN pm stnfam Dielectric_FE_29 constant 12613 178 | Dielectric_FE_29_QT pm stnfam Dielectric_FE_29 constant 37840 179 | Dielectric_FE_30_WK pm stnfam Dielectric_FE_30 constant 5600 180 | Dielectric_FE_30_MN pm stnfam Dielectric_FE_30 constant 24080 181 | Dielectric_FE_30_QT pm stnfam Dielectric_FE_30 constant 72240 182 | Dielectric_FE_31_WK pm stnfam Dielectric_FE_31 constant 3713 183 | Dielectric_FE_31_MN pm stnfam Dielectric_FE_31 constant 16088 184 | Dielectric_FE_31_QT pm stnfam Dielectric_FE_31 constant 48263 185 | EPI_36_WK pm stnfam EPI_36 constant 2700 186 | EPI_36_MN pm stnfam EPI_36 constant 11880 187 | EPI_36_QT pm stnfam EPI_36 constant 35640 188 | EPI_38_WK pm stnfam EPI_38 constant 4250 189 | EPI_38_MN pm stnfam EPI_38 constant 18700 190 | EPI_38_QT pm stnfam EPI_38 constant 56100 191 | Implant_119_WK pm stnfam Implant_119 constant 4450 192 | Implant_119_MN pm stnfam Implant_119 constant 19135 193 | Implant_119_QT pm stnfam Implant_119 constant 57405 194 | Implant_128_WK pm stnfam Implant_128 constant 8000 195 | Implant_128_MN pm stnfam Implant_128 constant 34700 196 | Implant_128_QT pm stnfam Implant_128 constant 104100 197 | Implant_132_WK pm stnfam Implant_132 constant 6806 198 | Implant_132_MN pm stnfam Implant_132 constant 29453 199 | Implant_132_QT pm stnfam Implant_132 constant 88358 200 | Implant_74_WK pm stnfam Implant_74 constant 2250 201 | Implant_74_MN pm stnfam Implant_74 constant 9900 202 | Implant_74_QT pm stnfam Implant_74 constant 29700 203 | Implant_88_WK pm stnfam Implant_88 constant 4600 204 | Implant_88_MN pm stnfam Implant_88 constant 19780 205 | Implant_88_QT pm stnfam Implant_88 constant 59340 206 | Implant_90_WK pm stnfam Implant_90 constant 4650 207 | Implant_90_MN pm stnfam Implant_90 constant 19995 208 | Implant_90_QT pm stnfam Implant_90 constant 59985 209 | Implant_91_WK pm stnfam Implant_91 constant 6134 210 | Implant_91_MN pm stnfam Implant_91 constant 26526 211 | Implant_91_QT pm stnfam Implant_91 constant 79580 212 | Planar_BE_75_WK pm stnfam Planar_BE_75 constant 3185 213 | Planar_BE_75_MN pm stnfam Planar_BE_75 constant 13818 214 | Planar_BE_75_QT pm stnfam Planar_BE_75 constant 41454 215 | Planar_FE_76_WK pm stnfam Planar_FE_76 constant 3733 216 | Planar_FE_76_MN pm stnfam Planar_FE_76 constant 16053 217 | Planar_FE_76_QT pm stnfam Planar_FE_76 constant 48160 218 | Planar_FE_77_WK pm stnfam Planar_FE_77 constant 4700 219 | Planar_FE_77_MN pm stnfam Planar_FE_77 constant 20210 220 | Planar_FE_77_QT pm stnfam Planar_FE_77 constant 60630 221 | Planar_FE_78_WK pm stnfam Planar_FE_78 constant 2600 222 | Planar_FE_78_MN pm stnfam Planar_FE_78 constant 11440 223 | Planar_FE_78_QT pm stnfam Planar_FE_78 constant 34320 224 | Planar_FE_79_WK pm stnfam Planar_FE_79 constant 3090 225 | Planar_FE_79_MN pm stnfam Planar_FE_79 constant 13390 226 | Planar_FE_79_QT pm stnfam Planar_FE_79 constant 40170 227 | Planar_FE_80_WK pm stnfam Planar_FE_80 constant 2375 228 | Planar_FE_80_MN pm stnfam Planar_FE_80 constant 10450 229 | Planar_FE_80_QT pm stnfam Planar_FE_80 constant 31350 230 | TF_BE_2_WK pm stnfam TF_BE_2 constant 2750 231 | TF_BE_2_MN pm stnfam TF_BE_2 constant 11825 232 | TF_BE_2_QT pm stnfam TF_BE_2 constant 35475 233 | TF_BE_23_WK pm stnfam TF_BE_23 constant 2808 234 | TF_BE_23_MN pm stnfam TF_BE_23 constant 12150 235 | TF_BE_23_QT pm stnfam TF_BE_23 constant 36452 236 | TF_BE_24_WK pm stnfam TF_BE_24 constant 1840 237 | TF_BE_24_MN pm stnfam TF_BE_24 constant 7912 238 | TF_BE_24_QT pm stnfam TF_BE_24 constant 23736 239 | TF_BE_26_WK pm stnfam TF_BE_26 constant 2910 240 | TF_BE_26_MN pm stnfam TF_BE_26 constant 12610 241 | TF_BE_26_QT pm stnfam TF_BE_26 constant 37830 242 | TF_BE_40_WK pm stnfam TF_BE_40 constant 2681 243 | TF_BE_40_MN pm stnfam TF_BE_40 constant 11633 244 | TF_BE_40_QT pm stnfam TF_BE_40 constant 34898 245 | TF_FE_103_WK pm stnfam TF_FE_103 constant 2425 246 | TF_FE_103_MN pm stnfam TF_FE_103 constant 10428 247 | TF_FE_103_QT pm stnfam TF_FE_103 constant 31283 248 | TF_FE_104_WK pm stnfam TF_FE_104 constant 2880 249 | TF_FE_104_MN pm stnfam TF_FE_104 constant 12480 250 | TF_FE_104_QT pm stnfam TF_FE_104 constant 37440 251 | TF_FE_113_WK pm stnfam TF_FE_113 constant 2825 252 | TF_FE_113_MN pm stnfam TF_FE_113 constant 12430 253 | TF_FE_113_QT pm stnfam TF_FE_113 constant 37290 254 | TF_FE_131_WK pm stnfam TF_FE_131 constant 2550 255 | TF_FE_131_MN pm stnfam TF_FE_131 constant 11050 256 | TF_FE_131_QT pm stnfam TF_FE_131 constant 33150 257 | TF_FE_3_WK pm stnfam TF_FE_3 constant 2175 258 | TF_FE_3_MN pm stnfam TF_FE_3 constant 9570 259 | TF_FE_3_QT pm stnfam TF_FE_3 constant 28710 260 | TF_FE_5_WK pm stnfam TF_FE_5 constant 2425 261 | TF_FE_5_MN pm stnfam TF_FE_5 constant 10428 262 | TF_FE_5_QT pm stnfam TF_FE_5 constant 31283 263 | WE_BE_14_WK pm stnfam WE_BE_14 constant 9800 264 | WE_BE_14_MN pm stnfam WE_BE_14 constant 42532 265 | WE_BE_14_QT pm stnfam WE_BE_14 constant 127596 266 | WE_BE_16_WK pm stnfam WE_BE_16 constant 10028 267 | WE_BE_16_MN pm stnfam WE_BE_16 constant 43489 268 | WE_BE_16_QT pm stnfam WE_BE_16 constant 130466 269 | WE_BE_17_WK pm stnfam WE_BE_17 constant 11100 270 | WE_BE_17_MN pm stnfam WE_BE_17 constant 48285 271 | WE_BE_17_QT pm stnfam WE_BE_17 constant 144855 272 | WE_BE_7_WK pm stnfam WE_BE_7 constant 4350 273 | WE_BE_7_MN pm stnfam WE_BE_7 constant 19140 274 | WE_BE_7_QT pm stnfam WE_BE_7 constant 57420 275 | WE_BE_81_WK pm stnfam WE_BE_81 constant 8166 276 | WE_BE_81_MN pm stnfam WE_BE_81 constant 35280 277 | WE_BE_81_QT pm stnfam WE_BE_81 constant 105840 278 | WE_BE_82_WK pm stnfam WE_BE_82 constant 11400 279 | WE_BE_82_MN pm stnfam WE_BE_82 constant 49400 280 | WE_BE_82_QT pm stnfam WE_BE_82 constant 148200 281 | WE_BE_9_WK pm stnfam WE_BE_9 constant 9300 282 | WE_BE_9_MN pm stnfam WE_BE_9 constant 40256 283 | WE_BE_9_QT pm stnfam WE_BE_9 constant 120767 284 | WE_FE_108_WK pm stnfam WE_FE_108 constant 11143 285 | WE_FE_108_MN pm stnfam WE_FE_108 constant 48286 286 | WE_FE_108_QT pm stnfam WE_FE_108 constant 144857 287 | WE_FE_41_WK pm stnfam WE_FE_41 constant 12480 288 | WE_FE_41_MN pm stnfam WE_FE_41 constant 54080 289 | WE_FE_41_QT pm stnfam WE_FE_41 constant 162240 290 | WE_FE_47_WK pm stnfam WE_FE_47 constant 9625 291 | WE_FE_47_MN pm stnfam WE_FE_47 constant 41650 292 | WE_FE_47_QT pm stnfam WE_FE_47 constant 124950 293 | WE_FE_8_WK pm stnfam WE_FE_8 constant 11000 294 | WE_FE_8_MN pm stnfam WE_FE_8 constant 47850 295 | WE_FE_8_QT pm stnfam WE_FE_8 constant 143550 296 | WE_FE_83_WK pm stnfam WE_FE_83 constant 10515 297 | WE_FE_83_MN pm stnfam WE_FE_83 constant 45605 298 | WE_FE_83_QT pm stnfam WE_FE_83 constant 136817 299 | WE_FE_84_WK pm stnfam WE_FE_84 constant 11050 300 | WE_FE_84_MN pm stnfam WE_FE_84 constant 47883 301 | WE_FE_84_QT pm stnfam WE_FE_84 constant 143650 302 | WE_FE_85_WK pm stnfam WE_FE_85 constant 6675 303 | WE_FE_85_MN pm stnfam WE_FE_85 constant 28925 304 | WE_FE_85_QT pm stnfam WE_FE_85 constant 86775 305 | -------------------------------------------------------------------------------- /docs/assets/img/bg/bg-corporate.svg: -------------------------------------------------------------------------------- 1 | Artboard 8 -------------------------------------------------------------------------------- /datasets/SMT2020_LVHM/tool.txt.1l: -------------------------------------------------------------------------------- 1 | STNFAM STN RULE FWLRANK WAKERESRANK BATCHCRITF BATCHPER LTIME LTUNITS ULTIME ULTUNITS STNCAP STNQTY STNGRP STNFAMSTEP_ACTLIST STNFAMLOC PRERULERWL SETUPGRP 2 | DE_BE_11 DE_BE_11 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 9.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 3 | DE_BE_12 DE_BE_12 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 7.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 4 | DE_BE_13 DE_BE_13 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR wake_LeastSetupTime 1.0 min 1.0 min 13.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 5 | DE_BE_48 DE_BE_48 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 11.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 6 | DE_BE_50 DE_BE_50 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 10.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 7 | DE_BE_65 DE_BE_65 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 11.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 8 | DE_BE_66 DE_BE_66 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR wake_LeastSetupTime 1.0 min 1.0 min 17.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 9 | DE_BE_67 DE_BE_67 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 11.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 10 | DE_BE_69 DE_BE_69 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 3.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 11 | DE_FE_1 DE_FE_1 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 5.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 12 | DE_FE_51 DE_FE_51 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 20.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 13 | DE_FE_53 DE_FE_53 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 5.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 14 | DE_FE_54 DE_FE_54 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 3.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 15 | DE_FE_56 DE_FE_56 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 16 | DE_FE_58 DE_FE_58 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 17 | DE_FE_59 DE_FE_59 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 8.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 18 | DE_FE_62 DE_FE_62 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 17.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 19 | DE_FE_70 DE_FE_70 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 11.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 20 | DE_FE_71 DE_FE_71 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 18.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 21 | DE_FE_72 DE_FE_72 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 11.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 22 | DE_FE_86 DE_FE_86 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 118.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 23 | DefMet_BE_33 DefMet_BE_33 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 24 | DefMet_BE_42 DefMet_BE_42 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 1.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 25 | DefMet_FE_10 DefMet_FE_10 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 26 | DefMet_FE_106 DefMet_FE_106 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 1.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 27 | DefMEt_FE_118 DefMEt_FE_118 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 28 | DefMet_FE_34 DefMet_FE_34 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 29 | DefMet_FE_43 DefMet_FE_43 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 5.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 30 | Delay_32 Delay1 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 0.0 min 0.0 min 400.0 Delay_32 Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Delay no 31 | Dielectric_BE_20 Dielectric_BE_20 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 5.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 32 | Dielectric_BE_21 Dielectric_BE_21 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 6.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 33 | Dielectric_BE_27 Dielectric_BE_27 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 12.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 34 | Dielectric_BE_28 Dielectric_BE_28 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 3.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 35 | Dielectric_BE_60 Dielectric_BE_60 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 6.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 36 | Dielectric_FE_112 Dielectric_FE_112 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 9.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 37 | Dielectric_FE_130 Dielectric_FE_130 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 4.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 38 | Dielectric_FE_29 Dielectric_FE_29 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 3.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 39 | Dielectric_FE_30 Dielectric_FE_30 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 40 | Dielectric_FE_31 Dielectric_FE_31 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 4.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 41 | Diffusion_BE_123 Diffusion_BE_123 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 9.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 42 | Diffusion_FE_100 Diffusion_FE_100 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 3.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 43 | Diffusion_FE_101 Diffusion_FE_101 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 10.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 44 | Diffusion_FE_120 Diffusion_FE_120 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 8.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 45 | Diffusion_FE_122 Diffusion_FE_122 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 6.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 46 | Diffusion_FE_125 Diffusion_FE_125 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 5.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 47 | Diffusion_FE_126 Diffusion_FE_126 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 4.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 48 | Diffusion_FE_127 Diffusion_FE_127 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 8.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 49 | Diffusion_FE_44 Diffusion_FE_44 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 7.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 50 | Diffusion_FE_94 Diffusion_FE_94 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR crit_sameroutestep piece 1.0 min 1.0 min 13.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 51 | EPI_36 EPI_36 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 52 | EPI_38 EPI_38 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 1.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 53 | Implant_119 Implant_119 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR wake_LeastSetupTime 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 54 | Implant_128 Implant_128 rule_LSSU rank_HP;rank_RSETUP;rank_CR wake_LeastSetupTime 1.0 min 1.0 min 2.0 11.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no Implant_Gas 55 | Implant_132 Implant_132 rule_LSSU rank_HP;rank_RSETUP;rank_CR wake_LeastSetupTime 1.0 min 1.0 min 2.0 7.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no Implant_Gas 56 | Implant_74 Implant_74 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 57 | Implant_88 Implant_88 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 58 | Implant_90 Implant_90 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR wake_LeastSetupTime 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 59 | Implant_91 Implant_91 rule_LSSU rank_HP;rank_RSETUP;rank_CR wake_LeastSetupTime 1.0 min 1.0 min 2.0 7.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no Implant_Gas 60 | Litho_BE_110 Litho_BE_110 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 23.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 61 | Litho_BE_93 Litho_BE_93 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 4.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 62 | Litho_BE_99 Litho_BE_99 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 3.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 63 | Litho_FE_111 Litho_FE_111 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 20.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 64 | Litho_FE_35 Litho_FE_35 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 65 | Litho_FE_92 Litho_FE_92 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 26.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 66 | Litho_FE_98 Litho_FE_98 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 4.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 67 | Litho_REG_BE_63 Litho_REG_BE_63 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 8.0 Litho_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 68 | Litho_REG_FE_64 Litho_REG_FE_64 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 12.0 Litho_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 69 | LithoMet_BE_18 LithoMet_BE_18 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 11.0 Litho_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 70 | LithoMet_FE_19 LithoMet_FE_19 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 14.0 Litho_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 71 | LithoTrack_BE_117 LithoTrack_BE_117 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 5.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 72 | LithoTrack_FE_115 LithoTrack_FE_115 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR wake_LeastSetupTime 1.0 min 1.0 min 41.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 73 | LithoTrack_FE_95 LithoTrack_FE_95 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR wake_LeastSetupTime 1.0 min 1.0 min 40.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 74 | LithoTrack_FE_96 LithoTrack_FE_96 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 75 | Planar_BE_75 Planar_BE_75 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 14.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 76 | Planar_FE_76 Planar_FE_76 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 77 | Planar_FE_77 Planar_FE_77 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 78 | Planar_FE_78 Planar_FE_78 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 79 | Planar_FE_79 Planar_FE_79 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 4.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 80 | Planar_FE_80 Planar_FE_80 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 81 | TF_BE_2 TF_BE_2 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 4.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 82 | TF_BE_23 TF_BE_23 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 14.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 83 | TF_BE_24 TF_BE_24 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 4.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 84 | TF_BE_26 TF_BE_26 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 13.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 85 | TF_BE_40 TF_BE_40 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 17.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 86 | TF_FE_103 TF_FE_103 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 7.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 87 | TF_FE_104 TF_FE_104 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 5.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 88 | TF_FE_113 TF_FE_113 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 3.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 89 | TF_FE_131 TF_FE_131 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 6.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 90 | TF_FE_3 TF_FE_3 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 3.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 91 | TF_FE_5 TF_FE_5 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 3.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 92 | TF_Met_FE_45 TF_Met_FE_45 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 TF_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 93 | TF_Met_FE_61 TF_Met_FE_61 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 TF_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 94 | WE_BE_14 WE_BE_14 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 5.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 95 | WE_BE_16 WE_BE_16 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 8.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 96 | WE_BE_17 WE_BE_17 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 97 | WE_BE_7 WE_BE_7 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 1.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 98 | WE_BE_81 WE_BE_81 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 3.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 99 | WE_BE_82 WE_BE_82 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 9.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 100 | WE_BE_9 WE_BE_9 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 5.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 101 | WE_FE_108 WE_FE_108 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 29.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 102 | WE_FE_41 WE_FE_41 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 5.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 103 | WE_FE_47 WE_FE_47 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 5.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 104 | WE_FE_8 WE_FE_8 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 105 | WE_FE_83 WE_FE_83 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 6.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 106 | WE_FE_84 WE_FE_84 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 17.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 107 | WE_FE_85 WE_FE_85 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_CR 1.0 min 1.0 min 2.0 2.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 108 | -------------------------------------------------------------------------------- /datasets/SMT2020_HVLM/tool.txt.1l: -------------------------------------------------------------------------------- 1 | STNFAM STN RULE FWLRANK WAKERESRANK BATCHCRITF BATCHPER LTIME LTUNITS ULTIME ULTUNITS STNCAP STNQTY STNGRP STNFAMSTEP_ACTLIST STNFAMLOC PRERULERWL SETUPGRP 2 | DE_BE_11 DE_BE_11 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 10.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 3 | DE_BE_12 DE_BE_12 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 9.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 4 | DE_BE_13 DE_BE_13 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO wake_LeastSetupTime 1.0 min 1.0 min 21.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 5 | DE_BE_48 DE_BE_48 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 10.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 6 | DE_BE_50 DE_BE_50 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 9.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 7 | DE_BE_65 DE_BE_65 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 17.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 8 | DE_BE_66 DE_BE_66 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO wake_LeastSetupTime 1.0 min 1.0 min 19.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 9 | DE_BE_67 DE_BE_67 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 10.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 10 | DE_BE_69 DE_BE_69 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 11 | DE_FE_1 DE_FE_1 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 7.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 12 | DE_FE_51 DE_FE_51 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 19.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 13 | DE_FE_53 DE_FE_53 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 5.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 14 | DE_FE_54 DE_FE_54 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 5.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 15 | DE_FE_56 DE_FE_56 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 16 | DE_FE_58 DE_FE_58 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 3.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 17 | DE_FE_59 DE_FE_59 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 15.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 18 | DE_FE_62 DE_FE_62 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 14.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 19 | DE_FE_70 DE_FE_70 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 13.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 20 | DE_FE_71 DE_FE_71 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 28.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 21 | DE_FE_72 DE_FE_72 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 9.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 22 | DE_FE_86 DE_FE_86 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 135.0 Dry_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 23 | DefMet_BE_33 DefMet_BE_33 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 24 | DefMet_BE_42 DefMet_BE_42 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 1.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 25 | DefMet_FE_10 DefMet_FE_10 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 26 | DefMet_FE_106 DefMet_FE_106 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 1.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 27 | DefMEt_FE_118 DefMEt_FE_118 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 28 | DefMet_FE_34 DefMet_FE_34 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 29 | DefMet_FE_43 DefMet_FE_43 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 6.0 Def_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 30 | Delay_32 Delay1 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 0.0 min 0.0 min 400.0 Delay_32 Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Delay no 31 | Dielectric_BE_20 Dielectric_BE_20 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 5.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 32 | Dielectric_BE_21 Dielectric_BE_21 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 8.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 33 | Dielectric_BE_27 Dielectric_BE_27 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 15.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 34 | Dielectric_BE_28 Dielectric_BE_28 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 4.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 35 | Dielectric_BE_60 Dielectric_BE_60 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 4.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 36 | Dielectric_FE_112 Dielectric_FE_112 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 10.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 37 | Dielectric_FE_130 Dielectric_FE_130 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 4.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 38 | Dielectric_FE_29 Dielectric_FE_29 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 3.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 39 | Dielectric_FE_30 Dielectric_FE_30 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 40 | Dielectric_FE_31 Dielectric_FE_31 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 4.0 Dielectric Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 41 | Diffusion_BE_123 Diffusion_BE_123 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 12.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 42 | Diffusion_FE_100 Diffusion_FE_100 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 2.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 43 | Diffusion_FE_101 Diffusion_FE_101 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 7.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 44 | Diffusion_FE_120 Diffusion_FE_120 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 11.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 45 | Diffusion_FE_122 Diffusion_FE_122 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 5.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 46 | Diffusion_FE_125 Diffusion_FE_125 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 4.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 47 | Diffusion_FE_126 Diffusion_FE_126 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 3.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 48 | Diffusion_FE_127 Diffusion_FE_127 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 9.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 49 | Diffusion_FE_44 Diffusion_FE_44 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 11.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 50 | Diffusion_FE_94 Diffusion_FE_94 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO crit_sameroutestep piece 1.0 min 1.0 min 11.0 Diffusion Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 51 | EPI_36 EPI_36 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 52 | EPI_38 EPI_38 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 1.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 53 | Implant_119 Implant_119 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO wake_LeastSetupTime 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 54 | Implant_128 Implant_128 rule_LSSU rank_HP;rank_RSETUP;rank_FIFO wake_LeastSetupTime 1.0 min 1.0 min 2.0 10.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no Implant_Gas 55 | Implant_132 Implant_132 rule_LSSU rank_HP;rank_RSETUP;rank_FIFO wake_LeastSetupTime 1.0 min 1.0 min 2.0 8.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no Implant_Gas 56 | Implant_74 Implant_74 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 57 | Implant_88 Implant_88 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 58 | Implant_90 Implant_90 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO wake_LeastSetupTime 1.0 min 1.0 min 2.0 2.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 59 | Implant_91 Implant_91 rule_LSSU rank_HP;rank_RSETUP;rank_FIFO wake_LeastSetupTime 1.0 min 1.0 min 2.0 6.0 Implant Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no Implant_Gas 60 | Litho_BE_110 Litho_BE_110 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 28.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 61 | Litho_BE_93 Litho_BE_93 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 3.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 62 | Litho_BE_99 Litho_BE_99 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 3.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 63 | Litho_FE_111 Litho_FE_111 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 22.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 64 | Litho_FE_35 Litho_FE_35 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 65 | Litho_FE_92 Litho_FE_92 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 33.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 66 | Litho_FE_98 Litho_FE_98 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 5.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 67 | Litho_REG_BE_63 Litho_REG_BE_63 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 8.0 Litho_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 68 | Litho_REG_FE_64 Litho_REG_FE_64 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 14.0 Litho_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 69 | LithoMet_BE_18 LithoMet_BE_18 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 13.0 Litho_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 70 | LithoMet_FE_19 LithoMet_FE_19 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 18.0 Litho_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 71 | LithoTrack_BE_117 LithoTrack_BE_117 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 5.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 72 | LithoTrack_FE_115 LithoTrack_FE_115 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO wake_LeastSetupTime 1.0 min 1.0 min 51.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 73 | LithoTrack_FE_95 LithoTrack_FE_95 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO wake_LeastSetupTime 1.0 min 1.0 min 49.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 74 | LithoTrack_FE_96 LithoTrack_FE_96 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 Litho Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 75 | Planar_BE_75 Planar_BE_75 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 20.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 76 | Planar_FE_76 Planar_FE_76 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 3.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 77 | Planar_FE_77 Planar_FE_77 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 78 | Planar_FE_78 Planar_FE_78 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 79 | Planar_FE_79 Planar_FE_79 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 5.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 80 | Planar_FE_80 Planar_FE_80 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Planar Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 81 | TF_BE_2 TF_BE_2 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 4.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 82 | TF_BE_23 TF_BE_23 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 19.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 83 | TF_BE_24 TF_BE_24 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 5.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 84 | TF_BE_26 TF_BE_26 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 15.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 85 | TF_BE_40 TF_BE_40 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 24.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 86 | TF_FE_103 TF_FE_103 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 4.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 87 | TF_FE_104 TF_FE_104 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 5.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 88 | TF_FE_113 TF_FE_113 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 89 | TF_FE_131 TF_FE_131 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 6.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 90 | TF_FE_3 TF_FE_3 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 91 | TF_FE_5 TF_FE_5 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 4.0 TF Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 92 | TF_Met_FE_45 TF_Met_FE_45 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 TF_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 93 | TF_Met_FE_61 TF_Met_FE_61 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 TF_Met Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 94 | WE_BE_14 WE_BE_14 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 5.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 95 | WE_BE_16 WE_BE_16 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 9.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 96 | WE_BE_17 WE_BE_17 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 97 | WE_BE_7 WE_BE_7 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 1.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 98 | WE_BE_81 WE_BE_81 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 3.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 99 | WE_BE_82 WE_BE_82 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 10.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 100 | WE_BE_9 WE_BE_9 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 7.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 101 | WE_FE_108 WE_FE_108 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 35.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 102 | WE_FE_41 WE_FE_41 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 5.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 103 | WE_FE_47 WE_FE_47 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 6.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 104 | WE_FE_8 WE_FE_8 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 105 | WE_FE_83 WE_FE_83 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 7.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 106 | WE_FE_84 WE_FE_84 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 18.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 107 | WE_FE_85 WE_FE_85 rule_HotLotFIRST rank_HP;rank_RSETUP;rank_FIFO 1.0 min 1.0 min 2.0 2.0 Wet_Etch Custom_actlist_ASISemiOpersDuringSetupAndAdditionalLoadUnload Fab no 108 | --------------------------------------------------------------------------------