# =============================================================================
# Makefile for TVS/TRIAC DEVSIM Simulation Pipeline
# =============================================================================

# Limit threads for parallel solvers to avoid starving the WSL VM resources
export OMP_NUM_THREADS = 4
export MKL_NUM_THREADS = 4
export TBB_NUM_THREADS = 4
export OPENBLAS_NUM_THREADS = 4

# Default simulation control options
avalanche ?= false
btbt ?= false
refine ?= false
refine_v_step ?= 50.0
temp ?= 300.0
pcad ?= true
sweep_target ?= 1000V
vds ?= 1.0

# Subdirectory device and output management
# dev must be defined by the user
YYMMDD := $(shell date +%y%m%d)
ifdef dev
  LATEST_NN := $(shell ls -d devices/$(dev)/output_$(YYMMDD)_[0-9]* 2>/dev/null | sed 's/.*_//' | sort -n | tail -n 1)
  ifeq ($(LATEST_NN),)
    DEFAULT_OUT := output_$(YYMMDD)_01
  else
    DEFAULT_OUT := output_$(YYMMDD)_$(LATEST_NN)
  endif
else
  DEFAULT_OUT := output_$(YYMMDD)_01
endif
out ?= $(DEFAULT_OUT)

# Check if dev is specified for targets that require it
ifeq ($(filter clean help help-detail,$(MAKECMDGOALS)),)
  ifneq ($(MAKECMDGOALS),)
    ifndef dev
      $(error dev is not defined. Please specify dev=devname, e.g., make sweep dev=Triac_rp)
    endif
  endif
endif

DEV_DIR = devices/$(dev)
OUT_DIR = $(DEV_DIR)/$(out)

PYTHON := .venv/bin/python

.PHONY: help help-detail clean mesh static sweep mos_sweep mos_transfer resume resume-bg show-conv monitor backup-run

help:
	@echo "============================================================================="
	@echo "TVS/TRIAC Simulation Pipeline - Developer Operations & Maintenance"
	@echo "============================================================================="
	@echo "Core Workflow:"
	@echo "  1. make mesh             - Build base grid device_2d.msh under 0V built-in field"
	@echo "  2. make static           - Verify equilibrium Poisson/doping convergence at 0V"
	@echo "  3. make sweep            - Run high-voltage bias sweep (avalanche & refinement controls)"
	@echo ""
	@echo "High-Level Operations:"
	@echo "  make static              - Solve equilibrium 0V Poisson state"
	@echo "  make sweep               - Execute bias sweep simulation"
	@echo "  make mos_sweep           - Execute MOSFET I-V curve sweep (for LDMOS)"
	@echo "  make mos_transfer        - Execute MOSFET transfer curves vs temperature (for LDMOS)"
	@echo "  make resume              - Resume from latest or specific checkpoint"
	@echo "  make resume-bg           - Resume simulation in the background (nohup)"
	@echo ""
	@echo "Maintenance & Diagnostics:"
	@echo "  make mesh                - (Re)generate adaptive base mesh"
	@echo "  make clean               - Clear temporary files and simulation logs"
	@echo "  make monitor             - Live-monitor convergence log of active sweep"
	@echo "  make show-conv           - Print last few convergence step error details"
	@echo ""
	@echo "Output & Backup Rules:"
	@echo "  devices/\$$(dev)/\$$(out)/ - Current logs, checkpoints & visualization plots"
	@echo "  * Note: Rebuilding mesh via make mesh auto-archives output_this_run to prevent"
	@echo "          loading old checkpoints on the updated grid structure."
	@echo ""
	@echo "For detail variables (e.g., dev=Triac_rp, avalanche=true, refine=false, sweep_target=1000V), run:"
	@echo "  make help-detail"
	@echo "============================================================================="

