import%20marimo%0A%0A__generated_with%20%3D%20%220.23.16%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Renewable%20Capacity%20Planning%20with%20Market%20Dispatch%0A%0A%20%20%20%20We%20consider%20renewable%20capacity%20planning%20in%20a%20power%20system%2C%20where%20a%0A%20%20%20%20generation%20planner%20must%20choose%20renewable%20capacity%20before%20an%20electricity%0A%20%20%20%20dispatcher%20sees%20the%20resulting%20operating%20limits%20and%20optimizes%20the%20dispatch%0A%20%20%20%20accordingly.%20The%20planner%20anticipates%20that%20response%20and%20trades%20investment%0A%20%20%20%20cost%20against%20the%20thermal%20generation%20that%20remains%20in%20the%20dispatch.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20cvxpy%20as%20cp%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20from%20blvpy%20import%20BilevelProblem%2C%20LowerProblem%0A%0A%20%20%20%20plt.style.use(Path(__file__).resolve().parents%5B1%5D%20%2F%20%22_shared%22%20%2F%20%22zhlatex.mplstyle%22)%0A%20%20%20%20return%20BilevelProblem%2C%20LowerProblem%2C%20Path%2C%20cp%2C%20mo%2C%20np%2C%20plt%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Bilevel%20formulation%0A%0A%20%20%20%20Let%20%24%5Calpha%5Cin%5Cmathbf%7BR%7D%24%20denote%20renewable%20capacity%2C%20and%20let%0A%20%20%20%20%24L%5Cin%5Cmathbf%7BR%7D%5Em%24%20denote%20renewable%20availability%20over%20%24m%24%20time%20periods.%0A%20%20%20%20Thus%2C%20%24%5Calpha%20L%5Cin%5Cmathbf%7BR%7D%5Em%24%20gives%20the%20renewable-generation%20limits.%0A%20%20%20%20Let%20%24D%5Cin%5Cmathbf%7BR%7D%5Em%24%20denote%20electricity%20demand%2C%20and%20let%0A%20%20%20%20%24r%2Cg%5Cin%5Cmathbf%7BR%7D%5Em%24%20denote%20renewable%20and%20thermal%20dispatch.%20The%20generation%0A%20%20%20%20planner%20solves%0A%0A%20%20%20%20%5C%5B%0A%20%20%20%20%5Cbegin%7Barray%7D%7Bll%7D%0A%20%20%20%20%5Cmathop%7B%5Cmathrm%7Bminimize%7D%7D_%7B%5Calpha%2Cr%2Cg%7D%0A%20%20%20%20%20%20%20%20%26%20p_r%5Calpha%5E2%2Bp_g%5Cmathbf%7B1%7D%5ETg%20%5C%5C%0A%20%20%20%20%5Cmathop%7B%5Cmathrm%7Bsubject%5C%20to%7D%7D%0A%20%20%20%20%20%20%20%20%26%200%5Cleq%5Calpha%5Cleq%5Calpha_%7B%5Cmathrm%7Bmax%7D%7D%2C%5C%5C%0A%20%20%20%20%20%20%20%20%26%20(r%2Cg)%5Cin%20S(%5Calpha).%0A%20%20%20%20%5Cend%7Barray%7D%0A%20%20%20%20%5C%5D%0A%0A%20%20%20%20For%20a%20fixed%20%24%5Calpha%24%2C%20the%20grid%20dispatcher%20solves%20the%20lower%20problem%0A%0A%20%20%20%20%5C%5B%0A%20%20%20%20%5Cbegin%7Barray%7D%7Bll%7D%0A%20%20%20%20S(%5Calpha)%3D%5Cmathop%7B%5Cmathrm%7Bargmin%7D%7D_%7Br%2Cg%7D%0A%20%20%20%20%20%20%20%20%26%20c_r%5Cmathbf%7B1%7D%5ETr%2Bc_g%5Cmathbf%7B1%7D%5ETg%0A%20%20%20%20%20%20%20%20%20%20%2B%5Cdelta%5Cleft(%5ClVert%20r%5CrVert_2%5E2%2B%5ClVert%20g%5CrVert_2%5E2%5Cright)%20%5C%5C%0A%20%20%20%20%5Cmathop%7B%5Cmathrm%7Bsubject%5C%20to%7D%7D%0A%20%20%20%20%20%20%20%20%26%200%5Cpreceq%20r%5Cpreceq%5Calpha%20L%2C%5Cquad%20g%5Csucceq0%2C%5C%5C%0A%20%20%20%20%20%20%20%20%26%20r%2Bg%5Csucceq%20D.%0A%20%20%20%20%5Cend%7Barray%7D%0A%20%20%20%20%5C%5D%0A%0A%20%20%20%20The%20upper%20variable%20is%20%24%5Calpha%24%2C%20while%20%24r%24%20and%20%24g%24%20are%20the%20lower%20variables.%0A%20%20%20%20The%20planning%20and%20dispatch%20cost%20coefficients%20%24p_r%2Cp_g%2Cc_r%2Cc_g%24%2C%20maximum%0A%20%20%20%20capacity%20%24%5Calpha_%7B%5Cmathrm%7Bmax%7D%7D%24%2C%20regularization%20parameter%20%24%5Cdelta%24%2C%20and%0A%20%20%20%20vectors%20%24L%2CD%24%20are%20given.%20The%20small%20quadratic%20term%20makes%20the%20lower%20response%0A%20%20%20%20stable.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Representative%20operating%20data%0A%0A%20%20%20%20Twenty-four%20hourly%20periods%20capture%20a%20morning%20shoulder%20and%20an%20evening%0A%20%20%20%20demand%20peak.%20The%20aggregate%20renewable-availability%20model%20has%20two%20distinct%0A%20%20%20%20windows%3A%20a%20smaller%20morning%20peak%20and%20a%20larger%20afternoon%20peak%20separated%20by%20a%0A%20%20%20%20midday%20lull.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20def%20demand_profile(time)%3A%0A%20%20%20%20%20%20%20%20return%203.5%20%2B%201.8%20*%20np.exp(-0.5%20*%20((time%20-%208.0)%20%2F%202.6)%20**%202)%20%2B%203.0%20*%20np.exp(-0.5%20*%20((time%20-%2019.0)%20%2F%203.2)%20**%202)%0A%0A%20%20%20%20def%20availability_profile(time)%3A%0A%20%20%20%20%20%20%20%20morning%20%3D%20np.where(%0A%20%20%20%20%20%20%20%20%20%20%20%20(time%20%3E%3D%205.0)%20%26%20(time%20%3C%3D%2011.0)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%200.8%20*%20np.sin(np.pi%20*%20(time%20-%205.0)%20%2F%206.0)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%200.0%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20afternoon%20%3D%20np.where(%0A%20%20%20%20%20%20%20%20%20%20%20%20(time%20%3E%3D%2013.0)%20%26%20(time%20%3C%3D%2021.0)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20np.sin(np.pi%20*%20(time%20-%2013.0)%20%2F%208.0)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%200.0%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20return%20morning%20%2B%20afternoon%0A%0A%20%20%20%20hours%20%3D%20np.arange(24)%0A%20%20%20%20m%20%3D%20hours.size%0A%20%20%20%20D%20%3D%20demand_profile(hours)%0A%20%20%20%20L%20%3D%20availability_profile(hours)%0A%0A%20%20%20%20p_r%20%3D%200.08%0A%20%20%20%20p_g%20%3D%200.6%0A%20%20%20%20c_r%20%3D%200.4%0A%20%20%20%20c_g%20%3D%202.5%0A%20%20%20%20alpha_max%20%3D%2012.0%0A%20%20%20%20delta%20%3D%201e-3%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20D%2C%0A%20%20%20%20%20%20%20%20L%2C%0A%20%20%20%20%20%20%20%20alpha_max%2C%0A%20%20%20%20%20%20%20%20availability_profile%2C%0A%20%20%20%20%20%20%20%20c_g%2C%0A%20%20%20%20%20%20%20%20c_r%2C%0A%20%20%20%20%20%20%20%20delta%2C%0A%20%20%20%20%20%20%20%20demand_profile%2C%0A%20%20%20%20%20%20%20%20m%2C%0A%20%20%20%20%20%20%20%20p_g%2C%0A%20%20%20%20%20%20%20%20p_r%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Specify%20and%20solve%20the%20model%0A%0A%20%20%20%20%60alpha%60%20is%20listed%20as%20a%20%60LowerProblem%60%20parameter%2C%20so%20BLVPY%20treats%20it%20as%0A%20%20%20%20fixed%20inside%20dispatch%20while%20retaining%20it%20as%20the%20planner's%20variable.%20Its%0A%20%20%20%20planning%20limits%20are%20written%20as%20explicit%20CVXPY%20constraints.%20The%20initial%0A%20%20%20%20%60.value%60%20provides%20a%20starting%20point%20for%20the%20nonlinear%20solve.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20BilevelProblem%2C%0A%20%20%20%20D%2C%0A%20%20%20%20L%2C%0A%20%20%20%20LowerProblem%2C%0A%20%20%20%20alpha_max%2C%0A%20%20%20%20c_g%2C%0A%20%20%20%20c_r%2C%0A%20%20%20%20cp%2C%0A%20%20%20%20delta%2C%0A%20%20%20%20m%2C%0A%20%20%20%20p_g%2C%0A%20%20%20%20p_r%2C%0A)%3A%0A%20%20%20%20alpha%20%3D%20cp.Variable(name%3D%22alpha%22)%0A%20%20%20%20r%20%3D%20cp.Variable(m%2C%20name%3D%22r%22)%0A%20%20%20%20g%20%3D%20cp.Variable(m%2C%20name%3D%22g%22)%0A%20%20%20%20alpha.value%20%3D%208.5%0A%0A%20%20%20%20dispatch%20%3D%20LowerProblem(%0A%20%20%20%20%20%20%20%20cp.Minimize(c_r%20*%20cp.sum(r)%20%2B%20c_g%20*%20cp.sum(g)%20%2B%20delta%20*%20(cp.sum_squares(r)%20%2B%20cp.sum_squares(g)))%2C%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20r%20%3E%3D%200.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20g%20%3E%3D%200.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20r%20%3C%3D%20cp.multiply(L%2C%20alpha)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20r%20%2B%20g%20%3E%3D%20D%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20parameters%3D%5Balpha%5D%2C%0A%20%20%20%20)%0A%20%20%20%20problem%20%3D%20BilevelProblem(%0A%20%20%20%20%20%20%20%20cp.Minimize(p_r%20*%20cp.square(alpha)%20%2B%20p_g%20*%20cp.sum(g))%2C%0A%20%20%20%20%20%20%20%20dispatch%2C%0A%20%20%20%20%20%20%20%20upper_constraints%3D%5Balpha%20%3E%3D%200.0%2C%20alpha%20%3C%3D%20alpha_max%5D%2C%0A%20%20%20%20)%0A%20%20%20%20return%20alpha%2C%20g%2C%20problem%0A%0A%0A%40app.cell%0Adef%20_(problem)%3A%0A%20%20%20%20result%20%3D%20problem.solve(%0A%20%20%20%20%20%20%20%20epsilon_initial%3D1e-2%2C%0A%20%20%20%20%20%20%20%20epsilon_target%3D1e-5%2C%0A%20%20%20%20%20%20%20%20verbose%3DFalse%2C%0A%20%20%20%20)%0A%20%20%20%20diagnostics%20%3D%20problem.gap_diagnostics(result)%0A%20%20%20%20return%20diagnostics%2C%20result%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(D%2C%20alpha%2C%20diagnostics%2C%20g%2C%20mo%2C%20np%2C%20result)%3A%0A%20%20%20%20assert%20result.succeeded%2C%20result.message%0A%0A%20%20%20%20baseline_g%20%3D%20float(np.sum(D))%0A%20%20%20%20optimized_g%20%3D%20float(np.sum(g.value))%0A%20%20%20%20assert%20optimized_g%20%3C%20baseline_g%20-%201e-3%2C%20%22Renewable%20investment%20did%20not%20reduce%20thermal%20generation.%22%0A%0A%20%20%20%20mo.md(rf%22%22%22%0A%20%20%20%20%23%23%20Result%0A%0A%20%20%20%20%7C%20quantity%20%7C%20value%20%7C%0A%20%20%20%20%7C%20---%20%7C%20---%3A%20%7C%0A%20%20%20%20%7C%20status%20%7C%20%60%7Bresult.status%7D%60%20%7C%0A%20%20%20%20%7C%20installed%20renewable%20capacity%20%24%5Calpha%24%20%7C%20%7Bfloat(alpha.value)%3A.3f%7D%20%7C%0A%20%20%20%20%7C%20thermal%20production%20without%20renewables%20%7C%20%7Bbaseline_g%3A.3f%7D%20%7C%0A%20%20%20%20%7C%20optimized%20thermal%20production%20%24%5Cmathbf%7B%7B1%7D%7D%5ETg%24%20%7C%20%7Boptimized_g%3A.3f%7D%20%7C%0A%20%20%20%20%7C%20upper%20objective%20%7C%20%7Bfloat(result.objective)%3A.6f%7D%20%7C%0A%20%20%20%20%7C%20final%20epsilon%20%7C%20%7Bresult.final_epsilon%3A.3e%7D%20%7C%0A%20%20%20%20%7C%20maximum%20lifted%20residual%20%7C%20%7Bresult.residuals.max_violation%3A.3e%7D%20%7C%0A%20%20%20%20%7C%20complementarity%20%7C%20%7Bresult.complementarity%3A.3e%7D%20%7C%0A%20%20%20%20%7C%20signed%20source%20gap%20%7C%20%7Bdiagnostics.source_gap%3A.3e%7D%20%7C%0A%0A%20%20%20%20The%20planner%20installs%20enough%20capacity%20to%20displace%20thermal%20generation%20during%0A%20%20%20%20both%20renewable-availability%20windows%2C%20but%20not%20so%20much%20that%20the%20quadratic%0A%20%20%20%20investment%20penalty%20dominates.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Interpreting%20the%20capacity%20and%20dispatch%0A%0A%20%20%20%20The%20top%20panel%20stacks%20renewable%20and%20thermal%20output%20against%20demand.%20The%0A%20%20%20%20dotted%20line%20is%20the%20renewable%20output%20physically%20available%20from%20the%20selected%0A%20%20%20%20capacity%3B%20thermal%20generation%20fills%20the%20shortfall%20when%20renewable%20potential%0A%20%20%20%20is%20below%20demand.%0A%0A%20%20%20%20The%20bottom%20panel%20explains%20the%20planner's%20choice%3A%20investment%20cost%20rises%0A%20%20%20%20quadratically%2C%20while%20the%20thermal-production%20penalty%20falls.%20Their%20sum%20is%0A%20%20%20%20minimized%20close%20to%20the%20capacity%20returned%20by%20BLVPY.%20These%20grid%20curves%20use%0A%20%20%20%20the%20hand-derived%20dispatch%20response%0A%20%20%20%20%24r_t(%5Calpha)%3D%5Cmin%5C%7BD_t%2C%5Calpha%20L_t%5C%7D%24%20and%0A%20%20%20%20%24g_t(%5Calpha)%3DD_t-r_t(%5Calpha)%24%20for%20this%20example.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20D%2C%0A%20%20%20%20L%2C%0A%20%20%20%20alpha%2C%0A%20%20%20%20alpha_max%2C%0A%20%20%20%20availability_profile%2C%0A%20%20%20%20demand_profile%2C%0A%20%20%20%20np%2C%0A%20%20%20%20p_g%2C%0A%20%20%20%20p_r%2C%0A%20%20%20%20result%2C%0A)%3A%0A%20%20%20%20alpha_grid%20%3D%20np.linspace(0.0%2C%20alpha_max%2C%20500)%0A%20%20%20%20r_grid%20%3D%20np.minimum(%0A%20%20%20%20%20%20%20%20D%5BNone%2C%20%3A%5D%2C%0A%20%20%20%20%20%20%20%20alpha_grid%5B%3A%2C%20None%5D%20*%20L%5BNone%2C%20%3A%5D%2C%0A%20%20%20%20)%0A%20%20%20%20g_grid%20%3D%20D%5BNone%2C%20%3A%5D%20-%20r_grid%0A%20%20%20%20g_totals%20%3D%20np.sum(g_grid%2C%20axis%3D1)%0A%20%20%20%20investment_costs%20%3D%20p_r%20*%20np.square(alpha_grid)%0A%20%20%20%20thermal_penalties%20%3D%20p_g%20*%20g_totals%0A%20%20%20%20planner_objectives%20%3D%20investment_costs%20%2B%20thermal_penalties%0A%20%20%20%20selected_alpha%20%3D%20float(np.asarray(result.variable_values%5Balpha%5D))%0A%0A%20%20%20%20plot_hours%20%3D%20np.linspace(0.0%2C%2023.0%2C%20461)%0A%20%20%20%20D_plot%20%3D%20demand_profile(plot_hours)%0A%20%20%20%20L_plot%20%3D%20availability_profile(plot_hours)%0A%20%20%20%20r_plot%20%3D%20np.minimum(D_plot%2C%20selected_alpha%20*%20L_plot)%0A%20%20%20%20g_plot%20%3D%20D_plot%20-%20r_plot%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20D_plot%2C%0A%20%20%20%20%20%20%20%20L_plot%2C%0A%20%20%20%20%20%20%20%20alpha_grid%2C%0A%20%20%20%20%20%20%20%20g_plot%2C%0A%20%20%20%20%20%20%20%20investment_costs%2C%0A%20%20%20%20%20%20%20%20planner_objectives%2C%0A%20%20%20%20%20%20%20%20plot_hours%2C%0A%20%20%20%20%20%20%20%20r_plot%2C%0A%20%20%20%20%20%20%20%20selected_alpha%2C%0A%20%20%20%20%20%20%20%20thermal_penalties%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(%0A%20%20%20%20D_plot%2C%0A%20%20%20%20L_plot%2C%0A%20%20%20%20Path%2C%0A%20%20%20%20alpha_grid%2C%0A%20%20%20%20g_plot%2C%0A%20%20%20%20investment_costs%2C%0A%20%20%20%20np%2C%0A%20%20%20%20planner_objectives%2C%0A%20%20%20%20plot_hours%2C%0A%20%20%20%20plt%2C%0A%20%20%20%20r_plot%2C%0A%20%20%20%20selected_alpha%2C%0A%20%20%20%20thermal_penalties%2C%0A)%3A%0A%20%20%20%20figure_dir%20%3D%20Path(__file__).resolve().parent%20%2F%20%22figures%22%0A%20%20%20%20figure_dir.mkdir(parents%3DTrue%2C%20exist_ok%3DTrue)%0A%0A%20%20%20%20fig%2C%20(dispatch_axis%2C%20objective_axis)%20%3D%20plt.subplots(2%2C%201%2C%20figsize%3D(6.5%2C%207))%0A%0A%20%20%20%20dispatch_axis.stackplot(%0A%20%20%20%20%20%20%20%20plot_hours%2C%0A%20%20%20%20%20%20%20%20r_plot%2C%0A%20%20%20%20%20%20%20%20g_plot%2C%0A%20%20%20%20%20%20%20%20labels%3D%5Br%22%24r%24%22%2C%20r%22%24g%24%22%5D%2C%0A%20%20%20%20%20%20%20%20colors%3D%5B%22C2%22%2C%20%22grey%22%5D%2C%0A%20%20%20%20%20%20%20%20alpha%3D0.85%2C%0A%20%20%20%20)%0A%20%20%20%20dispatch_axis.plot(plot_hours%2C%20D_plot%2C%20color%3D%22k%22%2C%20linestyle%3D%22--%22%2C%20label%3Dr%22%24D%24%22%2C%20zorder%3D10)%0A%20%20%20%20dispatch_axis.plot(%0A%20%20%20%20%20%20%20%20plot_hours%2C%0A%20%20%20%20%20%20%20%20selected_alpha%20*%20L_plot%2C%0A%20%20%20%20%20%20%20%20color%3D%22C2%22%2C%0A%20%20%20%20%20%20%20%20linestyle%3D%22%3A%22%2C%0A%20%20%20%20%20%20%20%20label%3Dr%22%24%5Calpha%20L%24%22%2C%0A%20%20%20%20)%0A%20%20%20%20dispatch_axis.set(xlabel%3Dr%22%24t%24%22%2C%20ylabel%3Dr%22Generation%20and%20demand%22%2C%20xticks%3Dnp.arange(0%2C%2024%2C%204)%2C%20xlim%3D(0%2C%2023))%0A%20%20%20%20dispatch_axis.legend(loc%3D%22upper%20left%22%2C%20frameon%3DFalse%2C%20fontsize%3D13)%0A%0A%20%20%20%20objective_axis.plot(alpha_grid%2C%20investment_costs%2C%20label%3Dr%22%24p_r%5Calpha%5E2%24%22%2C%20color%3D%22C2%22)%0A%20%20%20%20objective_axis.plot(alpha_grid%2C%20thermal_penalties%2C%20label%3Dr%22%24p_g%5Cmathbf%7B1%7D%5ETg%24%22%2C%20color%3D%22grey%22)%0A%20%20%20%20objective_axis.plot(%0A%20%20%20%20%20%20%20%20alpha_grid%2C%0A%20%20%20%20%20%20%20%20planner_objectives%2C%0A%20%20%20%20%20%20%20%20label%3Dr%22%24p_r%5Calpha%5E2%2Bp_g%5Cmathbf%7B1%7D%5ETg%24%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22k%22%2C%0A%20%20%20%20)%0A%20%20%20%20objective_axis.axvline(selected_alpha%2C%20color%3D%22C3%22%2C%20linestyle%3D%22--%22)%0A%20%20%20%20objective_axis.set(%0A%20%20%20%20%20%20%20%20xlabel%3Dr%22%24%5Calpha%24%22%2C%0A%20%20%20%20%20%20%20%20ylabel%3D%22Planning%20cost%22%2C%0A%20%20%20%20)%0A%20%20%20%20objective_axis.legend(loc%3D(0%2C%200.1)%2C%20frameon%3DFalse%2C%20fontsize%3D13)%0A%0A%20%20%20%20fig.tight_layout()%0A%20%20%20%20figure_path%20%3D%20figure_dir%20%2F%20%22renewable_capacity_planning.pdf%22%0A%20%20%20%20fig.savefig(figure_path%2C%20bbox_inches%3D%22tight%22)%0A%20%20%20%20plt.show()%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
32a2dbbc7deb3b54019f9f115743992d