# -*- coding: utf-8 -*-
"""电工杯 2024 A 题 园区微电网风光储协调优化配置 —— 数字真源。

确定性合成数据（仅用于跑通方法，非官方原题）。提供：
  - gen_dgcup2024a()  -> 返回全部关键数字（供范文附录 import 复现）
  - 直接运行本脚本     -> 生成 data/dgcup2024a.csv 与
                          assets/problems/dgcup2024a/figs/*.svg

成本/容量参数（量级贴近典型工程，仅作教学示例）：
  光伏 3500 元/kW，风电 6000 元/kW，储能 1500 元/kWh + 功率 800 元/kW（按 2h 率），
  20 年寿命 + 2% 运维。
"""
import math, os, csv

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA = os.path.join(ROOT, "assets", "problems", "data")
FIGS = os.path.join(ROOT, "assets", "problems", "dgcup2024a", "figs")
WIND = 300.0          # 风电装机 kW（赛题给定 300kW 风机）
PV_CAP = 1300.0       # 光伏装机 kW（问题1 固定配置）
H = list(range(24))

# 园区负荷曲线 (kW)：双峰（早 8-9、晚 19-21）
L = [320,300,290,285,290,320,420,600,720,680,600,600,650,580,580,580,620,700,800,780,700,500,400,360]
# 光伏出力 (kW)：6-18 时钟形，正午最大
Ppv = [ (PV_CAP*max(0.0, math.sin(math.pi*(h-6)/12.0)) if 6<=h<=18 else 0.0) for h in H ]
# 风电出力 (kW)：夜间强、午后弱
Pw  = [ 200+100*math.cos(2*math.pi*(h-3)/24.0) for h in H ]
R = [Ppv[h]+Pw[h] for h in H]
N = [R[h]-L[h] for h in H]

# 问题1：24h 净平衡所需储能容量/功率（S 累计净，容量=峰谷差）
S = [0.0]*24
S[0] = N[0]
for h in range(1,24):
    S[h] = S[h-1] + N[h]
E_cap = max(S) - min(S)
P_cap = max(abs(v) for v in N)
SOC0  = -min(S)
soc   = [SOC0 + S[h] for h in H]
sumR, sumL = sum(R), sum(L)

# 调度基准（无储能）与含储能对比
import_base = [max(0.0, L[h]-R[h]) for h in H]
curt_base   = [max(0.0, R[h]-L[h]) for h in H]
util_base = sum(min(R[h],L[h]) for h in H)/sumR
util_with = 1.0 if sumR>=sumL else sumR/sumL

def annual_cost(pv, st_e):
    capex = pv*3500 + WIND*6000 + st_e*1500 + (max(1,st_e/2.0))*800
    return capex/20.0 + capex*0.02

def sweep():
    pv_opts=[1000,1300,1600,1900]
    st_opts=[0,1000,2000,3000,4000,5000]
    rows=[]
    for pv in pv_opts:
        PpvS=[ (pv*max(0.0, math.sin(math.pi*(h-6)/12.0)) if 6<=h<=18 else 0.0) for h in H ]
        for st_e in st_opts:
            Rs=[PpvS[h]+Pw[h] for h in H]
            bat=0.0; Pmax=max(1.0, st_e/2.0); curt=0.0
            for h in H:
                net=Rs[h]-L[h]
                if net>0:
                    ch=min(net, st_e-bat, Pmax); bat+=ch; curt+=net-ch
                else:
                    d=min(-net, bat, Pmax); bat-=d
            util = 1.0 - curt/sum(Rs)
            rows.append((pv,st_e,util,annual_cost(pv,st_e)))
    cand=[r for r in rows if r[2]>=0.95]
    best=min(cand, key=lambda r:r[3]) if cand else min(rows, key=lambda r:(abs(r[2]-0.95),r[3]))
    return rows, best

def gen_dgcup2024a():
    """返回供范文附录复现的全部关键数字。"""
    rows, best = sweep()
    return {
        "H":H, "L":L, "Ppv":Ppv, "Pw":Pw, "R":R, "N":N, "S":S,
        "E_cap":E_cap, "P_cap":P_cap, "SOC0":SOC0, "soc":soc,
        "sumR":sumR, "sumL":sumL,
        "util_base":util_base, "util_with":util_with,
        "import_base_total":sum(import_base), "curt_base_total":sum(curt_base),
        "knee":best, "sweep":rows,
    }