help-detail:
	@echo "============================================================================="
	@echo "Detailed Command Parameters and Variables:"
	@echo "============================================================================="
	@echo "Command Variables:"
	@echo "  dev=<device_name>        - Target device directory name (REQUIRED)"
	@echo "  out=<output_name>        - Target output folder name (default: output_<yymmdd>_01)"
	@echo "  sweep_target=<voltage>   - Target sweep voltage limit (default: 1000V)"
	@echo "  avalanche=true|false     - Toggle impact ionization (avalanche) model"
	@echo "                             Default: false (normal sweep without avalanche)"
	@echo "  btbt=true|false          - Toggle band-to-band tunneling (BTBT) model"
	@echo "                             Default: false (normal sweep without BTBT)"
	@echo "  refine=true|false        - Toggle dynamic adaptive refinement during sweep"
	@echo "                             Default: false (enable grid splitting at milestones)"
	@echo "  refine_v_step=<voltage>  - Set voltage interval (V) to trigger dynamic refinement"
	@echo "                             Default: 50.0 (e.g., every 50V). Less than 1.0 disables it."
	@echo "  pcad=true|false          - Toggle PCAD doping model application"
	@echo "                             Default: true (use analytical doping expressions if not found)"
	@echo "  temp=<temperature>       - Set device simulation temperature in Kelvin"
	@echo "                             Default: 300.0 (e.g., room temperature)"
	@echo "  checkpoint=<filepath>    - Specify seed/recovery pickle file to resume from"
	@echo "                             Default: automatically searches for latest checkpoints"
	@echo ""
	@echo "Usage Examples:"
	@echo "  make sweep dev=Triac_rp out=output_260625_01 pcad=true"
	@echo "  make sweep dev=Triac_rp avalanche=true sweep_target=1200V"
	@echo "  make sweep dev=Triac_rp temp=350.0"
	@echo "  make resume dev=Triac_rp checkpoint=devices/Triac_rp/output_260625_01/seed_500V.pkl temp=350.0"
	@echo "  make resume-bg dev=Triac_rp avalanche=true refine_v_step=30.0 temp=350.0"
	@echo "============================================================================="

# --- 網格自適應優化流程 ---
# 1. 刪除舊的 bgmesh，以確保 generate_mesh_2d.py 產生的是最乾淨之基礎網格
# 2. 執行基礎網格生成
# 3. 執行 run_refinement_2d.py 讀取基礎網格，求解電場並寫出新的 device_bgmesh.pos
# 4. 再次執行 generate_mesh_2d.py，此時會自動載入 bgmesh 並輸出最終優化網格 device_2d.msh
mesh: $(DEV_DIR)/device_config.py generate_mesh_2d.py generate_analytical_bgmesh.py
	@echo ">>> [Mesh] 開始進行自適應網格重構流程 (dev=$(dev))..."
	rm -f $(DEV_DIR)/device_bgmesh.pos
	DEV_DIR=$(DEV_DIR) OUT_DIR=$(OUT_DIR)/ USE_PCAD=$(pcad) $(PYTHON) generate_mesh_2d.py
	DEV_DIR=$(DEV_DIR) OUT_DIR=$(OUT_DIR)/ USE_PCAD=$(pcad) $(PYTHON) generate_analytical_bgmesh.py
	DEV_DIR=$(DEV_DIR) OUT_DIR=$(OUT_DIR)/ USE_PCAD=$(pcad) $(PYTHON) generate_mesh_2d.py
	@echo ">>> [Mesh] 自適應優化網格生成完畢！(Saved: $(DEV_DIR)/device_2d.msh)"

# --- 熱平衡電位求解 ---
# 依賴於對應的網格與求解腳本
static: $(DEV_DIR)/device_2d.msh solve_static_2d.py
	@echo ">>> [Static] 求解零偏壓熱平衡狀態 (dev=$(dev), temp=$(temp))..."
	DEV_DIR=$(DEV_DIR) OUT_DIR=$(OUT_DIR)/ USE_PCAD=$(pcad) TEMP=$(temp) $(PYTHON) solve_static_2d.py

# --- 高壓偏壓掃描 ---
# 依賴於對應的網格與掃描腳本
sweep: $(DEV_DIR)/device_2d.msh solve_sweep_recon.py
	@echo ">>> [Sweep] 開始高壓偏壓漂移-擴散模擬 (dev=$(dev), out=$(out), avalanche=$(avalanche), btbt=$(btbt), refine=$(refine), refine_v_step=$(refine_v_step), temp=$(temp), sweep_target=$(sweep_target))..."
	mkdir -p $(OUT_DIR)
	DEV_DIR=$(DEV_DIR) OUT_DIR=$(OUT_DIR)/ USE_PCAD=$(pcad) AVALANCHE=$(avalanche) BTBT=$(btbt) REFINE=$(refine) REFINE_V_STEP=$(refine_v_step) TEMP=$(temp) SWEEP_TARGET=$(sweep_target) $(PYTHON) -u solve_sweep_recon.py > $(OUT_DIR)/sweeping.log 2>&1

