Skip to content

Commit 8454094

Browse files
samimkpelesh
authored andcommitted
Solved issue with Python script generation
1 parent ed8db9f commit 8454094

File tree

1 file changed

+132
-59
lines changed

1 file changed

+132
-59
lines changed

launcher/app.py

Lines changed: 132 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -644,134 +644,207 @@ def file_upload(label: str, extensions: list[str], key: str,
644644
py_app = app_key
645645
py_netfile = netfile or "<upload network file>"
646646

647-
lines = [
647+
# Map UI initialization names to Python API enum names
648+
_init_to_enum = {
649+
"MIDPOINT": "OPFLOWINIT_MIDPOINT",
650+
"FROMFILE": "OPFLOWINIT_FROMFILE",
651+
"ACPF": "OPFLOWINIT_ACPF",
652+
"FLATSTART": "OPFLOWINIT_FLATSTART",
653+
"DCOPF": "OPFLOWINIT_DCOPF",
654+
}
655+
# Map UI output format names to Python API constants
656+
_fmt_to_enum = {
657+
"MATPOWER": "exago.MATPOWER",
658+
"JSON": "exago.JSON",
659+
"CSV": "exago.CSV",
660+
}
661+
662+
# ── Build environment comment block from config ──────────────────────
663+
env_cfg = cfg.get("environment", {}) or {}
664+
env_comment_lines = [
665+
"#!/usr/bin/env python3",
666+
"# ExaGO Python API Script",
667+
"# Generated by ExaGO Launcher",
668+
"#",
669+
"# Required environment variables (set these before running):",
670+
]
671+
py_paths = env_cfg.get("pythonpath", []) or []
672+
if py_paths:
673+
env_comment_lines.append(f"# export PYTHONPATH={':'.join(py_paths)}:$PYTHONPATH")
674+
ld_paths = env_cfg.get("ld_library_path", []) or []
675+
if ld_paths:
676+
env_comment_lines.append(f"# export LD_LIBRARY_PATH={':'.join(ld_paths)}:$LD_LIBRARY_PATH")
677+
bin_paths = env_cfg.get("path", []) or []
678+
if bin_paths:
679+
env_comment_lines.append(f"# export PATH={':'.join(bin_paths)}:$PATH")
680+
681+
# ── Common preamble ──────────────────────────────────────────────────
682+
lines = env_comment_lines + [
683+
"",
648684
"import exago",
649685
"",
686+
f'# Initialize ExaGO (sets up PETSc/MPI)',
687+
f'exago.initialize("{py_app.lower()}")',
688+
"",
650689
]
651690

691+
# ── Body lines (filled per application, finalize appended after) ─────
692+
body = []
693+
652694
if py_app == "OPFLOW":
653-
lines += [
695+
body += [
654696
"# Create OPFLOW instance",
655697
"opf = exago.OPFLOW()",
656698
"",
657699
f'opf.read_mat_power_data("{py_netfile}")',
658700
"",
659701
]
660-
# Add model/solver/init from session state
661702
model_val = st.session_state.get("opf_model", "POWER_BALANCE_POLAR")
662703
solver_val = st.session_state.get("opf_solver", "IPOPT")
663704
init_val = st.session_state.get("opf_init", "MIDPOINT")
705+
init_enum = _init_to_enum.get(init_val, f"OPFLOWINIT_{init_val}")
664706

665-
lines.append(f'opf.set_model("{model_val}")')
666-
lines.append(f'opf.set_solver("{solver_val}")')
667-
lines.append(f'opf.set_initialization("{init_val}")')
668-
lines.append("")
707+
body.append(f'opf.set_model("{model_val}")')
708+
body.append(f'opf.set_solver("{solver_val}")')
709+
body.append(f'opf.set_initialization_type("{init_enum}")')
710+
body.append("")
669711

670712
if st.session_state.get("opf_ignore_lf"):
671-
lines.append("opf.set_ignore_lineflow_constraints(True)")
713+
body.append("opf.set_ignore_lineflow_constraints(True)")
672714
if st.session_state.get("opf_loadloss"):
673-
lines.append("opf.set_include_loadloss_variables(True)")
674-
lines.append(f"opf.set_loadloss_penalty({st.session_state.get('opf_ll_pen', 1000.0)})")
715+
body.append("opf.set_has_loadloss(True)")
716+
body.append(f"opf.set_loadloss_penalty({st.session_state.get('opf_ll_pen', 1000.0)})")
675717
if st.session_state.get("opf_pwrimb"):
676-
lines.append("opf.set_include_powerimbalance_variables(True)")
677-
lines.append(f"opf.set_powerimbalance_penalty({st.session_state.get('opf_pi_pen', 10000.0)})")
718+
body.append("opf.set_has_bus_power_imbalance(True)")
719+
body.append(f"opf.set_bus_power_imbalance_penalty({st.session_state.get('opf_pi_pen', 10000.0)})")
678720

679721
genbus_val = st.session_state.get("opf_genbus", "VARIABLE_WITHIN_BOUNDS")
680-
lines.append(f'opf.set_genbusvoltage("{genbus_val}")')
722+
body.append(f'opf.set_gen_bus_voltage_type("{genbus_val}")')
681723

682724
obj_val = st.session_state.get("opf_obj", "MIN_GEN_COST")
683-
lines.append(f'opf.set_objective("{obj_val}")')
725+
body.append(f'opf.set_objective_type("{obj_val}")')
684726

685727
tol_val = st.session_state.get("opf_tol", 1e-6)
686-
lines.append(f"opf.set_tolerance({tol_val})")
687-
lines.append("")
688-
lines.append("# Solve")
689-
lines.append("opf.solve()")
690-
lines.append("")
691-
lines.append("# Print solution")
728+
body.append(f"opf.set_tolerance({tol_val})")
729+
body.append("")
730+
body.append("# Solve")
731+
body.append("opf.solve()")
732+
body.append("")
692733
if print_output:
693-
lines.append("opf.print_solution()")
734+
body.append("# Print solution")
735+
body.append("opf.print_solution()")
694736
if save_output:
695737
fmt = output_format or "MATPOWER"
696-
lines.append(f'opf.save_solution("{fmt}")')
738+
fmt_enum = _fmt_to_enum.get(fmt, f"exago.{fmt}")
739+
body.append(f"opf.save_solution({fmt_enum})")
697740

698741
elif py_app == "SCOPFLOW":
699-
lines += [
742+
body += [
700743
"# Create SCOPFLOW instance",
701744
"scopf = exago.SCOPFLOW()",
702745
"",
703-
f'scopf.read_mat_power_data("{py_netfile}")',
746+
f'scopf.set_network_data("{py_netfile}")',
704747
"",
705748
]
706749
if st.session_state.get("scop_ctg"):
707-
lines.append(f'scopf.set_contingency_data("{st.session_state["scop_ctg"]}")')
750+
body.append(f'scopf.set_contingency_data("{st.session_state["scop_ctg"]}", exago.ContingencyFileInputFormat.NATIVE)')
708751
nc = st.session_state.get("scop_nc", -1)
709-
lines.append(f"scopf.set_num_contingencies({nc})")
752+
body.append(f"scopf.set_num_contingencies({nc})")
710753
solver_val = st.session_state.get("scop_solver", "IPOPT")
711-
lines.append(f'scopf.set_solver("{solver_val}")')
754+
body.append(f'scopf.set_solver("{solver_val}")')
712755
mode_val = st.session_state.get("scop_mode", "0 - Preventive")
713-
lines.append(f"scopf.set_mode({mode_val[0]})")
714-
lines.append("")
715-
lines.append("scopf.solve()")
756+
body.append(f"scopf.set_mode({mode_val[0]})")
757+
body.append("")
758+
body.append("# Solve")
759+
body.append("scopf.solve()")
716760
if print_output:
717-
lines.append("scopf.print_solution()")
761+
body.append("")
762+
body.append("# Print solution")
763+
body.append("scopf.print_solution(0)")
718764

719765
elif py_app == "SOPFLOW":
720-
lines += [
766+
body += [
721767
"# Create SOPFLOW instance",
722768
"sopf = exago.SOPFLOW()",
723769
"",
724-
f'sopf.read_mat_power_data("{py_netfile}")',
770+
f'sopf.set_network_data("{py_netfile}")',
725771
"",
726772
]
727773
if st.session_state.get("sop_scen"):
728-
lines.append(f'sopf.set_wind_gen_data("{st.session_state["sop_scen"]}")')
774+
body.append(f'sopf.set_scenario_data("{st.session_state["sop_scen"]}", exago.ScenarioFileInputFormat.NATIVE_SINGLEPERIOD, exago.ScenarioUncertaintyType.WIND)')
729775
ns = st.session_state.get("sop_ns", -1)
730-
lines.append(f"sopf.set_num_scenarios({ns})")
776+
body.append(f"sopf.set_num_scenarios({ns})")
731777
if st.session_state.get("sop_ctg"):
732-
lines.append(f'sopf.set_contingency_data("{st.session_state["sop_ctg"]}")')
778+
body.append(f'sopf.set_contingency_data("{st.session_state["sop_ctg"]}", exago.ContingencyFileInputFormat.NATIVE)')
733779
nc = st.session_state.get("sop_nc", -1)
734-
lines.append(f"sopf.set_num_contingencies({nc})")
780+
body.append(f"sopf.set_num_contingencies({nc})")
735781
solver_val = st.session_state.get("sop_solver", "IPOPT")
736-
lines.append(f'sopf.set_solver("{solver_val}")')
737-
lines.append("")
738-
lines.append("sopf.solve()")
782+
body.append(f'sopf.set_solver("{solver_val}")')
783+
body.append("")
784+
body.append("# Solve")
785+
body.append("sopf.solve()")
739786
if print_output:
740-
lines.append("sopf.print_solution()")
787+
body.append("")
788+
body.append("# Print solution")
789+
body.append("sopf.print_solution(0)")
741790

742791
elif py_app == "TCOPFLOW":
743-
lines += [
792+
body += [
744793
"# Create TCOPFLOW instance",
745794
"tcopf = exago.TCOPFLOW()",
746795
"",
747-
f'tcopf.read_mat_power_data("{py_netfile}")',
796+
f'tcopf.set_network_data("{py_netfile}")',
748797
"",
749798
]
750-
if st.session_state.get("tc_lp"):
751-
lines.append(f'tcopf.set_pload_profile("{st.session_state["tc_lp"]}")')
752-
if st.session_state.get("tc_lq"):
753-
lines.append(f'tcopf.set_qload_profile("{st.session_state["tc_lq"]}")')
799+
tc_lp = st.session_state.get("tc_lp")
800+
tc_lq = st.session_state.get("tc_lq")
801+
if tc_lp and tc_lq:
802+
body.append(f'tcopf.set_load_profiles("{tc_lp}", "{tc_lq}")')
754803
dt_val = st.session_state.get("tc_dt", 5.0)
755804
dur_val = st.session_state.get("tc_dur", 0.5)
756-
lines.append(f"tcopf.set_time_step({dt_val})")
757-
lines.append(f"tcopf.set_duration({dur_val})")
758-
lines.append("")
759-
lines.append("tcopf.solve()")
805+
body.append(f"tcopf.set_time_step_and_duration({dt_val}, {dur_val})")
806+
body.append("")
807+
body.append("# Solve")
808+
body.append("tcopf.solve()")
760809
if print_output:
761-
lines.append("tcopf.print_solution()")
762-
763-
elif py_app in ("PFLOW", "DCOPFLOW"):
764-
app_lower = py_app.lower()
765-
lines += [
766-
f"# Create {py_app} instance",
767-
f"pf = exago.{py_app}()",
810+
body.append("")
811+
body.append("# Print solution")
812+
body.append("tcopf.print_solution(0)")
813+
814+
elif py_app == "PFLOW":
815+
body += [
816+
"# Create PFLOW instance",
817+
"pf = exago.PFLOW()",
768818
"",
769819
f'pf.read_mat_power_data("{py_netfile}")',
770820
"",
821+
"# Solve",
771822
"pf.solve()",
772823
]
773824
if print_output:
774-
lines.append("pf.print_solution()")
825+
body.append("")
826+
body.append("# Print solution")
827+
body.append("pf.print_solution()")
828+
829+
elif py_app == "DCOPFLOW":
830+
# DCOPFLOW has no Python bindings — skip init/finalize wrapper
831+
lines = [
832+
"# NOTE: DCOPFLOW does not have Python API bindings.",
833+
"# Use the command-line interface instead (see Command Preview in the Run Simulation tab).",
834+
]
835+
body = []
836+
837+
# Assemble: preamble + body + finalize
838+
if body:
839+
lines += body
840+
lines += [
841+
"",
842+
"# Clean up",
843+
"try:",
844+
" exago.finalize()",
845+
"except Exception:",
846+
" pass # MPI finalization may throw during cleanup; results are valid",
847+
]
775848

776849
python_code = "\n".join(lines)
777850
st.code(python_code, language="python")

0 commit comments

Comments
 (0)