# ---------------- 生成数据 CSV ----------------
def write_csv():
    os.makedirs(DATA, exist_ok=True)
    path=os.path.join(DATA, "dgcup2024a.csv")
    with open(path,"w",newline="") as f:
        w=csv.writer(f)
        w.writerow(["hour","load_kw","pv_kw","wind_kw","renewable_kw","net_kw","soc_kwh"])
        for h in H:
            w.writerow([h, round(L[h],1), round(Ppv[h],1), round(Pw[h],1),
                        round(R[h],1), round(N[h],1), round(soc[h],1)])
    print("data ->", path)

# ---------------- 生成配图 ----------------
def line_svg(fname, title, series, ymax, xlabel, ylabel, w=760, hgt=440):
    x0,x1,y0,y1 = 90,710,350,70
    P=[]
    P.append('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 %d %d" font-family="Helvetica,SimHei,Arial,sans-serif">'%(w,hgt))
    P.append('<rect width="%d" height="%d" fill="#ffffff"/>'%(w,hgt))
    P.append('<text x="24" y="30" font-size="17" font-weight="700" fill="#1f2937">%s</text>'%(title))
    P.append('<line x1="24" y1="42" x2="736" y2="42" stroke="#2563eb" stroke-width="2"/>')
    for i in range(6):
        yy=y0+(y1-y0)*i/5.0; val=ymax*(5-i)/5.0
        P.append('<line x1="%d" y1="%.1f" x2="%d" y2="%.1f" stroke="#e5e7eb" stroke-dasharray="3 3"/>'%(x0,yy,x1,yy))
        P.append('<text x="%d" y="%.1f" font-size="11" fill="#6b7280" text-anchor="end">%.0f</text>'%(x0-8,yy+4,val))
    for h in [0,4,8,12,16,20,23]:
        xx=x0+(x1-x0)*h/23.0
        P.append('<text x="%.1f" y="%d" font-size="11" fill="#6b7280" text-anchor="middle">%d</text>'%(xx,hgt-22,h))
    P.append('<line x1="%d" y1="%d" x2="%d" y2="%d" stroke="#9ca3af" stroke-width="2"/>'%(x0,y0,x1,y0))
    P.append('<line x1="%d" y1="%d" x2="%d" y2="%d" stroke="#9ca3af" stroke-width="2"/>'%(x0,y0,x0,y1))
    for ci,(color,label,vals) in enumerate(series):
        pts=[]
        for h in H:
            xx=x0+(x1-x0)*h/23.0; yy=y0+(y1-y0)*(vals[h]/ymax)
            pts.append("%.1f,%.1f"%(xx,yy))
        P.append('<polyline points="%s" fill="none" stroke="%s" stroke-width="2.5" stroke-linejoin="round"/>'%( " ".join(pts), color))
        for h in H:
            xx=x0+(x1-x0)*h/23.0; yy=y0+(y1-y0)*(vals[h]/ymax)
            P.append('<circle cx="%.1f" cy="%.1f" r="2.5" fill="%s"/>'%(xx,yy,color))
        bx=110+ci*180
        P.append('<rect x="%d" y="46" width="14" height="14" fill="%s" rx="3"/>'%(bx,color))
        P.append('<text x="%d" y="57" font-size="12" fill="#1f2937">%s</text>'%(bx+18,label))
    P.append('<text x="400" y="%d" font-size="11" fill="#6b7280" text-anchor="middle">%s</text>'%(hgt-4,xlabel))
    P.append('</svg>')
    open(os.path.join(FIGS,fname),"w").write("\n".join(P))