# --- MOSFET I-V 曲線掃描 ---
# 針對 LDMOS 進行多閘極電壓下之 Ids-Vds 掃描
mos_sweep: $(DEV_DIR)/device_2d.msh mos_sweep.py
	@echo ">>> [MOS Sweep] 開始 MOSFET Ids-Vds 偏壓掃描 (dev=$(dev), out=$(out), temp=$(temp))..."
	mkdir -p $(OUT_DIR)
	DEV_DIR=$(DEV_DIR) OUT_DIR=$(OUT_DIR)/ USE_PCAD=$(pcad) TEMP=$(temp) $(PYTHON) -u mos_sweep.py > $(OUT_DIR)/sweeping.log 2>&1

# --- MOSFET 轉移特性溫度掃描 ---
# 針對 LDMOS 進行多溫度下之 Ids-Vgs 轉移特性掃描
mos_transfer: $(DEV_DIR)/device_2d.msh mos_transfer_temp_sweep.py mos_transfer_single_temp.py
	@echo ">>> [MOS Transfer] 開始 MOSFET 轉移特性多溫度掃描 (dev=$(dev), out=$(out), vds=$(vds))..."
	mkdir -p $(OUT_DIR)
	DEV_DIR=$(DEV_DIR) OUT_DIR=$(OUT_DIR)/ VDS=$(vds) $(PYTHON) -u mos_transfer_temp_sweep.py > $(OUT_DIR)/sweeping.log 2>&1


resume:
	@echo ">>> [Resume] 從指定的 Checkpoint ($(checkpoint)) 或最新的自動備份接續掃描 (dev=$(dev), out=$(out), avalanche=$(avalanche), btbt=$(btbt), refine=$(refine), refine_v_step=$(refine_v_step), temp=$(temp), sweep_target=$(sweep_target))..."
	mkdir -p $(OUT_DIR)
	DEV_DIR=$(DEV_DIR) OUT_DIR=$(OUT_DIR)/ USE_PCAD=$(pcad) AVALANCHE=$(avalanche) BTBT=$(btbt) REFINE=$(refine) REFINE_V_STEP=$(refine_v_step) TEMP=$(temp) SWEEP_TARGET=$(sweep_target) $(PYTHON) -u resume_run.py $(checkpoint) >> $(OUT_DIR)/sweeping.log 2>&1

resume-bg:
	@echo ">>> [Resume-BG] 在背景從指定的 Checkpoint ($(checkpoint)) 或最新的自動備份接續掃描 (dev=$(dev), out=$(out), avalanche=$(avalanche), btbt=$(btbt), refine=$(refine), refine_v_step=$(refine_v_step), temp=$(temp), sweep_target=$(sweep_target))..."
	mkdir -p $(OUT_DIR)
	DEV_DIR=$(DEV_DIR) OUT_DIR=$(OUT_DIR)/ USE_PCAD=$(pcad) AVALANCHE=$(avalanche) BTBT=$(btbt) REFINE=$(refine) REFINE_V_STEP=$(refine_v_step) TEMP=$(temp) SWEEP_TARGET=$(sweep_target) nohup $(PYTHON) -u resume_run.py $(checkpoint) >> $(OUT_DIR)/sweeping.log 2>&1 &

# --- 萃取與監控收斂曲線 ---
show-conv:
	@if [ -f $(OUT_DIR)/sweeping.log ]; then \
		awk '/Iteration:/ {printf "Iteration %s：", $$2} /Device:/ {print $$4}' $(OUT_DIR)/sweeping.log | tail -n 10; \
	else \
		echo "$(OUT_DIR)/sweeping.log does not exist."; \
	fi

monitor:
	@if [ -f $(OUT_DIR)/sweeping.log ]; then \
		tail -f $(OUT_DIR)/sweeping.log | awk '/Iteration:/ {printf "Iteration %s：", $$2; fflush()} /Device:/ {print $$4; fflush()}'; \
	else \
		echo "$(OUT_DIR)/sweeping.log does not exist."; \
	fi

# --- 網格依賴規則 ---
# 當沒有 device_2d.msh 或 device_config.py 有更動時，自動觸發 mesh 流程
$(DEV_DIR)/device_2d.msh: $(DEV_DIR)/device_config.py generate_mesh_2d.py generate_analytical_bgmesh.py
	$(MAKE) mesh dev=$(dev)

clean:
	@echo ">>> 清除暫存與網格檔案..."
	rm -f *.msh *.pos *.tec *.png *.csv *.vtm *.vtu *.visit
	rm -rf __pycache__ physics/__pycache__
ifneq ($(dev),)
	@echo ">>> 清除裝置 $(dev) 的網格與自適應暫存檔案..."
	rm -f $(DEV_DIR)/device_2d.msh $(DEV_DIR)/device_bgmesh.pos
endif