def write_figs():
    os.makedirs(FIGS, exist_ok=True)
    line_svg("dgcup2024a-1-fig1.svg","图1 园区 24h 负荷与风光出力曲线",
             [("#ea580c","负荷 L",L),("#2563eb","光伏 Ppv",Ppv),("#0d9488","风电 Pw",Pw)],
             1000,"时刻 (h)","功率 (kW)")
    line_svg("dgcup2024a-1-fig2.svg","图2 储能 SOC 24h 变化（容量 %.0f kWh）"%E_cap,
             [("#4f46e5","SOC",soc)], E_cap*1.05, "时刻 (h)","荷电量 (kWh)")
    # 图3 容量优化帕累托
    rows,best=sweep()
    fig3=['<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 440" font-family="Helvetica,SimHei,Arial,sans-serif">',
          '<rect width="760" height="440" fill="#ffffff"/>',
          '<text x="24" y="30" font-size="17" font-weight="700" fill="#1f2937">图3 容量配置帕累托：年成本 vs 可再生利用率</text>',
          '<line x1="24" y1="42" x2="736" y2="42" stroke="#2563eb" stroke-width="2"/>']
    x0,x1,y0,y1=90,710,350,70
    cmax=max(r[3] for r in rows)
    for i in range(6):
        yy=y0+(y1-y0)*i/5.0; val=cmax*(5-i)/5.0
        fig3.append('<line x1="%d" y1="%.1f" x2="%d" y2="%.1f" stroke="#e5e7eb" stroke-dasharray="3 3"/>'%(x0,yy,x1,yy))
        fig3.append('<text x="%d" y="%.1f" font-size="11" fill="#6b7280" text-anchor="end">%.0f</text>'%(x0-8,yy+4,val))
    for u in [0.5,0.6,0.7,0.8,0.9,1.0]:
        xx=x0+(x1-x0)*(u-0.5)/0.5
        fig3.append('<text x="%.1f" y="426" font-size="11" fill="#6b7280" text-anchor="middle">%.0f%%</text>'%(xx,u*100))
        fig3.append('<line x1="%.1f" y1="%d" x2="%.1f" y2="%d" stroke="#f3f4f6"/>'%(xx,y0,xx,y1))
    fig3.append('<line x1="%d" y1="%d" x2="%d" y2="%d" stroke="#9ca3af" stroke-width="2"/>'%(x0,y0,x1,y0))
    fig3.append('<line x1="%d" y1="%d" x2="%d" y2="%d" stroke="#9ca3af" stroke-width="2"/>'%(x0,y0,x0,y1))
    for (pv,st_e,util,c) in rows:
        xx=x0+(x1-x0)*(util-0.5)/0.5; yy=y0+(y1-y0)*(c/cmax)
        col="#dc2626" if (pv,st_e)==(best[0],best[1]) else "#2563eb"
        fig3.append('<circle cx="%.1f" cy="%.1f" r="5" fill="%s"/>'%(xx,yy,col))
        fig3.append('<text x="%.1f" y="%.1f" font-size="9" fill="#6b7280" text-anchor="middle">PV%d</text>'%(xx,yy-8,pv))
    fig3.append('<rect x="%d" y="46" width="14" height="14" fill="#dc2626" rx="3"/>'%(x0))
    fig3.append('<text x="%d" y="57" font-size="12" fill="#1f2937">最优(利用≈95%%)</text>'%(x0+18))
    fig3.append('<text x="400" y="426" font-size="11" fill="#6b7280" text-anchor="middle">可再生利用率</text>')
    fig3.append('</svg>')
    open(os.path.join(FIGS,"dgcup2024a-1-fig3.svg"),"w").write("\n".join(fig3))
    # 图4 方法学流程
    flow=['<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 300" font-family="Helvetica,SimHei,Arial,sans-serif">',
          '<rect width="760" height="300" fill="#ffffff"/>',
          '<text x="24" y="30" font-size="17" font-weight="700" fill="#1f2937">图4 风光储协调优化配置方法学流程</text>',
          '<line x1="24" y1="42" x2="736" y2="42" stroke="#2563eb" stroke-width="2"/>',
          '<defs><marker id="arr" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 z" fill="#2563eb"/></marker></defs>']
    boxes=[("赛题","风光储微网"),("负荷/风光","典型日曲线"),("净平衡","储能容量"),("容量优化","帕累托扫描"),("协调调度","规则策略")]
    bx=60; bw=130; gap=18
    for i,(t,s) in enumerate(boxes):
        x=bx+i*(bw+gap)
        flow.append('<rect x="%.1f" y="117" width="%d" height="66" rx="10" fill="#f8fafc" stroke="#2563eb" stroke-width="2"/>'%(x,bw))
        flow.append('<text x="%.1f" y="146" font-size="13" fill="#1f2937" text-anchor="middle" font-weight="700">%s</text>'%(x+bw/2,t))
        flow.append('<text x="%.1f" y="166" font-size="11" fill="#6b7280" text-anchor="middle">%s</text>'%(x+bw/2,s))
        if i<4:
            flow.append('<line x1="%.1f" y1="150" x2="%.1f" y2="150" stroke="#2563eb" stroke-width="2" marker-end="url(#arr)"/>'%(x+bw+gap-2, x+bw+2))
    flow.append('</svg>')
    open(os.path.join(FIGS,"dgcup2024a-1-fig4.svg"),"w").write("\n".join(flow))
    print("figs ->", FIGS)

if __name__ == "__main__":
    write_csv()
    write_figs()
    D=gen_dgcup2024a()
    print("sumR=%.1f sumL=%.1f"%(D["sumR"],D["sumL"]))
    print("E_cap=%.1f kWh P_cap=%.1f kW SOC0=%.1f kWh"%(D["E_cap"],D["P_cap"],D["SOC0"]))
    print("util_base=%.4f util_with=%.4f"%(D["util_base"],D["util_with"]))
    print("curt_base=%.1f kWh import_base=%.1f kWh"%(D["curt_base_total"],D["import_base_total"]))
    print("knee=", D["knee"])
