diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index c2bbaae99..18e21de8e 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -28,8 +28,10 @@
-
+
+
+
@@ -70,7 +72,7 @@
@@ -145,41 +147,57 @@
"Python tests.Nosetests in deep_copy_test.py.executor": "Run",
"Python tests.Nosetests in test_topology_processor.py.executor": "Run",
"Python tests.Nosetests in tests.executor": "Run",
+ "Python tests.pytest for src.tests.test_cgmes_ieeee.executor": "Run",
"Python tests.pytest for src.tests.test_cgmes_ieeee.test_ieee_grids.executor": "Debug",
- "Python tests.pytest for src.tests.test_derivatives.test_tau_derivatives.executor": "Debug",
- "Python tests.pytest for src.tests.test_generator_q_control.executor": "Debug",
+ "Python tests.pytest for src.tests.test_cgmes_to_gridcal_ac_transformers.test_ac_transformers3w.executor": "Debug",
+ "Python tests.pytest for src.tests.test_load_all_grids.test_all_grids.executor": "Run",
+ "Python tests.pytest for src.tests.test_load_save_load.test_load_save_load.executor": "Run",
+ "Python tests.pytest for src.tests.test_power_flow.executor": "Run",
+ "Python tests.pytest for src.tests.test_power_flow.test_controllable_shunt.executor": "Run",
+ "Python tests.pytest for src.tests.test_tutorials.test_define_grid_from_scratch_with_profiles.executor": "Debug",
"Python tests.pytest for test_cgmes_ieeee.test_ieee_grids.executor": "Run",
- "Python tests.pytest for test_generator_q_control.test_q_control_true.executor": "Run",
- "Python tests.pytest for test_power_flow.test_voltage_remote_control_with_generation.executor": "Run",
- "Python tests.pytest for test_raw_roundtrip.test_rawx_roundtrip.executor": "Run",
- "Python tests.pytest for test_sparse2.test_expand.executor": "Run",
- "Python tests.pytest for test_sparse2.test_sp_slice.executor": "Run",
- "Python tests.pytest for test_sparse2.test_spsolve.executor": "Debug",
- "Python tests.pytest for test_sparse2.test_stack_4.executor": "Run",
+ "Python tests.pytest for test_demo_5_node.test_demo_5_node.executor": "Run",
+ "Python tests.pytest for test_derivatives.test_bus_derivatives.executor": "Run",
+ "Python tests.pytest for test_nodal_capacity.test_linear_vs_nonlinear_ncap.executor": "Run",
+ "Python tests.pytest for test_power_flow.test_fubm.executor": "Run",
+ "Python tests.pytest for test_power_flow.test_power_flow_control_with_pst.executor": "Debug",
+ "Python tests.pytest for test_power_flow.test_power_flow_control_with_pst_pt.executor": "Run",
+ "Python tests.pytest for test_power_flow.test_qf_control_with_ltc.executor": "Run",
+ "Python tests.pytest for test_power_flow.test_qt_control_with_ltc.executor": "Debug",
+ "Python tests.pytest for test_power_flow.test_voltage_control_with_ltc.executor": "Run",
+ "Python tests.pytest for test_power_flow.test_voltage_local_control_with_generation.executor": "Debug",
+ "Python tests.pytest for test_power_flow.test_voltage_remote_control_with_generation.executor": "Debug",
+ "Python tests.pytest for test_sparse2.test_mat_mat_mult.executor": "Run",
"Python tests.pytest for test_topology_processor.test_topology_4_nodes_A.executor": "Debug",
"Python tests.pytest for test_topology_processor.test_topology_4_nodes_B.executor": "Debug",
+ "Python tests.pytest for test_transformer_controls.test_v_control_true.executor": "Debug",
"Python tests.pytest in test_cgmes_ieeee.py.executor": "Run",
- "Python tests.pytest in test_derivatives.py.executor": "Run",
+ "Python tests.pytest in test_deep_copy.py.executor": "Run",
+ "Python tests.pytest in test_load_save_load.py.executor": "Debug",
"Python tests.pytest in test_power_flow.py.executor": "Run",
- "Python tests.pytest in test_sparse2.py.executor": "Run",
+ "Python tests.pytest in test_profiles.py.executor": "Run",
"Python tests.pytest in test_topology_processor.py.executor": "Run",
+ "Python tests.pytest in test_transformer_controls.py.executor": "Run",
"Python tests.pytest in tests.executor": "Run",
"Python.AnalysisDialogue.executor": "Run",
"Python.ExecuteGridCal.executor": "Run",
+ "Python.GridCalMain.executor": "Run",
"Python.cgmes_rdfs_graph.executor": "Run",
- "Python.multi_select.executor": "Run",
+ "Python.download_stats.executor": "Run",
+ "Python.fubm_example.executor": "Run",
+ "Python.generate_ssl_key.executor": "Run",
+ "Python.make.executor": "Run",
"Python.new_circuit_objects.executor": "Run",
"Python.pymoo_example.executor": "Debug",
"Python.raw_imp_exp_test.executor": "Run",
- "Python.tallr_table_headers.executor": "Run",
- "Python.test_derivatives.executor": "Run",
+ "Python.run.executor": "Run",
"Python.update_gui_file.executor": "Run",
"Python.upload_to_pypi.executor": "Run",
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"WebServerToolWindowFactoryState": "false",
"git-widget-placeholder": "199__finalize__cgmes__import",
- "last_opened_file_path": "/home/santi/Documentos/Git/GitHub/GridCal/src/tests",
+ "last_opened_file_path": "/home/santi/Documentos/Git/GitHub/GridCal/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods",
"node.js.detected.package.eslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
@@ -197,21 +215,21 @@
-
-
+
+
+
+
+
+
-
-
-
-
-
+
@@ -478,7 +496,7 @@
-
+
@@ -487,12 +505,12 @@
-
+
-
+
@@ -501,7 +519,7 @@
-
+
@@ -510,35 +528,12 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -665,6 +660,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -684,19 +697,19 @@
-
-
-
+
+
+
-
-
+
+
-
+
@@ -1439,16 +1452,25 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
1656059954202
@@ -1793,7 +1815,7 @@
1698766404661
-
+
@@ -1807,6 +1829,7 @@
+
@@ -1839,32 +1862,32 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2233,12 +2256,12 @@
- file://$PROJECT_DIR$/src/tests/deep_copy_test.py
+ file://$PROJECT_DIR$/src/tests/test_deep_copy.py
58
- file://$PROJECT_DIR$/src/tests/deep_copy_test.py
+ file://$PROJECT_DIR$/src/tests/test_deep_copy.py
50
@@ -2252,16 +2275,21 @@
63
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_driver.py
+ 369
+
+
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_driver.py
+ 373
+
+
file://$PROJECT_DIR$/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/line_editor.py
210
-
- file://$PROJECT_DIR$/src/GridCalEngine/Devices/Branches/line.py
- 268
-
-
file://$PROJECT_DIR$/src/GridCalEngine/Devices/Branches/sequence_line_type.py
86
@@ -2288,75 +2316,163 @@
- file://$PROJECT_DIR$/src/GridCal/Gui/Diagrams/MapWidget/Tiles/tiles.py
- 166
-
+ file://$PROJECT_DIR$/src/trunk/qt_related/se_editor.py
+ 81
+
- file://$PROJECT_DIR$/src/GridCal/Gui/Diagrams/MapWidget/Tiles/tiles.py
- 173
-
+ file://$PROJECT_DIR$/src/GridCal/Gui/Diagrams/SchematicWidget/schematic_widget.py
+ 3485
+
- file://$PROJECT_DIR$/src/GridCal/Gui/Diagrams/MapWidget/Tiles/tiles.py
- 176
-
+
+ file://$PROJECT_DIR$/src/tests/test_generator_q_control.py
+ 30
+
- file://$PROJECT_DIR$/src/trunk/qt_related/se_editor.py
- 81
-
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/ContinuationPowerFlow/continuation_power_flow.py
+ 342
+
- file://$PROJECT_DIR$/src/GridCal/Gui/Diagrams/SchematicWidget/schematic_widget.py
- 3505
-
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/Derivatives/acdc_jacobian.py
+ 932
+
- file://$PROJECT_DIR$/src/GridCal/Gui/Main/SubClasses/io.py
- 157
-
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Devices/sparse_array.py
+ 45
+
- file://$PROJECT_DIR$/src/GridCal/Gui/Main/SubClasses/io.py
- 453
-
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/Derivatives/acdc_jacobian.py
+ 988
+
- file://$PROJECT_DIR$/src/GridCal/Gui/Diagrams/SchematicWidget/schematic_widget.py
- 1096
-
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/Derivatives/acdc_jacobian.py
+ 998
+
- file://$PROJECT_DIR$/src/trunk/acdc_pf/ieee9_Kriti.py
- 81
-
+ file://$PROJECT_DIR$/src/GridCalEngine/Utils/NumericalMethods/newton_raphson.py
+ 107
+
- file://$PROJECT_DIR$/src/GridCalEngine/IO/gridcal/pack_unpack.py
- 1152
-
+ file://$PROJECT_DIR$/src/GridCalEngine/Utils/NumericalMethods/newton_raphson.py
+ 98
+
- file://$PROJECT_DIR$/src/GridCalEngine/IO/gridcal/pack_unpack.py
- 1166
-
+ file://$PROJECT_DIR$/src/trunk/acopf/acopf_admittance_tap_derivation.py
+ 299
+
+
+
+ file://$PROJECT_DIR$/src/trunk/acopf/acopf_admittance_tap_derivation.py
+ 289
+
- file://$PROJECT_DIR$/src/GridCalEngine/IO/gridcal/pack_unpack.py
- 1180
-
+ file://$PROJECT_DIR$/src/trunk/acopf/acopf_admittance_tap_derivation.py
+ 288
+
+
+
+ file://$PROJECT_DIR$/src/trunk/acopf/acopf_admittance_tap_derivation.py
+ 255
+
+
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Devices/Parents/branch_parent.py
+ 123
+
+
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Devices/Parents/branch_parent.py
+ 128
+
+
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Devices/Parents/branch_parent.py
+ 133
+
+
+
+ file://$PROJECT_DIR$/src/tests/test_sparse2.py
+ 180
+
+
+
+ file://$PROJECT_DIR$/src/tests/test_sparse2.py
+ 178
+
+
+
+
+ file://$PROJECT_DIR$/src/tests/test_power_flow.py
+ 325
+
+
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_driver.py
+ 218
+
+
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_driver.py
+ 226
+
+
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/driver_template.py
+ 201
+
+
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/driver_template.py
+ 205
+
+
+
+ file://$PROJECT_DIR$/src/GridCalEngine/Simulations/driver_template.py
+ 208
+
+
+
+ file://$PROJECT_DIR$/src/GridCal/Gui/Main/SubClasses/simulations.py
+ 2467
+
+
+
+ file://$PROJECT_DIR$/src/GridCal/Gui/Main/SubClasses/simulations.py
+ 284
+
+
+
+ file://$PROJECT_DIR$/src/GridCal/Gui/Main/SubClasses/base_gui.py
+ 547
+
+
+
+ file://$PROJECT_DIR$/src/GridCal/Gui/Main/SubClasses/simulations.py
+ 279
+
-
+
-
+
@@ -2365,18 +2481,19 @@
-
+
-
+
+
-
+
@@ -2394,13 +2511,14 @@
-
+
+
-
+
@@ -2414,7 +2532,7 @@
-
+
@@ -2427,8 +2545,8 @@
-
+
@@ -2436,15 +2554,16 @@
-
-
-
+
+
+
+
@@ -2456,9 +2575,11 @@
+
+
@@ -2483,11 +2604,11 @@
-
-
-
+
+
+
@@ -2497,11 +2618,12 @@
-
+
+
@@ -2521,45 +2643,53 @@
+
-
-
+
+
+
-
+
-
-
+
+
+
+
-
+
+
+
+
+
@@ -2568,21 +2698,22 @@
-
+
-
+
+
-
+
@@ -2592,13 +2723,14 @@
+
-
+
@@ -2606,10 +2738,11 @@
+
-
+
@@ -2620,19 +2753,20 @@
+
-
-
+
+
-
+
@@ -2640,9 +2774,9 @@
-
+
@@ -2655,31 +2789,33 @@
+
-
+
-
+
-
+
+
-
+
@@ -2687,11 +2823,12 @@
-
+
+
-
+
@@ -2701,13 +2838,15 @@
+
+
-
+
@@ -2719,12 +2858,13 @@
+
-
+
@@ -2732,41 +2872,42 @@
-
+
-
+
+
-
+
-
+
-
+
-
+
-
+
\ No newline at end of file
diff --git a/Grids_and_profiles/grids/Controllable_shunt_example.gridcal b/Grids_and_profiles/grids/Controllable_shunt_example.gridcal
new file mode 100644
index 000000000..0c1bbb7c5
Binary files /dev/null and b/Grids_and_profiles/grids/Controllable_shunt_example.gridcal differ
diff --git a/Grids_and_profiles/grids/Illinois 200 Bus.gridcal b/Grids_and_profiles/grids/Illinois 200 Bus.gridcal
index 4f114e013..c21828a0f 100644
Binary files a/Grids_and_profiles/grids/Illinois 200 Bus.gridcal and b/Grids_and_profiles/grids/Illinois 200 Bus.gridcal differ
diff --git a/Grids_and_profiles/grids/fubm_case_57_14_2MTDC_ctrls.gridcal b/Grids_and_profiles/grids/fubm_case_57_14_2MTDC_ctrls.gridcal
index d7ad5f4f3..e1a57de6a 100644
Binary files a/Grids_and_profiles/grids/fubm_case_57_14_2MTDC_ctrls.gridcal and b/Grids_and_profiles/grids/fubm_case_57_14_2MTDC_ctrls.gridcal differ
diff --git a/Grids_and_profiles/grids/simple2.gridcal b/Grids_and_profiles/grids/simple2.gridcal
new file mode 100644
index 000000000..cc015e165
Binary files /dev/null and b/Grids_and_profiles/grids/simple2.gridcal differ
diff --git a/Grids_and_profiles/grids/test.gridcal b/Grids_and_profiles/grids/test.gridcal
new file mode 100644
index 000000000..d45bed737
Binary files /dev/null and b/Grids_and_profiles/grids/test.gridcal differ
diff --git a/doc/conf.py b/doc/conf.py
index 1b067b8d0..d255022ac 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -14,6 +14,7 @@
#
import os
import sys
+
sys.path.insert(0, os.path.abspath('../src'))
sys.path.append("..")
from doc.auto_document_models import write_models_to_rst
@@ -22,15 +23,17 @@
# -- Project information -----------------------------------------------------
project = 'GridCal'
-copyright = '2023, Santiago PeƱate Vera'
+copyright = '2024, Santiago PeƱate Vera'
author = 'Santiago PeƱate Vera'
# The full version, including alpha/beta/rc tags
release = __GridCalEngine_VERSION__
+
def setup(app):
app.add_css_file('style.css')
+
# -- General configuration ---------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
@@ -86,7 +89,6 @@ def setup(app):
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None
-
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
@@ -122,7 +124,6 @@ def setup(app):
# Output file base name for HTML help builder.
htmlhelp_basename = 'GridCaldoc'
-
# -- Options for LaTeX output ------------------------------------------------
fh = open('latex_preamble.tex', 'r+')
@@ -145,7 +146,6 @@ def setup(app):
'preamble': PREAMBLE,
}
-
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
@@ -153,7 +153,6 @@ def setup(app):
(master_doc, 'GridCal.tex', 'GridCal Documentation', 'Santiago Pe\~nate Vera', 'manual'),
]
-
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
@@ -163,7 +162,6 @@ def setup(app):
[author], 1)
]
-
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
@@ -175,7 +173,6 @@ def setup(app):
'Miscellaneous'),
]
-
# -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info.
@@ -193,5 +190,4 @@ def setup(app):
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
-
# -- Extension configuration -------------------------------------------------
diff --git a/doc/index.rst b/doc/index.rst
index 4d5b25214..8a63647d0 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -51,6 +51,7 @@ Contents
rst_source/benchmarks
rst_source/troubleshooting
rst_source/other_data_models
+ rst_source/plugins
rst_source/change_log
rst_source/api/auto/modules
diff --git a/doc/rst_source/other_data_models.rst b/doc/rst_source/other_data_models.rst
index 9fb964e02..e6bc58746 100644
--- a/doc/rst_source/other_data_models.rst
+++ b/doc/rst_source/other_data_models.rst
@@ -4479,6 +4479,7 @@ Battery
opex float e/MWh False Cost of operation. Used in expansion planning. False
build_status enum BuildStatus False Branch build status. Used in expansion planning. False
Cost float e/MWh False Cost of not served energy. Used in OPF. True
+ technologies AssociationsList p.u. False List of technologies False
control_bus Bus False Control bus True
control_cn Connectivity Node False Control connectivity node False
P float MW False Active power True
@@ -4508,6 +4509,8 @@ Battery
RampUp float MW/h False Maximum amount of generation increase per hour. False
RampDown float MW/h False Maximum amount of generation decrease per hour. False
enabled_dispatch bool False Enabled for dispatch? Used in OPF. False
+ emissions AssociationsList t/MWh False List of emissions False
+ fuels AssociationsList t/MWh False List of fuels False
Enom float MWh False Nominal energy capacity. False
max_soc float p.u. False Minimum state of charge. False
min_soc float p.u. False Maximum state of charge. False
@@ -4741,6 +4744,7 @@ Controllable shunt
opex float e/MWh False Cost of operation. Used in expansion planning. False
build_status enum BuildStatus False Branch build status. Used in expansion planning. False
Cost float e/MWh False Cost of not served energy. Used in OPF. True
+ technologies AssociationsList p.u. False List of technologies False
G float MW False Active power True
B float MVAr False Reactive power True
G0 float MW False Zero sequence active power of the impedance component at V=1.0 p.u. True
@@ -4793,6 +4797,7 @@ Current injection
opex float e/MWh False Cost of operation. Used in expansion planning. False
build_status enum BuildStatus False Branch build status. Used in expansion planning. False
Cost float e/MWh False Cost of not served energy. Used in OPF. True
+ technologies AssociationsList p.u. False List of technologies False
Ir float MW False Active power of the current component at V=1.0 p.u. True
Ii float MVAr False Reactive power of the current component at V=1.0 p.u. True
============ ================= ===== ========= ========= ====================================================== =========== =======
@@ -4876,6 +4881,7 @@ External grid
opex float e/MWh False Cost of operation. Used in expansion planning. False
build_status enum BuildStatus False Branch build status. Used in expansion planning. False
Cost float e/MWh False Cost of not served energy. Used in OPF. True
+ technologies AssociationsList p.u. False List of technologies False
P float MW False Active power True
Q float MVAr False Reactive power True
mode enum ExternalGridMode False Operation mode of the external grid (voltage or load) False
@@ -5034,6 +5040,7 @@ Generator
opex float e/MWh False Cost of operation. Used in expansion planning. False
build_status enum BuildStatus False Branch build status. Used in expansion planning. False
Cost float e/MWh False Cost of not served energy. Used in OPF. True
+ technologies AssociationsList p.u. False List of technologies False
control_bus Bus False Control bus True
control_cn Connectivity Node False Control connectivity node False
P float MW False Active power True
@@ -5063,66 +5070,11 @@ Generator
RampUp float MW/h False Maximum amount of generation increase per hour. False
RampDown float MW/h False Maximum amount of generation decrease per hour. False
enabled_dispatch bool False Enabled for dispatch? Used in OPF. False
+ emissions AssociationsList t/MWh False List of emissions False
+ fuels AssociationsList t/MWh False List of fuels False
======================== ================= ====== ========= ========= ========================================================================== =========== =======
-Generator Emission
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. table::
-
- ========= =============== ===== ========= ========= ====================================================== =========== =======
- name class_type unit mandatory max_chars descriptions has_profile comment
- ========= =============== ===== ========= ========= ====================================================== =========== =======
- idtag str False Unique ID False
- name str False Name of the device. False
- code str False Secondary ID False
- action enum ActionType False Object action to perform. Only used for model merging. False
- comment str False User comment False
- generator Generator False Generator False
- emission Emission False Emission False
- rate float t/MWh False Emissions rate of the gas in the generator (t/MWh) False
- ========= =============== ===== ========= ========= ====================================================== =========== =======
-
-
-Generator Fuel
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. table::
-
- ========= =============== ===== ========= ========= ====================================================== =========== =======
- name class_type unit mandatory max_chars descriptions has_profile comment
- ========= =============== ===== ========= ========= ====================================================== =========== =======
- idtag str False Unique ID False
- name str False Name of the device. False
- code str False Secondary ID False
- action enum ActionType False Object action to perform. Only used for model merging. False
- comment str False User comment False
- generator Generator False Generator False
- fuel Fuel False Fuel False
- rate float t/MWh False Fuel consumption rate in the generator False
- ========= =============== ===== ========= ========= ====================================================== =========== =======
-
-
-Generator Technology
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. table::
-
- ========== =============== ==== ========= ========= ====================================================== =========== =======
- name class_type unit mandatory max_chars descriptions has_profile comment
- ========== =============== ==== ========= ========= ====================================================== =========== =======
- idtag str False Unique ID False
- name str False Name of the device. False
- code str False Secondary ID False
- action enum ActionType False Object action to perform. Only used for model merging. False
- comment str False User comment False
- generator Generator False Generator object False
- technology Technology False Technology object False
- proportion float p.u. False Share of the generator associated to the technology False
- ========== =============== ==== ========= ========= ====================================================== =========== =======
-
-
HVDC Line
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -5183,8 +5135,8 @@ Investment
action enum ActionType False Object action to perform. Only used for model merging. False
comment str False User comment False
device_idtag str False Unique ID False
- CAPEX float Me False Capital expenditures. This is the initial investment. False
- OPEX float Me False Operation expenditures. Maintenance costs among other recurrent costs. False
+ CAPEX float Mā¬ False Capital expenditures. This is the initial investment. False
+ OPEX float Mā¬ False Operation expenditures. Maintenance costs among other recurrent costs. False
status bool False If true the investment activates when applied, otherwise is deactivated. False
group Investments Group False Investment group False
============ ================= ==== ========= ========= ======================================================================== =========== =======
@@ -5212,50 +5164,53 @@ Line
.. table::
- ======================== ================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
- name class_type unit mandatory max_chars descriptions has_profile comment
- ======================== ================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
- idtag str False Unique ID False
- name str False Name of the device. False
- code str False Secondary ID False
- action enum ActionType False Object action to perform. Only used for model merging. False
- comment str False User comment False
- bus_from Bus False Name of the bus at the "from" side False
- bus_to Bus False Name of the bus at the "to" side False
- cn_from Connectivity Node False Name of the connectivity node at the "from" side False
- cn_to Connectivity Node False Name of the connectivity node at the "to" side False
- active bool False Is active? True
- rate float MVA False Thermal rating power True
- contingency_factor float p.u. False Rating multiplier for contingencies True
- protection_rating_factor float p.u. False Rating multiplier that indicates the maximum flow before the protections tripping True
- monitor_loading bool False Monitor this device loading for OPF, NTC or contingency studies. False
- mttf float h False Mean time to failure False
- mttr float h False Mean time to repair False
- Cost float e/MWh False Cost of overloads. Used in OPF True
- build_status enum BuildStatus False Branch build status. Used in expansion planning. False
- capex float e/MW False Cost of investment. Used in expansion planning. False
- opex float e/MWh False Cost of operation. Used in expansion planning. False
- group Branch group False Group where this branch belongs False
- R float p.u. False Total positive sequence resistance. False
- X float p.u. False Total positive sequence reactance. False
- B float p.u. False Total positive sequence shunt susceptance. False
- R0 float p.u. False Total zero sequence resistance. False
- X0 float p.u. False Total zero sequence reactance. False
- B0 float p.u. False Total zero sequence shunt susceptance. False
- R2 float p.u. False Total negative sequence resistance. False
- X2 float p.u. False Total negative sequence reactance. False
- B2 float p.u. False Total negative sequence shunt susceptance. False
- tolerance float % False Tolerance expected for the impedance values % is expected for transformers0% for lines. False
- length float km False Length of the line (not used for calculation) False
- temp_base float ĀŗC False Base temperature at which R was measured. False
- temp_oper float ĀŗC False Operation temperature to modify R. True
- alpha float 1/ĀŗC False Thermal coefficient to modify R,around a reference temperatureusing a linear approximation.For example:Copper @ 20ĀŗC: 0.004041,Copper @ 75ĀŗC: 0.00323,Annealed copper @ 20ĀŗC: 0.00393,Aluminum @ 20ĀŗC: 0.004308,Aluminum @ 75ĀŗC: 0.00330 False
- r_fault float p.u. False Resistance of the mid-line fault.Used in short circuit studies. False
- x_fault float p.u. False Reactance of the mid-line fault.Used in short circuit studies. False
- fault_pos float p.u. False Per-unit positioning of the fault:0 would be at the "from" side,1 would be at the "to" side,therefore 0.5 is at the middle. False
- template Sequence line False False
- locations Line locations False False
- ======================== ================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ =============================== ================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ name class_type unit mandatory max_chars descriptions has_profile comment
+ =============================== ================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ idtag str False Unique ID False
+ name str False Name of the device. False
+ code str False Secondary ID False
+ action enum ActionType False Object action to perform. Only used for model merging. False
+ comment str False User comment False
+ bus_from Bus False Name of the bus at the "from" side False
+ bus_to Bus False Name of the bus at the "to" side False
+ cn_from Connectivity Node False Name of the connectivity node at the "from" side False
+ cn_to Connectivity Node False Name of the connectivity node at the "to" side False
+ active bool False Is active? True
+ rate float MVA False Thermal rating power True
+ contingency_factor float p.u. False Rating multiplier for contingencies True
+ protection_rating_factor float p.u. False Rating multiplier that indicates the maximum flow before the protections tripping True
+ monitor_loading bool False Monitor this device loading for OPF, NTC or contingency studies. False
+ mttf float h False Mean time to failure False
+ mttr float h False Mean time to repair False
+ Cost float e/MWh False Cost of overloads. Used in OPF True
+ build_status enum BuildStatus False Branch build status. Used in expansion planning. False
+ capex float e/MW False Cost of investment. Used in expansion planning. False
+ opex float e/MWh False Cost of operation. Used in expansion planning. False
+ group Branch group False Group where this branch belongs False
+ R float p.u. False Total positive sequence resistance. False
+ X float p.u. False Total positive sequence reactance. False
+ B float p.u. False Total positive sequence shunt susceptance. False
+ R0 float p.u. False Total zero sequence resistance. False
+ X0 float p.u. False Total zero sequence reactance. False
+ B0 float p.u. False Total zero sequence shunt susceptance. False
+ R2 float p.u. False Total negative sequence resistance. False
+ X2 float p.u. False Total negative sequence reactance. False
+ B2 float p.u. False Total negative sequence shunt susceptance. False
+ tolerance float % False Tolerance expected for the impedance values % is expected for transformers0% for lines. False
+ length float km False Length of the line (not used for calculation) False
+ temp_base float ĀŗC False Base temperature at which R was measured. False
+ temp_oper float ĀŗC False Operation temperature to modify R. True
+ alpha float 1/ĀŗC False Thermal coefficient to modify R,around a reference temperatureusing a linear approximation.For example:Copper @ 20ĀŗC: 0.004041,Copper @ 75ĀŗC: 0.00323,Annealed copper @ 20ĀŗC: 0.00393,Aluminum @ 20ĀŗC: 0.004308,Aluminum @ 75ĀŗC: 0.00330 False
+ r_fault float p.u. False Resistance of the mid-line fault.Used in short circuit studies. False
+ x_fault float p.u. False Reactance of the mid-line fault.Used in short circuit studies. False
+ fault_pos float p.u. False Per-unit positioning of the fault:0 would be at the "from" side,1 would be at the "to" side,therefore 0.5 is at the middle. False
+ template Sequence line False False
+ locations Line locations False False
+ possible_tower_types AssociationsList False Possible overhead line types (>1 to denote association), - to denote no association False
+ possible_underground_line_types AssociationsList False Possible underground line types (>1 to denote association), - to denote no association False
+ possible_sequence_line_types AssociationsList False Possible sequence line types (>1 to denote association), - to denote no association False
+ =============================== ================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
Load
@@ -5280,6 +5235,7 @@ Load
opex float e/MWh False Cost of operation. Used in expansion planning. False
build_status enum BuildStatus False Branch build status. Used in expansion planning. False
Cost float e/MWh False Cost of not served energy. Used in OPF. True
+ technologies AssociationsList p.u. False List of technologies False
P float MW False Active power True
Q float MVAr False Reactive power True
Ir float MW False Active power of the current component at V=1.0 p.u. True
@@ -5434,6 +5390,7 @@ Shunt
opex float e/MWh False Cost of operation. Used in expansion planning. False
build_status enum BuildStatus False Branch build status. Used in expansion planning. False
Cost float e/MWh False Cost of not served energy. Used in OPF. True
+ technologies AssociationsList p.u. False List of technologies False
G float MW False Active power True
B float MVAr False Reactive power True
G0 float MW False Zero sequence active power of the impedance component at V=1.0 p.u. True
@@ -5463,6 +5420,7 @@ Static Generator
opex float e/MWh False Cost of operation. Used in expansion planning. False
build_status enum BuildStatus False Branch build status. Used in expansion planning. False
Cost float e/MWh False Cost of not served energy. Used in OPF. True
+ technologies AssociationsList p.u. False List of technologies False
P float MW False Active power True
Q float MVAr False Reactive power True
============ ================= ===== ========= ========= ====================================================== =========== =======
@@ -5585,71 +5543,71 @@ Transformer
.. table::
- ======================== =========================== ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
- name class_type unit mandatory max_chars descriptions has_profile comment
- ======================== =========================== ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
- idtag str False Unique ID False
- name str False Name of the device. False
- code str False Secondary ID False
- action enum ActionType False Object action to perform. Only used for model merging. False
- comment str False User comment False
- bus_from Bus False Name of the bus at the "from" side False
- bus_to Bus False Name of the bus at the "to" side False
- cn_from Connectivity Node False Name of the connectivity node at the "from" side False
- cn_to Connectivity Node False Name of the connectivity node at the "to" side False
- active bool False Is active? True
- rate float MVA False Thermal rating power True
- contingency_factor float p.u. False Rating multiplier for contingencies True
- protection_rating_factor float p.u. False Rating multiplier that indicates the maximum flow before the protections tripping True
- monitor_loading bool False Monitor this device loading for OPF, NTC or contingency studies. False
- mttf float h False Mean time to failure False
- mttr float h False Mean time to repair False
- Cost float e/MWh False Cost of overloads. Used in OPF True
- build_status enum BuildStatus False Branch build status. Used in expansion planning. False
- capex float e/MW False Cost of investment. Used in expansion planning. False
- opex float e/MWh False Cost of operation. Used in expansion planning. False
- group Branch group False Group where this branch belongs False
- R float p.u. False Total positive sequence resistance. False
- X float p.u. False Total positive sequence reactance. False
- G float p.u. False Total positive sequence shunt conductance. False
- B float p.u. False Total positive sequence shunt susceptance. False
- R0 float p.u. False Total zero sequence resistance. False
- X0 float p.u. False Total zero sequence reactance. False
- G0 float p.u. False Total zero sequence shunt conductance. False
- B0 float p.u. False Total zero sequence shunt susceptance. False
- R2 float p.u. False Total negative sequence resistance. False
- X2 float p.u. False Total negative sequence reactance. False
- G2 float p.u. False Total negative sequence shunt conductance. False
- B2 float p.u. False Total negative sequence shunt susceptance. False
- tolerance float % False Tolerance expected for the impedance values% is expected for transformers0% for lines. False
- tap_changer Tap changer False Tap changer object False
- tap_module float False Tap changer module, it a value close to 1.0 True
- tap_module_max float False Tap changer module max value False
- tap_module_min float False Tap changer module min value False
- tap_phase float rad False Angle shift of the tap changer. True
- tap_phase_max float rad False Max angle. False
- tap_phase_min float rad False Min angle. False
- control_mode enum TransformerControlType False Control type of the transformer False
- tap_module_control_mode enum TapModuleControl False Control available with the tap module False
- tap_angle_control_mode enum TapAngleControl False Control available with the tap angle False
- vset float p.u. False Objective voltage at the "to" side of the bus when regulating the tap. False
- Pset float p.u. False Objective power at the "from" side of when regulating the angle. False
- regulation_branch Branch False Branch where the controls are applied. False
- regulation_bus Bus False Bus where the regulation is applied. False
- regulation_cn Connectivity Node False Connectivity node where the regulation is applied. False
- temp_base float ĀŗC False Base temperature at which R was measured. False
- temp_oper float ĀŗC False Operation temperature to modify R. True
- alpha float 1/ĀŗC False Thermal coefficient to modify R,around a reference temperatureusing a linear approximation.For example:Copper @ 20ĀŗC: 0.004041,Copper @ 75ĀŗC: 0.00323,Annealed copper @ 20ĀŗC: 0.00393,Aluminum @ 20ĀŗC: 0.004308,Aluminum @ 75ĀŗC: 0.00330 False
- HV float kV False High voltage rating False
- LV float kV False Low voltage rating False
- Sn float MVA False Nominal power False
- Pcu float kW False Copper losses (optional) False
- Pfe float kW False Iron losses (optional) False
- I0 float % False No-load current (optional) False
- Vsc float % False Short-circuit voltage (optional) False
- conn enum WindingsConnection False Windings connection (from, to):G: grounded starS: ungrounded starD: delta False
- template Transformer type False False
- ======================== =========================== ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ ========================== ======================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ name class_type unit mandatory max_chars descriptions has_profile comment
+ ========================== ======================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ idtag str False Unique ID False
+ name str False Name of the device. False
+ code str False Secondary ID False
+ action enum ActionType False Object action to perform. Only used for model merging. False
+ comment str False User comment False
+ bus_from Bus False Name of the bus at the "from" side False
+ bus_to Bus False Name of the bus at the "to" side False
+ cn_from Connectivity Node False Name of the connectivity node at the "from" side False
+ cn_to Connectivity Node False Name of the connectivity node at the "to" side False
+ active bool False Is active? True
+ rate float MVA False Thermal rating power True
+ contingency_factor float p.u. False Rating multiplier for contingencies True
+ protection_rating_factor float p.u. False Rating multiplier that indicates the maximum flow before the protections tripping True
+ monitor_loading bool False Monitor this device loading for OPF, NTC or contingency studies. False
+ mttf float h False Mean time to failure False
+ mttr float h False Mean time to repair False
+ Cost float e/MWh False Cost of overloads. Used in OPF True
+ build_status enum BuildStatus False Branch build status. Used in expansion planning. False
+ capex float e/MW False Cost of investment. Used in expansion planning. False
+ opex float e/MWh False Cost of operation. Used in expansion planning. False
+ group Branch group False Group where this branch belongs False
+ R float p.u. False Total positive sequence resistance. False
+ X float p.u. False Total positive sequence reactance. False
+ G float p.u. False Total positive sequence shunt conductance. False
+ B float p.u. False Total positive sequence shunt susceptance. False
+ R0 float p.u. False Total zero sequence resistance. False
+ X0 float p.u. False Total zero sequence reactance. False
+ G0 float p.u. False Total zero sequence shunt conductance. False
+ B0 float p.u. False Total zero sequence shunt susceptance. False
+ R2 float p.u. False Total negative sequence resistance. False
+ X2 float p.u. False Total negative sequence reactance. False
+ G2 float p.u. False Total negative sequence shunt conductance. False
+ B2 float p.u. False Total negative sequence shunt susceptance. False
+ tolerance float % False Tolerance expected for the impedance values% is expected for transformers0% for lines. False
+ tap_changer Tap changer False Tap changer object False
+ tap_module float False Tap changer module, it a value close to 1.0 True
+ tap_module_max float False Tap changer module max value False
+ tap_module_min float False Tap changer module min value False
+ tap_module_control_mode enum TapModuleControl False Control available with the tap module True
+ vset float p.u. False Objective voltage at the "to" side of the bus when regulating the tap. True
+ Qset float p.u. False Objective power at the selected side. True
+ regulation_bus Bus False Bus where the regulation is applied. False
+ regulation_cn Connectivity Node False Connectivity node where the regulation is applied. False
+ tap_phase float rad False Angle shift of the tap changer. True
+ tap_phase_max float rad False Max angle. False
+ tap_phase_min float rad False Min angle. False
+ tap_phase_control_mode enum TapPhaseControl False Control available with the tap angle True
+ Pset float p.u. False Objective power at the selected side. True
+ temp_base float ĀŗC False Base temperature at which R was measured. False
+ temp_oper float ĀŗC False Operation temperature to modify R. True
+ alpha float 1/ĀŗC False Thermal coefficient to modify R,around a reference temperatureusing a linear approximation.For example:Copper @ 20ĀŗC: 0.004041,Copper @ 75ĀŗC: 0.00323,Annealed copper @ 20ĀŗC: 0.00393,Aluminum @ 20ĀŗC: 0.004308,Aluminum @ 75ĀŗC: 0.00330 False
+ HV float kV False High voltage rating False
+ LV float kV False Low voltage rating False
+ Sn float MVA False Nominal power False
+ Pcu float kW False Copper losses (optional) False
+ Pfe float kW False Iron losses (optional) False
+ I0 float % False No-load current (optional) False
+ Vsc float % False Short-circuit voltage (optional) False
+ conn enum WindingsConnection False Windings connection (from, to):G: grounded starS: ungrounded starD: delta False
+ template Transformer type False False
+ possible_transformer_types AssociationsList False Possible transformer types (>1 to denote association), - to denote no association False
+ ========================== ======================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
Transformer type
@@ -5657,22 +5615,31 @@ Transformer type
.. table::
- ======= =============== ==== ========= ========= ====================================================== =========== =======
- name class_type unit mandatory max_chars descriptions has_profile comment
- ======= =============== ==== ========= ========= ====================================================== =========== =======
- idtag str False Unique ID False
- name str False Name of the device. False
- code str False Secondary ID False
- action enum ActionType False Object action to perform. Only used for model merging. False
- comment str False User comment False
- HV float kV False Nominal voltage al the high voltage side False
- LV float kV False Nominal voltage al the low voltage side False
- Sn float MVA False Nominal power False
- Pcu float kW False Copper losses False
- Pfe float kW False Iron losses False
- I0 float % False No-load current False
- Vsc float % False Short-circuit voltage False
- ======= =============== ==== ========= ========= ====================================================== =========== =======
+ ================ ==================== ==== ========= ========= ====================================================== =========== =======
+ name class_type unit mandatory max_chars descriptions has_profile comment
+ ================ ==================== ==== ========= ========= ====================================================== =========== =======
+ idtag str False Unique ID False
+ name str False Name of the device. False
+ code str False Secondary ID False
+ action enum ActionType False Object action to perform. Only used for model merging. False
+ comment str False User comment False
+ HV float kV False Nominal voltage al the high voltage side False
+ LV float kV False Nominal voltage al the low voltage side False
+ Sn float MVA False Nominal power False
+ Pcu float kW False Copper losses False
+ Pfe float kW False Iron losses False
+ I0 float % False No-load current False
+ Vsc float % False Short-circuit voltage False
+ tc_type enum TapChangerTypes False Regulation type False
+ total_positions int False Number of tap positions False
+ dV float p.u. False Voltage increment per step False
+ neutral_position int False neutral poition couting from zero False
+ asymmetry_angle float deg False Asymmetry_angle False
+ tap_module_min float p.u. False Min tap module False
+ tap_module_max float p.u. False Max tap module False
+ tap_phase_min float rad False Min tap phase False
+ tap_phase_max float rad False Max tap phase False
+ ================ ==================== ==== ========= ========= ====================================================== =========== =======
Transformer3W
@@ -5789,57 +5756,70 @@ VSC
.. table::
- ======================== ========================= ========= ========= ========= ================================================================================= =========== =======
- name class_type unit mandatory max_chars descriptions has_profile comment
- ======================== ========================= ========= ========= ========= ================================================================================= =========== =======
- idtag str False Unique ID False
- name str False Name of the device. False
- code str False Secondary ID False
- action enum ActionType False Object action to perform. Only used for model merging. False
- comment str False User comment False
- bus_from Bus False Name of the bus at the "from" side False
- bus_to Bus False Name of the bus at the "to" side False
- cn_from Connectivity Node False Name of the connectivity node at the "from" side False
- cn_to Connectivity Node False Name of the connectivity node at the "to" side False
- active bool False Is active? True
- rate float MVA False Thermal rating power True
- contingency_factor float p.u. False Rating multiplier for contingencies True
- protection_rating_factor float p.u. False Rating multiplier that indicates the maximum flow before the protections tripping True
- monitor_loading bool False Monitor this device loading for OPF, NTC or contingency studies. False
- mttf float h False Mean time to failure False
- mttr float h False Mean time to repair False
- Cost float e/MWh False Cost of overloads. Used in OPF True
- build_status enum BuildStatus False Branch build status. Used in expansion planning. False
- capex float e/MW False Cost of investment. Used in expansion planning. False
- opex float e/MWh False Cost of operation. Used in expansion planning. False
- group Branch group False Group where this branch belongs False
- R float p.u. False Resistive positive sequence losses. False
- X float p.u. False Magnetic positive sequence losses. False
- R0 float p.u. False Resistive zero sequence losses. False
- X0 float p.u. False Magnetic zero sequence losses. False
- R2 float p.u. False Resistive negative sequence losses. False
- X2 float p.u. False Magnetic negative sequence losses. False
- G0sw float p.u. False Inverter losses. False
- Beq float p.u. False Total shunt susceptance. False
- Beq_max float p.u. False Max total shunt susceptance. False
- Beq_min float p.u. False Min total shunt susceptance. False
- tap_module float False Tap changer module, it a value close to 1.0 False
- tap_module_max float False Max tap changer module False
- tap_module_min float False Min tap changer module False
- tap_phase float rad False Converter firing angle. False
- tap_phase_max float rad False Max converter firing angle. False
- tap_phase_min float rad False Min converter firing angle. False
- alpha1 float False Converter losses curve parameter (IEC 62751-2 loss Correction). False
- alpha2 float False Converter losses curve parameter (IEC 62751-2 loss Correction). False
- alpha3 float False Converter losses curve parameter (IEC 62751-2 loss Correction). False
- k float p.u./p.u. False Converter factor, typically 0.866. False
- control_mode enum ConverterControlType False Converter control mode False
- kdp float p.u./p.u. False Droop Power/Voltage slope. False
- Pdc_set float MW False DC power set point. False
- Qac_set float MVAr False AC Reactive power set point. False
- Vac_set float p.u. False AC voltage set point. False
- Vdc_set float p.u. False DC voltage set point. False
- ======================== ========================= ========= ========= ========= ================================================================================= =========== =======
+ ======================== ===================== ========= ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ name class_type unit mandatory max_chars descriptions has_profile comment
+ ======================== ===================== ========= ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ idtag str False Unique ID False
+ name str False Name of the device. False
+ code str False Secondary ID False
+ action enum ActionType False Object action to perform. Only used for model merging. False
+ comment str False User comment False
+ bus_from Bus False Name of the bus at the "from" side False
+ bus_to Bus False Name of the bus at the "to" side False
+ cn_from Connectivity Node False Name of the connectivity node at the "from" side False
+ cn_to Connectivity Node False Name of the connectivity node at the "to" side False
+ active bool False Is active? True
+ rate float MVA False Thermal rating power True
+ contingency_factor float p.u. False Rating multiplier for contingencies True
+ protection_rating_factor float p.u. False Rating multiplier that indicates the maximum flow before the protections tripping True
+ monitor_loading bool False Monitor this device loading for OPF, NTC or contingency studies. False
+ mttf float h False Mean time to failure False
+ mttr float h False Mean time to repair False
+ Cost float e/MWh False Cost of overloads. Used in OPF True
+ build_status enum BuildStatus False Branch build status. Used in expansion planning. False
+ capex float e/MW False Cost of investment. Used in expansion planning. False
+ opex float e/MWh False Cost of operation. Used in expansion planning. False
+ group Branch group False Group where this branch belongs False
+ R float p.u. False Total positive sequence resistance. False
+ X float p.u. False Total positive sequence reactance. False
+ G float p.u. False Total positive sequence shunt conductance. False
+ B float p.u. False Total positive sequence shunt susceptance. False
+ R0 float p.u. False Total zero sequence resistance. False
+ X0 float p.u. False Total zero sequence reactance. False
+ G0 float p.u. False Total zero sequence shunt conductance. False
+ B0 float p.u. False Total zero sequence shunt susceptance. False
+ R2 float p.u. False Total negative sequence resistance. False
+ X2 float p.u. False Total negative sequence reactance. False
+ G2 float p.u. False Total negative sequence shunt conductance. False
+ B2 float p.u. False Total negative sequence shunt susceptance. False
+ tolerance float % False Tolerance expected for the impedance values% is expected for transformers0% for lines. False
+ tap_changer Tap changer False Tap changer object False
+ tap_module float False Tap changer module, it a value close to 1.0 True
+ tap_module_max float False Tap changer module max value False
+ tap_module_min float False Tap changer module min value False
+ tap_module_control_mode enum TapModuleControl False Control available with the tap module True
+ vset float p.u. False Objective voltage at the "to" side of the bus when regulating the tap. True
+ Qset float p.u. False Objective power at the selected side. True
+ regulation_bus Bus False Bus where the regulation is applied. False
+ regulation_cn Connectivity Node False Connectivity node where the regulation is applied. False
+ tap_phase float rad False Angle shift of the tap changer. True
+ tap_phase_max float rad False Max angle. False
+ tap_phase_min float rad False Min angle. False
+ tap_phase_control_mode enum TapPhaseControl False Control available with the tap angle True
+ Pset float p.u. False Objective power at the selected side. True
+ temp_base float ĀŗC False Base temperature at which R was measured. False
+ temp_oper float ĀŗC False Operation temperature to modify R. True
+ alpha float 1/ĀŗC False Thermal coefficient to modify R,around a reference temperatureusing a linear approximation.For example:Copper @ 20ĀŗC: 0.004041,Copper @ 75ĀŗC: 0.00323,Annealed copper @ 20ĀŗC: 0.00393,Aluminum @ 20ĀŗC: 0.004308,Aluminum @ 75ĀŗC: 0.00330 False
+ G0sw float p.u. False Inverter losses. False
+ Beq float p.u. False Total shunt susceptance. False
+ Beq_max float p.u. False Max total shunt susceptance. False
+ Beq_min float p.u. False Min total shunt susceptance. False
+ alpha1 float False Losses constant parameter (IEC 62751-2 loss Correction). False
+ alpha2 float False Losses linear parameter (IEC 62751-2 loss Correction). False
+ alpha3 float False Losses quadratic parameter (IEC 62751-2 loss Correction). False
+ k float p.u./p.u. False Converter factor, typically 0.866. False
+ kdp float p.u./p.u. False Droop Power/Voltage slope. False
+ ======================== ===================== ========= ========= ========= ======================================================================================================================================================================================================================================== =========== =======
Voltage level
@@ -5865,71 +5845,71 @@ Winding
.. table::
- ======================== =========================== ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
- name class_type unit mandatory max_chars descriptions has_profile comment
- ======================== =========================== ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
- idtag str False Unique ID False
- name str False Name of the device. False
- code str False Secondary ID False
- action enum ActionType False Object action to perform. Only used for model merging. False
- comment str False User comment False
- bus_from Bus False Name of the bus at the "from" side False
- bus_to Bus False Name of the bus at the "to" side False
- cn_from Connectivity Node False Name of the connectivity node at the "from" side False
- cn_to Connectivity Node False Name of the connectivity node at the "to" side False
- active bool False Is active? True
- rate float MVA False Thermal rating power True
- contingency_factor float p.u. False Rating multiplier for contingencies True
- protection_rating_factor float p.u. False Rating multiplier that indicates the maximum flow before the protections tripping True
- monitor_loading bool False Monitor this device loading for OPF, NTC or contingency studies. False
- mttf float h False Mean time to failure False
- mttr float h False Mean time to repair False
- Cost float e/MWh False Cost of overloads. Used in OPF True
- build_status enum BuildStatus False Branch build status. Used in expansion planning. False
- capex float e/MW False Cost of investment. Used in expansion planning. False
- opex float e/MWh False Cost of operation. Used in expansion planning. False
- group Branch group False Group where this branch belongs False
- R float p.u. False Total positive sequence resistance. False
- X float p.u. False Total positive sequence reactance. False
- G float p.u. False Total positive sequence shunt conductance. False
- B float p.u. False Total positive sequence shunt susceptance. False
- R0 float p.u. False Total zero sequence resistance. False
- X0 float p.u. False Total zero sequence reactance. False
- G0 float p.u. False Total zero sequence shunt conductance. False
- B0 float p.u. False Total zero sequence shunt susceptance. False
- R2 float p.u. False Total negative sequence resistance. False
- X2 float p.u. False Total negative sequence reactance. False
- G2 float p.u. False Total negative sequence shunt conductance. False
- B2 float p.u. False Total negative sequence shunt susceptance. False
- tolerance float % False Tolerance expected for the impedance values% is expected for transformers0% for lines. False
- tap_changer Tap changer False Tap changer object False
- tap_module float False Tap changer module, it a value close to 1.0 True
- tap_module_max float False Tap changer module max value False
- tap_module_min float False Tap changer module min value False
- tap_phase float rad False Angle shift of the tap changer. True
- tap_phase_max float rad False Max angle. False
- tap_phase_min float rad False Min angle. False
- control_mode enum TransformerControlType False Control type of the transformer False
- tap_module_control_mode enum TapModuleControl False Control available with the tap module False
- tap_angle_control_mode enum TapAngleControl False Control available with the tap angle False
- vset float p.u. False Objective voltage at the "to" side of the bus when regulating the tap. False
- Pset float p.u. False Objective power at the "from" side of when regulating the angle. False
- regulation_branch Branch False Branch where the controls are applied. False
- regulation_bus Bus False Bus where the regulation is applied. False
- regulation_cn Connectivity Node False Connectivity node where the regulation is applied. False
- temp_base float ĀŗC False Base temperature at which R was measured. False
- temp_oper float ĀŗC False Operation temperature to modify R. True
- alpha float 1/ĀŗC False Thermal coefficient to modify R,around a reference temperatureusing a linear approximation.For example:Copper @ 20ĀŗC: 0.004041,Copper @ 75ĀŗC: 0.00323,Annealed copper @ 20ĀŗC: 0.00393,Aluminum @ 20ĀŗC: 0.004308,Aluminum @ 75ĀŗC: 0.00330 False
- HV float kV False High voltage rating False
- LV float kV False Low voltage rating False
- Sn float MVA False Nominal power False
- Pcu float kW False Copper losses (optional) False
- Pfe float kW False Iron losses (optional) False
- I0 float % False No-load current (optional) False
- Vsc float % False Short-circuit voltage (optional) False
- conn enum WindingsConnection False Windings connection (from, to):G: grounded starS: ungrounded starD: delta False
- template Transformer type False False
- ======================== =========================== ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ ========================== ======================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ name class_type unit mandatory max_chars descriptions has_profile comment
+ ========================== ======================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
+ idtag str False Unique ID False
+ name str False Name of the device. False
+ code str False Secondary ID False
+ action enum ActionType False Object action to perform. Only used for model merging. False
+ comment str False User comment False
+ bus_from Bus False Name of the bus at the "from" side False
+ bus_to Bus False Name of the bus at the "to" side False
+ cn_from Connectivity Node False Name of the connectivity node at the "from" side False
+ cn_to Connectivity Node False Name of the connectivity node at the "to" side False
+ active bool False Is active? True
+ rate float MVA False Thermal rating power True
+ contingency_factor float p.u. False Rating multiplier for contingencies True
+ protection_rating_factor float p.u. False Rating multiplier that indicates the maximum flow before the protections tripping True
+ monitor_loading bool False Monitor this device loading for OPF, NTC or contingency studies. False
+ mttf float h False Mean time to failure False
+ mttr float h False Mean time to repair False
+ Cost float e/MWh False Cost of overloads. Used in OPF True
+ build_status enum BuildStatus False Branch build status. Used in expansion planning. False
+ capex float e/MW False Cost of investment. Used in expansion planning. False
+ opex float e/MWh False Cost of operation. Used in expansion planning. False
+ group Branch group False Group where this branch belongs False
+ R float p.u. False Total positive sequence resistance. False
+ X float p.u. False Total positive sequence reactance. False
+ G float p.u. False Total positive sequence shunt conductance. False
+ B float p.u. False Total positive sequence shunt susceptance. False
+ R0 float p.u. False Total zero sequence resistance. False
+ X0 float p.u. False Total zero sequence reactance. False
+ G0 float p.u. False Total zero sequence shunt conductance. False
+ B0 float p.u. False Total zero sequence shunt susceptance. False
+ R2 float p.u. False Total negative sequence resistance. False
+ X2 float p.u. False Total negative sequence reactance. False
+ G2 float p.u. False Total negative sequence shunt conductance. False
+ B2 float p.u. False Total negative sequence shunt susceptance. False
+ tolerance float % False Tolerance expected for the impedance values% is expected for transformers0% for lines. False
+ tap_changer Tap changer False Tap changer object False
+ tap_module float False Tap changer module, it a value close to 1.0 True
+ tap_module_max float False Tap changer module max value False
+ tap_module_min float False Tap changer module min value False
+ tap_module_control_mode enum TapModuleControl False Control available with the tap module True
+ vset float p.u. False Objective voltage at the "to" side of the bus when regulating the tap. True
+ Qset float p.u. False Objective power at the selected side. True
+ regulation_bus Bus False Bus where the regulation is applied. False
+ regulation_cn Connectivity Node False Connectivity node where the regulation is applied. False
+ tap_phase float rad False Angle shift of the tap changer. True
+ tap_phase_max float rad False Max angle. False
+ tap_phase_min float rad False Min angle. False
+ tap_phase_control_mode enum TapPhaseControl False Control available with the tap angle True
+ Pset float p.u. False Objective power at the selected side. True
+ temp_base float ĀŗC False Base temperature at which R was measured. False
+ temp_oper float ĀŗC False Operation temperature to modify R. True
+ alpha float 1/ĀŗC False Thermal coefficient to modify R,around a reference temperatureusing a linear approximation.For example:Copper @ 20ĀŗC: 0.004041,Copper @ 75ĀŗC: 0.00323,Annealed copper @ 20ĀŗC: 0.00393,Aluminum @ 20ĀŗC: 0.004308,Aluminum @ 75ĀŗC: 0.00330 False
+ HV float kV False High voltage rating False
+ LV float kV False Low voltage rating False
+ Sn float MVA False Nominal power False
+ Pcu float kW False Copper losses (optional) False
+ Pfe float kW False Iron losses (optional) False
+ I0 float % False No-load current (optional) False
+ Vsc float % False Short-circuit voltage (optional) False
+ conn enum WindingsConnection False Windings connection (from, to):G: grounded starS: ungrounded starD: delta False
+ template Transformer type False False
+ possible_transformer_types AssociationsList False Possible transformer types (>1 to denote association), - to denote no association False
+ ========================== ======================= ===== ========= ========= ======================================================================================================================================================================================================================================== =========== =======
Wire
@@ -5945,10 +5925,13 @@ Wire
code str False Secondary ID False
action enum ActionType False Object action to perform. Only used for model merging. False
comment str False User comment False
- r float Ohm/km False resistance of the conductor False
- x float Ohm/km False reactance of the conductor False
- gmr float m False Geometric Mean Radius of the conductor False
+ R float Ohm/km False resistance of the conductor False
+ X float Ohm/km False reactance of the conductor False
+ GMR float m False Geometric Mean Radius of the conductor False
max_current float kA False Maximum current of the conductor False
+ stranding str False Stranding of wire False
+ material str False Material of wire False
+ diameter float cm False Diameter of wire False
=========== =============== ====== ========= ========= ====================================================== =========== =======
diff --git a/doc/rst_source/plugins.rst b/doc/rst_source/plugins.rst
new file mode 100644
index 000000000..57a23db86
--- /dev/null
+++ b/doc/rst_source/plugins.rst
@@ -0,0 +1,69 @@
+Plugins
+===========
+
+You can write your own Plugin for GridCal, and it will create an entry in the plugins menu with
+your custom icon if you desire so.
+
+First navigate to the GridCal user folder. If you don't know where that is, type `user_folder()`
+on GridCal's scripting console. Usually it is located in a folder called `.GridCal` on your user folder.
+
+Inside the `.GridCal` folder you will find a folder called `plugins`. We will create some files in there to
+declare our plugin. The files are:
+
+- `plugins.json`: This is the plugins index. It is a JSON file where you add your plugin information and should exist there for you.
+- `plugin1.py`: This is where you write your plugin.
+- `icon1.svg`: This is your icon to display in the plugins drop-down menu. You can create it with a design program such as InkScape.
+
+The content of `plugins.json` is:
+
+.. code-block:: json
+
+ [
+ {
+ "name": "my_plugin1",
+ "path": "plugin1.py",
+ "function_name": "main",
+ "icon_path": "icon1.svg"
+ },
+ {
+ "name": "my_plugin2",
+ "path": "plugin2.py",
+ "function_name": "main",
+ "icon_path": "icon2.svg"
+ }
+ ]
+
+The four parameters that we must specify are:
+
+- `name`: Name of the plugin to be displayed and referred to by GridCal.
+- `path`: Path of the plugin file relative to the base folder `.GridCal/plugins`.
+- `function_name`: Name of the entry point function inside the plugin file.
+- `icon_path`: Path of the SVG icon that you want to use. you can leave the field blank and GridCal will use an internal icon.
+
+Of course, we can add more entries for more plugins, following the JSON format.
+
+The content of `plugin1.py` is:
+
+.. code-block:: python
+
+ from GridCal.Gui.Main.GridCalMain import MainGUI
+
+
+ def main(gui_instance: MainGUI):
+ """
+ Initial plugin function
+ :param gui_instance: Instance of the GridCal GUI object
+ """
+ print("Hello from plugin1!")
+
+ grid = gui_instance.circuit
+
+ for bus in grid.buses:
+ print(bus.name)
+
+
+
+This is a very simple example. However the function that you set as the starting point of your plugin must accept only
+one argument of type `MainGUI`. See the function `main` in the code above. This is because GridCal will pass "itself"
+into the plugin so that you can aquire total control and access to do whatever you want to do from the plugin.
+Of course, with great power comes great responsability.
\ No newline at end of file
diff --git a/doc/rst_source/theory/opf/nodal_cap_ex.rst b/doc/rst_source/theory/opf/nodal_cap_ex.rst
index 5c21bc708..6032abde3 100644
--- a/doc/rst_source/theory/opf/nodal_cap_ex.rst
+++ b/doc/rst_source/theory/opf/nodal_cap_ex.rst
@@ -1,6 +1,8 @@
Linear example
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
.. code-block:: python
+
"""
IEEE14 example with linear OPF
"""
@@ -21,7 +23,9 @@ Linear example
Non-linear example
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
.. code-block:: python
+
"""
IEEE14 example with non-linear OPF
"""
diff --git a/examples/assocations.py b/examples/assocations.py
new file mode 100644
index 000000000..a859c1a6c
--- /dev/null
+++ b/examples/assocations.py
@@ -0,0 +1,11 @@
+import os
+import GridCalEngine.api as gce
+import pandas as pd
+pd.set_option('display.precision', 2)
+
+folder = os.path.join('..', 'Grids_and_profiles', 'grids')
+fname = os.path.join(folder, 'association_test.gridcal')
+
+main_circuit = gce.open_file(fname)
+
+print()
diff --git a/examples/associations_template.py b/examples/associations_template.py
new file mode 100644
index 000000000..6ada528a6
--- /dev/null
+++ b/examples/associations_template.py
@@ -0,0 +1,15 @@
+import os
+import GridCalEngine.api as gce
+import pandas as pd
+
+folder = os.path.join('..', 'Grids_and_profiles', 'grids')
+fname = os.path.join(folder, 'simple2.gridcal')
+
+main_circuit = gce.open_file(fname)
+
+results = gce.power_flow(main_circuit)
+
+print(main_circuit.name)
+print('Converged:', results.converged, '\nerror:', results.error)
+print(results.get_bus_df())
+print(results.get_branch_df())
diff --git a/examples/helm_run.py b/examples/helm_run.py
index 10ac3d26f..2f872d952 100644
--- a/examples/helm_run.py
+++ b/examples/helm_run.py
@@ -27,8 +27,8 @@
Ysh0=inputs.Ysh,
pq=inputs.pq,
pv=inputs.pv,
- sl=inputs.ref,
- pqpv=inputs.pqpv,
+ vd=inputs.ref,
+ no_slack=inputs.pqpv,
tolerance=1e-6,
max_coefficients=10,
use_pade=False,
diff --git a/examples/try_investment_optimization.py b/examples/try_investment_optimization.py
index e7113526d..d80450121 100644
--- a/examples/try_investment_optimization.py
+++ b/examples/try_investment_optimization.py
@@ -1,5 +1,7 @@
import os
import random
+from typing import Union
+
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
@@ -7,7 +9,7 @@
from GridCalEngine.IO.file_handler import FileOpen
import GridCalEngine.Devices as dev
import GridCalEngine.Simulations as sim
-from GridCalEngine.enumerations import InvestmentEvaluationMethod, ResultTypes
+from GridCalEngine.enumerations import InvestmentEvaluationMethod, ResultTypes, DeviceType
from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
from GridCalEngine.Simulations.PowerFlow.power_flow_worker import multi_island_pf_nc
@@ -40,7 +42,7 @@ def add_investments_to_grid(grid):
grid.add_line(line)
inv_group = dev.InvestmentsGroup(name='Ig' + str(i))
investment = dev.Investment(device_idtag=line.idtag, name='Investment' + str(i), CAPEX=1,
- group=inv_group)
+ group=inv_group) # template=line.possible_tower_types[:]
grid.add_investment(investment)
grid.add_investments_group(inv_group)
diff --git a/examples/try_template_loading.py b/examples/try_template_loading.py
new file mode 100644
index 000000000..8590b396c
--- /dev/null
+++ b/examples/try_template_loading.py
@@ -0,0 +1,61 @@
+import os
+import GridCalEngine.api as gce
+import GridCalEngine.Devices as dev
+import GridCal.templates as templs
+import GridCalEngine.Topology.topology as tp
+
+
+def open_dummy_grid():
+ # fname = os.path.join('C:/Users/J/Downloads/temp_tr1.gridcal')
+ # fname = os.path.join('C:/Users/J/Downloads/temp_tr1_invested.gridcal')
+ # fname = os.path.join('C:/Users/J/Downloads/temp_tr2.gridcal')
+ fname = os.path.join('C:/Users/J/Downloads/vg1.gridcal')
+ main_circuit = gce.open_file(fname)
+ results = gce.power_flow(main_circuit)
+ print(results.voltage)
+
+ abc = main_circuit.get_branch_active_time_array()
+ # tp.find_different_states(states_array=abc[main_circuit.time_indices])
+
+ return main_circuit
+
+
+def process_dummy_grid():
+ fname = os.path.join('C:/Users/J/Downloads/temp_tr1.gridcal')
+ main_circuit = gce.open_file(fname)
+ results = gce.power_flow(main_circuit)
+ print(results.voltage)
+
+ my_tr = main_circuit.transformers2w[0]
+
+ inv_group = dev.InvestmentsGroup(name='Ig0')
+ investment1 = dev.Investment(name='Investment 1x', group=inv_group, device_idtag=my_tr.idtag)
+ main_circuit.add_investment(investment1)
+ main_circuit.add_investments_group(inv_group)
+ gce.save_file(main_circuit, 'C:/Users/J/Downloads/temp_tr1_invested.gridcal')
+ return None
+
+
+def create_dummy_grid():
+ grid = gce.MultiCircuit()
+
+ bus1 = gce.Bus(name='Bus1', Vnom=20)
+ bus2 = gce.Bus(name='Bus2', Vnom=20)
+ grid.add_bus(bus1)
+ grid.add_bus(bus2)
+ tr1 = gce.Transformer2W(bus_from=bus1, bus_to=bus2)
+ grid.add_transformer2w(tr1)
+
+ grid.transformer_types = templs.get_transformer_catalogue()
+ grid.underground_cable_types = templs.get_cables_catalogue()
+ grid.circuit_wire_types = templs.get_wires_catalogue()
+ grid.sequence_line_types = templs.get_sequence_lines_catalogue()
+
+ return grid
+
+
+if __name__ == "__main__":
+ open_dummy_grid()
+ # pp = process_dummy_grid()
+ # gg = create_dummy_grid()
+
diff --git a/requirements.txt b/requirements.txt
index d884fcea8..3d13bbbd0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -33,6 +33,7 @@ fastapi
starlette
uvicorn
websockets
+cryptography
opencv-python
setuptools
packaging
\ No newline at end of file
diff --git a/src/GridCal/ExecuteGridCal.py b/src/GridCal/ExecuteGridCal.py
index 65bc18e08..f65289067 100644
--- a/src/GridCal/ExecuteGridCal.py
+++ b/src/GridCal/ExecuteGridCal.py
@@ -1,17 +1,19 @@
-# This file is part of GridCal.
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
#
-# GridCal is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
#
-# GridCal is distributed in the hope that it will be useful,
+# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
-# along with GridCal. If not, see .
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os
import sys
import ctypes
diff --git a/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_container.py b/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_container.py
index 597c3007e..1e43d24b3 100644
--- a/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_container.py
+++ b/src/GridCal/Gui/Diagrams/MapWidget/Branches/map_line_container.py
@@ -59,12 +59,12 @@ def __init__(self,
editor=editor,
draw_labels=draw_labels)
- self.editor: GridMapWidget = editor # re assign to make clear the editor type
+ self.editor: GridMapWidget = editor # reassign to make clear the editor type
self.nodes_list: List[NodeGraphicItem] = list()
self.segments_list: List[MapLineSegment] = list()
self.enabled = True
- self.original = True
+ self.original = True # TODO: Que es esto?
def setWidthScale(self, val: float):
"""
diff --git a/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py b/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py
index a6ff4c042..e380e2121 100644
--- a/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py
+++ b/src/GridCal/Gui/Diagrams/MapWidget/Substation/substation_graphic_item.py
@@ -18,8 +18,8 @@
from typing import List, TYPE_CHECKING, Tuple
from PySide6 import QtWidgets
from PySide6.QtWidgets import (QApplication, QMenu, QGraphicsSceneContextMenuEvent, QGraphicsSceneMouseEvent,
- QGraphicsRectItem, QGraphicsEllipseItem)
-from PySide6.QtCore import Qt, QPointF, QPoint
+ QGraphicsRectItem)
+from PySide6.QtCore import Qt, QPointF
from PySide6.QtGui import QBrush, QColor, QCursor
from GridCal.Gui.Diagrams.MapWidget.Substation.node_template import NodeTemplate
from GridCal.Gui.GuiFunctions import add_menu_entry
@@ -88,7 +88,9 @@ def __init__(self,
# self.resize(r)
self.setAcceptHoverEvents(True) # Enable hover events for the item
# self.setFlag(QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIsMovable) # Allow moving the node
- self.setFlag(self.GraphicsItemFlag.ItemIsSelectable) # Allow selecting the node
+ self.setFlag(
+ self.GraphicsItemFlag.ItemIsSelectable | QGraphicsRectItem.ItemIsMovable) # Allow selecting the node
+
self.setCursor(QCursor(Qt.PointingHandCursor))
# Create a pen with reduced line width
@@ -136,26 +138,13 @@ def sort_voltage_levels(self) -> None:
for i, vl_graphics in enumerate(sorted_objects):
vl_graphics.setZValue(i)
- def updatePosition(self) -> None:
- """
-
- :return:
- """
- real_position = self.pos()
- center_point = self.getPos()
- # self.x = center_point.x() + real_position.x()
- # self.y = center_point.y() + real_position.y()
- self.needsUpdate = True
-
- def updateDiagram(self):
+ def update_diagram(self):
"""
-
+ Updates the element position in the diagram (to save)
:return:
"""
lat, long = self.editor.to_lat_lon(self.rect().x(), self.rect().y())
- # print(f'Updating SE position id:{self.api_object.idtag}, lat:{lat}, lon:{long}')
-
self.editor.update_diagram_element(device=self.api_object,
latitude=lat,
longitude=long,
@@ -163,8 +152,8 @@ def updateDiagram(self):
def get_center_pos(self) -> QPointF:
"""
-
- :return:
+ Get the center position
+ :return: QPointF
"""
x = self.rect().x() + self.rect().width() / 2
y = self.rect().y() + self.rect().height() / 2
@@ -186,16 +175,16 @@ def mouseMoveEvent(self, event: QtWidgets.QGraphicsSceneMouseEvent) -> None:
for vl_graphics in self.voltage_level_graphics:
vl_graphics.center_on_substation()
- self.updateDiagram() # always update
+ self.update_diagram() # always update
def mousePressEvent(self, event: QGraphicsSceneMouseEvent):
"""
Event handler for mouse press events.
"""
super().mousePressEvent(event)
- selected_items = self.editor.map.view._scene.selectedItems()
- if len(selected_items) < 2:
- self.setSelected(True)
+ # selected_items = self.editor.map.view.selected_items()
+ # if len(selected_items) < 2:
+ self.setSelected(True)
event.setAccepted(True)
self.editor.map.view.disableMove = True
@@ -211,14 +200,13 @@ def mousePressEvent(self, event: QGraphicsSceneMouseEvent):
DeviceType.ZoneDevice: self.editor.circuit.get_zones(),
})
-
def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent):
"""
Event handler for mouse release events.
"""
# super().mouseReleaseEvent(event)
self.editor.disableMove = True
- self.updateDiagram() # always update
+ self.update_diagram() # always update
print("SE mouse release")
def hoverEnterEvent(self, event: QtWidgets.QGraphicsSceneHoverEvent) -> None:
@@ -252,7 +240,7 @@ def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent):
function_ptr=self.add_voltage_level)
add_menu_entry(menu=menu,
- text="Create line",
+ text="Create line from here",
icon_path="",
function_ptr=self.create_new_line)
@@ -276,15 +264,13 @@ def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent):
icon_path="",
function_ptr=self.new_substation_diagram)
-
-
menu.exec_(event.screenPos())
def create_new_line(self):
"""
Create a new line in the map wizard
"""
- self.editor.createNewLineWizard()
+ self.editor.create_new_line_wizard()
def add_function(self):
"""
@@ -319,7 +305,7 @@ def add_function(self):
pass
- def remove_function(self):
+ def remove_function(self) -> None:
"""
Function to be called when Action 1 is selected.
"""
diff --git a/src/GridCal/Gui/Diagrams/MapWidget/Tiles/tiles.py b/src/GridCal/Gui/Diagrams/MapWidget/Tiles/tiles.py
index 5fb891f6b..8b49904f6 100644
--- a/src/GridCal/Gui/Diagrams/MapWidget/Tiles/tiles.py
+++ b/src/GridCal/Gui/Diagrams/MapWidget/Tiles/tiles.py
@@ -23,6 +23,7 @@
def log(val: str):
print(val)
+
# # set how old disk-cache tiles can be before we re-request them from the
# # server. this is the number of days old a tile is before we re-request.
# # if 'None', never re-request tiles after first satisfied request.
diff --git a/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py b/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py
index 33729b6e6..b66ff77af 100644
--- a/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py
+++ b/src/GridCal/Gui/Diagrams/MapWidget/grid_map_widget.py
@@ -56,6 +56,7 @@
from GridCal.Gui.Diagrams.graphics_manager import ALL_MAP_GRAPHICS
from GridCal.Gui.Diagrams.MapWidget.Tiles.tiles import Tiles
from GridCal.Gui.Diagrams.base_diagram_widget import BaseDiagramWidget
+from GridCal.Gui.messages import error_msg
MAP_BRANCH_GRAPHIC_TYPES = Union[
MapAcLine, MapDcLine, MapHvdcLine, MapFluidPathLine
@@ -457,53 +458,60 @@ def merge_lines(self):
if it1 == it2:
return 0
- newline = Line()
- newline.set_data_from(it1.line_container.api_object)
+ new_line = Line()
+ new_line.set_data_from(it1.line_container.api_object)
# ln1 = self.api_object.copy()
- better_first, better_second, busfrom, busto = compare_options(it1, it2)
+ better_first, better_second, bus_from, bus_to = compare_options(it1, it2)
first_list = better_first.line_container.api_object.locations.data
second_list = better_second.line_container.api_object.locations.data
- newline.locations.data = first_list + second_list
+ new_line.locations.data = first_list + second_list
- newline.bus_from = busfrom
- newline.bus_to = busto
+ new_line.bus_from = bus_from
+ new_line.bus_to = bus_to
idx = 0
for nod in better_first.line_container.nodes_list:
- newline.locations.data[idx].lat = nod.lat
- newline.locations.data[idx].long = nod.lon
+ new_line.locations.data[idx].lat = nod.lat
+ new_line.locations.data[idx].long = nod.lon
idx = idx + 1
for nod in better_second.line_container.nodes_list:
- newline.locations.data[idx].lat = nod.lat
- newline.locations.data[idx].long = nod.lon
+ new_line.locations.data[idx].lat = nod.lat
+ new_line.locations.data[idx].long = nod.lon
idx = idx + 1
- newL = self.add_api_line(newline, original=False)
+ self.add_api_line(new_line, original=False)
+ self.circuit.add_line(new_line)
better_first.line_container.disable_line()
better_second.line_container.disable_line()
- def createNewLineWizard(self):
+ def get_selected_substations(self) -> List[SubstationGraphicItem]:
+ """
+ Get the selected substations graphics
+ :return: List[SubstationGraphicItem]
+ """
+ return [s for s in self.map.view.selected_items() if isinstance(s, SubstationGraphicItem)]
+
+ def create_new_line_wizard(self):
"""
Create a new line in the map with dialogues
"""
- selected_items = self.map.view._scene.selectedItems()
- selectedItems = []
- for item in selected_items:
- selectedItems.append(item)
+ selected_items = self.get_selected_substations()
- if len(selectedItems) < 2:
- return 0
+ if len(selected_items) != 2:
+ error_msg(text="Please select two substations", title="Create new line")
+ return None
- it1: SubstationGraphicItem = selectedItems[0]
- it2: SubstationGraphicItem = selectedItems[1]
+ it1: SubstationGraphicItem = selected_items[0]
+ it2: SubstationGraphicItem = selected_items[1]
if it1 == it2:
+ error_msg(text="Somehow the two substations are the same :(", title="Create new line")
return None
dialog = NewMapLineDialogue(grid=self.circuit, se_from=it1.api_object, se_to=it2.api_object)
@@ -512,8 +520,12 @@ def createNewLineWizard(self):
bus1 = dialog.bus_from()
bus2 = dialog.bus_to()
if bus1 is not None and bus2 is not None:
- newline = Line(bus_from=bus1, bus_to=bus2)
- self.add_api_line(newline, original=True)
+ new_line = Line(bus_from=bus1, bus_to=bus2)
+ self.add_api_line(new_line, original=True)
+ self.circuit.add_line(new_line)
+ else:
+ error_msg(text="Some of the buses was None :(", title="Create new line")
+ return None
def removeNode(self, node: NodeGraphicItem):
"""
@@ -570,8 +582,7 @@ def add_api_line(self, api_object: Line, original: bool = True) -> MapAcLine:
# create the nodes
line_container.draw_all()
- # there is not need to add to the scene
-
+ # there is nt need to add to the scene
return line_container
def add_api_dc_line(self, api_object: DcLine, original: bool = True) -> MapDcLine:
@@ -752,24 +763,16 @@ def draw_diagram(self, diagram: MapDiagram) -> None:
for idtag, graphic_object in dev_dict.items():
graphic_object.sort_voltage_levels()
- def add_object_to_the_schematic(
- self,
- elm: ALL_DEV_TYPES,
- injections_by_bus: Union[None, Dict[Bus, Dict[DeviceType, List[INJECTION_DEVICE_TYPES]]]] = None,
- injections_by_fluid_node: Union[None, Dict[FluidNode, Dict[DeviceType, List[FLUID_TYPES]]]] = None,
- injections_by_cn: Union[None, Dict[Bus, Dict[DeviceType, List[INJECTION_DEVICE_TYPES]]]] = None,
- logger: Logger = Logger()):
+ def add_object_to_the_schematic(self, elm: ALL_DEV_TYPES, logger: Logger = Logger()):
"""
:param elm:
- :param injections_by_bus:
- :param injections_by_fluid_node:
- :param injections_by_cn:
:param logger:
:return:
"""
+ graphic_obj = self.graphics_manager.query(elm=elm)
- if self.graphics_manager.query(elm=elm) is None:
+ if graphic_obj is None:
if isinstance(elm, Substation):
self.add_api_substation(api_object=elm,
@@ -797,31 +800,35 @@ def add_object_to_the_schematic(
lon=substation_graphics.lon,
lat=substation_graphics.lat)
- elif isinstance(elm, FluidNode):
-
- if injections_by_fluid_node is None:
- injections_by_fluid_node = self.circuit.get_injection_devices_grouped_by_fluid_node()
-
- # TODO: maybe new thing?
- self.add_api_fluid_node(node=elm,
- injections_by_tpe=injections_by_fluid_node.get(elm, dict()))
-
elif isinstance(elm, Line):
- self.add_api_line(elm)
+ line_container = self.add_api_line(elm)
+ for segment in line_container.segments_list:
+ self.add_to_scene(graphic_object=segment)
elif isinstance(elm, DcLine):
- self.add_api_dc_line(elm)
+ line_container = self.add_api_dc_line(elm)
+ for segment in line_container.segments_list:
+ self.add_to_scene(graphic_object=segment)
elif isinstance(elm, HvdcLine):
- self.add_api_hvdc_line(elm)
+ line_container = self.add_api_hvdc_line(elm)
+ for segment in line_container.segments_list:
+ self.add_to_scene(graphic_object=segment)
elif isinstance(elm, FluidPath):
- self.add_api_fluid_path(elm)
+ line_container = self.add_api_fluid_path(elm)
+ for segment in line_container.segments_list:
+ self.add_to_scene(graphic_object=segment)
else:
- pass
+ logger.add_warning("Unsupported device class",
+ device_class=elm.device_type.value,
+ device=elm.name)
else:
+
+ self.add_to_scene(graphic_obj)
+
logger.add_warning("Device already added", device_class=elm.device_type.value, device=elm.name)
def dropEvent(self, event: QDropEvent):
@@ -842,7 +849,6 @@ def dropEvent(self, event: QDropEvent):
# print(f"Dropped at x:{x0}, y:{y0}, lat:{lat}, lon:{lon}")
if obj_type == self.library_model.get_substation_mime_data():
-
api_object = Substation(name=f"Substation {self.circuit.get_substation_number()}",
latitude=lat,
longitude=lon)
diff --git a/src/GridCal/Gui/Diagrams/MapWidget/map_widget.py b/src/GridCal/Gui/Diagrams/MapWidget/map_widget.py
index 7b0102064..de52ae816 100644
--- a/src/GridCal/Gui/Diagrams/MapWidget/map_widget.py
+++ b/src/GridCal/Gui/Diagrams/MapWidget/map_widget.py
@@ -30,12 +30,12 @@
from __future__ import annotations
from typing import List, Union, Tuple, Callable, TYPE_CHECKING
from enum import Enum
-from PySide6.QtCore import Qt, QTimer, QEvent, QPointF, QRectF
+from PySide6.QtCore import Qt, QTimer, QEvent, QPointF
from PySide6.QtGui import (QPainter, QColor, QPixmap, QCursor,
QMouseEvent, QKeyEvent, QWheelEvent,
QResizeEvent, QEnterEvent, QPaintEvent, QDragEnterEvent, QDragMoveEvent, QDropEvent)
from PySide6.QtWidgets import (QSizePolicy, QWidget, QGraphicsScene, QGraphicsView, QVBoxLayout,
- QGraphicsSceneMouseEvent)
+ QGraphicsSceneMouseEvent, QGraphicsItem)
from GridCal.Gui.Diagrams.MapWidget.Tiles.tiles import Tiles
@@ -83,7 +83,7 @@ def mouseReleaseEvent(self, event):
:param event:
:return:
"""
- print(f"Scene released at {event.scenePos()}")
+ # print(f"Scene released at {event.scenePos()}")
super().mouseReleaseEvent(event)
def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
@@ -134,6 +134,13 @@ def __init__(self,
self.scale(initial_zoom_factor, initial_zoom_factor)
+ def selected_items(self) -> List[QGraphicsItem]:
+ """
+ Get the selected items
+ :return:
+ """
+ return self._scene.selectedItems()
+
def mousePressEvent(self, event: QMouseEvent):
"""
@@ -489,7 +496,7 @@ def tile_src(self, tile_src: Tiles):
while abs(self.view.schema_zoom - 0.015625) > 0.00001:
self.view.schema_zoom = self.view.schema_zoom / self.view.map_widget.zoom_factor
self.view.scale(1.0 / self.view.map_widget.zoom_factor, 1.0 / self.view.map_widget.zoom_factor)
- self.GotoLevelAndPosition(level=0, longitude=None, latitude=None)
+ self.GotoLevelAndPosition(level=0, longitude=0, latitude=0)
@property
def max_level(self):
@@ -606,6 +613,7 @@ def mousePressEvent(self, event: QMouseEvent) -> None:
elif b == Qt.MouseButton.LeftButton:
self.left_mbutton_down = True
+ self.editor.object_editor_table.setModel(None)
elif b == Qt.MouseButton.MiddleButton:
self.mid_mbutton_down = True
@@ -614,7 +622,8 @@ def mousePressEvent(self, event: QMouseEvent) -> None:
self.right_mbutton_down = True
else:
- print('mousePressEvent: unknown button')
+ pass
+ # print('mousePressEvent: unknown button')
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
"""
@@ -657,7 +666,8 @@ def mouseReleaseEvent(self, event: QMouseEvent) -> None:
self.right_mbutton_down = False
else:
- print('mouseReleaseEvent: unknown button')
+ pass
+ # print('mouseReleaseEvent: unknown button')
def mouseDoubleClickEvent(self, event: QMouseEvent):
"""
@@ -675,7 +685,8 @@ def mouseDoubleClickEvent(self, event: QMouseEvent):
elif b == Qt.RightButton:
pass
else:
- print('mouseDoubleClickEvent: unknown button')
+ pass
+ # print('mouseDoubleClickEvent: unknown button')
def mouseMoveEvent(self, event: QMouseEvent):
"""
@@ -1816,11 +1827,11 @@ def ChangeTileSet(self, tile_src: Tiles):
exist in the new tileset.
"""
- print('ChangeTileSet: tile_src=%s' % str(tile_src))
+ # print('ChangeTileSet: tile_src=%s' % str(tile_src))
# get level and geo position of view centre
level, longitude, latitude = self.get_level_and_position()
- print('level=%s, geo=(%s, %s)' % (str(level), str(longitude), str(latitude)))
+ # print('level=%s, geo=(%s, %s)' % (str(level), str(longitude), str(latitude)))
# remember old tileset
old_tileset = self.tile_src
diff --git a/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/transformer2w_graphics.py b/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/transformer2w_graphics.py
index b35a979f6..07f719108 100644
--- a/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/transformer2w_graphics.py
+++ b/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/transformer2w_graphics.py
@@ -24,7 +24,7 @@
from GridCal.Gui.Diagrams.SchematicWidget.Branches.transformer_editor import TransformerEditor
from GridCal.Gui.Diagrams.SchematicWidget.Branches.transformer_taps_editor import TransformerTapsEditor
from GridCalEngine.Devices.Branches.transformer import Transformer2W, TransformerType
-from GridCalEngine.enumerations import DeviceType
+from GridCalEngine.enumerations import DeviceType, TapModuleControl
if TYPE_CHECKING: # Only imports the below statements during type checking
from GridCal.Gui.Diagrams.SchematicWidget.schematic_widget import SchematicWidget
@@ -107,6 +107,16 @@ def contextMenuEvent(self, event):
function_ptr=self.tap_down,
icon_path=":/Icons/icons/down.svg")
+ add_menu_entry(menu=menu,
+ text="Control V from",
+ function_ptr=self.control_v_from,
+ icon_path=":/Icons/icons/edit.svg")
+
+ add_menu_entry(menu=menu,
+ text="Control V to",
+ function_ptr=self.control_v_to,
+ icon_path=":/Icons/icons/edit.svg")
+
menu.addSeparator()
add_menu_entry(menu=menu,
@@ -240,3 +250,19 @@ def tap_down(self):
Set one tap down
"""
self.api_object.tap_down()
+
+ def control_v_from(self):
+ """
+
+ :return:
+ """
+ self.api_object.regulation_bus = self.api_object.bus_from
+ self.api_object.tap_module_control_mode = TapModuleControl.Vm
+
+ def control_v_to(self):
+ """
+
+ :return:
+ """
+ self.api_object.regulation_bus = self.api_object.bus_to
+ self.api_object.tap_module_control_mode = TapModuleControl.Vm
diff --git a/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/upfc_graphics.py b/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/upfc_graphics.py
index b268f5de8..6ee55efed 100644
--- a/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/upfc_graphics.py
+++ b/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/upfc_graphics.py
@@ -21,6 +21,7 @@
from GridCal.Gui.GuiFunctions import add_menu_entry
from GridCal.Gui.Diagrams.SchematicWidget.terminal_item import BarTerminalItem
from GridCalEngine.Devices.Branches.upfc import UPFC
+from GridCalEngine.enumerations import TapModuleControl
from GridCal.Gui.Diagrams.SchematicWidget.Branches.line_graphics_template import LineGraphicTemplateItem
if TYPE_CHECKING: # Only imports the below statements during type checking
@@ -90,6 +91,18 @@ def contextMenuEvent(self, event):
menu.addSeparator()
+ add_menu_entry(menu=menu,
+ text="Control V from",
+ function_ptr=self.control_v_from,
+ icon_path=":/Icons/icons/edit.svg")
+
+ add_menu_entry(menu=menu,
+ text="Control V to",
+ function_ptr=self.control_v_to,
+ icon_path=":/Icons/icons/edit.svg")
+
+ menu.addSeparator()
+
ra6 = menu.addAction('Plot profiles')
plot_icon = QIcon()
plot_icon.addPixmap(QPixmap(":/Icons/icons/plot.svg"))
@@ -108,7 +121,22 @@ def contextMenuEvent(self, event):
ra5.setIcon(ra5_icon)
ra5.triggered.connect(self.assign_status_to_profile)
-
menu.exec_(event.screenPos())
else:
pass
+
+ def control_v_from(self):
+ """
+
+ :return:
+ """
+ self.api_object.regulation_bus = self.api_object.bus_from
+ self.api_object.tap_module_control_mode = TapModuleControl.Vm
+
+ def control_v_to(self):
+ """
+
+ :return:
+ """
+ self.api_object.regulation_bus = self.api_object.bus_to
+ self.api_object.tap_module_control_mode = TapModuleControl.Vm
diff --git a/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/vsc_graphics.py b/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/vsc_graphics.py
index f572c9f2a..aed61cf4c 100644
--- a/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/vsc_graphics.py
+++ b/src/GridCal/Gui/Diagrams/SchematicWidget/Branches/vsc_graphics.py
@@ -21,6 +21,7 @@
from GridCal.Gui.GuiFunctions import add_menu_entry
from GridCal.Gui.Diagrams.SchematicWidget.terminal_item import BarTerminalItem, RoundTerminalItem
from GridCalEngine.Devices.Branches.vsc import VSC
+from GridCalEngine.enumerations import TapModuleControl
from GridCal.Gui.Diagrams.SchematicWidget.Branches.line_graphics_template import LineGraphicTemplateItem
if TYPE_CHECKING: # Only imports the below statements during type checking
@@ -95,6 +96,18 @@ def contextMenuEvent(self, event):
menu.addSeparator()
+ add_menu_entry(menu=menu,
+ text="Control V from",
+ function_ptr=self.control_v_from,
+ icon_path=":/Icons/icons/edit.svg")
+
+ add_menu_entry(menu=menu,
+ text="Control V to",
+ function_ptr=self.control_v_to,
+ icon_path=":/Icons/icons/edit.svg")
+
+ menu.addSeparator()
+
ra6 = menu.addAction('Plot profiles')
plot_icon = QIcon()
plot_icon.addPixmap(QPixmap(":/Icons/icons/plot.svg"))
@@ -125,3 +138,19 @@ def mouseDoubleClickEvent(self, event):
"""
pass
+
+ def control_v_from(self):
+ """
+
+ :return:
+ """
+ self.api_object.regulation_bus = self.api_object.bus_from
+ self.api_object.tap_module_control_mode = TapModuleControl.Vm
+
+ def control_v_to(self):
+ """
+
+ :return:
+ """
+ self.api_object.regulation_bus = self.api_object.bus_to
+ self.api_object.tap_module_control_mode = TapModuleControl.Vm
diff --git a/src/GridCal/Gui/GuiFunctions.py b/src/GridCal/Gui/GuiFunctions.py
index 298523a96..44aa70a5e 100644
--- a/src/GridCal/Gui/GuiFunctions.py
+++ b/src/GridCal/Gui/GuiFunctions.py
@@ -129,7 +129,7 @@ def __init__(self, parent: QtWidgets.QTableView, objects: List[Any], object_name
self.object_names = object_names
@QtCore.Slot()
- def currentIndexChanged(self):
+ def currentIndexChanged(self) -> None:
"""
currentIndexChanged
"""
@@ -186,7 +186,7 @@ class TextDelegate(QtWidgets.QItemDelegate):
commitData = QtCore.Signal(object)
- def __init__(self, parent):
+ def __init__(self, parent: QtWidgets.QTableView) -> None:
"""
Constructor
:param parent: QTableView parent object
@@ -200,7 +200,9 @@ def returnPressed(self):
"""
self.commitData.emit(self.sender())
- def createEditor(self, parent, option, index):
+ def createEditor(self, parent: QtWidgets.QWidget,
+ option: QtWidgets.QStyleOptionViewItem,
+ index: QtCore.QModelIndex) -> QtWidgets.QLineEdit:
"""
:param parent:
@@ -256,13 +258,15 @@ def __init__(self,
self.decimals = decimals
@QtCore.Slot()
- def returnPressed(self):
+ def returnPressed(self) -> None:
"""
returnPressed
"""
self.commitData.emit(self.sender())
- def createEditor(self, parent, option, index):
+ def createEditor(self, parent: QtWidgets.QWidget,
+ option: QtWidgets.QStyleOptionViewItem,
+ index: QtCore.QModelIndex) -> QtWidgets.QDoubleSpinBox:
"""
:param parent:
@@ -922,29 +926,43 @@ def get_cim_tree_model(cim_model: CgmesCircuit):
def add_menu_entry(menu: QtWidgets.QMenu,
text: str,
icon_path: str = "",
+ icon_pixmap: QtGui.QPixmap = None,
function_ptr=None,
checkeable=False,
- checked_value=False) -> QtGui.QAction:
+ checked_value=False,
+ font_size: int = 9) -> QtGui.QAction:
"""
Add a context menu entry
:param menu:
:param text:
:param icon_path:
+ :param icon_pixmap:
:param function_ptr:
:param checkeable:
:param checked_value:
+ :param font_size:
:return:
"""
- entry = menu.addAction(text)
+ entry: QtGui.QAction = menu.addAction(text)
+
+ font = QtGui.QFont()
+ font.setPointSize(font_size)
+ entry.setFont(font)
if checkeable:
entry.setCheckable(checkeable)
entry.setChecked(checked_value)
- if len(icon_path) > 0:
+ if icon_pixmap is None:
+ if len(icon_path) > 0:
+ edit_icon = QtGui.QIcon()
+ edit_icon.addPixmap(QtGui.QPixmap(icon_path))
+ entry.setIcon(edit_icon)
+ else:
+ # prefer the icon pixmap if provided
edit_icon = QtGui.QIcon()
- edit_icon.addPixmap(QtGui.QPixmap(icon_path))
+ edit_icon.addPixmap(icon_pixmap)
entry.setIcon(edit_icon)
if function_ptr is not None:
diff --git a/src/GridCal/Gui/Main/GridCalMain.py b/src/GridCal/Gui/Main/GridCalMain.py
index 23ed740ce..da34e1425 100644
--- a/src/GridCal/Gui/Main/GridCalMain.py
+++ b/src/GridCal/Gui/Main/GridCalMain.py
@@ -85,7 +85,7 @@ def __init__(self) -> None:
self.load_all_config()
self.add_complete_bus_branch_diagram()
- self.add_map_diagram()
+ self.add_map_diagram(ask=False)
self.set_diagram_widget(self.diagram_widgets_list[0])
def save_all_config(self) -> None:
@@ -101,6 +101,7 @@ def load_all_config(self) -> None:
"""
self.load_gui_config()
self.load_server_config()
+ self.add_plugins()
def closeEvent(self, event: QtGui.QCloseEvent) -> None:
"""
diff --git a/src/GridCal/Gui/Main/MainWindow.py b/src/GridCal/Gui/Main/MainWindow.py
index 43aad3607..91920b261 100644
--- a/src/GridCal/Gui/Main/MainWindow.py
+++ b/src/GridCal/Gui/Main/MainWindow.py
@@ -31,8 +31,11 @@ class Ui_mainWindow(object):
def setupUi(self, mainWindow):
if not mainWindow.objectName():
mainWindow.setObjectName(u"mainWindow")
- mainWindow.resize(1393, 915)
+ mainWindow.resize(1346, 811)
mainWindow.setBaseSize(QSize(0, 0))
+ font = QFont()
+ font.setPointSize(10)
+ mainWindow.setFont(font)
icon = QIcon()
icon.addFile(u":/Program icon/GridCal_icon.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
mainWindow.setWindowIcon(icon)
@@ -48,164 +51,197 @@ def setupUi(self, mainWindow):
icon1 = QIcon()
icon1.addFile(u":/Icons/icons/loadc.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionOpen_file.setIcon(icon1)
+ self.actionOpen_file.setFont(font)
self.actionSave = QAction(mainWindow)
self.actionSave.setObjectName(u"actionSave")
icon2 = QIcon()
icon2.addFile(u":/Icons/icons/savec.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionSave.setIcon(icon2)
+ self.actionSave.setFont(font)
self.actionTakePicture = QAction(mainWindow)
self.actionTakePicture.setObjectName(u"actionTakePicture")
icon3 = QIcon()
icon3.addFile(u":/Icons/icons/picture.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionTakePicture.setIcon(icon3)
+ self.actionTakePicture.setFont(font)
self.actionNew_project = QAction(mainWindow)
self.actionNew_project.setObjectName(u"actionNew_project")
icon4 = QIcon()
icon4.addFile(u":/Icons/icons/new2c.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionNew_project.setIcon(icon4)
+ self.actionNew_project.setFont(font)
self.actionPower_flow = QAction(mainWindow)
self.actionPower_flow.setObjectName(u"actionPower_flow")
icon5 = QIcon()
icon5.addFile(u":/Icons/icons/pf.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionPower_flow.setIcon(icon5)
+ self.actionPower_flow.setFont(font)
self.actionPower_flow.setMenuRole(QAction.TextHeuristicRole)
self.actionPower_Flow_Time_series = QAction(mainWindow)
self.actionPower_Flow_Time_series.setObjectName(u"actionPower_Flow_Time_series")
icon6 = QIcon()
icon6.addFile(u":/Icons/icons/pf_ts.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionPower_Flow_Time_series.setIcon(icon6)
+ self.actionPower_Flow_Time_series.setFont(font)
self.actionBigger_nodes = QAction(mainWindow)
self.actionBigger_nodes.setObjectName(u"actionBigger_nodes")
icon7 = QIcon()
icon7.addFile(u":/Icons/icons/plus (gray).svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionBigger_nodes.setIcon(icon7)
+ self.actionBigger_nodes.setFont(font)
self.actionSmaller_nodes = QAction(mainWindow)
self.actionSmaller_nodes.setObjectName(u"actionSmaller_nodes")
icon8 = QIcon()
icon8.addFile(u":/Icons/icons/minus (gray).svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionSmaller_nodes.setIcon(icon8)
+ self.actionSmaller_nodes.setFont(font)
self.actionPower_flow_Stochastic = QAction(mainWindow)
self.actionPower_flow_Stochastic.setObjectName(u"actionPower_flow_Stochastic")
icon9 = QIcon()
icon9.addFile(u":/Icons/icons/stochastic_pf.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionPower_flow_Stochastic.setIcon(icon9)
+ self.actionPower_flow_Stochastic.setFont(font)
self.actionVoltage_stability = QAction(mainWindow)
self.actionVoltage_stability.setObjectName(u"actionVoltage_stability")
icon10 = QIcon()
icon10.addFile(u":/Icons/icons/continuation_power_flow.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionVoltage_stability.setIcon(icon10)
+ self.actionVoltage_stability.setFont(font)
self.actionAbout = QAction(mainWindow)
self.actionAbout.setObjectName(u"actionAbout")
self.actionAbout.setIcon(icon)
+ self.actionAbout.setFont(font)
self.actionCenter_view = QAction(mainWindow)
self.actionCenter_view.setObjectName(u"actionCenter_view")
icon11 = QIcon()
icon11.addFile(u":/Icons/icons/resize.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionCenter_view.setIcon(icon11)
+ self.actionCenter_view.setFont(font)
self.actionShort_Circuit = QAction(mainWindow)
self.actionShort_Circuit.setObjectName(u"actionShort_Circuit")
icon12 = QIcon()
icon12.addFile(u":/Icons/icons/short_circuit.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionShort_Circuit.setIcon(icon12)
+ self.actionShort_Circuit.setFont(font)
self.actionAutoatic_layout = QAction(mainWindow)
self.actionAutoatic_layout.setObjectName(u"actionAutoatic_layout")
icon13 = QIcon()
icon13.addFile(u":/Icons/icons/automatic_layout.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionAutoatic_layout.setIcon(icon13)
+ self.actionAutoatic_layout.setFont(font)
self.actionBlackout_cascade = QAction(mainWindow)
self.actionBlackout_cascade.setObjectName(u"actionBlackout_cascade")
self.actionBlackout_cascade.setCheckable(True)
icon14 = QIcon()
icon14.addFile(u":/Icons/icons/blackout.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionBlackout_cascade.setIcon(icon14)
+ self.actionBlackout_cascade.setFont(font)
self.actionOPF = QAction(mainWindow)
self.actionOPF.setObjectName(u"actionOPF")
icon15 = QIcon()
icon15.addFile(u":/Icons/icons/dcopf.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionOPF.setIcon(icon15)
+ self.actionOPF.setFont(font)
self.actionOPF_time_series = QAction(mainWindow)
self.actionOPF_time_series.setObjectName(u"actionOPF_time_series")
icon16 = QIcon()
icon16.addFile(u":/Icons/icons/dcopf_ts.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionOPF_time_series.setIcon(icon16)
+ self.actionOPF_time_series.setFont(font)
self.actionDetect_transformers = QAction(mainWindow)
self.actionDetect_transformers.setObjectName(u"actionDetect_transformers")
icon17 = QIcon()
icon17.addFile(u":/Icons/icons/detect_tr.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionDetect_transformers.setIcon(icon17)
+ self.actionDetect_transformers.setFont(font)
self.actionAuto_rate_branches = QAction(mainWindow)
self.actionAuto_rate_branches.setObjectName(u"actionAuto_rate_branches")
icon18 = QIcon()
icon18.addFile(u":/Icons/icons/rate_br.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionAuto_rate_branches.setIcon(icon18)
+ self.actionAuto_rate_branches.setFont(font)
self.actionExport_all_the_device_s_profiles = QAction(mainWindow)
self.actionExport_all_the_device_s_profiles.setObjectName(u"actionExport_all_the_device_s_profiles")
icon19 = QIcon()
icon19.addFile(u":/Icons/icons/save.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionExport_all_the_device_s_profiles.setIcon(icon19)
+ self.actionExport_all_the_device_s_profiles.setFont(font)
self.actionStorage_location_suggestion = QAction(mainWindow)
self.actionStorage_location_suggestion.setObjectName(u"actionStorage_location_suggestion")
self.actionStorage_location_suggestion.setCheckable(True)
icon20 = QIcon()
icon20.addFile(u":/Icons/icons/storage_loc.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionStorage_location_suggestion.setIcon(icon20)
+ self.actionStorage_location_suggestion.setFont(font)
self.actionLaunch_data_analysis_tool = QAction(mainWindow)
self.actionLaunch_data_analysis_tool.setObjectName(u"actionLaunch_data_analysis_tool")
icon21 = QIcon()
icon21.addFile(u":/Icons/icons/inputs_analysis 2.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionLaunch_data_analysis_tool.setIcon(icon21)
+ self.actionLaunch_data_analysis_tool.setFont(font)
self.actionOnline_documentation = QAction(mainWindow)
self.actionOnline_documentation.setObjectName(u"actionOnline_documentation")
icon22 = QIcon()
icon22.addFile(u":/Icons/icons/new.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionOnline_documentation.setIcon(icon22)
+ self.actionOnline_documentation.setFont(font)
self.actionExport_all_results = QAction(mainWindow)
self.actionExport_all_results.setObjectName(u"actionExport_all_results")
icon23 = QIcon()
icon23.addFile(u":/Icons/icons/export_pickle.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionExport_all_results.setIcon(icon23)
+ self.actionExport_all_results.setFont(font)
self.actionSave_as = QAction(mainWindow)
self.actionSave_as.setObjectName(u"actionSave_as")
self.actionSave_as.setIcon(icon19)
+ self.actionSave_as.setFont(font)
self.actionDelete_selected = QAction(mainWindow)
self.actionDelete_selected.setObjectName(u"actionDelete_selected")
icon24 = QIcon()
icon24.addFile(u":/Icons/icons/delete_db.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionDelete_selected.setIcon(icon24)
+ self.actionDelete_selected.setFont(font)
self.actionLinearAnalysis = QAction(mainWindow)
self.actionLinearAnalysis.setObjectName(u"actionLinearAnalysis")
icon25 = QIcon()
icon25.addFile(u":/Icons/icons/ptdf.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionLinearAnalysis.setIcon(icon25)
+ self.actionLinearAnalysis.setFont(font)
self.actionReset_console = QAction(mainWindow)
self.actionReset_console.setObjectName(u"actionReset_console")
icon26 = QIcon()
icon26.addFile(u":/Icons/icons/undo.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionReset_console.setIcon(icon26)
+ self.actionReset_console.setFont(font)
self.actionOpf_to_Power_flow = QAction(mainWindow)
self.actionOpf_to_Power_flow.setObjectName(u"actionOpf_to_Power_flow")
self.actionOpf_to_Power_flow.setCheckable(True)
icon27 = QIcon()
icon27.addFile(u":/Icons/icons/dcopf2ts.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionOpf_to_Power_flow.setIcon(icon27)
+ self.actionOpf_to_Power_flow.setFont(font)
self.actionTry_to_fix_buses_location = QAction(mainWindow)
self.actionTry_to_fix_buses_location.setObjectName(u"actionTry_to_fix_buses_location")
icon28 = QIcon()
icon28.addFile(u":/Icons/icons/move_bus.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionTry_to_fix_buses_location.setIcon(icon28)
+ self.actionTry_to_fix_buses_location.setFont(font)
self.actionSet_OPF_generation_to_profiles = QAction(mainWindow)
self.actionSet_OPF_generation_to_profiles.setObjectName(u"actionSet_OPF_generation_to_profiles")
self.actionSet_OPF_generation_to_profiles.setIcon(icon27)
+ self.actionSet_OPF_generation_to_profiles.setFont(font)
self.actionPTDF_time_series = QAction(mainWindow)
self.actionPTDF_time_series.setObjectName(u"actionPTDF_time_series")
icon29 = QIcon()
icon29.addFile(u":/Icons/icons/ptdf_ts.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionPTDF_time_series.setIcon(icon29)
+ self.actionPTDF_time_series.setFont(font)
self.actionAdd_circuit = QAction(mainWindow)
self.actionAdd_circuit.setObjectName(u"actionAdd_circuit")
icon30 = QIcon()
icon30.addFile(u":/Icons/icons/load_add.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionAdd_circuit.setIcon(icon30)
+ self.actionAdd_circuit.setFont(font)
self.actionSync = QAction(mainWindow)
self.actionSync.setObjectName(u"actionSync")
self.actionSync.setCheckable(True)
@@ -222,25 +258,30 @@ def setupUi(self, mainWindow):
icon33 = QIcon()
icon33.addFile(u":/Icons/icons/sigma.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionSigma_analysis.setIcon(icon33)
+ self.actionSigma_analysis.setFont(font)
self.actionClear_stuff_running_right_now = QAction(mainWindow)
self.actionClear_stuff_running_right_now.setObjectName(u"actionClear_stuff_running_right_now")
icon34 = QIcon()
icon34.addFile(u":/Icons/icons/clear_runs.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionClear_stuff_running_right_now.setIcon(icon34)
+ self.actionClear_stuff_running_right_now.setFont(font)
self.actionAdd_default_catalogue = QAction(mainWindow)
self.actionAdd_default_catalogue.setObjectName(u"actionAdd_default_catalogue")
icon35 = QIcon()
icon35.addFile(u":/Icons/icons/CatalogueAdd.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionAdd_default_catalogue.setIcon(icon35)
+ self.actionAdd_default_catalogue.setFont(font)
self.actionFind_node_groups = QAction(mainWindow)
self.actionFind_node_groups.setObjectName(u"actionFind_node_groups")
self.actionFind_node_groups.setCheckable(True)
icon36 = QIcon()
icon36.addFile(u":/Icons/icons/color_grid2.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionFind_node_groups.setIcon(icon36)
+ self.actionFind_node_groups.setFont(font)
self.actiongrid_Generator = QAction(mainWindow)
self.actiongrid_Generator.setObjectName(u"actiongrid_Generator")
self.actiongrid_Generator.setIcon(icon13)
+ self.actiongrid_Generator.setFont(font)
self.actionImportPlexosNodeLoad = QAction(mainWindow)
self.actionImportPlexosNodeLoad.setObjectName(u"actionImportPlexosNodeLoad")
icon37 = QIcon()
@@ -254,115 +295,140 @@ def setupUi(self, mainWindow):
icon38 = QIcon()
icon38.addFile(u":/Icons/icons/otdf_ts.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionOTDF_time_series.setIcon(icon38)
+ self.actionOTDF_time_series.setFont(font)
self.actionImportPlexosBranchRates = QAction(mainWindow)
self.actionImportPlexosBranchRates.setObjectName(u"actionImportPlexosBranchRates")
self.actionImportPlexosBranchRates.setIcon(icon37)
self.actionSetSelectedBusArea = QAction(mainWindow)
self.actionSetSelectedBusArea.setObjectName(u"actionSetSelectedBusArea")
self.actionSetSelectedBusArea.setIcon(icon32)
+ self.actionSetSelectedBusArea.setFont(font)
self.actionSetSelectedBusZone = QAction(mainWindow)
self.actionSetSelectedBusZone.setObjectName(u"actionSetSelectedBusZone")
self.actionSetSelectedBusZone.setIcon(icon32)
+ self.actionSetSelectedBusZone.setFont(font)
self.actionSetSelectedBusCountry = QAction(mainWindow)
self.actionSetSelectedBusCountry.setObjectName(u"actionSetSelectedBusCountry")
icon39 = QIcon()
icon39.addFile(u":/Icons/icons/map.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionSetSelectedBusCountry.setIcon(icon39)
+ self.actionSetSelectedBusCountry.setFont(font)
self.actionImport_bus_coordinates = QAction(mainWindow)
self.actionImport_bus_coordinates.setObjectName(u"actionImport_bus_coordinates")
self.actionImport_bus_coordinates.setIcon(icon30)
+ self.actionImport_bus_coordinates.setFont(font)
self.actionATC = QAction(mainWindow)
self.actionATC.setObjectName(u"actionATC")
icon40 = QIcon()
icon40.addFile(u":/Icons/icons/atc.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionATC.setIcon(icon40)
+ self.actionATC.setFont(font)
self.actionATC_Time_Series = QAction(mainWindow)
self.actionATC_Time_Series.setObjectName(u"actionATC_Time_Series")
icon41 = QIcon()
icon41.addFile(u":/Icons/icons/atc_ts.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionATC_Time_Series.setIcon(icon41)
+ self.actionATC_Time_Series.setFont(font)
self.actionContingency_analysis = QAction(mainWindow)
self.actionContingency_analysis.setObjectName(u"actionContingency_analysis")
icon42 = QIcon()
icon42.addFile(u":/Icons/icons/otdf.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionContingency_analysis.setIcon(icon42)
+ self.actionContingency_analysis.setFont(font)
self.actionOptimal_Net_Transfer_Capacity = QAction(mainWindow)
self.actionOptimal_Net_Transfer_Capacity.setObjectName(u"actionOptimal_Net_Transfer_Capacity")
icon43 = QIcon()
icon43.addFile(u":/Icons/icons/ntc_opf.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionOptimal_Net_Transfer_Capacity.setIcon(icon43)
+ self.actionOptimal_Net_Transfer_Capacity.setFont(font)
self.actionSet_schematic_positions_from_GPS_coordinates = QAction(mainWindow)
self.actionSet_schematic_positions_from_GPS_coordinates.setObjectName(u"actionSet_schematic_positions_from_GPS_coordinates")
self.actionSet_schematic_positions_from_GPS_coordinates.setIcon(icon39)
+ self.actionSet_schematic_positions_from_GPS_coordinates.setFont(font)
self.actionInputs_analysis = QAction(mainWindow)
self.actionInputs_analysis.setObjectName(u"actionInputs_analysis")
icon44 = QIcon()
icon44.addFile(u":/Icons/icons/stats.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionInputs_analysis.setIcon(icon44)
+ self.actionInputs_analysis.setFont(font)
self.actionFuse_devices = QAction(mainWindow)
self.actionFuse_devices.setObjectName(u"actionFuse_devices")
icon45 = QIcon()
icon45.addFile(u":/Icons/icons/fusion.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionFuse_devices.setIcon(icon45)
+ self.actionFuse_devices.setFont(font)
self.actionDelete_inconsistencies = QAction(mainWindow)
self.actionDelete_inconsistencies.setObjectName(u"actionDelete_inconsistencies")
icon46 = QIcon()
icon46.addFile(u":/Icons/icons/delete.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionDelete_inconsistencies.setIcon(icon46)
+ self.actionDelete_inconsistencies.setFont(font)
self.actionOptimal_Net_Transfer_Capacity_Time_Series = QAction(mainWindow)
self.actionOptimal_Net_Transfer_Capacity_Time_Series.setObjectName(u"actionOptimal_Net_Transfer_Capacity_Time_Series")
icon47 = QIcon()
icon47.addFile(u":/Icons/icons/ntc_opf_ts.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionOptimal_Net_Transfer_Capacity_Time_Series.setIcon(icon47)
+ self.actionOptimal_Net_Transfer_Capacity_Time_Series.setFont(font)
self.actionre_index_time = QAction(mainWindow)
self.actionre_index_time.setObjectName(u"actionre_index_time")
icon48 = QIcon()
icon48.addFile(u":/Icons/icons/data.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionre_index_time.setIcon(icon48)
+ self.actionre_index_time.setFont(font)
self.actionFix_generators_active_based_on_the_power = QAction(mainWindow)
self.actionFix_generators_active_based_on_the_power.setObjectName(u"actionFix_generators_active_based_on_the_power")
icon49 = QIcon()
icon49.addFile(u":/Icons/icons/gear.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionFix_generators_active_based_on_the_power.setIcon(icon49)
+ self.actionFix_generators_active_based_on_the_power.setFont(font)
self.actionFix_loads_active_based_on_the_power = QAction(mainWindow)
self.actionFix_loads_active_based_on_the_power.setObjectName(u"actionFix_loads_active_based_on_the_power")
self.actionFix_loads_active_based_on_the_power.setIcon(icon49)
+ self.actionFix_loads_active_based_on_the_power.setFont(font)
self.actionImport_contingencies = QAction(mainWindow)
self.actionImport_contingencies.setObjectName(u"actionImport_contingencies")
self.actionImport_contingencies.setIcon(icon30)
+ self.actionImport_contingencies.setFont(font)
self.actionInitialize_contingencies = QAction(mainWindow)
self.actionInitialize_contingencies.setObjectName(u"actionInitialize_contingencies")
icon50 = QIcon()
icon50.addFile(u":/Icons/icons/contingency_wizzard.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionInitialize_contingencies.setIcon(icon50)
+ self.actionInitialize_contingencies.setFont(font)
self.actionExport_contingencies = QAction(mainWindow)
self.actionExport_contingencies.setObjectName(u"actionExport_contingencies")
self.actionExport_contingencies.setIcon(icon19)
+ self.actionExport_contingencies.setFont(font)
self.actionAdd_selected_to_contingency = QAction(mainWindow)
self.actionAdd_selected_to_contingency.setObjectName(u"actionAdd_selected_to_contingency")
icon51 = QIcon()
icon51.addFile(u":/Icons/icons/add_contingency.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionAdd_selected_to_contingency.setIcon(icon51)
+ self.actionAdd_selected_to_contingency.setFont(font)
self.actionAdd_selected_as_new_investment = QAction(mainWindow)
self.actionAdd_selected_as_new_investment.setObjectName(u"actionAdd_selected_as_new_investment")
icon52 = QIcon()
icon52.addFile(u":/Icons/icons/investment.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionAdd_selected_as_new_investment.setIcon(icon52)
+ self.actionAdd_selected_as_new_investment.setFont(font)
self.actionZoom_in = QAction(mainWindow)
self.actionZoom_in.setObjectName(u"actionZoom_in")
icon53 = QIcon()
icon53.addFile(u":/Icons/icons/zoom_in.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionZoom_in.setIcon(icon53)
+ self.actionZoom_in.setFont(font)
self.actionZoom_out = QAction(mainWindow)
self.actionZoom_out.setObjectName(u"actionZoom_out")
icon54 = QIcon()
icon54.addFile(u":/Icons/icons/zoom_out.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionZoom_out.setIcon(icon54)
+ self.actionZoom_out.setFont(font)
self.actionClustering = QAction(mainWindow)
self.actionClustering.setObjectName(u"actionClustering")
icon55 = QIcon()
icon55.addFile(u":/Icons/icons/clustering.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionClustering.setIcon(icon55)
+ self.actionClustering.setFont(font)
self.actionClustering.setMenuRole(QAction.NoRole)
self.actionUse_clustering = QAction(mainWindow)
self.actionUse_clustering.setObjectName(u"actionUse_clustering")
@@ -370,24 +436,29 @@ def setupUi(self, mainWindow):
icon56 = QIcon()
icon56.addFile(u":/Icons/icons/clustering_use.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionUse_clustering.setIcon(icon56)
+ self.actionUse_clustering.setFont(font)
self.actionInvestments_evaluation = QAction(mainWindow)
self.actionInvestments_evaluation.setObjectName(u"actionInvestments_evaluation")
icon57 = QIcon()
icon57.addFile(u":/Icons/icons/expansion_planning.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionInvestments_evaluation.setIcon(icon57)
+ self.actionInvestments_evaluation.setFont(font)
self.actionNew_bus_branch_diagram_from_selection = QAction(mainWindow)
self.actionNew_bus_branch_diagram_from_selection.setObjectName(u"actionNew_bus_branch_diagram_from_selection")
icon58 = QIcon()
icon58.addFile(u":/Icons/icons/schematic.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionNew_bus_branch_diagram_from_selection.setIcon(icon58)
+ self.actionNew_bus_branch_diagram_from_selection.setFont(font)
self.actionAdd_general_bus_branch_diagram = QAction(mainWindow)
self.actionAdd_general_bus_branch_diagram.setObjectName(u"actionAdd_general_bus_branch_diagram")
self.actionAdd_general_bus_branch_diagram.setIcon(icon58)
+ self.actionAdd_general_bus_branch_diagram.setFont(font)
self.actionAdd_map = QAction(mainWindow)
self.actionAdd_map.setObjectName(u"actionAdd_map")
icon59 = QIcon()
icon59.addFile(u":/Icons/icons/map (add).svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionAdd_map.setIcon(icon59)
+ self.actionAdd_map.setFont(font)
self.actionRemove_selected_diagram = QAction(mainWindow)
self.actionRemove_selected_diagram.setObjectName(u"actionRemove_selected_diagram")
self.actionRemove_selected_diagram.setIcon(icon8)
@@ -396,89 +467,109 @@ def setupUi(self, mainWindow):
icon60 = QIcon()
icon60.addFile(u":/Icons/icons/bug.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionReport_a_bug.setIcon(icon60)
+ self.actionReport_a_bug.setFont(font)
self.actionSearchDiagram = QAction(mainWindow)
self.actionSearchDiagram.setObjectName(u"actionSearchDiagram")
icon61 = QIcon()
icon61.addFile(u":/Icons/icons/magnifying_glass.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionSearchDiagram.setIcon(icon61)
+ self.actionSearchDiagram.setFont(font)
self.actionProcess_topology = QAction(mainWindow)
self.actionProcess_topology.setObjectName(u"actionProcess_topology")
self.actionProcess_topology.setIcon(icon58)
+ self.actionProcess_topology.setFont(font)
self.actionEdit_simulation_time_limits = QAction(mainWindow)
self.actionEdit_simulation_time_limits.setObjectName(u"actionEdit_simulation_time_limits")
icon62 = QIcon()
icon62.addFile(u":/Icons/icons/time_series span.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionEdit_simulation_time_limits.setIcon(icon62)
+ self.actionEdit_simulation_time_limits.setFont(font)
self.actionactivate_time_series = QAction(mainWindow)
self.actionactivate_time_series.setObjectName(u"actionactivate_time_series")
self.actionactivate_time_series.setCheckable(True)
icon63 = QIcon()
icon63.addFile(u":/Icons/icons/time_series set.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionactivate_time_series.setIcon(icon63)
+ self.actionactivate_time_series.setFont(font)
self.actionClean_database = QAction(mainWindow)
self.actionClean_database.setObjectName(u"actionClean_database")
self.actionClean_database.setIcon(icon34)
+ self.actionClean_database.setFont(font)
self.actionSelect_buses_by_area = QAction(mainWindow)
self.actionSelect_buses_by_area.setObjectName(u"actionSelect_buses_by_area")
self.actionSelect_buses_by_area.setIcon(icon32)
+ self.actionSelect_buses_by_area.setFont(font)
self.actionSelect_buses_by_zone = QAction(mainWindow)
self.actionSelect_buses_by_zone.setObjectName(u"actionSelect_buses_by_zone")
self.actionSelect_buses_by_zone.setIcon(icon32)
+ self.actionSelect_buses_by_zone.setFont(font)
self.actionSelect_buses_by_country = QAction(mainWindow)
self.actionSelect_buses_by_country.setObjectName(u"actionSelect_buses_by_country")
self.actionSelect_buses_by_country.setIcon(icon39)
+ self.actionSelect_buses_by_country.setFont(font)
self.actionScale = QAction(mainWindow)
self.actionScale.setObjectName(u"actionScale")
icon64 = QIcon()
icon64.addFile(u":/Icons/icons/scale.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionScale.setIcon(icon64)
+ self.actionScale.setFont(font)
self.actionDisable_all_results_tags = QAction(mainWindow)
self.actionDisable_all_results_tags.setObjectName(u"actionDisable_all_results_tags")
icon65 = QIcon()
icon65.addFile(u":/Icons/icons/uncheck_all.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionDisable_all_results_tags.setIcon(icon65)
+ self.actionDisable_all_results_tags.setFont(font)
self.actionEnable_all_results_tags = QAction(mainWindow)
self.actionEnable_all_results_tags.setObjectName(u"actionEnable_all_results_tags")
icon66 = QIcon()
icon66.addFile(u":/Icons/icons/check_all.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionEnable_all_results_tags.setIcon(icon66)
+ self.actionEnable_all_results_tags.setFont(font)
self.actionDetect_substations = QAction(mainWindow)
self.actionDetect_substations.setObjectName(u"actionDetect_substations")
icon67 = QIcon()
icon67.addFile(u":/Icons/icons/chip.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionDetect_substations.setIcon(icon67)
+ self.actionDetect_substations.setFont(font)
self.actionNodal_capacity = QAction(mainWindow)
self.actionNodal_capacity.setObjectName(u"actionNodal_capacity")
icon68 = QIcon()
icon68.addFile(u":/Icons/icons/nodal_capacity.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionNodal_capacity.setIcon(icon68)
+ self.actionNodal_capacity.setFont(font)
self.actionEnable_server_mode = QAction(mainWindow)
self.actionEnable_server_mode.setObjectName(u"actionEnable_server_mode")
self.actionEnable_server_mode.setCheckable(True)
icon69 = QIcon()
icon69.addFile(u":/Icons/icons/server.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionEnable_server_mode.setIcon(icon69)
+ self.actionEnable_server_mode.setFont(font)
self.actionDelete_from_the_diagram = QAction(mainWindow)
self.actionDelete_from_the_diagram.setObjectName(u"actionDelete_from_the_diagram")
icon70 = QIcon()
icon70.addFile(u":/Icons/icons/delete_schematic.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionDelete_from_the_diagram.setIcon(icon70)
+ self.actionDelete_from_the_diagram.setFont(font)
self.actionRecord_video = QAction(mainWindow)
self.actionRecord_video.setObjectName(u"actionRecord_video")
icon71 = QIcon()
icon71.addFile(u":/Icons/icons/record.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionRecord_video.setIcon(icon71)
+ self.actionRecord_video.setFont(font)
self.actionExport_circuit_differential = QAction(mainWindow)
self.actionExport_circuit_differential.setObjectName(u"actionExport_circuit_differential")
self.actionExport_circuit_differential.setIcon(icon23)
+ self.actionExport_circuit_differential.setFont(font)
self.actionAdd_custom_catalogue = QAction(mainWindow)
self.actionAdd_custom_catalogue.setObjectName(u"actionAdd_custom_catalogue")
icon72 = QIcon()
icon72.addFile(u":/Icons/icons/CataloguePrivate.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionAdd_custom_catalogue.setIcon(icon72)
+ self.actionAdd_custom_catalogue.setFont(font)
self.actionExportCatalogue = QAction(mainWindow)
self.actionExportCatalogue.setObjectName(u"actionExportCatalogue")
self.actionExportCatalogue.setIcon(icon72)
+ self.actionExportCatalogue.setFont(font)
self.centralwidget = QWidget(mainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.gridLayout_3 = QGridLayout(self.centralwidget)
@@ -492,11 +583,21 @@ def setupUi(self, mainWindow):
self.gridLayout_7.setObjectName(u"gridLayout_7")
self.progress_label = QLabel(self.progress_frame)
self.progress_label.setObjectName(u"progress_label")
+ self.progress_label.setFont(font)
+
+ self.gridLayout_7.addWidget(self.progress_label, 2, 3, 1, 1)
+
+ self.cancelButton = QPushButton(self.progress_frame)
+ self.cancelButton.setObjectName(u"cancelButton")
+ self.cancelButton.setMinimumSize(QSize(0, 24))
+ self.cancelButton.setFont(font)
+ self.cancelButton.setIcon(icon46)
- self.gridLayout_7.addWidget(self.progress_label, 0, 2, 1, 1)
+ self.gridLayout_7.addWidget(self.cancelButton, 4, 0, 1, 1)
self.progressBar = QProgressBar(self.progress_frame)
self.progressBar.setObjectName(u"progressBar")
+ self.progressBar.setFont(font)
self.progressBar.setStyleSheet(u"QProgressBar {\n"
" border: 1px solid rgb(186, 189, 182);\n"
" border-radius: 5px;\n"
@@ -508,20 +609,14 @@ def setupUi(self, mainWindow):
self.progressBar.setValue(20)
self.progressBar.setInvertedAppearance(False)
- self.gridLayout_7.addWidget(self.progressBar, 2, 2, 1, 1)
-
- self.cancelButton = QPushButton(self.progress_frame)
- self.cancelButton.setObjectName(u"cancelButton")
- self.cancelButton.setMinimumSize(QSize(0, 24))
- self.cancelButton.setIcon(icon46)
-
- self.gridLayout_7.addWidget(self.cancelButton, 2, 0, 1, 1)
+ self.gridLayout_7.addWidget(self.progressBar, 4, 3, 1, 1)
self.gridLayout_3.addWidget(self.progress_frame, 3, 0, 1, 1)
self.tabWidget = QTabWidget(self.centralwidget)
self.tabWidget.setObjectName(u"tabWidget")
+ self.tabWidget.setFont(font)
self.GridTab = QWidget()
self.GridTab.setObjectName(u"GridTab")
self.verticalLayout_9 = QVBoxLayout(self.GridTab)
@@ -575,11 +670,6 @@ def setupUi(self, mainWindow):
self.verticalLayout_2 = QVBoxLayout(self.diagram_selection_frame)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
- self.grid_name_line_edit = QLineEdit(self.diagram_selection_frame)
- self.grid_name_line_edit.setObjectName(u"grid_name_line_edit")
-
- self.verticalLayout_2.addWidget(self.grid_name_line_edit)
-
self.tabWidget_6 = QTabWidget(self.diagram_selection_frame)
self.tabWidget_6.setObjectName(u"tabWidget_6")
self.tabWidget_6.setTabPosition(QTabWidget.North)
@@ -590,6 +680,9 @@ def setupUi(self, mainWindow):
self.verticalLayout_37.setContentsMargins(0, 0, 0, 5)
self.diagramsListView = QListView(self.tab_3)
self.diagramsListView.setObjectName(u"diagramsListView")
+ font1 = QFont()
+ font1.setPointSize(9)
+ self.diagramsListView.setFont(font1)
self.diagramsListView.setFrameShape(QFrame.NoFrame)
self.verticalLayout_37.addWidget(self.diagramsListView)
@@ -622,9 +715,7 @@ def setupUi(self, mainWindow):
self.schematic_step_label = QLabel(self.tab_3)
self.schematic_step_label.setObjectName(u"schematic_step_label")
- font = QFont()
- font.setPointSize(9)
- self.schematic_step_label.setFont(font)
+ self.schematic_step_label.setFont(font1)
self.schematic_step_label.setAlignment(Qt.AlignCenter)
self.verticalLayout_37.addWidget(self.schematic_step_label)
@@ -647,65 +738,171 @@ def setupUi(self, mainWindow):
self.frame_58.setObjectName(u"frame_58")
self.frame_58.setFrameShape(QFrame.NoFrame)
self.frame_58.setFrameShadow(QFrame.Raised)
- self.formLayout_2 = QFormLayout(self.frame_58)
- self.formLayout_2.setObjectName(u"formLayout_2")
- self.formLayout_2.setContentsMargins(6, 0, 6, 0)
- self.frame_3 = QFrame(self.frame_58)
- self.frame_3.setObjectName(u"frame_3")
- self.frame_3.setFrameShape(QFrame.NoFrame)
- self.frame_3.setFrameShadow(QFrame.Raised)
- self.horizontalLayout_11 = QHBoxLayout(self.frame_3)
- self.horizontalLayout_11.setObjectName(u"horizontalLayout_11")
- self.horizontalLayout_11.setContentsMargins(0, -1, 0, 0)
- self.label_110 = QLabel(self.frame_3)
- self.label_110.setObjectName(u"label_110")
- self.label_110.setMinimumSize(QSize(24, 24))
- self.label_110.setMaximumSize(QSize(24, 24))
- self.label_110.setPixmap(QPixmap(u":/Icons/icons/schematic.svg"))
- self.label_110.setScaledContents(True)
+ self.gridLayout = QGridLayout(self.frame_58)
+ self.gridLayout.setObjectName(u"gridLayout")
+ self.gridLayout.setContentsMargins(6, 0, 6, 0)
+ self.label_9 = QLabel(self.frame_58)
+ self.label_9.setObjectName(u"label_9")
+ font2 = QFont()
+ font2.setPointSize(8)
+ self.label_9.setFont(font2)
- self.horizontalLayout_11.addWidget(self.label_110)
+ self.gridLayout.addWidget(self.label_9, 10, 0, 1, 1)
- self.label_111 = QLabel(self.frame_3)
- self.label_111.setObjectName(u"label_111")
- palette = QPalette()
- brush = QBrush(QColor(85, 87, 83, 255))
- brush.setStyle(Qt.SolidPattern)
- palette.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- brush1 = QBrush(QColor(190, 190, 190, 255))
- brush1.setStyle(Qt.SolidPattern)
- palette.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_111.setPalette(palette)
- font1 = QFont()
- font1.setPointSize(12)
- self.label_111.setFont(font1)
- self.label_111.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
+ self.resolution_factor_spinBox = QSpinBox(self.frame_58)
+ self.resolution_factor_spinBox.setObjectName(u"resolution_factor_spinBox")
+ self.resolution_factor_spinBox.setFont(font2)
+ self.resolution_factor_spinBox.setMinimum(1)
+ self.resolution_factor_spinBox.setMaximum(100)
+ self.resolution_factor_spinBox.setValue(10)
+
+ self.gridLayout.addWidget(self.resolution_factor_spinBox, 15, 1, 1, 1)
+
+ self.label_118 = QLabel(self.frame_58)
+ self.label_118.setObjectName(u"label_118")
+ self.label_118.setFont(font2)
+
+ self.gridLayout.addWidget(self.label_118, 7, 0, 1, 1)
+
+ self.label_24 = QLabel(self.frame_58)
+ self.label_24.setObjectName(u"label_24")
+ self.label_24.setFont(font2)
+ self.label_24.setTextFormat(Qt.PlainText)
+ self.label_24.setScaledContents(True)
+
+ self.gridLayout.addWidget(self.label_24, 4, 0, 1, 1)
+
+ self.automatic_layout_comboBox = QComboBox(self.frame_58)
+ self.automatic_layout_comboBox.setObjectName(u"automatic_layout_comboBox")
+ self.automatic_layout_comboBox.setFont(font2)
- self.horizontalLayout_11.addWidget(self.label_111)
+ self.gridLayout.addWidget(self.automatic_layout_comboBox, 4, 1, 1, 1)
+ self.label_60 = QLabel(self.frame_58)
+ self.label_60.setObjectName(u"label_60")
+ self.label_60.setFont(font2)
+
+ self.gridLayout.addWidget(self.label_60, 2, 0, 1, 1)
+
+ self.min_node_size_spinBox = QDoubleSpinBox(self.frame_58)
+ self.min_node_size_spinBox.setObjectName(u"min_node_size_spinBox")
+ self.min_node_size_spinBox.setFont(font2)
+ self.min_node_size_spinBox.setDecimals(1)
+ self.min_node_size_spinBox.setMinimum(0.100000000000000)
+ self.min_node_size_spinBox.setSingleStep(0.100000000000000)
+ self.min_node_size_spinBox.setValue(20.000000000000000)
+
+ self.gridLayout.addWidget(self.min_node_size_spinBox, 9, 1, 1, 1)
+
+ self.tile_provider_comboBox = QComboBox(self.frame_58)
+ self.tile_provider_comboBox.setObjectName(u"tile_provider_comboBox")
+ self.tile_provider_comboBox.setFont(font2)
- self.formLayout_2.setWidget(0, QFormLayout.SpanningRole, self.frame_3)
+ self.gridLayout.addWidget(self.tile_provider_comboBox, 7, 1, 1, 1)
self.label_43 = QLabel(self.frame_58)
self.label_43.setObjectName(u"label_43")
- font2 = QFont()
- font2.setPointSize(8)
self.label_43.setFont(font2)
- self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.label_43)
+ self.gridLayout.addWidget(self.label_43, 3, 0, 1, 1)
- self.palette_comboBox = QComboBox(self.frame_58)
- self.palette_comboBox.setObjectName(u"palette_comboBox")
- self.palette_comboBox.setFont(font2)
+ self.label_15 = QLabel(self.frame_58)
+ self.label_15.setObjectName(u"label_15")
+ self.label_15.setFont(font2)
- self.formLayout_2.setWidget(1, QFormLayout.FieldRole, self.palette_comboBox)
+ self.gridLayout.addWidget(self.label_15, 12, 0, 1, 1)
self.label_35 = QLabel(self.frame_58)
self.label_35.setObjectName(u"label_35")
self.label_35.setFont(font2)
- self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_35)
+ self.gridLayout.addWidget(self.label_35, 1, 0, 1, 1)
+
+ self.label = QLabel(self.frame_58)
+ self.label.setObjectName(u"label")
+ self.label.setFont(font2)
+
+ self.gridLayout.addWidget(self.label, 9, 0, 1, 1)
+
+ self.label_14 = QLabel(self.frame_58)
+ self.label_14.setObjectName(u"label_14")
+ self.label_14.setFont(font2)
+
+ self.gridLayout.addWidget(self.label_14, 11, 0, 1, 1)
+
+ self.max_branch_size_spinBox = QDoubleSpinBox(self.frame_58)
+ self.max_branch_size_spinBox.setObjectName(u"max_branch_size_spinBox")
+ self.max_branch_size_spinBox.setFont(font2)
+ self.max_branch_size_spinBox.setDecimals(1)
+ self.max_branch_size_spinBox.setSingleStep(0.100000000000000)
+ self.max_branch_size_spinBox.setValue(20.000000000000000)
+
+ self.gridLayout.addWidget(self.max_branch_size_spinBox, 12, 1, 1, 1)
+
+ self.explosion_factor_doubleSpinBox = QDoubleSpinBox(self.frame_58)
+ self.explosion_factor_doubleSpinBox.setObjectName(u"explosion_factor_doubleSpinBox")
+ self.explosion_factor_doubleSpinBox.setFont(font2)
+ self.explosion_factor_doubleSpinBox.setDecimals(3)
+ self.explosion_factor_doubleSpinBox.setMinimum(1.000000000000000)
+ self.explosion_factor_doubleSpinBox.setMaximum(999999999.000000000000000)
+ self.explosion_factor_doubleSpinBox.setSingleStep(0.100000000000000)
+ self.explosion_factor_doubleSpinBox.setValue(1.500000000000000)
+
+ self.gridLayout.addWidget(self.explosion_factor_doubleSpinBox, 2, 1, 1, 1)
+
+ self.fps_spinBox = QSpinBox(self.frame_58)
+ self.fps_spinBox.setObjectName(u"fps_spinBox")
+ self.fps_spinBox.setFont(font2)
+ self.fps_spinBox.setMinimum(1)
+ self.fps_spinBox.setMaximum(9999)
+ self.fps_spinBox.setValue(30)
+
+ self.gridLayout.addWidget(self.fps_spinBox, 16, 1, 1, 1)
+
+ self.max_node_size_spinBox = QDoubleSpinBox(self.frame_58)
+ self.max_node_size_spinBox.setObjectName(u"max_node_size_spinBox")
+ self.max_node_size_spinBox.setFont(font2)
+ self.max_node_size_spinBox.setDecimals(1)
+ self.max_node_size_spinBox.setMinimum(0.100000000000000)
+ self.max_node_size_spinBox.setSingleStep(0.100000000000000)
+ self.max_node_size_spinBox.setValue(40.000000000000000)
+
+ self.gridLayout.addWidget(self.max_node_size_spinBox, 10, 1, 1, 1)
+
+ self.label_150 = QLabel(self.frame_58)
+ self.label_150.setObjectName(u"label_150")
+ self.label_150.setFont(font2)
+
+ self.gridLayout.addWidget(self.label_150, 16, 0, 1, 1)
+
+ self.palette_comboBox = QComboBox(self.frame_58)
+ self.palette_comboBox.setObjectName(u"palette_comboBox")
+ self.palette_comboBox.setFont(font2)
+
+ self.gridLayout.addWidget(self.palette_comboBox, 3, 1, 1, 1)
+
+ self.ask_before_appliying_layout_checkBox = QCheckBox(self.frame_58)
+ self.ask_before_appliying_layout_checkBox.setObjectName(u"ask_before_appliying_layout_checkBox")
+ self.ask_before_appliying_layout_checkBox.setFont(font2)
+ self.ask_before_appliying_layout_checkBox.setChecked(True)
+ self.ask_before_appliying_layout_checkBox.setTristate(False)
+
+ self.gridLayout.addWidget(self.ask_before_appliying_layout_checkBox, 5, 1, 1, 1)
+
+ self.label_32 = QLabel(self.frame_58)
+ self.label_32.setObjectName(u"label_32")
+ self.label_32.setFont(font2)
+
+ self.gridLayout.addWidget(self.label_32, 15, 0, 1, 1)
+
+ self.min_branch_size_spinBox = QDoubleSpinBox(self.frame_58)
+ self.min_branch_size_spinBox.setObjectName(u"min_branch_size_spinBox")
+ self.min_branch_size_spinBox.setFont(font2)
+ self.min_branch_size_spinBox.setDecimals(1)
+ self.min_branch_size_spinBox.setSingleStep(0.100000000000000)
+ self.min_branch_size_spinBox.setValue(0.500000000000000)
+
+ self.gridLayout.addWidget(self.min_branch_size_spinBox, 11, 1, 1, 1)
self.defaultBusVoltageSpinBox = QDoubleSpinBox(self.frame_58)
self.defaultBusVoltageSpinBox.setObjectName(u"defaultBusVoltageSpinBox")
@@ -714,7 +911,11 @@ def setupUi(self, mainWindow):
self.defaultBusVoltageSpinBox.setMaximum(999999999.000000000000000)
self.defaultBusVoltageSpinBox.setValue(10.000000000000000)
- self.formLayout_2.setWidget(2, QFormLayout.FieldRole, self.defaultBusVoltageSpinBox)
+ self.gridLayout.addWidget(self.defaultBusVoltageSpinBox, 1, 1, 1, 1)
+
+ self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.gridLayout.addItem(self.verticalSpacer, 17, 1, 1, 1)
self.frame_22 = QFrame(self.frame_58)
self.frame_22.setObjectName(u"frame_22")
@@ -734,30 +935,86 @@ def setupUi(self, mainWindow):
self.label_100 = QLabel(self.frame_22)
self.label_100.setObjectName(u"label_100")
+ palette = QPalette()
+ brush = QBrush(QColor(85, 87, 83, 255))
+ brush.setStyle(Qt.SolidPattern)
+ palette.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ brush1 = QBrush(QColor(190, 190, 190, 255))
+ brush1.setStyle(Qt.SolidPattern)
+ palette.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_100.setPalette(palette)
+ font3 = QFont()
+ font3.setPointSize(11)
+ self.label_100.setFont(font3)
+ self.label_100.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
+
+ self.horizontalLayout_15.addWidget(self.label_100)
+
+
+ self.gridLayout.addWidget(self.frame_22, 6, 0, 1, 2)
+
+ self.frame_3 = QFrame(self.frame_58)
+ self.frame_3.setObjectName(u"frame_3")
+ self.frame_3.setFrameShape(QFrame.NoFrame)
+ self.frame_3.setFrameShadow(QFrame.Raised)
+ self.formLayout_2 = QFormLayout(self.frame_3)
+ self.formLayout_2.setObjectName(u"formLayout_2")
+ self.formLayout_2.setContentsMargins(0, -1, 0, 0)
+ self.label_110 = QLabel(self.frame_3)
+ self.label_110.setObjectName(u"label_110")
+ self.label_110.setMinimumSize(QSize(24, 24))
+ self.label_110.setMaximumSize(QSize(24, 24))
+ self.label_110.setPixmap(QPixmap(u":/Icons/icons/schematic.svg"))
+ self.label_110.setScaledContents(True)
+
+ self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.label_110)
+
+ self.label_111 = QLabel(self.frame_3)
+ self.label_111.setObjectName(u"label_111")
palette1 = QPalette()
palette1.setBrush(QPalette.Active, QPalette.WindowText, brush)
palette1.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
palette1.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_100.setPalette(palette1)
- self.label_100.setFont(font1)
- self.label_100.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
+ self.label_111.setPalette(palette1)
+ self.label_111.setFont(font3)
+ self.label_111.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
- self.horizontalLayout_15.addWidget(self.label_100)
+ self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.label_111)
- self.formLayout_2.setWidget(3, QFormLayout.LabelRole, self.frame_22)
+ self.gridLayout.addWidget(self.frame_3, 0, 0, 1, 2)
- self.label_118 = QLabel(self.frame_58)
- self.label_118.setObjectName(u"label_118")
- self.label_118.setFont(font2)
+ self.frame_30 = QFrame(self.frame_58)
+ self.frame_30.setObjectName(u"frame_30")
+ self.frame_30.setFrameShape(QFrame.NoFrame)
+ self.frame_30.setFrameShadow(QFrame.Raised)
+ self.horizontalLayout_18 = QHBoxLayout(self.frame_30)
+ self.horizontalLayout_18.setObjectName(u"horizontalLayout_18")
+ self.horizontalLayout_18.setContentsMargins(0, 0, 0, 0)
+ self.label_66 = QLabel(self.frame_30)
+ self.label_66.setObjectName(u"label_66")
+ self.label_66.setMinimumSize(QSize(24, 24))
+ self.label_66.setMaximumSize(QSize(24, 24))
+ self.label_66.setPixmap(QPixmap(u":/Icons/icons/picture.svg"))
+ self.label_66.setScaledContents(True)
- self.formLayout_2.setWidget(4, QFormLayout.LabelRole, self.label_118)
+ self.horizontalLayout_18.addWidget(self.label_66)
+
+ self.label_45 = QLabel(self.frame_30)
+ self.label_45.setObjectName(u"label_45")
+ palette2 = QPalette()
+ palette2.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette2.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette2.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_45.setPalette(palette2)
+ self.label_45.setFont(font3)
+ self.label_45.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
+
+ self.horizontalLayout_18.addWidget(self.label_45)
- self.tile_provider_comboBox = QComboBox(self.frame_58)
- self.tile_provider_comboBox.setObjectName(u"tile_provider_comboBox")
- self.tile_provider_comboBox.setFont(font2)
- self.formLayout_2.setWidget(4, QFormLayout.FieldRole, self.tile_provider_comboBox)
+ self.gridLayout.addWidget(self.frame_30, 14, 0, 1, 2)
self.frame_24 = QFrame(self.frame_58)
self.frame_24.setObjectName(u"frame_24")
@@ -777,202 +1034,36 @@ def setupUi(self, mainWindow):
self.label_155 = QLabel(self.frame_24)
self.label_155.setObjectName(u"label_155")
- palette2 = QPalette()
- palette2.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette2.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette2.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_155.setPalette(palette2)
- self.label_155.setFont(font1)
- self.label_155.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
+ palette3 = QPalette()
+ palette3.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette3.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette3.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_155.setPalette(palette3)
+ self.label_155.setFont(font3)
+ self.label_155.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
self.horizontalLayout_17.addWidget(self.label_155)
- self.formLayout_2.setWidget(5, QFormLayout.LabelRole, self.frame_24)
+ self.gridLayout.addWidget(self.frame_24, 8, 0, 1, 2)
- self.label = QLabel(self.frame_58)
- self.label.setObjectName(u"label")
- self.label.setFont(font2)
+ self.branch_width_based_on_flow_checkBox = QCheckBox(self.frame_58)
+ self.branch_width_based_on_flow_checkBox.setObjectName(u"branch_width_based_on_flow_checkBox")
+ self.branch_width_based_on_flow_checkBox.setFont(font2)
+ self.branch_width_based_on_flow_checkBox.setChecked(False)
- self.formLayout_2.setWidget(6, QFormLayout.LabelRole, self.label)
+ self.gridLayout.addWidget(self.branch_width_based_on_flow_checkBox, 13, 1, 1, 1)
- self.min_node_size_spinBox = QDoubleSpinBox(self.frame_58)
- self.min_node_size_spinBox.setObjectName(u"min_node_size_spinBox")
- self.min_node_size_spinBox.setFont(font2)
- self.min_node_size_spinBox.setDecimals(1)
- self.min_node_size_spinBox.setMinimum(0.100000000000000)
- self.min_node_size_spinBox.setSingleStep(0.100000000000000)
- self.min_node_size_spinBox.setValue(20.000000000000000)
- self.formLayout_2.setWidget(6, QFormLayout.FieldRole, self.min_node_size_spinBox)
+ self.verticalLayout_38.addWidget(self.frame_58)
- self.label_9 = QLabel(self.frame_58)
- self.label_9.setObjectName(u"label_9")
- self.label_9.setFont(font2)
+ self.tabWidget_6.addTab(self.tab_4, icon49, "")
- self.formLayout_2.setWidget(7, QFormLayout.LabelRole, self.label_9)
+ self.verticalLayout_2.addWidget(self.tabWidget_6)
- self.max_node_size_spinBox = QDoubleSpinBox(self.frame_58)
- self.max_node_size_spinBox.setObjectName(u"max_node_size_spinBox")
- self.max_node_size_spinBox.setFont(font2)
- self.max_node_size_spinBox.setDecimals(1)
- self.max_node_size_spinBox.setMinimum(0.100000000000000)
- self.max_node_size_spinBox.setSingleStep(0.100000000000000)
- self.max_node_size_spinBox.setValue(40.000000000000000)
+ self.diagram_selection_splitter.addWidget(self.diagram_selection_frame)
- self.formLayout_2.setWidget(7, QFormLayout.FieldRole, self.max_node_size_spinBox)
-
- self.label_14 = QLabel(self.frame_58)
- self.label_14.setObjectName(u"label_14")
- self.label_14.setFont(font2)
-
- self.formLayout_2.setWidget(8, QFormLayout.LabelRole, self.label_14)
-
- self.min_branch_size_spinBox = QDoubleSpinBox(self.frame_58)
- self.min_branch_size_spinBox.setObjectName(u"min_branch_size_spinBox")
- self.min_branch_size_spinBox.setFont(font2)
- self.min_branch_size_spinBox.setDecimals(1)
- self.min_branch_size_spinBox.setSingleStep(0.100000000000000)
- self.min_branch_size_spinBox.setValue(0.500000000000000)
-
- self.formLayout_2.setWidget(8, QFormLayout.FieldRole, self.min_branch_size_spinBox)
-
- self.label_15 = QLabel(self.frame_58)
- self.label_15.setObjectName(u"label_15")
- self.label_15.setFont(font2)
-
- self.formLayout_2.setWidget(9, QFormLayout.LabelRole, self.label_15)
-
- self.max_branch_size_spinBox = QDoubleSpinBox(self.frame_58)
- self.max_branch_size_spinBox.setObjectName(u"max_branch_size_spinBox")
- self.max_branch_size_spinBox.setFont(font2)
- self.max_branch_size_spinBox.setDecimals(1)
- self.max_branch_size_spinBox.setSingleStep(0.100000000000000)
- self.max_branch_size_spinBox.setValue(20.000000000000000)
-
- self.formLayout_2.setWidget(9, QFormLayout.FieldRole, self.max_branch_size_spinBox)
-
- self.branch_width_based_on_flow_checkBox = QCheckBox(self.frame_58)
- self.branch_width_based_on_flow_checkBox.setObjectName(u"branch_width_based_on_flow_checkBox")
- self.branch_width_based_on_flow_checkBox.setFont(font2)
- self.branch_width_based_on_flow_checkBox.setChecked(False)
-
- self.formLayout_2.setWidget(10, QFormLayout.LabelRole, self.branch_width_based_on_flow_checkBox)
-
- self.frame_30 = QFrame(self.frame_58)
- self.frame_30.setObjectName(u"frame_30")
- self.frame_30.setFrameShape(QFrame.NoFrame)
- self.frame_30.setFrameShadow(QFrame.Raised)
- self.horizontalLayout_18 = QHBoxLayout(self.frame_30)
- self.horizontalLayout_18.setObjectName(u"horizontalLayout_18")
- self.horizontalLayout_18.setContentsMargins(0, 0, 0, 0)
- self.label_66 = QLabel(self.frame_30)
- self.label_66.setObjectName(u"label_66")
- self.label_66.setMinimumSize(QSize(24, 24))
- self.label_66.setMaximumSize(QSize(24, 24))
- self.label_66.setPixmap(QPixmap(u":/Icons/icons/picture.svg"))
- self.label_66.setScaledContents(True)
-
- self.horizontalLayout_18.addWidget(self.label_66)
-
- self.label_45 = QLabel(self.frame_30)
- self.label_45.setObjectName(u"label_45")
- palette3 = QPalette()
- palette3.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette3.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette3.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_45.setPalette(palette3)
- self.label_45.setFont(font1)
- self.label_45.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
-
- self.horizontalLayout_18.addWidget(self.label_45)
-
-
- self.formLayout_2.setWidget(11, QFormLayout.SpanningRole, self.frame_30)
-
- self.label_32 = QLabel(self.frame_58)
- self.label_32.setObjectName(u"label_32")
- self.label_32.setFont(font2)
-
- self.formLayout_2.setWidget(12, QFormLayout.LabelRole, self.label_32)
-
- self.resolution_factor_spinBox = QSpinBox(self.frame_58)
- self.resolution_factor_spinBox.setObjectName(u"resolution_factor_spinBox")
- self.resolution_factor_spinBox.setFont(font2)
- self.resolution_factor_spinBox.setMinimum(1)
- self.resolution_factor_spinBox.setMaximum(100)
- self.resolution_factor_spinBox.setValue(10)
-
- self.formLayout_2.setWidget(12, QFormLayout.FieldRole, self.resolution_factor_spinBox)
-
- self.label_150 = QLabel(self.frame_58)
- self.label_150.setObjectName(u"label_150")
- self.label_150.setFont(font2)
-
- self.formLayout_2.setWidget(13, QFormLayout.LabelRole, self.label_150)
-
- self.fps_spinBox = QSpinBox(self.frame_58)
- self.fps_spinBox.setObjectName(u"fps_spinBox")
- self.fps_spinBox.setFont(font2)
- self.fps_spinBox.setMinimum(1)
- self.fps_spinBox.setMaximum(9999)
- self.fps_spinBox.setValue(30)
-
- self.formLayout_2.setWidget(13, QFormLayout.FieldRole, self.fps_spinBox)
-
- self.frame_37 = QFrame(self.frame_58)
- self.frame_37.setObjectName(u"frame_37")
- self.frame_37.setFrameShape(QFrame.NoFrame)
- self.frame_37.setFrameShadow(QFrame.Raised)
- self.horizontalLayout_19 = QHBoxLayout(self.frame_37)
- self.horizontalLayout_19.setObjectName(u"horizontalLayout_19")
- self.horizontalLayout_19.setContentsMargins(0, 0, 0, 0)
- self.label_76 = QLabel(self.frame_37)
- self.label_76.setObjectName(u"label_76")
- self.label_76.setMinimumSize(QSize(24, 24))
- self.label_76.setMaximumSize(QSize(24, 24))
- self.label_76.setPixmap(QPixmap(u":/Icons/icons/plot.svg"))
- self.label_76.setScaledContents(True)
-
- self.horizontalLayout_19.addWidget(self.label_76)
-
- self.label_49 = QLabel(self.frame_37)
- self.label_49.setObjectName(u"label_49")
- palette4 = QPalette()
- palette4.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette4.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette4.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_49.setPalette(palette4)
- self.label_49.setFont(font1)
- self.label_49.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
-
- self.horizontalLayout_19.addWidget(self.label_49)
-
-
- self.formLayout_2.setWidget(14, QFormLayout.SpanningRole, self.frame_37)
-
- self.label_38 = QLabel(self.frame_58)
- self.label_38.setObjectName(u"label_38")
- self.label_38.setFont(font2)
-
- self.formLayout_2.setWidget(15, QFormLayout.LabelRole, self.label_38)
-
- self.plt_style_comboBox = QComboBox(self.frame_58)
- self.plt_style_comboBox.setObjectName(u"plt_style_comboBox")
- self.plt_style_comboBox.setFont(font2)
-
- self.formLayout_2.setWidget(15, QFormLayout.FieldRole, self.plt_style_comboBox)
-
-
- self.verticalLayout_38.addWidget(self.frame_58)
-
- self.tabWidget_6.addTab(self.tab_4, icon49, "")
-
- self.verticalLayout_2.addWidget(self.tabWidget_6)
-
- self.diagram_selection_splitter.addWidget(self.diagram_selection_frame)
-
- self.verticalLayout_5.addWidget(self.diagram_selection_splitter)
+ self.verticalLayout_5.addWidget(self.diagram_selection_splitter)
self.verticalLayout_30.addWidget(self.frame_6)
@@ -1052,7 +1143,7 @@ def setupUi(self, mainWindow):
self.dataStructureTableView = QTableView(self.tab_15)
self.dataStructureTableView.setObjectName(u"dataStructureTableView")
- self.dataStructureTableView.setFont(font)
+ self.dataStructureTableView.setFont(font1)
self.verticalLayout_20.addWidget(self.dataStructureTableView)
@@ -1080,7 +1171,7 @@ def setupUi(self, mainWindow):
self.db_step_label = QLabel(self.frame_9)
self.db_step_label.setObjectName(u"db_step_label")
self.db_step_label.setMinimumSize(QSize(200, 0))
- self.db_step_label.setFont(font)
+ self.db_step_label.setFont(font1)
self.db_step_label.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
self.horizontalLayout_25.addWidget(self.db_step_label)
@@ -1149,7 +1240,7 @@ def setupUi(self, mainWindow):
self.verticalLayout_14.setContentsMargins(0, 0, 0, 0)
self.associationsTableView = QTableView(self.frame_20)
self.associationsTableView.setObjectName(u"associationsTableView")
- self.associationsTableView.setFont(font)
+ self.associationsTableView.setFont(font1)
self.verticalLayout_14.addWidget(self.associationsTableView)
@@ -1226,7 +1317,7 @@ def setupUi(self, mainWindow):
self.profiles_tableView = QTableView(self.tab_16)
self.profiles_tableView.setObjectName(u"profiles_tableView")
- self.profiles_tableView.setFont(font)
+ self.profiles_tableView.setFont(font1)
self.profiles_tableView.setLayoutDirection(Qt.LeftToRight)
self.profiles_tableView.setAlternatingRowColors(True)
self.profiles_tableView.setSelectionMode(QAbstractItemView.ContiguousSelection)
@@ -1347,10 +1438,17 @@ def setupUi(self, mainWindow):
self.gridLayout_19 = QGridLayout(self.frame_28)
self.gridLayout_19.setObjectName(u"gridLayout_19")
self.gridLayout_19.setContentsMargins(-1, -1, 0, -1)
- self.simulationDataStructuresListView = QListView(self.frame_28)
- self.simulationDataStructuresListView.setObjectName(u"simulationDataStructuresListView")
+ self.simulation_data_island_comboBox = QComboBox(self.frame_28)
+ self.simulation_data_island_comboBox.setObjectName(u"simulation_data_island_comboBox")
+
+ self.gridLayout_19.addWidget(self.simulation_data_island_comboBox, 0, 2, 1, 2)
- self.gridLayout_19.addWidget(self.simulationDataStructuresListView, 1, 0, 1, 4)
+ self.exportSimulationDataButton = QPushButton(self.frame_28)
+ self.exportSimulationDataButton.setObjectName(u"exportSimulationDataButton")
+ self.exportSimulationDataButton.setMaximumSize(QSize(32, 16777215))
+ self.exportSimulationDataButton.setIcon(icon19)
+
+ self.gridLayout_19.addWidget(self.exportSimulationDataButton, 0, 1, 1, 1)
self.compute_simulation_data_pushButton = QPushButton(self.frame_28)
self.compute_simulation_data_pushButton.setObjectName(u"compute_simulation_data_pushButton")
@@ -1361,17 +1459,10 @@ def setupUi(self, mainWindow):
self.gridLayout_19.addWidget(self.compute_simulation_data_pushButton, 0, 0, 1, 1)
- self.exportSimulationDataButton = QPushButton(self.frame_28)
- self.exportSimulationDataButton.setObjectName(u"exportSimulationDataButton")
- self.exportSimulationDataButton.setMaximumSize(QSize(32, 16777215))
- self.exportSimulationDataButton.setIcon(icon19)
-
- self.gridLayout_19.addWidget(self.exportSimulationDataButton, 0, 1, 1, 1)
-
- self.simulation_data_island_comboBox = QComboBox(self.frame_28)
- self.simulation_data_island_comboBox.setObjectName(u"simulation_data_island_comboBox")
+ self.simulationDataStructuresTreeView = QTreeView(self.frame_28)
+ self.simulationDataStructuresTreeView.setObjectName(u"simulationDataStructuresTreeView")
- self.gridLayout_19.addWidget(self.simulation_data_island_comboBox, 0, 2, 1, 2)
+ self.gridLayout_19.addWidget(self.simulationDataStructuresTreeView, 1, 0, 1, 4)
self.simulationDataSplitter.addWidget(self.frame_28)
self.frame_29 = QFrame(self.simulationDataSplitter)
@@ -1481,13 +1572,13 @@ def setupUi(self, mainWindow):
self.label_16 = QLabel(self.frame_62)
self.label_16.setObjectName(u"label_16")
self.label_16.setMinimumSize(QSize(0, 24))
- palette5 = QPalette()
+ palette4 = QPalette()
brush2 = QBrush(QColor(119, 118, 123, 255))
brush2.setStyle(Qt.SolidPattern)
- palette5.setBrush(QPalette.Active, QPalette.WindowText, brush2)
- palette5.setBrush(QPalette.Inactive, QPalette.WindowText, brush2)
- palette5.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_16.setPalette(palette5)
+ palette4.setBrush(QPalette.Active, QPalette.WindowText, brush2)
+ palette4.setBrush(QPalette.Inactive, QPalette.WindowText, brush2)
+ palette4.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_16.setPalette(palette4)
self.horizontalLayout_34.addWidget(self.label_16)
@@ -1527,11 +1618,11 @@ def setupUi(self, mainWindow):
self.horizontalLayout_33.setContentsMargins(0, 0, 0, 0)
self.label_37 = QLabel(self.frame_60)
self.label_37.setObjectName(u"label_37")
- palette6 = QPalette()
- palette6.setBrush(QPalette.Active, QPalette.WindowText, brush2)
- palette6.setBrush(QPalette.Inactive, QPalette.WindowText, brush2)
- palette6.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_37.setPalette(palette6)
+ palette5 = QPalette()
+ palette5.setBrush(QPalette.Active, QPalette.WindowText, brush2)
+ palette5.setBrush(QPalette.Inactive, QPalette.WindowText, brush2)
+ palette5.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_37.setPalette(palette5)
self.horizontalLayout_33.addWidget(self.label_37)
@@ -1578,7 +1669,7 @@ def setupUi(self, mainWindow):
self.verticalLayout_24.setContentsMargins(0, 0, 8, 8)
self.resultsTableView = QTableView(self.frame_5)
self.resultsTableView.setObjectName(u"resultsTableView")
- self.resultsTableView.setFont(font)
+ self.resultsTableView.setFont(font1)
self.resultsTableView.setAlternatingRowColors(True)
self.resultsTableView.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.resultsTableView.setSelectionBehavior(QAbstractItemView.SelectItems)
@@ -1674,7 +1765,7 @@ def setupUi(self, mainWindow):
self.verticalLayout_41.setContentsMargins(-1, 6, -1, -1)
self.resultsLogsTreeView = QTreeView(self.tab_14)
self.resultsLogsTreeView.setObjectName(u"resultsLogsTreeView")
- self.resultsLogsTreeView.setFont(font)
+ self.resultsLogsTreeView.setFont(font1)
self.resultsLogsTreeView.setFrameShape(QFrame.StyledPanel)
self.verticalLayout_41.addWidget(self.resultsLogsTreeView)
@@ -1836,6 +1927,8 @@ def setupUi(self, mainWindow):
self.gridLayout_8.setObjectName(u"gridLayout_8")
self.frame_7 = QFrame(self.SettingsTab)
self.frame_7.setObjectName(u"frame_7")
+ self.frame_7.setMinimumSize(QSize(0, 0))
+ self.frame_7.setMaximumSize(QSize(250, 16777215))
self.frame_7.setFrameShape(QFrame.NoFrame)
self.frame_7.setFrameShadow(QFrame.Raised)
self.verticalLayout_12 = QVBoxLayout(self.frame_7)
@@ -1858,14 +1951,14 @@ def setupUi(self, mainWindow):
self.label_69 = QLabel(self.frame_41)
self.label_69.setObjectName(u"label_69")
- palette7 = QPalette()
- palette7.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette7.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette7.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_69.setPalette(palette7)
- font3 = QFont()
- font3.setPointSize(16)
- self.label_69.setFont(font3)
+ palette6 = QPalette()
+ palette6.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette6.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette6.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_69.setPalette(palette6)
+ font4 = QFont()
+ font4.setPointSize(16)
+ self.label_69.setFont(font4)
self.label_69.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.horizontalLayout_13.addWidget(self.label_69)
@@ -1875,13 +1968,13 @@ def setupUi(self, mainWindow):
self.line_5 = QFrame(self.frame_7)
self.line_5.setObjectName(u"line_5")
- palette8 = QPalette()
+ palette7 = QPalette()
brush3 = QBrush(QColor(186, 189, 182, 255))
brush3.setStyle(Qt.SolidPattern)
- palette8.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette8.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette8.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_5.setPalette(palette8)
+ palette7.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette7.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette7.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_5.setPalette(palette7)
self.line_5.setFrameShadow(QFrame.Plain)
self.line_5.setLineWidth(4)
self.line_5.setFrameShape(QFrame.Shape.HLine)
@@ -1894,13 +1987,26 @@ def setupUi(self, mainWindow):
self.frame_25.setFrameShadow(QFrame.Raised)
self.verticalLayout_17 = QVBoxLayout(self.frame_25)
self.verticalLayout_17.setObjectName(u"verticalLayout_17")
+ self.label_82 = QLabel(self.frame_25)
+ self.label_82.setObjectName(u"label_82")
+ self.label_82.setFont(font1)
+
+ self.verticalLayout_17.addWidget(self.label_82)
+
+ self.grid_name_line_edit = QLineEdit(self.frame_25)
+ self.grid_name_line_edit.setObjectName(u"grid_name_line_edit")
+
+ self.verticalLayout_17.addWidget(self.grid_name_line_edit)
+
self.label_57 = QLabel(self.frame_25)
self.label_57.setObjectName(u"label_57")
+ self.label_57.setFont(font1)
self.verticalLayout_17.addWidget(self.label_57)
self.sbase_doubleSpinBox = QDoubleSpinBox(self.frame_25)
self.sbase_doubleSpinBox.setObjectName(u"sbase_doubleSpinBox")
+ self.sbase_doubleSpinBox.setFont(font1)
self.sbase_doubleSpinBox.setDecimals(0)
self.sbase_doubleSpinBox.setMinimum(1.000000000000000)
self.sbase_doubleSpinBox.setMaximum(10000000000000000000.000000000000000)
@@ -1910,11 +2016,13 @@ def setupUi(self, mainWindow):
self.label_58 = QLabel(self.frame_25)
self.label_58.setObjectName(u"label_58")
+ self.label_58.setFont(font1)
self.verticalLayout_17.addWidget(self.label_58)
self.fbase_doubleSpinBox = QDoubleSpinBox(self.frame_25)
self.fbase_doubleSpinBox.setObjectName(u"fbase_doubleSpinBox")
+ self.fbase_doubleSpinBox.setFont(font1)
self.fbase_doubleSpinBox.setDecimals(0)
self.fbase_doubleSpinBox.setMinimum(50.000000000000000)
self.fbase_doubleSpinBox.setMaximum(60.000000000000000)
@@ -1924,11 +2032,13 @@ def setupUi(self, mainWindow):
self.label_101 = QLabel(self.frame_25)
self.label_101.setObjectName(u"label_101")
+ self.label_101.setFont(font1)
self.verticalLayout_17.addWidget(self.label_101)
self.snapshot_dateTimeEdit = QDateTimeEdit(self.frame_25)
self.snapshot_dateTimeEdit.setObjectName(u"snapshot_dateTimeEdit")
+ self.snapshot_dateTimeEdit.setFont(font1)
self.snapshot_dateTimeEdit.setCalendarPopup(True)
self.verticalLayout_17.addWidget(self.snapshot_dateTimeEdit)
@@ -1938,17 +2048,87 @@ def setupUi(self, mainWindow):
self.verticalLayout_17.addWidget(self.label_40)
- self.label_31 = QLabel(self.frame_25)
- self.label_31.setObjectName(u"label_31")
- self.label_31.setFont(font1)
+ self.frame_43 = QFrame(self.frame_25)
+ self.frame_43.setObjectName(u"frame_43")
+ self.frame_43.setFrameShape(QFrame.NoFrame)
+ self.frame_43.setFrameShadow(QFrame.Raised)
+ self.horizontalLayout_23 = QHBoxLayout(self.frame_43)
+ self.horizontalLayout_23.setObjectName(u"horizontalLayout_23")
+ self.horizontalLayout_23.setContentsMargins(0, 0, 0, 0)
+ self.label_86 = QLabel(self.frame_43)
+ self.label_86.setObjectName(u"label_86")
+ self.label_86.setMinimumSize(QSize(24, 24))
+ self.label_86.setMaximumSize(QSize(24, 24))
+ self.label_86.setPixmap(QPixmap(u":/Icons/icons/piece.svg"))
+ self.label_86.setScaledContents(True)
+
+ self.horizontalLayout_23.addWidget(self.label_86)
+
+ self.label_65 = QLabel(self.frame_43)
+ self.label_65.setObjectName(u"label_65")
+ palette8 = QPalette()
+ palette8.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette8.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette8.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_65.setPalette(palette8)
+ font5 = QFont()
+ font5.setPointSize(12)
+ self.label_65.setFont(font5)
+ self.label_65.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
+
+ self.horizontalLayout_23.addWidget(self.label_65)
- self.verticalLayout_17.addWidget(self.label_31)
+
+ self.verticalLayout_17.addWidget(self.frame_43)
self.engineComboBox = QComboBox(self.frame_25)
self.engineComboBox.setObjectName(u"engineComboBox")
+ self.engineComboBox.setFont(font1)
self.verticalLayout_17.addWidget(self.engineComboBox)
+ self.label_48 = QLabel(self.frame_25)
+ self.label_48.setObjectName(u"label_48")
+
+ self.verticalLayout_17.addWidget(self.label_48)
+
+ self.frame_37 = QFrame(self.frame_25)
+ self.frame_37.setObjectName(u"frame_37")
+ self.frame_37.setFrameShape(QFrame.NoFrame)
+ self.frame_37.setFrameShadow(QFrame.Raised)
+ self.horizontalLayout_19 = QHBoxLayout(self.frame_37)
+ self.horizontalLayout_19.setObjectName(u"horizontalLayout_19")
+ self.horizontalLayout_19.setContentsMargins(0, 0, 0, 0)
+ self.label_76 = QLabel(self.frame_37)
+ self.label_76.setObjectName(u"label_76")
+ self.label_76.setMinimumSize(QSize(24, 24))
+ self.label_76.setMaximumSize(QSize(24, 24))
+ self.label_76.setPixmap(QPixmap(u":/Icons/icons/plot.svg"))
+ self.label_76.setScaledContents(True)
+
+ self.horizontalLayout_19.addWidget(self.label_76)
+
+ self.label_49 = QLabel(self.frame_37)
+ self.label_49.setObjectName(u"label_49")
+ palette9 = QPalette()
+ palette9.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette9.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette9.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_49.setPalette(palette9)
+ self.label_49.setFont(font5)
+ self.label_49.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
+
+ self.horizontalLayout_19.addWidget(self.label_49)
+
+
+ self.verticalLayout_17.addWidget(self.frame_37)
+
+ self.plt_style_comboBox = QComboBox(self.frame_25)
+ self.plt_style_comboBox.setObjectName(u"plt_style_comboBox")
+ self.plt_style_comboBox.setFont(font1)
+
+ self.verticalLayout_17.addWidget(self.plt_style_comboBox)
+
self.verticalLayout_12.addWidget(self.frame_25)
@@ -1958,6 +2138,7 @@ def setupUi(self, mainWindow):
self.dark_mode_checkBox = QCheckBox(self.frame_7)
self.dark_mode_checkBox.setObjectName(u"dark_mode_checkBox")
+ self.dark_mode_checkBox.setFont(font1)
self.verticalLayout_12.addWidget(self.dark_mode_checkBox)
@@ -1967,7 +2148,7 @@ def setupUi(self, mainWindow):
self.settings_tabWidget = QTabWidget(self.SettingsTab)
self.settings_tabWidget.setObjectName(u"settings_tabWidget")
self.settings_tabWidget.setEnabled(True)
- self.settings_tabWidget.setFont(font1)
+ self.settings_tabWidget.setFont(font)
self.settings_tabWidget.setAutoFillBackground(False)
self.settings_tabWidget.setTabPosition(QTabWidget.South)
self.settings_tabWidget.setIconSize(QSize(16, 16))
@@ -1991,23 +2172,23 @@ def setupUi(self, mainWindow):
self.label_17 = QLabel(self.pf_tab)
self.label_17.setObjectName(u"label_17")
- palette9 = QPalette()
- palette9.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette9.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette9.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_17.setPalette(palette9)
- self.label_17.setFont(font3)
+ palette10 = QPalette()
+ palette10.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette10.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette10.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_17.setPalette(palette10)
+ self.label_17.setFont(font4)
self.label_17.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.gridLayout_24.addWidget(self.label_17, 0, 1, 1, 1)
self.line_14 = QFrame(self.pf_tab)
self.line_14.setObjectName(u"line_14")
- palette10 = QPalette()
- palette10.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette10.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette10.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_14.setPalette(palette10)
+ palette11 = QPalette()
+ palette11.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette11.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette11.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_14.setPalette(palette11)
self.line_14.setFrameShadow(QFrame.Plain)
self.line_14.setLineWidth(4)
self.line_14.setFrameShape(QFrame.Shape.HLine)
@@ -2020,180 +2201,97 @@ def setupUi(self, mainWindow):
self.frame_19.setFrameShadow(QFrame.Raised)
self.gridLayout_22 = QGridLayout(self.frame_19)
self.gridLayout_22.setObjectName(u"gridLayout_22")
- self.auto_precision_checkBox = QCheckBox(self.frame_19)
- self.auto_precision_checkBox.setObjectName(u"auto_precision_checkBox")
-
- self.gridLayout_22.addWidget(self.auto_precision_checkBox, 6, 0, 1, 2)
-
- self.helm_retry_checkBox = QCheckBox(self.frame_19)
- self.helm_retry_checkBox.setObjectName(u"helm_retry_checkBox")
- self.helm_retry_checkBox.setChecked(True)
-
- self.gridLayout_22.addWidget(self.helm_retry_checkBox, 3, 0, 1, 2)
-
- self.verbositySpinBox = QSpinBox(self.frame_19)
- self.verbositySpinBox.setObjectName(u"verbositySpinBox")
- self.verbositySpinBox.setMaximum(2)
-
- self.gridLayout_22.addWidget(self.verbositySpinBox, 13, 1, 1, 1)
-
- self.label_5 = QLabel(self.frame_19)
- self.label_5.setObjectName(u"label_5")
+ self.label_2 = QLabel(self.frame_19)
+ self.label_2.setObjectName(u"label_2")
+ self.label_2.setFont(font1)
- self.gridLayout_22.addWidget(self.label_5, 10, 0, 1, 1)
+ self.gridLayout_22.addWidget(self.label_2, 0, 0, 1, 1)
- self.label_86 = QLabel(self.frame_19)
- self.label_86.setObjectName(u"label_86")
+ self.verticalSpacer_10 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
- self.gridLayout_22.addWidget(self.label_86, 2, 0, 1, 2)
+ self.gridLayout_22.addItem(self.verticalSpacer_10, 13, 0, 1, 1)
self.label_22 = QLabel(self.frame_19)
self.label_22.setObjectName(u"label_22")
- self.gridLayout_22.addWidget(self.label_22, 14, 0, 1, 2)
+ self.gridLayout_22.addWidget(self.label_22, 12, 0, 1, 2)
+
+ self.label_23 = QLabel(self.frame_19)
+ self.label_23.setObjectName(u"label_23")
+ self.label_23.setFont(font1)
+
+ self.gridLayout_22.addWidget(self.label_23, 11, 0, 1, 1)
self.tolerance_spinBox = QSpinBox(self.frame_19)
self.tolerance_spinBox.setObjectName(u"tolerance_spinBox")
+ self.tolerance_spinBox.setFont(font1)
self.tolerance_spinBox.setMinimum(1)
self.tolerance_spinBox.setMaximum(15)
self.tolerance_spinBox.setValue(4)
- self.gridLayout_22.addWidget(self.tolerance_spinBox, 10, 1, 1, 1)
+ self.gridLayout_22.addWidget(self.tolerance_spinBox, 8, 1, 1, 1)
- self.distributed_slack_checkBox = QCheckBox(self.frame_19)
- self.distributed_slack_checkBox.setObjectName(u"distributed_slack_checkBox")
+ self.label_6 = QLabel(self.frame_19)
+ self.label_6.setObjectName(u"label_6")
+ self.label_6.setFont(font1)
- self.gridLayout_22.addWidget(self.distributed_slack_checkBox, 4, 0, 1, 2)
+ self.gridLayout_22.addWidget(self.label_6, 10, 0, 1, 1)
- self.label_2 = QLabel(self.frame_19)
- self.label_2.setObjectName(u"label_2")
+ self.label_11 = QLabel(self.frame_19)
+ self.label_11.setObjectName(u"label_11")
+ self.label_11.setFont(font1)
- self.gridLayout_22.addWidget(self.label_2, 0, 0, 1, 1)
+ self.gridLayout_22.addWidget(self.label_11, 9, 0, 1, 1)
- self.verticalSpacer_10 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
-
- self.gridLayout_22.addItem(self.verticalSpacer_10, 15, 0, 1, 1)
+ self.label_5 = QLabel(self.frame_19)
+ self.label_5.setObjectName(u"label_5")
+ self.label_5.setFont(font1)
- self.label_11 = QLabel(self.frame_19)
- self.label_11.setObjectName(u"label_11")
+ self.gridLayout_22.addWidget(self.label_5, 8, 0, 1, 1)
- self.gridLayout_22.addWidget(self.label_11, 11, 0, 1, 1)
+ self.find_automatic_precission_Button = QPushButton(self.frame_19)
+ self.find_automatic_precission_Button.setObjectName(u"find_automatic_precission_Button")
+ self.find_automatic_precission_Button.setMaximumSize(QSize(50, 16777215))
- self.max_iterations_spinBox = QSpinBox(self.frame_19)
- self.max_iterations_spinBox.setObjectName(u"max_iterations_spinBox")
- self.max_iterations_spinBox.setMinimum(1)
- self.max_iterations_spinBox.setMaximum(1000)
- self.max_iterations_spinBox.setValue(40)
-
- self.gridLayout_22.addWidget(self.max_iterations_spinBox, 12, 1, 1, 1)
-
- self.label_6 = QLabel(self.frame_19)
- self.label_6.setObjectName(u"label_6")
-
- self.gridLayout_22.addWidget(self.label_6, 12, 0, 1, 1)
+ self.gridLayout_22.addWidget(self.find_automatic_precission_Button, 8, 2, 1, 1)
self.muSpinBox = QDoubleSpinBox(self.frame_19)
self.muSpinBox.setObjectName(u"muSpinBox")
+ self.muSpinBox.setFont(font1)
self.muSpinBox.setDecimals(4)
self.muSpinBox.setMinimum(0.000100000000000)
self.muSpinBox.setMaximum(1.000000000000000)
self.muSpinBox.setSingleStep(0.100000000000000)
self.muSpinBox.setValue(1.000000000000000)
- self.gridLayout_22.addWidget(self.muSpinBox, 11, 1, 1, 1)
-
- self.use_voltage_guess_checkBox = QCheckBox(self.frame_19)
- self.use_voltage_guess_checkBox.setObjectName(u"use_voltage_guess_checkBox")
-
- self.gridLayout_22.addWidget(self.use_voltage_guess_checkBox, 7, 0, 1, 2)
-
- self.label_87 = QLabel(self.frame_19)
- self.label_87.setObjectName(u"label_87")
-
- self.gridLayout_22.addWidget(self.label_87, 9, 0, 1, 2)
-
- self.ignore_single_node_islands_checkBox = QCheckBox(self.frame_19)
- self.ignore_single_node_islands_checkBox.setObjectName(u"ignore_single_node_islands_checkBox")
- self.ignore_single_node_islands_checkBox.setChecked(True)
-
- self.gridLayout_22.addWidget(self.ignore_single_node_islands_checkBox, 5, 0, 1, 2)
+ self.gridLayout_22.addWidget(self.muSpinBox, 9, 1, 1, 2)
self.solver_comboBox = QComboBox(self.frame_19)
self.solver_comboBox.setObjectName(u"solver_comboBox")
+ self.solver_comboBox.setMinimumSize(QSize(200, 0))
+ self.solver_comboBox.setFont(font1)
- self.gridLayout_22.addWidget(self.solver_comboBox, 1, 0, 1, 2)
+ self.gridLayout_22.addWidget(self.solver_comboBox, 0, 1, 1, 2)
- self.label_23 = QLabel(self.frame_19)
- self.label_23.setObjectName(u"label_23")
+ self.max_iterations_spinBox = QSpinBox(self.frame_19)
+ self.max_iterations_spinBox.setObjectName(u"max_iterations_spinBox")
+ self.max_iterations_spinBox.setFont(font1)
+ self.max_iterations_spinBox.setMinimum(1)
+ self.max_iterations_spinBox.setMaximum(1000)
+ self.max_iterations_spinBox.setValue(40)
- self.gridLayout_22.addWidget(self.label_23, 13, 0, 1, 1)
+ self.gridLayout_22.addWidget(self.max_iterations_spinBox, 10, 1, 1, 2)
- self.addPowerFlowReportCheckBox = QCheckBox(self.frame_19)
- self.addPowerFlowReportCheckBox.setObjectName(u"addPowerFlowReportCheckBox")
+ self.verbositySpinBox = QSpinBox(self.frame_19)
+ self.verbositySpinBox.setObjectName(u"verbositySpinBox")
+ self.verbositySpinBox.setFont(font1)
+ self.verbositySpinBox.setMaximum(2)
- self.gridLayout_22.addWidget(self.addPowerFlowReportCheckBox, 8, 0, 1, 1)
+ self.gridLayout_22.addWidget(self.verbositySpinBox, 11, 1, 1, 2)
self.gridLayout_24.addWidget(self.frame_19, 2, 0, 1, 3)
- self.frame_36 = QFrame(self.pf_tab)
- self.frame_36.setObjectName(u"frame_36")
- self.frame_36.setFrameShape(QFrame.NoFrame)
- self.frame_36.setFrameShadow(QFrame.Plain)
- self.verticalLayout_4 = QVBoxLayout(self.frame_36)
- self.verticalLayout_4.setObjectName(u"verticalLayout_4")
- self.label_48 = QLabel(self.frame_36)
- self.label_48.setObjectName(u"label_48")
-
- self.verticalLayout_4.addWidget(self.label_48)
-
- self.reactive_power_control_mode_comboBox = QComboBox(self.frame_36)
- self.reactive_power_control_mode_comboBox.setObjectName(u"reactive_power_control_mode_comboBox")
-
- self.verticalLayout_4.addWidget(self.reactive_power_control_mode_comboBox)
-
- self.label_641 = QLabel(self.frame_36)
- self.label_641.setObjectName(u"label_641")
-
- self.verticalLayout_4.addWidget(self.label_641)
-
- self.label_50 = QLabel(self.frame_36)
- self.label_50.setObjectName(u"label_50")
-
- self.verticalLayout_4.addWidget(self.label_50)
-
- self.taps_control_mode_comboBox = QComboBox(self.frame_36)
- self.taps_control_mode_comboBox.setObjectName(u"taps_control_mode_comboBox")
-
- self.verticalLayout_4.addWidget(self.taps_control_mode_comboBox)
-
- self.label_65 = QLabel(self.frame_36)
- self.label_65.setObjectName(u"label_65")
-
- self.verticalLayout_4.addWidget(self.label_65)
-
- self.temperature_correction_checkBox = QCheckBox(self.frame_36)
- self.temperature_correction_checkBox.setObjectName(u"temperature_correction_checkBox")
-
- self.verticalLayout_4.addWidget(self.temperature_correction_checkBox)
-
- self.apply_impedance_tolerances_checkBox = QCheckBox(self.frame_36)
- self.apply_impedance_tolerances_checkBox.setObjectName(u"apply_impedance_tolerances_checkBox")
-
- self.verticalLayout_4.addWidget(self.apply_impedance_tolerances_checkBox)
-
- self.override_branch_controls_checkBox = QCheckBox(self.frame_36)
- self.override_branch_controls_checkBox.setObjectName(u"override_branch_controls_checkBox")
-
- self.verticalLayout_4.addWidget(self.override_branch_controls_checkBox)
-
- self.verticalSpacer_14 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
-
- self.verticalLayout_4.addItem(self.verticalSpacer_14)
-
-
- self.gridLayout_24.addWidget(self.frame_36, 2, 3, 1, 1)
-
self.horizontalSpacer_5 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
self.gridLayout_24.addItem(self.horizontalSpacer_5, 2, 6, 1, 1)
@@ -2209,23 +2307,23 @@ def setupUi(self, mainWindow):
self.label_71 = QLabel(self.pf_tab)
self.label_71.setObjectName(u"label_71")
- palette11 = QPalette()
- palette11.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette11.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette11.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_71.setPalette(palette11)
- self.label_71.setFont(font3)
+ palette12 = QPalette()
+ palette12.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette12.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette12.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_71.setPalette(palette12)
+ self.label_71.setFont(font4)
self.label_71.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.gridLayout_24.addWidget(self.label_71, 0, 5, 1, 1)
self.line_22 = QFrame(self.pf_tab)
self.line_22.setObjectName(u"line_22")
- palette12 = QPalette()
- palette12.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette12.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette12.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_22.setPalette(palette12)
+ palette13 = QPalette()
+ palette13.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette13.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette13.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_22.setPalette(palette13)
self.line_22.setFrameShadow(QFrame.Plain)
self.line_22.setLineWidth(4)
self.line_22.setFrameShape(QFrame.Shape.HLine)
@@ -2241,32 +2339,38 @@ def setupUi(self, mainWindow):
self.gridLayout_14.setContentsMargins(-1, 0, -1, -1)
self.ptdf_correct_nonsense_values_checkBox = QCheckBox(self.frame_32)
self.ptdf_correct_nonsense_values_checkBox.setObjectName(u"ptdf_correct_nonsense_values_checkBox")
+ self.ptdf_correct_nonsense_values_checkBox.setFont(font1)
self.ptdf_correct_nonsense_values_checkBox.setChecked(False)
self.gridLayout_14.addWidget(self.ptdf_correct_nonsense_values_checkBox, 3, 0, 1, 2)
self.usePfValuesForAtcCheckBox = QCheckBox(self.frame_32)
self.usePfValuesForAtcCheckBox.setObjectName(u"usePfValuesForAtcCheckBox")
+ self.usePfValuesForAtcCheckBox.setFont(font1)
self.usePfValuesForAtcCheckBox.setChecked(True)
self.gridLayout_14.addWidget(self.usePfValuesForAtcCheckBox, 4, 0, 1, 2)
self.ptdf_distributed_slack_checkBox = QCheckBox(self.frame_32)
self.ptdf_distributed_slack_checkBox.setObjectName(u"ptdf_distributed_slack_checkBox")
+ self.ptdf_distributed_slack_checkBox.setFont(font1)
self.ptdf_distributed_slack_checkBox.setChecked(False)
self.gridLayout_14.addWidget(self.ptdf_distributed_slack_checkBox, 2, 0, 1, 2)
self.ptdf_threshold_doubleSpinBox = QDoubleSpinBox(self.frame_32)
self.ptdf_threshold_doubleSpinBox.setObjectName(u"ptdf_threshold_doubleSpinBox")
+ self.ptdf_threshold_doubleSpinBox.setFont(font1)
self.ptdf_threshold_doubleSpinBox.setDecimals(6)
self.ptdf_threshold_doubleSpinBox.setMaximum(1.000000000000000)
+ self.ptdf_threshold_doubleSpinBox.setSingleStep(0.001000000000000)
self.ptdf_threshold_doubleSpinBox.setValue(0.010000000000000)
self.gridLayout_14.addWidget(self.ptdf_threshold_doubleSpinBox, 6, 1, 1, 1)
self.label_122 = QLabel(self.frame_32)
self.label_122.setObjectName(u"label_122")
+ self.label_122.setFont(font1)
self.gridLayout_14.addWidget(self.label_122, 7, 0, 1, 1)
@@ -2286,14 +2390,17 @@ def setupUi(self, mainWindow):
self.lodf_threshold_doubleSpinBox = QDoubleSpinBox(self.frame_32)
self.lodf_threshold_doubleSpinBox.setObjectName(u"lodf_threshold_doubleSpinBox")
+ self.lodf_threshold_doubleSpinBox.setFont(font1)
self.lodf_threshold_doubleSpinBox.setDecimals(6)
self.lodf_threshold_doubleSpinBox.setMaximum(1.000000000000000)
+ self.lodf_threshold_doubleSpinBox.setSingleStep(0.001000000000000)
self.lodf_threshold_doubleSpinBox.setValue(0.050000000000000)
self.gridLayout_14.addWidget(self.lodf_threshold_doubleSpinBox, 7, 1, 1, 1)
self.label_116 = QLabel(self.frame_32)
self.label_116.setObjectName(u"label_116")
+ self.label_116.setFont(font1)
self.gridLayout_14.addWidget(self.label_116, 6, 0, 1, 1)
@@ -2305,6 +2412,108 @@ def setupUi(self, mainWindow):
self.gridLayout_24.addWidget(self.frame_32, 2, 4, 1, 2)
+ self.frame_36 = QFrame(self.pf_tab)
+ self.frame_36.setObjectName(u"frame_36")
+ self.frame_36.setFrameShape(QFrame.NoFrame)
+ self.frame_36.setFrameShadow(QFrame.Plain)
+ self.verticalLayout_4 = QVBoxLayout(self.frame_36)
+ self.verticalLayout_4.setObjectName(u"verticalLayout_4")
+ self.helm_retry_checkBox = QCheckBox(self.frame_36)
+ self.helm_retry_checkBox.setObjectName(u"helm_retry_checkBox")
+ self.helm_retry_checkBox.setFont(font1)
+ self.helm_retry_checkBox.setChecked(True)
+
+ self.verticalLayout_4.addWidget(self.helm_retry_checkBox)
+
+ self.use_voltage_guess_checkBox = QCheckBox(self.frame_36)
+ self.use_voltage_guess_checkBox.setObjectName(u"use_voltage_guess_checkBox")
+ self.use_voltage_guess_checkBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.use_voltage_guess_checkBox)
+
+ self.ignore_single_node_islands_checkBox = QCheckBox(self.frame_36)
+ self.ignore_single_node_islands_checkBox.setObjectName(u"ignore_single_node_islands_checkBox")
+ self.ignore_single_node_islands_checkBox.setFont(font1)
+ self.ignore_single_node_islands_checkBox.setChecked(True)
+
+ self.verticalLayout_4.addWidget(self.ignore_single_node_islands_checkBox)
+
+ self.label_50 = QLabel(self.frame_36)
+ self.label_50.setObjectName(u"label_50")
+
+ self.verticalLayout_4.addWidget(self.label_50)
+
+ self.distributed_slack_checkBox = QCheckBox(self.frame_36)
+ self.distributed_slack_checkBox.setObjectName(u"distributed_slack_checkBox")
+ self.distributed_slack_checkBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.distributed_slack_checkBox)
+
+ self.control_q_checkBox = QCheckBox(self.frame_36)
+ self.control_q_checkBox.setObjectName(u"control_q_checkBox")
+ self.control_q_checkBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.control_q_checkBox)
+
+ self.control_tap_modules_checkBox = QCheckBox(self.frame_36)
+ self.control_tap_modules_checkBox.setObjectName(u"control_tap_modules_checkBox")
+ self.control_tap_modules_checkBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.control_tap_modules_checkBox)
+
+ self.control_tap_phase_checkBox = QCheckBox(self.frame_36)
+ self.control_tap_phase_checkBox.setObjectName(u"control_tap_phase_checkBox")
+ self.control_tap_phase_checkBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.control_tap_phase_checkBox)
+
+ self.control_remote_voltage_checkBox = QCheckBox(self.frame_36)
+ self.control_remote_voltage_checkBox.setObjectName(u"control_remote_voltage_checkBox")
+ self.control_remote_voltage_checkBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.control_remote_voltage_checkBox)
+
+ self.orthogonalize_pf_controls_checkBox = QCheckBox(self.frame_36)
+ self.orthogonalize_pf_controls_checkBox.setObjectName(u"orthogonalize_pf_controls_checkBox")
+ self.orthogonalize_pf_controls_checkBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.orthogonalize_pf_controls_checkBox)
+
+ self.label_54 = QLabel(self.frame_36)
+ self.label_54.setObjectName(u"label_54")
+
+ self.verticalLayout_4.addWidget(self.label_54)
+
+ self.temperature_correction_checkBox = QCheckBox(self.frame_36)
+ self.temperature_correction_checkBox.setObjectName(u"temperature_correction_checkBox")
+ self.temperature_correction_checkBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.temperature_correction_checkBox)
+
+ self.apply_impedance_tolerances_checkBox = QCheckBox(self.frame_36)
+ self.apply_impedance_tolerances_checkBox.setObjectName(u"apply_impedance_tolerances_checkBox")
+ self.apply_impedance_tolerances_checkBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.apply_impedance_tolerances_checkBox)
+
+ self.label_56 = QLabel(self.frame_36)
+ self.label_56.setObjectName(u"label_56")
+
+ self.verticalLayout_4.addWidget(self.label_56)
+
+ self.addPowerFlowReportCheckBox = QCheckBox(self.frame_36)
+ self.addPowerFlowReportCheckBox.setObjectName(u"addPowerFlowReportCheckBox")
+ self.addPowerFlowReportCheckBox.setFont(font1)
+
+ self.verticalLayout_4.addWidget(self.addPowerFlowReportCheckBox)
+
+ self.verticalSpacer_14 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.verticalLayout_4.addItem(self.verticalSpacer_14)
+
+
+ self.gridLayout_24.addWidget(self.frame_36, 2, 3, 1, 1)
+
self.settings_tabWidget.addTab(self.pf_tab, icon5, "")
self.cpf_tab = QWidget()
self.cpf_tab.setObjectName(u"cpf_tab")
@@ -2319,6 +2528,7 @@ def setupUi(self, mainWindow):
self.gridLayout_2.setContentsMargins(-1, 0, -1, -1)
self.vs_max_iterations_spinBox = QSpinBox(self.frame_21)
self.vs_max_iterations_spinBox.setObjectName(u"vs_max_iterations_spinBox")
+ self.vs_max_iterations_spinBox.setFont(font1)
self.vs_max_iterations_spinBox.setMinimum(1)
self.vs_max_iterations_spinBox.setMaximum(300)
self.vs_max_iterations_spinBox.setValue(20)
@@ -2327,21 +2537,25 @@ def setupUi(self, mainWindow):
self.label_8 = QLabel(self.frame_21)
self.label_8.setObjectName(u"label_8")
+ self.label_8.setFont(font1)
self.gridLayout_2.addWidget(self.label_8, 3, 0, 1, 1)
self.label_25 = QLabel(self.frame_21)
self.label_25.setObjectName(u"label_25")
+ self.label_25.setFont(font1)
self.gridLayout_2.addWidget(self.label_25, 15, 0, 1, 3)
self.vc_stop_at_comboBox = QComboBox(self.frame_21)
self.vc_stop_at_comboBox.setObjectName(u"vc_stop_at_comboBox")
+ self.vc_stop_at_comboBox.setFont(font1)
self.gridLayout_2.addWidget(self.vc_stop_at_comboBox, 3, 1, 1, 2)
self.alpha_doubleSpinBox = QDoubleSpinBox(self.frame_21)
self.alpha_doubleSpinBox.setObjectName(u"alpha_doubleSpinBox")
+ self.alpha_doubleSpinBox.setFont(font1)
self.alpha_doubleSpinBox.setMinimum(-99.000000000000000)
self.alpha_doubleSpinBox.setValue(2.000000000000000)
@@ -2349,11 +2563,11 @@ def setupUi(self, mainWindow):
self.line_17 = QFrame(self.frame_21)
self.line_17.setObjectName(u"line_17")
- palette13 = QPalette()
- palette13.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette13.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette13.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_17.setPalette(palette13)
+ palette14 = QPalette()
+ palette14.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette14.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette14.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_17.setPalette(palette14)
self.line_17.setFrameShadow(QFrame.Plain)
self.line_17.setLineWidth(4)
self.line_17.setFrameShape(QFrame.Shape.HLine)
@@ -2362,6 +2576,7 @@ def setupUi(self, mainWindow):
self.vs_departure_comboBox = QComboBox(self.frame_21)
self.vs_departure_comboBox.setObjectName(u"vs_departure_comboBox")
+ self.vs_departure_comboBox.setFont(font1)
self.gridLayout_2.addWidget(self.vs_departure_comboBox, 11, 1, 1, 2)
@@ -2372,21 +2587,25 @@ def setupUi(self, mainWindow):
self.label_19 = QLabel(self.frame_21)
self.label_19.setObjectName(u"label_19")
+ self.label_19.setFont(font1)
self.gridLayout_2.addWidget(self.label_19, 11, 0, 1, 1)
self.start_vs_from_selected_radioButton = QRadioButton(self.frame_21)
self.start_vs_from_selected_radioButton.setObjectName(u"start_vs_from_selected_radioButton")
+ self.start_vs_from_selected_radioButton.setFont(font1)
self.gridLayout_2.addWidget(self.start_vs_from_selected_radioButton, 10, 0, 1, 3)
self.vs_target_comboBox = QComboBox(self.frame_21)
self.vs_target_comboBox.setObjectName(u"vs_target_comboBox")
+ self.vs_target_comboBox.setFont(font1)
self.gridLayout_2.addWidget(self.vs_target_comboBox, 12, 1, 1, 2)
self.atcRadioButton = QRadioButton(self.frame_21)
self.atcRadioButton.setObjectName(u"atcRadioButton")
+ self.atcRadioButton.setFont(font1)
self.gridLayout_2.addWidget(self.atcRadioButton, 14, 0, 1, 3)
@@ -2397,16 +2616,19 @@ def setupUi(self, mainWindow):
self.label_18 = QLabel(self.frame_21)
self.label_18.setObjectName(u"label_18")
+ self.label_18.setFont(font1)
self.gridLayout_2.addWidget(self.label_18, 8, 0, 1, 1)
self.label_29 = QLabel(self.frame_21)
self.label_29.setObjectName(u"label_29")
+ self.label_29.setFont(font1)
self.gridLayout_2.addWidget(self.label_29, 2, 0, 1, 1)
self.label_20 = QLabel(self.frame_21)
self.label_20.setObjectName(u"label_20")
+ self.label_20.setFont(font1)
self.gridLayout_2.addWidget(self.label_20, 12, 0, 1, 1)
@@ -2433,12 +2655,12 @@ def setupUi(self, mainWindow):
self.label_46 = QLabel(self.frame_44)
self.label_46.setObjectName(u"label_46")
- palette14 = QPalette()
- palette14.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette14.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette14.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_46.setPalette(palette14)
- self.label_46.setFont(font3)
+ palette15 = QPalette()
+ palette15.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette15.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette15.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_46.setPalette(palette15)
+ self.label_46.setFont(font4)
self.label_46.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.horizontalLayout_16.addWidget(self.label_46)
@@ -2448,12 +2670,13 @@ def setupUi(self, mainWindow):
self.label_67 = QLabel(self.frame_21)
self.label_67.setObjectName(u"label_67")
- self.label_67.setFont(font1)
+ self.label_67.setFont(font5)
self.gridLayout_2.addWidget(self.label_67, 5, 0, 1, 3)
self.start_vs_from_default_radioButton = QRadioButton(self.frame_21)
self.start_vs_from_default_radioButton.setObjectName(u"start_vs_from_default_radioButton")
+ self.start_vs_from_default_radioButton.setFont(font1)
self.start_vs_from_default_radioButton.setChecked(True)
self.gridLayout_2.addWidget(self.start_vs_from_default_radioButton, 7, 0, 1, 3)
@@ -2474,99 +2697,32 @@ def setupUi(self, mainWindow):
self.opf_tab.setObjectName(u"opf_tab")
self.gridLayout_10 = QGridLayout(self.opf_tab)
self.gridLayout_10.setObjectName(u"gridLayout_10")
- self.groupBox = QGroupBox(self.opf_tab)
- self.groupBox.setObjectName(u"groupBox")
- font4 = QFont()
- font4.setPointSize(12)
- font4.setBold(False)
- self.groupBox.setFont(font4)
- self.gridLayout_18 = QGridLayout(self.groupBox)
- self.gridLayout_18.setObjectName(u"gridLayout_18")
- self.label_103 = QLabel(self.groupBox)
- self.label_103.setObjectName(u"label_103")
-
- self.gridLayout_18.addWidget(self.label_103, 2, 0, 1, 1)
-
- self.label_104 = QLabel(self.groupBox)
- self.label_104.setObjectName(u"label_104")
-
- self.gridLayout_18.addWidget(self.label_104, 3, 0, 1, 1)
-
- self.opfContingencyToleranceSpinBox = QDoubleSpinBox(self.groupBox)
- self.opfContingencyToleranceSpinBox.setObjectName(u"opfContingencyToleranceSpinBox")
- self.opfContingencyToleranceSpinBox.setDecimals(4)
- self.opfContingencyToleranceSpinBox.setValue(0.050000000000000)
-
- self.gridLayout_18.addWidget(self.opfContingencyToleranceSpinBox, 3, 1, 1, 1)
-
- self.label_10 = QLabel(self.groupBox)
- self.label_10.setObjectName(u"label_10")
-
- self.gridLayout_18.addWidget(self.label_10, 0, 0, 1, 1)
-
- self.label_4 = QLabel(self.groupBox)
- self.label_4.setObjectName(u"label_4")
-
- self.gridLayout_18.addWidget(self.label_4, 1, 0, 1, 1)
-
- self.opfZonalGroupByComboBox = QComboBox(self.groupBox)
- self.opfZonalGroupByComboBox.setObjectName(u"opfZonalGroupByComboBox")
-
- self.gridLayout_18.addWidget(self.opfZonalGroupByComboBox, 2, 1, 1, 1)
-
- self.opf_time_grouping_comboBox = QComboBox(self.groupBox)
- self.opf_time_grouping_comboBox.setObjectName(u"opf_time_grouping_comboBox")
-
- self.gridLayout_18.addWidget(self.opf_time_grouping_comboBox, 1, 1, 1, 1)
-
- self.mip_solver_comboBox = QComboBox(self.groupBox)
- self.mip_solver_comboBox.setObjectName(u"mip_solver_comboBox")
-
- self.gridLayout_18.addWidget(self.mip_solver_comboBox, 0, 1, 1, 1)
-
- self.verticalSpacer_18 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
-
- self.gridLayout_18.addItem(self.verticalSpacer_18, 10, 0, 1, 1)
-
- self.label_132 = QLabel(self.groupBox)
- self.label_132.setObjectName(u"label_132")
-
- self.gridLayout_18.addWidget(self.label_132, 4, 0, 1, 2)
-
- self.considerContingenciesOpfCheckBox = QCheckBox(self.groupBox)
- self.considerContingenciesOpfCheckBox.setObjectName(u"considerContingenciesOpfCheckBox")
-
- self.gridLayout_18.addWidget(self.considerContingenciesOpfCheckBox, 5, 0, 1, 2)
-
- self.save_mip_checkBox = QCheckBox(self.groupBox)
- self.save_mip_checkBox.setObjectName(u"save_mip_checkBox")
-
- self.gridLayout_18.addWidget(self.save_mip_checkBox, 9, 0, 1, 2)
-
-
- self.gridLayout_10.addWidget(self.groupBox, 4, 3, 1, 1)
-
- self.horizontalSpacer_10 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
-
- self.gridLayout_10.addItem(self.horizontalSpacer_10, 4, 5, 1, 1)
-
self.groupBox_3 = QGroupBox(self.opf_tab)
self.groupBox_3.setObjectName(u"groupBox_3")
- self.groupBox_3.setFont(font4)
+ font6 = QFont()
+ font6.setPointSize(12)
+ font6.setBold(False)
+ self.groupBox_3.setFont(font6)
self.gridLayout_27 = QGridLayout(self.groupBox_3)
self.gridLayout_27.setObjectName(u"gridLayout_27")
self.label_127 = QLabel(self.groupBox_3)
self.label_127.setObjectName(u"label_127")
+ font7 = QFont()
+ font7.setPointSize(9)
+ font7.setBold(False)
+ self.label_127.setFont(font7)
self.gridLayout_27.addWidget(self.label_127, 3, 0, 1, 1)
self.ips_method_comboBox = QComboBox(self.groupBox_3)
self.ips_method_comboBox.setObjectName(u"ips_method_comboBox")
+ self.ips_method_comboBox.setFont(font7)
self.gridLayout_27.addWidget(self.ips_method_comboBox, 0, 1, 1, 1)
self.label_125 = QLabel(self.groupBox_3)
self.label_125.setObjectName(u"label_125")
+ self.label_125.setFont(font7)
self.gridLayout_27.addWidget(self.label_125, 0, 0, 1, 1)
@@ -2576,11 +2732,13 @@ def setupUi(self, mainWindow):
self.label_126 = QLabel(self.groupBox_3)
self.label_126.setObjectName(u"label_126")
+ self.label_126.setFont(font7)
self.gridLayout_27.addWidget(self.label_126, 1, 0, 1, 1)
self.ips_tolerance_spinBox = QSpinBox(self.groupBox_3)
self.ips_tolerance_spinBox.setObjectName(u"ips_tolerance_spinBox")
+ self.ips_tolerance_spinBox.setFont(font7)
self.ips_tolerance_spinBox.setMinimum(1)
self.ips_tolerance_spinBox.setMaximum(15)
self.ips_tolerance_spinBox.setValue(4)
@@ -2589,18 +2747,22 @@ def setupUi(self, mainWindow):
self.ips_initialize_with_pf_checkBox = QCheckBox(self.groupBox_3)
self.ips_initialize_with_pf_checkBox.setObjectName(u"ips_initialize_with_pf_checkBox")
+ self.ips_initialize_with_pf_checkBox.setFont(font7)
self.gridLayout_27.addWidget(self.ips_initialize_with_pf_checkBox, 6, 0, 1, 2)
self.ips_trust_radius_doubleSpinBox = QDoubleSpinBox(self.groupBox_3)
self.ips_trust_radius_doubleSpinBox.setObjectName(u"ips_trust_radius_doubleSpinBox")
+ self.ips_trust_radius_doubleSpinBox.setFont(font7)
self.ips_trust_radius_doubleSpinBox.setDecimals(4)
+ self.ips_trust_radius_doubleSpinBox.setSingleStep(0.100000000000000)
self.ips_trust_radius_doubleSpinBox.setValue(1.000000000000000)
self.gridLayout_27.addWidget(self.ips_trust_radius_doubleSpinBox, 3, 1, 1, 1)
self.ips_iterations_spinBox = QSpinBox(self.groupBox_3)
self.ips_iterations_spinBox.setObjectName(u"ips_iterations_spinBox")
+ self.ips_iterations_spinBox.setFont(font7)
self.ips_iterations_spinBox.setMinimum(1)
self.ips_iterations_spinBox.setMaximum(9999999)
self.ips_iterations_spinBox.setValue(100)
@@ -2609,6 +2771,7 @@ def setupUi(self, mainWindow):
self.label_129 = QLabel(self.groupBox_3)
self.label_129.setObjectName(u"label_129")
+ self.label_129.setFont(font7)
self.gridLayout_27.addWidget(self.label_129, 2, 0, 1, 1)
@@ -2618,36 +2781,111 @@ def setupUi(self, mainWindow):
self.gridLayout_27.addWidget(self.label_130, 5, 0, 1, 1)
- self.gridLayout_10.addWidget(self.groupBox_3, 4, 4, 1, 1)
+ self.gridLayout_10.addWidget(self.groupBox_3, 3, 4, 1, 1)
- self.label_72 = QLabel(self.opf_tab)
- self.label_72.setObjectName(u"label_72")
- self.label_72.setMinimumSize(QSize(24, 24))
- self.label_72.setMaximumSize(QSize(24, 24))
- self.label_72.setPixmap(QPixmap(u":/Icons/icons/dcopf.svg"))
- self.label_72.setScaledContents(True)
+ self.horizontalSpacer_10 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
- self.gridLayout_10.addWidget(self.label_72, 0, 0, 1, 1)
+ self.gridLayout_10.addItem(self.horizontalSpacer_10, 3, 5, 1, 1)
+
+ self.groupBox = QGroupBox(self.opf_tab)
+ self.groupBox.setObjectName(u"groupBox")
+ self.groupBox.setFont(font6)
+ self.gridLayout_18 = QGridLayout(self.groupBox)
+ self.gridLayout_18.setObjectName(u"gridLayout_18")
+ self.label_103 = QLabel(self.groupBox)
+ self.label_103.setObjectName(u"label_103")
+ self.label_103.setFont(font7)
+
+ self.gridLayout_18.addWidget(self.label_103, 2, 0, 1, 1)
+
+ self.label_104 = QLabel(self.groupBox)
+ self.label_104.setObjectName(u"label_104")
+ self.label_104.setFont(font7)
+
+ self.gridLayout_18.addWidget(self.label_104, 3, 0, 1, 1)
+
+ self.opfContingencyToleranceSpinBox = QDoubleSpinBox(self.groupBox)
+ self.opfContingencyToleranceSpinBox.setObjectName(u"opfContingencyToleranceSpinBox")
+ self.opfContingencyToleranceSpinBox.setFont(font7)
+ self.opfContingencyToleranceSpinBox.setDecimals(4)
+ self.opfContingencyToleranceSpinBox.setSingleStep(0.010000000000000)
+ self.opfContingencyToleranceSpinBox.setValue(0.050000000000000)
+
+ self.gridLayout_18.addWidget(self.opfContingencyToleranceSpinBox, 3, 1, 1, 1)
+
+ self.label_10 = QLabel(self.groupBox)
+ self.label_10.setObjectName(u"label_10")
+ self.label_10.setFont(font7)
+
+ self.gridLayout_18.addWidget(self.label_10, 0, 0, 1, 1)
+
+ self.label_4 = QLabel(self.groupBox)
+ self.label_4.setObjectName(u"label_4")
+ self.label_4.setFont(font7)
+
+ self.gridLayout_18.addWidget(self.label_4, 1, 0, 1, 1)
+
+ self.opfZonalGroupByComboBox = QComboBox(self.groupBox)
+ self.opfZonalGroupByComboBox.setObjectName(u"opfZonalGroupByComboBox")
+ self.opfZonalGroupByComboBox.setFont(font7)
+
+ self.gridLayout_18.addWidget(self.opfZonalGroupByComboBox, 2, 1, 1, 1)
+
+ self.opf_time_grouping_comboBox = QComboBox(self.groupBox)
+ self.opf_time_grouping_comboBox.setObjectName(u"opf_time_grouping_comboBox")
+ self.opf_time_grouping_comboBox.setFont(font7)
+
+ self.gridLayout_18.addWidget(self.opf_time_grouping_comboBox, 1, 1, 1, 1)
+
+ self.mip_solver_comboBox = QComboBox(self.groupBox)
+ self.mip_solver_comboBox.setObjectName(u"mip_solver_comboBox")
+ self.mip_solver_comboBox.setFont(font7)
+
+ self.gridLayout_18.addWidget(self.mip_solver_comboBox, 0, 1, 1, 1)
+
+ self.verticalSpacer_18 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.gridLayout_18.addItem(self.verticalSpacer_18, 10, 0, 1, 1)
+
+ self.label_132 = QLabel(self.groupBox)
+ self.label_132.setObjectName(u"label_132")
+
+ self.gridLayout_18.addWidget(self.label_132, 4, 0, 1, 2)
+
+ self.considerContingenciesOpfCheckBox = QCheckBox(self.groupBox)
+ self.considerContingenciesOpfCheckBox.setObjectName(u"considerContingenciesOpfCheckBox")
+ self.considerContingenciesOpfCheckBox.setFont(font7)
+
+ self.gridLayout_18.addWidget(self.considerContingenciesOpfCheckBox, 5, 0, 1, 2)
+
+ self.save_mip_checkBox = QCheckBox(self.groupBox)
+ self.save_mip_checkBox.setObjectName(u"save_mip_checkBox")
+ self.save_mip_checkBox.setFont(font7)
+
+ self.gridLayout_18.addWidget(self.save_mip_checkBox, 9, 0, 1, 2)
+
+
+ self.gridLayout_10.addWidget(self.groupBox, 3, 3, 1, 1)
self.label_73 = QLabel(self.opf_tab)
self.label_73.setObjectName(u"label_73")
- palette15 = QPalette()
- palette15.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette15.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette15.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_73.setPalette(palette15)
- self.label_73.setFont(font3)
+ palette16 = QPalette()
+ palette16.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette16.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette16.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_73.setPalette(palette16)
+ self.label_73.setFont(font4)
self.label_73.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.gridLayout_10.addWidget(self.label_73, 0, 1, 1, 1)
self.line_16 = QFrame(self.opf_tab)
self.line_16.setObjectName(u"line_16")
- palette16 = QPalette()
- palette16.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette16.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette16.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_16.setPalette(palette16)
+ palette17 = QPalette()
+ palette17.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette17.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette17.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_16.setPalette(palette17)
self.line_16.setFrameShadow(QFrame.Plain)
self.line_16.setLineWidth(4)
self.line_16.setFrameShape(QFrame.Shape.HLine)
@@ -2656,16 +2894,18 @@ def setupUi(self, mainWindow):
self.groupBox_2 = QGroupBox(self.opf_tab)
self.groupBox_2.setObjectName(u"groupBox_2")
- self.groupBox_2.setFont(font4)
+ self.groupBox_2.setFont(font6)
self.gridLayout_26 = QGridLayout(self.groupBox_2)
self.gridLayout_26.setObjectName(u"gridLayout_26")
self.label_128 = QLabel(self.groupBox_2)
self.label_128.setObjectName(u"label_128")
+ self.label_128.setFont(font7)
self.gridLayout_26.addWidget(self.label_128, 1, 0, 1, 1)
self.label_42 = QLabel(self.groupBox_2)
self.label_42.setObjectName(u"label_42")
+ self.label_42.setFont(font7)
self.gridLayout_26.addWidget(self.label_42, 0, 0, 1, 1)
@@ -2675,16 +2915,19 @@ def setupUi(self, mainWindow):
self.lpf_solver_comboBox = QComboBox(self.groupBox_2)
self.lpf_solver_comboBox.setObjectName(u"lpf_solver_comboBox")
+ self.lpf_solver_comboBox.setFont(font7)
self.gridLayout_26.addWidget(self.lpf_solver_comboBox, 0, 1, 1, 1)
self.ips_verbose_spinBox = QSpinBox(self.groupBox_2)
self.ips_verbose_spinBox.setObjectName(u"ips_verbose_spinBox")
+ self.ips_verbose_spinBox.setFont(font7)
self.gridLayout_26.addWidget(self.ips_verbose_spinBox, 1, 1, 1, 1)
self.addOptimalPowerFlowReportCheckBox = QCheckBox(self.groupBox_2)
self.addOptimalPowerFlowReportCheckBox.setObjectName(u"addOptimalPowerFlowReportCheckBox")
+ self.addOptimalPowerFlowReportCheckBox.setFont(font7)
self.gridLayout_26.addWidget(self.addOptimalPowerFlowReportCheckBox, 6, 0, 1, 2)
@@ -2695,92 +2938,42 @@ def setupUi(self, mainWindow):
self.opfMaximizeExcahngeCheckBox = QCheckBox(self.groupBox_2)
self.opfMaximizeExcahngeCheckBox.setObjectName(u"opfMaximizeExcahngeCheckBox")
+ self.opfMaximizeExcahngeCheckBox.setFont(font7)
self.gridLayout_26.addWidget(self.opfMaximizeExcahngeCheckBox, 5, 0, 1, 2)
self.opfUnitCommitmentCheckBox = QCheckBox(self.groupBox_2)
self.opfUnitCommitmentCheckBox.setObjectName(u"opfUnitCommitmentCheckBox")
+ self.opfUnitCommitmentCheckBox.setFont(font7)
self.gridLayout_26.addWidget(self.opfUnitCommitmentCheckBox, 4, 0, 1, 2)
self.skipOpfGenerationLimitsCheckBox = QCheckBox(self.groupBox_2)
self.skipOpfGenerationLimitsCheckBox.setObjectName(u"skipOpfGenerationLimitsCheckBox")
+ self.skipOpfGenerationLimitsCheckBox.setFont(font7)
self.gridLayout_26.addWidget(self.skipOpfGenerationLimitsCheckBox, 3, 0, 1, 2)
- self.gridLayout_10.addWidget(self.groupBox_2, 4, 0, 1, 3)
+ self.gridLayout_10.addWidget(self.groupBox_2, 3, 0, 1, 3)
- self.label_131 = QLabel(self.opf_tab)
- self.label_131.setObjectName(u"label_131")
+ self.label_72 = QLabel(self.opf_tab)
+ self.label_72.setObjectName(u"label_72")
+ self.label_72.setMinimumSize(QSize(24, 24))
+ self.label_72.setMaximumSize(QSize(24, 24))
+ self.label_72.setPixmap(QPixmap(u":/Icons/icons/dcopf.svg"))
+ self.label_72.setScaledContents(True)
- self.gridLayout_10.addWidget(self.label_131, 3, 0, 1, 3)
+ self.gridLayout_10.addWidget(self.label_72, 0, 0, 1, 1)
self.settings_tabWidget.addTab(self.opf_tab, icon15, "")
self.ntc_tab = QWidget()
self.ntc_tab.setObjectName(u"ntc_tab")
self.gridLayout_13 = QGridLayout(self.ntc_tab)
self.gridLayout_13.setObjectName(u"gridLayout_13")
- self.horizontalSpacer_6 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
-
- self.gridLayout_13.addItem(self.horizontalSpacer_6, 3, 4, 2, 1)
-
- self.line_27 = QFrame(self.ntc_tab)
- self.line_27.setObjectName(u"line_27")
- palette17 = QPalette()
- palette17.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette17.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette17.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_27.setPalette(palette17)
- self.line_27.setFrameShadow(QFrame.Plain)
- self.line_27.setLineWidth(4)
- self.line_27.setFrameShape(QFrame.Shape.HLine)
-
- self.gridLayout_13.addWidget(self.line_27, 1, 0, 1, 4)
-
- self.groupBox_6 = QGroupBox(self.ntc_tab)
- self.groupBox_6.setObjectName(u"groupBox_6")
- self.groupBox_6.setFlat(False)
- self.groupBox_6.setCheckable(False)
- self.gridLayout_29 = QGridLayout(self.groupBox_6)
- self.gridLayout_29.setObjectName(u"gridLayout_29")
- self.verticalSpacer_24 = QSpacerItem(20, 393, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
-
- self.gridLayout_29.addItem(self.verticalSpacer_24, 3, 0, 1, 1)
-
- self.n1ConsiderationCheckBox = QCheckBox(self.groupBox_6)
- self.n1ConsiderationCheckBox.setObjectName(u"n1ConsiderationCheckBox")
- self.n1ConsiderationCheckBox.setChecked(True)
-
- self.gridLayout_29.addWidget(self.n1ConsiderationCheckBox, 2, 0, 1, 2)
-
- self.label_62 = QLabel(self.groupBox_6)
- self.label_62.setObjectName(u"label_62")
-
- self.gridLayout_29.addWidget(self.label_62, 0, 0, 1, 2)
-
- self.atcThresholdSpinBox = QDoubleSpinBox(self.groupBox_6)
- self.atcThresholdSpinBox.setObjectName(u"atcThresholdSpinBox")
- self.atcThresholdSpinBox.setDecimals(4)
- self.atcThresholdSpinBox.setMaximum(1.000000000000000)
- self.atcThresholdSpinBox.setValue(0.050000000000000)
-
- self.gridLayout_29.addWidget(self.atcThresholdSpinBox, 1, 0, 1, 2)
-
-
- self.gridLayout_13.addWidget(self.groupBox_6, 3, 3, 2, 1)
-
- self.label_97 = QLabel(self.ntc_tab)
- self.label_97.setObjectName(u"label_97")
- self.label_97.setMinimumSize(QSize(24, 24))
- self.label_97.setMaximumSize(QSize(24, 24))
- self.label_97.setPixmap(QPixmap(u":/Icons/icons/ntc_opf.svg"))
- self.label_97.setScaledContents(True)
-
- self.gridLayout_13.addWidget(self.label_97, 0, 0, 1, 1)
-
self.groupBox_5 = QGroupBox(self.ntc_tab)
self.groupBox_5.setObjectName(u"groupBox_5")
+ self.groupBox_5.setFont(font5)
self.gridLayout_15 = QGridLayout(self.groupBox_5)
self.gridLayout_15.setObjectName(u"gridLayout_15")
self.label_26 = QLabel(self.groupBox_5)
@@ -2790,20 +2983,28 @@ def setupUi(self, mainWindow):
self.consider_ntc_contingencies_checkBox = QCheckBox(self.groupBox_5)
self.consider_ntc_contingencies_checkBox.setObjectName(u"consider_ntc_contingencies_checkBox")
+ self.consider_ntc_contingencies_checkBox.setFont(font1)
self.gridLayout_15.addWidget(self.consider_ntc_contingencies_checkBox, 11, 0, 1, 2)
self.ntcSelectBasedOnAcerCriteriaCheckBox = QCheckBox(self.groupBox_5)
self.ntcSelectBasedOnAcerCriteriaCheckBox.setObjectName(u"ntcSelectBasedOnAcerCriteriaCheckBox")
+ self.ntcSelectBasedOnAcerCriteriaCheckBox.setFont(font1)
self.gridLayout_15.addWidget(self.ntcSelectBasedOnAcerCriteriaCheckBox, 7, 0, 1, 1)
self.label_105 = QLabel(self.groupBox_5)
self.label_105.setObjectName(u"label_105")
- font5 = QFont()
- font5.setPointSize(12)
- font5.setBold(True)
- self.label_105.setFont(font5)
+ palette18 = QPalette()
+ brush4 = QBrush(QColor(36, 31, 49, 255))
+ brush4.setStyle(Qt.SolidPattern)
+ palette18.setBrush(QPalette.Active, QPalette.WindowText, brush4)
+ brush5 = QBrush(QColor(0, 0, 0, 255))
+ brush5.setStyle(Qt.SolidPattern)
+ palette18.setBrush(QPalette.Inactive, QPalette.WindowText, brush5)
+ palette18.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_105.setPalette(palette18)
+ self.label_105.setFont(font6)
self.gridLayout_15.addWidget(self.label_105, 10, 0, 1, 2)
@@ -2814,6 +3015,7 @@ def setupUi(self, mainWindow):
self.skipNtcGenerationLimitsCheckBox = QCheckBox(self.groupBox_5)
self.skipNtcGenerationLimitsCheckBox.setObjectName(u"skipNtcGenerationLimitsCheckBox")
+ self.skipNtcGenerationLimitsCheckBox.setFont(font1)
self.skipNtcGenerationLimitsCheckBox.setChecked(True)
self.gridLayout_15.addWidget(self.skipNtcGenerationLimitsCheckBox, 0, 0, 1, 2)
@@ -2824,6 +3026,7 @@ def setupUi(self, mainWindow):
self.ntcAlphaSpinBox = QSpinBox(self.groupBox_5)
self.ntcAlphaSpinBox.setObjectName(u"ntcAlphaSpinBox")
+ self.ntcAlphaSpinBox.setFont(font1)
self.ntcAlphaSpinBox.setMaximum(100)
self.ntcAlphaSpinBox.setValue(5)
@@ -2831,18 +3034,25 @@ def setupUi(self, mainWindow):
self.ntcSelectBasedOnExchangeSensitivityCheckBox = QCheckBox(self.groupBox_5)
self.ntcSelectBasedOnExchangeSensitivityCheckBox.setObjectName(u"ntcSelectBasedOnExchangeSensitivityCheckBox")
+ self.ntcSelectBasedOnExchangeSensitivityCheckBox.setFont(font1)
self.ntcSelectBasedOnExchangeSensitivityCheckBox.setChecked(True)
self.gridLayout_15.addWidget(self.ntcSelectBasedOnExchangeSensitivityCheckBox, 5, 0, 1, 1)
self.label_64 = QLabel(self.groupBox_5)
self.label_64.setObjectName(u"label_64")
- self.label_64.setFont(font5)
+ palette19 = QPalette()
+ palette19.setBrush(QPalette.Active, QPalette.WindowText, brush4)
+ palette19.setBrush(QPalette.Inactive, QPalette.WindowText, brush5)
+ palette19.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_64.setPalette(palette19)
+ self.label_64.setFont(font6)
self.gridLayout_15.addWidget(self.label_64, 4, 0, 1, 2)
self.trmSpinBox = QSpinBox(self.groupBox_5)
self.trmSpinBox.setObjectName(u"trmSpinBox")
+ self.trmSpinBox.setFont(font1)
self.trmSpinBox.setMaximum(1500)
self.trmSpinBox.setSingleStep(10)
self.trmSpinBox.setValue(400)
@@ -2852,21 +3062,24 @@ def setupUi(self, mainWindow):
self.label_231 = QLabel(self.groupBox_5)
self.label_231.setObjectName(u"label_231")
+ self.label_231.setFont(font1)
self.gridLayout_15.addWidget(self.label_231, 1, 0, 1, 1)
self.ntcLoadRuleSpinBox = QSpinBox(self.groupBox_5)
self.ntcLoadRuleSpinBox.setObjectName(u"ntcLoadRuleSpinBox")
+ self.ntcLoadRuleSpinBox.setFont(font1)
self.ntcLoadRuleSpinBox.setMaximum(100)
self.ntcLoadRuleSpinBox.setValue(70)
self.gridLayout_15.addWidget(self.ntcLoadRuleSpinBox, 8, 0, 1, 1)
- self.gridLayout_13.addWidget(self.groupBox_5, 3, 2, 2, 1)
+ self.gridLayout_13.addWidget(self.groupBox_5, 2, 2, 2, 1)
self.groupBox_4 = QGroupBox(self.ntc_tab)
self.groupBox_4.setObjectName(u"groupBox_4")
+ self.groupBox_4.setFont(font5)
self.gridLayout_20 = QGridLayout(self.groupBox_4)
self.gridLayout_20.setObjectName(u"gridLayout_20")
self.verticalSpacer_22 = QSpacerItem(20, 325, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
@@ -2875,16 +3088,19 @@ def setupUi(self, mainWindow):
self.label_30 = QLabel(self.groupBox_4)
self.label_30.setObjectName(u"label_30")
+ self.label_30.setFont(font1)
self.gridLayout_20.addWidget(self.label_30, 3, 0, 1, 1)
self.label_77 = QLabel(self.groupBox_4)
self.label_77.setObjectName(u"label_77")
+ self.label_77.setFont(font1)
self.gridLayout_20.addWidget(self.label_77, 1, 0, 1, 1)
self.ntcReportLoadingThresholdSpinBox = QSpinBox(self.groupBox_4)
self.ntcReportLoadingThresholdSpinBox.setObjectName(u"ntcReportLoadingThresholdSpinBox")
+ self.ntcReportLoadingThresholdSpinBox.setFont(font1)
self.ntcReportLoadingThresholdSpinBox.setMaximum(9999)
self.ntcReportLoadingThresholdSpinBox.setValue(98)
@@ -2892,79 +3108,106 @@ def setupUi(self, mainWindow):
self.transferMethodComboBox = QComboBox(self.groupBox_4)
self.transferMethodComboBox.setObjectName(u"transferMethodComboBox")
+ self.transferMethodComboBox.setFont(font1)
self.gridLayout_20.addWidget(self.transferMethodComboBox, 2, 0, 1, 1)
- self.gridLayout_13.addWidget(self.groupBox_4, 3, 0, 2, 2)
+ self.gridLayout_13.addWidget(self.groupBox_4, 2, 0, 2, 2)
- self.label_96 = QLabel(self.ntc_tab)
- self.label_96.setObjectName(u"label_96")
- palette18 = QPalette()
- palette18.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette18.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette18.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_96.setPalette(palette18)
- self.label_96.setFont(font3)
+ self.line_27 = QFrame(self.ntc_tab)
+ self.line_27.setObjectName(u"line_27")
+ palette20 = QPalette()
+ palette20.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette20.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette20.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_27.setPalette(palette20)
+ self.line_27.setFrameShadow(QFrame.Plain)
+ self.line_27.setLineWidth(4)
+ self.line_27.setFrameShape(QFrame.Shape.HLine)
- self.gridLayout_13.addWidget(self.label_96, 0, 1, 1, 1)
+ self.gridLayout_13.addWidget(self.line_27, 1, 0, 1, 4)
- self.label_61 = QLabel(self.ntc_tab)
- self.label_61.setObjectName(u"label_61")
- self.label_61.setMinimumSize(QSize(0, 0))
- self.label_61.setMaximumSize(QSize(16777215, 16))
+ self.label_97 = QLabel(self.ntc_tab)
+ self.label_97.setObjectName(u"label_97")
+ self.label_97.setMinimumSize(QSize(24, 24))
+ self.label_97.setMaximumSize(QSize(24, 24))
+ self.label_97.setPixmap(QPixmap(u":/Icons/icons/ntc_opf.svg"))
+ self.label_97.setScaledContents(True)
- self.gridLayout_13.addWidget(self.label_61, 2, 0, 1, 2)
+ self.gridLayout_13.addWidget(self.label_97, 0, 0, 1, 1)
- self.settings_tabWidget.addTab(self.ntc_tab, icon43, "")
- self.nodal_capacity_tab = QWidget()
- self.nodal_capacity_tab.setObjectName(u"nodal_capacity_tab")
- self.gridLayout_16 = QGridLayout(self.nodal_capacity_tab)
- self.gridLayout_16.setObjectName(u"gridLayout_16")
- self.label_141 = QLabel(self.nodal_capacity_tab)
- self.label_141.setObjectName(u"label_141")
- self.label_141.setMinimumSize(QSize(24, 24))
- self.label_141.setMaximumSize(QSize(24, 24))
- self.label_141.setPixmap(QPixmap(u":/Icons/icons/nodal_capacity.svg"))
- self.label_141.setScaledContents(True)
+ self.horizontalSpacer_6 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
- self.gridLayout_16.addWidget(self.label_141, 0, 0, 1, 1)
+ self.gridLayout_13.addItem(self.horizontalSpacer_6, 2, 4, 2, 1)
- self.label_140 = QLabel(self.nodal_capacity_tab)
- self.label_140.setObjectName(u"label_140")
- palette19 = QPalette()
- palette19.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette19.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette19.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_140.setPalette(palette19)
- self.label_140.setFont(font3)
+ self.groupBox_6 = QGroupBox(self.ntc_tab)
+ self.groupBox_6.setObjectName(u"groupBox_6")
+ self.groupBox_6.setFont(font5)
+ self.groupBox_6.setFlat(False)
+ self.groupBox_6.setCheckable(False)
+ self.gridLayout_29 = QGridLayout(self.groupBox_6)
+ self.gridLayout_29.setObjectName(u"gridLayout_29")
+ self.verticalSpacer_24 = QSpacerItem(20, 393, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
- self.gridLayout_16.addWidget(self.label_140, 0, 1, 1, 1)
+ self.gridLayout_29.addItem(self.verticalSpacer_24, 3, 0, 1, 1)
- self.line_32 = QFrame(self.nodal_capacity_tab)
- self.line_32.setObjectName(u"line_32")
- palette20 = QPalette()
- palette20.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette20.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette20.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_32.setPalette(palette20)
- self.line_32.setFrameShadow(QFrame.Plain)
- self.line_32.setLineWidth(4)
- self.line_32.setFrameShape(QFrame.Shape.HLine)
+ self.n1ConsiderationCheckBox = QCheckBox(self.groupBox_6)
+ self.n1ConsiderationCheckBox.setObjectName(u"n1ConsiderationCheckBox")
+ self.n1ConsiderationCheckBox.setFont(font1)
+ self.n1ConsiderationCheckBox.setChecked(True)
+
+ self.gridLayout_29.addWidget(self.n1ConsiderationCheckBox, 2, 0, 1, 2)
+
+ self.label_62 = QLabel(self.groupBox_6)
+ self.label_62.setObjectName(u"label_62")
+ self.label_62.setFont(font1)
+
+ self.gridLayout_29.addWidget(self.label_62, 0, 0, 1, 2)
+
+ self.atcThresholdSpinBox = QDoubleSpinBox(self.groupBox_6)
+ self.atcThresholdSpinBox.setObjectName(u"atcThresholdSpinBox")
+ self.atcThresholdSpinBox.setFont(font1)
+ self.atcThresholdSpinBox.setDecimals(4)
+ self.atcThresholdSpinBox.setMaximum(1.000000000000000)
+ self.atcThresholdSpinBox.setSingleStep(0.010000000000000)
+ self.atcThresholdSpinBox.setValue(0.050000000000000)
- self.gridLayout_16.addWidget(self.line_32, 1, 0, 1, 3)
+ self.gridLayout_29.addWidget(self.atcThresholdSpinBox, 1, 0, 1, 2)
+
+
+ self.gridLayout_13.addWidget(self.groupBox_6, 2, 3, 2, 1)
+
+ self.label_96 = QLabel(self.ntc_tab)
+ self.label_96.setObjectName(u"label_96")
+ palette21 = QPalette()
+ palette21.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette21.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette21.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_96.setPalette(palette21)
+ self.label_96.setFont(font4)
+
+ self.gridLayout_13.addWidget(self.label_96, 0, 1, 1, 1)
+ self.settings_tabWidget.addTab(self.ntc_tab, icon43, "")
+ self.nodal_capacity_tab = QWidget()
+ self.nodal_capacity_tab.setObjectName(u"nodal_capacity_tab")
+ self.gridLayout_16 = QGridLayout(self.nodal_capacity_tab)
+ self.gridLayout_16.setObjectName(u"gridLayout_16")
self.groupBox_7 = QGroupBox(self.nodal_capacity_tab)
self.groupBox_7.setObjectName(u"groupBox_7")
+ self.groupBox_7.setFont(font5)
self.gridLayout_12 = QGridLayout(self.groupBox_7)
self.gridLayout_12.setObjectName(u"gridLayout_12")
self.label_143 = QLabel(self.groupBox_7)
self.label_143.setObjectName(u"label_143")
+ self.label_143.setFont(font1)
self.gridLayout_12.addWidget(self.label_143, 3, 0, 1, 1)
self.nodal_capacity_sense_SpinBox = QDoubleSpinBox(self.groupBox_7)
self.nodal_capacity_sense_SpinBox.setObjectName(u"nodal_capacity_sense_SpinBox")
+ self.nodal_capacity_sense_SpinBox.setFont(font1)
self.nodal_capacity_sense_SpinBox.setMinimum(-1.000000000000000)
self.nodal_capacity_sense_SpinBox.setMaximum(1.000000000000000)
self.nodal_capacity_sense_SpinBox.setValue(1.000000000000000)
@@ -2973,11 +3216,13 @@ def setupUi(self, mainWindow):
self.label_142 = QLabel(self.groupBox_7)
self.label_142.setObjectName(u"label_142")
+ self.label_142.setFont(font1)
self.gridLayout_12.addWidget(self.label_142, 0, 0, 1, 1)
self.nodal_capacity_method_comboBox = QComboBox(self.groupBox_7)
self.nodal_capacity_method_comboBox.setObjectName(u"nodal_capacity_method_comboBox")
+ self.nodal_capacity_method_comboBox.setFont(font1)
self.gridLayout_12.addWidget(self.nodal_capacity_method_comboBox, 1, 0, 1, 2)
@@ -2991,16 +3236,44 @@ def setupUi(self, mainWindow):
self.gridLayout_12.addWidget(self.label_144, 2, 0, 1, 1)
- self.gridLayout_16.addWidget(self.groupBox_7, 3, 0, 1, 2)
+ self.gridLayout_16.addWidget(self.groupBox_7, 2, 0, 1, 2)
- self.horizontalSpacer_4 = QSpacerItem(630, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
+ self.label_141 = QLabel(self.nodal_capacity_tab)
+ self.label_141.setObjectName(u"label_141")
+ self.label_141.setMinimumSize(QSize(24, 24))
+ self.label_141.setMaximumSize(QSize(24, 24))
+ self.label_141.setPixmap(QPixmap(u":/Icons/icons/nodal_capacity.svg"))
+ self.label_141.setScaledContents(True)
+
+ self.gridLayout_16.addWidget(self.label_141, 0, 0, 1, 1)
+
+ self.line_32 = QFrame(self.nodal_capacity_tab)
+ self.line_32.setObjectName(u"line_32")
+ palette22 = QPalette()
+ palette22.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette22.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette22.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_32.setPalette(palette22)
+ self.line_32.setFrameShadow(QFrame.Plain)
+ self.line_32.setLineWidth(4)
+ self.line_32.setFrameShape(QFrame.Shape.HLine)
+
+ self.gridLayout_16.addWidget(self.line_32, 1, 0, 1, 3)
+
+ self.label_140 = QLabel(self.nodal_capacity_tab)
+ self.label_140.setObjectName(u"label_140")
+ palette23 = QPalette()
+ palette23.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette23.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette23.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_140.setPalette(palette23)
+ self.label_140.setFont(font4)
- self.gridLayout_16.addItem(self.horizontalSpacer_4, 3, 2, 1, 1)
+ self.gridLayout_16.addWidget(self.label_140, 0, 1, 1, 1)
- self.label_145 = QLabel(self.nodal_capacity_tab)
- self.label_145.setObjectName(u"label_145")
+ self.horizontalSpacer_4 = QSpacerItem(630, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
- self.gridLayout_16.addWidget(self.label_145, 2, 0, 1, 2)
+ self.gridLayout_16.addItem(self.horizontalSpacer_4, 2, 2, 1, 1)
self.settings_tabWidget.addTab(self.nodal_capacity_tab, icon68, "")
self.transfer_tab = QWidget()
@@ -3015,11 +3288,11 @@ def setupUi(self, mainWindow):
self.gridLayout_4.setObjectName(u"gridLayout_4")
self.line_26 = QFrame(self.frame_40)
self.line_26.setObjectName(u"line_26")
- palette21 = QPalette()
- palette21.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette21.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette21.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_26.setPalette(palette21)
+ palette24 = QPalette()
+ palette24.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette24.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette24.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_26.setPalette(palette24)
self.line_26.setFrameShadow(QFrame.Plain)
self.line_26.setLineWidth(4)
self.line_26.setFrameShape(QFrame.Shape.HLine)
@@ -3028,12 +3301,12 @@ def setupUi(self, mainWindow):
self.label_95 = QLabel(self.frame_40)
self.label_95.setObjectName(u"label_95")
- palette22 = QPalette()
- palette22.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette22.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette22.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_95.setPalette(palette22)
- self.label_95.setFont(font3)
+ palette25 = QPalette()
+ palette25.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette25.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette25.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_95.setPalette(palette25)
+ self.label_95.setFont(font4)
self.gridLayout_4.addWidget(self.label_95, 0, 1, 1, 1)
@@ -3057,11 +3330,16 @@ def setupUi(self, mainWindow):
self.verticalLayout_29.setObjectName(u"verticalLayout_29")
self.label_41 = QLabel(self.frame_34)
self.label_41.setObjectName(u"label_41")
+ font8 = QFont()
+ font8.setFamilies([u"Ubuntu"])
+ font8.setPointSize(9)
+ self.label_41.setFont(font8)
self.verticalLayout_29.addWidget(self.label_41)
self.areaFromListView = QListView(self.frame_34)
self.areaFromListView.setObjectName(u"areaFromListView")
+ self.areaFromListView.setFont(font8)
self.verticalLayout_29.addWidget(self.areaFromListView)
@@ -3074,11 +3352,13 @@ def setupUi(self, mainWindow):
self.verticalLayout_19.setObjectName(u"verticalLayout_19")
self.label_21 = QLabel(self.frame_35)
self.label_21.setObjectName(u"label_21")
+ self.label_21.setFont(font8)
self.verticalLayout_19.addWidget(self.label_21)
self.areaToListView = QListView(self.frame_35)
self.areaToListView.setObjectName(u"areaToListView")
+ self.areaToListView.setFont(font8)
self.verticalLayout_19.addWidget(self.areaToListView)
@@ -3109,23 +3389,27 @@ def setupUi(self, mainWindow):
self.formLayout.setObjectName(u"formLayout")
self.label_151 = QLabel(self.frame_4)
self.label_151.setObjectName(u"label_151")
+ self.label_151.setFont(font1)
self.formLayout.setWidget(0, QFormLayout.SpanningRole, self.label_151)
self.label_152 = QLabel(self.frame_4)
self.label_152.setObjectName(u"label_152")
self.label_152.setMaximumSize(QSize(80, 16777215))
+ self.label_152.setFont(font1)
self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_152)
self.contingency_filter_by_comboBox = QComboBox(self.frame_4)
self.contingency_filter_by_comboBox.setObjectName(u"contingency_filter_by_comboBox")
+ self.contingency_filter_by_comboBox.setFont(font1)
self.formLayout.setWidget(1, QFormLayout.FieldRole, self.contingency_filter_by_comboBox)
self.contingency_group_filter_listView = QListView(self.frame_4)
self.contingency_group_filter_listView.setObjectName(u"contingency_group_filter_listView")
self.contingency_group_filter_listView.setMinimumSize(QSize(500, 0))
+ self.contingency_group_filter_listView.setFont(font1)
self.formLayout.setWidget(2, QFormLayout.SpanningRole, self.contingency_group_filter_listView)
@@ -3140,6 +3424,7 @@ def setupUi(self, mainWindow):
self.gridLayout_25.setObjectName(u"gridLayout_25")
self.label_123 = QLabel(self.frame_13)
self.label_123.setObjectName(u"label_123")
+ self.label_123.setFont(font1)
self.gridLayout_25.addWidget(self.label_123, 7, 0, 1, 1)
@@ -3150,26 +3435,31 @@ def setupUi(self, mainWindow):
self.label_53 = QLabel(self.frame_13)
self.label_53.setObjectName(u"label_53")
+ self.label_53.setFont(font1)
self.gridLayout_25.addWidget(self.label_53, 5, 0, 1, 1)
self.srap_revert_to_nominal_rating_checkBox = QCheckBox(self.frame_13)
self.srap_revert_to_nominal_rating_checkBox.setObjectName(u"srap_revert_to_nominal_rating_checkBox")
+ self.srap_revert_to_nominal_rating_checkBox.setFont(font1)
self.gridLayout_25.addWidget(self.srap_revert_to_nominal_rating_checkBox, 8, 0, 1, 1)
self.use_srap_checkBox = QCheckBox(self.frame_13)
self.use_srap_checkBox.setObjectName(u"use_srap_checkBox")
+ self.use_srap_checkBox.setFont(font1)
self.gridLayout_25.addWidget(self.use_srap_checkBox, 3, 0, 1, 1)
self.contingency_detailed_massive_report_checkBox = QCheckBox(self.frame_13)
self.contingency_detailed_massive_report_checkBox.setObjectName(u"contingency_detailed_massive_report_checkBox")
+ self.contingency_detailed_massive_report_checkBox.setFont(font1)
self.gridLayout_25.addWidget(self.contingency_detailed_massive_report_checkBox, 9, 0, 1, 1)
self.srap_limit_doubleSpinBox = QDoubleSpinBox(self.frame_13)
self.srap_limit_doubleSpinBox.setObjectName(u"srap_limit_doubleSpinBox")
+ self.srap_limit_doubleSpinBox.setFont(font1)
self.srap_limit_doubleSpinBox.setDecimals(1)
self.srap_limit_doubleSpinBox.setMaximum(9999999.000000000000000)
self.srap_limit_doubleSpinBox.setValue(1400.000000000000000)
@@ -3178,6 +3468,7 @@ def setupUi(self, mainWindow):
self.srap_top_n_SpinBox = QSpinBox(self.frame_13)
self.srap_top_n_SpinBox.setObjectName(u"srap_top_n_SpinBox")
+ self.srap_top_n_SpinBox.setFont(font1)
self.srap_top_n_SpinBox.setMinimum(1)
self.srap_top_n_SpinBox.setMaximum(9999999)
self.srap_top_n_SpinBox.setValue(10)
@@ -3186,6 +3477,7 @@ def setupUi(self, mainWindow):
self.contingency_deadband_SpinBox = QDoubleSpinBox(self.frame_13)
self.contingency_deadband_SpinBox.setObjectName(u"contingency_deadband_SpinBox")
+ self.contingency_deadband_SpinBox.setFont(font1)
self.contingency_deadband_SpinBox.setDecimals(2)
self.contingency_deadband_SpinBox.setValue(0.050000000000000)
@@ -3193,6 +3485,7 @@ def setupUi(self, mainWindow):
self.label_27 = QLabel(self.frame_13)
self.label_27.setObjectName(u"label_27")
+ self.label_27.setFont(font1)
self.gridLayout_25.addWidget(self.label_27, 2, 0, 1, 1)
@@ -3203,11 +3496,13 @@ def setupUi(self, mainWindow):
self.label_119 = QLabel(self.frame_13)
self.label_119.setObjectName(u"label_119")
+ self.label_119.setFont(font1)
self.gridLayout_25.addWidget(self.label_119, 0, 0, 1, 1)
self.srap_deadband_doubleSpinBox = QDoubleSpinBox(self.frame_13)
self.srap_deadband_doubleSpinBox.setObjectName(u"srap_deadband_doubleSpinBox")
+ self.srap_deadband_doubleSpinBox.setFont(font1)
self.srap_deadband_doubleSpinBox.setDecimals(1)
self.srap_deadband_doubleSpinBox.setMaximum(999999999.000000000000000)
self.srap_deadband_doubleSpinBox.setValue(10.000000000000000)
@@ -3220,6 +3515,7 @@ def setupUi(self, mainWindow):
self.contingencyEngineComboBox = QComboBox(self.frame_13)
self.contingencyEngineComboBox.setObjectName(u"contingencyEngineComboBox")
+ self.contingencyEngineComboBox.setFont(font1)
self.gridLayout_25.addWidget(self.contingencyEngineComboBox, 1, 0, 1, 2)
@@ -3244,12 +3540,12 @@ def setupUi(self, mainWindow):
self.label_117 = QLabel(self.frame_78)
self.label_117.setObjectName(u"label_117")
- palette23 = QPalette()
- palette23.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette23.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette23.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_117.setPalette(palette23)
- self.label_117.setFont(font3)
+ palette26 = QPalette()
+ palette26.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette26.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette26.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_117.setPalette(palette26)
+ self.label_117.setFont(font4)
self.label_117.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.horizontalLayout_41.addWidget(self.label_117)
@@ -3263,11 +3559,11 @@ def setupUi(self, mainWindow):
self.line_25 = QFrame(self.frame_76)
self.line_25.setObjectName(u"line_25")
- palette24 = QPalette()
- palette24.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette24.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette24.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_25.setPalette(palette24)
+ palette27 = QPalette()
+ palette27.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette27.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette27.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_25.setPalette(palette27)
self.line_25.setFrameShadow(QFrame.Plain)
self.line_25.setLineWidth(4)
self.line_25.setFrameShape(QFrame.Shape.HLine)
@@ -3289,17 +3585,14 @@ def setupUi(self, mainWindow):
self.gridLayout_21 = QGridLayout(self.frame_18)
self.gridLayout_21.setObjectName(u"gridLayout_21")
self.gridLayout_21.setContentsMargins(-1, 0, -1, -1)
- self.label_121 = QLabel(self.frame_18)
- self.label_121.setObjectName(u"label_121")
- palette25 = QPalette()
- palette25.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette25.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette25.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_121.setPalette(palette25)
- self.label_121.setFont(font3)
- self.label_121.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
+ self.label_7 = QLabel(self.frame_18)
+ self.label_7.setObjectName(u"label_7")
- self.gridLayout_21.addWidget(self.label_121, 18, 1, 1, 1)
+ self.gridLayout_21.addWidget(self.label_7, 12, 0, 1, 2)
+
+ self.verticalSpacer_16 = QSpacerItem(20, 250, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.gridLayout_21.addItem(self.verticalSpacer_16, 29, 1, 1, 1)
self.label_120 = QLabel(self.frame_18)
self.label_120.setObjectName(u"label_120")
@@ -3308,65 +3601,7 @@ def setupUi(self, mainWindow):
self.label_120.setPixmap(QPixmap(u":/Icons/icons/expansion_planning.svg"))
self.label_120.setScaledContents(True)
- self.gridLayout_21.addWidget(self.label_120, 18, 0, 1, 1)
-
- self.label_153 = QLabel(self.frame_18)
- self.label_153.setObjectName(u"label_153")
-
- self.gridLayout_21.addWidget(self.label_153, 22, 0, 1, 2)
-
- self.line_29 = QFrame(self.frame_18)
- self.line_29.setObjectName(u"line_29")
- palette26 = QPalette()
- palette26.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette26.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette26.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_29.setPalette(palette26)
- self.line_29.setFrameShadow(QFrame.Plain)
- self.line_29.setLineWidth(4)
- self.line_29.setFrameShape(QFrame.Shape.HLine)
-
- self.gridLayout_21.addWidget(self.line_29, 9, 0, 1, 3)
-
- self.label_3 = QLabel(self.frame_18)
- self.label_3.setObjectName(u"label_3")
-
- self.gridLayout_21.addWidget(self.label_3, 20, 0, 1, 2)
-
- self.label_88 = QLabel(self.frame_18)
- self.label_88.setObjectName(u"label_88")
- self.label_88.setMinimumSize(QSize(24, 24))
- self.label_88.setMaximumSize(QSize(24, 24))
- self.label_88.setPixmap(QPixmap(u":/Icons/icons/color_grid.svg"))
- self.label_88.setScaledContents(True)
-
- self.gridLayout_21.addWidget(self.label_88, 13, 0, 1, 1)
-
- self.label_51 = QLabel(self.frame_18)
- self.label_51.setObjectName(u"label_51")
-
- self.gridLayout_21.addWidget(self.label_51, 24, 0, 1, 2)
-
- self.node_distances_elements_spinBox = QSpinBox(self.frame_18)
- self.node_distances_elements_spinBox.setObjectName(u"node_distances_elements_spinBox")
- self.node_distances_elements_spinBox.setMinimum(1)
- self.node_distances_elements_spinBox.setMaximum(99999)
- self.node_distances_elements_spinBox.setValue(2)
-
- self.gridLayout_21.addWidget(self.node_distances_elements_spinBox, 16, 0, 1, 2)
-
- self.line_24 = QFrame(self.frame_18)
- self.line_24.setObjectName(u"line_24")
- palette27 = QPalette()
- palette27.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette27.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette27.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_24.setPalette(palette27)
- self.line_24.setFrameShadow(QFrame.Plain)
- self.line_24.setLineWidth(4)
- self.line_24.setFrameShape(QFrame.Shape.HLine)
-
- self.gridLayout_21.addWidget(self.line_24, 14, 0, 1, 2)
+ self.gridLayout_21.addWidget(self.label_120, 21, 0, 1, 1)
self.line_30 = QFrame(self.frame_18)
self.line_30.setObjectName(u"line_30")
@@ -3379,27 +3614,7 @@ def setupUi(self, mainWindow):
self.line_30.setLineWidth(4)
self.line_30.setFrameShape(QFrame.Shape.HLine)
- self.gridLayout_21.addWidget(self.line_30, 19, 0, 1, 2)
-
- self.cluster_number_spinBox = QSpinBox(self.frame_18)
- self.cluster_number_spinBox.setObjectName(u"cluster_number_spinBox")
- self.cluster_number_spinBox.setMinimum(1)
- self.cluster_number_spinBox.setMaximum(999999)
- self.cluster_number_spinBox.setValue(200)
-
- self.gridLayout_21.addWidget(self.cluster_number_spinBox, 11, 0, 1, 3)
-
- self.label_89 = QLabel(self.frame_18)
- self.label_89.setObjectName(u"label_89")
- palette29 = QPalette()
- palette29.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette29.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette29.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_89.setPalette(palette29)
- self.label_89.setFont(font3)
- self.label_89.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
-
- self.gridLayout_21.addWidget(self.label_89, 13, 1, 1, 1)
+ self.gridLayout_21.addWidget(self.line_30, 22, 0, 1, 3)
self.frame_59 = QFrame(self.frame_18)
self.frame_59.setObjectName(u"frame_59")
@@ -3410,12 +3625,12 @@ def setupUi(self, mainWindow):
self.horizontalLayout_32.setContentsMargins(0, 0, 0, 0)
self.label_93 = QLabel(self.frame_59)
self.label_93.setObjectName(u"label_93")
- palette30 = QPalette()
- palette30.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette30.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette30.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_93.setPalette(palette30)
- self.label_93.setFont(font3)
+ palette29 = QPalette()
+ palette29.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette29.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette29.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_93.setPalette(palette29)
+ self.label_93.setFont(font4)
self.label_93.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.horizontalLayout_32.addWidget(self.label_93)
@@ -3423,45 +3638,110 @@ def setupUi(self, mainWindow):
self.gridLayout_21.addWidget(self.frame_59, 8, 1, 1, 1)
+ self.label_33 = QLabel(self.frame_18)
+ self.label_33.setObjectName(u"label_33")
+ self.label_33.setFont(font1)
+
+ self.gridLayout_21.addWidget(self.label_33, 10, 0, 1, 2)
+
+ self.label_31 = QLabel(self.frame_18)
+ self.label_31.setObjectName(u"label_31")
+
+ self.gridLayout_21.addWidget(self.label_31, 20, 0, 1, 1)
+
self.max_investments_evluation_number_spinBox = QSpinBox(self.frame_18)
self.max_investments_evluation_number_spinBox.setObjectName(u"max_investments_evluation_number_spinBox")
+ self.max_investments_evluation_number_spinBox.setFont(font1)
self.max_investments_evluation_number_spinBox.setMinimum(1)
self.max_investments_evluation_number_spinBox.setMaximum(999999999)
self.max_investments_evluation_number_spinBox.setValue(4)
- self.gridLayout_21.addWidget(self.max_investments_evluation_number_spinBox, 25, 0, 1, 2)
+ self.gridLayout_21.addWidget(self.max_investments_evluation_number_spinBox, 27, 2, 1, 1)
- self.label_33 = QLabel(self.frame_18)
- self.label_33.setObjectName(u"label_33")
+ self.label_38 = QLabel(self.frame_18)
+ self.label_38.setObjectName(u"label_38")
+ self.label_38.setFont(font1)
- self.gridLayout_21.addWidget(self.label_33, 10, 0, 1, 2)
+ self.gridLayout_21.addWidget(self.label_38, 16, 0, 1, 2)
- self.node_distances_sigma_doubleSpinBox = QDoubleSpinBox(self.frame_18)
- self.node_distances_sigma_doubleSpinBox.setObjectName(u"node_distances_sigma_doubleSpinBox")
- self.node_distances_sigma_doubleSpinBox.setDecimals(6)
- self.node_distances_sigma_doubleSpinBox.setSingleStep(0.010000000000000)
- self.node_distances_sigma_doubleSpinBox.setValue(0.750000000000000)
+ self.label_3 = QLabel(self.frame_18)
+ self.label_3.setObjectName(u"label_3")
+ self.label_3.setFont(font1)
- self.gridLayout_21.addWidget(self.node_distances_sigma_doubleSpinBox, 15, 0, 1, 2)
+ self.gridLayout_21.addWidget(self.label_3, 23, 0, 1, 2)
- self.label_7 = QLabel(self.frame_18)
- self.label_7.setObjectName(u"label_7")
+ self.line_24 = QFrame(self.frame_18)
+ self.line_24.setObjectName(u"line_24")
+ palette30 = QPalette()
+ palette30.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette30.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette30.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_24.setPalette(palette30)
+ self.line_24.setFrameShadow(QFrame.Plain)
+ self.line_24.setLineWidth(4)
+ self.line_24.setFrameShape(QFrame.Shape.HLine)
- self.gridLayout_21.addWidget(self.label_7, 12, 0, 1, 2)
+ self.gridLayout_21.addWidget(self.line_24, 14, 0, 1, 3)
- self.label_44 = QLabel(self.frame_18)
- self.label_44.setObjectName(u"label_44")
+ self.cluster_number_spinBox = QSpinBox(self.frame_18)
+ self.cluster_number_spinBox.setObjectName(u"cluster_number_spinBox")
+ self.cluster_number_spinBox.setFont(font1)
+ self.cluster_number_spinBox.setMinimum(1)
+ self.cluster_number_spinBox.setMaximum(999999)
+ self.cluster_number_spinBox.setValue(200)
- self.gridLayout_21.addWidget(self.label_44, 17, 0, 1, 2)
+ self.gridLayout_21.addWidget(self.cluster_number_spinBox, 10, 2, 1, 1)
- self.verticalSpacer_16 = QSpacerItem(20, 250, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+ self.label_153 = QLabel(self.frame_18)
+ self.label_153.setObjectName(u"label_153")
+ self.label_153.setFont(font1)
+
+ self.gridLayout_21.addWidget(self.label_153, 25, 0, 1, 2)
+
+ self.label_88 = QLabel(self.frame_18)
+ self.label_88.setObjectName(u"label_88")
+ self.label_88.setMinimumSize(QSize(24, 24))
+ self.label_88.setMaximumSize(QSize(24, 24))
+ self.label_88.setPixmap(QPixmap(u":/Icons/icons/color_grid.svg"))
+ self.label_88.setScaledContents(True)
- self.gridLayout_21.addItem(self.verticalSpacer_16, 26, 1, 1, 1)
+ self.gridLayout_21.addWidget(self.label_88, 13, 0, 1, 1)
self.investment_evaluation_method_ComboBox = QComboBox(self.frame_18)
self.investment_evaluation_method_ComboBox.setObjectName(u"investment_evaluation_method_ComboBox")
+ self.investment_evaluation_method_ComboBox.setFont(font1)
+
+ self.gridLayout_21.addWidget(self.investment_evaluation_method_ComboBox, 23, 2, 1, 1)
+
+ self.label_44 = QLabel(self.frame_18)
+ self.label_44.setObjectName(u"label_44")
+
+ self.gridLayout_21.addWidget(self.label_44, 18, 0, 1, 2)
+
+ self.investment_evaluation_objfunc_ComboBox = QComboBox(self.frame_18)
+ self.investment_evaluation_objfunc_ComboBox.setObjectName(u"investment_evaluation_objfunc_ComboBox")
+ self.investment_evaluation_objfunc_ComboBox.setFont(font1)
+
+ self.gridLayout_21.addWidget(self.investment_evaluation_objfunc_ComboBox, 25, 2, 1, 1)
+
+ self.line_29 = QFrame(self.frame_18)
+ self.line_29.setObjectName(u"line_29")
+ palette31 = QPalette()
+ palette31.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette31.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette31.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_29.setPalette(palette31)
+ self.line_29.setFrameShadow(QFrame.Plain)
+ self.line_29.setLineWidth(4)
+ self.line_29.setFrameShape(QFrame.Shape.HLine)
+
+ self.gridLayout_21.addWidget(self.line_29, 9, 0, 1, 3)
+
+ self.label_51 = QLabel(self.frame_18)
+ self.label_51.setObjectName(u"label_51")
+ self.label_51.setFont(font1)
- self.gridLayout_21.addWidget(self.investment_evaluation_method_ComboBox, 21, 0, 1, 2)
+ self.gridLayout_21.addWidget(self.label_51, 27, 0, 1, 2)
self.label_94 = QLabel(self.frame_18)
self.label_94.setObjectName(u"label_94")
@@ -3470,12 +3750,55 @@ def setupUi(self, mainWindow):
self.label_94.setPixmap(QPixmap(u":/Icons/icons/clustering.svg"))
self.label_94.setScaledContents(True)
- self.gridLayout_21.addWidget(self.label_94, 8, 0, 1, 1)
+ self.gridLayout_21.addWidget(self.label_94, 8, 0, 1, 1)
+
+ self.label_89 = QLabel(self.frame_18)
+ self.label_89.setObjectName(u"label_89")
+ palette32 = QPalette()
+ palette32.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette32.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette32.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_89.setPalette(palette32)
+ self.label_89.setFont(font4)
+ self.label_89.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
+
+ self.gridLayout_21.addWidget(self.label_89, 13, 1, 1, 2)
+
+ self.node_distances_sigma_doubleSpinBox = QDoubleSpinBox(self.frame_18)
+ self.node_distances_sigma_doubleSpinBox.setObjectName(u"node_distances_sigma_doubleSpinBox")
+ self.node_distances_sigma_doubleSpinBox.setFont(font1)
+ self.node_distances_sigma_doubleSpinBox.setDecimals(6)
+ self.node_distances_sigma_doubleSpinBox.setSingleStep(0.010000000000000)
+ self.node_distances_sigma_doubleSpinBox.setValue(0.750000000000000)
+
+ self.gridLayout_21.addWidget(self.node_distances_sigma_doubleSpinBox, 16, 2, 1, 1)
+
+ self.label_121 = QLabel(self.frame_18)
+ self.label_121.setObjectName(u"label_121")
+ palette33 = QPalette()
+ palette33.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette33.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette33.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_121.setPalette(palette33)
+ self.label_121.setFont(font4)
+ self.label_121.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
+
+ self.gridLayout_21.addWidget(self.label_121, 21, 1, 1, 2)
+
+ self.node_distances_elements_spinBox = QSpinBox(self.frame_18)
+ self.node_distances_elements_spinBox.setObjectName(u"node_distances_elements_spinBox")
+ self.node_distances_elements_spinBox.setFont(font1)
+ self.node_distances_elements_spinBox.setMinimum(1)
+ self.node_distances_elements_spinBox.setMaximum(99999)
+ self.node_distances_elements_spinBox.setValue(2)
+
+ self.gridLayout_21.addWidget(self.node_distances_elements_spinBox, 17, 2, 1, 1)
- self.investment_evaluation_objfunc_ComboBox = QComboBox(self.frame_18)
- self.investment_evaluation_objfunc_ComboBox.setObjectName(u"investment_evaluation_objfunc_ComboBox")
+ self.label_61 = QLabel(self.frame_18)
+ self.label_61.setObjectName(u"label_61")
+ self.label_61.setFont(font1)
- self.gridLayout_21.addWidget(self.investment_evaluation_objfunc_ComboBox, 23, 0, 1, 2)
+ self.gridLayout_21.addWidget(self.label_61, 17, 0, 1, 2)
self.horizontalLayout_6.addWidget(self.frame_18)
@@ -3490,11 +3813,13 @@ def setupUi(self, mainWindow):
self.gridLayout_6.setContentsMargins(-1, 0, -1, -1)
self.stochastic_pf_method_comboBox = QComboBox(self.frame_15)
self.stochastic_pf_method_comboBox.setObjectName(u"stochastic_pf_method_comboBox")
+ self.stochastic_pf_method_comboBox.setFont(font1)
self.gridLayout_6.addWidget(self.stochastic_pf_method_comboBox, 3, 2, 1, 1)
self.label_55 = QLabel(self.frame_15)
self.label_55.setObjectName(u"label_55")
+ self.label_55.setFont(font1)
self.gridLayout_6.addWidget(self.label_55, 3, 0, 1, 2)
@@ -3509,45 +3834,47 @@ def setupUi(self, mainWindow):
self.label_79 = QLabel(self.frame_15)
self.label_79.setObjectName(u"label_79")
- palette31 = QPalette()
- palette31.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette31.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette31.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_79.setPalette(palette31)
- self.label_79.setFont(font3)
+ palette34 = QPalette()
+ palette34.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette34.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette34.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_79.setPalette(palette34)
+ self.label_79.setFont(font4)
self.label_79.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.gridLayout_6.addWidget(self.label_79, 8, 1, 1, 2)
self.label_12 = QLabel(self.frame_15)
self.label_12.setObjectName(u"label_12")
+ self.label_12.setFont(font1)
self.gridLayout_6.addWidget(self.label_12, 5, 0, 1, 2)
self.label_13 = QLabel(self.frame_15)
self.label_13.setObjectName(u"label_13")
+ self.label_13.setFont(font1)
self.gridLayout_6.addWidget(self.label_13, 6, 0, 1, 2)
self.label_47 = QLabel(self.frame_15)
self.label_47.setObjectName(u"label_47")
- palette32 = QPalette()
- palette32.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette32.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette32.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_47.setPalette(palette32)
- self.label_47.setFont(font3)
+ palette35 = QPalette()
+ palette35.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette35.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette35.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_47.setPalette(palette35)
+ self.label_47.setFont(font4)
self.label_47.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.gridLayout_6.addWidget(self.label_47, 0, 1, 1, 2)
self.line_4 = QFrame(self.frame_15)
self.line_4.setObjectName(u"line_4")
- palette33 = QPalette()
- palette33.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette33.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette33.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_4.setPalette(palette33)
+ palette36 = QPalette()
+ palette36.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette36.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette36.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_4.setPalette(palette36)
self.line_4.setFrameShadow(QFrame.Plain)
self.line_4.setLineWidth(4)
self.line_4.setFrameShape(QFrame.Shape.HLine)
@@ -3561,11 +3888,11 @@ def setupUi(self, mainWindow):
self.line_10 = QFrame(self.frame_15)
self.line_10.setObjectName(u"line_10")
- palette34 = QPalette()
- palette34.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette34.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette34.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_10.setPalette(palette34)
+ palette37 = QPalette()
+ palette37.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette37.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette37.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_10.setPalette(palette37)
self.line_10.setFrameShadow(QFrame.Plain)
self.line_10.setLineWidth(4)
self.line_10.setFrameShape(QFrame.Shape.HLine)
@@ -3574,6 +3901,7 @@ def setupUi(self, mainWindow):
self.max_iterations_stochastic_spinBox = QSpinBox(self.frame_15)
self.max_iterations_stochastic_spinBox.setObjectName(u"max_iterations_stochastic_spinBox")
+ self.max_iterations_stochastic_spinBox.setFont(font1)
self.max_iterations_stochastic_spinBox.setMinimum(10)
self.max_iterations_stochastic_spinBox.setMaximum(99999999)
self.max_iterations_stochastic_spinBox.setValue(1000)
@@ -3586,6 +3914,7 @@ def setupUi(self, mainWindow):
self.tolerance_stochastic_spinBox = QSpinBox(self.frame_15)
self.tolerance_stochastic_spinBox.setObjectName(u"tolerance_stochastic_spinBox")
+ self.tolerance_stochastic_spinBox.setFont(font1)
self.tolerance_stochastic_spinBox.setMinimum(1)
self.tolerance_stochastic_spinBox.setMaximum(20)
self.tolerance_stochastic_spinBox.setValue(4)
@@ -3603,16 +3932,18 @@ def setupUi(self, mainWindow):
self.label_28 = QLabel(self.frame_15)
self.label_28.setObjectName(u"label_28")
+ self.label_28.setFont(font1)
- self.gridLayout_6.addWidget(self.label_28, 10, 0, 1, 3)
+ self.gridLayout_6.addWidget(self.label_28, 10, 0, 1, 2)
self.cascading_islands_spinBox = QSpinBox(self.frame_15)
self.cascading_islands_spinBox.setObjectName(u"cascading_islands_spinBox")
+ self.cascading_islands_spinBox.setFont(font1)
self.cascading_islands_spinBox.setMinimum(1)
self.cascading_islands_spinBox.setMaximum(999999)
self.cascading_islands_spinBox.setValue(2)
- self.gridLayout_6.addWidget(self.cascading_islands_spinBox, 11, 0, 1, 3)
+ self.gridLayout_6.addWidget(self.cascading_islands_spinBox, 10, 2, 1, 1)
self.horizontalLayout_6.addWidget(self.frame_15)
@@ -3626,118 +3957,93 @@ def setupUi(self, mainWindow):
self.topology_tab.setObjectName(u"topology_tab")
self.gridLayout_17 = QGridLayout(self.topology_tab)
self.gridLayout_17.setObjectName(u"gridLayout_17")
- self.frame_39 = QFrame(self.topology_tab)
- self.frame_39.setObjectName(u"frame_39")
- self.frame_39.setFrameShape(QFrame.NoFrame)
- self.frame_39.setFrameShadow(QFrame.Raised)
- self.verticalLayout_36 = QVBoxLayout(self.frame_39)
- self.verticalLayout_36.setObjectName(u"verticalLayout_36")
- self.verticalLayout_36.setContentsMargins(-1, 0, -1, -1)
- self.frame_49 = QFrame(self.frame_39)
- self.frame_49.setObjectName(u"frame_49")
- self.frame_49.setFrameShape(QFrame.NoFrame)
- self.frame_49.setFrameShadow(QFrame.Raised)
- self.horizontalLayout_21 = QHBoxLayout(self.frame_49)
- self.horizontalLayout_21.setObjectName(u"horizontalLayout_21")
- self.horizontalLayout_21.setContentsMargins(0, 0, 0, 0)
- self.label_82 = QLabel(self.frame_49)
- self.label_82.setObjectName(u"label_82")
- self.label_82.setMinimumSize(QSize(24, 24))
- self.label_82.setMaximumSize(QSize(24, 24))
- self.label_82.setPixmap(QPixmap(u":/Icons/icons/automatic_layout.svg"))
- self.label_82.setScaledContents(True)
-
- self.horizontalLayout_21.addWidget(self.label_82)
-
- self.label_83 = QLabel(self.frame_49)
- self.label_83.setObjectName(u"label_83")
- palette35 = QPalette()
- palette35.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette35.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette35.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_83.setPalette(palette35)
- self.label_83.setFont(font3)
- self.label_83.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
-
- self.horizontalLayout_21.addWidget(self.label_83)
-
+ self.horizontalSpacer_18 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
- self.verticalLayout_36.addWidget(self.frame_49)
+ self.gridLayout_17.addItem(self.horizontalSpacer_18, 0, 2, 1, 1)
- self.line_21 = QFrame(self.frame_39)
- self.line_21.setObjectName(u"line_21")
- palette36 = QPalette()
- palette36.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette36.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette36.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_21.setPalette(palette36)
- self.line_21.setFrameShadow(QFrame.Plain)
- self.line_21.setLineWidth(4)
- self.line_21.setFrameShape(QFrame.Shape.HLine)
+ self.frame_27 = QFrame(self.topology_tab)
+ self.frame_27.setObjectName(u"frame_27")
+ self.frame_27.setFrameShape(QFrame.NoFrame)
+ self.frame_27.setFrameShadow(QFrame.Raised)
+ self.verticalLayout_21 = QVBoxLayout(self.frame_27)
+ self.verticalLayout_21.setObjectName(u"verticalLayout_21")
+ self.verticalLayout_21.setContentsMargins(-1, 0, -1, -1)
+ self.frame_48 = QFrame(self.frame_27)
+ self.frame_48.setObjectName(u"frame_48")
+ self.frame_48.setFrameShape(QFrame.NoFrame)
+ self.frame_48.setFrameShadow(QFrame.Raised)
+ self.horizontalLayout_20 = QHBoxLayout(self.frame_48)
+ self.horizontalLayout_20.setObjectName(u"horizontalLayout_20")
+ self.horizontalLayout_20.setContentsMargins(0, 0, 0, 0)
+ self.label_80 = QLabel(self.frame_48)
+ self.label_80.setObjectName(u"label_80")
+ self.label_80.setMinimumSize(QSize(24, 24))
+ self.label_80.setMaximumSize(QSize(24, 24))
+ self.label_80.setPixmap(QPixmap(u":/Icons/icons/grid_reduction.svg"))
+ self.label_80.setScaledContents(True)
- self.verticalLayout_36.addWidget(self.line_21)
+ self.horizontalLayout_20.addWidget(self.label_80)
- self.label_24 = QLabel(self.frame_39)
- self.label_24.setObjectName(u"label_24")
- self.label_24.setTextFormat(Qt.PlainText)
- self.label_24.setScaledContents(True)
+ self.label_81 = QLabel(self.frame_48)
+ self.label_81.setObjectName(u"label_81")
+ palette38 = QPalette()
+ palette38.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette38.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette38.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_81.setPalette(palette38)
+ self.label_81.setFont(font4)
+ self.label_81.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
- self.verticalLayout_36.addWidget(self.label_24)
+ self.horizontalLayout_20.addWidget(self.label_81)
- self.automatic_layout_comboBox = QComboBox(self.frame_39)
- self.automatic_layout_comboBox.setObjectName(u"automatic_layout_comboBox")
- self.verticalLayout_36.addWidget(self.automatic_layout_comboBox)
+ self.verticalLayout_21.addWidget(self.frame_48)
- self.ask_before_appliying_layout_checkBox = QCheckBox(self.frame_39)
- self.ask_before_appliying_layout_checkBox.setObjectName(u"ask_before_appliying_layout_checkBox")
- self.ask_before_appliying_layout_checkBox.setChecked(True)
- self.ask_before_appliying_layout_checkBox.setTristate(False)
+ self.line_20 = QFrame(self.frame_27)
+ self.line_20.setObjectName(u"line_20")
+ palette39 = QPalette()
+ palette39.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette39.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette39.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_20.setPalette(palette39)
+ self.line_20.setFrameShadow(QFrame.Plain)
+ self.line_20.setLineWidth(4)
+ self.line_20.setFrameShape(QFrame.Shape.HLine)
- self.verticalLayout_36.addWidget(self.ask_before_appliying_layout_checkBox)
+ self.verticalLayout_21.addWidget(self.line_20)
- self.line_13 = QFrame(self.frame_39)
- self.line_13.setObjectName(u"line_13")
- palette37 = QPalette()
- palette37.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette37.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette37.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_13.setPalette(palette37)
- self.line_13.setFrameShadow(QFrame.Plain)
- self.line_13.setLineWidth(4)
- self.line_13.setFrameShape(QFrame.Shape.HLine)
+ self.label_59 = QLabel(self.frame_27)
+ self.label_59.setObjectName(u"label_59")
+ self.label_59.setFont(font1)
- self.verticalLayout_36.addWidget(self.line_13)
+ self.verticalLayout_21.addWidget(self.label_59)
- self.label_60 = QLabel(self.frame_39)
- self.label_60.setObjectName(u"label_60")
+ self.removeByTypeListView = QListView(self.frame_27)
+ self.removeByTypeListView.setObjectName(u"removeByTypeListView")
+ self.removeByTypeListView.setFont(font1)
- self.verticalLayout_36.addWidget(self.label_60)
+ self.verticalLayout_21.addWidget(self.removeByTypeListView)
- self.explosion_factor_doubleSpinBox = QDoubleSpinBox(self.frame_39)
- self.explosion_factor_doubleSpinBox.setObjectName(u"explosion_factor_doubleSpinBox")
- self.explosion_factor_doubleSpinBox.setMinimum(0.000000000000000)
- self.explosion_factor_doubleSpinBox.setMaximum(999999999.000000000000000)
- self.explosion_factor_doubleSpinBox.setValue(1.500000000000000)
+ self.rxThresholdCheckBox = QCheckBox(self.frame_27)
+ self.rxThresholdCheckBox.setObjectName(u"rxThresholdCheckBox")
+ self.rxThresholdCheckBox.setFont(font1)
+ self.rxThresholdCheckBox.setChecked(True)
- self.verticalLayout_36.addWidget(self.explosion_factor_doubleSpinBox)
+ self.verticalLayout_21.addWidget(self.rxThresholdCheckBox)
- self.frame_52 = QFrame(self.frame_39)
- self.frame_52.setObjectName(u"frame_52")
- self.frame_52.setFrameShape(QFrame.NoFrame)
- self.frame_52.setFrameShadow(QFrame.Raised)
- self.horizontalLayout_24 = QHBoxLayout(self.frame_52)
- self.horizontalLayout_24.setObjectName(u"horizontalLayout_24")
- self.horizontalLayout_24.setContentsMargins(0, 0, 0, 0)
+ self.rxThresholdSpinBox = QSpinBox(self.frame_27)
+ self.rxThresholdSpinBox.setObjectName(u"rxThresholdSpinBox")
+ self.rxThresholdSpinBox.setFont(font1)
+ self.rxThresholdSpinBox.setValue(5)
- self.verticalLayout_36.addWidget(self.frame_52)
+ self.verticalLayout_21.addWidget(self.rxThresholdSpinBox)
- self.verticalSpacer_13 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+ self.verticalSpacer_11 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
- self.verticalLayout_36.addItem(self.verticalSpacer_13)
+ self.verticalLayout_21.addItem(self.verticalSpacer_11)
- self.gridLayout_17.addWidget(self.frame_39, 0, 1, 1, 1)
+ self.gridLayout_17.addWidget(self.frame_27, 0, 0, 1, 1)
self.frame_31 = QFrame(self.topology_tab)
self.frame_31.setObjectName(u"frame_31")
@@ -3764,12 +4070,12 @@ def setupUi(self, mainWindow):
self.label_85 = QLabel(self.frame_50)
self.label_85.setObjectName(u"label_85")
- palette38 = QPalette()
- palette38.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette38.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette38.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_85.setPalette(palette38)
- self.label_85.setFont(font3)
+ palette40 = QPalette()
+ palette40.setBrush(QPalette.Active, QPalette.WindowText, brush)
+ palette40.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
+ palette40.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.label_85.setPalette(palette40)
+ self.label_85.setFont(font4)
self.label_85.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.horizontalLayout_22.addWidget(self.label_85)
@@ -3779,11 +4085,11 @@ def setupUi(self, mainWindow):
self.line_8 = QFrame(self.frame_31)
self.line_8.setObjectName(u"line_8")
- palette39 = QPalette()
- palette39.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette39.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette39.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_8.setPalette(palette39)
+ palette41 = QPalette()
+ palette41.setBrush(QPalette.Active, QPalette.WindowText, brush3)
+ palette41.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
+ palette41.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
+ self.line_8.setPalette(palette41)
self.line_8.setFrameShadow(QFrame.Plain)
self.line_8.setLineWidth(4)
self.line_8.setFrameShape(QFrame.Shape.HLine)
@@ -3798,19 +4104,23 @@ def setupUi(self, mainWindow):
self.verticalLayout_15.setObjectName(u"verticalLayout_15")
self.label_34 = QLabel(self.frame_23)
self.label_34.setObjectName(u"label_34")
+ self.label_34.setFont(font1)
self.verticalLayout_15.addWidget(self.label_34)
self.branch_rating_doubleSpinBox = QDoubleSpinBox(self.frame_23)
self.branch_rating_doubleSpinBox.setObjectName(u"branch_rating_doubleSpinBox")
+ self.branch_rating_doubleSpinBox.setFont(font1)
self.branch_rating_doubleSpinBox.setMinimum(1.000000000000000)
self.branch_rating_doubleSpinBox.setMaximum(100.000000000000000)
+ self.branch_rating_doubleSpinBox.setSingleStep(0.100000000000000)
self.branch_rating_doubleSpinBox.setValue(1.200000000000000)
self.verticalLayout_15.addWidget(self.branch_rating_doubleSpinBox)
self.rating_override_checkBox = QCheckBox(self.frame_23)
self.rating_override_checkBox.setObjectName(u"rating_override_checkBox")
+ self.rating_override_checkBox.setFont(font1)
self.verticalLayout_15.addWidget(self.rating_override_checkBox)
@@ -3822,91 +4132,7 @@ def setupUi(self, mainWindow):
self.verticalLayout_25.addItem(self.verticalSpacer_15)
- self.gridLayout_17.addWidget(self.frame_31, 0, 2, 1, 1)
-
- self.horizontalSpacer_18 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
-
- self.gridLayout_17.addItem(self.horizontalSpacer_18, 0, 3, 1, 1)
-
- self.frame_27 = QFrame(self.topology_tab)
- self.frame_27.setObjectName(u"frame_27")
- self.frame_27.setFrameShape(QFrame.NoFrame)
- self.frame_27.setFrameShadow(QFrame.Raised)
- self.verticalLayout_21 = QVBoxLayout(self.frame_27)
- self.verticalLayout_21.setObjectName(u"verticalLayout_21")
- self.verticalLayout_21.setContentsMargins(-1, 0, -1, -1)
- self.frame_48 = QFrame(self.frame_27)
- self.frame_48.setObjectName(u"frame_48")
- self.frame_48.setFrameShape(QFrame.NoFrame)
- self.frame_48.setFrameShadow(QFrame.Raised)
- self.horizontalLayout_20 = QHBoxLayout(self.frame_48)
- self.horizontalLayout_20.setObjectName(u"horizontalLayout_20")
- self.horizontalLayout_20.setContentsMargins(0, 0, 0, 0)
- self.label_80 = QLabel(self.frame_48)
- self.label_80.setObjectName(u"label_80")
- self.label_80.setMinimumSize(QSize(24, 24))
- self.label_80.setMaximumSize(QSize(24, 24))
- self.label_80.setPixmap(QPixmap(u":/Icons/icons/grid_reduction.svg"))
- self.label_80.setScaledContents(True)
-
- self.horizontalLayout_20.addWidget(self.label_80)
-
- self.label_81 = QLabel(self.frame_48)
- self.label_81.setObjectName(u"label_81")
- palette40 = QPalette()
- palette40.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette40.setBrush(QPalette.Inactive, QPalette.WindowText, brush)
- palette40.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.label_81.setPalette(palette40)
- self.label_81.setFont(font3)
- self.label_81.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
-
- self.horizontalLayout_20.addWidget(self.label_81)
-
-
- self.verticalLayout_21.addWidget(self.frame_48)
-
- self.line_20 = QFrame(self.frame_27)
- self.line_20.setObjectName(u"line_20")
- palette41 = QPalette()
- palette41.setBrush(QPalette.Active, QPalette.WindowText, brush3)
- palette41.setBrush(QPalette.Inactive, QPalette.WindowText, brush3)
- palette41.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
- self.line_20.setPalette(palette41)
- self.line_20.setFrameShadow(QFrame.Plain)
- self.line_20.setLineWidth(4)
- self.line_20.setFrameShape(QFrame.Shape.HLine)
-
- self.verticalLayout_21.addWidget(self.line_20)
-
- self.label_59 = QLabel(self.frame_27)
- self.label_59.setObjectName(u"label_59")
-
- self.verticalLayout_21.addWidget(self.label_59)
-
- self.removeByTypeListView = QListView(self.frame_27)
- self.removeByTypeListView.setObjectName(u"removeByTypeListView")
-
- self.verticalLayout_21.addWidget(self.removeByTypeListView)
-
- self.rxThresholdCheckBox = QCheckBox(self.frame_27)
- self.rxThresholdCheckBox.setObjectName(u"rxThresholdCheckBox")
- self.rxThresholdCheckBox.setChecked(True)
-
- self.verticalLayout_21.addWidget(self.rxThresholdCheckBox)
-
- self.rxThresholdSpinBox = QSpinBox(self.frame_27)
- self.rxThresholdSpinBox.setObjectName(u"rxThresholdSpinBox")
- self.rxThresholdSpinBox.setValue(5)
-
- self.verticalLayout_21.addWidget(self.rxThresholdSpinBox)
-
- self.verticalSpacer_11 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
-
- self.verticalLayout_21.addItem(self.verticalSpacer_11)
-
-
- self.gridLayout_17.addWidget(self.frame_27, 0, 0, 1, 1)
+ self.gridLayout_17.addWidget(self.frame_31, 0, 1, 1, 1)
self.settings_tabWidget.addTab(self.topology_tab, icon13, "")
self.file_tab = QWidget()
@@ -3924,12 +4150,10 @@ def setupUi(self, mainWindow):
self.label_115.setObjectName(u"label_115")
palette42 = QPalette()
palette42.setBrush(QPalette.Active, QPalette.WindowText, brush)
- brush4 = QBrush(QColor(0, 0, 0, 255))
- brush4.setStyle(Qt.SolidPattern)
- palette42.setBrush(QPalette.Inactive, QPalette.WindowText, brush4)
+ palette42.setBrush(QPalette.Inactive, QPalette.WindowText, brush5)
palette42.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
self.label_115.setPalette(palette42)
- self.label_115.setFont(font3)
+ self.label_115.setFont(font4)
self.gridLayout_11.addWidget(self.label_115, 0, 1, 1, 1)
@@ -3948,6 +4172,7 @@ def setupUi(self, mainWindow):
self.label_39 = QLabel(self.frame_77)
self.label_39.setObjectName(u"label_39")
+ self.label_39.setFont(font1)
self.gridLayout_11.addWidget(self.label_39, 2, 0, 1, 2)
@@ -3966,21 +4191,25 @@ def setupUi(self, mainWindow):
self.saveResultsCheckBox = QCheckBox(self.frame_77)
self.saveResultsCheckBox.setObjectName(u"saveResultsCheckBox")
+ self.saveResultsCheckBox.setFont(font1)
self.gridLayout_11.addWidget(self.saveResultsCheckBox, 6, 0, 1, 2)
self.user_name_label = QLabel(self.frame_77)
self.user_name_label.setObjectName(u"user_name_label")
+ self.user_name_label.setFont(font1)
self.gridLayout_11.addWidget(self.user_name_label, 5, 0, 1, 2)
self.model_version_label = QLabel(self.frame_77)
self.model_version_label.setObjectName(u"model_version_label")
+ self.model_version_label.setFont(font1)
self.gridLayout_11.addWidget(self.model_version_label, 4, 0, 1, 2)
self.file_information_label = QLabel(self.frame_77)
self.file_information_label.setObjectName(u"file_information_label")
+ self.file_information_label.setFont(font1)
self.file_information_label.setWordWrap(True)
self.file_information_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse|Qt.TextSelectableByKeyboard|Qt.TextSelectableByMouse)
@@ -4000,40 +4229,46 @@ def setupUi(self, mainWindow):
self.label_134.setObjectName(u"label_134")
palette44 = QPalette()
palette44.setBrush(QPalette.Active, QPalette.WindowText, brush)
- palette44.setBrush(QPalette.Inactive, QPalette.WindowText, brush4)
+ palette44.setBrush(QPalette.Inactive, QPalette.WindowText, brush5)
palette44.setBrush(QPalette.Disabled, QPalette.WindowText, brush1)
self.label_134.setPalette(palette44)
- self.label_134.setFont(font3)
+ self.label_134.setFont(font4)
self.gridLayout_5.addWidget(self.label_134, 0, 1, 1, 2)
self.label_135 = QLabel(self.frame_79)
self.label_135.setObjectName(u"label_135")
+ self.label_135.setFont(font1)
self.gridLayout_5.addWidget(self.label_135, 2, 0, 1, 3)
self.cgmes_profiles_listView = QListView(self.frame_79)
self.cgmes_profiles_listView.setObjectName(u"cgmes_profiles_listView")
+ self.cgmes_profiles_listView.setFont(font1)
self.gridLayout_5.addWidget(self.cgmes_profiles_listView, 12, 0, 1, 3)
self.label_90 = QLabel(self.frame_79)
self.label_90.setObjectName(u"label_90")
+ self.label_90.setFont(font1)
self.gridLayout_5.addWidget(self.label_90, 8, 0, 1, 3)
self.cgmes_version_comboBox = QComboBox(self.frame_79)
self.cgmes_version_comboBox.setObjectName(u"cgmes_version_comboBox")
+ self.cgmes_version_comboBox.setFont(font1)
self.gridLayout_5.addWidget(self.cgmes_version_comboBox, 3, 0, 1, 3)
self.label_139 = QLabel(self.frame_79)
self.label_139.setObjectName(u"label_139")
+ self.label_139.setFont(font1)
self.gridLayout_5.addWidget(self.label_139, 11, 0, 1, 3)
self.cgmes_single_profile_per_file_checkBox = QCheckBox(self.frame_79)
self.cgmes_single_profile_per_file_checkBox.setObjectName(u"cgmes_single_profile_per_file_checkBox")
+ self.cgmes_single_profile_per_file_checkBox.setFont(font1)
self.gridLayout_5.addWidget(self.cgmes_single_profile_per_file_checkBox, 13, 0, 1, 3)
@@ -4062,11 +4297,13 @@ def setupUi(self, mainWindow):
self.selectCGMESBoundarySetButton = QPushButton(self.frame_79)
self.selectCGMESBoundarySetButton.setObjectName(u"selectCGMESBoundarySetButton")
self.selectCGMESBoundarySetButton.setMaximumSize(QSize(80, 16777215))
+ self.selectCGMESBoundarySetButton.setFont(font1)
self.gridLayout_5.addWidget(self.selectCGMESBoundarySetButton, 9, 2, 1, 1)
self.cgmes_boundary_set_label = QLabel(self.frame_79)
self.cgmes_boundary_set_label.setObjectName(u"cgmes_boundary_set_label")
+ self.cgmes_boundary_set_label.setFont(font1)
self.gridLayout_5.addWidget(self.cgmes_boundary_set_label, 9, 0, 1, 2)
@@ -4089,6 +4326,7 @@ def setupUi(self, mainWindow):
self.verticalLayout_7.setObjectName(u"verticalLayout_7")
self.server_tableView = QTableView(self.tab_5)
self.server_tableView.setObjectName(u"server_tableView")
+ self.server_tableView.setFont(font1)
self.verticalLayout_7.addWidget(self.server_tableView)
@@ -4101,21 +4339,25 @@ def setupUi(self, mainWindow):
self.horizontalLayout_8.setContentsMargins(0, 0, 0, 0)
self.label_146 = QLabel(self.frame_2)
self.label_146.setObjectName(u"label_146")
+ self.label_146.setFont(font1)
self.horizontalLayout_8.addWidget(self.label_146)
self.server_url_lineEdit = QLineEdit(self.frame_2)
self.server_url_lineEdit.setObjectName(u"server_url_lineEdit")
+ self.server_url_lineEdit.setFont(font1)
self.horizontalLayout_8.addWidget(self.server_url_lineEdit)
self.label_147 = QLabel(self.frame_2)
self.label_147.setObjectName(u"label_147")
+ self.label_147.setFont(font1)
self.horizontalLayout_8.addWidget(self.label_147)
self.server_port_spinBox = QSpinBox(self.frame_2)
self.server_port_spinBox.setObjectName(u"server_port_spinBox")
+ self.server_port_spinBox.setFont(font1)
self.server_port_spinBox.setMaximum(9999999)
self.server_port_spinBox.setValue(8000)
@@ -4123,11 +4365,13 @@ def setupUi(self, mainWindow):
self.label_148 = QLabel(self.frame_2)
self.label_148.setObjectName(u"label_148")
+ self.label_148.setFont(font1)
self.horizontalLayout_8.addWidget(self.label_148)
self.server_pwd_lineEdit = QLineEdit(self.frame_2)
self.server_pwd_lineEdit.setObjectName(u"server_pwd_lineEdit")
+ self.server_pwd_lineEdit.setFont(font1)
self.server_pwd_lineEdit.setEchoMode(QLineEdit.Password)
self.horizontalLayout_8.addWidget(self.server_pwd_lineEdit)
@@ -4138,6 +4382,7 @@ def setupUi(self, mainWindow):
self.server_status_label = QLabel(self.frame_2)
self.server_status_label.setObjectName(u"server_status_label")
+ self.server_status_label.setFont(font1)
self.horizontalLayout_8.addWidget(self.server_status_label)
@@ -4155,7 +4400,8 @@ def setupUi(self, mainWindow):
mainWindow.setCentralWidget(self.centralwidget)
self.menuBar = QMenuBar(mainWindow)
self.menuBar.setObjectName(u"menuBar")
- self.menuBar.setGeometry(QRect(0, 0, 1393, 22))
+ self.menuBar.setGeometry(QRect(0, 0, 1346, 20))
+ self.menuBar.setFont(font)
self.menuProject = QMenu(self.menuBar)
self.menuProject.setObjectName(u"menuProject")
self.menuExport = QMenu(self.menuProject)
@@ -4170,12 +4416,16 @@ def setupUi(self, mainWindow):
self.menuActions.setObjectName(u"menuActions")
self.menuSimulations = QMenu(self.menuBar)
self.menuSimulations.setObjectName(u"menuSimulations")
+ self.menuSimulations.setFont(font)
self.menuModel = QMenu(self.menuBar)
self.menuModel.setObjectName(u"menuModel")
+ self.menuModel.setFont(font)
self.menuDiagrams = QMenu(self.menuBar)
self.menuDiagrams.setObjectName(u"menuDiagrams")
self.menuBus_Branch_options = QMenu(self.menuDiagrams)
self.menuBus_Branch_options.setObjectName(u"menuBus_Branch_options")
+ self.menuplugins = QMenu(self.menuBar)
+ self.menuplugins.setObjectName(u"menuplugins")
mainWindow.setMenuBar(self.menuBar)
self.toolBar = QToolBar(mainWindow)
self.toolBar.setObjectName(u"toolBar")
@@ -4191,6 +4441,7 @@ def setupUi(self, mainWindow):
self.menuBar.addAction(self.menuDiagrams.menuAction())
self.menuBar.addAction(self.menuModel.menuAction())
self.menuBar.addAction(self.menuSimulations.menuAction())
+ self.menuBar.addAction(self.menuplugins.menuAction())
self.menuBar.addAction(self.menuAbout.menuAction())
self.menuProject.addAction(self.actionNew_project)
self.menuProject.addAction(self.actiongrid_Generator)
@@ -4215,21 +4466,23 @@ def setupUi(self, mainWindow):
self.menuActions.addAction(self.actionAdd_default_catalogue)
self.menuActions.addAction(self.actionClear_stuff_running_right_now)
self.menuActions.addAction(self.actionReset_console)
- self.menuSimulations.addAction(self.actionInputs_analysis)
+ self.menuSimulations.addAction(self.actionactivate_time_series)
+ self.menuSimulations.addAction(self.actionEdit_simulation_time_limits)
+ self.menuSimulations.addSeparator()
self.menuSimulations.addAction(self.actionPower_flow)
- self.menuSimulations.addAction(self.actionPower_Flow_Time_series)
- self.menuSimulations.addAction(self.actionStorage_location_suggestion)
+ self.menuSimulations.addAction(self.actionLinearAnalysis)
+ self.menuSimulations.addAction(self.actionSigma_analysis)
+ self.menuSimulations.addSeparator()
self.menuSimulations.addAction(self.actionShort_Circuit)
self.menuSimulations.addAction(self.actionVoltage_stability)
- self.menuSimulations.addAction(self.actionSigma_analysis)
self.menuSimulations.addSeparator()
self.menuSimulations.addAction(self.actionOPF)
- self.menuSimulations.addAction(self.actionOPF_time_series)
- self.menuSimulations.addAction(self.actionOptimal_Net_Transfer_Capacity)
- self.menuSimulations.addAction(self.actionOptimal_Net_Transfer_Capacity_Time_Series)
self.menuSimulations.addAction(self.actionOpf_to_Power_flow)
self.menuSimulations.addAction(self.actionSet_OPF_generation_to_profiles)
self.menuSimulations.addSeparator()
+ self.menuSimulations.addAction(self.actionATC)
+ self.menuSimulations.addAction(self.actionOptimal_Net_Transfer_Capacity)
+ self.menuSimulations.addSeparator()
self.menuSimulations.addAction(self.actionClustering)
self.menuSimulations.addAction(self.actionUse_clustering)
self.menuSimulations.addAction(self.actionFind_node_groups)
@@ -4238,17 +4491,15 @@ def setupUi(self, mainWindow):
self.menuSimulations.addAction(self.actionAdd_selected_as_new_investment)
self.menuSimulations.addAction(self.actionBlackout_cascade)
self.menuSimulations.addSeparator()
- self.menuSimulations.addAction(self.actionLinearAnalysis)
- self.menuSimulations.addAction(self.actionPTDF_time_series)
self.menuSimulations.addAction(self.actionContingency_analysis)
- self.menuSimulations.addAction(self.actionOTDF_time_series)
self.menuSimulations.addAction(self.actionInitialize_contingencies)
self.menuSimulations.addAction(self.actionAdd_selected_to_contingency)
- self.menuSimulations.addAction(self.actionATC)
- self.menuSimulations.addAction(self.actionATC_Time_Series)
+ self.menuSimulations.addSeparator()
+ self.menuSimulations.addAction(self.actionInputs_analysis)
+ self.menuSimulations.addAction(self.actionStorage_location_suggestion)
+ self.menuSimulations.addSeparator()
self.menuModel.addAction(self.actionAuto_rate_branches)
self.menuModel.addAction(self.actionDetect_transformers)
- self.menuModel.addAction(self.actionEdit_simulation_time_limits)
self.menuModel.addAction(self.actionProcess_topology)
self.menuModel.addAction(self.actionDetect_substations)
self.menuModel.addAction(self.actionFuse_devices)
@@ -4334,7 +4585,7 @@ def setupUi(self, mainWindow):
self.tabWidget_5.setCurrentIndex(0)
self.tabWidget_4.setCurrentIndex(0)
self.tabWidget_2.setCurrentIndex(0)
- self.settings_tabWidget.setCurrentIndex(7)
+ self.settings_tabWidget.setCurrentIndex(0)
QMetaObject.connectSlotsByName(mainWindow)
@@ -4670,9 +4921,6 @@ def retranslateUi(self, mainWindow):
self.cancelButton.setToolTip(QCoreApplication.translate("mainWindow", u"Cancel process", None))
#endif // QT_CONFIG(tooltip)
self.cancelButton.setText("")
-#if QT_CONFIG(tooltip)
- self.grid_name_line_edit.setToolTip(QCoreApplication.translate("mainWindow", u"Name of the grid model", None))
-#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(tooltip)
self.diagramsListView.setToolTip(QCoreApplication.translate("mainWindow", u"List of available diagrams", None))
#endif // QT_CONFIG(tooltip)
@@ -4680,51 +4928,57 @@ def retranslateUi(self, mainWindow):
self.available_results_to_color_comboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Available results", None))
#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(tooltip)
- self.colour_results_pushButton.setToolTip(QCoreApplication.translate("mainWindow", u"Color the grid with the selected study", None))
+ self.colour_results_pushButton.setToolTip(QCoreApplication.translate("mainWindow", u"Color the grid with the selected study", None))
+#endif // QT_CONFIG(tooltip)
+ self.colour_results_pushButton.setText("")
+ self.schematic_step_label.setText(QCoreApplication.translate("mainWindow", u"Snapshot", None))
+#if QT_CONFIG(tooltip)
+ self.diagram_step_slider.setToolTip(QCoreApplication.translate("mainWindow", u"
Time slider
Move this time slider to select the appropriate time slot to view.
The first position sets the snapshot values, the rest attend to the time series values.
", None))
+#endif // QT_CONFIG(tooltip)
+ self.tabWidget_6.setTabText(self.tabWidget_6.indexOf(self.tab_3), QCoreApplication.translate("mainWindow", u"Diagrams", None))
+ self.label_9.setText(QCoreApplication.translate("mainWindow", u"Node max. size", None))
+#if QT_CONFIG(tooltip)
+ self.resolution_factor_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Resolution factor.
1K = 1920 x 1080 pixels
", None))
+#endif // QT_CONFIG(tooltip)
+ self.resolution_factor_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" K", None))
+ self.label_118.setText(QCoreApplication.translate("mainWindow", u"Map tile provider", None))
+ self.label_24.setText(QCoreApplication.translate("mainWindow", u"Layout algorithm", None))
+#if QT_CONFIG(tooltip)
+ self.automatic_layout_comboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Algorithm to use for the automatic
layout of the grid nodes
", None))
+#endif // QT_CONFIG(tooltip)
+ self.label_60.setText(QCoreApplication.translate("mainWindow", u"Node expansion factor", None))
+ self.min_node_size_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" px", None))
+ self.label_43.setText(QCoreApplication.translate("mainWindow", u"Palette", None))
+ self.label_15.setText(QCoreApplication.translate("mainWindow", u"Branch max. size", None))
+ self.label_35.setText(QCoreApplication.translate("mainWindow", u"Default voltage", None))
+ self.label.setText(QCoreApplication.translate("mainWindow", u"Node min. size", None))
+ self.label_14.setText(QCoreApplication.translate("mainWindow", u"Branch min. size", None))
+ self.max_branch_size_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" px", None))
+#if QT_CONFIG(tooltip)
+ self.explosion_factor_doubleSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"When expanding or contracting the distances between nodes, this is the factor that applies.
", None))
#endif // QT_CONFIG(tooltip)
- self.colour_results_pushButton.setText("")
- self.schematic_step_label.setText(QCoreApplication.translate("mainWindow", u"Snapshot", None))
+ self.fps_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" FPS", None))
+ self.max_node_size_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" px", None))
+ self.label_150.setText(QCoreApplication.translate("mainWindow", u"Video FPS", None))
#if QT_CONFIG(tooltip)
- self.diagram_step_slider.setToolTip(QCoreApplication.translate("mainWindow", u"Time slider
Move this time slider to select the appropriate time slot to view.
The first position sets the snapshot values, the rest attend to the time series values.
", None))
+ self.ask_before_appliying_layout_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"Ask before running the automatic grid layout. This is because you might have a layout already and ruin it accidentally.", None))
#endif // QT_CONFIG(tooltip)
- self.tabWidget_6.setTabText(self.tabWidget_6.indexOf(self.tab_3), QCoreApplication.translate("mainWindow", u"Diagrams", None))
- self.label_110.setText("")
- self.label_111.setText(QCoreApplication.translate("mainWindow", u"Schematic", None))
- self.label_43.setText(QCoreApplication.translate("mainWindow", u"Palette", None))
- self.label_35.setText(QCoreApplication.translate("mainWindow", u"Default voltage", None))
+ self.ask_before_appliying_layout_checkBox.setText(QCoreApplication.translate("mainWindow", u"Ask before applying", None))
+ self.label_32.setText(QCoreApplication.translate("mainWindow", u"Export resolution", None))
+ self.min_branch_size_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" px", None))
#if QT_CONFIG(tooltip)
self.defaultBusVoltageSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Bus default voltage
This is the voltage that drag&drop buses have when they are created from the schematic.
", None))
#endif // QT_CONFIG(tooltip)
self.defaultBusVoltageSpinBox.setSuffix(QCoreApplication.translate("mainWindow", u" kV", None))
self.label_99.setText("")
self.label_100.setText(QCoreApplication.translate("mainWindow", u"Map", None))
- self.label_118.setText(QCoreApplication.translate("mainWindow", u"Map tile provider", None))
+ self.label_110.setText("")
+ self.label_111.setText(QCoreApplication.translate("mainWindow", u"Schematic", None))
+ self.label_66.setText("")
+ self.label_45.setText(QCoreApplication.translate("mainWindow", u"Export", None))
self.label_156.setText("")
self.label_155.setText(QCoreApplication.translate("mainWindow", u"Display", None))
- self.label.setText(QCoreApplication.translate("mainWindow", u"Node min. size", None))
- self.min_node_size_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" px", None))
- self.label_9.setText(QCoreApplication.translate("mainWindow", u"Node max. size", None))
- self.max_node_size_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" px", None))
- self.label_14.setText(QCoreApplication.translate("mainWindow", u"Branch min. size", None))
- self.min_branch_size_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" px", None))
- self.label_15.setText(QCoreApplication.translate("mainWindow", u"Branch max. size", None))
- self.max_branch_size_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" px", None))
self.branch_width_based_on_flow_checkBox.setText(QCoreApplication.translate("mainWindow", u"Width based on flow", None))
- self.label_66.setText("")
- self.label_45.setText(QCoreApplication.translate("mainWindow", u"Export", None))
- self.label_32.setText(QCoreApplication.translate("mainWindow", u"Export resolution", None))
-#if QT_CONFIG(tooltip)
- self.resolution_factor_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Resolution factor.
1K = 1920 x 1080 pixels
", None))
-#endif // QT_CONFIG(tooltip)
- self.resolution_factor_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" K", None))
- self.label_150.setText(QCoreApplication.translate("mainWindow", u"Video FPS", None))
- self.fps_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" FPS", None))
- self.label_76.setText("")
- self.label_49.setText(QCoreApplication.translate("mainWindow", u"Plotting", None))
- self.label_38.setText(QCoreApplication.translate("mainWindow", u"Style", None))
-#if QT_CONFIG(tooltip)
- self.plt_style_comboBox.setToolTip(QCoreApplication.translate("mainWindow", u"MatPlotlib plot styles to choose from", None))
-#endif // QT_CONFIG(tooltip)
self.tabWidget_6.setTabText(self.tabWidget_6.indexOf(self.tab_4), QCoreApplication.translate("mainWindow", u"Settings", None))
self.tabWidget_3.setTabText(self.tabWidget_3.indexOf(self.GridSectionTab), QCoreApplication.translate("mainWindow", u"Diagrams", None))
#if QT_CONFIG(tooltip)
@@ -4820,14 +5074,14 @@ def retranslateUi(self, mainWindow):
self.set_profile_value_pushButton.setText("")
self.tabWidget_5.setTabText(self.tabWidget_5.indexOf(self.tab_16), QCoreApplication.translate("mainWindow", u"Time series", None))
self.tabWidget_3.setTabText(self.tabWidget_3.indexOf(self.DataTab), QCoreApplication.translate("mainWindow", u"Database", None))
-#if QT_CONFIG(tooltip)
- self.compute_simulation_data_pushButton.setToolTip(QCoreApplication.translate("mainWindow", u"Update the islands dispayed", None))
-#endif // QT_CONFIG(tooltip)
- self.compute_simulation_data_pushButton.setText("")
#if QT_CONFIG(tooltip)
self.exportSimulationDataButton.setToolTip(QCoreApplication.translate("mainWindow", u"Export simulation data", None))
#endif // QT_CONFIG(tooltip)
self.exportSimulationDataButton.setText("")
+#if QT_CONFIG(tooltip)
+ self.compute_simulation_data_pushButton.setToolTip(QCoreApplication.translate("mainWindow", u"Update the islands dispayed", None))
+#endif // QT_CONFIG(tooltip)
+ self.compute_simulation_data_pushButton.setText("")
#if QT_CONFIG(tooltip)
self.copyArraysToNumpyButton.setToolTip(QCoreApplication.translate("mainWindow", u"Copy to data frame to clipboard in array format", None))
#endif // QT_CONFIG(tooltip)
@@ -4927,6 +5181,10 @@ def retranslateUi(self, mainWindow):
self.tabWidget.setTabText(self.tabWidget.indexOf(self.main_console_tab), QCoreApplication.translate("mainWindow", u"Scripting", None))
self.label_68.setText("")
self.label_69.setText(QCoreApplication.translate("mainWindow", u"General settings", None))
+ self.label_82.setText(QCoreApplication.translate("mainWindow", u"Grid name", None))
+#if QT_CONFIG(tooltip)
+ self.grid_name_line_edit.setToolTip(QCoreApplication.translate("mainWindow", u"Name of the grid model", None))
+#endif // QT_CONFIG(tooltip)
self.label_57.setText(QCoreApplication.translate("mainWindow", u"Base power", None))
#if QT_CONFIG(tooltip)
self.sbase_doubleSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Base power
Despite all the bibliography, changing this number to anything other than 100 MVA, might change the meaning of what sensible per-unit voltage are.
This is, 1.0 is no longer the nominal voltage and so on.
", None))
@@ -4939,9 +5197,16 @@ def retranslateUi(self, mainWindow):
self.fbase_doubleSpinBox.setSuffix(QCoreApplication.translate("mainWindow", u" Hz", None))
self.label_101.setText(QCoreApplication.translate("mainWindow", u"Snapshot time", None))
self.label_40.setText("")
- self.label_31.setText(QCoreApplication.translate("mainWindow", u"Engine", None))
+ self.label_86.setText("")
+ self.label_65.setText(QCoreApplication.translate("mainWindow", u"Engine", None))
#if QT_CONFIG(tooltip)
self.engineComboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Engine to be used when available", None))
+#endif // QT_CONFIG(tooltip)
+ self.label_48.setText("")
+ self.label_76.setText("")
+ self.label_49.setText(QCoreApplication.translate("mainWindow", u"Plotting", None))
+#if QT_CONFIG(tooltip)
+ self.plt_style_comboBox.setToolTip(QCoreApplication.translate("mainWindow", u"MatPlotlib plot styles to choose from", None))
#endif // QT_CONFIG(tooltip)
self.dark_mode_checkBox.setText(QCoreApplication.translate("mainWindow", u"Dark mode", None))
#if QT_CONFIG(tooltip)
@@ -4952,58 +5217,29 @@ def retranslateUi(self, mainWindow):
#endif // QT_CONFIG(tooltip)
self.label_63.setText("")
self.label_17.setText(QCoreApplication.translate("mainWindow", u"Power flow", None))
-#if QT_CONFIG(tooltip)
- self.auto_precision_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"If active, GridCal finds a precission that suits the magnitude of the power injections so that the power flow is meaningful", None))
-#endif // QT_CONFIG(tooltip)
- self.auto_precision_checkBox.setText(QCoreApplication.translate("mainWindow", u"Automatic precision", None))
-#if QT_CONFIG(tooltip)
- self.helm_retry_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"If the selected method does not converge, try a list of methods that may help
", None))
-#endif // QT_CONFIG(tooltip)
- self.helm_retry_checkBox.setText(QCoreApplication.translate("mainWindow", u"Retry with other methods if failed", None))
-#if QT_CONFIG(tooltip)
- self.verbositySpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Level of console information. 0: None, 1: some information, 2: all the information", None))
-#endif // QT_CONFIG(tooltip)
- self.label_5.setText(QCoreApplication.translate("mainWindow", u"Tolerance", None))
- self.label_86.setText("")
+ self.label_2.setText(QCoreApplication.translate("mainWindow", u"Solver", None))
self.label_22.setText("")
+ self.label_23.setText(QCoreApplication.translate("mainWindow", u"Verbosity", None))
#if QT_CONFIG(tooltip)
self.tolerance_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Error tolerance of the method
", None))
#endif // QT_CONFIG(tooltip)
self.tolerance_spinBox.setPrefix(QCoreApplication.translate("mainWindow", u"1e-", None))
-#if QT_CONFIG(tooltip)
- self.distributed_slack_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"If active, the slack power is distributed among the generators according to their installed power "Snom"
", None))
-#endif // QT_CONFIG(tooltip)
- self.distributed_slack_checkBox.setText(QCoreApplication.translate("mainWindow", u"Distributed slack", None))
- self.label_2.setText(QCoreApplication.translate("mainWindow", u"Solver", None))
+ self.label_6.setText(QCoreApplication.translate("mainWindow", u"Max. iterations", None))
self.label_11.setText(QCoreApplication.translate("mainWindow", u"Trust radius", None))
+ self.label_5.setText(QCoreApplication.translate("mainWindow", u"Tolerance", None))
#if QT_CONFIG(tooltip)
- self.max_iterations_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Maximum numberof iterations to use.
Tipical values:
Newton Raphson: 5
Levenberg-Marquards: 20
Fast decoupled: 10
Others: 20
", None))
+ self.find_automatic_precission_Button.setToolTip(QCoreApplication.translate("mainWindow", u"Find the tolerance that best represents the load values for power flow", None))
#endif // QT_CONFIG(tooltip)
- self.label_6.setText(QCoreApplication.translate("mainWindow", u"Max. iterations", None))
+ self.find_automatic_precission_Button.setText(QCoreApplication.translate("mainWindow", u"Find", None))
#if QT_CONFIG(tooltip)
self.muSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Factor that multiplies each increment solution.
In practice this is used to slow down troublesome solutions.
", None))
#endif // QT_CONFIG(tooltip)
- self.use_voltage_guess_checkBox.setText(QCoreApplication.translate("mainWindow", u"Use voltage guess", None))
- self.label_87.setText("")
-#if QT_CONFIG(tooltip)
- self.ignore_single_node_islands_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"If active, the islands of a single node are ignored.", None))
-#endif // QT_CONFIG(tooltip)
- self.ignore_single_node_islands_checkBox.setText(QCoreApplication.translate("mainWindow", u"Ignore single node islands", None))
- self.label_23.setText(QCoreApplication.translate("mainWindow", u"Verbosity", None))
#if QT_CONFIG(tooltip)
- self.addPowerFlowReportCheckBox.setToolTip(QCoreApplication.translate("mainWindow", u"Add a results report in the logs", None))
+ self.max_iterations_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Maximum numberof iterations to use.
Tipical values:
Newton Raphson: 5
Levenberg-Marquards: 20
Fast decoupled: 10
Others: 20
", None))
#endif // QT_CONFIG(tooltip)
- self.addPowerFlowReportCheckBox.setText(QCoreApplication.translate("mainWindow", u"Add report", None))
- self.label_48.setText(QCoreApplication.translate("mainWindow", u"Reactive power control mode", None))
- self.label_641.setText("")
- self.label_50.setText(QCoreApplication.translate("mainWindow", u"Transformer taps control mode", None))
- self.label_65.setText("")
#if QT_CONFIG(tooltip)
- self.temperature_correction_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"Correct the branches resistance using the temperature", None))
+ self.verbositySpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Level of console information. 0: None, 1: some information, 2: all the information", None))
#endif // QT_CONFIG(tooltip)
- self.temperature_correction_checkBox.setText(QCoreApplication.translate("mainWindow", u"Apply temperature correction", None))
- self.apply_impedance_tolerances_checkBox.setText(QCoreApplication.translate("mainWindow", u"Apply impedance tolerances", None))
- self.override_branch_controls_checkBox.setText(QCoreApplication.translate("mainWindow", u"Override branch controls", None))
self.label_70.setText("")
self.label_71.setText(QCoreApplication.translate("mainWindow", u"PTDF / LODF", None))
self.ptdf_correct_nonsense_values_checkBox.setText(QCoreApplication.translate("mainWindow", u"Correct nonsense values", None))
@@ -5021,6 +5257,51 @@ def retranslateUi(self, mainWindow):
#endif // QT_CONFIG(tooltip)
self.label_116.setText(QCoreApplication.translate("mainWindow", u"PTDF threshold", None))
self.label_124.setText("")
+#if QT_CONFIG(tooltip)
+ self.helm_retry_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"If the selected method does not converge, try a list of methods that may help
", None))
+#endif // QT_CONFIG(tooltip)
+ self.helm_retry_checkBox.setText(QCoreApplication.translate("mainWindow", u"Retry with other methods if failed", None))
+ self.use_voltage_guess_checkBox.setText(QCoreApplication.translate("mainWindow", u"Use voltage guess", None))
+#if QT_CONFIG(tooltip)
+ self.ignore_single_node_islands_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"If active, the islands of a single node are ignored.", None))
+#endif // QT_CONFIG(tooltip)
+ self.ignore_single_node_islands_checkBox.setText(QCoreApplication.translate("mainWindow", u"Ignore single node islands", None))
+ self.label_50.setText("")
+#if QT_CONFIG(tooltip)
+ self.distributed_slack_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"If active, the slack power is distributed among the generators according to their installed power "Snom"
", None))
+#endif // QT_CONFIG(tooltip)
+ self.distributed_slack_checkBox.setText(QCoreApplication.translate("mainWindow", u"Distributed slack", None))
+#if QT_CONFIG(tooltip)
+ self.control_q_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"General switch for reactive power limits control", None))
+#endif // QT_CONFIG(tooltip)
+ self.control_q_checkBox.setText(QCoreApplication.translate("mainWindow", u"Control generators Q", None))
+#if QT_CONFIG(tooltip)
+ self.control_tap_modules_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"General switch for branches tap module control", None))
+#endif // QT_CONFIG(tooltip)
+ self.control_tap_modules_checkBox.setText(QCoreApplication.translate("mainWindow", u"Control tap module", None))
+#if QT_CONFIG(tooltip)
+ self.control_tap_phase_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"General switch for branches tap phase control", None))
+#endif // QT_CONFIG(tooltip)
+ self.control_tap_phase_checkBox.setText(QCoreApplication.translate("mainWindow", u"Control tap phase", None))
+#if QT_CONFIG(tooltip)
+ self.control_remote_voltage_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"General switch for generators remote voltage control", None))
+#endif // QT_CONFIG(tooltip)
+ self.control_remote_voltage_checkBox.setText(QCoreApplication.translate("mainWindow", u"Control remote voltage", None))
+#if QT_CONFIG(tooltip)
+ self.orthogonalize_pf_controls_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"If checked, the controls are adjusted to their closest tap", None))
+#endif // QT_CONFIG(tooltip)
+ self.orthogonalize_pf_controls_checkBox.setText(QCoreApplication.translate("mainWindow", u"Orthogonalize controls", None))
+ self.label_54.setText("")
+#if QT_CONFIG(tooltip)
+ self.temperature_correction_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"Correct the branches resistance using the temperature", None))
+#endif // QT_CONFIG(tooltip)
+ self.temperature_correction_checkBox.setText(QCoreApplication.translate("mainWindow", u"Apply temperature correction", None))
+ self.apply_impedance_tolerances_checkBox.setText(QCoreApplication.translate("mainWindow", u"Apply impedance tolerances", None))
+ self.label_56.setText("")
+#if QT_CONFIG(tooltip)
+ self.addPowerFlowReportCheckBox.setToolTip(QCoreApplication.translate("mainWindow", u"Add a results report in the logs", None))
+#endif // QT_CONFIG(tooltip)
+ self.addPowerFlowReportCheckBox.setText(QCoreApplication.translate("mainWindow", u"Add report", None))
self.settings_tabWidget.setTabText(self.settings_tabWidget.indexOf(self.pf_tab), QCoreApplication.translate("mainWindow", u"Pf", None))
#if QT_CONFIG(tooltip)
self.settings_tabWidget.setTabToolTip(self.settings_tabWidget.indexOf(self.pf_tab), QCoreApplication.translate("mainWindow", u"Power flow settings", None))
@@ -5050,26 +5331,6 @@ def retranslateUi(self, mainWindow):
#if QT_CONFIG(tooltip)
self.opf_tab.setToolTip(QCoreApplication.translate("mainWindow", u"Optimal power flow settings", None))
#endif // QT_CONFIG(tooltip)
- self.groupBox.setTitle(QCoreApplication.translate("mainWindow", u"Linear settings", None))
- self.label_103.setText(QCoreApplication.translate("mainWindow", u"Zone grouping", None))
- self.label_104.setText(QCoreApplication.translate("mainWindow", u"Contingency tolerance", None))
-#if QT_CONFIG(tooltip)
- self.opfContingencyToleranceSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"LODF matrix tolerance choosing contingencies", None))
-#endif // QT_CONFIG(tooltip)
- self.label_10.setText(QCoreApplication.translate("mainWindow", u"MIP solver", None))
- self.label_4.setText(QCoreApplication.translate("mainWindow", u"Time grouping", None))
-#if QT_CONFIG(tooltip)
- self.opf_time_grouping_comboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Choose the time grouping to possibly shorten the solution time.
This splits the time series by week, month, etc. and the subproblems are solved sequentially.
", None))
-#endif // QT_CONFIG(tooltip)
-#if QT_CONFIG(tooltip)
- self.mip_solver_comboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Choose the external mixed integer programming solver", None))
-#endif // QT_CONFIG(tooltip)
- self.label_132.setText("")
- self.considerContingenciesOpfCheckBox.setText(QCoreApplication.translate("mainWindow", u"Consider contingencies", None))
-#if QT_CONFIG(tooltip)
- self.save_mip_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"The program will save the MIP file in .lp format in the user GridCal folder before running a linear optimization study.
", None))
-#endif // QT_CONFIG(tooltip)
- self.save_mip_checkBox.setText(QCoreApplication.translate("mainWindow", u"Save MIP file", None))
self.groupBox_3.setTitle(QCoreApplication.translate("mainWindow", u"Nonlinear settings", None))
#if QT_CONFIG(tooltip)
self.label_127.setToolTip(QCoreApplication.translate("mainWindow", u"Interior point trust radius", None))
@@ -5102,7 +5363,26 @@ def retranslateUi(self, mainWindow):
#endif // QT_CONFIG(tooltip)
self.label_129.setText(QCoreApplication.translate("mainWindow", u"Iterations", None))
self.label_130.setText("")
- self.label_72.setText("")
+ self.groupBox.setTitle(QCoreApplication.translate("mainWindow", u"Linear settings", None))
+ self.label_103.setText(QCoreApplication.translate("mainWindow", u"Zone grouping", None))
+ self.label_104.setText(QCoreApplication.translate("mainWindow", u"Contingency tolerance", None))
+#if QT_CONFIG(tooltip)
+ self.opfContingencyToleranceSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"LODF matrix tolerance choosing contingencies", None))
+#endif // QT_CONFIG(tooltip)
+ self.label_10.setText(QCoreApplication.translate("mainWindow", u"MIP solver", None))
+ self.label_4.setText(QCoreApplication.translate("mainWindow", u"Time grouping", None))
+#if QT_CONFIG(tooltip)
+ self.opf_time_grouping_comboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Choose the time grouping to possibly shorten the solution time.
This splits the time series by week, month, etc. and the subproblems are solved sequentially.
", None))
+#endif // QT_CONFIG(tooltip)
+#if QT_CONFIG(tooltip)
+ self.mip_solver_comboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Choose the external mixed integer programming solver", None))
+#endif // QT_CONFIG(tooltip)
+ self.label_132.setText("")
+ self.considerContingenciesOpfCheckBox.setText(QCoreApplication.translate("mainWindow", u"Consider contingencies", None))
+#if QT_CONFIG(tooltip)
+ self.save_mip_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"The program will save the MIP file in .lp format in the user GridCal folder before running a linear optimization study.
", None))
+#endif // QT_CONFIG(tooltip)
+ self.save_mip_checkBox.setText(QCoreApplication.translate("mainWindow", u"Save MIP file", None))
self.label_73.setText(QCoreApplication.translate("mainWindow", u"Optimal Power Flow", None))
self.groupBox_2.setTitle(QCoreApplication.translate("mainWindow", u"General settings", None))
self.label_128.setText(QCoreApplication.translate("mainWindow", u"Verbose", None))
@@ -5121,7 +5401,7 @@ def retranslateUi(self, mainWindow):
self.opfMaximizeExcahngeCheckBox.setText(QCoreApplication.translate("mainWindow", u"Maximize area exchange", None))
self.opfUnitCommitmentCheckBox.setText(QCoreApplication.translate("mainWindow", u"Unit commitment", None))
self.skipOpfGenerationLimitsCheckBox.setText(QCoreApplication.translate("mainWindow", u"Skip generation limits", None))
- self.label_131.setText("")
+ self.label_72.setText("")
self.settings_tabWidget.setTabText(self.settings_tabWidget.indexOf(self.opf_tab), QCoreApplication.translate("mainWindow", u"Opf", None))
#if QT_CONFIG(tooltip)
self.settings_tabWidget.setTabToolTip(self.settings_tabWidget.indexOf(self.opf_tab), QCoreApplication.translate("mainWindow", u"Optimal power flow settings", None))
@@ -5129,13 +5409,6 @@ def retranslateUi(self, mainWindow):
#if QT_CONFIG(tooltip)
self.ntc_tab.setToolTip(QCoreApplication.translate("mainWindow", u"Net transfer capacity settings", None))
#endif // QT_CONFIG(tooltip)
- self.groupBox_6.setTitle(QCoreApplication.translate("mainWindow", u"Linear", None))
- self.n1ConsiderationCheckBox.setText(QCoreApplication.translate("mainWindow", u"n-1 sensibility consideration", None))
- self.label_62.setText(QCoreApplication.translate("mainWindow", u"Transfer sensitivity threshold", None))
-#if QT_CONFIG(tooltip)
- self.atcThresholdSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Threshold used to discard insensitive branches", None))
-#endif // QT_CONFIG(tooltip)
- self.label_97.setText("")
self.groupBox_5.setTitle(QCoreApplication.translate("mainWindow", u"Optimization", None))
self.label_26.setText("")
#if QT_CONFIG(tooltip)
@@ -5174,11 +5447,17 @@ def retranslateUi(self, mainWindow):
self.label_30.setText(QCoreApplication.translate("mainWindow", u"Loading threshold to report", None))
self.label_77.setText(QCoreApplication.translate("mainWindow", u"Transfer method", None))
self.ntcReportLoadingThresholdSpinBox.setSuffix(QCoreApplication.translate("mainWindow", u"%", None))
+ self.label_97.setText("")
+ self.groupBox_6.setTitle(QCoreApplication.translate("mainWindow", u"Linear", None))
+ self.n1ConsiderationCheckBox.setText(QCoreApplication.translate("mainWindow", u"n-1 sensibility consideration", None))
+ self.label_62.setText(QCoreApplication.translate("mainWindow", u"Transfer sensitivity threshold", None))
+#if QT_CONFIG(tooltip)
+ self.atcThresholdSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Threshold used to discard insensitive branches", None))
+#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(tooltip)
self.label_96.setToolTip(QCoreApplication.translate("mainWindow", u"Select the solver in the OPF tab and the areas in the areas tab", None))
#endif // QT_CONFIG(tooltip)
self.label_96.setText(QCoreApplication.translate("mainWindow", u"Net transfer capacity", None))
- self.label_61.setText("")
self.settings_tabWidget.setTabText(self.settings_tabWidget.indexOf(self.ntc_tab), QCoreApplication.translate("mainWindow", u"Ntc", None))
#if QT_CONFIG(tooltip)
self.settings_tabWidget.setTabToolTip(self.settings_tabWidget.indexOf(self.ntc_tab), QCoreApplication.translate("mainWindow", u"Network transfer capacity related settings", None))
@@ -5186,11 +5465,6 @@ def retranslateUi(self, mainWindow):
#if QT_CONFIG(tooltip)
self.nodal_capacity_tab.setToolTip(QCoreApplication.translate("mainWindow", u"Nodal capacity hosting options", None))
#endif // QT_CONFIG(tooltip)
- self.label_141.setText("")
-#if QT_CONFIG(tooltip)
- self.label_140.setToolTip(QCoreApplication.translate("mainWindow", u"Select the solver in the OPF tab and the areas in the areas tab", None))
-#endif // QT_CONFIG(tooltip)
- self.label_140.setText(QCoreApplication.translate("mainWindow", u"Nodal hosting capacity", None))
self.groupBox_7.setTitle(QCoreApplication.translate("mainWindow", u"General", None))
#if QT_CONFIG(tooltip)
self.label_143.setToolTip(QCoreApplication.translate("mainWindow", u"If the sense is positive, the algorithm will asses the maximum generation capacity in the selected nodes. If it is negative it will asses the maximum loading capacity in the selected nodes.", None))
@@ -5210,7 +5484,11 @@ def retranslateUi(self, mainWindow):
self.nodal_capacity_method_comboBox.setStatusTip("")
#endif // QT_CONFIG(statustip)
self.label_144.setText("")
- self.label_145.setText("")
+ self.label_141.setText("")
+#if QT_CONFIG(tooltip)
+ self.label_140.setToolTip(QCoreApplication.translate("mainWindow", u"Select the solver in the OPF tab and the areas in the areas tab", None))
+#endif // QT_CONFIG(tooltip)
+ self.label_140.setText(QCoreApplication.translate("mainWindow", u"Nodal hosting capacity", None))
self.settings_tabWidget.setTabText(self.settings_tabWidget.indexOf(self.nodal_capacity_tab), QCoreApplication.translate("mainWindow", u"Nhc", None))
#if QT_CONFIG(tooltip)
self.settings_tabWidget.setTabToolTip(self.settings_tabWidget.indexOf(self.nodal_capacity_tab), QCoreApplication.translate("mainWindow", u"Nodal hosting capacity related settings", None))
@@ -5276,40 +5554,43 @@ def retranslateUi(self, mainWindow):
#if QT_CONFIG(tooltip)
self.ml_tab.setToolTip(QCoreApplication.translate("mainWindow", u"Machine-learning related settings", None))
#endif // QT_CONFIG(tooltip)
- self.label_121.setText(QCoreApplication.translate("mainWindow", u"Investment evaluation", None))
+ self.label_7.setText("")
self.label_120.setText("")
- self.label_153.setText(QCoreApplication.translate("mainWindow", u"Objective function", None))
- self.label_3.setText(QCoreApplication.translate("mainWindow", u"Method", None))
- self.label_88.setText("")
- self.label_51.setText(QCoreApplication.translate("mainWindow", u"Maximum evaluations", None))
+ self.label_93.setText(QCoreApplication.translate("mainWindow", u"Clustering", None))
+ self.label_33.setText(QCoreApplication.translate("mainWindow", u"Number of clusters", None))
+ self.label_31.setText("")
#if QT_CONFIG(tooltip)
- self.node_distances_elements_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Minimum size of the group", None))
+ self.max_investments_evluation_number_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Number of maximum evaluations for the optimization methods", None))
#endif // QT_CONFIG(tooltip)
-#if QT_CONFIG(statustip)
- self.node_distances_elements_spinBox.setStatusTip("")
-#endif // QT_CONFIG(statustip)
- self.node_distances_elements_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" elements", None))
+ self.max_investments_evluation_number_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" x number of investments", None))
+ self.label_38.setText(QCoreApplication.translate("mainWindow", u"Nodal distances", None))
+ self.label_3.setText(QCoreApplication.translate("mainWindow", u"Method", None))
#if QT_CONFIG(tooltip)
self.cluster_number_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Number of clusters, this affects all the simulations that deal with clustering
", None))
#endif // QT_CONFIG(tooltip)
self.cluster_number_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" Clusters", None))
- self.label_89.setText(QCoreApplication.translate("mainWindow", u"Node grouping", None))
- self.label_93.setText(QCoreApplication.translate("mainWindow", u"Clustering", None))
+ self.label_153.setText(QCoreApplication.translate("mainWindow", u"Objective function", None))
+ self.label_88.setText("")
#if QT_CONFIG(tooltip)
- self.max_investments_evluation_number_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Number of maximum evaluations for the optimization methods", None))
+ self.investment_evaluation_method_ComboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Select the investment evaluation method", None))
#endif // QT_CONFIG(tooltip)
- self.max_investments_evluation_number_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" x number of investments", None))
- self.label_33.setText(QCoreApplication.translate("mainWindow", u"Number of clusters", None))
+ self.label_44.setText("")
+ self.label_51.setText(QCoreApplication.translate("mainWindow", u"Maximum evaluations", None))
+ self.label_94.setText("")
+ self.label_89.setText(QCoreApplication.translate("mainWindow", u"Node grouping", None))
#if QT_CONFIG(tooltip)
self.node_distances_sigma_doubleSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"M\u00e1ximum standard deviation to determine the groups", None))
#endif // QT_CONFIG(tooltip)
self.node_distances_sigma_doubleSpinBox.setSuffix(QCoreApplication.translate("mainWindow", u" \u03c3", None))
- self.label_7.setText("")
- self.label_44.setText("")
+ self.label_121.setText(QCoreApplication.translate("mainWindow", u"Investment evaluation", None))
#if QT_CONFIG(tooltip)
- self.investment_evaluation_method_ComboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Select the investment evaluation method", None))
+ self.node_distances_elements_spinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Minimum size of the group", None))
#endif // QT_CONFIG(tooltip)
- self.label_94.setText("")
+#if QT_CONFIG(statustip)
+ self.node_distances_elements_spinBox.setStatusTip("")
+#endif // QT_CONFIG(statustip)
+ self.node_distances_elements_spinBox.setSuffix(QCoreApplication.translate("mainWindow", u" elements", None))
+ self.label_61.setText(QCoreApplication.translate("mainWindow", u"Min. group size", None))
self.label_55.setText(QCoreApplication.translate("mainWindow", u"Method", None))
self.label_78.setText("")
self.label_79.setText(QCoreApplication.translate("mainWindow", u"Cascading", None))
@@ -5327,20 +5608,14 @@ def retranslateUi(self, mainWindow):
#if QT_CONFIG(tooltip)
self.topology_tab.setToolTip(QCoreApplication.translate("mainWindow", u"Topology settings", None))
#endif // QT_CONFIG(tooltip)
- self.label_82.setText("")
- self.label_83.setText(QCoreApplication.translate("mainWindow", u"Node layout", None))
- self.label_24.setText(QCoreApplication.translate("mainWindow", u"Automatic layout algorithm", None))
-#if QT_CONFIG(tooltip)
- self.automatic_layout_comboBox.setToolTip(QCoreApplication.translate("mainWindow", u"Algorithm to use for the automatic
layout of the grid nodes
", None))
-#endif // QT_CONFIG(tooltip)
-#if QT_CONFIG(tooltip)
- self.ask_before_appliying_layout_checkBox.setToolTip(QCoreApplication.translate("mainWindow", u"Ask before running the automatic grid layout. This is because you might have a layout already and ruin it accidentally.", None))
-#endif // QT_CONFIG(tooltip)
- self.ask_before_appliying_layout_checkBox.setText(QCoreApplication.translate("mainWindow", u"Ask before applying", None))
- self.label_60.setText(QCoreApplication.translate("mainWindow", u"Node expansion factor", None))
+ self.label_80.setText("")
+ self.label_81.setText(QCoreApplication.translate("mainWindow", u"Grid reduction", None))
+ self.label_59.setText(QCoreApplication.translate("mainWindow", u"Select branch types to reduce", None))
+ self.rxThresholdCheckBox.setText(QCoreApplication.translate("mainWindow", u"Filter by r+x under threshold", None))
#if QT_CONFIG(tooltip)
- self.explosion_factor_doubleSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"When expanding or contracting the distances between nodes, this is the factor that applies.
", None))
+ self.rxThresholdSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Exponent of the threshold to use.
threshold = 1x10^-factor
i.e.
factor=3
threshold = 1e-3
", None))
#endif // QT_CONFIG(tooltip)
+ self.rxThresholdSpinBox.setPrefix(QCoreApplication.translate("mainWindow", u"1e-", None))
self.label_84.setText("")
self.label_85.setText(QCoreApplication.translate("mainWindow", u"Branch rating", None))
self.label_34.setText(QCoreApplication.translate("mainWindow", u"Branch rating factor", None))
@@ -5348,14 +5623,6 @@ def retranslateUi(self, mainWindow):
self.branch_rating_doubleSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Factor to aply to the branch calculated power to use as rating
", None))
#endif // QT_CONFIG(tooltip)
self.rating_override_checkBox.setText(QCoreApplication.translate("mainWindow", u"override values", None))
- self.label_80.setText("")
- self.label_81.setText(QCoreApplication.translate("mainWindow", u"Grid reduction", None))
- self.label_59.setText(QCoreApplication.translate("mainWindow", u"Select branch types to reduce", None))
- self.rxThresholdCheckBox.setText(QCoreApplication.translate("mainWindow", u"Filter by r+x under threshold", None))
-#if QT_CONFIG(tooltip)
- self.rxThresholdSpinBox.setToolTip(QCoreApplication.translate("mainWindow", u"Exponent of the threshold to use.
threshold = 1x10^-factor
i.e.
factor=3
threshold = 1e-3
", None))
-#endif // QT_CONFIG(tooltip)
- self.rxThresholdSpinBox.setPrefix(QCoreApplication.translate("mainWindow", u"1e-", None))
self.settings_tabWidget.setTabText(self.settings_tabWidget.indexOf(self.topology_tab), QCoreApplication.translate("mainWindow", u"Tplgy", None))
#if QT_CONFIG(tooltip)
self.settings_tabWidget.setTabToolTip(self.settings_tabWidget.indexOf(self.topology_tab), QCoreApplication.translate("mainWindow", u"Topology related settings", None))
@@ -5419,6 +5686,7 @@ def retranslateUi(self, mainWindow):
self.menuModel.setTitle(QCoreApplication.translate("mainWindow", u"Model", None))
self.menuDiagrams.setTitle(QCoreApplication.translate("mainWindow", u"Diagram", None))
self.menuBus_Branch_options.setTitle(QCoreApplication.translate("mainWindow", u"Current schematic", None))
+ self.menuplugins.setTitle(QCoreApplication.translate("mainWindow", u"plugins", None))
self.toolBar.setWindowTitle(QCoreApplication.translate("mainWindow", u"toolBar", None))
# retranslateUi
diff --git a/src/GridCal/Gui/Main/MainWindow.ui b/src/GridCal/Gui/Main/MainWindow.ui
index 89d898e0c..b080a3afe 100644
--- a/src/GridCal/Gui/Main/MainWindow.ui
+++ b/src/GridCal/Gui/Main/MainWindow.ui
@@ -6,8 +6,8 @@
0
0
- 1393
- 915
+ 1346
+ 811
@@ -16,6 +16,11 @@
0
+
+
+ 10
+
+
GridCal
@@ -70,34 +75,19 @@
QFrame::Raised
- -
+
-
+
+
+ 10
+
+
- -
-
-
- QProgressBar {
- border: 1px solid rgb(186, 189, 182);
- border-radius: 5px;
- text-align: center;
-}
-QProgressBar::chunk{
- background-color: rgb(0, 180, 136)
-}
-
-
- 20
-
-
- false
-
-
-
- -
+
-
@@ -105,6 +95,11 @@ QProgressBar::chunk{
24
+
+
+ 10
+
+
Cancel process
@@ -117,11 +112,41 @@ QProgressBar::chunk{
+ -
+
+
+
+ 10
+
+
+
+ QProgressBar {
+ border: 1px solid rgb(186, 189, 182);
+ border-radius: 5px;
+ text-align: center;
+}
+QProgressBar::chunk{
+ background-color: rgb(0, 180, 136)
+}
+
+
+ 20
+
+
+ false
+
+
+
-
+
+
+ 10
+
+
0
@@ -270,13 +295,6 @@ QProgressBar::chunk{
0
-
-
-
-
- Name of the grid model
-
-
-
-
@@ -308,6 +326,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
List of available diagrams
@@ -435,7 +458,7 @@ QProgressBar::chunk{
QFrame::Raised
-
+
6
@@ -448,398 +471,191 @@ QProgressBar::chunk{
0
-
-
-
-
- QFrame::NoFrame
+
-
+
+
+
+ 8
+
-
- QFrame::Raised
+
+ Node max. size
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 24
- 24
-
-
-
-
- 24
- 24
-
-
-
-
-
-
- :/Icons/icons/schematic.svg
-
-
- true
-
-
-
- -
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
-
- 12
-
-
-
- Schematic
-
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
-
-
-
-
- -
-
+
-
+
8
-
- Palette
+
+ <html><head/><body><p>Resolution factor.</p><p>1K = 1920 x 1080 pixels</p></body></html>
+
+
+ K
+
+
+ 1
+
+
+ 100
+
+
+ 10
- -
-
+
-
+
8
+
+ Map tile provider
+
- -
-
+
-
+
8
- Default voltage
+ Layout algorithm
+
+
+ Qt::PlainText
+
+
+ true
- -
-
+
-
+
8
- <html><head/><body><p><span style=" font-weight:700;">Bus default voltage</span></p><p>This is the voltage that drag&drop buses have when they are created from the schematic.</p></body></html>
+ <html><head/><body><p>Algorithm to use for the automatic </p><p>layout of the grid nodes</p></body></html>
+
+
+
+ -
+
+
+
+ 8
+
+
+
+ Node expansion factor
+
+
+
+ -
+
+
+
+ 8
+
- kV
+ px
1
-
- 999999999.000000000000000
+
+ 0.100000000000000
+
+
+ 0.100000000000000
- 10.000000000000000
+ 20.000000000000000
+
+
+
+ -
+
+
+
+ 8
+
-
-
-
- QFrame::NoFrame
+
+
+
+ 8
+
-
- QFrame::Raised
+
+ Palette
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 24
- 24
-
-
-
-
- 24
- 24
-
-
-
-
-
-
- :/Icons/icons/show_color_controls.svg
-
-
- true
-
-
-
- -
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
-
- 12
-
-
-
- Map
-
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
-
-
-
-
- -
-
+
-
+
8
- Map tile provider
+ Branch max. size
- -
-
+
-
+
8
+
+ Default voltage
+
- -
-
-
- QFrame::NoFrame
+
-
+
+
+
+ 8
+
-
- QFrame::Raised
+
+ Node min. size
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 24
- 24
-
-
-
-
- 24
- 24
-
-
-
-
-
-
- :/Icons/icons/grid_icon.svg
-
-
- true
-
-
-
- -
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
-
- 12
-
-
-
- Display
-
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
-
-
-
-
- -
-
+
-
+
8
- Node min. size
+ Branch min. size
- -
-
+
-
+
8
@@ -851,9 +667,6 @@ QProgressBar::chunk{
1
-
- 0.100000000000000
-
0.100000000000000
@@ -862,56 +675,56 @@ QProgressBar::chunk{
- -
-
-
-
- 8
-
-
-
- Node max. size
-
-
-
- -
-
+
-
+
8
-
- px
+
+ <html><head/><body><p>When expanding or contracting the distances between nodes, this is the factor that applies.</p></body></html>
- 1
+ 3
- 0.100000000000000
+ 1.000000000000000
+
+
+ 999999999.000000000000000
0.100000000000000
- 40.000000000000000
+ 1.500000000000000
- -
-
+
-
+
8
-
- Branch min. size
+
+ FPS
+
+
+ 1
+
+
+ 9999
+
+
+ 30
- -
-
+
-
+
8
@@ -923,71 +736,138 @@ QProgressBar::chunk{
1
+
+ 0.100000000000000
+
0.100000000000000
- 0.500000000000000
+ 40.000000000000000
- -
-
+
-
+
8
- Branch max. size
+ Video FPS
- -
-
+
-
+
8
-
- px
-
-
+
+
+ -
+
+
+
+ 8
+
+
+
+ Ask before running the automatic grid layout. This is because you might have a layout already and ruin it accidentally.
+
+
+ Ask before applying
+
+
+ true
+
+
+ false
+
+
+
+ -
+
+
+
+ 8
+
+
+
+ Export resolution
+
+
+
+ -
+
+
+
+ 8
+
+
+
+ px
+
+
1
0.100000000000000
- 20.000000000000000
+ 0.500000000000000
- -
-
+
-
+
8
-
- Width based on flow
+
+ <html><head/><body><p><span style=" font-weight:700;">Bus default voltage</span></p><p>This is the voltage that drag&drop buses have when they are created from the schematic.</p></body></html>
-
- false
+
+ kV
+
+
+ 1
+
+
+ 999999999.000000000000000
+
+
+ 10.000000000000000
- -
-
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
QFrame::NoFrame
QFrame::Raised
-
+
0
@@ -1001,7 +881,7 @@ QProgressBar::chunk{
0
-
-
+
24
@@ -1018,7 +898,7 @@ QProgressBar::chunk{
- :/Icons/icons/picture.svg
+ :/Icons/icons/show_color_controls.svg
true
@@ -1026,7 +906,7 @@ QProgressBar::chunk{
-
-
+
@@ -1066,98 +946,127 @@ QProgressBar::chunk{
- 12
+ 11
- Export
+ Map
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
- -
-
-
-
- 8
-
-
-
- Export resolution
-
-
-
- -
-
-
-
- 8
-
-
-
- <html><head/><body><p>Resolution factor.</p><p>1K = 1920 x 1080 pixels</p></body></html>
-
-
- K
-
-
- 1
-
-
- 100
-
-
- 10
-
-
-
- -
-
-
-
- 8
-
-
-
- Video FPS
-
-
-
- -
-
-
-
- 8
-
-
-
- FPS
-
-
- 1
-
-
- 9999
+
-
+
+
+ QFrame::NoFrame
-
- 30
+
+ QFrame::Raised
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+
+
+
+ :/Icons/icons/schematic.svg
+
+
+ true
+
+
+
+ -
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
+
+
+ 11
+
+
+
+ Schematic
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+
-
-
+
QFrame::NoFrame
QFrame::Raised
-
+
0
@@ -1171,7 +1080,7 @@ QProgressBar::chunk{
0
-
-
+
24
@@ -1188,7 +1097,7 @@ QProgressBar::chunk{
- :/Icons/icons/plot.svg
+ :/Icons/icons/picture.svg
true
@@ -1196,7 +1105,7 @@ QProgressBar::chunk{
-
-
+
@@ -1236,41 +1145,133 @@ QProgressBar::chunk{
- 12
+ 11
- Plotting
+ Export
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
- -
-
-
-
- 8
-
+
-
+
+
+ QFrame::NoFrame
-
- Style
+
+ QFrame::Raised
-
-
- -
-
-
-
- 8
-
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+
+
+
+ :/Icons/icons/grid_icon.svg
+
+
+ true
+
+
+
+ -
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
+
+
+ 11
+
+
+
+ Display
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+
+
+
+ -
+
+
+
+ 8
+
-
- MatPlotlib plot styles to choose from
+
+ Width based on flow
+
+
+ false
@@ -2101,11 +2102,11 @@ QProgressBar::chunk{
0
- -
-
+
-
+
- -
-
+
-
+
32
@@ -2113,19 +2114,19 @@ QProgressBar::chunk{
- Update the islands dispayed
+ Export simulation data
- :/Icons/icons/calculator.svg:/Icons/icons/calculator.svg
+ :/Icons/icons/save.svg:/Icons/icons/save.svg
- -
-
+
-
+
32
@@ -2133,19 +2134,19 @@ QProgressBar::chunk{
- Export simulation data
+ Update the islands dispayed
- :/Icons/icons/save.svg:/Icons/icons/save.svg
+ :/Icons/icons/calculator.svg:/Icons/icons/calculator.svg
- -
-
+
-
+
@@ -3188,6 +3189,18 @@ QProgressBar::chunk{
-
+
+
+ 0
+ 0
+
+
+
+
+ 250
+ 16777215
+
+
QFrame::NoFrame
@@ -3355,8 +3368,32 @@ QProgressBar::chunk{
QFrame::Raised
+ -
+
+
+
+ 9
+
+
+
+ Grid name
+
+
+
+ -
+
+
+ Name of the grid model
+
+
+
-
+
+
+ 9
+
+
Base power
@@ -3364,6 +3401,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p><span style=" font-weight:700;">Base power</span></p><p>Despite all the bibliography, changing this number to anything other than 100 MVA, might change the meaning of what sensible per-unit voltage are.</p><p>This is, 1.0 is no longer the nominal voltage and so on.</p></body></html>
@@ -3386,6 +3428,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Frequency
@@ -3393,6 +3440,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p><span style=" font-weight:700;">System frequency</span></p><p>This only has an effect in the program when computing lines' per-unit impedance from ohm values.</p></body></html>
@@ -3415,6 +3467,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Snapshot time
@@ -3422,6 +3479,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
true
@@ -3435,21 +3497,235 @@ QProgressBar::chunk{
-
-
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+
+
+
+ :/Icons/icons/piece.svg
+
+
+ true
+
+
+
+ -
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
+
+
+ 12
+
+
+
+ Engine
+
+
+ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+
+
+
+
+
+
+ -
+
- 12
+ 9
+
+ Engine to be used when available
+
+
+
+ -
+
- Engine
+
-
-
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+
+
+
+ :/Icons/icons/plot.svg
+
+
+ true
+
+
+
+ -
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
+
+
+ 12
+
+
+
+ Plotting
+
+
+ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+
+
+
+
+
+
+ -
+
+
+
+ 9
+
+
- Engine to be used when available
+ MatPlotlib plot styles to choose from
@@ -3471,6 +3747,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Dark mode
@@ -3486,7 +3767,7 @@ QProgressBar::chunk{
- 12
+ 10
@@ -3499,7 +3780,7 @@ QProgressBar::chunk{
QTabWidget::South
- 7
+ 0
@@ -3673,62 +3954,57 @@ QProgressBar::chunk{
QFrame::Raised
-
-
-
-
- If active, GridCal finds a precission that suits the magnitude of the power injections so that the power flow is meaningful
+
-
+
+
+
+ 9
+
- Automatic precision
+ Solver
- -
-
-
- <html><head/><body><p>If the selected method does not converge, try a list of methods that may help</p></body></html>
-
-
- Retry with other methods if failed
+
-
+
+
+ Qt::Vertical
-
- true
+
+
+ 20
+ 40
+
-
+
- -
-
-
- Level of console information. 0: None, 1: some information, 2: all the information
-
-
- 2
+
-
+
+
+
- -
-
-
- Tolerance
-
-
-
- -
-
-
-
+
-
+
+
+
+ 9
+
-
-
- -
-
-
+ Verbosity
- -
+
-
+
+
+ 9
+
+
<html><head/><body><p>Error tolerance of the method</p></body></html>
@@ -3746,68 +4022,65 @@ QProgressBar::chunk{
- -
-
-
- <html><head/><body><p>If active, the slack power is distributed among the generators according to their installed power "Snom"</p></body></html>
+
-
+
+
+
+ 9
+
- Distributed slack
+ Max. iterations
- -
-
+
-
+
+
+
+ 9
+
+
- Solver
+ Trust radius
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
+
-
+
+
+
+ 9
+
-
-
- -
-
- Trust radius
+ Tolerance
- -
-
-
- <html><head/><body><p>Maximum numberof iterations to use.</p><p><br/></p><p>Tipical values: </p><p>Newton Raphson: 5</p><p>Levenberg-Marquards: 20</p><p>Fast decoupled: 10</p><p>Others: 20</p></body></html>
-
-
- 1
-
-
- 1000
+
-
+
+
+
+ 50
+ 16777215
+
-
- 40
+
+ Find the tolerance that best represents the load values for power flow
-
-
- -
-
- Max. iterations
+ Find
- -
+
-
+
+
+ 9
+
+
<html><head/><body><p>Factor that multiplies each increment solution. </p><p>In practice this is used to slow down troublesome solutions.</p></body></html>
@@ -3828,136 +4101,57 @@ QProgressBar::chunk{
- -
-
-
- Use voltage guess
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- If active, the islands of a single node are ignored.
-
-
- Ignore single node islands
+
-
+
+
+
+ 200
+ 0
+
-
- true
+
+
+ 9
+
- -
-
-
- -
-
-
- Verbosity
+
-
+
+
+
+ 9
+
-
-
- -
-
- Add a results report in the logs
-
-
- Add report
+ <html><head/><body><p>Maximum numberof iterations to use.</p><p><br/></p><p>Tipical values: </p><p>Newton Raphson: 5</p><p>Levenberg-Marquards: 20</p><p>Fast decoupled: 10</p><p>Others: 20</p></body></html>
-
-
-
-
-
- -
-
-
- QFrame::NoFrame
-
-
- QFrame::Plain
-
-
-
-
-
-
- Reactive power control mode
+
+ 1
-
-
- -
-
-
- -
-
-
-
+
+ 1000
-
-
- -
-
-
- Transformer taps control mode
+
+ 40
- -
-
-
- -
-
-
-
+
-
+
+
+
+ 9
+
-
-
- -
-
- Correct the branches resistance using the temperature
-
-
- Apply temperature correction
-
-
-
- -
-
-
- Apply impedance tolerances
+ Level of console information. 0: None, 1: some information, 2: all the information
-
-
- -
-
-
- Override branch controls
+
+ 2
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
@@ -4115,6 +4309,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Correct nonsense values
@@ -4125,6 +4324,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Use existing power flow values for the contingency initialization in the net transfer capacity and contingency simulations
@@ -4138,6 +4342,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Distributed slack
@@ -4148,6 +4357,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Threshold under which sensitivities are ignored when the PTDF is converted to sparse
@@ -4157,6 +4371,9 @@ QProgressBar::chunk{
1.000000000000000
+
+ 0.001000000000000
+
0.010000000000000
@@ -4164,6 +4381,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
LODF threshold
@@ -4208,6 +4430,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Threshold under which sensitivities are ignored when the LODF is converted to sparse
@@ -4217,6 +4444,9 @@ QProgressBar::chunk{
1.000000000000000
+
+ 0.001000000000000
+
0.050000000000000
@@ -4224,6 +4454,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
PTDF threshold
@@ -4239,13 +4474,239 @@ QProgressBar::chunk{
-
-
-
-
- Continuation power flow settings
-
-
+ -
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Plain
+
+
+
-
+
+
+
+ 9
+
+
+
+ <html><head/><body><p>If the selected method does not converge, try a list of methods that may help</p></body></html>
+
+
+ Retry with other methods if failed
+
+
+ true
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ Use voltage guess
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ If active, the islands of a single node are ignored.
+
+
+ Ignore single node islands
+
+
+ true
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ <html><head/><body><p>If active, the slack power is distributed among the generators according to their installed power "Snom"</p></body></html>
+
+
+ Distributed slack
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ General switch for reactive power limits control
+
+
+ Control generators Q
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ General switch for branches tap module control
+
+
+ Control tap module
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ General switch for branches tap phase control
+
+
+ Control tap phase
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ General switch for generators remote voltage control
+
+
+ Control remote voltage
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ If checked, the controls are adjusted to their closest tap
+
+
+ Orthogonalize controls
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ Correct the branches resistance using the temperature
+
+
+ Apply temperature correction
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ Apply impedance tolerances
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ Add a results report in the logs
+
+
+ Add report
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+ Continuation power flow settings
+
+
:/Icons/icons/continuation_power_flow.svg:/Icons/icons/continuation_power_flow.svg
@@ -4270,6 +4731,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
1
@@ -4283,6 +4749,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Stop at
@@ -4290,16 +4761,32 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Refer to the NTC areas (Linear tab)
-
-
+
+
+
+ 9
+
+
+
-
+
+
+ 9
+
+
-99.000000000000000
@@ -4359,7 +4846,13 @@ QProgressBar::chunk{
-
-
+
+
+
+ 9
+
+
+
-
@@ -4370,6 +4863,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Now
@@ -4377,16 +4875,32 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Use departure and target points from time series
-
-
+
+
+
+ 9
+
+
+
-
+
+
+ 9
+
+
Available transfer capacity
@@ -4401,6 +4915,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p>Lambda factor</p></body></html>
@@ -4408,6 +4927,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Max. Iterations
@@ -4415,7 +4939,12 @@ QProgressBar::chunk{
-
-
+
+
+ 9
+
+
+
Target
@@ -4542,6 +5071,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Increase system loading
@@ -4596,130 +5130,7 @@ QProgressBar::chunk{
Optimal power flow settings
-
-
-
-
-
- 12
- false
-
-
-
- Linear settings
-
-
-
-
-
-
- Zone grouping
-
-
-
- -
-
-
- Contingency tolerance
-
-
-
- -
-
-
- LODF matrix tolerance choosing contingencies
-
-
- 4
-
-
- 0.050000000000000
-
-
-
- -
-
-
- MIP solver
-
-
-
- -
-
-
- Time grouping
-
-
-
- -
-
-
- -
-
-
- <html><head/><body><p>Choose the time grouping to possibly shorten the solution time.</p><p>This splits the time series by week, month, etc. and the subproblems are solved sequentially.</p></body></html>
-
-
-
- -
-
-
- Choose the external mixed integer programming solver
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- Consider contingencies
-
-
-
- -
-
-
- <html><head/><body><p>The program will save the MIP file in .lp format in the user GridCal folder before running a linear optimization study.</p></body></html>
-
-
- Save MIP file
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
+
-
@@ -4733,6 +5144,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Interior point trust radius
@@ -4742,10 +5159,23 @@ QProgressBar::chunk{
-
-
+
+
+
+ 9
+ false
+
+
+
-
+
+
+ 9
+ false
+
+
Interior point solver method
@@ -4769,6 +5199,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Interior point solver tolerance
@@ -4779,6 +5215,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
<html><head/><body><p>Error tolerance of the method</p></body></html>
@@ -4798,6 +5240,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Initialize the interior point OPF with the power flow solution
@@ -4808,12 +5256,21 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
<html><head/><body><p>Factor that multiplies each increment solution. </p><p>In practice this is used to slow down troublesome solutions.</p></body></html>
4
+
+ 0.100000000000000
+
1.000000000000000
@@ -4821,6 +5278,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Number of iterations of the method
@@ -4837,6 +5300,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Interior point solver maximum number of iterations
@@ -4855,91 +5324,253 @@ QProgressBar::chunk{
- -
-
-
-
- 24
- 24
-
+
-
+
+
+ Qt::Horizontal
-
+
- 24
- 24
+ 40
+ 20
-
-
-
-
- :/Icons/icons/dcopf.svg
-
-
- true
-
-
+
- -
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
+
-
+
- 16
+ 12
+ false
-
- Optimal Power Flow
-
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+
+ Linear settings
-
-
- -
-
-
-
-
-
-
-
+
+
-
+
+
+
+ 9
+ false
+
+
+
+ Zone grouping
+
+
+
+ -
+
+
+
+ 9
+ false
+
+
+
+ Contingency tolerance
+
+
+
+ -
+
+
+
+ 9
+ false
+
+
+
+ LODF matrix tolerance choosing contingencies
+
+
+ 4
+
+
+ 0.010000000000000
+
+
+ 0.050000000000000
+
+
+
+ -
+
+
+
+ 9
+ false
+
+
+
+ MIP solver
+
+
+
+ -
+
+
+
+ 9
+ false
+
+
+
+ Time grouping
+
+
+
+ -
+
+
+
+ 9
+ false
+
+
+
+
+ -
+
+
+
+ 9
+ false
+
+
+
+ <html><head/><body><p>Choose the time grouping to possibly shorten the solution time.</p><p>This splits the time series by week, month, etc. and the subproblems are solved sequentially.</p></body></html>
+
+
+
+ -
+
+
+
+ 9
+ false
+
+
+
+ Choose the external mixed integer programming solver
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ 9
+ false
+
+
+
+ Consider contingencies
+
+
+
+ -
+
+
+
+ 9
+ false
+
+
+
+ <html><head/><body><p>The program will save the MIP file in .lp format in the user GridCal folder before running a linear optimization study.</p></body></html>
+
+
+ Save MIP file
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
+
+
+ 16
+
+
+
+ Optimal Power Flow
+
+
+ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+
+
+
+ -
+
+
+
+
+
+
+
186
189
182
@@ -4982,7 +5613,7 @@ QProgressBar::chunk{
- -
+
-
@@ -4996,6 +5627,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Verbose
@@ -5003,6 +5640,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Method
@@ -5023,6 +5666,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Choose the optimal power flow method
@@ -5030,6 +5679,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Verbosity level
@@ -5037,6 +5692,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Add a results report in the logs
@@ -5054,6 +5715,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Maximize area exchange
@@ -5061,6 +5728,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Unit commitment
@@ -5068,6 +5741,12 @@ QProgressBar::chunk{
-
+
+
+ 9
+ false
+
+
Skip generation limits
@@ -5076,11 +5755,29 @@ QProgressBar::chunk{
- -
-
+
-
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+ :/Icons/icons/dcopf.svg
+
+
+ true
+
@@ -5100,157 +5797,13 @@ QProgressBar::chunk{
Network transfer capacity related settings
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
- QFrame::Plain
-
-
- 4
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Linear
-
-
- false
-
-
- false
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 393
-
-
-
-
- -
-
-
- n-1 sensibility consideration
-
-
- true
-
-
-
- -
-
-
- Transfer sensitivity threshold
-
-
-
- -
-
-
- Threshold used to discard insensitive branches
-
-
- 4
-
-
- 1.000000000000000
-
-
- 0.050000000000000
-
-
-
-
-
-
- -
-
-
-
- 24
- 24
-
-
-
-
- 24
- 24
-
-
-
-
-
-
- :/Icons/icons/ntc_opf.svg
-
-
- true
-
-
-
- -
+
-
+
+
+ 12
+
+
Optimization
@@ -5264,6 +5817,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
If checked, the NTC optimization will use the system declared contingencies
@@ -5274,6 +5832,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p>This criteria springs from the ACER (Agency for the Cooperation for Energy Regulators).</p><p>It determines that a branch is only relevant to be considered in a NTC calculation if the flow due to the exchange is over a percentage (70%) </p><p><br/></p><p>A branch is monitored only if:</p><p>(branch_rate * 70%) / branch_alpha <= total exchange rating</p></body></html>
@@ -5284,10 +5847,47 @@ QProgressBar::chunk{
-
+
+
+
+
+
+
+ 36
+ 31
+ 49
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
12
- true
+ false
@@ -5304,6 +5904,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
If activated, the generation limits are not considered
@@ -5330,6 +5935,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Minimum exchange contribution (Alpha)
@@ -5346,6 +5956,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p>A branch is monitored solely based on its contribution to the inter-area excahge sensitivity. Therefore a branch is selected if it's alpha value is greater than the set alpha %</p></body></html>
@@ -5359,10 +5974,47 @@ QProgressBar::chunk{
-
+
+
+
+
+
+
+ 36
+ 31
+ 49
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
12
- true
+ false
@@ -5375,6 +6027,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
MW
@@ -5394,6 +6051,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Transmission reliability margin (TRM)
@@ -5404,6 +6066,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
%
@@ -5418,12 +6085,17 @@ QProgressBar::chunk{
- -
+
-
-
- General
-
-
+
+
+ 12
+
+
+
+ General
+
+
-
@@ -5439,6 +6111,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Loading threshold to report
@@ -5446,6 +6123,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Transfer method
@@ -5453,6 +6135,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
%
@@ -5465,22 +6152,28 @@ QProgressBar::chunk{
-
-
+
+
+
+ 9
+
+
+
- -
-
+
-
+
- 85
- 87
- 83
+ 186
+ 189
+ 182
@@ -5489,9 +6182,9 @@ QProgressBar::chunk{
- 85
- 87
- 83
+ 186
+ 189
+ 182
@@ -5509,57 +6202,19 @@ QProgressBar::chunk{
-
-
- 16
-
-
-
- Select the solver in the OPF tab and the areas in the areas tab
-
-
- Net transfer capacity
-
-
-
- -
-
-
-
- 0
- 0
-
+
+ QFrame::Plain
-
-
- 16777215
- 16
-
+
+ 4
-
-
+
+ Qt::Horizontal
-
-
-
-
- Nodal capacity hosting options
-
-
-
- :/Icons/icons/nodal_capacity.svg:/Icons/icons/nodal_capacity.svg
-
-
- Nhc
-
-
- Nodal hosting capacity related settings
-
-
-
-
+
24
@@ -5576,15 +6231,112 @@ QProgressBar::chunk{
- :/Icons/icons/nodal_capacity.svg
+ :/Icons/icons/ntc_opf.svg
true
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ Linear
+
+
+ false
+
+
+ false
+
+
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 393
+
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ n-1 sensibility consideration
+
+
+ true
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ Transfer sensitivity threshold
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ Threshold used to discard insensitive branches
+
+
+ 4
+
+
+ 1.000000000000000
+
+
+ 0.010000000000000
+
+
+ 0.050000000000000
+
+
+
+
+
+
-
-
+
@@ -5631,68 +6383,45 @@ QProgressBar::chunk{
Select the solver in the OPF tab and the areas in the areas tab
- Nodal hosting capacity
+ Net transfer capacity
- -
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
- QFrame::Plain
+
+
+
+
+ Nodal capacity hosting options
+
+
+
+ :/Icons/icons/nodal_capacity.svg:/Icons/icons/nodal_capacity.svg
+
+
+ Nhc
+
+
+ Nodal hosting capacity related settings
+
+
+ -
+
+
+
+ 12
+
-
- 4
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- General
+
+ General
-
+
+
+ 9
+
+
If the sense is positive, the algorithm will asses the maximum generation capacity in the selected nodes. If it is negative it will asses the maximum loading capacity in the selected nodes.
@@ -5706,6 +6435,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
If the sense is positive, the algorithm will asses the maximum generation capacity in the selected nodes. If it is negative it will asses the maximum loading capacity in the selected nodes.
@@ -5722,6 +6456,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Method
@@ -5729,6 +6468,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Optimization method to use
@@ -5760,7 +6504,134 @@ QProgressBar::chunk{
- -
+
-
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+
+
+
+ :/Icons/icons/nodal_capacity.svg
+
+
+ true
+
+
+
+ -
+
+
+
+
+
+
+
+ 186
+ 189
+ 182
+
+
+
+
+
+
+
+
+ 186
+ 189
+ 182
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
+
+ QFrame::Plain
+
+
+ 4
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
+
+
+ 16
+
+
+
+ Select the solver in the OPF tab and the areas in the areas tab
+
+
+ Nodal hosting capacity
+
+
+
+ -
Qt::Horizontal
@@ -5773,13 +6644,6 @@ QProgressBar::chunk{
- -
-
-
-
-
-
-
@@ -5945,13 +6809,26 @@ QProgressBar::chunk{
-
+
+
+ Ubuntu
+ 9
+
+
From
-
-
+
+
+
+ Ubuntu
+ 9
+
+
+
@@ -5965,13 +6842,26 @@ QProgressBar::chunk{
-
+
+
+ Ubuntu
+ 9
+
+
To
-
-
+
+
+
+ Ubuntu
+ 9
+
+
+
@@ -6020,6 +6910,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Contingency filter
@@ -6033,13 +6928,24 @@ QProgressBar::chunk{
16777215
+
+
+ 9
+
+
Filter by
-
-
+
+
+
+ 9
+
+
+
-
@@ -6049,6 +6955,11 @@ QProgressBar::chunk{
0
+
+
+ 9
+
+
<html><head/><body><p><span style=" font-weight:700;">Filter contingencies</span></p><p>This option allows you to only consider the contingencies that fall in ceratain groupings such as Area, Zone or Country. The filtering is performed based on the information stored in the Buses.</p><p>This is highly discouraged. We trully advise you to not to filter the contingencies and select All Contingencies. Use this feature at your own risk.</p></body></html>
@@ -6068,6 +6979,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p>Dead band over the SRAP rating.</p><p>If greater than zero, the SRAP is investigated for values over the branch protections rating until the specified value.</p></body></html>
@@ -6085,6 +7001,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
SRAP limit
@@ -6092,6 +7013,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p>If checked the SRAP objective solution is the branch nominal rate. Otherwise the objective rating is the contingency rating.</p></body></html>
@@ -6102,6 +7028,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p>Activate SRAP (Sistema de reducciĆ³n automĆ”tica de potencia)</p><p>It is a mechanism that helps avoiding considering a contingency if it would be eventually resolved by nearby generation shifting.</p></body></html>
@@ -6112,6 +7043,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p>If checked, a massive posibly intractable report is generated.</p></body></html>
@@ -6122,6 +7058,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Maximum overload power that is solvable using the SRAP technique.
@@ -6141,6 +7082,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
1
@@ -6154,6 +7100,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
%
@@ -6167,6 +7118,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
<html><head/><body><p>Amount of contingency loading with respect to the base situation loading that triggers the report of the contingency. This is specially useful when we want to avoig reporting contingencies that are not significant with respect to the base situation.</p></body></html>
@@ -6187,6 +7143,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Contingency engine
@@ -6194,6 +7155,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
%
@@ -6222,7 +7188,13 @@ QProgressBar::chunk{
-
-
+
+
+
+ 9
+
+
+
@@ -6423,59 +7395,27 @@ QProgressBar::chunk{
0
- -
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
-
- 16
-
-
+
-
+
- Investment evaluation
-
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+
- -
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 250
+
+
+
+
+ -
@@ -6500,15 +7440,8 @@ QProgressBar::chunk{
- -
-
-
- Objective function
-
-
-
- -
-
+
-
+
@@ -6557,119 +7490,151 @@ QProgressBar::chunk{
- -
-
-
- Method
+
-
+
+
+ QFrame::NoFrame
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
+
+
+ 16
+
+
+
+ Clustering
+
+
+ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+
+
+
+
- -
-
-
-
- 24
- 24
-
-
-
-
- 24
- 24
-
+
-
+
+
+
+ 9
+
-
-
-
- :/Icons/icons/color_grid.svg
-
-
- true
+ Number of clusters
- -
-
+
-
+
- Maximum evaluations
+
- -
-
-
- Minimum size of the group
+
-
+
+
+
+ 9
+
-
-
+
+ Number of maximum evaluations for the optimization methods
- elements
+ x number of investments
1
- 99999
+ 999999999
- 2
+ 4
- -
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
+
-
+
+
+
+ 9
+
-
- QFrame::Plain
+
+ Nodal distances
-
- 4
+
+
+ -
+
+
+
+ 9
+
-
- Qt::Horizontal
+
+ Method
- -
-
+
-
+
@@ -6718,8 +7683,13 @@ QProgressBar::chunk{
- -
+
-
+
+
+ 9
+
+
<html><head/><body><p>Number of clusters, this affects all the simulations that deal with clustering</p></body></html>
@@ -6737,17 +7707,82 @@ QProgressBar::chunk{
- -
-
-
-
-
-
-
-
- 85
- 87
- 83
+
-
+
+
+
+ 9
+
+
+
+ Objective function
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+
+
+
+ :/Icons/icons/color_grid.svg
+
+
+ true
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ Select the investment evaluation method
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ 9
+
+
+
+
+ -
+
+
+
+
+
+
+
+ 186
+ 189
+ 182
@@ -6756,9 +7791,9 @@ QProgressBar::chunk{
- 85
- 87
- 83
+ 186
+ 189
+ 182
@@ -6776,123 +7811,113 @@ QProgressBar::chunk{
-
-
- 16
-
+
+ QFrame::Plain
-
- Node grouping
+
+ 4
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+
+ Qt::Horizontal
- -
-
-
- QFrame::NoFrame
+
-
+
+
+
+ 9
+
-
- QFrame::Raised
+
+ Maximum evaluations
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
-
- 16
-
-
-
- Clustering
-
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
-
-
-
-
- -
-
-
- Number of maximum evaluations for the optimization methods
+
-
+
+
+
+ 24
+ 24
+
-
- x number of investments
+
+
+ 24
+ 24
+
-
- 1
+
+
-
- 999999999
+
+ :/Icons/icons/clustering.svg
-
- 4
+
+ true
- -
-
+
-
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
+
+
+
+ 16
+
+
- Number of clusters
+ Node grouping
+
+
+ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
- -
+
-
+
+
+ 9
+
+
MƔximum standard deviation to determine the groups
@@ -6910,67 +7935,96 @@ QProgressBar::chunk{
- -
-
-
-
-
-
-
- -
-
-
-
+
-
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 85
+ 87
+ 83
+
+
+
+
+
+
+
+
+ 190
+ 190
+ 190
+
+
+
+
+
-
-
- -
-
-
- Qt::Vertical
+
+
+ 16
+
-
-
- 20
- 250
-
+
+ Investment evaluation
-
-
- -
-
-
- Select the investment evaluation method
+
+ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
-
- -
-
-
-
- 24
- 24
-
+
+ -
+
+
+
+ 9
+
-
-
- 24
- 24
-
+
+ Minimum size of the group
-
+
-
- :/Icons/icons/clustering.svg
+
+ elements
-
- true
+
+ 1
+
+
+ 99999
+
+
+ 2
- -
-
+
-
+
+
+
+ 9
+
+
+
+ Min. group size
+
+
@@ -6994,10 +8048,21 @@ QProgressBar::chunk{
0
-
-
+
+
+
+ 9
+
+
+
-
+
+
+ 9
+
+
Method
@@ -7082,6 +8147,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Voltage variance
@@ -7089,6 +8159,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Samples
@@ -7135,359 +8210,19 @@ QProgressBar::chunk{
- 16
-
-
-
- Stochastic power flow
-
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
-
-
-
- -
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
- QFrame::Plain
-
-
- 4
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 186
- 189
- 182
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
- QFrame::Plain
-
-
- 4
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- 10
-
-
- 99999999
-
-
- 1000
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- 1e-
-
-
- 1
-
-
- 20
-
-
- 4
-
-
-
- -
-
-
-
- 24
- 24
-
-
-
-
- 24
- 24
-
-
-
-
-
-
- :/Icons/icons/stochastic_power_flow.svg
-
-
- true
-
-
-
- -
-
-
- Aditional islands until stop
-
-
-
- -
-
-
- 1
-
-
- 999999
-
-
- 2
+ 16
+
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 935
- 20
-
-
-
-
-
-
-
-
- Topology settings
-
-
-
- :/Icons/icons/automatic_layout.svg:/Icons/icons/automatic_layout.svg
-
-
- Tplgy
-
-
- Topology related settings
-
-
- -
-
-
- QFrame::NoFrame
-
-
- QFrame::Raised
-
-
-
- 0
-
-
-
-
-
- QFrame::NoFrame
+
+ Stochastic power flow
-
- QFrame::Raised
+
+ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 24
- 24
-
-
-
-
- 24
- 24
-
-
-
-
-
-
- :/Icons/icons/automatic_layout.svg
-
-
- true
-
-
-
- -
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 85
- 87
- 83
-
-
-
-
-
-
-
-
- 190
- 190
- 190
-
-
-
-
-
-
-
-
- 16
-
-
-
- Node layout
-
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
-
-
-
-
- -
-
+
-
+
@@ -7536,44 +8271,15 @@ QProgressBar::chunk{
- -
-
-
- Automatic layout algorithm
-
-
- Qt::PlainText
-
-
- true
-
-
-
- -
-
-
- <html><head/><body><p>Algorithm to use for the automatic </p><p>layout of the grid nodes</p></body></html>
-
-
-
- -
-
-
- Ask before running the automatic grid layout. This is because you might have a layout already and ruin it accidentally.
-
+
-
+
- Ask before applying
-
-
- true
-
-
- false
+
- -
-
+
-
+
@@ -7620,92 +8326,182 @@ QProgressBar::chunk{
Qt::Horizontal
-
-
- -
-
+
+
+ -
+
+
+
+ 9
+
+
+
+ 10
+
+
+ 99999999
+
+
+ 1000
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ 1e-
+
+
+ 1
+
+
+ 20
+
+
+ 4
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+
+
+
+ :/Icons/icons/stochastic_power_flow.svg
+
+
+ true
+
+
+
+ -
+
+
+
+ 9
+
+
- Node expansion factor
+ Aditional islands until stop
- -
-
-
- <html><head/><body><p>When expanding or contracting the distances between nodes, this is the factor that applies.</p></body></html>
+
-
+
+
+
+ 9
+
- 0.000000000000000
+ 1
- 999999999.000000000000000
+ 999999
- 1.500000000000000
-
-
-
- -
-
-
- QFrame::NoFrame
-
-
- QFrame::Raised
+ 2
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 935
+ 20
+
+
+
+
+
+
+
+
+ Topology settings
+
+
+
+ :/Icons/icons/automatic_layout.svg:/Icons/icons/automatic_layout.svg
+
+
+ Tplgy
+
+
+ Topology related settings
+
+
-
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
QFrame::NoFrame
QFrame::Raised
-
+
0
-
-
+
QFrame::NoFrame
QFrame::Raised
-
+
0
@@ -7719,7 +8515,7 @@ QProgressBar::chunk{
0
-
-
+
24
@@ -7736,7 +8532,7 @@ QProgressBar::chunk{
- :/Icons/icons/rate_br.svg
+ :/Icons/icons/grid_reduction.svg
true
@@ -7744,7 +8540,7 @@ QProgressBar::chunk{
-
-
+
@@ -7788,7 +8584,7 @@ QProgressBar::chunk{
- Branch rating
+ Grid reduction
Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
@@ -7799,7 +8595,7 @@ QProgressBar::chunk{
-
-
+
@@ -7849,49 +8645,61 @@ QProgressBar::chunk{
-
-
-
- QFrame::NoFrame
+
+
+
+ 9
+
-
- QFrame::Raised
+
+ Select branch types to reduce
-
-
-
-
-
- Branch rating factor
-
-
-
- -
-
-
- <html><head/><body><p>Factor to aply to the branch calculated power to use as rating</p></body></html>
-
-
- 1.000000000000000
-
-
- 100.000000000000000
-
-
- 1.200000000000000
-
-
-
- -
-
-
- override values
-
-
-
-
-
-
+
+
+
+ 9
+
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ Filter by r+x under threshold
+
+
+ true
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ <html><head/><body><p>Exponent of the threshold to use.</p><p>threshold = 1x10^-factor</p><p>i.e.</p><p>factor=3</p><p>threshold = 1e-3</p></body></html>
+
+
+ 1e-
+
+
+ 5
+
+
+
+ -
+
Qt::Vertical
@@ -7906,40 +8714,27 @@ QProgressBar::chunk{
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
+
-
+
QFrame::NoFrame
QFrame::Raised
-
+
0
-
-
+
QFrame::NoFrame
QFrame::Raised
-
+
0
@@ -7953,7 +8748,7 @@ QProgressBar::chunk{
0
-
-
+
24
@@ -7970,7 +8765,7 @@ QProgressBar::chunk{
- :/Icons/icons/grid_reduction.svg
+ :/Icons/icons/rate_br.svg
true
@@ -7978,7 +8773,7 @@ QProgressBar::chunk{
-
-
+
@@ -8022,7 +8817,7 @@ QProgressBar::chunk{
- Grid reduction
+ Branch rating
Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
@@ -8033,7 +8828,7 @@ QProgressBar::chunk{
-
-
+
@@ -8083,40 +8878,67 @@ QProgressBar::chunk{
-
-
-
- Select branch types to reduce
-
-
-
- -
-
-
- -
-
-
- Filter by r+x under threshold
-
-
- true
-
-
-
- -
-
-
- <html><head/><body><p>Exponent of the threshold to use.</p><p>threshold = 1x10^-factor</p><p>i.e.</p><p>factor=3</p><p>threshold = 1e-3</p></body></html>
-
-
- 1e-
+
+
+ QFrame::NoFrame
-
- 5
+
+ QFrame::Raised
+
+
-
+
+
+
+ 9
+
+
+
+ Branch rating factor
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ <html><head/><body><p>Factor to aply to the branch calculated power to use as rating</p></body></html>
+
+
+ 1.000000000000000
+
+
+ 100.000000000000000
+
+
+ 0.100000000000000
+
+
+ 1.200000000000000
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ override values
+
+
+
+
-
-
+
Qt::Vertical
@@ -8252,6 +9074,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
File path
@@ -8309,6 +9136,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
If checked, the results are stored inside the gridcal file in a compressed format.
@@ -8319,6 +9151,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
...
@@ -8326,6 +9163,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
...
@@ -8333,6 +9175,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
...
@@ -8413,26 +9260,53 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Export version
-
-
+
+
+
+ 9
+
+
+
-
+
+
+ 9
+
+
Boundary set
-
-
+
+
+
+ 9
+
+
+
-
+
+
+ 9
+
+
Profiles to export
@@ -8440,6 +9314,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
One file per profile
@@ -8528,6 +9407,11 @@ QProgressBar::chunk{
16777215
+
+
+ 9
+
+
Select the CGMES boundary set (single zip file)
@@ -8538,6 +9422,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Path of the CGMES default boundary set (single zip file)
@@ -8582,6 +9471,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Server jobs currently on cue
@@ -8610,6 +9504,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Url
@@ -8617,6 +9516,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Type here the GridCal server URL (ask your IT team)
@@ -8624,6 +9528,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Port
@@ -8631,6 +9540,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Type here the GridCal server Port (ask your IT team)
@@ -8644,6 +9558,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Password
@@ -8651,6 +9570,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
Type here the GridCal server password (ask your IT team)
@@ -8674,6 +9598,11 @@ QProgressBar::chunk{
-
+
+
+ 9
+
+
...
@@ -8697,10 +9626,15 @@ QProgressBar::chunk{
0
0
- 1393
- 22
+ 1346
+ 20
+
+
+ 10
+
+
+
+
@@ -8933,6 +9883,11 @@ QProgressBar::chunk{
Open file
+
+
+ 10
+
+
Ctrl+O
@@ -8945,6 +9900,11 @@ QProgressBar::chunk{
Save
+
+
+ 10
+
+
Ctrl+S
@@ -8957,6 +9917,11 @@ QProgressBar::chunk{
Take picture
+
+
+ 10
+
+
@@ -8966,6 +9931,11 @@ QProgressBar::chunk{
New project
+
+
+ 10
+
+
Ctrl+N
@@ -8981,6 +9951,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Power Flow</span></p><p>Run a power flow analysis</p></body></html>
+
+
+ 10
+
+
F5
@@ -8999,6 +9974,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Power flow</span></p><p>Run the power flow study with time series data</p></body></html>
+
+
+ 10
+
+
Ctrl+F5
@@ -9014,6 +9994,11 @@ QProgressBar::chunk{
Expand distances
+
+
+ 10
+
+
Ctrl+Alt++
@@ -9029,6 +10014,11 @@ QProgressBar::chunk{
Shrink distances
+
+
+ 10
+
+
Ctrl+Alt+-
@@ -9044,6 +10034,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Stochastic power flow</span></p><p>Perform a stochastic power flow over the time series data</p></body></html>
+
+
+ 10
+
+
@@ -9056,6 +10051,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Continuation power flow</span></p><p>Run a continuation power flow over the snapshot data</p></body></html>
+
+
+ 10
+
+
@@ -9065,6 +10065,11 @@ QProgressBar::chunk{
About
+
+
+ 10
+
+
@@ -9077,6 +10082,11 @@ QProgressBar::chunk{
Center view
+
+
+ 10
+
+
Ctrl+E
@@ -9092,6 +10102,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Short Circuit</span></p><p>Run a short circuit study over the snapshot data</p></body></html>
+
+
+ 10
+
+
@@ -9104,6 +10119,11 @@ QProgressBar::chunk{
Automatic layout the of the grid
+
+
+ 10
+
+
@@ -9119,6 +10139,11 @@ QProgressBar::chunk{
Run a simulation or step by step blackout cascade
+
+
+ 10
+
+
@@ -9131,6 +10156,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Optimal power flow</span></p><p>This runs an optimal power flow</p></body></html>
+
+
+ 10
+
+
F6
@@ -9146,6 +10176,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Optimal power flow</span></p><p>This runs an optimal power flow for the time series data</p></body></html>
+
+
+ 10
+
+
Ctrl+F6
@@ -9161,6 +10196,11 @@ QProgressBar::chunk{
<html><head/><body><p>Detect transformers.</p><p>Use the nodes nominal voltage to determine which branches should be a transformer.</p><p>If a branch joins two nodes with different voltage levels, the branch should be a transformer.</p></body></html>
+
+
+ 10
+
+
@@ -9173,6 +10213,11 @@ QProgressBar::chunk{
<html><head/><body><p>Automatic rating of the branches.</p><p>Use the branches calculated power to establish a rate, if the branch rate is unknown. A factor is available in the settings.</p></body></html>
+
+
+ 10
+
+
@@ -9182,6 +10227,11 @@ QProgressBar::chunk{
All the devices' profiles
+
+
+ 10
+
+
@@ -9197,6 +10247,11 @@ QProgressBar::chunk{
Suggest places where storage devices are useful
+
+
+ 10
+
+
@@ -9209,6 +10264,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Data analysis</span></p><p>Launch the data analysis tool that finds and tries to repair common grid modelling issues</p></body></html>
+
+
+ 10
+
+
F12
@@ -9221,6 +10281,11 @@ QProgressBar::chunk{
Online documentation
+
+
+ 10
+
+
F1
@@ -9236,6 +10301,11 @@ QProgressBar::chunk{
Export all the results
+
+
+ 10
+
+
@@ -9245,6 +10315,11 @@ QProgressBar::chunk{
Save as
+
+
+ 10
+
+
@@ -9257,6 +10332,11 @@ QProgressBar::chunk{
Delete selected objects from the diagrams and the database
+
+
+ 10
+
+
Ctrl+Del
@@ -9272,6 +10352,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Linear analysis</span></p><p>Perform linear analysis with distribution factors (PTDF, LODF)</p></body></html>
+
+
+ 10
+
+
F7
@@ -9284,6 +10369,11 @@ QProgressBar::chunk{
Reset console
+
+
+ 10
+
+
@@ -9299,6 +10389,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Copy OPF data</span></p><p>Set the OPF results into the power flow or time series simulations (non destructive)</p></body></html>
+
+
+ 10
+
+
@@ -9311,6 +10406,11 @@ QProgressBar::chunk{
Set selected buses location closer to their neighbours
+
+
+ 10
+
+
@@ -9323,6 +10423,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Copy OPF data</span></p><p>Destructive copy of the OPF generation results to the input profiles</p></body></html>
+
+
+ 10
+
+
@@ -9335,6 +10440,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Linear analysis</span></p><p>PTDF based time series power flow</p></body></html>
+
+
+ 10
+
+
Ctrl+F7
@@ -9350,6 +10460,11 @@ QProgressBar::chunk{
Add circuit to the current circuit
+
+
+ 10
+
+
Ctrl+N, Ctrl+O
@@ -9389,6 +10504,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Sigma analysis</span></p><p>Perform HELM-Sigma analysis over the snapshot data</p></body></html>
+
+
+ 10
+
+
@@ -9398,6 +10518,11 @@ QProgressBar::chunk{
Clear "stuff running right now"
+
+
+ 10
+
+
@@ -9407,6 +10532,11 @@ QProgressBar::chunk{
Add default catalogue
+
+
+ 10
+
+
@@ -9422,6 +10552,11 @@ QProgressBar::chunk{
<html><head/><body><p>Finds the electrically related nodes by using their electrical distance and the DBSCAN clustering method</p></body></html>
+
+
+ 10
+
+
@@ -9431,6 +10566,11 @@ QProgressBar::chunk{
Grid Generator
+
+
+ 10
+
+
Ctrl+G
@@ -9464,6 +10604,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Contingency analysis</span></p><p>Per form a contingency analysis with the selected method over the time series data</p></body></html>
+
+
+ 10
+
+
Ctrl+F8
@@ -9485,6 +10630,11 @@ QProgressBar::chunk{
Set selected buses' Area
+
+
+ 10
+
+
@@ -9494,6 +10644,11 @@ QProgressBar::chunk{
Set selected buses' Zone
+
+
+ 10
+
+
@@ -9503,6 +10658,11 @@ QProgressBar::chunk{
Set seleted buses' Country
+
+
+ 10
+
+
@@ -9512,6 +10672,11 @@ QProgressBar::chunk{
Import bus coordinates
+
+
+ 10
+
+
@@ -9524,6 +10689,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Net Transfer Capacity</span></p><p>Perform a linear net transfer capacity assesment for the snapshot data</p></body></html>
+
+
+ 10
+
+
@@ -9536,6 +10706,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Net Transfer Capacity</span></p><p>Perform a linear net transfer capacity assesment for the time series data</p></body></html>
+
+
+ 10
+
+
@@ -9548,6 +10723,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Contingency analysis</span></p><p>Perform a contingency analysis with the selected method</p></body></html>
+
+
+ 10
+
+
F8
@@ -9563,6 +10743,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Optimal Net Transfer Capacity</span></p><p>Perform an optimal net transfer capacity optimization</p></body></html>
+
+
+ 10
+
+
@@ -9572,6 +10757,11 @@ QProgressBar::chunk{
Set schematic (x,y) from (lat,lon)
+
+
+ 10
+
+
@@ -9584,6 +10774,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Inputs analysis</span></p><p>Perform an analysis of the inputs for both the snapshot and time series data</p></body></html>
+
+
+ 10
+
+
F11
@@ -9599,6 +10794,11 @@ QProgressBar::chunk{
Fuse devices into a single device of each category per node
+
+
+ 10
+
+
@@ -9611,6 +10811,11 @@ QProgressBar::chunk{
Delete inconsistencies
+
+
+ 10
+
+
@@ -9623,6 +10828,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Net Transfer Capacity</span></p><p>Perform a net transfer capacity optimization over the time series data</p></body></html>
+
+
+ 10
+
+
@@ -9632,6 +10842,11 @@ QProgressBar::chunk{
re-index time
+
+
+ 10
+
+
@@ -9641,6 +10856,11 @@ QProgressBar::chunk{
Fix generators active based on the power
+
+
+ 10
+
+
@@ -9653,6 +10873,11 @@ QProgressBar::chunk{
Fix loads active based on the power
+
+
+ 10
+
+
@@ -9662,6 +10887,11 @@ QProgressBar::chunk{
Contingencies
+
+
+ 10
+
+
@@ -9674,6 +10904,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Contingencies wizard</span></p><p>Launch the contingencies wizard to automatically set up the contingency objects</p></body></html>
+
+
+ 10
+
+
@@ -9683,6 +10918,11 @@ QProgressBar::chunk{
Contingencies
+
+
+ 10
+
+
@@ -9695,6 +10935,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Add contingency</span></p><p>Create a new contingency from the schematic selection</p></body></html>
+
+
+ 10
+
+
Ctrl+A, Ctrl+C
@@ -9710,6 +10955,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Investments</span></p><p>Create new investment with the schematic selection</p></body></html>
+
+
+ 10
+
+
Ctrl+A, Ctrl+I
@@ -9722,6 +10972,11 @@ QProgressBar::chunk{
Zoom in
+
+
+ 10
+
+
Ctrl++
@@ -9734,6 +10989,11 @@ QProgressBar::chunk{
Zoom out
+
+
+ 10
+
+
Ctrl+-
@@ -9749,6 +11009,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Clustering</span></p><p>Perform a clustering study of the time series data</p></body></html>
+
+
+ 10
+
+
QAction::NoRole
@@ -9767,6 +11032,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Clustering</span></p><p>If active, the available clustering results are used in all the simulations that handle time series data non-destructivelly</p></body></html>
+
+
+ 10
+
+
@@ -9779,6 +11049,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Investments</span></p><p>Perform the investments evaluation</p></body></html>
+
+
+ 10
+
+
Ctrl+I, Ctrl+E
@@ -9791,6 +11066,11 @@ QProgressBar::chunk{
New diagram from selection
+
+
+ 10
+
+
@@ -9800,6 +11080,11 @@ QProgressBar::chunk{
New schematic
+
+
+ 10
+
+
@@ -9809,6 +11094,11 @@ QProgressBar::chunk{
New map
+
+
+ 10
+
+
@@ -9827,6 +11117,11 @@ QProgressBar::chunk{
Report a bug or feature
+
+
+ 10
+
+
@@ -9836,6 +11131,11 @@ QProgressBar::chunk{
Search
+
+
+ 10
+
+
@@ -9845,6 +11145,11 @@ QProgressBar::chunk{
Process topology
+
+
+ 10
+
+
@@ -9857,6 +11162,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Time series</span></p><p>Edit simulation time limits</p></body></html>
+
+
+ 10
+
+
@@ -9872,6 +11182,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Time series mode</span></p><p>When activated, the simulations run their time series version</p></body></html>
+
+
+ 10
+
+
Ctrl+T
@@ -9884,6 +11199,11 @@ QProgressBar::chunk{
Clean database
+
+
+ 10
+
+
Ctrl+C, Ctrl+D
@@ -9896,6 +11216,11 @@ QProgressBar::chunk{
Select buses by area
+
+
+ 10
+
+
@@ -9905,6 +11230,11 @@ QProgressBar::chunk{
Select buses by zone
+
+
+ 10
+
+
@@ -9914,6 +11244,11 @@ QProgressBar::chunk{
Select buses by country
+
+
+ 10
+
+
@@ -9926,6 +11261,11 @@ QProgressBar::chunk{
Scale the system load and or generation
+
+
+ 10
+
+
@@ -9935,6 +11275,11 @@ QProgressBar::chunk{
Disable all results tags
+
+
+ 10
+
+
@@ -9944,6 +11289,11 @@ QProgressBar::chunk{
Enable all results tags
+
+
+ 10
+
+
@@ -9953,6 +11303,11 @@ QProgressBar::chunk{
Detect substations
+
+
+ 10
+
+
@@ -9965,6 +11320,11 @@ QProgressBar::chunk{
<html><head/><body><p><span style=" font-weight:700;">Nodal hosting capacity</span></p><p>Run the nodal hosting capacity calculation using the selected optimization method</p></body></html>
+
+
+ 10
+
+
@@ -9977,6 +11337,11 @@ QProgressBar::chunk{
Enable server mode
+
+
+ 10
+
+
@@ -9986,6 +11351,11 @@ QProgressBar::chunk{
Delete selected from the diagram
+
+
+ 10
+
+
Del
@@ -10001,6 +11371,11 @@ QProgressBar::chunk{
Record video of the schematic
+
+
+ 10
+
+
@@ -10010,6 +11385,11 @@ QProgressBar::chunk{
Circuit differential
+
+
+ 10
+
+
@@ -10022,6 +11402,11 @@ QProgressBar::chunk{
Catalogue
+
+
+ 10
+
+
@@ -10031,6 +11416,11 @@ QProgressBar::chunk{
Catalogue
+
+
+ 10
+
+
diff --git a/src/GridCal/Gui/Main/SubClasses/Model/compiled_arrays.py b/src/GridCal/Gui/Main/SubClasses/Model/compiled_arrays.py
index 7f655425d..ce64b7986 100644
--- a/src/GridCal/Gui/Main/SubClasses/Model/compiled_arrays.py
+++ b/src/GridCal/Gui/Main/SubClasses/Model/compiled_arrays.py
@@ -18,9 +18,11 @@
from PySide6 import QtCore
from matplotlib import pyplot as plt
-from GridCalEngine.enumerations import EngineType
from GridCal.Gui.pandas_model import PandasModel
from GridCal.Gui.Main.SubClasses.Server.server import ServerMain
+import GridCal.Gui.GuiFunctions as gf
+
+from GridCalEngine.enumerations import EngineType
from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
@@ -50,24 +52,37 @@ def __init__(self, parent=None):
self.ui.copyArraysButton.clicked.connect(self.copy_simulation_objects_data)
self.ui.copyArraysToNumpyButton.clicked.connect(self.copy_simulation_objects_data_to_numpy)
- # list clicks
- self.ui.simulationDataStructuresListView.clicked.connect(self.view_simulation_objects_data)
+ # tree clicks
+ self.ui.simulationDataStructuresTreeView.clicked.connect(self.view_simulation_objects_data)
- def view_simulation_objects_data(self):
+ def view_simulation_objects_data(self, index):
"""
Simulation data structure clicked
"""
- i = self.ui.simulation_data_island_comboBox.currentIndex()
+ tree_mdl = self.ui.simulationDataStructuresTreeView.model()
+ item = tree_mdl.itemFromIndex(index)
+ path = gf.get_tree_item_path(item)
+
+ if len(path) == 2:
+ group_name = path[0]
+ elm_type = path[1]
- if i > -1 and self.circuit.valid_for_simulation():
- elm_type = self.ui.simulationDataStructuresListView.selectedIndexes()[0].data(role=QtCore.Qt.ItemDataRole.DisplayRole)
+ island_idx = self.ui.simulation_data_island_comboBox.currentIndex()
- df = self.calculation_inputs_to_display[i].get_structure(elm_type)
+ if island_idx > -1 and self.circuit.valid_for_simulation():
+ # elm_type = self.ui.simulationDataStructuresTreeView.selectedIndexes()[0].data(role=QtCore.Qt.ItemDataRole.DisplayRole)
- mdl = PandasModel(df)
+ df = self.calculation_inputs_to_display[island_idx].get_structure(elm_type)
- self.ui.simulationDataStructureTableView.setModel(mdl)
+ mdl = PandasModel(df)
+
+ self.ui.simulationDataStructureTableView.setModel(mdl)
+
+ else:
+ self.ui.simulationDataStructureTableView.setModel(None)
+ else:
+ self.ui.simulationDataStructureTableView.setModel(None)
def copy_simulation_objects_data(self):
"""
diff --git a/src/GridCal/Gui/Main/SubClasses/Model/diagrams.py b/src/GridCal/Gui/Main/SubClasses/Model/diagrams.py
index 30c03d4aa..5ed663a44 100644
--- a/src/GridCal/Gui/Main/SubClasses/Model/diagrams.py
+++ b/src/GridCal/Gui/Main/SubClasses/Model/diagrams.py
@@ -24,6 +24,7 @@
from pandas.plotting import register_matplotlib_converters
import GridCalEngine.Devices.Diagrams.palettes as palettes
+from GridCalEngine.Devices import TransformerType, OverheadLineType, SequenceLineType, UndergroundLineType
from GridCalEngine.IO.file_system import get_create_gridcal_folder
from GridCal.Gui.GeneralDialogues import (CheckListDialogue, StartEndSelectionDialogue, InputSearchDialogue,
InputNumberDialogue)
@@ -800,7 +801,6 @@ def colour_diagrams(self) -> None:
"""
Color the grid now
"""
- print("Colour!")
if self.ui.available_results_to_color_comboBox.currentIndex() > -1:
current_study = self.ui.available_results_to_color_comboBox.currentText()
@@ -1120,31 +1120,37 @@ def create_circuit_stored_diagrams(self):
self.set_diagrams_list_view()
- def add_map_diagram(self) -> None:
+ def add_map_diagram(self, ask: bool = True) -> None:
"""
Adds a Map diagram
"""
+ if ask:
+ ok = yes_no_question(text=f"Do you want to add all substations to the map?\nYou can add them later.",
+ title="New map")
+ else:
+ ok = True
+
+ if ok:
+ diagram = generate_map_diagram(substations=self.circuit.get_substations(),
+ voltage_levels=self.circuit.get_voltage_levels(),
+ lines=self.circuit.get_lines(),
+ dc_lines=self.circuit.get_dc_lines(),
+ hvdc_lines=self.circuit.get_hvdc(),
+ fluid_nodes=self.circuit.get_fluid_nodes(),
+ fluid_paths=self.circuit.get_fluid_paths(),
+ prog_func=None,
+ text_func=None,
+ name='Map diagram')
+
+ # set other default properties of the diagram
+ diagram.tile_source = self.ui.tile_provider_comboBox.currentText()
+ diagram.start_level = 5
+ else:
+ diagram = dev.MapDiagram(name='Map diagram')
+
# select the tile source
tile_source = self.tile_name_dict[self.ui.tile_provider_comboBox.currentText()]
- diagram = generate_map_diagram(substations=self.circuit.get_substations(),
- voltage_levels=self.circuit.get_voltage_levels(),
- lines=self.circuit.get_lines(),
- dc_lines=self.circuit.get_dc_lines(),
- hvdc_lines=self.circuit.get_hvdc(),
- fluid_nodes=self.circuit.get_fluid_nodes(),
- fluid_paths=self.circuit.get_fluid_paths(),
- prog_func=None,
- text_func=None,
- name='Map diagram')
-
- # set other default properties of the diagram
- diagram.tile_source = self.ui.tile_provider_comboBox.currentText()
- diagram.start_level = 5
-
- # diagram.longitude = -15.41
- # diagram.latitude = 40.11
-
# create the map widget
map_widget = GridMapWidget(tile_src=tile_source,
start_level=diagram.start_level,
@@ -1749,7 +1755,7 @@ def show_diagrams_context_menu(self, pos: QtCore.QPoint):
gf.add_menu_entry(menu=context_menu,
text="New map",
icon_path=":/Icons/icons/map (add).svg",
- function_ptr=self.add_map_diagram)
+ function_ptr=lambda: self.add_map_diagram(True))
context_menu.addSeparator()
gf.add_menu_entry(menu=context_menu,
@@ -1825,6 +1831,14 @@ def set_diagrams_palette(self):
cmap = self.cmap_dict[cmap_text]
diagram_widget.diagram.palette = cmap
+ current_study = self.ui.available_results_to_color_comboBox.currentText()
+ val = self.ui.diagram_step_slider.value()
+ t_idx = val if val > -1 else None
+
+ self.grid_colour_function(diagram=diagram_widget,
+ current_study=current_study,
+ t_idx=t_idx)
+
def set_diagrams_map_tile_provider(self):
"""
Set the size constraints
@@ -1836,4 +1850,4 @@ def set_diagrams_map_tile_provider(self):
if isinstance(diagram_widget, GridMapWidget):
tile_name = self.ui.tile_provider_comboBox.currentText()
tile_src = self.tile_name_dict[tile_name]
- diagram_widget.map.tile_src = tile_src
\ No newline at end of file
+ diagram_widget.map.tile_src = tile_src
diff --git a/src/GridCal/Gui/Main/SubClasses/Model/objects.py b/src/GridCal/Gui/Main/SubClasses/Model/objects.py
index f4e88c57f..c51edc0e2 100644
--- a/src/GridCal/Gui/Main/SubClasses/Model/objects.py
+++ b/src/GridCal/Gui/Main/SubClasses/Model/objects.py
@@ -38,6 +38,7 @@
from GridCal.Gui.TowerBuilder.LineBuilderDialogue import TowerBuilderGUI
from GridCal.Gui.GeneralDialogues import LogsDialogue
from GridCal.Gui.Diagrams.SchematicWidget.schematic_widget import SchematicWidget
+from GridCal.Gui.Diagrams.MapWidget.grid_map_widget import GridMapWidget
from GridCal.Gui.SystemScaler.system_scaler import SystemScaler
@@ -61,7 +62,7 @@ def __init__(self, parent=None):
self.ui.dataStructuresTreeView.setModel(gf.get_tree_model(self.circuit.get_objects_with_profiles_str_dict()))
self.expand_object_tree_nodes()
- self.ui.simulationDataStructuresListView.setModel(gf.get_list_model(NumericalCircuit.available_structures))
+ self.ui.simulationDataStructuresTreeView.setModel(gf.get_tree_model(NumericalCircuit.available_structures))
# Buttons
self.ui.filter_pushButton.clicked.connect(self.objects_smart_search)
@@ -539,21 +540,27 @@ def add_objects_to_current_diagram(self):
if len(selected_objects):
diagram = self.get_selected_diagram_widget()
+ logger = bs.Logger()
if isinstance(diagram, SchematicWidget):
injections_by_bus = self.circuit.get_injection_devices_grouped_by_bus()
injections_by_fluid_node = self.circuit.get_injection_devices_grouped_by_fluid_node()
- logger = bs.Logger()
+
for device in selected_objects:
diagram.add_object_to_the_schematic(elm=device,
injections_by_bus=injections_by_bus,
injections_by_fluid_node=injections_by_fluid_node,
logger=logger)
- if len(logger):
- dlg = LogsDialogue(name="Add selected DB objects to current diagram", logger=logger)
- dlg.setModal(True)
- dlg.exec()
+ elif isinstance(diagram, GridMapWidget):
+
+ for device in selected_objects:
+ diagram.add_object_to_the_schematic(elm=device, logger=logger)
+
+ if len(logger):
+ dlg = LogsDialogue(name="Add selected DB objects to current diagram", logger=logger)
+ dlg.setModal(True)
+ dlg.exec()
def add_objects(self):
"""
diff --git a/src/GridCal/Gui/Main/SubClasses/Scripting/scripting.py b/src/GridCal/Gui/Main/SubClasses/Scripting/scripting.py
index c261a488e..4e334815b 100644
--- a/src/GridCal/Gui/Main/SubClasses/Scripting/scripting.py
+++ b/src/GridCal/Gui/Main/SubClasses/Scripting/scripting.py
@@ -51,11 +51,11 @@ def __init__(self, parent=None):
self.ui.sourceCodeTextEdit.highlighter = PythonHighlighter(self.ui.sourceCodeTextEdit.document())
- # tree view
- root_path = self.scripts_path()
+ # scripts tree view
+ scripts_path = self.scripts_path()
self.python_fs_model = CustomFileSystemModel(root_path=self.scripts_path(), ext_filter=['*.py'])
self.ui.sourceCodeTreeView.setModel(self.python_fs_model)
- self.ui.sourceCodeTreeView.setRootIndex(self.python_fs_model.index(root_path))
+ self.ui.sourceCodeTreeView.setRootIndex(self.python_fs_model.index(scripts_path))
# actions ------------------------------------------------------------------------------------------------------
self.ui.actionReset_console.triggered.connect(self.create_console)
diff --git a/src/GridCal/Gui/Main/SubClasses/Settings/configuration.py b/src/GridCal/Gui/Main/SubClasses/Settings/configuration.py
index 5c28a8142..42cadb7ef 100644
--- a/src/GridCal/Gui/Main/SubClasses/Settings/configuration.py
+++ b/src/GridCal/Gui/Main/SubClasses/Settings/configuration.py
@@ -24,6 +24,8 @@
from GridCal.Gui.Main.SubClasses.Results.results import ResultsMain
from GridCal.Gui.Diagrams.SchematicWidget.schematic_widget import SchematicWidget
from GridCal.Gui.Diagrams.generic_graphics import set_dark_mode, set_light_mode
+from GridCal.Gui.plugins import PluginsInfo
+from GridCal.Gui.GuiFunctions import add_menu_entry
def config_data_to_struct(data_: Dict[str, Union[Dict[str, Any], str, Any]],
@@ -90,6 +92,9 @@ def __init__(self, parent=None):
# create main window
ResultsMain.__init__(self, parent)
+ # plugins
+ self.plugins_info = PluginsInfo()
+
# check boxes
self.ui.dark_mode_checkBox.clicked.connect(self.change_theme_mode)
@@ -218,17 +223,20 @@ def get_config_structure(self) -> Dict[str, Dict[str, any]]:
"retry": self.ui.helm_retry_checkBox,
"distributed_slack": self.ui.distributed_slack_checkBox,
"ignore_single_node_islands": self.ui.ignore_single_node_islands_checkBox,
- "automatic_precision": self.ui.auto_precision_checkBox,
"use_voltage_guess": self.ui.use_voltage_guess_checkBox,
"precision": self.ui.tolerance_spinBox,
"acceleration": self.ui.muSpinBox,
"max_iterations": self.ui.max_iterations_spinBox,
"verbosity": self.ui.verbositySpinBox,
- "reactive_power_control_mode": self.ui.reactive_power_control_mode_comboBox,
- "transformer_taps_control_mode": self.ui.taps_control_mode_comboBox,
+
+ "reactive_power_control_mode": self.ui.control_q_checkBox,
+ "transformer_taps_module_control": self.ui.control_tap_modules_checkBox,
+ "transformer_taps_phase_control": self.ui.control_tap_phase_checkBox,
+ "remote_voltage_controls_switch": self.ui.control_remote_voltage_checkBox,
+ "orthogonalize_controls": self.ui.orthogonalize_pf_controls_checkBox,
+
"apply_temperature_correction": self.ui.temperature_correction_checkBox,
"apply_impedance_tolerances": self.ui.apply_impedance_tolerances_checkBox,
- "override_branch_controls": self.ui.override_branch_controls_checkBox,
"add_pf_report": self.ui.addPowerFlowReportCheckBox,
},
"optimal_power_flow": {
@@ -426,3 +434,29 @@ def snapshot_datetime_changed(self):
date_time_value = self.ui.snapshot_dateTimeEdit.dateTime().toPython()
self.circuit.snapshot_time = date_time_value
+
+ def add_plugins(self):
+ """
+ Add the plugins information and create the menu entries
+ """
+ self.ui.menuplugins.clear()
+
+ add_menu_entry(menu=self.ui.menuplugins,
+ text="Reload",
+ icon_path=":/Icons/icons/undo.svg",
+ function_ptr=self.add_plugins)
+
+ self.plugins_info.read() # force refresh
+
+ for plugin_info in self.plugins_info.plugins:
+
+ if plugin_info.function_ptr is not None:
+
+ add_menu_entry(menu=self.ui.menuplugins,
+ text=plugin_info.name,
+ icon_path=":/Icons/icons/plugin.svg",
+ icon_pixmap=plugin_info.icon,
+ function_ptr=lambda: plugin_info.function_ptr(self))
+
+ else:
+ print(f"{plugin_info.name} has no function_ptr, see trace for errors :/")
diff --git a/src/GridCal/Gui/Main/SubClasses/base_gui.py b/src/GridCal/Gui/Main/SubClasses/base_gui.py
index 5a3ea42f5..9308e38dd 100644
--- a/src/GridCal/Gui/Main/SubClasses/base_gui.py
+++ b/src/GridCal/Gui/Main/SubClasses/base_gui.py
@@ -40,7 +40,7 @@
from GridCalEngine.Compilers.circuit_to_bentayga import BENTAYGA_AVAILABLE
from GridCalEngine.Compilers.circuit_to_newton_pa import NEWTON_PA_AVAILABLE
from GridCalEngine.Compilers.circuit_to_pgm import PGM_AVAILABLE
-
+from GridCalEngine.IO.file_system import get_create_gridcal_folder
import GridCal.Gui.GuiFunctions as gf
import GridCal.Session.synchronization_driver as syncdrv
from GridCal.Gui.AboutDialogue.about_dialogue import AboutDialogueGuiGUI
@@ -161,8 +161,8 @@ def __init__(self, parent=None):
self.file_sync_thread = syncdrv.FileSyncThread(self.circuit, None, None)
# simulation start end
- self.simulation_start_index: int = 0
- self.simulation_end_index: int = 0
+ self.simulation_start_index: int = -1
+ self.simulation_end_index: int = -1
# window pointers ------------------------------------------------------------------------------------------
self.file_sync_window: Union[SyncDialogueWindow, None] = None
@@ -277,7 +277,8 @@ def create_console(self) -> None:
"pd: pandas\n"
"plt: matplotlib\n"
"app: This instance of GridCal\n"
- "circuit: The current grid\n\n")
+ "circuit: The current grid\n"
+ "user_folder: path to the user folder\n")
self.console.buffer_size = 10000
@@ -285,13 +286,17 @@ def create_console(self) -> None:
self.ui.pythonConsoleTab.layout().addWidget(self.console)
# push some variables to the console
- self.console.push_vars({"hlp": self.print_console_help,
- "np": np,
- "pd": pd,
- "plt": plt,
- "clc": self.clc,
- 'app': self,
- 'circuit': self.circuit})
+ self.console.push_vars(
+ {"hlp": self.print_console_help,
+ "np": np,
+ "pd": pd,
+ "plt": plt,
+ "clc": self.clc,
+ 'app': self,
+ 'circuit': self.circuit,
+ 'user_folder': get_create_gridcal_folder,
+ }
+ )
if IS_DARK:
self.console.set_dark_theme()
@@ -581,6 +586,7 @@ def update_date_dependent_combos(self):
else:
mdl = QtGui.QStandardItemModel()
+ self.setup_sim_indices(-1, -1)
self.ui.vs_departure_comboBox.setModel(mdl)
self.ui.vs_target_comboBox.setModel(mdl)
self.setup_time_sliders()
diff --git a/src/GridCal/Gui/Main/SubClasses/io.py b/src/GridCal/Gui/Main/SubClasses/io.py
index 694682d7b..2f839a1ea 100644
--- a/src/GridCal/Gui/Main/SubClasses/io.py
+++ b/src/GridCal/Gui/Main/SubClasses/io.py
@@ -208,7 +208,7 @@ def new_project_now(self, create_default_diagrams=True):
if create_default_diagrams:
self.add_complete_bus_branch_diagram()
- self.add_map_diagram()
+ self.add_map_diagram(ask=False)
self.set_diagram_widget(self.diagram_widgets_list[0])
self.collect_memory()
@@ -340,6 +340,10 @@ def post_open_file(self) -> None:
# create the diagrams that came with the file
self.create_circuit_stored_diagrams()
+ if len(self.diagram_widgets_list) > 0:
+ diagram = self.diagram_widgets_list[0]
+ self.set_diagram_widget(diagram)
+
else:
if self.circuit.get_bus_number() > 1500:
quit_msg = ("The grid is quite large, hence the schematic might be slow.\n"
@@ -895,10 +899,11 @@ def export_simulation_data(self):
for c, calc_input in enumerate(calculation_inputs):
- for elm_type in calc_input.available_structures:
- name = elm_type + '_' + str(c)
- df = calc_input.get_structure(elm_type).astype(str)
- df.to_excel(writer, name)
+ for category, elms_in_category in calc_input.available_structures.items():
+ for elm_type in elms_in_category:
+ name = f"{category}_{elm_type}@{c}"
+ df = calc_input.get_structure(elm_type).astype(str)
+ df.to_excel(excel_writer=writer, sheet_name=name[:31]) # excel supports 31 chars per sheet name
def load_results_driver(self):
"""
diff --git a/src/GridCal/Gui/Main/SubClasses/simulations.py b/src/GridCal/Gui/Main/SubClasses/simulations.py
index 2d8f6f205..a6165d477 100644
--- a/src/GridCal/Gui/Main/SubClasses/simulations.py
+++ b/src/GridCal/Gui/Main/SubClasses/simulations.py
@@ -14,6 +14,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from __future__ import annotations
+
import os
import datetime
import numpy as np
@@ -41,8 +43,7 @@
from GridCalEngine.IO.gridcal.remote import RemoteInstruction
from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
from GridCalEngine.Simulations.types import DRIVER_OBJECTS
-from GridCalEngine.enumerations import (DeviceType, AvailableTransferMode, SolverType,
- ReactivePowerControlMode, TapsControlMode, MIPSolvers, TimeGrouping,
+from GridCalEngine.enumerations import (DeviceType, AvailableTransferMode, SolverType, MIPSolvers, TimeGrouping,
ZonalGrouping, ContingencyMethod, InvestmentEvaluationMethod, EngineType,
BranchImpedanceMode, ResultTypes, SimulationTypes, NodalCapacityMethod,
ContingencyFilteringMethods, InvestmentsEvaluationObjectives)
@@ -65,9 +66,9 @@ def __init__(self, parent=None):
# Power Flow Methods
self.solvers_dict = OrderedDict()
self.solvers_dict[SolverType.NR.value] = SolverType.NR
- self.solvers_dict[SolverType.NRI.value] = SolverType.NRI
self.solvers_dict[SolverType.IWAMOTO.value] = SolverType.IWAMOTO
self.solvers_dict[SolverType.LM.value] = SolverType.LM
+ self.solvers_dict[SolverType.PowellDogLeg.value] = SolverType.PowellDogLeg
self.solvers_dict[SolverType.FASTDECOUPLED.value] = SolverType.FASTDECOUPLED
self.solvers_dict[SolverType.HELM.value] = SolverType.HELM
self.solvers_dict[SolverType.GAUSS.value] = SolverType.GAUSS
@@ -77,20 +78,6 @@ def __init__(self, parent=None):
self.ui.solver_comboBox.setModel(gf.get_list_model(list(self.solvers_dict.keys())))
self.ui.solver_comboBox.setCurrentIndex(0)
- # reactive power controls
- self.q_control_modes_dict = OrderedDict()
- self.q_control_modes_dict['No control'] = ReactivePowerControlMode.NoControl
- self.q_control_modes_dict['Direct'] = ReactivePowerControlMode.Direct
- lst = list(self.q_control_modes_dict.keys())
- self.ui.reactive_power_control_mode_comboBox.setModel(gf.get_list_model(lst))
-
- # taps controls (transformer voltage regulator)
- self.taps_control_modes_dict = OrderedDict()
- self.taps_control_modes_dict['No control'] = TapsControlMode.NoControl
- self.taps_control_modes_dict['Direct'] = TapsControlMode.Direct
- lst = list(self.taps_control_modes_dict.keys())
- self.ui.taps_control_mode_comboBox.setModel(gf.get_list_model(lst))
-
# transfer modes
self.transfer_modes_dict = OrderedDict()
self.transfer_modes_dict['Area generation'] = AvailableTransferMode.Generation
@@ -250,6 +237,9 @@ def __init__(self, parent=None):
self.ui.engineComboBox.currentTextChanged.connect(self.modify_ui_options_according_to_the_engine)
self.ui.contingency_filter_by_comboBox.currentTextChanged.connect(self.modify_contingency_filter_mode)
+ # button
+ self.ui.find_automatic_precission_Button.clicked.connect(self.automatic_pf_precission)
+
def get_simulations(self) -> List[DRIVER_OBJECTS]:
"""
Get all threads that have to do with simulation
@@ -280,16 +270,19 @@ def get_available_results(self):
return lst
- def get_time_indices(self) -> np.ndarray:
+ def get_time_indices(self) -> np.ndarray | None:
"""
Get an array of indices of the time steps selected within the start-end interval
:return: np.array[int]
"""
- start = self.get_simulation_start()
- end = self.get_simulation_end()
+ if self.circuit.time_profile is None:
+ return None
+ else:
+ start = self.get_simulation_start()
+ end = self.get_simulation_end()
- return np.arange(start, end + 1)
+ return np.arange(start, end + 1)
def modify_ui_options_according_to_the_engine(self) -> None:
"""
@@ -310,8 +303,8 @@ def modify_ui_options_according_to_the_engine(self) -> None:
# Power Flow Methods
self.solvers_dict[SolverType.NR.value] = SolverType.NR
- self.solvers_dict[SolverType.NRI.value] = SolverType.NRI
self.solvers_dict[SolverType.IWAMOTO.value] = SolverType.IWAMOTO
+
self.solvers_dict[SolverType.LM.value] = SolverType.LM
self.solvers_dict[SolverType.FASTDECOUPLED.value] = SolverType.FASTDECOUPLED
self.solvers_dict[SolverType.HELM.value] = SolverType.HELM
@@ -338,9 +331,9 @@ def modify_ui_options_according_to_the_engine(self) -> None:
# Power Flow Methods
self.solvers_dict = OrderedDict()
self.solvers_dict[SolverType.NR.value] = SolverType.NR
- self.solvers_dict[SolverType.NRI.value] = SolverType.NRI
self.solvers_dict[SolverType.IWAMOTO.value] = SolverType.IWAMOTO
self.solvers_dict[SolverType.LM.value] = SolverType.LM
+ self.solvers_dict[SolverType.PowellDogLeg.value] = SolverType.PowellDogLeg
self.solvers_dict[SolverType.FASTDECOUPLED.value] = SolverType.FASTDECOUPLED
self.solvers_dict[SolverType.HELM.value] = SolverType.HELM
self.solvers_dict[SolverType.GAUSS.value] = SolverType.GAUSS
@@ -366,7 +359,6 @@ def modify_ui_options_according_to_the_engine(self) -> None:
# Power Flow Methods
self.solvers_dict = OrderedDict()
self.solvers_dict[SolverType.NR.value] = SolverType.NR
- self.solvers_dict[SolverType.NRI.value] = SolverType.NRI
self.solvers_dict[SolverType.IWAMOTO.value] = SolverType.IWAMOTO
self.solvers_dict[SolverType.LM.value] = SolverType.LM
self.solvers_dict[SolverType.FASTDECOUPLED.value] = SolverType.FASTDECOUPLED
@@ -629,66 +621,38 @@ def get_compatible_areas_from_to(self) -> Tuple[
lst_br_hvdc = self.circuit.get_inter_areas_hvdc_branches(areas_from, areas_to)
return True, lst_from, lst_to, lst_br, lst_br_hvdc, areas_from, areas_to
- def get_selected_power_flow_options(self):
+ def get_selected_power_flow_options(self) -> sim.PowerFlowOptions:
"""
Gather power flow run options
- :return:
+ :return: sim.PowerFlowOptions
"""
- solver_type = self.solvers_dict[self.ui.solver_comboBox.currentText()]
-
- q_control_mode = self.q_control_modes_dict[self.ui.reactive_power_control_mode_comboBox.currentText()]
- taps_control_mode = self.taps_control_modes_dict[self.ui.taps_control_mode_comboBox.currentText()]
-
- verbose = self.ui.verbositySpinBox.value()
-
- exponent = self.ui.tolerance_spinBox.value()
- tolerance = 1.0 / (10.0 ** exponent)
-
- max_iter = self.ui.max_iterations_spinBox.value()
-
- max_outer_iter = 1000 # not used anymore
-
- mu = self.ui.muSpinBox.value()
-
- if self.ui.helm_retry_checkBox.isChecked():
- retry_with_other_methods = True # to set a value
- else:
- retry_with_other_methods = False
+ tolerance = 1.0 / (10.0 ** self.ui.tolerance_spinBox.value())
if self.ui.apply_impedance_tolerances_checkBox.isChecked():
branch_impedance_tolerance_mode = BranchImpedanceMode.Upper
else:
branch_impedance_tolerance_mode = BranchImpedanceMode.Specified
- temp_correction = self.ui.temperature_correction_checkBox.isChecked()
-
- distributed_slack = self.ui.distributed_slack_checkBox.isChecked()
-
- ignore_single_node_islands = self.ui.ignore_single_node_islands_checkBox.isChecked()
-
- use_stored_guess = self.ui.use_voltage_guess_checkBox.isChecked()
-
- override_branch_controls = self.ui.override_branch_controls_checkBox.isChecked()
-
- generate_report = self.ui.addPowerFlowReportCheckBox.isChecked()
-
- ops = sim.PowerFlowOptions(solver_type=solver_type,
- retry_with_other_methods=retry_with_other_methods,
- verbose=verbose,
- tolerance=tolerance,
- max_iter=max_iter,
- max_outer_loop_iter=max_outer_iter,
- control_q=q_control_mode,
- control_taps=taps_control_mode,
- apply_temperature_correction=temp_correction,
- branch_impedance_tolerance_mode=branch_impedance_tolerance_mode,
- distributed_slack=distributed_slack,
- ignore_single_node_islands=ignore_single_node_islands,
- trust_radius=mu,
- use_stored_guess=use_stored_guess,
- override_branch_controls=override_branch_controls,
- generate_report=generate_report)
+ ops = sim.PowerFlowOptions(
+ solver_type=self.solvers_dict[self.ui.solver_comboBox.currentText()],
+ retry_with_other_methods=self.ui.helm_retry_checkBox.isChecked(),
+ verbose=self.ui.verbositySpinBox.value(),
+ tolerance=tolerance,
+ max_iter=self.ui.max_iterations_spinBox.value(),
+ max_outer_loop_iter=1000,
+ control_q=self.ui.control_q_checkBox.isChecked(),
+ control_taps_phase=self.ui.control_tap_phase_checkBox.isChecked(),
+ control_taps_modules=self.ui.control_tap_modules_checkBox.isChecked(),
+ control_remote_voltage=self.ui.control_remote_voltage_checkBox.isChecked(),
+ apply_temperature_correction=self.ui.temperature_correction_checkBox.isChecked(),
+ branch_impedance_tolerance_mode=branch_impedance_tolerance_mode,
+ distributed_slack=self.ui.distributed_slack_checkBox.isChecked(),
+ ignore_single_node_islands=self.ui.ignore_single_node_islands_checkBox.isChecked(),
+ trust_radius=self.ui.muSpinBox.value(),
+ use_stored_guess=self.ui.use_voltage_guess_checkBox.isChecked(),
+ generate_report=self.ui.addPowerFlowReportCheckBox.isChecked()
+ )
return ops
@@ -888,16 +852,6 @@ def run_power_flow(self):
# get the power flow options from the GUI
options = self.get_selected_power_flow_options()
- # compute the automatic precision
- if self.ui.auto_precision_checkBox.isChecked():
-
- options.tolerance, tol_idx = self.circuit.get_automatic_precision()
-
- if tol_idx > 12:
- tol_idx = 12
-
- self.ui.tolerance_spinBox.setValue(tol_idx)
-
opf_results = self.get_opf_results(use_opf=self.ui.actionOpf_to_Power_flow.isChecked())
self.ui.progress_label.setText('Running power flow...')
@@ -987,8 +941,7 @@ def run_short_circuit(self):
# get the power flow options from the GUI
sc_options = sim.ShortCircuitOptions(bus_index=sel_buses[0],
- fault_type=self_short_circuit_types[0],
- branch_impedance_tolerance_mode=branch_impedance_tolerance_mode)
+ fault_type=self_short_circuit_types[0])
pf_options = self.get_selected_power_flow_options()
@@ -2814,3 +2767,15 @@ def post_nodal_capacity(self):
if not self.session.is_anything_running():
self.UNLOCK()
+
+ def automatic_pf_precission(self):
+ """
+ Find the automatic tolerance
+ :return:
+ """
+ tolerance, tol_idx = self.circuit.get_automatic_precision()
+
+ if tol_idx > 12:
+ tol_idx = 12
+
+ self.ui.tolerance_spinBox.setValue(tol_idx)
diff --git a/src/GridCal/Gui/Main/icons.qrc b/src/GridCal/Gui/Main/icons.qrc
index f7d3bbf94..8802b8780 100644
--- a/src/GridCal/Gui/Main/icons.qrc
+++ b/src/GridCal/Gui/Main/icons.qrc
@@ -1,5 +1,6 @@
+ icons/plugin.svg
icons/picture.svg
icons/CataloguePrivate.svg
icons/record.svg
diff --git a/src/GridCal/Gui/Main/icons/plugin.svg b/src/GridCal/Gui/Main/icons/plugin.svg
new file mode 100644
index 000000000..b3058d3a9
--- /dev/null
+++ b/src/GridCal/Gui/Main/icons/plugin.svg
@@ -0,0 +1,87 @@
+
+
+
+
diff --git a/src/GridCal/Gui/Main/icons_rc.py b/src/GridCal/Gui/Main/icons_rc.py
index ac1074f92..a8fac2e6b 100644
--- a/src/GridCal/Gui/Main/icons_rc.py
+++ b/src/GridCal/Gui/Main/icons_rc.py
@@ -3204,6 +3204,208 @@
paint-order:norm\
al;fill-opacity:\
1\x22 />\x0a\x0a\
+\x00\x00\x0c\x80\
+<\
+?xml version=\x221.\
+0\x22 encoding=\x22UTF\
+-8\x22 standalone=\x22\
+no\x22?>\x0a\x0a\
+\x0a\x0a\
\x00\x00\x04\xe6\
\x00\
\x00\x1d\xb9x\xda\xed\x99Mo\xe36\x10\x86\xef\xfb+\
@@ -15002,144 +15204,6 @@
\xa1\x15Z\xdfc,\x1dH\x03:a9Hg\xf4\x84\
\x96P\xff\xbe]\xcf\x027-ix\xd3\xc1\xfd\xef\x93\
\xd4\xff]\x84\x1f\xb4}\xf3\xe2\x7fPK\x9bk\
-\x00\x00\x08r\
-<\
-?xml version=\x221.\
-0\x22 encoding=\x22UTF\
--8\x22 standalone=\x22\
-no\x22?>\x0a\x0a\
-\x0a\
-\x0a\
\x00\x00\x0dN\
<\
?xml version=\x221.\
@@ -15355,6 +15419,144 @@
rray:none;stroke\
-opacity:1\x22 />\x0a \
\x0a\x0a\
+\x00\x00\x08r\
+<\
+?xml version=\x221.\
+0\x22 encoding=\x22UTF\
+-8\x22 standalone=\x22\
+no\x22?>\x0a\x0a\
+\x0a\
+\x0a\
\x00\x00\x05\xee\
\x00\
\x00\x15Tx\xda\xe5X\xdbn\xe36\x10}\xdf\xaf\x10\
@@ -30233,6 +30435,10 @@
\x06\xbbO\xe7\
\x00a\
\x00t\x00c\x00_\x00t\x00s\x00.\x00s\x00v\x00g\
+\x00\x0a\
+\x0e\x0f\xbd\xa7\
+\x00p\
+\x00l\x00u\x00g\x00i\x00n\x00.\x00s\x00v\x00g\
\x00\x0e\
\x0b0\xc5\xa7\
\x00c\
@@ -30513,14 +30719,14 @@
\x00p\
\x00f\x00_\x00t\x00s\x00_\x00c\x00l\x00u\x00s\x00t\x00e\x00r\x00.\x00s\x00v\x00g\
\
-\x00\x09\
-\x0a\x86\xb3G\
-\x00n\
-\x00e\x00w\x002\x00c\x00.\x00s\x00v\x00g\
\x00\x0b\
\x05\x03\x96\xa7\
\x00z\
\x00o\x00o\x00m\x00_\x00i\x00n\x00.\x00s\x00v\x00g\
+\x00\x09\
+\x0a\x86\xb3G\
+\x00n\
+\x00e\x00w\x002\x00c\x00.\x00s\x00v\x00g\
\x00\x06\
\x05xZ\xc7\
\x00S\
@@ -30871,327 +31077,329 @@
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00.\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01\x8b\xd7}+v\
-\x00\x00\x00T\x00\x02\x00\x00\x00\xa0\x00\x00\x00\x05\
+\x00\x00\x00T\x00\x02\x00\x00\x00\xa1\x00\x00\x00\x05\
\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x0d\xb6\x00\x00\x00\x00\x00\x01\x00\x05\x22#\
+\x00\x00\x0d\xd0\x00\x00\x00\x00\x00\x01\x00\x05.\xa7\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0bV\x00\x00\x00\x00\x00\x01\x00\x04$\x1a\
+\x00\x00\x0bp\x00\x00\x00\x00\x00\x01\x00\x040\x9e\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x13\xb4\x00\x00\x00\x00\x00\x01\x00\x07\x10\xcf\
+\x00\x00\x13\xce\x00\x00\x00\x00\x00\x01\x00\x07\x1dS\
\x00\x00\x01\x88\xae\xf9[-\
\x00\x00\x01T\x00\x00\x00\x00\x00\x01\x00\x00\x95\xa7\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0a(\x00\x00\x00\x00\x00\x01\x00\x03\xc1\xb4\
+\x00\x00\x0aB\x00\x00\x00\x00\x00\x01\x00\x03\xce8\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x11\xe6\x00\x00\x00\x00\x00\x01\x00\x06w\xe5\
+\x00\x00\x12\x00\x00\x00\x00\x00\x00\x01\x00\x06\x84i\
\x00\x00\x01\x90N\xda\x14\x95\
-\x00\x00\x13\xee\x00\x00\x00\x00\x00\x01\x00\x07$\xd5\
+\x00\x00\x14\x08\x00\x00\x00\x00\x00\x01\x00\x071Y\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x07\x88\x00\x00\x00\x00\x00\x01\x00\x02\xd5I\
+\x00\x00\x07\xa2\x00\x00\x00\x00\x00\x01\x00\x02\xe1\xcd\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x05~\x00\x00\x00\x00\x00\x01\x00\x02-H\
+\x00\x00\x05\x98\x00\x00\x00\x00\x00\x01\x00\x029\xcc\
\x00\x00\x01\x88\xae\xf9[)\
\x00\x00\x01$\x00\x00\x00\x00\x00\x01\x00\x00~d\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x02\x86\x00\x00\x00\x00\x00\x01\x00\x01\x0a\xa7\
+\x00\x00\x02\xa0\x00\x00\x00\x00\x00\x01\x00\x01\x17+\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0f2\x00\x00\x00\x00\x00\x01\x00\x05\xa8\xd7\
+\x00\x00\x0fL\x00\x00\x00\x00\x00\x01\x00\x05\xb5[\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x13$\x00\x00\x00\x00\x00\x01\x00\x06\xe3\x1f\
+\x00\x00\x13>\x00\x00\x00\x00\x00\x01\x00\x06\xef\xa3\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x0d.\x00\x00\x00\x00\x00\x01\x00\x05\x00!\
+\x00\x00\x0dH\x00\x00\x00\x00\x00\x01\x00\x05\x0c\xa5\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0cx\x00\x00\x00\x00\x00\x01\x00\x04\x9ah\
+\x00\x00\x0c\x92\x00\x00\x00\x00\x00\x01\x00\x04\xa6\xec\
\x00\x00\x01\x8d\x0d\x8c\x812\
-\x00\x00\x05(\x00\x00\x00\x00\x00\x01\x00\x02\x16\x90\
+\x00\x00\x05B\x00\x00\x00\x00\x00\x01\x00\x02#\x14\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0fT\x00\x00\x00\x00\x00\x01\x00\x05\xb2l\
+\x00\x00\x0fn\x00\x00\x00\x00\x00\x01\x00\x05\xbe\xf0\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0f\x88\x00\x01\x00\x00\x00\x01\x00\x05\xc8\x00\
+\x00\x00\x0f\xa2\x00\x01\x00\x00\x00\x01\x00\x05\xd4\x84\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x12h\x00\x00\x00\x00\x00\x01\x00\x06\xa9\x8a\
+\x00\x00\x12\x82\x00\x00\x00\x00\x00\x01\x00\x06\xb6\x0e\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x05\x12\x00\x00\x00\x00\x00\x01\x00\x02\x06\xec\
+\x00\x00\x05,\x00\x00\x00\x00\x00\x01\x00\x02\x13p\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x09F\x00\x01\x00\x00\x00\x01\x00\x03b\xa4\
+\x00\x00\x09`\x00\x01\x00\x00\x00\x01\x00\x03o(\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x07<\x00\x01\x00\x00\x00\x01\x00\x02\xc0\xe3\
+\x00\x00\x07V\x00\x01\x00\x00\x00\x01\x00\x02\xcdg\
\x00\x00\x01\x8f\x04\xde\x0ap\
-\x00\x00\x04\xce\x00\x00\x00\x00\x00\x01\x00\x01\xe7c\
+\x00\x00\x04\xe8\x00\x00\x00\x00\x00\x01\x00\x01\xf3\xe7\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x01\x00\x03\xffR\
+\x00\x00\x0b\x1a\x00\x00\x00\x00\x00\x01\x00\x04\x0b\xd6\
\x00\x00\x01\x88\xae\xf9[)\
\x00\x00\x00\xae\x00\x00\x00\x00\x00\x01\x00\x00'2\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x04\xf0\x00\x00\x00\x00\x00\x01\x00\x01\xf7\xb0\
+\x00\x00\x05\x0a\x00\x00\x00\x00\x00\x01\x00\x02\x044\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x0e\xfe\x00\x00\x00\x00\x00\x01\x00\x05\x86\xe9\
+\x00\x00\x0f\x18\x00\x00\x00\x00\x00\x01\x00\x05\x93m\
\x00\x00\x01\x8f\x04\xde\x0ap\
-\x00\x00\x07T\x00\x01\x00\x00\x00\x01\x00\x02\xc5\x9c\
+\x00\x00\x07n\x00\x01\x00\x00\x00\x01\x00\x02\xd2 \
\x00\x00\x01\x88\xae\xf9[%\
\x00\x00\x00d\x00\x00\x00\x00\x00\x01\x00\x00\x11y\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x0bv\x00\x01\x00\x00\x00\x01\x00\x041\x0b\
+\x00\x00\x0b\x90\x00\x01\x00\x00\x00\x01\x00\x04=\x8f\
\x00\x00\x01\x88\xae\xf9[)\
\x00\x00\x00\xf8\x00\x00\x00\x00\x00\x01\x00\x00d4\
\x00\x00\x01\x88\xae\xf9[-\
\x00\x00\x01|\x00\x00\x00\x00\x00\x01\x00\x00\xa3\xc2\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x10\xee\x00\x00\x00\x00\x00\x01\x00\x064\xa7\
+\x00\x00\x11\x08\x00\x00\x00\x00\x00\x01\x00\x06A+\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x10\xb2\x00\x01\x00\x00\x00\x01\x00\x06 \xd9\
+\x00\x00\x10\xcc\x00\x01\x00\x00\x00\x01\x00\x06-]\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0aL\x00\x01\x00\x00\x00\x01\x00\x03\xca\xe4\
+\x00\x00\x0af\x00\x01\x00\x00\x00\x01\x00\x03\xd7h\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x09\xe4\x00\x00\x00\x00\x00\x01\x00\x03\xa6\xd0\
+\x00\x00\x09\xe6\x00\x00\x00\x00\x00\x01\x00\x03\xaa\xde\
\x00\x00\x01\x8b\xd7}+~\
-\x00\x00\x0dn\x00\x01\x00\x00\x00\x01\x00\x05\x15\xee\
+\x00\x00\x0d\x88\x00\x01\x00\x00\x00\x01\x00\x05\x22r\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x04\x18\x00\x01\x00\x00\x00\x01\x00\x01\xa1\xcc\
+\x00\x00\x042\x00\x01\x00\x00\x00\x01\x00\x01\xaeP\
\x00\x00\x01\x8b\xd7}+~\
-\x00\x00\x09Z\x00\x00\x00\x00\x00\x01\x00\x03w,\
+\x00\x00\x09t\x00\x00\x00\x00\x00\x01\x00\x03\x83\xb0\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x08x\x00\x00\x00\x00\x00\x01\x00\x03 \xda\
+\x00\x00\x08\x92\x00\x00\x00\x00\x00\x01\x00\x03-^\
\x00\x00\x01\x8f\x04\xde\x0ap\
-\x00\x00\x0d\xdc\x00\x00\x00\x00\x00\x01\x00\x05)\xbc\
+\x00\x00\x0d\xf6\x00\x00\x00\x00\x00\x01\x00\x056@\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0a\x00\x00\x01\x00\x00\x00\x01\x00\x03\xb4\x22\
+\x00\x00\x0a\x1a\x00\x01\x00\x00\x00\x01\x00\x03\xc0\xa6\
\x00\x00\x01\x88\xae\xf9[%\
-\x00\x00\x02\xee\x00\x01\x00\x00\x00\x01\x00\x01-S\
+\x00\x00\x03\x08\x00\x01\x00\x00\x00\x01\x00\x019\xd7\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x07\xd0\x00\x00\x00\x00\x00\x01\x00\x02\xf5\xc8\
+\x00\x00\x07\xea\x00\x00\x00\x00\x00\x01\x00\x03\x02L\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x08\xf8\x00\x00\x00\x00\x00\x01\x00\x03H\x0b\
+\x00\x00\x09\x12\x00\x00\x00\x00\x00\x01\x00\x03T\x8f\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x06\xac\x00\x01\x00\x00\x00\x01\x00\x02\x97\xf3\
+\x00\x00\x06\xc6\x00\x01\x00\x00\x00\x01\x00\x02\xa4w\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0ex\x00\x01\x00\x00\x00\x01\x00\x05b\x8e\
+\x00\x00\x0e\x92\x00\x01\x00\x00\x00\x01\x00\x05o\x12\
\x00\x00\x01\x88\xae\xf9[%\
\x00\x00\x00\xd8\x00\x00\x00\x00\x00\x01\x00\x00B:\
\x00\x00\x01\x90N\xda\x14\x95\
-\x00\x00\x0eF\x00\x01\x00\x00\x00\x01\x00\x05M\xb6\
+\x00\x00\x0e`\x00\x01\x00\x00\x00\x01\x00\x05Z:\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x02\xd2\x00\x00\x00\x00\x00\x01\x00\x01\x1c\xf5\
+\x00\x00\x02\xec\x00\x00\x00\x00\x00\x01\x00\x01)y\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x12\x22\x00\x01\x00\x00\x00\x01\x00\x06\x8fb\
+\x00\x00\x12<\x00\x01\x00\x00\x00\x01\x00\x06\x9b\xe6\
\x00\x00\x01\x8b\xd7}+~\
-\x00\x00\x03\xea\x00\x01\x00\x00\x00\x01\x00\x01\x8e\xf7\
+\x00\x00\x04\x04\x00\x01\x00\x00\x00\x01\x00\x01\x9b{\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x03\xbe\x00\x01\x00\x00\x00\x01\x00\x01z\xa0\
+\x00\x00\x03\xd8\x00\x01\x00\x00\x00\x01\x00\x01\x87$\
\x00\x00\x01\x8f\x04\xde\x0ap\
-\x00\x00\x0b\x98\x00\x00\x00\x00\x00\x01\x00\x048\xad\
+\x00\x00\x0b\xb2\x00\x00\x00\x00\x00\x01\x00\x04E1\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x03R\x00\x00\x00\x00\x00\x01\x00\x01Z\xb2\
+\x00\x00\x03l\x00\x00\x00\x00\x00\x01\x00\x01g6\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x13n\x00\x00\x00\x00\x00\x01\x00\x06\xf9\xd7\
+\x00\x00\x13\x88\x00\x00\x00\x00\x00\x01\x00\x07\x06[\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x12\x88\x00\x00\x00\x00\x00\x01\x00\x06\xb3\xd0\
+\x00\x00\x12\xa2\x00\x00\x00\x00\x00\x01\x00\x06\xc0T\
\x00\x00\x01\x90N\xda\x14\x95\
-\x00\x00\x13\x0a\x00\x00\x00\x00\x00\x01\x00\x06\xdb\xad\
+\x00\x00\x13$\x00\x00\x00\x00\x00\x01\x00\x06\xe81\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x03\x06\x00\x00\x00\x00\x00\x01\x00\x011\xb4\
+\x00\x00\x03 \x00\x00\x00\x00\x00\x01\x00\x01>8\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x02\xa8\x00\x01\x00\x00\x00\x01\x00\x01\x15\xc8\
+\x00\x00\x02\xc2\x00\x01\x00\x00\x00\x01\x00\x01\x22L\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0f\xd0\x00\x01\x00\x00\x00\x01\x00\x05\xd4\x91\
+\x00\x00\x0f\xea\x00\x01\x00\x00\x00\x01\x00\x05\xe1\x15\
\x00\x00\x01\x88\xae\xf9[-\
\x00\x00\x01\x90\x00\x00\x00\x00\x00\x01\x00\x00\xadk\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0c\xbc\x00\x00\x00\x00\x00\x01\x00\x04\xd1`\
+\x00\x00\x0c\xd6\x00\x00\x00\x00\x00\x01\x00\x04\xdd\xe4\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x12>\x00\x00\x00\x00\x00\x01\x00\x06\x9c\xd5\
+\x00\x00\x12X\x00\x00\x00\x00\x00\x01\x00\x06\xa9Y\
\x00\x00\x01\x90N\xda\x14\x95\
\x00\x00\x00\x98\x00\x00\x00\x00\x00\x01\x00\x00\x1f\xb1\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x12\xa2\x00\x00\x00\x00\x00\x01\x00\x06\xbc|\
+\x00\x00\x12\xbc\x00\x00\x00\x00\x00\x01\x00\x06\xc9\x00\
\x00\x00\x01\x8b\xd7}+~\
-\x00\x00\x09\x10\x00\x00\x00\x00\x00\x01\x00\x03O\x9d\
+\x00\x00\x09*\x00\x00\x00\x00\x00\x01\x00\x03\x5c!\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x04h\x00\x00\x00\x00\x00\x01\x00\x01\xb6H\
+\x00\x00\x04\x82\x00\x00\x00\x00\x00\x01\x00\x01\xc2\xcc\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x10\x10\x00\x00\x00\x00\x00\x01\x00\x05\xed\xf0\
+\x00\x00\x10*\x00\x00\x00\x00\x00\x01\x00\x05\xfat\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x01\xe2\x00\x01\x00\x00\x00\x01\x00\x00\xd3*\
+\x00\x00\x01\xfc\x00\x01\x00\x00\x00\x01\x00\x00\xdf\xae\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x06\x9a\x00\x00\x00\x00\x00\x01\x00\x02\x88\xce\
+\x00\x00\x06\xb4\x00\x00\x00\x00\x00\x01\x00\x02\x95R\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x10\xd0\x00\x00\x00\x00\x00\x01\x00\x06)\xd9\
+\x00\x00\x10\xea\x00\x00\x00\x00\x00\x01\x00\x066]\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x04\x06\x00\x01\x00\x00\x00\x01\x00\x01\x9b\xcf\
+\x00\x00\x04 \x00\x01\x00\x00\x00\x01\x00\x01\xa8S\
\x00\x00\x01\x8f\x04\xde\x0ap\
-\x00\x00\x11\x92\x00\x01\x00\x00\x00\x01\x00\x06]\xd2\
+\x00\x00\x11\xac\x00\x01\x00\x00\x00\x01\x00\x06jV\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x07\xa2\x00\x00\x00\x00\x00\x01\x00\x02\xdfP\
+\x00\x00\x07\xbc\x00\x00\x00\x00\x00\x01\x00\x02\xeb\xd4\
\x00\x00\x01\x8e.\xfc\xa1\x83\
-\x00\x00\x0ft\x00\x00\x00\x00\x00\x01\x00\x05\xbd\x83\
+\x00\x00\x0f\x8e\x00\x00\x00\x00\x00\x01\x00\x05\xca\x07\
\x00\x00\x01\x88\xae\xf9[%\
-\x00\x00\x02\x1a\x00\x00\x00\x00\x00\x01\x00\x00\xdf\x03\
+\x00\x00\x024\x00\x00\x00\x00\x00\x01\x00\x00\xeb\x87\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0a\xc6\x00\x00\x00\x00\x00\x01\x00\x03\xf3\x1d\
+\x00\x00\x0a\xe0\x00\x00\x00\x00\x00\x01\x00\x03\xff\xa1\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x05\xa0\x00\x00\x00\x00\x00\x01\x00\x02<\xed\
+\x00\x00\x05\xba\x00\x00\x00\x00\x00\x01\x00\x02Iq\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x03\x18\x00\x00\x00\x00\x00\x01\x00\x019\xa4\
+\x00\x00\x032\x00\x00\x00\x00\x00\x01\x00\x01F(\
\x00\x00\x01\x88\xae\xf9[%\
-\x00\x00\x07\x00\x00\x00\x00\x00\x00\x01\x00\x02\xa7\x98\
+\x00\x00\x07\x1a\x00\x00\x00\x00\x00\x01\x00\x02\xb4\x1c\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0e\x98\x00\x00\x00\x00\x00\x01\x00\x05i\xab\
+\x00\x00\x0e\xb2\x00\x00\x00\x00\x00\x01\x00\x05v/\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x12\xc0\x00\x00\x00\x00\x00\x01\x00\x06\xc7\xa8\
+\x00\x00\x12\xda\x00\x00\x00\x00\x00\x01\x00\x06\xd4,\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0c\xe6\x00\x00\x00\x00\x00\x01\x00\x04\xef%\
+\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x01\x00\x04\xfb\xa9\
\x00\x00\x01\x8f\x04\xde\x0ap\
-\x00\x00\x08@\x00\x00\x00\x00\x00\x01\x00\x03\x0c\x8a\
+\x00\x00\x08Z\x00\x00\x00\x00\x00\x01\x00\x03\x19\x0e\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x060\x00\x00\x00\x00\x00\x01\x00\x02q)\
+\x00\x00\x06J\x00\x00\x00\x00\x00\x01\x00\x02}\xad\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x11\xce\x00\x01\x00\x00\x00\x01\x00\x06s\x90\
+\x00\x00\x11\xe8\x00\x01\x00\x00\x00\x01\x00\x06\x80\x14\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x13\xd8\x00\x00\x00\x00\x00\x01\x00\x07\x1ct\
+\x00\x00\x13\xf2\x00\x00\x00\x00\x00\x01\x00\x07(\xf8\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x08\xe2\x00\x00\x00\x00\x00\x01\x00\x03A\xca\
+\x00\x00\x08\xfc\x00\x00\x00\x00\x00\x01\x00\x03NN\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x03>\x00\x00\x00\x00\x00\x01\x00\x01D\xb7\
+\x00\x00\x03X\x00\x00\x00\x00\x00\x01\x00\x01Q;\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x08\x9e\x00\x00\x00\x00\x00\x01\x00\x03,\xbd\
+\x00\x00\x08\xb8\x00\x00\x00\x00\x00\x01\x00\x039A\
\x00\x00\x01\x8e.\xfc\xa1\x87\
-\x00\x00\x0b$\x00\x00\x00\x00\x00\x01\x00\x04\x11\xdc\
+\x00\x00\x0b>\x00\x00\x00\x00\x00\x01\x00\x04\x1e`\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0a\x12\x00\x00\x00\x00\x00\x01\x00\x03\xba\x14\
+\x00\x00\x0a,\x00\x00\x00\x00\x00\x01\x00\x03\xc6\x98\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x10^\x00\x00\x00\x00\x00\x01\x00\x06\x02\xb6\
+\x00\x00\x10x\x00\x00\x00\x00\x00\x01\x00\x06\x0f:\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0c\x98\x00\x00\x00\x00\x00\x01\x00\x04\xa8\xfb\
+\x00\x00\x0c\xb2\x00\x00\x00\x00\x00\x01\x00\x04\xb5\x7f\
\x00\x00\x01\x8b\xd7}+~\
-\x00\x00\x0a\xde\x00\x01\x00\x00\x00\x01\x00\x03\xfa\x9c\
+\x00\x00\x0a\xf8\x00\x01\x00\x00\x00\x01\x00\x04\x07 \
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x11\xb2\x00\x00\x00\x00\x00\x01\x00\x06h\x87\
+\x00\x00\x11\xcc\x00\x00\x00\x00\x00\x01\x00\x06u\x0b\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x07\xfa\x00\x00\x00\x00\x00\x01\x00\x02\xfev\
+\x00\x00\x08\x14\x00\x00\x00\x00\x00\x01\x00\x03\x0a\xfa\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x14\x04\x00\x01\x00\x00\x00\x01\x00\x07>\xf6\
+\x00\x00\x14\x1e\x00\x01\x00\x00\x00\x01\x00\x07Kz\
\x00\x00\x01\x90N\xda\x14\x95\
-\x00\x00\x03\xa0\x00\x00\x00\x00\x00\x01\x00\x01o\x88\
+\x00\x00\x03\xba\x00\x00\x00\x00\x00\x01\x00\x01|\x0c\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x13P\x00\x00\x00\x00\x00\x01\x00\x06\xf0\xf4\
+\x00\x00\x13j\x00\x00\x00\x00\x00\x01\x00\x06\xfdx\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x04|\x00\x01\x00\x00\x00\x01\x00\x01\xc2T\
+\x00\x00\x04\x96\x00\x01\x00\x00\x00\x01\x00\x01\xce\xd8\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0c\xd2\x00\x00\x00\x00\x00\x01\x00\x04\xe1\x82\
+\x00\x00\x0c\xec\x00\x00\x00\x00\x00\x01\x00\x04\xee\x06\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x09\xa4\x00\x01\x00\x00\x00\x01\x00\x03\x91\xf7\
+\x00\x00\x09\xbe\x00\x01\x00\x00\x00\x01\x00\x03\x9e{\
\x00\x00\x01\x88\xae\xf9[-\
\x00\x00\x00\xc4\x00\x00\x00\x00\x00\x01\x00\x000\x1c\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x11r\x00\x01\x00\x00\x00\x01\x00\x06W\x08\
+\x00\x00\x11\x8c\x00\x01\x00\x00\x00\x01\x00\x06c\x8c\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x05`\x00\x00\x00\x00\x00\x01\x00\x02\x22\x82\
+\x00\x00\x05z\x00\x00\x00\x00\x00\x01\x00\x02/\x06\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0a\x9c\x00\x00\x00\x00\x00\x01\x00\x03\xe5\xaa\
+\x00\x00\x0a\xb6\x00\x00\x00\x00\x00\x01\x00\x03\xf2.\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x10\x96\x00\x00\x00\x00\x00\x01\x00\x06\x12\xc4\
+\x00\x00\x10\xb0\x00\x00\x00\x00\x00\x01\x00\x06\x1fH\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x12\x06\x00\x00\x00\x00\x00\x01\x00\x06\x86N\
+\x00\x00\x12 \x00\x00\x00\x00\x00\x01\x00\x06\x92\xd2\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x05\xf8\x00\x00\x00\x00\x00\x01\x00\x02U\xa8\
+\x00\x00\x06\x12\x00\x00\x00\x00\x00\x01\x00\x02b,\
\x00\x00\x01\x8d\x0d\x8c\x812\
-\x00\x00\x09\xcc\x00\x00\x00\x00\x00\x01\x00\x03\x9eZ\
+\x00\x00\x0a\x02\x00\x00\x00\x00\x00\x01\x00\x03\xb80\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x05\xde\x00\x00\x00\x00\x00\x01\x00\x02K\x12\
+\x00\x00\x05\xf8\x00\x00\x00\x00\x00\x01\x00\x02W\x96\
\x00\x00\x01\x90N\xda\x14\x95\
-\x00\x00\x06\xd8\x00\x01\x00\x00\x00\x01\x00\x02\x9e!\
+\x00\x00\x06\xf2\x00\x01\x00\x00\x00\x01\x00\x02\xaa\xa5\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0cJ\x00\x01\x00\x00\x00\x01\x00\x04\x93\xe4\
+\x00\x00\x0cd\x00\x01\x00\x00\x00\x01\x00\x04\xa0h\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x08(\x00\x00\x00\x00\x00\x01\x00\x03\x05\xb7\
+\x00\x00\x08B\x00\x00\x00\x00\x00\x01\x00\x03\x12;\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x07r\x00\x00\x00\x00\x00\x01\x00\x02\xcan\
+\x00\x00\x07\x8c\x00\x00\x00\x00\x00\x01\x00\x02\xd6\xf2\
\x00\x00\x01\x8b\xd7}+~\
-\x00\x00\x04\xa0\x00\x00\x00\x00\x00\x01\x00\x01\xc7\xbe\
+\x00\x00\x04\xba\x00\x00\x00\x00\x00\x01\x00\x01\xd4B\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0e*\x00\x00\x00\x00\x00\x01\x00\x05F\xca\
+\x00\x00\x0eD\x00\x00\x00\x00\x00\x01\x00\x05SN\
\x00\x00\x01\x8f\x04\xde\x0ap\
-\x00\x00\x0c\xfe\x00\x00\x00\x00\x00\x01\x00\x04\xf6L\
+\x00\x00\x0d\x18\x00\x00\x00\x00\x00\x01\x00\x05\x02\xd0\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x01\xcc\x00\x00\x00\x00\x00\x01\x00\x00\xcb\x07\
+\x00\x00\x01\xe6\x00\x00\x00\x00\x00\x01\x00\x00\xd7\x8b\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x01\xaa\x00\x01\x00\x00\x00\x01\x00\x00\xc6\x1d\
+\x00\x00\x01\xc4\x00\x01\x00\x00\x00\x01\x00\x00\xd2\xa1\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x100\x00\x01\x00\x00\x00\x01\x00\x05\xfb\x9e\
+\x00\x00\x10J\x00\x01\x00\x00\x00\x01\x00\x06\x08\x22\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0f\xe8\x00\x00\x00\x00\x00\x01\x00\x05\xdbK\
+\x00\x00\x10\x02\x00\x00\x00\x00\x00\x01\x00\x05\xe7\xcf\
\x00\x00\x01\x88\xae\xf9[)\
\x00\x00\x01\x0e\x00\x00\x00\x00\x00\x01\x00\x00q\x06\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x028\x00\x01\x00\x00\x00\x01\x00\x00\xea\xc3\
+\x00\x00\x02R\x00\x01\x00\x00\x00\x01\x00\x00\xf7G\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x04\xb6\x00\x00\x00\x00\x00\x01\x00\x01\xe0D\
+\x00\x00\x04\xd0\x00\x00\x00\x00\x00\x01\x00\x01\xec\xc8\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0e\xe8\x00\x00\x00\x00\x00\x01\x00\x05}r\
+\x00\x00\x0f\x02\x00\x00\x00\x00\x00\x01\x00\x05\x89\xf6\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x10t\x00\x01\x00\x00\x00\x01\x00\x06\x09\xf2\
+\x00\x00\x10\x8e\x00\x01\x00\x00\x00\x01\x00\x06\x16v\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x03h\x00\x01\x00\x00\x00\x01\x00\x01c\x9e\
+\x00\x00\x03\x82\x00\x01\x00\x00\x00\x01\x00\x01p\x22\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0f\xb2\x00\x01\x00\x00\x00\x01\x00\x05\xce\xd6\
+\x00\x00\x0f\xcc\x00\x01\x00\x00\x00\x01\x00\x05\xdbZ\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x07(\x00\x00\x00\x00\x00\x01\x00\x02\xb1\x9f\
+\x00\x00\x07B\x00\x00\x00\x00\x00\x01\x00\x02\xbe#\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0d\xf2\x00\x00\x00\x00\x00\x01\x00\x051?\
+\x00\x00\x0e\x0c\x00\x00\x00\x00\x00\x01\x00\x05=\xc3\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0e\x0e\x00\x00\x00\x00\x00\x01\x00\x05\
+\x00\x00\x11F\x00\x00\x00\x00\x00\x01\x00\x06R\xc2\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0b<\x00\x00\x00\x00\x00\x01\x00\x04\x1b\x0d\
+\x00\x00\x0bV\x00\x00\x00\x00\x00\x01\x00\x04'\x91\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0d\x9e\x00\x00\x00\x00\x00\x01\x00\x05\x1aB\
+\x00\x00\x0d\xb8\x00\x00\x00\x00\x00\x01\x00\x05&\xc6\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x02l\x00\x00\x00\x00\x00\x01\x00\x01\x00R\
+\x00\x00\x02\x86\x00\x00\x00\x00\x00\x01\x00\x01\x0c\xd6\
\x00\x00\x01\x90N\xda\x14\x95\
-\x00\x00\x05\xb2\x00\x01\x00\x00\x00\x01\x00\x02D\x22\
+\x00\x00\x05\xcc\x00\x01\x00\x00\x00\x01\x00\x02P\xa6\
\x00\x00\x01\x8e.\xfc\xa1\x83\
-\x00\x00\x11\x16\x00\x00\x00\x00\x00\x01\x00\x06>\xf3\
+\x00\x00\x110\x00\x00\x00\x00\x00\x01\x00\x06Kw\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x04D\x00\x00\x00\x00\x00\x01\x00\x01\xa9J\
+\x00\x00\x04^\x00\x00\x00\x00\x00\x01\x00\x01\xb5\xce\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x11B\x00\x01\x00\x00\x00\x01\x00\x06N\xb8\
+\x00\x00\x11\x5c\x00\x01\x00\x00\x00\x01\x00\x06[<\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x09v\x00\x00\x00\x00\x00\x01\x00\x03\x80\x9e\
-\x00\x00\x01\x91\x0c\xf5\xa9z\
-\x00\x00\x0b\xdc\x00\x00\x00\x00\x00\x01\x00\x04V\x85\
+\x00\x00\x09\x90\x00\x00\x00\x00\x00\x01\x00\x03\x8d\x22\
+\x00\x00\x01\x916\x08\x04)\
+\x00\x00\x0b\xf6\x00\x00\x00\x00\x00\x01\x00\x04c\x09\
\x00\x00\x01\x8b\xd7}+~\
-\x00\x00\x0a|\x00\x01\x00\x00\x00\x01\x00\x03\xcf\xf6\
+\x00\x00\x0a\x96\x00\x01\x00\x00\x00\x01\x00\x03\xdcz\
\x00\x00\x01\x8b\xd7}+z\
-\x00\x00\x08\x5c\x00\x00\x00\x00\x00\x01\x00\x03\x141\
+\x00\x00\x08v\x00\x00\x00\x00\x00\x01\x00\x03 \xb5\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x03\xd6\x00\x00\x00\x00\x00\x01\x00\x01\x80\x94\
+\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x01\x8d\x18\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x03\x86\x00\x01\x00\x00\x00\x01\x00\x01j^\
+\x00\x00\x03\xa0\x00\x01\x00\x00\x00\x01\x00\x01v\xe2\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0b\xfe\x00\x00\x00\x00\x00\x01\x00\x04r\x84\
+\x00\x00\x0c\x18\x00\x00\x00\x00\x00\x01\x00\x04\x7f\x08\
\x00\x00\x01\x88\xae\xf9[%\
-\x00\x00\x0dV\x00\x00\x00\x00\x00\x01\x00\x05\x08\xb2\
+\x00\x00\x01\xaa\x00\x00\x00\x00\x00\x01\x00\x00\xc6\x1d\
+\x00\x00\x01\x91\x97\xfc\xe9\xb2\
+\x00\x00\x0dp\x00\x00\x00\x00\x00\x01\x00\x05\x156\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x0b\xb8\x00\x00\x00\x00\x00\x01\x00\x04IF\
+\x00\x00\x0b\xd2\x00\x00\x00\x00\x00\x01\x00\x04U\xca\
\x00\x00\x01\x8b\xd7}+~\
-\x00\x00\x0e\xb8\x00\x01\x00\x00\x00\x01\x00\x05q\xb2\
+\x00\x00\x0e\xd2\x00\x01\x00\x00\x00\x01\x00\x05~6\
\x00\x00\x01\x88\xae\xf9[)\
\x00\x00\x01>\x00\x00\x00\x00\x00\x01\x00\x00\x8a\x97\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x13\x8a\x00\x01\x00\x00\x00\x01\x00\x07\x07m\
+\x00\x00\x13\xa4\x00\x01\x00\x00\x00\x01\x00\x07\x13\xf1\
\x00\x00\x01\x8e.\xfc\xa1\x83\
-\x00\x00\x06\x0c\x00\x00\x00\x00\x00\x01\x00\x02gq\
+\x00\x00\x06&\x00\x00\x00\x00\x00\x01\x00\x02s\xf5\
\x00\x00\x01\x88\xae\xf9[-\
-\x00\x00\x08\xc2\x00\x00\x00\x00\x00\x01\x00\x036\xaa\
+\x00\x00\x08\xdc\x00\x00\x00\x00\x00\x01\x00\x03C.\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x0c\x1e\x00\x00\x00\x00\x00\x01\x00\x04{\xc8\
+\x00\x00\x0c8\x00\x00\x00\x00\x00\x01\x00\x04\x88L\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x09,\x00\x00\x00\x00\x00\x01\x00\x03X\x83\
+\x00\x00\x09F\x00\x00\x00\x00\x00\x01\x00\x03e\x07\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x06l\x00\x00\x00\x00\x00\x01\x00\x02\x7f\x01\
+\x00\x00\x06\x86\x00\x00\x00\x00\x00\x01\x00\x02\x8b\x85\
\x00\x00\x01\x88\xae\xf9[)\
-\x00\x00\x12\xe4\x00\x00\x00\x00\x00\x01\x00\x06\xcen\
+\x00\x00\x12\xfe\x00\x00\x00\x00\x00\x01\x00\x06\xda\xf2\
\x00\x00\x01\x8e.\xfc\xa1\x83\
"
diff --git a/src/GridCal/Gui/plugins.py b/src/GridCal/Gui/plugins.py
new file mode 100644
index 000000000..847705ddc
--- /dev/null
+++ b/src/GridCal/Gui/plugins.py
@@ -0,0 +1,221 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from __future__ import annotations
+
+import os
+import importlib
+import importlib.util
+import hashlib
+from typing import List, Dict
+import json
+from PySide6.QtGui import QPixmap
+
+from GridCalEngine.IO.file_system import get_create_gridcal_folder
+
+
+def plugins_path() -> str:
+ """
+ get the config file path
+ :return: config file path
+ """
+ pth = os.path.join(get_create_gridcal_folder(), 'plugins')
+
+ if not os.path.exists(pth):
+ os.makedirs(pth)
+
+ return pth
+
+
+class PluginInfo:
+ """
+ Plugin information
+ """
+
+ def __init__(self) -> None:
+ """
+
+ """
+ self.name = ""
+ self.path = ""
+ self.icon_path = ""
+ self.function_name = ""
+
+ self.function_ptr = None
+ self.icon: QPixmap | None = None
+
+ def to_dict(self) -> Dict[str, str]:
+ """
+ To dict
+ :return: string, strig dictionary to save in json format
+ """
+ return {
+ 'name': self.name,
+ 'path': self.path,
+ 'icon_path': self.icon_path,
+ 'function_name': self.function_name,
+ }
+
+ def parse(self, data: Dict[str, str]) -> None:
+ """
+ Parse data
+ :param data: Data like the one saved
+ """
+ self.name = data.get('name', '')
+ self.path = data.get('path', '')
+ self.icon_path = data.get('icon_path', '')
+ self.function_name = data.get('function_name', '')
+
+ def read_plugin(self) -> None:
+ """
+ Read the pointed plugin
+ """
+ base_path = plugins_path()
+ plugin_path = os.path.join(base_path, self.path)
+
+ if os.path.exists(plugin_path):
+
+ if plugin_path.endswith('.py'):
+
+ # hot read python file
+ try:
+ self.function_ptr = load_function_from_file_path(file_path=plugin_path,
+ function_name=self.function_name)
+
+ except ImportError as e:
+ print(e)
+ except AttributeError as e:
+ print(e)
+ except TypeError as e:
+ print(e)
+
+ else:
+ print(f"Plugin {self.name}: Path {plugin_path} not a python file :(")
+ else:
+ print(f"Plugin {self.name}: Path {plugin_path} not found :/")
+
+ icon_path = os.path.join(base_path, self.icon_path)
+ if os.path.exists(icon_path):
+ self.icon = QPixmap(icon_path)
+ else:
+ print(f"Plugin {self.name}: Path {icon_path} not found :/")
+
+
+class PluginsInfo:
+ """
+ Plugins information
+ """
+
+ def __init__(self) -> None:
+ """
+
+ """
+ self.index_fname = os.path.join(plugins_path(), 'plugins.json')
+
+ self.plugins: List[PluginInfo] = list()
+
+ if os.path.exists(self.index_fname):
+ self.read()
+ else:
+ self.save()
+
+ def to_data(self) -> List[Dict[str, str]]:
+ """
+ Get dictionary of plugin data
+ :return:
+ """
+ return [pl.to_dict() for pl in self.plugins]
+
+ def parse(self, data: List[Dict[str, str]]):
+ """
+ Parse data: Create the plugins information
+ :param data:
+ :return:
+ """
+ self.plugins.clear()
+ for entry in data:
+ pl = PluginInfo()
+ pl.parse(entry)
+ pl.read_plugin()
+ self.plugins.append(pl)
+
+ def read(self) -> None:
+ """
+ Thead the plugins info file
+ :return:
+ """
+ # Open the JSON file
+ with open(self.index_fname, 'r') as file:
+ # Load the JSON data into a dictionary
+ data = json.load(file)
+ self.parse(data)
+
+ def save(self):
+ """
+ Save the plugins information
+ :return:
+ """
+ # Write the dictionary to a JSON file
+ with open(self.index_fname, 'w') as json_file:
+ data = self.to_data()
+ json.dump(data, json_file)
+
+
+def load_function_from_file_path(file_path: str, function_name: str):
+ """
+ Dynamically load a function from a Python file at a given file path.
+
+ :param file_path: The path to the Python (.py) file.
+ :param function_name: The name of the function to load from the file.
+ :return: The loaded function object.
+ :raises FileNotFoundError: If the specified file does not exist.
+ :raises ImportError: If the module cannot be imported.
+ :raises AttributeError: If the function does not exist in the module.
+ :raises TypeError: If the retrieved attribute is not callable.
+ """
+ # Ensure the file exists
+ if not os.path.isfile(file_path):
+ raise FileNotFoundError(f"No such file: {file_path}")
+
+ # Generate a unique module name to avoid conflicts
+ # Here, we use the file's absolute path hashed to ensure uniqueness
+ absolute_path = os.path.abspath(file_path)
+ module_name = f"dynamic_module_{hashlib.md5(absolute_path.encode()).hexdigest()}"
+
+ # Create a module specification from the file location
+ spec = importlib.util.spec_from_file_location(module_name, absolute_path)
+ if spec is None:
+ raise ImportError(f"Cannot create a module spec for '{file_path}'")
+
+ # Create a new module based on the spec
+ module = importlib.util.module_from_spec(spec)
+
+ try:
+ # Execute the module to populate its namespace
+ spec.loader.exec_module(module)
+ except Exception as e:
+ raise ImportError(f"Failed to execute module '{file_path}': {e}") from e
+
+ # Retrieve the function from the module
+ if not hasattr(module, function_name):
+ raise AttributeError(f"The function '{function_name}' does not exist in '{file_path}'")
+
+ func = getattr(module, function_name)
+
+ if not callable(func):
+ raise TypeError(f"'{function_name}' in '{file_path}' is not callable")
+
+ return func
diff --git a/src/GridCal/Session/server_driver.py b/src/GridCal/Session/server_driver.py
index 5572d9cc6..54aefc625 100644
--- a/src/GridCal/Session/server_driver.py
+++ b/src/GridCal/Session/server_driver.py
@@ -14,32 +14,45 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
+import os
import time
import requests
import asyncio
+from urllib3 import disable_warnings, exceptions
from typing import Callable, Dict, Union, List, Any
from PySide6.QtCore import QThread, Signal
from PySide6 import QtCore
from GridCalEngine.basic_structures import Logger
+from GridCalEngine.IO.file_system import get_create_gridcal_folder
from GridCalEngine.IO.gridcal.remote import gather_model_as_jsons_for_communication, RemoteInstruction, RemoteJob
from GridCalEngine.Devices.multi_circuit import MultiCircuit
+disable_warnings(exceptions.InsecureRequestWarning)
+
-async def send_json_data(json_data: Dict[str, Union[str, Dict[str, Dict[str, str]]]], endpoint_url: str):
+async def send_json_data(json_data: Dict[str, Union[str, Dict[str, Dict[str, str]]]], endpoint_url: str, certificate: str):
"""
Send a file along with instructions about the file
:param json_data: Json with te model
:param endpoint_url: Web socket URL to connect to
+ :param certificate: SSL certificate path
:return service response
"""
- response = requests.post(endpoint_url, json=json_data, stream=True)
+ response = requests.post(endpoint_url, json=json_data, stream=True, verify=certificate)
# return server response
return response.json()
+def get_certificate_path() -> str:
+ """
+
+ :return:
+ """
+ return os.path.join(get_create_gridcal_folder(), "server_cert.pem")
+
+
class JobsModel(QtCore.QAbstractTableModel):
"""
Class to populate a Qt table view with a pandas data frame
@@ -186,6 +199,9 @@ def __init__(self, url: str, port: int, pwd: str, sleep_time: int = 2, status_fu
self.data_model = JobsModel()
+ self._loaded_certificate = False
+ self._certificate_path = os.path.join(get_create_gridcal_folder(), "server_cert.pem")
+
self.__cancel__ = False
self.__pause__ = False
@@ -220,7 +236,7 @@ def base_url(self):
Base URL of the service
:return:
"""
- return f"http://{self.url}:{self.port}"
+ return f"https://{self.url}:{self.port}"
def is_running(self) -> bool:
"""
@@ -229,17 +245,55 @@ def is_running(self) -> bool:
"""
return self.__running__
+ def get_certificate(self) -> bool:
+ """
+ Try connecting to the server
+ :return: ok?
+ """
+ # Make a GET request to the root endpoint
+ try:
+ response = requests.get(f"{self.base_url()}/get_cert",
+ headers={"API-Key": self.pwd},
+ verify=False,
+ timeout=2)
+
+ # Save the certificate to a file
+
+ with open(self._certificate_path, "wb") as cert_file:
+ cert_file.write(response.content)
+
+ # Check if the request was successful
+ if response.status_code == 200:
+ # Print the response body
+ # print("Response Body:", response.json())
+ # self.data_model.parse_data(data=response.json())
+ return True
+ else:
+ # Print error message
+ self.logger.add_error(msg=f"Response error", value=response.text)
+ return False
+ except ConnectionError as e:
+ self.logger.add_error(msg=f"Connection error", value=str(e))
+ return False
+ except Exception as e:
+ self.logger.add_error(msg=f"General exception error", value=str(e))
+ return False
+
def server_connect(self) -> bool:
"""
Try connecting to the server
:return: ok?
"""
+
+ # get the SSL certificate (only once per class instance)
+ if not self._loaded_certificate:
+ self._loaded_certificate = self.get_certificate()
+
# Make a GET request to the root endpoint
try:
response = requests.get(f"{self.base_url()}/",
- headers={
- "API-Key": self.pwd
- },
+ headers={"API-Key": self.pwd},
+ verify=self._certificate_path,
timeout=2)
# Check if the request was successful
@@ -266,9 +320,8 @@ def get_jobs(self) -> bool:
# Make a GET request to the root endpoint
try:
response = requests.get(f"{self.base_url()}/jobs_list",
- headers={
- "API-Key": self.pwd
- },
+ headers={"API-Key": self.pwd},
+ verify=self._certificate_path,
timeout=2)
# Check if the request was successful
@@ -302,7 +355,8 @@ def send_data(self, circuit: MultiCircuit, instruction: RemoteInstruction) -> No
model_data = gather_model_as_jsons_for_communication(circuit=circuit, instruction=instruction)
response = asyncio.get_event_loop().run_until_complete(send_json_data(json_data=model_data,
- endpoint_url=websocket_url))
+ endpoint_url=websocket_url,
+ certificate=self._certificate_path))
self.get_jobs()
@@ -319,7 +373,7 @@ def delete_job(self, job_id: str, api_key: str) -> dict:
"accept": "application/json",
"API-Key": api_key
}
- response = requests.delete(url, headers=headers)
+ response = requests.delete(url, headers=headers, verify=self._certificate_path)
if response.status_code == 200:
return response.json()
@@ -348,7 +402,7 @@ def download_results(self, job_id: str, api_key: str, local_filename: str):
chunk_size = 1024 * 1024 # 1 MB
sent = 0
# Stream the download to avoid loading the entire file into memory
- with requests.get(url, headers=headers, stream=True) as response:
+ with requests.get(url, headers=headers, stream=True, verify=self._certificate_path) as response:
if response.status_code == 200:
@@ -378,7 +432,7 @@ def cancel_job(self, job_id: str, api_key: str) -> dict:
"accept": "application/json",
"API-Key": api_key
}
- response = requests.post(url, headers=headers)
+ response = requests.post(url, headers=headers, verify=self._certificate_path)
if response.status_code == 200:
return response.json()
@@ -395,6 +449,7 @@ def run(self) -> None:
self.__pause__ = False
self.report_status("Trying to connect")
+ self._loaded_certificate = False # set to false, so that we force re-download
ok = self.server_connect()
if ok:
@@ -421,6 +476,10 @@ def run(self) -> None:
# check if alive
ok = self.server_connect()
+ if not ok:
+ # set to false, so that we force re-download on reconnection
+ self._loaded_certificate = False
+
else:
# bad connection
self.report_status("Could not connect")
diff --git a/src/GridCal/__version__.py b/src/GridCal/__version__.py
index 1c8a40e3d..c10267ab2 100644
--- a/src/GridCal/__version__.py
+++ b/src/GridCal/__version__.py
@@ -16,7 +16,7 @@
_current_year_ = datetime.datetime.now().year
# do not forget to keep a three-number version!!!
-__GridCal_VERSION__ = "5.1.21"
+__GridCal_VERSION__ = "5.2.0"
url = 'https://github.com/SanPen/GridCal'
diff --git a/src/GridCalEngine/Compilers/circuit_to_bentayga.py b/src/GridCalEngine/Compilers/circuit_to_bentayga.py
index 6403fffef..0a611c07c 100644
--- a/src/GridCalEngine/Compilers/circuit_to_bentayga.py
+++ b/src/GridCalEngine/Compilers/circuit_to_bentayga.py
@@ -17,7 +17,7 @@
import os.path
import numpy as np
-from GridCalEngine.enumerations import SolverType, ReactivePowerControlMode, HvdcControlType
+from GridCalEngine.enumerations import SolverType, HvdcControlType
from GridCalEngine.Simulations.PowerFlow.power_flow_options import PowerFlowOptions
from GridCalEngine.Simulations.PowerFlow.power_flow_results import PowerFlowResults
from GridCalEngine.Devices.multi_circuit import MultiCircuit
@@ -616,9 +616,9 @@ def get_snapshots_from_bentayga(circuit: MultiCircuit):
data.k_pf_tau = btg_data.control_indices.k_pf_tau
data.k_qf_m = btg_data.control_indices.k_qf_m
- data.k_zero_beq = btg_data.control_indices.k_zero_beq
+ data.k_zero_beq = btg_data.control_indices.k_qf_beq
data.k_vf_beq = btg_data.control_indices.k_vf_beq
- data.k_vt_m = btg_data.control_indices.k_vt_m
+ data.k_vt_m = btg_data.control_indices.k_v_m
data.k_qt_m = btg_data.control_indices.k_qt_m
data.k_pf_dp = btg_data.control_indices.k_pf_dp
data.i_vsc = btg_data.control_indices.i_vsc
@@ -645,8 +645,8 @@ def get_bentayga_pf_options(opt: PowerFlowOptions):
SolverType.FASTDECOUPLED: btg.PowerFlowSolvers.FastDecoupled
}
- q_control_dict = {ReactivePowerControlMode.NoControl: btg.QControlMode.NoControl,
- ReactivePowerControlMode.Direct: btg.QControlMode.Direct}
+ q_control_dict = {False: btg.QControlMode.NoControl,
+ True: btg.QControlMode.Direct}
solver_type = solver_dict.get(opt.solver_type, btg.PowerFlowSolvers.NewtonRaphson)
diff --git a/src/GridCalEngine/Compilers/circuit_to_data.py b/src/GridCalEngine/Compilers/circuit_to_data.py
index 129a51250..97a83bff5 100644
--- a/src/GridCalEngine/Compilers/circuit_to_data.py
+++ b/src/GridCalEngine/Compilers/circuit_to_data.py
@@ -17,12 +17,14 @@
from __future__ import annotations
from typing import Dict, Union, TYPE_CHECKING, Tuple
from GridCalEngine.basic_structures import Logger
+import GridCalEngine.Devices as dev
from GridCalEngine.Devices.Substation.bus import Bus
from GridCalEngine.Devices.Aggregation.area import Area
from GridCalEngine.Devices.multi_circuit import MultiCircuit
-from GridCalEngine.enumerations import (BusMode, BranchImpedanceMode, ExternalGridMode, ConverterControlType,
- TransformerControlType, HvdcControlType)
+from GridCalEngine.enumerations import (BusMode, BranchImpedanceMode, ExternalGridMode,
+ TapModuleControl, TapPhaseControl, HvdcControlType)
from GridCalEngine.basic_structures import BoolVec
+from GridCalEngine.Devices.types import BRANCH_TYPES
import GridCalEngine.DataStructures as ds
if TYPE_CHECKING: # Only imports the below statements during type checking
@@ -104,8 +106,7 @@ def get_bus_data(circuit: MultiCircuit,
bus_data.Vmax[i] = bus.Vmax
bus_data.Vnom[i] = bus.Vnom
bus_data.cost_v[i] = bus.Vm_cost
- # TODO: Check that the devices are are changing the guess
- bus_data.Vbus[i] = bus.get_voltage_guess(None, use_stored_guess=use_stored_guess)
+ bus_data.Vbus[i] = bus.get_voltage_guess(use_stored_guess=use_stored_guess)
bus_data.is_dc[i] = bus.is_dc
bus_data.angle_min[i] = bus.angle_min
@@ -114,8 +115,8 @@ def get_bus_data(circuit: MultiCircuit,
if bus.is_slack:
bus_data.bus_types[i] = BusMode.Slack_tpe.value # VD
else:
- # bus.determine_bus_type().value
- bus_data.bus_types[i] = BusMode.PQ_tpe.value # PQ by default, later it is modified by generators and batteries
+ # PQ by default, later it is modified by generators and batteries
+ bus_data.bus_types[i] = BusMode.PQ_tpe.value
bus_data.substations[i] = substation_dict.get(bus.substation, 0)
@@ -271,14 +272,17 @@ def get_load_data(circuit: MultiCircuit,
return data
-def get_shunt_data(circuit: MultiCircuit,
- bus_dict,
- bus_voltage_used: BoolVec,
- bus_data: ds.BusData,
- logger: Logger,
- t_idx=-1,
- time_series=False,
- use_stored_guess=False) -> ds.ShuntData:
+def get_shunt_data(
+ circuit: MultiCircuit,
+ bus_dict,
+ bus_voltage_used: BoolVec,
+ bus_data: ds.BusData,
+ logger: Logger,
+ t_idx=-1,
+ time_series=False,
+ use_stored_guess=False,
+ control_remote_voltage: bool = True,
+) -> ds.ShuntData:
"""
:param circuit:
@@ -347,7 +351,7 @@ def get_shunt_data(circuit: MultiCircuit,
set_bus_control_voltage(i=i,
j=j,
- remote_control=remote_control,
+ remote_control=remote_control and control_remote_voltage,
bus_name=elm.bus.name,
bus_data=bus_data,
bus_voltage_used=bus_voltage_used,
@@ -370,7 +374,7 @@ def get_shunt_data(circuit: MultiCircuit,
set_bus_control_voltage(i=i,
j=j,
- remote_control=remote_control,
+ remote_control=remote_control and control_remote_voltage,
bus_name=elm.bus.name,
bus_data=bus_data,
bus_voltage_used=bus_voltage_used,
@@ -384,15 +388,18 @@ def get_shunt_data(circuit: MultiCircuit,
return data
-def get_generator_data(circuit: MultiCircuit,
- bus_dict,
- bus_voltage_used: BoolVec,
- logger: Logger,
- bus_data: ds.BusData,
- opf_results: Union[OptimalPowerFlowResults, None] = None,
- t_idx=-1,
- time_series=False,
- use_stored_guess=False) -> Tuple[ds.GeneratorData, Dict[str, int]]:
+def get_generator_data(
+ circuit: MultiCircuit,
+ bus_dict,
+ bus_voltage_used: BoolVec,
+ logger: Logger,
+ bus_data: ds.BusData,
+ opf_results: Union[OptimalPowerFlowResults, None] = None,
+ t_idx=-1,
+ time_series=False,
+ use_stored_guess=False,
+ control_remote_voltage: bool = True,
+) -> Tuple[ds.GeneratorData, Dict[str, int]]:
"""
:param circuit:
@@ -404,6 +411,7 @@ def get_generator_data(circuit: MultiCircuit,
:param t_idx:
:param time_series:
:param use_stored_guess:
+ :param control_remote_voltage:
:return:
"""
devices = circuit.get_generators()
@@ -475,7 +483,7 @@ def get_generator_data(circuit: MultiCircuit,
set_bus_control_voltage(i=i,
j=j,
- remote_control=remote_control,
+ remote_control=remote_control and control_remote_voltage,
bus_name=elm.bus.name,
bus_data=bus_data,
bus_voltage_used=bus_voltage_used,
@@ -502,22 +510,23 @@ def get_generator_data(circuit: MultiCircuit,
if elm.srap_enabled and data.p[k] > 0.0:
bus_data.srap_availbale_power[i] += data.p[k]
- if elm.control_bus is not None:
- remote_control = True
- j = bus_dict[elm.control_bus]
- else:
- remote_control = False
- j = -1
+ if elm.is_controlled:
+ if elm.control_bus is not None:
+ remote_control = True
+ j = bus_dict[elm.control_bus]
+ else:
+ remote_control = False
+ j = -1
- set_bus_control_voltage(i=i,
- j=j,
- remote_control=remote_control,
- bus_name=elm.bus.name,
- bus_data=bus_data,
- bus_voltage_used=bus_voltage_used,
- candidate_Vm=elm.Vset,
- use_stored_guess=use_stored_guess,
- logger=logger)
+ set_bus_control_voltage(i=i,
+ j=j,
+ remote_control=remote_control and control_remote_voltage,
+ bus_name=elm.bus.name,
+ bus_data=bus_data,
+ bus_voltage_used=bus_voltage_used,
+ candidate_Vm=elm.Vset,
+ use_stored_guess=use_stored_guess,
+ logger=logger)
# reactive power limits, for the given power value
if elm.use_reactive_power_curve:
@@ -532,15 +541,18 @@ def get_generator_data(circuit: MultiCircuit,
return data, gen_index_dict
-def get_battery_data(circuit: MultiCircuit,
- bus_dict: Dict[Bus, int],
- bus_voltage_used: BoolVec,
- logger: Logger,
- bus_data: ds.BusData,
- opf_results: Union[OptimalPowerFlowResults, None] = None,
- t_idx=-1,
- time_series=False,
- use_stored_guess=False) -> ds.BatteryData:
+def get_battery_data(
+ circuit: MultiCircuit,
+ bus_dict: Dict[Bus, int],
+ bus_voltage_used: BoolVec,
+ logger: Logger,
+ bus_data: ds.BusData,
+ opf_results: Union[OptimalPowerFlowResults, None] = None,
+ t_idx=-1,
+ time_series=False,
+ use_stored_guess=False,
+ control_remote_voltage: bool = True,
+) -> ds.BatteryData:
"""
:param circuit:
@@ -552,6 +564,7 @@ def get_battery_data(circuit: MultiCircuit,
:param t_idx:
:param time_series:
:param use_stored_guess:
+ :param control_remote_voltage:
:return:
"""
devices = circuit.get_batteries()
@@ -629,7 +642,7 @@ def get_battery_data(circuit: MultiCircuit,
set_bus_control_voltage(i=i,
j=j,
- remote_control=remote_control,
+ remote_control=remote_control and control_remote_voltage,
bus_name=elm.bus.name,
bus_data=bus_data,
bus_voltage_used=bus_voltage_used,
@@ -667,7 +680,7 @@ def get_battery_data(circuit: MultiCircuit,
set_bus_control_voltage(i=i,
j=j,
- remote_control=remote_control,
+ remote_control=remote_control and control_remote_voltage,
bus_name=elm.bus.name,
bus_data=bus_data,
bus_voltage_used=bus_voltage_used,
@@ -688,21 +701,242 @@ def get_battery_data(circuit: MultiCircuit,
return data
-def get_branch_data(circuit: MultiCircuit,
- bus_dict: Dict[Bus, int],
- bus_data: ds.BusData,
- bus_voltage_used: BoolVec,
- apply_temperature: bool,
- branch_tolerance_mode: BranchImpedanceMode,
- t_idx: int = -1,
- time_series: bool = False,
- opf_results: Union[OptimalPowerFlowResults, None] = None,
- use_stored_guess: bool = False,
- logger: Logger = Logger()) -> ds.BranchData:
+def fill_parent_branch(i: int,
+ elm: BRANCH_TYPES,
+ data: ds.BranchData,
+ bus_dict: Dict[Bus, int],
+ apply_temperature: bool,
+ branch_tolerance_mode: BranchImpedanceMode,
+ t_idx: int = -1,
+ time_series: bool = False,
+ is_dc_branch: bool = False, ):
+ """
+
+ :param i:
+ :param elm:
+ :param data:
+ :param bus_dict:
+ :param apply_temperature:
+ :param branch_tolerance_mode:
+ :param t_idx:
+ :param time_series:
+ :param is_dc_branch:
+ :return:
+ """
+ data.names[i] = elm.name
+ data.idtag[i] = elm.idtag
+
+ data.mttf[i] = elm.mttf
+ data.mttr[i] = elm.mttr
+
+ if time_series:
+ data.active[i] = elm.active_prof[t_idx]
+ data.rates[i] = elm.rate_prof[t_idx]
+ data.contingency_rates[i] = elm.rate_prof[t_idx] * elm.contingency_factor_prof[t_idx]
+ data.protection_rates[i] = elm.rate_prof[t_idx] * elm.protection_rating_factor_prof[t_idx]
+
+ data.overload_cost[i] = elm.Cost_prof[t_idx]
+
+ else:
+ data.active[i] = elm.active
+ data.rates[i] = elm.rate
+ data.contingency_rates[i] = elm.rate * elm.contingency_factor
+ data.protection_rates[i] = elm.rate * elm.protection_rating_factor
+
+ data.overload_cost[i] = elm.Cost
+
+ f = bus_dict[elm.bus_from]
+ t = bus_dict[elm.bus_to]
+ data.C_branch_bus_f[i, f] = 1
+ data.C_branch_bus_t[i, t] = 1
+ data.F[i] = f
+ data.T[i] = t
+
+ if apply_temperature:
+ data.R[i] = elm.R_corrected
+ else:
+ data.R[i] = elm.R
+
+ if branch_tolerance_mode == BranchImpedanceMode.Lower:
+ data.R[i] *= (1 - elm.tolerance / 100.0)
+ elif branch_tolerance_mode == BranchImpedanceMode.Upper:
+ data.R[i] *= (1 + elm.tolerance / 100.0)
+
+ if not is_dc_branch:
+ data.X[i] = elm.X
+ data.B[i] = elm.B
+
+ data.R0[i] = elm.R0
+ data.X0[i] = elm.X0
+ data.B0[i] = elm.B0
+
+ data.R2[i] = elm.R2
+ data.X2[i] = elm.X2
+ data.B2[i] = elm.B2
+
+ data.contingency_enabled[i] = int(elm.contingency_enabled)
+ data.monitor_loading[i] = int(elm.monitor_loading)
+
+ data.virtual_tap_f[i], data.virtual_tap_t[i] = elm.get_virtual_taps()
+
+ return f, t
+
+
+def fill_controllable_branch(
+ ii: int,
+ elm: Union[dev.Transformer2W, dev.Winding, dev.VSC, dev.UPFC],
+ data: ds.BranchData,
+ bus_data: ds.BusData,
+ bus_dict: Dict[Bus, int],
+ apply_temperature: bool,
+ branch_tolerance_mode: BranchImpedanceMode,
+ t_idx: int,
+ time_series: bool,
+ opf_results: Union[OptimalPowerFlowResults, None],
+ use_stored_guess: bool,
+ bus_voltage_used: BoolVec,
+ Sbase: float,
+ control_taps_modules: bool,
+ control_taps_phase: bool,
+ control_remote_voltage: bool,
+ logger: Logger):
+ """
+
+ :param ii:
+ :param elm:
+ :param data:
+ :param bus_data:
+ :param bus_dict:
+ :param apply_temperature:
+ :param branch_tolerance_mode:
+ :param t_idx:
+ :param time_series:
+ :param opf_results:
+ :param use_stored_guess:
+ :param bus_voltage_used:
+ :param Sbase:
+ :param control_taps_modules:
+ :param control_taps_phase:
+ :param control_remote_voltage:
+ :param logger:
+ :return:
+ """
+ _, t = fill_parent_branch(i=ii,
+ elm=elm,
+ data=data,
+ bus_dict=bus_dict,
+ apply_temperature=apply_temperature,
+ branch_tolerance_mode=branch_tolerance_mode,
+ t_idx=t_idx,
+ time_series=time_series,
+ is_dc_branch=False)
+
+ if time_series:
+
+ if control_taps_phase:
+ data.tap_phase_control_mode[ii] = elm.tap_phase_control_mode_prof[t_idx]
+
+ if control_taps_modules:
+ data.tap_module_control_mode[ii] = elm.tap_module_control_mode_prof[t_idx]
+ if elm.regulation_bus is None:
+ reg_bus = elm.bus_from
+ if data.tap_module_control_mode[ii] == TapModuleControl.Vm:
+ logger.add_warning("Unspecified regulation bus",
+ device_class=elm.device_type.value,
+ device=elm.name)
+ else:
+ reg_bus = elm.regulation_bus
+
+ data.tap_controlled_buses[ii] = bus_dict[reg_bus]
+
+ data.Pset[ii] = elm.Pset_prof[t_idx] / Sbase
+ data.Qset[ii] = elm.Qset_prof[t_idx] / Sbase
+ data.vset[ii] = elm.vset_prof[t_idx]
+
+ if opf_results is not None:
+ data.tap_module[ii] = elm.tap_module
+ data.tap_angle[ii] = opf_results.phase_shift[t_idx, ii]
+ else:
+ data.tap_module[ii] = elm.tap_module_prof[t_idx]
+ data.tap_angle[ii] = elm.tap_phase_prof[t_idx]
+ else:
+
+ if control_taps_phase:
+ data.tap_phase_control_mode[ii] = elm.tap_phase_control_mode
+
+ if control_taps_modules:
+ data.tap_module_control_mode[ii] = elm.tap_module_control_mode
+
+ if elm.regulation_bus is None:
+ reg_bus = elm.bus_from
+ if data.tap_module_control_mode[ii] == TapModuleControl.Vm:
+ logger.add_warning("Unspecified regulation bus",
+ device_class=elm.device_type.value,
+ device=elm.name)
+ else:
+ reg_bus = elm.regulation_bus
+ data.tap_controlled_buses[ii] = bus_dict[reg_bus]
+
+ data.Pset[ii] = elm.Pset / Sbase
+ data.Qset[ii] = elm.Qset / Sbase
+ data.vset[ii] = elm.vset
+
+ if opf_results is not None:
+ data.tap_module[ii] = elm.tap_module
+ data.tap_angle[ii] = opf_results.phase_shift[ii]
+ else:
+ data.tap_module[ii] = elm.tap_module
+ data.tap_angle[ii] = elm.tap_phase
+
+ data.tap_module_min[ii] = elm.tap_module_min
+ data.tap_module_max[ii] = elm.tap_module_max
+ data.tap_angle_min[ii] = elm.tap_phase_min
+ data.tap_angle_max[ii] = elm.tap_phase_max
+
+ if (data.tap_module_control_mode[ii] != TapModuleControl.fixed
+ or data.tap_phase_control_mode[ii] != TapPhaseControl.fixed):
+ data._any_pf_control = True
+
+ if not use_stored_guess:
+ if data.tap_module_control_mode[ii] == TapModuleControl.Vm:
+ data._any_pf_control = True
+ bus_idx = data.tap_controlled_buses[ii]
+ if not bus_voltage_used[bus_idx]:
+ if elm.vset > 0.0:
+ bus_data.Vbus[bus_idx] = elm.vset
+ else:
+ logger.add_warning("Branch control voltage out of bounds",
+ device_class=str(elm.device_type.value),
+ device=elm.name,
+ value=elm.vset)
+ elif elm.vset != bus_data.Vbus[bus_idx]:
+ logger.add_error(msg='Different control voltage set points',
+ device=bus_data.names[bus_idx],
+ value=elm.vset,
+ expected_value=bus_data.Vbus[bus_idx])
+
+
+def get_branch_data(
+ circuit: MultiCircuit,
+ bus_dict: Dict[Bus, int],
+ bus_data: ds.BusData,
+ bus_voltage_used: BoolVec,
+ apply_temperature: bool,
+ branch_tolerance_mode: BranchImpedanceMode,
+ t_idx: int = -1,
+ time_series: bool = False,
+ opf_results: Union[OptimalPowerFlowResults, None] = None,
+ use_stored_guess: bool = False,
+ control_taps_modules: bool = True,
+ control_taps_phase: bool = True,
+ control_remote_voltage: bool = True,
+ logger: Logger = Logger()
+) -> ds.BranchData:
"""
Compile BranchData for a time step or the snapshot
:param circuit: MultiCircuit
:param bus_dict: Dictionary of buses to compute the indices
+ :param bus_data: BusData
:param bus_voltage_used:
:param apply_temperature: apply the temperature correction?
:param branch_tolerance_mode: BranchImpedanceMode
@@ -710,6 +944,9 @@ def get_branch_data(circuit: MultiCircuit,
:param time_series: compile time series? else the sanpshot is compiled
:param opf_results: OptimalPowerFlowResults
:param use_stored_guess: use the stored voltage ?
+ :param control_taps_modules: Control TapsModules
+ :param control_taps_phase: Control TapsPhase
+ :param control_remote_voltage: Control RemoteVoltage
:param logger: Logger
:return: BranchData
"""
@@ -722,201 +959,55 @@ def get_branch_data(circuit: MultiCircuit,
# Compile the lines
for i, elm in enumerate(circuit.lines):
# generic stuff
- data.names[i] = elm.name
- data.idtag[i] = elm.idtag
-
- data.mttf[i] = elm.mttf
- data.mttr[i] = elm.mttr
-
- if time_series:
- data.active[i] = elm.active_prof[t_idx]
- data.rates[i] = elm.rate_prof[t_idx]
- data.contingency_rates[i] = elm.rate_prof[t_idx] * elm.contingency_factor_prof[t_idx]
- data.protection_rates[i] = elm.rate_prof[t_idx] * elm.protection_rating_factor_prof[t_idx]
-
- data.overload_cost[i] = elm.Cost_prof[t_idx]
-
- else:
- data.active[i] = elm.active
- data.rates[i] = elm.rate
- data.contingency_rates[i] = elm.rate * elm.contingency_factor
- data.protection_rates[i] = elm.rate * elm.protection_rating_factor
-
- data.overload_cost[i] = elm.Cost
-
- f = bus_dict[elm.bus_from]
- t = bus_dict[elm.bus_to]
- data.C_branch_bus_f[i, f] = 1
- data.C_branch_bus_t[i, t] = 1
- data.F[i] = f
- data.T[i] = t
-
- if apply_temperature:
- data.R[i] = elm.R_corrected
- else:
- data.R[i] = elm.R
-
- if branch_tolerance_mode == BranchImpedanceMode.Lower:
- data.R[i] *= (1 - elm.tolerance / 100.0)
- elif branch_tolerance_mode == BranchImpedanceMode.Upper:
- data.R[i] *= (1 + elm.tolerance / 100.0)
-
- data.X[i] = elm.X
- data.B[i] = elm.B
-
- data.R0[i] = elm.R0
- data.X0[i] = elm.X0
- data.B0[i] = elm.B0
-
- data.R2[i] = elm.R2
- data.X2[i] = elm.X2
- data.B2[i] = elm.B2
-
- # data.conn[i] = elm.conn
-
- data.contingency_enabled[i] = int(elm.contingency_enabled)
- data.monitor_loading[i] = int(elm.monitor_loading)
-
- data.virtual_tap_f[i], data.virtual_tap_t[i] = elm.get_virtual_taps()
-
- data.control_mode[i] = TransformerControlType.fixed
+ fill_parent_branch(i=i,
+ elm=elm,
+ data=data,
+ bus_dict=bus_dict,
+ apply_temperature=apply_temperature,
+ branch_tolerance_mode=branch_tolerance_mode,
+ t_idx=t_idx,
+ time_series=time_series,
+ is_dc_branch=False)
ii += 1
# DC-lines
for i, elm in enumerate(circuit.dc_lines):
# generic stuff
- f = bus_dict[elm.bus_from]
- t = bus_dict[elm.bus_to]
-
- data.names[ii] = elm.name
- data.idtag[ii] = elm.idtag
-
- data.mttf[ii] = elm.mttf
- data.mttr[ii] = elm.mttr
-
- data.dc[ii] = 1
-
- if time_series:
- data.active[ii] = elm.active_prof[t_idx]
- data.rates[ii] = elm.rate_prof[t_idx]
- data.contingency_rates[ii] = elm.rate_prof[t_idx] * elm.contingency_factor_prof[t_idx]
- data.protection_rates[ii] = elm.rate_prof[t_idx] * elm.protection_rating_factor_prof[t_idx]
- data.overload_cost[ii] = elm.Cost_prof[t_idx]
- else:
- data.active[ii] = elm.active
- data.rates[ii] = elm.rate
- data.contingency_rates[ii] = elm.rate * elm.contingency_factor
- data.protection_rates[ii] = elm.rate * elm.protection_rating_factor
- data.overload_cost[ii] = elm.Cost
-
- data.C_branch_bus_f[ii, f] = 1
- data.C_branch_bus_t[ii, t] = 1
- data.F[ii] = f
- data.T[ii] = t
-
- data.contingency_enabled[ii] = int(elm.contingency_enabled)
- data.monitor_loading[ii] = int(elm.monitor_loading)
-
- data.control_mode[ii] = TransformerControlType.fixed
-
- data.virtual_tap_f[ii], data.virtual_tap_t[ii] = elm.get_virtual_taps()
-
- if apply_temperature:
- data.R[ii] = elm.R_corrected
- else:
- data.R[ii] = elm.R
-
- if branch_tolerance_mode == BranchImpedanceMode.Lower:
- data.R[ii] *= (1 - elm.tolerance / 100.0)
- elif branch_tolerance_mode == BranchImpedanceMode.Upper:
- data.R[ii] *= (1 + elm.tolerance / 100.0)
+ fill_parent_branch(i=ii,
+ elm=elm,
+ data=data,
+ bus_dict=bus_dict,
+ apply_temperature=apply_temperature,
+ branch_tolerance_mode=branch_tolerance_mode,
+ t_idx=t_idx,
+ time_series=time_series,
+ is_dc_branch=True)
ii += 1
# 2-winding transformers
for i, elm in enumerate(circuit.transformers2w):
-
- # generic stuff
- f = bus_dict[elm.bus_from]
- t = bus_dict[elm.bus_to]
-
- data.names[ii] = elm.name
- data.idtag[ii] = elm.idtag
-
- data.mttf[ii] = elm.mttf
- data.mttr[ii] = elm.mttr
-
- if time_series:
- data.active[ii] = elm.active_prof[t_idx]
- data.rates[ii] = elm.rate_prof[t_idx]
- data.contingency_rates[ii] = elm.rate_prof[t_idx] * elm.contingency_factor_prof[t_idx]
- data.protection_rates[ii] = elm.rate_prof[t_idx] * elm.protection_rating_factor_prof[t_idx]
- data.overload_cost[ii] = elm.Cost_prof[t_idx]
- else:
- data.active[ii] = elm.active
- data.rates[ii] = elm.rate
- data.contingency_rates[ii] = elm.rate * elm.contingency_factor
- data.protection_rates[ii] = elm.rate * elm.protection_rating_factor
- data.overload_cost[ii] = elm.Cost
-
- data.C_branch_bus_f[ii, f] = 1
- data.C_branch_bus_t[ii, t] = 1
- data.F[ii] = f
- data.T[ii] = t
-
- data.R[ii] = elm.R
- data.X[ii] = elm.X
- data.G[ii] = elm.G
- data.B[ii] = elm.B
-
- data.R0[ii] = elm.R0
- data.X0[ii] = elm.X0
- data.G0[ii] = elm.G0
- data.B0[ii] = elm.B0
-
- data.R2[ii] = elm.R2
- data.X2[ii] = elm.X2
- data.G2[ii] = elm.G2
- data.B2[ii] = elm.B2
+ fill_controllable_branch(ii=ii,
+ elm=elm,
+ data=data,
+ bus_data=bus_data,
+ bus_dict=bus_dict,
+ apply_temperature=apply_temperature,
+ branch_tolerance_mode=branch_tolerance_mode,
+ t_idx=t_idx,
+ time_series=time_series,
+ opf_results=opf_results,
+ use_stored_guess=use_stored_guess,
+ bus_voltage_used=bus_voltage_used,
+ Sbase=circuit.Sbase,
+ control_taps_modules=control_taps_modules,
+ control_taps_phase=control_taps_phase,
+ control_remote_voltage=control_remote_voltage,
+ logger=logger)
data.conn[ii] = elm.conn
- if time_series:
- if opf_results is not None:
- data.tap_module[ii] = elm.tap_module
- data.tap_angle[ii] = opf_results.phase_shift[t_idx, ii]
- else:
- data.tap_module[ii] = elm.tap_module_prof[t_idx]
- data.tap_angle[ii] = elm.tap_phase_prof[t_idx]
- else:
- if opf_results is not None:
- data.tap_module[ii] = elm.tap_module
- data.tap_angle[ii] = opf_results.phase_shift[ii]
- else:
- data.tap_module[ii] = elm.tap_module
- data.tap_angle[ii] = elm.tap_phase
-
- data.tap_module_min[ii] = elm.tap_module_min
- data.tap_module_max[ii] = elm.tap_module_max
- data.tap_angle_min[ii] = elm.tap_phase_min
- data.tap_angle_max[ii] = elm.tap_phase_max
-
- data.Pfset[ii] = elm.Pset
-
- data.control_mode[ii] = elm.control_mode
- data.virtual_tap_f[ii], data.virtual_tap_t[ii] = elm.get_virtual_taps()
-
- data.contingency_enabled[ii] = int(elm.contingency_enabled)
- data.monitor_loading[ii] = int(elm.monitor_loading)
-
- if not use_stored_guess:
- if elm.control_mode == TransformerControlType.V:
- bus_data.Vbus[t] = elm.vset
-
- elif elm.control_mode == TransformerControlType.PtV: # 2a:Vdc
- bus_data.Vbus[t] = elm.vset
-
ii += 1
# windings
@@ -924,84 +1015,26 @@ def get_branch_data(circuit: MultiCircuit,
if elm.bus_from is not None and elm.bus_to is not None:
# generic stuff
- data.names[ii] = elm.name
- data.idtag[ii] = elm.idtag
-
- data.mttf[ii] = elm.mttf
- data.mttr[ii] = elm.mttr
-
- if time_series:
- data.active[ii] = elm.active_prof[t_idx]
- data.rates[ii] = elm.rate_prof[t_idx]
- data.contingency_rates[ii] = elm.rate_prof[t_idx] * elm.contingency_factor_prof[t_idx]
- data.protection_rates[ii] = elm.rate_prof[t_idx] * elm.protection_rating_factor_prof[t_idx]
- data.overload_cost[ii] = elm.Cost_prof[t_idx]
- else:
- data.active[ii] = elm.active
- data.rates[ii] = elm.rate
- data.contingency_rates[ii] = elm.rate * elm.contingency_factor
- data.protection_rates[ii] = elm.rate * elm.protection_rating_factor
- data.overload_cost[ii] = elm.Cost
-
- f = bus_dict[elm.bus_from]
- t = bus_dict[elm.bus_to]
- data.C_branch_bus_f[ii, f] = 1
- data.C_branch_bus_t[ii, t] = 1
- data.F[ii] = f
- data.T[ii] = t
-
- data.R[ii] = elm.R
- data.X[ii] = elm.X
- data.G[ii] = elm.G
- data.B[ii] = elm.B
-
- data.R0[ii] = elm.R0
- data.X0[ii] = elm.X0
- data.G0[ii] = elm.G0
- data.B0[ii] = elm.B0
-
- data.R2[ii] = elm.R2
- data.X2[ii] = elm.X2
- data.G2[ii] = elm.G2
- data.B2[ii] = elm.B2
+ fill_controllable_branch(ii=ii,
+ elm=elm,
+ data=data,
+ bus_data=bus_data,
+ bus_dict=bus_dict,
+ apply_temperature=apply_temperature,
+ branch_tolerance_mode=branch_tolerance_mode,
+ t_idx=t_idx,
+ time_series=time_series,
+ opf_results=opf_results,
+ use_stored_guess=use_stored_guess,
+ bus_voltage_used=bus_voltage_used,
+ Sbase=circuit.Sbase,
+ control_taps_modules=control_taps_modules,
+ control_taps_phase=control_taps_phase,
+ control_remote_voltage=control_remote_voltage,
+ logger=logger)
data.conn[ii] = elm.conn
- if time_series:
- if opf_results is not None:
- data.tap_module[ii] = elm.tap_module
- data.tap_angle[ii] = opf_results.phase_shift[t_idx, ii]
- else:
- data.tap_module[ii] = elm.tap_module_prof[t_idx]
- data.tap_angle[ii] = elm.tap_phase_prof[t_idx]
- else:
- if opf_results is not None:
- data.tap_module[ii] = elm.tap_module
- data.tap_angle[ii] = opf_results.phase_shift[ii]
- else:
- data.tap_module[ii] = elm.tap_module
- data.tap_angle[ii] = elm.tap_phase
-
- data.tap_module_min[ii] = elm.tap_module_min
- data.tap_module_max[ii] = elm.tap_module_max
- data.tap_angle_min[ii] = elm.tap_phase_min
- data.tap_angle_max[ii] = elm.tap_phase_max
-
- data.Pfset[ii] = elm.Pset
-
- data.control_mode[ii] = elm.control_mode
- data.virtual_tap_f[ii], data.virtual_tap_t[ii] = elm.get_virtual_taps()
-
- data.contingency_enabled[ii] = int(elm.contingency_enabled)
- data.monitor_loading[ii] = int(elm.monitor_loading)
-
- if not use_stored_guess:
- if elm.control_mode == TransformerControlType.V:
- bus_data.Vbus[t] = elm.vset
-
- elif elm.control_mode == TransformerControlType.PtV: # 2a:Vdc
- bus_data.Vbus[t] = elm.vset
-
ii += 1
else:
@@ -1009,107 +1042,30 @@ def get_branch_data(circuit: MultiCircuit,
# VSC
for i, elm in enumerate(circuit.vsc_devices):
-
# generic stuff
- f = bus_dict[elm.bus_from]
- t = bus_dict[elm.bus_to]
-
- data.names[ii] = elm.name
- data.idtag[ii] = elm.idtag
-
- data.mttf[ii] = elm.mttf
- data.mttr[ii] = elm.mttr
-
- if time_series:
- data.active[ii] = elm.active_prof[t_idx]
- data.rates[ii] = elm.rate_prof[t_idx]
- data.contingency_rates[ii] = elm.rate_prof[t_idx] * elm.contingency_factor_prof[t_idx]
- data.protection_rates[ii] = elm.rate_prof[t_idx] * elm.protection_rating_factor_prof[t_idx]
- data.overload_cost[ii] = elm.Cost_prof[t_idx]
- else:
- data.active[ii] = elm.active
- data.rates[ii] = elm.rate
- data.contingency_rates[ii] = elm.rate * elm.contingency_factor
- data.protection_rates[ii] = elm.rate * elm.protection_rating_factor
- data.overload_cost[ii] = elm.Cost
-
- data.C_branch_bus_f[ii, f] = 1
- data.C_branch_bus_t[ii, t] = 1
- data.F[ii] = f
- data.T[ii] = t
-
- data.R[ii] = elm.R
- data.X[ii] = elm.X
-
- data.R0[ii] = elm.R0
- data.X0[ii] = elm.X0
-
- data.R2[ii] = elm.R2
- data.X2[ii] = elm.X2
-
- data.G0sw[ii] = elm.G0sw
- data.Beq[ii] = elm.Beq
- data.tap_module[ii] = elm.tap_module
- data.tap_module_max[ii] = elm.tap_module_max
- data.tap_module_min[ii] = elm.tap_module_min
+ fill_controllable_branch(ii=ii,
+ elm=elm,
+ data=data,
+ bus_data=bus_data,
+ bus_dict=bus_dict,
+ apply_temperature=apply_temperature,
+ branch_tolerance_mode=branch_tolerance_mode,
+ t_idx=t_idx,
+ time_series=time_series,
+ opf_results=opf_results,
+ use_stored_guess=use_stored_guess,
+ bus_voltage_used=bus_voltage_used,
+ Sbase=circuit.Sbase,
+ control_taps_modules=control_taps_modules,
+ control_taps_phase=control_taps_phase,
+ control_remote_voltage=control_remote_voltage,
+ logger=logger)
+ data.Kdp[ii] = elm.kdp
+ data.is_converter[ii] = True
data.alpha1[ii] = elm.alpha1
data.alpha2[ii] = elm.alpha2
data.alpha3[ii] = elm.alpha3
- data.k[ii] = elm.k # 0.8660254037844386 # sqrt(3)/2 (do not confuse with k droop)
-
- if time_series:
- if opf_results is not None:
- data.tap_angle[ii] = opf_results.phase_shift[t_idx, ii]
- else:
- data.tap_angle[ii] = elm.tap_phase
- else:
- if opf_results is not None:
- data.tap_angle[ii] = opf_results.phase_shift[ii]
- else:
- data.tap_angle[ii] = elm.tap_phase
-
- data.tap_angle_min[ii] = elm.tap_phase_min
- data.tap_angle_max[ii] = elm.tap_phase_max
- data.Pfset[ii] = elm.Pdc_set
- data.Qtset[ii] = elm.Qac_set
- data.Kdp[ii] = elm.kdp
- data.vf_set[ii] = elm.Vac_set
- data.vt_set[ii] = elm.Vdc_set
- data.control_mode[ii] = elm.control_mode
- data.contingency_enabled[ii] = int(elm.contingency_enabled)
- data.monitor_loading[ii] = int(elm.monitor_loading)
-
- '''
- type_0_free = '0:Free'
- type_I_1 = '1:Vac'
- type_I_2 = '2:Pdc+Qac'
- type_I_3 = '3:Pdc+Vac'
- type_II_4 = '4:Vdc+Qac'
- type_II_5 = '5:Vdc+Vac'
- type_III_6 = '6:Droop+Qac'
- type_III_7 = '7:Droop+Vac'
- '''
-
- if not use_stored_guess:
- if elm.control_mode == ConverterControlType.type_I_1: # 1a:Vac
- bus_data.Vbus[t] = elm.Vac_set
-
- elif elm.control_mode == ConverterControlType.type_I_3: # 3:Pdc+Vac
- bus_data.Vbus[t] = elm.Vac_set
-
- elif elm.control_mode == ConverterControlType.type_II_4: # 4:Vdc+Qac
- bus_data.Vbus[f] = elm.Vdc_set
-
- elif elm.control_mode == ConverterControlType.type_II_5: # 5:Vdc+Vac
- bus_data.Vbus[f] = elm.Vdc_set
- bus_data.Vbus[t] = elm.Vac_set
-
- elif elm.control_mode == ConverterControlType.type_III_7: # 7:Droop+Vac
- bus_data.Vbus[t] = elm.Vac_set
-
- elif elm.control_mode == ConverterControlType.type_IV_I: # 8:Vdc
- bus_data.Vbus[f] = elm.Vdc_set
-
+ data._any_pf_control = True
ii += 1
# UPFC
@@ -1154,70 +1110,28 @@ def get_branch_data(circuit: MultiCircuit,
ysh1 = elm.get_ysh1()
data.Beq[ii] = ysh1.imag
- data.Pfset[ii] = elm.Pfset
+ data.Pset[ii] = elm.Pfset / circuit.Sbase
data.contingency_enabled[ii] = int(elm.contingency_enabled)
data.monitor_loading[ii] = int(elm.monitor_loading)
- data.control_mode[ii] = TransformerControlType.fixed
+ data.tap_phase_control_mode[i] = 0
+ data.tap_module_control_mode[i] = 0
ii += 1
# Series reactance
for i, elm in enumerate(circuit.series_reactances):
# generic stuff
- f = bus_dict[elm.bus_from]
- t = bus_dict[elm.bus_to]
-
- data.names[ii] = elm.name
- data.idtag[ii] = elm.idtag
-
- data.mttf[ii] = elm.mttf
- data.mttr[ii] = elm.mttr
-
- data.dc[ii] = 0
-
- if time_series:
- data.active[ii] = elm.active_prof[t_idx]
- data.rates[ii] = elm.rate_prof[t_idx]
- data.contingency_rates[ii] = elm.rate_prof[t_idx] * elm.contingency_factor_prof[t_idx]
- data.protection_rates[ii] = elm.rate_prof[t_idx] * elm.protection_rating_factor_prof[t_idx]
- data.overload_cost[ii] = elm.Cost_prof[t_idx]
- else:
- data.active[ii] = elm.active
- data.rates[ii] = elm.rate
- data.contingency_rates[ii] = elm.rate * elm.contingency_factor
- data.protection_rates[ii] = elm.rate * elm.protection_rating_factor
- data.overload_cost[ii] = elm.Cost
-
- data.C_branch_bus_f[ii, f] = 1
- data.C_branch_bus_t[ii, t] = 1
- data.F[ii] = f
- data.T[ii] = t
-
- data.contingency_enabled[ii] = int(elm.contingency_enabled)
- data.monitor_loading[ii] = int(elm.monitor_loading)
-
- data.control_mode[ii] = TransformerControlType.fixed
-
- data.virtual_tap_f[ii], data.virtual_tap_t[ii] = elm.get_virtual_taps()
-
- if apply_temperature:
- data.R[ii] = elm.R_corrected
- else:
- data.R[ii] = elm.R
-
- if branch_tolerance_mode == BranchImpedanceMode.Lower:
- data.R[ii] *= (1 - elm.tolerance / 100.0)
- elif branch_tolerance_mode == BranchImpedanceMode.Upper:
- data.R[ii] *= (1 + elm.tolerance / 100.0)
-
- data.X[ii] = elm.X
- data.R0[ii] = elm.R0
- data.X0[ii] = elm.X0
-
- data.R2[ii] = elm.R2
- data.X2[ii] = elm.X2
+ fill_parent_branch(i=ii,
+ elm=elm,
+ data=data,
+ bus_dict=bus_dict,
+ apply_temperature=apply_temperature,
+ branch_tolerance_mode=branch_tolerance_mode,
+ t_idx=t_idx,
+ time_series=time_series,
+ is_dc_branch=False)
ii += 1
return data
diff --git a/src/GridCalEngine/Compilers/circuit_to_newton_pa.py b/src/GridCalEngine/Compilers/circuit_to_newton_pa.py
index efd9e224e..17d8dc6c4 100644
--- a/src/GridCalEngine/Compilers/circuit_to_newton_pa.py
+++ b/src/GridCalEngine/Compilers/circuit_to_newton_pa.py
@@ -21,8 +21,8 @@
from typing import List, Dict, Union, TYPE_CHECKING
from GridCalEngine.basic_structures import IntVec, Vec
from GridCalEngine.Devices.multi_circuit import MultiCircuit
-from GridCalEngine.enumerations import (TransformerControlType, HvdcControlType, SolverType, TimeGrouping,
- ReactivePowerControlMode, ZonalGrouping, MIPSolvers, ContingencyMethod)
+from GridCalEngine.enumerations import (HvdcControlType, SolverType, TimeGrouping,
+ ZonalGrouping, MIPSolvers, ContingencyMethod)
import GridCalEngine.Devices as dev
from GridCalEngine.Simulations.PowerFlow.power_flow_options import PowerFlowOptions
from GridCalEngine.Simulations.PowerFlow.power_flow_results import PowerFlowResults
@@ -668,14 +668,14 @@ def add_transformer_data(circuit: MultiCircuit,
:param override_controls: If true the controls are set to Fix
"""
- ctrl_dict = {
- TransformerControlType.fixed: npa.BranchControlModes.Fixed,
- TransformerControlType.Pf: npa.BranchControlModes.BranchPt,
- TransformerControlType.Qt: npa.BranchControlModes.BranchQt,
- TransformerControlType.PtQt: npa.BranchControlModes.BranchPt,
- TransformerControlType.V: npa.BranchControlModes.BranchVt,
- TransformerControlType.PtV: npa.BranchControlModes.BranchPt,
- }
+ # ctrl_dict = {
+ # TransformerControlType.fixed: npa.BranchControlModes.Fixed,
+ # TransformerControlType.Pf: npa.BranchControlModes.BranchPt,
+ # TransformerControlType.Qt: npa.BranchControlModes.BranchQt,
+ # TransformerControlType.PtQt: npa.BranchControlModes.BranchPt,
+ # TransformerControlType.V: npa.BranchControlModes.BranchVt,
+ # TransformerControlType.PtV: npa.BranchControlModes.BranchPt,
+ # }
for i, elm in enumerate(circuit.transformers2w):
tr2 = npa.Transformer2WFull(uuid=elm.idtag,
@@ -715,7 +715,8 @@ def add_transformer_data(circuit: MultiCircuit,
if override_controls:
tr2.setAllControlMode(npa.BranchControlModes.Fixed)
else:
- tr2.setAllControlMode(ctrl_dict[elm.control_mode]) # TODO: Warn about this
+ # tr2.setAllControlMode(ctrl_dict[elm.control_mode]) # TODO: implement this in Newton
+ pass
tr2.phase_min = elm.tap_phase_min
tr2.phase_max = elm.tap_phase_max
@@ -742,14 +743,14 @@ def add_transformer3w_data(circuit: MultiCircuit,
:param override_controls: If true the controls are set to Fix
"""
- ctrl_dict = {
- TransformerControlType.fixed: npa.BranchControlModes.Fixed,
- TransformerControlType.Pf: npa.BranchControlModes.BranchPt,
- TransformerControlType.Qt: npa.BranchControlModes.BranchQt,
- TransformerControlType.PtQt: npa.BranchControlModes.BranchPt,
- TransformerControlType.V: npa.BranchControlModes.BranchVt,
- TransformerControlType.PtV: npa.BranchControlModes.BranchPt,
- }
+ # ctrl_dict = {
+ # TransformerControlType.fixed: npa.BranchControlModes.Fixed,
+ # TransformerControlType.Pf: npa.BranchControlModes.BranchPt,
+ # TransformerControlType.Qt: npa.BranchControlModes.BranchQt,
+ # TransformerControlType.PtQt: npa.BranchControlModes.BranchPt,
+ # TransformerControlType.V: npa.BranchControlModes.BranchVt,
+ # TransformerControlType.PtV: npa.BranchControlModes.BranchPt,
+ # }
for i, elm in enumerate(circuit.transformers3w):
tr3 = npa.Transformer3W(uuid=elm.idtag,
@@ -824,9 +825,9 @@ def add_vsc_data(circuit: MultiCircuit,
vsc.phase_max = elm.tap_phase_max
vsc.phase_min = elm.tap_phase_min
- vsc.setAllPdcSet(elm.Pdc_set)
- vsc.setAllVacSet(elm.Vac_set)
- vsc.setAllVdcSet(elm.Vdc_set)
+ vsc.setAllPdcSet(elm.Pset)
+ vsc.setAllVacSet(elm.vset)
+ vsc.setAllVdcSet(elm.vset)
vsc.k_droop = elm.kdp
vsc.alpha1 = elm.alpha1
@@ -1109,9 +1110,9 @@ def get_snapshots_from_newtonpa(circuit: MultiCircuit, override_branch_controls=
data.k_pf_tau = control_indices.k_pf_tau
data.k_qf_m = control_indices.k_qf_m
- data.k_zero_beq = control_indices.k_zero_beq
+ data.k_zero_beq = control_indices.k_qf_beq
data.k_vf_beq = control_indices.k_vf_beq
- data.k_vt_m = control_indices.k_vt_m
+ data.k_vt_m = control_indices.k_v_m
data.k_qt_m = control_indices.k_qt_m
data.k_pf_dp = control_indices.k_pf_dp
data.i_vsc = control_indices.i_vsc
@@ -1138,8 +1139,8 @@ def get_newton_pa_pf_options(opt: PowerFlowOptions) -> "npa.PowerFlowOptions":
SolverType.FASTDECOUPLED: npa.SolverType.FD
}
- q_control_dict = {ReactivePowerControlMode.NoControl: npa.ReactivePowerControlMode.NoControl,
- ReactivePowerControlMode.Direct: npa.ReactivePowerControlMode.Direct}
+ q_control_dict = {False: npa.ReactivePowerControlMode.NoControl,
+ True: npa.ReactivePowerControlMode.Direct}
if opt.solver_type in solver_dict.keys():
solver_type = solver_dict[opt.solver_type]
@@ -1195,8 +1196,8 @@ def get_newton_pa_nonlinear_opf_options(pf_opt: PowerFlowOptions,
:param opf_opt: OptimalPowerFlowOptions instance
:return: NonlinearOpfOptions
"""
- q_control_dict = {ReactivePowerControlMode.NoControl: npa.ReactivePowerControlMode.NoControl,
- ReactivePowerControlMode.Direct: npa.ReactivePowerControlMode.Direct}
+ q_control_dict = {False: npa.ReactivePowerControlMode.NoControl,
+ True: npa.ReactivePowerControlMode.Direct}
solver_dict = {MIPSolvers.CBC: npa.LpSolvers.Highs,
MIPSolvers.HIGHS: npa.LpSolvers.Highs,
@@ -1279,10 +1280,12 @@ def newton_pa_pf(circuit: MultiCircuit,
:param opf_results: Instance of
:return: Newton Power flow results object
"""
+ override_branch_controls = not (pf_opt.control_taps_modules and pf_opt.control_taps_phase)
+
npa_circuit, _ = to_newton_pa(circuit,
use_time_series=time_series,
time_indices=None,
- override_branch_controls=pf_opt.override_branch_controls,
+ override_branch_controls=override_branch_controls,
opf_results=opf_results)
pf_options = get_newton_pa_pf_options(pf_opt)
@@ -1319,10 +1322,13 @@ def newton_pa_contingencies(circuit: MultiCircuit,
:param time_indices: Array of time indices
:return: Newton Power flow results object
"""
+
+ override_branch_controls = not (con_opt.pf_options.control_taps_modules and con_opt.pf_options.control_taps_phase)
+
npa_circuit, _ = to_newton_pa(circuit,
use_time_series=time_series,
time_indices=None,
- override_branch_controls=con_opt.pf_options.override_branch_controls)
+ override_branch_controls=override_branch_controls)
pf_options = get_newton_pa_pf_options(con_opt.pf_options)
lin_opt = get_newton_pa_linear_options(con_opt.lin_options)
@@ -1370,7 +1376,7 @@ def newton_pa_contingencies(circuit: MultiCircuit,
pf_options=pf_options,
mode=mode,
using_srap=con_opt.use_srap,
- srap_max_loading=con_opt.srap_max_loading,
+ srap_max_loading=1.4,
srap_max_power=con_opt.srap_max_power
)
diff --git a/src/GridCalEngine/DataStructures/__init__.py b/src/GridCalEngine/DataStructures/__init__.py
index 7bb72a7c4..b26fcd423 100644
--- a/src/GridCalEngine/DataStructures/__init__.py
+++ b/src/GridCalEngine/DataStructures/__init__.py
@@ -19,7 +19,7 @@
from GridCalEngine.DataStructures.bus_data import BusData
from GridCalEngine.DataStructures.generator_data import GeneratorData
from GridCalEngine.DataStructures.hvdc_data import HvdcData
-from GridCalEngine.DataStructures.vsc_data import VscData
+# from GridCalEngine.DataStructures.vsc_data import VscData
from GridCalEngine.DataStructures.load_data import LoadData
from GridCalEngine.DataStructures.shunt_data import ShuntData
from GridCalEngine.DataStructures.fluid_node_data import FluidNodeData
diff --git a/src/GridCalEngine/DataStructures/branch_data.py b/src/GridCalEngine/DataStructures/branch_data.py
index bfcdc96b0..8e58801da 100644
--- a/src/GridCalEngine/DataStructures/branch_data.py
+++ b/src/GridCalEngine/DataStructures/branch_data.py
@@ -18,8 +18,8 @@
import pandas as pd
import scipy.sparse as sp
import GridCalEngine.Topology.topology as tp
-from GridCalEngine.enumerations import WindingsConnection, TransformerControlType
-from GridCalEngine.basic_structures import Vec, IntVec, StrVec, ObjVec
+from GridCalEngine.enumerations import WindingsConnection
+from GridCalEngine.basic_structures import Vec, IntVec, StrVec, ObjVec, CxVec, BoolVec
from typing import List, Tuple, Dict
@@ -50,17 +50,14 @@ def __init__(self, nelm: int, nbus: int):
self.F: IntVec = np.zeros(self.nelm, dtype=int) # indices of the "from" buses
self.T: IntVec = np.zeros(self.nelm, dtype=int) # indices of the "to" buses
- self.ctrl_bus1: IntVec = np.zeros(self.nelm, dtype=int) # indices of the control buses1
- self.ctrl_bus2: IntVec = np.zeros(self.nelm, dtype=int) # indices of the control buses2
-
# reliabilty
self.mttf: Vec = np.zeros(self.nelm, dtype=float)
self.mttr: Vec = np.zeros(self.nelm, dtype=float)
- # composite losses curve (a * x^2 + b * x + c)
- self.a: Vec = np.zeros(self.nelm, dtype=float)
- self.b: Vec = np.zeros(self.nelm, dtype=float)
- self.c: Vec = np.zeros(self.nelm, dtype=float)
+ # composite losses curve (c * x^2 + b * x + a)
+ # self.a: Vec = np.zeros(self.nelm, dtype=float)
+ # self.b: Vec = np.zeros(self.nelm, dtype=float)
+ # self.c: Vec = np.zeros(self.nelm, dtype=float)
self.R: Vec = np.zeros(self.nelm, dtype=float)
self.X: Vec = np.zeros(self.nelm, dtype=float)
@@ -93,31 +90,35 @@ def __init__(self, nelm: int, nbus: int):
self.virtual_tap_t: Vec = np.ones(self.nelm, dtype=float)
self.virtual_tap_f: Vec = np.ones(self.nelm, dtype=float)
- self.Pfset: Vec = np.zeros(nelm, dtype=float)
- self.Qfset: Vec = np.zeros(nelm, dtype=float)
- self.Qtset: Vec = np.zeros(nelm, dtype=float)
- self.vf_set: Vec = np.ones(nelm, dtype=float)
- self.vt_set: Vec = np.ones(nelm, dtype=float)
+ self.Pset: Vec = np.zeros(nelm, dtype=float) # always over the controlled side
+ self.Qset: Vec = np.zeros(nelm, dtype=float) # always over the controlled side
+ self.vset: Vec = np.ones(nelm, dtype=float) # always over the controlled side
self.Kdp: Vec = np.ones(self.nelm, dtype=float)
self.Kdp_va: Vec = np.ones(self.nelm, dtype=float)
self.alpha1: Vec = np.zeros(self.nelm, dtype=float) # converter losses parameter (alpha1)
self.alpha2: Vec = np.zeros(self.nelm, dtype=float) # converter losses parameter (alpha2)
self.alpha3: Vec = np.zeros(self.nelm, dtype=float) # converter losses parameter (alpha3)
- self.control_mode: ObjVec = np.zeros(self.nelm, dtype=object)
+
+ self.tap_module_control_mode: ObjVec = np.zeros(self.nelm, dtype=object)
+ self.tap_phase_control_mode: ObjVec = np.zeros(self.nelm, dtype=object)
+ self.tap_controlled_buses: IntVec = np.zeros(self.nelm, dtype=int)
+ self.is_converter: BoolVec = np.zeros(self.nelm, dtype=bool)
self.contingency_enabled: IntVec = np.ones(self.nelm, dtype=int)
self.monitor_loading: IntVec = np.ones(self.nelm, dtype=int)
- self.C_branch_bus_f: sp.lil_matrix = sp.lil_matrix((self.nelm, nbus),
- dtype=int) # connectivity branch with their "from" bus
- self.C_branch_bus_t: sp.lil_matrix = sp.lil_matrix((self.nelm, nbus),
- dtype=int) # connectivity branch with their "to" bus
+ # connectivity branch with their "from" bus
+ self.C_branch_bus_f: sp.lil_matrix = sp.lil_matrix((self.nelm, nbus), dtype=int)
+ # connectivity branch with their "to" bus
+ self.C_branch_bus_t: sp.lil_matrix = sp.lil_matrix((self.nelm, nbus), dtype=int)
self.overload_cost: Vec = np.zeros(nelm, dtype=float)
self.original_idx: IntVec = np.zeros(nelm, dtype=int)
+ self._any_pf_control = False
+
def size(self) -> int:
"""
Get size of the structure
@@ -169,7 +170,11 @@ def slice(self, elm_idx: IntVec, bus_idx: IntVec) -> "BranchData":
data.conn = self.conn[elm_idx] # winding connection
- data.control_mode = self.control_mode[elm_idx]
+ data.tap_phase_control_mode = self.tap_phase_control_mode[elm_idx]
+ data.tap_module_control_mode = self.tap_module_control_mode[elm_idx]
+ data.tap_controlled_buses = self.tap_controlled_buses[elm_idx]
+ data.is_converter = self.is_converter[elm_idx]
+
data.contingency_enabled = self.contingency_enabled[elm_idx]
data.monitor_loading = self.monitor_loading[elm_idx]
@@ -186,11 +191,9 @@ def slice(self, elm_idx: IntVec, bus_idx: IntVec) -> "BranchData":
data.tap_angle_max = self.tap_angle_max[elm_idx]
data.Beq = self.Beq[elm_idx]
data.G0sw = self.G0sw[elm_idx]
- data.Pfset = self.Pfset[elm_idx]
- data.Qfset = self.Qfset[elm_idx]
- data.Qtset = self.Qtset[elm_idx]
- data.vf_set = self.vf_set[elm_idx]
- data.vt_set = self.vt_set[elm_idx]
+ data.Pset = self.Pset[elm_idx]
+ data.Qset = self.Qset[elm_idx]
+ data.vset = self.vset[elm_idx]
data.C_branch_bus_f = self.C_branch_bus_f[np.ix_(elm_idx, bus_idx)]
data.C_branch_bus_t = self.C_branch_bus_t[np.ix_(elm_idx, bus_idx)]
@@ -198,13 +201,8 @@ def slice(self, elm_idx: IntVec, bus_idx: IntVec) -> "BranchData":
# first slice, then remap
data.F = self.F[elm_idx]
data.T = self.T[elm_idx]
- data.ctrl_bus1 = self.ctrl_bus1[elm_idx]
- data.ctrl_bus2 = self.ctrl_bus2[elm_idx]
bus_map: Dict[int, int] = {o: i for i, o in enumerate(bus_idx)}
for k in range(data.nelm):
- if data.control_mode[k] != TransformerControlType.fixed:
- data.ctrl_bus1[k] = bus_map[data.ctrl_bus1[k]]
- data.ctrl_bus2[k] = bus_map[data.ctrl_bus2[k]]
data.F[k] = bus_map[data.F[k]]
data.T[k] = bus_map[data.T[k]]
@@ -212,6 +210,8 @@ def slice(self, elm_idx: IntVec, bus_idx: IntVec) -> "BranchData":
data.original_idx = elm_idx
+ data._any_pf_control = self._any_pf_control
+
return data
def copy(self) -> "BranchData":
@@ -255,7 +255,11 @@ def copy(self) -> "BranchData":
data.conn = self.conn.copy() # winding connection
- data.control_mode = self.control_mode.copy()
+ data.tap_phase_control_mode = self.tap_phase_control_mode.copy()
+ data.tap_module_control_mode = self.tap_module_control_mode.copy()
+ data.tap_controlled_buses = self.tap_controlled_buses.copy()
+ data.is_converter = self.is_converter.copy()
+
data.contingency_enabled = self.contingency_enabled.copy()
data.monitor_loading = self.monitor_loading.copy()
@@ -272,11 +276,9 @@ def copy(self) -> "BranchData":
data.tap_angle_max = self.tap_angle_max.copy()
data.Beq = self.Beq.copy()
data.G0sw = self.G0sw.copy()
- data.Pfset = self.Pfset.copy()
- data.Qfset = self.Qfset.copy()
- data.Qtset = self.Qtset.copy()
- data.vf_set = self.vf_set.copy()
- data.vt_set = self.vt_set.copy()
+ data.Pset = self.Pset.copy()
+ data.Qset = self.Qset.copy()
+ data.vset = self.vset.copy()
data.C_branch_bus_f = self.C_branch_bus_f.copy()
data.C_branch_bus_t = self.C_branch_bus_t.copy()
@@ -288,6 +290,8 @@ def copy(self) -> "BranchData":
data.original_idx = self.original_idx.copy()
+ data._any_pf_control = self._any_pf_control
+
return data
def get_island(self, bus_idx: Vec) -> IntVec:
@@ -317,6 +321,13 @@ def get_dc_indices(self) -> IntVec:
"""
return np.where(self.dc != 0)[0]
+ def get_series_admittance(self) -> CxVec:
+ """
+
+ :return:
+ """
+ return 1.0 / (self.R + 1.0j * self.X)
+
def get_linear_series_admittance(self) -> Vec:
"""
Get the linear version of the series admittance for ACDC systems
@@ -390,5 +401,13 @@ def to_df(self) -> pd.DataFrame:
}
return pd.DataFrame(data=data)
+ @property
+ def tap(self) -> CxVec:
+ """
+
+ :return:
+ """
+ return self.tap_module * np.exp(1.0j * self.tap_angle)
+
def __len__(self) -> int:
return self.nelm
diff --git a/src/GridCalEngine/DataStructures/numerical_circuit.py b/src/GridCalEngine/DataStructures/numerical_circuit.py
index 1ea00e9c8..3543ea9cc 100644
--- a/src/GridCalEngine/DataStructures/numerical_circuit.py
+++ b/src/GridCalEngine/DataStructures/numerical_circuit.py
@@ -23,11 +23,10 @@
from GridCalEngine.basic_structures import Logger
from GridCalEngine.Devices.multi_circuit import MultiCircuit
from GridCalEngine.basic_structures import Vec, IntVec, CxVec
-from GridCalEngine.enumerations import BranchImpedanceMode
+from GridCalEngine.enumerations import BranchImpedanceMode, BusMode
import GridCalEngine.Topology.topology as tp
import GridCalEngine.Topology.simulation_indices as si
-from GridCalEngine.Utils.NumericalMethods.sparse_solve import get_sparse_type
import GridCalEngine.Compilers.circuit_to_data as gc_compiler2
import GridCalEngine.Topology.admittance_matrices as ycalc
import GridCalEngine.DataStructures as ds
@@ -39,8 +38,6 @@
if TYPE_CHECKING: # Only imports the below statements during type checking
from GridCalEngine.Simulations.OPF.opf_results import OptimalPowerFlowResults
-sparse_type = get_sparse_type()
-
ALL_STRUCTS = Union[
ds.BusData,
ds.GeneratorData,
@@ -141,46 +138,72 @@ class NumericalCircuit:
"""
Class storing the calculation information of the devices
"""
- available_structures = [
- 'Vbus',
- 'Sbus',
- 'Ibus',
- 'Ybus',
- 'G',
- 'B',
- 'Yf',
- 'Yt',
- 'Bbus',
- 'Bf',
- 'Cf',
- 'Ct',
- 'Yshunt',
- 'Yseries',
- "B'",
- "B''",
- 'Types',
- 'Jacobian',
- 'Qmin',
- 'Qmax',
- 'pq',
- 'pqv',
- 'p',
- 'pv',
- 'vd',
- 'pqpv',
- 'tap_f',
- 'tap_t',
- 'k_pf_tau',
- 'k_qf_m',
- 'k_zero_beq',
- 'k_vf_beq',
- 'k_vt_m',
- 'k_qt_m',
- 'k_pf_dp',
- 'i_vsc',
- 'i_vf_beq',
- 'i_vt_m'
- ]
+ available_structures = {
+ "Bus arrays": [
+ 'V', 'Va', 'Vm',
+ 'S', 'P', 'Q',
+ 'I',
+ 'Y',
+ 'Qmin',
+ 'Qmax',
+ ],
+ "Bus indices": [
+ 'Types',
+ 'bus_ctrl',
+ 'pq',
+ 'pqv',
+ 'p',
+ 'pv',
+ 'vd'
+ ],
+ "Branch arrays": [
+ 'tap_f',
+ 'tap_t',
+ 'Pf_set',
+ 'Qf_set',
+ 'Pt_set',
+ 'Qt_set',
+ ],
+ "Branch indices": [
+ 'branch_ctrl',
+ 'k_pf_tau',
+ 'k_pt_tau',
+ 'k_qf_m',
+ 'k_qt_m',
+ 'k_qf_beq',
+ 'k_v_m',
+ 'k_v_beq',
+ ],
+ "System matrices": [
+ 'Ybus',
+ 'G',
+ 'B',
+ 'Yf',
+ 'Yt',
+ 'Bbus',
+ 'Bf',
+ 'Cf',
+ 'Ct',
+ "B'",
+ "B''",
+ 'Yshunt',
+ 'Yseries',
+ ],
+ "Power flow arrays": [
+ 'idx_dPf',
+ 'idx_dQf',
+ 'idx_dPt',
+ 'idx_dQt',
+ 'idx_dVa',
+ 'idx_dVm',
+ 'idx_dm',
+ 'idx_dtau',
+ 'idx_dbeq',
+ 'x',
+ 'f(x)',
+ 'Jacobian',
+ ]
+ }
def __init__(self,
nbus: int,
@@ -777,7 +800,7 @@ def branch_rates(self):
@property
def ac_indices(self):
"""
- Array of indices of the AC Branches
+ Array of indices of the AC buses
:return: array of indices
"""
if self.simulation_indices_ is None:
@@ -788,7 +811,7 @@ def ac_indices(self):
@property
def dc_indices(self):
"""
- Array of indices of the DC Branches
+ Array of indices of the DC buses
:return: array of indices
"""
if self.simulation_indices_ is None:
@@ -838,10 +861,13 @@ def get_simulation_indices(self) -> si.SimulationIndices:
"""
return si.SimulationIndices(bus_types=self.bus_data.bus_types,
Pbus=self.Sbus.real,
- control_mode=self.branch_data.control_mode,
+ tap_module_control_mode=self.branch_data.tap_module_control_mode,
+ tap_phase_control_mode=self.branch_data.tap_phase_control_mode,
+ tap_controlled_buses=self.branch_data.tap_controlled_buses,
+ is_converter=self.branch_data.is_converter,
F=self.branch_data.F,
T=self.branch_data.T,
- dc=self.bus_data.is_dc)
+ is_dc_bus=self.bus_data.is_dc)
def get_connectivity_matrices(self) -> tp.ConnectivityMatrices:
"""
@@ -874,11 +900,7 @@ def get_admittance_matrices(self) -> ycalc.AdmittanceMatrices:
Beq=self.branch_data.Beq,
Cf=self.Cf,
Ct=self.Ct,
- G0sw=self.branch_data.G0sw,
- If=np.zeros(len(self.branch_data)),
- a=self.branch_data.a,
- b=self.branch_data.b,
- c=self.branch_data.c,
+ Gsw=self.branch_data.G0sw,
Yshunt_bus=self.Yshunt_from_devices,
conn=self.branch_data.conn,
seq=1,
@@ -905,9 +927,9 @@ def get_series_admittance_matrices(self) -> ycalc.SeriesAdmittanceMatrices:
Ct=self.Ct,
G0sw=self.branch_data.G0sw,
If=np.zeros(len(self.branch_data)),
- a=self.branch_data.a,
- b=self.branch_data.b,
- c=self.branch_data.c,
+ a=self.branch_data.alpha1,
+ b=self.branch_data.alpha2,
+ c=self.branch_data.alpha3,
Yshunt_bus=self.Yshunt_from_devices,
)
@@ -920,8 +942,8 @@ def get_fast_decoupled_amittances(self) -> ycalc.FastDecoupledAdmittanceMatrices
X=self.branch_data.X,
B=self.branch_data.B,
tap_module=self.branch_data.tap_module,
- vtap_f=self.branch_data.vf_set,
- vtap_t=self.branch_data.vt_set,
+ vtap_f=self.branch_data.virtual_tap_f,
+ vtap_t=self.branch_data.virtual_tap_t,
Cf=self.Cf,
Ct=self.Ct,
)
@@ -954,7 +976,7 @@ def Ybus(self):
if self.admittances_ is None:
self.admittances_ = self.get_admittance_matrices()
- return self.admittances_.Ybus
+ return self.admittances_.Ybus.tocsc()
@property
def Yf(self):
@@ -1140,10 +1162,7 @@ def any_control(self):
:return:
"""
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.any_control
+ return self.branch_data._any_pf_control
@property
def k_pf_tau(self):
@@ -1157,70 +1176,26 @@ def k_pf_tau(self):
return self.simulation_indices_.k_pf_tau
@property
- def k_qf_m(self):
+ def k_qf_beq(self):
"""
- Get k_qf_m
+ Get k_qf_beq
:return:
"""
if self.simulation_indices_ is None:
self.simulation_indices_ = self.get_simulation_indices()
- return self.simulation_indices_.k_qf_m
+ return self.simulation_indices_.k_qf_beq
@property
- def k_zero_beq(self):
+ def k_v_m(self):
"""
- Get k_zero_beq
+ Get k_v_m
:return:
"""
if self.simulation_indices_ is None:
self.simulation_indices_ = self.get_simulation_indices()
- return self.simulation_indices_.k_zero_beq
-
- @property
- def k_vf_beq(self):
- """
- Get k_vf_beq
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.k_vf_beq
-
- @property
- def k_vt_m(self):
- """
- Get k_vt_m
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.k_vt_m
-
- @property
- def k_qt_m(self):
- """
- Get k_qt_m
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.k_qt_m
-
- @property
- def k_pf_dp(self):
- """
- Get k_pf_dp
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.k_pf_dp
+ return self.simulation_indices_.k_v_m
@property
def k_m(self):
@@ -1255,83 +1230,6 @@ def k_mtau(self):
return self.simulation_indices_.k_mtau
- @property
- def i_m(self):
- """
- Get i_m
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.i_m
-
- @property
- def i_tau(self):
- """
- Get i_tau
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.i_tau
-
- @property
- def i_mtau(self):
- """
- Get i_mtau
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.i_mtau
-
- @property
- def iPfdp_va(self):
- """
- Get iPfdp_va
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.iPfdp_va
-
- @property
- def i_vsc(self):
- """
- Get i_vsc
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.i_vsc
-
- @property
- def i_vf_beq(self):
- """
- Get i_vf_beq
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.i_vf_beq
-
- @property
- def i_vt_m(self):
- """
- Get i_vt_m
- :return:
- """
- if self.simulation_indices_ is None:
- self.simulation_indices_ = self.get_simulation_indices()
-
- return self.simulation_indices_.i_vt_m
-
@property
def structs_dict(self):
"""
@@ -1467,27 +1365,85 @@ def get_structure(self, structure_type: str) -> pd.DataFrame:
:return: pandas DataFrame
"""
- if structure_type == 'Vbus':
+ if self.simulation_indices_ is None:
+ self.simulation_indices_ = self.get_simulation_indices()
+
+ # idx_dm = np.r_[self.simulation_indices_.k_v_m, self.simulation_indices_.k_qf_m, self.simulation_indices_.k_qt_m]
+ # idx_dtau = np.r_[self.simulation_indices_.k_pf_tau, self.simulation_indices_.k_pt_tau]
+ # idx_dbeq = self.simulation_indices_.k_qf_beq
+ # idx_dPf = self.simulation_indices_.k_pf_tau
+ # idx_dQf = np.r_[self.simulation_indices_.k_qf_m, self.simulation_indices_.k_qf_beq]
+ # idx_dPt = self.simulation_indices_.k_pt_tau
+ # idx_dQt = self.simulation_indices_.k_qt_m
+
+ from GridCalEngine.Simulations.PowerFlow.NumericalMethods.pf_advanced_formulation import (
+ PfAdvancedFormulation)
+ from GridCalEngine.Simulations.PowerFlow.power_flow_options import PowerFlowOptions
+
+ formulation = PfAdvancedFormulation(V0=self.Vbus,
+ S0=self.Sbus,
+ I0=self.Ibus,
+ Y0=self.YLoadBus,
+ Qmin=self.Qmin_bus,
+ Qmax=self.Qmax_bus,
+ nc=self,
+ options=PowerFlowOptions(),
+ logger=Logger())
+
+ if structure_type == 'V':
df = pd.DataFrame(
data=self.Vbus,
columns=['Voltage (p.u.)'],
index=self.bus_data.names,
)
- elif structure_type == 'Sbus':
+ elif structure_type == 'Va':
+ df = pd.DataFrame(
+ data=np.angle(self.Vbus),
+ columns=['Voltage angles (rad)'],
+ index=self.bus_data.names,
+ )
+ elif structure_type == 'Vm':
+ df = pd.DataFrame(
+ data=np.abs(self.Vbus),
+ columns=['Voltage modules (p.u.)'],
+ index=self.bus_data.names,
+ )
+ elif structure_type == 'S':
df = pd.DataFrame(
data=self.Sbus,
columns=['Power (p.u.)'],
index=self.bus_data.names,
)
- elif structure_type == 'Ibus':
+ elif structure_type == 'P':
+ df = pd.DataFrame(
+ data=self.Sbus.real,
+ columns=['Power (p.u.)'],
+ index=self.bus_data.names,
+ )
+
+ elif structure_type == 'Q':
+ df = pd.DataFrame(
+ data=self.Sbus.imag,
+ columns=['Power (p.u.)'],
+ index=self.bus_data.names,
+ )
+
+ elif structure_type == 'I':
df = pd.DataFrame(
data=self.Ibus,
columns=['Current (p.u.)'],
index=self.bus_data.names,
)
+ elif structure_type == 'Y':
+ df = pd.DataFrame(
+ data=self.YLoadBus,
+ columns=['Admittance (p.u.)'],
+ index=self.bus_data.names,
+ )
+
elif structure_type == 'Ybus':
df = pd.DataFrame(
data=self.Ybus.toarray(),
@@ -1602,88 +1558,23 @@ def get_structure(self, structure_type: str) -> pd.DataFrame:
index=self.bus_data.names,
)
- elif structure_type == 'Jacobian':
-
- from GridCalEngine.Simulations.PowerFlow.NumericalMethods.acdc_jacobian import fubm_jacobian
-
- pvpq = np.r_[self.pv, self.pq]
-
- cols = ['1) dVa {0}'.format(i) for i in pvpq]
- cols += ['2) dVm {0}'.format(i) for i in self.pq]
- cols += ['3) dPfsh {0}'.format(i) for i in self.k_pf_tau]
- cols += ['4) dQfma {0}'.format(i) for i in self.k_qf_m]
- cols += ['5) dBeqz {0}'.format(i) for i in self.k_zero_beq]
- cols += ['6) dBeqv {0}'.format(i) for i in self.k_vf_beq]
- cols += ['7) dVtma {0}'.format(i) for i in self.k_vt_m]
- cols += ['8) dQtma {0}'.format(i) for i in self.k_qt_m]
- cols += ['9) dPfdp {0}'.format(i) for i in self.k_pf_dp]
-
- rows = ['1) dP {0}'.format(i) for i in pvpq]
- rows += ['2) dQ {0}'.format(i) for i in self.pq]
- rows += ['3) dQ {0}'.format(i) for i in self.k_vf_beq]
- rows += ['4) dQ {0}'.format(i) for i in self.k_vt_m]
- rows += ['5) dPf {0}'.format(i) for i in self.k_pf_tau]
- rows += ['6) dQf {0}'.format(i) for i in self.k_qf_m]
- rows += ['7) dQf {0}'.format(i) for i in self.k_zero_beq]
- rows += ['8) dQt {0}'.format(i) for i in self.k_qt_m]
- rows += ['9) dPfdp {0}'.format(i) for i in self.k_pf_dp]
-
- # compute admittances
- Ys = 1.0 / (self.branch_data.R + 1j * self.branch_data.X)
- Ybus, Yf, Yt, tap = ycalc.compile_y_acdc(
- Cf=self.Cf,
- Ct=self.Ct,
- C_bus_shunt=self.shunt_data.C_bus_elm.tocsc(),
- shunt_admittance=self.shunt_data.Y,
- shunt_active=self.shunt_data.active,
- ys=Ys,
- B=self.branch_data.B,
- Sbase=self.Sbase,
- tap_module=self.branch_data.tap_module,
- tap_angle=self.branch_data.tap_angle,
- Beq=self.branch_data.Beq,
- Gsw=self.branch_data.G0sw,
- virtual_tap_from=self.branch_data.virtual_tap_f,
- virtual_tap_to=self.branch_data.virtual_tap_t,
- )
-
- J = fubm_jacobian(
- nb=self.nbus,
- nl=self.nbr,
- k_pf_tau=self.k_pf_tau,
- k_pf_dp=self.k_pf_dp,
- k_qf_m=self.k_qf_m,
- k_qt_m=self.k_qt_m,
- k_vt_m=self.k_vt_m,
- k_zero_beq=self.k_zero_beq,
- k_vf_beq=self.k_vf_beq,
- i_vf_beq=self.i_vf_beq,
- i_vt_m=self.i_vt_m,
- F=self.F,
- T=self.T,
- Ys=Ys,
- k2=self.branch_data.k,
- complex_tap=tap,
- tap_modules=self.branch_data.tap_module,
- Bc=self.branch_data.B,
- Beq=self.branch_data.Beq,
- Kdp=self.branch_data.Kdp,
- V=self.Vbus,
- Ybus=Ybus.tocsc(),
- Yf=Yf.tocsc(),
- Yt=Yt.tocsc(),
- Cf=self.Cf.tocsc(),
- Ct=self.Ct.tocsc(),
- pvpq=pvpq,
- pq=self.pq,
+ elif structure_type == 'x':
+ df = pd.DataFrame(
+ data=formulation.var2x(),
+ columns=['x'],
+ index=formulation.get_x_names(),
)
+ elif structure_type == 'f(x)':
df = pd.DataFrame(
- data=J.toarray(),
- columns=cols,
- index=rows,
+ data=formulation.fx(),
+ columns=['f(x)'],
+ index=formulation.get_fx_names(),
)
+ elif structure_type == 'Jacobian':
+ df = formulation.get_jacobian_df(autodiff=False)
+
elif structure_type == 'Qmin':
df = pd.DataFrame(
data=self.Qmin_bus,
@@ -1698,44 +1589,70 @@ def get_structure(self, structure_type: str) -> pd.DataFrame:
index=self.bus_data.names,
)
+ elif structure_type == 'bus_ctrl':
+ data1 = [BusMode.as_str(val) for val in self.bus_data.bus_types]
+
+ df = pd.DataFrame(
+ data=data1,
+ columns=['bus_ctrl'],
+ index=self.bus_data.names,
+ )
+
+ elif structure_type == 'branch_ctrl':
+
+ data1 = [val.value if val != 0 else "-" for val in self.branch_data.tap_module_control_mode]
+ data2 = [val.value if val != 0 else "-" for val in self.branch_data.tap_phase_control_mode]
+
+ df = pd.DataFrame(
+ data=np.c_[
+ self.branch_data.F,
+ self.branch_data.T,
+ self.branch_data.tap_controlled_buses,
+ data1,
+ data2
+ ],
+ columns=['bus F', 'bus T', 'V ctrl bus', 'm control', 'tau control'],
+ index=[f"{k}) {name}" for k, name in enumerate(self.branch_data.names)],
+ )
+
elif structure_type == 'pq':
df = pd.DataFrame(
- data=self.pq,
+ data=self.pq.astype(int).astype(str),
columns=['pq'],
index=self.bus_data.names[self.pq],
)
elif structure_type == 'pv':
df = pd.DataFrame(
- data=self.pv,
+ data=self.pv.astype(int).astype(str),
columns=['pv'],
index=self.bus_data.names[self.pv],
)
elif structure_type == 'pqv':
df = pd.DataFrame(
- data=self.pqv,
+ data=self.pqv.astype(int).astype(str),
columns=['pqv'],
index=self.bus_data.names[self.pqv],
)
elif structure_type == 'p':
df = pd.DataFrame(
- data=self.p,
+ data=self.p.astype(int).astype(str),
columns=['p'],
index=self.bus_data.names[self.p],
)
elif structure_type == 'vd':
df = pd.DataFrame(
- data=self.vd,
+ data=self.vd.astype(int).astype(str),
columns=['vd'],
index=self.bus_data.names[self.vd],
)
elif structure_type == 'pqpv':
df = pd.DataFrame(
- data=self.pqpv,
+ data=self.pqpv.astype(int).astype(str),
columns=['pqpv'],
index=self.bus_data.names[self.pqpv],
)
@@ -1756,72 +1673,140 @@ def get_structure(self, structure_type: str) -> pd.DataFrame:
elif structure_type == 'k_pf_tau':
df = pd.DataFrame(
- data=self.k_pf_tau,
+ data=self.simulation_indices_.k_pf_tau.astype(int).astype(str),
columns=['k_pf_tau'],
- index=self.branch_data.names[self.k_pf_tau],
+ index=self.branch_data.names[self.simulation_indices_.k_pf_tau],
+ )
+
+ elif structure_type == 'k_pt_tau':
+ df = pd.DataFrame(
+ data=self.simulation_indices_.k_pt_tau.astype(int).astype(str),
+ columns=['k_pt_tau'],
+ index=self.branch_data.names[self.simulation_indices_.k_pt_tau],
)
elif structure_type == 'k_qf_m':
df = pd.DataFrame(
- data=self.k_qf_m,
+ data=self.simulation_indices_.k_qf_m.astype(int).astype(str),
columns=['k_qf_m'],
- index=self.branch_data.names[self.k_qf_m],
+ index=self.branch_data.names[self.simulation_indices_.k_qf_m],
+ )
+
+ elif structure_type == 'k_qt_m':
+ df = pd.DataFrame(
+ data=self.simulation_indices_.k_qt_m.astype(int).astype(str),
+ columns=['k_qt_m'],
+ index=self.branch_data.names[self.simulation_indices_.k_qt_m],
)
- elif structure_type == 'k_zero_beq':
+ elif structure_type == 'k_qf_beq':
df = pd.DataFrame(
- data=self.k_zero_beq,
- columns=['k_zero_beq'],
- index=self.branch_data.names[self.k_zero_beq],
+ data=self.simulation_indices_.k_qf_beq.astype(int).astype(str),
+ columns=['k_qf_beq'],
+ index=self.branch_data.names[self.simulation_indices_.k_qf_beq],
)
- elif structure_type == 'k_vf_beq':
+ elif structure_type == 'k_v_m':
df = pd.DataFrame(
- data=self.k_vf_beq,
- columns=['k_vf_beq'],
- index=self.branch_data.names[self.k_vf_beq],
+ data=self.simulation_indices_.k_v_m.astype(int).astype(str),
+ columns=['k_v_m'],
+ index=self.branch_data.names[self.simulation_indices_.k_v_m],
+ )
+ elif structure_type == 'k_v_beq':
+ df = pd.DataFrame(
+ data=self.simulation_indices_.k_v_beq.astype(int).astype(str),
+ columns=['k_v_beq'],
+ index=self.branch_data.names[self.simulation_indices_.k_v_beq],
+ )
+ elif structure_type == 'idx_dPf':
+ df = pd.DataFrame(
+ data=formulation.idx_dPf.astype(int).astype(str),
+ columns=['idx_dPf'],
+ index=self.branch_data.names[formulation.idx_dPf],
)
- elif structure_type == 'k_vt_m':
+ elif structure_type == 'idx_dQf':
df = pd.DataFrame(
- data=self.k_vt_m,
- columns=['k_vt_m'],
- index=self.branch_data.names[self.k_vt_m],
+ data=formulation.idx_dQf.astype(int).astype(str),
+ columns=['idx_dQf'],
+ index=self.branch_data.names[formulation.idx_dQf],
)
- elif structure_type == 'k_qt_m':
+ elif structure_type == 'idx_dPt':
df = pd.DataFrame(
- data=self.k_qt_m,
- columns=['k_qt_m'],
- index=self.branch_data.names[self.k_qt_m],
+ data=formulation.idx_dPt.astype(int).astype(str),
+ columns=['idx_dPt'],
+ index=self.branch_data.names[formulation.idx_dPt],
+ )
+
+ elif structure_type == 'idx_dQt':
+ df = pd.DataFrame(
+ data=formulation.idx_dQt.astype(int).astype(str),
+ columns=['idx_dQt'],
+ index=self.branch_data.names[formulation.idx_dQt],
+ )
+
+ elif structure_type == 'idx_dVa':
+ df = pd.DataFrame(
+ data=formulation.idx_dVa.astype(int).astype(str),
+ columns=['idx_dVa'],
+ index=self.bus_data.names[formulation.idx_dVa],
+ )
+
+ elif structure_type == 'idx_dVm':
+ df = pd.DataFrame(
+ data=formulation.idx_dVm.astype(int).astype(str),
+ columns=['idx_dVm'],
+ index=self.bus_data.names[formulation.idx_dVm],
+ )
+
+ elif structure_type == 'idx_dm':
+ df = pd.DataFrame(
+ data=formulation.idx_dm.astype(int).astype(str),
+ columns=['idx_dm'],
+ index=self.branch_data.names[formulation.idx_dm],
+ )
+
+ elif structure_type == 'idx_dtau':
+ df = pd.DataFrame(
+ data=formulation.idx_dtau.astype(int).astype(str),
+ columns=['idx_dtau'],
+ index=self.branch_data.names[formulation.idx_dtau],
+ )
+
+ elif structure_type == 'idx_dbeq':
+ df = pd.DataFrame(
+ data=formulation.idx_dbeq.astype(int).astype(str),
+ columns=['idx_dbeq'],
+ index=self.branch_data.names[formulation.idx_dbeq],
)
- elif structure_type == 'k_pf_dp':
+ elif structure_type == 'Pf_set':
df = pd.DataFrame(
- data=self.k_pf_dp,
- columns=['k_pf_dp'],
- index=self.branch_data.names[self.k_pf_dp],
+ data=self.branch_data.Pset[formulation.idx_dPf],
+ columns=['Pf_set'],
+ index=self.branch_data.names[formulation.idx_dPf],
)
- elif structure_type == 'i_vsc':
+ elif structure_type == 'Pt_set':
df = pd.DataFrame(
- data=self.i_vsc,
- columns=['i_vsc'],
- index=self.branch_data.names[self.i_vsc],
+ data=self.branch_data.Pset[formulation.idx_dPt],
+ columns=['Pt_set'],
+ index=self.branch_data.names[formulation.idx_dPt],
)
- elif structure_type == 'i_vf_beq':
+ elif structure_type == 'Qf_set':
df = pd.DataFrame(
- data=self.i_vf_beq,
- columns=['i_vf_beq'],
- index=self.bus_data.names[self.i_vf_beq],
+ data=self.branch_data.Qset[formulation.idx_dQf],
+ columns=['Qf_set'],
+ index=self.branch_data.names[formulation.idx_dQf],
)
- elif structure_type == 'i_vt_m':
+ elif structure_type == 'Qt_set':
df = pd.DataFrame(
- data=self.i_vt_m,
- columns=['i_vt_m'],
- index=self.bus_data.names[self.i_vt_m],
+ data=self.branch_data.Qset[formulation.idx_dQt],
+ columns=['Qt_set'],
+ index=self.branch_data.names[formulation.idx_dQt],
)
else:
@@ -2034,6 +2019,9 @@ def compile_numerical_circuit_at(circuit: MultiCircuit,
use_stored_guess=False,
bus_dict: Union[Dict[Bus, int], None] = None,
areas_dict: Union[Dict[Area, int], None] = None,
+ control_taps_modules: bool = True,
+ control_taps_phase: bool = True,
+ control_remote_voltage: bool = True,
logger=Logger()) -> NumericalCircuit:
"""
Compile a NumericalCircuit from a MultiCircuit
@@ -2045,6 +2033,9 @@ def compile_numerical_circuit_at(circuit: MultiCircuit,
:param use_stored_guess: use the storage voltage guess?
:param bus_dict (optional) Dict[Bus, int] dictionary
:param areas_dict (optional) Dict[Area, int] dictionary
+ :param control_taps_modules: control taps modules?
+ :param control_taps_phase: control taps phase?
+ :param control_remote_voltage: control remote voltage?
:param logger: Logger instance
:return: NumericalCircuit instance
"""
@@ -2059,20 +2050,22 @@ def compile_numerical_circuit_at(circuit: MultiCircuit,
bus_voltage_used = np.zeros(circuit.get_bus_number(), dtype=bool)
# declare the numerical circuit
- nc = NumericalCircuit(nbus=0,
- nbr=0,
- nhvdc=0,
- nload=0,
- ngen=0,
- nbatt=0,
- nshunt=0,
- nfluidnode=0,
- nfluidturbine=0,
- nfluidpump=0,
- nfluidp2x=0,
- nfluidpath=0,
- sbase=circuit.Sbase,
- t_idx=t_idx)
+ nc = NumericalCircuit(
+ nbus=0,
+ nbr=0,
+ nhvdc=0,
+ nload=0,
+ ngen=0,
+ nbatt=0,
+ nshunt=0,
+ nfluidnode=0,
+ nfluidturbine=0,
+ nfluidpump=0,
+ nfluidp2x=0,
+ nfluidpath=0,
+ sbase=circuit.Sbase,
+ t_idx=t_idx
+ )
if bus_dict is None:
bus_dict = {bus: i for i, bus in enumerate(circuit.buses)}
@@ -2080,96 +2073,126 @@ def compile_numerical_circuit_at(circuit: MultiCircuit,
if areas_dict is None:
areas_dict = {elm: i for i, elm in enumerate(circuit.areas)}
- nc.bus_data = gc_compiler2.get_bus_data(circuit=circuit,
- t_idx=t_idx,
- time_series=time_series,
- areas_dict=areas_dict,
- use_stored_guess=use_stored_guess)
-
- nc.generator_data, gen_dict = gc_compiler2.get_generator_data(circuit=circuit,
- bus_dict=bus_dict,
- bus_data=nc.bus_data,
- t_idx=t_idx,
- time_series=time_series,
- bus_voltage_used=bus_voltage_used,
- logger=logger,
- opf_results=opf_results,
- use_stored_guess=use_stored_guess)
-
- nc.battery_data = gc_compiler2.get_battery_data(circuit=circuit,
- bus_dict=bus_dict,
- bus_data=nc.bus_data,
- t_idx=t_idx,
- time_series=time_series,
- bus_voltage_used=bus_voltage_used,
- logger=logger,
- opf_results=opf_results,
- use_stored_guess=use_stored_guess)
-
- nc.shunt_data = gc_compiler2.get_shunt_data(circuit=circuit,
- bus_dict=bus_dict,
- bus_voltage_used=bus_voltage_used,
- bus_data=nc.bus_data,
- t_idx=t_idx,
- time_series=time_series,
- logger=logger,
- use_stored_guess=use_stored_guess)
-
- nc.load_data = gc_compiler2.get_load_data(circuit=circuit,
- bus_dict=bus_dict,
- bus_voltage_used=bus_voltage_used,
- bus_data=nc.bus_data,
- logger=logger,
- t_idx=t_idx,
- time_series=time_series,
- opf_results=opf_results,
- use_stored_guess=use_stored_guess)
-
- nc.branch_data = gc_compiler2.get_branch_data(circuit=circuit,
- t_idx=t_idx,
- time_series=time_series,
- bus_dict=bus_dict,
- bus_data=nc.bus_data,
- bus_voltage_used=bus_voltage_used,
- apply_temperature=apply_temperature,
- branch_tolerance_mode=branch_tolerance_mode,
- opf_results=opf_results,
- use_stored_guess=use_stored_guess)
-
- nc.hvdc_data = gc_compiler2.get_hvdc_data(circuit=circuit,
- t_idx=t_idx,
- time_series=time_series,
- bus_dict=bus_dict,
- bus_types=nc.bus_data.bus_types,
- bus_data=nc.bus_data,
- bus_voltage_used=bus_voltage_used,
- opf_results=opf_results,
- use_stored_guess=use_stored_guess,
- logger=logger)
+ nc.bus_data = gc_compiler2.get_bus_data(
+ circuit=circuit,
+ t_idx=t_idx,
+ time_series=time_series,
+ areas_dict=areas_dict,
+ use_stored_guess=use_stored_guess
+ )
+
+ nc.generator_data, gen_dict = gc_compiler2.get_generator_data(
+ circuit=circuit,
+ bus_dict=bus_dict,
+ bus_data=nc.bus_data,
+ t_idx=t_idx,
+ time_series=time_series,
+ bus_voltage_used=bus_voltage_used,
+ logger=logger,
+ opf_results=opf_results,
+ use_stored_guess=use_stored_guess,
+ control_remote_voltage=control_remote_voltage
+ )
+
+ nc.battery_data = gc_compiler2.get_battery_data(
+ circuit=circuit,
+ bus_dict=bus_dict,
+ bus_data=nc.bus_data,
+ t_idx=t_idx,
+ time_series=time_series,
+ bus_voltage_used=bus_voltage_used,
+ logger=logger,
+ opf_results=opf_results,
+ use_stored_guess=use_stored_guess,
+ control_remote_voltage=control_remote_voltage
+ )
+
+ nc.shunt_data = gc_compiler2.get_shunt_data(
+ circuit=circuit,
+ bus_dict=bus_dict,
+ bus_voltage_used=bus_voltage_used,
+ bus_data=nc.bus_data,
+ t_idx=t_idx,
+ time_series=time_series,
+ logger=logger,
+ use_stored_guess=use_stored_guess,
+ control_remote_voltage=control_remote_voltage
+ )
+
+ nc.load_data = gc_compiler2.get_load_data(
+ circuit=circuit,
+ bus_dict=bus_dict,
+ bus_voltage_used=bus_voltage_used,
+ bus_data=nc.bus_data,
+ logger=logger,
+ t_idx=t_idx,
+ time_series=time_series,
+ opf_results=opf_results,
+ use_stored_guess=use_stored_guess
+ )
+
+ nc.branch_data = gc_compiler2.get_branch_data(
+ circuit=circuit,
+ t_idx=t_idx,
+ time_series=time_series,
+ bus_dict=bus_dict,
+ bus_data=nc.bus_data,
+ bus_voltage_used=bus_voltage_used,
+ apply_temperature=apply_temperature,
+ branch_tolerance_mode=branch_tolerance_mode,
+ opf_results=opf_results,
+ use_stored_guess=use_stored_guess,
+ control_taps_modules=control_taps_modules,
+ control_taps_phase=control_taps_phase,
+ control_remote_voltage=control_remote_voltage,
+ )
+
+ nc.hvdc_data = gc_compiler2.get_hvdc_data(
+ circuit=circuit,
+ t_idx=t_idx,
+ time_series=time_series,
+ bus_dict=bus_dict,
+ bus_types=nc.bus_data.bus_types,
+ bus_data=nc.bus_data,
+ bus_voltage_used=bus_voltage_used,
+ opf_results=opf_results,
+ use_stored_guess=use_stored_guess,
+ logger=logger
+ )
if len(circuit.fluid_nodes) > 0:
- nc.fluid_node_data, plant_dict = gc_compiler2.get_fluid_node_data(circuit=circuit,
- t_idx=t_idx,
- time_series=time_series)
-
- nc.fluid_turbine_data = gc_compiler2.get_fluid_turbine_data(circuit=circuit,
- plant_dict=plant_dict,
- gen_dict=gen_dict,
- t_idx=t_idx)
-
- nc.fluid_pump_data = gc_compiler2.get_fluid_pump_data(circuit=circuit,
- plant_dict=plant_dict,
- gen_dict=gen_dict,
- t_idx=t_idx)
-
- nc.fluid_p2x_data = gc_compiler2.get_fluid_p2x_data(circuit=circuit,
- plant_dict=plant_dict,
- gen_dict=gen_dict,
- t_idx=t_idx)
-
- nc.fluid_path_data = gc_compiler2.get_fluid_path_data(circuit=circuit,
- plant_dict=plant_dict,
- t_idx=t_idx)
+ nc.fluid_node_data, plant_dict = gc_compiler2.get_fluid_node_data(
+ circuit=circuit,
+ t_idx=t_idx,
+ time_series=time_series
+ )
+
+ nc.fluid_turbine_data = gc_compiler2.get_fluid_turbine_data(
+ circuit=circuit,
+ plant_dict=plant_dict,
+ gen_dict=gen_dict,
+ t_idx=t_idx
+ )
+
+ nc.fluid_pump_data = gc_compiler2.get_fluid_pump_data(
+ circuit=circuit,
+ plant_dict=plant_dict,
+ gen_dict=gen_dict,
+ t_idx=t_idx
+ )
+
+ nc.fluid_p2x_data = gc_compiler2.get_fluid_p2x_data(
+ circuit=circuit,
+ plant_dict=plant_dict,
+ gen_dict=gen_dict,
+ t_idx=t_idx
+ )
+
+ nc.fluid_path_data = gc_compiler2.get_fluid_path_data(
+ circuit=circuit,
+ plant_dict=plant_dict,
+ t_idx=t_idx
+ )
nc.consolidate_information()
diff --git a/src/GridCalEngine/DataStructures/vsc_data.py b/src/GridCalEngine/DataStructures/vsc_data.py
index 7d678909f..18fa2f59b 100644
--- a/src/GridCalEngine/DataStructures/vsc_data.py
+++ b/src/GridCalEngine/DataStructures/vsc_data.py
@@ -1,9 +1,10 @@
import numpy as np
from typing import List, Tuple
import scipy.sparse as sp
-from GridCalEngine.enumerations import ConverterControlType
+# from GridCalEngine.enumerations import ConverterControlType
from GridCalEngine.basic_structures import Vec, IntVec, BoolVec, StrVec
+
class VscData:
"""
VscData class provides a structured model for managing data related to Voltage Source Converters (VSC) in power grid simulations.
@@ -49,19 +50,17 @@ def __init__(self, nelm: int, nbus: int):
self.tap_module: Vec = np.zeros(nelm, dtype=float)
self.tap_module_max: Vec = np.zeros(nelm, dtype=float)
self.tap_module_min: Vec = np.zeros(nelm, dtype=float)
-
-
+
# Loss Params
self.alpha1: Vec = np.zeros(nelm, dtype=float)
self.alpha2: Vec = np.zeros(nelm, dtype=float)
self.alpha3: Vec = np.zeros(nelm, dtype=float)
-
# Connection Matrix
self.C_vsc_bus_f: sp.lil_matrix = sp.lil_matrix((nelm, nbus),
- dtype=int) # this ons is just for splitting islands
+ dtype=int) # this ons is just for splitting islands
self.C_vsc_bus_t: sp.lil_matrix = sp.lil_matrix((nelm, nbus),
- dtype=int) # this ons is just for splitting islands
+ dtype=int) # this ons is just for splitting islands
# Control settings
self.control_mode: List[ConverterControlType] = [ConverterControlType.type_0_free] * nelm
@@ -71,7 +70,6 @@ def __init__(self, nelm: int, nbus: int):
self.Vac_set: Vec = np.zeros(nelm, dtype=float)
self.Vdc_set: Vec = np.zeros(nelm, dtype=float)
-
def update_loading(self, Pbus: Vec, Vbus: Vec, Sbase: float):
"""
Calculate loading and losses for each VSC based on current power and voltage levels.
diff --git a/src/GridCalEngine/Devices/Aggregation/investment.py b/src/GridCalEngine/Devices/Aggregation/investment.py
index 39e5c4d7e..e835476eb 100644
--- a/src/GridCalEngine/Devices/Aggregation/investment.py
+++ b/src/GridCalEngine/Devices/Aggregation/investment.py
@@ -30,8 +30,8 @@ def __init__(self,
device_idtag: Union[str, None] = None,
name="Investment",
code='',
- CAPEX=0.0,
- OPEX=0.0,
+ CAPEX: float = 0.0,
+ OPEX: float = 0.0,
status: bool = True,
group: InvestmentsGroup = None,
comment: str = ""):
@@ -43,7 +43,7 @@ def __init__(self,
:param CAPEX: Float. Capital expenditures
:param OPEX: Float. Operating expenditures
:param status: If true the investment activates when applied, otherwise is deactivated
- :param group: ContingencyGroup. Contingency group
+ :param group: InvestmentGroup. Investment group
:param comment: Comment
"""
@@ -55,16 +55,16 @@ def __init__(self,
comment=comment)
# Contingency type
- self.device_idtag = device_idtag
- self.CAPEX = CAPEX
- self.OPEX = OPEX
+ self.device_idtag: str = device_idtag
+ self.CAPEX: float = CAPEX
+ self.OPEX: float = OPEX
self._group: InvestmentsGroup = group
self.status: bool = status
self.register(key='device_idtag', units='', tpe=str, definition='Unique ID')
- self.register(key='CAPEX', units='Me', tpe=float,
+ self.register(key='CAPEX', units='Mā¬', tpe=float,
definition='Capital expenditures. This is the initial investment.')
- self.register(key='OPEX', units='Me', tpe=float,
+ self.register(key='OPEX', units='Mā¬', tpe=float,
definition='Operation expenditures. Maintenance costs among other recurrent costs.')
self.register(key='status', units='', tpe=bool,
definition='If true the investment activates when applied, otherwise is deactivated.')
@@ -92,5 +92,5 @@ def category(self):
@category.setter
def category(self, val):
- # self.group.category = val
+ # The category is set through the group, so no implementation here
pass
diff --git a/src/GridCalEngine/Devices/Associations/association.py b/src/GridCalEngine/Devices/Associations/association.py
index eb4bb397e..39ee5c1eb 100644
--- a/src/GridCalEngine/Devices/Associations/association.py
+++ b/src/GridCalEngine/Devices/Associations/association.py
@@ -76,7 +76,7 @@ def __eq__(self, other: "Association") -> bool:
class Associations:
"""
- GridCal associations object, this handless a set of associations
+ GridCal associations object, this handles a set of associations
"""
def __init__(self, device_type: DeviceType):
@@ -85,32 +85,51 @@ def __init__(self, device_type: DeviceType):
:param device_type: DeviceType
"""
self._data: Dict[str, Association] = dict()
-
self._device_type = device_type
+ @property
+ def data(self):
+ """
+
+ :return:
+ """
+ return self._data
+
@property
def device_type(self) -> DeviceType:
"""
Device Type
- :return:
+ :return: DeviceType
"""
return self._device_type
+ @device_type.setter
+ def device_type(self, value: DeviceType):
+ """
+ Set the device type of the association, as needed in empty investments
+ :param value: DeviceType
+ """
+ if isinstance(value, DeviceType):
+ self._device_type = value
+ else:
+ raise ValueError("value must be an instance of DeviceType")
+
def add(self, val: Association):
"""
Add Association
- :param val:
- :return:
+ :param val: Association
+ :return: None
"""
+
if val.api_object is not None:
self._data[val.api_object.idtag] = val
def add_object(self, api_object: ASSOCIATION_TYPES, val: float) -> Association:
"""
Add association
- :param api_object:
- :param val:
- :return:
+ :param api_object: ASSOCIATION_TYPES
+ :param val: float
+ :return: Association
"""
assoc = Association(api_object=api_object, value=val)
self.add(assoc)
@@ -119,8 +138,8 @@ def add_object(self, api_object: ASSOCIATION_TYPES, val: float) -> Association:
def remove(self, val: Association):
"""
Remove Association
- :param val:
- :return:
+ :param val: Association
+ :return: None
"""
if val.api_object is not None:
del self._data[val.api_object.idtag]
@@ -153,13 +172,15 @@ def parse(self,
data: List[Dict[str, Union[str, float]]],
elements_dict: Dict[str, ALL_DEV_TYPES],
logger: Logger,
- elm_name: str) -> None:
+ elm_name: str,
+ updatable_device_type: bool = False) -> None:
"""
Parse the data generated with to_dict()
:param data: Json data
:param elements_dict: dictionary of elements of the type self.device_type
:param logger: Logger
:param elm_name: base element name for reporting
+ :param updatable_device_type: if the device type has to be updated in case of empty investments
"""
for entry in data:
@@ -227,8 +248,3 @@ def __eq__(self, other: "Associations") -> bool:
return False
return True
-
-
-
-
-
diff --git a/src/GridCalEngine/Devices/Branches/line.py b/src/GridCalEngine/Devices/Branches/line.py
index ac5c6ffd4..f556fb6ae 100644
--- a/src/GridCalEngine/Devices/Branches/line.py
+++ b/src/GridCalEngine/Devices/Branches/line.py
@@ -16,7 +16,7 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import numpy as np
-from typing import Union
+from typing import Union, Tuple
from GridCalEngine.basic_structures import Logger
from GridCalEngine.Devices.Substation.bus import Bus
from GridCalEngine.Devices.Substation.connectivity_node import ConnectivityNode
@@ -104,7 +104,7 @@ def __init__(self, bus_from: Bus = None, bus_to: Bus = None, cn_from: Connectivi
device_type=DeviceType.LineDevice)
# line length in km
- self.length = length
+ self._length = length
# line impedance tolerance
self.tolerance = tolerance
@@ -140,7 +140,7 @@ def __init__(self, bus_from: Bus = None, bus_to: Bus = None, cn_from: Connectivi
# association with various templates
self.possible_tower_types: Associations = Associations(device_type=DeviceType.OverheadLineTypeDevice)
- self.possible_undergroud_line_types: Associations = Associations(device_type=DeviceType.UnderGroundLineDevice)
+ self.possible_underground_line_types: Associations = Associations(device_type=DeviceType.UnderGroundLineDevice)
self.possible_sequence_line_types: Associations = Associations(device_type=DeviceType.SequenceLineDevice)
# Line locations
@@ -183,7 +183,7 @@ def __init__(self, bus_from: Bus = None, bus_to: Bus = None, cn_from: Connectivi
definition='Possible overhead line types (>1 to denote association), - to denote no association',
display=False)
- self.register(key='possible_undergroud_line_types', units='', tpe=SubObjectType.Associations,
+ self.register(key='possible_underground_line_types', units='', tpe=SubObjectType.Associations,
definition='Possible underground line types (>1 to denote association), - to denote no association',
display=False)
@@ -191,6 +191,25 @@ def __init__(self, bus_from: Bus = None, bus_to: Bus = None, cn_from: Connectivi
definition='Possible sequence line types (>1 to denote association), - to denote no association',
display=False)
+ @property
+ def length(self) -> float:
+ """
+ Line length in km
+ :return: float
+ """
+ return self._length
+
+ @length.setter
+ def length(self, val: float):
+ if isinstance(val, float):
+ if val > 0.0:
+ self._length = val
+ else:
+ print('The length cannot be zero, setting it to 1.0 km')
+ self._length = 1.0
+ else:
+ raise Exception('The length must be a float value')
+
@property
def temp_oper_prof(self) -> Profile:
"""
@@ -278,6 +297,23 @@ def apply_template(self, obj: Union[OverheadLineType, UndergroundLineType, Seque
else:
logger.add_error('Template not recognised', self.name)
+ def get_line_type(self) -> SequenceLineType:
+ """
+ Get the equivalent sequence line type of this line
+ :return: SequenceLineType
+ """
+ if self.length == 0.0:
+ raise Exception("Length must be greater than 0")
+
+ return SequenceLineType(name=f"{self.name}_type",
+ Imax=1, Vnom=self.get_max_bus_nominal_voltage(),
+ R=self.R / self.length,
+ X=self.X / self.length,
+ B=self.B / self.length,
+ R0=self.R0 / self.length,
+ X0=self.X0 / self.length,
+ B0=self.B0 / self.length)
+
def get_save_data(self):
"""
Return the data that matches the edit_headers
@@ -385,6 +421,31 @@ def fill_design_properties(self, r_ohm, x_ohm, c_nf, length, Imax, freq, Sbase):
self.rate = np.round(Imax * Vf * 1.73205080757, 6) # nominal power in MVA = kA * kV * sqrt(3)
self.length = length
+ def get_virtual_taps(self) -> Tuple[float, float]:
+ """
+ Get the branch virtual taps
+
+ The virtual taps generate when a line nominal voltage ate the two connection buses differ
+
+ Returns:
+
+ **tap_f** (float, 1.0): Virtual tap at the *from* side
+
+ **tap_t** (float, 1.0): Virtual tap at the *to* side
+
+ """
+ # resolve how the transformer is actually connected and set the virtual taps
+ bus_f_v = self.bus_from.Vnom
+ bus_t_v = self.bus_to.Vnom
+
+ if bus_f_v == bus_t_v:
+ return 1.0, 1.0
+ else:
+ if bus_f_v > 0.0 and bus_t_v > 0.0:
+ return 1.0, bus_f_v / bus_t_v
+ else:
+ return 1.0, 1.0
+
def set_data_from(self, second_Line: "Line"):
"""
Set the data from another line
diff --git a/src/GridCalEngine/Devices/Branches/tap_changer.py b/src/GridCalEngine/Devices/Branches/tap_changer.py
index 5a498dc69..98e4bd777 100644
--- a/src/GridCalEngine/Devices/Branches/tap_changer.py
+++ b/src/GridCalEngine/Devices/Branches/tap_changer.py
@@ -18,28 +18,8 @@
import numpy as np
import pandas as pd
from typing import Union, Dict
+from GridCalEngine.Utils.NumericalMethods.common import find_closest_number
from GridCalEngine.enumerations import TapChangerTypes
-from GridCalEngine.basic_structures import Vec
-
-
-def find_closest_number(arr: Vec, target: float) -> int:
- """
-
- :param arr:
- :param target:
- :return:
- """
- idx = np.searchsorted(arr, target)
- if idx == 0:
- return arr[0]
- if idx == len(arr):
- return arr[-1]
- before = arr[idx - 1]
- after = arr[idx]
- if after - target < target - before:
- return after
- else:
- return before
class TapChanger:
@@ -54,16 +34,16 @@ def __init__(self,
asymmetry_angle: float = 90.0,
tc_type: TapChangerTypes = TapChangerTypes.NoRegulation) -> None:
"""
-
- :param total_positions:
- :param neutral_position:
- :param dV: per unit of voltage increment
- :param asymmetry_angle:
- :param tc_type:
+ Tap changer
+ :param total_positions: Total number of positions
+ :param neutral_position: Neutral position
+ :param dV: per unit of voltage increment (p.u.)
+ :param asymmetry_angle: Asymmetry angle (deg)
+ :param tc_type: Tap changer type
"""
self.asymmetry_angle = asymmetry_angle # assymetry angle (Theta)
- self.total_positions = total_positions # total number of positions
+ self._total_positions = total_positions # total number of positions
self.dV = dV # voltage increment in p.u.
self.neutral_position = neutral_position # neutral position
self._tap_position = neutral_position # index with respect to the neutral position
@@ -75,6 +55,22 @@ def __init__(self,
self._m_array = np.zeros(total_positions)
self.recalc()
+ @property
+ def total_positions(self) -> int:
+ """
+ Tap changer total number of positions
+ :return: int
+ """
+ return self._total_positions
+
+ @total_positions.setter
+ def total_positions(self, value: int):
+ if isinstance(value, int):
+ self._total_positions = value
+ self.resize()
+ else:
+ raise TypeError(f'Expected int but got {type(value)}')
+
@property
def tap_position(self) -> int:
"""
@@ -91,6 +87,15 @@ def tap_position(self, val: int):
"""
self._tap_position = val
+ def resize(self) -> None:
+ """
+ Resize and recalc the tap positions array
+ """
+ self._ndv = np.zeros(self.total_positions)
+ self._tau_array = np.zeros(self.total_positions)
+ self._m_array = np.zeros(self.total_positions)
+ self.recalc()
+
def recalc(self) -> None:
"""
Recalculate the phase and modules corresponding to each tap position
@@ -241,21 +246,42 @@ def get_tap_module(self) -> float:
"""
return self._m_array[self.tap_position]
- def set_tap_module(self, tap_module: float):
+ def set_tap_module(self, tap_module: float) -> float:
"""
Set the tap position closest to the tap module
:param tap_module: float value of the tap module
"""
- # if tap_module == 1.0:
- # self.tap_position = 0
- # elif tap_module > 1:
- # self.tap_position = round((tap_module - 1.0) / self.inc_reg_up)
- # elif tap_module < 1:
- # self.tap_position = -round((1.0 - tap_module) / self.inc_reg_down)
-
if self.tc_type != TapChangerTypes.NoRegulation:
return find_closest_number(arr=self._tau_array, target=tap_module)
+ def get_tap_module_min(self) -> float:
+ """
+ Min tap module, computed on the fly
+ :return: float
+ """
+ return self.get_tap_module2(tap_position=0)
+
+ def get_tap_module_max(self) -> float:
+ """
+ Max tap module, computed on the fly
+ :return: float
+ """
+ return self.get_tap_module2(tap_position=self.total_positions - 1)
+
+ def get_tap_phase_min(self) -> float:
+ """
+ Min tap phase, cputed on the fly
+ :return: float
+ """
+ return self.get_tap_phase2(tap_position=0)
+
+ def get_tap_phase_max(self) -> float:
+ """
+ Maximum tap phase (calculated)
+ :return: float
+ """
+ return self.get_tap_phase2(tap_position=self.total_positions - 1)
+
def __eq__(self, other: "TapChanger") -> bool:
"""
Equality check
@@ -269,6 +295,9 @@ def __eq__(self, other: "TapChanger") -> bool:
and (self.tap_position == other.tap_position)
and (self.tc_type == other.tc_type))
- def __str__(self):
-
+ def __str__(self) -> str:
+ """
+ String representation
+ :return:
+ """
return "Tap changer"
diff --git a/src/GridCalEngine/Devices/Branches/transformer.py b/src/GridCalEngine/Devices/Branches/transformer.py
index 04a53e00b..45cd3f163 100644
--- a/src/GridCalEngine/Devices/Branches/transformer.py
+++ b/src/GridCalEngine/Devices/Branches/transformer.py
@@ -16,14 +16,14 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import numpy as np
-from typing import Tuple, Union
+from typing import Tuple, Union, List
from GridCalEngine.basic_structures import Logger
from GridCalEngine.Devices.Substation.bus import Bus
from GridCalEngine.Devices.Substation.connectivity_node import ConnectivityNode
from GridCalEngine.Devices.Associations.association import Associations
-from GridCalEngine.enumerations import (TransformerControlType, WindingsConnection, BuildStatus,
- TapAngleControl, TapModuleControl, TapChangerTypes, SubObjectType)
+from GridCalEngine.enumerations import (WindingsConnection, BuildStatus, TapPhaseControl,
+ TapModuleControl, SubObjectType, TapChangerTypes)
from GridCalEngine.Devices.Parents.controllable_branch_parent import ControllableBranchParent
from GridCalEngine.Devices.Branches.transformer_type import TransformerType, reverse_transformer_short_circuit_study
from GridCalEngine.Devices.Parents.editable_device import DeviceType
@@ -64,12 +64,12 @@ def __init__(self,
mttr: float = 0.0,
vset: float = 1.0,
Pset: float = 0.0,
+ Qset: float = 0.0,
temp_base: float = 20.0,
temp_oper: float = 20.0,
alpha: float = 0.00330,
- control_mode: TransformerControlType = TransformerControlType.fixed, # legacy?
tap_module_control_mode: TapModuleControl = TapModuleControl.fixed,
- tap_angle_control_mode: TapAngleControl = TapAngleControl.fixed,
+ tap_phase_control_mode: TapPhaseControl = TapPhaseControl.fixed,
template: TransformerType = None,
contingency_factor: float = 1.0,
protection_rating_factor: float = 1.4,
@@ -127,7 +127,6 @@ def __init__(self,
:param temp_base: Base temperature at which `r` is measured in Ā°C
:param temp_oper: Operating temperature in Ā°C
:param alpha: Thermal constant of the material in Ā°C
- :param control_mode: Control model
:param template: Branch template
:param contingency_factor: Rating factor in case of contingency
:param contingency_enabled: enabled for contingencies (Legacy)
@@ -172,15 +171,16 @@ def __init__(self,
mttr=mttr,
vset=vset,
Pset=Pset,
+ Qset=Qset,
regulation_branch=None,
regulation_bus=None,
regulation_cn=None,
temp_base=temp_base,
temp_oper=temp_oper,
alpha=alpha,
- control_mode=control_mode,
+ # control_mode=control_mode,
tap_module_control_mode=tap_module_control_mode,
- tap_angle_control_mode=tap_angle_control_mode,
+ tap_phase_control_mode=tap_phase_control_mode,
contingency_factor=contingency_factor,
protection_rating_factor=protection_rating_factor,
contingency_enabled=contingency_enabled,
@@ -270,50 +270,6 @@ def set_hv_and_lv(self, HV: float, LV: float):
else:
self.LV = LV
- # def copy(self, bus_dict=None):
- # """
- # Returns a copy of the branch
- # @return: A new with the same content as this
- # """
- #
- # if bus_dict is None:
- # f = self.bus_from
- # t = self.bus_to
- # else:
- # f = bus_dict[self.bus_from]
- # t = bus_dict[self.bus_to]
- #
- # # z_series = complex(self.R, self.X)
- # # y_shunt = complex(self.G, self.B)
- # b = Transformer2W(bus_from=f,
- # bus_to=t,
- # name=self.name,
- # r=self.R,
- # x=self.X,
- # g=self.G,
- # b=self.B,
- # rate=self.rate,
- # tap_module=self.tap_module,
- # tap_phase=self.tap_phase,
- # active=self.active,
- # mttf=self.mttf,
- # mttr=self.mttr,
- # vset=self.vset,
- # temp_base=self.temp_base,
- # temp_oper=self.temp_oper,
- # alpha=self.alpha,
- # template=self.template,
- # opex=self.opex,
- # capex=self.capex)
- #
- # b.regulation_bus = self.regulation_bus
- # b.regulation_cn = self.regulation_cn
- # b.active_prof = self.active_prof
- # b.rate_prof = self.rate_prof
- # b.Cost_prof = self.Cost_prof
- #
- # return b
-
def get_from_to_nominal_voltages(self) -> Tuple[float, float]:
"""
@@ -395,6 +351,8 @@ def apply_template(self, obj: TransformerType, Sbase, logger=Logger()):
self.HV = obj.HV
self.LV = obj.LV
+ self.tap_changer = obj.get_tap_changer()
+
if self.template is not None:
if obj != self.template:
self.template = obj
@@ -403,7 +361,7 @@ def apply_template(self, obj: TransformerType, Sbase, logger=Logger()):
else:
self.template = obj
- def get_save_data(self):
+ def get_save_data(self) -> Union[None, List[str]]:
"""
Return the data that matches the edit_headers
:return:
@@ -412,18 +370,17 @@ def get_save_data(self):
for property_name, properties in self.registered_properties.items():
obj = getattr(self, property_name)
- if obj is not None:
- if properties.tpe == DeviceType.BusDevice:
- obj = obj.idtag
+ if properties.tpe == DeviceType.BusDevice:
+ obj = obj.idtag
- elif properties.tpe == DeviceType.TransformerTypeDevice:
- if obj is None:
- obj = ''
- else:
- obj = obj.idtag
+ elif properties.tpe == DeviceType.TransformerTypeDevice:
+ if obj is None:
+ obj = ''
+ else:
+ obj = obj.idtag
- elif properties.tpe not in [str, float, int, bool]:
- obj = str(obj)
+ elif properties.tpe not in [str, float, int, bool]:
+ obj = str(obj)
data.append(obj)
return data
@@ -510,7 +467,8 @@ def get_vcc(self) -> float:
def get_transformer_type(self, Sbase: float = 100.0) -> TransformerType:
"""
-
+ Get the equivalent transformer type of this transformer
+ :return: SequenceLineType
:param Sbase:
:return:
"""
diff --git a/src/GridCalEngine/Devices/Branches/transformer_type.py b/src/GridCalEngine/Devices/Branches/transformer_type.py
index e396d2256..f84206cec 100644
--- a/src/GridCalEngine/Devices/Branches/transformer_type.py
+++ b/src/GridCalEngine/Devices/Branches/transformer_type.py
@@ -16,8 +16,9 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from typing import Tuple, Union
from numpy import sqrt
-
+from GridCalEngine.enumerations import TapChangerTypes
from GridCalEngine.Devices.Parents.editable_device import EditableDevice, DeviceType
+from GridCalEngine.Devices.Branches.tap_changer import TapChanger
class TransformerType(EditableDevice):
@@ -32,6 +33,11 @@ def __init__(self,
short_circuit_voltage: float = 0.0,
gr_hv1: float = 0.5,
gx_hv1: float = 0.5,
+ total_positions: int = 5,
+ neutral_position: int = 2,
+ dV: float = 0.01,
+ asymmetry_angle: float = 90.0,
+ tc_type: TapChangerTypes = TapChangerTypes.NoRegulation,
name: str = 'TransformerType',
idtag: Union[None, str] = None) -> None:
"""
@@ -45,6 +51,11 @@ def __init__(self,
:param short_circuit_voltage: Short circuit voltage in %
:param gr_hv1: proportion of the resistance in the HV side (i.e. 0.5)
:param gx_hv1: proportion of the reactance in the HV side (i.e. 0.5)
+ :param total_positions: Total number of positions
+ :param neutral_position: Neutral position
+ :param dV: per unit of voltage increment
+ :param asymmetry_angle: Asymmetry angle (deg)
+ :param tc_type: Tap changer type
:param name: Name of the device template
:param idtag: device UUID
"""
@@ -72,6 +83,13 @@ def __init__(self,
self.GX_hv1 = gx_hv1
+ # The tap changer parameters are stored and used with the help of the TapChanger object
+ self._tap_changer = TapChanger(total_positions=total_positions,
+ neutral_position=neutral_position,
+ dV=dV,
+ asymmetry_angle=asymmetry_angle,
+ tc_type=tc_type)
+
self.register(key='HV', units='kV', tpe=float, definition='Nominal voltage al the high voltage side')
self.register(key='LV', units='kV', tpe=float, definition='Nominal voltage al the low voltage side')
self.register(key='Sn', units='MVA', tpe=float, definition='Nominal power', old_names=['rating'])
@@ -80,7 +98,148 @@ def __init__(self,
self.register(key='I0', units='%', tpe=float, definition='No-load current')
self.register(key='Vsc', units='%', tpe=float, definition='Short-circuit voltage')
- def get_impedances(self, VH, VL, Sbase):
+ self.register(key='tc_type', units='', tpe=TapChangerTypes, definition='Regulation type')
+ self.register(key='total_positions', units='', tpe=int, definition='Number of tap positions')
+ self.register(key='dV', units='p.u.', tpe=float, definition='Voltage increment per step')
+ self.register(key='neutral_position', units='', tpe=int, definition='neutral poition couting from zero')
+ self.register(key='asymmetry_angle', units='deg', tpe=float, definition='Asymmetry_angle')
+
+ self.register(key='tap_module_min', units='p.u.', tpe=float, definition='Min tap module', editable=False)
+ self.register(key='tap_module_max', units='p.u.', tpe=float, definition='Max tap module', editable=False)
+ self.register(key='tap_phase_min', units='rad', tpe=float, definition='Min tap phase', editable=False)
+ self.register(key='tap_phase_max', units='rad', tpe=float, definition='Max tap phase', editable=False)
+
+ @property
+ def tap_module_min(self) -> float:
+ """
+ Min tap module, computed on the fly
+ :return: float
+ """
+ return self._tap_changer.get_tap_module_min()
+
+ @tap_module_min.setter
+ def tap_module_min(self, val: float):
+ # this is a read only property
+ pass
+
+ @property
+ def tap_module_max(self) -> float:
+ """
+ Max tap module, computed on the fly
+ :return: float
+ """
+ return self._tap_changer.get_tap_module_max()
+
+ @tap_module_max.setter
+ def tap_module_max(self, val: float):
+ # this is a read only property
+ pass
+
+ @property
+ def tap_phase_min(self) -> float:
+ """
+ Min tap phase, cputed on the fly
+ :return: float
+ """
+ return self._tap_changer.get_tap_phase_min()
+
+ @tap_phase_min.setter
+ def tap_phase_min(self, val: float):
+ # this is a read only property
+ pass
+
+ @property
+ def tap_phase_max(self) -> float:
+ """
+ Maximum tap phase (calculated)
+ :return: float
+ """
+ return self._tap_changer.get_tap_phase_max()
+
+ @tap_phase_max.setter
+ def tap_phase_max(self, val: float):
+ # this is a read only property
+ pass
+
+ @property
+ def total_positions(self) -> int:
+ """
+ Tap changer total number of positions
+ :return: int
+ """
+ return self._tap_changer.total_positions
+
+ @total_positions.setter
+ def total_positions(self, value: int):
+ if isinstance(value, int):
+ self._tap_changer.total_positions = value
+ else:
+ raise TypeError(f'Expected int but got {type(value)}')
+
+ @property
+ def neutral_position(self) -> int:
+ """
+ Tap changer neutral position
+ :return: int
+ """
+ return self._tap_changer.neutral_position
+
+ @neutral_position.setter
+ def neutral_position(self, value: int):
+ if isinstance(value, int):
+ if 0 <= value < self._tap_changer.total_positions:
+ self._tap_changer.neutral_position = value
+ else:
+ pass
+ else:
+ raise TypeError(f'Expected int but got {type(value)}')
+
+ @property
+ def dV(self) -> float:
+ """
+ Tap changer Voltage increment per step (p.u.)
+ :return: float
+ """
+ return self._tap_changer.dV
+
+ @dV.setter
+ def dV(self, value: float):
+ if isinstance(value, float):
+ self._tap_changer.dV = value
+ else:
+ raise TypeError(f'Expected int but got {type(value)}')
+
+ @property
+ def asymmetry_angle(self) -> float:
+ """
+ Tap changer assymetry angle (deg)
+ :return: float
+ """
+ return self._tap_changer.asymmetry_angle
+
+ @asymmetry_angle.setter
+ def asymmetry_angle(self, value: float):
+ if isinstance(value, float):
+ self._tap_changer.asymmetry_angle = value
+ else:
+ raise TypeError(f'Expected float but got {type(value)}')
+
+ @property
+ def tc_type(self) -> TapChangerTypes:
+ """
+ Get the tap changer type
+ :return: TapChangerTypes
+ """
+ return self._tap_changer.tc_type
+
+ @tc_type.setter
+ def tc_type(self, value: TapChangerTypes):
+ if isinstance(value, TapChangerTypes):
+ self._tap_changer.tc_type = value
+ else:
+ raise TypeError(f'Expected TapChangerTypes but got {type(value)}')
+
+ def get_impedances(self, VH: float, VL: float, Sbase: float):
"""
Compute the branch parameters of a transformer from the short circuit test
values.
@@ -104,6 +263,17 @@ def get_impedances(self, VH, VL, Sbase):
return z_series, y_shunt
+ def get_tap_changer(self) -> TapChanger:
+ """
+ Get tap changer object
+ :return: TapChanger
+ """
+ return TapChanger(total_positions=self.total_positions,
+ neutral_position=self.neutral_position,
+ dV=self.dV,
+ asymmetry_angle=self.asymmetry_angle,
+ tc_type=self.tc_type)
+
def get_impedances(VH_bus: float, VL_bus: float, Sn: float, HV: float, LV: float,
Pcu: float, Pfe: float, I0: float, Vsc: float, Sbase: float,
diff --git a/src/GridCalEngine/Devices/Branches/vsc.py b/src/GridCalEngine/Devices/Branches/vsc.py
index ee64fdc03..96bee0c3e 100644
--- a/src/GridCalEngine/Devices/Branches/vsc.py
+++ b/src/GridCalEngine/Devices/Branches/vsc.py
@@ -22,31 +22,58 @@
from GridCalEngine.Devices.Substation.bus import Bus
from GridCalEngine.Devices.Substation.connectivity_node import ConnectivityNode
-from GridCalEngine.enumerations import ConverterControlType, BuildStatus
-from GridCalEngine.Devices.Parents.branch_parent import BranchParent
+from GridCalEngine.enumerations import BuildStatus, TapModuleControl, TapPhaseControl
+from GridCalEngine.Devices.Parents.controllable_branch_parent import ControllableBranchParent
from GridCalEngine.Devices.Parents.editable_device import DeviceType
-class VSC(BranchParent):
+class VSC(ControllableBranchParent):
def __init__(self,
- bus_from: Bus = None, bus_to: Bus = None,
+ bus_from: Bus = None,
+ bus_to: Bus = None,
cn_from: ConnectivityNode = None,
cn_to: ConnectivityNode = None,
- name='VSC', idtag=None, code='', active=True,
- r=0.0001, x=0.05,
- tap_module=1.0, tap_module_max=1.1, tap_module_min=0.8,
- tap_phase=0.1, tap_phase_max=6.28, tap_phase_min=-6.28,
- Beq=0.001, Beq_min=-0.1, Beq_max=0.1,
- G0sw=1e-5, rate=1e-9, kdp=-0.05, k=1.0,
- control_mode: ConverterControlType = ConverterControlType.type_0_free,
- Pfset=0.0, Qfset=0.0, Vac_set=1.0, Vdc_set=1.0,
- alpha1=0.0001, alpha2=0.015, alpha3=0.2,
- mttf=0, mttr=0, cost=100, contingency_factor=1.0,
+ name='VSC',
+ idtag=None,
+ code='',
+ active=True,
+ r=0.0001,
+ x=0.05,
+ tap_module=1.0,
+ tap_module_max=1.1,
+ tap_module_min=0.8,
+ tap_phase=0.1,
+ tap_phase_max=6.28,
+ tap_phase_min=-6.28,
+ Beq=0.001,
+ Beq_min=-0.1,
+ Beq_max=0.1,
+ G0sw=1e-5,
+ rate=1e-9,
+ kdp=-0.05,
+ k=1.0,
+ alpha1=0.0001,
+ alpha2=0.015,
+ alpha3=0.2,
+ mttf=0.0,
+ mttr=0.0,
+ tap_module_control_mode: TapModuleControl = TapModuleControl.fixed,
+ tap_phase_control_mode: TapPhaseControl = TapPhaseControl.fixed,
+ vset: float = 1.0,
+ Pset: float = 0.0,
+ Qset: float = 0.0,
+ cost=100,
+ contingency_factor=1.0,
protection_rating_factor: float = 1.4,
- contingency_enabled=True, monitor_loading=True,
- r0=0.0001, x0=0.05, r2=0.0001, x2=0.05,
- capex=0, opex=0, build_status: BuildStatus = BuildStatus.Commissioned):
+ contingency_enabled=True,
+ monitor_loading=True,
+ r0=0.0001,
+ x0=0.05,
+ r2=0.0001,
+ x2=0.05,
+ capex=0,
+ opex=0, build_status: BuildStatus = BuildStatus.Commissioned):
"""
Voltage source converter (VSC)
:param bus_from:
@@ -70,11 +97,6 @@ def __init__(self,
:param rate:
:param kdp:
:param k:
- :param control_mode:
- :param Pfset:
- :param Qfset:
- :param Vac_set:
- :param Vdc_set:
:param alpha1:
:param alpha2:
:param alpha3:
@@ -93,27 +115,58 @@ def __init__(self,
:param build_status:
"""
- BranchParent.__init__(self,
- name=name,
- idtag=idtag,
- code=code,
- bus_from=bus_from,
- bus_to=bus_to,
- cn_from=cn_from,
- cn_to=cn_to,
- active=active,
- rate=rate,
- contingency_factor=contingency_factor,
- protection_rating_factor=protection_rating_factor,
- contingency_enabled=contingency_enabled,
- monitor_loading=monitor_loading,
- mttf=mttf,
- mttr=mttr,
- build_status=build_status,
- capex=capex,
- opex=opex,
- Cost=cost,
- device_type=DeviceType.VscDevice)
+ ControllableBranchParent.__init__(self,
+ name=name,
+ idtag=idtag,
+ code=code,
+ bus_from=bus_from,
+ bus_to=bus_to,
+ cn_from=cn_from,
+ cn_to=cn_to,
+ active=active,
+ rate=rate,
+ r=r,
+ x=x,
+ g=0.0,
+ b=0.0,
+ tap_module=tap_module,
+ tap_module_max=tap_module_max,
+ tap_module_min=tap_module_min,
+ tap_phase=tap_phase,
+ tap_phase_max=tap_phase_max,
+ tap_phase_min=tap_phase_min,
+ tolerance=0.0,
+ Cost=cost,
+ mttf=mttf,
+ mttr=mttr,
+ vset=vset,
+ Pset=Pset,
+ Qset=Qset,
+ regulation_branch=None,
+ regulation_bus=None,
+ regulation_cn=None,
+ temp_base=20.0,
+ temp_oper=20.0,
+ alpha=0.00330,
+ # control_mode=control_mode,
+ tap_module_control_mode=tap_module_control_mode,
+ tap_phase_control_mode=tap_phase_control_mode,
+ contingency_factor=contingency_factor,
+ protection_rating_factor=protection_rating_factor,
+ contingency_enabled=contingency_enabled,
+ monitor_loading=monitor_loading,
+ r0=r0,
+ x0=x0,
+ g0=0.0,
+ b0=0.0,
+ r2=r2,
+ x2=x2,
+ g2=0.0,
+ b2=0.0,
+ capex=capex,
+ opex=opex,
+ build_status=build_status,
+ device_type=DeviceType.VscDevice)
# the VSC must only connect from an DC to a AC bus
# this connectivity sense is done to keep track with the articles that set it
@@ -137,19 +190,6 @@ def __init__(self,
self.bus_from = None
self.bus_to = None
- # List of measurements
- self.measurements = list()
-
- # total impedance and admittance in p.u.
- self.R = r
- self.X = x
-
- self.R0 = r0
- self.X0 = x0
-
- self.R2 = r2
- self.X2 = x2
-
self.G0sw = G0sw
self.Beq = Beq
self.tap_module = tap_module
@@ -163,66 +203,26 @@ def __init__(self,
self.Beq_min = Beq_min
self.Beq_max = Beq_max
- self.Pdc_set = Pfset
- self.Qac_set = Qfset
- self.Vac_set = Vac_set
- self.Vdc_set = Vdc_set
- self.control_mode = control_mode
-
self.kdp = kdp
self.alpha1 = alpha1
self.alpha2 = alpha2
self.alpha3 = alpha3
- self.register(key='R', units='p.u.', tpe=float, definition='Resistive positive sequence losses.',
- old_names=['R1'])
- self.register(key='X', units='p.u.', tpe=float, definition='Magnetic positive sequence losses.',
- old_names=['X1'])
- self.register(key='R0', units='p.u.', tpe=float, definition='Resistive zero sequence losses.')
- self.register(key='X0', units='p.u.', tpe=float, definition='Magnetic zero sequence losses.')
- self.register(key='R2', units='p.u.', tpe=float, definition='Resistive negative sequence losses.')
- self.register(key='X2', units='p.u.', tpe=float, definition='Magnetic negative sequence losses.')
-
self.register(key='G0sw', units='p.u.', tpe=float, definition='Inverter losses.')
self.register(key='Beq', units='p.u.', tpe=float, definition='Total shunt susceptance.')
self.register(key='Beq_max', units='p.u.', tpe=float, definition='Max total shunt susceptance.')
self.register(key='Beq_min', units='p.u.', tpe=float, definition='Min total shunt susceptance.')
- self.register(key='tap_module', units='', tpe=float, definition='Tap changer module, it a value close to 1.0',
- old_names=['m'])
- self.register(key='tap_module_max', units='', tpe=float, definition='Max tap changer module',
- old_names=['m_max'])
- self.register(key='tap_module_min', units='', tpe=float, definition='Min tap changer module',
- old_names=['m_min'])
-
- self.register(key='tap_phase', units='rad', tpe=float, definition='Converter firing angle.',
- old_names=['theta'])
- self.register(key='tap_phase_max', units='rad', tpe=float, definition='Max converter firing angle.',
- old_names=['theta_max'])
- self.register(key='tap_phase_min', units='rad', tpe=float, definition='Min converter firing angle.',
- old_names=['theta_min'])
-
self.register(key='alpha1', units='', tpe=float,
- definition='Converter losses curve parameter (IEC 62751-2 loss Correction).')
+ definition='Losses constant parameter (IEC 62751-2 loss Correction).')
self.register(key='alpha2', units='', tpe=float,
- definition='Converter losses curve parameter (IEC 62751-2 loss Correction).')
+ definition='Losses linear parameter (IEC 62751-2 loss Correction).')
self.register(key='alpha3', units='', tpe=float,
- definition='Converter losses curve parameter (IEC 62751-2 loss Correction).')
+ definition='Losses quadratic parameter (IEC 62751-2 loss Correction).')
+
self.register(key='k', units='p.u./p.u.', tpe=float, definition='Converter factor, typically 0.866.')
- self.register(key='control_mode', units='', tpe=ConverterControlType, definition='Converter control mode')
- self.register(key='kdp', units='p.u./p.u.', tpe=float, definition='Droop Power/Voltage slope.')
- self.register(key='Pdc_set', units='MW', tpe=float, definition='DC power set point.')
- self.register(key='Qac_set', units='MVAr', tpe=float, definition='AC Reactive power set point.')
- self.register(key='Vac_set', units='p.u.', tpe=float, definition='AC voltage set point.')
- self.register(key='Vdc_set', units='p.u.', tpe=float, definition='DC voltage set point.')
- def get_weight(self):
- """
- Get a weight of this line for graph porpuses
- the weight is the impedance moudule (sqrt(r^2 + x^2))
- :return: weight value
- """
- return np.sqrt(self.R * self.R + self.X * self.X)
+ self.register(key='kdp', units='p.u./p.u.', tpe=float, definition='Droop Power/Voltage slope.')
def change_base(self, Sbase_old: float, Sbase_new: float):
"""
@@ -230,10 +230,8 @@ def change_base(self, Sbase_old: float, Sbase_new: float):
:param Sbase_old: old base (MVA)
:param Sbase_new: new base (MVA)
"""
+ super().change_base(Sbase_old, Sbase_new)
b = Sbase_new / Sbase_old
-
- self.R *= b
- self.X *= b
self.G0sw *= b
self.Beq *= b
@@ -302,3 +300,5 @@ def plot_profiles(self, time_series=None, my_index=0, show_fig=True):
if show_fig:
plt.show()
+
+
diff --git a/src/GridCalEngine/Devices/Branches/winding.py b/src/GridCalEngine/Devices/Branches/winding.py
index 8fa91a263..75e5d8a12 100644
--- a/src/GridCalEngine/Devices/Branches/winding.py
+++ b/src/GridCalEngine/Devices/Branches/winding.py
@@ -18,8 +18,7 @@
from typing import Union
from GridCalEngine.Devices.Substation.bus import Bus
from GridCalEngine.Devices.Substation.connectivity_node import ConnectivityNode
-from GridCalEngine.enumerations import (TransformerControlType, WindingsConnection, BuildStatus,
- TapAngleControl, TapModuleControl)
+from GridCalEngine.enumerations import (WindingsConnection, BuildStatus, TapPhaseControl, TapModuleControl)
from GridCalEngine.Devices.Branches.transformer_type import TransformerType
from GridCalEngine.Devices.Branches.transformer import Transformer2W
from GridCalEngine.Devices.Parents.editable_device import DeviceType
@@ -60,12 +59,12 @@ def __init__(self,
mttr: float = 0.0,
vset: float = 1.0,
Pset: float = 0.0,
+ Qset: float = 0.0,
temp_base: float = 20.0,
temp_oper: float = 20.0,
alpha: float = 0.00330,
- control_mode: TransformerControlType = TransformerControlType.fixed,
tap_module_control_mode: TapModuleControl = TapModuleControl.fixed,
- tap_angle_control_mode: TapAngleControl = TapAngleControl.fixed,
+ tap_phase_control_mode: TapPhaseControl = TapPhaseControl.fixed,
template: TransformerType = None,
contingency_factor: float = 1.0,
protection_rating_factor: float = 1.4,
@@ -118,7 +117,8 @@ def __init__(self,
:param temp_base: Base temperature at which `r` is measured in Ā°C
:param temp_oper: Operating temperature in Ā°C
:param alpha: Thermal constant of the material in Ā°C
- :param control_mode: Control model
+ :param tap_module_control_mode: Tap module Control model
+ :param tap_phase_control_mode: Tap phase Control model
:param template: Branch template
:param contingency_factor: Rating factor in case of contingency
:param contingency_enabled: enabled for contingencies (Legacy)
@@ -169,12 +169,12 @@ def __init__(self,
mttr=mttr,
vset=vset,
Pset=Pset,
+ Qset=Qset,
temp_base=temp_base,
temp_oper=temp_oper,
alpha=alpha,
- control_mode=control_mode,
tap_module_control_mode=tap_module_control_mode,
- tap_angle_control_mode=tap_angle_control_mode,
+ tap_phase_control_mode=tap_phase_control_mode,
contingency_factor=contingency_factor,
protection_rating_factor=protection_rating_factor,
contingency_enabled=contingency_enabled,
diff --git a/src/GridCalEngine/Devices/Branches/wire.py b/src/GridCalEngine/Devices/Branches/wire.py
index 4cbcf56c2..b4372dc07 100644
--- a/src/GridCalEngine/Devices/Branches/wire.py
+++ b/src/GridCalEngine/Devices/Branches/wire.py
@@ -24,7 +24,12 @@ class Wire(EditableDevice):
This class represents a wire (an actual wire)
to compose towers
"""
- def __init__(self, name='', idtag: Union[str, None] = None, gmr=0.01, r=0.01, x=0.0, max_current=1, stranding=0.0, material=0.0, diameter=0.0):
+ def __init__(self, name='', idtag: Union[str, None] = None,
+ gmr: float = 0.01, r: float = 0.01, x: float = 0.0,
+ max_current: float = 1.0,
+ stranding: str = "",
+ material: str = "",
+ diameter: float = 0.0):
"""
Wire definition
:param name: Name of the wire type
@@ -42,26 +47,42 @@ def __init__(self, name='', idtag: Union[str, None] = None, gmr=0.01, r=0.01, x=
device_type=DeviceType.WireDevice)
# self.wire_name = name
- self.stranding = stranding
- self.material = material
+ self._stranding = str(stranding)
+ self._material = str(material)
self.diameter = diameter
- self.r = r
- self.x = x
- self.gmr = gmr
+ self.R = r
+ self.X = x
+ self.GMR = gmr
self.max_current = max_current
- self.register(key='r', units='Ohm/km', tpe=float, definition='resistance of the conductor')
- self.register(key='x', units='Ohm/km', tpe=float, definition='reactance of the conductor')
- self.register(key='gmr', units='m', tpe=float, definition='Geometric Mean Radius of the conductor')
+ self.register(key='R', units='Ohm/km', tpe=float, definition='resistance of the conductor')
+ self.register(key='X', units='Ohm/km', tpe=float, definition='reactance of the conductor')
+ self.register(key='GMR', units='m', tpe=float, definition='Geometric Mean Radius of the conductor')
self.register(key='max_current', units='kA', tpe=float, definition='Maximum current of the conductor')
- self.register(key='stranding', tpe=float, definition='Stranding of wire')
- self.register(key='material', tpe=float, definition='Material of wire')
+ self.register(key='stranding', tpe=str, definition='Stranding of wire')
+ self.register(key='material', tpe=str, definition='Material of wire')
self.register(key='diameter', units='cm', tpe=float, definition='Diameter of wire')
- def copy(self):
+ @property
+ def stranding(self) -> str:
"""
- Copy of the wire
+ Stranding of wire
:return:
"""
- # name='', idtag=None, gmr=0.01, r=0.01, x=0.0, max_current=1
- return Wire(name=self.name, gmr=self.gmr, r=self.r, x=self.x, max_current=self.max_current, stranding=self.stranding, material=self.material, diameter=self.diameter)
+ return self._stranding
+
+ @stranding.setter
+ def stranding(self, value: str):
+ self._stranding = str(value)
+
+ @property
+ def material(self) -> str:
+ """
+ Material of wire
+ :return:
+ """
+ return self._material
+
+ @material.setter
+ def material(self, value: str):
+ self._material = str(value)
diff --git a/src/GridCalEngine/Devices/Parents/__init__.py b/src/GridCalEngine/Devices/Parents/__init__.py
index e3101ac1e..f9abe3e7c 100644
--- a/src/GridCalEngine/Devices/Parents/__init__.py
+++ b/src/GridCalEngine/Devices/Parents/__init__.py
@@ -14,4 +14,3 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
diff --git a/src/GridCalEngine/Devices/Parents/branch_parent.py b/src/GridCalEngine/Devices/Parents/branch_parent.py
index 627375135..3146be9c4 100644
--- a/src/GridCalEngine/Devices/Parents/branch_parent.py
+++ b/src/GridCalEngine/Devices/Parents/branch_parent.py
@@ -120,13 +120,19 @@ def __init__(self,
self.build_status = build_status
# line rating in MVA
- self.rate = rate
+ if not isinstance(rate, Union[float, int]):
+ raise ValueError("Rate must be a float")
+ self._rate = float(rate)
self._rate_prof = Profile(default_value=rate, data_type=float)
- self.contingency_factor = contingency_factor
+ if not isinstance(contingency_factor, Union[float, int]):
+ raise ValueError("contingency_factor must be a float")
+ self._contingency_factor = float(contingency_factor)
self._contingency_factor_prof = Profile(default_value=contingency_factor, data_type=float)
- self.protection_rating_factor = protection_rating_factor
+ if not isinstance(protection_rating_factor, Union[float, int]):
+ raise ValueError("protection_rating_factor must be a float")
+ self._protection_rating_factor = float(protection_rating_factor)
self._protection_rating_factor_prof = Profile(default_value=protection_rating_factor, data_type=float)
# List of measurements
@@ -334,6 +340,51 @@ def Cost_prof(self, val: Union[Profile, np.ndarray]):
else:
raise Exception(str(type(val)) + 'not supported to be set into a Cost_prof')
+ @property
+ def rate(self):
+ """
+ Rate (MVA)
+ :return:
+ """
+ return self._rate
+
+ @rate.setter
+ def rate(self, val: float):
+ if isinstance(val, float):
+ self._rate = val
+ else:
+ raise ValueError(f'{val} is not a float')
+
+ @property
+ def contingency_factor(self):
+ """
+ Rate (MVA)
+ :return:
+ """
+ return self._contingency_factor
+
+ @contingency_factor.setter
+ def contingency_factor(self, val: float):
+ if isinstance(val, float):
+ self._contingency_factor = val
+ else:
+ raise ValueError(f'{val} is not a float')
+
+ @property
+ def protection_rating_factor(self):
+ """
+ Rate (MVA)
+ :return:
+ """
+ return self._protection_rating_factor
+
+ @protection_rating_factor.setter
+ def protection_rating_factor(self, val: float):
+ if isinstance(val, float):
+ self._protection_rating_factor = val
+ else:
+ raise ValueError(f'{val} is not a float')
+
def get_max_bus_nominal_voltage(self):
"""
GEt the maximum nominal voltage
@@ -362,28 +413,10 @@ def get_sorted_buses_voltages(self):
def get_virtual_taps(self) -> Tuple[float, float]:
"""
- Get the branch virtual taps
-
- The virtual taps generate when a line nominal voltage ate the two connection buses differ
-
- Returns:
-
- **tap_f** (float, 1.0): Virtual tap at the *from* side
-
- **tap_t** (float, 1.0): Virtual tap at the *to* side
-
+ Always unit vitual taps (unless proven otherwise)
+ :return: tap_f, tap_t
"""
- # resolve how the transformer is actually connected and set the virtual taps
- bus_f_v = self.bus_from.Vnom
- bus_t_v = self.bus_to.Vnom
-
- if bus_f_v == bus_t_v:
- return 1.0, 1.0
- else:
- if bus_f_v > 0.0 and bus_t_v > 0.0:
- return 1.0, bus_f_v / bus_t_v
- else:
- return 1.0, 1.0
+ return 1.0, 1.0
def get_coordinates(self):
"""
diff --git a/src/GridCalEngine/Devices/Parents/controllable_branch_parent.py b/src/GridCalEngine/Devices/Parents/controllable_branch_parent.py
index a0f138865..b410c14fe 100644
--- a/src/GridCalEngine/Devices/Parents/controllable_branch_parent.py
+++ b/src/GridCalEngine/Devices/Parents/controllable_branch_parent.py
@@ -19,8 +19,7 @@
from typing import Union
from GridCalEngine.Devices.Substation.bus import Bus
from GridCalEngine.Devices.Substation.connectivity_node import ConnectivityNode
-from GridCalEngine.enumerations import (TransformerControlType, BuildStatus, TapModuleControl, TapAngleControl,
- SubObjectType, TapChangerTypes)
+from GridCalEngine.enumerations import (BuildStatus, TapModuleControl, TapPhaseControl, SubObjectType, TapChangerTypes)
from GridCalEngine.Devices.Parents.branch_parent import BranchParent
from GridCalEngine.Devices.Branches.tap_changer import TapChanger
from GridCalEngine.Devices.Parents.editable_device import DeviceType
@@ -52,15 +51,16 @@ def __init__(self,
tolerance: float,
vset: float,
Pset: float,
+ Qset: float,
regulation_branch: Union[BranchParent, None],
regulation_bus: Union[Bus, None],
regulation_cn: Union[ConnectivityNode, None],
temp_base: float,
temp_oper: float,
alpha: float,
- control_mode: TransformerControlType,
+ # control_mode: TransformerControlType,
tap_module_control_mode: TapModuleControl,
- tap_angle_control_mode: TapAngleControl,
+ tap_phase_control_mode: TapPhaseControl,
contingency_factor: float,
protection_rating_factor: float,
contingency_enabled: bool,
@@ -116,7 +116,8 @@ def __init__(self,
:param temp_base: Base temperature at which `r` is measured in Ā°C
:param temp_oper: Operating temperature in Ā°C
:param alpha: Thermal constant of the material in Ā°C
- :param control_mode: Control model
+ :param tap_module_control_mode: Tap module Control model
+ :param tap_phase_control_mode: Tap phase Control model
:param contingency_factor: Rating factor in case of contingency
:param contingency_enabled: enabled for contingencies (Legacy)
:param monitor_loading: monitor the loading (used in OPF)
@@ -198,30 +199,40 @@ def __init__(self,
self._tap_module_prof = Profile(default_value=tap_module, data_type=float)
+ self._tap_module_max = tap_module_max
+ self._tap_module_min = tap_module_min
+
+ self._tap_phase_control_mode: TapPhaseControl = tap_phase_control_mode
+ self._tap_phase_control_mode_prof = Profile(default_value=tap_phase_control_mode, data_type=TapPhaseControl)
+
+ self.Pset = Pset
+ self._Pset_prof = Profile(default_value=Pset, data_type=float)
+
+ self.Qset = Qset
+ self._Qset_prof = Profile(default_value=Qset, data_type=float)
+
# Tap angle
self.tap_phase = tap_phase
self._tap_phase_prof = Profile(default_value=tap_phase, data_type=float)
- self.tap_module_max = tap_module_max
- self.tap_module_min = tap_module_min
- self.tap_phase_max = tap_phase_max
- self.tap_phase_min = tap_phase_min
-
- self.vset = vset
- self.Pset = Pset
+ self._tap_phase_max = tap_phase_max
+ self._tap_phase_min = tap_phase_min
- self.control_mode: TransformerControlType = control_mode # Legacy
+ self._tap_module_control_mode: TapModuleControl = tap_module_control_mode
+ self._tap_module_control_mode_prof = Profile(default_value=tap_module_control_mode, data_type=TapModuleControl)
- self.tap_module_control_mode: TapModuleControl = tap_module_control_mode
- self.tap_angle_control_mode: TapAngleControl = tap_angle_control_mode
+ self.vset = vset
+ self._vset_prof = Profile(default_value=vset, data_type=float)
self.regulation_branch: BranchParent = regulation_branch
self.regulation_bus: Bus = regulation_bus
self.regulation_cn: ConnectivityNode = regulation_cn
- self.register(key='R', units='p.u.', tpe=float, definition='Total positive sequence resistance.')
- self.register(key='X', units='p.u.', tpe=float, definition='Total positive sequence reactance.')
+ self.register(key='R', units='p.u.', tpe=float, definition='Total positive sequence resistance.',
+ old_names=['R1', 'Rl'])
+ self.register(key='X', units='p.u.', tpe=float, definition='Total positive sequence reactance.',
+ old_names=['X1', 'Xl'])
self.register(key='G', units='p.u.', tpe=float, definition='Total positive sequence shunt conductance.')
self.register(key='B', units='p.u.', tpe=float, definition='Total positive sequence shunt susceptance.')
self.register(key='R0', units='p.u.', tpe=float, definition='Total zero sequence resistance.')
@@ -241,38 +252,47 @@ def __init__(self,
editable=False)
self.register(key='tap_module', units='', tpe=float, definition='Tap changer module, it a value close to 1.0',
- profile_name='tap_module_prof', old_names=['tap'])
- self.register(key='tap_module_max', units='', tpe=float, definition='Tap changer module max value')
- self.register(key='tap_module_min', units='', tpe=float, definition='Tap changer module min value')
-
- self.register(key='tap_phase', units='rad', tpe=float, definition='Angle shift of the tap changer.',
- profile_name='tap_phase_prof', old_names=['angle'])
- self.register(key='tap_phase_max', units='rad', tpe=float, definition='Max angle.', old_names=['angle_max'])
- self.register(key='tap_phase_min', units='rad', tpe=float, definition='Min angle.', old_names=['angle_min'])
-
- self.register(key='control_mode', units='', tpe=TransformerControlType,
- definition='Control type of the transformer')
+ profile_name='tap_module_prof', old_names=['tap', 'm'])
+ self.register(key='tap_module_max', units='', tpe=float, definition='Tap changer module max value',
+ old_names=['m_max'])
+ self.register(key='tap_module_min', units='', tpe=float, definition='Tap changer module min value',
+ old_names=['m_min'])
self.register(key='tap_module_control_mode', units='', tpe=TapModuleControl,
- definition='Control available with the tap module')
-
- self.register(key='tap_angle_control_mode', units='', tpe=TapAngleControl,
- definition='Control available with the tap angle')
+ definition='Control available with the tap module',
+ profile_name='tap_module_control_mode_prof')
self.register(key='vset', units='p.u.', tpe=float,
- definition='Objective voltage at the "to" side of the bus when regulating the tap.')
+ definition='Objective voltage at the "to" side of the bus when regulating the tap.',
+ profile_name='vset_prof', old_names=['Vdc_set'])
- self.register(key='Pset', units='p.u.', tpe=float,
- definition='Objective power at the "from" side of when regulating the angle.')
-
- self.register(key='regulation_branch', units='', tpe=DeviceType.BranchDevice,
- definition='Branch where the controls are applied.', editable=False)
+ self.register(key='Qset', units='p.u.', tpe=float,
+ definition='Objective power at the selected side.',
+ profile_name='Qset_prof')
self.register(key='regulation_bus', units='', tpe=DeviceType.BusDevice,
- definition='Bus where the regulation is applied.', editable=False)
+ definition='Bus where the regulation is applied.', editable=True)
self.register(key='regulation_cn', units='', tpe=DeviceType.ConnectivityNodeDevice,
- definition='Connectivity node where the regulation is applied.', editable=False)
+ definition='Connectivity node where the regulation is applied.', editable=True)
+
+ self.register(key='tap_phase', units='rad', tpe=float, definition='Angle shift of the tap changer.',
+ profile_name='tap_phase_prof', old_names=['angle', 'theta'])
+ self.register(key='tap_phase_max', units='rad', tpe=float, definition='Max angle.',
+ old_names=['angle_max', 'theta_max'])
+ self.register(key='tap_phase_min', units='rad', tpe=float, definition='Min angle.',
+ old_names=['angle_min', 'theta_min'])
+
+ self.register(key='tap_phase_control_mode', units='', tpe=TapPhaseControl,
+ definition='Control available with the tap angle', old_names=['tap_angle_control_mode'],
+ profile_name='tap_phase_control_mode_prof')
+
+ self.register(key='Pset', units='p.u.', tpe=float,
+ definition='Objective power at the selected side.',
+ profile_name='Pset_prof', old_names=['Pdc_set'])
+
+ # self.register(key='regulation_branch', units='', tpe=DeviceType.BranchDevice,
+ # definition='Branch where the controls are applied.', editable=False)
self.register(key='temp_base', units='ĀŗC', tpe=float, definition='Base temperature at which R was measured.')
self.register(key='temp_oper', units='ĀŗC', tpe=float, definition='Operation temperature to modify R.',
@@ -316,6 +336,91 @@ def tap_phase_prof(self, val: Union[Profile, np.ndarray]):
else:
raise Exception(str(type(val)) + 'not supported to be set into a tap_phase_prof')
+ @property
+ def vset_prof(self) -> Profile:
+ """
+ vset profile
+ :return: Profile
+ """
+ return self._vset_prof
+
+ @vset_prof.setter
+ def vset_prof(self, val: Union[Profile, np.ndarray]):
+ if isinstance(val, Profile):
+ self._vset_prof = val
+ elif isinstance(val, np.ndarray):
+ self._vset_prof.set(arr=val)
+ else:
+ raise Exception(str(type(val)) + 'not supported to be set into a vset_prof')
+
+ @property
+ def Pset_prof(self) -> Profile:
+ """
+ vset profile
+ :return: Profile
+ """
+ return self._Pset_prof
+
+ @Pset_prof.setter
+ def Pset_prof(self, val: Union[Profile, np.ndarray]):
+ if isinstance(val, Profile):
+ self._Pset_prof = val
+ elif isinstance(val, np.ndarray):
+ self._Pset_prof.set(arr=val)
+ else:
+ raise Exception(str(type(val)) + 'not supported to be set into a Pset_prof')
+
+ @property
+ def Qset_prof(self) -> Profile:
+ """
+ vset profile
+ :return: Profile
+ """
+ return self._Qset_prof
+
+ @Qset_prof.setter
+ def Qset_prof(self, val: Union[Profile, np.ndarray]):
+ if isinstance(val, Profile):
+ self._Qset_prof = val
+ elif isinstance(val, np.ndarray):
+ self._Qset_prof.set(arr=val)
+ else:
+ raise Exception(str(type(val)) + 'not supported to be set into a Qset_prof')
+
+ @property
+ def tap_module_control_mode_prof(self) -> Profile:
+ """
+ _tap_module_control_mode_prof profile
+ :return: Profile
+ """
+ return self._tap_module_control_mode_prof
+
+ @tap_module_control_mode_prof.setter
+ def tap_module_control_mode_prof(self, val: Union[Profile, np.ndarray]):
+ if isinstance(val, Profile):
+ self._tap_module_control_mode_prof = val
+ elif isinstance(val, np.ndarray):
+ self._tap_module_control_mode_prof.set(arr=val)
+ else:
+ raise Exception(str(type(val)) + 'not supported to be set into a tap_module_control_mode_prof')
+
+ @property
+ def tap_phase_control_mode_prof(self) -> Profile:
+ """
+ tap_phase_control_mode_prof profile
+ :return: Profile
+ """
+ return self._tap_phase_control_mode_prof
+
+ @tap_phase_control_mode_prof.setter
+ def tap_phase_control_mode_prof(self, val: Union[Profile, np.ndarray]):
+ if isinstance(val, Profile):
+ self._tap_phase_control_mode_prof = val
+ elif isinstance(val, np.ndarray):
+ self._tap_phase_control_mode_prof.set(arr=val)
+ else:
+ raise Exception(str(type(val)) + 'not supported to be set into a tap_phase_control_mode_prof')
+
@property
def temp_oper_prof(self) -> Profile:
"""
@@ -333,6 +438,66 @@ def temp_oper_prof(self, val: Union[Profile, np.ndarray]):
else:
raise Exception(str(type(val)) + 'not supported to be set into a temp_oper_prof')
+ @property
+ def tap_module_min(self):
+ """
+
+ :return:
+ """
+ return self._tap_module_min
+
+ @tap_module_min.setter
+ def tap_module_min(self, val: float):
+ if isinstance(val, float):
+ self._tap_module_min = val
+ else:
+ raise Exception(str(type(val)) + 'not supported to be set into a tap_module_min')
+
+ @property
+ def tap_module_max(self):
+ """
+
+ :return:
+ """
+ return self._tap_module_max
+
+ @tap_module_max.setter
+ def tap_module_max(self, val: float):
+ if isinstance(val, float):
+ self._tap_module_max = val
+ else:
+ raise Exception(str(type(val)) + 'not supported to be set into a tap_module_min')
+
+ @property
+ def tap_phase_min(self):
+ """
+
+ :return:
+ """
+ return self._tap_phase_min
+
+ @tap_phase_min.setter
+ def tap_phase_min(self, val: float):
+ if isinstance(val, float):
+ self._tap_phase_min = val
+ else:
+ raise Exception(str(type(val)) + 'not supported to be set into a tap_module_min')
+
+ @property
+ def tap_phase_max(self):
+ """
+
+ :return:
+ """
+ return self._tap_phase_max
+
+ @tap_phase_max.setter
+ def tap_phase_max(self, val: float):
+ if isinstance(val, float):
+ self._tap_phase_max = val
+ else:
+ raise Exception(str(type(val)) + 'not supported to be set into a tap_module_min')
+
@property
def tap_changer(self) -> TapChanger:
"""
@@ -345,9 +510,39 @@ def tap_changer(self) -> TapChanger:
def tap_changer(self, val: TapChanger):
if isinstance(val, TapChanger):
self._tap_changer = val
+ self.tap_module_min = val.get_tap_module_min()
+ self.tap_module_max = val.get_tap_module_max()
+ self.tap_phase_min = val.get_tap_phase_min()
+ self.tap_phase_max = val.get_tap_phase_max()
else:
raise Exception(str(type(val)) + 'not supported to be set into a tap_changer')
+ @property
+ def tap_phase_control_mode(self) -> TapPhaseControl:
+ """
+ Get the tap phase control mode
+ :return: TapPhaseControl
+ """
+ return self._tap_phase_control_mode
+
+ @tap_phase_control_mode.setter
+ def tap_phase_control_mode(self, val: TapPhaseControl):
+ assert isinstance(val, TapPhaseControl)
+ self._tap_phase_control_mode = val
+
+ @property
+ def tap_module_control_mode(self) -> TapModuleControl:
+ """
+ Get the tap module control mode
+ :return: TapPhaseControl
+ """
+ return self._tap_module_control_mode
+
+ @tap_module_control_mode.setter
+ def tap_module_control_mode(self, val: TapModuleControl):
+ assert isinstance(val, TapModuleControl)
+ self._tap_module_control_mode = val
+
@property
def R_corrected(self):
"""
@@ -385,6 +580,15 @@ def flip(self):
F, T = self.bus_from, self.bus_to
self.bus_to, self.bus_from = F, T
+ def set_tap_controls(self, tap_phase_control_mode: TapPhaseControl, tap_module_control_mode: TapModuleControl):
+ """
+ Set both tap controls
+ :param tap_phase_control_mode: TapPhaseControl
+ :param tap_module_control_mode: TapModuleControl
+ """
+ self.tap_phase_control_mode = tap_phase_control_mode
+ self.tap_module_control_mode = tap_module_control_mode
+
def tap_up(self):
"""
Move the tap changer one position up
diff --git a/src/GridCalEngine/Devices/Parents/editable_device.py b/src/GridCalEngine/Devices/Parents/editable_device.py
index 146b06d3a..fb0cb048e 100644
--- a/src/GridCalEngine/Devices/Parents/editable_device.py
+++ b/src/GridCalEngine/Devices/Parents/editable_device.py
@@ -19,13 +19,13 @@
import numpy as np
from GridCalEngine.Devices.profile import Profile
from typing import List, Dict, AnyStr, Any, Optional, Union, Type, Tuple
-from GridCalEngine.enumerations import (DeviceType, TimeFrame, BuildStatus, WindingsConnection, TransformerControlType,
- ConverterControlType, TapModuleControl, TapAngleControl, SubObjectType,
+from GridCalEngine.enumerations import (DeviceType, TimeFrame, BuildStatus, WindingsConnection,
+ TapModuleControl, TapPhaseControl, SubObjectType,
HvdcControlType, ActionType, AvailableTransferMode, ContingencyMethod,
CpfParametrization, CpfStopAt, InvestmentEvaluationMethod, SolverType,
InvestmentsEvaluationObjectives, NodalCapacityMethod, TimeGrouping,
- ZonalGrouping, MIPSolvers, AcOpfMode, ReactivePowerControlMode,
- BranchImpedanceMode, FaultType)
+ ZonalGrouping, MIPSolvers, AcOpfMode,
+ BranchImpedanceMode, FaultType, TapChangerTypes)
# types that can be assigned to a GridCal property
GCPROP_TYPES = Union[
@@ -38,10 +38,8 @@
Type[HvdcControlType],
Type[BuildStatus],
Type[WindingsConnection],
- Type[TransformerControlType],
- Type[ConverterControlType],
Type[TapModuleControl],
- Type[TapAngleControl],
+ Type[TapPhaseControl],
Type[ActionType],
Type[AvailableTransferMode],
Type[ContingencyMethod],
@@ -55,9 +53,9 @@
Type[ZonalGrouping],
Type[MIPSolvers],
Type[AcOpfMode],
- Type[ReactivePowerControlMode],
Type[BranchImpedanceMode],
- Type[FaultType]
+ Type[FaultType],
+ Type[TapChangerTypes]
]
@@ -662,14 +660,13 @@ def create_profile(self, magnitude, index):
"""
# get the value of the magnitude
snapshot_value = getattr(self, magnitude)
- # val = Profile(default_value=snapshot_value)
- val = self.get_profile(magnitude=magnitude)
+ prof = self.get_profile(magnitude=magnitude)
- val.create_sparse(size=len(index), default_value=snapshot_value)
+ prof.create_sparse(size=len(index), default_value=snapshot_value)
# set the profile variable associated with the magnitude
- setattr(self, self.properties_with_profile[magnitude], val)
+ setattr(self, self.properties_with_profile[magnitude], prof)
def ensure_profiles_exist(self, index):
"""
diff --git a/src/GridCalEngine/Devices/Substation/bus.py b/src/GridCalEngine/Devices/Substation/bus.py
index 186cf7e6b..803c2e01a 100644
--- a/src/GridCalEngine/Devices/Substation/bus.py
+++ b/src/GridCalEngine/Devices/Substation/bus.py
@@ -267,10 +267,9 @@ def determine_bus_type(self) -> BusMode:
return BusMode.PQ_tpe
- def get_voltage_guess(self, logger=None, use_stored_guess=False):
+ def get_voltage_guess(self, use_stored_guess=False) -> complex:
"""
Determine the voltage initial guess
- :param logger: Logger object
:param use_stored_guess: use the stored guess or get one from the devices
:return: voltage guess
"""
diff --git a/src/GridCalEngine/Devices/assets.py b/src/GridCalEngine/Devices/assets.py
index 3fef2db54..29f5ee2f2 100644
--- a/src/GridCalEngine/Devices/assets.py
+++ b/src/GridCalEngine/Devices/assets.py
@@ -3302,9 +3302,9 @@ def delete_investment_groups(self, obj: dev.InvestmentsGroup):
for invst in to_del:
self.delete_investment(invst)
- def get_investmenst_by_groups(self) -> List[Tuple[dev.InvestmentsGroup, List[dev.Investment]]]:
+ def get_investments_by_groups(self) -> List[Tuple[dev.InvestmentsGroup, List[dev.Investment]]]:
"""
- Get a dictionary of investments goups and their
+ Get a dictionary of investments groups and their
:return: list of investment groups and their list of associated investments
"""
d = {e: list() for e in self._investments_groups}
diff --git a/src/GridCalEngine/Devices/sparse_array.py b/src/GridCalEngine/Devices/sparse_array.py
index d11504141..ef74a9d6f 100644
--- a/src/GridCalEngine/Devices/sparse_array.py
+++ b/src/GridCalEngine/Devices/sparse_array.py
@@ -18,6 +18,7 @@
from typing import Dict, Any, Union
import numpy as np
+from enum import Enum
from GridCalEngine.enumerations import DeviceType
from GridCalEngine.basic_structures import Numeric, NumericVec, IntVec
@@ -39,6 +40,8 @@ def check_type(dtype: PROFILE_TYPES, value: Any) -> bool:
assert dtype == int or dtype == float
elif tpe in [float, np.float32, np.float64]:
assert dtype == float
+ elif issubclass(tpe, Enum):
+ assert tpe == dtype # check that the enyum type is the same
else:
assert isinstance(dtype, DeviceType)
@@ -87,8 +90,12 @@ def default_value(self, val):
val2 = None
else:
val2 = val
+ elif issubclass(self._dtype, Enum):
+ # if it is an Enum type, cast the value to the Enum
+ val2 = self._dtype(val)
else:
val2 = val
+
check_type(dtype=self.dtype, value=val2)
self._default_value = val2
diff --git a/src/GridCalEngine/Devices/types.py b/src/GridCalEngine/Devices/types.py
index 91df2486c..b557d1cde 100644
--- a/src/GridCalEngine/Devices/types.py
+++ b/src/GridCalEngine/Devices/types.py
@@ -49,6 +49,13 @@
SeriesReactance
]
+BRANCH_TEMPLATE_TYPES = Union[
+ OverheadLineType,
+ UndergroundLineType,
+ SequenceLineType,
+ TransformerType
+]
+
FLUID_TYPES = Union[
FluidNode,
FluidPath,
diff --git a/src/GridCalEngine/IO/cim/cgmes/cgmes_to_gridcal.py b/src/GridCalEngine/IO/cim/cgmes/cgmes_to_gridcal.py
index b628b99db..f7a121dd0 100644
--- a/src/GridCalEngine/IO/cim/cgmes/cgmes_to_gridcal.py
+++ b/src/GridCalEngine/IO/cim/cgmes/cgmes_to_gridcal.py
@@ -767,7 +767,7 @@ def get_gcdev_ac_transformers(cgmes_model: CgmesCircuit,
# windings = get_windings(cgmes_elm)
# windings: List[PowerTransformerEnd] = list(cgmes_elm.references_to_me['PowerTransformerEnd'])
- rate_mva = rates_dict.get(cgmes_elm.uuid, None) # min PATL rate in MW/MVA
+ rate_mva = rates_dict.get(cgmes_elm.uuid, 9999.0) # min PATL rate in MW/MVA
if len(windings) == 2:
calc_nodes, cns = find_connections(cgmes_elm=cgmes_elm,
@@ -887,7 +887,7 @@ def get_gcdev_ac_transformers(cgmes_model: CgmesCircuit,
gcdev_elm.winding1.X0 = x0
gcdev_elm.winding1.G0 = g0
gcdev_elm.winding1.B0 = b0
- gcdev_elm.winding1.rate = windings[0].ratedS
+ gcdev_elm.winding1.rate = float(windings[0].ratedS)
gcdev_elm.winding1.cn_from = cn_1
gcdev_elm.winding1.cn_to = cn_2
@@ -900,7 +900,7 @@ def get_gcdev_ac_transformers(cgmes_model: CgmesCircuit,
gcdev_elm.winding2.X0 = x0
gcdev_elm.winding2.G0 = g0
gcdev_elm.winding2.B0 = b0
- gcdev_elm.winding2.rate = windings[1].ratedS
+ gcdev_elm.winding2.rate = float(windings[1].ratedS)
gcdev_elm.winding2.cn_from = cn_2
gcdev_elm.winding2.cn_to = cn_3
@@ -913,7 +913,7 @@ def get_gcdev_ac_transformers(cgmes_model: CgmesCircuit,
gcdev_elm.winding3.X0 = x0
gcdev_elm.winding3.G0 = g0
gcdev_elm.winding3.B0 = b0
- gcdev_elm.winding3.rate = windings[2].ratedS
+ gcdev_elm.winding3.rate = float(windings[2].ratedS)
gcdev_elm.winding3.cn_from = cn_3
gcdev_elm.winding3.cn_to = cn_1
@@ -1203,6 +1203,7 @@ def get_gcdev_voltage_levels(cgmes_model: CgmesCircuit,
gcdev_model.add_voltage_level(gcdev_elm)
volt_lev_dict[gcdev_elm.idtag] = gcdev_elm
else:
+ # TODO: this is very weird and cgmes_elm might not be defined
logger.add_error(msg='Base voltage not found', device=str(cgmes_elm.BaseVoltage))
return volt_lev_dict
diff --git a/src/GridCalEngine/IO/gridcal/catalogue.py b/src/GridCalEngine/IO/gridcal/catalogue.py
index ad6442771..0322b04a7 100644
--- a/src/GridCalEngine/IO/gridcal/catalogue.py
+++ b/src/GridCalEngine/IO/gridcal/catalogue.py
@@ -16,7 +16,10 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from typing import List, Tuple
import pandas as pd
-from GridCalEngine.Devices.Branches import TransformerType, SequenceLineType, UndergroundLineType, Wire
+from GridCalEngine.Devices.Branches.transformer_type import TransformerType
+from GridCalEngine.Devices.Branches.sequence_line_type import SequenceLineType
+from GridCalEngine.Devices.Branches.underground_line_type import UndergroundLineType
+from GridCalEngine.Devices.Branches.wire import Wire
from GridCalEngine.Devices.assets import Assets
from GridCalEngine.Devices.multi_circuit import MultiCircuit
from GridCalEngine.enumerations import DeviceType
@@ -82,8 +85,8 @@ def get_wires_catalogue_df(grid: MultiCircuit):
'Stranding': elm.stranding,
'Material': elm.material,
'Diameter [cm]': elm.diameter,
- 'GMR [m]': elm.gmr,
- 'R [Ohm/km]': elm.r,
+ 'GMR [m]': elm.GMR,
+ 'R [Ohm/km]': elm.R,
'Rating [kA]': elm.max_current
})
return pd.DataFrame(data)
diff --git a/src/GridCalEngine/IO/gridcal/json_parser.py b/src/GridCalEngine/IO/gridcal/json_parser.py
index c798ffad1..33023937a 100644
--- a/src/GridCalEngine/IO/gridcal/json_parser.py
+++ b/src/GridCalEngine/IO/gridcal/json_parser.py
@@ -26,8 +26,8 @@
import GridCalEngine.Devices as dev
from GridCalEngine.Devices.profile import Profile
from GridCalEngine.Devices.Parents.editable_device import EditableDevice
-from GridCalEngine.enumerations import (DeviceType, ConverterControlType, HvdcControlType, BuildStatus,
- TransformerControlType)
+from GridCalEngine.enumerations import (DeviceType, HvdcControlType, BuildStatus,
+ TapModuleControl, TapPhaseControl)
def add_to_dict(main_dict: Dict[str, List[Any]], data_to_append: Dict[Any, Any], key: str):
@@ -890,16 +890,16 @@ def parse_json_data_v3(data: dict, logger: Logger):
('vdc_set', 'Vdc_set'),
]
- modes = {0: ConverterControlType.type_0_free,
- 1: ConverterControlType.type_I_1,
- 2: ConverterControlType.type_I_2,
- 3: ConverterControlType.type_I_3,
- 4: ConverterControlType.type_II_4,
- 5: ConverterControlType.type_II_5,
- 6: ConverterControlType.type_III_6,
- 7: ConverterControlType.type_III_7,
- 8: ConverterControlType.type_IV_I,
- 9: ConverterControlType.type_IV_II}
+ # modes = {0: ConverterControlType.type_0_free,
+ # 1: ConverterControlType.type_I_1,
+ # 2: ConverterControlType.type_I_2,
+ # 3: ConverterControlType.type_I_3,
+ # 4: ConverterControlType.type_II_4,
+ # 5: ConverterControlType.type_II_5,
+ # 6: ConverterControlType.type_III_6,
+ # 7: ConverterControlType.type_III_7,
+ # 8: ConverterControlType.type_IV_I,
+ # 9: ConverterControlType.type_IV_II}
for entry in devices["VSC"]:
@@ -1765,12 +1765,15 @@ def save_json_file_v3(file_path: str, circuit: MultiCircuit, simulation_drivers:
circuit.get_dc_lines()]
# Transformer 2W
- control_modes = {TransformerControlType.fixed: 0,
- TransformerControlType.V: 1,
- TransformerControlType.Pf: 2,
- TransformerControlType.PtV: 3,
- TransformerControlType.Qt: 4,
- TransformerControlType.PtQt: 5}
+ control_modes = {TapModuleControl.fixed: None,
+ TapModuleControl.Vm: "Vm",
+ TapModuleControl.Qf: "Qf",
+ TapModuleControl.Qt: "Qt",
+ TapPhaseControl.fixed: None,
+ TapPhaseControl.Pf: "Pf",
+ TapPhaseControl.Pt: "Pt",
+ }
+
elements["Transformer2w"] = [{'id': elm.idtag,
'type': 'transformer',
'phases': 'ps',
@@ -1804,7 +1807,8 @@ def save_json_file_v3(file_path: str, circuit: MultiCircuit, simulation_drivers:
'max_tap_angle': elm.tap_phase_max,
'id_tap_angle_table': "",
- 'control_mode': control_modes[elm.control_mode],
+ 'tap_phase_control_mode': control_modes[elm.tap_phase_control_mode],
+ 'tap_module_control_mode': control_modes[elm.tap_module_control_mode],
# 'min_tap_position': self.tap_changer.min_tap,
# 'max_tap_position': self.tap_changer.max_tap,
@@ -1867,7 +1871,8 @@ def save_json_file_v3(file_path: str, circuit: MultiCircuit, simulation_drivers:
'max_tap_angle': elm.tap_phase_max,
'id_tap_angle_table': "",
- 'control_mode': control_modes[elm.control_mode],
+ 'tap_phase_control_mode': control_modes[elm.tap_phase_control_mode],
+ 'tap_module_control_mode': control_modes[elm.tap_module_control_mode],
# 'min_tap_position': self.tap_changer.min_tap,
# 'max_tap_position': self.tap_changer.max_tap,
@@ -1987,16 +1992,17 @@ def save_json_file_v3(file_path: str, circuit: MultiCircuit, simulation_drivers:
circuit.get_upfc()]
# VSC
- modes = {ConverterControlType.type_0_free: 0,
- ConverterControlType.type_I_1: 1,
- ConverterControlType.type_I_2: 2,
- ConverterControlType.type_I_3: 3,
- ConverterControlType.type_II_4: 4,
- ConverterControlType.type_II_5: 5,
- ConverterControlType.type_III_6: 6,
- ConverterControlType.type_III_7: 7,
- ConverterControlType.type_IV_I: 8,
- ConverterControlType.type_IV_II: 9}
+ # modes = {ConverterControlType.type_0_free: 0,
+ # ConverterControlType.type_I_1: 1,
+ # ConverterControlType.type_I_2: 2,
+ # ConverterControlType.type_I_3: 3,
+ # ConverterControlType.type_II_4: 4,
+ # ConverterControlType.type_II_5: 5,
+ # ConverterControlType.type_III_6: 6,
+ # ConverterControlType.type_III_7: 7,
+ # ConverterControlType.type_IV_I: 8,
+ # ConverterControlType.type_IV_II: 9}
+
elements["VSC"] = [{'id': elm.idtag,
'type': 'vsc',
'phases': 'ps',
diff --git a/src/GridCalEngine/IO/gridcal/pack_unpack.py b/src/GridCalEngine/IO/gridcal/pack_unpack.py
index dcdef0382..31b8f0c95 100644
--- a/src/GridCalEngine/IO/gridcal/pack_unpack.py
+++ b/src/GridCalEngine/IO/gridcal/pack_unpack.py
@@ -26,7 +26,7 @@
from GridCalEngine.Devices.Parents.editable_device import GCProp
from GridCalEngine.Devices.profile import Profile
from GridCalEngine.Devices.types import ALL_DEV_TYPES
-from GridCalEngine.enumerations import (DiagramType, DeviceType, SubObjectType, TransformerControlType)
+from GridCalEngine.enumerations import (DiagramType, DeviceType, SubObjectType, TapPhaseControl, TapModuleControl)
def get_objects_dictionary() -> Dict[str, ALL_DEV_TYPES]:
@@ -735,7 +735,7 @@ def parse_object_type_from_dataframe(main_df: pd.DataFrame,
could_not_fix_it = True
if could_not_fix_it:
- logger.add_error("Could not locate refference",
+ logger.add_error("Could not locate reference",
device=row.get('idtag', 'not provided'),
device_class=template_elm.device_type.value,
device_property=gc_prop.name,
@@ -820,16 +820,9 @@ def parse_object_type_from_dataframe(main_df: pd.DataFrame,
prof.fill(val)
except ValueError:
- skip = False
- if property_name == 'control_mode':
- if property_value == "1:Pt":
- elm.set_snapshot_value(gc_prop.name, TransformerControlType.Pf)
- skip = True
-
- if not skip:
- logger.add_error(f'Cannot cast value to {gc_prop.tpe}',
- device=elm.name,
- value=property_value)
+ logger.add_error(f'Cannot cast value to {gc_prop.tpe}',
+ device=elm.name,
+ value=property_value)
else:
raise Exception(f'Unsupported property type: {gc_prop.tpe}')
@@ -865,10 +858,70 @@ def parse_object_type_from_dataframe(main_df: pd.DataFrame,
if property_name in ['is_controlled', 'Bmin', 'Bmax', 'Vset']:
skip = True
+ if template_elm.device_type == DeviceType.VscDevice:
+ if property_name == 'control_mode':
+ if "Pdc" in property_value:
+ elm.tap_phase_control_mode = TapPhaseControl.Pf
+ skip = True
+ if "Qac" in property_value:
+ elm.tap_phase_module_mode = TapModuleControl.Qf
+ skip = True
+ if "Vac" in property_value:
+ elm.tap_module_control_mode = TapModuleControl.Vm
+ elm.regulation_bus = elm.bus_to
+ skip = True
+ if "Vdc" in property_value:
+ elm.tap_module_control_mode = TapModuleControl.Vm
+ elm.regulation_bus = elm.bus_from
+ skip = True
+
+ if "fixed" in property_value:
+ elm.tap_module_control_mode = TapModuleControl.fixed
+ elm.tap_phase_control_mode = TapPhaseControl.fixed
+ skip = True
+
+ elif property_name == 'Vac_set':
+ if property_value > 0.0:
+ elm.vset = property_value
+ skip = True
+
+ elif property_name == 'Vdc_set':
+ if property_value > 0.0:
+ elm.vset = property_value
+ skip = True
+
+ elif property_name == 'Qac_set':
+ elm.Qset = property_value
+ skip = True
+
+ if template_elm.device_type == DeviceType.Transformer2WDevice:
+ if property_name == 'control_mode':
+ if "Pf" in property_value:
+ elm.tap_phase_control_mode = TapPhaseControl.Pf
+ skip = True
+ if "Pt" in property_value:
+ elm.tap_phase_control_mode = TapPhaseControl.Pt
+ skip = True
+ if "V" in property_value:
+ elm.tap_module_control_mode = TapModuleControl.Vm
+ elm.regulation_bus = elm.bus_to
+ skip = True
+ if "Qf" in property_value:
+ elm.tap_module_control_mode = TapModuleControl.Qf
+ skip = True
+ if "Qt" in property_value:
+ elm.tap_module_control_mode = TapModuleControl.Qt
+ skip = True
+ if "fixed" in property_value:
+ elm.tap_module_control_mode = TapModuleControl.fixed
+ elm.tap_phase_control_mode = TapPhaseControl.fixed
+ skip = True
+
if property_name == 'contingency_enabled':
# this is a branch with the legacy property "contingency_enabled", hence, create a contingency
on_the_fly.create_contingency(elm=elm)
skip = True
+
elif property_name == 'technology':
on_the_fly.create_technology(elm=elm, tech_name=property_value)
skip = True
@@ -920,7 +973,7 @@ def search_and_apply_json_profile(json_entry: Dict[str, Dict[str, Union[str, Uni
property_value: Any,
collection: Union[None, Dict[str, Any]] = None) -> None:
"""
- Search fro the property profiles into the json and apply it
+ Search from the property profiles into the json and apply it
:param json_entry: Json entry of an object
:param gc_prop: GCProp
:param elm: THe device to set the profile into
@@ -986,7 +1039,7 @@ def parse_object_type_from_json(template_elm: ALL_DEV_TYPES,
if isinstance(gc_prop.tpe, DeviceType):
# this is a hyperlink to another object
- # we must look for the refference in elements_dict
+ # we must look for the reference in elements_dict
collection = elements_dict_by_type.get(gc_prop.tpe, None)
if collection is not None:
@@ -1321,7 +1374,7 @@ def parse_gridcal_data(data: Dict[str, Union[str, float, pd.DataFrame, Dict[str,
circuit.set_snapshot_time_unix(val=snapshot_unix_time)
else:
- logger.add_error(msg=f'The file must have time data regardless of the profiles existance')
+ logger.add_error(msg=f'The file must have time data regardless of the profiles existence')
circuit.time_profile = None
# for each element type...
diff --git a/src/GridCalEngine/IO/matpower/matpower_parser.py b/src/GridCalEngine/IO/matpower/matpower_parser.py
index 64be9a236..26ce76fda 100644
--- a/src/GridCalEngine/IO/matpower/matpower_parser.py
+++ b/src/GridCalEngine/IO/matpower/matpower_parser.py
@@ -21,7 +21,7 @@
import pandas as pd
from GridCalEngine.basic_structures import Logger
-from GridCalEngine.enumerations import ConverterControlType
+from GridCalEngine.enumerations import TapModuleControl, TapPhaseControl
from GridCalEngine.Devices.multi_circuit import MultiCircuit
import GridCalEngine.Devices as dev
import GridCalEngine.IO.matpower.matpower_branch_definitions as matpower_branches
@@ -62,10 +62,11 @@ def txt2mat(txt: str, line_splitter=';', to_float=True):
# preprocess lines (remove the comments)
lines2 = list()
for i, line in enumerate(lines):
- if line.lstrip()[0] == '%':
- print('skipping', line)
- else:
+ if line.lstrip()[0] != '%':
lines2.append(line)
+ else:
+ # print('skipping', line)
+ pass
# convert the lines to data
nrows = len(lines2)
@@ -262,7 +263,7 @@ def parse_generators(circuit: MultiCircuit,
# parse the OPF data
opf_table = data['gencost']
- for i in range(opf_table.shape[0]):
+ for i in gen_dict.keys():
curve_model = opf_table[i, 0]
gen_dict[i].StartupCost = opf_table[i, 1]
gen_dict[i].ShutdownCost = opf_table[i, 2]
@@ -313,62 +314,105 @@ def parse_branches_data(circuit: MultiCircuit,
for i in range(n):
f_idx = int(table[i, matpower_branches.F_BUS])
t_idx = int(table[i, matpower_branches.T_BUS])
- f = circuit.buses[bus_idx_dict[f_idx]]
- t = circuit.buses[bus_idx_dict[t_idx]]
+ bus_f = circuit.buses[bus_idx_dict[f_idx]]
+ bus_t = circuit.buses[bus_idx_dict[t_idx]]
if table.shape[1] == 37: # FUBM model
# converter type (I, II, III)
matpower_converter_mode = table[i, matpower_branches.CONV_A]
+ # determine the converter control mode
+ Pfset = table[i, matpower_branches.PF]
+ Ptset = table[i, matpower_branches.PT]
+ Vt_set = table[i, matpower_branches.VT_SET]
+ Vf_set = table[i, matpower_branches.VF_SET] # dc voltage
+ Qfset = table[i, matpower_branches.QF]
+ Qtset = table[i, matpower_branches.QT]
+ m = table[i, matpower_branches.TAP] if table[i, matpower_branches.TAP] > 0 else 1.0
+ tap_phase = np.deg2rad(table[i, matpower_branches.SHIFT])
+ v_set = 1.0
+ Pset = 0.0
+ Qset = 0.0
+ control_bus = None
+
+ is_transformer = (bus_f.Vnom != bus_t.Vnom or
+ (table[i, matpower_branches.TAP] != 1.0 and table[i, matpower_branches.TAP] != 0) or
+ table[i, matpower_branches.SHIFT] != 0.0 or
+ Pfset != 0.0 or
+ Ptset != 0.0 or
+ Qtset != 0.0 or
+ Qfset != 0.0 or
+ Vf_set != 0.0 or
+ Vt_set != 0.0)
+
+ # tau based controls
+ if Pfset != 0.0:
+ tap_phase_control_mode = TapPhaseControl.Pf
+ Pset = Pfset
+ elif Ptset != 0.0:
+ tap_phase_control_mode = TapPhaseControl.Pt
+ Pset = Ptset
+ else:
+ tap_phase_control_mode = TapPhaseControl.fixed
+
+ # m based controls
+ if Qtset != 0.0:
+ tap_module_control_mode = TapModuleControl.Qt
+ Qset = Qtset
+ elif Qfset != 0.0:
+ tap_module_control_mode = TapModuleControl.Qf
+ Qset = Qtset
+ elif Vt_set != 0.0:
+ tap_module_control_mode = TapModuleControl.Vm
+ v_set = Vt_set
+ control_bus = bus_t
+ elif Vf_set != 0.0:
+ tap_module_control_mode = TapModuleControl.Vm
+ v_set = Vf_set
+ control_bus = bus_f
+ else:
+ tap_module_control_mode = TapModuleControl.fixed
+
if matpower_converter_mode > 0: # it is a converter
+ """
+ FUBM control chart
+
+ Type I are the ones making Qf = 0, therefore each DC grid must have at least one
+ Type II control the voltage, and DC grids must have at least one
+ Type III are the droop controlled ones, there may be one
+
+ Control Mode Constraint1 Constraint2 VSC type
+ 1 tau vac -> Vt I
+ 2 Pf Qac -> Qt I
+ 3 Pf vac -> Vt I
+
+ 4 vdc -> Vf Qac -> Qt II
+ 5 vdc -> Vf vac -> Vt II
+
+ 6 vdc droop Qac -> Qt III
+ 7 vdc droop vac -> Vt III
+
+ """
+
# set the from bus as a DC bus
# this is by design of the matpower FUBM model,
# if it is a converter,
# the DC bus is always the "from" bus
- f.is_dc = True
-
- # determine the converter control mode
- Pfset = table[i, matpower_branches.PF]
- Ptset = table[i, matpower_branches.PT]
- Vac_set = table[i, matpower_branches.VT_SET]
- Vdc_set = table[i, matpower_branches.VF_SET]
- Qfset = table[i, matpower_branches.QF]
- Qtset = table[i, matpower_branches.QT]
- m = table[i, matpower_branches.TAP] if table[i, matpower_branches.TAP] > 0 else 1.0
-
- if matpower_converter_mode == 1:
-
- if Pfset != 0.0:
-
- if Qtset != 0.0:
- control_mode = ConverterControlType.type_I_2
-
- elif Vac_set != 0.0:
- control_mode = ConverterControlType.type_I_3
-
- else:
- control_mode = ConverterControlType.type_I_1
-
- else:
- control_mode = ConverterControlType.type_0_free
-
- elif matpower_converter_mode == 2:
+ bus_f.is_dc = True
- if Vac_set == 0.0:
- control_mode = ConverterControlType.type_II_4
- else:
- control_mode = ConverterControlType.type_II_5
+ if matpower_converter_mode == 1: # Type I: normal converter
+ pass
- elif matpower_converter_mode == 3:
- control_mode = ConverterControlType.type_III_6
+ elif matpower_converter_mode == 2: # Type II: voltage controlling converter (slack converter)
+ pass
- elif matpower_converter_mode == 4:
- control_mode = ConverterControlType.type_III_7
+ elif matpower_converter_mode == 3: # Type III: Power-voltage droop
+ pass
else:
- control_mode = ConverterControlType.type_0_free
+ pass
rate = max(table[i, [matpower_branches.RATE_A, matpower_branches.RATE_B, matpower_branches.RATE_C]])
@@ -379,8 +423,8 @@ def parse_branches_data(circuit: MultiCircuit,
else:
monitor_loading = True
- branch = dev.VSC(bus_from=f,
- bus_to=t,
+ branch = dev.VSC(bus_from=bus_f,
+ bus_to=bus_t,
code="{0}_{1}_1".format(f_idx, t_idx),
name='VSC' + str(len(circuit.vsc_devices) + 1),
active=bool(table[i, matpower_branches.BR_STATUS]),
@@ -389,9 +433,9 @@ def parse_branches_data(circuit: MultiCircuit,
tap_module=m,
tap_module_max=table[i, matpower_branches.MA_MAX],
tap_module_min=table[i, matpower_branches.MA_MIN],
- tap_phase=np.deg2rad(table[i, matpower_branches.SHIFT]), # * np.pi / 180,
- tap_phase_max=np.deg2rad(table[i, matpower_branches.ANGMAX]),
- tap_phase_min=np.deg2rad(table[i, matpower_branches.ANGMIN]),
+ tap_phase=tap_phase,
+ tap_phase_max=np.deg2rad(table[i, matpower_branches.SH_MAX]),
+ tap_phase_min=np.deg2rad(table[i, matpower_branches.SH_MIN]),
G0sw=table[i, matpower_branches.GSW],
Beq=table[i, matpower_branches.BEQ],
Beq_max=table[i, matpower_branches.BEQ_MAX],
@@ -399,78 +443,85 @@ def parse_branches_data(circuit: MultiCircuit,
rate=rate,
kdp=table[i, matpower_branches.KDP],
k=table[i, matpower_branches.K2],
- control_mode=control_mode,
- Pfset=Pfset,
- Qfset=Qfset,
- Vac_set=Vac_set if Vac_set > 0 else 1.0,
- Vdc_set=Vdc_set if Vdc_set > 0 else 1.0,
+ tap_phase_control_mode=tap_phase_control_mode,
+ tap_module_control_mode=tap_module_control_mode,
+ Pset=Pset,
+ Qset=Qset,
+ vset=v_set,
alpha1=table[i, matpower_branches.ALPHA1],
alpha2=table[i, matpower_branches.ALPHA2],
alpha3=table[i, matpower_branches.ALPHA3],
monitor_loading=monitor_loading)
+
+ branch.regulation_bus = control_bus
+
circuit.add_vsc(obj=branch)
logger.add_info('Branch as converter', 'Branch {}'.format(str(i + 1)))
- else:
+ elif is_transformer:
+
+ rate = table[i, matpower_branches.RATE_A]
+
+ if rate == 0.0:
+ # in matpower rate=0 means not limited by rating
+ rate = 10000
+ monitor_loading = False
+ else:
+ monitor_loading = True
+
+ branch = dev.Transformer2W(bus_from=bus_f,
+ bus_to=bus_t,
+ code="{0}_{1}_1".format(f_idx, t_idx),
+ name=names[i],
+ r=float(table[i, matpower_branches.BR_R]),
+ x=float(table[i, matpower_branches.BR_X]),
+ g=0.0,
+ b=float(table[i, matpower_branches.BR_B]),
+ rate=rate,
+ active=bool(table[i, matpower_branches.BR_STATUS]),
+ monitor_loading=monitor_loading,
+ tap_module=m,
+ tap_module_max=float(table[i, matpower_branches.MA_MAX]),
+ tap_module_min=float(table[i, matpower_branches.MA_MIN]),
+ tap_phase=tap_phase,
+ tap_phase_max=np.deg2rad(table[i, matpower_branches.SH_MAX]),
+ tap_phase_min=np.deg2rad(table[i, matpower_branches.SH_MIN]),
+ tap_phase_control_mode=tap_phase_control_mode,
+ tap_module_control_mode=tap_module_control_mode,
+ Pset=Pset,
+ Qset=Qset,
+ vset=v_set)
+ branch.regulation_bus = control_bus
+ circuit.add_transformer2w(obj=branch)
+ logger.add_info('Branch as 2w transformer', 'Branch {}'.format(str(i + 1)))
- if (f.Vnom != t.Vnom or
- (table[i, matpower_branches.TAP] != 1.0 and
- table[i, matpower_branches.TAP] != 0) or
- table[i, matpower_branches.SHIFT] != 0.0):
-
- rate = table[i, matpower_branches.RATE_A]
-
- if rate == 0.0:
- # in matpower rate=0 means not limited by rating
- rate = 10000
- monitor_loading = False
- else:
- monitor_loading = True
-
- branch = dev.Transformer2W(bus_from=f,
- bus_to=t,
- code="{0}_{1}_1".format(f_idx, t_idx),
- name=names[i],
- r=float(table[i, matpower_branches.BR_R]),
- x=float(table[i, matpower_branches.BR_X]),
- g=0.0,
- b=float(table[i, matpower_branches.BR_B]),
- rate=rate,
- monitor_loading=monitor_loading,
- tap_module=float(table[i, matpower_branches.TAP]),
- tap_phase=np.deg2rad(table[i, matpower_branches.SHIFT]),
- # * np.pi / 180,
- active=bool(table[i, matpower_branches.BR_STATUS]))
- circuit.add_transformer2w(obj=branch)
- logger.add_info('Branch as 2w transformer', 'Branch {}'.format(str(i + 1)))
+ else:
+ rate = table[i, matpower_branches.RATE_A]
+ if rate == 0.0:
+ # in matpower rate=0 means not limited by rating
+ rate = 10000
+ monitor_loading = False
else:
- rate = table[i, matpower_branches.RATE_A]
-
- if rate == 0.0:
- # in matpower rate=0 means not limited by rating
- rate = 10000
- monitor_loading = False
- else:
- monitor_loading = True
-
- branch = dev.Line(bus_from=f,
- bus_to=t,
- code="{0}_{1}_1".format(f_idx, t_idx),
- name=names[i],
- r=table[i, matpower_branches.BR_R],
- x=table[i, matpower_branches.BR_X],
- b=table[i, matpower_branches.BR_B],
- rate=rate,
- monitor_loading=monitor_loading,
- active=bool(table[i, matpower_branches.BR_STATUS]))
- circuit.add_line(obj=branch, logger=logger)
- logger.add_info('Branch as line', 'Branch {}'.format(str(i + 1)))
+ monitor_loading = True
+
+ branch = dev.Line(bus_from=bus_f,
+ bus_to=bus_t,
+ code="{0}_{1}_1".format(f_idx, t_idx),
+ name=names[i],
+ r=table[i, matpower_branches.BR_R],
+ x=table[i, matpower_branches.BR_X],
+ b=table[i, matpower_branches.BR_B],
+ rate=rate,
+ monitor_loading=monitor_loading,
+ active=bool(table[i, matpower_branches.BR_STATUS]))
+ circuit.add_line(obj=branch, logger=logger)
+ logger.add_info('Branch as line', 'Branch {}'.format(str(i + 1)))
else:
- if (f.Vnom != t.Vnom or
+ if (bus_f.Vnom != bus_t.Vnom or
(table[i, matpower_branches.TAP] != 1.0 and table[i, matpower_branches.TAP] != 0) or
table[i, matpower_branches.SHIFT] != 0.0):
@@ -483,8 +534,8 @@ def parse_branches_data(circuit: MultiCircuit,
else:
monitor_loading = True
- branch = dev.Transformer2W(bus_from=f,
- bus_to=t,
+ branch = dev.Transformer2W(bus_from=bus_f,
+ bus_to=bus_t,
code="{0}_{1}_1".format(f_idx, t_idx),
name=names[i],
r=float(table[i, matpower_branches.BR_R]),
@@ -510,8 +561,8 @@ def parse_branches_data(circuit: MultiCircuit,
else:
monitor_loading = True
- branch = dev.Line(bus_from=f,
- bus_to=t,
+ branch = dev.Line(bus_from=bus_f,
+ bus_to=bus_t,
code="{0}_{1}_1".format(f_idx, t_idx),
name=names[i],
r=table[i, matpower_branches.BR_R],
@@ -604,6 +655,9 @@ def read_matpower_file(filename: str) -> [MultiCircuit, Logger]:
# further process the loaded text
for chunk in chunks:
+ if ',' in chunk:
+ chunk = chunk.replace(',', '')
+
vals = chunk.split('=')
key = vals[0].strip()
diff --git a/src/GridCalEngine/Simulations/ContingencyAnalysis/Methods/helm_contingencies.py b/src/GridCalEngine/Simulations/ContingencyAnalysis/Methods/helm_contingencies.py
index ae3fb096f..ce00acdf3 100644
--- a/src/GridCalEngine/Simulations/ContingencyAnalysis/Methods/helm_contingencies.py
+++ b/src/GridCalEngine/Simulations/ContingencyAnalysis/Methods/helm_contingencies.py
@@ -88,11 +88,7 @@ def calc_V_outage(nc: NumericalCircuit,
Beq=nc.branch_data.Beq[contingency_br_indices],
Cf=nc.branch_data.C_branch_bus_f[contingency_br_indices, :],
Ct=nc.branch_data.C_branch_bus_t[contingency_br_indices, :],
- G0sw=nc.branch_data.G0sw[contingency_br_indices],
- If=If[contingency_br_indices],
- a=nc.branch_data.a[contingency_br_indices],
- b=nc.branch_data.b[contingency_br_indices],
- c=nc.branch_data.c[contingency_br_indices],
+ Gsw=nc.branch_data.G0sw[contingency_br_indices],
Yshunt_bus=np.zeros(nc.nbus),
conn=nc.branch_data.conn[contingency_br_indices],
seq=1,
diff --git a/src/GridCalEngine/Simulations/ContinuationPowerFlow/continuation_power_flow.py b/src/GridCalEngine/Simulations/ContinuationPowerFlow/continuation_power_flow.py
index 6b89cd8b2..e23a96429 100644
--- a/src/GridCalEngine/Simulations/ContinuationPowerFlow/continuation_power_flow.py
+++ b/src/GridCalEngine/Simulations/ContinuationPowerFlow/continuation_power_flow.py
@@ -17,8 +17,8 @@
import numpy as np
-from GridCalEngine.enumerations import ReactivePowerControlMode, CpfParametrization, CpfStopAt
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobian
+from GridCalEngine.enumerations import CpfParametrization, CpfStopAt
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobianVc
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import control_q_direct
from GridCalEngine.Topology.simulation_indices import compile_types
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import (polar_to_rect, compute_power)
@@ -73,8 +73,15 @@ def __len__(self) -> int:
return len(self.V)
-def cpf_p(parametrization: CpfParametrization, step: float, z: Vec, V: CxVec, lam: Vec,
- V_prev: CxVec, lamprv: Vec, pv: IntVec, pq: IntVec, pvpq: IntVec):
+def cpf_p(parametrization: CpfParametrization,
+ step: float,
+ z: Vec,
+ V: CxVec,
+ lam: Vec,
+ V_prev: CxVec,
+ lamprv: Vec,
+ idx_dtheta: IntVec,
+ idx_dVm: IntVec):
"""
Computes the value of the Current Parametrization Function
:param parametrization: Value of option (1: Natural, 2:Arc-length, 3: pseudo arc-length)
@@ -84,9 +91,8 @@ def cpf_p(parametrization: CpfParametrization, step: float, z: Vec, V: CxVec, la
:param lam: scalar lambda value at current solution
:param V_prev: complex bus voltage vector at previous solution
:param lamprv: scalar lambda value at previous solution
- :param pv: vector of indices of PV buses
- :param pq: vector of indices of PQ buses
- :param pvpq: vector of indices of PQ and PV buses
+ :param idx_dtheta: vector of indices of PV|PQ|PQV|P buses
+ :param idx_dVm: vector of indices of PQ|P buses
:return: value of the parametrization function at the current point
"""
@@ -138,8 +144,8 @@ def cpf_p(parametrization: CpfParametrization, step: float, z: Vec, V: CxVec, la
Vm = np.abs(V)
Va_prev = np.angle(V_prev)
Vm_prev = np.abs(V_prev)
- a = np.r_[Va[pvpq], Vm[pq], lam]
- b = np.r_[Va_prev[pvpq], Vm_prev[pq], lamprv]
+ a = np.r_[Va[idx_dtheta], Vm[idx_dVm], lam]
+ b = np.r_[Va_prev[idx_dtheta], Vm_prev[idx_dVm], lamprv]
P = np.sum(np.power(a - b, 2)) - np.power(step, 2)
elif parametrization == CpfParametrization.PseudoArcLength: # pseudo arc length
@@ -148,9 +154,9 @@ def cpf_p(parametrization: CpfParametrization, step: float, z: Vec, V: CxVec, la
Vm = np.abs(V)
Va_prev = np.angle(V_prev)
Vm_prev = np.abs(V_prev)
- a = z[np.r_[pv, pq, nb + pq, 2 * nb]]
- b = np.r_[Va[pvpq], Vm[pq], lam]
- c = np.r_[Va_prev[pvpq], Vm_prev[pq], lamprv]
+ a = z[np.r_[idx_dtheta, nb + idx_dVm, 2 * nb]]
+ b = np.r_[Va[idx_dtheta], Vm[idx_dVm], lam]
+ c = np.r_[Va_prev[idx_dtheta], Vm_prev[idx_dVm], lamprv]
P = np.dot(a, b - c) - step
else:
# natural
@@ -163,7 +169,7 @@ def cpf_p(parametrization: CpfParametrization, step: float, z: Vec, V: CxVec, la
def cpf_p_jac(parametrization: CpfParametrization, z, V, lam, Vprv, lamprv,
- pv: IntVec, pq: IntVec, pvpq: IntVec):
+ idx_dtheta: IntVec, idx_dVm: IntVec):
"""
Computes partial derivatives of Current Parametrization Function (CPF).
:param parametrization:
@@ -172,9 +178,8 @@ def cpf_p_jac(parametrization: CpfParametrization, z, V, lam, Vprv, lamprv,
:param lam: scalar lambda value at current solution
:param Vprv: complex bus voltage vector at previous solution
:param lamprv: scalar lambda value at previous solution
- :param pv: vector of indices of PV buses
- :param pq: vector of indices of PQ buses
- :param pvpq: vector of indices of PQ and PV buses
+ :param idx_dtheta: vector of indices of PV|PQ|PQV|P buses
+ :param idx_dVm: vector of indices of PQ|P buses
:return: partial of parametrization function w.r.t. voltages
partial of parametrization function w.r.t. lambda
"""
@@ -218,9 +223,7 @@ def cpf_p_jac(parametrization: CpfParametrization, z, V, lam, Vprv, lamprv,
"""
if parametrization == CpfParametrization.Natural: # natural
- npv = len(pv)
- npq = len(pq)
- dP_dV = np.zeros(npv + 2 * npq)
+ dP_dV = np.zeros(len(idx_dtheta) + len(idx_dVm))
if lam >= lamprv:
dP_dlam = 1.0
else:
@@ -231,7 +234,7 @@ def cpf_p_jac(parametrization: CpfParametrization, z, V, lam, Vprv, lamprv,
Vm = np.abs(V)
Vaprv = np.angle(Vprv)
Vmprv = np.abs(Vprv)
- dP_dV = 2.0 * (np.r_[Va[pvpq], Vm[pq]] - np.r_[Vaprv[pvpq], Vmprv[pq]])
+ dP_dV = 2.0 * (np.r_[Va[idx_dtheta], Vm[idx_dVm]] - np.r_[Vaprv[idx_dtheta], Vmprv[idx_dVm]])
if lam == lamprv: # first step
dP_dlam = 1.0 # avoid singular Jacobian that would result from [dP_dV, dP_dlam] = 0
@@ -240,19 +243,21 @@ def cpf_p_jac(parametrization: CpfParametrization, z, V, lam, Vprv, lamprv,
elif parametrization == CpfParametrization.PseudoArcLength: # pseudo arc length
nb = len(V)
- dP_dV = z[np.r_[pv, pq, nb + pq]]
+ dP_dV = z[np.r_[idx_dtheta, nb + idx_dVm]]
dP_dlam = z[2 * nb]
else:
# pseudo arc length for any other case
nb = len(V)
- dP_dV = z[np.r_[pv, pq, nb + pq]]
+ dP_dV = z[np.r_[idx_dtheta, nb + idx_dVm]]
dP_dlam = z[2 * nb]
return dP_dV, dP_dlam
-def predictor(V, lam, Ybus, Sxfr, pv: IntVec, pq: IntVec, step: float, z, Vprv, lamprv,
+def predictor(V, lam, Ybus, Sxfr,
+ idx_dtheta: IntVec, idx_dVm: IntVec, idx_dP: IntVec, idx_dQ: IntVec,
+ step: float, z, Vprv, lamprv,
parametrization: CpfParametrization):
"""
Computes a prediction (approximation) to the next solution of the
@@ -261,8 +266,10 @@ def predictor(V, lam, Ybus, Sxfr, pv: IntVec, pq: IntVec, step: float, z, Vprv,
:param lam: scalar lambda value at current solution
:param Ybus: complex bus admittance matrix
:param Sxfr: complex vector of scheduled transfers (difference between bus Injections in base and target cases)
- :param pv: vector of indices of PV buses
- :param pq: vector of indices of PQ buses
+ :param idx_dtheta: vector of indices of PV|PQ|PQV|P buses
+ :param idx_dVm: vector of indices of PQ|P buses
+ :param idx_dP: vector of indices of PV|PQ|PQV|P buses
+ :param idx_dQ: vector of indices of PQ|PQV buses
:param step: continuation step length
:param z: normalized tangent prediction vector from previous step
:param Vprv: complex bus voltage vector at previous solution
@@ -275,17 +282,20 @@ def predictor(V, lam, Ybus, Sxfr, pv: IntVec, pq: IntVec, step: float, z, Vprv,
# sizes
nb = len(V)
- npv = len(pv)
- npq = len(pq)
- pvpq = np.r_[pv, pq]
- nj = npv + npq * 2
+ # npv = len(pv)
+ # npq = len(pq)
+ # pvpq = np.r_[pv, pq]
+ # nj = npv + npq * 2
# compute Jacobian for the power flow equations
- J = AC_jacobian(Ybus, V, pvpq, pq)
+ J = AC_jacobianVc(Ybus, V, idx_dtheta, idx_dVm, idx_dQ)
- dF_dlam = -np.r_[Sxfr[pvpq].real, Sxfr[pq].imag]
+ dF_dlam = -np.r_[
+ Sxfr[idx_dP].real,
+ Sxfr[idx_dQ].imag
+ ]
- dP_dV, dP_dlam = cpf_p_jac(parametrization, z, V, lam, Vprv, lamprv, pv, pq, pvpq)
+ dP_dV, dP_dlam = cpf_p_jac(parametrization, z, V, lam, Vprv, lamprv, idx_dtheta, idx_dVm)
# linear operator for computing the tangent predictor
'''
@@ -306,31 +316,36 @@ def predictor(V, lam, Ybus, Sxfr, pv: IntVec, pq: IntVec, step: float, z, Vprv,
Vm_prev = np.abs(V)
# compute normalized tangent predictor
- s = np.zeros(npv + 2 * npq + 1)
+ s = np.zeros(len(idx_dP) + len(idx_dQ) + 1)
# increase in the direction of lambda
- s[npv + 2 * npq] = 1
+ s[len(idx_dP) + len(idx_dQ)] = 1
# tangent vector
- z[np.r_[pvpq, nb + pq, 2 * nb]] = spsolve_csc(J2, s)
+ z[np.r_[idx_dP, nb + idx_dQ, 2 * nb]], ok = spsolve_csc(J2, s)
- # normalize_string tangent predictor (dividing by the euclidean norm)
- z /= np.linalg.norm(z)
+ if ok:
+ # normalize_string tangent predictor (dividing by the euclidean norm)
+ z /= np.linalg.norm(z)
- Va0 = Va_prev
- Vm0 = Vm_prev
- # lam0 = lam
+ Va0 = Va_prev
+ Vm0 = Vm_prev
+ # lam0 = lam
- # prediction for next step
- Va0[pvpq] = Va_prev[pvpq] + step * z[pvpq]
- Vm0[pq] = Vm_prev[pq] + step * z[pq + nb]
- lam0 = lam + step * z[2 * nb]
- V0 = Vm0 * np.exp(1j * Va0)
+ # prediction for next step
+ Va0[idx_dtheta] = Va_prev[idx_dtheta] + step * z[idx_dtheta]
+ Vm0[idx_dVm] = Vm_prev[idx_dVm] + step * z[idx_dVm + nb]
+ lam0 = lam + step * z[2 * nb]
+ V0 = Vm0 * np.exp(1j * Va0)
- return V0, lam0, z
+ return V0, lam0, z
+ else:
+ return V, lam, z
-def corrector(Ybus, Sbus, V0, pv: IntVec, pq: IntVec, lam0, Sxfr, Vprv, lamprv, z, step, parametrization, tol, max_it,
+def corrector(Ybus, Sbus: CxVec, V0: CxVec,
+ idx_dtheta: IntVec, idx_dVm: IntVec, idx_dP: IntVec, idx_dQ: IntVec,
+ lam0, Sxfr, Vprv, lamprv, z, step, parametrization, tol, max_it,
verbose, mu_0=1.0, acceleration_parameter=0.5):
"""
Solves the corrector step of a continuation power flow using a full Newton method
@@ -352,8 +367,10 @@ def corrector(Ybus, Sbus, V0, pv: IntVec, pq: IntVec, lam0, Sxfr, Vprv, lamprv,
:param Ybus: Admittance matrix (CSC sparse)
:param Sbus: Bus power Injections
:param V0: Bus initial voltages
- :param pv: list of pv nodes
- :param pq: list of pq nodes
+ :param idx_dtheta: vector of indices of PV|PQ|PQV|P buses
+ :param idx_dVm: vector of indices of PQ|P buses
+ :param idx_dP: vector of indices of PV|PQ|PQV|P buses
+ :param idx_dQ: vector of indices of PQ|PQV buses
:param lam0: initial value of lambda (loading parameter)
:param Sxfr: [delP+j*delQ] transfer/loading vector for all buses
:param Vprv: final complex V corrector solution from previous continuation step
@@ -380,16 +397,16 @@ def corrector(Ybus, Sbus, V0, pv: IntVec, pq: IntVec, lam0, Sxfr, Vprv, lamprv,
# dlam = 0
# set up indexing for updating V
- npv = len(pv)
- npq = len(pq)
- pvpq = np.r_[pv, pq]
- nj = npv + npq * 2
+ # npv = len(pv)
+ # npq = len(pq)
+ # pvpq = np.r_[pv, pq]
+ # nj = npv + npq * 2
# j1:j2 - V angle of pv and pq buses
j1 = 0
- j2 = npv + npq
+ j2 = len(idx_dtheta)
# j2:j3 - V mag of pq buses
- j3 = j2 + npq
+ j3 = j2 + len(idx_dVm)
# evaluate F(x0, lam0), including Sxfr transfer/loading
Scalc = V * np.conj(Ybus * V)
@@ -397,10 +414,14 @@ def corrector(Ybus, Sbus, V0, pv: IntVec, pq: IntVec, lam0, Sxfr, Vprv, lamprv,
# F = np.r_[mismatch[pvpq].real, mismatch[pq].imag]
# evaluate P(x0, lambda0)
- P = cpf_p(parametrization, step, z, V, lam, Vprv, lamprv, pv, pq, pvpq)
+ P = cpf_p(parametrization, step, z, V, lam, Vprv, lamprv, idx_dtheta, idx_dVm)
# augment F(x,lambda) with P(x,lambda)
- F = np.r_[mismatch[pvpq].real, mismatch[pq].imag, P]
+ F = np.r_[
+ mismatch[idx_dP].real,
+ mismatch[idx_dQ].imag,
+ P
+ ]
# check tolerance
normF = np.linalg.norm(F, np.Inf)
@@ -408,7 +429,10 @@ def corrector(Ybus, Sbus, V0, pv: IntVec, pq: IntVec, lam0, Sxfr, Vprv, lamprv,
if verbose:
print('\nConverged!\n')
- dF_dlam = -np.r_[Sxfr[pvpq].real, Sxfr[pq].imag]
+ dF_dlam = -np.r_[
+ Sxfr[idx_dP].real,
+ Sxfr[idx_dQ].imag
+ ]
# do Newton iterations
while not converged and i < max_it:
@@ -417,9 +441,9 @@ def corrector(Ybus, Sbus, V0, pv: IntVec, pq: IntVec, lam0, Sxfr, Vprv, lamprv,
i += 1
# evaluate Jacobian
- J = AC_jacobian(Ybus, V, pvpq, pq)
+ J = AC_jacobianVc(Ybus, V, idx_dtheta, idx_dVm, idx_dQ)
- dP_dV, dP_dlam = cpf_p_jac(parametrization, z, V, lam, Vprv, lamprv, pv, pq, pvpq)
+ dP_dV, dP_dlam = cpf_p_jac(parametrization, z, V, lam, Vprv, lamprv, idx_dtheta, idx_dVm)
# augment J with real/imag - Sxfr and z^T
'''
@@ -439,9 +463,9 @@ def corrector(Ybus, Sbus, V0, pv: IntVec, pq: IntVec, lam0, Sxfr, Vprv, lamprv,
J = extend(J, dF_dlam, dP_dV, dP_dlam)
# compute update step
- dx = spsolve_csc(J, F)
- dVa[pvpq] = dx[j1:j2]
- dVm[pq] = dx[j2:j3]
+ dx, ok = spsolve_csc(J, F)
+ dVa[idx_dtheta] = dx[j1:j2]
+ dVm[idx_dVm] = dx[j2:j3]
dlam = dx[j3]
# set the restoration values
@@ -475,10 +499,10 @@ def corrector(Ybus, Sbus, V0, pv: IntVec, pq: IntVec, lam0, Sxfr, Vprv, lamprv,
mismatch = Scalc - Sbus - lam * Sxfr
# evaluate the parametrization function P(x, lambda)
- P = cpf_p(parametrization, step, z, V, lam, Vprv, lamprv, pv, pq, pvpq)
+ P = cpf_p(parametrization, step, z, V, lam, Vprv, lamprv, idx_dtheta, idx_dVm)
# compose the mismatch vector
- F = np.r_[mismatch[pvpq].real, mismatch[pq].imag, P]
+ F = np.r_[mismatch[idx_dP].real, mismatch[idx_dQ].imag, P]
# check for convergence
normF_new = np.linalg.norm(F, np.Inf)
@@ -513,9 +537,10 @@ def corrector(Ybus, Sbus, V0, pv: IntVec, pq: IntVec, lam0, Sxfr, Vprv, lamprv,
def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_target,
V, distributed_slack, bus_installed_power,
- vd, pv: IntVec, pq: IntVec, step, approximation_order: CpfParametrization,
+ vd: IntVec, pv: IntVec, pq: IntVec, pqv: IntVec, p: IntVec,
+ step: float, approximation_order: CpfParametrization,
adapt_step, step_min, step_max, error_tol=1e-3, tol=1e-6, max_it=20,
- stop_at=CpfStopAt.Nose, control_q=ReactivePowerControlMode.NoControl,
+ stop_at=CpfStopAt.Nose, control_q=False, control_remote_voltage: bool = True,
qmax_bus=None, qmin_bus=None, original_bus_types=None, base_overload_number=0,
verbose=False, call_back_fx=None) -> CpfNumericResults:
"""
@@ -536,6 +561,8 @@ def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_t
:param vd: Array of slack bus indices
:param pv: Array of pv bus indices
:param pq: Array of pq bus indices
+ :param pqv: Array of p bus indices
+ :param p: Array of p bus indices
:param step: Adaptation step
:param approximation_order: order of the approximation {Natural, Arc, Pseudo arc}
:param adapt_step: use adaptive step size?
@@ -546,6 +573,7 @@ def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_t
:param max_it: Maximum iterations
:param stop_at: Value of Lambda to stop at. It can be a number or {'NOSE', 'FULL'}
:param control_q: Type of reactive power control
+ :param control_remote_voltage: Apply remote voltage controls?
:param qmax_bus: Array of maximum reactive power per node
:param qmin_bus: Array of minimum reactive power per node
:param original_bus_types: array of bus types
@@ -578,7 +606,13 @@ def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_t
V_prev = V # V at previous step
continuation = True
cont_steps = 0
- pvpq = np.r_[pv, pq]
+ # pvpq = np.r_[pv, pq]
+
+ idx_dtheta = np.r_[pv, pq, pqv, p]
+ idx_dVm = np.r_[pq, p]
+ idx_dP = idx_dtheta
+ idx_dQ = np.r_[pq, pqv]
+
bus_types = original_bus_types.copy()
z = np.zeros(2 * nb + 1)
@@ -599,8 +633,10 @@ def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_t
lam=lam,
Ybus=Ybus,
Sxfr=Sxfr,
- pv=pv,
- pq=pq,
+ idx_dtheta=idx_dtheta,
+ idx_dVm=idx_dVm,
+ idx_dP=idx_dP,
+ idx_dQ=idx_dQ,
step=step,
z=z,
Vprv=V_prev,
@@ -615,8 +651,10 @@ def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_t
V, success, i, lam, normF, Scalc = corrector(Ybus=Ybus,
Sbus=Sbus_base,
V0=V0,
- pv=pv,
- pq=pq,
+ idx_dtheta=idx_dtheta,
+ idx_dVm=idx_dVm,
+ idx_dP=idx_dP,
+ idx_dQ=idx_dQ,
lam0=lam0,
Sxfr=Sxfr,
Vprv=V_prev,
@@ -640,8 +678,10 @@ def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_t
V, success, i, lam, normF, Scalc = corrector(Ybus=Ybus,
Sbus=Sbus_base + delta,
V0=V,
- pv=pv,
- pq=pq,
+ idx_dtheta=idx_dtheta,
+ idx_dVm=idx_dVm,
+ idx_dP=idx_dP,
+ idx_dQ=idx_dQ,
lam0=lam0,
Sxfr=Sxfr,
Vprv=V_prev,
@@ -679,7 +719,7 @@ def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_t
print(V)
# Check controls
- if control_q == ReactivePowerControlMode.Direct:
+ if control_q == True:
Vm = np.abs(V)
(V,
@@ -707,7 +747,7 @@ def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_t
Sxfr = Sbus_target - Sbus
- vd, pq, pv, pqv, p, pqpv = compile_types(Pbus=Sbus.real, types=types_new)
+ vd, pq, pv, pqv, p, pqpv = compile_types(Pbus=Sbus.real, types=types_new,)
else:
if verbose:
print('Q controls Ok')
@@ -752,7 +792,8 @@ def continuation_nr(Ybus, Cf, Ct, Yf, Yt, branch_rates, Sbase, Sbus_base, Sbus_t
if adapt_step and continuation:
# Adapt step size
- fx = np.r_[np.angle(V[pq]), np.abs(V[pvpq]), lam] - np.r_[np.angle(V0[pq]), np.abs(V0[pvpq]), lam0]
+ fx = (np.r_[np.angle(V[idx_dtheta]), np.abs(V[idx_dVm]), lam]
+ - np.r_[np.angle(V0[idx_dtheta]), np.abs(V0[idx_dVm]), lam0])
cpf_error = np.linalg.norm(fx, np.Inf)
if cpf_error == 0:
diff --git a/src/GridCalEngine/Simulations/ContinuationPowerFlow/continuation_power_flow_driver.py b/src/GridCalEngine/Simulations/ContinuationPowerFlow/continuation_power_flow_driver.py
index fb96da52c..defa34c1c 100644
--- a/src/GridCalEngine/Simulations/ContinuationPowerFlow/continuation_power_flow_driver.py
+++ b/src/GridCalEngine/Simulations/ContinuationPowerFlow/continuation_power_flow_driver.py
@@ -98,9 +98,9 @@ def run_at(self, t_idx: Union[int, None] = None) -> ContinuationPowerFlowResults
result_series = list()
- for island in islands:
+ for is_idx, island in enumerate(islands):
- self.report_text('Running voltage collapse at circuit ' + str(nc) + '...')
+ self.report_text(f'Running voltage collapse at circuit island {is_idx + 1}...')
if len(island.vd) > 0 and len(island.pqpv) > 0:
results = continuation_nr(Ybus=island.Ybus,
@@ -118,6 +118,8 @@ def run_at(self, t_idx: Union[int, None] = None) -> ContinuationPowerFlowResults
vd=island.vd,
pv=island.pv,
pq=island.pq,
+ pqv=island.pqv,
+ p=island.p,
step=self.options.step,
approximation_order=self.options.approximation_order,
adapt_step=self.options.adapt_step,
@@ -128,6 +130,7 @@ def run_at(self, t_idx: Union[int, None] = None) -> ContinuationPowerFlowResults
max_it=self.options.max_it,
stop_at=self.options.stop_at,
control_q=self.pf_options.control_Q,
+ control_remote_voltage=self.pf_options.control_remote_voltage,
qmax_bus=island.Qmax_bus,
qmin_bus=island.Qmin_bus,
original_bus_types=island.bus_types,
diff --git a/src/GridCalEngine/Simulations/Derivatives/__init__.py b/src/GridCalEngine/Simulations/Derivatives/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/ac_jacobian.py b/src/GridCalEngine/Simulations/Derivatives/ac_jacobian.py
similarity index 73%
rename from src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/ac_jacobian.py
rename to src/GridCalEngine/Simulations/Derivatives/ac_jacobian.py
index f33e0d341..ed6bff711 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/ac_jacobian.py
+++ b/src/GridCalEngine/Simulations/Derivatives/ac_jacobian.py
@@ -1,41 +1,27 @@
-# Copyright 1996-2015 PSERC. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-from typing import Any
-
-# Copyright (c) 2016-2020 by University of Kassel and Fraunhofer Institute for for Energy Economics
-# and Energy System Technology (IEE) Kassel and individual contributors (see AUTHORS file for details).
-# All rights reserved.
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
#
-# Redistribution and use in source and binary forms, with or without modification, are permitted
-# provided that the following conditions are met:
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
#
-# 1. Redistributions of source code must retain the above copyright notice, this list of conditions
-# and the following disclaimer.
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-# 2. Redistributions in binary form must reproduce the above copyright notice, this list of
-# conditions and the following disclaimer in the documentation and/or other materials provided
-# with the distribution.
-#
-# 3. Neither the name of the copyright holder nor the names of its contributors may be used to
-# endorse or promote products derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
-# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from numba import jit
from numpy import float64, int32
import numpy as np
from scipy.sparse import csr_matrix, csc_matrix
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.derivatives import (dSbus_dV_numba_sparse_csc,
- dSbus_dV_numba_sparse_csr)
-from GridCalEngine.basic_structures import Vec, IntVec, CxVec
-from GridCalEngine.Utils.Sparse.csc2 import create_lookup, CSC
+from GridCalEngine.Simulations.Derivatives.csr_derivatives import dSbus_dV_numba_sparse_csr
+from GridCalEngine.Simulations.Derivatives.csc_derivatives import dSbus_dV_numba_sparse_csc
+from GridCalEngine.basic_structures import IntVec, CxVec
+from GridCalEngine.Utils.Sparse.csc2 import make_lookup, CSC
@jit(nopython=True, cache=True)
@@ -91,7 +77,7 @@ def create_J_csr(nbus, dS_dVm_x, dS_dVa_x, Yp, Yj, pvpq, pq, Jx, Jj, Jp): # pra
Note: The row and column pointer of of dVm and dVa are the same as the one from Ybus
"""
- pvpq_lookup = create_lookup(nbus, pvpq)
+ pvpq_lookup = make_lookup(nbus, pvpq)
# get length of vectors
npvpq = len(pvpq)
@@ -190,7 +176,7 @@ def AC_jacobian_csr(Ybus: csr_matrix, V: CxVec, pvpq: IntVec, pq: IntVec) -> csc
return csr_matrix((Jx, Jj, Jp), shape=(nj, nj)).tocsc()
-@jit(nopython=True, cache=True)
+@jit(nopython=True)
def create_J_csc(nbus, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec, pvpq, pq) -> CSC:
"""
Calculates Jacobian in CSC format.
@@ -220,8 +206,8 @@ def create_J_csc(nbus, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec, pvpq, pq) ->
# Note: The row and column pointer of of dVm and dVa are the same as the one from Ybus
- lookup_pvpq = create_lookup(nbus, pvpq)
- lookup_pq = create_lookup(nbus, pq)
+ lookup_dP = make_lookup(nbus, pvpq)
+ lookup_dQ = make_lookup(nbus, pq)
# get length of vectors
npvpq = len(pvpq)
@@ -229,6 +215,7 @@ def create_J_csc(nbus, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec, pvpq, pq) ->
# nonzeros in J
nnz = 0
p = 0
+ J.indptr[p] = nnz
# J1 and J3 -----------------------------------------------------------------------------------------
for j in pvpq: # columns
@@ -236,7 +223,7 @@ def create_J_csc(nbus, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec, pvpq, pq) ->
# J1
for k in range(Yp[j], Yp[j + 1]): # rows
i = Yi[k]
- ii = lookup_pvpq[i]
+ ii = lookup_dP[i]
if pvpq[ii] == i:
J.data[nnz] = dS_dVa_x[k].real
@@ -246,7 +233,7 @@ def create_J_csc(nbus, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec, pvpq, pq) ->
# J3
for k in range(Yp[j], Yp[j + 1]): # rows
i = Yi[k]
- ii = lookup_pq[i]
+ ii = lookup_dQ[i]
if pq[ii] == i:
J.data[nnz] = dS_dVa_x[k].imag
@@ -262,7 +249,7 @@ def create_J_csc(nbus, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec, pvpq, pq) ->
# J2
for k in range(Yp[j], Yp[j + 1]): # rows
i = Yi[k]
- ii = lookup_pvpq[i]
+ ii = lookup_dP[i]
if pvpq[ii] == i:
J.data[nnz] = dS_dVm_x[k].real
@@ -272,7 +259,7 @@ def create_J_csc(nbus, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec, pvpq, pq) ->
# J4
for k in range(Yp[j], Yp[j + 1]): # rows
i = Yi[k]
- ii = lookup_pq[i]
+ ii = lookup_dQ[i]
if pq[ii] == i:
J.data[nnz] = dS_dVm_x[k].imag
@@ -309,54 +296,56 @@ def AC_jacobian(Ybus: csc_matrix, V: CxVec, pvpq: IntVec, pq: IntVec) -> CSC:
@jit(nopython=True)
def create_J_vc_csc(nbus: int, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec,
- block1_idx: IntVec, block2_idx: IntVec, block3_idx: IntVec) -> CSC:
+ idx_dtheta: IntVec, idx_dVm: IntVec, idx_dP: IntVec, idx_dQ: IntVec) -> CSC:
"""
Calculates Jacobian in CSC format.
J has the shape
- bl1 bl2
- bl1 | dP_dVa | dP_dVm |
- bl3 | dQ_dVa | dQ_dVm |
+ idx_dtheta idx_dVm
+ idx_dP | dP_dVa | dP_dVm |
+ idx_dQ | dQ_dVa | dQ_dVm |
:param nbus:
:param Yx:
:param Yp:
:param Yi:
:param V:
- :param block1_idx: pv, pq, p, pqv
- :param block2_idx: pq, p
- :param block3_idx: pq, pqv
+ :param idx_dtheta: pv, pq, p, pqv
+ :param idx_dVm: pq, p
+ :param idx_dP: pv, pq, p, pqv
+ :param idx_dQ: pq, pqv
:return: Jacobina matrix
"""
# create Jacobian from fast calc of dS_dV
dS_dVm_x, dS_dVa_x = dSbus_dV_numba_sparse_csc(Yx, Yp, Yi, V, np.abs(V))
- nj = len(block1_idx) + len(block2_idx)
+ nj = len(idx_dtheta) + len(idx_dVm)
nnz_estimate = 5 * len(dS_dVm_x)
J = CSC(nj, nj, nnz_estimate, False)
# Note: The row and column pointer of of dVm and dVa are the same as the one from Ybus
- lookup_block1 = create_lookup(nbus, block1_idx)
- lookup_block3 = create_lookup(nbus, block3_idx)
+ lookup_dP = make_lookup(nbus, idx_dP)
+ lookup_dQ = make_lookup(nbus, idx_dQ)
# get length of vectors
- n_no_slack = len(block1_idx)
+ n_no_slack = len(idx_dtheta)
# nonzeros in J
nnz = 0
p = 0
+ J.indptr[p] = nnz
# J1 and J3 -----------------------------------------------------------------------------------------
- for j in block1_idx: # columns
+ for j in idx_dtheta: # columns
# J1
for k in range(Yp[j], Yp[j + 1]): # rows
i = Yi[k]
- ii = lookup_block1[i]
+ ii = lookup_dP[i]
- if block1_idx[ii] == i:
+ if idx_dtheta[ii] == i:
J.data[nnz] = dS_dVa_x[k].real
J.indices[nnz] = ii
nnz += 1
@@ -364,9 +353,9 @@ def create_J_vc_csc(nbus: int, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec,
# J3
for k in range(Yp[j], Yp[j + 1]): # rows
i = Yi[k]
- ii = lookup_block3[i]
+ ii = lookup_dQ[i]
- if block3_idx[ii] == i:
+ if idx_dQ[ii] == i:
J.data[nnz] = dS_dVa_x[k].imag
J.indices[nnz] = ii + n_no_slack
nnz += 1
@@ -375,14 +364,14 @@ def create_J_vc_csc(nbus: int, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec,
J.indptr[p] = nnz
# J2 and J4 -----------------------------------------------------------------------------------------
- for j in block2_idx: # columns
+ for j in idx_dVm: # columns
# J2
- for k in range(Yp[j], Yp[j + 1]): # rows
- i = Yi[k]
- ii = lookup_block1[i]
+ for k in range(Yp[j], Yp[j + 1]):
+ i = Yi[k] # row at Y
+ ii = lookup_dP[i]
- if block1_idx[ii] == i:
+ if idx_dtheta[ii] == i:
J.data[nnz] = dS_dVm_x[k].real
J.indices[nnz] = ii
nnz += 1
@@ -390,9 +379,9 @@ def create_J_vc_csc(nbus: int, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec,
# J4
for k in range(Yp[j], Yp[j + 1]): # rows
i = Yi[k]
- ii = lookup_block3[i]
+ ii = lookup_dQ[i]
- if block3_idx[ii] == i:
+ if idx_dQ[ii] == i:
J.data[nnz] = dS_dVm_x[k].imag
J.indices[nnz] = ii + n_no_slack
nnz += 1
@@ -405,14 +394,14 @@ def create_J_vc_csc(nbus: int, Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec,
return J
-def AC_jacobianVc(Ybus: csc_matrix, V: CxVec, block1_idx: IntVec, block2_idx: IntVec, block3_idx: IntVec) -> CSC:
+def AC_jacobianVc(Ybus: csc_matrix, V: CxVec, idx_dtheta: IntVec, idx_dVm: IntVec, idx_dQ: IntVec) -> CSC:
"""
Create the AC Jacobian function with no embedded controls
:param Ybus: Ybus matrix in CSC format
:param V: Voltages vector
- :param block1_idx: pv, pq, p, pqv
- :param block2_idx: pq, p
- :param block3_idx: pq, pqv
+ :param idx_dtheta: pv, pq, p, pqv
+ :param idx_dVm: pq, p
+ :param idx_dQ: pq, pqv
:return: Jacobian Matrix in CSC format
"""
if Ybus.format != 'csc':
@@ -421,6 +410,6 @@ def AC_jacobianVc(Ybus: csc_matrix, V: CxVec, block1_idx: IntVec, block2_idx: In
nbus = Ybus.shape[0]
# Create J in CSC order
- J = create_J_vc_csc(nbus, Ybus.data, Ybus.indptr, Ybus.indices, V, block1_idx, block2_idx, block3_idx)
+ J = create_J_vc_csc(nbus, Ybus.data, Ybus.indptr, Ybus.indices, V, idx_dtheta, idx_dVm, idx_dtheta, idx_dQ)
return J
diff --git a/src/GridCalEngine/Simulations/Derivatives/acdc_jacobian.py b/src/GridCalEngine/Simulations/Derivatives/acdc_jacobian.py
new file mode 100644
index 000000000..182f85391
--- /dev/null
+++ b/src/GridCalEngine/Simulations/Derivatives/acdc_jacobian.py
@@ -0,0 +1,999 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import numpy as np
+import numba as nb
+from cmath import rect
+import GridCalEngine.Simulations.Derivatives.csc_derivatives as deriv
+from GridCalEngine.basic_structures import Vec, IntVec, CxVec
+from GridCalEngine.Utils.Sparse.csc2 import CSC, CxCSC, make_lookup, sp_slice, csc_stack_2d_ff, sp_slice_rows
+
+
+# @nb.njit()
+# def rect(mod, ang):
+#
+# return nb.complex128(mod * np.sin(ang), mod * np.cos(ang))
+
+
+class AcDcSolSlicer:
+ """
+ AcDcSolSlicer
+ """
+
+ def __init__(self, block1, block2, k_zero_beq, k_vf_beq, k_qf_m, k_qt_m, k_vt_m, k_pf_tau, k_pf_dp):
+ """
+ Declare the slicing limits in the same order as the Jacobian rows
+ :param block1: no-slack (pv + pq + pqv + p)
+ :param block2: pq + p
+ :param k_zero_beq:
+ :param k_vf_beq:
+ :param k_qf_m:
+ :param k_qt_m:
+ :param k_vt_m:
+ :param k_pf_tau:
+ :param k_pf_dp:
+ """
+
+ self.va_idx = block1
+ self.vm_idx = block2
+ self.beq_idx = np.r_[k_zero_beq, k_vf_beq]
+ self.m_idx = np.r_[k_qf_m, k_qt_m, k_vt_m]
+ self.tau_idx = np.r_[k_pf_tau, k_pf_dp]
+
+ n_col_block1 = len(block1)
+ n_col_block2 = len(block2)
+ n_col_block3 = len(k_zero_beq) + len(k_vf_beq)
+ n_col_block4 = len(k_qf_m) + len(k_qt_m) + len(k_vt_m)
+ n_col_block5 = len(k_pf_tau) + len(k_pf_dp)
+
+ self.a0 = 0
+ self.a1 = self.a0 + n_col_block1
+ self.a2 = self.a1 + n_col_block2
+ self.a3 = self.a2 + n_col_block3
+ self.a4 = self.a3 + n_col_block4
+ self.a5 = self.a4 + n_col_block5
+
+ def split(self, dx):
+ """
+ Split the linear system solution
+ :param dx: linear system solution
+ :return: dVa, dVm, dBeq, dm, dtau
+ """
+ dVa = dx[self.a0:self.a1]
+ dVm = dx[self.a1:self.a2]
+ dBeq = dx[self.a2:self.a3]
+ dm = dx[self.a3:self.a4]
+ dtau = dx[self.a4:self.a5]
+
+ return dVa, dVm, dBeq, dm, dtau
+
+ def assign(self, dx, Va, Vm, Beq, m, tau, mu=1.0):
+ dVa = dx[self.a0:self.a1]
+ dVm = dx[self.a1:self.a2]
+ dBeq = dx[self.a2:self.a3]
+ dm = dx[self.a3:self.a4]
+ dtau = dx[self.a4:self.a5]
+
+ # assign the new values
+ if mu != 1.0:
+ Va[self.va_idx] -= dVa * mu
+ Vm[self.vm_idx] -= dVm * mu
+ Beq[self.beq_idx] -= dBeq * mu
+ m[self.m_idx] -= dm * mu
+ tau[self.tau_idx] -= dtau * mu
+ else:
+ Va[self.va_idx] -= dVa
+ Vm[self.vm_idx] -= dVm
+ Beq[self.beq_idx] -= dBeq
+ m[self.m_idx] -= dm
+ tau[self.tau_idx] -= dtau
+
+
+@nb.njit(cache=True)
+def fill_acdc_jacobian_data(Y_indptr: IntVec, Y_indices: IntVec, Yx: CxVec,
+ Yf_indptr: IntVec, Yf_indices: IntVec, Yfx: CxVec,
+ Yt_indptr: IntVec, Yt_indices: IntVec, Ytx: CxVec,
+ yff: CxVec, yft: CxVec, ytf: CxVec, ytt: CxVec,
+ Yseries_br: CxVec,
+ idx_dtheta: IntVec,
+ idx_dvm: IntVec,
+ idx_dm: IntVec,
+ idx_dtau: IntVec,
+ idx_dbeq: IntVec,
+ idx_dP: IntVec,
+ idx_dQ: IntVec,
+ idx_dQf: IntVec,
+ idx_dQt: IntVec,
+ idx_dPf: IntVec,
+ idx_dPdp: IntVec,
+ F: IntVec,
+ T: IntVec,
+ V: CxVec,
+ Vm: Vec,
+ Va: Vec,
+ tap_modules_m: Vec,
+ tap_complex: CxVec,
+ k2: Vec,
+ Bc: Vec,
+ b_eq: Vec,
+ Kdp: Vec) -> CSC:
+ """
+ Compute the ACDC jacobian using Numba
+ :param Y_indptr: Ybus CSC pointer array
+ :param Y_indices: Ybus CSC row indices array
+ :param Yx:
+ :param Yf_indptr:
+ :param Yf_indices:
+ :param Yfx:
+ :param Yt_indptr:
+ :param Yt_indices:
+ :param Ytx:
+ :param Yseries_br: Branches' series admittance array
+ :param idx_dtheta:
+ :param idx_dvm:
+ :param idx_dm:
+ :param idx_dtau:
+ :param idx_dbeq:
+ :param idx_dP:
+ :param idx_dQ:
+ :param idx_dQf:
+ :param idx_dQt:
+ :param idx_dPf:
+ :param idx_dPdp:
+ :param F: Array of "from" bus indices
+ :param T: Array of "to" bus indices
+ :param V: Array of complex bus voltages
+ :param Vm:
+ :param Va:
+ :param tap_modules_m: Array of tap modules
+ :param tap_complex: Array of complex tap values {remember tap = ma * exp(1j * theta) }
+ :param k2: Array of branch converter k2 parameters
+ :param Bc: Array of branch full susceptances
+ :param b_eq: Array of branch equivalent (variable) susceptances
+ :param Kdp:
+ :return: Jacobian matrix
+ """
+
+ n_idx_dtheta = len(idx_dtheta) # notice that idx_dtheta is the same as idx_dP
+ n_idx_dvm = len(idx_dvm)
+ n_idx_dm = len(idx_dm)
+ n_idx_dtau = len(idx_dtau)
+ n_idx_dbeq = len(idx_dbeq)
+
+ n_idx_dP = len(idx_dP)
+ n_idx_dQ = len(idx_dQ)
+ n_idx_dQf = len(idx_dQf)
+ n_idx_dQt = len(idx_dQt)
+ n_idx_dPf = len(idx_dPf)
+ n_idx_dPdp = len(idx_dPdp)
+
+ n_cols = n_idx_dtheta + n_idx_dvm + n_idx_dm + n_idx_dtau + n_idx_dbeq
+ n_rows = n_idx_dP + n_idx_dQ + n_idx_dQf + n_idx_dQt + n_idx_dPf + n_idx_dPdp
+ assert n_cols == n_rows
+
+ nbus = len(V)
+ nbr = len(Yseries_br)
+
+ # compose the derivatives of the power Injections w.r.t Va and Vm
+ dSbus_dVm_x, dSbus_dVa_x = deriv.dSbus_dV_numba_sparse_csc(Yx, Y_indptr, Y_indices, V, np.abs(V))
+
+ # declare the Jacobian matrix
+ nnz_estimate = len(Yx) * 8
+ J = CSC(n_rows, n_cols, nnz_estimate, False)
+
+ # generate lookup for the row slicing (these follow the structure of the residuals vector)
+ lookup_idx_dP = make_lookup(nbus, idx_dP)
+ lookup_idx_dQ = make_lookup(nbus, idx_dQ)
+ lookup_idx_dQf = make_lookup(nbr, idx_dQf)
+ lookup_idx_dQt = make_lookup(nbr, idx_dQt)
+ lookup_idx_dPf = make_lookup(nbr, idx_dPf)
+ lookup_idx_dPdp = make_lookup(nbr, idx_dPdp)
+
+ nnz = 0
+ p = 0
+ J.indptr[p] = 0
+
+ # column 1: derivatives w.r.t Va -----------------------------------------------------------------------------------
+ for j in idx_dtheta: # sliced columns
+
+ # J11: dP/dĪø
+ if n_idx_dP:
+ for pos in range(Y_indptr[j], Y_indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = Y_indices[pos] # bus index (row index in Ybus)
+ ii = lookup_idx_dP[i] # jacobian row index
+
+ if idx_dP[ii] == i:
+ # entry found
+ J.data[nnz] = dSbus_dVa_x[pos].real # dP/dĘ
+ J.indices[nnz] = ii
+ nnz += 1
+
+ # J21: dQ/dĪø
+ offset = n_idx_dP
+ if n_idx_dQ:
+ for pos in range(Y_indptr[j], Y_indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = Y_indices[pos]
+ ii = lookup_idx_dQ[i] # in: bus index, out: index in row_block2
+
+ if idx_dQ[ii] == i:
+ # entry found
+ J.data[nnz] = dSbus_dVa_x[pos].imag # dQ/dĘ
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J31: dQf/dĪø
+ offset += n_idx_dQ
+ if n_idx_dQf:
+ for pos in range(Yf_indptr[j], Yf_indptr[j + 1]):
+
+ k = Yf_indices[pos]
+ f = F[k]
+ t = T[k]
+
+ if f == j or f == t:
+
+ val = 1j * Vm[f] * Vm[t] * rect(1.0, Va[f] - Va[t]) * np.conj(yft[k]) # dSf/dĪøf
+
+ if f == j:
+ J.data[nnz] = val.imag
+ elif t == j:
+ J.data[nnz] = -val.imag
+
+ J.indices[nnz] = lookup_idx_dQf[k] + offset
+ nnz += 1
+
+ # J41: dQt/dĪø
+ offset += n_idx_dQf
+ if n_idx_dQt:
+
+ for pos in range(Yt_indptr[j], Yt_indptr[j + 1]): # rows of A[:, j]
+
+ k = Yt_indices[pos]
+ f = F[k]
+ t = T[k]
+
+ if f == j or f == t:
+
+ val = 1j * Vm[f] * Vm[t] * rect(1.0, Va[f] - Va[t]) * np.conj(ytf[k]) # dSf/dĪøf
+
+ if f == j:
+ J.data[nnz] = -val.imag
+ elif t == j:
+ J.data[nnz] = val.imag
+
+ J.indices[nnz] = lookup_idx_dQt[k] + offset
+ nnz += 1
+
+ # J51: dPf/dĪø
+ offset += n_idx_dQt
+ if n_idx_dPf:
+ for pos in range(Yf_indptr[j], Yf_indptr[j + 1]): # rows of A[:, j]
+
+ k = Yf_indices[pos]
+ f = F[k]
+ t = T[k]
+
+ if f == j or f == t:
+
+ val = 1j * Vm[f] * Vm[t] * rect(1.0, Va[f] - Va[t]) * np.conj(yft[k]) # dSf/dĪøf
+
+ if f == j:
+ J.data[nnz] = val.real
+ elif t == j:
+ J.data[nnz] = -val.real
+
+ J.indices[nnz] = lookup_idx_dPf[k] + offset
+ nnz += 1
+
+ # J61: -dPf/dĘ
+ offset += n_idx_dPf
+ if n_idx_dPdp:
+ for pos in range(Yf_indptr[j], Yf_indptr[j + 1]): # rows of A[:, j]
+
+ k = Yf_indices[pos]
+ f = F[k]
+ t = T[k]
+
+ if f == j or f == t:
+
+ val = 1j * Vm[f] * Vm[t] * rect(1.0, Va[f] - Va[t]) * np.conj(yft[k]) # dSf/dĪøf
+
+ if f == j:
+ J.data[nnz] = -val.real
+ elif t == j:
+ J.data[nnz] = val.real
+
+ J.indices[nnz] = lookup_idx_dPdp[k] + offset
+ nnz += 1
+
+ # finalize column
+ p += 1
+ J.indptr[p] = nnz
+
+ # column 2: derivatives w.r.t Vm -----------------------------------------------------------------------------------
+ for j in idx_dvm: # sliced columns
+
+ # J12: dP/dVm
+ if n_idx_dP:
+ for pos in range(Y_indptr[j], Y_indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = Y_indices[pos]
+ ii = lookup_idx_dP[i]
+
+ if idx_dP[ii] == i:
+ # entry found
+ J.data[nnz] = dSbus_dVm_x[pos].real # dP/dVm
+ J.indices[nnz] = ii
+ nnz += 1
+
+ # J22: dQ/dVm
+ offset = n_idx_dP
+ if n_idx_dQ:
+ for pos in range(Y_indptr[j], Y_indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = Y_indices[pos]
+ ii = lookup_idx_dQ[i]
+
+ if idx_dQ[ii] == i:
+ # entry found
+ J.data[nnz] = dSbus_dVm_x[pos].imag # dQ/dVm
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J32: dQf/dVm
+ offset += n_idx_dQ
+ if n_idx_dQf:
+ for pos in range(Yf_indptr[j], Yf_indptr[j + 1]): # rows of A[:, j]
+
+ k = Yf_indices[pos]
+ f = F[k]
+ t = T[k]
+
+ if f == j or f == t:
+
+ if f == j:
+ # dSf/dvf
+ val = 2.0 * Vm[f] * np.conj(yff[k]) + rect(Vm[t], Va[f] - Va[t]) * np.conj(yft[k])
+ J.data[nnz] = val.imag
+ elif t == j:
+ val = rect(Vm[f], Va[f] - Va[t]) * np.conj(yft[k]) # dSf/dvt
+ J.data[nnz] = -val.imag
+
+ J.indices[nnz] = lookup_idx_dQf[k] + offset
+ nnz += 1
+
+ # J42: dQt/dVm
+ offset += n_idx_dQf
+ if n_idx_dQt:
+ for pos in range(Yt_indptr[j], Yt_indptr[j + 1]): # rows of A[:, j]
+
+ k = Yf_indices[pos]
+ f = F[k]
+ t = T[k]
+
+ if f == j or f == t:
+
+ if f == j:
+ val = rect(Vm[t], Va[t] - Va[f]) * np.conj(ytf[k]) # dSf/dvt
+ J.data[nnz] = val.imag
+ elif t == j:
+ # dSf/dvf
+ val = 2.0 * Vm[t] * np.conj(ytt[k]) + rect(Vm[f], Va[t] - Va[f]) * np.conj(ytf[k])
+ J.data[nnz] = -val.imag
+
+ J.indices[nnz] = lookup_idx_dQt[k] + offset
+ nnz += 1
+
+ # J52: dPf/dVm
+ offset += n_idx_dQt
+ if n_idx_dPf:
+ for pos in range(Yf_indptr[j], Yf_indptr[j + 1]):
+
+ k = Yf_indices[pos]
+ f = F[k]
+ t = T[k]
+
+ if f == j or f == t:
+
+ if f == j:
+ val = 2.0 * Vm[f] * np.conj(yff[k]) + rect(Vm[t], Va[f] - Va[t]) * np.conj(yft[k]) # dPf/dVmf
+ J.data[nnz] = val.real
+ elif t == j:
+ val = rect(Vm[f], Va[f] - Va[t]) * np.conj(yft[k]) # dPf/dVmt
+ J.data[nnz] = val.real
+
+ J.indices[nnz] = lookup_idx_dPf[k] + offset
+ nnz += 1
+
+ # J62: dPfdp/dVm
+ offset += n_idx_dPf
+ if n_idx_dPdp:
+
+ # # compute the droop derivative
+ # dVmf_dVm = lil_matrix((nl, nb))
+ # dVmf_dVm[k_pf_dp, :] = Cf[k_pf_dp, :]
+ # dPfdp_dVm = -dSf_dVm.real + diags(Kdp) * dVmf_dVm
+ #
+ for pos in range(Yf_indptr[j], Yf_indptr[j + 1]):
+
+ k = Yf_indices[pos]
+ f = F[k]
+ t = T[k]
+
+ if f == j or f == t:
+
+ if f == j:
+ val = 2.0 * Vm[f] * np.conj(yff[k]) + rect(Vm[t], Va[f] - Va[t]) * np.conj(yft[k]) # dPf/dVmf
+ J.data[nnz] = val.real - Kdp[k]
+ elif t == j:
+ val = rect(Vm[f], Va[f] - Va[t]) * np.conj(yft[k]) # dPf/dVmt
+ J.data[nnz] = val.real
+
+ J.indices[nnz] = lookup_idx_dPdp[k] + offset
+ nnz += 1
+ pass
+
+ # finalize column
+ p += 1
+ J.indptr[p] = nnz
+
+ # Column 3: derivatives w.r.t Beq ----------------------------------------------------------------
+
+ for k in idx_dbeq: # sliced columns
+
+ # J13: dP/dBeq
+ if n_idx_dP:
+ for pos in range(Y_indptr[k], Y_indptr[k + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = Y_indices[pos] # bus index (row index in Ybus)
+ f = F[k]
+ t = T[k]
+ if f == i:
+ # entry found
+ val = Vm[f] * np.conj((Vm[t]) / (k2[k] * k2[k] * tap_modules_m[k]))
+ J.data[nnz] = val.real
+ J.indices[nnz] = lookup_idx_dP[i] # jacobian row index
+ nnz += 1
+ elif t == i:
+ pass # the derivative is 0
+
+ # J23: dQ/dBeq
+ offset = n_idx_dP
+ if n_idx_dQ:
+ for pos in range(Y_indptr[k], Y_indptr[k + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = Y_indices[pos] # bus index (row index in Ybus)
+ f = F[k]
+ t = T[k]
+ if f == i:
+ # entry found
+ val = Vm[f] * np.conj((Vm[t]) / (k2[k] * k2[k] * tap_modules_m[k]))
+ J.data[nnz] = val.imag
+ J.indices[nnz] = lookup_idx_dQ[i] # jacobian row index
+ nnz += 1
+ elif t == i:
+ pass # the derivative is 0
+
+ # J33: dQf/dBeq
+ offset += n_idx_dQ
+ if n_idx_dQf:
+ for pos in range(Yf_indptr[k], Yf_indptr[k + 1]):
+
+ k_row = Yf_indices[pos]
+ f_col = F[k]
+ t_col = T[k]
+ f_row = F[k_row]
+ t_row = T[k_row]
+
+ if f_col == f_row or t_col == t_row:
+
+ if f_col == f_row:
+ # dSf/dvf
+ val = Vm[f] * np.conj((Vm[t]) / (k2[k] * k2[k] * tap_modules_m[k]))
+ J.data[nnz] = val.imag
+
+ elif t_col == t_row:
+ val = rect(Vm[f], Va[f] - Va[t]) * np.conj(yft[k]) # dSf/dvt
+ J.data[nnz] = -val.imag
+
+ J.indices[nnz] = lookup_idx_dQf[k] + offset
+ nnz += 1
+
+ # J43
+ offset += n_row_block3
+ # if n_row_block4: # --> The Jacobian is always zero :|
+ # for k in range(dSt_dBeqz.indptr[j], dSt_dBeqz.indptr[j + 1]): # rows of A[:, j]
+ #
+ # # row index translation to the "rows" space
+ # i = dSt_dBeqz.indices[k]
+ # ii = iQtma_lookup[i]
+ #
+ # if iQtma[ii] == i:
+ # # entry found
+ # J.data[nnz] = dSt_dBeqz.data[k].imag
+ # J.indices[nnz] = ii + offset
+ # nnz += 1
+
+ # J53
+ offset += n_row_block4
+ if n_row_block5:
+ for pos in range(dSf_dBeq.indptr[j], dSf_dBeq.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSf_dBeq.indices[pos]
+ ii = row_block5_lookup[i]
+
+ if k_pf_tau[ii] == i:
+ # entry found
+ J.data[nnz] = dSf_dBeq.data[pos].real # dPf/dBeq
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J63
+ offset += n_row_block5
+ if n_row_block6:
+ for pos in range(dSf_dBeq.indptr[j], dSf_dBeq.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSf_dBeq.indices[pos]
+ ii = row_block6_lookup[i]
+
+ if k_pf_dp[ii] == i:
+ # entry found
+ J.data[nnz] = -dSf_dBeq.data[pos].real # dPf/dBeq
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # finalize column
+ p += 1
+ J.indptr[p] = nnz
+
+ # Column 4: derivative w.r.t "m" for iQfma + iQfma + iVtma ---------------------------------------------------------
+ # if n_col_block4:
+ #
+ # dSbus_dm, dSf_dm, dSt_dm = deriv.derivatives_ma_csc_numba(nb=nbus, nl=nbr, iXxma=col_block4,
+ # F=F, T=T, Ys=Yseries_br, k2=k2,
+ # tap=tap_complex, ma=tap_modules_m,
+ # Bc=Bc, Beq=b_eq, V=V)
+
+ for j in idx_dm: # sliced columns
+
+ # J14
+ if n_row_block1:
+ for pos in range(dSbus_dm.indptr[j], dSbus_dm.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSbus_dm.indices[pos]
+ ii = lookup_block1[i]
+
+ if i_block1[ii] == i:
+ # entry found
+ J.data[nnz] = dSbus_dm.data[pos].real # dP/dm
+ J.indices[nnz] = ii
+ nnz += 1
+
+ # J24
+ offset = n_row_block1
+ if n_row_block2:
+ for pos in range(dSbus_dm.indptr[j], dSbus_dm.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSbus_dm.indices[pos]
+ ii = row_block2_lookup[i]
+
+ if row_block2[ii] == i:
+ # entry found
+ J.data[nnz] = dSbus_dm.data[pos].imag # dQ/dm
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J34
+ offset += n_row_block2
+ if n_row_block3:
+ for pos in range(dSf_dm.indptr[j], dSf_dm.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSf_dm.indices[pos]
+ ii = row_block3_lookup[i]
+
+ if row_block3[ii] == i:
+ # entry found
+ J.data[nnz] = dSf_dm.data[pos].imag # dQf/dm
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J44
+ offset += n_row_block3
+ if n_row_block4:
+ for pos in range(dSt_dm.indptr[j], dSt_dm.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSt_dm.indices[pos]
+ ii = row_block4_lookup[i]
+
+ if k_qt_m[ii] == i:
+ # entry found
+ J.data[nnz] = dSt_dm.data[pos].imag # dQt/dm
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J54
+ offset += n_row_block4
+ if n_row_block5:
+ for pos in range(dSf_dm.indptr[j], dSf_dm.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSf_dm.indices[pos]
+ ii = row_block5_lookup[i]
+
+ if k_pf_tau[ii] == i:
+ # entry found
+ J.data[nnz] = dSf_dm.data[pos].real # dPf/dm
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J64
+ offset += n_row_block5
+ if n_row_block6:
+ for pos in range(dSf_dm.indptr[j], dSf_dm.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSf_dm.indices[pos]
+ ii = row_block6_lookup[i]
+
+ if k_pf_dp[ii] == i:
+ # entry found
+ J.data[nnz] = -dSf_dm.data[pos].real # dPf/dm
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # finalize column
+ p += 1
+ J.indptr[p] = nnz
+
+ # Column 5: derivatives w.r.t theta sh for iPfsh + droop -----------------------------------------------------------
+ # if n_col_block5:
+ #
+ # dSbus_dtau, dSf_dtau, dSt_dtau = deriv.derivatives_tau_csc_numba(nb=nbus, nl=nbr,
+ # iPxsh=col_block5,
+ # F=F, T=T, Ys=Yseries_br, k2=k2,
+ # tap=tap_complex, V=V)
+
+ for j in idx_dtau: # sliced columns
+
+ # J15
+ if n_row_block1:
+ for pos in range(dSbus_dtau.indptr[j], dSbus_dtau.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSbus_dtau.indices[pos]
+ ii = lookup_block1[i]
+
+ if i_block1[ii] == i:
+ # entry found
+ J.data[nnz] = dSbus_dtau.data[pos].real # dP/dtau
+ J.indices[nnz] = ii
+ nnz += 1
+
+ # J25
+ offset = n_row_block1
+ if n_row_block2:
+ for pos in range(dSbus_dtau.indptr[j], dSbus_dtau.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSbus_dtau.indices[pos]
+ ii = row_block2_lookup[i]
+
+ if row_block2[ii] == i:
+ # entry found
+ J.data[nnz] = dSbus_dtau.data[pos].imag # dQ/dtau
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J35
+ offset += n_row_block2
+ if n_row_block3:
+ for pos in range(dSf_dtau.indptr[j], dSf_dtau.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSf_dtau.indices[pos]
+ ii = row_block3_lookup[i]
+
+ if row_block3[ii] == i:
+ # entry found
+ J.data[nnz] = dSf_dtau.data[pos].imag # dQf/dtau
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J45
+ offset += n_row_block3
+ if n_row_block4:
+ for pos in range(dSt_dtau.indptr[j], dSt_dtau.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSt_dtau.indices[pos]
+ ii = row_block4_lookup[i]
+
+ if k_qt_m[ii] == i:
+ # entry found
+ J.data[nnz] = dSt_dtau.data[pos].imag # dQt/dtau
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J55
+ offset += n_row_block4
+ if n_row_block5:
+ for pos in range(dSf_dtau.indptr[j], dSf_dtau.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSf_dtau.indices[pos]
+ ii = row_block5_lookup[i]
+
+ if k_pf_tau[ii] == i:
+ # entry found
+ J.data[nnz] = dSf_dtau.data[pos].real # dPf/dtau
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # J65
+ offset += n_row_block6
+ if n_row_block6:
+ for pos in range(dSf_dtau.indptr[j], dSf_dtau.indptr[j + 1]): # rows of A[:, j]
+
+ # row index translation to the "rows" space
+ i = dSf_dtau.indices[pos]
+ ii = row_block6_lookup[i]
+
+ if k_pf_dp[ii] == i:
+ # entry found
+ J.data[nnz] = -dSf_dtau.data[pos].real # - dPf/dtau
+ J.indices[nnz] = ii + offset
+ nnz += 1
+
+ # finalize column
+ p += 1
+ J.indptr[p] = nnz
+
+ # Finalize ----------------------------------------------------------------------------
+ # finalize the Jacobian Pointer
+ J.indptr[p] = nnz
+ J.resize(nnz)
+
+ return J
+
+
+def fubm_jacobian_old(nb, nl,
+ idx_dtheta: IntVec,
+ idx_dvm: IntVec,
+ idx_dm: IntVec,
+ idx_dtau: IntVec,
+ idx_dbeq: IntVec,
+ idx_dP: IntVec,
+ idx_dQ: IntVec,
+ idx_dQf: IntVec,
+ idx_dQt: IntVec,
+ idx_dPf: IntVec,
+ idx_dPdp: IntVec,
+ F, T, Ys, k2, complex_tap, tap_modules, Bc, Beq, Kdp, V,
+ Ybus, Yf, Yt, yff, yft, ytf, ytt) -> CSC:
+ """
+ Compute the FUBM jacobian in a dynamic fashion by only computing the derivatives that are needed
+ :param nb: number of buses
+ :param nl: Number of lines
+ :param k_pf_tau: indices of the Pf controlled with the shunt susceptance Branches
+ :param k_pf_dp: indices of the Pf-droop controlled Branches
+ :param k_qf_m: indices of the Qf controlled with ma Branches
+ :param k_qt_m: Indices of the Qt controlled with ma Branches
+ :param k_v_m: Indices of the Vt controlled with ma Branches
+ :param k_zero_beq: Indices of the Qf made zero with the equivalent susceptance Branches
+ :param k_vf_beq: Indices of the Vf Controlled with the equivalent susceptance Branches
+ :param i_vf_beq: Indices of the buses where Vf is controlled with Beq
+ :param i_vt_m: Indices of the buses where Vt is controlled with ma
+ :param F: Array of "from" bus indices
+ :param T: Array of "to" bus indices
+ :param Ys: Array of branch series admittances
+ :param k2: Array of branch converter k2 parameters
+ :param complex_tap: Array of complex tap values {remember tap = ma * exp(1j * theta) }
+ :param tap_modules: Array of tap modules
+ :param Bc: Array of branch full susceptances
+ :param Beq: Array of branch equivalent (variable) susceptances
+ :param Kdp: Array of branch converter droop constants
+ :param V: Array of complex bus voltages
+ :param Ybus: Admittance matrix
+ :param Yf: Admittances matrix of the Branches with the "from" buses
+ :param Yt: Admittances matrix of the Branches with the "to" buses
+ :param Cf: Connectivity matrix of the Branches with the "from" buses
+ :param Ct: Connectivity matrix of the Branches with the "to" buses
+ :param pvpq: Array of pv and then pq bus indices (not sorted)
+ :param pq: Array of PQ bus indices
+ :return: FUBM Jacobian matrix
+ """
+
+ # fill the jacobian data with numba
+ J = fill_acdc_jacobian_data(Y_indptr=Ybus.indptr, Y_indices=Ybus.indices, Yx=Ybus.data,
+ Yf_indptr=Yf.indptr, Yf_indices=Yf.indices, Yfx=Yf.data,
+ Yt_indptr=Yt.indptr, Yt_indices=Yt.indices, Ytx=Yt.data,
+ yff=yff, yft=yft, ytf=ytf, ytt=ytt,
+ Yseries_br=Ys,
+ idx_dtheta=idx_dtheta,
+ idx_dvm=idx_dvm,
+ idx_dm=idx_dm,
+ idx_dtau=idx_dtau,
+ idx_dbeq=idx_dbeq,
+ idx_dP=idx_dP,
+ idx_dQ=idx_dQ,
+ idx_dQf=idx_dQf,
+ idx_dQt=idx_dQt,
+ idx_dPf=idx_dPf,
+ idx_dPdp=idx_dPdp,
+ F=F,
+ T=T,
+ V=V,
+ tap_modules_m=tap_modules,
+ tap_complex=complex_tap,
+ k2=k2,
+ Bc=Bc,
+ b_eq=Beq,
+ Kdp=Kdp)
+
+ return J
+
+
+# @nb.njit()
+def fubm_jacobian(nbus: int,
+ nbr: int,
+ idx_dtheta: IntVec,
+ idx_dvm: IntVec,
+ idx_dm: IntVec,
+ idx_dtau: IntVec,
+ idx_dbeq: IntVec,
+ idx_dP: IntVec,
+ idx_dQ: IntVec,
+ idx_dQf: IntVec,
+ idx_dPf: IntVec,
+ F: IntVec,
+ T: IntVec,
+ Ys: CxVec,
+ kconv: Vec,
+ complex_tap: CxVec,
+ tap_modules: Vec,
+ Bc: Vec,
+ Beq: Vec,
+ Kdp: Vec,
+ V: CxVec,
+ Vm: Vec,
+ Ybus_x: CxVec,
+ Ybus_p: IntVec,
+ Ybus_i: IntVec,
+ yff: CxVec,
+ yft: CxVec,
+ ytf: CxVec,
+ ytt: CxVec) -> CSC:
+ """
+
+ :param nbus:
+ :param idx_dtheta:
+ :param idx_dvm:
+ :param idx_dm:
+ :param idx_dtau:
+ :param idx_dbeq:
+ :param idx_dP:
+ :param idx_dQ:
+ :param idx_dQf:
+ :param idx_dPf:
+ :param F:
+ :param T:
+ :param Ys:
+ :param kconv:
+ :param complex_tap:
+ :param tap_modules:
+ :param Bc:
+ :param Beq:
+ :param Kdp:
+ :param V:
+ :param Vm:
+ :param Ybus_x:
+ :param Ybus_p:
+ :param Ybus_i:
+ :param yff:
+ :param yft:
+ :param ytf:
+ :param ytt:
+ :return:
+ """
+ n_rows = len(idx_dP) + len(idx_dQ) + len(idx_dQf) + len(idx_dPf)
+ n_cols = len(idx_dtheta) + len(idx_dvm) + len(idx_dm) + len(idx_dtau) + len(idx_dbeq)
+
+ if not np.all(idx_dtau == idx_dPf):
+ raise ValueError("Pf indices must be equal to tau indices!")
+
+ if n_cols != n_rows:
+ raise ValueError("Incorrect J indices!")
+
+ # bus-bus derivatives (always needed)
+ dS_dVm_x, dS_dVa_x = deriv.dSbus_dV_numba_sparse_csc(Ybus_x, Ybus_p, Ybus_i, V, Vm)
+
+ dS_dVm = CxCSC(nbus, nbus, len(dS_dVm_x), False)
+ dS_dVm.set(Ybus_i, Ybus_p, dS_dVm_x)
+
+ dS_dVa = CxCSC(nbus, nbus, len(dS_dVa_x), False)
+ dS_dVa.set(Ybus_i, Ybus_p, dS_dVa_x)
+
+ dP_dVa__ = sp_slice(dS_dVa.real, idx_dP, idx_dtheta)
+ dQ_dVa__ = sp_slice(dS_dVa.imag, idx_dQ, idx_dtheta)
+ dPf_dVa_ = deriv.dSf_dVa_csc(nbus, idx_dPf, idx_dtheta, yff, yft, V, F, T).real
+ dQf_dVa_ = deriv.dSf_dVa_csc(nbus, idx_dQf, idx_dtheta, yff, yft, V, F, T).imag
+ # dQt_dVa_ = deriv.dSt_dVa_csc(nbus, idx_dQt, idx_dtheta, ytf, V, F, T).imag
+ # dPdp_dVa = deriv.dSf_dVa_csc(nbus, idx_dPdp, idx_dtheta, yff, yft, V, F, T).real
+
+ dP_dVm__ = sp_slice(dS_dVm.real, idx_dP, idx_dvm)
+ dQ_dVm__ = sp_slice(dS_dVm.imag, idx_dQ, idx_dvm)
+ dPf_dVm_ = deriv.dSf_dVm_csc(nbus, idx_dPf, idx_dtheta, yff, yft, V, F, T).real
+ dQf_dVm_ = deriv.dSf_dVm_csc(nbus, idx_dQf, idx_dtheta, yff, yft, V, F, T).imag
+ # dQt_dVm_ = deriv.dSt_dVm_csc(nbus, idx_dQt, idx_dtheta, ytt, ytf, V, F, T).imag
+ # dPdp_dVm = deriv.dPfdp_dVm_csc(nbus, idx_dPdp, idx_dtheta, yff, yft, Kdp, V, F, T)
+
+ dP_dm__ = deriv.dSbus_dm_csc(nbus, idx_dP, idx_dm, F, T, Ys, Bc, Beq, kconv, complex_tap, tap_modules, V).real
+ dQ_dm__ = deriv.dSbus_dm_csc(nbus, idx_dQ, idx_dm, F, T, Ys, Bc, Beq, kconv, complex_tap, tap_modules, V).imag
+ dPf_dm_ = deriv.dSf_dm_csc(nbr, idx_dPf, idx_dm, F, T, Ys, Bc, Beq, kconv, complex_tap, tap_modules, V).real
+ dQf_dm_ = deriv.dSf_dm_csc(nbr, idx_dQf, idx_dm, F, T, Ys, Bc, Beq, kconv, complex_tap, tap_modules, V).imag
+ # dQt_dm_ = deriv.dSt_dm_csc(idx_dQt, idx_dm, F, T, Ys, kconv, complex_tap, tap_modules, V).imag
+ # dPdp_dm = deriv.dSf_dm_csc(idx_dPdp, idx_dm, F, T, Ys, Bc, Beq, kconv, complex_tap, tap_modules, V).real
+
+ dP_dtau__ = deriv.dSbus_dtau_csc(nbus, idx_dP, idx_dtau, F, T, Ys, kconv, complex_tap, V).real
+ dQ_dtau__ = deriv.dSbus_dtau_csc(nbus, idx_dQ, idx_dtau, F, T, Ys, kconv, complex_tap, V).imag
+ dPf_dtau_ = deriv.dSf_dtau_csc(nbr, idx_dPf, idx_dtau, F, T, Ys, kconv, complex_tap, V).real
+ dQf_dtau_ = deriv.dSf_dtau_csc(nbr, idx_dQf, idx_dtau, F, T, Ys, kconv, complex_tap, V).imag
+ # dQt_dtau_ = deriv.dSt_dtau_csc(idx_dQt, idx_dtau, F, T, Ys, kconv, complex_tap, V).imag
+ # dPdp_dtau = deriv.dSf_dtau_csc(idx_dPdp, idx_dtau, F, T, Ys, kconv, complex_tap, V).real
+
+ dP_dbeq__ = deriv.dSbus_dbeq_csc(nbus, idx_dP, idx_dbeq, F, kconv, tap_modules, V).real
+ dQ_dbeq__ = deriv.dSbus_dbeq_csc(nbus, idx_dQ, idx_dbeq, F, kconv, tap_modules, V).imag
+ dPf_dbeq_ = deriv.dSf_dbeq_csc(nbr, idx_dPf, idx_dbeq, F, kconv, tap_modules, V).real
+ dQf_dbeq_ = deriv.dSf_dbeq_csc(nbr, idx_dQf, idx_dbeq, F, kconv, tap_modules, V).imag
+ # dQt_dbeq_ = CSC(len(idx_dQt), len(idx_dbeq), 0, False)
+ # dPdp_dbeq = deriv.dSf_dbeq_csc(idx_dPdp, idx_dbeq, F, kconv, tap_modules, V).real
+
+ # compose the Jacobian
+ # J = csc_stack_2d_ff(mats=
+ # [dP_dVa__, dP_dVm__, dP_dbeq__, dP_dm__, dP_dtau__,
+ # dQ_dVa__, dQ_dVm__, dQ_dbeq__, dQ_dm__, dQ_dtau__,
+ # dQf_dVa_, dQf_dVm_, dQf_dbeq_, dQf_dm_, dQf_dtau_,
+ # dQt_dVa_, dQt_dVm_, dQt_dbeq_, dQt_dm_, dQt_dtau_,
+ # dPf_dVa_, dPf_dVm_, dPf_dbeq_, dPf_dm_, dPf_dtau_,
+ # dPdp_dVa, dPdp_dVm, dPdp_dbeq, dPdp_dm, dPdp_dtau],
+ # n_rows=6, n_cols=5)
+
+ J = csc_stack_2d_ff(mats=
+ [dP_dVa__, dP_dVm__, dP_dm__, dP_dtau__, dP_dbeq__,
+ dQ_dVa__, dQ_dVm__, dQ_dm__, dQ_dtau__, dQ_dbeq__,
+ dPf_dVa_, dPf_dVm_, dPf_dm_, dPf_dtau_, dPf_dbeq_,
+ dQf_dVa_, dQf_dVm_, dQf_dm_, dQf_dtau_, dQf_dbeq_,],
+ n_rows=4, n_cols=5)
+
+ if J.n_cols != J.n_rows:
+ raise ValueError("J is not square!")
+
+ return J
diff --git a/src/GridCalEngine/Simulations/Derivatives/csc_derivatives.py b/src/GridCalEngine/Simulations/Derivatives/csc_derivatives.py
new file mode 100644
index 000000000..7ab18c83d
--- /dev/null
+++ b/src/GridCalEngine/Simulations/Derivatives/csc_derivatives.py
@@ -0,0 +1,1282 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import numpy as np
+from numba import njit, complex128, int32
+from typing import Tuple
+from scipy.sparse import csc_matrix
+from GridCalEngine.basic_structures import CxVec, IntVec, Vec
+from GridCalEngine.Utils.Sparse.csc2 import CSC, CxCSC, make_lookup
+
+
+@njit(cache=True)
+def dSbus_dV_numba_sparse_csc(Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec, Vm: CxVec) -> Tuple[CxVec, CxVec]:
+ """
+ Compute the power injection derivatives w.r.t the voltage module and angle
+ :param Yx: data of Ybus in CSC format
+ :param Yp: indptr of Ybus in CSC format
+ :param Yi: indices of Ybus in CSC format
+ :param V: Voltages vector
+ :param Vm: voltage modules vector
+ :return: dS_dVm, dS_dVa data ordered in the CSC format to match the indices of Ybus
+ """
+
+ """
+ The matrix operations that this is performing are:
+
+ diagV = diags(V)
+ diagE = diags(V / np.abs(V))
+ Ibus = Ybus * V
+ diagIbus = diags(Ibus)
+
+ dSbus_dVa = 1j * diagV * np.conj(diagIbus - Ybus * diagV)
+ dSbus_dVm = diagV * np.conj(Ybus * diagE) + np.conj(diagIbus) * diagE
+ """
+
+ # init buffer vector
+ n = len(Yp) - 1
+ Ibus = np.zeros(n, dtype=complex128)
+ dS_dVm_x = Yx.copy()
+ dS_dVa_x = Yx.copy()
+ E = V.copy()
+
+ # pass 1: perform the matrix-vector products
+ for j in range(n): # for each column ...
+
+ # compute the unitary vector of the voltage
+ E[j] /= Vm[j]
+
+ for k in range(Yp[j], Yp[j + 1]): # for each row ...
+ # row index
+ i = Yi[k]
+
+ # Ibus = Ybus * V
+ I = Yx[k] * V[j]
+
+ # store in the Ibus vector
+ Ibus[i] += I # Yx[k] -> Y(i,j)
+
+ # Ybus * diagE
+ dS_dVm_x[k] = Yx[k] * E[j]
+
+ # - Ybus * diag(V)
+ dS_dVa_x[k] = -I
+
+ # pass 2: finalize the operations
+ for j in range(n): # for each column ...
+
+ # set buffer variable:
+ # this operation cannot be done in the pass1
+ # because Ibus is not fully formed, but here it is.
+ buffer = np.conj(Ibus[j]) * E[j]
+
+ for k in range(Yp[j], Yp[j + 1]): # for each row ...
+
+ # row index
+ i = Yi[k]
+
+ # diag(V) * conj(Ybus * diagE)
+ dS_dVm_x[k] = V[i] * np.conj(dS_dVm_x[k])
+
+ if j == i:
+ # diagonal elements
+ dS_dVa_x[k] += Ibus[j] # diagIbus, after this it contains: diagIbus - Ybus * diagV
+ dS_dVm_x[
+ k] += buffer # conj(I(j)) * E(j), after this it contains; diag(V) * conj(Ybus * diagE) + conj(diagIbus) * diagE
+
+ # 1j * diagV * conj(diagIbus - Ybus * diagV)
+ dS_dVa_x[k] = (1j * V[i]) * np.conj(dS_dVa_x[k])
+
+ return dS_dVm_x, dS_dVa_x
+
+
+def dSbus_dV_csc(Ybus: csc_matrix, V: CxVec, Vm) -> Tuple[CxCSC, CxCSC]:
+ """
+ Call the numba sparse constructor of the derivatives
+ :param Ybus: Ybus in CSC format
+ :param V: Voltages vector
+ :param Vm: Voltages modules
+ :return: dS_dVm, dS_dVa in CSC format
+ """
+ # compute the derivatives' data fast
+ dS_dVm_x, dS_dVa_x = dSbus_dV_numba_sparse_csc(Ybus.data, Ybus.indptr, Ybus.indices, V, Vm)
+
+ dS_dVm = CxCSC(Ybus.shape[0], Ybus.shape[1], len(dS_dVm_x), False)
+ dS_dVm.set(Ybus.indices, Ybus.indptr, dS_dVm_x)
+
+ dS_dVa = CxCSC(Ybus.shape[0], Ybus.shape[1], len(dS_dVa_x), False)
+ dS_dVa.set(Ybus.indices, Ybus.indptr, dS_dVa_x)
+
+ # generate sparse CSC matrices with computed data and return them
+ return dS_dVm, dS_dVa
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+
+
+@njit()
+def map_coordinates_numba(nrows, ncols, indptr, indices, F, T):
+ """
+
+ :param nrows:
+ :param ncols:
+ :param indptr:
+ :param indices:
+ :param F:
+ :param T:
+ :return:
+ """
+ idx_f = np.zeros(nrows, dtype=int32)
+ idx_t = np.zeros(nrows, dtype=int32)
+ for j in range(ncols): # para cada columna j ...
+ for k in range(indptr[j], indptr[j + 1]): # para cada entrada de la columna ....
+ i = indices[k] # obtener el Ćndice de la fila
+
+ if j == F[i]:
+ idx_f[i] = k
+ elif j == T[i]:
+ idx_t[i] = k
+
+ return idx_f, idx_t
+
+
+@njit()
+def dSf_dV_numba(Yf_nrows, Yf_ncols, Yf_indices, Yf_indptr, Yf_data, V, F, T) -> Tuple[CxCSC, CxCSC]:
+ """
+
+ :param Yf_nrows:
+ :param Yf_ncols:
+ :param Yf_indices:
+ :param Yf_indptr:
+ :param Yf_data:
+ :param V:
+ :param F:
+ :param T:
+ :return:
+ """
+ # map the i, j coordinates
+ idx_f, idx_t = map_coordinates_numba(nrows=Yf_nrows,
+ ncols=Yf_ncols,
+ indptr=Yf_indptr,
+ indices=Yf_indices,
+ F=F,
+ T=T)
+ Yf_nnz = len(Yf_data)
+
+ dSf_dVm = CxCSC(Yf_nrows, Yf_ncols, Yf_nnz, False)
+ dSf_dVm.indptr = Yf_indptr
+ dSf_dVm.indices = Yf_indices
+
+ dSf_dVa = CxCSC(Yf_nrows, Yf_ncols, Yf_nnz, False)
+ dSf_dVa.indptr = Yf_indptr
+ dSf_dVa.indices = Yf_indices
+
+ for k in range(Yf_nrows): # number of Branches (rows), actually k is the branch index
+ f = F[k]
+ t = T[k]
+ kf = idx_f[k]
+ kt = idx_t[k]
+
+ Vm_f = np.abs(V[f])
+ Vm_t = np.abs(V[t])
+ th_f = np.angle(V[f])
+ th_t = np.angle(V[t])
+ ea = np.exp((th_f - th_t) * 1j)
+
+ dSf_dVm.data[kf] = 2 * Vm_f * np.conj(Yf_data[kf]) + Vm_t * np.conj(Yf_data[kt]) * ea
+ dSf_dVm.data[kt] = Vm_f * np.conj(Yf_data[kt]) * ea
+ dSf_dVa.data[kf] = Vm_f * Vm_t * np.conj(Yf_data[kt]) * ea * 1j
+ dSf_dVa.data[kt] = -dSf_dVa.data[kf]
+
+ return dSf_dVm, dSf_dVa
+
+
+@njit()
+def dSt_dV_numba(Yt_nrows, Yt_ncols, Yt_indices, Yt_indptr, Yt_data, V, F, T) -> Tuple[CxCSC, CxCSC]:
+ """
+
+ :param Yt_nrows:
+ :param Yt_ncols:
+ :param Yt_indices:
+ :param Yt_indptr:
+ :param Yt_data:
+ :param V:
+ :param F:
+ :param T:
+ :return:
+ """
+ # map the i, j coordinates
+ idx_f, idx_t = map_coordinates_numba(nrows=Yt_nrows,
+ ncols=Yt_ncols,
+ indptr=Yt_indptr,
+ indices=Yt_indices,
+ F=F,
+ T=T)
+ Yt_nnz = len(Yt_data)
+
+ dSt_dVm = CxCSC(Yt_nrows, Yt_ncols, Yt_nnz, False)
+ dSt_dVm.indptr = Yt_indptr
+ dSt_dVm.indices = Yt_indices
+
+ dSt_dVa = CxCSC(Yt_nrows, Yt_ncols, Yt_nnz, False)
+ dSt_dVa.indptr = Yt_indptr
+ dSt_dVa.indices = Yt_indices
+
+ for k in range(Yt_nrows): # number of Branches (rows), actually k is the branch index
+ f = F[k]
+ t = T[k]
+ kf = idx_f[k]
+ kt = idx_t[k]
+
+ Vm_f = np.abs(V[f])
+ Vm_t = np.abs(V[t])
+ th_f = np.angle(V[f])
+ th_t = np.angle(V[t])
+ ea = np.exp((th_t - th_f) * 1j)
+
+ dSt_dVm.data[kf] = Vm_t * np.conj(Yt_data[kf]) * ea
+ dSt_dVm.data[kt] = 2 * Vm_t * np.conj(Yt_data[kt]) + Vm_f * np.conj(Yt_data[kf]) * ea
+ dSt_dVa.data[kf] = - Vm_f * Vm_t * np.conj(Yt_data[kf]) * ea * 1j
+ dSt_dVa.data[kt] = - dSt_dVa.data[kf]
+
+ return dSt_dVm, dSt_dVa
+
+
+def dSf_dV_csc(Yf, V, F, T) -> Tuple[CxCSC, CxCSC]:
+ """
+ Flow "from" derivative w.r.t the voltage
+ :param Yf:
+ :param V:
+ :param F:
+ :param T:
+ :return:
+ """
+
+ dSf_dVm, dSf_dVa = dSf_dV_numba(Yf_nrows=Yf.shape[0],
+ Yf_ncols=Yf.shape[1],
+ Yf_indices=Yf.indices,
+ Yf_indptr=Yf.indptr,
+ Yf_data=Yf.data,
+ V=V,
+ F=F,
+ T=T)
+
+ return dSf_dVm, dSf_dVa
+
+
+def dSt_dV_csc(Yt, V, F, T) -> Tuple[CxCSC, CxCSC]:
+ """
+ Flow "to" derivative w.r.t the voltage
+ :param Yt:
+ :param V:
+ :param F:
+ :param T:
+ :return:
+ """
+
+ dSt_dVm, dSt_dVa = dSt_dV_numba(Yt_nrows=Yt.shape[0],
+ Yt_ncols=Yt.shape[1],
+ Yt_indices=Yt.indices,
+ Yt_indptr=Yt.indptr,
+ Yt_data=Yt.data,
+ V=V,
+ F=F,
+ T=T)
+
+ return dSt_dVm, dSt_dVa
+
+
+@njit()
+def dSf_dVm_csc(nbus, br_indices, bus_indices, yff, yft, V, F, T) -> CxCSC:
+ """
+ dSf_dVm[br_indices, bus_indices]
+ checked agins matpower derivatives
+ :param nbus: number of buses
+ :param br_indices: Branch indices
+ :param bus_indices: Bus indices
+ :param yff: yff primitives array
+ :param yft: yft primitives array
+ :param V: Voltages array
+ :param F: Array of "from" indices
+ :param T: Array of "to" indices
+ :return: dSf_dVm
+ """
+ n_row = len(br_indices)
+ n_cols = len(bus_indices)
+ max_nnz = len(yff) * 2
+ mat = CxCSC(n_row, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+
+ j_lookup = make_lookup(nbus, bus_indices)
+
+ nnz = 0
+ # for j_counter, j in enumerate(bus_indices): # para cada columna j ...
+ for k_counter, k in enumerate(br_indices):
+ f = F[k]
+ t = T[k]
+ f_idx = j_lookup[f]
+ t_idx = j_lookup[t]
+ Vm_f = np.abs(V[f])
+ Vm_t = np.abs(V[t])
+ th_f = np.angle(V[f])
+ th_t = np.angle(V[t])
+ ea = np.exp((th_f - th_t) * 1.0j)
+
+ # from side
+ if f_idx >= 0:
+ Tx[nnz] = 2.0 * Vm_f * np.conj(yff[k]) + Vm_t * np.conj(yft[k]) * ea
+ Ti[nnz] = k_counter
+ Tj[nnz] = f_idx
+ nnz += 1
+
+ # to side
+ if t_idx >= 0:
+ Tx[nnz] = Vm_f * np.conj(yft[k]) * ea
+ Ti[nnz] = k_counter
+ Tj[nnz] = t_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dPfdp_dVm_csc(nbus, br_indices, bus_indices, yff, yft, kdp, V, F, T) -> CSC:
+ """
+ dSf_dVm[br_indices, bus_indices]
+ checked agins matpower derivatives
+ :param nbus: number of buses
+ :param br_indices: Branch indices
+ :param bus_indices: Bus indices
+ :param yff: yff primitives array
+ :param yft: yft primitives array
+ :param V: Voltages array
+ :param F: Array of "from" indices
+ :param T: Array of "to" indices
+ :return: dSf_dVm
+ """
+
+ """
+ # # compute the droop derivative
+ # dVmf_dVm = lil_matrix((nl, nb))
+ # dVmf_dVm[k_pf_dp, :] = Cf[k_pf_dp, :]
+ # dPfdp_dVm = -dSf_dVm.real + diags(Kdp) * dVmf_dVm
+ """
+
+ n_row = len(br_indices)
+ n_cols = len(bus_indices)
+ max_nnz = len(yff) * 2
+ mat = CSC(n_row, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.float64)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+
+ j_lookup = make_lookup(nbus, bus_indices)
+
+ nnz = 0
+ # for j_counter, j in enumerate(bus_indices): # para cada columna j ...
+ for k_counter, k in enumerate(br_indices):
+ f = F[k]
+ t = T[k]
+ f_idx = j_lookup[f]
+ t_idx = j_lookup[t]
+ Vm_f = np.abs(V[f])
+ Vm_t = np.abs(V[t])
+ th_f = np.angle(V[f])
+ th_t = np.angle(V[t])
+ ea = np.exp((th_f - th_t) * 1.0j)
+
+ # from side
+ if f_idx >= 0:
+ dSf_dvm = 2.0 * Vm_f * np.conj(yff[k]) + Vm_t * np.conj(yft[k]) * ea
+ Tx[nnz] = - dSf_dvm.real + kdp[k]
+ Ti[nnz] = k_counter
+ Tj[nnz] = f_idx
+ nnz += 1
+
+ # to side
+ if t_idx >= 0:
+ dSf_dvm = Vm_f * np.conj(yft[k]) * ea
+ Tx[nnz] = - dSf_dvm.real
+ Ti[nnz] = k_counter
+ Tj[nnz] = t_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dSf_dVa_csc(nbus, br_indices, bus_indices, yff, yft, V, F, T) -> CxCSC:
+ """
+
+ :param nbus: number of buses
+ :param br_indices:
+ :param bus_indices:
+ :param yff:
+ :param yft:
+ :param V:
+ :param F:
+ :param T:
+ :return:
+ """
+ n_row = len(br_indices)
+ n_cols = len(bus_indices)
+ max_nnz = len(yff) * 2
+ mat = CxCSC(n_row, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+
+ j_lookup = make_lookup(nbus, bus_indices)
+
+ nnz = 0
+ # for j_counter, j in enumerate(bus_indices): # para cada columna j ...
+ for k_counter, k in enumerate(br_indices):
+ f = F[k]
+ t = T[k]
+ f_idx = j_lookup[f]
+ t_idx = j_lookup[t]
+ Vm_f = np.abs(V[f])
+ Vm_t = np.abs(V[t])
+ th_f = np.angle(V[f])
+ th_t = np.angle(V[t])
+ ea = np.exp((th_f - th_t) * 1.0j)
+
+ if f_idx >= 0 or t_idx >= 0:
+ val = Vm_f * Vm_t * np.conj(yft[k]) * ea * 1.0j
+
+ # from side
+ if f_idx >= 0:
+ Tx[nnz] = val
+ Ti[nnz] = k_counter
+ Tj[nnz] = f_idx
+ nnz += 1
+
+ # to side
+ if t_idx >= 0:
+ Tx[nnz] = -val
+ Ti[nnz] = k_counter
+ Tj[nnz] = t_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dSt_dVm_csc(nbus, br_indices, bus_indices, ytt, ytf, V, F, T) -> CxCSC:
+ """
+
+ :param nbus
+ :param br_indices:
+ :param bus_indices:
+ :param ytt:
+ :param ytf:
+ :param V:
+ :param F:
+ :param T:
+ :return:
+ """
+ n_row = len(br_indices)
+ n_cols = len(bus_indices)
+ max_nnz = len(ytt) * 2
+ mat = CxCSC(n_row, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+
+ j_lookup = make_lookup(nbus, bus_indices)
+
+ nnz = 0
+ # for j_counter, j in enumerate(bus_indices): # para cada columna j ...
+ for k_counter, k in enumerate(br_indices):
+ f = F[k]
+ t = T[k]
+ f_idx = j_lookup[f]
+ t_idx = j_lookup[t]
+ Vm_f = np.abs(V[f])
+ Vm_t = np.abs(V[t])
+ th_f = np.angle(V[f])
+ th_t = np.angle(V[t])
+ ea = np.exp((th_f - th_t) * 1.0j)
+
+ # from side
+ if f_idx >= 0:
+ Tx[nnz] = Vm_t * np.conj(ytf[k]) * ea
+ Ti[nnz] = k_counter
+ Tj[nnz] = f_idx
+ nnz += 1
+
+ # to side
+ if t_idx >= 0:
+ Tx[nnz] = 2 * Vm_t * np.conj(ytt[k]) + Vm_f * np.conj(ytf[k]) * ea
+ Ti[nnz] = k_counter
+ Tj[nnz] = t_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dSt_dVa_csc(nbus, br_indices, bus_indices, ytf, V, F, T) -> CxCSC:
+ """
+
+ :param nbus
+ :param br_indices:
+ :param bus_indices:
+ :param ytf:
+ :param V:
+ :param F:
+ :param T:
+ :return:
+ """
+ n_row = len(br_indices)
+ n_cols = len(bus_indices)
+ max_nnz = len(ytf) * 2
+ mat = CxCSC(n_row, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+
+ j_lookup = make_lookup(nbus, bus_indices)
+
+ nnz = 0
+ # for j_counter, j in enumerate(bus_indices): # para cada columna j ...
+ for k_counter, k in enumerate(br_indices):
+ f = F[k]
+ t = T[k]
+ f_idx = j_lookup[f]
+ t_idx = j_lookup[t]
+ Vm_f = np.abs(V[f])
+ Vm_t = np.abs(V[t])
+ th_f = np.angle(V[f])
+ th_t = np.angle(V[t])
+ ea = np.exp((th_f - th_t) * 1.0j)
+
+ if f_idx >= 0 or t_idx >= 0:
+ val = Vm_f * Vm_t * np.conj(ytf[k]) * ea * 1j
+
+ # from side
+ if f_idx >= 0:
+ Tx[nnz] = -val
+ Ti[nnz] = k_counter
+ Tj[nnz] = f_idx
+ nnz += 1
+
+ # to side
+ if t_idx >= 0:
+ Tx[nnz] = val
+ Ti[nnz] = k_counter
+ Tj[nnz] = t_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+
+
+@njit()
+def derivatives_tau_csc_numba(nbus, nbr, iPxsh,
+ F: IntVec, T: IntVec,
+ Ys: CxVec, kconv, tap, V) -> Tuple[CxCSC, CxCSC, CxCSC]:
+ """
+ This function computes the derivatives of Sbus, Sf and St w.r.t. the tap angle (tau)
+ - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
+ - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
+
+ :param nbus:
+ :param nbr:
+ :param iPxsh: array of indices {iPfsh or iPfdp}
+ :param F: Array of branch "from" bus indices
+ :param T: Array of branch "to" bus indices
+ :param Ys: Array of branch series admittances
+ :param kconv: Array of "k2" parameters
+ :param tap: Array of branch complex taps (m * exp(1j * tau)
+ :param V: Array of complex voltages
+ :return:
+ - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
+ - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
+ """
+ ndev = len(iPxsh)
+
+ # dSbus_dPxsh = lil_matrix((nb, ndev), dtype=complex)
+ dSbus_dsh = CxCSC(nbus, ndev, ndev * 2, False)
+ # dSbus_dsh_data = np.empty(ndev * 2, dtype=np.complex128)
+ # dSbus_dsh_indices = np.empty(ndev * 2, dtype=np.int32)
+ # dSbus_dsh_indptr = np.empty(ndev + 1, dtype=np.int32)
+
+ # dSf_dsh = lil_matrix((nl, ndev), dtype=complex)
+ dSf_dsh = CxCSC(nbr, ndev, ndev, False)
+ # dSf_dsh_data = np.empty(ndev, dtype=np.complex128)
+ # dSf_dsh_indices = np.empty(ndev, dtype=np.int32)
+ # dSf_dsh_indptr = np.empty(ndev + 1, dtype=np.int32)
+
+ # dSt_dsh = lil_matrix((nl, ndev), dtype=complex)
+ dSt_dsh = CxCSC(nbr, ndev, ndev, False)
+ # dSt_dsh_data = np.empty(ndev, dtype=np.complex128)
+ # dSt_dsh_indices = np.empty(ndev, dtype=np.int32)
+ # dSt_dsh_indptr = np.empty(ndev + 1, dtype=np.int32)
+
+ for k, idx in enumerate(iPxsh):
+ f = F[idx]
+ t = T[idx]
+
+ # Partials of Ytt, Yff, Yft and Ytf w.r.t. Ę shift
+ yft_dsh = -Ys[idx] / (-1j * kconv[idx] * np.conj(tap[idx]))
+ ytf_dsh = -Ys[idx] / (1j * kconv[idx] * tap[idx])
+
+ # Partials of S w.r.t. Ę shift
+ val_f = V[f] * np.conj(yft_dsh * V[t])
+ val_t = V[t] * np.conj(ytf_dsh * V[f])
+
+ # dSbus_dPxsh[f, k] = val_f
+ # dSbus_dPxsh[t, k] = val_t
+ dSbus_dsh.data[2 * k] = val_f
+ dSbus_dsh.data[2 * k + 1] = val_t
+ dSbus_dsh.indices[2 * k] = f
+ dSbus_dsh.indices[2 * k + 1] = t
+ dSbus_dsh.indptr[k] = 2 * k
+
+ # Partials of Sf w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "from" bus)
+ # dSf_dshx2[idx, k] = val_f
+ dSf_dsh.data[k] = val_f
+ dSf_dsh.indices[k] = idx
+ dSf_dsh.indptr[k] = k
+
+ # Partials of St w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "to" bus)
+ # dSt_dshx2[idx, k] = val_t
+ dSt_dsh.data[k] = val_t
+ dSt_dsh.indices[k] = idx
+ dSt_dsh.indptr[k] = k
+
+ dSbus_dsh.indptr[ndev] = ndev * 2
+ dSf_dsh.indptr[ndev] = ndev
+ dSt_dsh.indptr[ndev] = ndev
+
+ return dSbus_dsh, dSf_dsh, dSt_dsh
+
+
+@njit()
+def dSbus_dtau_csc(nbus, bus_indices, tau_indices, F: IntVec, T: IntVec, Ys: CxVec,
+ kconv: Vec, tap: CxVec, V: CxVec) -> CxCSC:
+ """
+ This function computes the derivatives of Sbus, Sf and St w.r.t. the tap angle (tau)
+ - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
+ - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
+
+ :param nbus:
+ :param bus_indices:
+ :param tau_indices: array of indices {iPfsh or iPfdp}
+ :param F: Array of branch "from" bus indices
+ :param T: Array of branch "to" bus indices
+ :param Ys: Array of branch series admittances
+ :param kconv: Array of "k2" parameters
+ :param tap: Array of branch complex taps (m * exp(1j * tau)
+ :param V: Array of complex voltages
+ :return: dSbus_dsh
+ """
+ n_cols = len(tau_indices)
+ n_rows = len(bus_indices)
+ max_nnz = len(tau_indices) * 2
+ mat = CxCSC(n_rows, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+
+ i_lookup = make_lookup(nbus, bus_indices)
+
+ nnz = 0
+ # for j_counter, j in enumerate(bus_indices): # para cada columna j ...
+ for k_counter, k in enumerate(tau_indices):
+ f = F[k]
+ t = T[k]
+ f_idx = i_lookup[f]
+ t_idx = i_lookup[t]
+
+ # from side
+ if f_idx >= 0:
+ yft_dsh = -Ys[k] / (-1j * kconv[k] * np.conj(tap[k]))
+ Tx[nnz] = V[f] * np.conj(yft_dsh * V[t])
+ Ti[nnz] = f_idx
+ Tj[nnz] = k_counter
+ nnz += 1
+
+ # to side
+ if t_idx >= 0:
+ ytf_dsh = -Ys[k] / (1j * kconv[k] * tap[k])
+ Tx[nnz] = V[t] * np.conj(ytf_dsh * V[f])
+ Ti[nnz] = t_idx
+ Tj[nnz] = k_counter
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dSf_dtau_csc(nbr, sf_indices, tau_indices, F: IntVec, T: IntVec, Ys: CxVec, kconv: Vec, tap: CxVec, V: CxVec) -> CxCSC:
+ """
+ This function computes the derivatives of Sbus, Sf and St w.r.t. the tap angle (tau)
+ - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
+ - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
+
+ :param nbr: number of branches
+ :param sf_indices: array of sf indices
+ :param tau_indices: array of branch indices with tau control (must be equal to sf_indices)
+ :param F: Array of branch "from" bus indices
+ :param T: Array of branch "to" bus indices
+ :param Ys: Array of branch series admittances
+ :param kconv: Array of "k2" parameters
+ :param tap: Array of branch complex taps (m * exp(1j * tau)
+ :param V: Array of complex voltages
+ :return: dSf_dsh
+ """
+ n_cols = len(tau_indices)
+ n_rows = len(sf_indices)
+ max_nnz = len(tau_indices)
+ mat = CxCSC(n_rows, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+ i_lookup = make_lookup(nbr, sf_indices)
+ nnz = 0
+ for k_idx, k in enumerate(tau_indices):
+
+ i_idx = i_lookup[k]
+
+ if i_idx > -1:
+ f = F[k]
+ t = T[k]
+
+ # Partials of Ytt, Yff, Yft and Ytf w.r.t. Ę shift
+ yft_dsh = -Ys[k] / (-1j * kconv[k] * np.conj(tap[k]))
+
+ # Partials of Sf w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "from" bus)
+ Tx[nnz] = V[f] * np.conj(yft_dsh * V[t])
+ Ti[nnz] = i_idx
+ Tj[nnz] = k_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dSt_dtau_csc(nbr, st_indices, tau_indices, F: IntVec, T: IntVec, Ys: CxVec, kconv: Vec, tap: CxVec, V: CxVec) -> CxCSC:
+ """
+ This function computes the derivatives of Sbus, Sf and St w.r.t. the tap angle (tau)
+ - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
+ - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
+
+ :param nbr: number of branches
+ :param st_indices: array of st indices
+ :param tau_indices: array of branch indices with tau control
+ :param F: Array of branch "from" bus indices
+ :param T: Array of branch "to" bus indices
+ :param Ys: Array of branch series admittances
+ :param kconv: Array of "k2" parameters
+ :param tap: Array of branch complex taps (m * exp(1j * tau)
+ :param V: Array of complex voltages
+ :return: dSf_dsh
+ :return: dSt_dtau
+ """
+
+ n_cols = len(tau_indices)
+ n_rows = len(st_indices)
+ max_nnz = len(tau_indices)
+ mat = CxCSC(n_rows, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+ i_lookup = make_lookup(nbr, st_indices)
+ nnz = 0
+ for k_idx, k in enumerate(tau_indices):
+ i_idx = i_lookup[k]
+
+ if i_idx > -1:
+ f = F[k]
+ t = T[k]
+
+ # Partials of Ytt, Yff, Yft and Ytf w.r.t. Ę shift
+ ytf_dsh = -Ys[k] / (1j * kconv[k] * tap[k])
+
+ # Partials of Sf w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "from" bus)
+ Tx[nnz] = V[t] * np.conj(ytf_dsh * V[f])
+ Ti[nnz] = i_idx
+ Tj[nnz] = k_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def derivatives_ma_csc_numba(nbus, nbr, iXxma, F, T, Ys, kconv, tap, tap_module, Bc, Beq, V) -> Tuple[CxCSC, CxCSC, CxCSC]:
+ """
+ Useful for the calculation of
+ - dSbus_dQfma, dSf_dQfma, dSt_dQfma -> wih iXxma=iQfma
+ - dSbus_dQtma, dSf_dQtma, dSt_dQtma -> wih iXxma=iQtma
+ - dSbus_dVtma, dSf_dVtma, dSt_dVtma -> wih iXxma=iVtma
+
+ :param nbus: Number of buses
+ :param nbr: Number of Branches
+ :param iXxma: Array of indices {iQfma, iQtma, iVtma}
+ :param F: Array of branch "from" bus indices
+ :param T: Array of branch "to" bus indices
+ :param Ys: Array of branch series admittances
+ :param kconv: Array of "k2" parameters
+ :param tap: Array of branch complex taps (ma * exp(1j * theta_sh)
+ :param tap_module: Array of tap modules (this is to avoid extra calculations)
+ :param Bc: Array of branch total shunt susceptance values (sum of the two legs)
+ :param Beq: Array of regulation susceptance of the FUBM model
+ :param V:Array of complex voltages
+
+ :return: dSbus_dma, dSf_dma, dSt_dma
+ """
+ # Declare the derivative
+ ndev = len(iXxma)
+
+ # dSbus_dma = lil_matrix((nb, ndev), dtype=complex)
+ dSbus_dma = CxCSC(nbus, ndev, ndev * 2, False)
+ # dSbus_dma_data = np.empty(ndev2, dtype=np.complex128)
+ # dSbus_dma_indices = np.empty(ndev2, dtype=np.int32)
+ # dSbus_dma_indptr = np.empty(ndev + 1, dtype=np.int32)
+
+ # dSf_dma = lil_matrix((nl, ndev), dtype=complex)
+ dSf_dma = CxCSC(nbr, ndev, ndev, False)
+ # dSf_dma_data = np.empty(ndev, dtype=np.complex128)
+ # dSf_dma_indices = np.empty(ndev, dtype=np.int32)
+ # dSf_dma_indptr = np.empty(ndev + 1, dtype=np.int32)
+
+ # dSt_dma = lil_matrix((nl, ndev), dtype=complex)
+ dSt_dma = CxCSC(nbr, ndev, ndev, False)
+ # dSt_dma_data = np.empty(ndev, dtype=np.complex128)
+ # dSt_dma_indices = np.empty(ndev, dtype=np.int32)
+ # dSt_dma_indptr = np.empty(ndev + 1, dtype=np.int32)
+
+ for k, idx in enumerate(iXxma):
+ f = F[idx]
+ t = T[idx]
+
+ YttB = Ys[idx] + 1j * (Bc[idx] / 2 + Beq[idx])
+
+ # Partials of Ytt, Yff, Yft and Ytf w.r.t.ma
+ dyff_dma = -2 * YttB / (np.power(kconv[idx], 2) * np.power(tap_module[idx], 3))
+ dyft_dma = Ys[idx] / (kconv[idx] * tap_module[idx] * np.conj(tap[idx]))
+ dytf_dma = Ys[idx] / (kconv[idx] * tap_module[idx] * tap[idx])
+
+ val_f = V[f] * np.conj(dyff_dma * V[f] + dyft_dma * V[t])
+ val_t = V[t] * np.conj(dytf_dma * V[f])
+
+ # Partials of S w.r.t.ma
+ # dSbus_dma[f, k] = val_f
+ # dSbus_dma[t, k] = val_t
+ dSbus_dma.data[2 * k] = val_f
+ dSbus_dma.indices[2 * k] = f
+ dSbus_dma.data[2 * k + 1] = val_t
+ dSbus_dma.indices[2 * k + 1] = t
+ dSbus_dma.indptr[k] = 2 * k
+
+ # dSf_dma[idx, k] = val_f
+ dSf_dma.data[k] = val_f
+ dSf_dma.indices[k] = idx
+ dSf_dma.indptr[k] = k
+
+ # dSt_dma[idx, k] = val_f
+ dSt_dma.data[k] = val_t
+ dSt_dma.indices[k] = idx
+ dSt_dma.indptr[k] = k
+
+ dSbus_dma.indptr[ndev] = ndev * 2
+ dSf_dma.indptr[ndev] = ndev
+ dSt_dma.indptr[ndev] = ndev
+
+ return dSbus_dma, dSf_dma, dSt_dma
+
+
+@njit()
+def dSbus_dm_csc(nbus, bus_indices, m_indices, F: IntVec, T: IntVec, Ys: CxVec, Bc: CxVec, Beq: Vec,
+ kconv: Vec, tap: CxVec, tap_module: Vec, V: CxVec) -> CxCSC:
+ """
+
+ :param nbus:
+ :param bus_indices:
+ :param m_indices:
+ :param F: Array of branch "from" bus indices
+ :param T: Array of branch "to" bus indices
+ :param Ys: Array of branch series admittances
+ :param Bc: Array of branch total susceptance values (sum of the two legs)
+ :param Beq: Array of regulation susceptance of the FUBM model
+ :param kconv: Array of "k2" parameters
+ :param tap: Array of branch complex taps (m * exp(1j * tau)
+ :param tap_module: Array of tap modules
+ :param V: Array of complex voltages
+ :return:
+ """
+ n_cols = len(m_indices)
+ n_rows = len(bus_indices)
+ max_nnz = len(m_indices) * 2
+ mat = CxCSC(n_rows, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+
+ j_lookup = make_lookup(nbus, bus_indices)
+
+ nnz = 0
+ # for j_counter, j in enumerate(bus_indices): # para cada columna j ...
+ for k_counter, k in enumerate(m_indices):
+ f = F[k]
+ t = T[k]
+ f_idx = j_lookup[f]
+ t_idx = j_lookup[t]
+
+ # from side
+ if f_idx >= 0:
+ YttB = Ys[k] + 1j * (Bc[k] / 2 + Beq[k])
+ dyff_dm = -2 * YttB / (np.power(kconv[k], 2) * np.power(tap_module[k], 3))
+ dyft_dm = Ys[k] / (kconv[k] * tap_module[k] * np.conj(tap[k]))
+ Tx[nnz] = V[f] * np.conj(dyff_dm * V[f] + dyft_dm * V[t])
+ Ti[nnz] = f_idx
+ Tj[nnz] = k_counter
+ nnz += 1
+
+ # to side
+ if t_idx >= 0:
+ dytf_dm = Ys[k] / (kconv[k] * tap_module[k] * tap[k])
+ Tx[nnz] = V[t] * np.conj(dytf_dm * V[f])
+ Ti[nnz] = t_idx
+ Tj[nnz] = k_counter
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dSf_dm_csc(nbr, sf_indices, m_indices, F: IntVec, T: IntVec, Ys: CxVec, Bc: CxVec, Beq: Vec,
+ kconv: Vec, tap: CxVec, tap_module: Vec, V: CxVec) -> CxCSC:
+ """
+ This function computes the derivatives of Sbus, Sf and St w.r.t. the tap angle (tau)
+ - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
+ - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
+
+ :param nbr
+ :param sf_indices: array of sf indices
+ :param m_indices: array of branch indices with tau control
+ :param F: Array of branch "from" bus indices
+ :param T: Array of branch "to" bus indices
+ :param Ys: Array of branch series admittances
+ :param Bc: Array of branch total susceptance values
+ :param Beq: Array of regulation susceptance of the FUBM model
+ :param kconv: Array of "k2" parameters
+ :param tap: Array of branch complex taps (m * exp(1j * tau)
+ :param tap_module: Array of tap modules
+ :param V: Array of complex voltages
+ :return: dSf_dsh
+ """
+ n_cols = len(m_indices)
+ n_rows = len(sf_indices)
+ max_nnz = len(m_indices)
+ mat = CxCSC(n_rows, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+ i_lookup = make_lookup(nbr, sf_indices)
+ nnz = 0
+ for k_idx, k in enumerate(m_indices):
+ i_idx = i_lookup[k]
+
+ if i_idx > -1:
+ f = F[k]
+ t = T[k]
+
+ YttB = Ys[k] + 1j * ((Bc[k] / 2.0) + Beq[k])
+
+ # Partials of Ytt, Yff, Yft and Ytf w.r.t.ma
+ dyff_dma = -2 * YttB / (np.power(kconv[k], 2) * np.power(tap_module[k], 3))
+ dyft_dma = Ys[k] / (kconv[k] * tap_module[k] * np.conj(tap[k]))
+
+ # Partials of Sf w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "from" bus)
+ Tx[nnz] = V[f] * np.conj(dyff_dma * V[f] + dyft_dma * V[t])
+ Ti[nnz] = i_idx
+ Tj[nnz] = k_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dSt_dm_csc(nbr, st_indices, m_indices, F: IntVec, T: IntVec, Ys: CxVec, kconv: Vec,
+ tap: CxVec, tap_module: Vec, V: CxVec) -> CxCSC:
+ """
+ This function computes the derivatives of Sbus, Sf and St w.r.t. the tap angle (tau)
+ - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
+ - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
+
+ :param nbr:
+ :param st_indices: array of st indices
+ :param m_indices: array of branch indices with tau control
+ :param F: Array of branch "from" bus indices
+ :param T: Array of branch "to" bus indices
+ :param Ys: Array of branch series admittances
+ :param kconv: Array of "k2" parameters
+ :param tap: Array of branch complex taps (m * exp(1j * tau)
+ :param tap_module
+ :param V: Array of complex voltages
+ :return: dSf_dsh
+ :return: dSt_dtau
+ """
+
+ n_cols = len(m_indices)
+ n_rows = len(st_indices)
+ max_nnz = len(m_indices)
+ mat = CxCSC(n_rows, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+ i_lookup = make_lookup(nbr, st_indices)
+ nnz = 0
+ for k_idx, k in enumerate(m_indices):
+ i_idx = i_lookup[k]
+
+ if i_idx > -1:
+ f = F[k]
+ t = T[k]
+
+ dytf_dma = Ys[k] / (kconv[k] * tap_module[k] * tap[k])
+
+ # Partials of Sf w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "from" bus)
+ Tx[nnz] = V[t] * np.conj(dytf_dma * V[f])
+ Ti[nnz] = i_idx
+ Tj[nnz] = k_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def derivatives_Beq_csc_numba(nbus, nbr, iBeqx, F, V, tap_module, kconv):
+ """
+ Compute the derivatives of:
+ - dSbus_dBeqz, dSf_dBeqz, dSt_dBeqz -> iBeqx=iBeqz
+ - dSbus_dBeqv, dSf_dBeqv, dSt_dBeqv -> iBeqx=iBeqv
+
+ :param nbus: Number of buses
+ :param nbr: Number of Branches
+ :param iBeqx: array of indices {iBeqz, iBeqv}
+ :param F: Array of branch "from" bus indices
+ :param V:Array of complex voltages
+ :param tap_module: Array of branch taps modules
+ :param kconv: Array of "k2" parameters
+
+ :return:
+ - dSbus_dBeqz, dSf_dBeqz, dSt_dBeqz -> if iBeqx=iBeqz
+ - dSbus_dBeqv, dSf_dBeqv, dSt_dBeqv -> if iBeqx=iBeqv
+ """
+
+ ndev = len(iBeqx)
+
+ dSbus_dBeq = CxCSC(nbus, ndev, ndev, False)
+ dSf_dBeq = CxCSC(nbr, ndev, ndev, False)
+ dSt_dBeq = CxCSC(nbr, ndev, 0, True)
+
+ for k, idx in enumerate(iBeqx):
+ # k: 0, 1, 2, 3, 4, ...
+ # idx: actual branch index in the general Branches schema
+
+ f = F[idx]
+
+ # Partials of Ytt, Yff, Yft and Ytf w.r.t.Beq
+ dyff_dBeq = 1j / np.power(kconv[idx] * tap_module[idx], 2.0)
+
+ # Partials of S w.r.t.Beq
+ val_f = V[f] * np.conj(dyff_dBeq * V[f])
+
+ # dSbus_dBeqx[f, k] = val_f
+ dSbus_dBeq.data[k] = val_f
+ dSbus_dBeq.indices[k] = f
+ dSbus_dBeq.indptr[k] = k
+
+ # dSbus_dBeqx[t, k] = val_t
+ # (no need to store this one)
+
+ # Partials of Sf w.r.t.Beq
+ # dSf_dBeqx[idx, k] = val_f
+ dSf_dBeq.data[k] = val_f
+ dSf_dBeq.indices[k] = idx
+ dSf_dBeq.indptr[k] = k
+
+ # Partials of St w.r.t.Beq
+ # dSt_dBeqx[idx, k] = val_t
+ # (no need to store this one)
+
+ dSbus_dBeq.indptr[ndev] = ndev
+ dSf_dBeq.indptr[ndev] = ndev
+
+ return dSbus_dBeq, dSf_dBeq, dSt_dBeq
+
+
+@njit()
+def dSbus_dbeq_csc(nbus, bus_indices, beq_indices, F: IntVec, kconv: Vec, tap_module: Vec, V: CxVec) -> CxCSC:
+ """
+
+ :param nbus:
+ :param bus_indices:
+ :param beq_indices:
+ :param F: Array of branch "from" bus indices
+ :param kconv: Array of "k2" parameters
+ :param tap_module: Array of tap modules
+ :param V: Array of complex voltages
+ :return:
+ """
+ n_cols = len(beq_indices)
+ n_rows = len(bus_indices)
+ max_nnz = len(beq_indices)
+ mat = CxCSC(n_rows, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+
+ j_lookup = make_lookup(nbus, bus_indices)
+
+ nnz = 0
+ # for j_counter, j in enumerate(bus_indices): # para cada columna j ...
+ for k_counter, k in enumerate(beq_indices):
+ f = F[k]
+ f_idx = j_lookup[f]
+
+ # from side
+ if f_idx >= 0:
+ """
+ # Partials of Ytt, Yff, Yft and Ytf w.r.t.Beq
+ dyff_dBeq = 1j / np.power(kconv[idx] * tap_module[idx], 2.0)
+
+ # Partials of S w.r.t.Beq
+ val_f = V[f] * np.conj(dyff_dBeq * V[f])
+ """
+
+ dyff_dBeq = 1.0j / np.power(kconv[k] * tap_module[k] + 1e-20, 2.0)
+ Tx[nnz] = V[f] * np.conj(dyff_dBeq * V[f])
+ Ti[nnz] = f_idx
+ Tj[nnz] = k_counter
+ nnz += 1
+
+ # to side: it is zero
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dSf_dbeq_csc(nbr, sf_indices, beq_indices, F: IntVec, kconv: Vec, tap_module: Vec, V: CxVec) -> CxCSC:
+ """
+ This function computes the derivatives of Sbus, Sf and St w.r.t. the tap angle (tau)
+ - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
+ - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
+
+ :param nbr: Number of branches
+ :param sf_indices: array of sf indices
+ :param beq_indices: array of branch indices with tau control
+ :param F: Array of branch "from" bus indices
+ :param kconv: Array of "k2" parameters
+ :param tap_module: Array of tap modules
+ :param V: Array of complex voltages
+ :return: dSf_dsh
+ """
+ n_cols = len(beq_indices)
+ n_rows = len(sf_indices)
+ max_nnz = len(beq_indices)
+ mat = CxCSC(n_rows, n_cols, max_nnz, False)
+ Tx = np.empty(max_nnz, dtype=np.complex128)
+ Ti = np.empty(max_nnz, dtype=np.int32)
+ Tj = np.empty(max_nnz, dtype=np.int32)
+ i_lookup = make_lookup(nbr, sf_indices)
+ nnz = 0
+ for k_idx, k in enumerate(beq_indices):
+ i_idx = i_lookup[k]
+
+ if i_idx > -1:
+ f = F[k]
+
+ # Partials of Ytt, Yff, Yft and Ytf w.r.t.Beq
+ dyff_dBeq = 1j / np.power(kconv[k] * tap_module[k] + 1e-20, 2.0)
+
+ # Partials of Sf w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "from" bus)
+ Tx[nnz] = V[f] * np.conj(dyff_dBeq * V[f])
+ Ti[nnz] = i_idx
+ Tj[nnz] = k_idx
+ nnz += 1
+
+ # convert to csc
+ mat.fill_from_coo(Ti, Tj, Tx, nnz)
+
+ return mat
+
+
+@njit()
+def dSt_dbeq_csc(sf_indices, beq_indices) -> CxCSC:
+ """
+ This function computes the derivatives of Sbus, Sf and St w.r.t. the tap angle (tau)
+ - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
+ - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
+
+ :param sf_indices: array of sf indices
+ :param beq_indices: array of branch indices with tau control
+ :return: dSf_dsh
+ :return: dSt_dtau
+ """
+
+ n_cols = len(beq_indices)
+ n_rows = len(sf_indices)
+ mat = CxCSC(n_rows, n_cols, 0, False)
+
+ # the whole thing is zero
+
+ return mat
diff --git a/src/GridCalEngine/Simulations/Derivatives/csr_derivatives.py b/src/GridCalEngine/Simulations/Derivatives/csr_derivatives.py
new file mode 100644
index 000000000..91c13b880
--- /dev/null
+++ b/src/GridCalEngine/Simulations/Derivatives/csr_derivatives.py
@@ -0,0 +1,101 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import numpy as np
+from numba import njit, complex128, int32, float64
+from typing import Tuple
+import scipy.sparse as sp
+from scipy.sparse import lil_matrix, diags, csc_matrix, csr_matrix
+from GridCalEngine.basic_structures import CxVec, IntVec
+from GridCalEngine.Utils.Sparse.csc2 import CSC, CxCSC
+
+
+@njit(cache=True)
+def dSbus_dV_numba_sparse_csr(Yx: CxVec, Yp: IntVec, Yj: IntVec, V: CxVec, E: CxVec) -> Tuple[
+ CxVec, CxVec]: # pragma: no cover
+ """
+ partial derivatives of power injection w.r.t. voltage.
+ :param Yx: Ybus data in CSC format
+ :param Yp: Ybus indptr in CSC format
+ :param Yj: Ybus indices in CSC format
+ :param V: Voltage vector
+ :param E: Normalized voltage vector
+ :return: dS_dVm, dS_dVa data in CSR format, index pointer and indices are the same as the ones from Ybus
+ """
+
+ # init buffer vector
+ n = len(V)
+ buffer = np.zeros(n, dtype=complex128)
+ Ibus = np.zeros(n, dtype=complex128)
+
+ # buffer = np.zeros(n, dtype=complex)
+ # Ibus = np.zeros(n, dtype=complex)
+
+ dS_dVm = Yx.copy()
+ dS_dVa = Yx.copy()
+
+ # iterate through sparse matrix
+ for r in range(len(Yp) - 1):
+ for k in range(Yp[r], Yp[r + 1]):
+ # Ibus = Ybus * V
+ buffer[r] += Yx[k] * V[Yj[k]]
+
+ # Ybus * diag(Vnorm)
+ dS_dVm[k] *= E[Yj[k]]
+
+ # Ybus * diag(V)
+ dS_dVa[k] *= V[Yj[k]]
+
+ Ibus[r] += buffer[r]
+
+ # conj(diagIbus) * diagVnorm
+ buffer[r] = np.conj(buffer[r]) * E[r]
+
+ for r in range(len(Yp) - 1):
+ for k in range(Yp[r], Yp[r + 1]):
+ # diag(V) * conj(Ybus * diagVnorm)
+ dS_dVm[k] = np.conj(dS_dVm[k]) * V[r]
+
+ if r == Yj[k]:
+ # diagonal elements
+ dS_dVa[k] = -Ibus[r] + dS_dVa[k]
+ dS_dVm[k] += buffer[r]
+
+ # 1j * diagV * conj(diagIbus - Ybus * diagV)
+ dS_dVa[k] = np.conj(-dS_dVa[k]) * (1j * V[r])
+
+ return dS_dVm, dS_dVa
+
+
+def dSbus_dV_csr(Ybus: csc_matrix, V: CxVec) -> Tuple[csr_matrix, csr_matrix]:
+ """
+ Calls functions to calculate dS/dV depending on whether Ybus is sparse or not
+ :param Ybus: Ybus in CSC
+ :param V: Voltages vector
+ :return: dS_dVm, dS_dVa in CSR format
+ """
+
+ # I is subtracted from Y*V,
+ # therefore it must be negative for numba version of dSbus_dV if it is not zeros anyways
+ # calculates sparse data
+ dS_dVm, dS_dVa = dSbus_dV_numba_sparse_csr(Ybus.data, Ybus.indptr, Ybus.indices, V, V / np.abs(V))
+
+ # generate sparse CSR matrices with computed data and return them
+ return (sp.csr_matrix((dS_dVm, Ybus.indices, Ybus.indptr)),
+ sp.csr_matrix((dS_dVa, Ybus.indices, Ybus.indptr)))
+
+
diff --git a/src/GridCalEngine/Simulations/Derivatives/matpower_derivatives.py b/src/GridCalEngine/Simulations/Derivatives/matpower_derivatives.py
new file mode 100644
index 000000000..b45eb2625
--- /dev/null
+++ b/src/GridCalEngine/Simulations/Derivatives/matpower_derivatives.py
@@ -0,0 +1,314 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import numpy as np
+from typing import Tuple
+from scipy.sparse import diags, csc_matrix, vstack, hstack
+from GridCalEngine.basic_structures import CxVec, IntVec, Vec
+
+
+def dSbus_dV_matpower(Ybus: csc_matrix, V: CxVec) -> Tuple[csc_matrix, csc_matrix]:
+ """
+ Derivatives of the power Injections w.r.t the voltage
+ :param Ybus: Admittance matrix
+ :param V: complex voltage arrays
+ :return: dSbus_dVa, dSbus_dVm
+ """
+ diagV = diags(V)
+ diagE = diags(V / np.abs(V))
+ Ibus = Ybus * V
+ diagIbus = diags(Ibus)
+
+ dSbus_dVa = 1j * diagV * np.conj(diagIbus - Ybus * diagV) # dSbus / dVa
+ dSbus_dVm = diagV * np.conj(Ybus * diagE) + np.conj(diagIbus) * diagE # dSbus / dVm
+
+ return dSbus_dVa.tocsc(), dSbus_dVm.tocsc()
+
+
+def dSbr_dV_matpower(Yf: csc_matrix, Yt: csc_matrix, V: CxVec,
+ F: IntVec, T: IntVec,
+ Cf: csc_matrix, Ct: csc_matrix) -> Tuple[csc_matrix, csc_matrix, csc_matrix, csc_matrix]:
+ """
+ Derivatives of the branch power w.r.t the branch voltage modules and angles
+ :param Yf: Admittances matrix of the Branches with the "from" buses
+ :param Yt: Admittances matrix of the Branches with the "to" buses
+ :param V: Array of voltages
+ :param F: Array of branch "from" bus indices
+ :param T: Array of branch "to" bus indices
+ :param Cf: Connectivity matrix of the Branches with the "from" buses
+ :param Ct: Connectivity matrix of the Branches with the "to" buses
+ :return: dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm
+ """
+ Yfc = np.conj(Yf)
+ Ytc = np.conj(Yt)
+ Vc = np.conj(V)
+ Ifc = Yfc * Vc # conjugate of "from" current
+ Itc = Ytc * Vc # conjugate of "to" current
+
+ diagIfc = diags(Ifc)
+ diagItc = diags(Itc)
+ Vf = V[F]
+ Vt = V[T]
+ diagVf = diags(Vf)
+ diagVt = diags(Vt)
+ diagVc = diags(Vc)
+
+ Vnorm = V / np.abs(V)
+ diagVnorm = diags(Vnorm)
+ diagV = diags(V)
+
+ CVf = Cf * diagV
+ CVt = Ct * diagV
+ CVnf = Cf * diagVnorm
+ CVnt = Ct * diagVnorm
+
+ dSf_dVa = 1j * (diagIfc * CVf - diagVf * Yfc * diagVc)
+ dSf_dVm = diagVf * np.conj(Yf * diagVnorm) + diagIfc * CVnf
+ dSt_dVa = 1j * (diagItc * CVt - diagVt * Ytc * diagVc)
+ dSt_dVm = diagVt * np.conj(Yt * diagVnorm) + diagItc * CVnt
+
+ return dSf_dVa.tocsc(), dSf_dVm.tocsc(), dSt_dVa.tocsc(), dSt_dVm.tocsc()
+
+
+def dSf_dV_matpower(Yf: csc_matrix, V: CxVec, F: IntVec,
+ Cf: csc_matrix, Vc: CxVec,
+ diagVc: csc_matrix,
+ diagE: csc_matrix,
+ diagV: csc_matrix) -> Tuple[csc_matrix, csc_matrix]:
+ """
+ Derivatives of the branch power "from" w.r.t the branch voltage modules and angles
+ :param Yf: Admittances matrix of the Branches with the "from" buses
+ :param V: Array of voltages
+ :param F: Array of branch "from" bus indices
+ :param Cf: Connectivity matrix of the Branches with the "from" buses
+ :param Vc: array of conjugate voltages
+ :param diagVc: diagonal matrix of conjugate voltages
+ :param diagE: diagonal matrix of normalized voltages
+ :param diagV: diagonal matrix of voltages
+ :return: dSf_dVa, dSf_dVm
+ """
+
+ Yfc = np.conj(Yf)
+ Ifc = Yfc * Vc # conjugate of "from" current
+
+ diagIfc = diags(Ifc)
+ Vf = V[F]
+ diagVf = diags(Vf)
+
+ CVf = Cf * diagV
+ CVnf = Cf * diagE
+
+ dSf_dVa = 1j * (diagIfc * CVf - diagVf * Yfc * diagVc)
+ dSf_dVm = diagVf * np.conj(Yf * diagE) + diagIfc * CVnf
+
+ return dSf_dVa.tocsc(), dSf_dVm.tocsc()
+
+
+def dSt_dV_matpower(Yt, V, T, Ct, Vc, diagVc, diagE, diagV):
+ """
+ Derivatives of the branch power "to" w.r.t the branch voltage modules and angles
+ :param Yt: Admittances matrix of the Branches with the "to" buses
+ :param V: Array of voltages
+ :param T: Array of branch "to" bus indices
+ :param Ct: Connectivity matrix of the Branches with the "to" buses
+ :param Vc: array of conjugate voltages
+ :param diagVc: diagonal matrix of conjugate voltages
+ :param diagE: diagonal matrix of normalized voltages
+ :param diagV: diagonal matrix of voltages
+ :return: dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm
+ """
+ Ytc = np.conj(Yt)
+ Itc = Ytc * Vc # conjugate of "to" current
+
+ diagItc = diags(Itc)
+ Vt = V[T]
+ diagVt = diags(Vt)
+
+ CVt = Ct * diagV
+ CVnt = Ct * diagE
+
+ dSt_dVa = 1j * (diagItc * CVt - diagVt * Ytc * diagVc)
+ dSt_dVm = diagVt * np.conj(Yt * diagE) + diagItc * CVnt
+
+ return dSt_dVa.tocsc(), dSt_dVm.tocsc()
+
+
+def dS_dm_matpower(V: CxVec, Cf: csc_matrix, Ct: csc_matrix,
+ R: Vec, X: Vec, B: Vec, Beq: Vec, k2: Vec, m: Vec, tau: Vec):
+ """
+
+ :param V:
+ :param Cf:
+ :param Ct:
+ :param R:
+ :param X:
+ :param B:
+ :param Beq:
+ :param k2:
+ :param m:
+ :param tau:
+ :return:
+ """
+ diagV = diags(V)
+ Vf = Cf @ V
+ Vt = Ct @ V
+ diagVf = diags(Vf)
+ diagVt = diags(Vt)
+
+ ys = 1.0 / (R + 1j * X + 1e-20)
+
+ dyff_dm = (-2.0 * (ys + 1.0j * B / 2.0 + 1.0j * Beq)) / (np.power(k2, 2) * np.power(m, 3))
+ dyft_dm = ys / (k2 * np.power(m, 2) * np.exp(-1j * tau))
+ dytf_dm = ys / (k2 * np.power(m, 2) * np.exp(1j * tau))
+ dytt_dm = np.zeros(len(m))
+
+ dYf_dm = diags(dyff_dm) @ Cf + diags(dyft_dm) @ Ct
+ dYt_dm = diags(dytf_dm) @ Cf + diags(dytt_dm) @ Ct
+
+ dY_dm = Cf.T @ dYf_dm + Ct.T @ dYt_dm
+
+ dS_dm = diagV @ np.conj(dY_dm @ diagV)
+ dSf_dm = diagVf @ diags(np.conj(dYf_dm @ V))
+ dSt_dm = diagVt @ diags(np.conj(dYt_dm @ V))
+
+ return dS_dm, dSf_dm, dSt_dm
+
+
+def dS_dtau_matpower(V: CxVec, Cf: csc_matrix, Ct: csc_matrix,
+ R: Vec, X: Vec, k2: Vec, m: Vec, tau: Vec):
+ """
+ Ybus = Cf' * Yf + Ct' * Yt + diag(Ysh)
+
+ Yf = Yff * Cf + Yft * Ct
+ Yt = Ytf * Cf + Ytt * Ct
+
+ Ytt = Ys + 1j*Bc/2
+ Yff = Gsw+( (Ytt+1j*Beq) ./ ((k2.^2).*tap .* conj(tap)) ) %%< csc_matrix:
+ """
+ Computes the system Jacobian matrix in polar coordinates
+ Args:
+ :param Ybus: Admittance matrix
+ :param V: Array of nodal voltages
+ :param idx_dVa: vector of indices of PV|PQ|PQV|P buses
+ :param idx_dVm: vector of indices of PQ|P buses
+ :param idx_dP: vector of indices of PV|PQ|PQV|P buses
+ :param idx_dQ: vector of indices of PQ|PQV buses
+
+ Returns:
+ The system Jacobian matrix
+ """
+ assert np.all(idx_dP == idx_dVa)
+
+ dS_dVa, dS_dVm = dSbus_dV_matpower(Ybus, V)
+
+ J11 = dS_dVa[np.ix_(idx_dP, idx_dVa)].real
+ J12 = dS_dVm[np.ix_(idx_dP, idx_dVm)].real
+ J21 = dS_dVa[np.ix_(idx_dQ, idx_dVa)].imag
+ J22 = dS_dVm[np.ix_(idx_dQ, idx_dVm)].imag
+
+ J = vstack([hstack([J11, J12]),
+ hstack([J21, J22])], format="csc")
+
+ return csc_matrix(J)
diff --git a/src/GridCalEngine/Simulations/InvestmentsEvaluation/Methods/mixed_variable_NSGA_2.py b/src/GridCalEngine/Simulations/InvestmentsEvaluation/Methods/mixed_variable_NSGA_2.py
index fbfd8adef..6cb90afaf 100644
--- a/src/GridCalEngine/Simulations/InvestmentsEvaluation/Methods/mixed_variable_NSGA_2.py
+++ b/src/GridCalEngine/Simulations/InvestmentsEvaluation/Methods/mixed_variable_NSGA_2.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from typing import List, Dict, Union
from pymoo.core.mixed import MixedVariableGA
from pymoo.algorithms.moo.nsga2 import RankAndCrowding
# from pymoo.decomposition.asf import ASF
@@ -23,35 +24,100 @@
from pymoo.core.problem import ElementwiseProblem
from pymoo.core.variable import Real, Integer, Choice, Binary
+from GridCalEngine.Devices.Aggregation.investment import Investment
+from GridCalEngine.Devices.multi_circuit import MultiCircuit
+from GridCalEngine.Devices.Branches.transformer import Transformer2W
+from GridCalEngine.Devices.Branches.line import Line
+from GridCalEngine.Devices.types import BRANCH_TYPES, BRANCH_TEMPLATE_TYPES
+from GridCalEngine.enumerations import DeviceType
+from GridCalEngine.basic_structures import Logger
+
class MixedVariableProblem(ElementwiseProblem):
"""
Problem formulation packaging to use the pymoo library
"""
- def __init__(self, obj_func, n_obj):
+
+ def __init__(self, grid: MultiCircuit, obj_func, n_obj):
"""
:param obj_func:
:param n_obj:
"""
- # These will need to be inputted automatically from the csv file on GridCal
- vars = {
- "react1_bi": Binary(),
- "react2_bi": Binary(),
- "react3_bi": Binary(),
- "react4_bi": Binary(),
- "react5_bi": Binary(),
- # "vol_level": Choice(options=["vol132","vol220"]),
- "vol_level": Choice(options=["vol220"]),
- # "vol_level": Choice(options=["vol132"]),
- "n_cables": Integer(bounds=(2, 3)),
- "S_rtr": Real(bounds=(500e6, 1000e6)),
- "react1": Real(bounds=(0.0, 1.0)),
- "react2": Real(bounds=(0.0, 1.0)),
- "react3": Real(bounds=(0.0, 1.0)),
- "react4": Real(bounds=(0.0, 1.0)),
- "react5": Real(bounds=(0.0, 1.0))}
- super().__init__(n_obj=n_obj,
- vars=vars)
+
+ ElementwiseProblem.__init__(self, n_var=n_obj, n_obj=n_obj)
+
+ self.logger = Logger()
+
+ self.grid = grid
+
+ all_dict = self.grid.get_all_elements_dict()
+ self.device_template_dict: Dict[BRANCH_TYPES, List[BRANCH_TEMPLATE_TYPES]] = dict()
+
+ # create the decision vars
+ for investment_group, investments_list in self.grid.get_investments_by_groups():
+
+ if len(investments_list) == 1:
+
+ for investment in investments_list:
+
+ device = all_dict.get(investment.device_idtag, None)
+
+ if device is not None:
+ if isinstance(device, Transformer2W):
+
+ for ass_key, association in device.possible_transformer_types.data.items():
+ template = association.api_object
+ lst = self.device_template_dict.get(device, None)
+ if lst is None:
+ self.device_template_dict[device] = [template]
+ else:
+ lst.extend([template])
+
+ elif isinstance(device, Line):
+
+ for association_type in [device.possible_tower_types,
+ device.possible_sequence_line_types,
+ device.possible_underground_line_types]:
+
+ for ass_key, association in association_type.data.items():
+ template = association.api_object
+ lst = self.device_template_dict.get(device, None)
+ if lst is None:
+ self.device_template_dict[device] = [template]
+ else:
+ lst.extend([template])
+ else:
+ self.logger.add_error("Investment device not recognized",
+ device=device.name,
+ device_class=device.device_type)
+ else:
+ self.logger.add_error("Investment device is none",
+ device=investment.device_idtag)
+ else:
+ self.logger.add_error("Only single-investment groups can be considered",
+ device=investment_group.name,
+ device_class=investment_group.device_type.value)
+
+ # convert the data to decision vars: the decision vars are
+ # integers from 0 to the number of templates of each device (the template position in self.data[device])
+ self.variables: Dict[str, Integer] = dict()
+ self.devices = list() # list of devices in sequential order to match the order of the vars
+ self.default_template = list() # list of templates that represent the devices in their initial state
+ for elm, template_list in self.device_template_dict.items():
+ self.variables[elm.idtag] = Integer(bounds=(0, len(template_list) + 1))
+ self.devices.append(elm)
+
+ if isinstance(elm, Line):
+ default_template = elm.get_line_type()
+
+ elif isinstance(elm, Transformer2W):
+ default_template = elm.get_transformer_type(Sbase=self.grid.Sbase)
+ else:
+ raise Exception('Device not recognized')
+
+ self.default_template.append(default_template)
+
+ super().__init__(n_obj=n_obj, vars=self.variables)
self.obj_func = obj_func
def _evaluate(self, x, out, *args, **kwargs):
@@ -63,23 +129,29 @@ def _evaluate(self, x, out, *args, **kwargs):
:param kwargs:
:return:
"""
- # Ideally, we want this to be automatically inputted:
- # react1_bi, react2_bi, react3_bi, react4_bi, react5_bi, vol, n_cables, S_rtr, react1, react2, react3, react4,
- # react5 = x["react1_bi"], x["react2_bi"], x["react3_bi"], x["react4_bi"], x["react5_bi"], x["vol_level"],
- # x["n_cables"], x["S_rtr"], x["react1"], x["react2"], x["react3"], x["react4"], x["react5"]
- # def build_grid_data
- # then
- # def run_pf or now run_opf
- # then
- # def compute_costs
- # then
- # obj_func = capex + opex
- # to be outputted as out["F"]
+
+ for i, xi in enumerate(x):
+ device = self.devices[i]
+ if i > 0:
+ template = self.data[device.idtag][xi]
+
+ if isinstance(device, Line):
+ device.apply_template(template, Sbase=self.grid.Sbase, logger=self.logger)
+
+ elif isinstance(device, Transformer2W):
+ device.apply_template(template, Sbase=self.grid.Sbase, logger=self.logger)
+
+ else:
+ raise Exception('Device not recognized')
+ else:
+ device.apply_template(self.default_template[i], Sbase=self.grid.Sbase, logger=self.logger)
out["F"] = self.obj_func(x)
+ print("Completed eval")
-def NSGA_2(obj_func,
+def NSGA_2(grid: MultiCircuit,
+ obj_func,
n_obj: int = 2,
max_evals: int = 30,
pop_size: int = 1,
@@ -98,7 +170,7 @@ def NSGA_2(obj_func,
# :param eta:
:return:
"""
- problem = MixedVariableProblem(obj_func, n_obj)
+ problem = MixedVariableProblem(grid, obj_func, n_obj)
algorithm = MixedVariableGA(pop_size=pop_size,
sampling=MixedVariableSampling(),
@@ -113,7 +185,7 @@ def NSGA_2(obj_func,
verbose=True,
save_history=False)
- # Shall we need this?
+ # Do they want opex or capex to have more weight?
# weights = np.array([0.5, 0.5])
# decomp = ASF()
# I = decomp(res.F, weights).argmin()
diff --git a/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_driver.py b/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_driver.py
index a43fa4590..6344f83e0 100644
--- a/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_driver.py
+++ b/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_driver.py
@@ -215,6 +215,7 @@ def __init__(self,
:param opf_time_series_results: Optimal power flow results
:param clustering_results: Clustering results
"""
+
TimeSeriesDriverTemplate.__init__(self,
grid=grid,
time_indices=time_indices,
@@ -624,6 +625,7 @@ def optimized_evaluation_mixed_nsga2(self) -> None:
# optimize
X, obj_values = NSGA_2(
+ grid=self.grid,
obj_func=self.objective_function,
n_obj=len(ret),
max_evals=self.options.max_eval, # termination
@@ -633,7 +635,16 @@ def optimized_evaluation_mixed_nsga2(self) -> None:
# eta=30,
)
- self.results.set_best_combination(combination=X[:, 0])
+ res_x = []
+ for i, v in enumerate(X):
+ if isinstance(v, dict):
+ vall = list(v.values())[0]
+ res_x.append(vall)
+ else:
+ res_x.append(v)
+
+ self.results.set_best_combination(combination=np.array(res_x))
+ # self.results.set_best_combination(combination=X[:, 0])
self.results.trim()
diff --git a/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_results.py b/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_results.py
index b52f7ee76..b06c67166 100644
--- a/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_results.py
+++ b/src/GridCalEngine/Simulations/InvestmentsEvaluation/investments_evaluation_results.py
@@ -164,7 +164,17 @@ def set_at(self, eval_idx,
self._voltage_score[eval_idx] = voltage_score
self._financial[eval_idx] = financial
self._f_obj[eval_idx] = objective_function_sum
- self._combinations[eval_idx, :] = combination
+
+ lst_comb = []
+ if isinstance(combination, np.ndarray):
+ lst_comb = combination.tolist()
+ elif isinstance(combination, dict):
+ lst_comb = list(combination.values())
+ else:
+ raise TypeError(f"Invalid type for combination: {type(combination)}")
+
+ self._combinations[eval_idx, :] = lst_comb
+ # self._combinations[eval_idx, :] = combination
self._index_names[eval_idx] = index_name
def scaling_factor(self, max_magnitude, target_magnitude) -> float:
diff --git a/src/GridCalEngine/Simulations/LinearFactors/linear_analysis.py b/src/GridCalEngine/Simulations/LinearFactors/linear_analysis.py
index 14cce1160..a38cbd4ab 100644
--- a/src/GridCalEngine/Simulations/LinearFactors/linear_analysis.py
+++ b/src/GridCalEngine/Simulations/LinearFactors/linear_analysis.py
@@ -26,8 +26,8 @@
from GridCalEngine.Devices.multi_circuit import MultiCircuit
from GridCalEngine.Devices.Aggregation.contingency_group import ContingencyGroup
from GridCalEngine.Devices.Aggregation.contingency import Contingency
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobian
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.derivatives import dSf_dV_csc
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobian
+from GridCalEngine.Simulations.Derivatives.csc_derivatives import dSf_dV_csc
from GridCalEngine.Utils.Sparse.csc import dense_to_csc
import GridCalEngine.Utils.Sparse.csc2 as csc
from GridCalEngine.Utils.MIP.selected_interface import lpDot
@@ -128,14 +128,14 @@ def make_acptdf(Ybus: sp.csc_matrix,
dS = np.r_[dP[pvpq, :], dQ]
# solve the voltage increments
- dx = csc.spsolve_csc(J, dS)
+ dx, ok = csc.spsolve_csc(J, dS)
# compute branch derivatives
dSf_dVm, dSf_dVa = dSf_dV_csc(Yf.tocsc(), V, F, T)
# compose the final AC-PTDF
- dPf_dVa = dSf_dVa.real[:, pvpq]
- dPf_dVm = dSf_dVm.real[:, pq]
+ dPf_dVa = csc.mat_to_scipy(dSf_dVa.real)[:, pvpq]
+ dPf_dVm = csc.mat_to_scipy(dSf_dVm.real)[:, pq]
PTDF = sp.hstack((dPf_dVa, dPf_dVm)) * dx
return PTDF
diff --git a/src/GridCalEngine/Simulations/NTC/ntc_opf.py b/src/GridCalEngine/Simulations/NTC/ntc_opf.py
index ea1a0e4f1..79d6511ba 100644
--- a/src/GridCalEngine/Simulations/NTC/ntc_opf.py
+++ b/src/GridCalEngine/Simulations/NTC/ntc_opf.py
@@ -31,7 +31,7 @@
from GridCalEngine.DataStructures.bus_data import BusData
from GridCalEngine.basic_structures import Logger, Vec, IntVec, BoolVec, StrVec, CxMat
from GridCalEngine.Utils.MIP.selected_interface import LpExp, LpVar, LpModel, lpDot, set_var_bounds, join
-from GridCalEngine.enumerations import TransformerControlType, HvdcControlType, AvailableTransferMode
+from GridCalEngine.enumerations import TapPhaseControl, HvdcControlType, AvailableTransferMode
from GridCalEngine.Simulations.LinearFactors.linear_analysis import LinearAnalysis, LinearMultiContingencies
from GridCalEngine.Simulations.ATC.available_transfer_capacity_driver import compute_alpha
@@ -692,7 +692,7 @@ def add_linear_branches_formulation(t_idx: int,
bk = 1.0 / branch_data_t.X[m]
# compute the flow
- if branch_data_t.control_mode[m] == TransformerControlType.Pf:
+ if branch_data_t.tap_phase_control_mode[m] == TapPhaseControl.Pf:
# add angle
branch_vars.tap_angles[t_idx, m] = prob.add_var(
diff --git a/src/GridCalEngine/Simulations/NTC/ntc_results.py b/src/GridCalEngine/Simulations/NTC/ntc_results.py
index 636464f92..18b116559 100644
--- a/src/GridCalEngine/Simulations/NTC/ntc_results.py
+++ b/src/GridCalEngine/Simulations/NTC/ntc_results.py
@@ -19,7 +19,7 @@
from GridCalEngine.Simulations.results_table import ResultsTable
from GridCalEngine.Simulations.results_template import ResultsTemplate
from GridCalEngine.basic_structures import DateVec, IntVec, Vec, StrVec, CxMat
-from GridCalEngine.enumerations import StudyResultsType, TransformerControlType, ResultTypes, DeviceType
+from GridCalEngine.enumerations import StudyResultsType, ResultTypes, DeviceType
def add_shifter_data(y, columns, controlled_shifters, phase_shift):
@@ -1015,13 +1015,6 @@ def create_all_reports(self, loading_threshold, reverse, save_memory=False):
if save_memory:
self.alpha_n1 = None
- def get_controlled_shifters_as_pt(self):
- shifter_idx = np.where(self.branch_control_modes == TransformerControlType.Pf)
- shifter_names = self.branch_names[shifter_idx]
-
- return shifter_idx, shifter_names
-
-
def make_report(self, path_out=None):
"""
diff --git a/src/GridCalEngine/Simulations/OPF/NumericalMethods/ac_opf.py b/src/GridCalEngine/Simulations/OPF/NumericalMethods/ac_opf.py
index 835176229..624528dfa 100644
--- a/src/GridCalEngine/Simulations/OPF/NumericalMethods/ac_opf.py
+++ b/src/GridCalEngine/Simulations/OPF/NumericalMethods/ac_opf.py
@@ -26,7 +26,7 @@
from GridCalEngine.Simulations.PowerFlow.power_flow_worker import multi_island_pf_nc
from GridCalEngine.Simulations.PowerFlow.power_flow_options import PowerFlowOptions
from GridCalEngine.Simulations.OPF.opf_options import OptimalPowerFlowOptions
-from GridCalEngine.enumerations import ReactivePowerControlMode, AcOpfMode
+from GridCalEngine.enumerations import AcOpfMode
from typing import Union
from GridCalEngine.basic_structures import Vec, CxVec, IntVec, Logger
from GridCalEngine.Simulations.OPF.NumericalMethods.ac_opf_derivatives import (x2var, var2x, eval_f,
@@ -272,14 +272,14 @@ def compute_analytic_structures(x, mu, lmbda, compute_jac: bool, compute_hess: b
fx, Gx, Hx, fxx, Gxx, Hxx, der_times = jacobians_and_hessians(x=x, c1=c1, c2=c2, c_s=c_s, c_v=c_v, Cg=Cg, Cf=Cf,
Ct=Ct, Yf=Yf,
- Yt=Yt, Ybus=Ybus, Sbase=Sbase, il=il, ig=ig,
+ Yt=Yt, Ybus=Ybus, Sbase=Sbase, mon_br_idx=il, ig=ig,
slack=slack,
nslcap=nslcap,
nodal_capacity_sign=nodal_capacity_sign,
capacity_nodes_idx=capacity_nodes_idx, pq=pq,
pv=pv, tanmax=tanmax, alltapm=alltapm,
- alltapt=alltapt, fdc=fdc,
- tdc=tdc, k_m=k_m, k_tau=k_tau, mu=mu, lmbda=lmbda,
+ alltapt=alltapt, F_hvdc=fdc,
+ T_hvdc=tdc, k_m=k_m, k_tau=k_tau, mu=mu, lmbda=lmbda,
R=R, X=X,
F=from_idx, T=to_idx, ctQ=ctQ, acopf_mode=acopf_mode,
compute_jac=compute_jac, compute_hess=compute_hess)
@@ -671,7 +671,7 @@ def ac_optimal_power_flow(nc: NumericalCircuit,
# Number of inequalities: Line ratings, max and min angle of buses, voltage module range and
- if pf_options.control_Q == ReactivePowerControlMode.NoControl:
+ if pf_options.control_Q == False:
NI = 2 * n_br_mon + 2 * npq + 4 * n_gen_disp + 2 * ntapm + 2 * ntapt + 2 * n_disp_hvdc + nsl # No Reactive constraint (power curve)
else:
NI = 2 * n_br_mon + 2 * npq + 5 * n_gen_disp + 2 * ntapm + 2 * ntapt + 2 * n_disp_hvdc + nsl
diff --git a/src/GridCalEngine/Simulations/OPF/NumericalMethods/ac_opf_derivatives.py b/src/GridCalEngine/Simulations/OPF/NumericalMethods/ac_opf_derivatives.py
index df3ce7ae1..05e3750e7 100644
--- a/src/GridCalEngine/Simulations/OPF/NumericalMethods/ac_opf_derivatives.py
+++ b/src/GridCalEngine/Simulations/OPF/NumericalMethods/ac_opf_derivatives.py
@@ -22,9 +22,9 @@
from scipy.sparse import lil_matrix
from GridCalEngine.Utils.Sparse.csc import diags
-from typing import Tuple, Union
+from typing import Tuple
from GridCalEngine.basic_structures import Vec, CxVec, IntVec, csr_matrix, csc_matrix
-from GridCalEngine.enumerations import ReactivePowerControlMode, AcOpfMode
+from GridCalEngine.enumerations import AcOpfMode
def x2var(x: Vec,
@@ -51,6 +51,8 @@ def x2var(x: Vec,
:param ntapm: number of module controlled transformers
:param ntapt: number of phase controlled transformers
:param ndc: number of dispatchable DC links
+ :param nslcap:
+ :param acopf_mode: AcOpfMode
:return: Tuple of sliced variables
"""
a = 0
@@ -137,6 +139,7 @@ def var2x(Va: Vec,
:param sl_st: Bound slacks for the 'to' power through a line
:param sl_vmax: Bound slacks for the maximum voltage of the buses
:param sl_vmin: Bound slacks for the minimum voltage of the buses
+ :param slcap:
:param tapm: Tap modules
:param tapt: Tap phases
:param Pfdc: From power of the dispatchable DC links
@@ -145,99 +148,104 @@ def var2x(Va: Vec,
return np.r_[Va, Vm, Pg, Qg, sl_sf, sl_st, sl_vmax, sl_vmin, slcap, tapm, tapt, Pfdc]
-def compute_branch_power_derivatives(alltapm: Vec,
- alltapt: Vec,
+def compute_branch_power_derivatives(all_tap_m: Vec,
+ all_tap_tau: Vec,
V: CxVec,
k_m: Vec,
k_tau: Vec,
Cf: csc,
Ct: csc,
+ F: IntVec,
+ T: IntVec,
R: Vec,
- X: Vec) -> Tuple[csr_matrix, lil_matrix, lil_matrix, csr_matrix, lil_matrix,
- lil_matrix]:
+ X: Vec) -> Tuple[
+ csr_matrix, lil_matrix, lil_matrix, csr_matrix, lil_matrix, lil_matrix]:
"""
- :param alltapm: Vector with all the tap module, including the non-controlled ones
- :param alltapt: Vector with all the tap phases, including the non-controlled ones
+ :param all_tap_m: Vector with all the tap module, including the non-controlled ones
+ :param all_tap_tau: Vector with all the tap phases, including the non-controlled ones
:param V: Complex voltages
:param k_m: List with the index of the module controlled transformers
:param k_tau: List with the index of the phase controlled transformers
:param Cf: From connectivity matrix
:param Ct: To connectivity matrix
+ :param F: Array of "from" buses of each branch
+ :param T: Array of "to" buses of each branch
:param R: Line resistances
:param X: Line inductances
- :return: Power first derivatives with respect to the tap variables [dSbusdm, dSfdm, dStdm, dSbusdt, dSfdt, dStdt]
+ :return: First power derivatives with respect to the tap variables
+ [dSbusdm, dSfdm, dStdm, dSbusdt, dSfdtau, dStdtau]
"""
ys = 1.0 / (R + 1.0j * X + 1e-20)
- Vf = Cf @ V
- Vt = Ct @ V
- N = len(alltapm)
- dSfdm = lil_matrix((N, len(k_m)), dtype=complex)
- dStdm = lil_matrix((N, len(k_m)), dtype=complex)
- dSfdt = lil_matrix((N, len(k_tau)), dtype=complex)
- dStdt = lil_matrix((N, len(k_tau)), dtype=complex)
-
- for mod, line in enumerate(k_m):
- Vf_ = Vf[line]
- Vt_ = Vt[line]
- mp = alltapm[line]
- tau = alltapt[line]
- yk = ys[line]
+ nbr = len(all_tap_m)
+ dSfdm = lil_matrix((nbr, len(k_m)), dtype=complex)
+ dStdm = lil_matrix((nbr, len(k_m)), dtype=complex)
+ dSfdtau = lil_matrix((nbr, len(k_tau)), dtype=complex)
+ dStdtau = lil_matrix((nbr, len(k_tau)), dtype=complex)
+
+ for k_pos, k in enumerate(k_m):
+ Vf = V[F[k]]
+ Vt = V[T[k]]
+ mp = all_tap_m[k]
+ tau = all_tap_tau[k]
+ yk = ys[k]
mp2 = np.power(mp, 2)
- # First derivatives with respect to the tap module. Each line is computed individually and stored
- dSfdm[line, mod] = Vf_ * ((-2 * np.conj(yk * Vf_) / np.power(mp, 3)) + np.conj(yk * Vt_) / (mp2 * np.exp(1j * tau)))
- dStdm[line, mod] = Vt_ * (np.conj(yk * Vf_) / (mp2 * np.exp(-1j * tau)))
-
- for ang, line in enumerate(k_tau):
- Vf_ = Vf[line]
- Vt_ = Vt[line]
- mp = alltapm[line]
- tau = alltapt[line]
- yk = ys[line]
- # First derivatives with respect to the tap phase. Each line is computed individually and stored
- dSfdt[line, ang] = Vf_ * 1j * np.conj(yk * Vt_) / (mp * np.exp(1j * tau))
- dStdt[line, ang] = Vt_ * -1j * np.conj(yk * Vf_) / (mp * np.exp(-1j * tau))
+
+ # First derivatives with respect to the tap module.
+ # Each branch is computed individually and stored
+ dSfdm[k, k_pos] = Vf * ((-2 * np.conj(yk * Vf) / np.power(mp, 3)) + np.conj(yk * Vt) / (mp2 * np.exp(1j * tau)))
+ dStdm[k, k_pos] = Vt * (np.conj(yk * Vf) / (mp2 * np.exp(-1j * tau)))
+
+ for k_pos, k in enumerate(k_tau):
+ Vf = V[F[k]]
+ Vt = V[T[k]]
+ mp = all_tap_m[k]
+ tau = all_tap_tau[k]
+ yk = ys[k]
+
+ # First derivatives with respect to the tap phase.
+ # Each branch is computed individually and stored
+ dSfdtau[k, k_pos] = Vf * 1j * np.conj(yk * Vt) / (mp * np.exp(1j * tau))
+ dStdtau[k, k_pos] = Vt * -1j * np.conj(yk * Vf) / (mp * np.exp(-1j * tau))
+
# Bus power injection is computed using the 'from' and 'to' powers and their connectivity matrices
dSbusdm = Cf.T @ dSfdm + Ct.T @ dStdm
- dSbusdt = Cf.T @ dSfdt + Ct.T @ dStdt
+ dSbusdt = Cf.T @ dSfdtau + Ct.T @ dStdtau
- return dSbusdm, dSfdm, dStdm, dSbusdt, dSfdt, dStdt
+ return dSbusdm, dSfdm, dStdm, dSbusdt, dSfdtau, dStdtau
-def compute_branch_power_second_derivatives(alltapm: Vec,
- alltapt: Vec,
+def compute_branch_power_second_derivatives(all_tap_m: Vec,
+ all_tap_tau: Vec,
vm: Vec,
va: Vec,
- k_m: Vec,
- k_tau: Vec,
- il: Vec,
- Cf: csc,
- Ct: csc,
+ k_m: IntVec,
+ k_tau: IntVec,
+ mon_idx: IntVec,
R: Vec,
X: Vec,
- F: Vec,
- T: Vec,
+ F: IntVec,
+ T: IntVec,
lam: Vec,
mu: Vec,
Sf: CxVec,
- St: CxVec) -> Tuple[lil_matrix, lil_matrix, lil_matrix,
- lil_matrix, lil_matrix, lil_matrix,
- lil_matrix, lil_matrix, lil_matrix,
- lil_matrix, lil_matrix, lil_matrix,
- lil_matrix, lil_matrix, lil_matrix,
- lil_matrix, lil_matrix, lil_matrix,
- lil_matrix, lil_matrix, lil_matrix]:
+ St: CxVec) -> Tuple[
+ lil_matrix, lil_matrix, lil_matrix,
+ lil_matrix, lil_matrix, lil_matrix,
+ lil_matrix, lil_matrix, lil_matrix,
+ lil_matrix, lil_matrix, lil_matrix,
+ lil_matrix, lil_matrix, lil_matrix,
+ lil_matrix, lil_matrix, lil_matrix,
+ lil_matrix, lil_matrix, lil_matrix]:
"""
- :param alltapm: Vector with all the tap module, including the non-controlled ones
- :param alltapt: Vector with all the tap phase, including the non-controlled ones
+ :param all_tap_m: Vector with all the tap module, including the non-controlled ones
+ :param all_tap_tau: Vector with all the tap phase, including the non-controlled ones
:param vm: Voltage modules
:param va: Voltage angles
:param k_m: List with the index of the module controlled transformers
:param k_tau: List with the index of the phase controlled transformers
- :param il: List with the index of the monitored lines
- :param Cf: From connectivity matrix
- :param Ct: To connectivity matrix
+ :param mon_idx: List with the index of the monitored lines
:param R: Line resistances
:param X: Line inductances
:param F: Indexes of the 'from' buses
@@ -250,10 +258,9 @@ def compute_branch_power_second_derivatives(alltapm: Vec,
"""
ys = 1.0 / (R + 1.0j * X + 1e-20)
V = vm * np.exp(1j * va)
- Vf = Cf @ V
- Vt = Ct @ V
+
N = len(vm)
- M = len(il)
+ M = len(mon_idx)
ntapm = len(k_m)
ntapt = len(k_tau)
@@ -285,129 +292,136 @@ def compute_branch_power_second_derivatives(alltapm: Vec,
dSfdmdt = lil_matrix((ntapt, ntapm), dtype=complex)
dStdmdt = lil_matrix((ntapt, ntapm), dtype=complex)
- for mod, line in enumerate(k_m):
- Vf_ = Vf[line]
- Vt_ = Vt[line]
- mp = alltapm[line]
- tau = alltapt[line]
- yk = ys[line]
+ for k_pos, k in enumerate(k_m):
+ f = F[k]
+ t = T[k]
+ Vf = V[f]
+ Vt = V[t]
+ mp = all_tap_m[k]
+ tau = all_tap_tau[k]
+ yk = ys[k]
+ tap_unit = np.exp(1j * tau)
+ tap_unit_c = np.exp(-1j * tau)
- f = F[line]
- t = T[line]
# For each line with a module controlled transformer, compute its second derivatives w.r.t. the tap module and
# the rest of the variables.
mp2 = mp * mp
mp3 = mp2 * mp
mp4 = mp3 * mp
- dSfdmdm_ = Vf_ * ((6 * np.conj(yk * Vf_) / mp4) - 2 * np.conj(yk * Vt_) / (mp3 * np.exp(1j * tau)))
- dStdmdm_ = - Vt_ * 2 * np.conj(yk * Vf_) / (mp3 * np.exp(-1j * tau))
+ dSfdmdm_ = Vf * ((6 * np.conj(yk * Vf) / mp4) - 2 * np.conj(yk * Vt) / (mp3 * tap_unit))
+ dStdmdm_ = - Vt * 2 * np.conj(yk * Vf) / (mp3 * tap_unit_c)
+
+ dSfdmdva_f = Vf * 1j * np.conj(yk * Vt) / (mp2 * tap_unit)
+ dSfdmdva_t = - Vf * 1j * np.conj(yk * Vt) / (mp2 * tap_unit)
- dSfdmdva_f = Vf_ * 1j * np.conj(yk * Vt_) / (mp2 * np.exp(1j * tau))
- dSfdmdva_t = - Vf_ * 1j * np.conj(yk * Vt_) / (mp2 * np.exp(1j * tau))
+ dStdmdva_f = - Vt * 1j * np.conj(yk * Vf) / (mp2 * tap_unit_c)
+ dStdmdva_t = Vt * 1j * np.conj(yk * Vf) / (mp2 * tap_unit_c)
- dStdmdva_f = - Vt_ * 1j * np.conj(yk * Vf_) / (mp2 * np.exp(-1j * tau))
- dStdmdva_t = Vt_ * 1j * np.conj(yk * Vf_) / (mp2 * np.exp(-1j * tau))
+ dSfdmdvm_f = Vf * (1 / vm[f]) * ((-4 * np.conj(yk * Vf) / mp3) + np.conj(yk * Vt) / (mp2 * tap_unit))
+ dSfdmdvm_t = Vf * (1 / vm[t]) * np.conj(yk * Vt) / (mp2 * tap_unit)
- dSfdmdvm_f = Vf_ * (1 / vm[f]) * ((-4 * np.conj(yk * Vf_) / mp3)
- + np.conj(yk * Vt_) / (mp2 * np.exp(1j * tau)))
- dSfdmdvm_t = Vf_ * (1 / vm[t]) * np.conj(yk * Vt_) / (mp2 * np.exp(1j * tau))
+ dStdmdvm_f = Vt * (1 / vm[f]) * np.conj(yk * Vf) / (mp2 * tap_unit_c)
+ dStdmdvm_t = Vt * (1 / vm[t]) * np.conj(yk * Vf) / (mp2 * tap_unit_c)
- dStdmdvm_f = Vt_ * (1 / vm[f]) * np.conj(yk * Vf_) / (mp2 * np.exp(-1j * tau))
- dStdmdvm_t = Vt_ * (1 / vm[t]) * np.conj(yk * Vf_) / (mp2 * np.exp(-1j * tau))
+ lin = np.where(k_tau == k)[0] # TODO: should pass along the control type and check that instead
- lin = np.where(k_tau == line)[0]
if len(lin) != 0:
- ang = lin[0]
+ k_pos = lin[0]
# If the trafo is controlled for both module and phase, compute these derivatives. Otherwise, they are 0
- dSfdmdt_ = - Vf_ * 1j * (np.conj(yk * Vt_) / (mp2 * np.exp(1j * tau)))
- dStdmdt_ = Vt_ * 1j * (np.conj(yk * Vf_) / (mp2 * np.exp(-1j * tau)))
+ dSfdmdt_ = - Vf * 1j * (np.conj(yk * Vt) / (mp2 * tap_unit))
+ dStdmdt_ = Vt * 1j * (np.conj(yk * Vf) / (mp2 * tap_unit_c))
- dSbusdmdt[ang, mod] = ((dSfdmdt_ * lam[f]).real + (dSfdmdt_ * lam[f + N]).imag
- + (dStdmdt_ * lam[t]).real + (dStdmdt_ * lam[t + N]).imag)
- if line in il:
+ dSbusdmdt[k_pos, k_pos] = ((dSfdmdt_ * lam[f]).real + (dSfdmdt_ * lam[f + N]).imag
+ + (dStdmdt_ * lam[t]).real + (dStdmdt_ * lam[t + N]).imag)
+ if k in mon_idx:
# This is only included if the branch is monitored.
- li = np.where(il == line)[0]
- dSfdmdt[ang, mod] = dSfdmdt_ * Sf[li].conj() * mu[li]
- dStdmdt[ang, mod] = dStdmdt_ * St[li].conj() * mu[li + M]
+ li = np.where(mon_idx == k)[0] # TODO: Why is this here?
+ dSfdmdt[k_pos, k_pos] = dSfdmdt_ * Sf[li].conj() * mu[li]
+ dStdmdt[k_pos, k_pos] = dStdmdt_ * St[li].conj() * mu[li + M]
+
# Compute the hessian terms merging Sf and St into Sbus
- dSbusdmdm[mod, mod] = ((dSfdmdm_ * lam[f]).real + (dSfdmdm_ * lam[f + N]).imag
- + (dStdmdm_ * lam[t]).real + (dStdmdm_ * lam[t + N]).imag)
- dSbusdmdva[f, mod] = ((dSfdmdva_f * lam[f]).real + (dSfdmdva_f * lam[f + N]).imag
- + (dStdmdva_f * lam[t]).real + (dStdmdva_f * lam[t + N]).imag)
- dSbusdmdva[t, mod] = ((dSfdmdva_t * lam[f]).real + (dSfdmdva_t * lam[f + N]).imag
- + (dStdmdva_t * lam[t]).real + (dStdmdva_t * lam[t + N]).imag)
- dSbusdmdvm[f, mod] = ((dSfdmdvm_f * lam[f]).real + (dSfdmdvm_f * lam[f + N]).imag
- + (dStdmdvm_f * lam[t]).real + (dStdmdvm_f * lam[t + N]).imag)
- dSbusdmdvm[t, mod] = ((dSfdmdvm_t * lam[f]).real + (dSfdmdvm_t * lam[f + N]).imag
- + (dStdmdvm_t * lam[t]).real + (dStdmdvm_t * lam[t + N]).imag)
-
- if line in il:
+ dSbusdmdm[k_pos, k_pos] = ((dSfdmdm_ * lam[f]).real + (dSfdmdm_ * lam[f + N]).imag
+ + (dStdmdm_ * lam[t]).real + (dStdmdm_ * lam[t + N]).imag)
+ dSbusdmdva[f, k_pos] = ((dSfdmdva_f * lam[f]).real + (dSfdmdva_f * lam[f + N]).imag
+ + (dStdmdva_f * lam[t]).real + (dStdmdva_f * lam[t + N]).imag)
+ dSbusdmdva[t, k_pos] = ((dSfdmdva_t * lam[f]).real + (dSfdmdva_t * lam[f + N]).imag
+ + (dStdmdva_t * lam[t]).real + (dStdmdva_t * lam[t + N]).imag)
+ dSbusdmdvm[f, k_pos] = ((dSfdmdvm_f * lam[f]).real + (dSfdmdvm_f * lam[f + N]).imag
+ + (dStdmdvm_f * lam[t]).real + (dStdmdvm_f * lam[t + N]).imag)
+ dSbusdmdvm[t, k_pos] = ((dSfdmdvm_t * lam[f]).real + (dSfdmdvm_t * lam[f + N]).imag
+ + (dStdmdvm_t * lam[t]).real + (dStdmdvm_t * lam[t + N]).imag)
+
+ if k in mon_idx:
# Hessian terms, only for monitored lines
- li = np.where(il == line)[0]
- dSfdmdm[mod, mod] = dSfdmdm_ * Sf[li].conj() * mu[li]
- dStdmdm[mod, mod] = dStdmdm_ * St[li].conj() * mu[li + M]
- dSfdmdva[f, mod] = dSfdmdva_f * Sf[li].conj() * mu[li]
- dStdmdva[f, mod] = dStdmdva_f * St[li].conj() * mu[li + M]
- dSfdmdva[t, mod] = dSfdmdva_t * Sf[li].conj() * mu[li]
- dStdmdva[t, mod] = dStdmdva_t * St[li].conj() * mu[li + M]
- dSfdmdvm[f, mod] = dSfdmdvm_f * Sf[li].conj() * mu[li]
- dStdmdvm[f, mod] = dStdmdvm_f * St[li].conj() * mu[li + M]
- dSfdmdvm[t, mod] = dSfdmdvm_t * Sf[li].conj() * mu[li]
- dStdmdvm[t, mod] = dStdmdvm_t * St[li].conj() * mu[li + M]
-
- for ang, line in enumerate(k_tau):
- Vf_ = Vf[line]
- Vt_ = Vt[line]
- mp = alltapm[line]
- tau = alltapt[line]
- yk = ys[line]
-
- f = F[line]
- t = T[line]
+ li = np.where(mon_idx == k)[0] # TODO: Why is this here?
+ dSfdmdm[k_pos, k_pos] = dSfdmdm_ * Sf[li].conj() * mu[li]
+ dStdmdm[k_pos, k_pos] = dStdmdm_ * St[li].conj() * mu[li + M]
+ dSfdmdva[f, k_pos] = dSfdmdva_f * Sf[li].conj() * mu[li]
+ dStdmdva[f, k_pos] = dStdmdva_f * St[li].conj() * mu[li + M]
+ dSfdmdva[t, k_pos] = dSfdmdva_t * Sf[li].conj() * mu[li]
+ dStdmdva[t, k_pos] = dStdmdva_t * St[li].conj() * mu[li + M]
+ dSfdmdvm[f, k_pos] = dSfdmdvm_f * Sf[li].conj() * mu[li]
+ dStdmdvm[f, k_pos] = dStdmdvm_f * St[li].conj() * mu[li + M]
+ dSfdmdvm[t, k_pos] = dSfdmdvm_t * Sf[li].conj() * mu[li]
+ dStdmdvm[t, k_pos] = dStdmdvm_t * St[li].conj() * mu[li + M]
+
+ for k_pos, k in enumerate(k_tau):
+ f = F[k]
+ t = T[k]
+ Vf = V[f]
+ Vt = V[t]
+ Vmf = abs(Vf)
+ Vmt = abs(Vt)
+ mp = all_tap_m[k]
+ tau = all_tap_tau[k]
+ yk = ys[k]
+ tap = mp * np.exp(1j * tau)
+ tap_c = mp * np.exp(-1j * tau)
+
# Same procedure for phase controlled transformers
- dSfdtdt_ = Vf_ * np.conj(yk * Vt_) / (mp * np.exp(1j * tau))
- dStdtdt_ = Vt_ * np.conj(yk * Vf_) / (mp * np.exp(-1j * tau))
+ dSfdtdt_ = Vf * np.conj(yk * Vt) / tap
+ dStdtdt_ = Vt * np.conj(yk * Vf) / tap_c
- dSfdtdva_f = - Vf_ * np.conj(yk * Vt_) / (mp * np.exp(1j * tau))
- dSfdtdva_t = Vf_ * np.conj(yk * Vt_) / (mp * np.exp(1j * tau))
+ dSfdtdva_f = - Vf * np.conj(yk * Vt) / tap
+ dSfdtdva_t = Vf * np.conj(yk * Vt) / tap
- dStdtdva_f = - Vt_ * np.conj(yk * Vf_) / (mp * np.exp(-1j * tau))
- dStdtdva_t = Vt_ * np.conj(yk * Vf_) / (mp * np.exp(-1j * tau))
+ dStdtdva_f = - Vt * np.conj(yk * Vf) / tap_c
+ dStdtdva_t = Vt * np.conj(yk * Vf) / tap_c
- dSfdtdvm_f = 1j * Vf_ / abs(Vf_) * np.conj(yk * Vt_) / (mp * np.exp(1j * tau))
- dSfdtdvm_t = 1j * Vf_ / abs(Vt_) * np.conj(yk * Vt_) / (mp * np.exp(1j * tau))
+ dSfdtdvm_f = 1.0j * Vf / Vmf * np.conj(yk * Vt) / tap
+ dSfdtdvm_t = 1.0j * Vf / Vmt * np.conj(yk * Vt) / tap
- dStdtdvm_f = -1j * Vt_ / abs(Vf_) * np.conj(yk * Vf_) / (mp * np.exp(-1j * tau))
- dStdtdvm_t = -1j * Vt_ / abs(Vt_) * np.conj(yk * Vf_) / (mp * np.exp(-1j * tau))
+ dStdtdvm_f = -1.0j * Vt / Vmf * np.conj(yk * Vf) / tap_c
+ dStdtdvm_t = -1.0j * Vt / Vmt * np.conj(yk * Vf) / tap_c
# Merge Sf and St in Sbus
- dSbusdtdt[ang, ang] = ((dSfdtdt_ * lam[f]).real + (dSfdtdt_ * lam[f + N]).imag
- + (dStdtdt_ * lam[t]).real + (dStdtdt_ * lam[t + N]).imag)
- dSbusdtdva[f, ang] = ((dSfdtdva_f * lam[f]).real + (dSfdtdva_f * lam[f + N]).imag
- + (dStdtdva_f * lam[t]).real + (dStdtdva_f * lam[t + N]).imag)
- dSbusdtdva[t, ang] = ((dSfdtdva_t * lam[f]).real + (dSfdtdva_t * lam[f + N]).imag
- + (dStdtdva_t * lam[t]).real + (dStdtdva_t * lam[t + N]).imag)
- dSbusdtdvm[f, ang] = ((dSfdtdvm_f * lam[f]).real + (dSfdtdvm_f * lam[f + N]).imag
- + (dStdtdvm_f * lam[t]).real + (dStdtdvm_f * lam[t + N]).imag)
- dSbusdtdvm[t, ang] = ((dSfdtdvm_t * lam[f]).real + (dSfdtdvm_t * lam[f + N]).imag
- + (dStdtdvm_t * lam[t]).real + (dStdtdvm_t * lam[t + N]).imag)
- dSbusdtdt[ang, ang] = ((dSfdtdt_ * lam[f]).real + (dSfdtdt_ * lam[f + N]).imag
- + (dStdtdt_ * lam[t]).real + (dStdtdt_ * lam[t + N]).imag)
-
- if line in il:
- li = np.where(il == line)[0]
- dSfdtdt[ang, ang] = dSfdtdt_ * Sf[li].conj() * mu[li]
- dStdtdt[ang, ang] = dStdtdt_ * St[li].conj() * mu[li + M]
- dSfdtdva[f, ang] = dSfdtdva_f * Sf[li].conj() * mu[li]
- dStdtdva[f, ang] = dStdtdva_f * St[li].conj() * mu[li + M]
- dSfdtdva[t, ang] = dSfdtdva_t * Sf[li].conj() * mu[li]
- dStdtdva[t, ang] = dStdtdva_t * St[li].conj() * mu[li + M]
- dSfdtdvm[f, ang] = dSfdtdvm_f * Sf[li].conj() * mu[li]
- dStdtdvm[f, ang] = dStdtdvm_f * St[li].conj() * mu[li + M]
- dSfdtdvm[t, ang] = dSfdtdvm_t * Sf[li].conj() * mu[li]
- dStdtdvm[t, ang] = dStdtdvm_t * St[li].conj() * mu[li + M]
- dSfdtdt[ang, ang] = dSfdtdt_ * Sf[li].conj() * mu[li]
- dStdtdt[ang, ang] = dStdtdt_ * St[li].conj() * mu[li + M]
+ dSbusdtdt[k_pos, k_pos] = ((dSfdtdt_ * lam[f]).real + (dSfdtdt_ * lam[f + N]).imag
+ + (dStdtdt_ * lam[t]).real + (dStdtdt_ * lam[t + N]).imag)
+ dSbusdtdva[f, k_pos] = ((dSfdtdva_f * lam[f]).real + (dSfdtdva_f * lam[f + N]).imag
+ + (dStdtdva_f * lam[t]).real + (dStdtdva_f * lam[t + N]).imag)
+ dSbusdtdva[t, k_pos] = ((dSfdtdva_t * lam[f]).real + (dSfdtdva_t * lam[f + N]).imag
+ + (dStdtdva_t * lam[t]).real + (dStdtdva_t * lam[t + N]).imag)
+ dSbusdtdvm[f, k_pos] = ((dSfdtdvm_f * lam[f]).real + (dSfdtdvm_f * lam[f + N]).imag
+ + (dStdtdvm_f * lam[t]).real + (dStdtdvm_f * lam[t + N]).imag)
+ dSbusdtdvm[t, k_pos] = ((dSfdtdvm_t * lam[f]).real + (dSfdtdvm_t * lam[f + N]).imag
+ + (dStdtdvm_t * lam[t]).real + (dStdtdvm_t * lam[t + N]).imag)
+ dSbusdtdt[k_pos, k_pos] = ((dSfdtdt_ * lam[f]).real + (dSfdtdt_ * lam[f + N]).imag
+ + (dStdtdt_ * lam[t]).real + (dStdtdt_ * lam[t + N]).imag)
+
+ if k in mon_idx:
+ li = np.where(mon_idx == k)[0] # TODO: Why is this here?
+ dSfdtdt[k_pos, k_pos] = dSfdtdt_ * Sf[li].conj() * mu[li]
+ dStdtdt[k_pos, k_pos] = dStdtdt_ * St[li].conj() * mu[li + M]
+ dSfdtdva[f, k_pos] = dSfdtdva_f * Sf[li].conj() * mu[li]
+ dStdtdva[f, k_pos] = dStdtdva_f * St[li].conj() * mu[li + M]
+ dSfdtdva[t, k_pos] = dSfdtdva_t * Sf[li].conj() * mu[li]
+ dStdtdva[t, k_pos] = dStdtdva_t * St[li].conj() * mu[li + M]
+ dSfdtdvm[f, k_pos] = dSfdtdvm_f * Sf[li].conj() * mu[li]
+ dStdtdvm[f, k_pos] = dStdtdvm_f * St[li].conj() * mu[li + M]
+ dSfdtdvm[t, k_pos] = dSfdtdvm_t * Sf[li].conj() * mu[li]
+ dStdtdvm[t, k_pos] = dStdtdvm_t * St[li].conj() * mu[li + M]
+ dSfdtdt[k_pos, k_pos] = dSfdtdt_ * Sf[li].conj() * mu[li]
+ dStdtdt[k_pos, k_pos] = dStdtdt_ * St[li].conj() * mu[li + M]
return (dSbusdmdm, dSfdmdm, dStdmdm,
dSbusdmdvm, dSfdmdvm, dStdmdvm,
@@ -424,7 +438,7 @@ def eval_f(x: Vec, Cg: csc_matrix, k_m: Vec, k_tau: Vec, nll: int, c0: Vec, c1:
"""
Calculates the value of the objective function at the current state (given by x)
:param x: State vector
-
+ # //////////////////////////////////////////////////////
:param Cg: Generation connectivity matrix
:param k_m: List with the index of the module controlled transformers
:param k_tau: List with the index of the phase controlled transformers
@@ -433,11 +447,14 @@ def eval_f(x: Vec, Cg: csc_matrix, k_m: Vec, k_tau: Vec, nll: int, c0: Vec, c1:
:param c1: Linear cost of generators
:param c2: Quadratic cost of generators
:param c_s: Cost of overloading a line
+ :param nslcap:
+ :param nodal_capacity_sign:
:param c_v: Cost of over or undervoltages
:param ig: Dispatchable generators
:param npq: Number of pq buses
:param ndc: Number of dispatchable DC links
:param Sbase: Base power (per unit reference)
+ :param acopf_mode: AcOpfMode
:return: Scalar value: Cost of operation (objective function)
"""
N, _ = Cg.shape # Check
@@ -446,8 +463,8 @@ def eval_f(x: Vec, Cg: csc_matrix, k_m: Vec, k_tau: Vec, nll: int, c0: Vec, c1:
ntapt = len(k_tau)
_, _, Pg, Qg, sl_sf, sl_st, sl_vmax, sl_vmin, slcap, _, _, _ = x2var(x, nVa=N, nVm=N, nPg=Ng, nQg=Ng, npq=npq,
- M=nll, ntapm=ntapm, ntapt=ntapt, ndc=ndc,
- nslcap=nslcap, acopf_mode=acopf_mode)
+ M=nll, ntapm=ntapm, ntapt=ntapt, ndc=ndc,
+ nslcap=nslcap, acopf_mode=acopf_mode)
# Obj. function: Active power generation costs plus overloads and voltage deviation penalties
fval = 1e-4 * (np.sum((c0 + c1 * Pg * Sbase + c2 * np.power(Pg * Sbase, 2)))
@@ -471,20 +488,24 @@ def eval_g(x: Vec, Ybus: csc_matrix, Yf: csc_matrix, Cg: csc_matrix, Sd: CxVec,
:param ig: indices of dispatchable gens
:param nig: indices of non dispatchable gens
:param nll: Number of monitored lines
+ :param nslcap:
+ :param nodal_capacity_sign:
+ :param capacity_nodes_idx:
:param npq: Number of pq buses
:param pv: Index of PV buses
:param f_nd_dc: Index of 'from' buses of non dispatchable DC links
:param t_nd_dc: Index of 'to' buses of non dispatchable DC links
:param fdc: Index of 'from' buses of dispatchable DC links
:param tdc: Index of 'to' buses of dispatchable DC links
+ :param Pf_nondisp:
:param k_m: Index of module controlled transformers
:param k_tau: Index of phase controlled transformers
:param Vm_max: Maximum bound for voltage
:param Sg_undis: undispatchable complex power
:param slack: Index of slack buses
- :param use_bound_slacks: Determine if there will be bound slacks in the optimization model
- :return: Vector with the value of each equality constraint G = [g1(x), ... gn(x)] s.t. gi(x) = 0. It also
- returns the value of the power injections S
+ :param acopf_mode:
+ :return: Vector with the value of each equality constraint G = [g1(x), ... gn(x)] s.t. gi(x) = 0.
+ It also returns the value of the power injections S
"""
M, N = Yf.shape
Ng = len(ig)
@@ -494,7 +515,8 @@ def eval_g(x: Vec, Ybus: csc_matrix, Yf: csc_matrix, Cg: csc_matrix, Sd: CxVec,
va, vm, Pg_dis, Qg_dis, sl_sf, sl_st, sl_vmax, sl_vmin, slcap, _, _, Pfdc = x2var(x, nVa=N, nVm=N, nPg=Ng, nQg=Ng,
npq=npq, M=nll, ntapm=ntapm,
- ntapt=ntapt, ndc=ndc, nslcap=nslcap,
+ ntapt=ntapt, ndc=ndc,
+ nslcap=nslcap,
acopf_mode=acopf_mode)
V = vm * np.exp(1j * va)
@@ -503,7 +525,7 @@ def eval_g(x: Vec, Ybus: csc_matrix, Yf: csc_matrix, Cg: csc_matrix, Sd: CxVec,
S_undispatch = Cg[:, nig] @ Sg_undis # Fixed generation
dS = S + Sd - S_dispatch - S_undispatch # Nodal power balance
if nslcap != 0:
- dS[capacity_nodes_idx] -= slcap # Nodal capacity slack generator addition
+ dS[capacity_nodes_idx] -= slcap # Nodal capacity slack generator addition
for link in range(len(Pfdc)):
dS[fdc[link]] += Pfdc[link] # Variable DC links. Lossless model (Pdc_From = Pdc_To)
@@ -517,10 +539,11 @@ def eval_g(x: Vec, Ybus: csc_matrix, Yf: csc_matrix, Cg: csc_matrix, Sd: CxVec,
return gval, S
-def eval_h(x: Vec, Yf: csc_matrix, Yt: csc_matrix, from_idx: Vec, to_idx: Vec, nslcap:int, pq: Vec, k_m: Vec, k_tau: Vec,
+def eval_h(x: Vec, Yf: csc_matrix, Yt: csc_matrix, from_idx: Vec, to_idx: Vec, nslcap: int,
+ pq: Vec, k_m: Vec, k_tau: Vec,
Vm_max: Vec, Vm_min: Vec, Pg_max: Vec, Pg_min: Vec, Qg_max: Vec, Qg_min: Vec, tapm_max: Vec,
tapm_min: Vec, tapt_max: Vec, tapt_min: Vec, Pdcmax: Vec, rates: Vec, il: Vec, ig: Vec,
- tanmax: Vec, ctQ: ReactivePowerControlMode, acopf_mode: AcOpfMode) -> Tuple[Vec, CxVec, CxVec]:
+ tanmax: Vec, ctQ: bool, acopf_mode: AcOpfMode) -> Tuple[Vec, CxVec, CxVec]:
"""
Calculates the inequality constraints at the current state (given by x)
:param x: State vector
@@ -528,15 +551,16 @@ def eval_h(x: Vec, Yf: csc_matrix, Yt: csc_matrix, from_idx: Vec, to_idx: Vec, n
:param Yt: To admittance matrix
:param from_idx: Vector with the indices of the 'from' buses for each line
:param to_idx: Vector with the indices of the 'from' buses for each line
+ :param nslcap:
:param pq: Index of PQ buses
:param k_m: Index of module controlled transformers
:param k_tau: Index of phase controlles transformers
:param Vm_max: upper bound for voltage module per bus
- :param vm_min: lower bound for voltage module per bus
- :param pg_max: upper bound for active power generation per generator
- :param pg_min: lower bound for active power generation per generator
- :param qg_max: upper bound for reactive power generation per generator
- :param qg_min: lower bound for reactive power generation per generator
+ :param Vm_min: lower bound for voltage module per bus
+ :param Pg_max: upper bound for active power generation per generator
+ :param Pg_min: lower bound for active power generation per generator
+ :param Qg_max: upper bound for reactive power generation per generator
+ :param Qg_min: lower bound for reactive power generation per generator
:param tapm_max: Upper bound for tap module per transformer
:param tapm_min: Lower bound for tap module per transformer
:param tapt_max: Upper bound for tap phase per transformer
@@ -547,8 +571,10 @@ def eval_h(x: Vec, Yf: csc_matrix, Yt: csc_matrix, from_idx: Vec, to_idx: Vec, n
:param ig: Index of dispatchable generators
:param tanmax: Maximum value of tan(phi), where phi is the angle of the complex generation, for each generator
:param ctQ: Boolean indicating if limits to reactive power generation realted to active generation apply
- :return: Vector with the value of each inequality constraint H = [h1(x), ... hn(x)] s.t. hi(x) <= 0 and the
- calculated from and to branch powers.
+ :param acopf_mode: AcOpfMode
+ :return: Vector with the value of each inequality constraint
+ H = [h1(x), ... hn(x)] s.t. hi(x) <= 0
+ and the calculated from and to branch powers.
"""
M, N = Yf.shape
@@ -610,7 +636,7 @@ def eval_h(x: Vec, Yf: csc_matrix, Yt: csc_matrix, from_idx: Vec, to_idx: Vec, n
tapt_min - tapt # Tap phase lower bound
]
- if ctQ != ReactivePowerControlMode.NoControl:
+ if ctQ: # if reactive power control...
hval = np.r_[hval, np.power(Qg, 2.0) - np.power(tanmax, 2.0) * np.power(Pg, 2.0)]
if ndc != 0:
@@ -620,13 +646,12 @@ def eval_h(x: Vec, Yf: csc_matrix, Yt: csc_matrix, from_idx: Vec, to_idx: Vec, n
def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc_matrix, Cf: csc, Ct: csc,
- Yf: csc_matrix, Yt: csc_matrix, Ybus: csc_matrix, Sbase: float, il: Vec, ig: Vec,
- slack: Vec, nslcap: int, nodal_capacity_sign: float, capacity_nodes_idx: IntVec, pq: Vec,
- pv: Vec, tanmax: Vec, alltapm: Vec, alltapt: Vec, fdc: Vec, tdc: Vec,
- k_m: Vec, k_tau: Vec, mu, lmbda, R: Vec, X: Vec, F: Vec, T: Vec,
- ctQ: ReactivePowerControlMode, acopf_mode: AcOpfMode, compute_jac: bool,
+ Yf: csc_matrix, Yt: csc_matrix, Ybus: csc_matrix, Sbase: float, mon_br_idx: IntVec, ig: IntVec,
+ slack: Vec, nslcap: int, nodal_capacity_sign: float, capacity_nodes_idx: IntVec, pq: IntVec,
+ pv: IntVec, tanmax: Vec, alltapm: Vec, alltapt: Vec, F_hvdc: IntVec, T_hvdc: IntVec,
+ k_m: IntVec, k_tau: IntVec, mu, lmbda, R: Vec, X: Vec, F: IntVec, T: IntVec,
+ ctQ: bool, acopf_mode: AcOpfMode, compute_jac: bool,
compute_hess: bool) -> Tuple[Vec, csc, csc, csc, csc, csc, Vec]:
-
"""
Calculates the jacobians and hessians of the objective function and the equality and inequality constraints
at the current state given by x
@@ -642,16 +667,19 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
:param Yt: To admittance matrix
:param Ybus: Bus admittance matrix
:param Sbase: Base power
- :param il: Index of monitored lines
- :param ig: Index of dispatchable generatora
+ :param mon_br_idx: Index of monitored branches
+ :param ig: Index of dispatchable generators
:param slack: Index of slack buses
+ :param nslcap:
+ :param nodal_capacity_sign:
+ :param capacity_nodes_idx:
:param pq: Index of PQ buses
:param pv: Index of PV buses
:param tanmax: Maximum value of tan(phi), where phi is the angle of the complex generation, for each generator
:param alltapm: value of all the tap modules, including the non controlled ones
:param alltapt: value of all the tap phases, including the non controlled ones
- :param fdc: Index of the 'from' buses for the dispatchable DC links
- :param tdc: Index of the 'to' buses for the dispatchable DC links
+ :param F_hvdc: Index of the 'from' buses for the dispatchable DC links
+ :param T_hvdc: Index of the 'to' buses for the dispatchable DC links
:param k_m: Index of the module controlled transformers
:param k_tau: Index of the phase controlled transformers
:param mu: Vector of mu multipliers
@@ -661,20 +689,21 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
:param F: Index of the 'form' bus for each line
:param T: Index of the 'to' bus for each line
:param ctQ: Boolean that indicates if the Reactive control applies
+ :param acopf_mode: AcOpfMode
:param compute_jac: Boolean that indicates if the Jacobians have to be calculated
:param compute_hess: Boolean that indicates if the Hessians have to be calculated
:return: Jacobians and hessians matrices for the objective function and the equality and inequality constraints
"""
Mm, N = Yf.shape
- M = len(il)
+ M = len(mon_br_idx)
Ng = len(ig)
NV = len(x)
ntapm = len(k_m)
ntapt = len(k_tau)
- ndc = len(fdc)
+ ndc = len(F_hvdc)
npq = len(pq)
- if ctQ != ReactivePowerControlMode.NoControl:
+ if ctQ: # if reactive power control...
nqct = Ng
else:
nqct = 0
@@ -775,7 +804,7 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
Gvm[i, N + ss] = 1.
(dSbusdm, dSfdm, dStdm,
- dSbusdt, dSfdt, dStdt) = compute_branch_power_derivatives(alltapm, alltapt, V, k_m, k_tau, Cf, Ct, R, X)
+ dSbusdt, dSfdt, dStdt) = compute_branch_power_derivatives(alltapm, alltapt, V, k_m, k_tau, Cf, Ct, F, T, R, X)
if ntapm > 0:
Gtapm = dSbusdm.copy()
@@ -788,15 +817,15 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
Gtapt = lil_matrix((N, ntapt), dtype=complex)
GSpfdc = lil_matrix((N, ndc), dtype=complex)
- for link in range(ndc):
- GSpfdc[fdc, link] = 1
- GSpfdc[tdc, link] = -1
+ for k_link in range(ndc):
+ GSpfdc[F_hvdc[k_link], k_link] = 1.0 # TODO: check that this is correct
+ GSpfdc[T_hvdc[k_link], k_link] = -1.0 # TODO: check that this is correct
Gslack = lil_matrix((N, nsl), dtype=complex)
Gslcap = lil_matrix((N, nslcap), dtype=complex)
- if nslcap !=0:
+ if nslcap != 0:
for idslcap, capbus in enumerate(capacity_nodes_idx):
Gslcap[capbus, idslcap] = -1
@@ -855,13 +884,13 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
"""
ts_hx = timeit.default_timer()
- Vfmat = diags(Cf[il, :] @ V)
- Vtmat = diags(Ct[il, :] @ V)
+ Vfmat = diags(Cf[mon_br_idx, :] @ V)
+ Vtmat = diags(Ct[mon_br_idx, :] @ V)
- IfCJmat = np.conj(diags(Yf[il, :] @ V))
- ItCJmat = np.conj(diags(Yt[il, :] @ V))
- Sf = Vfmat @ np.conj(Yf[il, :] @ V)
- St = Vtmat @ np.conj(Yt[il, :] @ V)
+ IfCJmat = np.conj(diags(Yf[mon_br_idx, :] @ V))
+ ItCJmat = np.conj(diags(Yt[mon_br_idx, :] @ V))
+ Sf = Vfmat @ np.conj(Yf[mon_br_idx, :] @ V)
+ St = Vtmat @ np.conj(Yt[mon_br_idx, :] @ V)
allSf = diags(Cf @ V) @ np.conj(Yf @ V)
allSt = diags(Ct @ V) @ np.conj(Yt @ V)
@@ -869,11 +898,11 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
Sfmat = diags(Sf)
Stmat = diags(St)
- Sfvm = (IfCJmat @ Cf[il, :] @ E + Vfmat @ np.conj(Yf[il, :]) @ np.conj(E))
- Stvm = (ItCJmat @ Ct[il, :] @ E + Vtmat @ np.conj(Yt[il, :]) @ np.conj(E))
+ Sfvm = (IfCJmat @ Cf[mon_br_idx, :] @ E + Vfmat @ np.conj(Yf[mon_br_idx, :]) @ np.conj(E))
+ Stvm = (ItCJmat @ Ct[mon_br_idx, :] @ E + Vtmat @ np.conj(Yt[mon_br_idx, :]) @ np.conj(E))
- Sfva = (1j * (IfCJmat @ Cf[il, :] @ Vmat - Vfmat @ np.conj(Yf[il, :]) @ np.conj(Vmat)))
- Stva = (1j * (ItCJmat @ Ct[il, :] @ Vmat - Vtmat @ np.conj(Yt[il, :]) @ np.conj(Vmat)))
+ Sfva = (1j * (IfCJmat @ Cf[mon_br_idx, :] @ Vmat - Vfmat @ np.conj(Yf[mon_br_idx, :]) @ np.conj(Vmat)))
+ Stva = (1j * (ItCJmat @ Ct[mon_br_idx, :] @ Vmat - Vtmat @ np.conj(Yt[mon_br_idx, :]) @ np.conj(Vmat)))
Hpu = sp.hstack([lil_matrix((Ng, 2 * N)), diags(np.ones(Ng)), lil_matrix((Ng, NV - 2 * N - Ng))])
Hpl = sp.hstack([lil_matrix((Ng, 2 * N)), diags(- np.ones(Ng)), lil_matrix((Ng, NV - 2 * N - Ng))])
@@ -895,7 +924,7 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
lil_matrix((M, 2 * npq + nslcap + ntapm + ntapt + ndc))])
Hslvmax = sp.hstack([lil_matrix((npq, npfvar + 2 * M)), diags(- np.ones(npq)),
- lil_matrix((npq, npq + nslcap + ntapm + ntapt + ndc))])
+ lil_matrix((npq, npq + nslcap + ntapm + ntapt + ndc))])
Hslvmin = sp.hstack([lil_matrix((npq, npfvar + 2 * M + npq)), diags(- np.ones(npq)),
lil_matrix((npq, nslcap + ntapm + ntapt + ndc))])
@@ -910,10 +939,10 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
if (ntapm + ntapt) != 0:
- Sftapm = dSfdm[il, :].copy()
- Sftapt = dSfdt[il, :].copy()
- Sttapm = dStdm[il, :].copy()
- Sttapt = dStdt[il, :].copy()
+ Sftapm = dSfdm[mon_br_idx, :].copy()
+ Sftapt = dSfdt[mon_br_idx, :].copy()
+ Sttapm = dStdm[mon_br_idx, :].copy()
+ Sttapt = dStdt[mon_br_idx, :].copy()
SfX = sp.hstack([Sfva, Sfvm, lil_matrix((M, 2 * Ng + nsl + nslcap)), Sftapm, Sftapt, lil_matrix((M, ndc))])
StX = sp.hstack([Stva, Stvm, lil_matrix((M, 2 * Ng + nsl + nslcap)), Sttapm, Sttapt, lil_matrix((M, ndc))])
@@ -966,7 +995,7 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
HSf = 2 * (Sfmat.real @ SfX.real + Sfmat.imag @ SfX.imag)
HSt = 2 * (Stmat.real @ StX.real + Stmat.imag @ StX.imag)
- if ctQ != ReactivePowerControlMode.NoControl:
+ if ctQ: # if reactive power control...
# tanmax curves (simplified capability curves of generators)
Hqmaxp = - 2 * np.power(tanmax, 2) * Pg
Hqmaxq = 2 * Qg
@@ -1023,7 +1052,7 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
np.zeros(2 * N),
2 * c2 * (Sbase * Sbase),
np.zeros(Ng + nsl + nslcap + ntapm + ntapt + ndc)
- ]) * 1e-4).tocsc()
+ ]) * 1e-4).tocsc()
else:
fxx = csc((NV, NV))
@@ -1096,7 +1125,7 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
GSdtdt, dSfdtdt, dStdtdt,
GSdtdvm, dSfdtdvm, dStdtdvm,
GSdtdva, dSfdtdva, dStdtdva) = compute_branch_power_second_derivatives(alltapm, alltapt, vm, va, k_m,
- k_tau, il, Cf, Ct, R, X, F, T,
+ k_tau, mon_br_idx, R, X, F, T,
lmbda[0: 2 * N], mu[0: 2 * M],
allSf, allSt)
@@ -1150,7 +1179,7 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
Smuf_mat = diags(Sfmat.conj() @ muf)
Smut_mat = diags(Stmat.conj() @ mut)
- Af = np.conj(Yf[il, :]).T @ Smuf_mat @ Cf[il, :]
+ Af = np.conj(Yf[mon_br_idx, :]).T @ Smuf_mat @ Cf[mon_br_idx, :]
Bf = np.conj(Vmat) @ Af @ Vmat
Df = diags(Af @ V) @ np.conj(Vmat)
Ef = diags(Af.T @ np.conj(V)) @ Vmat
@@ -1160,7 +1189,7 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
Sfvavm = Sfvmva.T
Sfvmvm = vm_inv @ Ff @ vm_inv
- if ctQ != ReactivePowerControlMode.NoControl:
+ if ctQ: # using reactive power control
Hqpgpg = diags(-2 * np.power(tanmax, 2) * mu[-Ng:])
Hqqgqg = diags(np.array([2] * Ng) * mu[-Ng:])
else:
@@ -1172,7 +1201,7 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
Hfvavm = 2 * (Sfvavm + Sfva.T @ muf_mat @ np.conj(Sfvm)).real
Hfvmvm = 2 * (Sfvmvm + Sfvm.T @ muf_mat @ np.conj(Sfvm)).real
- At = np.conj(Yt[il, :]).T @ Smut_mat @ Ct[il, :]
+ At = np.conj(Yt[mon_br_idx, :]).T @ Smut_mat @ Ct[mon_br_idx, :]
Bt = np.conj(Vmat) @ At @ Vmat
Dt = diags(At @ V) @ np.conj(Vmat)
Et = diags(At.T @ np.conj(V)) @ Vmat
@@ -1256,12 +1285,11 @@ def jacobians_and_hessians(x: Vec, c1: Vec, c2: Vec, c_s: Vec, c_v: Vec, Cg: csc
ts_hxx = 0
te_hxx = 0
-
- der_times= np.array([te_fx - ts_fx,
- te_gx - ts_gx,
- te_hx - ts_hx,
- te_fxx - ts_fxx,
- te_gxx - ts_gxx,
- te_hxx - ts_hxx])
+ der_times = np.array([te_fx - ts_fx,
+ te_gx - ts_gx,
+ te_hx - ts_hx,
+ te_fxx - ts_fxx,
+ te_gxx - ts_gxx,
+ te_hxx - ts_hxx])
return fx, Gx, Hx, fxx, Gxx, Hxx, der_times
diff --git a/src/GridCalEngine/Simulations/OPF/linear_opf_ts.py b/src/GridCalEngine/Simulations/OPF/linear_opf_ts.py
index 8a05c0f31..eb06b87f4 100644
--- a/src/GridCalEngine/Simulations/OPF/linear_opf_ts.py
+++ b/src/GridCalEngine/Simulations/OPF/linear_opf_ts.py
@@ -40,7 +40,7 @@
from GridCalEngine.DataStructures.fluid_p2x_data import FluidP2XData
from GridCalEngine.basic_structures import Logger, Vec, IntVec, DateVec, Mat
from GridCalEngine.Utils.MIP.selected_interface import LpExp, LpVar, LpModel, lpDot, set_var_bounds, join
-from GridCalEngine.enumerations import TransformerControlType, HvdcControlType, ZonalGrouping, MIPSolvers
+from GridCalEngine.enumerations import HvdcControlType, ZonalGrouping, MIPSolvers, TapPhaseControl
from GridCalEngine.Simulations.LinearFactors.linear_analysis import (LinearAnalysis, LinearMultiContingency,
LinearMultiContingencies)
@@ -1115,7 +1115,7 @@ def add_linear_branches_formulation(t: int,
bk = 1.0 / branch_data_t.X[m]
# compute the flow
- if branch_data_t.control_mode[m] == TransformerControlType.Pf:
+ if branch_data_t.tap_phase_control_mode[m] == TapPhaseControl.Pf:
# add angle
branch_vars.tap_angles[t, m] = prob.add_var(lb=branch_data_t.tap_angle_min[m],
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/__init__.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/__init__.py
index d06876ef8..e561f94a5 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/__init__.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/__init__.py
@@ -16,14 +16,6 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.fast_decoupled import FDPF
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.iwamoto_newton_raphson import IwamotoNR
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.levenberg_marquardt import levenberg_marquardt_pf
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.newton_raphson import NR_LS
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.newton_raphson_current import NR_I_LS
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.newton_raphson_ode import ContinuousNR
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.gauss_power_flow import gausspf
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.helm_power_flow import helm_josep, helm_coefficients_josep, helm_coefficients_dY, helm_preparation_dY
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.newton_raphson_acdc import NR_LS_ACDC
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.newton_raphson_general import NR_LS_GENERAL
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.newton_raphson_decoupled import NRD_LS
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.levenberg_marquardt_acdc import LM_ACDC
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.linearized_power_flow import dcpf, lacpf
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/acdc_jacobian.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/acdc_jacobian.py
deleted file mode 100644
index 32cc1d121..000000000
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/acdc_jacobian.py
+++ /dev/null
@@ -1,856 +0,0 @@
-# GridCal
-# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import numpy as np
-import numba as nb
-from typing import Tuple
-from scipy.sparse import lil_matrix, diags, csc_matrix
-import GridCalEngine.Simulations.PowerFlow.NumericalMethods.derivatives as deriv
-from GridCalEngine.basic_structures import Vec, IntVec, CxVec
-
-
-class AcDcSolSlicer:
-
- def __init__(self, pvpq, pq, k_zero_beq, k_vf_beq, k_qf_m, k_qt_m, k_vt_m, k_pf_tau, k_pf_dp):
- """
- Declare the slicing limits in the same order as the Jacobian rows
- :param pvpq:
- :param pq:
- :param k_zero_beq:
- :param k_vf_beq:
- :param k_qf_m:
- :param k_qt_m:
- :param k_vt_m:
- :param k_pf_tau:
- :param k_pf_dp:
- """
-
- self.va_idx = pvpq
- self.vm_idx = pq
- self.beq_idx = np.r_[k_zero_beq, k_vf_beq]
- self.m_idx = np.r_[k_qf_m, k_qt_m, k_vt_m]
- self.tau_idx = np.r_[k_pf_tau, k_pf_dp]
-
- n_col_block1 = len(pvpq)
- n_col_block2 = len(pq)
- n_col_block3 = len(k_zero_beq) + len(k_vf_beq)
- n_col_block4 = len(k_qf_m) + len(k_qt_m) + len(k_vt_m)
- n_col_block5 = len(k_pf_tau) + len(k_pf_dp)
-
- self.a0 = 0
- self.a1 = self.a0 + n_col_block1
- self.a2 = self.a1 + n_col_block2
- self.a3 = self.a2 + n_col_block3
- self.a4 = self.a3 + n_col_block4
- self.a5 = self.a4 + n_col_block5
-
- def split(self, dx):
- """
- Split the linear system solution
- :param dx: linear system solution
- :return: dVa, dVm, dBeq, dm, dtau
- """
- dVa = dx[self.a0:self.a1]
- dVm = dx[self.a1:self.a2]
- dBeq = dx[self.a2:self.a3]
- dm = dx[self.a3:self.a4]
- dtau = dx[self.a4:self.a5]
-
- return dVa, dVm, dBeq, dm, dtau
-
- def assign(self, dx, Va, Vm, Beq, m, tau, mu=1.0):
- dVa = dx[self.a0:self.a1]
- dVm = dx[self.a1:self.a2]
- dBeq = dx[self.a2:self.a3]
- dm = dx[self.a3:self.a4]
- dtau = dx[self.a4:self.a5]
-
- # assign the new values
- if mu != 1.0:
- Va[self.va_idx] -= dVa * mu
- Vm[self.vm_idx] -= dVm * mu
- Beq[self.beq_idx] -= dBeq * mu
- m[self.m_idx] -= dm * mu
- tau[self.tau_idx] -= dtau * mu
- else:
- Va[self.va_idx] -= dVa
- Vm[self.vm_idx] -= dVm
- Beq[self.beq_idx] -= dBeq
- m[self.m_idx] -= dm
- tau[self.tau_idx] -= dtau
-
-@nb.njit(cache=True)
-def make_lookup(n, arr):
- """
-
- :param n: size of the lookup
- :param arr: positions of the elemnts in an array of size n
- :return:
- """
- lookup = np.zeros(n, dtype=np.int32)
- lookup[arr] = np.arange(len(arr), dtype=np.int32)
- return lookup
-
-
-@nb.njit(cache=True)
-def fill_acdc_jacobian_data(Jx: Vec, Ji: IntVec, Jp: IntVec,
- Yp, Yi: IntVec,
- Ys: CxVec,
- dSbus_dVa_x: Vec,
- dSbus_dVm_x: Vec,
- dSf_dVa_x: Vec, dSf_dVa_i: IntVec, dSf_dVa_p: IntVec,
- dSf_dVm_x: Vec, dSf_dVm_i: IntVec, dSf_dVm_p: IntVec,
- dSt_dVa_x: Vec, dSt_dVa_i: IntVec, dSt_dVa_p: IntVec,
- dSt_dVm_x: Vec, dSt_dVm_i: IntVec, dSt_dVm_p: IntVec,
- dPfdp_dVm_x: Vec, dPfdp_dVm_i: IntVec, dPfdp_dVm_p: IntVec,
- pvpq: IntVec, pq: IntVec,
- k_pf_tau: IntVec,
- k_qt_m: IntVec,
- k_qf_m: IntVec,
- k_vt_m: IntVec,
- k_pf_dp: IntVec,
- k_zero_beq: IntVec,
- k_vf_beq: IntVec,
- i_vf_beq: IntVec,
- i_vt_m: IntVec,
- F: IntVec, T: IntVec, V: CxVec,
- tap_modules_m: Vec, tap_complex: CxVec,
- k2: Vec, Bc: Vec, b_eq: Vec) -> Tuple[int, Vec, IntVec, IntVec]:
- """
- Compute the ACDC jacobian using Numba
- :param Jx: Jacobian CSC data array (to be filled)
- :param Ji: Jacobian CSC row indices array (to be filled)
- :param Jp: Jacobian CSC pointer array (to be filled)
- :param Yp: Ybus CSC pointer array
- :param Yi: Ybus CSC row indices array
- :param Ys: Branches' series admittance array
- :param dSbus_dVa_x: dSbus_dVa CSC data array
- :param dSbus_dVm_x: dSbus_dVm CSC data array
- :param dSf_dVa_x: dSf_dVa CSC data array
- :param dSf_dVa_i: dSf_dVa CSC row indices array
- :param dSf_dVa_p: dSf_dVa CSC pointer array
- :param dSf_dVm_x: dSf_dVm CSC data array
- :param dSf_dVm_i: dSf_dVm CSC row indices array
- :param dSf_dVm_p: dSf_dVm CSC pointer array
- :param dSt_dVa_x: dSt_dVa CSC data array
- :param dSt_dVa_i: dSt_dVa CSC row indices array
- :param dSt_dVa_p: dSt_dVa CSC pointer array
- :param dSt_dVm_x: dSt_dVm CSC data array
- :param dSt_dVm_i: dSt_dVm CSC row indices array
- :param dSt_dVm_p: dSt_dVm CSC pointer array
- :param dPfdp_dVm_x: dPfdp_dVm CSC data array
- :param dPfdp_dVm_i: dPfdp_dVm CSC row indices array
- :param dPfdp_dVm_p: dPfdp_dVm CSC pointer array
- :param pvpq: Array of pv and then pq bus indices (not sorted)
- :param pq: Array of PQ bus indices
- :param k_pf_tau: Indices of the Pf controlled with the shunt susceptance Branches
- :param k_qt_m: Indices of the Qt controlled with ma Branches
- :param k_qf_m: Indices of the Qf controlled with ma Branches
- :param k_vt_m: Indices of the Vt controlled with ma Branches
- :param k_pf_dp: indices of the Pf-droop controlled Branches
- :param k_zero_beq: Indices of the Qf made zero with the equivalent susceptance Branches
- :param k_vf_beq: Indices of the Vf Controlled with the equivalent susceptance Branches
- :param i_vf_beq: Indices of the buses where Vf is controlled with Beq
- :param i_vt_m: Indices of the buses where Vt is controlled with m
- :param F: Array of "from" bus indices
- :param T: Array of "to" bus indices
- :param V: Array of complex bus voltages
- :param tap_modules_m: Array of tap modules
- :param k2: Array of branch converter k2 parameters
- :param tap_complex: Array of complex tap values {remember tap = ma * exp(1j * theta) }
- :param Bc: Array of branch full susceptances
- :param b_eq: Array of branch equivalent (variable) susceptances
- :return: nnz, Jx, Ji, Jp
- """
- n_pf_tau = len(k_pf_tau)
- n_pf_dp = len(k_pf_dp)
- n_qt_m = len(k_qt_m)
-
- nbus = len(V)
- nbr = len(Ys)
-
- row_block2 = np.concatenate((pq, i_vf_beq, i_vt_m))
- row_block3 = np.concatenate((k_qf_m, k_zero_beq))
-
- col_block3 = np.concatenate((k_zero_beq, k_vf_beq))
- n_col_block3 = len(col_block3)
-
- col_block4 = np.concatenate((k_qf_m, k_qt_m, k_vt_m))
- n_col_block4 = len(col_block4)
-
- col_block5 = np.concatenate((k_pf_tau, k_pf_dp))
- n_col_block5 = len(col_block5)
-
- # generate lookup for the row slicing (these follow the structure of the residuals vector)
- row_block1_lookup = make_lookup(nbus, pvpq) # in: bus index, out: index in pvpq
- row_block2_lookup = make_lookup(nbus, row_block2) # in: bus index, out: index in row_block2
- row_block3_lookup = make_lookup(nbr, row_block3) # in: branch index, out: index in row_block3
- row_block4_lookup = make_lookup(nbr, k_qt_m) # in: branch index, out: index in k_qt_m
- row_block5_lookup = make_lookup(nbr, k_pf_tau) # in: branch index, out: index in k_pf_tau
- row_block6_lookup = make_lookup(nbr, k_pf_dp) # in: branch index, out: index in k_pf_dp
-
- n_row_block1 = len(pvpq)
- n_row_block2 = len(row_block2)
- n_row_block3 = len(row_block3)
- n_row_block4 = len(k_qt_m)
- n_row_block5 = len(k_pf_tau)
- n_row_block6 = len(k_pf_dp)
-
- nnz = 0
- p = 0
- Jp[p] = 0
-
- # column 1: derivatives w.r.t Va -----------------------------------------------------------------------------------
- for j in pvpq: # sliced columns
-
- # J11
- if n_row_block1:
- for k in range(Yp[j], Yp[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = Yi[k] # bus index (row index in Ybus)
- ii = row_block1_lookup[i] # jacobian row index
-
- if pvpq[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dVa_x[k].real # dP/dĘ
- Ji[nnz] = ii
- nnz += 1
-
- # J21
- offset = n_row_block1
- if n_row_block2:
- for k in range(Yp[j], Yp[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = Yi[k]
- ii = row_block2_lookup[i] # in: bus index, out: index in row_block2
-
- if row_block2[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dVa_x[k].imag # dQ/dĘ
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J31
- offset += n_row_block2
- if n_row_block3:
- for k in range(dSf_dVa_p[j], dSf_dVa_p[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dVa_i[k]
- ii = row_block3_lookup[i] # in: branch index, out: index in row_block3
-
- if row_block3[ii] == i:
- # entry found
- Jx[nnz] = dSf_dVa_x[k].imag # dQf/dĘ
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J41
- offset += n_row_block3
- if n_qt_m:
- for k in range(dSt_dVa_p[j], dSt_dVa_p[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSt_dVa_i[k]
- ii = row_block4_lookup[i]
-
- if k_qt_m[ii] == i:
- # entry found
- Jx[nnz] = dSt_dVa_x[k].imag # dQt/dĘ
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J51
- offset += n_row_block4
- if n_pf_tau:
- for k in range(dSf_dVa_p[j], dSf_dVa_p[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dVa_i[k]
- ii = row_block5_lookup[i]
-
- if k_pf_tau[ii] == i:
- # entry found
- Jx[nnz] = dSf_dVa_x[k].real # dPf/dĘ
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J61
- offset += n_row_block5
- if n_pf_dp:
- for k in range(dSf_dVa_p[j], dSf_dVa_p[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dVa_i[k]
- ii = row_block6_lookup[i]
-
- if k_pf_dp[ii] == i:
- # entry found
- Jx[nnz] = -dSf_dVa_x[k].real # dPf/dĘ
- Ji[nnz] = ii + offset
- nnz += 1
-
- # finalize column
- p += 1
- Jp[p] = nnz
-
- # column 2: derivatives w.r.t Vm -----------------------------------------------------------------------------------
- for j in pq: # sliced columns
-
- # J12
- if n_row_block1:
- for k in range(Yp[j], Yp[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = Yi[k]
- ii = row_block1_lookup[i]
-
- if pvpq[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dVm_x[k].real # dP/dVm
- Ji[nnz] = ii
- nnz += 1
-
- # J22
- offset = n_row_block1
- if n_row_block2:
- for k in range(Yp[j], Yp[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = Yi[k]
- ii = row_block2_lookup[i]
-
- if row_block2[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dVm_x[k].imag # dQ/dVm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J32
- offset += n_row_block2
- if n_row_block3:
- for k in range(dSf_dVm_p[j], dSf_dVm_p[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dVm_i[k]
- ii = row_block3_lookup[i]
-
- if row_block3[ii] == i:
- # entry found
- Jx[nnz] = dSf_dVm_x[k].imag # dQf/dVm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J42
- offset += n_row_block3
- if n_qt_m:
- for k in range(dSt_dVm_p[j], dSt_dVm_p[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSt_dVm_i[k]
- ii = row_block4_lookup[i]
-
- if k_qt_m[ii] == i:
- # entry found
- Jx[nnz] = dSt_dVm_x[k].imag # dQt/dVm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J52
- offset += n_row_block4
- if n_pf_tau:
- for k in range(dSf_dVm_p[j], dSf_dVm_p[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dVm_i[k]
- ii = row_block5_lookup[i]
-
- if k_pf_tau[ii] == i:
- # entry found
- Jx[nnz] = dSf_dVm_x[k].real # dPf/dVm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J62
- offset += n_row_block5
- if n_pf_dp:
-
- for k in range(dPfdp_dVm_p[j], dPfdp_dVm_p[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dPfdp_dVm_i[k]
- ii = row_block6_lookup[i]
-
- if k_pf_dp[ii] == i:
- # entry found
- Jx[nnz] = dPfdp_dVm_x[k] # dPfdp/dVm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # finalize column
- p += 1
- Jp[p] = nnz
-
- # Column 3: derivatives w.r.t Beq for iBeqz + iBeqv ----------------------------------------------------------------
- if n_col_block3:
-
- (dSbus_dBeq_data,
- dSbus_dBeq_indices,
- dSbus_dBeq_indptr,
- dSf_dBeqx_data,
- dSf_dBeqx_indices,
- dSf_dBeqx_indptr) = deriv.derivatives_Beq_csc_numba(iBeqx=col_block3, F=F, V=V, ma=tap_modules_m, k2=k2)
-
- for j in range(n_col_block3): # sliced columns
-
- # J13
- if n_row_block1:
- for k in range(dSbus_dBeq_indptr[j], dSbus_dBeq_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSbus_dBeq_indices[k]
- ii = row_block1_lookup[i]
-
- if pvpq[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dBeq_data[k].real # dP/dBeq
- Ji[nnz] = ii
- nnz += 1
-
- # J23
- offset = n_row_block1
- if n_row_block2:
- for k in range(dSbus_dBeq_indptr[j], dSbus_dBeq_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSbus_dBeq_indices[k]
- ii = row_block2_lookup[i]
-
- if row_block2[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dBeq_data[k].imag # dQ/dBeq
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J33
- offset += n_row_block2
- if n_row_block3:
- for k in range(dSf_dBeqx_indptr[j], dSf_dBeqx_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dBeqx_indices[k]
- ii = row_block3_lookup[i]
-
- if row_block3[ii] == i:
- # entry found
- Jx[nnz] = dSf_dBeqx_data[k].imag # dQf/dBeq
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J43
- offset += n_row_block3
- # if n_row_block4: # --> The Jacobian is always zero :|
- # for k in range(dSt_dBeqz.indptr[j], dSt_dBeqz.indptr[j + 1]): # rows of A[:, j]
- #
- # # row index translation to the "rows" space
- # i = dSt_dBeqz.indices[k]
- # ii = iQtma_lookup[i]
- #
- # if iQtma[ii] == i:
- # # entry found
- # Jx[nnz] = dSt_dBeqz.data[k].imag
- # Ji[nnz] = ii + offset
- # nnz += 1
-
- # J53
- offset += n_row_block4
- if n_row_block5:
- for k in range(dSf_dBeqx_indptr[j], dSf_dBeqx_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dBeqx_indices[k]
- ii = row_block5_lookup[i]
-
- if k_pf_tau[ii] == i:
- # entry found
- Jx[nnz] = dSf_dBeqx_data[k].real # dPf/dBeq
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J63
- offset += n_row_block5
- if n_row_block6:
- for k in range(dSf_dBeqx_indptr[j], dSf_dBeqx_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dBeqx_indices[k]
- ii = row_block6_lookup[i]
-
- if k_pf_dp[ii] == i:
- # entry found
- Jx[nnz] = -dSf_dBeqx_data[k].real # dPf/dBeq
- Ji[nnz] = ii + offset
- nnz += 1
-
- # finalize column
- p += 1
- Jp[p] = nnz
-
- # Column 4: derivative w.r.t "m" for iQfma + iQfma + iVtma ---------------------------------------------------------
- if n_col_block4:
-
- (dSbus_dm_data,
- dSbus_dm_indices,
- dSbus_dm_indptr,
- dSf_dm_data,
- dSf_dm_indices,
- dSf_dm_indptr,
- dSt_dm_data,
- dSt_dm_indices,
- dSt_dm_indptr) = deriv.derivatives_ma_csc_numba(iXxma=col_block4, F=F, T=T, Ys=Ys, k2=k2,
- tap=tap_complex, ma=tap_modules_m, Bc=Bc,
- Beq=b_eq, V=V)
-
- for j in range(n_col_block4): # sliced columns
-
- # J14
- if n_row_block1:
- for k in range(dSbus_dm_indptr[j], dSbus_dm_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSbus_dm_indices[k]
- ii = row_block1_lookup[i]
-
- if pvpq[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dm_data[k].real # dP/dm
- Ji[nnz] = ii
- nnz += 1
-
- # J24
- offset = n_row_block1
- if n_row_block2:
- for k in range(dSbus_dm_indptr[j], dSbus_dm_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSbus_dm_indices[k]
- ii = row_block2_lookup[i]
-
- if row_block2[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dm_data[k].imag # dQ/dm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J34
- offset += n_row_block2
- if n_row_block3:
- for k in range(dSf_dm_indptr[j], dSf_dm_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dm_indices[k]
- ii = row_block3_lookup[i]
-
- if row_block3[ii] == i:
- # entry found
- Jx[nnz] = dSf_dm_data[k].imag # dQf/dm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J44
- offset += n_row_block3
- if n_row_block4:
- for k in range(dSt_dm_indptr[j], dSt_dm_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSt_dm_indices[k]
- ii = row_block4_lookup[i]
-
- if k_qt_m[ii] == i:
- # entry found
- Jx[nnz] = dSt_dm_data[k].imag # dQt/dm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J54
- offset += n_row_block4
- if n_row_block5:
- for k in range(dSf_dm_indptr[j], dSf_dm_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dm_indices[k]
- ii = row_block5_lookup[i]
-
- if k_pf_tau[ii] == i:
- # entry found
- Jx[nnz] = dSf_dm_data[k].real # dPf/dm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J64
- offset += n_row_block5
- if n_row_block6:
- for k in range(dSf_dm_indptr[j], dSf_dm_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dm_indices[k]
- ii = row_block6_lookup[i]
-
- if k_pf_dp[ii] == i:
- # entry found
- Jx[nnz] = -dSf_dm_data[k].real # dPf/dm
- Ji[nnz] = ii + offset
- nnz += 1
-
- # finalize column
- p += 1
- Jp[p] = nnz
-
- # Column 5: derivatives w.r.t theta sh for iPfsh + droop -----------------------------------------------------------
- if n_col_block5:
-
- (dSbus_dtau_data,
- dSbus_dtau_indices,
- dSbus_dtau_indptr,
- dSf_dtau_data,
- dSf_dtau_indices,
- dSf_dtau_indptr,
- dSt_dtau_data,
- dSt_dtau_indices,
- dSt_dtau_indptr) = deriv.derivatives_tau_csc_numba(iPxsh=col_block5,
- F=F, T=T, Ys=Ys,
- k2=k2, tap=tap_complex, V=V)
-
- for j in range(n_col_block5): # sliced columns
-
- # J15
- if n_row_block1:
- for k in range(dSbus_dtau_indptr[j], dSbus_dtau_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSbus_dtau_indices[k]
- ii = row_block1_lookup[i]
-
- if pvpq[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dtau_data[k].real # dP/dtau
- Ji[nnz] = ii
- nnz += 1
-
- # J25
- offset = n_row_block1
- if n_row_block2:
- for k in range(dSbus_dtau_indptr[j], dSbus_dtau_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSbus_dtau_indices[k]
- ii = row_block2_lookup[i]
-
- if row_block2[ii] == i:
- # entry found
- Jx[nnz] = dSbus_dtau_data[k].imag # dQ/dtau
- Ji[nnz] = ii + offset
- nnz += 1
-
-
- # J35
- offset += n_row_block2
- if n_row_block3:
- for k in range(dSf_dtau_indptr[j], dSf_dtau_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dtau_indices[k]
- ii = row_block3_lookup[i]
-
- if row_block3[ii] == i:
- # entry found
- Jx[nnz] = dSf_dtau_data[k].imag # dQf/dtau
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J45
- offset += n_row_block3
- if n_row_block4:
- for k in range(dSt_dtau_indptr[j], dSt_dtau_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSt_dtau_indices[k]
- ii = row_block4_lookup[i]
-
- if k_qt_m[ii] == i:
- # entry found
- Jx[nnz] = dSt_dtau_data[k].imag # dQt/dtau
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J55
- offset += n_row_block4
- if n_row_block5:
- for k in range(dSf_dtau_indptr[j], dSf_dtau_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dtau_indices[k]
- ii = row_block5_lookup[i]
-
- if k_pf_tau[ii] == i:
- # entry found
- Jx[nnz] = dSf_dtau_data[k].real # dPf/dtau
- Ji[nnz] = ii + offset
- nnz += 1
-
- # J65
- offset += n_row_block6
- if n_row_block6:
- for k in range(dSf_dtau_indptr[j], dSf_dtau_indptr[j + 1]): # rows of A[:, j]
-
- # row index translation to the "rows" space
- i = dSf_dtau_indices[k]
- ii = row_block6_lookup[i]
-
- if k_pf_dp[ii] == i:
- # entry found
- Jx[nnz] = -dSf_dtau_data[k].real # - dPf/dtau
- Ji[nnz] = ii + offset
- nnz += 1
-
- # finalize column
- p += 1
- Jp[p] = nnz
-
- # Finalize ----------------------------------------------------------------------------
- # finalize the Jacobian Pointer
- Jp[p] = nnz
-
- return nnz, Jx, Ji, Jp
-
-
-def fubm_jacobian(nb, nl, k_pf_tau, k_pf_dp, k_qf_m, k_qt_m, k_vt_m, k_zero_beq, k_vf_beq, i_vf_beq, i_vt_m,
- F, T, Ys, k2, complex_tap, tap_modules, Bc, Beq, Kdp, V, Ybus, Yf, Yt, Cf, Ct, pvpq, pq):
- """
- Compute the FUBM jacobian in a dynamic fashion by only computing the derivatives that are needed
- :param nb: number of buses
- :param nl: Number of lines
- :param k_pf_tau: indices of the Pf controlled with the shunt susceptance Branches
- :param k_pf_dp: indices of the Pf-droop controlled Branches
- :param k_qf_m: indices of the Qf controlled with ma Branches
- :param k_qt_m: Indices of the Qt controlled with ma Branches
- :param k_vt_m: Indices of the Vt controlled with ma Branches
- :param k_zero_beq: Indices of the Qf made zero with the equivalent susceptance Branches
- :param k_vf_beq: Indices of the Vf Controlled with the equivalent susceptance Branches
- :param i_vf_beq: Indices of the buses where Vf is controlled with Beq
- :param i_vt_m: Indices of the buses where Vt is controlled with ma
- :param F: Array of "from" bus indices
- :param T: Array of "to" bus indices
- :param Ys: Array of branch series admittances
- :param k2: Array of branch converter k2 parameters
- :param complex_tap: Array of complex tap values {remember tap = ma * exp(1j * theta) }
- :param tap_modules: Array of tap modules
- :param Bc: Array of branch full susceptances
- :param Beq: Array of branch equivalent (variable) susceptances
- :param Kdp: Array of branch converter droop constants
- :param V: Array of complex bus voltages
- :param Ybus: Admittance matrix
- :param Yf: Admittances matrix of the Branches with the "from" buses
- :param Yt: Admittances matrix of the Branches with the "to" buses
- :param Cf: Connectivity matrix of the Branches with the "from" buses
- :param Ct: Connectivity matrix of the Branches with the "to" buses
- :param pvpq: Array of pv and then pq bus indices (not sorted)
- :param pq: Array of PQ bus indices
- :return: FUBM Jacobian matrix
- """
- n_pf_tau = len(k_pf_tau)
- n_pf_dp = len(k_pf_dp)
- n_qf_m = len(k_qf_m)
- n_qt_m = len(k_qt_m)
- n_vt_m = len(k_vt_m)
- n_zero_beq = len(k_zero_beq)
- n_vf_beq = len(k_vf_beq)
- nVfBeqbus = len(i_vf_beq)
- nVtmabus = len(i_vt_m)
- npq = len(pq)
- npvpq = len(pvpq)
- nbus = Ybus.shape[0]
- nbr = Yf.shape[0]
-
- # i2 = np.r_[pq, i_vf_beq, i_vt_m]
- # i4 = np.r_[k_qf_m, k_zero_beq]
- # ni2 = len(i2)
- # ni4 = len(i4)
- E = V / np.abs(V)
-
- # compose the derivatives of the power Injections w.r.t Va and Vm
- dSbus_dVm_x, dSbus_dVa_x = deriv.dSbus_dV_numba_sparse_csc(Ybus.data, Ybus.indptr, Ybus.indices, V, np.abs(V))
-
- # compose the derivatives of the branch flow w.r.t Va and Vm
- dSf_dVm, dSf_dVa = deriv.dSf_dV_csc(Yf, V, F, T)
-
- if len(k_qt_m):
- dSt_dVm, dSt_dVa = deriv.dSt_dV_csc(Yt, V, F, T)
- else:
- dSt_dVa = csc_matrix((nl, nb))
- dSt_dVm = csc_matrix((nl, nb))
-
- if n_pf_dp:
- # compute the droop derivative
- dVmf_dVm = lil_matrix((nl, nb))
- dVmf_dVm[k_pf_dp, :] = Cf[k_pf_dp, :]
- dPfdp_dVm = -dSf_dVm.real + diags(Kdp) * dVmf_dVm
- else:
- dPfdp_dVm = csc_matrix((n_pf_dp, nb))
-
- n_cols = npvpq + npq + n_zero_beq + n_vf_beq + n_qf_m + n_qt_m + n_vt_m + n_pf_tau + n_pf_dp
- n_rows = n_cols
-
- nnz_estimate = Ybus.nnz * 8
- Jx = np.empty(nnz_estimate, dtype=np.float64) # data
- Ji = np.empty(nnz_estimate, dtype=np.int32) # indices
- Jp = np.empty(n_cols + 1, dtype=np.int32) # pointers
-
- # fill the jacobian data with numba
- nnz, Jx, Ji, Jp = fill_acdc_jacobian_data(Jx=Jx, Ji=Ji, Jp=Jp,
- Yp=Ybus.indptr, Yi=Ybus.indices, Ys=Ys,
- dSbus_dVa_x=dSbus_dVa_x, dSbus_dVm_x=dSbus_dVm_x,
- dSf_dVa_x=dSf_dVa.data, dSf_dVa_i=dSf_dVa.indices, dSf_dVa_p=dSf_dVa.indptr,
- dSf_dVm_x=dSf_dVm.data, dSf_dVm_i=dSf_dVm.indices, dSf_dVm_p=dSf_dVm.indptr,
- dSt_dVa_x=dSt_dVa.data, dSt_dVa_i=dSt_dVa.indices, dSt_dVa_p=dSt_dVa.indptr,
- dSt_dVm_x=dSt_dVm.data, dSt_dVm_i=dSt_dVm.indices, dSt_dVm_p=dSt_dVm.indptr,
- dPfdp_dVm_x=dPfdp_dVm.data, dPfdp_dVm_i=dPfdp_dVm.indices, dPfdp_dVm_p=dPfdp_dVm.indptr,
- pvpq=pvpq,
- pq=pq,
- k_pf_tau=k_pf_tau,
- k_qt_m=k_qt_m,
- k_qf_m=k_qf_m,
- k_vt_m=k_vt_m,
- k_pf_dp=k_pf_dp,
- k_zero_beq=k_zero_beq,
- k_vf_beq=k_vf_beq,
- i_vf_beq=i_vf_beq,
- i_vt_m=i_vt_m,
- F=F, T=T, V=V,
- tap_modules_m=tap_modules, tap_complex=complex_tap,
- k2=k2, Bc=Bc, b_eq=Beq)
-
- Jx = np.resize(Jx, nnz)
- Ji = np.resize(Ji, nnz)
-
- J = csc_matrix((Jx, Ji, Jp), shape=(n_rows, n_cols))
-
- return J
-
-
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/common_functions.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/common_functions.py
index cce2624ac..f1597fdea 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/common_functions.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/common_functions.py
@@ -64,6 +64,20 @@ def polar_to_rect(Vm, Va) -> CxVec:
return Vm * np.exp(1.0j * Va)
+def expand(n, arr: Vec, idx: IntVec, default: float) -> Vec:
+ """
+ Expand array
+ :param n: number of elements
+ :param arr: short array
+ :param idx: indices in the longer array
+ :param default: default value for the longer array
+ :return: longer array
+ """
+ x = np.full(n, default)
+ x[idx] = arr
+ return x
+
+
@nb.njit(cache=True, fastmath=True)
def compute_zip_power(S0: CxVec, I0: CxVec, Y0: CxVec, Vm: Vec) -> CxVec:
"""
@@ -88,31 +102,31 @@ def compute_power(Ybus: csc_matrix, V: CxVec) -> CxVec:
@nb.njit(cache=True, fastmath=True)
-def compute_fx(Scalc: CxVec, Sbus: CxVec, pvpq: IntVec, pq: IntVec) -> Vec:
+def compute_fx(Scalc: CxVec, Sbus: CxVec, idx_dP: IntVec, idx_dQ: IntVec) -> Vec:
"""
Compute the NR-like error function
f = [āP(pqpv), āQ(pq)]
:param Scalc: Calculated power injections
:param Sbus: Specified power injections
- :param pvpq: Array pf pq and pv node indices
- :param pq: Array of pq node indices
+ :param idx_dP: Array of node indices updated with dP (pvpq)
+ :param idx_dQ: Array of node indices updated with dQ (pq)
:return: error
"""
# dS = Scalc - Sbus # compute the mismatch
- # return np.r_[dS[pvpq].real, dS[pq].imag]
+ # return np.r_[dS[idx_dP].real, dS[idx_dQ].imag]
- n = len(pvpq) + len(pq)
+ n = len(idx_dP) + len(idx_dQ)
fx = np.empty(n, dtype=float)
k = 0
- for i in pvpq:
+ for i in idx_dP:
# F1(x0) Power balance mismatch - Va
# fx[k] = mis[i].real
fx[k] = Scalc[i].real - Sbus[i].real
k += 1
- for i in pq:
+ for i in idx_dQ:
# F2(x0) Power balance mismatch - Vm
# fx[k] = mis[i].imag
fx[k] = Scalc[i].imag - Sbus[i].imag
@@ -174,6 +188,76 @@ def compute_converter_losses(V: CxVec,
return Gsw
+@nb.njit()
+def get_Sf(k: IntVec, Vm: Vec, V: CxVec, yff: CxVec, yft: CxVec, F: IntVec, T: IntVec):
+ """
+
+ :param k:
+ :param Vm:
+ :param V:
+ :param yff:
+ :param yft:
+ :param F:
+ :param T:
+ :return:
+ """
+ f = F[k]
+ t = T[k]
+ return np.power(Vm[f], 2.0) * np.conj(yff[k]) + V[f] * np.conj(V[t]) * np.conj(yft[k])
+
+
+@nb.njit()
+def get_St(k: IntVec, Vm: Vec, V: CxVec, ytf: CxVec, ytt: CxVec, F: IntVec, T: IntVec):
+ """
+
+ :param k:
+ :param Vm:
+ :param V:
+ :param ytf:
+ :param ytt:
+ :param F:
+ :param T:
+ :return:
+ """
+ f = F[k]
+ t = T[k]
+ return np.power(Vm[t], 2.0) * np.conj(ytt[k]) + V[t] * np.conj(V[f]) * np.conj(ytf[k])
+
+
+@nb.njit()
+def get_If(k: IntVec, V: CxVec, yff: CxVec, yft: CxVec, F: IntVec, T: IntVec):
+ """
+
+ :param k:
+ :param V:
+ :param yff:
+ :param yft:
+ :param F:
+ :param T:
+ :return:
+ """
+ f = F[k]
+ t = T[k]
+ return np.conj(V[f]) * np.conj(yff[k]) + np.conj(V[t]) * np.conj(yft[k])
+
+
+@nb.njit()
+def get_It(k: IntVec, V: CxVec, ytf: CxVec, ytt: CxVec, F: IntVec, T: IntVec):
+ """
+
+ :param k:
+ :param V:
+ :param ytf:
+ :param ytt:
+ :param F:
+ :param T:
+ :return:
+ """
+ f = F[k]
+ t = T[k]
+ return np.conj(V[t]) * np.conj(ytt[k]) + np.conj(V[f]) * np.conj(ytf[k])
+
+
@nb.jit(nopython=True, cache=True, fastmath=True)
def compute_acdc_fx(Vm: Vec,
Sbus: CxVec,
@@ -221,7 +305,8 @@ def compute_acdc_fx(Vm: Vec,
"""
# mis = Scalc - Sbus # F1(x0) & F2(x0) Power balance mismatch
- n = len(pvpq) + len(pq) + len(i_vf_beq) + len(i_vt_m) + len(k_pf_tau) + len(k_qf_m) + len(k_zero_beq) + len(k_qt_m) + len(
+ n = len(pvpq) + len(pq) + len(i_vf_beq) + len(i_vt_m) + len(k_pf_tau) + len(k_qf_m) + len(k_zero_beq) + len(
+ k_qt_m) + len(
k_pf_dp)
fx = np.empty(n)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/derivatives.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/derivatives.py
deleted file mode 100644
index c816b93cb..000000000
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/derivatives.py
+++ /dev/null
@@ -1,965 +0,0 @@
-# GridCal
-# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import numpy as np
-import numba as nb
-from typing import Tuple
-import scipy.sparse as sp
-from scipy.sparse import lil_matrix, diags, csc_matrix, csr_matrix
-from GridCalEngine.basic_structures import CxVec, IntVec
-
-
-def dSbus_dV(Ybus: csc_matrix, V: CxVec) -> Tuple[csc_matrix, csc_matrix]:
- """
- Derivatives of the power Injections w.r.t the voltage
- :param Ybus: Admittance matrix
- :param V: complex voltage arrays
- :return: dSbus_dVa, dSbus_dVm
- """
- diagV = diags(V)
- diagE = diags(V / np.abs(V))
- Ibus = Ybus * V
- diagIbus = diags(Ibus)
-
- dSbus_dVa = 1j * diagV * np.conj(diagIbus - Ybus * diagV) # dSbus / dVa
- dSbus_dVm = diagV * np.conj(Ybus * diagE) + np.conj(diagIbus) * diagE # dSbus / dVm
-
- return dSbus_dVa, dSbus_dVm
-
-
-@nb.njit(cache=True)
-def dSbus_dV_numba_sparse_csc(Yx: CxVec, Yp: IntVec, Yi: IntVec, V: CxVec, Vm: CxVec) -> Tuple[CxVec, CxVec]:
- """
- Compute the power injection derivatives w.r.t the voltage module and angle
- :param Yx: data of Ybus in CSC format
- :param Yp: indptr of Ybus in CSC format
- :param Yi: indices of Ybus in CSC format
- :param V: Voltages vector
- :param Vm: voltage modules vector
- :return: dS_dVm, dS_dVa data ordered in the CSC format to match the indices of Ybus
- """
-
- """
- The matrix operations that this is performing are:
-
- diagV = diags(V)
- diagE = diags(V / np.abs(V))
- Ibus = Ybus * V
- diagIbus = diags(Ibus)
-
- dSbus_dVa = 1j * diagV * np.conj(diagIbus - Ybus * diagV)
- dSbus_dVm = diagV * np.conj(Ybus * diagE) + np.conj(diagIbus) * diagE
- """
-
- # init buffer vector
- n = len(Yp) - 1
- Ibus = np.zeros(n, dtype=nb.complex128)
- dS_dVm = Yx.copy()
- dS_dVa = Yx.copy()
- E = V.copy()
-
- # pass 1: perform the matrix-vector products
- for j in range(n): # for each column ...
-
- # compute the unitary vector of the voltage
- E[j] /= Vm[j]
-
- for k in range(Yp[j], Yp[j + 1]): # for each row ...
- # row index
- i = Yi[k]
-
- # Ibus = Ybus * V
- I = Yx[k] * V[j]
-
- # store in the Ibus vector
- Ibus[i] += I # Yx[k] -> Y(i,j)
-
- # Ybus * diagE
- dS_dVm[k] = Yx[k] * E[j]
-
- # - Ybus * diag(V)
- dS_dVa[k] = -I
-
- # pass 2: finalize the operations
- for j in range(n): # for each column ...
-
- # set buffer variable:
- # this operation cannot be done in the pass1
- # because Ibus is not fully formed, but here it is.
- buffer = np.conj(Ibus[j]) * E[j]
-
- for k in range(Yp[j], Yp[j + 1]): # for each row ...
-
- # row index
- i = Yi[k]
-
- # diag(V) * conj(Ybus * diagE)
- dS_dVm[k] = V[i] * np.conj(dS_dVm[k])
-
- if j == i:
- # diagonal elements
- dS_dVa[k] += Ibus[j] # diagIbus, after this it contains: diagIbus - Ybus * diagV
- dS_dVm[k] += buffer # conj(I(j)) * E(j), after this it contains; diag(V) * conj(Ybus * diagE) + conj(diagIbus) * diagE
-
- # 1j * diagV * conj(diagIbus - Ybus * diagV)
- dS_dVa[k] = (1j * V[i]) * np.conj(dS_dVa[k])
-
- return dS_dVm, dS_dVa
-
-
-@nb.jit(nopython=True, cache=True)
-def dSbus_dV_numba_sparse_csr(Yx: CxVec, Yp: IntVec, Yj: IntVec, V: CxVec, E: CxVec) -> Tuple[
- CxVec, CxVec]: # pragma: no cover
- """
- partial derivatives of power injection w.r.t. voltage.
- :param Yx: Ybus data in CSC format
- :param Yp: Ybus indptr in CSC format
- :param Yj: Ybus indices in CSC format
- :param V: Voltage vector
- :param E: Normalized voltage vector
- :return: dS_dVm, dS_dVa data in CSR format, index pointer and indices are the same as the ones from Ybus
- """
-
- # init buffer vector
- n = len(V)
- buffer = np.zeros(n, dtype=nb.complex128)
- Ibus = np.zeros(n, dtype=nb.complex128)
-
- # buffer = np.zeros(n, dtype=complex)
- # Ibus = np.zeros(n, dtype=complex)
-
- dS_dVm = Yx.copy()
- dS_dVa = Yx.copy()
-
- # iterate through sparse matrix
- for r in range(len(Yp) - 1):
- for k in range(Yp[r], Yp[r + 1]):
- # Ibus = Ybus * V
- buffer[r] += Yx[k] * V[Yj[k]]
-
- # Ybus * diag(Vnorm)
- dS_dVm[k] *= E[Yj[k]]
-
- # Ybus * diag(V)
- dS_dVa[k] *= V[Yj[k]]
-
- Ibus[r] += buffer[r]
-
- # conj(diagIbus) * diagVnorm
- buffer[r] = np.conj(buffer[r]) * E[r]
-
- for r in range(len(Yp) - 1):
- for k in range(Yp[r], Yp[r + 1]):
- # diag(V) * conj(Ybus * diagVnorm)
- dS_dVm[k] = np.conj(dS_dVm[k]) * V[r]
-
- if r == Yj[k]:
- # diagonal elements
- dS_dVa[k] = -Ibus[r] + dS_dVa[k]
- dS_dVm[k] += buffer[r]
-
- # 1j * diagV * conj(diagIbus - Ybus * diagV)
- dS_dVa[k] = np.conj(-dS_dVa[k]) * (1j * V[r])
-
- return dS_dVm, dS_dVa
-
-
-def dSbus_dV_csc(Ybus: csc_matrix, V: CxVec, Vm) -> Tuple[csc_matrix, csc_matrix]:
- """
- Call the numba sparse constructor of the derivatives
- :param Ybus: Ybus in CSC format
- :param V: Voltages vector
- :param Vm: Voltages modules
- :return: dS_dVm, dS_dVa in CSC format
- """
- # compute the derivatives' data fast
- dS_dVm, dS_dVa = dSbus_dV_numba_sparse_csc(Ybus.data, Ybus.indptr, Ybus.indices, V, Vm)
-
- # generate sparse CSC matrices with computed data and return them
- return (sp.csc_matrix((dS_dVa, Ybus.indices, Ybus.indptr)),
- sp.csc_matrix((dS_dVm, Ybus.indices, Ybus.indptr)))
-
-
-def dSbus_dV_csr(Ybus: csc_matrix, V: CxVec) -> Tuple[csr_matrix, csr_matrix]:
- """
- Calls functions to calculate dS/dV depending on whether Ybus is sparse or not
- :param Ybus: Ybus in CSC
- :param V: Voltages vector
- :return: dS_dVm, dS_dVa in CSR format
- """
-
- # I is subtracted from Y*V,
- # therefore it must be negative for numba version of dSbus_dV if it is not zeros anyways
- # calculates sparse data
- dS_dVm, dS_dVa = dSbus_dV_numba_sparse_csr(Ybus.data, Ybus.indptr, Ybus.indices, V, V / np.abs(V))
-
- # generate sparse CSR matrices with computed data and return them
- return (sp.csr_matrix((dS_dVm, Ybus.indices, Ybus.indptr)),
- sp.csr_matrix((dS_dVa, Ybus.indices, Ybus.indptr)))
-
-
-def dSbr_dV_matpower(Yf: csc_matrix, Yt: csc_matrix, V: CxVec,
- F: IntVec, T: IntVec,
- Cf: csc_matrix, Ct: csc_matrix) -> Tuple[csc_matrix, csc_matrix, csc_matrix, csc_matrix]:
- """
- Derivatives of the branch power w.r.t the branch voltage modules and angles
- :param Yf: Admittances matrix of the Branches with the "from" buses
- :param Yt: Admittances matrix of the Branches with the "to" buses
- :param V: Array of voltages
- :param F: Array of branch "from" bus indices
- :param T: Array of branch "to" bus indices
- :param Cf: Connectivity matrix of the Branches with the "from" buses
- :param Ct: Connectivity matrix of the Branches with the "to" buses
- :return: dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm
- """
- Yfc = np.conj(Yf)
- Ytc = np.conj(Yt)
- Vc = np.conj(V)
- Ifc = Yfc * Vc # conjugate of "from" current
- Itc = Ytc * Vc # conjugate of "to" current
-
- diagIfc = diags(Ifc)
- diagItc = diags(Itc)
- Vf = V[F]
- Vt = V[T]
- diagVf = diags(Vf)
- diagVt = diags(Vt)
- diagVc = diags(Vc)
-
- Vnorm = V / np.abs(V)
- diagVnorm = diags(Vnorm)
- diagV = diags(V)
-
- CVf = Cf * diagV
- CVt = Ct * diagV
- CVnf = Cf * diagVnorm
- CVnt = Ct * diagVnorm
-
- dSf_dVa = 1j * (diagIfc * CVf - diagVf * Yfc * diagVc)
- dSf_dVm = diagVf * np.conj(Yf * diagVnorm) + diagIfc * CVnf
- dSt_dVa = 1j * (diagItc * CVt - diagVt * Ytc * diagVc)
- dSt_dVm = diagVt * np.conj(Yt * diagVnorm) + diagItc * CVnt
-
- return dSf_dVa.tocsc(), dSf_dVm.tocsc(), dSt_dVa.tocsc(), dSt_dVm.tocsc()
-
-
-def dSf_dV_matpower(Yf: csc_matrix, V: CxVec, F: IntVec,
- Cf: csc_matrix, Vc: CxVec,
- diagVc: csc_matrix,
- diagE: csc_matrix,
- diagV: csc_matrix) -> Tuple[csc_matrix, csc_matrix]:
- """
- Derivatives of the branch power "from" w.r.t the branch voltage modules and angles
- :param Yf: Admittances matrix of the Branches with the "from" buses
- :param V: Array of voltages
- :param F: Array of branch "from" bus indices
- :param Cf: Connectivity matrix of the Branches with the "from" buses
- :param Vc: array of conjugate voltages
- :param diagVc: diagonal matrix of conjugate voltages
- :param diagE: diagonal matrix of normalized voltages
- :param diagV: diagonal matrix of voltages
- :return: dSf_dVa, dSf_dVm
- """
-
- Yfc = np.conj(Yf)
- Ifc = Yfc * Vc # conjugate of "from" current
-
- diagIfc = diags(Ifc)
- Vf = V[F]
- diagVf = diags(Vf)
-
- CVf = Cf * diagV
- CVnf = Cf * diagE
-
- dSf_dVa = 1j * (diagIfc * CVf - diagVf * Yfc * diagVc)
- dSf_dVm = diagVf * np.conj(Yf * diagE) + diagIfc * CVnf
-
- return dSf_dVa.tocsc(), dSf_dVm.tocsc()
-
-
-def dSt_dV_matpower(Yt, V, T, Ct, Vc, diagVc, diagE, diagV):
- """
- Derivatives of the branch power "to" w.r.t the branch voltage modules and angles
- :param Yt: Admittances matrix of the Branches with the "to" buses
- :param V: Array of voltages
- :param T: Array of branch "to" bus indices
- :param Ct: Connectivity matrix of the Branches with the "to" buses
- :param Vc: array of conjugate voltages
- :param diagVc: diagonal matrix of conjugate voltages
- :param diagE: diagonal matrix of normalized voltages
- :param diagV: diagonal matrix of voltages
- :return: dSf_dVa, dSf_dVm, dSt_dVa, dSt_dVm
- """
- Ytc = np.conj(Yt)
- Itc = Ytc * Vc # conjugate of "to" current
-
- diagItc = diags(Itc)
- Vt = V[T]
- diagVt = diags(Vt)
-
- CVt = Ct * diagV
- CVnt = Ct * diagE
-
- dSt_dVa = 1j * (diagItc * CVt - diagVt * Ytc * diagVc)
- dSt_dVm = diagVt * np.conj(Yt * diagE) + diagItc * CVnt
-
- return dSt_dVa.tocsc(), dSt_dVm.tocsc()
-
-
-# ----------------------------------------------------------------------------------------------------------------------
-
-
-@nb.jit(cache=True, nopython=True)
-def map_coordinates_numba(nrows, ncols, indptr, indices, F, T):
- """
-
- :param nrows:
- :param ncols:
- :param indptr:
- :param indices:
- :param F:
- :param T:
- :return:
- """
- idx_f = np.zeros(nrows, dtype=nb.int32)
- idx_t = np.zeros(nrows, dtype=nb.int32)
- for j in range(ncols): # para cada columna j ...
- for k in range(indptr[j], indptr[j + 1]): # para cada entrada de la columna ....
- i = indices[k] # obtener el Ćndice de la fila
-
- if j == F[i]:
- idx_f[i] = k
- elif j == T[i]:
- idx_t[i] = k
-
- return idx_f, idx_t
-
-
-@nb.jit(cache=True, nopython=True)
-def dSf_dV_numba(Yf_nrows, Yf_nnz, Yf_data, V, F, T, idx_f, idx_t):
- """
-
- :param Yf_nrows:
- :param Yf_nnz:
- :param Yf_data:
- :param V:
- :param F:
- :param T:
- :param idx_f:
- :param idx_t:
- :return:
- """
- dSf_dVm = np.zeros(Yf_nnz, dtype=nb.complex128)
- dSf_dVa = np.zeros(Yf_nnz, dtype=nb.complex128)
- for k in range(Yf_nrows): # number of Branches (rows), actually k is the branch index
- f = F[k]
- t = T[k]
- kf = idx_f[k]
- kt = idx_t[k]
-
- Vm_f = np.abs(V[f])
- Vm_t = np.abs(V[t])
- th_f = np.angle(V[f])
- th_t = np.angle(V[t])
- ea = np.exp((th_f - th_t) * 1j)
-
- dSf_dVm[kf] = 2 * Vm_f * np.conj(Yf_data[kf]) + Vm_t * np.conj(Yf_data[kt]) * ea
- dSf_dVm[kt] = Vm_f * np.conj(Yf_data[kt]) * ea
- dSf_dVa[kf] = Vm_f * Vm_t * np.conj(Yf_data[kt]) * ea * 1j
- dSf_dVa[kt] = -dSf_dVa[kf]
-
- return dSf_dVm, dSf_dVa
-
-
-@nb.jit(cache=True, nopython=True)
-def dSt_dV_numba(Yt_nrows, Yt_nnz, Yt_data, V, F, T, idx_f, idx_t):
- """
-
- :param Yt_nrows:
- :param Yt_nnz:
- :param Yt_data:
- :param V:
- :param F:
- :param T:
- :param idx_f:
- :param idx_t:
- :return:
- """
- dSt_dVm = np.zeros(Yt_nnz, dtype=nb.complex128)
- dSt_dVa = np.zeros(Yt_nnz, dtype=nb.complex128)
- for k in range(Yt_nrows): # number of Branches (rows), actually k is the branch index
- f = F[k]
- t = T[k]
- kf = idx_f[k]
- kt = idx_t[k]
-
- Vm_f = np.abs(V[f])
- Vm_t = np.abs(V[t])
- th_f = np.angle(V[f])
- th_t = np.angle(V[t])
- ea = np.exp((th_t - th_f) * 1j)
-
- dSt_dVm[kf] = Vm_t * np.conj(Yt_data[kf]) * ea
- dSt_dVm[kt] = 2 * Vm_t * np.conj(Yt_data[kt]) + Vm_f * np.conj(Yt_data[kf]) * ea
- dSt_dVa[kf] = - Vm_f * Vm_t * np.conj(Yt_data[kf]) * ea * 1j
- dSt_dVa[kt] = - dSt_dVa[kf]
-
- return dSt_dVm, dSt_dVa
-
-
-def dSf_dV_csc(Yf, V, F, T):
- """
- Flow "from" derivative w.r.t the voltage
- :param Yf:
- :param V:
- :param F:
- :param T:
- :return:
- """
- # map the i, j coordinates
- idx_f, idx_t = map_coordinates_numba(nrows=Yf.shape[0],
- ncols=Yf.shape[1],
- indptr=Yf.indptr,
- indices=Yf.indices,
- F=F,
- T=T)
-
- dSf_dVm_data, dSf_dVa_data = dSf_dV_numba(Yf_nrows=Yf.shape[0],
- Yf_nnz=Yf.nnz,
- Yf_data=Yf.data,
- V=V,
- F=F,
- T=T,
- idx_f=idx_f,
- idx_t=idx_t)
-
- return (csc_matrix((dSf_dVm_data, Yf.indices, Yf.indptr), shape=Yf.shape),
- csc_matrix((dSf_dVa_data, Yf.indices, Yf.indptr), shape=Yf.shape))
-
-
-def dSt_dV_csc(Yt, V, F, T):
- """
- Flow "to" derivative w.r.t the voltage
- :param Yt:
- :param V:
- :param F:
- :param T:
- :return:
- """
-
- # map the i, j coordinates
- idx_f, idx_t = map_coordinates_numba(nrows=Yt.shape[0],
- ncols=Yt.shape[1],
- indptr=Yt.indptr,
- indices=Yt.indices,
- F=F,
- T=T)
-
- dSt_dVm_data, dSt_dVa_data = dSt_dV_numba(Yt_nrows=Yt.shape[0],
- Yt_nnz=Yt.nnz,
- Yt_data=Yt.data,
- V=V,
- F=F,
- T=T,
- idx_f=idx_f,
- idx_t=idx_t)
-
- return (csc_matrix((dSt_dVm_data, Yt.indices, Yt.indptr), shape=Yt.shape),
- csc_matrix((dSt_dVa_data, Yt.indices, Yt.indptr), shape=Yt.shape))
-
-
-# ----------------------------------------------------------------------------------------------------------------------
-
-def derivatives_sh(nb, nl, iPxsh, F, T, Ys, k2, tap, V):
- """
- This function computes the derivatives of Sbus, Sf and St w.r.t. Ęsh
- - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
- - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
-
- :param nb: number of buses
- :param nl: number of Branches
- :param iPxsh: array of indices {iPfsh or iPfdp}, this is the indices of the phase shifting Branches
- :param F: Array of branch "from" bus indices
- :param T: Array of branch "to" bus indices
- :param Ys: Array of branch series admittances
- :param k2: Array of "k2" parameters
- :param tap: Array of branch complex taps (ma * exp(1j * theta_sh)
- :param V: Array of complex voltages
- :return:
- - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
- - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
- """
- dSbus_dPxsh = lil_matrix((nb, len(iPxsh)), dtype=complex)
- dSf_dshx2 = lil_matrix((nl, len(iPxsh)), dtype=complex)
- dSt_dshx2 = lil_matrix((nl, len(iPxsh)), dtype=complex)
-
- for k, idx in enumerate(iPxsh):
- f = F[idx]
- t = T[idx]
-
- # Partials of Ytt, Yff, Yft and Ytf w.r.t. Ę shift
- ytt_dsh = 0.0
- yff_dsh = 0.0
- yft_dsh = -Ys[idx] / (-1j * k2[idx] * np.conj(tap[idx]))
- ytf_dsh = -Ys[idx] / (1j * k2[idx] * tap[idx])
-
- # Partials of S w.r.t. Ę shift
- val_f = V[f] * np.conj(yft_dsh * V[t])
- val_t = V[t] * np.conj(ytf_dsh * V[f])
-
- dSbus_dPxsh[f, k] = val_f
- dSbus_dPxsh[t, k] = val_t
-
- # Partials of Sf w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "from" bus)
- dSf_dshx2[idx, k] = val_f
-
- # Partials of St w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "to" bus)
- dSt_dshx2[idx, k] = val_t
-
- return dSbus_dPxsh.tocsc(), dSf_dshx2.tocsc(), dSt_dshx2.tocsc()
-
-
-@nb.njit(cache=True)
-def derivatives_tau_csc_numba(iPxsh, F: IntVec, T: IntVec, Ys: CxVec, k2, tap, V):
- """
- This function computes the derivatives of Sbus, Sf and St w.r.t. the tap angle (tau)
- - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
- - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
-
- :param iPxsh: array of indices {iPfsh or iPfdp}
- :param F: Array of branch "from" bus indices
- :param T: Array of branch "to" bus indices
- :param Ys: Array of branch series admittances
- :param k2: Array of "k2" parameters
- :param tap: Array of branch complex taps (m * exp(1j * tau)
- :param V: Array of complex voltages
- :return:
- - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
- - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
- """
- ndev = len(iPxsh)
-
- # dSbus_dPxsh = lil_matrix((nb, ndev), dtype=complex)
- dSbus_dsh_data = np.empty(ndev * 2, dtype=np.complex128)
- dSbus_dsh_indices = np.empty(ndev * 2, dtype=np.int32)
- dSbus_dsh_indptr = np.empty(ndev + 1, dtype=np.int32)
-
- # dSf_dsh = lil_matrix((nl, ndev), dtype=complex)
- dSf_dsh_data = np.empty(ndev, dtype=np.complex128)
- dSf_dsh_indices = np.empty(ndev, dtype=np.int32)
- dSf_dsh_indptr = np.empty(ndev + 1, dtype=np.int32)
-
- # dSt_dsh = lil_matrix((nl, ndev), dtype=complex)
- dSt_dsh_data = np.empty(ndev, dtype=np.complex128)
- dSt_dsh_indices = np.empty(ndev, dtype=np.int32)
- dSt_dsh_indptr = np.empty(ndev + 1, dtype=np.int32)
-
- for k, idx in enumerate(iPxsh):
- f = F[idx]
- t = T[idx]
-
- # Partials of Ytt, Yff, Yft and Ytf w.r.t. Ę shift
- yft_dsh = -Ys[idx] / (-1j * k2[idx] * np.conj(tap[idx]))
- ytf_dsh = -Ys[idx] / (1j * k2[idx] * tap[idx])
-
- # Partials of S w.r.t. Ę shift
- val_f = V[f] * np.conj(yft_dsh * V[t])
- val_t = V[t] * np.conj(ytf_dsh * V[f])
-
- # dSbus_dPxsh[f, k] = val_f
- # dSbus_dPxsh[t, k] = val_t
- dSbus_dsh_data[2 * k] = val_f
- dSbus_dsh_data[2 * k + 1] = val_t
- dSbus_dsh_indices[2 * k] = f
- dSbus_dsh_indices[2 * k + 1] = t
- dSbus_dsh_indptr[k] = 2 * k
-
- # Partials of Sf w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "from" bus)
- # dSf_dshx2[idx, k] = val_f
- dSf_dsh_data[k] = val_f
- dSf_dsh_indices[k] = idx
- dSf_dsh_indptr[k] = k
-
- # Partials of St w.r.t. Ę shift (makes sense that this is āSbus/āPxsh assigned to the "to" bus)
- # dSt_dshx2[idx, k] = val_t
- dSt_dsh_data[k] = val_t
- dSt_dsh_indices[k] = idx
- dSt_dsh_indptr[k] = k
-
- dSbus_dsh_indptr[ndev] = ndev * 2
- dSf_dsh_indptr[ndev] = ndev
- dSt_dsh_indptr[ndev] = ndev
-
- return (dSbus_dsh_data, dSbus_dsh_indices, dSbus_dsh_indptr,
- dSf_dsh_data, dSf_dsh_indices, dSf_dsh_indptr,
- dSt_dsh_data, dSt_dsh_indices, dSt_dsh_indptr)
-
-
-def derivatives_sh_csc_fast(nb, nl, iPxsh, F, T, Ys, k2, tap, V):
- """
- This function computes the derivatives of Sbus, Sf and St w.r.t. Ęsh
- - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
- - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
-
- :param nb: number of buses
- :param nl: number of Branches
- :param iPxsh: array of indices {iPfsh or iPfdp}
- :param F: Array of branch "from" bus indices
- :param T: Array of branch "to" bus indices
- :param Ys: Array of branch series admittances
- :param k2: Array of "k2" parameters
- :param tap: Array of branch complex taps (ma * exp(1j * theta_sh)
- :param V: Array of complex voltages
- :return:
- - dSbus_dPfsh, dSf_dPfsh, dSt_dPfsh -> if iPxsh=iPfsh
- - dSbus_dPfdp, dSf_dPfdp, dSt_dPfdp -> if iPxsh=iPfdp
- """
- ndev = len(iPxsh)
-
- (dSbus_dsh_data, dSbus_dsh_indices, dSbus_dsh_indptr,
- dSf_dsh_data, dSf_dsh_indices, dSf_dsh_indptr,
- dSt_dsh_data, dSt_dsh_indices, dSt_dsh_indptr) = derivatives_tau_csc_numba(iPxsh, F, T, Ys, k2, tap, V)
-
- dSbus_dsh = sp.csc_matrix((dSbus_dsh_data, dSbus_dsh_indices, dSbus_dsh_indptr), shape=(nb, ndev))
- dSf_dsh = sp.csc_matrix((dSf_dsh_data, dSf_dsh_indices, dSf_dsh_indptr), shape=(nl, ndev))
- dSt_dsh = sp.csc_matrix((dSt_dsh_data, dSt_dsh_indices, dSt_dsh_indptr), shape=(nl, ndev))
-
- return dSbus_dsh, dSf_dsh, dSt_dsh
-
-
-def derivatives_ma(nb, nl, iXxma, F, T, Ys, k2, tap, ma, Bc, Beq, V):
- """
- Useful for the calculation of
- - dSbus_dQfma, dSf_dQfma, dSt_dQfma -> wih iXxma=iQfma
- - dSbus_dQtma, dSf_dQtma, dSt_dQtma -> wih iXxma=iQtma
- - dSbus_dVtma, dSf_dVtma, dSt_dVtma -> wih iXxma=iVtma
-
- :param nb: Number of buses
- :param nl: Number of Branches
- :param iXxma: Array of indices {iQfma, iQtma, iVtma}
- :param F: Array of branch "from" bus indices
- :param T: Array of branch "to" bus indices
- :param Ys: Array of branch series admittances
- :param k2: Array of "k2" parameters
- :param tap: Array of branch complex taps (ma * exp(1j * theta_sh)
- :param ma: Array of tap modules (this is to avoid extra calculations)
- :param Bc: Array of branch total shunt susceptance values (sum of the two legs)
- :param Beq: Array of regulation susceptance of the FUBM model
- :param V:Array of complex voltages
-
- :return:
- - dSbus_dQfma, dSf_dQfma, dSt_dQfma -> if iXxma=iQfma
- - dSbus_dQtma, dSf_dQtma, dSt_dQtma -> if iXxma=iQtma
- - dSbus_dVtma, dSf_dVtma, dSt_dVtma -> if iXxma=iVtma
- """
- # Declare the derivative
- dSbus_dmax2 = lil_matrix((nb, len(iXxma)), dtype=complex)
- dSf_dmax2 = lil_matrix((nl, len(iXxma)), dtype=complex)
- dSt_dmax2 = lil_matrix((nl, len(iXxma)), dtype=complex)
-
- for k, idx in enumerate(iXxma):
- f = F[idx]
- t = T[idx]
-
- YttB = Ys[idx] + 1j * Bc[idx] / 2 + 1j * Beq[idx]
-
- # Partials of Ytt, Yff, Yft and Ytf w.r.t.ma
- dyff_dma = -2 * YttB / (np.power(k2[idx], 2) * np.power(ma[idx], 3))
- dyft_dma = Ys[idx] / (k2[idx] * ma[idx] * np.conj(tap[idx]))
- dytf_dma = Ys[idx] / (k2[idx] * ma[idx] * tap[idx])
- dytt_dma = 0
-
- # Partials of S w.r.t.ma
- val_f = V[f] * np.conj(dyff_dma * V[f] + dyft_dma * V[t])
- val_t = V[t] * np.conj(dytf_dma * V[f] + dytt_dma * V[t])
- dSbus_dmax2[f, k] = val_f
- dSbus_dmax2[t, k] = val_t
-
- dSf_dmax2[idx, k] = val_f
- dSt_dmax2[idx, k] = val_t
-
- return dSbus_dmax2.tocsc(), dSf_dmax2.tocsc(), dSt_dmax2.tocsc()
-
-
-@nb.njit(cache=True)
-def derivatives_ma_csc_numba(iXxma, F, T, Ys, k2, tap, ma, Bc, Beq, V):
- """
- Useful for the calculation of
- - dSbus_dQfma, dSf_dQfma, dSt_dQfma -> wih iXxma=iQfma
- - dSbus_dQtma, dSf_dQtma, dSt_dQtma -> wih iXxma=iQtma
- - dSbus_dVtma, dSf_dVtma, dSt_dVtma -> wih iXxma=iVtma
-
- :param iXxma: Array of indices {iQfma, iQtma, iVtma}
- :param F: Array of branch "from" bus indices
- :param T: Array of branch "to" bus indices
- :param Ys: Array of branch series admittances
- :param k2: Array of "k2" parameters
- :param tap: Array of branch complex taps (ma * exp(1j * theta_sh)
- :param ma: Array of tap modules (this is to avoid extra calculations)
- :param Bc: Array of branch total shunt susceptance values (sum of the two legs)
- :param Beq: Array of regulation susceptance of the FUBM model
- :param V:Array of complex voltages
-
- :return:
- - dSbus_dQfma, dSf_dQfma, dSt_dQfma -> if iXxma=iQfma
- - dSbus_dQtma, dSf_dQtma, dSt_dQtma -> if iXxma=iQtma
- - dSbus_dVtma, dSf_dVtma, dSt_dVtma -> if iXxma=iVtma
- """
- # Declare the derivative
- ndev = len(iXxma)
- ndev2 = ndev * 2
-
- # dSbus_dma = lil_matrix((nb, ndev), dtype=complex)
- dSbus_dma_data = np.empty(ndev2, dtype=np.complex128)
- dSbus_dma_indices = np.empty(ndev2, dtype=np.int32)
- dSbus_dma_indptr = np.empty(ndev + 1, dtype=np.int32)
-
- # dSf_dma = lil_matrix((nl, ndev), dtype=complex)
- dSf_dma_data = np.empty(ndev, dtype=np.complex128)
- dSf_dma_indices = np.empty(ndev, dtype=np.int32)
- dSf_dma_indptr = np.empty(ndev + 1, dtype=np.int32)
-
- # dSt_dma = lil_matrix((nl, ndev), dtype=complex)
- dSt_dma_data = np.empty(ndev, dtype=np.complex128)
- dSt_dma_indices = np.empty(ndev, dtype=np.int32)
- dSt_dma_indptr = np.empty(ndev + 1, dtype=np.int32)
-
- for k, idx in enumerate(iXxma):
- f = F[idx]
- t = T[idx]
-
- YttB = Ys[idx] + 1j * (Bc[idx] / 2 + Beq[idx])
-
- # Partials of Ytt, Yff, Yft and Ytf w.r.t.ma
- dyff_dma = -2 * YttB / (np.power(k2[idx], 2) * np.power(ma[idx], 3))
- dyft_dma = Ys[idx] / (k2[idx] * ma[idx] * np.conj(tap[idx]))
- dytf_dma = Ys[idx] / (k2[idx] * ma[idx] * tap[idx])
-
- val_f = V[f] * np.conj(dyff_dma * V[f] + dyft_dma * V[t])
- val_t = V[t] * np.conj(dytf_dma * V[f])
-
- # Partials of S w.r.t.ma
- # dSbus_dma[f, k] = val_f
- # dSbus_dma[t, k] = val_t
- dSbus_dma_data[2 * k] = val_f
- dSbus_dma_indices[2 * k] = f
- dSbus_dma_data[2 * k + 1] = val_t
- dSbus_dma_indices[2 * k + 1] = t
- dSbus_dma_indptr[k] = 2 * k
-
- # dSf_dma[idx, k] = val_f
- dSf_dma_data[k] = val_f
- dSf_dma_indices[k] = idx
- dSf_dma_indptr[k] = k
-
- # dSt_dma[idx, k] = val_f
- dSt_dma_data[k] = val_t
- dSt_dma_indices[k] = idx
- dSt_dma_indptr[k] = k
-
- dSbus_dma_indptr[ndev] = ndev * 2
- dSf_dma_indptr[ndev] = ndev
- dSt_dma_indptr[ndev] = ndev
-
- return (dSbus_dma_data, dSbus_dma_indices, dSbus_dma_indptr,
- dSf_dma_data, dSf_dma_indices, dSf_dma_indptr,
- dSt_dma_data, dSt_dma_indices, dSt_dma_indptr)
-
-
-def derivatives_ma_csc_fast(nb, nl, iXxma, F, T, Ys, k2, tap, ma, Bc, Beq, V):
- """
- Useful for the calculation of
- - dSbus_dQfma, dSf_dQfma, dSt_dQfma -> wih iXxma=iQfma
- - dSbus_dQtma, dSf_dQtma, dSt_dQtma -> wih iXxma=iQtma
- - dSbus_dVtma, dSf_dVtma, dSt_dVtma -> wih iXxma=iVtma
-
- :param nb: Number of buses
- :param nl: Number of Branches
- :param iXxma: Array of indices {iQfma, iQtma, iVtma}
- :param F: Array of branch "from" bus indices
- :param T: Array of branch "to" bus indices
- :param Ys: Array of branch series admittances
- :param k2: Array of "k2" parameters
- :param tap: Array of branch complex taps (ma * exp(1j * theta_sh)
- :param ma: Array of tap modules (this is to avoid extra calculations)
- :param Bc: Array of branch total shunt susceptance values (sum of the two legs)
- :param Beq: Array of regulation susceptance of the FUBM model
- :param V:Array of complex voltages
-
- :return:
- - dSbus_dQfma, dSf_dQfma, dSt_dQfma -> if iXxma=iQfma
- - dSbus_dQtma, dSf_dQtma, dSt_dQtma -> if iXxma=iQtma
- - dSbus_dVtma, dSf_dVtma, dSt_dVtma -> if iXxma=iVtma
- """
- # Declare the derivative
- ndev = len(iXxma)
-
- (dSbus_dma_data, dSbus_dma_indices, dSbus_dma_indptr,
- dSf_dma_data, dSf_dma_indices, dSf_dma_indptr,
- dSt_dma_data, dSt_dma_indices, dSt_dma_indptr) = derivatives_ma_csc_numba(iXxma, F, T, Ys, k2, tap, ma, Bc, Beq, V)
-
- dSbus_dma = sp.csc_matrix((dSbus_dma_data, dSbus_dma_indices, dSbus_dma_indptr), shape=(nb, ndev))
- dSf_dma = sp.csc_matrix((dSf_dma_data, dSf_dma_indices, dSf_dma_indptr), shape=(nl, ndev))
- dSt_dma = sp.csc_matrix((dSt_dma_data, dSt_dma_indices, dSt_dma_indptr), shape=(nl, ndev))
-
- return dSbus_dma, dSf_dma, dSt_dma
-
-
-def derivatives_Beq(nb, nl, iBeqx, F, T, V, ma, k2):
- """
- Compute the derivatives of:
- - dSbus_dBeqz, dSf_dBeqz, dSt_dBeqz -> iBeqx=iBeqz
- - dSbus_dBeqv, dSf_dBeqv, dSt_dBeqv -> iBeqx=iBeqv
-
- :param nb: Number of buses
- :param nl: Number of Branches
- :param iBeqx: array of indices {iBeqz, iBeqv}
- :param F: Array of branch "from" bus indices
- :param T: Array of branch "to" bus indices
- :param V:Array of complex voltages
- :param ma: Array of branch taps modules
- :param k2: Array of "k2" parameters
-
- :return:
- - dSbus_dBeqz, dSf_dBeqz, dSt_dBeqz -> if iBeqx=iBeqz
- - dSbus_dBeqv, dSf_dBeqv, dSt_dBeqv -> if iBeqx=iBeqv
- """
- # Declare the derivative
- dSbus_dBeqx = lil_matrix((nb, len(iBeqx)), dtype=complex)
- dSf_dBeqx = lil_matrix((nl, len(iBeqx)), dtype=complex)
- dSt_dBeqx = lil_matrix((nl, len(iBeqx)), dtype=complex)
-
- for k, idx in enumerate(iBeqx):
- f = F[idx]
- t = T[idx]
-
- # Partials of Ytt, Yff, Yft and Ytf w.r.t.Beq
- dyff_dBeq = 1j / np.power(k2[idx] * ma[idx], 2.0)
- dyft_dBeq = 0
- dytf_dBeq = 0
- dytt_dBeq = 0
-
- # Partials of S w.r.t.Beq
- val_f = V[f] * np.conj(dyff_dBeq * V[f] + dyft_dBeq * V[t])
- val_t = V[t] * np.conj(dytf_dBeq * V[f] + dytt_dBeq * V[t]) # 0
-
- dSbus_dBeqx[f, k] = val_f
- dSbus_dBeqx[t, k] = val_t
-
- # Partials of Sf w.r.t.Beq
- dSf_dBeqx[idx, k] = val_f
-
- # Partials of St w.r.t.Beq
- dSt_dBeqx[idx, k] = val_t
-
- return dSbus_dBeqx.tocsc(), dSf_dBeqx.tocsc(), dSt_dBeqx.tocsc()
-
-
-@nb.njit(cache=True)
-def derivatives_Beq_csc_numba(iBeqx, F, V, ma, k2):
- """
- Compute the derivatives of:
- - dSbus_dBeqz, dSf_dBeqz, dSt_dBeqz -> iBeqx=iBeqz
- - dSbus_dBeqv, dSf_dBeqv, dSt_dBeqv -> iBeqx=iBeqv
-
- :param iBeqx: array of indices {iBeqz, iBeqv}
- :param F: Array of branch "from" bus indices
- :param V:Array of complex voltages
- :param ma: Array of branch taps modules
- :param k2: Array of "k2" parameters
-
- :return:
- - dSbus_dBeqz, dSf_dBeqz, dSt_dBeqz -> if iBeqx=iBeqz
- - dSbus_dBeqv, dSf_dBeqv, dSt_dBeqv -> if iBeqx=iBeqv
- """
-
- ndev = len(iBeqx)
-
- dSbus_dBeq_data = np.empty(ndev, dtype=np.complex128)
- dSbus_dBeq_indices = np.empty(ndev, dtype=np.int32)
- dSbus_dBeq_indptr = np.empty(ndev + 1, dtype=np.int32)
-
- dSf_dBeqx_data = np.empty(ndev, dtype=np.complex128)
- dSf_dBeqx_indices = np.empty(ndev, dtype=np.int32)
- dSf_dBeqx_indptr = np.empty(ndev + 1, dtype=np.int32)
-
- for k, idx in enumerate(iBeqx):
- # k: 0, 1, 2, 3, 4, ...
- # idx: actual branch index in the general Branches schema
-
- f = F[idx]
-
- # Partials of Ytt, Yff, Yft and Ytf w.r.t.Beq
- dyff_dBeq = 1j / np.power(k2[idx] * ma[idx], 2.0)
-
- # Partials of S w.r.t.Beq
- val_f = V[f] * np.conj(dyff_dBeq * V[f])
-
- # dSbus_dBeqx[f, k] = val_f
- dSbus_dBeq_data[k] = val_f
- dSbus_dBeq_indices[k] = f
- dSbus_dBeq_indptr[k] = k
-
- # dSbus_dBeqx[t, k] = val_t
- # (no need to store this one)
-
- # Partials of Sf w.r.t.Beq
- # dSf_dBeqx[idx, k] = val_f
- dSf_dBeqx_data[k] = val_f
- dSf_dBeqx_indices[k] = idx
- dSf_dBeqx_indptr[k] = k
-
- # Partials of St w.r.t.Beq
- # dSt_dBeqx[idx, k] = val_t
- # (no need to store this one)
-
- dSbus_dBeq_indptr[ndev] = ndev
- dSf_dBeqx_indptr[ndev] = ndev
-
- return dSbus_dBeq_data, dSbus_dBeq_indices, dSbus_dBeq_indptr, dSf_dBeqx_data, dSf_dBeqx_indices, dSf_dBeqx_indptr
-
-
-def derivatives_Beq_csc_fast(nb, nl, iBeqx, F, T, V, ma, k2):
- """
- Compute the derivatives of:
- - dSbus_dBeqz, dSf_dBeqz, dSt_dBeqz -> iBeqx=iBeqz
- - dSbus_dBeqv, dSf_dBeqv, dSt_dBeqv -> iBeqx=iBeqv
-
- :param nb: Number of buses
- :param nl: Number of Branches
- :param iBeqx: array of indices {iBeqz, iBeqv}
- :param F: Array of branch "from" bus indices
- :param T: Array of branch "to" bus indices
- :param V:Array of complex voltages
- :param ma: Array of branch taps modules
- :param k2: Array of "k2" parameters
-
- :return:
- - dSbus_dBeqz, dSf_dBeqz, dSt_dBeqz -> if iBeqx=iBeqz
- - dSbus_dBeqv, dSf_dBeqv, dSt_dBeqv -> if iBeqx=iBeqv
- """
-
- ndev = len(iBeqx)
-
- (dSbus_dBeq_data, dSbus_dBeq_indices, dSbus_dBeq_indptr,
- dSf_dBeqx_data, dSf_dBeqx_indices, dSf_dBeqx_indptr) = derivatives_Beq_csc_numba(iBeqx, F, V, ma, k2)
-
- dSbus_dBeqx = sp.csc_matrix((dSbus_dBeq_data, dSbus_dBeq_indices, dSbus_dBeq_indptr), shape=(nb, ndev))
- dSf_dBeqx = sp.csc_matrix((dSf_dBeqx_data, dSf_dBeqx_indices, dSf_dBeqx_indptr), shape=(nl, ndev))
- dSt_dBeqx = sp.csc_matrix((nl, ndev), dtype=complex)
-
- return dSbus_dBeqx, dSf_dBeqx, dSt_dBeqx
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/discrete_controls.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/discrete_controls.py
index dbd64a333..824dff792 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/discrete_controls.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/discrete_controls.py
@@ -16,6 +16,7 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import numpy as np
import numba as nb
+from typing import Tuple
from GridCalEngine.enumerations import BusMode
from GridCalEngine.basic_structures import Vec, IntVec, CxVec
@@ -46,172 +47,6 @@ def get_q_increment(V1, V2, k):
return 2 * (1 / (1 + np.exp(-k * np.abs(V2 - V1))) - 0.5)
-def control_q_iterative(V, Vset, Q, Qmax, Qmin, types, original_types, verbose, k):
- """
- Change the buses type in order to control the generators reactive power using
- iterative changes in Q to reach Vset.
-
- Arguments:
-
- **V** (list): array of voltages (all buses)
-
- **Vset** (list): Array of set points (all buses)
-
- **Q** (list): Array of reactive power (all buses)
-
- **Qmin** (list): Array of minimal reactive power (all buses)
-
- **Qmax** (list): Array of maximal reactive power (all buses)
-
- **types** (list): Array of types (all buses)
-
- **original_types** (list): Types as originally intended (all buses)
-
- **verbose** (list): output messages via the console
-
- **k** (float, 30): Steepness factor
-
- Return:
-
- **Qnew** (list): New reactive power values
-
- **types_new** (list): Modified types array
-
- **any_control_issue** (bool): Was there any control issue?
- """
-
- if verbose:
- print('Q control logic (iterative)')
-
- n = len(V)
- Vm = np.abs(V)
- Qnew = Q.copy()
- types_new = types.copy()
- any_control_issue = False
- precision = 4
- inc_prec = int(1.5 * precision)
-
- for i in range(n):
-
- if types[i] == BusMode.Slack_tpe.value:
- pass
-
- elif types[i] == BusMode.PQ_tpe.value and original_types[i] == BusMode.PV_tpe.value:
-
- gain = get_q_increment(Vm[i], abs(Vset[i]), k)
-
- if round(Vm[i], precision) < round(abs(Vset[i]), precision):
- increment = round(abs(Qmax[i] - Q[i]) * gain, inc_prec)
-
- if increment > 0 and Q[i] + increment < Qmax[i]:
- # I can push more VAr, so let's do so
- Qnew[i] = Q[i] + increment
- if verbose:
- print("Bus {} gain = {} (V = {}, Vset = {})".format(i,
- round(gain, precision),
- round(Vm[i], precision),
- abs(Vset[i])))
- print("Bus {} increment = {} (Q = {}, Qmax = {})".format(i,
- round(increment, inc_prec),
- round(Q[i], precision),
- round(abs(Qmax[i]), precision),
- ))
- print("Bus {} raising its Q from {} to {} (V = {}, Vset = {})".format(i,
- round(Q[i], precision),
- round(Qnew[i], precision),
- round(Vm[i], precision),
- abs(Vset[i]),
- ))
- any_control_issue = True
-
- else:
- if verbose:
- print("Bus {} stable enough (inc = {}, Q = {}, Qmax = {}, V = {}, Vset = {})".format(i,
- round(
- increment,
- inc_prec),
- round(Q[i],
- precision),
- round(abs(
- Qmax[
- i]),
- precision),
- round(
- Vm[i],
- precision),
- abs(Vset[
- i]),
- )
- )
-
- elif round(Vm[i], precision) > round(abs(Vset[i]), precision):
- increment = round(abs(Qmin[i] - Q[i]) * gain, inc_prec)
-
- if increment > 0 and Q[i] - increment > Qmin[i]:
- # I can pull more VAr, so let's do so
- Qnew[i] = Q[i] - increment
- if verbose:
- print("Bus {} increment = {} (Q = {}, Qmin = {})".format(i,
- round(increment, inc_prec),
- round(Q[i], precision),
- round(abs(Qmin[i]), precision),
- )
- )
- print("Bus {} gain = {} (V = {}, Vset = {})".format(i,
- round(gain, precision),
- round(Vm[i], precision),
- abs(Vset[i]),
- )
- )
- print("Bus {} lowering its Q from {} to {} (V = {}, Vset = {})".format(i,
- round(Q[i], precision),
- round(Qnew[i],
- precision),
- round(Vm[i], precision),
- abs(Vset[i]),
- )
- )
- any_control_issue = True
-
- else:
- if verbose:
- print("Bus {} stable enough (inc = {}, Q = {}, Qmin = {}, V = {}, Vset = {})".format(i,
- round(
- increment,
- inc_prec),
- round(Q[i],
- precision),
- round(abs(
- Qmin[
- i]),
- precision),
- round(
- Vm[i],
- precision),
- abs(Vset[
- i]),
- )
- )
-
- else:
- if verbose:
- print("Bus {} stable (V = {}, Vset = {})".format(i,
- round(Vm[i], precision),
- abs(Vset[i]),
- )
- )
-
- elif types[i] == BusMode.PV_tpe.value:
- # If it's still in PV mode (first run), change it to PQ mode
- types_new[i] = BusMode.PQ_tpe.value
- Qnew[i] = 0
- if verbose:
- print("Bus {} switching to PQ control, with a Q of 0".format(i))
- any_control_issue = True
-
- return Qnew, types_new, any_control_issue
-
-
def control_q_direct(V, Vm, Vset, Q, Qmax, Qmin, types, original_types, verbose=False):
"""
Change the buses type in order to control the generators reactive power.
@@ -354,7 +189,9 @@ def control_q_direct(V, Vm, Vset, Q, Qmax, Qmin, types, original_types, verbose=
@nb.njit(cache=True)
-def control_q_inside_method(Scalc, S0, pv, pq, pqv, p, Qmin, Qmax):
+def control_q_inside_method(Scalc: CxVec, S0: CxVec,
+ pv: IntVec, pq: IntVec, pqv: IntVec, p: IntVec,
+ Qmin: Vec, Qmax: Vec):
"""
Control of reactive power within the numerical method
:param Scalc: Calculated power array (changed inside)
@@ -390,226 +227,23 @@ def control_q_inside_method(Scalc, S0, pv, pq, pqv, p, Qmin, Qmax):
return changed, pv, pq, pqv, p
-def tap_up(tap, max_tap):
+def compute_slack_distribution(Scalc: CxVec, vd: IntVec, bus_installed_power: Vec) -> Tuple[bool, Vec]:
"""
- Go to the next upper tap position
+ Slack distribution logic
+ :param Scalc: Computed power array
+ :param vd: slack indices
+ :param bus_installed_power: Amount of installed power
+ :return: is slack division possible?
"""
- if tap + 1 <= max_tap:
- return tap + 1
- else:
- return tap
+ # Distribute the slack power
+ slack_power = Scalc[vd].real.sum()
+ total_installed_power = bus_installed_power.sum()
-
-def tap_down(tap, min_tap):
- """
- Go to the next upper tap position
- """
- if tap - 1 >= min_tap:
- return tap - 1
+ if total_installed_power > 0.0:
+ delta = slack_power * bus_installed_power / total_installed_power
+ ok = True
else:
- return tap
-
-
-def control_taps_iterative(voltage, T, bus_to_regulated_idx, tap_position, tap_module, min_tap, max_tap,
- tap_inc_reg_up, tap_inc_reg_down, vset, verbose=False):
- """
- Change the taps and compute the continuous tap magnitude.
-
- Arguments:
-
- **voltage** (list): array of bus voltages solution
-
- **T** (list): array of indices of the "to" buses of each branch
+ delta = np.zeros(len(Scalc))
+ ok = False
- **bus_to_regulated_idx** (list): array with the indices of the Branches that regulate the bus "to"
-
- **tap_position** (list): array of branch tap positions
-
- **tap_module** (list): array of branch tap modules
-
- **min_tap** (list): array of minimum tap positions
-
- **max_tap** (list): array of maximum tap positions
-
- **tap_inc_reg_up** (list): array of tap increment when regulating up
-
- **tap_inc_reg_down** (list): array of tap increment when regulating down
-
- **vset** (list): array of set voltages to control
-
- Returns:
-
- **stable** (bool): Is the system stable (i.e.: are controllers stable)?
-
- **tap_magnitude** (list): Tap module at each bus in per unit
-
- **tap_position** (list): Tap position at each bus
- """
-
- stable = True
- for i in bus_to_regulated_idx: # traverse the indices of the Branches that are regulated at the "to" bus
-
- j = T[i] # get the index of the "to" bus of the branch "i"
- v = np.abs(voltage[j])
- if verbose:
- print("Bus", j, "regulated by branch", i, ": U =", round(v, 4), "pu, U_set =", vset[i])
-
- if tap_position[i] > 0:
-
- if vset[i] > v + tap_inc_reg_up[i] / 2:
- if tap_position[i] == min_tap[i]:
- if verbose:
- print("Branch", i, ": Already at lowest tap (", tap_position[i], "), skipping")
- else:
- tap_position[i] = tap_down(tap_position[i], min_tap[i])
- tap_module[i] = 1.0 + tap_position[i] * tap_inc_reg_up[i]
- if verbose:
- print("Branch", i, ": Lowering from tap ", tap_position[i])
- stable = False
-
- elif vset[i] < v - tap_inc_reg_up[i] / 2:
- if tap_position[i] == max_tap[i]:
- if verbose:
- print("Branch", i, ": Already at highest tap (", tap_position[i], "), skipping")
- else:
- tap_position[i] = tap_up(tap_position[i], max_tap[i])
- tap_module[i] = 1.0 + tap_position[i] * tap_inc_reg_up[i]
- if verbose:
- print("Branch", i, ": Raising from tap ", tap_position[i])
- stable = False
-
- elif tap_position[i] < 0:
- if vset[i] > v + tap_inc_reg_down[i] / 2:
- if tap_position[i] == min_tap[i]:
- if verbose:
- print("Branch", i, ": Already at lowest tap (", tap_position[i], "), skipping")
- else:
- tap_position[i] = tap_down(tap_position[i], min_tap[i])
- tap_module[i] = 1.0 + tap_position[i] * tap_inc_reg_down[i]
- if verbose:
- print("Branch", i, ": Lowering from tap", tap_position[i])
- stable = False
-
- elif vset[i] < v - tap_inc_reg_down[i] / 2:
- if tap_position[i] == max_tap[i]:
- print("Branch", i, ": Already at highest tap (", tap_position[i], "), skipping")
- else:
- tap_position[i] = tap_up(tap_position[i], max_tap[i])
- tap_module[i] = 1.0 + tap_position[i] * tap_inc_reg_down[i]
- if verbose:
- print("Branch", i, ": Raising from tap", tap_position[i])
- stable = False
-
- else:
- if vset[i] > v + tap_inc_reg_up[i] / 2:
- if tap_position[i] == min_tap[i]:
- if verbose:
- print("Branch", i, ": Already at lowest tap (", tap_position[i], "), skipping")
- else:
- tap_position[i] = tap_down(tap_position[i], min_tap[i])
- tap_module[i] = 1.0 + tap_position[i] * tap_inc_reg_down[i]
- if verbose:
- print("Branch", i, ": Lowering from tap ", tap_position[i])
- stable = False
-
- elif vset[i] < v - tap_inc_reg_down[i] / 2:
- if tap_position[i] == max_tap[i]:
- if verbose:
- print("Branch", i, ": Already at highest tap (", tap_position[i], "), skipping")
- else:
- tap_position[i] = tap_up(tap_position[i], max_tap[i])
- tap_module[i] = 1.0 + tap_position[i] * tap_inc_reg_up[i]
- if verbose:
- print("Branch", i, ": Raising from tap ", tap_position[i])
- stable = False
-
- return stable, tap_module, tap_position
-
-
-def control_taps_direct(voltage, T, bus_to_regulated_idx, tap_position, tap_module, min_tap, max_tap,
- tap_inc_reg_up, tap_inc_reg_down, vset, tap_index_offset, verbose=False):
- """
- Change the taps and compute the continuous tap magnitude.
-
- Arguments:
-
- **voltage** (list): array of bus voltages solution
-
- **T** (list): array of indices of the "to" buses of each branch
-
- **bus_to_regulated_idx** (list): array with the indices of the Branches
- that regulate the bus "to"
-
- **tap_position** (list): array of branch tap positions
-
- **tap_module** (list): array of branch tap modules
-
- **min_tap** (list): array of minimum tap positions
-
- **max_tap** (list): array of maximum tap positions
-
- **tap_inc_reg_up** (list): array of tap increment when regulating up
-
- **tap_inc_reg_down** (list): array of tap increment when regulating down
-
- **vset** (list): array of set voltages to control
-
- Returns:
-
- **stable** (bool): Is the system stable (i.e.: are controllers stable)?
-
- **tap_magnitude** (list): Tap module at each bus in per unit
-
- **tap_position** (list): Tap position at each bus
- """
- stable = True
-
- # traverse the indices of the Branches that are regulated at the "to" bus
- for k, bus_idx in enumerate(bus_to_regulated_idx):
-
- j = T[bus_idx] # get the index of the "to" bus of the branch "i"
- v = np.abs(voltage[j]) # voltage at to "to" bus
- if verbose:
- print("Bus", j, "regulated by branch", bus_idx, ": U=", round(v, 4), "pu, U_set=", vset[k])
-
- tap_inc = tap_inc_reg_up
- if tap_inc_reg_up.all() != tap_inc_reg_down.all():
- print("Error: tap_inc_reg_up and down are not equal for branch {}".format(bus_idx))
-
- desired_module = v / vset[k] * tap_module[tap_index_offset + k]
- desired_pos = round((desired_module - 1) / tap_inc[k])
-
- if desired_pos == tap_position[k]:
- continue
-
- elif desired_pos > 0 and desired_pos > max_tap[k]:
- if verbose:
- print("Branch {}: Changing from tap {} to {} (module {} to {})".format(bus_idx,
- tap_position[k],
- max_tap[k],
- tap_module[tap_index_offset + k],
- 1 + max_tap[k] * tap_inc[k]))
- tap_position[k] = max_tap[k]
-
- elif desired_pos < 0 and desired_pos < min_tap[k]:
- if verbose:
- print("Branch {}: Changing from tap {} to {} (module {} to {})".format(bus_idx,
- tap_position[k],
- min_tap[k],
- tap_module[tap_index_offset + k],
- 1 + min_tap[k] * tap_inc[k]))
- tap_position[k] = min_tap[k]
-
- else:
- if verbose:
- print("Branch {}: Changing from tap {} to {} (module {} to {})".format(bus_idx,
- tap_position[k],
- desired_pos,
- tap_module[tap_index_offset + k],
- 1 + desired_pos * tap_inc[k]))
- tap_position[k] = desired_pos
-
- tap_module[tap_index_offset + k] = 1 + tap_position[k] * tap_inc[k]
- stable = False
-
- return stable, tap_module, tap_position
+ return ok, delta
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/fast_decoupled.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/fast_decoupled.py
index e8b333f88..dfeef8769 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/fast_decoupled.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/fast_decoupled.py
@@ -1,18 +1,53 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
import numpy as np
-from numpy import angle, conj, exp, r_, Inf
+from numpy import exp, r_, Inf
from numpy.linalg import norm
from scipy.sparse.linalg import splu
import time
import GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions as cf
from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
-from GridCalEngine.enumerations import ReactivePowerControlMode
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import control_q_inside_method
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import (control_q_inside_method,
+ compute_slack_distribution)
+from GridCalEngine.basic_structures import Vec, CxVec, CscMat, IntVec
np.set_printoptions(linewidth=320)
-def FDPF(Vbus, S0, I0, Y0, Ybus, B1, B2, pv_, pq_, pqv_, p_, Qmin, Qmax, tol=1e-9, max_it=100,
- control_q=ReactivePowerControlMode.NoControl, ) -> NumericPowerFlowResults:
+def FDPF(Vbus: CxVec,
+ S0: CxVec,
+ I0: CxVec,
+ Y0: CxVec,
+ Ybus: CscMat,
+ B1: CscMat,
+ B2: CscMat,
+ pv_: IntVec,
+ pq_: IntVec,
+ pqv_: IntVec,
+ p_: IntVec,
+ vd_: IntVec,
+ Qmin: Vec,
+ Qmax: Vec,
+ bus_installed_power: Vec,
+ tol: float = 1e-9,
+ max_it: float = 100,
+ control_q: bool = False,
+ distribute_slack: bool = False) -> NumericPowerFlowResults:
"""
Fast decoupled power flow
:param Vbus: array of initial voltages
@@ -26,11 +61,14 @@ def FDPF(Vbus, S0, I0, Y0, Ybus, B1, B2, pv_, pq_, pqv_, p_, Qmin, Qmax, tol=1e-
:param pq_: Array with the indices of the PQ buses
:param pqv_: Array with the indices of the PQV buses
:param p_: Array with the indices of the P buses
+ :param vd_: Array with the indices of the VD buses
:param Qmin: Minimum voltage
:param Qmax: Maximum voltage
- :param tol: desired tolerance
+ :param tol: Tolerance
+ :param bus_installed_power: Array of installed power per bus
:param max_it: maximum number of iterations
:param control_q: Control Q method
+ :param distribute_slack: Distribute Slack method
:return: NumericPowerFlowResults instance
"""
@@ -118,7 +156,7 @@ def FDPF(Vbus, S0, I0, Y0, Ybus, B1, B2, pv_, pq_, pqv_, p_, Qmin, Qmax, tol=1e-
# it is only worth checking Q limits with a low error
# since with higher errors, the Q values may be far from realistic
# finally, the Q control only makes sense if there are pv nodes
- if control_q != ReactivePowerControlMode.NoControl and normQ < 1e-2 and (len(pv) + len(p)) > 0:
+ if control_q and normQ < 1e-2 and (len(pv) + len(p)) > 0:
# check and adjust the reactive power
# this function passes pv buses to pq when the limits are violated,
@@ -135,6 +173,13 @@ def FDPF(Vbus, S0, I0, Y0, Ybus, B1, B2, pv_, pq_, pqv_, p_, Qmin, Qmax, tol=1e-
B1_factorization = splu(B1[np.ix_(blck1_idx, blck1_idx)])
B2_factorization = splu(B2[np.ix_(blck3_idx, blck2_idx)])
+ if distribute_slack and normQ < 1e-2:
+ ok, delta = compute_slack_distribution(Scalc=Scalc,
+ vd=vd_,
+ bus_installed_power=bus_installed_power)
+ if ok:
+ S0 += delta
+
F = r_[dP, dQ] # concatenate again
normF = norm(F, Inf)
@@ -150,8 +195,8 @@ def FDPF(Vbus, S0, I0, Y0, Ybus, B1, B2, pv_, pq_, pqv_, p_, Qmin, Qmax, tol=1e-
converged=converged,
norm_f=normF,
Scalc=Scalc,
- ma=None,
- theta=None,
+ m=None,
+ tau=None,
Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_,
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/gauss_power_flow.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/gauss_power_flow.py
index 5fb5e6721..742895e78 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/gauss_power_flow.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/gauss_power_flow.py
@@ -15,19 +15,17 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-"""
-Solves the power flow using a Gauss-Seidel method.
-"""
-
import time
import numpy as np
import GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions as cf
from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import (control_q_inside_method,
+ compute_slack_distribution)
from GridCalEngine.basic_structures import Logger
-def gausspf(Ybus, S0, I0, Y0, V0, pv, pq, tol=1e-3, max_it=50,
- verbose=False, logger: Logger = None) -> NumericPowerFlowResults:
+def gausspf(Ybus, S0, I0, Y0, V0, pv, pq, p, pqv, vd, bus_installed_power, Qmin, Qmax, tol=1e-3, max_it=50,
+ control_q=False, distribute_slack=False, verbose=False, logger: Logger = None) -> NumericPowerFlowResults:
"""
Gauss-Seidel Power flow
:param Ybus: Admittance matrix
@@ -37,8 +35,16 @@ def gausspf(Ybus, S0, I0, Y0, V0, pv, pq, tol=1e-3, max_it=50,
:param V0: Voltage seed solution array
:param pv: array of pv-node indices
:param pq: array of pq-node indices
+ :param p: array of p-node indices
+ :param pqv: array of pqv-node indices
+ :param vd: array of vd-node indices
+ :param bus_installed_power: array of bus installed power
+ :param Qmin: Minimum Q limits per bus
+ :param Qmax: Maximum Q limits per bus
:param tol: Tolerance
:param max_it: Maximum number of iterations
+ :param control_q: Control Q limits?
+ :param distribute_slack: Distribute Slack?
:param verbose: Verbose?
:param logger: Logger to store the debug information
:return: NumericPowerFlowResults instance
@@ -54,7 +60,6 @@ def gausspf(Ybus, S0, I0, Y0, V0, pv, pq, tol=1e-3, max_it=50,
# set up indexing for updating V
npv = len(pv)
- npq = len(pq)
pvpq = np.r_[pv, pq]
# evaluate F(x0)
@@ -96,6 +101,35 @@ def gausspf(Ybus, S0, I0, Y0, V0, pv, pq, tol=1e-3, max_it=50,
# check for convergence
converged = normF < tol
+ # control of Q limits --------------------------------------------------------------------------------------
+ # review reactive power limits
+ # it is only worth checking Q limits with a low error
+ # since with higher errors, the Q values may be far from realistic
+ # finally, the Q control only makes sense if there are pv nodes
+ if control_q and normF < 1e-2 and (len(pv) + len(p)) > 0:
+
+ # check and adjust the reactive power
+ # this function passes pv buses to pq when the limits are violated,
+ # but not pq to pv because that is unstable
+ changed, pv, pq, pqv, p = control_q_inside_method(Scalc, S0, pv, pq, pqv, p, Qmin, Qmax)
+
+ if len(changed) > 0:
+ # adjust internal variables to the new pq|pv values
+ F = cf.compute_fx(Scalc, Sbus, pvpq, pq)
+ normF = cf.compute_fx_error(F)
+ converged = normF < tol
+
+ if distribute_slack and normF < 1e-2:
+ ok, delta = compute_slack_distribution(Scalc=Scalc,
+ vd=vd,
+ bus_installed_power=bus_installed_power)
+ if ok:
+ S0 += delta
+ Sbus = cf.compute_zip_power(S0, I0, Y0, Vm)
+ F = cf.compute_fx(Scalc, Sbus, pvpq, pq)
+ normF = cf.compute_fx_error(F)
+ converged = normF < tol
+
if verbose:
logger.add_debug('GS Iteration {0}'.format(iter_) + '-' * 200)
@@ -111,8 +145,7 @@ def gausspf(Ybus, S0, I0, Y0, V0, pv, pq, tol=1e-3, max_it=50,
end = time.time()
elapsed = end - start
- # return NumericPowerFlowResults(V, converged, normF, Scalc, None, None, None, None, None, None, iter_, elapsed)
return NumericPowerFlowResults(V=V, converged=converged, norm_f=normF,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/helm_power_flow.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/helm_power_flow.py
index 16bf282c1..335dabad8 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/helm_power_flow.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/helm_power_flow.py
@@ -262,6 +262,7 @@ def helm_coefficients_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, sl, pqpv, toler
"""
Holomorphic Embedding LoadFlow Method as formulated by Josep Fanals Batllori in 2020
THis function just returns the coefficients for further usage in other routines
+ :param Ybus: Admittance matrix
:param Yseries: Admittance matrix of the series elements
:param V0: vector of specified voltages
:param S0: vector of specified power
@@ -394,9 +395,11 @@ def helm_coefficients_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, sl, pqpv, toler
valor[pq_] = (vec_P[pq_] - vec_Q[pq_] * 1j) * X[c - 1, pq_] - U[c - 1, pq_] * Ysh[pq_]
valor[pv_] = -1j * conv2(X, Q, c, pv_) - U[c - 1, pv_] * Ysh[pv_] + X[c - 1, pv_] * vec_P[pv_]
- RHS = np.r_[valor.real,
- valor.imag,
- -conv3(U, U, c, pv_).real]
+ RHS = np.r_[
+ valor.real,
+ valor.imag,
+ -conv3(U, U, c, pv_).real
+ ]
# LHS = spsolve(MAT, RHS)
LHS = mat_factorized(RHS)
@@ -428,10 +431,30 @@ def helm_coefficients_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, sl, pqpv, toler
class HelmPreparation:
-
+ """
+ HelmPreparation
+ """
def __init__(self, sys_mat_factorization, Uini, Xini, Yslack, Vslack,
vec_P, vec_Q, Ysh, vec_W, pq, pv, pqpv, sl,
npqpv, nbus):
+ """
+
+ :param sys_mat_factorization:
+ :param Uini:
+ :param Xini:
+ :param Yslack:
+ :param Vslack:
+ :param vec_P:
+ :param vec_Q:
+ :param Ysh:
+ :param vec_W:
+ :param pq:
+ :param pv:
+ :param pqpv:
+ :param sl:
+ :param npqpv:
+ :param nbus:
+ """
self.sys_mat_factorization = sys_mat_factorization
self.Uini = Uini
self.Xini = Xini
@@ -644,7 +667,7 @@ def helm_coefficients_dY(dY, sys_mat_factorization, Uini, Xini, Yslack, Ysh, Ybu
return U, V, iter_, norm_f
-def helm_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, sl, pqpv, tolerance=1e-6, max_coefficients=30, use_pade=True,
+def helm_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, vd, no_slack, tolerance=1e-6, max_coefficients=30, use_pade=True,
verbose=False, logger: Logger = None) -> NumericPowerFlowResults:
"""
Holomorphic Embedding LoadFlow Method as formulated by Josep Fanals Batllori in 2020
@@ -655,8 +678,8 @@ def helm_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, sl, pqpv, tolerance=1e-6, ma
:param Ysh0: vector of shunt admittances (including the shunt "legs" of the pi Branches)
:param pq: list of pq nodes
:param pv: list of pv nodes
- :param sl: list of slack nodes
- :param pqpv: sorted list of pq and pv nodes
+ :param vd: list of slack nodes
+ :param no_slack: sorted list of pq and pv nodes
:param tolerance: target error (or tolerance)
:param max_coefficients: maximum number of coefficients
:param use_pade: Use the PadĆØ approximation? otherwise, a simple summation is done
@@ -671,7 +694,7 @@ def helm_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, sl, pqpv, tolerance=1e-6, ma
if n < 2:
# return NumericPowerFlowResults(V0, True, 0.0, S0, None, None, None, None, None, None, 0, 0.0)
return NumericPowerFlowResults(V=V0, converged=True, norm_f=0.0,
- Scalc=S0, ma=None, theta=None, Beq=None,
+ Scalc=S0, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=0, elapsed=0.0)
@@ -683,8 +706,8 @@ def helm_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, sl, pqpv, tolerance=1e-6, ma
Ysh0=Ysh0,
pq=pq,
pv=pv,
- sl=sl,
- pqpv=pqpv,
+ sl=vd,
+ pqpv=no_slack,
tolerance=tolerance,
max_coeff=max_coefficients,
verbose=verbose,
@@ -698,14 +721,14 @@ def helm_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, sl, pqpv, tolerance=1e-6, ma
if use_pade:
V = V0.copy()
try:
- V[pqpv] = pade4all(max_coefficients - 1, U, 1)
+ V[no_slack] = pade4all(max_coefficients - 1, U, 1)
except:
warn('PadĆØ failed :(, using coefficients summation')
- V[pqpv] = U.sum(axis=0)
+ V[no_slack] = U.sum(axis=0)
# compute power mismatch
Scalc = cf.compute_power(Ybus, V)
- norm_f = cf.compute_fx_error(cf.compute_fx(Scalc, S0, pqpv, pq))
+ norm_f = cf.compute_fx_error(cf.compute_fx(Scalc, S0, no_slack, pq))
# check convergence
converged = norm_f < tolerance
@@ -714,6 +737,6 @@ def helm_josep(Ybus, Yseries, V0, S0, Ysh0, pq, pv, sl, pqpv, tolerance=1e-6, ma
# return NumericPowerFlowResults(V, converged, norm_f, Scalc, None, None, None, None, None, None, iter_, elapsed)
return NumericPowerFlowResults(V=V, converged=converged, norm_f=norm_f,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/iwamoto_newton_raphson.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/iwamoto_newton_raphson.py
index 9a52a7a5d..661b23714 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/iwamoto_newton_raphson.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/iwamoto_newton_raphson.py
@@ -20,10 +20,9 @@
import numpy as np
from GridCalEngine.Utils.NumericalMethods.sparse_solve import get_sparse_type, get_linear_solver
from GridCalEngine.Utils.Sparse.csc2 import spsolve_csc
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobianVc, CSC
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobianVc, CSC
import GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions as cf
from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
-from GridCalEngine.enumerations import ReactivePowerControlMode
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import control_q_inside_method
from GridCalEngine.basic_structures import Vec, CxVec, IntVec, Logger
@@ -70,8 +69,7 @@ def mu(Ybus, J: CSC, incS: Vec, dV: CxVec, dx: Vec, block1_idx: IntVec, block2_i
def IwamotoNR(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
- control_q=ReactivePowerControlMode.NoControl, robust=False,
- logger: Logger = None) -> NumericPowerFlowResults:
+ control_q=False, robust=False, logger: Logger = None) -> NumericPowerFlowResults:
"""
Solves the power flow using a full Newton's method with the Iwamoto optimal step factor.
:param Ybus: Admittance matrix
@@ -87,8 +85,9 @@ def IwamotoNR(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=
:param Qmax: Array of nodal maximum reactive power injections
:param tol: Tolerance
:param max_it: Maximum number of iterations
- :param control_q: ReactivePowerControlMode
+ :param control_q: Control reactive power?
:param robust: use of the Iwamoto optimal step factor?.
+ :param logger: Logger
:return: Voltage solution, converged?, error, calculated power Injections
"""
start = time.time()
@@ -133,15 +132,15 @@ def IwamotoNR(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=
# compute update step
try:
- dx = spsolve_csc(J, f)
+ dx, ok = spsolve_csc(J, f)
- if np.isnan(dx).any():
+ if not ok:
end = time.time()
elapsed = end - start
logger.add_error('NR Singular matrix @iter:'.format(iter_))
return NumericPowerFlowResults(V=V0, converged=converged, norm_f=norm_f,
- Scalc=S0, ma=None, theta=None, Beq=None,
+ Scalc=S0, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_, elapsed=elapsed)
@@ -152,7 +151,7 @@ def IwamotoNR(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=
end = time.time()
elapsed = end - start
return NumericPowerFlowResults(V=V, converged=converged, norm_f=norm_f,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_, elapsed=elapsed)
@@ -189,7 +188,7 @@ def IwamotoNR(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=
# it is only worth checking Q limits with a low error
# since with higher errors, the Q values may be far from realistic
# finally, the Q control only makes sense if there are pv nodes
- if control_q != ReactivePowerControlMode.NoControl and norm_f < 1e-2 and (len(pv) + len(p)) > 0:
+ if control_q and norm_f < 1e-2 and (len(pv) + len(p)) > 0:
# check and adjust the reactive power
# this function passes pv buses to pq when the limits are violated,
@@ -225,6 +224,6 @@ def IwamotoNR(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=
# return NumericPowerFlowResults(V, converged, norm_f, Scalc, None, None, None, None, None, None, iter_, elapsed)
return NumericPowerFlowResults(V=V, converged=converged, norm_f=norm_f,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/levenberg_marquadt_fx.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/levenberg_marquadt_fx.py
new file mode 100644
index 000000000..30dd3398a
--- /dev/null
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/levenberg_marquadt_fx.py
@@ -0,0 +1,165 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+import time
+import numpy as np
+import scipy.sparse as sp
+from GridCalEngine.Utils.NumericalMethods.sparse_solve import get_linear_solver
+from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.pf_formulation_template import PfFormulationTemplate
+from GridCalEngine.Utils.Sparse.csc2 import mat_to_scipy
+from GridCalEngine.basic_structures import Logger
+
+linear_solver = get_linear_solver()
+
+
+def levenberg_marquadt_fx(problem: PfFormulationTemplate,
+ tol: float = 1e-6,
+ max_iter: int = 10,
+ trust: float = 1.0,
+ verbose: int = 0,
+ logger: Logger = Logger()) -> NumericPowerFlowResults:
+ """
+ Levenberg-Marquardt to solve:
+
+ min: error(f(x))
+ s.t.
+ f(x) = 0
+
+ From METHODS FOR NON-LINEAR LEAST SQUARES PROBLEMS by K. Madsen, H.B. Nielsen, O. Tingleff
+
+ :param problem: PfFormulationTemplate
+ :param tol: Error tolerance
+ :param max_iter: Maximum number of iterations
+ :param trust: trust amount in the derivative length correctness
+ :param verbose: Display console information
+ :param logger: Logger instance
+ :return: ConvexMethodResult
+ """
+ start = time.time()
+
+ # get the initial point
+ x = problem.var2x()
+
+ if len(x) == 0:
+ # if the lenght of x is zero, means that there's nothing to solve
+ # for instance there might be a single node that is a slack node
+ return problem.get_solution(elapsed=time.time() - start, iterations=0)
+
+ normF = 100000
+ update_jacobian = True
+ converged = False
+ iter_ = 0
+ nu = 2.0
+ lbmda = 0
+ f_prev = 1e9 # very large number
+ # csc_matrix identity
+ H: sp.csc_matrix = sp.csc_matrix((0, 0))
+ Ht: sp.csc_matrix = sp.csc_matrix((0, 0))
+ A: sp.csc_matrix = sp.csc_matrix((0, 0))
+ error_evolution = np.zeros(max_iter + 1)
+
+ error, converged, x, dz = problem.update(x, update_controls=False)
+
+ # save the error evolution
+ error_evolution[iter_] = problem.error
+
+ if verbose > 0:
+ print(f'It {iter_}, error {problem.error}, converged {problem.converged}, x {x}, dx not computed yet')
+
+ if problem.converged:
+ return problem.get_solution(elapsed=time.time() - start, iterations=iter_)
+
+ else:
+
+ while not converged and iter_ < max_iter:
+
+ # update iteration counter
+ iter_ += 1
+
+ if verbose > 0:
+ print('-' * 200)
+ print(f'Iter: {iter_}')
+ print('-' * 200)
+
+ if update_jacobian:
+ H = mat_to_scipy(problem.Jacobian())
+ # system matrix
+ # H1 = H^t
+ Ht = H.T # .tocsr()
+
+ # H2 = H1Ā·H
+ HtH = Ht @ H
+
+ # set first value of lmbda
+ if iter_ == 0:
+ lbmda = 1e-3 * HtH.diagonal().max()
+
+ # compute system matrix A = H^TĀ·H - lambdaĀ·I
+ Idn = sp.diags(np.ones(H.shape[0]))
+ A = (HtH + lbmda * Idn).tocsc()
+
+ # right-hand side
+ # H^tĀ·dz
+ rhs = Ht @ dz
+
+ # compute update step
+ try:
+
+ # Solve the increment
+ dx = linear_solver(A, rhs)
+
+ except RuntimeError:
+ logger.add_error(f"Levenberg-Marquardt's system matrix is singular @iter {iter_}:")
+ return problem.get_solution(elapsed=time.time() - start, iterations=iter_)
+
+ if verbose > 1:
+ import pandas as pd
+ print("H:\n", pd.DataFrame(H.toarray()).to_string(index=False))
+ print("g:\n", rhs)
+ print("h:\n", dx)
+
+ # objective function to minimize
+ f = 0.5 * dz @ dz
+
+ # decision function
+ dL = 0.5 * dx @ (lbmda * dx + rhs)
+ dF = f_prev - f
+ if (dL > 0.0) and (dF > 0.0):
+ update_jacobian = True
+ rho = dF / dL
+ lbmda *= max([1.0 / 3.0, 1 - (2 * rho - 1) ** 3])
+ nu = 2.0
+
+ # update x
+ x -= dx
+ error, converged, x, dz = problem.update(x, update_controls=True)
+
+ else:
+ update_jacobian = False
+ lbmda *= nu
+ nu *= 2.0
+
+ # save the error evolution
+ error_evolution[iter_] = error
+
+ if verbose > 0:
+ if verbose == 1:
+ print(f'It {iter_}, error {error}, converged {converged}, x {x}, dx {dx}')
+ else:
+ print(f'error {error}, converged {converged}, x {x}, dx {dx}')
+
+ return problem.get_solution(elapsed=time.time() - start, iterations=iter_)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/levenberg_marquardt_acdc.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/levenberg_marquardt_acdc.py
deleted file mode 100644
index 7d3aac985..000000000
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/levenberg_marquardt_acdc.py
+++ /dev/null
@@ -1,318 +0,0 @@
-# GridCal
-# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import time
-
-import numpy as np
-import scipy.sparse as sp
-from scipy.sparse.linalg import spsolve
-
-from GridCalEngine.Topology.admittance_matrices import compile_y_acdc
-from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
-import GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions as cf
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.acdc_jacobian import fubm_jacobian, AcDcSolSlicer
-from GridCalEngine.DataStructures.numerical_circuit import NumericalCircuit
-from GridCalEngine.basic_structures import CxVec
-
-
-def LM_ACDC(nc: NumericalCircuit, Vbus: CxVec, S0: CxVec, I0: CxVec, Y0: CxVec,
- tolerance=1e-6, max_iter=4, verbose=False) -> NumericPowerFlowResults:
- """
- Solves the power flow problem by the Levenberg-Marquardt power flow algorithm.
- It is usually better than Newton-Raphson, but it takes an order of magnitude more time to converge.
-
- :param verbose:
- :param Y0:
- :param I0:
- :param S0:
- :param Vbus:
- :param nc: SnapshotData instance
- :param tolerance: maximum error allowed
- :param max_iter: maximum number of iterations
- :return:
- """
- start = time.time()
-
- # initialize the variables
- nb = nc.nbus
- nl = nc.nbr
- V = Vbus
-
- Va = np.angle(V)
- Vm = np.abs(V)
-
- # compute the ZIP power injection
- Sbus = cf.compute_zip_power(S0=S0, I0=I0, Y0=Y0, Vm=Vm)
-
- Vmfset = nc.branch_data.vf_set
- m = nc.branch_data.tap_module.copy()
- tau = nc.branch_data.tap_angle.copy()
- Beq = nc.branch_data.Beq.copy()
- Gsw = nc.branch_data.G0sw
- Pfset = nc.branch_data.Pfset / nc.Sbase
- Qfset = nc.branch_data.Qfset / nc.Sbase
- Qtset = nc.branch_data.Qfset / nc.Sbase
- Kdp = nc.branch_data.Kdp
- k2 = nc.branch_data.k
- Cf = nc.Cf
- Ct = nc.Ct
- F = nc.F
- T = nc.T
- Ys = 1.0 / (nc.branch_data.R + 1j * nc.branch_data.X)
- Bc = nc.branch_data.B
- pq = nc.pq.copy().astype(int)
- pvpq_orig = np.r_[nc.pv, pq].astype(int)
- pvpq_orig.sort()
-
- # the elements of PQ that exist in the control indices Ivf and Ivt must be passed from the PQ to the PV list
- # otherwise those variables would be in two sets of equations
- i_ctrl_v = np.unique(np.r_[nc.i_vf_beq, nc.i_vt_m])
- for val in pq:
- if val in i_ctrl_v:
- pq = pq[pq != val]
-
- # compose the new pvpq indices Ć la NR
- pv = np.unique(np.r_[i_ctrl_v, nc.pv]).astype(int)
- pv.sort()
- pvpq = np.r_[pv, pq].astype(int)
- npv = len(pv)
- npq = len(pq)
-
- if (npq + npv) > 0:
- # --------------------------------------------------------------------------
- # variables dimensions in Jacobian
- sol_slicer = AcDcSolSlicer(pvpq=pvpq,
- pq=pq,
- k_zero_beq=nc.k_zero_beq,
- k_vf_beq=nc.k_vf_beq,
- k_qf_m=nc.k_qf_m,
- k_qt_m=nc.k_qt_m,
- k_vt_m=nc.k_vt_m,
- k_pf_tau=nc.k_pf_tau,
- k_pf_dp=nc.k_pf_dp)
- # -------------------------------------------------------------------------
- # compute initial admittances
- Ybus, Yf, Yt, tap = compile_y_acdc(Cf=Cf, Ct=Ct,
- C_bus_shunt=nc.shunt_data.C_bus_elm,
- shunt_admittance=nc.shunt_data.Y,
- shunt_active=nc.shunt_data.active,
- ys=Ys,
- B=Bc,
- Sbase=nc.Sbase,
- tap_module=m, tap_angle=tau, Beq=Beq, Gsw=Gsw,
- virtual_tap_from=nc.branch_data.virtual_tap_f,
- virtual_tap_to=nc.branch_data.virtual_tap_t)
-
- # compute branch power Sf
- If = Yf * V # complex current injected at "from" bus, Yf(br, :) * V; For in-service Branches
- It = Yt * V # complex current injected at "to" bus, Yt(br, :) * V; For in-service Branches
- Sf = V[F] * np.conj(If) # complex power injected at "from" bus
- St = V[T] * np.conj(It) # complex power injected at "to" bus
-
- # compute converter losses
- Gsw = cf.compute_converter_losses(V=V, It=It, F=F,
- alpha1=nc.branch_data.alpha1,
- alpha2=nc.branch_data.alpha2,
- alpha3=nc.branch_data.alpha3,
- iVscL=nc.i_vsc)
-
- # compute total mismatch
- Scalc = cf.compute_power(Ybus, V)
- dz = cf.compute_acdc_fx(Vm=Vm,
- Sbus=Sbus,
- Scalc=Scalc,
- Sf=Sf,
- St=St,
- Pfset=Pfset,
- Qfset=Qfset,
- Qtset=Qtset,
- Vmfset=Vmfset,
- Kdp=Kdp,
- F=F,
- pvpq=pvpq,
- pq=pq,
- k_pf_tau=nc.k_pf_tau,
- k_qf_m=nc.k_qf_m,
- k_zero_beq=nc.k_zero_beq,
- k_qt_m=nc.k_qt_m,
- k_pf_dp=nc.k_pf_dp,
- i_vf_beq=nc.i_vf_beq,
- i_vt_m=nc.i_vt_m)
-
- norm_f = np.max(np.abs(dz))
-
- update_jacobian = True
- converged = norm_f < tolerance
- iter_ = 0
- nu = 2.0
- lbmda = 0
- f_prev = 1e9 # very large number
-
- # generate lookup pvpq -> index pvpq (used in createJ)
- pvpq_lookup = np.zeros(Ybus.shape[0], dtype=int)
- pvpq_lookup[pvpq] = np.arange(len(pvpq))
-
- while not converged and iter_ < max_iter:
-
- # evaluate Jacobian
- if update_jacobian:
- H = fubm_jacobian(nb, nl, nc.k_pf_tau, nc.k_pf_dp, nc.k_qf_m, nc.k_qt_m, nc.k_vt_m, nc.k_zero_beq, nc.k_vf_beq,
- nc.i_vf_beq, nc.i_vt_m,
- F, T, Ys, k2, tap, m, Bc, Beq, Kdp, V, Ybus, Yf, Yt, Cf, Ct, pvpq, pq)
-
- if iter_ == 0:
- # compute this identity only once
- Idn = sp.diags(np.ones(H.shape[0])) # csc_matrix identity
-
- # system matrix
- # H1 = H^t
- H1 = H.transpose()
-
- # H2 = H1Ā·H
- H2 = H1.dot(H)
-
- # set first value of lmbda
- if iter_ == 0:
- lbmda = 1e-3 * H2.diagonal().max()
-
- # compute system matrix A = H^TĀ·H - lambdaĀ·I
- A = H2 + lbmda * Idn
-
- # right hand side
- # H^tĀ·dz
- rhs = H1.dot(dz)
-
- # Solve the increment
- dx = spsolve(A, rhs)
-
- # objective function to minimize
- f = 0.5 * dz.dot(dz)
-
- # decision function
- val = dx.dot(lbmda * dx + rhs)
- if val > 0.0:
- rho = (f_prev - f) / (0.5 * val)
- else:
- rho = -1.0
-
- # lambda update
- if rho >= 0:
- update_jacobian = True
- lbmda *= max([1.0 / 3.0, 1 - (2 * rho - 1) ** 3])
- nu = 2.0
-
- # split the solution
- dVa, dVm, dBeq, dm, dTau = sol_slicer.split(dx)
-
- # assign the new values
- Va[sol_slicer.va_idx] -= dVa
- Vm[sol_slicer.vm_idx] -= dVm
- Beq[sol_slicer.beq_idx] -= dBeq
- m[sol_slicer.m_idx] -= dm
- tau[sol_slicer.tau_idx] -= dTau
-
- V = cf.polar_to_rect(Vm, Va)
-
- # compute the ZIP power injection
- Sbus = cf.compute_zip_power(S0=S0, I0=I0, Y0=Y0, Vm=Vm)
-
- else:
- update_jacobian = False
- lbmda *= nu
- nu *= 2.0
-
- # compute initial admittances
- Ybus, Yf, Yt, tap = compile_y_acdc(Cf=Cf,
- Ct=Ct,
- C_bus_shunt=nc.shunt_data.C_bus_elm,
- shunt_admittance=nc.shunt_data.Y,
- shunt_active=nc.shunt_data.active,
- ys=Ys,
- B=Bc,
- Sbase=nc.Sbase,
- tap_module=m, tap_angle=tau, Beq=Beq, Gsw=Gsw,
- virtual_tap_from=nc.branch_data.virtual_tap_f,
- virtual_tap_to=nc.branch_data.virtual_tap_t)
-
- # compute branch power Sf
- If = Yf * V # complex current injected at "from" bus, Yf(br, :) * V; For in-service Branches
- It = Yt * V # complex current injected at "to" bus, Yt(br, :) * V; For in-service Branches
- Sf = V[F] * np.conj(If) # complex power injected at "from" bus
- St = V[T] * np.conj(It) # complex power injected at "to" bus
-
- # compute converter losses
- Gsw = cf.compute_converter_losses(V=V, It=It, F=F,
- alpha1=nc.branch_data.alpha1,
- alpha2=nc.branch_data.alpha2,
- alpha3=nc.branch_data.alpha3,
- iVscL=nc.i_vsc)
-
- # check convergence
- Scalc = cf.compute_power(Ybus, V)
- dz = cf.compute_acdc_fx(Vm=Vm,
- Sbus=Sbus,
- Scalc=Scalc,
- Sf=Sf,
- St=St,
- Pfset=Pfset,
- Qfset=Qfset,
- Qtset=Qtset,
- Vmfset=Vmfset,
- Kdp=Kdp,
- F=F,
- pvpq=pvpq,
- pq=pq,
- k_pf_tau=nc.k_pf_tau,
- k_qf_m=nc.k_qf_m,
- k_zero_beq=nc.k_zero_beq,
- k_qt_m=nc.k_qt_m,
- k_pf_dp=nc.k_pf_dp,
- i_vf_beq=nc.i_vf_beq,
- i_vt_m=nc.i_vt_m)
-
- norm_f = np.max(np.abs(dz))
- converged = norm_f < tolerance
- f_prev = f
-
- if verbose:
- print('dx:', dx)
- print('Va:', Va)
- print('Vm:', Vm)
- print('theta:', tau)
- print('ma:', m)
- print('Beq:', Beq)
- print('norm_f:', norm_f)
-
- # update iteration counter
- iter_ += 1
- else:
- norm_f = 0
- converged = True
- Scalc = S0 + I0 * Vm + Y0 * np.power(Vm, 2) # compute the ZIP power injection
- iter_ = 0
- Ybus = None
- Yf = None
- Yt = None
-
- end = time.time()
- elapsed = end - start
-
- # return NumericPowerFlowResults(V, converged, norm_f, Scalc, m, theta, Beq, Ybus, Yf, Yt, iter_, elapsed)
- return NumericPowerFlowResults(V=V, converged=converged, norm_f=norm_f,
- Scalc=Scalc, ma=m, theta=tau, Beq=Beq,
- Ybus=Ybus, Yf=Yf, Yt=Yt,
- iterations=iter_, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/linearized_power_flow.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/linearized_power_flow.py
index 50b3d221f..27daeb230 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/linearized_power_flow.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/linearized_power_flow.py
@@ -30,7 +30,7 @@
def dcpf(Ybus: sp.csc_matrix, Bpqpv: sp.csc_matrix, Bref: sp.csc_matrix, Bf: sp.csc_matrix,
S0: CxVec, I0: CxVec, Y0: CxVec, V0: CxVec, tau: Vec,
- vd: IntVec, pvpq: IntVec, pq: IntVec, pv: IntVec) -> NumericPowerFlowResults:
+ vd: IntVec, no_slack: IntVec, pq: IntVec, pv: IntVec) -> NumericPowerFlowResults:
"""
Solves a linear-DC power flow.
:param Ybus: Normal circuit admittance matrix
@@ -43,7 +43,7 @@ def dcpf(Ybus: sp.csc_matrix, Bpqpv: sp.csc_matrix, Bref: sp.csc_matrix, Bf: sp.
:param V0: Array of complex seed voltage (it contains the ref voltages)
:param tau: Array of branch angles
:param vd: array of the indices of the slack nodes
- :param pvpq: array of the indices of the non-slack nodes
+ :param no_slack: array of the indices of the non-slack nodes
:param pq: array of the indices of the pq nodes
:param pv: array of the indices of the pv nodes
:return: NumericPowerFlowResults instance
@@ -67,10 +67,10 @@ def dcpf(Ybus: sp.csc_matrix, Bpqpv: sp.csc_matrix, Bref: sp.csc_matrix, Bf: sp.
# Since we have removed the slack nodes, we must account their influence as Injections Bref * Va_ref
# We also need to account for the effect of the phase shifters (Pps)
Pps = Bf.T @ tau
- Pinj = Sbus[pvpq].real - (Bref @ Va_ref) * Vm[pvpq] + Pps[pvpq] # TODO: add G from shunts
+ Pinj = Sbus[no_slack].real - (Bref @ Va_ref) * Vm[no_slack] + Pps[no_slack] # TODO: add G from shunts
# update angles for non-reference buses
- Va[pvpq] = linear_solver(Bpqpv, Pinj)
+ Va[no_slack] = linear_solver(Bpqpv, Pinj)
Va[vd] = Va_ref
# re assemble the voltage
@@ -80,7 +80,7 @@ def dcpf(Ybus: sp.csc_matrix, Bpqpv: sp.csc_matrix, Bref: sp.csc_matrix, Bf: sp.
Scalc = cf.compute_power(Ybus, V)
# compute the power mismatch between the specified power Sbus and the calculated power Scalc
- mismatch = cf.compute_fx(Scalc, S0, pvpq, pq)
+ mismatch = cf.compute_fx(Scalc, S0, no_slack, pq)
# check for convergence
norm_f = np.linalg.norm(mismatch, np.Inf)
@@ -94,7 +94,7 @@ def dcpf(Ybus: sp.csc_matrix, Bpqpv: sp.csc_matrix, Bref: sp.csc_matrix, Bf: sp.
# return NumericPowerFlowResults(V, True, norm_f, Scalc, None, None, None, None, None, None, 1, elapsed)
return NumericPowerFlowResults(V=V, converged=True, norm_f=norm_f,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=1, elapsed=elapsed)
@@ -148,7 +148,7 @@ def lacpf(Ybus, Ys, S0: CxVec, I0: CxVec, V0: CxVec, pq: IntVec, pv: IntVec) ->
V = V0
# Calculate the error and check the convergence
Scalc = cf.compute_power(Ybus, V)
- mismatch = cf.compute_fx(Scalc=Scalc, Sbus=S0, pvpq=pvpq, pq=pq)
+ mismatch = cf.compute_fx(Scalc=Scalc, Sbus=S0, idx_dP=pvpq, idx_dQ=pq)
norm_f = cf.compute_fx_error(mismatch)
# check for convergence
@@ -157,7 +157,7 @@ def lacpf(Ybus, Ys, S0: CxVec, I0: CxVec, V0: CxVec, pq: IntVec, pv: IntVec) ->
# return NumericPowerFlowResults(V, False, norm_f, Scalc,
# None, None, None, None, None, None, 1, elapsed)
return NumericPowerFlowResults(V=V, converged=False, norm_f=norm_f,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=1, elapsed=elapsed)
@@ -189,7 +189,7 @@ def lacpf(Ybus, Ys, S0: CxVec, I0: CxVec, V0: CxVec, pq: IntVec, pv: IntVec) ->
# return NumericPowerFlowResults(V, True, norm_f, Scalc,
# None, None, None, None, None, None, 1, elapsed)
return NumericPowerFlowResults(V=V, converged=True, norm_f=norm_f,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=1, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_acdc.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_acdc.py
deleted file mode 100644
index 449fcefaa..000000000
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_acdc.py
+++ /dev/null
@@ -1,397 +0,0 @@
-# GridCal
-# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import time
-
-import numpy as np
-
-from GridCalEngine.DataStructures.numerical_circuit import NumericalCircuit
-from GridCalEngine.Topology.admittance_matrices import compile_y_acdc
-from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import control_q_inside_method
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.acdc_jacobian import fubm_jacobian, AcDcSolSlicer
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import (compute_acdc_fx,
- compute_converter_losses,
- compute_power, compute_zip_power)
-from GridCalEngine.basic_structures import CxVec
-from GridCalEngine.enumerations import ReactivePowerControlMode
-import GridCalEngine.Utils.NumericalMethods.sparse_solve as gcsp
-
-
-def NR_LS_ACDC(nc: NumericalCircuit,
- V0: CxVec,
- S0: CxVec,
- I0: CxVec,
- Y0: CxVec,
- tolerance=1e-6,
- max_iter=4,
- mu_0=1.0,
- acceleration_parameter=0.05,
- verbose=False,
- control_q=ReactivePowerControlMode.NoControl) -> NumericPowerFlowResults:
- """
- Newton-Raphson Line search with the FUBM formulation
- :param nc: NumericalCircuit
- :param V0: Initial voltage solution
- :param S0: Power injections
- :param I0: Current injections
- :param Y0: Admittance injections
- :param tolerance: maximum error allowed
- :param max_iter: maximum number of iterations
- :param mu_0: Initial solution multiplier
- :param acceleration_parameter: Acceleration parameter (rate to decrease mu)
- :param verbose: Verbose?
- :param control_q: Reactive power control mode
- :return: NumericPowerFlowResults
- """
- start = time.time()
-
- # initialize the variables
- nb = nc.nbus
- nl = nc.nbr
- V = V0
-
- Va = np.angle(V)
- Vm = np.abs(V)
-
- # compute the ZIP power injection
- Sbus = compute_zip_power(S0=S0, I0=I0, Y0=Y0, Vm=Vm)
-
- Vmfset = nc.branch_data.vf_set
- m = nc.branch_data.tap_module.copy()
- tau = nc.branch_data.tap_angle.copy()
- Beq = nc.branch_data.Beq.copy()
- Gsw = nc.branch_data.G0sw
- Pfset = nc.branch_data.Pfset / nc.Sbase
- Qfset = nc.branch_data.Qfset / nc.Sbase
- Qtset = nc.branch_data.Qfset / nc.Sbase
- Qmin = nc.Qmin_bus
- Qmax = nc.Qmax_bus
- Kdp = nc.branch_data.Kdp
- k2 = nc.branch_data.k
- Cf = nc.Cf.tocsc()
- Ct = nc.Ct.tocsc()
- F = nc.F
- T = nc.T
- Ys = 1.0 / (nc.branch_data.R + 1j * nc.branch_data.X)
- Bc = nc.branch_data.B
- pq = nc.pq.copy().astype(int)
- pvpq_orig = np.r_[nc.pv, pq].astype(int)
- pvpq_orig.sort()
-
- # the elements of PQ that exist in the control indices Ivf and Ivt must be passed from the PQ to the PV list
- # otherwise those variables would be in two sets of equations
- i_ctrl_v = np.unique(np.r_[nc.i_vf_beq, nc.i_vt_m])
- for val in pq:
- if val in i_ctrl_v:
- pq = pq[pq != val]
-
- # compose the new pvpq indices Ć la NR
- pv = np.unique(np.r_[i_ctrl_v, nc.pv]).astype(int)
- pv.sort()
- pvpq = np.r_[pv, pq].astype(int)
- npv = len(pv)
- npq = len(pq)
-
- # --------------------------------------------------------------------------
- # variables dimensions in Jacobian
- sol_slicer = AcDcSolSlicer(pvpq=pvpq,
- pq=pq,
- k_zero_beq=nc.k_zero_beq,
- k_vf_beq=nc.k_vf_beq,
- k_qf_m=nc.k_qf_m,
- k_qt_m=nc.k_qt_m,
- k_vt_m=nc.k_vt_m,
- k_pf_tau=nc.k_pf_tau,
- k_pf_dp=nc.k_pf_dp)
-
- # -------------------------------------------------------------------------
- # compute initial admittances
- Ybus, Yf, Yt, tap = compile_y_acdc(Cf=Cf, Ct=Ct,
- C_bus_shunt=nc.shunt_data.C_bus_elm.tocsc(),
- shunt_admittance=nc.shunt_data.Y,
- shunt_active=nc.shunt_data.active,
- ys=Ys,
- B=Bc,
- Sbase=nc.Sbase,
- tap_module=m, tap_angle=tau, Beq=Beq, Gsw=Gsw,
- virtual_tap_from=nc.branch_data.virtual_tap_f,
- virtual_tap_to=nc.branch_data.virtual_tap_t)
-
- # compute branch power Sf
- If = Yf * V # complex current injected at "from" bus, Yf(br, :) * V; For in-service Branches
- It = Yt * V # complex current injected at "to" bus, Yt(br, :) * V; For in-service Branches
- Sf = V[F] * np.conj(If) # complex power injected at "from" bus
- St = V[T] * np.conj(It) # complex power injected at "to" bus
-
- # compute converter losses
- Gsw = compute_converter_losses(V=V, It=It, F=F,
- alpha1=nc.branch_data.alpha1,
- alpha2=nc.branch_data.alpha2,
- alpha3=nc.branch_data.alpha3,
- iVscL=nc.i_vsc)
-
- # compute total mismatch
- Scalc = compute_power(Ybus, V)
- fx = compute_acdc_fx(Vm=Vm,
- Sbus=Sbus,
- Scalc=Scalc,
- Sf=Sf,
- St=St,
- Pfset=Pfset,
- Qfset=Qfset,
- Qtset=Qtset,
- Vmfset=Vmfset,
- Kdp=Kdp,
- F=F,
- pvpq=pvpq,
- pq=pq,
- k_pf_tau=nc.k_pf_tau,
- k_qf_m=nc.k_qf_m,
- k_zero_beq=nc.k_zero_beq,
- k_qt_m=nc.k_qt_m,
- k_pf_dp=nc.k_pf_dp,
- i_vf_beq=nc.i_vf_beq,
- i_vt_m=nc.i_vt_m)
-
- norm_f = np.max(np.abs(fx))
-
- # -------------------------------------------------------------------------
- converged = norm_f < tolerance
- iterations = 0
- while not converged and iterations < max_iter:
-
- # compute the Jacobian
- J = fubm_jacobian(nb, nl, nc.k_pf_tau, nc.k_pf_dp, nc.k_qf_m, nc.k_qt_m, nc.k_vt_m, nc.k_zero_beq, nc.k_vf_beq,
- nc.i_vf_beq, nc.i_vt_m,
- F, T, Ys, k2, tap, m, Bc, Beq, Kdp, V, Ybus, Yf, Yt, Cf, Ct, pvpq, pq)
-
- # solve the linear system
- dx = gcsp.super_lu_linsolver(J, -fx)
-
- if not np.isnan(dx).any(): # check if the solution worked
-
- # split the solution
- dVa, dVm, dBeq, dm, dTau = sol_slicer.split(dx)
-
- # set the restoration values
- prev_Vm = Vm.copy()
- prev_Va = Va.copy()
- prev_m = m.copy()
- prev_tau = tau.copy()
- prev_Beq = Beq.copy()
- prev_Scalc = Scalc.copy()
-
- mu = mu_0 # ideally 1.0
- cond = True
- l_iter = 0
- norm_f_new = 0.0
- while cond and l_iter < max_iter and mu > tolerance: # backtracking: if all goes well it is only done 1 time
-
- # restore the previous values if we are backtracking (the first iteration is the normal NR procedure)
- if l_iter > 0:
- Va = prev_Va.copy()
- Vm = prev_Vm.copy()
- m = prev_m.copy()
- tau = prev_tau.copy()
- Beq = prev_Beq.copy()
-
- # assign the new values
- Va[sol_slicer.va_idx] -= dVa * mu
- Vm[sol_slicer.vm_idx] -= dVm * mu
- Beq[sol_slicer.beq_idx] -= dBeq * mu
- m[sol_slicer.m_idx] -= dm * mu
- tau[sol_slicer.tau_idx] -= dTau * mu
-
- V = Vm * np.exp(1j * Va)
-
- # compute the ZIP power injection
- Sbus = compute_zip_power(S0=S0, I0=I0, Y0=Y0, Vm=Vm)
-
- # compute admittances
- Ybus, Yf, Yt, tap = compile_y_acdc(Cf=Cf, Ct=Ct,
- C_bus_shunt=nc.shunt_data.C_bus_elm.tocsc(),
- shunt_admittance=nc.shunt_data.Y,
- shunt_active=nc.shunt_data.active,
- ys=Ys,
- B=Bc,
- Sbase=nc.Sbase,
- tap_module=m, tap_angle=tau, Beq=Beq, Gsw=Gsw,
- virtual_tap_from=nc.branch_data.virtual_tap_f,
- virtual_tap_to=nc.branch_data.virtual_tap_t)
-
- # compute branch power Sf
- If = Yf * V # complex current injected at "from" bus
- It = Yt * V # complex current injected at "to" bus
- Sf = V[F] * np.conj(If) # complex power injected at "from" bus
- St = V[T] * np.conj(It) # complex power injected at "to" bus
-
- # compute converter losses
- Gsw = compute_converter_losses(V=V, It=It, F=F,
- alpha1=nc.branch_data.alpha1,
- alpha2=nc.branch_data.alpha2,
- alpha3=nc.branch_data.alpha3,
- iVscL=nc.i_vsc)
-
- # compute total mismatch
- Scalc = compute_power(Ybus, V)
- fx = compute_acdc_fx(Vm=Vm,
- Sbus=Sbus,
- Scalc=Scalc,
- Sf=Sf,
- St=St,
- Pfset=Pfset,
- Qfset=Qfset,
- Qtset=Qtset,
- Vmfset=Vmfset,
- Kdp=Kdp,
- F=F,
- pvpq=pvpq,
- pq=pq,
- k_pf_tau=nc.k_pf_tau,
- k_qf_m=nc.k_qf_m,
- k_zero_beq=nc.k_zero_beq,
- k_qt_m=nc.k_qt_m,
- k_pf_dp=nc.k_pf_dp,
- i_vf_beq=nc.i_vf_beq,
- i_vt_m=nc.i_vt_m)
-
- norm_f_new = np.max(np.abs(fx))
- cond = norm_f_new > norm_f # condition to back track (no improvement at all)
-
- mu *= acceleration_parameter
- l_iter += 1
-
- if l_iter > 1 and norm_f_new > norm_f:
- # this means that not even the backtracking was able to correct the solution so, restore and end
- Va = prev_Va.copy()
- Vm = prev_Vm.copy()
- m = prev_m.copy()
- tau = prev_tau.copy()
- Beq = prev_Beq.copy()
- V = Vm * np.exp(1j * Va)
- end = time.time()
- elapsed = end - start
-
- # set the state for the next solver_type
- nc.branch_data.tap_module = m
- nc.branch_data.tap_angle = tau
- nc.branch_data.Beq = Beq
-
- # return NumericPowerFlowResults(V, converged, norm_f_new, prev_Scalc,
- # m, tau, Beq, Ybus, Yf, Yt, iterations, elapsed)
- return NumericPowerFlowResults(V=V, converged=converged, norm_f=norm_f,
- Scalc=Scalc, ma=m, theta=tau, Beq=Beq,
- Ybus=Ybus, Yf=Yf, Yt=Yt,
- iterations=iterations, elapsed=elapsed)
- else:
- # the iteration was ok, check the controls if the error is small enough
- if norm_f < 1e-2:
-
- for idx in nc.i_vsc:
- # correct m (tap modules)
- if m[idx] < nc.branch_data.tap_module_min[idx]:
- m[idx] = nc.branch_data.tap_module_min[idx]
- elif m[idx] > nc.branch_data.tap_module_max[idx]:
- m[idx] = nc.branch_data.tap_module_max[idx]
-
- # correct theta (tap angles)
- if tau[idx] < nc.branch_data.tap_angle_min[idx]:
- tau[idx] = nc.branch_data.tap_angle_min[idx]
- elif tau[idx] > nc.branch_data.tap_angle_max[idx]:
- tau[idx] = nc.branch_data.tap_angle_max[idx]
-
- # review reactive power limits
- # it is only worth checking Q limits with a low error
- # since with higher errors, the Q values may be far from realistic
- # finally, the Q control only makes sense if there are pv nodes
- if control_q != ReactivePowerControlMode.NoControl and npv > 0:
-
- # check and adjust the reactive power
- # this function passes pv buses to pq when the limits are violated,
- # but not pq to pv because that is unstable
- changed, pv, pq, pqv, p = control_q_inside_method(Scalc, S0, pv, pq, pqv, p, Qmin, Qmax)
-
- if len(changed) > 0:
- # adjust internal variables to the new pq|pv values
- blck1_idx = np.r_[pv, pq, p, pqv]
- blck2_idx = np.r_[pq, p]
- blck3_idx = np.r_[pq, pqv]
- n_block1 = len(blck1_idx)
-
- # re declare the slicer because the indices of pq and pv changed
- sol_slicer = AcDcSolSlicer(pvpq=pvpq,
- pq=pq,
- k_zero_beq=nc.k_zero_beq,
- k_vf_beq=nc.k_vf_beq,
- k_qf_m=nc.k_qf_m,
- k_qt_m=nc.k_qt_m,
- k_vt_m=nc.k_vt_m,
- k_pf_tau=nc.k_pf_tau,
- k_pf_dp=nc.k_pf_dp)
-
- # recompute the mismatch, based on the new S0
- Scalc = compute_power(Ybus, V)
- fx = compute_acdc_fx(Vm=Vm,
- Sbus=Sbus,
- Scalc=Scalc,
- Sf=Sf,
- St=St,
- Pfset=Pfset,
- Qfset=Qfset,
- Qtset=Qtset,
- Vmfset=Vmfset,
- Kdp=Kdp,
- F=F,
- pvpq=pvpq,
- pq=pq,
- k_pf_tau=nc.k_pf_tau,
- k_qf_m=nc.k_qf_m,
- k_zero_beq=nc.k_zero_beq,
- k_qt_m=nc.k_qt_m,
- k_pf_dp=nc.k_pf_dp,
- i_vf_beq=nc.i_vf_beq,
- i_vt_m=nc.i_vt_m)
- norm_f_new = np.max(np.abs(fx))
-
- # set the mismatch to the new mismatch
- norm_f = norm_f_new
-
- if verbose:
- print('dx:', dx)
- print('Va:', Va)
- print('Vm:', Vm)
- print('theta:', tau)
- print('ma:', m)
- print('Beq:', Beq)
- print('norm_f:', norm_f)
-
- iterations += 1
- converged = norm_f <= tolerance
- else:
- iterations = max_iter
- converged = False
-
- end = time.time()
- elapsed = end - start
-
- # return NumericPowerFlowResults(V, converged, norm_f, Scalc,
- # m, tau, Beq, Ybus, Yf, Yt, iterations, elapsed)
- return NumericPowerFlowResults(V=V, converged=converged, norm_f=norm_f,
- Scalc=Scalc, ma=m, theta=tau, Beq=Beq,
- Ybus=Ybus, Yf=Yf, Yt=Yt,
- iterations=iterations, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_current.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_current.py
deleted file mode 100644
index e87e8b10d..000000000
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_current.py
+++ /dev/null
@@ -1,189 +0,0 @@
-# GridCal
-# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import time
-import scipy
-import scipy.sparse as sp
-import numpy as np
-
-from GridCalEngine.Utils.NumericalMethods.sparse_solve import get_sparse_type, get_linear_solver
-from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
-
-linear_solver = get_linear_solver()
-sparse = get_sparse_type()
-scipy.ALLOW_THREADS = True
-np.set_printoptions(precision=8, suppress=True, linewidth=320)
-
-
-def Jacobian_I(Ybus, V, pq, pvpq):
- """
- Computes the system Jacobian matrix
- Args:
- Ybus: Admittance matrix
- V: Array of nodal voltages
- pq: Array with the indices of the PQ buses
- pvpq: Array with the indices of the PV and PQ buses
-
- Returns:
- The system Jacobian matrix in current equations
- """
- dI_dVm = Ybus * sp.diags(V / np.abs(V))
- dI_dVa = 1j * (Ybus * sp.diags(V))
-
- J11 = dI_dVa[np.array([pvpq]).T, pvpq].real
- J12 = dI_dVm[np.array([pvpq]).T, pq].real
- J21 = dI_dVa[np.array([pq]).T, pvpq].imag
- J22 = dI_dVm[np.array([pq]).T, pq].imag
-
- J = sp.vstack([sp.hstack([J11, J12]),
- sp.hstack([J21, J22])], format="csr")
-
- return J
-
-
-def NR_I_LS(Ybus, Sbus_sp, V0, Ibus_sp, pv, pq, tol, max_it=15, acceleration_parameter=0.5) -> NumericPowerFlowResults:
- """
- Solves the power flow using a full Newton's method in current equations with current mismatch with line search
- Args:
- Ybus: Admittance matrix
- Sbus_sp: Array of nodal specified power Injections
- V0: Array of nodal voltages (initial solution)
- Ibus_sp: Array of nodal specified current Injections
- pv: Array with the indices of the PV buses
- pq: Array with the indices of the PQ buses
- tol: Tolerance
- max_it: Maximum number of iterations
- acceleration_parameter: value used to correct bad iterations
- Returns:
- Voltage solution, converged?, error, calculated power Injections
-
- @Author: Santiago Penate Vera
- """
- start = time.time()
-
- # initialize
- back_track_counter = 0
- back_track_iterations = 0
- alpha = 1e-4
- converged = 0
- iter_ = 0
- V = V0
- Va = np.angle(V)
- Vm = np.abs(V)
- dVa = np.zeros_like(Va)
- dVm = np.zeros_like(Vm)
-
- # set up indexing for updating V
- pvpq = np.r_[pv, pq]
- npv = len(pv)
- npq = len(pq)
-
- # j1:j2 - V angle of pv buses
- j1 = 0
- j2 = npv
- # j3:j4 - V angle of pq buses
- j3 = j2
- j4 = j2 + npq
- # j5:j6 - V mag of pq buses
- j5 = j4
- j6 = j4 + npq
-
- # evaluate F(x0)
- Icalc = Ybus * V - Ibus_sp
- dI = np.conj(Sbus_sp / V) - Icalc # compute the mismatch
- F = np.r_[dI[pvpq].real, dI[pq].imag]
- normF = np.linalg.norm(F, np.Inf) # check tolerance
-
- converged = normF < tol
-
- # do Newton iterations
- while not converged and iter_ < max_it:
- # update iteration counter
- iter_ += 1
-
- # evaluate Jacobian
- J = Jacobian_I(Ybus, V, pq, pvpq)
-
- # compute update step
- dx = linear_solver(J, F)
-
- # reassign the solution vector
- dVa[pvpq] = dx[j1:j4]
- dVm[pq] = dx[j5:j6]
-
- # update voltage the Newton way (mu=1)
- mu_ = 1.0
- Vm += mu_ * dVm
- Va += mu_ * dVa
- Vnew = Vm * np.exp(1j * Va)
-
- # compute the mismatch function f(x_new)
- Icalc = Ybus * Vnew - Ibus_sp
- dI = np.conj(Sbus_sp / Vnew) - Icalc
- Fnew = np.r_[dI[pvpq].real, dI[pq].imag]
-
- normFnew = np.linalg.norm(Fnew, np.Inf)
-
- cond = normF < normFnew # condition to back track (no improvement at all)
-
- if not cond:
- back_track_counter += 1
-
- l_iter = 0
- while cond and l_iter < max_it and mu_ > tol:
- # line search back
-
- # reset voltage
- Va = np.angle(V)
- Vm = np.abs(V)
-
- # update voltage with a closer value to the last value in the Jacobian direction
- mu_ *= acceleration_parameter
- Vm -= mu_ * dVm
- Va -= mu_ * dVa
- Vnew = Vm * np.exp(1j * Va)
-
- # compute the mismatch function f(x_new)
- Icalc = Ybus * Vnew - Ibus_sp
- dI = np.conj(Sbus_sp / Vnew) - Icalc
- Fnew = np.r_[dI[pvpq].real, dI[pq].imag]
-
- normFnew = np.linalg.norm(Fnew, np.Inf)
- cond = normF < normFnew
-
- l_iter += 1
- back_track_iterations += 1
-
- # update calculation variables
- V = Vnew
- F = Fnew
-
- # check for convergence
- normF = normFnew
-
- converged = normF < tol
-
- end = time.time()
- elapsed = end - start
-
- Scalc = V * np.conj(Icalc)
-
- # return NumericPowerFlowResults(V, converged, normF, Scalc, None, None, None, None, None, None, iter_, elapsed)
- return NumericPowerFlowResults(V=V, converged=converged, norm_f=normF,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
- Ybus=None, Yf=None, Yt=None,
- iterations=iter_, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_fx.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_fx.py
new file mode 100644
index 000000000..5f32e905c
--- /dev/null
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_fx.py
@@ -0,0 +1,146 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+import time
+import numpy as np
+from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.pf_formulation_template import PfFormulationTemplate
+from GridCalEngine.Utils.Sparse.csc2 import CSC, spsolve_csc
+from GridCalEngine.basic_structures import Logger
+
+
+def newton_raphson_fx(problem: PfFormulationTemplate,
+ tol: float = 1e-6,
+ max_iter: int = 10,
+ trust: float = 1.0,
+ verbose: int = 0,
+ logger: Logger = Logger()) -> NumericPowerFlowResults:
+ """
+ Newton-Raphson with Line search to solve:
+
+ min: error(g(x))
+ s.t.
+ g(x) = 0
+
+ :param problem: PfFormulationTemplate
+ :param tol: Error tolerance
+ :param max_iter: Maximum number of iterations
+ :param trust: trust amount in the derivative length correctness
+ :param verbose: Display console information
+ :param logger: Logger instance
+ :return: ConvexMethodResult
+ """
+ start = time.time()
+
+ # get the initial point
+ x = problem.var2x()
+
+ if len(x) == 0:
+ # if the lenght of x is zero, means that there's nothing to solve
+ # for instance there might be a single node that is a slack node
+ return problem.get_solution(elapsed=time.time() - start, iterations=0)
+
+ # set the problem state
+ error, converged, _, f = problem.update(x, update_controls=False)
+
+ iteration = 0
+ error_evolution = np.zeros(max_iter + 1)
+ trust0 = trust if trust <= 1.0 else 1.0 # trust radius in NR should not be greater than 1
+
+ # save the error evolution
+ error_evolution[iteration] = problem.error
+
+ if verbose > 0:
+ print(f'It {iteration}, error {problem.error}, converged {problem.converged}, x {x}, dx not computed yet')
+
+ if problem.converged:
+ return problem.get_solution(elapsed=time.time() - start, iterations=iteration)
+
+ else:
+
+ while not converged and iteration < max_iter:
+
+ # update iteration counter
+ iteration += 1
+
+ if verbose > 0:
+ print('-' * 200)
+ print(f'Iter: {iteration}')
+ print('-' * 200)
+
+ # compute update step
+ try:
+
+ # compute update step: J x Īx = Īg
+ J: CSC = problem.Jacobian()
+ dx, ok = spsolve_csc(J, -f)
+ # dx, ok = problem.solve_step()
+
+ if verbose > 1:
+ import pandas as pd
+ print("J:\n", pd.DataFrame(J.toarray()).to_string(index=False))
+ print("F:\n", f)
+ print("dx:\n", dx)
+
+ if not ok:
+ logger.add_error(f"Newton-Raphson's Jacobian is singular @iter {iteration}:")
+ print("(newton_raphson_fx.py) Singular Jacobian")
+ return problem.get_solution(elapsed=time.time() - start, iterations=iteration)
+ except RuntimeError:
+ logger.add_error(f"Newton-Raphson's Jacobian is singular @iter {iteration}:")
+ print("(newton_raphson_fx.py) Singular Jacobian")
+ return problem.get_solution(elapsed=time.time() - start, iterations=iteration)
+
+ # mu = trust0
+ # back_track_condition = True
+ # l_iter = 0
+ # while back_track_condition and mu > tol:
+ #
+ # x2 = x - mu * dx
+ # error2, converged2, _ = problem.update(x2, update_controls=False)
+ #
+ # # change mu for the next iteration
+ # mu *= 0.5 # acceleration_parameter
+ #
+ # # keep back-tracking?
+ # back_track_condition = error2 > error
+ # l_iter += 1
+ #
+ # if not back_track_condition:
+ # # accept the solution
+ # x = x2
+ #
+ # if back_track_condition:
+ # # this means that not even the backtracking was able to correct
+ # # the solution, so terminate
+ # logger.add_warning(f"Newton-Raphson's stagnated @iter {iteration}:")
+ # return problem.get_solution(elapsed=time.time() - start, iterations=iteration)
+
+ x += dx
+
+ # set the problem state
+ error, converged, x, f = problem.update(x, update_controls=True)
+
+ # save the error evolution
+ error_evolution[iteration] = error
+
+ if verbose > 0:
+ if verbose == 1:
+ print(f'It {iteration}, error {error}, converged {converged}, x {x}, dx {dx}')
+ else:
+ print(f'error {error}, converged {converged}, x {x}, dx {dx}')
+
+ return problem.get_solution(elapsed=time.time() - start, iterations=iteration)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_general.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_general.py
deleted file mode 100644
index 4a09eb0d9..000000000
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_general.py
+++ /dev/null
@@ -1,973 +0,0 @@
-# GridCal
-# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import time
-
-import numpy as np
-
-from GridCalEngine.DataStructures.numerical_circuit import NumericalCircuit
-from GridCalEngine.Topology.admittance_matrices import compile_y_acdc
-from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import control_q_inside_method
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.acdc_jacobian import fubm_jacobian, AcDcSolSlicer
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import (compute_acdc_fx,
- compute_converter_losses,
- compute_power, compute_zip_power)
-from GridCalEngine.Utils.NumericalMethods.common import (ConvexMethodResult, ConvexFunctionResult)
-from GridCalEngine.Utils.NumericalMethods.newton_raphson import newton_raphson
-from GridCalEngine.enumerations import ReactivePowerControlMode
-import GridCalEngine.Utils.NumericalMethods.sparse_solve as gcsp
-from scipy.sparse import csr_matrix, csc_matrix
-from GridCalEngine.basic_structures import Vec, CscMat, CxVec, IntVec, Logger
-
-
-def NR_LS_GENERAL(nc: NumericalCircuit,
- V0: CxVec,
- S0: CxVec,
- I0: CxVec,
- Y0: CxVec,
- tolerance=1e-6,
- max_iter=4,
- mu_0=1.0,
- acceleration_parameter=0.05,
- verbose=False,
- control_q=ReactivePowerControlMode.NoControl,
- pf_options=None) -> NumericPowerFlowResults:
- """
- Newton-Raphson Line search with the FUBM formulation
- :param nc: NumericalCircuit
- :param V0: Initial voltage solution
- :param S0: Power injections
- :param I0: Current injections
- :param Y0: Admittance injections
- :param tolerance: maximum error allowed
- :param max_iter: maximum number of iterations
- :param mu_0: Initial solution multiplier
- :param acceleration_parameter: Acceleration parameter (rate to decrease mu)
- :param verbose: Verbose?
- :param control_q: Reactive power control mode
- :param pf_options: PF options
- :return: NumericPowerFlowResults
- """
- start = time.time()
-
- '''
- Split the AC and DC subsystems
- '''
- Ybus = isolate_AC_DC(nc, nc.Ybus)
- print("Ybus")
- print(Ybus.todense())
-
- '''
- Initialising from and to powers, and tau and modulation
- '''
- p_from = np.zeros(nc.nbus)
- p_to = np.zeros(nc.nbus)
- q_from = np.zeros(nc.nbus)
- q_to = np.zeros(nc.nbus)
- p_zip = np.zeros(nc.nbus)
- q_zip = np.zeros(nc.nbus)
- modulations = np.ones(nc.nbus)
- taus = np.zeros(nc.nbus)
- Vm0 = np.abs(V0)
- Va0 = np.angle(V0)
-
- branch_from_indices = nc.branch_data.F
- branch_to_indices = nc.branch_data.T
-
- print("branch_from_indices full array")
- print(branch_from_indices)
-
- print("branch_to_indices full array")
- print(branch_to_indices)
-
- vsc_from_indices = nc.vsc_data.F
- vsc_to_indices = nc.vsc_data.T
-
- print("vsc_from_indices full array")
- print(vsc_from_indices)
-
- print("vsc_to_indices full array")
- print(vsc_to_indices)
-
- for i in range(len(nc.kn_pfrom_kdx)):
- print("(newtown_raphson_general.py) the from bus of the first pfrom kdx",
- branch_from_indices[nc.kn_pfrom_kdx[i]])
- print("(newtown_raphson_general.py) the setpoint of this", nc.kn_pfrom_setpoints[i])
-
- for i in range(len(nc.kn_qfrom_kdx)):
- print("(newtown_raphson_general.py) the from bus of the first qfrom kdx",
- branch_from_indices[nc.kn_qfrom_kdx[i]])
- print("(newtown_raphson_general.py) the setpoint of this", nc.kn_qfrom_setpoints[i])
-
- for i in range(len(nc.kn_pto_kdx)):
- print("(newtown_raphson_general.py) the to bus of the first pto kdx", branch_to_indices[nc.kn_pto_kdx[i]])
- print("(newtown_raphson_general.py) the setpoint of this", nc.kn_pto_setpoints[i])
-
- for i in range(len(nc.kn_qto_kdx)):
- print("(newtown_raphson_general.py) the to bus of the first qto kdx", branch_to_indices[nc.kn_qto_kdx[i]])
- print("(newtown_raphson_general.py) the setpoint of this", nc.kn_qto_setpoints[i])
-
- for i in range(len(nc.un_pfrom_kdx)):
- print("(newtown_raphson_general.py) known pfrom", branch_from_indices[nc.un_pfrom_kdx[i]])
-
- for i in range(len(nc.un_qfrom_kdx)):
- print("(newtown_raphson_general.py) known qfrom", branch_from_indices[nc.un_qfrom_kdx[i]])
-
- for i in range(len(nc.un_pto_kdx)):
- print("(newtown_raphson_general.py) known pto", branch_to_indices[nc.un_pto_kdx[i]])
-
- for i in range(len(nc.un_qto_kdx)):
- print("(newtown_raphson_general.py) known qto", branch_to_indices[nc.un_qto_kdx[i]])
-
- # Creating the known dictionary with checks for non-empty arrays
- known_dict = {
- 'Voltage': {idx: val for idx, val in zip(nc.kn_volt_idx, nc.kn_volt_setpoints) if
- len(nc.kn_volt_idx) > 0 and len(nc.kn_volt_setpoints) > 0},
- 'Angle': {idx: val for idx, val in zip(nc.kn_angle_idx, nc.kn_angle_setpoints) if
- len(nc.kn_angle_idx) > 0 and len(nc.kn_angle_setpoints) > 0},
- 'Pzip': {idx: val for idx, val in zip(nc.kn_pzip_idx, nc.kn_pzip_setpoints) if
- len(nc.kn_pzip_idx) > 0 and len(nc.kn_pzip_setpoints) > 0},
- 'Qzip': {idx: val for idx, val in zip(nc.kn_qzip_idx, nc.kn_qzip_setpoints) if
- len(nc.kn_qzip_idx) > 0 and len(nc.kn_qzip_setpoints) > 0},
- 'Pfrom': {
- (branch_from_indices[nc.kn_pfrom_kdx[i]], branch_to_indices[nc.kn_pfrom_kdx[i]]): nc.kn_pfrom_setpoints[i]
- for i in range(len(nc.kn_pfrom_kdx)) if len(nc.kn_pfrom_setpoints) > 0},
- 'Pto': {(branch_from_indices[nc.kn_pto_kdx[i]], branch_to_indices[nc.kn_pto_kdx[i]]): nc.kn_pto_setpoints[i] for
- i in range(len(nc.kn_pto_kdx)) if len(nc.kn_pto_setpoints) > 0},
- 'Qfrom': {
- (branch_from_indices[nc.kn_qfrom_kdx[i]], branch_to_indices[nc.kn_qfrom_kdx[i]]): nc.kn_qfrom_setpoints[i]
- for i in range(len(nc.kn_qfrom_kdx)) if len(nc.kn_qfrom_setpoints) > 0},
- 'Qto': {(branch_from_indices[nc.kn_qto_kdx[i]], branch_to_indices[nc.kn_qto_kdx[i]]): nc.kn_qto_setpoints[i] for
- i in range(len(nc.kn_qto_kdx)) if len(nc.kn_qto_setpoints) > 0},
- 'Modulation': {
- (branch_from_indices[nc.kn_mod_kdx[i]], branch_to_indices[nc.kn_mod_kdx[i]]): nc.kn_mod_setpoints[i] for i
- in range(len(nc.kn_mod_kdx)) if len(nc.kn_mod_setpoints) > 0},
- 'Tau': {(branch_from_indices[nc.kn_tau_kdx[i]], branch_to_indices[nc.kn_tau_kdx[i]]): nc.kn_tau_setpoints[i] for
- i in range(len(nc.kn_tau_kdx)) if len(nc.kn_tau_setpoints) > 0}
- }
-
- # Creating the unknown dictionary with similar checks
- unknown_dict = {
- 'Voltage': {idx: '' for idx in nc.un_volt_idx if len(nc.un_volt_idx) > 0},
- 'Angle': {idx: '' for idx in nc.un_angle_idx if len(nc.un_angle_idx) > 0},
- 'Pzip': {idx: '' for idx in nc.un_pzip_idx if len(nc.un_pzip_idx) > 0},
- 'Qzip': {idx: '' for idx in nc.un_qzip_idx if len(nc.un_qzip_idx) > 0},
- 'Pfrom': {(branch_from_indices[nc.un_pfrom_kdx[i]], branch_to_indices[nc.un_pfrom_kdx[i]]): '' for i in
- range(len(nc.un_pfrom_kdx)) if len(nc.un_pfrom_kdx) > 0},
- 'Pto': {(branch_from_indices[nc.un_pto_kdx[i]], branch_to_indices[nc.un_pto_kdx[i]]): '' for i in
- range(len(nc.un_pto_kdx)) if len(nc.un_pto_kdx) > 0},
- 'Qfrom': {(branch_from_indices[nc.un_qfrom_kdx[i]], branch_to_indices[nc.un_qfrom_kdx[i]]): '' for i in
- range(len(nc.un_qfrom_kdx)) if len(nc.un_qfrom_kdx) > 0},
- 'Qto': {(branch_from_indices[nc.un_qto_kdx[i]], branch_to_indices[nc.un_qto_kdx[i]]): '' for i in
- range(len(nc.un_qto_kdx)) if len(nc.un_qto_kdx) > 0},
- 'Modulation': {(branch_from_indices[nc.un_mod_kdx[i]], branch_to_indices[nc.un_mod_kdx[i]]): '' for i in
- range(len(nc.un_mod_kdx)) if len(nc.un_mod_kdx) > 0},
- 'Tau': {(branch_from_indices[nc.un_tau_kdx[i]], branch_to_indices[nc.un_tau_kdx[i]]): '' for i in
- range(len(nc.un_tau_kdx)) if len(nc.un_tau_kdx) > 0}
- }
-
- # Passive branch dictionary remains empty as previously defined
- passive_branch_dict = {
- 'Pfrom': {},
- 'Pto': {},
- 'Qfrom': {},
- 'Qto': {}
- }
-
- print("known_dict: ", known_dict)
- print("unknown_dict: ", unknown_dict)
- print("passive_branch_dict: ", passive_branch_dict)
-
- '''
- Using known values, update setpoints
- '''
- Vm0, Va0, S0, I0, Y0, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus = update_setpoints(known_dict, nc,
- Vm0, Va0, S0,
- I0, Y0, p_from,
- p_to, q_from,
- q_to, p_zip,
- q_zip,
- modulations,
- taus,
- verbose=0)
-
- '''
- Create unknowns vector
- '''
- x0 = var2x_raiyan_ver2(unknown_dict, Vm0, Va0, S0, I0, Y0, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations,
- taus, verbose=1)
-
- logger = Logger()
-
- ret: ConvexMethodResult = newton_raphson(func=pf_function_raiyan,
- func_args=(
- unknown_dict, passive_branch_dict, known_dict, Vm0, Va0, S0, I0, Y0, p_to,
- p_from, q_to, q_from, p_zip, q_zip, modulations, taus, nc.Ybus, nc,
- nc.dc_indices, nc.ac_indices),
- x0=x0,
- tol=pf_options.tolerance,
- max_iter=pf_options.max_iter,
- trust=pf_options.trust_radius,
- verbose=pf_options.verbose,
- logger=logger)
-
- Vm0, Va0, S0, I0, Y0, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus = update_setpoints(known_dict, nc,
- Vm0, Va0, S0,
- I0, Y0, p_from,
- p_to, q_from,
- q_to, p_zip,
- q_zip,
- modulations,
- taus,
- verbose=0)
- V = Vm0 * np.exp(1j * Va0)
- Scalc = compute_power(nc.Ybus, V)
-
- print("(newton_raphson_general.py) after compile information")
- print("(newton_raphson_general.py) nc.ac_indices", nc.ac_indices)
- print("(newton_raphson_general.py) nc.dc_indices", nc.dc_indices)
-
- print("(newton_raphson_general.py) vsc data")
- print("(newton_raphson_general.py) nc.vsc_data.F", nc.vsc_data.F)
- print("(newton_raphson_general.py) nc.vsc_data.T", nc.vsc_data.T)
-
- print("(newton_raphson_general.py) nc.vsc_data.branch_index", nc.vsc_data.branch_index)
-
- print("(newton_raphson_general.py) nc.kn_volt_idx")
- print(nc.kn_volt_idx)
- print(nc.kn_volt_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_angle_idx")
- print(nc.kn_angle_idx)
- print(nc.kn_angle_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_pzip_idx")
- print(nc.kn_pzip_idx)
- print(nc.kn_pzip_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_qzip_idx")
- print(nc.kn_qzip_idx)
- print(nc.kn_qzip_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_pfrom_kdx")
- print(nc.kn_pfrom_kdx)
- print(nc.kn_pfrom_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_qfrom_kdx")
- print(nc.kn_qfrom_kdx)
- print(nc.kn_qfrom_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_pto_kdx")
- print(nc.kn_pto_kdx)
- print(nc.kn_pto_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_qto_kdx")
- print(nc.kn_qto_kdx)
- print(nc.kn_qto_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_tau_kdx")
- print(nc.kn_tau_kdx)
- print(nc.kn_tau_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_mod_kdx")
- print(nc.kn_mod_kdx)
- print(nc.kn_mod_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_passive_pfrom_kdx")
- print(nc.kn_passive_pfrom_kdx)
- print(nc.kn_passive_pfrom_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_passive_qfrom_kdx")
- print(nc.kn_passive_qfrom_kdx)
- print(nc.kn_passive_qfrom_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_passive_pto_kdx")
- print(nc.kn_passive_pto_kdx)
- print(nc.kn_passive_pto_setpoints)
-
- print("(newton_raphson_general.py) nc.kn_passive_qto_kdx")
- print(nc.kn_passive_qto_kdx)
- print(nc.kn_passive_qto_setpoints)
-
- print("(newton_raphson_general.py) nc.un_volt_idx")
- print(nc.un_volt_idx)
-
- print("(newton_raphson_general.py) nc.un_angle_idx")
- print(nc.un_angle_idx)
-
- print("(newton_raphson_general.py) nc.un_pzip_idx")
- print(nc.un_pzip_idx)
-
- print("(newton_raphson_general.py) nc.un_qzip_idx")
- print(nc.un_qzip_idx)
-
- print("(newton_raphson_general.py) nc.un_pfrom_kdx")
- print(nc.un_pfrom_kdx)
-
- print("(newton_raphson_general.py) nc.un_qfrom_kdx")
- print(nc.un_qfrom_kdx)
-
- print("(newton_raphson_general.py) nc.un_pto_kdx")
- print(nc.un_pto_kdx)
-
- print("(newton_raphson_general.py) nc.un_qto_kdx")
- print(nc.un_qto_kdx)
-
- print("(newton_raphson_general.py) nc.un_tau_kdx")
- print(nc.un_tau_kdx)
-
- print("(newton_raphson_general.py) nc.un_mod_kdx")
- print(nc.un_mod_kdx)
-
- print("(newton_raphson_general.py) Voltages")
- for i in range(len(V)):
- print("Bus", i, ":", V[i])
-
- end = time.time()
- elapsed = end - start
-
- return NumericPowerFlowResults(V=V, converged=ret.converged, norm_f=ret.error,
- Scalc=Scalc)
-
-
-def isolate_AC_DC(nc, Ybus) -> csc_matrix:
- """
- Isolates the AC and DC components of a power nc within its admittance matrix.
-
- This function modifies the admittance matrix (Ybus) of a power nc to isolate the contributions of DC lines. It zeroes out the admittance values directly associated with DC lines and adjusts the matrix to account for the DC lines' resistances as conductances. This operation helps in analyzing the AC network components separately from DC elements.
-
- Parameters
- ----------
- nc : nc object
- An object representing the power nc, which includes AC and DC buses and lines.
- Ybus : csc_matrix
- The original sparse column-compressed admittance matrix of the nc.
-
- Returns
- -------
- csc_matrix
- The modified admittance matrix with the AC and DC components isolated.
-
- """
- _matrix = Ybus.copy()
- n = _matrix.shape[0] # Assuming Ybus is square
-
- # iterate through and first delete anything that has to do with the dc_lines
- for i in range(len(nc.vsc_data.F)):
- # Get indices for the buses
- from_idx = nc.vsc_data.F[i]
- to_idx = nc.vsc_data.T[i]
- _z1 = _matrix[from_idx, to_idx]
- _z2 = _matrix[to_idx, from_idx]
- _matrix[from_idx, to_idx] = 0
- _matrix[to_idx, from_idx] = 0
-
- # set all diagonals to zero
- for i in range(n):
- _matrix[i, i] = 0
-
- # recalculate the diagonals
- for i in range(n):
- _matrix[i, i] = -np.sum(_matrix[i, :])
-
- # for elm in nc.dc_lines:
- # # Get indices for the buses
- # from_idx = nc.buses.index(elm.bus_from)
- # to_idx = nc.buses.index(elm.bus_to)
-
- # # print("from_idx: ", from_idx)
- # # print("to_idx: ", to_idx)
- # # print("R", elm.R)
-
- # # Convert resistance to conductance?
- # G = 1 / elm.R
- # # G = elm.R
-
- # # Subtract conductance from off-diagonal elements
- # _matrix[from_idx, to_idx] -= G
- # _matrix[to_idx, from_idx] -= G
-
- # # Add conductance to diagonal elements
- # _matrix[from_idx, from_idx] += G
- # _matrix[to_idx, to_idx] += G
-
- # print("altered Ybus: ", _matrix.copy().todense())
-
- return _matrix
-
-
-def update_setpoints(known_dict,
- nc,
- Vm0,
- Va0,
- S0,
- I0,
- Y0,
- p_from,
- p_to,
- q_from,
- q_to,
- p_zip,
- q_zip,
- modulations,
- taus,
- verbose=0):
- """
- Updates the initial setpoints for various nc parameters based on the known values.
-
- This function takes a dictionary of known setpoints for different parameters (such as voltage magnitude, voltage angle, power flows, and others) and updates the corresponding initial guess arrays/lists for these parameters.
-
- Parameters
- ----------
- known_dict : dict
- A dictionary containing known setpoints for various parameters like 'Voltage', 'Angle', 'Pto', etc.
- nc : nc object
- The electrical nc object. Currently not used directly but required for future extensions or checks.
- Vm0, Va0 : list or np.array
- Initial guesses for voltage magnitudes and angles, respectively.
- S0, I0, Y0 : list or np.array
- Not directly updated but included for consistency and future use.
- p_from, p_to, q_from, q_to : list or np.array
- Lists containing initial guesses for active and reactive power flows from and to connected buses.
- p_zip, q_zip : list or np.array
- Lists containing initial guesses for active and reactive ZIP load injections at buses.
- modulations, taus : list or np.array
- Lists containing initial guesses for modulation values and time constants associated with dynamic components.
- verbose : int, optional
- If set to 1, prints updated arrays/lists after applying known setpoints.
-
- Returns
- -------
- tuple
- Returns a tuple containing updated arrays/lists for all input parameters, reflecting the known setpoints.
- """
-
- # Check and update 'Voltage' if it's present in known_dict
- if 'Voltage' in known_dict:
- for bus_index, voltage in known_dict['Voltage'].items():
- Vm0[bus_index] = voltage # Update the voltage magnitude at the specified bus index
-
- # Check and update 'Angle' if it's present in known_dict
- if 'Angle' in known_dict:
- for bus_index, angle in known_dict['Angle'].items():
- Va0[bus_index] = angle # Convert angle to radians and update
-
- if 'Pto' in known_dict:
- for bus_index, pto in known_dict['Pto'].items():
- # add the pto setpoint to the p_to list using the index
- p_to[bus_index[1]] = pto
-
- if 'Pfrom' in known_dict:
- for bus_index, pfrom in known_dict['Pfrom'].items():
- # add the pfrom setpoint to the p_from list using the index
- p_from[bus_index[0]] = pfrom
-
- if 'Qto' in known_dict:
- for bus_index, qto in known_dict['Qto'].items():
- # add the qto setpoint to the q_to list using the index
- q_to[bus_index[1]] = qto
-
- if 'Qfrom' in known_dict:
- for bus_index, qfrom in known_dict['Qfrom'].items():
- # add the qfrom setpoint to the q_from list using the index
- q_from[bus_index[0]] = qfrom
-
- if 'Pzip' in known_dict:
- for bus_index, pzip in known_dict['Pzip'].items():
- # add the pzip setpoint to the p_zip list using the index
- p_zip[bus_index] = pzip
-
- if 'Qzip' in known_dict:
- for bus_index, qzip in known_dict['Qzip'].items():
- # add the qzip setpoint to the q_zip list using the index
- q_zip[bus_index] = qzip
-
- if 'Modulation' in known_dict:
- for bus_index, modulation in known_dict['Modulation'].items():
- modulations[bus_index[0]] = modulation
-
- if 'Tau' in known_dict:
- for bus_index, tau in known_dict['Tau'].items():
- taus[bus_index[0]] = tau
-
- if verbose:
- print('Vm0 after updating known Voltage setpoints:', Vm0)
- print('Va0 after updating known Angle setpoints:', Va0)
- print('Pto after updating known Pto setpoints:', p_to)
- print('Pfrom after updating known Pfrom setpoints:', p_from)
- print('Qto after updating known Qto setpoints:', q_to)
- print('Qfrom after updating known Qfrom setpoints:', q_from)
- print('Pzip after updating known Pzip setpoints:', p_zip)
- print('Qzip after updating known Qzip setpoints:', q_zip)
- print('Modulation after updating known Modulation setpoints:', modulations)
- print('Tau after updating known Tau setpoints:', taus)
- return Vm0, Va0, S0, I0, Y0, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus
-
-
-def pf_function_raiyan(x: Vec,
- compute_jac: bool,
- # these are the args:
- unknown_dict: dict,
- passive_branch_dict: dict,
- known_dict: dict,
- Vm0: Vec,
- Va0: Vec,
- S0: CxVec,
- I0: CxVec,
- Y0: CxVec,
- p_to: Vec,
- p_from: Vec,
- q_to: Vec,
- q_from: Vec,
- p_zip: Vec,
- q_zip: Vec,
- modulations: Vec,
- taus: Vec,
- Ybus: CscMat,
- nc: NumericalCircuit,
- dc_buses: IntVec,
- ac_buses) -> ConvexFunctionResult:
- Va = Va0.copy()
- Vm = Vm0.copy()
- Vm, Va, S0, I0, Y0, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus = x2var_raiyan_ver2(x, unknown_dict,
- Vm0, Va0, S0,
- I0, Y0, p_to,
- p_from, q_to,
- q_from, p_zip,
- q_zip,
- modulations,
- taus, verbose=0)
- V = Vm * np.exp(1j * Va)
-
- g = compute_g(V, Ybus, S0, I0, Y0, Vm, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus, nc, dc_buses,
- ac_buses, passive_branch_dict, known_dict)
-
- if compute_jac:
- Gx = compute_gx(x, g, Vm, Va, Ybus, S0, I0, Y0, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus, nc,
- dc_buses, ac_buses, unknown_dict, passive_branch_dict, known_dict)
- else:
- Gx = None
-
- return ConvexFunctionResult(f=g, J=Gx)
-
-
-def compute_g(V, Ybus, S0, I0, Y0, Vm, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus, nc, dc_buses,
- ac_buses, passive_branch_dict, known_dict) -> Vec:
- """
- Compose the power flow function
- :param V:
- :param Ybus:
- :param S0:
- :param I0:
- :param Y0:
- :param Vm:
- :param pq:
- :param pvpq:
- :return:
- """
- Sbus = compute_zip_power(S0, I0, Y0, Vm)
- Scalc = compute_power(Ybus, V)
-
- # mapping of bus-VSC and bus-trafo
- vsc_frombus = nc.vsc_data.F
- vsc_tobus = nc.vsc_data.T
- controllable_trafo_frombus = np.zeros((0))
- controllable_trafo_tobus = np.zeros((0))
- controllable_trafo_yshunt = np.zeros((0))
- controllable_trafo_yseries = np.zeros((0))
-
- g = compute_fx_raiyan(Scalc, Sbus, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus, dc_buses, ac_buses,
- vsc_frombus, vsc_tobus, controllable_trafo_frombus, controllable_trafo_tobus,
- controllable_trafo_yshunt, controllable_trafo_yseries, V, passive_branch_dict, known_dict,
- Ybus)
- return g
-
-
-def compute_gx(x, fx, Vm, Va, Ybus, S0, I0, Y0, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus, nc,
- dc_buses, ac_buses, unknown_dict, passive_branch_dict, known_dict) -> CscMat:
- """
- Autodiff jacobian
- :param x:
- :param fx:
- :param Vm:
- :param Va:
- :param Ybus:
- :param S0:
- :param I0:
- :param Y0:
- :param p_to:
- :param p_from:
- :param q_to:
- :param q_from:
- :param p_zip:
- :param q_zip:
- :param modulations:
- :param taus:
- :param nc:
- :param dc_buses:
- :param ac_buses:
- :param unknown_dict:
- :param passive_branch_dict:
- :param known_dict:
- :return:
- """
- delta = 1e-6
- x1 = x.copy()
- J = np.zeros((len(x), len(x)), dtype=float)
- for i in range(len(x)):
- '''
- Make a deepcopy and alter the ith element
- '''
- x1 = np.array(x.copy())
- Va_after = np.array(Va.copy())
- Vm_after = np.array(Vm.copy())
- p_to_after = np.array(p_to.copy())
- p_from_after = np.array(p_from.copy())
- q_to_after = np.array(q_to.copy())
- q_from_after = np.array(q_from.copy())
- p_zip_after = np.array(p_zip.copy())
- q_zip_after = np.array(q_zip.copy())
- modulations_after = np.array(modulations.copy())
- taus_after = np.array(taus.copy())
- x1[i] += delta
-
- '''
- Put the unknowns back into their vectors
- '''
- Vm_after, Va_after, S0, I0, Y0, p_to_after, p_from_after, q_to_after, q_from_after, p_zip_after, q_zip_after, modulations_after, taus_after = x2var_raiyan_ver2(
- x1, unknown_dict, Vm_after, Va_after, S0, I0, Y0, p_to_after, p_from_after, q_to_after, q_from_after,
- p_zip_after, q_zip_after, modulations_after, taus_after, verbose=0)
-
- '''
- Calculate powers
- '''
- V = Vm_after * np.exp(1j * Va_after)
- Sbus = compute_zip_power(S0, I0, Y0, Vm)
- Scalc = compute_power(Ybus, V)
-
- '''
- Get the difference in the vectors and append to J
- '''
- # move this outside maybe? get mapping between bus-vsc and bus-trafo
- vsc_frombus = nc.vsc_data.F
- vsc_tobus = nc.vsc_data.T
- controllable_trafo_frombus = np.zeros((0))
- controllable_trafo_tobus = np.zeros((0))
- controllable_trafo_yshunt = np.zeros((0))
- controllable_trafo_yseries = np.zeros((0))
-
- fx_altered = compute_fx_raiyan(Scalc, Sbus, p_to_after, p_from_after, q_to_after, q_from_after, p_zip_after,
- q_zip_after, modulations_after, taus_after, dc_buses, ac_buses, vsc_frombus,
- vsc_tobus, controllable_trafo_frombus, controllable_trafo_tobus,
- controllable_trafo_yshunt, controllable_trafo_yseries, V, passive_branch_dict,
- known_dict, Ybus)
- diff = (fx_altered - fx) / delta
- J[:, i] = diff
-
- # print("(newton_raphson_general.py) J: ")
- # print(J)
- # make a df of J
- # import pandas as pd
- # df = pd.DataFrame(J)
- # listOfFuncs = ['DC Real Bus:3', 'DC Real Bus:4', 'DC Real Bus:5', 'AC Real Bus:0', 'AC Imag Bus:0', 'AC Real Bus:1', 'AC Imag Bus:1', 'AC Real Bus:2', 'AC Imag Bus:2', 'AC Real Bus:6', 'AC Imag Bus:6', 'AC Real Bus:7', 'AC Imag Bus:7', 'AC Real Bus:8', 'AC Imag Bus:8', 'AC Real Bus:9', 'AC Imag Bus:9', 'VSC Active Power Balance:32', 'VSC Active Power Balance:56', 'Trafo Active Power From:8', 'Trafo Active Power From:8', 'Trafo Reactive Power To:9', 'Trafo Reactive Power To:9']
- # df.index = listOfFuncs
- # df.columns = ['V_1', 'V_2', 'V_4', 'V_5', 'V_7', 'V_8', 'Angle_1', 'Angle_2', 'Angle_6', 'Angle_7', 'Angle_8', 'Pzip_0', 'Pzip_9', 'Qzip_0', 'Qzip_9', 'Pfrom_3', 'Pfrom_5', 'Pfrom_8', 'Pto_2', 'Pto_6', 'Qfrom_8', 'Qto_9', 'Mod_8']
-
- return csr_matrix((J), shape=(len(x), len(x))).tocsc()
-
-
-def compute_fx_raiyan(Scalc, Sbus, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus, dc_buses, ac_buses,
- vsc_frombus, vsc_tobus, controllable_trafo_frombus, controllable_trafo_tobus,
- controllable_trafo_yshunt, controllable_trafo_yseries, V, passive_branch_dict, known_dict,
- Ybus) -> Vec:
- """
- Compute the NR-like error function
- :param Scalc: Calculated power injections
- :param Sbus: Specified power injections
- :return: error
- """
- a = 0.00010000
- b = 0.01500000
- c = 0.20000000
-
- fx = []
- listOfFuncs = []
-
- '''
- DC bus active power balance
- '''
- for bus in dc_buses:
- fx.append(Scalc[bus].real - Sbus[bus].real + p_to[bus] + p_from[bus] - p_zip[bus])
- listOfFuncs.append("DC Real Bus:" + str(bus))
-
- '''
- AC bus active and reactive power balance
- '''
- for bus in ac_buses:
- fx.append(Scalc[bus].real - Sbus[bus].real + p_to[bus] + p_from[bus] - p_zip[bus])
- fx.append(Scalc[bus].imag - Sbus[bus].imag + q_to[bus] + q_from[bus] - q_zip[bus])
- listOfFuncs.append("AC Real Bus:" + str(bus))
- listOfFuncs.append("AC Imag Bus:" + str(bus))
-
- '''
- VSC active power balance
- '''
- Vm = np.abs(V)
- for busfrom, busTo in zip(vsc_frombus, vsc_tobus):
- _loss = (p_to[busTo] ** 2 + q_to[busTo] ** 2) ** 0.5 / Vm[busTo]
- fx.append(a + b * _loss + c * _loss ** 2 - p_to[busTo] - p_from[busfrom])
- listOfFuncs.append("VSC Active Power Balance:" + str(busfrom) + str(busTo))
-
- '''
- Trafo from and to bus active and reactive power balance
- '''
- for i in range(len(controllable_trafo_frombus)):
- # right what are we going to do here, we need to form four equations
- _a = Vm[controllable_trafo_frombus[i]] ** 2 * (
- np.conj(controllable_trafo_yseries[i]) + np.conj(controllable_trafo_yshunt[i])) / modulations[
- controllable_trafo_frombus[i]] ** 2
- _b = V[controllable_trafo_frombus[i]] * np.conj(V[controllable_trafo_tobus[i]]) * np.conj(
- controllable_trafo_yseries[i]) / (
- modulations[controllable_trafo_frombus[i]] * np.exp(1j * taus[controllable_trafo_frombus[i]]))
- Sfrom = _a - _b
- _c = Vm[controllable_trafo_tobus[i]] ** 2 * (
- np.conj(controllable_trafo_yseries[i]) + np.conj(controllable_trafo_yshunt[i]))
- _d = V[controllable_trafo_tobus[i]] * np.conj(V[controllable_trafo_frombus[i]]) * np.conj(
- controllable_trafo_yseries[i]) / (
- modulations[controllable_trafo_frombus[i]] * np.exp(-1j * taus[controllable_trafo_frombus[i]]))
- Sto = _c - _d
-
- fx.append(Sfrom.real - p_from[controllable_trafo_frombus[i]])
- fx.append(Sto.real - p_to[controllable_trafo_tobus[i]])
- fx.append(Sfrom.imag - q_from[controllable_trafo_frombus[i]])
- fx.append(Sto.imag - q_to[controllable_trafo_tobus[i]])
-
- listOfFuncs.append("Trafo Active Power From:" + str(controllable_trafo_frombus[i]))
- listOfFuncs.append("Trafo Active Power From:" + str(controllable_trafo_frombus[i]))
- listOfFuncs.append("Trafo Reactive Power To:" + str(controllable_trafo_tobus[i]))
- listOfFuncs.append("Trafo Reactive Power To:" + str(controllable_trafo_tobus[i]))
-
- if len(passive_branch_dict["Pfrom"]):
- for key, value in passive_branch_dict["Pfrom"].items():
- print("Passive Branch Active Power From:")
- print("Key: ", key)
- print("Value: ", value)
- from_bus = key[0]
- to_bus = key[1]
- _a = value - (V[from_bus] * (V[from_bus] - V[to_bus]) * np.conj(Ybus[from_bus, to_bus])).real
- fx.append(_a)
-
- if len(passive_branch_dict["Pto"]):
- for key, value in passive_branch_dict["Pto"].items():
- print("Passive Branch Active Power To:")
- print("Key: ", key)
- print("Value: ", value)
- from_bus = key[0]
- to_bus = key[1]
- _a = value - (V[to_bus] * (V[to_bus] - V[from_bus]) * np.conj(Ybus[to_bus, from_bus])).real
- fx.append(_a)
-
- if len(passive_branch_dict["Qfrom"]):
- for key, value in passive_branch_dict["Qfrom"].items():
- print("Passive Branch Reactive Power From:")
- print("Key: ", key)
- print("Value: ", value)
- from_bus = key[0]
- to_bus = key[1]
- _a = value - (V[from_bus] * (V[from_bus] - V[to_bus]) * np.conj(Ybus[from_bus, to_bus])).imag
- fx.append(_a)
-
- if len(passive_branch_dict["Qto"]):
- for key, value in passive_branch_dict["Qto"].items():
- print("Passive Branch Reactive Power To:")
- print("Key: ", key)
- print("Value: ", value)
- from_bus = key[0]
- to_bus = key[1]
- _a = value - (V[to_bus] * (V[to_bus] - V[from_bus]) * np.conj(Ybus[to_bus, from_bus])).imag
- fx.append(_a)
-
- # DO NOT DELETE THIS LINE: nb has does not do well with loops
- for i in range(1):
- pass
-
- return np.array(fx)
-
-
-def x2var_raiyan_ver2(x0,
- unknown_dict,
- Vm0, Va0,
- S0, I0, Y0,
- p_to, p_from, q_to, q_from,
- p_zip, q_zip,
- modulations,
- taus,
- verbose=1):
- """
- Arrange the unknowns vector into the physical variables
- """
-
- # Initialize an index for x0
- x0_index = 0
-
- # Process Voltage and Angle which are directly indexed
- if 'Voltage' in unknown_dict:
- for bus_index in unknown_dict['Voltage']:
- Vm0[bus_index] = x0[x0_index]
- x0_index += 1
- if 'Angle' in unknown_dict:
- for bus_index in unknown_dict['Angle']:
- Va0[bus_index] = x0[x0_index]
- x0_index += 1
-
- # Assuming similar direct indexing for Pzip, Qzip, Modulation, and Tau
- if 'Pzip' in unknown_dict:
- for bus_index in unknown_dict['Pzip']:
- p_zip[bus_index] = x0[x0_index]
- x0_index += 1
- if 'Qzip' in unknown_dict:
- for bus_index in unknown_dict['Qzip']:
- q_zip[bus_index] = x0[x0_index]
- x0_index += 1
-
- # Process other parameters which might involve tuple keys
- # For tuples, use the specified index for p_from/p_to and q_from/q_to
- for category, items in unknown_dict.items():
- if category in ['Pfrom', 'Pto', 'Qfrom', 'Qto', 'Modulation', 'Tau']:
- for bus_indices in items:
- if category == 'Pfrom':
- p_from[bus_indices[0]] = x0[x0_index]
- elif category == 'Pto':
- p_to[bus_indices[1]] = x0[x0_index]
- elif category == 'Qfrom':
- q_from[bus_indices[0]] = x0[x0_index]
- elif category == 'Qto':
- q_to[bus_indices[1]] = x0[x0_index]
- elif category == 'Modulation':
- modulations[bus_indices[0]] = x0[x0_index]
- elif category == 'Tau':
- taus[bus_indices[0]] = x0[x0_index]
- # raise an aerror
- x0_index += 1
-
- if verbose:
- # Print updated values
- print("Updated Vm0: ", Vm0)
- print("Updated Va0: ", Va0)
- print("Updated p_to: ", p_to)
- print("Updated p_from: ", p_from)
- print("Updated q_to: ", q_to)
- print("Updated q_from: ", q_from)
- print("Updated p_zip: ", p_zip)
- print("Updated q_zip: ", q_zip)
- print("Updated modulations: ", modulations)
- print("Updated taus: ", taus)
-
- # Return the updated arrays
- return Vm0, Va0, S0, I0, Y0, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus
-
-
-def var2x_raiyan_ver2(unknown_dict, Vm0, Va0, S0, I0, Y0, p_to, p_from, q_to, q_from, p_zip, q_zip, modulations, taus,
- verbose=0):
- """
- Converts variable parameters into a vector form based on a dictionary of unknowns.
-
- This function takes various electrical network parameters and a dictionary specifying which of these parameters are unknown. It then constructs a vector `x` that contains the values of these unknown parameters for use in optimization or analysis processes. Additionally, it generates a list of names `x_names` corresponding to each entry in `x` for identification.
-
- Parameters
- ----------
- unknown_dict : dict
- A dictionary with keys corresponding to parameter types (e.g., 'Voltage', 'Angle') and values being lists of indices or tuples indicating which parameters are unknown.
- Vm0, Va0 : list or np.array
- Lists containing initial guesses or values for voltage magnitudes and angles, respectively.
- S0, I0, Y0 : list or np.array
- Lists containing initial values for power, current, and admittance injections at buses (not directly used but included for completeness and future extensions).
- p_to, p_from, q_to, q_from : list or np.array
- Lists containing power flow values to and from connected buses.
- p_zip, q_zip : list or np.array
- Lists containing ZIP load injections at buses.
- modulations, taus : list or np.array
- Lists containing modulation variables and time constants associated with dynamic elements of the network.
- verbose : int, optional
- If set to 1, prints detailed information about the constructed vector `x` and its identifiers `x_names`.
-
- Returns
- -------
- list
- The vector `x` containing values for the unknown parameters as specified in `unknown_dict`.
- """
-
- x = []
- x_names = []
-
- if 'Voltage' in unknown_dict:
- for bus_index in unknown_dict['Voltage']:
- x.append(Vm0[bus_index])
- x_names.append(f'Voltage_{bus_index}')
-
- if 'Angle' in unknown_dict:
- for bus_index in unknown_dict['Angle']:
- x.append(Va0[bus_index])
- x_names.append(f'Angle_{bus_index}')
-
- if 'Pzip' in unknown_dict:
- for bus_index in unknown_dict['Pzip']:
- x.append(p_zip[bus_index])
- x_names.append(f'Pzip_{bus_index}')
-
- if 'Qzip' in unknown_dict:
- for bus_index in unknown_dict['Qzip']:
- x.append(q_zip[bus_index])
- x_names.append(f'Qzip_{bus_index}')
-
- if 'Pfrom' in unknown_dict:
- for bus_indices in unknown_dict['Pfrom']:
- x.append(p_from[bus_indices[0]])
- x_names.append(f'Pfrom_{bus_indices[0]}')
-
- if 'Pto' in unknown_dict:
- for bus_indices in unknown_dict['Pto']:
- x.append(p_to[bus_indices[1]])
- x_names.append(f'Pto_{bus_indices[1]}')
-
- if 'Qfrom' in unknown_dict:
- for bus_indices in unknown_dict['Qfrom']:
- x.append(q_from[bus_indices[0]])
- x_names.append(f'Qfrom_{bus_indices[0]}')
-
- if 'Qto' in unknown_dict:
- for bus_indices in unknown_dict['Qto']:
- x.append(q_to[bus_indices[1]])
- x_names.append(f'Qto_{bus_indices[1]}')
-
- if 'Modulation' in unknown_dict:
- for bus_indices in unknown_dict['Modulation']:
- x.append(modulations[bus_indices[0]])
- x_names.append(f'Modulation_{bus_indices[0]}')
-
- if 'Tau' in unknown_dict:
- for bus_indices in unknown_dict['Tau']:
- x.append(taus[bus_indices[0]])
- x_names.append(f'Tau_{bus_indices[0]}')
-
- if verbose:
- print('Unknowns vector x:', x)
- print('Identifiers of x:', x_names)
- print('Length of x:', len(x))
-
- return x
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/pf_advanced_formulation.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/pf_advanced_formulation.py
new file mode 100644
index 000000000..4b2d1a21c
--- /dev/null
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/pf_advanced_formulation.py
@@ -0,0 +1,848 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from typing import Tuple, List, Callable
+import numpy as np
+import pandas as pd
+from numba import njit
+from scipy.sparse import lil_matrix, csc_matrix
+from GridCalEngine.Topology.admittance_matrices import compute_admittances
+from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
+from GridCalEngine.Simulations.PowerFlow.power_flow_options import PowerFlowOptions
+from GridCalEngine.DataStructures.numerical_circuit import NumericalCircuit
+import GridCalEngine.Simulations.Derivatives.csc_derivatives as deriv
+from GridCalEngine.Topology.simulation_indices import compile_types
+from GridCalEngine.Utils.Sparse.csc2 import CSC, CxCSC, sp_slice, csc_stack_2d_ff, scipy_to_mat
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import expand
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import compute_fx_error
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import (control_q_inside_method,
+ compute_slack_distribution)
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.pf_formulation_template import PfFormulationTemplate
+from GridCalEngine.enumerations import BusMode, TapPhaseControl, TapModuleControl
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import (compute_zip_power, compute_power,
+ polar_to_rect, get_Sf, get_St,
+ get_It)
+from GridCalEngine.basic_structures import Vec, IntVec, CxVec, Logger
+
+
+@njit()
+def adv_jacobian(nbus: int,
+ nbr: int,
+ idx_dva: IntVec,
+ idx_dvm: IntVec,
+ idx_dm: IntVec,
+ idx_dtau: IntVec,
+ idx_dbeq: IntVec,
+ idx_dP: IntVec,
+ idx_dQ: IntVec,
+ idx_dPf: IntVec,
+ idx_dQf: IntVec,
+ idx_dPt: IntVec,
+ idx_dQt: IntVec,
+ F: IntVec,
+ T: IntVec,
+ Ys: CxVec,
+ kconv: Vec,
+ complex_tap: CxVec,
+ tap_modules: Vec,
+ Bc: Vec,
+ Beq: Vec,
+ V: CxVec,
+ Vm: Vec,
+ Ybus_x: CxVec,
+ Ybus_p: IntVec,
+ Ybus_i: IntVec,
+ yff: CxVec,
+ yft: CxVec,
+ ytf: CxVec,
+ ytt: CxVec) -> CSC:
+ """
+ Compute the advanced jacobian
+ :param nbus:
+ :param nbr:
+ :param idx_dva:
+ :param idx_dvm:
+ :param idx_dm:
+ :param idx_dtau:
+ :param idx_dbeq:
+ :param idx_dP:
+ :param idx_dQ:
+ :param idx_dQf:
+ :param idx_dPf:
+ :param idx_dPt:
+ :param idx_dQt:
+ :param F:
+ :param T:
+ :param Ys: Series admittance 1 / (R + jX)
+ :param kconv:
+ :param complex_tap:
+ :param tap_modules:
+ :param Bc: Total changing susceptance
+ :param Beq:
+ :param V:
+ :param Vm:
+ :param Ybus_x:
+ :param Ybus_p:
+ :param Ybus_i:
+ :param yff:
+ :param yft:
+ :param ytf:
+ :param ytt:
+ :return:
+ """
+ # bus-bus derivatives (always needed)
+ dS_dVm_x, dS_dVa_x = deriv.dSbus_dV_numba_sparse_csc(Ybus_x, Ybus_p, Ybus_i, V, Vm)
+ dS_dVm = CxCSC(nbus, nbus, len(dS_dVm_x), False).set(Ybus_i, Ybus_p, dS_dVm_x)
+ dS_dVa = CxCSC(nbus, nbus, len(dS_dVa_x), False).set(Ybus_i, Ybus_p, dS_dVa_x)
+
+ dP_dVa__ = sp_slice(dS_dVa.real, idx_dP, idx_dva)
+ dQ_dVa__ = sp_slice(dS_dVa.imag, idx_dQ, idx_dva)
+ dPf_dVa_ = deriv.dSf_dVa_csc(nbus, idx_dPf, idx_dva, yff, yft, V, F, T).real
+ dQf_dVa_ = deriv.dSf_dVa_csc(nbus, idx_dQf, idx_dva, yff, yft, V, F, T).imag
+ dPt_dVa_ = deriv.dSt_dVa_csc(nbus, idx_dPt, idx_dva, ytf, V, F, T).real
+ dQt_dVa_ = deriv.dSt_dVa_csc(nbus, idx_dQt, idx_dva, ytf, V, F, T).imag
+
+ dP_dVm__ = sp_slice(dS_dVm.real, idx_dP, idx_dvm)
+ dQ_dVm__ = sp_slice(dS_dVm.imag, idx_dQ, idx_dvm)
+ dPf_dVm_ = deriv.dSf_dVm_csc(nbus, idx_dPf, idx_dvm, yff, yft, V, F, T).real
+ dQf_dVm_ = deriv.dSf_dVm_csc(nbus, idx_dQf, idx_dvm, yff, yft, V, F, T).imag
+ dPt_dVm_ = deriv.dSt_dVm_csc(nbus, idx_dPt, idx_dvm, ytt, ytf, V, F, T).real
+ dQt_dVm_ = deriv.dSt_dVm_csc(nbus, idx_dQt, idx_dvm, ytt, ytf, V, F, T).imag
+
+ dP_dm__ = deriv.dSbus_dm_csc(nbus, idx_dP, idx_dm, F, T, Ys, Bc, Beq, kconv, complex_tap, tap_modules, V).real
+ dQ_dm__ = deriv.dSbus_dm_csc(nbus, idx_dQ, idx_dm, F, T, Ys, Bc, Beq, kconv, complex_tap, tap_modules, V).imag
+ dPf_dm_ = deriv.dSf_dm_csc(nbr, idx_dPf, idx_dm, F, T, Ys, Bc, Beq, kconv, complex_tap, tap_modules, V).real
+ dQf_dm_ = deriv.dSf_dm_csc(nbr, idx_dQf, idx_dm, F, T, Ys, Bc, Beq, kconv, complex_tap, tap_modules, V).imag
+ dPt_dm_ = deriv.dSt_dm_csc(nbr, idx_dPt, idx_dm, F, T, Ys, kconv, complex_tap, tap_modules, V).real
+ dQt_dm_ = deriv.dSt_dm_csc(nbr, idx_dQt, idx_dm, F, T, Ys, kconv, complex_tap, tap_modules, V).imag
+
+ dP_dtau__ = deriv.dSbus_dtau_csc(nbus, idx_dP, idx_dtau, F, T, Ys, kconv, complex_tap, V).real
+ dQ_dtau__ = deriv.dSbus_dtau_csc(nbus, idx_dQ, idx_dtau, F, T, Ys, kconv, complex_tap, V).imag
+ dPf_dtau_ = deriv.dSf_dtau_csc(nbr, idx_dPf, idx_dtau, F, T, Ys, kconv, complex_tap, V).real
+ dQf_dtau_ = deriv.dSf_dtau_csc(nbr, idx_dQf, idx_dtau, F, T, Ys, kconv, complex_tap, V).imag
+ dPt_dtau_ = deriv.dSt_dtau_csc(nbr, idx_dPt, idx_dtau, F, T, Ys, kconv, complex_tap, V).real
+ dQt_dtau_ = deriv.dSt_dtau_csc(nbr, idx_dQt, idx_dtau, F, T, Ys, kconv, complex_tap, V).imag
+
+ dP_dbeq__ = deriv.dSbus_dbeq_csc(nbus, idx_dP, idx_dbeq, F, kconv, tap_modules, V).real
+ dQ_dbeq__ = deriv.dSbus_dbeq_csc(nbus, idx_dQ, idx_dbeq, F, kconv, tap_modules, V).imag
+ dPf_dbeq_ = deriv.dSf_dbeq_csc(nbr, idx_dPf, idx_dbeq, F, kconv, tap_modules, V).real
+ dQf_dbeq_ = deriv.dSf_dbeq_csc(nbr, idx_dQf, idx_dbeq, F, kconv, tap_modules, V).imag
+ dPt_dbeq_ = deriv.dSt_dbeq_csc(idx_dPt, idx_dbeq).real
+ dQt_dbeq_ = deriv.dSt_dbeq_csc(idx_dQt, idx_dbeq).imag
+
+ # compose the Jacobian
+ J = csc_stack_2d_ff(mats=
+ [dP_dVa__, dP_dVm__, dP_dm__, dP_dtau__, dP_dbeq__,
+ dQ_dVa__, dQ_dVm__, dQ_dm__, dQ_dtau__, dQ_dbeq__,
+ dPf_dVa_, dPf_dVm_, dPf_dm_, dPf_dtau_, dPf_dbeq_,
+ dQf_dVa_, dQf_dVm_, dQf_dm_, dQf_dtau_, dQf_dbeq_,
+ dPt_dVa_, dPt_dVm_, dPt_dm_, dPt_dtau_, dPt_dbeq_,
+ dQt_dVa_, dQt_dVm_, dQt_dm_, dQt_dtau_, dQt_dbeq_],
+ n_rows=6, n_cols=5)
+
+ return J
+
+
+def calc_autodiff_jacobian(func: Callable[[Vec], Vec], x: Vec, h=1e-8) -> csc_matrix:
+ """
+ Compute the Jacobian matrix of `func` at `x` using finite differences.
+
+ :param func: function accepting a vector x and args, and returning either a vector or a
+ tuple where the first argument is a vector and the second.
+ :param x: Point at which to evaluate the Jacobian (numpy array).
+ :param h: Small step for finite difference.
+ :return: Jacobian matrix as a CSC matrix.
+ """
+ nx = len(x)
+ f0 = func(x)
+
+ n_rows = len(f0)
+
+ jac = lil_matrix((n_rows, nx))
+
+ for j in range(nx):
+ x_plus_h = np.copy(x)
+ x_plus_h[j] += h
+ f_plus_h = func(x_plus_h)
+ row = (f_plus_h - f0) / h
+ for i in range(n_rows):
+ if row[i] != 0.0:
+ jac[i, j] = row[i]
+
+ return jac.tocsc()
+
+
+class PfAdvancedFormulation(PfFormulationTemplate):
+
+ def __init__(self, V0: CxVec, S0: CxVec, I0: CxVec, Y0: CxVec,
+ Qmin: Vec, Qmax: Vec,
+ nc: NumericalCircuit,
+ options: PowerFlowOptions,
+ logger: Logger):
+ """
+ Constructor
+ :param V0: Initial voltage solution
+ :param S0: Set power injections
+ :param I0: Set current injections
+ :param Y0: Set admittance injections
+ :param Qmin: Minimum reactive power per bus
+ :param Qmax: Maximum reactive power per bus
+ :param nc: NumericalCircuit
+ :param options: PowerFlowOptions
+ :param logger: Logger (modified in-place)
+ """
+ PfFormulationTemplate.__init__(self, V0=V0, options=options)
+
+ self.nc: NumericalCircuit = nc
+
+ self.logger: Logger = logger
+
+ self.S0: CxVec = S0
+ self.I0: CxVec = I0
+ self.Y0: CxVec = Y0
+
+ self.Qmin = Qmin
+ self.Qmax = Qmax
+
+ self.bus_types = self.nc.bus_data.bus_types.copy()
+ self.tap_module_control_mode = self.nc.branch_data.tap_module_control_mode.copy()
+ self.tap_phase_control_mode = self.nc.branch_data.tap_phase_control_mode.copy()
+
+ self.pq = np.array(0, dtype=int)
+ self.pv = np.array(0, dtype=int)
+ self.pqv = np.array(0, dtype=int)
+ self.p = np.array(0, dtype=int)
+ self.idx_conv = np.array(0, dtype=int)
+
+ self.idx_dVa = np.array(0, dtype=int)
+ self.idx_dVm = np.array(0, dtype=int)
+ self.idx_dP = np.array(0, dtype=int)
+ self.idx_dQ = np.array(0, dtype=int)
+
+ self.idx_dm = np.array(0, dtype=int)
+ self.idx_dtau = np.array(0, dtype=int)
+ self.idx_dbeq = np.array(0, dtype=int)
+
+ self.idx_dPf = np.array(0, dtype=int)
+ self.idx_dQf = np.array(0, dtype=int)
+
+ self.idx_dPt = np.array(0, dtype=int)
+ self.idx_dQt = np.array(0, dtype=int)
+
+ k_v_m = self.analyze_branch_controls() # this fills the indices above
+ vd, pq, pv, pqv, p, self.no_slack = compile_types(
+ Pbus=self.nc.Sbus.real,
+ types=self.bus_types
+ )
+ self.update_bus_types(pq=pq, pv=pv, pqv=pqv, p=p)
+
+ self.m: Vec = self.nc.branch_data.tap_module[self.idx_dm]
+ self.tau: Vec = self.nc.branch_data.tap_angle[self.idx_dtau]
+ self.beq: Vec = self.nc.branch_data.Beq[self.idx_dbeq]
+
+ self.Gsw = self.nc.branch_data.G0sw[self.idx_conv]
+
+ self.Ys = 1.0 / (self.nc.branch_data.R + 1j * self.nc.branch_data.X)
+
+ self.adm = compute_admittances(
+ R=self.nc.branch_data.R,
+ X=self.nc.branch_data.X,
+ G=self.nc.branch_data.G,
+ B=self.nc.branch_data.B,
+ k=self.nc.branch_data.k,
+ tap_module=expand(self.nc.nbr, self.m, self.idx_dm, 1.0),
+ vtap_f=self.nc.branch_data.virtual_tap_f,
+ vtap_t=self.nc.branch_data.virtual_tap_t,
+ tap_angle=expand(self.nc.nbr, self.tau, self.idx_dtau, 0.0),
+ Beq=expand(self.nc.nbr, self.beq, self.idx_dbeq, 0.0),
+ Cf=self.nc.Cf,
+ Ct=self.nc.Ct,
+ Gsw=expand(self.nc.nbr, self.Gsw, self.idx_conv, 0.0),
+ Yshunt_bus=self.nc.Yshunt_from_devices,
+ conn=self.nc.branch_data.conn,
+ seq=1,
+ add_windings_phase=False
+ )
+
+ if not len(self.pqv) >= len(k_v_m):
+ raise ValueError("k_v_m indices must be the same size as pqv indices!")
+
+ def update_bus_types(self, pq: IntVec, pv: IntVec, pqv: IntVec, p: IntVec) -> None:
+ """
+ Update the bus types
+ :param pq: Array of PQ indices
+ :param pv: Array of PV indices
+ :param pqv: Array of PQV indices
+ :param p: Array of P indices
+ """
+ self.pq = pq
+ self.pv = pv
+ self.pqv = pqv
+ self.p = p
+
+ self.idx_dVa = np.r_[self.pqv, self.pv, self.pq, self.p]
+ self.idx_dVm = np.r_[self.pq, self.p]
+ self.idx_dP = self.idx_dVa
+ self.idx_dQ = np.r_[self.pq, self.pqv]
+
+ def analyze_branch_controls(self) -> List[int]:
+ """
+ Analyze the control branches and compute the indices
+ :return: k_v_m for later comparison with pqv
+ """
+ k_pf_tau = list()
+ k_pt_tau = list()
+ k_qf_m = list()
+ k_qt_m = list()
+ k_qfzero_beq = list()
+ k_v_m = list()
+ k_v_beq = list()
+ k_vsc = list()
+
+ nbr = len(self.tap_phase_control_mode)
+ for k in range(nbr):
+
+ ctrl_m = self.tap_module_control_mode[k]
+ ctrl_tau = self.tap_phase_control_mode[k]
+ is_conv = self.nc.branch_data.is_converter[k]
+
+ conv_type = 1 if is_conv else 0
+
+ # analyze tap-module controls
+ if ctrl_m == TapModuleControl.Vm:
+
+ # Every bus controlled by m has to become a PQV bus
+ bus_idx = self.nc.branch_data.tap_controlled_buses[k]
+ self.bus_types[bus_idx] = BusMode.PQV_tpe.value
+
+ if is_conv and bus_idx == self.nc.branch_data.F[k]:
+ # if this is a converter,
+ # the voltage can be managed with Beq
+ # if the control bus is the "From" bus
+ k_v_beq.append(k)
+ conv_type = 2
+ else:
+ # In any other case, the voltage is managed by the tap module
+ k_v_m.append(k)
+
+ elif ctrl_m == TapModuleControl.Qf:
+
+ if not is_conv:
+ k_qf_m.append(k)
+
+ elif ctrl_m == TapModuleControl.Qt:
+ k_qt_m.append(k)
+
+ elif ctrl_m == TapModuleControl.fixed:
+ pass
+
+ elif ctrl_m == 0:
+ pass
+
+ else:
+ raise Exception(f"Unknown tap phase module mode {ctrl_m}")
+
+ # analyze tap-phase controls
+ if ctrl_tau == TapPhaseControl.Pf:
+ k_pf_tau.append(k)
+ # conv_type = 1
+
+ elif ctrl_tau == TapPhaseControl.Pt:
+ k_pt_tau.append(k)
+ # conv_type = 1
+
+ elif ctrl_tau == TapPhaseControl.fixed:
+ if ctrl_m == TapModuleControl.fixed:
+ conv_type = 1
+
+ # elif ctrl_tau == TapPhaseControl.Droop:
+ # pass
+
+ elif ctrl_tau == 0:
+ pass
+
+ else:
+ raise Exception(f"Unknown tap phase control mode {ctrl_tau}")
+
+ # Beq->qf=0
+ if conv_type == 1:
+ k_qfzero_beq.append(k)
+
+ if is_conv:
+ k_vsc.append(k)
+
+ # turn the lists into the final arrays
+ self.idx_conv = np.array(k_vsc, dtype=int)
+
+ self.idx_dm = np.r_[k_v_m, k_qf_m, k_qt_m].astype(int)
+ self.idx_dtau = np.r_[k_pf_tau, k_pt_tau].astype(int)
+ self.idx_dbeq = np.r_[k_qfzero_beq, k_v_beq].astype(int)
+
+ self.idx_dPf = np.array(k_pf_tau, dtype=int)
+ self.idx_dQf = np.r_[k_qf_m, k_qfzero_beq].astype(int)
+
+ self.idx_dPt = np.array(k_pt_tau, dtype=int)
+ self.idx_dQt = np.array(k_qt_m, dtype=int)
+
+ self.m: Vec = self.nc.branch_data.tap_module[self.idx_dm]
+ self.tau: Vec = self.nc.branch_data.tap_angle[self.idx_dtau]
+ self.beq: Vec = self.nc.branch_data.Beq[self.idx_dbeq]
+
+ self.Gsw = self.nc.branch_data.G0sw[self.idx_conv]
+
+ return k_v_m
+
+ def x2var(self, x: Vec) -> None:
+ """
+ Convert X to decission variables
+ :param x: solution vector
+ """
+ a = len(self.idx_dVa)
+ b = a + len(self.idx_dVm)
+ c = b + len(self.idx_dm)
+ d = c + len(self.idx_dtau)
+ e = d + len(self.idx_dbeq)
+
+ # update the vectors
+ self.Va[self.idx_dVa] = x[0:a]
+ self.Vm[self.idx_dVm] = x[a:b]
+ self.m = x[b:c]
+ self.tau = x[c:d]
+ self.beq = x[d:e]
+
+ def var2x(self) -> Vec:
+ """
+ Convert the internal decission variables into the vector
+ :return: Vector
+ """
+ return np.r_[
+ self.Va[self.idx_dVa],
+ self.Vm[self.idx_dVm],
+ self.m,
+ self.tau,
+ self.beq,
+ ]
+
+ def size(self) -> int:
+ """
+ Size of the jacobian matrix
+ :return:
+ """
+ return (len(self.idx_dVa)
+ + len(self.idx_dVm)
+ + len(self.idx_dm)
+ + len(self.idx_dtau)
+ + len(self.idx_dbeq))
+
+ def update(self, x: Vec, update_controls: bool = False) -> Tuple[float, bool, Vec, Vec]:
+ """
+ Update step
+ :param x: Solution vector
+ :param update_controls:
+ :return: error, converged?, x, fx
+ """
+ # set the problem state
+ self.x2var(x)
+
+ # recompute admittances
+ self.adm = compute_admittances(
+ R=self.nc.branch_data.R,
+ X=self.nc.branch_data.X,
+ G=self.nc.branch_data.G,
+ B=self.nc.branch_data.B,
+ k=self.nc.branch_data.k,
+ tap_module=expand(self.nc.nbr, self.m, self.idx_dm, 1.0),
+ vtap_f=self.nc.branch_data.virtual_tap_f,
+ vtap_t=self.nc.branch_data.virtual_tap_t,
+ tap_angle=expand(self.nc.nbr, self.tau, self.idx_dtau, 0.0),
+ Beq=expand(self.nc.nbr, self.beq, self.idx_dbeq, 0.0),
+ Cf=self.nc.Cf,
+ Ct=self.nc.Ct,
+ Gsw=expand(self.nc.nbr, self.Gsw, self.idx_conv, 0.0),
+ Yshunt_bus=self.nc.Yshunt_from_devices,
+ conn=self.nc.branch_data.conn,
+ seq=1,
+ add_windings_phase=False,
+ verbose=self.options.verbose,
+ )
+
+ # compute the complex voltage
+ self.V = polar_to_rect(self.Vm, self.Va)
+
+ # Update converter losses
+ It = get_It(k=self.idx_conv, V=self.V, ytf=self.adm.ytf, ytt=self.adm.ytt, F=self.nc.F, T=self.nc.T)
+ Itm = np.abs(It)
+ Itm2 = Itm * Itm
+ PLoss_IEC = (self.nc.branch_data.alpha3[self.idx_conv] * Itm2
+ + self.nc.branch_data.alpha2[self.idx_conv] * Itm2
+ + self.nc.branch_data.alpha1[self.idx_conv])
+
+ self.Gsw = PLoss_IEC / np.power(self.Vm[self.nc.F[self.idx_conv]], 2.0)
+
+ # compute the function residual
+ Sbus = compute_zip_power(self.S0, self.I0, self.Y0, self.Vm)
+ self.Scalc = compute_power(self.adm.Ybus, self.V)
+
+ dS = self.Scalc - Sbus # compute the mismatch
+
+ Pf = get_Sf(k=self.idx_dPf, Vm=self.Vm, V=self.V,
+ yff=self.adm.yff, yft=self.adm.yft, F=self.nc.F, T=self.nc.T).real
+
+ Qf = get_Sf(k=self.idx_dQf, Vm=self.Vm, V=self.V,
+ yff=self.adm.yff, yft=self.adm.yft, F=self.nc.F, T=self.nc.T).imag
+
+ Pt = get_St(k=self.idx_dPt, Vm=self.Vm, V=self.V,
+ ytf=self.adm.ytf, ytt=self.adm.ytt, F=self.nc.F, T=self.nc.T).real
+
+ Qt = get_St(k=self.idx_dQt, Vm=self.Vm, V=self.V,
+ ytf=self.adm.ytf, ytt=self.adm.ytt, F=self.nc.F, T=self.nc.T).imag
+
+ self._f = np.r_[
+ dS[self.idx_dP].real,
+ dS[self.idx_dQ].imag,
+ Pf - self.nc.branch_data.Pset[self.idx_dPf],
+ Qf - self.nc.branch_data.Qset[self.idx_dQf],
+ Pt - self.nc.branch_data.Pset[self.idx_dPt],
+ Qt - self.nc.branch_data.Qset[self.idx_dQt]
+ ]
+
+ # compute the rror
+ self._error = compute_fx_error(self._f)
+
+ if self.options.verbose > 1:
+ print("Vm:", self.Vm)
+ print("Va:", self.Va)
+ print("tau:", self.tau)
+ print("beq:", self.beq)
+ print("m:", self.m)
+ print("Gsw:", self.Gsw)
+
+ # Update controls only below a certain error
+ if update_controls and self._error < self._controls_tol:
+ any_change = False
+ branch_ctrl_change = False
+
+ # review reactive power limits
+ # it is only worth checking Q limits with a low error
+ # since with higher errors, the Q values may be far from realistic
+ # finally, the Q control only makes sense if there are pv nodes
+ if self.options.control_Q and (len(self.pv) + len(self.p)) > 0:
+
+ # check and adjust the reactive power
+ # this function passes pv buses to pq when the limits are violated,
+ # but not pq to pv because that is unstable
+ changed, pv, pq, pqv, p = control_q_inside_method(self.Scalc, self.S0,
+ self.pv, self.pq,
+ self.pqv, self.p,
+ self.Qmin,
+ self.Qmax)
+
+ if len(changed) > 0:
+ any_change = True
+
+ # update the bus type lists
+ self.update_bus_types(pq=pq, pv=pv, pqv=pqv, p=p)
+
+ # the composition of x may have changed, so recompute
+ x = self.var2x()
+
+ # update Slack control
+ if self.options.distributed_slack:
+ ok, delta = compute_slack_distribution(Scalc=self.Scalc,
+ vd=self.vd,
+ bus_installed_power=self.nc.bus_installed_power)
+ if ok:
+ any_change = True
+ # Update the objective power to reflect the slack distribution
+ self.S0 += delta
+
+ # update the tap module control
+ if self.options.control_taps_modules:
+ for i, k in enumerate(self.idx_dm):
+ if self.m[i] < self.nc.branch_data.tap_module_min[k]:
+ self.m[i] = self.nc.branch_data.tap_module_min[k]
+ self.tap_module_control_mode[k] = TapModuleControl.fixed
+ branch_ctrl_change = True
+ self.logger.add_info("Min tap module reached",
+ device=self.nc.branch_data.names[k],
+ value=self.m[i])
+
+ if self.m[i] > self.nc.branch_data.tap_module_max[k]:
+ self.m[i] = self.nc.branch_data.tap_module_max[k]
+ self.tap_module_control_mode[k] = TapModuleControl.fixed
+ branch_ctrl_change = True
+ self.logger.add_info("Max tap module reached",
+ device=self.nc.branch_data.names[k],
+ value=self.m[i])
+
+ # update the tap phase control
+ if self.options.control_taps_phase:
+ for i, k in enumerate(self.idx_dtau):
+ if self.tau[i] < self.nc.branch_data.tap_angle_min[k]:
+ self.tau[i] = self.nc.branch_data.tap_angle_min[k]
+ self.tap_phase_control_mode[k] = TapPhaseControl.fixed
+ branch_ctrl_change = True
+ self.logger.add_info("Min tap phase reached",
+ device=self.nc.branch_data.names[k],
+ value=self.tau[i])
+
+ if self.tau[i] > self.nc.branch_data.tap_angle_max[k]:
+ self.tau[i] = self.nc.branch_data.tap_angle_max[k]
+ self.tap_phase_control_mode[k] = TapPhaseControl.fixed
+ branch_ctrl_change = True
+ self.logger.add_info("Max tap phase reached",
+ device=self.nc.branch_data.names[k],
+ value=self.tau[i])
+
+ if branch_ctrl_change:
+ k_v_m = self.analyze_branch_controls()
+ vd, pq, pv, pqv, p, self.no_slack = compile_types(Pbus=self.nc.Sbus.real, types=self.bus_types)
+ self.update_bus_types(pq=pq, pv=pv, pqv=pqv, p=p)
+
+ if any_change or branch_ctrl_change:
+ # recompute the error based on the new Scalc and S0
+ self._f = self.fx()
+
+ # compute the rror
+ self._error = compute_fx_error(self._f)
+
+ # converged?
+ self._converged = self._error < self.options.tolerance
+
+ return self._error, self._converged, x, self.f
+
+ def fx(self) -> Vec:
+ """
+
+ :return:
+ """
+
+ # Assumes the internal vars were updated already with self.x2var()
+ Sbus = compute_zip_power(self.S0, self.I0, self.Y0, self.Vm)
+ self.Scalc = compute_power(self.adm.Ybus, self.V)
+
+ dS = self.Scalc - Sbus # compute the mismatch
+
+ Pf = get_Sf(k=self.idx_dPf, Vm=self.Vm, V=self.V,
+ yff=self.adm.yff, yft=self.adm.yft, F=self.nc.F, T=self.nc.T).real
+
+ Qf = get_Sf(k=self.idx_dQf, Vm=self.Vm, V=self.V,
+ yff=self.adm.yff, yft=self.adm.yft, F=self.nc.F, T=self.nc.T).imag
+
+ Pt = get_St(k=self.idx_dPt, Vm=self.Vm, V=self.V,
+ ytf=self.adm.ytf, ytt=self.adm.ytt, F=self.nc.F, T=self.nc.T).real
+
+ Qt = get_St(k=self.idx_dQt, Vm=self.Vm, V=self.V,
+ ytf=self.adm.ytf, ytt=self.adm.ytt, F=self.nc.F, T=self.nc.T).imag
+
+ self._f = np.r_[
+ dS[self.idx_dP].real,
+ dS[self.idx_dQ].imag,
+ Pf - self.nc.branch_data.Pset[self.idx_dPf],
+ Qf - self.nc.branch_data.Qset[self.idx_dQf],
+ Pt - self.nc.branch_data.Pset[self.idx_dPt],
+ Qt - self.nc.branch_data.Qset[self.idx_dQt]
+ ]
+ return self._f
+
+ def fx_diff(self, x: Vec) -> Vec:
+ """
+ Fx for autodiff
+ :param x: solutions vector
+ :return: f(x)
+ """
+ a = len(self.idx_dVa)
+ b = a + len(self.idx_dVm)
+ c = b + len(self.idx_dm)
+ d = c + len(self.idx_dtau)
+ e = d + len(self.idx_dbeq)
+
+ # update the vectors
+ Va = self.Va.copy()
+ Vm = self.Vm.copy()
+ m = np.ones(self.nc.nbr, dtype=float)
+ tau = np.zeros(self.nc.nbr, dtype=float)
+ beq = np.zeros(self.nc.nbr, dtype=float)
+
+ Va[self.idx_dVa] = x[0:a]
+ Vm[self.idx_dVm] = x[a:b]
+ m[self.idx_dm] = x[b:c]
+ tau[self.idx_dtau] = x[c:d]
+ beq[self.idx_dbeq] = x[d:e]
+
+ # compute the complex voltage
+ V = polar_to_rect(Vm, Va)
+
+ adm = compute_admittances(
+ R=self.nc.branch_data.R,
+ X=self.nc.branch_data.X,
+ G=self.nc.branch_data.G,
+ B=self.nc.branch_data.B,
+ k=self.nc.branch_data.k,
+ tap_module=m,
+ vtap_f=self.nc.branch_data.virtual_tap_f,
+ vtap_t=self.nc.branch_data.virtual_tap_t,
+ tap_angle=tau,
+ Beq=beq,
+ Cf=self.nc.Cf,
+ Ct=self.nc.Ct,
+ Gsw=expand(self.nc.nbr, self.Gsw, self.idx_conv, 0.0),
+ Yshunt_bus=self.nc.Yshunt_from_devices,
+ conn=self.nc.branch_data.conn,
+ seq=1,
+ add_windings_phase=False
+ )
+
+ Sbus = compute_zip_power(self.S0, self.I0, self.Y0, Vm)
+ Scalc = compute_power(adm.Ybus, V)
+
+ dS = Scalc - Sbus # compute the mismatch
+
+ Pf = get_Sf(k=self.idx_dPf, Vm=Vm, V=V, yff=adm.yff, yft=adm.yft, F=self.nc.F, T=self.nc.T).real
+ Qf = get_Sf(k=self.idx_dQf, Vm=Vm, V=V, yff=adm.yff, yft=adm.yft, F=self.nc.F, T=self.nc.T).real
+ Pt = get_St(k=self.idx_dPt, Vm=Vm, V=V, ytf=adm.ytf, ytt=adm.ytt, F=self.nc.F, T=self.nc.T).real
+ Qt = get_St(k=self.idx_dQt, Vm=Vm, V=V, ytf=adm.ytf, ytt=adm.ytt, F=self.nc.F, T=self.nc.T).real
+
+ f = np.r_[
+ dS[self.idx_dP].real,
+ dS[self.idx_dQ].imag,
+ Pf - self.nc.branch_data.Pset[self.idx_dPf],
+ Qf - self.nc.branch_data.Qset[self.idx_dQf],
+ Pt - self.nc.branch_data.Pset[self.idx_dPt],
+ Qt - self.nc.branch_data.Qset[self.idx_dQt]
+ ]
+ return f
+
+ def Jacobian(self, autodiff: bool = False) -> CSC:
+ """
+ Get the Jacobian
+ :return:
+ """
+ if autodiff:
+ J = calc_autodiff_jacobian(func=self.fx_diff, x=self.var2x(), h=1e-12)
+ return scipy_to_mat(J)
+ else:
+ n_rows = (len(self.idx_dP)
+ + len(self.idx_dQ)
+ + len(self.idx_dPf)
+ + len(self.idx_dQf)
+ + len(self.idx_dPt)
+ + len(self.idx_dQt))
+
+ n_cols = (len(self.idx_dVa)
+ + len(self.idx_dVm)
+ + len(self.idx_dm)
+ + len(self.idx_dtau)
+ + len(self.idx_dbeq))
+
+ if n_cols != n_rows:
+ raise ValueError("Incorrect J indices!")
+
+ tap_modules = expand(self.nc.nbr, self.m, self.idx_dm, 1.0)
+ tap_angles = expand(self.nc.nbr, self.tau, self.idx_dtau, 0.0)
+ tap = polar_to_rect(tap_modules, tap_angles)
+
+ J = adv_jacobian(nbus=self.nc.nbus,
+ nbr=self.nc.nbr,
+ idx_dva=self.idx_dVa,
+ idx_dvm=self.idx_dVm,
+ idx_dm=self.idx_dm,
+ idx_dtau=self.idx_dtau,
+ idx_dbeq=self.idx_dbeq,
+ idx_dP=self.idx_dP,
+ idx_dQ=self.idx_dQ,
+ idx_dPf=self.idx_dPf,
+ idx_dQf=self.idx_dQf,
+ idx_dPt=self.idx_dPt,
+ idx_dQt=self.idx_dQt,
+ F=self.nc.F,
+ T=self.nc.T,
+ Ys=self.Ys,
+ kconv=self.nc.branch_data.k,
+ complex_tap=tap,
+ tap_modules=tap_modules,
+ Bc=self.nc.branch_data.B,
+ Beq=expand(self.nc.nbr, self.beq, self.idx_dbeq, 0.0),
+ V=self.V,
+ Vm=self.Vm,
+ Ybus_x=self.adm.Ybus.data,
+ Ybus_p=self.adm.Ybus.indptr,
+ Ybus_i=self.adm.Ybus.indices,
+ yff=self.adm.yff,
+ yft=self.adm.yft,
+ ytf=self.adm.ytf,
+ ytt=self.adm.ytt)
+
+ return J
+
+ def get_x_names(self) -> List[str]:
+ """
+ Names matching x
+ :return:
+ """
+ cols = [f'dVa {i}' for i in self.idx_dVa]
+ cols += [f'dVm {i}' for i in self.idx_dVm]
+ cols += [f'dm {i}' for i in self.idx_dm]
+ cols += [f'dtau {i}' for i in self.idx_dtau]
+ cols += [f'dBeq {i}' for i in self.idx_dbeq]
+
+ return cols
+
+ def get_fx_names(self) -> List[str]:
+ """
+ Names matching fx
+ :return:
+ """
+ rows = [f'dP {i}' for i in self.idx_dP]
+ rows += [f'dQ {i}' for i in self.idx_dQ]
+ rows += [f'dPf {i}' for i in self.idx_dPf]
+ rows += [f'dQf {i}' for i in self.idx_dQf]
+ rows += [f'dPt {i}' for i in self.idx_dPt]
+ rows += [f'dQt {i}' for i in self.idx_dQt]
+
+ return rows
+
+ def get_jacobian_df(self, autodiff=True) -> pd.DataFrame:
+ """
+ Get the Jacobian DataFrame
+ :return: DataFrame
+ """
+ J = self.Jacobian(autodiff=autodiff)
+ return pd.DataFrame(
+ data=J.toarray(),
+ columns=self.get_x_names(),
+ index=self.get_fx_names(),
+ )
+
+ def get_solution(self, elapsed: float, iterations: int) -> NumericPowerFlowResults:
+ """
+ Get the problem solution
+ :param elapsed: Elapsed seconds
+ :param iterations: Iteration number
+ :return: NumericPowerFlowResults
+ """
+ return NumericPowerFlowResults(V=self.V,
+ converged=self.converged,
+ norm_f=self.error,
+ Scalc=self.Scalc,
+ m=expand(self.nc.nbr, self.m, self.idx_dm, 1.0),
+ tau=expand(self.nc.nbr, self.tau, self.idx_dtau, 0.0),
+ Beq=expand(self.nc.nbr, self.beq, self.idx_dbeq, 0.0),
+ Ybus=self.adm.Ybus,
+ Yf=self.adm.Yf,
+ Yt=self.adm.Yt,
+ iterations=iterations,
+ elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/pf_basic_formulation.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/pf_basic_formulation.py
new file mode 100644
index 000000000..4a447eb01
--- /dev/null
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/pf_basic_formulation.py
@@ -0,0 +1,242 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from typing import Tuple
+import numpy as np
+from GridCalEngine.DataStructures.numerical_circuit import NumericalCircuit
+from GridCalEngine.Topology.admittance_matrices import AdmittanceMatrices
+from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
+from GridCalEngine.Simulations.PowerFlow.power_flow_options import PowerFlowOptions
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import create_J_vc_csc
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import compute_fx_error
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import (control_q_inside_method,
+ compute_slack_distribution)
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.pf_formulation_template import PfFormulationTemplate
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import (compute_zip_power, compute_power,
+ compute_fx, polar_to_rect)
+from GridCalEngine.Topology.simulation_indices import compile_types
+from GridCalEngine.basic_structures import Vec, IntVec, CxVec
+from GridCalEngine.Utils.Sparse.csc2 import CSC
+
+
+class PfBasicFormulation(PfFormulationTemplate):
+
+ def __init__(self, V0: CxVec, S0: CxVec, I0: CxVec, Y0: CxVec, Qmin: Vec, Qmax: Vec,
+ nc: NumericalCircuit, options: PowerFlowOptions):
+ """
+
+ :param V0:
+ :param S0:
+ :param I0:
+ :param Y0:
+ :param Qmin:
+ :param Qmax:
+ :param options:
+ """
+ PfFormulationTemplate.__init__(self, V0=V0, options=options)
+
+ self.nc = nc
+ self.adm: AdmittanceMatrices = nc.admittances_
+
+ self.S0: CxVec = S0
+ self.I0: CxVec = I0
+ self.Y0: CxVec = Y0
+
+ self.Qmin = Qmin
+ self.Qmax = Qmax
+
+ self.vd, self.pq, self.pv, self.pqv, self.p, self.no_slack = compile_types(
+ Pbus=self.nc.Sbus.real,
+ types=self.nc.bus_data.bus_types
+ )
+
+ self.idx_dVa = np.r_[self.pv, self.pq, self.pqv, self.p]
+ self.idx_dVm = np.r_[self.pq, self.p]
+ self.idx_dP = self.idx_dVa
+ self.idx_dQ = np.r_[self.pq, self.pqv]
+
+ def x2var(self, x: Vec):
+ """
+ Convert X to decission variables
+ :param x: solution vector
+ """
+ a = len(self.idx_dVa)
+ b = a + len(self.idx_dVm)
+
+ # update the vectors
+ self.Va[self.idx_dVa] = x[0:a]
+ self.Vm[self.idx_dVm] = x[a:b]
+
+ def var2x(self) -> Vec:
+ """
+ Convert the internal decission variables into the vector
+ :return: Vector
+ """
+ return np.r_[
+ self.Va[self.idx_dVa],
+ self.Vm[self.idx_dVm]
+ ]
+
+ def update_bus_types(self, pq: IntVec, pv: IntVec, pqv: IntVec, p: IntVec):
+ """
+
+ :param pq:
+ :param pv:
+ :param pqv:
+ :param p:
+ :return:
+ """
+ self.pq = pq
+ self.pv = pv
+ self.pqv = pqv
+ self.p = p
+
+ self.idx_dVa = np.r_[self.pv, self.pq, self.pqv, self.p]
+ self.idx_dVm = np.r_[self.pq, self.p]
+ self.idx_dP = self.idx_dVa
+ self.idx_dQ = np.r_[self.pq, self.pqv]
+
+ def size(self) -> int:
+ """
+ Size of the jacobian matrix
+ :return:
+ """
+ return len(self.idx_dVa) + len(self.idx_dVm)
+
+ def update(self, x: Vec, update_controls: bool = False) -> Tuple[float, bool, Vec, Vec]:
+ """
+ Update step
+ :param x: Solution vector
+ :param update_controls:
+ :return: error, converged?, x
+ """
+ # set the problem state
+ self.x2var(x)
+
+ # compute the complex voltage
+ self.V = polar_to_rect(self.Vm, self.Va)
+
+ # compute the function residual
+ # Assumes the internal vars were updated already with self.x2var()
+ Sbus = compute_zip_power(self.S0, self.I0, self.Y0, self.Vm)
+ self.Scalc = compute_power(self.adm.Ybus, self.V)
+ dS = self.Scalc - Sbus # compute the mismatch
+ self._f = np.r_[
+ dS[self.idx_dP].real,
+ dS[self.idx_dQ].imag
+ ]
+ # self._f = compute_fx(self.Scalc, Sbus, self.idx_dP, self.idx_dQ)
+
+ # compute the rror
+ self._error = compute_fx_error(self._f)
+
+ # review reactive power limits
+ # it is only worth checking Q limits with a low error
+ # since with higher errors, the Q values may be far from realistic
+ # finally, the Q control only makes sense if there are pv nodes
+ if update_controls and self._error < self._controls_tol:
+ any_change = False
+
+ # update Q limits control
+ if self.options.control_Q and (len(self.pv) + len(self.p)) > 0:
+
+ # check and adjust the reactive power
+ # this function passes pv buses to pq when the limits are violated,
+ # but not pq to pv because that is unstable
+ changed, pv, pq, pqv, p = control_q_inside_method(self.Scalc, self.S0,
+ self.pv, self.pq,
+ self.pqv, self.p,
+ self.Qmin,
+ self.Qmax)
+
+ if len(changed) > 0:
+ any_change = True
+
+ # update the bus type lists
+ self.update_bus_types(pq=pq, pv=pv, pqv=pqv, p=p)
+
+ # the composition of x may have changed, so recompute
+ x = self.var2x()
+
+ # update Slack control
+ if self.options.distributed_slack:
+ ok, delta = compute_slack_distribution(Scalc=self.Scalc,
+ vd=self.vd,
+ bus_installed_power=self.nc.bus_installed_power)
+ if ok:
+ any_change = True
+ # Update the objective power to reflect the slack distribution
+ self.S0 += delta
+
+ if any_change:
+ # recompute the error based on the new Scalc and S0
+ self._f = self.fx()
+
+ # compute the rror
+ self._error = compute_fx_error(self._f)
+
+ # converged?
+ self._converged = self._error < self.options.tolerance
+
+ return self._error, self._converged, x, self.f
+
+ def fx(self) -> Vec:
+ """
+
+ :return:
+ """
+ # Assumes the internal vars were updated already with self.x2var()
+ Sbus = compute_zip_power(self.S0, self.I0, self.Y0, self.Vm)
+ self.Scalc = compute_power(self.adm.Ybus, self.V)
+ self._f = compute_fx(self.Scalc, Sbus, self.idx_dP, self.idx_dQ)
+ return self._f
+
+ def Jacobian(self) -> CSC:
+ """
+
+ :return:
+ """
+ # Assumes the internal vars were updated already with self.x2var()
+ if self.adm.Ybus.format != 'csc':
+ self.adm.Ybus = self.adm.Ybus.tocsc()
+
+ nbus = self.adm.Ybus.shape[0]
+
+ # Create J in CSC order
+ J = create_J_vc_csc(nbus, self.adm.Ybus.data, self.adm.Ybus.indptr, self.adm.Ybus.indices,
+ self.V, self.idx_dVa, self.idx_dVm, self.idx_dP, self.idx_dQ)
+
+ return J
+
+ def get_solution(self, elapsed: float, iterations: int) -> NumericPowerFlowResults:
+ """
+ Get the problem solution
+ :param elapsed: Elapsed seconds
+ :param iterations: Iteration number
+ :return: NumericPowerFlowResults
+ """
+ return NumericPowerFlowResults(V=self.V,
+ converged=self.converged,
+ norm_f=self.error,
+ Scalc=self.Scalc,
+ m=None,
+ tau=None,
+ Beq=None,
+ Ybus=self.adm.Ybus,
+ Yf=self.adm.Yf,
+ Yt=self.adm.Yt,
+ iterations=iterations,
+ elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/pf_formulation_template.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/pf_formulation_template.py
new file mode 100644
index 000000000..a370ae31d
--- /dev/null
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/pf_formulation_template.py
@@ -0,0 +1,180 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from typing import Tuple
+import numpy as np
+import pandas as pd
+from GridCalEngine.basic_structures import Vec, CxVec
+from GridCalEngine.Utils.Sparse.csc2 import CSC, spsolve_csc
+from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
+from GridCalEngine.Simulations.PowerFlow.power_flow_options import PowerFlowOptions
+
+pd.set_option('display.float_format', '{:.4f}'.format)
+
+
+class PfFormulationTemplate:
+ """
+ Base Power Flow Formulation class
+ """
+
+ def __init__(self, V0: CxVec, options: PowerFlowOptions):
+ """
+
+ :param V0:
+ :param options:
+ """
+ self.V = V0
+
+ self._Vm = np.abs(V0)
+ self._Va = np.angle(V0)
+
+ self.Scalc: CxVec = np.zeros(len(V0), dtype=complex)
+
+ self.options: PowerFlowOptions = options
+
+ self._f: Vec = np.zeros(0)
+
+ self._error: float = 0.0
+
+ self._converged: bool = False
+
+ self._controls_tol: float = 1.0e-2 # min(1e-2, self.options.tolerance * 100.0)
+
+ @property
+ def converged(self) -> bool:
+ """
+ Converged?
+ :return:
+ """
+ return self._converged
+
+ @property
+ def error(self) -> float:
+ """
+ Converged?
+ :return:
+ """
+ return self._error
+
+ @property
+ def f(self) -> Vec:
+ """
+ Converged?
+ :return:
+ """
+ return self._f
+
+ @property
+ def Va(self) -> Vec:
+ """
+ Voltage angles
+ :return:
+ """
+ return self._Va
+
+ @property
+ def Vm(self) -> Vec:
+ """
+ Voltage modules
+ :return:
+ """
+ return self._Vm
+
+ def x2var(self, x: Vec):
+ """
+ Convert X to decission variables
+ :param x: solution vector
+ """
+ pass
+
+ def var2x(self) -> Vec:
+ """
+ Convert the internal decission variables into the vector
+ """
+ pass
+
+ def update(self, x: Vec, update_controls: bool = False) -> Tuple[float, bool, Vec, Vec]:
+ """
+ Update the problem
+ :param x: Solution vector
+ :param update_controls: Update controls
+ :return: error, converged, x, f
+ """
+ return self.error, self.converged, self.var2x(), self._f
+
+ def size(self) -> int:
+ """
+ Size of the jacobian matrix
+ :return:
+ """
+ return 0
+
+ def fx(self) -> Vec:
+ """
+
+ :return:
+ """
+ pass
+
+ def Jacobian(self) -> CSC:
+ """
+
+ :return:
+ """
+ pass
+
+ def solve_step_from_f(self, f: Vec) -> Tuple[Vec, bool]:
+ """
+
+ :param f: Function residual
+ :return:
+ """
+ # Compute the Jacobian
+ J = self.Jacobian() # Assumes the internal vars were updated already with self.x2var()
+
+ # Solve the sparse system
+ dx, ok = spsolve_csc(J, f)
+
+ if self.options.verbose > 1:
+ cols = np.array([0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 7])
+ rows = np.array([0, 1, 2, 3, 4, 5, 6, 9, 10, 8, 7])
+ # print("J original:\n", pd.DataFrame(J.toarray()))
+ print("J mod:\n", pd.DataFrame(J.toarray()[:, cols][rows, :]).to_string(index=False))
+ print("F:\n", f[rows])
+ print("dx:\n", dx[cols])
+ if self.options.verbose > 2:
+ Jdf = pd.DataFrame(J.toarray())
+ Jdf.to_csv(f'J.csv', index=False, float_format='%.4f')
+
+ return dx, ok
+
+ def solve_step(self) -> Tuple[Vec, bool]:
+ """
+
+ :return:
+ """
+
+ # Solve the sparse system
+ dx, ok = self.solve_step_from_f(self._f)
+
+ return dx, ok
+
+ def get_solution(self, elapsed: float, iterations: int) -> NumericPowerFlowResults:
+ """
+
+ :return:
+ """
+ pass
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/powell_fx.py b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/powell_fx.py
new file mode 100644
index 000000000..291bfd972
--- /dev/null
+++ b/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/powell_fx.py
@@ -0,0 +1,187 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+import time
+import numpy as np
+from GridCalEngine.Utils.NumericalMethods.sparse_solve import get_linear_solver
+from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.pf_formulation_template import PfFormulationTemplate
+from GridCalEngine.Utils.Sparse.csc2 import mat_to_scipy
+from GridCalEngine.basic_structures import Logger, Vec
+from GridCalEngine.Utils.NumericalMethods.common import norm
+
+linear_solver = get_linear_solver()
+
+
+def compute_beta(a: Vec, b: Vec, delta: float):
+ """
+ compute the beta parameter
+ :param a: alpha + hsd
+ :param b: hgn
+ :param delta: trust region
+ :return: beta value
+ """
+ ba = b - a
+ c = a @ ba
+ norm2_a = a @ a
+ norm2_ba = ba @ ba
+ delta2_norm2a = (delta * delta - norm2_a)
+ if c <= 0.0:
+ return (-c + np.sqrt(c * c + norm2_ba * delta2_norm2a)) / norm2_ba
+ else:
+ return delta2_norm2a / (c + np.sqrt(c * c + norm2_ba * delta2_norm2a))
+
+
+def compute_hdl(hgn: Vec, hsd: Vec, g: Vec, alpha: float, delta: float, f_error: float) -> Vec:
+ """
+ Compute the Hdl vector
+ :param hgn: Hgn vector
+ :param hsd: Hsd vector
+ :param g: g vector
+ :param alpha: alpha parameter
+ :param delta: delta parameter (trust region size)
+ :param f_error: error of the function top optimize
+ :return: Hdl Vector, L(0) - L(hdl)
+ """
+ if norm(hgn) <= delta:
+ return hgn, f_error
+ elif norm(hsd * alpha) >= delta:
+ hdl = (delta / norm(hsd)) * hsd
+ val = (delta * (2 * norm(alpha * g) - delta)) / (2 * alpha)
+ return hdl, val
+ else:
+ beta = compute_beta(a=hsd * alpha, b=hgn, delta=delta)
+ hdl = alpha * hsd + beta * (hgn - alpha * hsd)
+ val = 0.5 * alpha * (1.0 - beta) ** 2 + (g @ g) + beta * (2.0 - beta) * f_error
+ return hdl, val
+
+
+def powell_fx(problem: PfFormulationTemplate,
+ tol: float = 1e-6,
+ max_iter: int = 10,
+ trust: float = 1.0,
+ verbose: int = 0,
+ logger: Logger = Logger()) -> NumericPowerFlowResults:
+ """
+ Powell's Dog leg algorithm to solve:
+
+ min: error(f(x))
+ s.t.
+ f(x) = 0
+
+ From METHODS FOR NON-LINEAR LEAST SQUARES PROBLEMS by K. Madsen, H.B. Nielsen, O. Tingleff
+
+ :param problem: PfFormulationTemplate
+ :param tol: Error tolerance
+ :param max_iter: Maximum number of iterations
+ :param trust: trust amount in the derivative length correctness
+ :param verbose: Display console information
+ :param logger: Logger instance
+ :return: ConvexMethodResult
+ """
+ start = time.time()
+
+ # get the initial point
+ x = problem.var2x()
+
+ if len(x) == 0:
+ # if the lenght of x is zero, means that there's nothing to solve
+ # for instance there might be a single node that is a slack node
+ return problem.get_solution(elapsed=time.time() - start, iterations=0)
+
+ delta = trust
+ f_error, converged, x, f = problem.update(x, update_controls=False)
+ J = mat_to_scipy(problem.Jacobian())
+ g = J.T @ f
+
+ iteration = 0
+ error_evolution = np.zeros(max_iter + 1)
+
+ # save the error evolution
+ error_evolution[iteration] = f_error
+
+ if verbose > 0:
+ print(f'It {iteration}, error {f_error}, converged {converged}, x {x}, dx not computed yet')
+
+ if problem.converged:
+ return problem.get_solution(elapsed=time.time() - start, iterations=iteration)
+
+ else:
+
+ while not converged and iteration < max_iter:
+
+ # update iteration counter
+ iteration += 1
+
+ # compute alpha (3.19)
+ g_proy = J @ g
+ alpha = (g @ g) / (g_proy @ g_proy)
+ hsd = -alpha * g
+
+ if verbose > 0:
+ print('-' * 200)
+ print(f'Iter: {iteration}')
+ print('-' * 200)
+
+ # compute update step
+ try:
+
+ # compute update step: J x Īx = Īg
+ hgn = linear_solver(J, -f)
+
+ except RuntimeError:
+ logger.add_error(f"Powell's system matrix is singular @iter {iteration}:")
+ return problem.get_solution(elapsed=time.time() - start, iterations=iteration)
+
+ # compute hdl (3.20)
+ hdl, L0_Lhdl = compute_hdl(hgn=hgn, hsd=hsd, g=g, alpha=alpha, delta=delta, f_error=f_error)
+
+ if verbose > 1:
+ import pandas as pd
+ print("H:\n", pd.DataFrame(J.toarray()).to_string(index=False))
+ print("f:\n", f)
+ print("dx:\n", hdl)
+
+ tol2 = tol * (norm(x) + tol)
+
+ f_error_new, converged, x, f = problem.update(x + hdl, update_controls=True)
+
+ rho = (f_error - f_error_new) / L0_Lhdl if L0_Lhdl > 0 else -1.0
+
+ if rho > 0.0 or len(f) != J.shape[0]:
+ J = mat_to_scipy(problem.Jacobian()) # compute the Jacobian too
+ g = J.T @ f
+ f_error = f_error_new
+
+ elif rho > 0.75:
+ delta = max(delta, 3.0 * norm(hdl))
+
+ elif rho < 0.25:
+ delta *= 0.5
+
+ else:
+ raise Exception(f'Unhandled rho {rho}')
+
+ # save the error evolution
+ error_evolution[iteration] = f_error
+
+ if verbose > 0:
+ if verbose == 1:
+ print(f'It {iteration}, error {f_error}, converged {converged}, x {x}, dx {hdl}')
+ else:
+ print(f'error {f_error}, converged {converged}, x {x}, dx {hdl}')
+
+ return problem.get_solution(elapsed=time.time() - start, iterations=iteration)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/power_flow_driver.py b/src/GridCalEngine/Simulations/PowerFlow/power_flow_driver.py
index a97c6eff8..bbb7cc4ef 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/power_flow_driver.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/power_flow_driver.py
@@ -179,20 +179,20 @@ def run(self) -> None:
n = len(convergence_report.error_)
for i in range(n):
self.logger.add_info(msg=f"Method {convergence_report.methods_[i]}",
- device=f"Converged",
+ device_property=f"Converged",
value=convergence_report.converged_[i],
expected_value="True")
self.logger.add_info(msg=f"Method {convergence_report.methods_[i]}",
- device="Elapsed (s)",
- value=convergence_report.elapsed_[i])
+ device_property="Elapsed (s)",
+ value='{:.4f}'.format(convergence_report.elapsed_[i]))
self.logger.add_info(msg=f"Method {convergence_report.methods_[i]}",
- device="Error (p.u.)",
- value=convergence_report.error_[i],
- expected_value=self.options.tolerance)
+ device_property="Error (p.u.)",
+ value='{:.4e}'.format(convergence_report.error_[i]),
+ expected_value=f"<{self.options.tolerance}")
self.logger.add_info(msg=f"Method {convergence_report.methods_[i]}",
- device="Iterations",
+ device_property="Iterations",
value=convergence_report.iterations_[i],
- expected_value=self.options.max_iter)
+ expected_value=f"<{self.options.max_iter}")
if self.options.generate_report:
self.add_report()
diff --git a/src/GridCalEngine/Simulations/PowerFlow/power_flow_options.py b/src/GridCalEngine/Simulations/PowerFlow/power_flow_options.py
index 9a0183b10..9199702bf 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/power_flow_options.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/power_flow_options.py
@@ -15,7 +15,7 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-from GridCalEngine.enumerations import BranchImpedanceMode, ReactivePowerControlMode, SolverType, TapsControlMode
+from GridCalEngine.enumerations import BranchImpedanceMode, SolverType
from GridCalEngine.Simulations.options_template import OptionsTemplate
@@ -26,24 +26,24 @@ class PowerFlowOptions(OptionsTemplate):
def __init__(self,
solver_type: SolverType = SolverType.NR,
- retry_with_other_methods=True,
- verbose=0,
- initialize_with_existing_solution=False,
- tolerance=1e-6,
- max_iter=25,
- max_outer_loop_iter=100,
- control_q=ReactivePowerControlMode.NoControl,
- control_taps=TapsControlMode.NoControl,
- apply_temperature_correction=False,
+ retry_with_other_methods: bool = True,
+ verbose: int = 0,
+ initialize_with_existing_solution: bool = False,
+ tolerance: float = 1e-6,
+ max_iter: int = 25,
+ max_outer_loop_iter: int = 100,
+ control_q: bool = True,
+ control_taps_modules: bool = True,
+ control_taps_phase: bool = True,
+ control_remote_voltage: bool = True,
+ apply_temperature_correction: bool = True,
branch_impedance_tolerance_mode=BranchImpedanceMode.Specified,
- distributed_slack=False,
- ignore_single_node_islands=False,
- trust_radius=1.0,
- backtracking_parameter=0.05,
- use_stored_guess=False,
- override_branch_controls=False,
- generate_report=False,
- generalised_pf=False):
+ distributed_slack: bool = False,
+ ignore_single_node_islands: bool = False,
+ trust_radius: float = 1.0,
+ backtracking_parameter: float = 0.05,
+ use_stored_guess: bool = False,
+ generate_report: bool = False):
"""
Power flow options class
:param solver_type: Solver type
@@ -53,8 +53,6 @@ def __init__(self,
:param max_iter: Maximum number of iterations for the power flow numerical method
:param max_outer_loop_iter: Maximum number of iterations for the controls outer loop
:param control_q: Control mode for the PV nodes reactive power limits
- :param control_taps: Control mode for the transformer taps equipped with a voltage regulator
- (as part of the outer loop)
:param apply_temperature_correction: Apply the temperature correction to the resistance of the Branches?
:param branch_impedance_tolerance_mode: Type of modification of the Branches impedance
:param distributed_slack: Applies the redistribution of the slack power proportionally among the controlled generators
@@ -62,9 +60,7 @@ def __init__(self,
:param trust_radius:
:param backtracking_parameter: parameter used to correct the "bad" iterations, typically 0.5
:param use_stored_guess: Use the existing solution from the Bus class (Vm0, Va0)
- :param override_branch_controls:
- :param generate_report:
- :param generalised_pf:
+ :param generate_report: Generate the power flow report after the solution?
"""
OptionsTemplate.__init__(self, name='PowerFlowOptions')
@@ -84,7 +80,11 @@ def __init__(self,
self.initialize_with_existing_solution = initialize_with_existing_solution
- self.control_taps = control_taps
+ self.control_taps_modules = control_taps_modules
+
+ self.control_taps_phase = control_taps_phase
+
+ self.control_remote_voltage = control_remote_voltage
self.apply_temperature_correction = apply_temperature_correction
@@ -100,21 +100,19 @@ def __init__(self,
self.use_stored_guess = use_stored_guess
- self.override_branch_controls = override_branch_controls
-
self.generate_report = generate_report
- self.generalised_pf = generalised_pf # TODO: Remove this
-
self.register(key="solver_type", tpe=SolverType)
self.register(key="retry_with_other_methods", tpe=bool)
self.register(key="tolerance", tpe=float)
self.register(key="max_iter", tpe=int)
self.register(key="max_outer_loop_iter", tpe=int)
- self.register(key="control_Q", tpe=ReactivePowerControlMode)
+ self.register(key="control_Q", tpe=bool)
self.register(key="verbose", tpe=int)
self.register(key="initialize_with_existing_solution", tpe=bool)
- self.register(key="control_taps", tpe=bool)
+ self.register(key="control_taps_modules", tpe=bool)
+ self.register(key="control_taps_phase", tpe=bool)
+ self.register(key="control_remote_voltage", tpe=bool)
self.register(key="apply_temperature_correction", tpe=bool)
self.register(key="branch_impedance_tolerance_mode", tpe=BranchImpedanceMode)
self.register(key="distributed_slack", tpe=bool)
@@ -122,6 +120,4 @@ def __init__(self,
self.register(key="trust_radius", tpe=float)
self.register(key="backtracking_parameter", tpe=float)
self.register(key="use_stored_guess", tpe=bool)
- self.register(key="override_branch_controls", tpe=bool)
self.register(key="generate_report", tpe=bool)
- self.register(key="generalised_pf", tpe=bool)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/power_flow_results.py b/src/GridCalEngine/Simulations/PowerFlow/power_flow_results.py
index 255f55e85..a0700583e 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/power_flow_results.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/power_flow_results.py
@@ -37,8 +37,8 @@ def __init__(self,
converged: bool,
norm_f: float,
Scalc: CxVec,
- ma: Union[Vec, None] = None,
- theta: Union[Vec, None] = None,
+ m: Union[Vec, None] = None,
+ tau: Union[Vec, None] = None,
Beq: Union[Vec, None] = None,
Ybus: Union[CscMat, None] = None,
Yf: Union[CscMat, None] = None,
@@ -51,8 +51,8 @@ def __init__(self,
:param converged: converged?
:param norm_f: error
:param Scalc: Calculated power vector
- :param ma: Tap modules vector for all the Branches
- :param theta: Tap angles vector for all the Branches
+ :param m: Tap modules vector for all the Branches
+ :param tau: Tap angles vector for all the Branches
:param Beq: Equivalent susceptance vector for all the Branches
:param Ybus: Admittance matrix
:param Yf: Admittance matrix of the "from" buses
@@ -64,8 +64,8 @@ def __init__(self,
self.converged = converged
self.norm_f = norm_f
self.Scalc = Scalc
- self.ma = ma
- self.theta = theta
+ self.tap_module = m
+ self.tap_angle = tau
self.Beq = Beq
self.Ybus = Ybus
self.Yf = Yf
@@ -173,9 +173,11 @@ def __init__(
self.St: CxVec = np.zeros(m, dtype=complex)
self.If: CxVec = np.zeros(m, dtype=complex)
self.It: CxVec = np.zeros(m, dtype=complex)
+
self.tap_module: Vec = np.zeros(m, dtype=float)
self.tap_angle: Vec = np.zeros(m, dtype=float)
self.Beq: Vec = np.zeros(m, dtype=float)
+
self.Vbranch: CxVec = np.zeros(m, dtype=complex)
self.loading: CxVec = np.zeros(m, dtype=complex)
self.losses: CxVec = np.zeros(m, dtype=complex)
@@ -282,19 +284,19 @@ def apply_from_island(self,
**elm_idx**: branch original indices
"""
self.Sbus[b_idx] = results.Sbus
-
self.voltage[b_idx] = results.voltage
self.Sf[br_idx] = results.Sf
-
self.St[br_idx] = results.St
-
self.If[br_idx] = results.If
+ self.It[br_idx] = results.It
- self.Vbranch[br_idx] = results.Vbranch
+ self.tap_module[br_idx] = results.tap_module
+ self.tap_angle[br_idx] = results.tap_angle
+ self.Beq[br_idx] = results.Beq
+ self.Vbranch[br_idx] = results.Vbranch
self.loading[br_idx] = results.loading
-
self.losses[br_idx] = results.losses
self.convergence_reports += results.convergence_reports
diff --git a/src/GridCalEngine/Simulations/PowerFlow/power_flow_worker.py b/src/GridCalEngine/Simulations/PowerFlow/power_flow_worker.py
index 25043f12f..f6b17d2e6 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/power_flow_worker.py
+++ b/src/GridCalEngine/Simulations/PowerFlow/power_flow_worker.py
@@ -24,71 +24,49 @@
from GridCalEngine.Simulations.PowerFlow.power_flow_results import PowerFlowResults
from GridCalEngine.Simulations.PowerFlow.power_flow_options import PowerFlowOptions
from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.pf_basic_formulation import PfBasicFormulation
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.pf_advanced_formulation import PfAdvancedFormulation
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.newton_raphson_fx import newton_raphson_fx
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.powell_fx import powell_fx
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.levenberg_marquadt_fx import levenberg_marquadt_fx
+from GridCalEngine.Topology.simulation_indices import compile_types
from GridCalEngine.DataStructures.numerical_circuit import NumericalCircuit
from GridCalEngine.Devices.multi_circuit import MultiCircuit
from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
-from GridCalEngine.DataStructures.numerical_circuit import (
- compile_numerical_circuit_at as compile_numerical_circuit_at_generalised_pf)
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import compute_slack_distribution
from GridCalEngine.Devices.Substation.bus import Bus
from GridCalEngine.Devices.Aggregation.area import Area
-from GridCalEngine.basic_structures import CxVec, Vec, IntVec, CscMat
+from GridCalEngine.basic_structures import CxVec, CscMat
if TYPE_CHECKING: # Only imports the below statements during type checking
from GridCalEngine.Simulations.OPF.opf_results import OptimalPowerFlowResults
-def solve(circuit: NumericalCircuit,
+def solve(nc: NumericalCircuit,
options: PowerFlowOptions,
report: ConvergenceReport,
V0: CxVec,
S0: CxVec,
- I0: CxVec,
- Y0: CxVec,
- tap_modules: Vec,
- tap_angles: Vec,
- Beq: Vec,
- pq: IntVec,
- pv: IntVec,
- pqv: IntVec,
- p: IntVec,
- ref: IntVec,
- pqpv: IntVec,
- Qmin: Vec,
- Qmax: Vec,
logger=Logger()) -> NumericPowerFlowResults:
"""
Run a power flow simulation using the selected method (no outer loop controls).
- :param circuit: SnapshotData circuit, this ensures on-demand admittances computation
+ :param nc: SnapshotData circuit, this ensures on-demand admittances computation
:param options: PowerFlow options
:param report: Convergence report to fill in
:param V0: Array of initial voltages
:param S0: Array of power Injections
- :param I0: Array of current Injections
- :param Y0: Array of admittance injections
- :param tap_modules: Array of branch tap modules
- :param tap_angles: Array of branch tap angles
- :param Beq: Array of branch equivalent susceptances
- :param pq: Array of pq nodes
- :param pv: Array of pv nodes
- :param pqv: Array of pqv nodes
- :param p: Array of p values
- :param ref: Array of slack nodes
- :param pqpv: Array of (sorted) pq and pv nodes
- :param Qmin: Array of minimum reactive power capability per bus
- :param Qmax: Array of maximum reactive power capability per bus
:param logger: Logger
:return: NumericPowerFlowResults
"""
if options.retry_with_other_methods:
- if circuit.any_control:
+ if nc.any_control:
solver_list = [SolverType.NR,
- SolverType.LM,
- SolverType.HELM,
- SolverType.IWAMOTO,
- SolverType.LACPF]
+ SolverType.PowellDogLeg,
+ SolverType.LM]
else:
solver_list = [SolverType.NR,
+ SolverType.PowellDogLeg,
SolverType.HELM,
SolverType.IWAMOTO,
SolverType.LM,
@@ -106,397 +84,431 @@ def solve(circuit: NumericalCircuit,
solver_idx = 0
# set the initial value
+ Qmin = nc.Qmin_bus
+ Qmax = nc.Qmax_bus
+ I0 = nc.Ibus
+ Y0 = nc.YLoadBus
+
+ vd, pq, pv, pqv, p, no_slack = compile_types(
+ Pbus=nc.Sbus.real,
+ types=nc.bus_data.bus_types
+ )
- final_solution = NumericPowerFlowResults(V=V0,
- converged=False,
- norm_f=1e200,
- Scalc=S0,
- ma=tap_modules,
- theta=circuit.branch_data.tap_angle,
- Beq=Beq,
- Ybus=circuit.Ybus,
- Yf=circuit.Yf,
- Yt=circuit.Yt,
- iterations=0,
- elapsed=0)
-
- while solver_idx < len(solvers) and not final_solution.converged:
- # get the solver
- solver_type = solvers[solver_idx]
-
- # type HELM
- if solver_type == SolverType.HELM:
- solution = pflw.helm_josep(Ybus=circuit.Ybus,
- Yseries=circuit.Yseries,
- V0=V0, # take V0 instead of V
- S0=S0,
- Ysh0=circuit.Yshunt,
- pq=pq,
- pv=pv,
- sl=ref,
- pqpv=pqpv,
- tolerance=options.tolerance,
- max_coefficients=options.max_iter,
- use_pade=False,
- verbose=options.verbose,
- logger=logger)
-
- # type DC
- elif solver_type == SolverType.DC:
- solution = pflw.dcpf(Ybus=circuit.Ybus,
- Bpqpv=circuit.Bpqpv,
- Bref=circuit.Bref,
- Bf=circuit.Bf,
- S0=S0,
- I0=I0,
- Y0=Y0,
- V0=V0,
- tau=tap_angles,
- vd=ref,
- pvpq=pqpv,
- pq=pq,
- pv=pv)
-
- # LAC PF
- elif solver_type == SolverType.LACPF:
- solution = pflw.lacpf(Ybus=circuit.Ybus,
- Ys=circuit.Yseries,
- S0=S0,
- I0=I0,
- V0=V0,
- pq=pq,
- pv=pv)
-
- # Gauss-Seidel
- elif solver_type == SolverType.GAUSS:
- solution = pflw.gausspf(Ybus=circuit.Ybus,
- S0=S0,
- I0=I0,
- Y0=Y0,
- V0=V0,
- pv=pv,
- pq=pq,
- tol=options.tolerance,
- max_it=options.max_iter,
- verbose=options.verbose,
- logger=logger)
-
- # Levenberg-Marquardt
- elif solver_type == SolverType.LM:
- if circuit.any_control:
- solution = pflw.LM_ACDC(nc=circuit,
- Vbus=V0,
- S0=S0,
- I0=I0,
- Y0=Y0,
- tolerance=options.tolerance,
- max_iter=options.max_iter)
- else:
- solution = pflw.levenberg_marquardt_pf(Ybus=circuit.Ybus,
- S0=S0,
- V0=final_solution.V,
- I0=I0,
- Y0=Y0,
- pv_=pv,
- pq_=pq,
- pqv_=pqv,
- p_=p,
- Qmin=Qmin,
- Qmax=Qmax,
- tol=options.tolerance,
- max_it=options.max_iter,
- control_q=options.control_Q,
- verbose=options.verbose,
- logger=logger)
-
- # Fast decoupled
- elif solver_type == SolverType.FASTDECOUPLED:
- solution = pflw.FDPF(Vbus=V0,
- S0=S0,
- I0=I0,
- Y0=Y0,
- Ybus=circuit.Ybus,
- B1=circuit.B1,
- B2=circuit.B2,
- pv_=pv,
- pq_=pq,
- pqv_=pqv,
- p_=p,
- Qmin=Qmin,
- Qmax=Qmax,
- tol=options.tolerance,
- max_it=options.max_iter,
- control_q=options.control_Q)
-
- # Newton-Raphson (full)
- elif solver_type == SolverType.NR:
- if circuit.any_control:
- # Solve NR with the AC/DC algorithm
- solution = pflw.NR_LS_ACDC(nc=circuit,
- V0=V0,
+ if len(vd) == 0:
+ solution = NumericPowerFlowResults(V=np.zeros(len(S0), dtype=complex),
+ converged=False,
+ norm_f=1e200,
+ Scalc=S0,
+ m=nc.branch_data.tap_module,
+ tau=nc.branch_data.tap_angle,
+ Beq=nc.branch_data.Beq,
+ Ybus=nc.Ybus,
+ Yf=nc.Yf,
+ Yt=nc.Yt,
+ iterations=0,
+ elapsed=0)
+ report.add(SolverType.NoSolver, True, 0, 0.0, 0.0)
+ logger.add_error('Not solving power flow because there is no slack bus')
+ return solution
+
+ else:
+ final_solution = NumericPowerFlowResults(V=V0,
+ converged=False,
+ norm_f=1e200,
+ Scalc=S0,
+ m=nc.branch_data.tap_module,
+ tau=nc.branch_data.tap_angle,
+ Beq=nc.branch_data.Beq,
+ Ybus=nc.Ybus,
+ Yf=nc.Yf,
+ Yt=nc.Yt,
+ iterations=0,
+ elapsed=0)
+
+ while solver_idx < len(solvers) and not final_solution.converged:
+ # get the solver
+ solver_type = solvers[solver_idx]
+
+ # type HELM
+ if solver_type == SolverType.HELM:
+ solution = pflw.helm_josep(Ybus=nc.Ybus,
+ Yseries=nc.Yseries,
+ V0=V0, # take V0 instead of V
S0=S0,
- I0=I0,
- Y0=Y0,
+ Ysh0=nc.Yshunt,
+ pq=pq,
+ pv=pv,
+ vd=vd,
+ no_slack=no_slack,
tolerance=options.tolerance,
- max_iter=options.max_iter,
- acceleration_parameter=options.backtracking_parameter,
- mu_0=options.trust_radius,
- control_q=options.control_Q)
- else:
- # Solve NR with the AC algorithm
- solution = pflw.NR_LS(Ybus=circuit.Ybus,
- S0=S0,
- V0=final_solution.V,
- I0=I0,
- Y0=Y0,
- pv_=pv,
- pq_=pq,
- pqv_=pqv,
- p_=p,
- Qmin=Qmin,
- Qmax=Qmax,
- tol=options.tolerance,
- max_it=options.max_iter,
- mu_0=options.trust_radius,
- acceleration_parameter=options.backtracking_parameter,
- control_q=options.control_Q,
- verbose=options.verbose,
- logger=logger)
-
- # Newton-Raphson-Decpupled
- elif solver_type == SolverType.NRD:
- # Solve NR with the linear AC solution
- solution = pflw.NRD_LS(Ybus=circuit.Ybus,
- S0=S0,
- V0=final_solution.V,
- I0=I0,
- Y0=Y0,
- pv=pv,
- pq=pq,
- tol=options.tolerance,
- max_it=options.max_iter,
- acceleration_parameter=options.backtracking_parameter)
-
- # Newton-Raphson-Iwamoto
- elif solver_type == SolverType.IWAMOTO:
- solution = pflw.IwamotoNR(Ybus=circuit.Ybus,
+ max_coefficients=options.max_iter,
+ use_pade=False,
+ verbose=options.verbose,
+ logger=logger)
+
+ if options.distributed_slack:
+ ok, delta = compute_slack_distribution(Scalc=solution.Scalc,
+ vd=vd,
+ bus_installed_power=nc.bus_installed_power)
+ if ok:
+ solution = pflw.helm_josep(Ybus=nc.Ybus,
+ Yseries=nc.Yseries,
+ V0=V0, # take V0 instead of V
+ S0=S0 + delta,
+ Ysh0=nc.Yshunt,
+ pq=pq,
+ pv=pv,
+ vd=vd,
+ no_slack=no_slack,
+ tolerance=options.tolerance,
+ max_coefficients=options.max_iter,
+ use_pade=False,
+ verbose=options.verbose,
+ logger=logger)
+
+ # type DC
+ elif solver_type == SolverType.DC:
+ solution = pflw.dcpf(Ybus=nc.Ybus,
+ Bpqpv=nc.Bpqpv,
+ Bref=nc.Bref,
+ Bf=nc.Bf,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ V0=V0,
+ tau=nc.branch_data.tap_angle,
+ vd=vd,
+ no_slack=no_slack,
+ pq=pq,
+ pv=pv)
+
+ if options.distributed_slack:
+ ok, delta = compute_slack_distribution(Scalc=solution.Scalc,
+ vd=vd,
+ bus_installed_power=nc.bus_installed_power)
+ if ok:
+ solution = pflw.dcpf(Ybus=nc.Ybus,
+ Bpqpv=nc.Bpqpv,
+ Bref=nc.Bref,
+ Bf=nc.Bf,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ V0=V0,
+ tau=nc.branch_data.tap_angle,
+ vd=vd,
+ no_slack=no_slack,
+ pq=pq,
+ pv=pv)
+
+ # LAC PF
+ elif solver_type == SolverType.LACPF:
+ solution = pflw.lacpf(Ybus=nc.Ybus,
+ Ys=nc.Yseries,
S0=S0,
- V0=final_solution.V,
I0=I0,
- Y0=Y0,
- pv_=pv,
- pq_=pq,
- pqv_=pqv,
- p_=p,
- Qmin=Qmin,
- Qmax=Qmax,
- tol=options.tolerance,
- max_it=options.max_iter,
- control_q=options.control_Q,
- robust=True,
- logger=logger)
-
- # Newton-Raphson in current equations
- elif solver_type == SolverType.NRI:
- solution = pflw.NR_I_LS(Ybus=circuit.Ybus,
- Sbus_sp=S0,
- V0=final_solution.V,
- Ibus_sp=I0,
- pv=pv,
- pq=pq,
- tol=options.tolerance,
- max_it=options.max_iter)
+ V0=V0,
+ pq=pq,
+ pv=pv)
+ if options.distributed_slack:
+ ok, delta = compute_slack_distribution(Scalc=solution.Scalc,
+ vd=vd,
+ bus_installed_power=nc.bus_installed_power)
+ if ok:
+ solution = pflw.lacpf(Ybus=nc.Ybus,
+ Ys=nc.Yseries,
+ S0=S0,
+ I0=I0,
+ V0=V0,
+ pq=pq,
+ pv=pv)
+
+ # Gauss-Seidel
+ elif solver_type == SolverType.GAUSS:
+ solution = pflw.gausspf(Ybus=nc.Ybus,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ V0=V0,
+ pv=pv,
+ pq=pq,
+ p=p,
+ pqv=pqv,
+ vd=vd,
+ bus_installed_power=nc.bus_installed_power,
+ Qmin=Qmin,
+ Qmax=Qmax,
+ tol=options.tolerance,
+ max_it=options.max_iter,
+ control_q=options.control_Q,
+ distribute_slack=options.distributed_slack,
+ verbose=options.verbose,
+ logger=logger)
+
+ # Levenberg-Marquardt
+ elif solver_type == SolverType.LM:
+ if nc.any_control:
+ # Solve NR with the AC/DC algorithm
+
+ problem = PfAdvancedFormulation(V0=final_solution.V,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ Qmin=Qmin,
+ Qmax=Qmax,
+ nc=nc,
+ options=options,
+ logger=logger)
+
+ solution = levenberg_marquadt_fx(problem=problem,
+ tol=options.tolerance,
+ max_iter=options.max_iter,
+ trust=options.trust_radius,
+ verbose=options.verbose,
+ logger=logger)
+ else:
+ # Solve NR with the AC algorithm
+ problem = PfBasicFormulation(V0=final_solution.V,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ Qmin=Qmin,
+ Qmax=Qmax,
+ nc=nc,
+ options=options)
+
+ solution = levenberg_marquadt_fx(problem=problem,
+ tol=options.tolerance,
+ max_iter=options.max_iter,
+ trust=options.trust_radius,
+ verbose=options.verbose,
+ logger=logger)
+
+ # Fast decoupled
+ elif solver_type == SolverType.FASTDECOUPLED:
+ solution = pflw.FDPF(Vbus=V0,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ Ybus=nc.Ybus,
+ B1=nc.B1,
+ B2=nc.B2,
+ pv_=pv,
+ pq_=pq,
+ pqv_=pqv,
+ p_=p,
+ vd_=vd,
+ Qmin=Qmin,
+ Qmax=Qmax,
+ bus_installed_power=nc.bus_installed_power,
+ tol=options.tolerance,
+ max_it=options.max_iter,
+ control_q=options.control_Q,
+ distribute_slack=options.distributed_slack)
+
+ # Newton-Raphson (full)
+ elif solver_type == SolverType.NR:
+ if nc.any_control:
+ # Solve NR with the AC/DC algorithm
+
+ problem = PfAdvancedFormulation(V0=final_solution.V,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ Qmin=Qmin,
+ Qmax=Qmax,
+ nc=nc,
+ options=options,
+ logger=logger)
+
+ solution = newton_raphson_fx(problem=problem,
+ tol=options.tolerance,
+ max_iter=options.max_iter,
+ trust=options.trust_radius,
+ verbose=options.verbose,
+ logger=logger)
+ else:
+ # Solve NR with the AC algorithm
+ problem = PfBasicFormulation(V0=final_solution.V,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ Qmin=Qmin,
+ Qmax=Qmax,
+ nc=nc,
+ options=options)
+
+ solution = newton_raphson_fx(problem=problem,
+ tol=options.tolerance,
+ max_iter=options.max_iter,
+ trust=options.trust_radius,
+ verbose=options.verbose,
+ logger=logger)
+
+ # Powell's Dog Leg (full)
+ elif solver_type == SolverType.PowellDogLeg:
+ if nc.any_control:
+ # Solve NR with the AC/DC algorithm
+
+ problem = PfAdvancedFormulation(V0=final_solution.V,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ Qmin=Qmin,
+ Qmax=Qmax,
+ nc=nc,
+ options=options,
+ logger=logger)
+
+ solution = powell_fx(problem=problem,
+ tol=options.tolerance,
+ max_iter=options.max_iter,
+ trust=options.trust_radius,
+ verbose=options.verbose,
+ logger=logger)
+ else:
+ # Solve NR with the AC algorithm
+ problem = PfBasicFormulation(V0=final_solution.V,
+ S0=S0,
+ I0=I0,
+ Y0=Y0,
+ Qmin=Qmin,
+ Qmax=Qmax,
+ nc=nc,
+ options=options)
+
+ solution = powell_fx(problem=problem,
+ tol=options.tolerance,
+ max_iter=options.max_iter,
+ trust=options.trust_radius,
+ verbose=options.verbose,
+ logger=logger)
+
+ # Newton-Raphson-Iwamoto
+ elif solver_type == SolverType.IWAMOTO:
+ solution = pflw.IwamotoNR(Ybus=nc.Ybus,
+ S0=S0,
+ V0=final_solution.V,
+ I0=I0,
+ Y0=Y0,
+ pv_=pv,
+ pq_=pq,
+ pqv_=pqv,
+ p_=p,
+ Qmin=Qmin,
+ Qmax=Qmax,
+ tol=options.tolerance,
+ max_it=options.max_iter,
+ control_q=options.control_Q,
+ robust=True,
+ logger=logger)
- else:
- # for any other method, raise exception
- raise Exception(solver_type.value + ' Not supported in power flow mode')
-
- # record the solution type
- solution.method = solver_type
-
- # record the method used, if it improved the solution
- if abs(solution.norm_f) < abs(final_solution.norm_f):
- report.add(method=solver_type,
- converged=solution.converged,
- error=solution.norm_f,
- elapsed=solution.elapsed,
- iterations=solution.iterations)
- final_solution = solution
- else:
- logger.add_info('Tried solver but it did not improve the solution',
- solver_type.value, value=solution.norm_f,
- expected_value=final_solution.norm_f)
+ else:
+ # for any other method, raise exception
+ raise Exception(solver_type.value + ' Not supported in power flow mode')
+
+ # record the solution type
+ solution.method = solver_type
+
+ # record the method used, if it improved the solution
+ if abs(solution.norm_f) < abs(final_solution.norm_f):
+ report.add(method=solver_type,
+ converged=solution.converged,
+ error=solution.norm_f,
+ elapsed=solution.elapsed,
+ iterations=solution.iterations)
+ final_solution = solution
+ else:
+ logger.add_info('Tried solver but it did not improve the solution',
+ solver_type.value,
+ value="{:.4e}".format(solution.norm_f),
+ expected_value=final_solution.norm_f)
- # record the solver steps
- solver_idx += 1
+ # next solver
+ solver_idx += 1
- if not final_solution.converged:
- logger.add_error('Did not converge, even after retry!', 'Error', str(final_solution.norm_f), options.tolerance)
+ if not final_solution.converged:
+ logger.add_error('Did not converge, even after retry!',
+ device='Error',
+ value="{:.4e}".format(final_solution.norm_f),
+ expected_value=f"<{options.tolerance}")
- if final_solution.ma is None:
- final_solution.ma = tap_modules
+ if final_solution.tap_module is None:
+ final_solution.tap_module = nc.branch_data.tap_module
- if final_solution.theta is None:
- final_solution.theta = tap_angles
+ if final_solution.tap_angle is None:
+ final_solution.tap_angle = nc.branch_data.tap_angle
- if final_solution.Beq is None:
- final_solution.Beq = Beq
+ if final_solution.Beq is None:
+ final_solution.Beq = nc.branch_data.Beq
- return final_solution
+ return final_solution
-def single_island_pf(circuit: NumericalCircuit, options: PowerFlowOptions,
+def single_island_pf(nc: NumericalCircuit,
+ options: PowerFlowOptions,
voltage_solution: CxVec,
S0: CxVec,
- I0: CxVec,
- Y0: CxVec,
- tap_modules: Vec,
- tap_angles: Vec,
- Beq: Vec,
- branch_rates: Vec,
- pq: IntVec,
- pv: IntVec,
- pqv: IntVec,
- p: IntVec,
- vd: IntVec,
- pqpv: IntVec,
- Qmin: Vec,
- Qmax: Vec, logger=Logger()) -> "PowerFlowResults":
+ logger=Logger()) -> "PowerFlowResults":
"""
Run a power flow simulation for a single circuit using the
selected outer loop controls.
This method shouldn't be called directly.
- :param circuit: CalculationInputs instance
+ :param nc: CalculationInputs instance
:param options: PowerFlowOptions
:param voltage_solution: vector of initial voltages
:param S0: Array of power Injections
- :param I0: Array of current Injections
- :param Y0: Array of admittance injections
- :param tap_modules: Array of branch tap modules
- :param tap_angles: Array of branch tap angles
- :param Beq: Array of branch equivalent susceptances
- :param branch_rates: Array of branch rates
- :param pq: Array of pq nodes
- :param pv: Array of pv nodes
- :param pqv: Array of pqv nodes
- :param p: Array of p nodes
- :param vd: Array of slack nodes
- :param pqpv: Array of (sorted) pq and pv nodes
- :param Qmin: Array of minimum reactive power capability per bus
- :param Qmax: Array of maximum reactive power capability per bus
:param logger: Logger object
:return: PowerFlowResults instance
"""
# get the original types and compile this class' own lists of node types for thread independence
- bus_types = circuit.bus_types.copy()
+ bus_types = nc.bus_types.copy()
report = ConvergenceReport()
- solution = NumericPowerFlowResults(V=voltage_solution,
- converged=False,
- norm_f=1e200,
- Scalc=S0,
- ma=tap_modules,
- theta=tap_angles,
- Beq=Beq,
- Ybus=circuit.Ybus,
- Yf=circuit.Yf,
- Yt=circuit.Yt,
- iterations=0,
- elapsed=0)
-
- # this the "outer-loop"
- if len(vd) == 0:
- solution.V = np.zeros(len(S0), dtype=complex)
- report.add(SolverType.NoSolver, True, 0, 0.0, 0.0)
- logger.add_error('Not solving power flow because there is no slack bus')
- else:
- # run the power flow method that shall be run
- solution = solve(circuit=circuit,
- options=options,
- report=report, # is modified here
- V0=voltage_solution,
- S0=S0,
- I0=I0,
- Y0=Y0,
- tap_modules=tap_modules,
- tap_angles=tap_angles,
- Beq=Beq,
- pq=pq,
- pv=pv,
- pqv=pqv,
- p=p,
- ref=vd,
- pqpv=pqpv,
- Qmin=Qmin,
- Qmax=Qmax,
- logger=logger)
-
- if options.distributed_slack:
- # Distribute the slack power
- slack_power = S0[circuit.vd].real.sum()
- total_installed_power = circuit.bus_installed_power.sum()
-
- if total_installed_power > 0.0:
- delta = slack_power * circuit.bus_installed_power / total_installed_power
-
- # repeat power flow with the redistributed power
- solution = solve(circuit=circuit,
- options=options,
- report=report, # is modified here
- V0=solution.V,
- S0=S0 + delta,
- I0=I0,
- Y0=Y0,
- tap_modules=tap_modules,
- tap_angles=tap_angles,
- Beq=Beq,
- pq=pq,
- pv=pv,
- pqv=pqv,
- p=p,
- ref=vd,
- pqpv=pqpv,
- Qmin=Qmin,
- Qmax=Qmax,
- logger=logger)
+ # run the power flow method that shall be run
+ solution = solve(nc=nc,
+ options=options,
+ report=report, # is modified here
+ V0=voltage_solution,
+ S0=S0,
+ logger=logger)
# Compute the Branches power and the slack buses power
- Sfb, Stb, If, It, Vbranch, loading, losses, S0 = power_flow_post_process(calculation_inputs=circuit,
+ Sfb, Stb, If, It, Vbranch, loading, losses, S0 = power_flow_post_process(calculation_inputs=nc,
Sbus=solution.Scalc,
V=solution.V,
- branch_rates=branch_rates,
+ branch_rates=nc.Rates,
Ybus=solution.Ybus,
Yf=solution.Yf,
Yt=solution.Yt,
method=solution.method)
# voltage, Sf, loading, losses, error, converged, Qpv
- results = PowerFlowResults(n=circuit.nbus,
- m=circuit.nbr,
- n_hvdc=circuit.nhvdc,
- bus_names=circuit.bus_names,
- branch_names=circuit.branch_names,
- hvdc_names=circuit.hvdc_names,
+ results = PowerFlowResults(n=nc.nbus,
+ m=nc.nbr,
+ n_hvdc=nc.nhvdc,
+ bus_names=nc.bus_names,
+ branch_names=nc.branch_names,
+ hvdc_names=nc.hvdc_names,
bus_types=bus_types)
- results.Sbus = solution.Scalc * circuit.Sbase # MVA
+ results.Sbus = solution.Scalc * nc.Sbase # MVA
results.voltage = solution.V
results.Sf = Sfb # in MVA already
results.St = Stb # in MVA already
results.If = If # in p.u.
results.It = It # in p.u.
- results.tap_module = solution.ma
- results.tap_angle = solution.theta
+ results.tap_module = solution.tap_module
+ results.tap_angle = solution.tap_angle
results.Beq = solution.Beq
results.Vbranch = Vbranch
results.loading = loading
results.losses = losses
results.convergence_reports.append(report)
- results.Qpv = S0.imag[circuit.pv]
- # HVDC results are gathered in the multi island power flow function due to their nature
+ # HVDC results are gathered in the multi island power flow function due to their poly-island nature
return results
@@ -652,24 +664,11 @@ def multi_island_pf_nc(nc: NumericalCircuit,
Sbus = (Sbus_input + Shvdc)[island.original_bus_idx]
res = single_island_pf(
- circuit=island,
+ nc=island,
options=options,
voltage_solution=island.Vbus if V_guess is None else V_guess[island.original_bus_idx],
S0=Sbus,
- I0=island.Ibus,
- Y0=island.YLoadBus,
- tap_modules=island.branch_data.tap_module,
- tap_angles=island.branch_data.tap_angle,
- Beq=island.branch_data.Beq,
- branch_rates=island.Rates,
- pq=island.pq,
- pv=island.pv,
- pqv=island.pqv,
- p=island.p,
- vd=island.vd,
- pqpv=island.pqpv,
- Qmin=island.Qmin_bus,
- Qmax=island.Qmax_bus,
+
logger=logger
)
@@ -766,34 +765,20 @@ def multi_island_pf(multi_circuit: MultiCircuit,
:return: PowerFlowResults instance
"""
- # Generalised PowerFlow
- if options.generalised_pf:
- nc = compile_numerical_circuit_at_generalised_pf(
- circuit=multi_circuit,
- t_idx=t,
- apply_temperature=options.apply_temperature_correction,
- branch_tolerance_mode=options.branch_impedance_tolerance_mode,
- opf_results=opf_results,
- use_stored_guess=options.use_stored_guess,
- bus_dict=bus_dict,
- areas_dict=areas_dict
- )
- # print("Generalised PowerFlow")
-
- # Normal PowerFlow
- else:
- nc = compile_numerical_circuit_at(
- circuit=multi_circuit,
- t_idx=t,
- apply_temperature=options.apply_temperature_correction,
- branch_tolerance_mode=options.branch_impedance_tolerance_mode,
- opf_results=opf_results,
- use_stored_guess=options.use_stored_guess,
- bus_dict=bus_dict,
- areas_dict=areas_dict,
- logger=logger,
- )
- # print("Normal PowerFlow")
+ nc = compile_numerical_circuit_at(
+ circuit=multi_circuit,
+ t_idx=t,
+ apply_temperature=options.apply_temperature_correction,
+ branch_tolerance_mode=options.branch_impedance_tolerance_mode,
+ opf_results=opf_results,
+ use_stored_guess=options.use_stored_guess,
+ bus_dict=bus_dict,
+ areas_dict=areas_dict,
+ control_taps_modules=options.control_taps_modules,
+ control_taps_phase=options.control_taps_phase,
+ control_remote_voltage=options.control_remote_voltage,
+ logger=logger,
+ )
res = multi_island_pf_nc(nc=nc, options=options, logger=logger)
diff --git a/src/GridCalEngine/Simulations/ShortCircuitStudies/short_circuit_worker.py b/src/GridCalEngine/Simulations/ShortCircuitStudies/short_circuit_worker.py
index 0a5541250..1d21a9ebd 100644
--- a/src/GridCalEngine/Simulations/ShortCircuitStudies/short_circuit_worker.py
+++ b/src/GridCalEngine/Simulations/ShortCircuitStudies/short_circuit_worker.py
@@ -155,11 +155,7 @@ def short_circuit_unbalanced(calculation_inputs: NumericalCircuit,
Beq=np.zeros(nbr),
Cf=calculation_inputs.branch_data.C_branch_bus_f.tocsc(),
Ct=calculation_inputs.branch_data.C_branch_bus_t.tocsc(),
- G0sw=np.zeros(nbr),
- If=np.zeros(nbr),
- a=np.zeros(nbr),
- b=np.zeros(nbr),
- c=np.zeros(nbr),
+ Gsw=np.zeros(nbr),
Yshunt_bus=Yshunt_bus0,
conn=calculation_inputs.branch_data.conn,
seq=0,
@@ -181,11 +177,7 @@ def short_circuit_unbalanced(calculation_inputs: NumericalCircuit,
Beq=calculation_inputs.branch_data.Beq,
Cf=calculation_inputs.branch_data.C_branch_bus_f.tocsc(),
Ct=calculation_inputs.branch_data.C_branch_bus_t.tocsc(),
- G0sw=calculation_inputs.branch_data.G0sw,
- If=np.zeros(nbr),
- a=calculation_inputs.branch_data.a,
- b=calculation_inputs.branch_data.b,
- c=calculation_inputs.branch_data.c,
+ Gsw=calculation_inputs.branch_data.G0sw,
Yshunt_bus=Yshunt_bus1,
conn=calculation_inputs.branch_data.conn,
seq=1,
@@ -207,11 +199,7 @@ def short_circuit_unbalanced(calculation_inputs: NumericalCircuit,
Beq=np.zeros(nbr),
Cf=calculation_inputs.branch_data.C_branch_bus_f.tocsc(),
Ct=calculation_inputs.branch_data.C_branch_bus_t.tocsc(),
- G0sw=np.zeros(nbr),
- If=np.zeros(nbr),
- a=np.zeros(nbr),
- b=np.zeros(nbr),
- c=np.zeros(nbr),
+ Gsw=np.zeros(nbr),
Yshunt_bus=Yshunt_bus2,
conn=calculation_inputs.branch_data.conn,
seq=2,
@@ -251,11 +239,7 @@ def short_circuit_unbalanced(calculation_inputs: NumericalCircuit,
Beq=np.zeros(nbr),
Cf=calculation_inputs.branch_data.C_branch_bus_f.tocsc(),
Ct=calculation_inputs.branch_data.C_branch_bus_t.tocsc(),
- G0sw=np.zeros(nbr),
- If=np.zeros(nbr),
- a=calculation_inputs.branch_data.a,
- b=calculation_inputs.branch_data.b,
- c=calculation_inputs.branch_data.c,
+ Gsw=np.zeros(nbr),
Yshunt_bus=np.zeros(nbus, dtype=complex),
conn=calculation_inputs.branch_data.conn,
seq=1,
diff --git a/src/GridCalEngine/Simulations/StateEstimation/state_estimation.py b/src/GridCalEngine/Simulations/StateEstimation/state_estimation.py
index c692a8d0a..ae472ab28 100644
--- a/src/GridCalEngine/Simulations/StateEstimation/state_estimation.py
+++ b/src/GridCalEngine/Simulations/StateEstimation/state_estimation.py
@@ -393,6 +393,6 @@ def solve_se_lm(Ybus, Yf, Yt, f, t, se_input, ref, pq, pv) -> NumericPowerFlowRe
# return NumericPowerFlowResults(V, converged, err, Scalc, None, None, None, None, None, None, iter_, elapsed)
return NumericPowerFlowResults(V=V, converged=converged, norm_f=err,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/Stochastic/reliability_driver.py b/src/GridCalEngine/Simulations/Stochastic/reliability_driver.py
index c67bdd133..2d9b1d6d4 100644
--- a/src/GridCalEngine/Simulations/Stochastic/reliability_driver.py
+++ b/src/GridCalEngine/Simulations/Stochastic/reliability_driver.py
@@ -184,13 +184,13 @@ def __init__(self, circuit: MultiCircuit, pf_options: PowerFlowOptions):
self.__cancel__ = False
- def progress_callback(self, l):
+ def progress_callback(self, lmbda: float):
"""
Send progress report
- :param l: lambda value
+ :param lmbda: lambda value
:return: None
"""
- self.report_text('Running voltage collapse lambda:' + "{0:.2f}".format(l) + '...')
+ self.report_text('Running voltage collapse lambda:' + "{0:.2f}".format(lmbda) + '...')
def run(self):
"""
diff --git a/src/GridCalEngine/Simulations/driver_template.py b/src/GridCalEngine/Simulations/driver_template.py
index 4e4b14a11..b25e9bd5d 100644
--- a/src/GridCalEngine/Simulations/driver_template.py
+++ b/src/GridCalEngine/Simulations/driver_template.py
@@ -88,7 +88,7 @@ def tic(self, skip_logger=False):
if not skip_logger:
self.logger.add_info(msg="Elapsed total (s)",
- device="Started")
+ device_property="Started")
def toc(self, skip_logger=False):
"""
@@ -99,8 +99,8 @@ def toc(self, skip_logger=False):
if not skip_logger:
self.logger.add_info(msg="Elapsed total (s)",
- device="Ended",
- value=self.elapsed)
+ device_property="Ended (s)",
+ value='{:.4f}'.format(self.elapsed))
def get_steps(self):
"""
diff --git a/src/GridCalEngine/Topology/admittance_matrices.py b/src/GridCalEngine/Topology/admittance_matrices.py
index 3ba7eb119..cd138a1af 100644
--- a/src/GridCalEngine/Topology/admittance_matrices.py
+++ b/src/GridCalEngine/Topology/admittance_matrices.py
@@ -39,7 +39,8 @@ def __init__(self,
ytf: CxVec,
ytt: CxVec,
Yshunt_bus: CxVec,
- Gsw: Vec):
+ Gsw: Vec,
+ beq: Vec):
"""
Constructor
:param Ybus: Admittance matrix
@@ -54,15 +55,15 @@ def __init__(self,
:param Yshunt_bus: array of shunt admittances per bus
:param Gsw: Switch losses in the converters
"""
- self.Ybus = Ybus
+ self.Ybus = Ybus if Ybus.format == 'csc' else Ybus.tocsc()
- self.Yf = Yf
+ self.Yf = Yf if Yf.format == 'csc' else Yf.tocsc()
- self.Yt = Yt
+ self.Yt = Yt if Yt.format == 'csc' else Yt.tocsc()
- self.Cf = Cf
+ self.Cf = Cf if Cf.format == 'csc' else Cf.tocsc()
- self.Ct = Ct
+ self.Ct = Ct if Ct.format == 'csc' else Ct.tocsc()
self.yff = yff
@@ -76,6 +77,8 @@ def __init__(self,
self.Gsw = Gsw
+ self.beq = beq
+
def modify_taps(self, m: Vec, m2: Vec, tau: Vec, tau2: Vec,
idx: Union[IntVec, None] = None) -> Tuple[sp.csc_matrix, sp.csc_matrix, sp.csc_matrix]:
"""
@@ -115,6 +118,23 @@ def modify_taps(self, m: Vec, m2: Vec, tau: Vec, tau2: Vec,
return self.Ybus, self.Yf, self.Yt
+ def copy(self) -> "AdmittanceMatrices":
+ """
+ Get a deep copy
+ """
+ return AdmittanceMatrices(Ybus=self.Ybus.copy(),
+ Yf=self.Yf.copy(),
+ Yt=self.Yt.copy(),
+ Cf=self.Cf.copy(),
+ Ct=self.Ct.copy(),
+ yff=self.yff.copy(),
+ yft=self.yft.copy(),
+ ytf=self.ytf.copy(),
+ ytt=self.ytt.copy(),
+ Yshunt_bus=self.Yshunt_bus.copy(),
+ Gsw=self.Gsw.copy(),
+ beq=self.beq.copy())
+
def compute_admittances(R: Vec,
X: Vec,
@@ -126,17 +146,14 @@ def compute_admittances(R: Vec,
vtap_t: Vec,
tap_angle: Vec,
Beq: Vec,
- If: CxVec,
Cf: sp.csc_matrix,
Ct: sp.csc_matrix,
- G0sw: Vec,
- a: Vec,
- b: Vec,
- c: Vec,
+ Gsw: Vec,
Yshunt_bus: CxVec,
conn: Union[List[WindingsConnection], ObjVec],
seq: int,
- add_windings_phase: bool = False) -> AdmittanceMatrices:
+ add_windings_phase: bool = False,
+ verbose: int = 0) -> AdmittanceMatrices:
"""
Compute the complete admittance matrices for the general power flow methods (Newton-Raphson based)
@@ -150,22 +167,19 @@ def compute_admittances(R: Vec,
:param vtap_t: array of virtual taps at the "to" side
:param tap_angle: array of tap angles (for all Branches, regardless of their type)
:param Beq: Array of equivalent susceptance
- :param If: Array of currents "from" in all the Branches
:param Cf: Connectivity branch-bus "from" with the branch states computed
:param Ct: Connectivity branch-bus "to" with the branch states computed
- :param G0sw: base converter switch losses
- :param a: quadratic converter losses coefficient
- :param b: linear converter losses coefficient
- :param c: constant converter losses coefficient
+ :param Gsw: converter switch losses
:param Yshunt_bus: array of shunts equivalent power per bus, from the shunt devices (p.u.)
:param seq: Sequence [0, 1, 2]
:param conn: array of windings connections (numpy array of WindingsConnection)
:param add_windings_phase: Add the phases of the transformer windings (for short circuits mainly)
+ :param verbose
:return: Admittance instance
"""
# compute G-switch
- Gsw = G0sw + a * np.power(If, 2) + b * If + c
+ # Gsw = G0sw + a * np.power(If, 2) + b * If + c
# form the admittance matrices
ys = 1.0 / (R + 1.0j * X + 1e-20) # series admittance
@@ -223,17 +237,34 @@ def compute_admittances(R: Vec,
raise Exception('Unsupported sequence when computing the admittance matrix sequence={}'.format(seq))
else: # original
+ # with np.errstate(all='raise'):
Yff = Gsw + (ys + bc2 + 1.0j * Beq) / (mp * mp * vtap_f * vtap_f)
Yft = -ys / (mp * np.exp(-1.0j * tap_angle) * vtap_f * vtap_t)
Ytf = -ys / (mp * np.exp(1.0j * tap_angle) * vtap_t * vtap_f)
Ytt = (ys + bc2) / (vtap_t * vtap_t)
+ # tap = tap_module * np.exp(1.0j * tap_angle)
+ # Ytt = ys + 1j * bc2
+ # Yff = Gsw + ((Ytt + 1j * Beq) / (k*k * tap * np.conj(tap)))
+ # Yft = - ys / (k * np.conj(tap))
+ # Ytf = - ys / (k * tap)
+
+ if verbose > 0:
+ print('yff:', Yff)
+ print('yft:', Yft)
+ print('ytf:', Ytf)
+ print('ytt:', Ytt)
+
# compose the matrices
Yf = sp.diags(Yff) * Cf + sp.diags(Yft) * Ct
Yt = sp.diags(Ytf) * Cf + sp.diags(Ytt) * Ct
Ybus = Cf.T * Yf + Ct.T * Yt + sp.diags(Yshunt_bus)
- return AdmittanceMatrices(Ybus, Yf, Yt, Cf, Ct, Yff, Yft, Ytf, Ytt, Yshunt_bus, Gsw)
+ if verbose > 0:
+ print('Ybus:', Ybus.toarray())
+
+ return AdmittanceMatrices(Ybus.tocsc(), Yf.tocsc(), Yt.tocsc(), Cf.tocsc(), Ct.tocsc(),
+ Yff, Yft, Ytf, Ytt, Yshunt_bus, Gsw, Beq)
def compute_passive_admittances(R: Vec,
@@ -328,7 +359,7 @@ def compute_passive_admittances(R: Vec,
Yt = sp.diags(ytf) * Cf + sp.diags(ytt) * Ct
Ybus = Cf.T * Yf + Ct.T * Yt + sp.diags(Yshunt_bus)
- return AdmittanceMatrices(Ybus, Yf, Yt, Cf, Ct, yff, yft, ytf, ytt, Yshunt_bus, np.zeros_like(R))
+ return AdmittanceMatrices(Ybus, Yf, Yt, Cf, Ct, yff, yft, ytf, ytt, Yshunt_bus, np.zeros_like(R), np.zeros_like(R))
def compute_tap_control_admittances_injectins(
@@ -411,7 +442,8 @@ def compile_y_acdc(Cf: sp.csc_matrix,
Beq: Vec,
Gsw: Vec,
virtual_tap_from: Vec,
- virtual_tap_to: Vec) -> Tuple[sp.csc_matrix, sp.csc_matrix, sp.csc_matrix, CxVec]:
+ virtual_tap_to: Vec) -> Tuple[
+ sp.csc_matrix, sp.csc_matrix, sp.csc_matrix, CxVec, CxVec, CxVec, CxVec, CxVec]:
"""
Compile the admittance matrices using the variable elements
:param Cf: Connectivity branch-bus "from" with the branch states computed
@@ -443,17 +475,17 @@ def compile_y_acdc(Cf: sp.csc_matrix,
tap = tap_module * np.exp(1.0j * tap_angle)
# compose the primitives
- Yff = Gsw + (ys + bc2 + 1.0j * Beq + yshunt_f) / (tap_module * tap_module * virtual_tap_from * virtual_tap_from)
- Yft = -ys / (np.conj(tap) * virtual_tap_from * virtual_tap_to)
- Ytf = -ys / (tap * virtual_tap_from * virtual_tap_to)
- Ytt = ys + bc2 + yshunt_t / (virtual_tap_to * virtual_tap_to)
+ yff = Gsw + (ys + bc2 + 1.0j * Beq + yshunt_f) / (tap_module * tap_module * virtual_tap_from * virtual_tap_from)
+ yft = -ys / (np.conj(tap) * virtual_tap_from * virtual_tap_to)
+ ytf = -ys / (tap * virtual_tap_from * virtual_tap_to)
+ ytt = ys + bc2 + yshunt_t / (virtual_tap_to * virtual_tap_to)
# compose the matrices
- Yf = sp.diags(Yff) * Cf + sp.diags(Yft) * Ct
- Yt = sp.diags(Ytf) * Cf + sp.diags(Ytt) * Ct
+ Yf = sp.diags(yff) * Cf + sp.diags(yft) * Ct
+ Yt = sp.diags(ytf) * Cf + sp.diags(ytt) * Ct
Ybus = sp.csc_matrix(Cf.T * Yf + Ct.T * Yt)
- return Ybus, Yf.tocsc(), Yt.tocsc(), tap
+ return Ybus, Yf.tocsc(), Yt.tocsc(), tap, yff, yft, ytf, ytt
class SeriesAdmittanceMatrices:
diff --git a/src/GridCalEngine/Topology/simulation_indices.py b/src/GridCalEngine/Topology/simulation_indices.py
index d95efb545..3c3f6153c 100644
--- a/src/GridCalEngine/Topology/simulation_indices.py
+++ b/src/GridCalEngine/Topology/simulation_indices.py
@@ -18,13 +18,14 @@
import numpy as np
import numba as nb
-from typing import Union, Tuple, List
-from GridCalEngine.enumerations import TransformerControlType, ConverterControlType, BusMode
+from typing import Tuple, List
+from GridCalEngine.enumerations import BusMode, TapPhaseControl, TapModuleControl
from GridCalEngine.basic_structures import Vec, IntVec, BoolVec
@nb.njit(cache=True)
-def compile_types(Pbus: Vec, types: IntVec) -> Tuple[IntVec, IntVec, IntVec, IntVec, IntVec, IntVec]:
+def compile_types(Pbus: Vec,
+ types: IntVec) -> Tuple[IntVec, IntVec, IntVec, IntVec, IntVec, IntVec]:
"""
Compile the types.
:param Pbus: array of real power Injections per node used to choose the slack as
@@ -72,103 +73,6 @@ def compile_types(Pbus: Vec, types: IntVec) -> Tuple[IntVec, IntVec, IntVec, Int
return ref, pq, pv, pqv, p, no_slack
-@nb.njit(cache=True)
-def compose_generator_voltage_profile(nbus: int,
- gen_bus_indices: np.ndarray,
- gen_vset: np.ndarray,
- gen_status: np.ndarray,
- gen_is_controlled: np.ndarray,
- bat_bus_indices: np.ndarray,
- bat_vset: np.ndarray,
- bat_status: np.ndarray,
- bat_is_controlled: np.ndarray,
- hvdc_bus_f: np.ndarray,
- hvdc_bus_t: np.ndarray,
- hvdc_status: np.ndarray,
- hvdc_vf: np.ndarray,
- hvdc_vt: np.ndarray,
- k_vf_beq: np.ndarray,
- k_vt_m: np.ndarray,
- i_vf_beq: np.ndarray,
- i_vt_m: np.ndarray,
- branch_status: np.ndarray,
- br_vf: np.ndarray,
- br_vt: np.ndarray):
- """
- Get the array of voltage set points per bus
- :param nbus: number of buses
- :param gen_bus_indices: array of bus indices per generator (ngen)
- :param gen_vset: array of voltage set points (ngen)
- :param gen_status: array of generator status (ngen)
- :param gen_is_controlled: array of values indicating if a generator controls the voltage or not (ngen)
- :param bat_bus_indices: array of bus indices per battery (nbatt)
- :param bat_vset: array of voltage set points (nbatt)
- :param bat_status: array of battery status (nbatt)
- :param bat_is_controlled: array of values indicating if a battery controls the voltage or not (nbatt)
- :param hvdc_bus_f: array of hvdc bus from indices (nhvdc)
- :param hvdc_bus_t: array of hvdc bus to indices (nhvdc)
- :param hvdc_status: array of hvdc status (nhvdc)
- :param hvdc_vf: array of hvdc voltage from set points (nhvdc)
- :param hvdc_vt: array of hvdc voltage to set points (nhvdc)
- :param k_vf_beq: indices of the Branches when controlling Vf with Beq
- :param k_vt_m: indices of the Branches when controlling Vt with ma
- :param i_vf_beq: indices of the buses where Vf is controlled by Beq
- :param i_vt_m: indices of the buses where Vt is controlled by ma
- :param branch_status: array of brach status (nbr)
- :param br_vf: array of branch voltage from set points (nbr)
- :param br_vt: array of branch voltage from set points (nbr)
- :return: Voltage set points array per bus nbus
- """
- V = np.ones(nbus, dtype=nb.complex128)
- used = np.zeros(nbus, dtype=nb.int8)
- # V = np.ones(nbus, dtype=complex)
- # used = np.zeros(nbus, dtype=int)
-
- # generators
- for i, bus_idx in enumerate(gen_bus_indices):
- if gen_is_controlled[i]:
- if used[bus_idx] == 0:
- if gen_status[i]:
- V[bus_idx] = complex(gen_vset[i], 0)
- used[bus_idx] = 1
-
- # batteries
- for i, bus_idx in enumerate(bat_bus_indices):
- if bat_is_controlled[i]:
- if used[bus_idx] == 0:
- if bat_status[i]:
- V[bus_idx] = complex(bat_vset[i], 0)
- used[bus_idx] = 1
-
- # HVDC
- for i in range(hvdc_status.shape[0]):
- from_idx = hvdc_bus_f[i]
- to_idx = hvdc_bus_t[i]
- if hvdc_status[i] != 0:
- if used[from_idx] == 0:
- V[from_idx] = complex(hvdc_vf[i], 0)
- used[from_idx] = 1
- if used[to_idx] == 0:
- V[to_idx] = complex(hvdc_vt[i], 0)
- used[to_idx] = 1
-
- # branch - from
- for k, from_idx in zip(k_vf_beq, i_vf_beq): # Branches controlling Vf
- if branch_status[k] != 0:
- if used[from_idx] == 0:
- V[from_idx] = complex(br_vf[k], 0)
- used[from_idx] = 1
-
- # branch - to
- for k, from_idx in zip(k_vt_m, i_vt_m): # Branches controlling Vt
- if branch_status[k] != 0:
- if used[from_idx] == 0:
- V[from_idx] = complex(br_vt[k], 0)
- used[from_idx] = 1
-
- return V
-
-
class SimulationIndices:
"""
Class to handle the simulation indices
@@ -177,316 +81,189 @@ class SimulationIndices:
def __init__(self,
bus_types: IntVec,
Pbus: Vec,
- control_mode: List[Union[TransformerControlType, ConverterControlType]],
+ tap_module_control_mode: List[TapModuleControl],
+ tap_phase_control_mode: List[TapPhaseControl],
+ tap_controlled_buses: IntVec,
+ is_converter: BoolVec,
F: IntVec,
T: IntVec,
- dc: IntVec):
+ is_dc_bus: BoolVec):
"""
:param bus_types: Bus type initial guess array
:param Pbus: Active power per bus array
- :param control_mode: Branch control mode array
- :param F: Array of bus_from indices
- :param T: Array of bus_to indices
- :param dc: Arra of is DC ? per bus
+ :param tap_module_control_mode: TapModuleControl control mode array
+ :param tap_phase_control_mode: TapPhaseControl control mode array
+ :param tap_controlled_buses: Array of bus indices where the tap module control occurs
+ :param is_converter: Array of is converter per branch?
+ :param is_dc_bus: Array of is DC ? per bus
"""
# master aray of bus types (nbus)
self.bus_types = bus_types
- # master array of branch control types (nbr)
- self.control_mode = control_mode
+ # arrays for branch control types (nbr)
+ self.tap_module_control_mode = tap_module_control_mode
+ self.tap_controlled_buses = tap_controlled_buses
+ self.tap_phase_control_mode = tap_phase_control_mode
+ self.is_converter = is_converter
+ self.F = F
+ self.T = T
# AC and DC indices
- self.ac: IntVec = np.where(~dc)[0]
- self.dc: IntVec = np.where(dc)[0]
-
- # bus type indices
- self.pq: IntVec = np.zeros(0, dtype=int)
- self.pqv: IntVec = np.zeros(0, dtype=int)
- self.pv: IntVec = np.zeros(0, dtype=int) # PV-local
- self.p: IntVec = np.zeros(0, dtype=int) # PV-remote
- self.vd: IntVec = np.zeros(0, dtype=int)
- self.no_slack: IntVec = np.zeros(0, dtype=int)
+ self.ac: IntVec = np.where(~is_dc_bus)[0]
+ self.dc: IntVec = np.where(is_dc_bus)[0]
# branch control indices
self.any_control: bool = False
- # (old iPfsh) indices of the Branches controlling Pf flow with theta sh
+ # indices of the Branches controlling Pf flow with tau
self.k_pf_tau: IntVec = np.zeros(0, dtype=int)
-
- # (old iQfma) indices of the Branches controlling Qf with ma
+ self.k_pt_tau: IntVec = np.zeros(0, dtype=int)
self.k_qf_m: IntVec = np.zeros(0, dtype=int)
-
- # (old iBeqz) indices of the Branches when forcing the Qf flow to zero (aka "the zero condition")
- self.k_zero_beq: IntVec = np.zeros(0, dtype=int)
-
- # (old iBeqv) indices of the Branches when controlling Vf with Beq
- self.k_vf_beq: IntVec = np.zeros(0, dtype=int)
-
- # (old iVtma) indices of the Branches when controlling Vt with ma
- self.k_vt_m: IntVec = np.zeros(0, dtype=int)
-
- # (old iQtma) indices of the Branches controlling the Qt flow with ma
self.k_qt_m: IntVec = np.zeros(0, dtype=int)
+ self.k_qf_beq: IntVec = np.zeros(0, dtype=int) # make Qf = 0 for DC grids
+ self.k_v_m: IntVec = np.zeros(0, dtype=int)
+ self.k_v_beq: IntVec = np.zeros(0, dtype=int)
- # (old iPfdp) indices of the drop-Vm converters controlling the power flow with theta sh
- self.k_pf_dp: IntVec = np.zeros(0, dtype=int)
-
- # indices of the transformers with controlled tap module
- self.k_m: IntVec = np.zeros(0, dtype=int)
-
- # indices of the transformers with controlled tap angle
- self.k_tau: IntVec = np.zeros(0, dtype=int)
-
- # indices of the transformers with controlled tap angle and module
- self.k_mtau: IntVec = np.zeros(0, dtype=int)
-
- # indices of the buses with controlled tap module
- self.i_m: IntVec = np.zeros(0, dtype=int)
-
- # indices of the buses with controlled tap angle
- self.i_tau: IntVec = np.zeros(0, dtype=int)
-
- # indices of the buses with controlled tap angle and module
- self.i_mtau: IntVec = np.zeros(0, dtype=int)
-
- # (old iPfdp_va) indices of the drop-Va converters controlling the power flow with theta sh
- self.iPfdp_va: IntVec = np.zeros(0, dtype=int)
-
- # indices of the converters
- self.i_vsc: IntVec = np.zeros(0, dtype=int)
-
- # (old VfBeqbus) indices of the buses where Vf is controlled by Beq
- self.i_vf_beq: IntVec = np.zeros(0, dtype=int)
-
- # (old Vtmabus) indices of the buses where Vt is controlled by ma
- self.i_vt_m: IntVec = np.zeros(0, dtype=int)
+ self.k_vsc: IntVec = np.zeros(0, dtype=int)
+ self.analyze_branch_controls()
# determine the bus indices
- self.vd, self.pq, self.pv, self.pqv, self.p, self.no_slack = compile_types(Pbus=Pbus, types=bus_types)
-
- # determine the branch indices
- self.compile_control_indices(control_mode=control_mode, F=F, T=T)
+ self.pq: IntVec = np.zeros(0, dtype=int)
+ self.pv: IntVec = np.zeros(0, dtype=int) # PV-local
+ self.p: IntVec = np.zeros(0, dtype=int) # PV-remote
+ self.pqv: IntVec = np.zeros(0, dtype=int) # PV-remote pair
+ self.vd: IntVec = np.zeros(0, dtype=int) # slack
+ self.no_slack: IntVec = np.zeros(0, dtype=int) # all bus indices that are not slack, sorted
+ self.vd, self.pq, self.pv, self.pqv, self.p, self.no_slack = compile_types(
+ Pbus=Pbus,
+ types=self.bus_types
+ )
+
+ @property
+ def k_m(self):
+ """
+ Return a composition of all indices affected by m
+ :return: k_v_m | k_qf_m | k_qt_m
+ """
+ return np.r_[self.k_v_m, self.k_qf_m, self.k_qt_m]
- def recompile_types(self,
- bus_types: IntVec,
- Pbus: Vec):
+ @property
+ def k_tau(self):
+ """
+ Return a composition of all indices affected by tau
+ :return: k_pf_tau | k_pt_tau
"""
+ return np.r_[self.k_pf_tau, self.k_pt_tau]
- :param bus_types:
- :param Pbus:
+ @property
+ def k_mtau(self):
+ """
+ Return a composition of all indices affected by the intersection of "m" and "tau"
:return:
"""
- self.bus_types = bus_types
+ return np.intersect1d(self.k_m, self.k_tau)
- # determine the bus indices
- self.vd, self.pq, self.pv, self.pqv, self.p, self.no_slack = compile_types(Pbus=Pbus, types=bus_types)
-
- def compile_control_indices(self,
- control_mode: List[Union[TransformerControlType, ConverterControlType]],
- F: IntVec,
- T: IntVec) -> None:
+ def analyze_branch_controls(self) -> None:
"""
- This function fills in the lists of indices to control different magnitudes
-
- VSC Control modes:
-
- in the paper's scheme:
- from -> DC
- to -> AC
-
- | Mode | const.1 | const.2 | type |
- -------------------------------------------------
- | 1 | theta | Vac | I |
- | 2 | Pf | Qac | I |
- | 3 | Pf | Vac | I |
- -------------------------------------------------
- | 4 | Vdc | Qac | II |
- | 5 | Vdc | Vac | II |
- -------------------------------------------------
- | 6 | Vdc droop | Qac | III |
- | 7 | Vdc droop | Vac | III |
- -------------------------------------------------
-
- Indices where each control goes:
- mismatch ā | āPf Qf Qf Qt āQt
- variable ā | Ęsh Beq m m Beq
- Indices ā | Ish Iqz Ivf Ivt Iqt
- ------------------------------------
- VSC 1 | - 1 - 1 - | AC voltage control (voltage ātoā)
- VSC 2 | 1 1 - - 1 | Active and reactive power control
- VSC 3 | 1 1 - 1 - | Active power and AC voltage control
- VSC 4 | - - 1 - 1 | Dc voltage and Reactive power flow control
- VSC 5 | - - - 1 1 | Ac and Dc voltage control
- ------------------------------------
- Transformer 0| - - - - - | Fixed transformer
- Transformer 1| 1 - - - - | Phase shifter ā controls power
- Transformer 2| - - 1 - - | Control the voltage at the āfromā side
- Transformer 3| - - - 1 - | Control the voltage at the ātoā side
- Transformer 4| 1 - 1 - - | Control the power flow and the voltage at the āfromā side
- Transformer 5| 1 - - 1 - | Control the power flow and the voltage at the ātoā side
- ------------------------------------
+ Analyze the control branches and compute the indices
+ :return: None
"""
-
- # indices in the global branch scheme
- k_pf_tau_lst = list() # indices of the Branches controlling Pf flow with theta sh
- k_qf_m_lst = list() # indices of the Branches controlling Qf with ma
- k_zero_beq_lst = list() # indices of the Branches when forcing the Qf flow to zero (aka "the zero condition")
- k_vf_beq_lst = list() # indices of the Branches when controlling Vf with Beq
- k_vt_m_lst = list() # indices of the Branches when controlling Vt with ma
- k_qt_m_lst = list() # indices of the Branches controlling the Qt flow with ma
- k_pf_dp_lst = list() # indices of the drop converters controlling the power flow with theta sh
- k_m_modif_lst = list() # indices of the transformers with controlled tap module
- k_tau_modif_lst = list() # indices of the transformers with controlled tap angle
- k_mtau_modif_lst = list() # indices of the transformers with controlled tap angle and module
- i_m_modif_lst = list() # indices of the controlled buses with tap module
- i_tau_modif_lst = list() # indices of the controlled buses with tap angle
- i_mtau_modif_lst = list() # indices of the controlled buses with tap module and angle
- i_vsc_lst = list() # indices of the converters
- iPfdp_va_lst = list()
-
- self.any_control = False
-
- for k, tpe in enumerate(control_mode):
-
- if tpe == TransformerControlType.fixed:
+ k_pf_tau = list()
+ k_pt_tau = list()
+ k_qf_m = list()
+ k_qt_m = list()
+ k_qfzero_beq = list()
+ k_v_m = list()
+ k_v_beq = list()
+ k_vsc = list()
+
+ nbr = len(self.tap_phase_control_mode)
+ for k in range(nbr):
+
+ ctrl_m = self.tap_module_control_mode[k]
+ ctrl_tau = self.tap_phase_control_mode[k]
+ is_conv = self.is_converter[k]
+
+ conv_type = 1 if is_conv else 0
+
+ # analyze tap-module controls
+ if ctrl_m == TapModuleControl.Vm:
+
+ # Every bus controlled by m has to become a PQV bus
+ bus_idx = self.tap_controlled_buses[k]
+ self.bus_types[bus_idx] = BusMode.PQV_tpe.value
+
+ if is_conv and bus_idx == self.F[k]:
+ # if this is a converter,
+ # the voltage can be managed with Beq
+ # if the control bus is the "From" bus
+ k_v_beq.append(k)
+ conv_type = 2
+ else:
+ # In any other case, the voltage is managed by the tap module
+ k_v_m.append(k)
+
+ elif ctrl_m == TapModuleControl.Qf:
+
+ if not is_conv:
+ k_qf_m.append(k)
+
+ elif ctrl_m == TapModuleControl.Qt:
+ k_qt_m.append(k)
+
+ elif ctrl_m == TapModuleControl.fixed:
pass
- elif tpe == TransformerControlType.Pf: # TODO: change name .Pt by .Pf
- k_pf_tau_lst.append(k)
- k_tau_modif_lst.append(k)
- i_tau_modif_lst.append(F[k]) # TODO: identify which index is the controlled one
- self.any_control = True
-
- elif tpe == TransformerControlType.Qt:
- k_qt_m_lst.append(k)
- k_m_modif_lst.append(k)
- i_m_modif_lst.append(T[k])
- self.any_control = True
-
- elif tpe == TransformerControlType.PtQt:
- k_pf_tau_lst.append(k)
- k_qt_m_lst.append(k)
- k_m_modif_lst.append(k)
- k_tau_modif_lst.append(k)
- k_mtau_modif_lst.append(k)
- i_tau_modif_lst.append(F[k])
- i_m_modif_lst.append(T[k])
- self.any_control = True
-
- elif tpe == TransformerControlType.V:
- k_vt_m_lst.append(k)
- k_m_modif_lst.append(k)
- i_m_modif_lst.append(T[k])
- self.any_control = True
-
- elif tpe == TransformerControlType.PtV:
- k_pf_tau_lst.append(k)
- k_vt_m_lst.append(k)
- k_m_modif_lst.append(k)
- k_tau_modif_lst.append(k)
- k_mtau_modif_lst.append(k)
- i_tau_modif_lst.append(F[k])
- i_m_modif_lst.append(T[k])
- self.any_control = True
-
- # VSC ------------------------------------------------------------------------------------------------------
- elif tpe == ConverterControlType.type_0_free: # 1a:Free
- k_zero_beq_lst.append(k)
- i_vsc_lst.append(k)
- self.any_control = True
-
- elif tpe == ConverterControlType.type_I_1: # 1:Vac
- k_vt_m_lst.append(k)
- k_zero_beq_lst.append(k)
- i_vsc_lst.append(k)
- self.any_control = True
-
- elif tpe == ConverterControlType.type_I_2: # 2:Pdc+Qac
-
- k_pf_tau_lst.append(k)
- k_qt_m_lst.append(k)
- k_zero_beq_lst.append(k)
-
- i_vsc_lst.append(k)
- self.any_control = True
-
- elif tpe == ConverterControlType.type_I_3: # 3:Pdc+Vac
- k_pf_tau_lst.append(k)
- k_vt_m_lst.append(k)
- k_zero_beq_lst.append(k)
-
- i_vsc_lst.append(k)
- self.any_control = True
-
- elif tpe == ConverterControlType.type_II_4: # 4:Vdc+Qac
- k_vf_beq_lst.append(k)
- k_qt_m_lst.append(k)
-
- i_vsc_lst.append(k)
- self.any_control = True
-
- elif tpe == ConverterControlType.type_II_5: # 5:Vdc+Vac
- k_vf_beq_lst.append(k)
- k_vt_m_lst.append(k)
-
- i_vsc_lst.append(k)
- self.any_control = True
-
- elif tpe == ConverterControlType.type_III_6: # 6:Droop+Qac
- k_pf_dp_lst.append(k)
- k_qt_m_lst.append(k)
-
- i_vsc_lst.append(k)
- self.any_control = True
-
- elif tpe == ConverterControlType.type_III_7: # 4a:Droop-slack
- k_pf_dp_lst.append(k)
- k_vt_m_lst.append(k)
-
- i_vsc_lst.append(k)
- self.any_control = True
-
- elif tpe == ConverterControlType.type_IV_I: # 8:Vdc
- k_vf_beq_lst.append(k)
- i_vsc_lst.append(k)
-
- self.any_control = True
-
- elif tpe == ConverterControlType.type_IV_II: # 9:Pdc
- k_pf_tau_lst.append(k)
- k_zero_beq_lst.append(k)
-
- self.any_control = True
-
- elif tpe == 0:
- pass # required for the no-control case
+ elif ctrl_m == 0:
+ pass
else:
- raise Exception('Unknown control type:' + str(tpe))
-
- # FUBM- Saves the "from" bus identifier for Vf controlled by Beq
- # (Converters type II for Vdc control)
- self.i_vf_beq = F[k_vf_beq_lst]
-
- # FUBM- Saves the "to" bus identifier for Vt controlled by ma
- # (Converters and Transformers)
- self.i_vt_m = T[k_vt_m_lst]
-
- self.k_pf_tau = np.array(k_pf_tau_lst, dtype=int)
- self.k_qf_m = np.array(k_qf_m_lst, dtype=int)
- self.k_zero_beq = np.array(k_zero_beq_lst, dtype=int)
- self.k_vf_beq = np.array(k_vf_beq_lst, dtype=int)
- self.k_vt_m = np.array(k_vt_m_lst, dtype=int)
- self.k_qt_m = np.array(k_qt_m_lst, dtype=int)
- self.k_pf_dp = np.array(k_pf_dp_lst, dtype=int)
- self.k_m = np.array(k_m_modif_lst, dtype=int)
- self.k_tau = np.array(k_tau_modif_lst, dtype=int)
- self.k_mtau = np.array(k_mtau_modif_lst, dtype=int)
- self.i_m = np.array(i_m_modif_lst, dtype=int)
- self.i_tau = np.array(i_tau_modif_lst, dtype=int)
- self.i_mtau = np.array(i_mtau_modif_lst, dtype=int)
- self.iPfdp_va = np.array(iPfdp_va_lst, dtype=int)
- self.i_vsc = np.array(i_vsc_lst, dtype=int)
+ raise Exception(f"Unknown tap phase module mode {ctrl_m}")
+
+ # analyze tap-phase controls
+ if ctrl_tau == TapPhaseControl.Pf:
+ k_pf_tau.append(k)
+ conv_type = 1
+ elif ctrl_tau == TapPhaseControl.Pt:
+ k_pt_tau.append(k)
+ conv_type = 1
+ elif ctrl_tau == TapPhaseControl.fixed:
+ if ctrl_m == TapModuleControl.fixed:
+ conv_type = 1
+
+ # elif ctrl_tau == TapPhaseControl.Droop:
+ # pass
+
+ elif ctrl_tau == 0:
+ pass
+
+ else:
+ raise Exception(f"Unknown tap phase control mode {ctrl_tau}")
+
+ # Beq->qf=0
+ if conv_type == 1:
+ k_qfzero_beq.append(k)
+
+ if is_conv:
+ k_vsc.append(k)
+
+ # determine if there is any control
+ self.any_control = bool(len(k_pf_tau)
+ + len(k_pt_tau)
+ + len(k_qf_m)
+ + len(k_qt_m)
+ + len(k_qfzero_beq)
+ + len(k_v_m))
+
+ # convert lists to integer arrays
+ self.k_pf_tau = np.array(k_pf_tau, dtype=int)
+ self.k_pt_tau = np.array(k_pt_tau, dtype=int)
+ self.k_qf_m = np.array(k_qf_m, dtype=int)
+ self.k_qt_m = np.array(k_qt_m, dtype=int)
+ self.k_qf_beq = np.array(k_qfzero_beq, dtype=int)
+ self.k_v_m = np.array(k_v_m, dtype=int)
+ self.k_v_beq = np.array(k_v_beq, dtype=int)
+ self.k_vsc = np.array(k_vsc, dtype=int)
diff --git a/src/GridCalEngine/Utils/NumericalMethods/autodiff.py b/src/GridCalEngine/Utils/NumericalMethods/autodiff.py
index 5cd8295e9..1a61ef966 100644
--- a/src/GridCalEngine/Utils/NumericalMethods/autodiff.py
+++ b/src/GridCalEngine/Utils/NumericalMethods/autodiff.py
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-from typing import Callable, Union, Tuple, List, Any
+from typing import Callable, Union, Tuple, Any
import numpy as np
from scipy.sparse import csc_matrix as csc
from scipy.sparse import lil_matrix
diff --git a/src/GridCalEngine/Utils/NumericalMethods/common.py b/src/GridCalEngine/Utils/NumericalMethods/common.py
index 604b9da4c..593a4b6a7 100644
--- a/src/GridCalEngine/Utils/NumericalMethods/common.py
+++ b/src/GridCalEngine/Utils/NumericalMethods/common.py
@@ -15,7 +15,7 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from dataclasses import dataclass
-from typing import Callable, List, Tuple
+from typing import Callable, Tuple
import numpy as np
import numba as nb
from matplotlib import pyplot as plt
@@ -82,7 +82,7 @@ class ConvexFunctionResult:
"""
Result of the convex function evaluated iterativelly for a given method
"""
- f: Vec # function increment of the equalities
+ f: Vec # function increment of the equalities
J: CscMat # Jacobian matrix
def compute_f_error(self):
@@ -99,12 +99,12 @@ class ConvexMethodResult:
"""
Iterative convex method result
"""
- x: Vec # x solution
- error: float # method error
- converged: bool # converged?
- iterations: int # number of iterations
- elapsed: float # time elapsed in seconds
- error_evolution: Vec # array of errors to plot
+ x: Vec # x solution
+ error: float # method error
+ converged: bool # converged?
+ iterations: int # number of iterations
+ elapsed: float # time elapsed in seconds
+ error_evolution: Vec # array of errors to plot
def plot_error(self) -> None:
"""
@@ -116,7 +116,7 @@ def plot_error(self) -> None:
plt.ylabel("Error")
plt.yscale('log')
plt.show()
-
+
def print_info(self):
"""
Print information about the ConvexMethodResult
@@ -126,3 +126,23 @@ def print_info(self):
print("Converged:\t", self.converged)
print("Error:\t", self.error)
print("Elapsed:\t", self.elapsed, 's')
+
+
+def find_closest_number(arr: Vec, target: float) -> float:
+ """
+ Find the closest number that exists in array
+ :param arr: Array to be searched
+ :param target: Value to search for
+ :return: Closes adjusted or truncated value
+ """
+ idx = np.searchsorted(arr, target)
+ if idx == 0:
+ return arr[0]
+ if idx == len(arr):
+ return arr[-1]
+ before = arr[idx - 1]
+ after = arr[idx]
+ if after - target < target - before:
+ return after
+ else:
+ return before
diff --git a/src/GridCalEngine/Utils/Sparse/csc2.py b/src/GridCalEngine/Utils/Sparse/csc2.py
index 4d90b3dbb..673e7d9e3 100644
--- a/src/GridCalEngine/Utils/Sparse/csc2.py
+++ b/src/GridCalEngine/Utils/Sparse/csc2.py
@@ -14,14 +14,18 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from __future__ import annotations
+
+import warnings
+import math
from typing import List
-from numba import njit, int32, float64
+from numba import njit, int32, float64, complex128
from numba import types
from numba.experimental import jitclass
import numpy as np
from scipy.sparse import csc_matrix
from scipy.sparse.linalg._dsolve._superlu import gstrf, SuperLU
-from GridCalEngine.basic_structures import IntVec, IntMat, Vec
+from GridCalEngine.basic_structures import IntVec, IntMat, Vec, CxVec
@jitclass([
@@ -54,12 +58,58 @@ def __init__(self, n_rows: int, n_cols: int, nnz: int, force_zeros: bool):
if force_zeros:
self.data = np.zeros(nnz, dtype=np.float64)
self.indices = np.zeros(nnz, dtype=np.int32)
+ self.indptr = np.zeros(n_cols + 1, dtype=np.int32)
else:
self.data = np.empty(nnz, dtype=np.float64)
self.indices = np.empty(nnz, dtype=np.int32)
+ self.indptr = np.empty(n_cols + 1, dtype=np.int32)
+
+ self.indptr[0] = 0 # always
+
+ def set(self, indices: IntVec, indptr: IntVec, data: Vec) -> "CSC":
+ """
+ Set the internal arrays
+ :param indices:
+ :param indptr:
+ :param data:
+ :return:
+ """
+ self.indices = indices
+ self.indptr = indptr
+ self.data = data
+ self.nnz = len(self.data)
+ self.indptr[0] = 0 # always
+ return self
+
+ def fill_from_coo(self, Ti: IntVec, Tj: IntVec, Tx: CxVec, nnz: int):
+ """
+ C = compressed-column form of a triplet matrix T.
+ The columns of T are not sorted, and duplicate entries may be present in T.
+
+ :param Ti: array of row indices (could be longer than nnz)
+ :param Tj: array of column indices (could be longer than nnz)
+ :param Tx: array of data (could be longer than nnz)
+ :param nnz: number of non-zeros
+ """
+ self.nnz = nnz
+ self.data = np.empty(self.nnz, dtype=np.float64)
+ self.indices = np.empty(self.nnz, dtype=np.int32)
+ self.indptr = np.empty(self.n_cols + 1, dtype=np.int32)
+ self.indptr[0] = 0 # always
+
+ w = np.zeros(self.n_cols, dtype=int32) # get workspace
+
+ for k in range(self.nnz):
+ w[Tj[k]] += 1 # column counts
- # must always be zeros
- self.indptr = np.zeros(n_cols + 1, dtype=np.int32)
+ csc_cumsum_i(self.indptr, w, self.n_cols) # column pointers
+
+ for k in range(self.nnz):
+ p = w[Tj[k]]
+ w[Tj[k]] += 1
+ self.indices[p] = Ti[k] # A(i,j) is the pth entry in C
+ # if Cx is not None:
+ self.data[p] = Tx[k]
@property
def shape(self):
@@ -108,25 +158,250 @@ def copy(self):
res.indptr = self.indptr.copy()
return res
- def dot(self, x: Vec):
+ def dot(self, x: np.ndarray):
"""
Mat-vector multiplication
:param x: vector
:return:
"""
- assert self.n_cols == x.shape[0]
- assert x.ndim == 1
+ return csc_matvec_ff(self, x)
+
+ # @property
+ # def T(self) -> "CSC":
+ # """
+ # Traspose
+ # :return:
+ # """
+ # return sp_transpose(self)
- y = np.zeros(self.n_rows, dtype=float64)
+ def get_diag_max(self) -> float:
+ """
+ Get the maximum value of the diagonal
+ :return: value
+ """
+ val = -1e20
for j in range(self.n_cols):
for p in range(self.indptr[j], self.indptr[j + 1]):
- y[self.indices[p]] += self.data[p] * x[j]
- return y
+ if self.data[p] > val:
+ val = self.data[p]
+ return val
+
+ def add_val_to_diagonal(self, val: float) -> "CSC":
+ """
+ Add value to the diagonal in-place
+ :param val: some value
+ :return: copy with modified diagonal
+ """
+ A = self.copy()
+ for j in range(A.n_cols):
+ for p in range(A.indptr[j], A.indptr[j + 1]):
+ if A.indices[p] == j:
+ A.data[p] += val
+ return A
+
+ def __matmul__(self, B: "CSC" | np.ndarray) -> "CSC" | np.ndarray:
+ """
+ @ operator
+ :param B: CSC matrix or ndarray
+ :return: CSC matrix or ndarray
+ """
+ if isinstance(B, CSC):
+ # return csc_multiply_ff(self, B)
+ Cm, Cn, Cp, Ci, Cx, Cnz = csc_multiply_ff2(self.n_rows, self.n_cols, self.indptr, self.indices, self.data,
+ B.n_rows, B.n_cols, B.indptr, B.indices, B.data)
+ return CSC(Cm, Cn, Cnz, False).set(Ci, Cp, Cx)
+ elif isinstance(B, np.ndarray):
+ return csc_matvec_ff(self, B)
+ else:
+ raise TypeError
-def mat_to_scipy(csc: CSC) -> csc_matrix:
+@jitclass([
+ ('n_rows', int32),
+ ('n_cols', int32),
+ ('nnz', int32),
+ ('data', complex128[:]),
+ ('indices', int32[:]),
+ ('indptr', int32[:],),
+ ('format', types.unicode_type)
+])
+class CxCSC:
+ """
+ numba CSC matrix struct
"""
+ def __init__(self, n_rows: int, n_cols: int, nnz: int, force_zeros: bool):
+ """
+ Constructor
+ :param n_rows:
+ :param n_cols:
+ :param nnz:
+ :param force_zeros:
+ """
+ self.format = "csc"
+ self.n_rows = n_rows # n rows
+ self.n_cols = n_cols # n cols
+ self.nnz = nnz
+
+ if force_zeros:
+ self.data = np.zeros(nnz, dtype=np.complex128)
+ self.indices = np.zeros(nnz, dtype=np.int32)
+ self.indptr = np.zeros(n_cols + 1, dtype=np.int32)
+ else:
+ self.data = np.empty(nnz, dtype=np.complex128)
+ self.indices = np.empty(nnz, dtype=np.int32)
+ self.indptr = np.empty(n_cols + 1, dtype=np.int32)
+
+ self.indptr[0] = 0 # always
+
+ def set(self, indices: IntVec, indptr: IntVec, data: CxVec) -> "CxCSC":
+ """
+ Set the internal arrays
+ :param indices:
+ :param indptr:
+ :param data:
+ :return:
+ """
+ self.indices = indices
+ self.indptr = indptr
+ self.data = data
+ self.nnz = len(self.data)
+
+ return self
+
+ def fill_from_coo(self, Ti: IntVec, Tj: IntVec, Tx: CxVec, nnz: int):
+ """
+ C = compressed-column form of a triplet matrix T.
+ The columns of T are not sorted, and duplicate entries may be present in T.
+
+ :param Ti: array of row indices (could be longer than nnz)
+ :param Tj: array of column indices (could be longer than nnz)
+ :param Tx: array of data (could be longer than nnz)
+ :param nnz: number of non-zeros
+ """
+ self.nnz = nnz
+ self.data = np.empty(self.nnz, dtype=np.complex128)
+ self.indices = np.empty(self.nnz, dtype=np.int32)
+ self.indptr = np.empty(self.n_cols + 1, dtype=np.int32)
+ self.indptr[0] = 0 # always
+
+ w = np.zeros(self.n_cols, dtype=np.int32) # get workspace
+
+ for k in range(self.nnz):
+ w[Tj[k]] += 1 # column counts
+
+ # csc_cumsum_i(p, c, n)
+ csc_cumsum_i(self.indptr, w, self.n_cols) # column pointers
+ # nz = 0
+ # for i in range(self.n_cols):
+ # self.indptr[i] = nz
+ # nz += w[i]
+ # w[i] = self.indptr[i] # also copy p[0..n-1] back into c[0..n-1]
+ # self.indptr[self.n_cols] = nz
+
+ for k in range(self.nnz):
+ p = w[Tj[k]]
+ w[Tj[k]] += 1
+ self.indices[p] = Ti[k] # A(i,j) is the pth entry in C
+ # if Cx is not None:
+ self.data[p] = Tx[k]
+
+ @property
+ def shape(self):
+ """
+ Shape for scipy compatibility
+ :return: n_rows, n_cols
+ """
+ return self.n_rows, self.n_cols
+
+ @property
+ def real(self) -> CSC:
+ """
+ Get the real representation of this matrix
+ :return: CSC
+ """
+ A = CSC(self.n_rows, self.n_cols, self.nnz, False)
+ A.indptr = self.indptr
+ A.indices = self.indices
+ A.data = self.data.real
+ return A
+
+ @property
+ def imag(self) -> CSC:
+ """
+ Get the imaginary representation of this matrix
+ :return: CSC
+ """
+ A = CSC(self.n_rows, self.n_cols, self.nnz, False)
+ A.indptr = self.indptr
+ A.indices = self.indices
+ A.data = self.data.imag
+ return A
+
+ def resize(self, nnz: int32):
+ """
+ Resize this matrix
+ :param nnz: number of non-zeros
+ """
+ self.nnz = nnz
+ self.data = self.data[:nnz]
+ self.indices = self.indices[:nnz] # np.resize is not suported by numba
+
+ def todense(self):
+ """
+ Get dense array representation
+ :return:
+ """
+ val = np.zeros((self.n_rows, self.n_cols), dtype=np.complex128)
+
+ for j in range(self.n_cols):
+ for p in range(self.indptr[j], self.indptr[j + 1]):
+ val[self.indices[p], j] = self.data[p]
+ return val
+
+ def toarray(self):
+ """
+ Get dense array representation
+ :return:
+ """
+ return self.todense()
+
+ def copy(self):
+ """
+ Create a copy of this matrix
+ :return:
+ """
+ res = CSC(self.n_rows, self.n_cols, self.nnz, False)
+ res.data = self.data.copy()
+ res.indices = self.indices.copy()
+ res.indptr = self.indptr.copy()
+ return res
+
+ def dot(self, x: np.ndarray) -> np.ndarray:
+ """
+ Mat-vector multiplication
+ :param x: vector
+ :return:
+ """
+ return csc_matvec_cx(self, x)
+
+ def __matmul__(self, B: "CxCSC" | np.ndarray) -> "CxCSC" | np.ndarray:
+ """
+
+ :param B:
+ :return:
+ """
+ if isinstance(B, CSC):
+ return csc_multiply_cx(self, B)
+ elif isinstance(B, np.ndarray):
+ return csc_matvec_cx(self, B)
+ else:
+ raise TypeError
+
+
+def mat_to_scipy(csc: CSC | CxCSC) -> csc_matrix:
+ """
+ CSC or CxCSC Matrix to Scipy
:param csc:
:return:
"""
@@ -135,10 +410,14 @@ def mat_to_scipy(csc: CSC) -> csc_matrix:
def scipy_to_mat(mat: csc_matrix) -> CSC:
"""
-
- :param mat:
- :return:
+ Scipy CSC matrix to CSC marix
+ :param mat: Scipy CSC matrix
+ :return: CSC marix
"""
+ if not mat.format == 'csc':
+ warnings.warn('scipy_to_cxmat: Converting matrix to CSC format...')
+ mat = mat.tocsc()
+
x = CSC(mat.shape[0], mat.shape[1], mat.nnz, False)
x.data = mat.data.astype(float)
x.indices = mat.indices.astype(np.int32)
@@ -146,7 +425,24 @@ def scipy_to_mat(mat: csc_matrix) -> CSC:
return x
-def spfactor(A: CSC) -> SuperLU:
+def scipy_to_cxmat(mat: csc_matrix) -> CxCSC:
+ """
+ Scipy CSC matrix to CxCSC marix
+ :param mat: Scipy CSC matrix
+ :return: CxCSC marix
+ """
+ if not mat.format == 'csc':
+ warnings.warn('scipy_to_cxmat: Converting matrix to CSC format...')
+ mat = mat.tocsc()
+
+ x = CxCSC(mat.shape[0], mat.shape[1], mat.nnz, False)
+ x.data = mat.data.astype(np.complex128)
+ x.indices = mat.indices.astype(np.int32)
+ x.indptr = mat.indptr.astype(np.int32)
+ return x
+
+
+def spfactor(A: CSC) -> None | SuperLU:
"""
Sparse factorization with SuperLU
:param A: CSC matrix
@@ -164,10 +460,12 @@ def spfactor(A: CSC) -> SuperLU:
if _options["ColPerm"] == "NATURAL":
_options["SymmetricMode"] = True
- ret = gstrf(A.n_cols, A.nnz, A.data, A.indices, A.indptr,
- ilu=False, options=_options, csc_construct_func=None)
-
- return ret
+ try:
+ ret = gstrf(A.n_cols, A.nnz, A.data, A.indices, A.indptr,
+ ilu=False, options=_options, csc_construct_func=None)
+ return ret
+ except RuntimeError:
+ return None
def spsolve_csc(A: CSC, x: Vec) -> Vec:
@@ -177,7 +475,11 @@ def spsolve_csc(A: CSC, x: Vec) -> Vec:
:param x: vector
:return: solution
"""
- return spfactor(A).solve(x)
+ factor = spfactor(A)
+ if factor is None:
+ return np.full(len(x), np.nan), False
+ else:
+ return factor.solve(x), True
@njit(cache=True)
@@ -377,7 +679,7 @@ def sp_slice_rows(mat: CSC, rows: np.ndarray) -> CSC:
return sp_transpose(A)
-@njit(cache=True)
+@njit()
def sp_slice(A: CSC, rows: IntVec, cols: IntVec):
"""
/*
@@ -428,8 +730,8 @@ def sp_slice(A: CSC, rows: IntVec, cols: IntVec):
return B
-@njit(cache=True)
-def csc_stack_2d_ff(mats: List[CSC], m_rows: int = 1, m_cols: int = 1) -> CSC:
+@njit()
+def csc_stack_2d_ff(mats: List[CSC], n_rows: int = 1, n_cols: int = 1) -> CSC:
"""
Assemble matrix from a list of matrices representing a "super matrix"
@@ -443,8 +745,8 @@ def csc_stack_2d_ff(mats: List[CSC], m_rows: int = 1, m_cols: int = 1) -> CSC:
m_cols = 3
:param mats: list of CSC matrices arranged in row-major order (i.e. [mat11, mat12, mat13, mat21, mat22, mat23]
- :param m_rows: number of rows of the mats structure
- :param m_cols: number of cols of the mats structure
+ :param n_rows: number of rows of the mats structure
+ :param n_cols: number of cols of the mats structure
:return: Final assembled matrix in CSC format
"""
@@ -452,11 +754,11 @@ def csc_stack_2d_ff(mats: List[CSC], m_rows: int = 1, m_cols: int = 1) -> CSC:
nnz = 0
nrows = 0
ncols = 0
- for r in range(m_rows):
- nrows += mats[r * m_cols].n_rows # equivalent to mats[r, 0]
- for c in range(m_cols):
- col = mats[c + r * m_cols].n_cols # equivalent to mats[r, c]
- nnz += mats[c + r * m_cols].nnz
+ for r in range(n_rows):
+ nrows += mats[r * n_cols].n_rows # equivalent to mats[r, 0]
+ for c in range(n_cols):
+ col = mats[c + r * n_cols].n_cols # equivalent to mats[r, c]
+ nnz += mats[c + r * n_cols].nnz
if r == 0:
ncols += col
@@ -465,7 +767,7 @@ def csc_stack_2d_ff(mats: List[CSC], m_rows: int = 1, m_cols: int = 1) -> CSC:
cnt = 0
res.indptr[0] = 0
offset_col = 0
- for c in range(m_cols): # for each column of the array of matrices
+ for c in range(n_cols): # for each column of the array of matrices
# number of columns
n = mats[c].n_cols # equivalent to mats[0, c]
@@ -475,19 +777,19 @@ def csc_stack_2d_ff(mats: List[CSC], m_rows: int = 1, m_cols: int = 1) -> CSC:
offset_row = 0
- for r in range(m_rows): # for each row of the array of rows
+ for r in range(n_rows): # for each row of the array of rows
# get the current sub-matrix
- A: CSC = mats[r * m_cols + c] # equivalent to mats[r, c]
+ A: CSC = mats[r * n_cols + c] # equivalent to mats[r, c]
- if A.n_rows > 0:
+ if A.n_rows > 0 and A.nnz > 0:
for k in range(A.indptr[j], A.indptr[j + 1]): # for every entry in the column from A
res.indices[cnt] = A.indices[k] + offset_row # row index
res.data[cnt] = A.data[k]
cnt += 1
- offset_row += A.n_rows
+ offset_row += A.n_rows
res.indptr[offset_col + j + 1] = cnt
offset_col += n
@@ -536,14 +838,14 @@ def diagc(m: int, value: float = 1.0) -> CSC:
@njit(cache=True)
-def create_lookup(size: int, indices: IntVec) -> IntVec:
+def make_lookup(size: int, indices: IntVec) -> IntVec:
"""
Create a lookup array
:param size: Size of the thing (i.e. number of buses)
:param indices: indices to map (i.e. pq indices)
- :return: lookup array
+ :return: lookup array, -1 at the indices that do not match with the "indices" input array
"""
- lookup = np.zeros(size, dtype=int32)
+ lookup = np.full(size, -1, dtype=int32)
lookup[indices] = np.arange(len(indices), dtype=int32)
return lookup
@@ -613,3 +915,302 @@ def extend(A: CSC, last_col: Vec, last_row: Vec, corner_val: float) -> CSC:
B.resize(nnz)
return B
+
+
+@njit(cache=True)
+def csc_multiply_ff(A: CSC, B: CSC) -> CSC:
+ """
+ Sparse matrix multiplication, C = A*B where A and B are CSC sparse matrices
+ :param A:
+ :param B:
+ :return:
+ """
+ assert A.n_cols == B.n_rows
+ nz = 0
+ anz = A.indptr[A.n_cols]
+ bnz = B.indptr[B.n_cols]
+ Cm = A.n_rows
+ Cn = B.n_cols
+
+ w = np.zeros(Cn, dtype=int32) # ialloc(m) # get workspace
+ x = np.empty(Cn, dtype=float64) # xalloc(m) # get workspace
+
+ # allocate result
+
+ Cnzmax = int(np.sqrt(Cm)) * anz + bnz # the trick here is to allocate just enough memory to avoid reallocating
+ Cp = np.empty(Cn + 1, dtype=int32)
+ Ci = np.empty(Cnzmax, dtype=int32)
+ Cx = np.empty(Cnzmax, dtype=float64)
+
+ for j in range(Cn):
+
+ # claim more space
+ if nz + Cm > Cnzmax:
+ # Ci, Cx, Cnzmax = csc_sprealloc_f(Cn, Cp, Ci, Cx, 2 * Cnzmax + m)
+ # print('Re-Allocating')
+ Cnzmax = 2 * Cnzmax + Cm
+ if Cnzmax <= 0:
+ Cnzmax = Cp[A.n_cols]
+
+ length = min(Cnzmax, len(Ci))
+ Cinew = np.empty(Cnzmax, dtype=int32)
+ for i in range(length):
+ Cinew[i] = Ci[i]
+ Ci = Cinew
+
+ length = min(Cnzmax, len(Cx))
+ Cxnew = np.empty(Cnzmax, dtype=float64)
+ for i in range(length):
+ Cxnew[i] = Cx[i]
+ Cx = Cxnew
+
+ # column j of C starts here
+ Cp[j] = nz
+
+ # perform the multiplication
+ for pb in range(B.indptr[j], B.indptr[j + 1]):
+ for pa in range(A.indptr[B.indices[pb]], A.indptr[B.indices[pb] + 1]):
+ ia = A.indices[pa]
+ if w[ia] < j + 1:
+ w[ia] = j + 1
+ Ci[nz] = ia
+ nz += 1
+ x[ia] = B.data[pb] * A.data[pa]
+ else:
+ x[ia] += B.data[pb] * A.data[pa]
+
+ for pc in range(Cp[j], nz):
+ Cx[pc] = x[Ci[pc]]
+
+ Cp[Cn] = nz # finalize the last column of C
+
+ # cut the arrays to their nominal size nnz
+ # Ci, Cx, Cnzmax = csc_sprealloc_f(Cn, Cp, Ci, Cx, 0)
+ Cnzmax = Cp[Cn]
+ C = CSC(Cm, Cn, Cnzmax, False)
+ C.indptr = Cp
+ C.indices = Ci[:Cnzmax]
+ C.data = Cx[:Cnzmax]
+
+ return C
+
+
+# @nb.njit("Tuple((i8, i8, i4[:], i4[:], f8[:], i8))(i8, i8, i4[:], i4[:], f8[:], i8, i8, i4[:], i4[:], f8[:])",
+# parallel=False, nogil=True, fastmath=False, cache=True) # fastmath=True breaks the code
+@njit(cache=True)
+def csc_multiply_ff2(Am, An, Ap, Ai, Ax,
+ Bm, Bn, Bp, Bi, Bx):
+ """
+ Sparse matrix multiplication, C = A*B where A and B are CSC sparse matrices
+ :param Am: number of rows in A
+ :param An: number of columns in A
+ :param Ap: column pointers of A
+ :param Ai: indices of A
+ :param Ax: data of A
+ :param Bm: number of rows in B
+ :param Bn: number of columns in B
+ :param Bp: column pointers of B
+ :param Bi: indices of B
+ :param Bx: data of B
+ :return: Cm, Cn, Cp, Ci, Cx, Cnzmax
+ """
+ assert An == Bm
+ nz = 0
+ anz = Ap[An]
+ bnz = Bp[Bn]
+ Cm = Am
+ Cn = Bn
+
+ w = np.zeros(Cn, dtype=int32) # ialloc(m) # get workspace
+ x = np.empty(Cn, dtype=float64) # xalloc(m) # get workspace
+
+ # allocate result
+
+ Cnzmax = int(np.sqrt(Cm)) * anz + bnz # the trick here is to allocate just enough memory to avoid reallocating
+ Cp = np.empty(Cn + 1, dtype=int32)
+ Ci = np.empty(Cnzmax, dtype=int32)
+ Cx = np.empty(Cnzmax, dtype=float64)
+
+ for j in range(Cn):
+
+ # claim more space
+ if nz + Cm > Cnzmax:
+ # Ci, Cx, Cnzmax = csc_sprealloc_f(Cn, Cp, Ci, Cx, 2 * Cnzmax + m)
+ print('Re-Allocating')
+ Cnzmax = 2 * Cnzmax + Cm
+ if Cnzmax <= 0:
+ Cnzmax = Cp[An]
+
+ length = min(Cnzmax, len(Ci))
+ Cinew = np.empty(Cnzmax, dtype=int32)
+ for i in range(length):
+ Cinew[i] = Ci[i]
+ Ci = Cinew
+
+ length = min(Cnzmax, len(Cx))
+ Cxnew = np.empty(Cnzmax, dtype=float64)
+ for i in range(length):
+ Cxnew[i] = Cx[i]
+ Cx = Cxnew
+
+ # column j of C starts here
+ Cp[j] = nz
+
+ # perform the multiplication
+ for pb in range(Bp[j], Bp[j + 1]):
+ for pa in range(Ap[Bi[pb]], Ap[Bi[pb] + 1]):
+ ia = Ai[pa]
+ if w[ia] < j + 1:
+ w[ia] = j + 1
+ Ci[nz] = ia
+ nz += 1
+ x[ia] = Bx[pb] * Ax[pa]
+ else:
+ x[ia] += Bx[pb] * Ax[pa]
+
+ for pc in range(Cp[j], nz):
+ Cx[pc] = x[Ci[pc]]
+
+ Cp[Cn] = nz # finalize the last column of C
+
+ # cut the arrays to their nominal size nnz
+ # Ci, Cx, Cnzmax = csc_sprealloc_f(Cn, Cp, Ci, Cx, 0)
+ Cnzmax = Cp[Cn]
+ Cinew = Ci[:Cnzmax]
+ Cxnew = Cx[:Cnzmax]
+
+ return Cm, Cn, Cp, Cinew, Cxnew, Cnzmax
+
+
+@njit(cache=True)
+def csc_multiply_cx(A: CxCSC, B: CSC) -> CxCSC:
+ """
+ Sparse matrix multiplication, C = A*B where A and B are CSC sparse matrices
+ :param A:
+ :param B:
+ :return:
+ """
+ assert A.n_cols == B.n_rows
+ nz = 0
+ anz = A.indptr[A.n_cols]
+ bnz = B.indptr[B.n_cols]
+ Cm = A.n_rows
+ Cn = B.n_cols
+
+ w = np.zeros(Cn, dtype=int32) # ialloc(m) # get workspace
+ x = np.empty(Cn, dtype=complex128) # xalloc(m) # get workspace
+
+ # allocate result
+
+ Cnzmax = int(np.sqrt(Cm)) * anz + bnz # the trick here is to allocate just enough memory to avoid reallocating
+ Cp = np.empty(Cn + 1, dtype=int32)
+ Ci = np.empty(Cnzmax, dtype=int32)
+ Cx = np.empty(Cnzmax, dtype=complex128)
+
+ for j in range(Cn):
+
+ # claim more space
+ if nz + Cm > Cnzmax:
+ # Ci, Cx, Cnzmax = csc_sprealloc_f(Cn, Cp, Ci, Cx, 2 * Cnzmax + m)
+ # print('Re-Allocating')
+ Cnzmax = 2 * Cnzmax + Cm
+ if Cnzmax <= 0:
+ Cnzmax = Cp[A.n_cols]
+
+ length = min(Cnzmax, len(Ci))
+ Cinew = np.empty(Cnzmax, dtype=int32)
+ for i in range(length):
+ Cinew[i] = Ci[i]
+ Ci = Cinew
+
+ length = min(Cnzmax, len(Cx))
+ Cxnew = np.empty(Cnzmax, dtype=complex128)
+ for i in range(length):
+ Cxnew[i] = Cx[i]
+ Cx = Cxnew
+
+ # column j of C starts here
+ Cp[j] = nz
+
+ # perform the multiplication
+ for pb in range(B.indptr[j], B.indptr[j + 1]):
+ for pa in range(A.indptr[B.indices[pb]], A.indptr[B.indices[pb] + 1]):
+ ia = A.indices[pa]
+ if w[ia] < j + 1:
+ w[ia] = j + 1
+ Ci[nz] = ia
+ nz += 1
+ x[ia] = B.data[pb] * A.data[pa]
+ else:
+ x[ia] += B.data[pb] * A.data[pa]
+
+ for pc in range(Cp[j], nz):
+ Cx[pc] = x[Ci[pc]]
+
+ Cp[Cn] = nz # finalize the last column of C
+
+ # cut the arrays to their nominal size nnz
+ # Ci, Cx, Cnzmax = csc_sprealloc_f(Cn, Cp, Ci, Cx, 0)
+ Cnzmax = Cp[Cn]
+ C = CxCSC(Cm, Cn, Cnzmax, False)
+ C.indptr = Cp
+ C.indices = Ci[:Cnzmax]
+ C.data = Cx[:Cnzmax]
+
+ return C
+
+
+@njit(cache=True)
+def csc_matvec_ff(A: CSC, x: np.ndarray) -> np.ndarray:
+ """
+
+ :param A:
+ :param x:
+ :return:
+ """
+ assert A.n_cols == x.shape[0]
+ if x.ndim == 1:
+
+ y = np.zeros(A.n_rows, dtype=float64)
+ for j in range(A.n_cols):
+ for p in range(A.indptr[j], A.indptr[j + 1]):
+ y[A.indices[p]] += A.data[p] * x[j]
+ return y
+ elif x.ndim == 2:
+ ncols = x.shape[1]
+ y = np.zeros((A.n_rows, ncols), dtype=float64)
+ for k in range(ncols):
+ for j in range(A.n_cols):
+ for p in range(A.indptr[j], A.indptr[j + 1]):
+ y[A.indices[p], k] += A.data[p] * x[j, k]
+ return y
+ else:
+ raise Exception("Wrong number of dimensions")
+
+
+@njit(cache=True)
+def csc_matvec_cx(A: CxCSC, x: np.ndarray) -> np.ndarray:
+ """
+
+ :param A:
+ :param x:
+ :return:
+ """
+ assert A.n_cols == x.shape[0]
+ if x.ndim == 1:
+
+ y = np.zeros(A.n_rows, dtype=complex128)
+ for j in range(A.n_cols):
+ for p in range(A.indptr[j], A.indptr[j + 1]):
+ y[A.indices[p]] += A.data[p] * x[j]
+ return y
+ elif x.ndim == 2:
+ ncols = x.shape[1]
+ y = np.zeros((A.n_rows, ncols), dtype=complex128)
+ for k in range(ncols):
+ for j in range(A.n_cols):
+ for p in range(A.indptr[j], A.indptr[j + 1]):
+ y[A.indices[p], k] += A.data[p] * x[j, k]
+ return y
+ else:
+ raise Exception("Wrong number of dimensions")
diff --git a/src/tests/zip_file_mgmt.py b/src/GridCalEngine/Utils/zip_file_mgmt.py
similarity index 100%
rename from src/tests/zip_file_mgmt.py
rename to src/GridCalEngine/Utils/zip_file_mgmt.py
diff --git a/src/GridCalEngine/__version__.py b/src/GridCalEngine/__version__.py
index e8fc85d17..e4b141939 100644
--- a/src/GridCalEngine/__version__.py
+++ b/src/GridCalEngine/__version__.py
@@ -16,7 +16,7 @@
_current_year_ = datetime.datetime.now().year
# do not forget to keep a three-number version!!!
-__GridCalEngine_VERSION__ = "5.1.21"
+__GridCalEngine_VERSION__ = "5.2.0"
url = 'https://github.com/SanPen/GridCal'
diff --git a/src/GridCalEngine/enumerations.py b/src/GridCalEngine/enumerations.py
index 0183a77bd..491fcfe89 100644
--- a/src/GridCalEngine/enumerations.py
+++ b/src/GridCalEngine/enumerations.py
@@ -46,6 +46,26 @@ def argparse(s):
except KeyError:
return s
+ @staticmethod
+ def as_str(val: int) -> str:
+ """
+ Get the string representation of the numeric value
+ :param val:
+ :return:
+ """
+ if val == 1:
+ return "PQ"
+ elif val == 2:
+ return "PV"
+ elif val == 3:
+ return "Slack"
+ elif val == 4:
+ return "PQV"
+ elif val == 5:
+ return "P"
+ else:
+ return ""
+
class CpfStopAt(Enum):
"""
@@ -156,7 +176,6 @@ class SolverType(Enum):
"""
NR = 'Newton Raphson'
- NRD = 'Newton Raphson Decoupled'
NRFD_XB = 'Fast decoupled XB'
NRFD_BX = 'Fast decoupled BX'
GAUSS = 'Gauss-Seidel'
@@ -174,7 +193,6 @@ class SolverType(Enum):
NONLINEAR_OPF = 'Nonlinear OPF'
SIMPLE_OPF = 'Simple dispatch'
Proportional_OPF = 'Proportional OPF'
- NRI = 'Newton-Raphson in current'
DYCORS_OPF = 'DYCORS OPF'
GA_OPF = 'Genetic Algorithm OPF'
NELDER_MEAD_OPF = 'Nelder Mead OPF'
@@ -206,157 +224,157 @@ def argparse(s):
return s
-class ReactivePowerControlMode(Enum):
- """
- The :ref:`ReactivePowerControlMode` offers 3 modes to control how
- :ref:`Generator` objects supply reactive power:
-
- **NoControl**: In this mode, the :ref:`generators` don't try to regulate
- the voltage at their :ref:`bus`.
-
- **Direct**: In this mode, the :ref:`generators` try to regulate the
- voltage at their :ref:`bus`. **GridCal** does so by applying the following
- algorithm in an outer control loop. For grids with numerous
- :ref:`generators` tied to the same system, for example wind farms, this
- control method sometimes fails with some :ref:`generators` not trying
- hard enough*. In this case, the simulation converges but the voltage controlled
- :ref:`buses` do not reach their target voltage, while their
- :ref:`generator(s)` haven't reached their reactive power limit. In this
- case, the slower **Iterative** control mode may be used (see below).
-
- ON PV-PQ BUS TYPE SWITCHING LOGIC IN POWER FLOW COMPUTATION
- Jinquan Zhao
-
- 1) Bus i is a PQ bus in the previous iteration and its
- reactive power was fixed at its lower limit:
-
- If its voltage magnitude Vi >= Viset, then
-
- it is still a PQ bus at current iteration and set Qi = Qimin .
-
- If Vi < Viset , then
-
- compare Qi with the upper and lower limits.
-
- If Qi >= Qimax , then
- it is still a PQ bus but set Qi = Qimax .
- If Qi <= Qimin , then
- it is still a PQ bus and set Qi = Qimin .
- If Qimin < Qi < Qi max , then
- it is switched to PV bus, set Vinew = Viset.
-
- 2) Bus i is a PQ bus in the previous iteration and
- its reactive power was fixed at its upper limit:
-
- If its voltage magnitude Vi <= Viset , then:
- bus i still a PQ bus and set Q i = Q i max.
-
- If Vi > Viset , then
-
- Compare between Qi and its upper/lower limits
-
- If Qi >= Qimax , then
- it is still a PQ bus and set Q i = Qimax .
- If Qi <= Qimin , then
- it is still a PQ bus but let Qi = Qimin in current iteration.
- If Qimin < Qi < Qimax , then
- it is switched to PV bus and set Vinew = Viset
-
- 3) Bus i is a PV bus in the previous iteration.
-
- Compare Q i with its upper and lower limits.
-
- If Qi >= Qimax , then
- it is switched to PQ and set Qi = Qimax .
- If Qi <= Qimin , then
- it is switched to PQ and set Qi = Qimin .
- If Qi min < Qi < Qimax , then
- it is still a PV bus.
-
- **Iterative**: As mentioned above, the **Direct** control mode may not yield
- satisfying results in some isolated cases. The **Direct** control mode tries to
- jump to the final solution in a single or few iterations, but in grids where a
- significant change in reactive power at one :ref:`generator` has a
- significant impact on other :ref:`generators`, additional iterations may
- be required to reach a satisfying solution.
-
- Instead of trying to jump to the final solution, the **Iterative** mode raises or
- lowers each :ref:`generator's` reactive power incrementally. The
- increment is determined using a logistic function based on the difference between
- the current :ref:`bus` voltage its target voltage. The steepness factor
- :code:`k` of the logistic function was determined through trial and error, with the
- intent of reducing the number of iterations while avoiding instability. Other
- values may be specified in :ref:`PowerFlowOptions`.
-
- The :math:`Q_{Increment}` in per unit is determined by:
-
- .. math::
-
- Q_{Increment} = 2 * \\left[\\frac{1}{1 + e^{-k|V_2 - V_1|}}-0.5\\right]
-
- Where:
-
- k = 30 (by default)
-
- """
- NoControl = "NoControl"
- Direct = "Direct"
- Iterative = "Iterative"
-
-
-class TapsControlMode(Enum):
- """
- The :ref:`TapsControlMode` offers 3 modes to control how
- :ref:`transformers`' :ref:`tap changer` regulate
- voltage on their regulated :ref:`bus`:
-
- **NoControl**: In this mode, the :ref:`transformers` don't try to
- regulate the voltage at their :ref:`bus`.
-
- **Direct**: In this mode, the :ref:`transformers` try to regulate
- the voltage at their bus. **GridCal** does so by jumping straight to the tap that
- corresponds to the desired transformation ratio, or the highest or lowest tap if
- the desired ratio is outside of the tap range.
-
- This behavior may fail in certain cases, especially if both the
- :ref:`TapControlMode` and :ref:`ReactivePowerControlMode`
- are set to **Direct**. In this case, the simulation converges but the voltage
- controlled :ref:`buses` do not reach their target voltage, while their
- :ref:`generator(s)` haven't reached their reactive power limit. When
- this happens, the slower **Iterative** control mode may be used (see below).
-
- **Iterative**: As mentioned above, the **Direct** control mode may not yield
- satisfying results in some isolated cases. The **Direct** control mode tries to
- jump to the final solution in a single or few iterations, but in grids where a
- significant change of tap at one :ref:`transformer` has a
- significant impact on other :ref:`transformers`, additional
- iterations may be required to reach a satisfying solution.
-
- Instead of trying to jump to the final solution, the **Iterative** mode raises or
- lowers each :ref:`transformer's` tap incrementally.
- """
-
- NoControl = "NoControl"
- Direct = "Direct"
- Iterative = "Iterative"
-
- def __str__(self):
- return self.value
-
- def __repr__(self):
- return str(self)
-
- @staticmethod
- def argparse(s):
- """
-
- :param s:
- :return:
- """
- try:
- return TapsControlMode[s]
- except KeyError:
- return s
+# class ReactivePowerControlMode(Enum):
+# """
+# The :ref:`ReactivePowerControlMode` offers 3 modes to control how
+# :ref:`Generator` objects supply reactive power:
+#
+# **NoControl**: In this mode, the :ref:`generators` don't try to regulate
+# the voltage at their :ref:`bus`.
+#
+# **Direct**: In this mode, the :ref:`generators` try to regulate the
+# voltage at their :ref:`bus`. **GridCal** does so by applying the following
+# algorithm in an outer control loop. For grids with numerous
+# :ref:`generators` tied to the same system, for example wind farms, this
+# control method sometimes fails with some :ref:`generators` not trying
+# hard enough*. In this case, the simulation converges but the voltage controlled
+# :ref:`buses` do not reach their target voltage, while their
+# :ref:`generator(s)` haven't reached their reactive power limit. In this
+# case, the slower **Iterative** control mode may be used (see below).
+#
+# ON PV-PQ BUS TYPE SWITCHING LOGIC IN POWER FLOW COMPUTATION
+# Jinquan Zhao
+#
+# 1) Bus i is a PQ bus in the previous iteration and its
+# reactive power was fixed at its lower limit:
+#
+# If its voltage magnitude Vi >= Viset, then
+#
+# it is still a PQ bus at current iteration and set Qi = Qimin .
+#
+# If Vi < Viset , then
+#
+# compare Qi with the upper and lower limits.
+#
+# If Qi >= Qimax , then
+# it is still a PQ bus but set Qi = Qimax .
+# If Qi <= Qimin , then
+# it is still a PQ bus and set Qi = Qimin .
+# If Qimin < Qi < Qi max , then
+# it is switched to PV bus, set Vinew = Viset.
+#
+# 2) Bus i is a PQ bus in the previous iteration and
+# its reactive power was fixed at its upper limit:
+#
+# If its voltage magnitude Vi <= Viset , then:
+# bus i still a PQ bus and set Q i = Q i max.
+#
+# If Vi > Viset , then
+#
+# Compare between Qi and its upper/lower limits
+#
+# If Qi >= Qimax , then
+# it is still a PQ bus and set Q i = Qimax .
+# If Qi <= Qimin , then
+# it is still a PQ bus but let Qi = Qimin in current iteration.
+# If Qimin < Qi < Qimax , then
+# it is switched to PV bus and set Vinew = Viset
+#
+# 3) Bus i is a PV bus in the previous iteration.
+#
+# Compare Q i with its upper and lower limits.
+#
+# If Qi >= Qimax , then
+# it is switched to PQ and set Qi = Qimax .
+# If Qi <= Qimin , then
+# it is switched to PQ and set Qi = Qimin .
+# If Qi min < Qi < Qimax , then
+# it is still a PV bus.
+#
+# **Iterative**: As mentioned above, the **Direct** control mode may not yield
+# satisfying results in some isolated cases. The **Direct** control mode tries to
+# jump to the final solution in a single or few iterations, but in grids where a
+# significant change in reactive power at one :ref:`generator` has a
+# significant impact on other :ref:`generators`, additional iterations may
+# be required to reach a satisfying solution.
+#
+# Instead of trying to jump to the final solution, the **Iterative** mode raises or
+# lowers each :ref:`generator's` reactive power incrementally. The
+# increment is determined using a logistic function based on the difference between
+# the current :ref:`bus` voltage its target voltage. The steepness factor
+# :code:`k` of the logistic function was determined through trial and error, with the
+# intent of reducing the number of iterations while avoiding instability. Other
+# values may be specified in :ref:`PowerFlowOptions`.
+#
+# The :math:`Q_{Increment}` in per unit is determined by:
+#
+# .. math::
+#
+# Q_{Increment} = 2 * \\left[\\frac{1}{1 + e^{-k|V_2 - V_1|}}-0.5\\right]
+#
+# Where:
+#
+# k = 30 (by default)
+#
+# """
+# NoControl = "NoControl"
+# Direct = "Direct"
+# Iterative = "Iterative"
+#
+#
+# class TapsControlMode(Enum):
+# """
+# The :ref:`TapsControlMode` offers 3 modes to control how
+# :ref:`transformers`' :ref:`tap changer` regulate
+# voltage on their regulated :ref:`bus`:
+#
+# **NoControl**: In this mode, the :ref:`transformers` don't try to
+# regulate the voltage at their :ref:`bus`.
+#
+# **Direct**: In this mode, the :ref:`transformers` try to regulate
+# the voltage at their bus. **GridCal** does so by jumping straight to the tap that
+# corresponds to the desired transformation ratio, or the highest or lowest tap if
+# the desired ratio is outside of the tap range.
+#
+# This behavior may fail in certain cases, especially if both the
+# :ref:`TapControlMode` and :ref:`ReactivePowerControlMode`
+# are set to **Direct**. In this case, the simulation converges but the voltage
+# controlled :ref:`buses` do not reach their target voltage, while their
+# :ref:`generator(s)` haven't reached their reactive power limit. When
+# this happens, the slower **Iterative** control mode may be used (see below).
+#
+# **Iterative**: As mentioned above, the **Direct** control mode may not yield
+# satisfying results in some isolated cases. The **Direct** control mode tries to
+# jump to the final solution in a single or few iterations, but in grids where a
+# significant change of tap at one :ref:`transformer` has a
+# significant impact on other :ref:`transformers`, additional
+# iterations may be required to reach a satisfying solution.
+#
+# Instead of trying to jump to the final solution, the **Iterative** mode raises or
+# lowers each :ref:`transformer's` tap incrementally.
+# """
+#
+# NoControl = "NoControl"
+# Direct = "Direct"
+# Iterative = "Iterative"
+#
+# def __str__(self):
+# return self.value
+#
+# def __repr__(self):
+# return str(self)
+#
+# @staticmethod
+# def argparse(s):
+# """
+#
+# :param s:
+# :return:
+# """
+# try:
+# return TapsControlMode[s]
+# except KeyError:
+# return s
class SyncIssueType(Enum):
@@ -598,42 +616,42 @@ def list(cls):
return list(map(lambda c: c.value, cls))
-class TransformerControlType(Enum):
- """
- Transformer control types
- """
- fixed = '0:Fixed'
- Pf = '1:Pf'
- Qt = '2:Qt'
- PtQt = '3:Pt+Qt'
- V = '4:V'
- PtV = '5:Pt+V'
-
- def __str__(self) -> str:
- return str(self.value)
-
- def __repr__(self):
- return str(self)
-
- @staticmethod
- def argparse(s):
- """
-
- :param s:
- :return:
- """
- try:
- return TransformerControlType[s]
- except KeyError:
- return s
-
- @classmethod
- def list(cls):
- """
-
- :return:
- """
- return list(map(lambda c: c.value, cls))
+# class TransformerControlType(Enum):
+# """
+# Transformer control types
+# """
+# fixed = '0:Fixed'
+# Pf = '1:Pf'
+# Qt = '2:Qt'
+# PtQt = '3:Pt+Qt'
+# V = '4:V'
+# PtV = '5:Pt+V'
+#
+# def __str__(self) -> str:
+# return str(self.value)
+#
+# def __repr__(self):
+# return str(self)
+#
+# @staticmethod
+# def argparse(s):
+# """
+#
+# :param s:
+# :return:
+# """
+# try:
+# return TransformerControlType[s]
+# except KeyError:
+# return s
+#
+# @classmethod
+# def list(cls):
+# """
+#
+# :return:
+# """
+# return list(map(lambda c: c.value, cls))
class TapModuleControl(Enum):
@@ -672,13 +690,14 @@ def list(cls):
return list(map(lambda c: c.value, cls))
-class TapAngleControl(Enum):
+class TapPhaseControl(Enum):
"""
Tap angle control types
"""
fixed = 'Fixed'
Pf = 'Pf'
Pt = 'Pt'
+ # Droop = "Droop"
def __str__(self) -> str:
return str(self.value)
@@ -694,7 +713,7 @@ def argparse(s):
:return:
"""
try:
- return TapAngleControl[s]
+ return TapPhaseControl[s]
except KeyError:
return s
@@ -707,63 +726,63 @@ def list(cls):
return list(map(lambda c: c.value, cls))
-class ConverterControlType(Enum):
- """
- Converter control types
- """
- # Type I
- # theta_vac = '1:Angle+Vac'
- # pf_qac = '2:Pflow + Qflow'
- # pf_vac = '3:Pflow + Vac'
- #
- # # Type II
- # vdc_qac = '4:Vdc+Qflow'
- # vdc_vac = '5:Vdc+Vac'
- #
- # # type III
- # vdc_droop_qac = '6:VdcDroop+Qac'
- # vdc_droop_vac = '7:VdcDroop+Vac'
-
- type_0_free = '0:Free'
-
- type_I_1 = '1:Vac'
- type_I_2 = '2:Pdc+Qac'
- type_I_3 = '3:Pdc+Vac'
-
- type_II_4 = '4:Vdc+Qac'
- type_II_5 = '5:Vdc+Vac'
-
- type_III_6 = '6:Droop+Qac'
- type_III_7 = '7:Droop+Vac'
-
- type_IV_I = '8:Vdc'
- type_IV_II = '9:Pdc'
-
- def __str__(self) -> str:
- return str(self.value)
-
- def __repr__(self):
- return str(self)
-
- @staticmethod
- def argparse(s):
- """
-
- :param s:
- :return:
- """
- try:
- return ConverterControlType[s]
- except KeyError:
- return s
-
- @classmethod
- def list(cls):
- """
-
- :return:
- """
- return list(map(lambda c: c.value, cls))
+# class ConverterControlType(Enum):
+# """
+# Converter control types
+# """
+# # Type I
+# # theta_vac = '1:Angle+Vac'
+# # pf_qac = '2:Pflow + Qflow'
+# # pf_vac = '3:Pflow + Vac'
+# #
+# # # Type II
+# # vdc_qac = '4:Vdc+Qflow'
+# # vdc_vac = '5:Vdc+Vac'
+# #
+# # # type III
+# # vdc_droop_qac = '6:VdcDroop+Qac'
+# # vdc_droop_vac = '7:VdcDroop+Vac'
+#
+# type_0_free = '0:Free'
+#
+# type_I_1 = '1:Vac'
+# type_I_2 = '2:Pdc+Qac'
+# type_I_3 = '3:Pdc+Vac'
+#
+# type_II_4 = '4:Vdc+Qac'
+# type_II_5 = '5:Vdc+Vac'
+#
+# type_III_6 = '6:Droop+Qac'
+# type_III_7 = '7:Droop+Vac'
+#
+# type_IV_I = '8:Vdc'
+# type_IV_II = '9:Pdc'
+#
+# def __str__(self) -> str:
+# return str(self.value)
+#
+# def __repr__(self):
+# return str(self)
+#
+# @staticmethod
+# def argparse(s):
+# """
+#
+# :param s:
+# :return:
+# """
+# try:
+# return ConverterControlType[s]
+# except KeyError:
+# return s
+#
+# @classmethod
+# def list(cls):
+# """
+#
+# :return:
+# """
+# return list(map(lambda c: c.value, cls))
class HvdcControlType(Enum):
@@ -787,7 +806,7 @@ def argparse(s):
:return:
"""
try:
- return ConverterControlType[s]
+ return HvdcControlType[s]
except KeyError:
return s
@@ -932,8 +951,8 @@ class DeviceType(Enum):
"""
Device types
"""
- NoDevice = "NoDevice"
- TimeDevice = "Time"
+ NoDevice = 'NoDevice'
+ TimeDevice = 'Time'
CircuitDevice = 'Circuit'
BusDevice = 'Bus'
BranchDevice = 'Branch'
diff --git a/src/GridCalServer/__version__.py b/src/GridCalServer/__version__.py
index eb2ada850..7db66f638 100644
--- a/src/GridCalServer/__version__.py
+++ b/src/GridCalServer/__version__.py
@@ -16,7 +16,7 @@
_current_year_ = datetime.datetime.now().year
# do not forget to keep a three-number version!!!
-__GridCalServer_VERSION__ = "5.1.21"
+__GridCalServer_VERSION__ = "5.2.0"
url = 'https://github.com/SanPen/GridCal'
diff --git a/src/GridCalServer/endpoints.py b/src/GridCalServer/endpoints.py
index 1371dead7..ef47173ac 100644
--- a/src/GridCalServer/endpoints.py
+++ b/src/GridCalServer/endpoints.py
@@ -71,6 +71,16 @@ def verify_api_key(api_key: str = Header(None)):
raise HTTPException(status_code=403, detail="Invalid API Key")
+@app.get("/get_cert")
+def get_cert():
+ """
+ Get the certificate from the server
+ :return:
+ """
+ # Serve the certificate file
+ return FileResponse("cert.pem", media_type="application/x-pem-file", filename="cert.pem")
+
+
@app.get("/")
async def read_root():
"""
@@ -260,6 +270,17 @@ def iterfile(chunk_size=1024 * 1024):
if __name__ == "__main__":
import uvicorn
+ from GridCalServer.generate_ssl_key import generate_ssl_certificate
# uvicorn.run(app, host="0.0.0.0", port=8000, ssl_keyfile="key.pem", ssl_certfile="cert.pem")
- uvicorn.run(app, host="0.0.0.0", port=8000)
+ # uvicorn.run(app, host="0.0.0.0", port=8000)
+
+ key_fname = "key.pem"
+ cert_fname = "cert.pem"
+ host = "0.0.0.0"
+ port = 8080
+
+ if not os.path.exists(key_fname) or not os.path.exists(cert_fname):
+ generate_ssl_certificate(key_fname=key_fname, cert_fname=cert_fname)
+
+ uvicorn.run(app, host=host, port=port, ssl_keyfile=key_fname, ssl_certfile=cert_fname)
diff --git a/src/GridCalServer/generate_ssl_key.py b/src/GridCalServer/generate_ssl_key.py
new file mode 100644
index 000000000..9910062e1
--- /dev/null
+++ b/src/GridCalServer/generate_ssl_key.py
@@ -0,0 +1,83 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from cryptography import x509
+from cryptography.x509.oid import NameOID
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import hashes, serialization
+from cryptography.hazmat.primitives.asymmetric import rsa
+import datetime
+
+
+def generate_ssl_certificate(key_fname="key.pem", cert_fname="cert.pem"):
+ """
+ Generates a new SSL certificate and saves it to a file
+ :param key_fname:
+ :param cert_fname:
+ :return:
+ """
+ # Generate a private key
+ private_key = rsa.generate_private_key(
+ public_exponent=65537,
+ key_size=2048,
+ backend=default_backend()
+ )
+
+ # Write the private key to a file
+ with open(key_fname, "wb") as key_file:
+ key_file.write(private_key.private_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PrivateFormat.TraditionalOpenSSL,
+ encryption_algorithm=serialization.NoEncryption()
+ ))
+
+ # Define certificate subject and issuer details
+ subject = issuer = x509.Name([
+ x509.NameAttribute(NameOID.COUNTRY_NAME, u"ES"),
+ x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Las Palmas"),
+ x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"),
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"GridCal"),
+ x509.NameAttribute(NameOID.COMMON_NAME, u"localhost"),
+ ])
+
+ # Build the certificate
+ cert = x509.CertificateBuilder().subject_name(
+ subject
+ ).issuer_name(
+ issuer
+ ).public_key(
+ private_key.public_key()
+ ).serial_number(
+ x509.random_serial_number()
+ ).not_valid_before(
+ datetime.datetime.utcnow()
+ ).not_valid_after(
+ # Certificate is valid for 365 days
+ datetime.datetime.utcnow() + datetime.timedelta(days=365)
+ ).add_extension(
+ x509.SubjectAlternativeName([x509.DNSName(u"localhost")]),
+ critical=False,
+ ).sign(private_key, hashes.SHA256(), default_backend())
+
+ # Write the certificate to a file
+ with open(cert_fname, "wb") as cert_file:
+ cert_file.write(cert.public_bytes(serialization.Encoding.PEM))
+
+ print("SSL certificate and key have been generated.")
+
+
+if __name__ == "__main__":
+ generate_ssl_certificate()
diff --git a/src/GridCalServer/run.py b/src/GridCalServer/run.py
index 49768d8e7..80190da72 100644
--- a/src/GridCalServer/run.py
+++ b/src/GridCalServer/run.py
@@ -1,17 +1,19 @@
-# This file is part of GridCal.
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
#
-# GridCal is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
#
-# GridCal is distributed in the hope that it will be useful,
+# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
-# along with GridCal. If not, see .
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os
import sys
import uvicorn
@@ -21,16 +23,22 @@
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))
from GridCalServer.__version__ import about_msg
from GridCalServer.endpoints import app
+from GridCalServer.generate_ssl_key import generate_ssl_certificate
-
-def start_server():
+def start_server(key_fname: str = "key.pem", cert_fname: str = "cert.pem", host: str = "0.0.0.0", port: int = 8000):
"""
-
- :return:
+ Start server function
+ :param key_fname: name of the key file
+ :param cert_fname: name of the certificate file
+ :param host: Hosting ip (localhost ussually)
+ :param port: Port to serve (8000 ussually)
"""
- uvicorn.run(app, host="0.0.0.0", port=8000, ssl_keyfile="key.pem", ssl_certfile="cert.pem")
+ if not os.path.exists(key_fname) or not os.path.exists(cert_fname):
+ generate_ssl_certificate(key_fname=key_fname, cert_fname=cert_fname)
+
+ uvicorn.run(app, host=host, port=port, ssl_keyfile=key_fname, ssl_certfile=cert_fname)
if __name__ == "__main__":
diff --git a/src/GridCalServer/setup.py b/src/GridCalServer/setup.py
index 2b9aa920b..49749f58a 100644
--- a/src/GridCalServer/setup.py
+++ b/src/GridCalServer/setup.py
@@ -77,6 +77,7 @@
"fastapi",
"uvicorn",
"websockets",
+ "cryptography",
"GridCalEngine==" + __GridCalServer_VERSION__, # the GridCalEngine version must be exactly the same
]
diff --git a/src/tests/ac_dc_power_flow.py b/src/tests/ac_dc_power_flow.py
deleted file mode 100644
index ab25660a4..000000000
--- a/src/tests/ac_dc_power_flow.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# GridCal
-# Copyright (C) 2022 Santiago PeƱate Vera
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os
-
-import numpy as np
-
-import GridCalEngine.api as gce
-
-
-def test_1():
- """
-
- :return:
- """
- fname = os.path.join('data', 'grids', 'fubm_caseHVDC_vt.gridcal')
- grid = gce.open_file(fname)
-
- results = gce.power_flow(grid)
-
- # print(results.get_bus_df())
- # print()
- # print(results.get_branch_df())
- # print("Error:", results.error)
- vm = np.abs(results.voltage)
- expected_vm = np.array([1.010000, 1.0, 0.995883, 1.0, 1.013787, 1.02])
- assert np.allclose(vm, expected_vm, rtol=1e-4)
diff --git a/src/tests/conftest.py b/src/tests/conftest.py
deleted file mode 100644
index d7ebbe507..000000000
--- a/src/tests/conftest.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# GridCal
-# Copyright (C) 2022 Santiago PeƱate Vera
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-from pathlib import Path
-
-import pytest
-
-ROOT_PATH = Path(__file__).parent
-
-
-@pytest.fixture
-def root_path():
- """
-
- :return:
- """
- return ROOT_PATH
diff --git a/src/tests/data/grids/5Bus_LTC_FACTS_Fig4.7.gridcal b/src/tests/data/grids/5Bus_LTC_FACTS_Fig4.7.gridcal
new file mode 100644
index 000000000..207e6cd18
Binary files /dev/null and b/src/tests/data/grids/5Bus_LTC_FACTS_Fig4.7.gridcal differ
diff --git a/src/tests/data/grids/5Bus_PST_FACTS_Fig4.10(Pt).gridcal b/src/tests/data/grids/5Bus_PST_FACTS_Fig4.10(Pt).gridcal
new file mode 100644
index 000000000..c5637f0f8
Binary files /dev/null and b/src/tests/data/grids/5Bus_PST_FACTS_Fig4.10(Pt).gridcal differ
diff --git a/src/tests/data/grids/5Bus_PST_FACTS_Fig4.10(Qf).gridcal b/src/tests/data/grids/5Bus_PST_FACTS_Fig4.10(Qf).gridcal
new file mode 100644
index 000000000..a96ab10f4
Binary files /dev/null and b/src/tests/data/grids/5Bus_PST_FACTS_Fig4.10(Qf).gridcal differ
diff --git a/src/tests/data/grids/5Bus_PST_FACTS_Fig4.10.gridcal b/src/tests/data/grids/5Bus_PST_FACTS_Fig4.10.gridcal
new file mode 100644
index 000000000..90e76d482
Binary files /dev/null and b/src/tests/data/grids/5Bus_PST_FACTS_Fig4.10.gridcal differ
diff --git a/src/tests/data/grids/fubm_case1354pegase_2MTDC_ctrls_pf_qt_dp.m b/src/tests/data/grids/fubm_case1354pegase_2MTDC_ctrls_pf_qt_dp.m
new file mode 100644
index 000000000..0c2b2c430
--- /dev/null
+++ b/src/tests/data/grids/fubm_case1354pegase_2MTDC_ctrls_pf_qt_dp.m
@@ -0,0 +1,3986 @@
+function mpc = fubm_case1354pegase_2MTDC_ctrls_pf_qt_dp
+%FUBM-CASE1354PEGASE Power flow data for medium part of European system (Modified).
+% Please see CASEFORMAT for details on the case file format.
+%
+% This case accurately represents the size and complexity of part of the
+% European high voltage transmission network. The network contains 1,354
+% buses, 260 generators, and 1,991 branches and it operates at 380 and
+% 220 kV. Please note that the data are fictitious and do not correspond
+% to real world data. They can thus be used to validate methods and tools
+% but should not be used for operation and planning of the European grid.
+%
+% The data stems from the Pan European Grid Advanced Simulation and State
+% Estimation (PEGASE) project, part of the 7th Framework Program of the
+% European Union (https://www.fp7-pegase.com/).
+%
+% When publishing results based on this data, please cite:
+%
+% C. Josz, S. Fliscounakis, J. Maeght, and P. Panciatici, "AC Power Flow
+% Data in MATPOWER and QCQP Format: iTesla, RTE Snapshots, and PEGASE"
+% https://arxiv.org/abs/1603.01533
+%
+% S. Fliscounakis, P. Panciatici, F. Capitanescu, and L. Wehenkel,
+% "Contingency ranking with respect to overloads in very large power
+% systems taking into account uncertainty, preventive and corrective
+% actions", Power Systems, IEEE Trans. on, (28)4:4909-4917, 2013.
+% https://doi.org/10.1109/TPWRS.2013.2251015
+%
+% Remarks:
+%
+% 1. Line flow limits are 100 MVA (at 1 p.u. voltage) lower than the
+% current flow limits found in PEGASE data.
+%
+% 2. PEGASE data contains asymmetric shunt conductance and susceptance in
+% the PI transmission line model of branches. Thus total line charging
+% susceptance of branches is set to 0 p.u. and the nodal representation
+% of shunt condutance and susceptance is used. As a result, power flow
+% equations are left unchanged compared with original PEGASE data.
+% However, line flow constraints in the optimal flow problem are
+% modified.
+%
+% 3. Identical linear costs are used for all generators to form a loss
+% minimizing OPF objective function.
+%
+% 4. Since some parts of the network are aggregated, some generators
+% (e.g. with negative PMIN) represent aggregations of multiple loads
+% and generators.
+%
+% Contacts:
+% CƩdric Josz, StƩphane Fliscounakis, Jean Maeght, Patrick Panciatici
+% firstname.lastname@rte-france.com
+% RƩseau de Transport d'ElectricitƩ (French Transmission System Operator)
+% DĆ©partement Expertise SystĆØme, Immeuble "Le Colbert"
+% 9 rue de la Porte de Buc, 78000 Versailles Cedex, France
+%
+% This file has been modified to include 1 HVDC link and 1 MTDC grid.
+% Also control variables in the indicated buses are now automatic to meet
+% a setting.
+
+% ABRAHAM ALVAREZ BUSTOS
+% This code is based and created for MATPOWER
+% This is part of the Flexible Universal Branch Model (FUBM) for Matpower
+% For more info about the model, and modifications to this case, email:
+% snoop_and@hotmail.com, abraham.alvarez-bustos@durham.ac.uk
+
+% May 15th, 2020
+
+% MATPOWER
+% Copyright (c) 2015, 2016 by CƩdric Josz, StƩphane Fliscounakis, Jean Maeght,
+% and Patrick Panciatici
+% Licensed under the Creative Commons Attribution 4.0 International license,
+% https://creativecommons.org/licenses/by/4.0/
+
+%% MATPOWER Case Format : Version 2
+mpc.version = '2';
+
+%%----- Power Flow Data -----%%
+%% system MVA base
+mpc.baseMVA = 100;
+
+%% bus data
+% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin
+mpc.bus = [
+ 3 1 151 48.8 0 4.69 0 1.016674 -21.761632 220 5 1.1 0.9;
+ 4 1 171.41 23.4 0 2.1 0 1.026472 -7.007354 220 5 1.1 0.9;
+ 10 1 134 24.7 0 12.44 0 1.038534 -24.281644 220 5 1.1 0.9;
+ 21 1 161.2 39.3 0 30.71 0 1.036195 -21.958828 220 5 1.1 0.9;
+ 22 1 0 -0 0 0.85 0 1.035058 -18.483339 220 5 1.1 0.9;
+ 26 1 167.3 54.8 0 110.54 0 1.032267 -3.318448 380 5 1.1 0.9;
+ 29 1 152.9 49.4 0 27.65 0 0.994409 -13.816418 380 5 1.1 0.9;
+ 44 1 -0 0 0 7.27 0 1.045829 -22.181066 220 5 1.1 0.9;
+ 53 1 48.65 16.1 0 7.14 0 1.063422 -9.070013 220 5 1.1 0.9;
+ 58 1 0 0 0 2.31 0 0.983702 -21.159412 380 5 1.1 0.9;
+ 59 1 119.2 20.7 0 3.31 0 1.036808 -23.631999 220 5 1.1 0.9;
+ 90 1 363.25 115.39 0 3.95 0 1.042187 -27.546292 220 5 1.1 0.9;
+ 96 1 -8.4 28.66 0 3.49 0 1.030441 -15.689479 220 5 1.1 0.9;
+ 113 1 -0 -0 0 6.532711 0 1.030718 -14.242909 380 5 1.1 0.9;
+ 115 1 0 -0 0 4.21 0 1.066797 -19.783678 220 5 1.1 0.9;
+ 118 1 704.53 -35.33 0 13.102834 0 1.020256 -11.430028 380 5 1.1 0.9;
+ 124 2 0 0 0 0 0 1.081537 8.330657 220 5 1.1 0.9;
+ 128 1 23.73 12.7 0 0.52 0 1.020482 -16.063366 220 5 1.1 0.9;
+ 145 1 38.34 5.6 0 7.64 0 1.039096 -8.903623 220 5 1.1 0.9;
+ 148 1 32.34 12 0 6.1 0 1.041568 -7.991267 220 5 1.1 0.9;
+ 150 2 0 0 0 0 0 1.062805 2.531831 220 5 1.1 0.9;
+ 163 1 147.76 32.73 0 8.34 0 1.047047 -10.672351 220 5 1.1 0.9;
+ 171 1 100.8 13.2 0 5.24 0 1.069649 -25.153324 220 5 1.1 0.9;
+ 174 1 370.5 -17 0 9.91 0 1.074846 -27.942789 220 5 1.1 0.9;
+ 184 1 -0 -0 0 2.42 0 1.042771 -11.94851 220 5 1.1 0.9;
+ 188 1 36.84 13.9 0 3.3 0 1.018752 -19.550413 220 5 1.1 0.9;
+ 195 1 73.14 21.55 0 8.52 0 1.056337 -8.791116 220 5 1.1 0.9;
+ 196 1 0 -0 0 12.48 0 1.074825 -26.319857 220 5 1.1 0.9;
+ 198 1 39.74 11.8 0 1.44 0 1.01673 -16.306681 220 5 1.1 0.9;
+ 207 1 321.98 84.4 0 1.34 0 1.026604 -13.457588 220 5 1.1 0.9;
+ 216 1 155.6 54.7 0 2.21 0 1.039362 -24.590496 220 5 1.1 0.9;
+ 217 1 105.2 0.1 0 7.36 0 1.042762 -2.603638 220 5 1.1 0.9;
+ 218 1 69.83 15.12 0 2.23 0 1.045923 -13.114892 220 5 1.1 0.9;
+ 221 2 0 0 0 0 0 0.984682 -21.807603 380 5 1.1 0.9;
+ 225 1 0 0 0 1.15 0 1.063761 -20.174043 220 5 1.1 0.9;
+ 280 1 119.6 29.6 0 5.34 0 1.035725 -11.193679 220 5 1.1 0.9;
+ 283 1 27.33 11.9 0 1.17 0 1.035204 -12.094637 220 5 1.1 0.9;
+ 292 1 13.82 1.4 0 0.7 0 1.047544 -14.765137 220 5 1.1 0.9;
+ 305 1 103 12 0 0.63 0 1.067188 -32.434719 220 5 1.1 0.9;
+ 306 1 -0 0 0 4.76 0 1.030032 -18.823594 220 5 1.1 0.9;
+ 314 1 163.1 46.3 0 10.6 0 1.005548 -16.020947 220 5 1.1 0.9;
+ 333 1 524.5 43 0 6.85 0 1.014579 -42.137692 220 5 1.1 0.9;
+ 338 2 0 0 0 0 0 1.048249 -6.162533 220 5 1.1 0.9;
+ 346 1 197.5 48.3 0 0.71 0 1.040694 -21.298393 220 5 1.1 0.9;
+ 350 1 110.4 26.2 0 5.62 0 1.043185 -24.295117 220 5 1.1 0.9;
+ 352 2 0 0 0 0 0 1.055378 0.262953 380 5 1.1 0.9;
+ 367 1 65.17 -51.5 0 4.85 0 1.07164 -23.599251 220 5 1.1 0.9;
+ 401 1 56.5 36.29 0 3.08 0 1.026548 -14.262083 220 5 1.1 0.9;
+ 408 1 129.1 7.4 0 0.04 0 1.039791 -11.549917 220 5 1.1 0.9;
+ 410 1 170.89 50.38 0 6.44 0 1.041564 -26.439994 220 5 1.1 0.9;
+ 413 2 0 0 0 0 0 1.05013 -6.606455 220 5 1.1 0.9;
+ 416 1 70.68 13.5 0 6.96 0 1.0458 -6.728632 220 5 1.1 0.9;
+ 426 1 123.1 6.5 0 3.25 0 1.040489 -18.395441 220 5 1.1 0.9;
+ 432 1 -0 -0 0 68.517663 0 1.047774 2.403578 380 5 1.1 0.9;
+ 444 1 0 -0 0 2.45 0 1.036267 -12.201434 220 5 1.1 0.9;
+ 449 1 0 0 0 29.42 0 1.021739 -8.489958 380 5 1.1 0.9;
+ 453 2 0 0 0 0 0 1.018914 -7.857046 380 5 1.1 0.9;
+ 455 1 274.32 5.66 0 13.24 0 1.045882 -30.596498 220 5 1.1 0.9;
+ 490 1 20.52 4 0 2.77 0 1.036451 -23.014287 220 5 1.1 0.9;
+ 500 1 144.4 35.5 0 7.66 0 1.040423 -15.042452 220 5 1.1 0.9;
+ 502 1 -0 0 0 1.96 0 1.043564 -6.675538 220 5 1.1 0.9;
+ 506 1 -0 0 0 0.4 0 1.063297 -9.078728 380 5 1.1 0.9;
+ 513 1 57.46 17.1 0 1.61 0 1.038461 -7.443414 220 5 1.1 0.9;
+ 516 2 0 0 0 0 0 1.075592 -33.453515 220 5 1.1 0.9;
+ 520 1 118.5 20.4 0 2.57 0 1.048239 -27.108761 220 5 1.1 0.9;
+ 549 1 0 -0 0 5.15 0 1.074517 -10.959606 220 5 1.1 0.9;
+ 554 1 0 -0 0 1.97 0 1.024071 -20.793083 220 5 1.1 0.9;
+ 556 1 16.52 9 0 1.17 0 1.03694 -22.762979 220 5 1.1 0.9;
+ 561 1 0 -0 0 0.32 0 1.055451 -11.021763 220 5 1.1 0.9;
+ 564 2 0 0 0 0 0 1.069817 -47.078276 220 5 1.1 0.9;
+ 575 1 0 -0 0 0.67 0 1.04436 -11.163788 220 5 1.1 0.9;
+ 583 2 0 0 0 0 0 1.045397 -15.568574 220 5 1.1 0.9;
+ 594 1 67.57 17 0 5.75 0 1.036683 -8.869667 220 5 1.1 0.9;
+ 601 1 140.6 42.6 0 5.71 0 1.040685 -14.418335 220 5 1.1 0.9;
+ 604 1 33.24 4.4 0 24.54 0 0.996939 -12.93567 380 5 1.1 0.9;
+ 608 1 150.9 10.4 0 4.77 0 1.071753 -32.66829 220 5 1.1 0.9;
+ 609 1 -0 -0 0 5.67 0 1.025344 -14.779536 220 5 1.1 0.9;
+ 615 2 0 0 0 0 0 1.063876 -10.607341 220 5 1.1 0.9;
+ 616 2 0 0 0 0 0 1.048713 -12.997468 220 5 1.1 0.9;
+ 619 1 72.88 14.4 0 2.96 0 1.046742 -25.252227 220 5 1.1 0.9;
+ 639 2 0 0 0 0 0 1.051376 -29.999643 220 5 1.1 0.9;
+ 641 1 45.32 18.5 0 0.74 0 1.03515 -13.956622 220 5 1.1 0.9;
+ 658 1 258.4 66.7 0 5.87 0 1.033849 -17.442414 220 5 1.1 0.9;
+ 661 1 -0 -0 0 0.6 0 1.040021 2.414523 380 5 1.1 0.9;
+ 666 1 -5.61 -2.79 0 150.93 0 1.03076 -5.413919 380 5 1.1 0.9;
+ 678 1 232.1 89.8 0 0.09 0 0.986375 -18.62447 220 5 1.1 0.9;
+ 682 2 0 0 0 0 0 1.0691 -10.045044 220 5 1.1 0.9;
+ 687 1 -0 0 0 5.6 0 1.05742 -4.068613 220 5 1.1 0.9;
+ 707 1 83.99 21.2 0 5.36 0 1.054495 -25.620212 220 5 1.1 0.9;
+ 718 1 135.11 41 0 5.31 0 1.031148 -24.884639 220 5 1.1 0.9;
+ 720 1 -0 -0 0 23.554121 0 0.981824 -26.763103 380 5 1.1 0.9;
+ 726 1 400.3 189.9 0 0.53 0 1.048069 -4.933448 220 5 1.1 0.9;
+ 742 1 0 -0 0 2.83 0 1.05759 -4.070122 220 5 1.1 0.9;
+ 747 1 69.58 16 0 3.03 0 1.073922 -26.380554 220 5 1.1 0.9;
+ 749 2 0 0 0 0 0 1.057884 -28.950791 220 5 1.1 0.9;
+ 750 1 -0 -0 0 18.63 0 1.041141 -24.444747 220 5 1.1 0.9;
+ 757 2 0 0 0 0 0 1.017567 -13.765564 380 5 1.1 0.9;
+ 766 1 -0 0 0 7.85 0 1.047952 -19.8489 220 5 1.1 0.9;
+ 769 1 152.57 40 0 6.12 0 1.024104 -10.886119 220 5 1.1 0.9;
+ 772 1 343.9 141.9 0 5.55 0 1.034361 -14.167643 220 5 1.1 0.9;
+ 776 2 0 0 0 0 0 1.026368 -13.331099 220 5 1.1 0.9;
+ 778 2 0 0 0 0 0 1.049411 -6.680953 220 5 1.1 0.9;
+ 789 1 -0 -0 0 6.63 0 1.051689 -5.954643 220 5 1.1 0.9;
+ 795 2 0 0 0 0 0 1.035522 -15.484388 220 5 1.1 0.9;
+ 800 1 50.56 18 0 0.11 0 1.034778 -12.128589 220 5 1.1 0.9;
+ 803 2 0 0 0 0 0 1.041369 -24.768342 220 5 1.1 0.9;
+ 804 1 -0 -0 0 7.26 0 1.05585 -7.563603 220 5 1.1 0.9;
+ 805 1 124.5 29.6 0 15.4 0 1.05673 -11.12828 220 5 1.1 0.9;
+ 809 1 0 -0 0 58.088687 0 1.027525 -0.064839 380 5 1.1 0.9;
+ 819 1 0 -0 0 0.22 0 1.052169 -0.720463 220 5 1.1 0.9;
+ 823 2 0 0 0 0 0 1.044097 -2.229251 380 5 1.1 0.9;
+ 839 1 -0 -0 0 8.17514 0 1.024385 -1.386321 380 5 1.1 0.9;
+ 851 2 0 0 0 0 0 1.00025 -17.401395 220 5 1.1 0.9;
+ 858 2 0 0 0 0 0 1.031745 1.110134 380 5 1.1 0.9;
+ 870 1 110 3.4 0 11.95 0 1.040762 -24.602002 220 5 1.1 0.9;
+ 871 1 108.89 -21.76 0 3.72 0 1.056945 -11.955754 220 5 1.1 0.9;
+ 883 1 192.5 78.3 0 6.65 0 1.017176 -10.133417 220 5 1.1 0.9;
+ 891 2 0 0 0 0 0 1.064525 -18.97841 380 5 1.1 0.9;
+ 892 1 -0 -0 0 9.1 0 1.069234 -34.99461 220 5 1.1 0.9;
+ 900 1 0 0 0 0.15 0 1.050278 -15.385577 220 5 1.1 0.9;
+ 903 1 82.69 20.1 0 1.36 0 1.073885 -26.405705 220 5 1.1 0.9;
+ 905 1 631.71 -54.16 0 7.534129 0 1.035643 -15.075813 380 5 1.1 0.9;
+ 907 1 -0 -0 0 0.05 0 1.038555 -9.767436 220 5 1.1 0.9;
+ 908 1 125.9 -0.5 0 0.21 0 1.065214 -7.929625 220 5 1.1 0.9;
+ 920 1 34.44 8.5 0 1.11 0 1.045537 -20.769903 220 5 1.1 0.9;
+ 923 1 62.07 14.7 0 4.84 0 1.035596 -23.090183 220 5 1.1 0.9;
+ 933 1 -0 0 0 22.75 0 1.019946 -21.525393 220 5 1.1 0.9;
+ 935 1 -0 0 0 9.46 0 1.049182 -24.470238 220 5 1.1 0.9;
+ 953 1 108.7 -12.15 0 37.11 0 1.065973 -13.014498 380 5 1.1 0.9;
+ 954 1 66.27 13.6 0 0.67 0 1.044324 -21.525875 220 5 1.1 0.9;
+ 960 1 -0 -0 0 108.728602 0 1.063295 -9.078724 380 5 1.1 0.9;
+ 964 1 88.5 16.5 0 146.44 0 1.015553 -11.659761 380 5 1.1 0.9;
+ 972 2 0 0 0 0 0 1.072621 5.35893 380 5 1.3 0.7;
+ 980 1 14.71 4.6 0 7.88 0 1.047164 -25.138433 220 5 1.1 0.9;
+ 1001 2 0 0 0 0 0 1.074143 -33.62199 220 5 1.1 0.9;
+ 1002 2 0 0 0 0 0 1.041506 -20.086455 220 5 1.1 0.9;
+ 1005 1 0 0 0 0.81 0 1.053955 -12.379476 220 5 1.1 0.9;
+ 1015 1 44.55 0 0 4.78 0 1.056277 -5.398682 220 5 1.1 0.9;
+ 1026 1 201.4 53 0 9.67 0 1.028182 -29.352232 220 5 1.1 0.9;
+ 1027 1 -5.91 -2.33 0 30.393595 0 0.990542 -18.181223 380 5 1.1 0.9;
+ 1033 1 26.33 5.3 0 4.31 0 1.040934 -24.521854 220 5 1.1 0.9;
+ 1035 1 382.5 57.9 0 8.16 0 1.067815 -32.322562 220 5 1.1 0.9;
+ 1039 1 34.64 -0 0 0.91 0 1.034441 -19.543294 220 5 1.1 0.9;
+ 1040 1 31.94 8.8 0 3.79 0 1.038913 -9.027471 220 5 1.1 0.9;
+ 1043 2 0 0 0 0 0 1.028946 -3.693426 380 5 1.1 0.9;
+ 1051 1 -0 0 0 3.79 0 1.041627 -12.829065 220 5 1.1 0.9;
+ 1077 1 -0 0 0 0.1 0 1.035206 -12.094658 220 5 1.1 0.9;
+ 1078 1 -0 -0 0 4.74 0 1.061509 -3.472987 220 5 1.1 0.9;
+ 1081 1 277.86 58.95 0 182.880644 0 1.038644 -10.509999 380 5 1.1 0.9;
+ 1083 2 0 0 0 0 0 1.049472 -8.613737 220 5 1.1 0.9;
+ 1090 1 56.06 18.7 0 4.24 0 1.0101 -21.692579 220 5 1.1 0.9;
+ 1093 2 0 0 0 0 0 1.027056 -8.507308 380 5 1.1 0.9;
+ 1096 1 0 -0 0 0.16 0 1.050189 -1.116839 220 5 1.1 0.9;
+ 1100 2 0 0 0 0 0 1.042801 -4.348181 220 5 1.1 0.9;
+ 1101 1 -0 -0 0 2.05 0 1.033508 -14.209132 220 5 1.1 0.9;
+ 1102 2 0 0 0 0 0 1.049879 -6.64195 220 5 1.1 0.9;
+ 1105 1 29.83 7.3 0 6.49 0 1.074759 -26.325932 220 5 1.1 0.9;
+ 1111 1 0 0 0 1.1 0 1.036823 -8.871578 220 5 1.1 0.9;
+ 1129 1 190.47 55.03 0 6.7 0 1.003325 -22.532961 220 5 1.1 0.9;
+ 1136 1 16.22 2 0 0.71 0 1.034786 -18.539009 220 5 1.1 0.9;
+ 1137 1 -0 -0 0 0.05 0 1.048666 -24.42816 220 5 1.1 0.9;
+ 1146 1 32.84 -0 0 1.41 0 1.032638 -5.627486 220 5 1.1 0.9;
+ 1151 1 -0 -0 0 18.82 0 1.043354 -20.606997 220 5 1.1 0.9;
+ 1153 1 12.41 3.9 0 2.23 0 1.034654 -6.058841 220 5 1.1 0.9;
+ 1156 1 65.67 24 0 9.95 0 1.038055 -22.501868 220 5 1.1 0.9;
+ 1159 1 112.4 13 0 3.99 0 1.052615 -36.244174 220 5 1.1 0.9;
+ 1172 1 -0 -0 0 2.3 0 1.074468 -25.55724 220 5 1.1 0.9;
+ 1179 1 86.6 23.4 0 0.39 0 1.040896 -2.802576 220 5 1.1 0.9;
+ 1183 1 199.4 -19.9 0 6.68 0 1.066643 -33.081849 220 5 1.1 0.9;
+ 1187 1 67.57 21.2 0 5.71 0 1.039857 -4.955282 220 5 1.1 0.9;
+ 1188 1 30.93 6.6 0 9.09 0 1.054495 -14.222981 220 5 1.1 0.9;
+ 1194 1 129.6 13.3 0 13.98 0 1.03896 -15.127161 380 5 1.1 0.9;
+ 1198 1 0 0 0 30.637696 0 0.987964 -14.637206 380 5 1.1 0.9;
+ 1201 1 114.1 23.5 0 1.08 0 1.050304 -19.627666 220 5 1.1 0.9;
+ 1216 1 0 0 0 4.93 0 1.040626 -10.966354 220 5 1.1 0.9;
+ 1233 1 0 -0 0 1.72 0 1.037981 -22.526704 220 5 1.1 0.9;
+ 1234 1 71.78 17.9 0 1.96 0 1.022628 -16.524518 220 5 1.1 0.9;
+ 1237 2 0 0 0 0 0 1.108028 -6.285992 380 5 1.3 0.7;
+ 1248 1 0 0 0 1.17 0 1.047205 -10.673893 220 5 1.1 0.9;
+ 1249 1 348.93 26.47 0 9.36 0 1.019402 -11.26449 380 5 1.1 0.9;
+ 1251 2 0 0 0 0 0 1.027102 -8.516785 380 5 1.1 0.9;
+ 1262 1 -0 0 0 10.73 0 1.038607 -22.034538 220 5 1.1 0.9;
+ 1265 1 173 -21.3 0 5.93 0 1.066705 -50.057306 220 5 1.1 0.9;
+ 1275 1 52.46 2.9 0 0.35 0 1.032647 -18.856368 220 5 1.1 0.9;
+ 1295 2 0 0 0 0 0 1.03682 -8.643487 220 5 1.1 0.9;
+ 1301 1 479 99.2 0 10.68 0 1.05167 -28.720012 220 5 1.1 0.9;
+ 1305 1 -0 -0 0 4.34 0 1.038253 -22.269637 220 5 1.1 0.9;
+ 1311 1 37.94 15.2 0 35.31 0 1.033986 -21.654604 380 5 1.1 0.9;
+ 1326 1 0 0 0 0.98 0 1.069384 -34.995605 220 5 1.1 0.9;
+ 1334 1 0 0 0 0.59 0 1.025188 -16.314102 220 5 1.1 0.9;
+ 1341 2 0 0 0 0 0 1.032899 -14.204982 220 5 1.1 0.9;
+ 1343 1 -0 -0 0 58.3 0 0.996377 -14.200565 380 5 1.1 0.9;
+ 1354 2 0 0 0 0 0 1.041045 -7.375163 220 5 1.1 0.9;
+ 1355 1 -3.29 -1.32 0 190.704588 0 1.0328 -8.554156 380 5 1.1 0.9;
+ 1364 1 40.85 14.5 0 0.59 0 1.039851 -12.092524 220 5 1.1 0.9;
+ 1380 1 145.2 21.4 0 1.09 0 1.033661 -22.574327 220 5 1.1 0.9;
+ 1394 1 30.93 7.6 0 4.69 0 1.074659 -26.314245 220 5 1.1 0.9;
+ 1397 1 0 -0 0 2.14 0 1.037924 -12.820941 220 5 1.1 0.9;
+ 1398 1 196.7 44.2 0 0.1 0 1.017322 -19.003234 220 5 1.1 0.9;
+ 1401 1 11.91 2.9 0 5.27 0 1.038647 -14.758146 220 5 1.1 0.9;
+ 1414 1 144.7 20.3 0 6.35 0 1.022683 -27.895964 220 5 1.1 0.9;
+ 1415 1 0 -0 0 0.3 0 1.032141 -11.506028 220 5 1.1 0.9;
+ 1422 2 0 0 0 0 0 1.04353 -20.966559 220 5 1.1 0.9;
+ 1435 1 -0 0 0 3.85 0 1.044674 -24.345986 220 5 1.1 0.9;
+ 1436 2 0 0 0 0 0 1.047684 -12.917585 220 5 1.1 0.9;
+ 1448 1 0 0 0 9.49 0 1.075069 -15.319825 220 5 1.1 0.9;
+ 1459 1 -0 -0 0 3.38 0 1.042934 -21.817757 220 5 1.1 0.9;
+ 1462 1 -0 0 0 0.42 0 1.043552 -20.967069 220 5 1.1 0.9;
+ 1465 1 -11.03 -5.11 0 29.706803 0 0.988454 -15.339654 380 5 1.1 0.9;
+ 1478 2 0 0 0 0 0 1.048068 -15.82908 220 5 1.1 0.9;
+ 1483 1 0 0 0 4.86 0 1.064156 -26.867437 220 5 1.1 0.9;
+ 1486 1 79.59 18.8 0 6.78 0 1.034956 -23.34269 220 5 1.1 0.9;
+ 1494 1 -1.85 -1.63 0 31.424588 0 1.034255 -11.521816 380 5 1.1 0.9;
+ 1502 1 -0 0 0 37.116157 0 1.027764 -26.693479 380 5 1.1 0.9;
+ 1504 1 0 -0 0 1.84 0 1.025322 -14.28951 220 5 1.1 0.9;
+ 1526 1 -10.86 -5.93 0 12.54 0 1.042753 -11.9479 220 5 1.1 0.9;
+ 1538 1 36.34 15.2 0 0.3 0 1.033256 -8.75699 220 5 1.1 0.9;
+ 1539 1 73.58 3.24 0 52.35 0 1.059384 -15.296455 220 5 1.1 0.9;
+ 1541 1 125.4 45.8 0 0 0 1.039282 -23.538177 220 5 1.1 0.9;
+ 1545 1 42.55 8.2 0 2.06 0 1.042222 -23.472695 220 5 1.1 0.9;
+ 1547 1 -0 -0 0 1.02 0 1.040481 -15.042995 220 5 1.1 0.9;
+ 1551 1 -0 -0 0 7.99 0 1.043158 -20.41875 220 5 1.1 0.9;
+ 1552 1 20.42 8.1 0 35.15 0 1.042604 -16.620759 380 5 1.1 0.9;
+ 1554 1 0 -0 0 4.96 0 1.020729 -16.043428 220 5 1.1 0.9;
+ 1556 1 -0 -0 0 0.95 0 1.061796 -11.391738 220 5 1.1 0.9;
+ 1562 1 77.39 24.1 0 2.67 0 1.042236 -25.854486 220 5 1.1 0.9;
+ 1566 1 156.9 -4 0 2.48 0 1.036219 -24.756749 220 5 1.1 0.9;
+ 1568 1 69.08 21.5 0 1.65 0 1.046858 -25.154702 220 5 1.1 0.9;
+ 1578 1 0 -0 0 1.38 0 1.040417 -12.029853 220 5 1.1 0.9;
+ 1584 1 0 -0 0 3.24 0 1.026871 -14.239921 220 5 1.1 0.9;
+ 1592 1 28.33 44.8 0 0.51 0 1.037512 -2.335282 220 5 1.1 0.9;
+ 1595 1 71.77 13.57 0 3.84 0 1.01584 -29.283839 220 5 1.1 0.9;
+ 1604 2 0 0 0 0 0 1.043862 -6.640235 220 5 1.1 0.9;
+ 1605 1 -0 0 0 0.05 0 1.076968 -24.357645 220 5 1.1 0.9;
+ 1607 1 73.78 -0 0 2.69 0 1.030671 -5.514136 380 5 1.1 0.9;
+ 1609 1 0 0 0 6.55 0 1.05016 -20.676376 220 5 1.1 0.9;
+ 1625 1 73.18 22.3 0 8.77 0 1.047827 -19.847235 220 5 1.1 0.9;
+ 1629 1 41.95 8.5 0 1.05 0 1.043667 -11.062381 220 5 1.1 0.9;
+ 1642 2 0 0 0 0 0 1.028554 0.427747 380 5 1.1 0.9;
+ 1643 1 95.71 25.9 0 11.38 0 1.042277 -25.887944 220 5 1.1 0.9;
+ 1644 1 449.56 245.72 0 94.55 0 1.054472 3.4279 380 5 1.1 0.9;
+ 1662 1 3.67 -1.86 0 3.89 0 1.046228 -20.80193 220 5 1.1 0.9;
+ 1672 1 -28.13 -0.83 0 0.1 0 1.061821 -11.405066 220 5 1.1 0.9;
+ 1680 2 0 0 0 0 0 1.04395 -2.225166 380 5 1.1 0.9;
+ 1692 1 83.19 25.8 0 0.33 0 1.047275 -10.47462 220 5 1.1 0.9;
+ 1704 1 62.16 8 0 2.99 0 1.038923 -13.052366 220 5 1.1 0.9;
+ 1708 2 0 0 0 0 0 1.037938 -13.186223 380 5 1.1 0.9;
+ 1709 1 -15.38 -4.94 0 33.241519 0 1.007462 -14.734072 380 5 1.1 0.9;
+ 1711 1 25.13 -61.6 0 3.68 0 1.052686 -29.767092 220 5 1.1 0.9;
+ 1721 2 0 0 0 0 0 1.062238 2.466713 220 5 1.1 0.9;
+ 1730 1 -17.18 -4.35 0 44.419365 0 1.025799 -14.51076 380 5 1.1 0.9;
+ 1742 1 0 0 0 6.68 0 1.030326 -32.491405 220 5 1.1 0.9;
+ 1746 1 -0 0 0 1.86 0 1.049354 -24.089302 220 5 1.1 0.9;
+ 1750 1 58.46 6.6 0 10.13 0 1.036578 -19.191311 220 5 1.1 0.9;
+ 1754 2 0 0 0 0 0 1.04286 -17.149587 380 5 1.1 0.9;
+ 1758 1 0 -0 0 121.29 0 1.03465 -4.424306 380 5 1.1 0.9;
+ 1763 1 -0 -0 0 0.28 0 1.034875 -30.808254 380 5 1.1 0.9;
+ 1767 1 333.5 -1.4 0 8.37 0 1.049612 -45.569227 220 5 1.1 0.9;
+ 1768 1 73.98 22.5 0 1.15 0 1.042927 -11.13756 220 5 1.1 0.9;
+ 1775 1 -0 0 0 1.64 0 1.05106 -25.97492 220 5 1.1 0.9;
+ 1794 2 0 0 0 0 0 1.05295 -0.236871 380 5 1.1 0.9;
+ 1798 1 -0.63 -0.83 0 22.810288 0 0.987325 -7.424983 380 5 1.1 0.9;
+ 1803 1 -0 -0 0 0.05 0 1.038883 -22.036572 220 5 1.1 0.9;
+ 1808 2 0 0 0 0 0 1.046224 -0.834506 220 5 1.1 0.9;
+ 1813 1 88.92 19.79 0 2.81 0 1.029057 -7.519944 220 5 1.1 0.9;
+ 1817 1 108.91 33.7 0 56.24 0 1.069539 -12.567622 380 5 1.1 0.9;
+ 1833 1 0 0 0 3.33 0 1.036371 -22.480232 220 5 1.1 0.9;
+ 1838 1 0 -0 0 3.02 0 1.037419 -22.162507 220 5 1.1 0.9;
+ 1844 1 -28.14 -0.76 0 0.1 0 1.061839 -11.404513 220 5 1.1 0.9;
+ 1851 2 0 0 0 0 0 1.04762 -12.927099 220 5 1.1 0.9;
+ 1852 2 0 0 0 0 0 1.054325 -25.744509 220 5 1.1 0.9;
+ 1857 1 0 0 0 1.53 0 1.028608 -11.055937 220 5 1.1 0.9;
+ 1860 1 88.8 -3.2 0 13.63 0 1.060858 -25.532569 220 5 1.1 0.9;
+ 1866 1 209.2 23.5 0 6.44 0 1.04474 -28.285319 220 5 1.1 0.9;
+ 1868 1 11.71 3.8 0 2.96 0 1.035258 -15.877966 220 5 1.1 0.9;
+ 1876 1 -0 -0 0 6.273568 0 1.030797 -14.242223 380 5 1.1 0.9;
+ 1883 1 27.33 5 0 6.77 0 1.029787 -16.425673 220 5 1.1 0.9;
+ 1888 2 0 0 0 0 0 1.039377 -2.376673 220 5 1.1 0.9;
+ 1895 1 20.82 -0 0 0.14 0 1.070353 7.588403 220 5 1.1 0.9;
+ 1896 1 -0 -0 0 1.18 0 1.021131 -6.153674 380 5 1.1 0.9;
+ 1910 1 -0 0 0 2.68 0 1.049243 -6.695385 220 5 1.1 0.9;
+ 1914 2 0 0 0 0 0 1.035636 -20.619184 220 5 1.1 0.9;
+ 1917 1 197.5 -31 0 17.34 0 1.050486 -25.132946 220 5 1.1 0.9;
+ 1923 1 192.11 45.5 0 68.04 0 1.002407 -11.646061 380 5 1.1 0.9;
+ 1940 1 0 0 0 1.19 0 1.03614 -18.037347 220 5 1.1 0.9;
+ 1959 2 0 0 0 0 0 1.064692 -10.511132 220 5 1.1 0.9;
+ 1965 1 248.7 8.1 0 12.46 0 1.066548 -49.702693 220 5 1.1 0.9;
+ 1973 1 210.1 66.2 0 59.36 0 1.074741 -26.300211 220 5 1.1 0.9;
+ 1979 1 0 0 0 0.14 0 1.074144 -33.621995 220 5 1.1 0.9;
+ 1980 1 177.3 36.4 0 0.7 0 1.040983 -21.42173 220 5 1.1 0.9;
+ 1998 1 25.73 7.3 0 2.82 0 1.033294 -20.141362 220 5 1.1 0.9;
+ 2012 1 41.45 4.9 0 18.43 0 1.038506 -18.675791 220 5 1.1 0.9;
+ 2019 1 72.08 21.3 0 7.19 0 1.044528 -21.078894 220 5 1.1 0.9;
+ 2020 1 0 0 0 9.98 0 1.051074 -24.096673 220 5 1.1 0.9;
+ 2021 1 3.9 1 0 3.81 0 1.050096 -24.96566 220 5 1.1 0.9;
+ 2035 2 0 0 0 0 0 1.03088 0.693557 380 5 1.1 0.9;
+ 2042 1 14.02 6.5 0 0.09 0 1.037536 -5.903671 220 5 1.1 0.9;
+ 2043 1 3.2 1.7 0 0.05 0 1.043517 -20.967534 220 5 1.1 0.9;
+ 2044 1 0 0 0 0.14 0 1.032138 -12.426968 220 5 1.1 0.9;
+ 2050 2 0 0 0 0 0 1.009914 -1.144693 380 5 1.1 0.9;
+ 2056 1 -0 0 0 7.338808 0 1.038215 -9.076082 380 5 1.1 0.9;
+ 2057 1 120.2 20.5 0 19.94 0 1.04971 -30.773674 220 5 1.1 0.9;
+ 2072 1 101.2 2.1 0 38.43 0 1.065746 -17.405584 380 5 1.1 0.9;
+ 2078 1 77.19 18.6 0 2.22 0 1.020675 -14.721188 220 5 1.1 0.9;
+ 2079 1 0 -0 0 13.94 0 1.050272 -12.128304 220 5 1.1 0.9;
+ 2083 1 121.4 20.2 0 16.61 0 1.035 -18.482915 220 5 1.1 0.9;
+ 2085 2 0 0 0 0 0 1.040351 2.467063 380 5 1.1 0.9;
+ 2088 1 -0 0 0 6.02 0 1.052176 -12.052739 220 5 1.1 0.9;
+ 2089 1 199.86 56.93 0 46.83 0 1.04312 -25.770522 220 5 1.1 0.9;
+ 2093 1 -5.64 -2.84 0 34.582195 0 1.016671 -8.086067 380 5 1.1 0.9;
+ 2101 1 -0 -0 0 38.32 0 1.02998 -5.549174 380 5 1.1 0.9;
+ 2128 1 79.09 18.7 0 10.8 0 1.035961 -23.062582 220 5 1.1 0.9;
+ 2129 1 0 0 0 56.686515 0 1.016495 -8.242431 380 5 1.1 0.9;
+ 2132 1 107.3 14.2 0 20.23 0 1.039669 -15.783021 220 5 1.1 0.9;
+ 2142 1 0 -0 0 7.63 0 1.050391 -7.902365 220 5 1.1 0.9;
+ 2155 1 63.67 20.2 0 6.13 0 1.037645 -5.893797 220 5 1.1 0.9;
+ 2161 1 35.66 -9.39 0 7.89 0 1.048364 -28.662661 220 5 1.1 0.9;
+ 2166 1 20.92 7.7 0 1.21 0 1.052887 -14.673236 220 5 1.1 0.9;
+ 2174 1 0 0 0 61.795782 0 1.011944 -13.202451 380 5 1.1 0.9;
+ 2177 2 0 0 0 0 0 1.07333 -28.416356 220 5 1.1 0.9;
+ 2183 1 0 0 0 32.849821 0 0.995876 -16.181883 380 5 1.1 0.9;
+ 2189 1 -0 0 0 0.18 0 1.047761 -6.28234 220 5 1.1 0.9;
+ 2197 2 0 0 0 0 0 1.035528 -6.012095 380 5 1.1 0.9;
+ 2208 1 74.98 26.9 0 2.96 0 1.051126 -13.420372 220 5 1.1 0.9;
+ 2229 1 0 -0 0 2.91 0 1.062959 -13.080678 220 5 1.1 0.9;
+ 2230 1 0 -0 0 1.71 0 1.036513 -22.481463 220 5 1.1 0.9;
+ 2231 1 0 0 0 0.45 0 1.049391 1.166976 220 5 1.1 0.9;
+ 2242 1 -0 -0 0 2.76 0 1.02489 -19.020985 220 5 1.1 0.9;
+ 2252 1 100.7 -4.2 0 1.57 0 1.068023 -47.917821 220 5 1.1 0.9;
+ 2273 1 141.3 32.4 0 7.29 0 1.074359 -26.339387 220 5 1.1 0.9;
+ 2276 2 0 0 0 0 0 1.05324 -23.758819 220 5 1.1 0.9;
+ 2286 1 208.88 60.8 0 6.68 0 1.023269 -8.717089 220 5 1.1 0.9;
+ 2288 1 170.9 39 0 11.25 0 1.034468 -8.57662 220 5 1.1 0.9;
+ 2291 2 0 0 0 0 0 1.072528 -10.610728 220 5 1.1 0.9;
+ 2303 1 0 -0 0 7.94 0 1.03744 -15.856049 220 5 1.1 0.9;
+ 2304 1 88.7 -0.1 0 2.83 0 1.058495 -25.832763 220 5 1.1 0.9;
+ 2308 1 32.04 6.6 0 0.44 0 1.038612 -24.078628 220 5 1.1 0.9;
+ 2313 1 0 -0 0 0.41 0 1.046654 -21.265608 220 5 1.1 0.9;
+ 2319 1 39.64 20.9 0 0.65 0 1.061069 -8.962289 220 5 1.1 0.9;
+ 2327 1 114.5 25.2 0 17.57 0 1.047194 -25.133812 220 5 1.1 0.9;
+ 2328 1 -0 0 0 0.4 0 1.017489 -14.250876 220 5 1.1 0.9;
+ 2337 1 103.4 27 0 1.41 0 1.045493 -29.7818 220 5 1.1 0.9;
+ 2340 1 96.91 13.9 0 3.98 0 1.03958 -12.236094 220 5 1.1 0.9;
+ 2341 1 -0 0 0 3.28 0 1.065118 -26.070582 220 5 1.1 0.9;
+ 2359 2 0 0 0 0 0 1.024884 -9.921886 380 5 1.1 0.9;
+ 2360 1 215.5 31.3 0 14.23 0 1.044563 -21.085033 220 5 1.1 0.9;
+ 2361 1 16.9 3.85 0 25.09 0 1.052288 -29.004707 220 5 1.1 0.9;
+ 2365 1 37.94 15.4 0 117.386167 0 1.033702 -22.17424 380 5 1.1 0.9;
+ 2372 1 0 -0 0 14.490904 0 0.991274 -17.482034 380 5 1.1 0.9;
+ 2377 1 101.7 17.6 0 13.14 0 1.036655 -14.897845 220 5 1.1 0.9;
+ 2393 1 20.82 0 0 0.13 0 1.070495 7.700354 220 5 1.1 0.9;
+ 2406 1 0 0 0 1.69 0 1.048666 -24.428158 220 5 1.1 0.9;
+ 2421 2 0 0 0 0 0 1.047766 -23.702161 220 5 1.1 0.9;
+ 2424 1 44.55 16.8 0 2.31 0 1.034979 -22.416002 220 5 1.1 0.9;
+ 2425 2 0 0 0 0 0 1.041186 -9.882232 220 5 1.1 0.9;
+ 2426 2 0 0 0 0 0 1.037687 -13.762974 220 5 1.1 0.9;
+ 2430 1 -0 0 0 6.21 0 1.041369 -11.921713 220 5 1.1 0.9;
+ 2432 1 291.2 35.4 0 21.87 0 1.030479 -32.300033 220 5 1.1 0.9;
+ 2438 1 -0 0 0 0.64 0 1.046626 -21.265307 220 5 1.1 0.9;
+ 2446 2 0 0 0 0 0 1.06157 7.557722 380 5 1.1 0.9;
+ 2457 1 30.73 9.6 0 2.75 0 1.040059 -24.619174 220 5 1.1 0.9;
+ 2458 1 132 26 0 27.18 0 1.006537 -13.460583 380 5 1.1 0.9;
+ 2467 1 0 -0 0 11.65 0 1.018095 -14.100158 220 5 1.1 0.9;
+ 2468 2 0 0 0 0 0 1.048132 -6.215141 220 5 1.1 0.9;
+ 2475 1 0 0 0 0.21 0 1.065573 -7.808732 220 5 1.1 0.9;
+ 2479 1 -2.65 -1.17 0 65.673108 0 1.008158 -2.627166 380 5 1.1 0.9;
+ 2481 2 0 0 0 0 0 1.042777 -18.185589 220 5 1.1 0.9;
+ 2489 2 0 0 0 0 0 1.049366 1.167288 220 5 1.1 0.9;
+ 2503 1 -0 0 0 2.09 0 1.012856 -21.48175 220 5 1.1 0.9;
+ 2510 1 115.87 29.41 0 7.92 0 1.028486 -12.08393 220 5 1.1 0.9;
+ 2518 1 -5.29 -1.91 0 42.622979 0 0.999088 -11.536983 380 5 1.1 0.9;
+ 2526 1 238.45 46.86 0 125.534496 0 1.044376 -19.855823 380 5 1.1 0.9;
+ 2527 1 59.77 16.7 0 0.64 0 1.043988 -4.63491 220 5 1.1 0.9;
+ 2535 1 51.56 2.1 0 0.18 0 1.037544 -2.896669 220 5 1.1 0.9;
+ 2550 2 0 0 0 0 0 1.049384 -6.666685 220 5 1.1 0.9;
+ 2558 1 159.27 38.31 0 2.18 0 1.023305 -16.640241 220 5 1.1 0.9;
+ 2563 1 52.86 13 0 6.04 0 1.046977 -4.707678 220 5 1.1 0.9;
+ 2575 1 62.97 17.4 0 0.3 0 1.04159 -2.724929 220 5 1.1 0.9;
+ 2591 1 253.77 84.6 0 20.71 0 1.030923 -15.233022 220 5 1.1 0.9;
+ 2597 1 14.72 5.4 0 0.72 0 1.033106 -10.863404 220 5 1.1 0.9;
+ 2598 1 25.63 12.7 0 8.42 0 1.040506 -15.286014 220 5 1.1 0.9;
+ 2600 2 0 0 0 0 0 1.038821 -13.64341 220 5 1.1 0.9;
+ 2627 2 0 0 0 0 0 1.061488 7.521439 380 5 1.1 0.9;
+ 2629 1 203.1 65.2 0 0.64 0 1.045498 -24.492103 220 5 1.1 0.9;
+ 2641 1 0 0 0 1.72 0 1.042124 -11.251293 220 5 1.1 0.9;
+ 2644 1 0 0 0 0.19 0 1.07369 -24.808555 220 5 1.1 0.9;
+ 2653 2 0 0 0 0 0 1.036517 -23.007774 220 5 1.1 0.9;
+ 2654 1 207.1 50.4 0 4.93 0 1.019228 -18.770253 220 5 1.1 0.9;
+ 2656 1 -0.72 0 0 69.582294 0 1.034308 -22.749906 380 5 1.1 0.9;
+ 2676 1 123.24 23.65 0 6.44 0 1.035697 -14.93988 220 5 1.1 0.9;
+ 2689 1 0 0 0 0.45 0 1.034001 -3.213772 220 5 1.1 0.9;
+ 2695 1 16.22 8.9 0 2.2 0 1.038344 -21.004788 220 5 1.1 0.9;
+ 2702 1 151.7 27.6 0 6.49 0 1.043222 -25.609448 220 5 1.1 0.9;
+ 2719 2 0 0 0 0 0 1.035384 -15.495326 220 5 1.1 0.9;
+ 2721 1 -0 0 0 10.040547 0 0.983623 -22.371652 380 5 1.1 0.9;
+ 2732 1 85.59 20.72 0 142.79 0 1.013054 -10.064991 380 5 1.1 0.9;
+ 2749 1 55.56 26.5 0 1.09 0 1.049925 -30.124895 220 5 1.1 0.9;
+ 2751 1 34.54 8.6 0 5.05 0 1.042162 -21.896741 220 5 1.1 0.9;
+ 2754 1 -0 0 0 3.72 0 1.051994 -13.365671 220 5 1.1 0.9;
+ 2770 1 85.39 14.3 0 0.35 0 1.047946 -9.667144 220 5 1.1 0.9;
+ 2782 1 -28.13 -0.81 0 0.1 0 1.06184 -11.404239 220 5 1.1 0.9;
+ 2786 2 0 0 0 0 0 1.073795 6.427789 380 5 1.3 0.7;
+ 2794 1 0 -0 0 0.39 0 1.035004 -18.482955 220 5 1.1 0.9;
+ 2795 1 -0 -0 0 1.94 0 1.070164 -32.44656 220 5 1.1 0.9;
+ 2797 2 0 0 0 0 0 1.042226 -4.483231 220 5 1.1 0.9;
+ 2799 2 0 0 0 0 0 1.05396 -12.355638 220 5 1.1 0.9;
+ 2801 1 0 -0 0 12.17 0 1.041023 -24.502823 220 5 1.1 0.9;
+ 2806 1 -0 -0 0 0.39 0 1.050477 0.170291 220 5 1.1 0.9;
+ 2815 1 25.33 14.2 0 4.05 0 1.03655 -22.984441 220 5 1.1 0.9;
+ 2816 2 0 0 0 0 0 1.053944 -0.390904 380 5 1.1 0.9;
+ 2841 2 0 0 0 0 0 1.08248 -26.223645 220 5 1.1 0.9;
+ 2842 2 0 0 0 0 0 1.043712 -6.650222 220 5 1.1 0.9;
+ 2847 1 40.14 8.8 0 0.82 0 1.050663 -3.956106 220 5 1.1 0.9;
+ 2848 1 453.23 139.16 0 25.583218 0 0.998047 -7.830482 380 5 1.1 0.9;
+ 2850 1 -0 -0 0 4.76 0 1.03307 -18.741426 220 5 1.1 0.9;
+ 2854 1 -12.33 -2.65 0 69.323028 0 1.044838 -10.677353 380 5 1.1 0.9;
+ 2863 1 37.73 13.84 0 0.09 0 1.028402 -11.074681 220 5 1.1 0.9;
+ 2866 1 -0 0 0 4.21 0 1.03784 -7.272198 220 5 1.1 0.9;
+ 2872 2 0 0 0 0 0 1.063841 -10.631082 220 5 1.1 0.9;
+ 2877 1 29.93 -0 0 0.46 0 1.041807 -14.920901 220 5 1.1 0.9;
+ 2878 2 0 0 0 0 0 1.057626 -10.952158 220 5 1.1 0.9;
+ 2886 2 0 0 0 0 0 1.055151 -14.128145 220 5 1.1 0.9;
+ 2888 1 -0 0 0 0.22 0 1.013722 -21.258074 220 5 1.1 0.9;
+ 2889 1 -0 0 0 3.2 0 1.050185 -1.116811 220 5 1.1 0.9;
+ 2898 1 56.76 13.4 0 1.18 0 1.035844 -23.070363 220 5 1.1 0.9;
+ 2902 2 0 0 0 0 0 1.059072 -23.273273 220 5 1.1 0.9;
+ 2910 1 -0 0 0 2.87 0 1.040554 -2.262281 220 5 1.1 0.9;
+ 2918 1 0 0 0 53.25003 0 1.02385 -28.205516 380 5 1.1 0.9;
+ 2919 1 -0 0 0 32.049116 0 0.991588 -18.308905 380 5 1.1 0.9;
+ 2924 1 19.92 7.4 0 17.28 0 1.057573 -33.080856 220 5 1.1 0.9;
+ 2928 1 0 -0 0 92.38 0 1.074568 -26.335879 220 5 1.1 0.9;
+ 2930 2 0 0 0 0 0 1.047695 -12.912307 220 5 1.1 0.9;
+ 2931 1 230.7 19.3 0 4.56 0 1.043622 -32.26389 220 5 1.1 0.9;
+ 2934 2 0 0 0 0 0 1.051149 -6.52803 220 5 1.1 0.9;
+ 2938 1 0 -0 0 137.29 0 1.005521 -7.42176 380 5 1.1 0.9;
+ 2940 1 103 28.7 0 2.88 0 1.01671 -14.352513 220 5 1.1 0.9;
+ 2949 1 -0 -0 0 11.03 0 1.050433 -4.837602 220 5 1.1 0.9;
+ 2961 1 159.9 53.2 0 7.99 0 1.041215 -24.387727 220 5 1.1 0.9;
+ 2967 1 0 -0 0 0.19 0 1.046973 -17.07434 220 5 1.1 0.9;
+ 2968 1 112.51 16.51 0 1.63 0 1.044527 -8.952764 220 5 1.1 0.9;
+ 2972 1 97.82 20.59 0 6.67 0 1.038342 -15.064035 220 5 1.1 0.9;
+ 2980 1 -0 0 0 0.42 0 1.063297 -9.078731 380 5 1.1 0.9;
+ 2981 1 -0 0 0 1.68 0 1.075422 -15.322665 220 5 1.1 0.9;
+ 2985 2 0 0 0 0 0 1.053607 -8.47854 220 5 1.1 0.9;
+ 2995 1 0 -0 0 3.9 0 1.051891 -3.763961 220 5 1.1 0.9;
+ 3013 1 2.2 1.1 0 0.67 0 1.049575 -5.241034 220 5 1.1 0.9;
+ 3018 2 0 0 0 0 0 1.041705 -12.798969 220 5 1.1 0.9;
+ 3019 1 0 -0 0 1.37 0 1.036837 -22.763335 220 5 1.1 0.9;
+ 3021 1 74.38 8.8 0 6.1 0 1.042535 -11.458053 220 5 1.1 0.9;
+ 3022 1 149 19.8 0 23.89 0 1.038441 -14.928463 380 5 1.1 0.9;
+ 3028 2 0 0 0 0 0 1.030654 0.605264 380 5 1.1 0.9;
+ 3036 1 116.93 33.6 0 3.35 0 1.046808 -25.175878 220 5 1.1 0.9;
+ 3037 1 221 146.8 0 8.35 0 1.04857 -6.585978 220 5 1.1 0.9;
+ 3044 1 29.33 5.6 0 6.56 0 1.044991 -21.014316 220 5 1.1 0.9;
+ 3051 1 0 0 0 0 0 1.031148 -24.884639 220 5 1.1 0.9;
+ 3069 1 89.6 22.7 0 4.06 0 1.033466 -8.740353 220 5 1.1 0.9;
+ 3070 1 0 -0 0 4.27 0 1.013716 -21.258029 220 5 1.1 0.9;
+ 3071 1 0 -0 0 2.83 0 1.044715 -7.284056 220 5 1.1 0.9;
+ 3072 1 92.9 27.7 0 5.22 0 1.050676 -30.097241 220 5 1.1 0.9;
+ 3075 1 30.33 10.5 0 0.33 0 1.020662 -16.898848 220 5 1.1 0.9;
+ 3082 1 0 0 0 75.076038 0 0.998938 -15.122127 380 5 1.1 0.9;
+ 3083 1 567.97 130.73 0 1.09 0 1.068389 -27.641331 220 5 1.1 0.9;
+ 3085 1 64.67 24.5 0 1.46 0 1.067218 -27.697899 220 5 1.1 0.9;
+ 3112 1 -0 0 0 0 0 1.057299 2.403578 220 5 1.1 0.9;
+ 3114 2 0 0 0 0 0 1.071964 -11.598423 220 5 1.1 0.9;
+ 3121 1 242.16 73.64 0 12.79 0 1.031627 -7.214885 220 5 1.1 0.9;
+ 3126 1 104.78 20.92 0 6.17 0 1.021547 -17.925447 220 5 1.1 0.9;
+ 3133 2 0 0 0 0 0 1.065372 -9.169038 220 5 1.1 0.9;
+ 3134 2 0 0 0 0 0 1.023117 -15.704702 220 5 1.1 0.9;
+ 3137 1 0 -0 0 0.03 0 1.065118 -26.070583 220 5 1.1 0.9;
+ 3145 1 860.95 -182.67 0 18.309116 0 0.993017 -41.441031 380 5 1.1 0.9;
+ 3166 1 184.91 32.8 0 8.35 0 1.039048 -17.527734 220 5 1.1 0.9;
+ 3183 2 0 0 0 0 0 1.055515 -11.832574 220 5 1.1 0.9;
+ 3184 1 14.12 7.7 0 1.42 0 1.040299 -21.338667 220 5 1.1 0.9;
+ 3187 1 107 34.7 0 1.54 0 1.042404 -12.953299 220 5 1.1 0.9;
+ 3191 1 127.8 15.2 0 9.34 0 1.040776 -12.071062 220 5 1.1 0.9;
+ 3200 1 86.2 19.9 0 5.43 0 1.036168 -23.053307 220 5 1.1 0.9;
+ 3204 1 8.51 3.2 0 0.96 0 1.017023 -10.267075 220 5 1.1 0.9;
+ 3205 2 0 0 0 0 0 1.041982 -1.292668 380 5 1.1 0.9;
+ 3218 2 0 0 0 0 0 1.028507 -11.253521 220 5 1.1 0.9;
+ 3221 1 76.38 24.8 0 3.24 0 1.047766 -12.146786 220 5 1.1 0.9;
+ 3231 1 251.3 42.6 0 5.47 0 1.025161 -14.287368 220 5 1.1 0.9;
+ 3239 1 -5.06 -1.84 0 187.327025 0 1.056229 -11.611515 380 5 1.1 0.9;
+ 3240 2 0 0 0 0 0 1.050305 -1.129073 220 5 1.1 0.9;
+ 3241 1 132 27 0 4.66 0 1.030192 -17.957576 220 5 1.1 0.9;
+ 3243 1 -0 0 0 1.18 0 0.990554 -18.181283 380 5 1.1 0.9;
+ 3246 1 20.9 -171.5 0 0.21 0 1.080513 7.863586 220 5 1.1 0.9;
+ 3248 1 84.19 17.3 0 6.2 0 1.05498 -11.325947 220 5 1.1 0.9;
+ 3255 1 0 0 0 1.44 0 1.038882 -22.03657 220 5 1.1 0.9;
+ 3276 1 -0 -0 0 0.13 0 1.050076 -7.893785 220 5 1.1 0.9;
+ 3293 1 33.14 11.6 0 4.51 0 1.038075 -11.39812 220 5 1.1 0.9;
+ 3306 2 0 0 0 0 0 1.071978 8.08029 220 5 1.1 0.9;
+ 3324 2 0 0 0 0 0 1.014126 -16.129669 220 5 1.1 0.9;
+ 3325 1 -0 0 0 0.91 0 1.033998 -20.055869 220 5 1.1 0.9;
+ 3327 1 -0 -0 0 2.27 0 1.038066 -12.156606 220 5 1.1 0.9;
+ 3331 1 -0 -0 0 4.56 0 1.0175 -10.215862 220 5 1.1 0.9;
+ 3344 1 83.29 24.1 0 1.23 0 1.039524 -16.595479 220 5 1.1 0.9;
+ 3346 2 0 0 0 0 0 1.01594 -12.063974 380 5 1.1 0.9;
+ 3353 2 0 0 0 0 0 1.045739 -3.042188 220 5 1.1 0.9;
+ 3364 2 0 0 0 0 0 1.0538 -12.359552 220 5 1.1 0.9;
+ 3377 1 77.49 21.4 0 0.05 0 1.018192 -10.51029 220 5 1.1 0.9;
+ 3390 2 0 0 0 0 0 1.039984 -11.495624 220 5 1.1 0.9;
+ 3391 1 302.5 65.1 0 8.87 0 1.059691 -20.937372 220 5 1.1 0.9;
+ 3400 1 0 0 0 17.31 0 1.047571 -25.085016 220 5 1.1 0.9;
+ 3401 1 23.22 6.3 0 0.66 0 1.034711 -14.123031 220 5 1.1 0.9;
+ 3412 1 -0 0 0 0 0 1.057299 2.403578 220 5 1.1 0.9;
+ 3422 2 0 0 0 0 0 1.063657 -10.680951 220 5 1.1 0.9;
+ 3430 1 125.1 44 0 6.04 0 1.015255 -16.040907 220 5 1.1 0.9;
+ 3435 1 -0 0 0 10.13 0 1.043606 -25.55539 220 5 1.1 0.9;
+ 3436 2 0 0 0 0 0 1.060777 -13.286433 220 5 1.1 0.9;
+ 3445 1 45.14 -6.64 0 88.82001 0 0.999706 -5.879329 380 5 1.1 0.9;
+ 3450 1 78.99 16.2 0 1.97 0 1.046643 -21.48337 220 5 1.1 0.9;
+ 3481 1 142.5 23.6 0 4.24 0 1.023602 -20.789174 220 5 1.1 0.9;
+ 3483 1 157.78 276.03 0 91.192543 0 1.051877 2.264367 380 5 1.1 0.9;
+ 3485 1 -0 0 0 6.501668 0 0.991148 -16.268999 380 5 1.1 0.9;
+ 3486 1 101.5 -18.3 0 8.47 0 1.037237 -20.871205 220 5 1.1 0.9;
+ 3488 1 55.66 4.5 0 1.33 0 1.038891 -12.374272 220 5 1.1 0.9;
+ 3492 2 0 0 0 0 0 1.04852 -8.570568 220 5 1.1 0.9;
+ 3496 1 99.3 23.3 0 1.88 0 1.03602 -21.337931 220 5 1.1 0.9;
+ 3498 1 138.5 19.3 0 5.26 0 1.04022 -10.181185 220 5 1.1 0.9;
+ 3499 1 180.4 71.6 0 81.042938 0 1.035853 -3.63424 380 5 1.1 0.9;
+ 3502 1 98.2 19.1 0 10.92 0 1.020854 -10.552336 220 5 1.1 0.9;
+ 3503 1 -0 0 0 1.93 0 1.032128 -11.505891 220 5 1.1 0.9;
+ 3513 2 0 0 0 0 0 1.028771 -3.782955 380 5 1.1 0.9;
+ 3519 1 -0 0 0 68.053762 0 1.033967 -22.784898 380 5 1.1 0.9;
+ 3520 1 -0 0 0 2.47 0 1.037612 -5.896123 220 5 1.1 0.9;
+ 3526 1 33.34 13.2 0 0.76 0 1.056871 -4.128916 220 5 1.1 0.9;
+ 3535 1 -0 0 0 0.49 0 1.035787 -24.451001 220 5 1.1 0.9;
+ 3541 1 0 -0 0 3.34 0 1.039193 -23.983552 220 5 1.1 0.9;
+ 3543 1 -0 -0 0 14.079026 0 0.991625 -17.553669 380 5 1.1 0.9;
+ 3545 1 20.12 7.6 0 0.89 0 1.049206 -8.009952 220 5 1.1 0.9;
+ 3557 1 87.2 31.8 0 5.96 0 1.048975 -30.444694 220 5 1.1 0.9;
+ 3558 1 -0 0 0 2.51 0 1.062152 2.457422 220 5 1.1 0.9;
+ 3565 2 0 0 0 0 0 1.081614 -26.430835 220 5 1.1 0.9;
+ 3577 1 -38.7 -12.99 0 13.47383 0 1.031951 -5.185856 380 5 1.1 0.9;
+ 3579 1 277.72 7.35 0 3.58 0 1.072032 -39.86741 220 5 1.1 0.9;
+ 3580 2 0 0 0 0 0 1.07602 -33.404876 220 5 1.1 0.9;
+ 3589 1 37.54 18.3 0 0.22 0 1.042938 -6.728326 220 5 1.1 0.9;
+ 3594 1 31.43 6.6 0 3.32 0 1.034276 -19.803995 220 5 1.1 0.9;
+ 3601 1 0 0 0 0.23 0 1.040409 -21.360272 220 5 1.1 0.9;
+ 3602 1 86.6 14.9 0 1.34 0 1.032076 -18.933744 220 5 1.1 0.9;
+ 3608 1 0 -0 0 58.146813 0 1.00943 -41.64982 380 5 1.1 0.9;
+ 3609 1 -28.13 -0.82 0 0.1 0 1.061834 -11.405533 220 5 1.1 0.9;
+ 3610 1 185.8 31.8 0 3.73 0 1.03662 -22.744804 220 5 1.1 0.9;
+ 3611 2 0 0 0 0 0 1.03905 -18.955066 220 5 1.1 0.9;
+ 3613 1 152.5 14.4 0 24.61 0 1.03039 -28.045674 380 5 1.1 0.9;
+ 3643 1 24.23 6.4 0 3.9 0 1.033238 -19.364356 220 5 1.1 0.9;
+ 3645 1 42.55 17.6 0 17.28 0 1.057259 -33.103595 220 5 1.1 0.9;
+ 3649 1 -0 -0 0 4.86 0 1.049277 -36.568687 220 5 1.1 0.9;
+ 3654 1 20.72 5 0 6.64 0 1.074155 -26.393413 220 5 1.1 0.9;
+ 3656 2 0 0 0 0 0 1.070983 -11.746409 220 5 1.1 0.9;
+ 3657 1 131 1.3 0 120.45 0 1.075593 -26.08278 220 5 1.1 0.9;
+ 3661 2 0 0 0 0 0 1.059676 4.513427 380 5 1.1 0.9;
+ 3670 1 28.03 6.5 0 6.32 0 1.036121 -21.979516 220 5 1.1 0.9;
+ 3672 1 82.99 25.9 0 0.23 0 1.032626 -12.873557 220 5 1.1 0.9;
+ 3674 1 155.05 39.56 0 6.27 0 1.042158 -14.835571 220 5 1.1 0.9;
+ 3680 1 -0 -0 0 12.4 0 1.035367 -15.507057 220 5 1.1 0.9;
+ 3697 1 -32.71 -13.76 0 135.136611 0 1.04888 -20.581455 380 5 1.1 0.9;
+ 3698 2 0 0 0 0 0 1.041813 -24.312887 220 5 1.1 0.9;
+ 3701 1 -0 0 0 0.43 0 1.048029 -25.022699 220 5 1.1 0.9;
+ 3707 1 77.49 17.3 0 0.1 0 1.050811 -15.306372 220 5 1.1 0.9;
+ 3718 1 179.4 58.3 0 0.64 0 1.04576 -25.247909 220 5 1.1 0.9;
+ 3737 1 42.48 10.36 0 0.37 0 1.036909 -2.934488 220 5 1.1 0.9;
+ 3740 1 0 -0 0 13.03 0 1.03798 -21.218929 220 5 1.1 0.9;
+ 3741 2 0 0 0 0 0 1.031629 0.717314 380 5 1.1 0.9;
+ 3749 1 115.1 16.4 0 7.67 0 1.041217 -17.23173 220 5 1.1 0.9;
+ 3758 1 83.49 17.4 0 19.32 0 1.023928 -19.012865 220 5 1.1 0.9;
+ 3760 1 163.5 44.9 0 1.17 0 1.058074 -20.932224 220 5 1.1 0.9;
+ 3768 1 19.82 10.9 0 0.05 0 1.042031 -21.905161 220 5 1.1 0.9;
+ 3775 1 55.54 15.06 0 6.28 0 1.001347 -23.504647 220 5 1.1 0.9;
+ 3786 1 -0 -0 0 26.98 0 1.052535 -19.650048 220 5 1.1 0.9;
+ 3793 1 197.7 67.65 0 13.58 0 1.034254 -20.635259 220 5 1.1 0.9;
+ 3794 1 165.3 7.4 0 28.32 0 1.030869 -28.137864 380 5 1.1 0.9;
+ 3809 2 0 0 0 0 0 1.084785 -33.980103 220 5 1.1 0.9;
+ 3814 1 130.5 24.7 0 0.4 0 1.041172 -21.968498 220 5 1.1 0.9;
+ 3817 1 0 -0 0 1.02 0 1.089268 -15.202915 220 5 1.1 0.9;
+ 3818 1 44.45 10.9 0 2.23 0 1.042892 -25.785119 220 5 1.1 0.9;
+ 3825 2 0 0 0 0 0 1.026994 -8.529973 380 5 1.1 0.9;
+ 3830 1 -0 0 0 97.326028 0 0.99448 -13.765558 380 5 1.1 0.9;
+ 3834 1 160 69.2 0 0.19 0 1.036267 -22.248651 220 5 1.1 0.9;
+ 3855 1 -38.73 -15.32 0 97.23 0 1.07551 -26.170776 220 5 1.1 0.9;
+ 3857 1 -0 -0 0 11.68 0 1.081278 -23.127573 220 5 1.1 0.9;
+ 3865 1 -0 -0 0 2.26 0 1.027017 -14.866102 220 5 1.1 0.9;
+ 3866 1 201.06 19.46 0 2.87 0 1.048033 -27.549636 220 5 1.1 0.9;
+ 3869 2 0 0 0 0 0 1.031907 1.193974 380 5 1.1 0.9;
+ 3876 2 0 0 0 0 0 1.044501 -9.587109 220 5 1.1 0.9;
+ 3880 1 -28.13 -0.82 0 0.09 0 1.061821 -11.404764 220 5 1.1 0.9;
+ 3894 1 0 0 0 4.77 0 1.02402 -15.319245 220 5 1.1 0.9;
+ 3903 1 0 0 0 4.36 0 1.051358 -24.515174 220 5 1.1 0.9;
+ 3906 1 0 0 0 98.2 0 1.037271 -13.381903 380 5 1.1 0.9;
+ 3912 1 0 -0 0 19.73 0 1.038244 -21.078792 220 5 1.1 0.9;
+ 3916 2 0 0 0 0 0 1.043758 -14.004059 220 5 1.1 0.9;
+ 3918 1 -11.8 -5.47 0 88.050735 0 1.02393 -1.867594 380 5 1.1 0.9;
+ 3919 1 -0 0 0 39.95 0 1.024896 -6.075842 380 5 1.1 0.9;
+ 3925 1 89.3 25.1 0 2.98 0 1.026482 -13.116396 220 5 1.1 0.9;
+ 3928 1 105.2 24.2 0 0.25 0 1.046535 -4.757211 220 5 1.1 0.9;
+ 3929 1 48.95 11.6 0 2 0 1.03267 -20.217595 220 5 1.1 0.9;
+ 3951 2 0 0 0 0 0 1.027439 -12.908691 220 5 1.1 0.9;
+ 3956 1 -0 -0 0 1.18 0 1.049338 -24.08911 220 5 1.1 0.9;
+ 3962 1 19.42 11.8 0 2.6 0 1.041036 -23.700249 220 5 1.1 0.9;
+ 3969 1 -0 -0 0 0.84 0 1.018397 -10.494183 220 5 1.1 0.9;
+ 3971 2 0 0 0 0 0 1.063145 -8.854993 220 5 1.1 0.9;
+ 3975 1 148 26.1 0 9.44 0 0.986357 -24.771259 220 5 1.1 0.9;
+ 3985 1 77.19 26.5 0 6.2 0 1.047148 -0.061532 220 5 1.1 0.9;
+ 3994 1 36.34 10.4 0 2.67 0 1.035393 -2.725702 220 5 1.1 0.9;
+ 3997 1 26.13 9.7 0 2.37 0 1.042584 -11.956467 220 5 1.1 0.9;
+ 3999 1 110.8 36.9 0 23.2 0 1.051666 -6.639084 220 5 1.1 0.9;
+ 4000 1 -0 0 0 24.103274 0 0.991622 -15.520854 380 5 1.1 0.9;
+ 4005 1 171.18 28.49 0 0 0 1.067869 -31.620043 220 5 1.1 0.9;
+ 4024 2 0 0 0 0 0 1.040328 2.440561 380 5 1.1 0.9;
+ 4025 1 0 0 0 2.67 0 1.035538 -2.7146 220 5 1.1 0.9;
+ 4031 1 0 -0 0 6.42 0 1.063769 -10.640029 220 5 1.1 0.9;
+ 4032 1 265.7 113.5 0 1.85 0 0.999578 -11.699686 220 5 1.1 0.9;
+ 4039 1 -0 -0 0 1.18 0 1.037985 -22.526852 220 5 1.1 0.9;
+ 4049 1 -0 -0 0 0.89 0 1.017178 -10.133503 220 5 1.1 0.9;
+ 4054 1 0 -0 0 2.71 0 1.035023 -18.483102 220 5 1.1 0.9;
+ 4056 2 0 0 0 0 0 1.038526 -9.78553 220 5 1.1 0.9;
+ 4060 1 -0 0 0 2.08 0 1.066903 -14.674014 220 5 1.1 0.9;
+ 4084 2 0 0 0 0 0 1.063234 -8.796721 220 5 1.1 0.9;
+ 4100 1 -0 -0 0 1.23 0 1.063607 -10.700214 220 5 1.1 0.9;
+ 4103 1 81.09 12.5 0 2.4 0 1.037109 -21.700054 220 5 1.1 0.9;
+ 4110 1 13.01 3.8 0 3.59 0 1.048623 0.630118 220 5 1.1 0.9;
+ 4114 1 9.91 5.4 0 4.6 0 1.048622 -24.482065 220 5 1.1 0.9;
+ 4118 2 0 0 0 0 0 1.027195 -14.802318 220 5 1.1 0.9;
+ 4125 2 0 0 0 0 0 1.003502 -8.417156 380 5 1.1 0.9;
+ 4127 1 39.14 7.7 0 11.68 0 1.033235 -20.156948 220 5 1.1 0.9;
+ 4128 2 0 0 0 0 0 1.019761 -15.71382 220 5 1.1 0.9;
+ 4134 1 -0 0 0 0.09 0 1.074144 -33.622001 220 5 1.1 0.9;
+ 4141 1 -0.62 0 0 75.020288 0 1.032772 -21.096452 380 5 1.1 0.9;
+ 4143 1 11.11 4.1 0 0.8 0 1.05009 -1.152786 220 5 1.1 0.9;
+ 4144 1 310.2 4.5 0 8.51 0 1.048354 -19.735876 220 5 1.1 0.9;
+ 4157 1 0 0 0 1.2 0 1.074571 -26.335983 220 5 1.1 0.9;
+ 4185 1 87.5 21.3 0 7.52 0 1.042708 -25.806182 220 5 1.1 0.9;
+ 4186 1 -0 0 0 5.06 0 1.036176 -23.132591 220 5 1.1 0.9;
+ 4189 1 200.65 30.72 0 9.72 0 1.037191 -26.003681 220 5 1.1 0.9;
+ 4196 1 -3.2 -1.05 0 48.471563 0 1.029571 -7.552855 380 5 1.1 0.9;
+ 4197 1 9.01 4.9 0 0.64 0 1.06874 0.692131 220 5 1.1 0.9;
+ 4205 1 5.81 1.7 0 0.42 0 1.052019 -12.684377 220 5 1.1 0.9;
+ 4215 1 -0 -0 0 17.29 0 1.046292 -23.032269 220 5 1.1 0.9;
+ 4231 3 0 0 0 0 0 1.049182 0 380 5 1.1 0.9;
+ 4234 1 0 0 0 8.95 0 1.046192 -17.159976 220 5 1.1 0.9;
+ 4235 1 -0 -0 0 12.68 0 1.053821 -19.119448 220 5 1.1 0.9;
+ 4239 1 190.7 52 0 20.57 0 1.052709 -13.186066 220 5 1.1 0.9;
+ 4245 1 24.93 9.6 0 0.09 0 1.041034 -9.897904 220 5 1.1 0.9;
+ 4251 1 47.15 15.7 0 5.41 0 1.026731 -17.726744 220 5 1.1 0.9;
+ 4267 1 70.78 19.6 0 7.9 0 1.038616 -8.918342 220 5 1.1 0.9;
+ 4281 1 -0 -0 0 11.4 0 1.05107 -11.692848 220 5 1.1 0.9;
+ 4300 1 81.49 25.1 0 0.36 0 1.00381 -16.189999 220 5 1.1 0.9;
+ 4301 1 -0 -0 0 2.27 0 1.038253 -21.079157 220 5 1.1 0.9;
+ 4306 1 0 -0 0 0.3 0 1.034875 -30.808256 380 5 1.1 0.9;
+ 4313 1 133.4 29.4 0 10.87 0 1.043554 -21.132272 220 5 1.1 0.9;
+ 4314 1 26.13 2.7 0 1.7 0 1.044059 -14.213235 220 5 1.1 0.9;
+ 4324 1 307.42 -38.3 0 0 0 1.06402 -29.724601 220 5 1.1 0.9;
+ 4331 2 0 0 0 0 0 1.028646 -11.048944 220 5 1.1 0.9;
+ 4339 1 -0 -0 0 42.345005 0 0.994972 -15.805227 380 5 1.1 0.9;
+ 4353 1 165.8 44 0 6.15 0 1.055169 -26.615369 220 5 1.1 0.9;
+ 4355 1 65.07 15 0 1.37 0 1.07349 -26.435642 220 5 1.1 0.9;
+ 4357 1 235 58.9 0 14.47 0 1.046909 -15.944189 220 5 1.1 0.9;
+ 4368 1 90.6 15.8 0 7.99 0 1.060945 -25.082183 220 5 1.1 0.9;
+ 4395 2 0 0 0 0 0 1.039834 -20.6569 220 5 1.1 0.9;
+ 4402 1 -0 0 0 1.02 0 1.089271 -15.202973 220 5 1.1 0.9;
+ 4410 1 45.05 13.2 0 44.93 0 1.046754 -36.877378 220 5 1.1 0.9;
+ 4418 1 -0 0 0 0.05 0 1.076968 -24.357646 220 5 1.1 0.9;
+ 4419 2 0 0 0 0 0 1.059565 4.496453 380 5 1.1 0.9;
+ 4426 1 485.5 -63.38 0 34.92 0 1.068079 -46.755413 220 5 1.1 0.9;
+ 4432 1 -0 0 0 0.8 0 1.07457 -26.335948 220 5 1.1 0.9;
+ 4435 1 -0 -0 0 102.217726 0 1.006778 -8.596561 380 5 1.1 0.9;
+ 4454 1 -0 -0 0 1 0 0.987785 -18.481884 220 5 1.1 0.9;
+ 4480 2 0 0 0 0 0 1.071852 7.973164 220 5 1.1 0.9;
+ 4482 2 0 0 0 0 0 1.049914 -6.455681 220 5 1.1 0.9;
+ 4484 1 69.78 25 0 14.24 0 1.051896 -13.325368 220 5 1.1 0.9;
+ 4491 1 0 -0 0 1.75 0 1.032064 -28.901791 220 5 1.1 0.9;
+ 4494 1 -0 0 0 55.514618 0 1.024773 -0.869931 380 5 1.1 0.9;
+ 4504 1 170.1 -9.3 0 5.97 0 1.072324 -42.518571 220 5 1.1 0.9;
+ 4505 1 95.51 17.1 0 8.5 0 1.047176 -15.911012 220 5 1.1 0.9;
+ 4506 2 0 0 0 0 0 1.036047 -5.941934 220 5 1.1 0.9;
+ 4511 1 81.89 19.9 0 5.1 0 1.041941 -25.929686 220 5 1.1 0.9;
+ 4513 1 92.1 29.5 0 3.14 0 1.030552 -9.829625 220 5 1.1 0.9;
+ 4520 1 -0 -0 0 0.94 0 1.017179 -10.133508 220 5 1.1 0.9;
+ 4525 1 -0 0 0 6.12 0 1.060611 -8.826883 220 5 1.1 0.9;
+ 4529 1 48.48 8.7 0 10.14 0 1.055612 -15.125162 220 5 1.1 0.9;
+ 4541 1 0 -0 0 150.797812 0 1.023455 -9.910829 380 5 1.1 0.9;
+ 4544 1 -0 -0 0 14.64 0 1.047769 -14.697837 220 5 1.1 0.9;
+ 4549 1 0 -0 0 0.3 0 1.03214 -11.506046 220 5 1.1 0.9;
+ 4550 1 0 -0 0 124.2 0 1.019271 -10.38876 380 5 1.1 0.9;
+ 4554 1 119 21.9 0 0.95 0 1.041048 -9.799798 220 5 1.1 0.9;
+ 4562 1 130.5 25.7 0 2.27 0 1.02147 -16.819485 220 5 1.1 0.9;
+ 4566 2 0 0 0 0 0 1.073282 -27.676255 220 5 1.1 0.9;
+ 4580 1 11.01 3.9 0 7.98 0 1.045713 -12.00096 220 5 1.1 0.9;
+ 4594 1 -1.73 -1.71 0 22.062314 0 0.998779 -5.591046 380 5 1.1 0.9;
+ 4598 1 -0 0 0 52.958443 0 1.024757 -7.997137 380 5 1.1 0.9;
+ 4615 1 42.55 17.6 0 1.2 0 1.066957 -25.393864 220 5 1.1 0.9;
+ 4623 1 0 -0 0 80.388213 0 0.9943 -16.866228 380 5 1.1 0.9;
+ 4624 2 0 0 0 0 0 1.042135 -15.685962 220 5 1.1 0.9;
+ 4656 1 93.9 -0.4 0 3.66 0 1.052781 -19.605607 220 5 1.1 0.9;
+ 4661 2 0 0 0 0 0 1.049813 -26.16746 220 5 1.1 0.9;
+ 4674 1 124 29.2 0 0.53 0 1.032396 -12.4247 220 5 1.1 0.9;
+ 4679 1 102.7 17.8 0 48.05 0 1.042344 -20.616305 220 5 1.1 0.9;
+ 4683 1 38.84 8.5 0 7.31 0 1.052059 -3.729961 220 5 1.1 0.9;
+ 4685 1 46.15 11.2 0 10.16 0 1.042999 -25.790941 220 5 1.1 0.9;
+ 4689 1 109.7 15 0 30.97 0 1.048918 -30.792772 220 5 1.1 0.9;
+ 4701 2 0 0 0 0 0 1.043063 -9.879302 380 5 1.1 0.9;
+ 4710 1 195.4 76.84 0 8.59 0 1.026719 -9.176978 220 5 1.1 0.9;
+ 4711 1 -0 0 0 16.11 0 1.042937 -11.415152 220 5 1.1 0.9;
+ 4725 1 4.91 1.6 0 4.15 0 1.014202 -10.601951 220 5 1.1 0.9;
+ 4728 1 3.1 0.1 0 1.34 0 1.040401 -21.360189 220 5 1.1 0.9;
+ 4729 1 0 0 0 2.38 0 1.032006 -8.433928 220 5 1.1 0.9;
+ 4734 1 0 0 0 25.339116 0 1.014516 -10.190708 380 5 1.1 0.9;
+ 4738 1 101.89 25.72 0 5.11 0 1.06866 -10.715961 220 5 1.1 0.9;
+ 4747 1 93.3 27.8 0 6.1 0 1.035644 -12.325346 220 5 1.1 0.9;
+ 4748 1 -0 -0 0 1.49 0 1.032136 -12.426948 220 5 1.1 0.9;
+ 4765 1 33.04 10.1 0 0.43 0 1.03734 -12.246628 220 5 1.1 0.9;
+ 4783 2 0 0 0 0 0 1.071981 8.277038 220 5 1.1 0.9;
+ 4787 1 71.98 27.1 0 7.2 0 0.99123 -14.709219 380 5 1.1 0.9;
+ 4816 2 0 0 0 0 0 1.067305 -23.812093 220 5 1.1 0.9;
+ 4819 2 0 0 0 0 0 1.031907 1.213157 380 5 1.1 0.9;
+ 4823 2 0 0 0 0 0 1.067114 -14.648331 220 5 1.1 0.9;
+ 4826 1 103.6 16 0 11.22 0 1.076968 -24.357644 220 5 1.1 0.9;
+ 4829 1 171.9 39.1 0 4.23 0 1.020877 -5.66958 220 5 1.1 0.9;
+ 4831 1 130.4 44.33 0 5.22 0 1.023656 -15.867691 220 5 1.1 0.9;
+ 4850 2 0 0 0 0 0 1.054975 -13.889155 220 5 1.1 0.9;
+ 4852 1 45.55 -59.9 0 30.04 0 1.040672 -20.328499 220 5 1.1 0.9;
+ 4864 1 -28.21 -6 0 0.05 0 1.037977 -12.814047 220 5 1.1 0.9;
+ 4867 1 65.77 27.3 0 0.49 0 1.031537 -3.407292 220 5 1.1 0.9;
+ 4874 1 -0.58 -53.03 0 6.85 0 1.07611 -39.379591 220 5 1.1 0.9;
+ 4880 2 0 0 0 0 0 1.034991 -15.897969 220 5 1.1 0.9;
+ 4885 1 166.4 50.4 0 1.23 0 1.074189 -26.349591 220 5 1.1 0.9;
+ 4889 1 74.98 19.8 0 6.47 0 1.034333 -12.232863 220 5 1.1 0.9;
+ 4907 1 125.16 29.2 0 2.69 0 1.041821 -13.302552 220 5 1.1 0.9;
+ 4908 1 50.06 9.9 0 11.56 0 1.037684 -21.273347 220 5 1.1 0.9;
+ 4914 1 14.91 -8.73 0 34.66 0 1.036628 -22.980806 220 5 1.1 0.9;
+ 4918 2 0 0 0 0 0 1.057325 -11.046567 220 5 1.1 0.9;
+ 4925 1 -0 0 0 0.3 0 1.036525 -22.48156 220 5 1.1 0.9;
+ 4936 1 312.2 28 0 48.6 0 1.049019 -30.699604 220 5 1.1 0.9;
+ 4939 1 56.76 31.1 0 0.37 0 1.043989 -4.549265 220 5 1.1 0.9;
+ 4942 1 109.9 33.6 0 3.72 0 1.028311 -12.898354 220 5 1.1 0.9;
+ 4950 1 218.7 -9.1 0 49 0 1.036717 -40.104666 220 5 1.1 0.9;
+ 4951 1 183.95 -6.47 0 5.74 0 1.053531 -1.663312 220 5 1.1 0.9;
+ 4952 2 0 0 0 0 0 1.045386 -17.502534 220 5 1.1 0.9;
+ 4970 1 -0 -0 0 171.931977 0 1.064315 -17.672609 380 5 1.1 0.9;
+ 4974 1 89.08 26.9 0 4.68 0 1.023886 -13.4778 220 5 1.1 0.9;
+ 5002 1 -0 0 0 4.34 0 1.071581 -8.674239 220 5 1.1 0.9;
+ 5003 1 17.87 -8.59 0 0.21 0 1.042135 -9.676575 220 5 1.1 0.9;
+ 5004 2 0 0 0 0 0 1.0663 -15.374553 220 5 1.1 0.9;
+ 5007 1 0 0 0 40.291745 0 1.021829 -15.303707 380 5 1.1 0.9;
+ 5016 1 -0 0 0 8.347383 0 1.02139 -5.019103 380 5 1.1 0.9;
+ 5019 2 0 0 0 0 0 1.047693 -12.9179 220 5 1.1 0.9;
+ 5049 1 136.6 29 0 2.05 0 1.01997 -20.429759 220 5 1.1 0.9;
+ 5051 2 0 0 0 0 0 1.037373 -16.452704 220 5 1.1 0.9;
+ 5067 2 0 0 0 0 0 1.021924 -7.972254 380 5 1.1 0.9;
+ 5077 1 30.93 5.8 0 4.45 0 1.055018 -26.635396 220 5 1.1 0.9;
+ 5083 1 80.39 10.8 0 0.35 0 1.039314 -12.19306 220 5 1.1 0.9;
+ 5093 1 70.78 28 0 1.49 0 1.010775 -14.861295 220 5 1.1 0.9;
+ 5099 1 0 0 0 9.34 0 1.058325 1.539585 220 5 1.1 0.9;
+ 5106 1 39.94 13 0 2.47 0 1.071273 -31.590024 220 5 1.1 0.9;
+ 5110 2 0 0 0 0 0 1.032061 -10.28337 220 5 1.1 0.9;
+ 5120 2 0 0 0 0 0 1.055539 -23.597086 220 5 1.1 0.9;
+ 5131 1 -0 0 0 7.84 0 1.074641 -26.336733 220 5 1.1 0.9;
+ 5137 1 16.92 0 0 0.57 0 1.025017 -16.369795 220 5 1.1 0.9;
+ 5144 2 0 0 0 0 0 1.035201 -3.127844 380 5 1.1 0.9;
+ 5146 1 229.9 48.9 0 8.36 0 1.01309 -34.0847 220 5 1.1 0.9;
+ 5174 1 0 -0 0 8.19 0 1.045055 -21.030104 220 5 1.1 0.9;
+ 5179 1 179.8 5.67 0 12.83 0 1.049521 -30.437104 220 5 1.1 0.9;
+ 5182 1 0 0 0 0.18 0 1.04247 -7.991956 220 5 1.1 0.9;
+ 5212 1 -0 0 0 0.2 0 1.043532 -11.000335 220 5 1.1 0.9;
+ 5213 1 246.8 36.3 0 16.01 0 1.046557 -26.37211 220 5 1.1 0.9;
+ 5215 1 -0 -0 0 0.89 0 1.029858 -5.840941 220 5 1.1 0.9;
+ 5233 1 -0 -0 0 14.04 0 1.040607 -10.965139 220 5 1.1 0.9;
+ 5237 2 0 0 0 0 0 1.052719 -14.75067 220 5 1.1 0.9;
+ 5241 1 0 -0 0 70.905048 0 1.030298 -3.61649 380 5 1.1 0.9;
+ 5256 1 91 36 0 5.47 0 1.00434 -16.654648 220 5 1.1 0.9;
+ 5257 1 -0 0 0 0.18 0 1.04776 -6.282341 220 5 1.1 0.9;
+ 5270 1 -0 -0 0 7.4 0 1.040679 -21.118583 220 5 1.1 0.9;
+ 5278 2 0 0 0 0 0 1.042037 -24.259299 220 5 1.1 0.9;
+ 5286 1 17.22 5.1 0 0.99 0 1.037376 -22.164674 220 5 1.1 0.9;
+ 5288 1 -0 -0 0 3.06 0 0.998946 -15.122249 380 5 1.1 0.9;
+ 5297 1 55.26 11 0 7.68 0 1.041403 -24.362719 220 5 1.1 0.9;
+ 5300 1 -0 -0 0 1.3 0 1.045246 -10.990672 220 5 1.1 0.9;
+ 5308 1 0 -0 0 42.19206 0 0.984486 -18.190432 380 5 1.1 0.9;
+ 5317 1 293.2 87.4 0 26.36 0 1.028707 -44.346536 220 5 1.1 0.9;
+ 5334 1 17.52 6.6 0 3.79 0 1.033829 -12.746707 220 5 1.1 0.9;
+ 5340 2 0 0 0 0 0 1.054941 -11.154638 220 5 1.1 0.9;
+ 5341 1 64.27 17.5 0 0.43 0 1.011142 -21.65338 220 5 1.1 0.9;
+ 5350 1 0 0 0 28.208233 0 0.981529 -24.398889 380 5 1.1 0.9;
+ 5351 1 0 0 0 3.28 0 1.034562 -14.13742 220 5 1.1 0.9;
+ 5354 1 70.18 19.5 0 3.59 0 1.045497 -8.643995 220 5 1.1 0.9;
+ 5362 1 152.73 -17.2 0 45.85 0 1.043688 -24.235922 220 5 1.1 0.9;
+ 5365 2 0 0 0 0 0 1.061754 -11.4194 220 5 1.1 0.9;
+ 5379 2 0 0 0 0 0 1.107976 -6.815844 380 5 1.3 0.7;
+ 5383 1 0 -0 0 24.7 0 1.048549 -24.463345 220 5 1.1 0.9;
+ 5388 1 159.5 42 0 2.3 0 1.013391 -14.763695 220 5 1.1 0.9;
+ 5393 1 -0 0 0 9.43 0 1.065867 -15.42107 220 5 1.1 0.9;
+ 5395 2 0 0 0 0 0 1.048137 -27.33134 220 5 1.1 0.9;
+ 5400 1 241.62 52.78 0 0.82 0 1.025608 -14.012865 220 5 1.1 0.9;
+ 5410 1 69.78 26 0 5.18 0 1.045719 -21.375392 220 5 1.1 0.9;
+ 5413 1 -0 -0 0 5.57 0 1.036008 -18.03631 220 5 1.1 0.9;
+ 5417 1 32.74 5.3 0 3.07 0 1.057776 -12.050099 220 5 1.1 0.9;
+ 5418 1 -0 0 0 3.96 0 1.037717 -21.273778 220 5 1.1 0.9;
+ 5419 1 349.3 144.3 0 0.54 0 1.021201 -15.134475 220 5 1.1 0.9;
+ 5420 1 56.96 1.94 0 26.48 0 1.024419 -22.859247 380 5 1.1 0.9;
+ 5421 1 -0 -0 0 0.92 0 0.998945 -15.122174 380 5 1.1 0.9;
+ 5441 1 138.01 34.55 0 8.44 0 1.037781 -2.820227 220 5 1.1 0.9;
+ 5455 1 -0 -0 0 5.27 0 1.042465 -7.991918 220 5 1.1 0.9;
+ 5458 1 0 0 0 9.09 0 1.038913 -21.424694 220 5 1.1 0.9;
+ 5460 1 -15.89 -6.42 0 38.657071 0 0.992989 -17.9255 380 5 1.1 0.9;
+ 5461 2 0 0 0 0 0 1.06213 -18.41436 380 5 1.1 0.9;
+ 5469 1 106.6 -18.8 0 4.1 0 1.067374 -38.727555 220 5 1.1 0.9;
+ 5477 1 -0 -0 0 18.02 0 1.075392 -26.166931 220 5 1.1 0.9;
+ 5481 2 0 0 0 0 0 1.063711 -8.933875 380 5 1.1 0.9;
+ 5482 2 0 0 0 0 0 1.044486 -7.317519 220 5 1.1 0.9;
+ 5486 2 0 0 0 0 0 1.059636 4.495854 380 5 1.1 0.9;
+ 5488 2 0 0 0 0 0 1.041881 -29.8855 220 5 1.1 0.9;
+ 5490 2 0 0 0 0 0 1.068845 -15.202054 380 5 1.1 0.9;
+ 5502 1 -0 -0 0 0.58 0 1.038483 -20.512891 220 5 1.1 0.9;
+ 5519 1 0 -0 0 1.98 0 1.048798 -24.5238 220 5 1.1 0.9;
+ 5522 1 -0 -0 0 1.18 0 1.068862 0.701223 220 5 1.1 0.9;
+ 5525 1 236.33 59.35 0 18.71 0 1.03913 -14.017648 220 5 1.1 0.9;
+ 5529 1 0 0 0 0.36 0 1.037801 -2.820407 220 5 1.1 0.9;
+ 5533 2 0 0 0 0 0 1.038212 -13.663692 220 5 1.1 0.9;
+ 5546 2 0 0 0 0 0 1.05378 -23.67431 220 5 1.1 0.9;
+ 5550 1 0 -0 0 10.83 0 1.051152 -25.756092 220 5 1.1 0.9;
+ 5564 2 0 0 0 0 0 1.04123 -12.598948 220 5 1.1 0.9;
+ 5567 1 0 0 0 3.59 0 1.017813 -18.930548 220 5 1.1 0.9;
+ 5571 1 -0 0 0 1.01 0 1.036516 -22.481578 220 5 1.1 0.9;
+ 5573 1 0 -0 0 2.94 0 1.05903 -23.279891 220 5 1.1 0.9;
+ 5574 1 99.7 6 0 2.06 0 1.03922 -11.857544 220 5 1.1 0.9;
+ 5586 1 -0 0 0 0 0 1.057299 2.403578 220 5 1.1 0.9;
+ 5589 1 0 0 0 173.904854 0 1.034874 -30.808253 380 5 1.1 0.9;
+ 5610 1 99.5 9.2 0 27.55 0 1.045824 -24.167858 220 5 1.1 0.9;
+ 5616 1 225.2 35.2 0 11.99 0 1.076287 -35.225281 220 5 1.1 0.9;
+ 5627 1 -0 -0 0 0.53 0 1.030337 -32.491502 220 5 1.1 0.9;
+ 5630 1 0 0 0 11.52 0 1.043599 -4.085534 220 5 1.1 0.9;
+ 5641 1 -0 -0 0 5.98 0 1.049836 -26.047052 220 5 1.1 0.9;
+ 5648 1 -0 -0 0 115.528858 0 0.995233 -13.451687 380 5 1.1 0.9;
+ 5653 1 96.59 7.28 0 2.52 0 1.045504 -7.661043 220 5 1.1 0.9;
+ 5658 2 0 0 0 0 0 1.017689 -23.66504 380 5 1.1 0.9;
+ 5664 2 0 0 0 0 0 1.070507 0.956534 220 5 1.1 0.9;
+ 5666 1 124.8 34.7 0 3.66 0 1.046065 -10.74401 220 5 1.1 0.9;
+ 5686 1 52.26 19.6 0 2.64 0 1.030503 -10.223727 220 5 1.1 0.9;
+ 5688 1 14.12 5.2 0 1.44 0 1.033877 -8.079704 220 5 1.1 0.9;
+ 5691 1 195.1 -14.2 0 12.89 0 1.061392 -45.226837 220 5 1.1 0.9;
+ 5695 1 142.8 20.3 0 6.77 0 1.047646 -27.137982 220 5 1.1 0.9;
+ 5699 1 -0 0 0 0.59 0 1.049081 -6.522248 220 5 1.1 0.9;
+ 5709 2 0 0 0 0 0 1.027078 -8.525839 380 5 1.1 0.9;
+ 5712 1 183.07 44.65 0 2.77 0 1.0445 -4.578143 220 5 1.1 0.9;
+ 5720 1 337.6 -15.4 0 6.27 0 1.045667 -24.989207 220 5 1.1 0.9;
+ 5723 1 141.2 45.4 0 7.55 0 1.045129 -9.640756 220 5 1.1 0.9;
+ 5735 1 161.3 10.04 0 4.38 0 1.060348 -26.902429 220 5 1.1 0.9;
+ 5738 1 -0 -0 0 8.13 0 1.013795 -10.544291 220 5 1.1 0.9;
+ 5743 1 -0 0 0 4.28 0 1.052165 -24.123493 220 5 1.1 0.9;
+ 5753 1 -0 -0 0 1.81 0 1.033984 -3.213627 220 5 1.1 0.9;
+ 5764 1 99.4 4.3 0 3.69 0 1.034962 -25.335623 220 5 1.1 0.9;
+ 5781 2 0 0 0 0 0 1.0396 -11.754534 380 5 1.1 0.9;
+ 5789 1 0 0 0 0.35 0 1.005562 -16.021128 220 5 1.1 0.9;
+ 5799 1 -0 -0 0 1.38 0 1.043907 -32.265811 220 5 1.1 0.9;
+ 5803 1 0 -0 0 0.35 0 1.043774 -14.004171 220 5 1.1 0.9;
+ 5814 2 0 0 0 0 0 1.044051 -11.822108 220 5 1.1 0.9;
+ 5836 1 244.09 48.92 0 5.96 0 1.040266 -12.0279 220 5 1.1 0.9;
+ 5837 1 -0 -0 0 132.04744 0 1.019818 -10.148769 380 5 1.1 0.9;
+ 5853 1 122.5 38.9 0 0.84 0 1.042789 -7.464608 220 5 1.1 0.9;
+ 5856 2 0 0 0 0 0 1.038417 -11.615407 220 5 1.1 0.9;
+ 5857 1 78.39 21.2 0 0.97 0 1.057665 -21.071135 220 5 1.1 0.9;
+ 5881 2 0 0 0 0 0 1.065605 -10.395605 220 5 1.1 0.9;
+ 5891 1 14.02 5.5 0 3.3 0 1.036617 -12.108533 220 5 1.1 0.9;
+ 5907 1 186.1 14.8 0 17.28 0 1.046917 -8.47729 220 5 1.1 0.9;
+ 5918 1 73.83 16.41 0 15.77 0 1.053364 -25.787722 220 5 1.1 0.9;
+ 5926 1 0 -0 0 3.98 0 1.072067 -47.920607 220 5 1.1 0.9;
+ 5935 1 -0 0 0 5.75 0 1.065025 -22.144776 220 5 1.1 0.9;
+ 5940 2 0 0 0 0 0 1.030075 -14.582177 220 5 1.1 0.9;
+ 5944 1 71.88 21.7 0 9.63 0 1.059622 -25.872698 220 5 1.1 0.9;
+ 5957 1 208.06 36.6 0 3.55 0 1.025527 -16.209872 220 5 1.1 0.9;
+ 5971 2 0 0 0 0 0 1.070056 4.938459 380 5 1.3 0.7;
+ 5983 2 0 0 0 0 0 1.066029 -14.886912 380 5 1.1 0.9;
+ 5987 1 24.04 1.68 0 4.02 0 1.036825 -13.937479 220 5 1.1 0.9;
+ 5990 1 0 -0 0 4.53 0 1.023107 -10.218557 220 5 1.1 0.9;
+ 5993 1 0 -0 0 2.75 0 1.043528 -11.000279 220 5 1.1 0.9;
+ 5994 2 0 0 0 0 0 1.029184 -15.420668 220 5 1.1 0.9;
+ 6010 1 0 0 0 1.35 0 1.08135 -23.128077 220 5 1.1 0.9;
+ 6031 1 0 0 0 2.22 0 1.041572 -15.751421 220 5 1.1 0.9;
+ 6036 2 0 0 0 0 0 1.043738 -0.899698 380 5 1.1 0.9;
+ 6041 1 0 0 0 0.53 0 1.072109 -47.920883 220 5 1.1 0.9;
+ 6053 1 412.1 79.3 0 7.73 0 1.058134 -26.592239 220 5 1.1 0.9;
+ 6071 1 163.5 35.6 0 4.59 0 1.035726 -16.340255 220 5 1.1 0.9;
+ 6101 1 103 40.2 0 1.13 0 1.02679 -10.858615 220 5 1.1 0.9;
+ 6104 1 93.12 4.99 0 0.18 0 1.056405 -12.076426 220 5 1.1 0.9;
+ 6110 1 78.59 16 0 1.87 0 1.056871 -35.945281 220 5 1.1 0.9;
+ 6112 1 45.28 15.27 0 7.88 0 1.024189 -9.306431 220 5 1.1 0.9;
+ 6114 1 0 0 0 8.78 0 1.048769 -10.298802 220 5 1.1 0.9;
+ 6115 1 -0 -0 0 1.18 0 1.02848 -11.273668 220 5 1.1 0.9;
+ 6119 1 221.25 72.56 0 8.23 0 1.039102 -15.995867 220 5 1.1 0.9;
+ 6146 1 0 -0 0 3.15 0 1.028373 -12.079992 220 5 1.1 0.9;
+ 6151 1 60.67 33.2 0 0.31 0 1.032517 -24.013495 220 5 1.1 0.9;
+ 6153 2 0 0 0 0 0 0.988112 -14.90068 380 5 1.1 0.9;
+ 6163 1 0 -0 0 4.96 0 1.036223 -21.959198 220 5 1.1 0.9;
+ 6168 2 0 0 0 0 0 1.040343 -13.438292 220 5 1.1 0.9;
+ 6178 1 91 28.4 0 10.57 0 1.040244 -24.602196 220 5 1.1 0.9;
+ 6194 1 0 -0 0 3.14 0 1.026211 -16.329018 220 5 1.1 0.9;
+ 6199 1 -4.82 -0.88 0 224.85 0 1.072632 -12.599054 380 5 1.1 0.9;
+ 6203 1 14.02 5.6 0 2.34 0 1.070264 -27.353716 220 5 1.1 0.9;
+ 6206 1 -7.62 -2.52 0 33.197994 0 1.037591 0.03956 380 5 1.1 0.9;
+ 6219 1 -0 -0 0 0.22 0 1.033837 -12.746776 220 5 1.1 0.9;
+ 6220 1 231.9 27.6 0 0.36 0 1.055297 -22.931727 220 5 1.1 0.9;
+ 6224 1 0 0 0 58.990785 0 1.000545 -12.907246 380 5 1.1 0.9;
+ 6231 1 -0 0 0 11.5 0 1.034263 -8.032463 220 5 1.1 0.9;
+ 6232 1 49.25 12 0 7.28 0 1.042941 -25.794518 220 5 1.1 0.9;
+ 6240 1 0 -0 0 6.31 0 1.075696 -34.242457 220 5 1.1 0.9;
+ 6246 1 1769.94 -353.95 0 62.59 0 1.045739 -36.412972 380 5 1.1 0.9;
+ 6252 1 164.7 44.5 0 3.67 0 1.020382 -29.885564 220 5 1.1 0.9;
+ 6253 1 128.8 29.3 0 26.74 0 1.04318 -25.753603 220 5 1.1 0.9;
+ 6267 1 91.3 18.1 0 3.05 0 1.041192 -24.394509 220 5 1.1 0.9;
+ 6271 1 3.7 2.6 0 4.45 0 1.054472 -20.10439 220 5 1.1 0.9;
+ 6290 1 47.65 20.4 0 3.63 0 1.062557 -12.82926 220 5 1.1 0.9;
+ 6291 2 0 0 0 0 0 1.040598 -23.840293 220 5 1.1 0.9;
+ 6306 1 0 -0 0 2.13 0 1.077228 -24.297873 220 5 1.1 0.9;
+ 6308 1 0 -0 0 0.05 0 1.044666 -25.545467 220 5 1.1 0.9;
+ 6313 1 48.95 14.9 0 4.04 0 1.033893 -23.915745 220 5 1.1 0.9;
+ 6331 2 0 0 0 0 0 1.052181 -0.845895 220 5 1.1 0.9;
+ 6332 2 0 0 0 0 0 1.062214 -11.259336 220 5 1.1 0.9;
+ 6337 1 0 0 0 8.26 0 1.090736 -9.663194 380 5 1.1 0.9;
+ 6351 2 0 0 0 0 0 1.064446 -16.194964 220 5 1.1 0.9;
+ 6357 1 430.8 107.9 0 11.64 0 0.986449 -24.787083 220 5 1.1 0.9;
+ 6368 2 0 0 0 0 0 1.043835 -8.297319 220 5 1.1 0.9;
+ 6371 1 -0 -0 0 0.35 0 1.04624 -0.834636 220 5 1.1 0.9;
+ 6376 2 0 0 0 0 0 1.046714 -0.304027 220 5 1.1 0.9;
+ 6382 1 75.43 10.49 0 7.91 0 1.042008 -9.653397 220 5 1.1 0.9;
+ 6384 1 159.9 47.4 0 3.65 0 1.042953 -1.650086 220 5 1.1 0.9;
+ 6405 1 76.48 19.8 0 5.41 0 1.016603 -16.051975 220 5 1.1 0.9;
+ 6416 1 67.67 16.4 0 3.7 0 1.044399 -9.544276 220 5 1.1 0.9;
+ 6426 1 10.21 3.8 0 4.6 0 1.054991 1.525091 220 5 1.1 0.9;
+ 6427 1 83.19 22.9 0 28.5 0 1.00477 -13.123224 380 5 1.1 0.9;
+ 6429 2 0 0 0 0 0 1.039574 -18.343476 220 5 1.1 0.9;
+ 6430 1 0 -0 0 6.03 0 1.052192 -28.928753 220 5 1.1 0.9;
+ 6450 1 5.51 2.1 0 1.92 0 1.010198 -10.933937 220 5 1.1 0.9;
+ 6455 1 20.52 13.3 0 0.17 0 1.038267 -22.056487 220 5 1.1 0.9;
+ 6472 1 0 -0 0 9.93 0 1.042806 -24.004462 220 5 1.1 0.9;
+ 6474 2 0 0 0 0 0 1.06557 -7.808697 220 5 1.1 0.9;
+ 6475 1 -0 0 0 149.047157 0 1.026549 -8.701988 380 5 1.1 0.9;
+ 6478 1 141.2 34.8 0 2.37 0 1.012128 -14.390515 220 5 1.1 0.9;
+ 6486 1 31.74 17.4 0 0.89 0 1.048545 -3.989815 220 5 1.1 0.9;
+ 6495 1 49.66 12.3 0 2.2 0 1.043059 -21.768062 220 5 1.1 0.9;
+ 6510 1 88.2 26.7 0 8.91 0 1.050118 -26.338765 220 5 1.1 0.9;
+ 6516 2 0 0 0 0 0 1.052452 -3.60194 220 5 1.1 0.9;
+ 6521 1 0 0 0 2.3 0 1.046651 -4.738353 220 5 1.1 0.9;
+ 6532 1 120.69 18.1 0 15.46 0 1.075728 -31.435419 220 5 1.1 0.9;
+ 6552 2 0 0 0 0 0 1.048796 -21.140924 220 5 1.1 0.9;
+ 6555 1 -37.81 -21.64 0 83.362314 0 1.008884 -43.693382 380 5 1.1 0.9;
+ 6556 1 -0 -0 0 4.61 0 1.052054 -12.679594 220 5 1.1 0.9;
+ 6563 1 0 -0 0 8.94 0 1.040617 -24.64966 220 5 1.1 0.9;
+ 6565 1 0 -0 0 4.05 0 1.033616 -7.247992 220 5 1.1 0.9;
+ 6570 1 -0 0 0 32.43 0 1.045563 -20.766442 220 5 1.1 0.9;
+ 6581 1 153.8 23.4 0 87.73 0 1.042943 -2.447442 380 5 1.1 0.9;
+ 6612 1 41.14 15.25 0 3.96 0 1.047964 -31.701384 220 5 1.1 0.9;
+ 6616 1 -0 -0 0 3.06 0 1.044855 -15.904052 220 5 1.1 0.9;
+ 6619 1 -0 -0 0 10.67 0 1.050275 -15.385558 220 5 1.1 0.9;
+ 6624 1 -37.33 -11.88 0 145.18 0 1.058707 4.26077 380 5 1.1 0.9;
+ 6629 1 62.63 16.3 0 2.03 0 1.054419 -11.400101 220 5 1.1 0.9;
+ 6630 1 134.1 24.8 0 13.73 0 1.039511 -24.152951 220 5 1.1 0.9;
+ 6636 1 -0 0 0 0.31 0 1.036596 0.577218 220 5 1.1 0.9;
+ 6638 1 61.65 10.24 0 3.48 0 1.020424 -14.95076 220 5 1.1 0.9;
+ 6639 1 388.04 52.61 0 2.87 0 1.050408 -2.453064 220 5 1.1 0.9;
+ 6648 1 -26.03 -0.84 0 0.1 0 1.06183 -11.406171 220 5 1.1 0.9;
+ 6664 1 -0 0 0 10.68 0 1.06971 -46.294482 220 5 1.1 0.9;
+ 6675 1 37.94 7.5 0 11.89 0 1.035344 -23.290216 220 5 1.1 0.9;
+ 6684 1 -0 0 0 9.84 0 1.044665 -25.545459 220 5 1.1 0.9;
+ 6691 1 42.55 12.5 0 1.26 0 1.083988 -34.063221 220 5 1.1 0.9;
+ 6692 1 10.33 3.3 0 4.65 0 1.02441 -15.580999 220 5 1.1 0.9;
+ 6697 1 309 74.5 0 3.69 0 1.0463 -37.100468 220 5 1.1 0.9;
+ 6714 1 -0 -0 0 0.3 0 1.046238 -0.834605 220 5 1.1 0.9;
+ 6723 1 0 0 0 1.58 0 1.032514 -9.464819 220 5 1.1 0.9;
+ 6730 1 -0 0 0 2.18 0 1.038253 -21.079078 220 5 1.1 0.9;
+ 6734 2 0 0 0 0 0 1.061492 -3.472634 220 5 1.1 0.9;
+ 6735 1 -0 -0 0 0.4 0 1.041984 -1.292675 380 5 1.1 0.9;
+ 6737 1 0 -0 0 9.74 0 1.021139 -10.532887 220 5 1.1 0.9;
+ 6738 1 -4.91 -2.53 0 120.576812 0 1.029435 -24.781868 380 5 1.1 0.9;
+ 6742 1 137.4 23.9 0 7.26 0 1.037902 -21.502542 220 5 1.1 0.9;
+ 6744 1 244.12 95.29 0 7.55 0 1.033513 -10.221422 220 5 1.1 0.9;
+ 6757 1 0 0 0 6.57 0 1.040789 -1.178761 380 5 1.1 0.9;
+ 6763 1 0 -0 0 5.46 0 1.043751 -24.236704 220 5 1.1 0.9;
+ 6772 1 61.37 23.2 0 0.22 0 1.045385 -24.09701 220 5 1.1 0.9;
+ 6773 1 0 -0 0 2.18 0 1.041981 -24.273746 220 5 1.1 0.9;
+ 6785 1 0 0 0 8.9 0 1.054082 -0.784591 220 5 1.1 0.9;
+ 6791 1 46.35 9.1 0 18.2 0 1.04692 -25.227196 220 5 1.1 0.9;
+ 6802 1 -0 0 0 7.43 0 1.034691 -6.054841 220 5 1.1 0.9;
+ 6806 1 135.84 15.97 0 4.57 0 1.046591 -21.264934 220 5 1.1 0.9;
+ 6807 2 0 0 0 0 0 1.006037 -16.618507 220 5 1.1 0.9;
+ 6816 2 0 0 0 0 0 1.053803 -24.150678 220 5 1.1 0.9;
+ 6820 2 0 0 0 0 0 1.049557 -6.650937 220 5 1.1 0.9;
+ 6828 1 58.16 16.5 0 6.24 0 1.037156 -13.39716 220 5 1.1 0.9;
+ 6831 2 0 0 0 0 0 1.031347 -9.785828 220 5 1.1 0.9;
+ 6837 1 47.75 11 0 0.05 0 1.050311 -7.914424 220 5 1.1 0.9;
+ 6842 1 98 21.7 0 6 0 1.037762 -8.446373 220 5 1.1 0.9;
+ 6844 1 -0 -0 0 1.04 0 1.015966 -29.284947 220 5 1.1 0.9;
+ 6845 2 0 0 0 0 0 1.055216 -11.135397 220 5 1.1 0.9;
+ 6846 1 44.35 19.3 0 3.25 0 1.053078 -4.617698 220 5 1.1 0.9;
+ 6852 2 0 0 0 0 0 1.031296 -19.801967 220 5 1.1 0.9;
+ 6854 1 0 0 0 0 0 1.054902 -11.343079 220 5 1.1 0.9;
+ 6857 2 0 0 0 0 0 1.021411 -8.599284 380 5 1.1 0.9;
+ 6880 1 0 0 0 1.36 0 1.045265 -4.460667 220 5 1.1 0.9;
+ 6887 1 -0 -0 0 3.13 0 1.045229 -3.097099 220 5 1.1 0.9;
+ 6888 2 0 0 0 0 0 1.039234 -13.670722 220 5 1.1 0.9;
+ 6889 1 -12.49 -5.83 0 6.235224 0 1.040018 2.414551 380 5 1.1 0.9;
+ 6891 1 135.61 26.86 0 1.93 0 1.042154 -14.327292 220 5 1.1 0.9;
+ 6897 1 176.8 39.4 0 28.24 0 1.05642 -16.592196 380 5 1.1 0.9;
+ 6901 1 -37.84 -19.23 0 28.140258 0 1.010989 -32.14614 380 5 1.1 0.9;
+ 6908 1 0 0 0 3.01 0 1.037832 -40.113954 220 5 1.1 0.9;
+ 6909 1 122.5 8.7 0 15.85 0 1.036123 -23.128738 220 5 1.1 0.9;
+ 6921 1 -37.34 -13.33 0 251.529665 0 1.036075 -1.608828 380 5 1.1 0.9;
+ 6922 1 113.6 44.7 0 1.91 0 1.036504 -8.622098 220 5 1.1 0.9;
+ 6926 1 124.5 101.4 0 0.53 0 1.033188 -12.416059 220 5 1.1 0.9;
+ 6940 1 0 -0 0 10.46 0 1.057214 -27.586432 220 5 1.1 0.9;
+ 6947 2 0 0 0 0 0 1.051367 -3.749893 220 5 1.1 0.9;
+ 6952 1 180.9 33.2 0 29.17 0 1.074941 -25.158601 220 5 1.1 0.9;
+ 6954 1 18.12 10 0 1.03 0 1.033937 -20.057453 220 5 1.1 0.9;
+ 6961 1 56.56 18.4 0 3.29 0 1.046702 -0.041292 220 5 1.1 0.9;
+ 6969 2 0 0 0 0 0 1.059486 -23.158005 220 5 1.1 0.9;
+ 6982 2 0 0 0 0 0 1.036531 -20.798066 220 5 1.1 0.9;
+ 6989 1 0 0 0 1.91 0 1.046262 -24.006134 220 5 1.1 0.9;
+ 6990 1 -0 0 0 4.54 0 1.049424 -24.091607 220 5 1.1 0.9;
+ 7014 1 0 0 0 0.3 0 1.042775 -2.603788 220 5 1.1 0.9;
+ 7019 1 52.56 12.8 0 2.87 0 1.042599 -25.81851 220 5 1.1 0.9;
+ 7021 1 226.8 53.3 0 3.26 0 1.00593 -17.187001 220 5 1.1 0.9;
+ 7030 1 0 0 0 0.19 0 1.065574 -7.808728 220 5 1.1 0.9;
+ 7036 2 0 0 0 0 0 1.041241 -12.591424 220 5 1.1 0.9;
+ 7042 1 220.98 91 0 1.16 0 1.05498 -30.089269 220 5 1.1 0.9;
+ 7047 1 339.9 70.5 0 28.91 0 1.036489 -21.901119 220 5 1.1 0.9;
+ 7049 2 0 0 0 0 0 1.049669 -14.344403 220 5 1.1 0.9;
+ 7050 1 120 26 0 22.01 0 1.037777 -21.239311 220 5 1.1 0.9;
+ 7052 1 111 36.6 0 2.21 0 1.047794 -12.393218 220 5 1.1 0.9;
+ 7056 2 0 0 0 0 0 1.006597 -4.279873 380 5 1.1 0.9;
+ 7069 1 258.79 42.82 0 9.28 0 1.041721 -7.971411 220 5 1.1 0.9;
+ 7070 1 142.9 25.8 0 24.18 0 1.051529 -13.392684 220 5 1.1 0.9;
+ 7076 1 0 -0 0 0.36 0 1.032543 -12.400826 220 5 1.1 0.9;
+ 7092 1 44.65 8.8 0 20.17 0 1.048118 -25.098572 220 5 1.1 0.9;
+ 7098 1 0 -0 0 7.17 0 1.040402 -2.260554 220 5 1.1 0.9;
+ 7115 2 0 0 0 0 0 1.008722 -16.289324 220 5 1.1 0.9;
+ 7119 1 149.53 34.9 0 8.9 0 1.011547 -16.3375 220 5 1.1 0.9;
+ 7124 1 -0 0 0 16.73 0 1.071843 -27.185513 220 5 1.1 0.9;
+ 7129 1 33.34 5 0 0.38 0 1.03765 -2.840915 220 5 1.1 0.9;
+ 7132 1 222 90.5 0 0.16 0 1.017449 -15.909765 220 5 1.1 0.9;
+ 7133 1 102.3 19 0 1.84 0 1.034901 -14.267058 220 5 1.1 0.9;
+ 7144 1 8.48 -1.82 0 0.37 0 1.03015 -13.008541 220 5 1.1 0.9;
+ 7148 1 -0 -0 0 10.89 0 1.050811 -23.312468 220 5 1.1 0.9;
+ 7159 2 0 0 0 0 0 1.059575 4.500856 380 5 1.1 0.9;
+ 7162 1 -0 0 0 2.48 0 1.051693 -13.395189 220 5 1.1 0.9;
+ 7163 1 -0 0 0 2.9 0 1.04999 -24.866445 220 5 1.1 0.9;
+ 7164 1 -18.6 -6.72 0 152.683271 0 1.027379 -22.063848 380 5 1.1 0.9;
+ 7165 1 -0 -0 0 9.26 0 1.071048 -34.202221 220 5 1.1 0.9;
+ 7178 1 -0 -0 0 2.45 0 1.017469 -14.250696 220 5 1.1 0.9;
+ 7183 2 0 0 0 0 0 1.107733 -6.868685 380 5 1.3 0.7;
+ 7202 1 18.62 6.1 0 2 0 1.050711 -3.937783 220 5 1.1 0.9;
+ 7209 2 0 0 0 0 0 1.051113 -6.533675 220 5 1.1 0.9;
+ 7222 1 0 -0 0 5 0 1.068964 -23.827934 220 5 1.1 0.9;
+ 7226 1 144 31.3 0 3.18 0 1.022196 -15.530828 220 5 1.1 0.9;
+ 7231 1 0 0 0 0.05 0 1.039985 -11.495627 220 5 1.1 0.9;
+ 7253 1 7.51 3.1 0 0 0 1.048698 -2.446191 220 5 1.1 0.9;
+ 7256 1 392.25 92.02 0 9.45 0 1.022568 -35.394958 220 5 1.1 0.9;
+ 7259 1 82.39 0 0 0.15 0 1.06537 -7.876917 220 5 1.1 0.9;
+ 7264 1 0 -0 0 3.42 0 1.042846 -10.973594 220 5 1.1 0.9;
+ 7266 1 -0 -0 0 2.12 0 1.032954 -5.485507 220 5 1.1 0.9;
+ 7267 2 0 0 0 0 0 1.010817 -7.692119 380 5 1.1 0.9;
+ 7273 1 219.6 36.4 0 17.89 0 1.042886 -24.322652 220 5 1.1 0.9;
+ 7274 1 54.93 16.5 0 6.75 0 1.040156 -3.899721 220 5 1.1 0.9;
+ 7282 2 0 0 0 0 0 1.034538 -4.68119 380 5 1.1 0.9;
+ 7284 1 0 0 0 0 0 1.094644 -0.869931 220 5 1.1 0.9;
+ 7289 1 0 -0 0 26.5 0 1.054049 -6.174395 220 5 1.1 0.9;
+ 7309 1 0 -0 0 1.32 0 1.054902 -11.343079 220 5 1.1 0.9;
+ 7316 1 -0 0 0 0.09 0 1.044717 -7.284069 220 5 1.1 0.9;
+ 7325 1 0 0 0 0.41 0 1.052061 -12.679657 220 5 1.1 0.9;
+ 7327 2 0 0 0 0 0 1.043172 -18.073929 220 5 1.1 0.9;
+ 7328 2 0 0 0 0 0 0.999675 -14.476061 380 5 1.1 0.9;
+ 7338 1 0 -0 0 2.98 0 1.045891 -14.743514 220 5 1.1 0.9;
+ 7341 1 37.44 0 0 0.67 0 1.040136 -2.402429 220 5 1.1 0.9;
+ 7342 1 169 70.8 0 5.23 0 1.018398 -16.108009 220 5 1.1 0.9;
+ 7351 1 61.67 16.3 0 0.05 0 1.037551 -2.8443 220 5 1.1 0.9;
+ 7353 1 127.3 26.7 0 7.02 0 0.985936 -22.42059 220 5 1.1 0.9;
+ 7361 1 -0 -0 0 14.29 0 1.053815 -15.271705 220 5 1.1 0.9;
+ 7367 1 1.5 0.4 0 0.15 0 1.028631 -18.905659 220 5 1.1 0.9;
+ 7373 1 0 -0 0 1.81 0 1.071954 -23.60091 220 5 1.1 0.9;
+ 7377 1 0 0 0 0.63 0 1.014168 -16.130077 220 5 1.1 0.9;
+ 7380 1 105.67 0.56 0 18.05 0 0.992016 -14.57117 380 5 1.1 0.9;
+ 7396 1 -0 0 0 5.68 0 1.019741 -19.557023 220 5 1.1 0.9;
+ 7422 1 65.67 25.6 0 2.34 0 1.033674 -10.805957 220 5 1.1 0.9;
+ 7437 1 18.32 5.3 0 7.32 0 1.04383 -25.64578 220 5 1.1 0.9;
+ 7438 1 121.3 20.7 0 2.39 0 1.035924 -12.727575 220 5 1.1 0.9;
+ 7464 1 197.65 28.23 0 5.87 0 1.041056 -12.617278 220 5 1.1 0.9;
+ 7466 2 0 0 0 0 0 1.057257 -34.871885 220 5 1.1 0.9;
+ 7471 1 -18.95 -6.93 0 33.11439 0 1.020554 -6.279485 380 5 1.1 0.9;
+ 7473 1 113.44 71.42 0 11.08 0 1.035336 -16.025005 220 5 1.1 0.9;
+ 7474 2 0 0 0 0 0 1.027108 -14.200631 220 5 1.1 0.9;
+ 7485 1 44.35 10.8 0 8.72 0 1.042606 -25.826706 220 5 1.1 0.9;
+ 7491 1 0 -0 0 4.29 0 1.012242 -21.474958 220 5 1.1 0.9;
+ 7495 2 0 0 0 0 0 1.035256 -15.196734 220 5 1.1 0.9;
+ 7507 1 4 0.8 0 17.65 0 1.04914 -24.08765 220 5 1.1 0.9;
+ 7513 1 0 -0 0 38.549494 0 0.993009 -15.030612 380 5 1.1 0.9;
+ 7519 1 97.97 31.8 0 5.02 0 1.036786 -10.798224 220 5 1.1 0.9;
+ 7520 2 0 0 0 0 0 1.037447 -9.123264 380 5 1.1 0.9;
+ 7522 2 0 0 0 0 0 0.99994 -10.953994 380 5 1.1 0.9;
+ 7523 1 -0 0 0 2.11 0 1.052161 -0.72038 220 5 1.1 0.9;
+ 7530 1 0 0 0 31.242294 0 1.046869 -19.820201 380 5 1.1 0.9;
+ 7537 1 0 0 0 17.184121 0 0.989983 -15.6248 380 5 1.1 0.9;
+ 7539 1 40.85 15.7 0 2.08 0 1.053724 -12.373239 220 5 1.1 0.9;
+ 7541 1 346.42 89.04 0 43.55 0 1.054084 -16.465783 380 5 1.1 0.9;
+ 7571 1 -0 -0 0 13.9 0 1.044943 -13.985525 220 5 1.1 0.9;
+ 7576 1 0 0 0 0.5 0 1.04028 -12.028046 220 5 1.1 0.9;
+ 7577 1 0 0 0 6.69 0 1.0481 -10.467484 220 5 1.1 0.9;
+ 7579 1 136.9 11.4 0 3.05 0 1.048022 -26.50227 220 5 1.1 0.9;
+ 7580 1 0 0 0 0.17 0 1.05695 -11.9558 220 5 1.1 0.9;
+ 7582 1 0 -0 0 3.44 0 1.035758 -24.450751 220 5 1.1 0.9;
+ 7583 1 5.01 1.8 0 3.68 0 1.04744 -0.936009 220 5 1.1 0.9;
+ 7599 1 0 -0 0 2.13 0 1.034704 -6.055108 220 5 1.1 0.9;
+ 7624 1 32.74 10.5 0 1.78 0 1.01592 -20.903943 220 5 1.1 0.9;
+ 7626 1 78.89 45.6 0 0.04 0 1.032312 -12.417124 220 5 1.1 0.9;
+ 7635 1 0 0 0 1.86 0 1.050003 -7.891572 220 5 1.1 0.9;
+ 7640 1 68.78 35 0 34.52 0 1.033083 -6.005598 380 5 1.1 0.9;
+ 7641 2 0 0 0 0 0 1.051427 -6.243524 220 5 1.1 0.9;
+ 7647 1 -0 -0 0 0.1 0 1.063763 -20.174055 220 5 1.1 0.9;
+ 7653 1 33.94 11.4 0 0 0 1.0368 -22.767059 220 5 1.1 0.9;
+ 7663 1 37.14 2.7 0 2.33 0 1.042204 -11.956017 220 5 1.1 0.9;
+ 7691 1 0 -0 0 96.48 0 1.026843 -3.944271 380 5 1.1 0.9;
+ 7694 1 -14.96 -4.7 0 0.04 0 1.027078 -14.861465 220 5 1.1 0.9;
+ 7697 2 0 0 0 0 0 1.052424 -3.583012 220 5 1.1 0.9;
+ 7700 1 66.17 27.4 0 14.12 0 1.018432 -10.528155 220 5 1.1 0.9;
+ 7702 1 -0 -0 0 11.68 0 1.025153 -16.313747 220 5 1.1 0.9;
+ 7726 1 0 0 0 2.03 0 1.018323 -10.493485 220 5 1.1 0.9;
+ 7738 1 31.84 9.2 0 5.23 0 1.027755 -21.847912 220 5 1.1 0.9;
+ 7752 1 524.5 126 0 7.45 0 1.03043 -18.412915 220 5 1.1 0.9;
+ 7766 1 78.89 25.6 0 1.6 0 1.033279 -12.689648 220 5 1.1 0.9;
+ 7770 1 207.9 32.36 0 8.31 0 1.031073 -44.333742 220 5 1.1 0.9;
+ 7772 1 223.6 51.8 0 18.45 0 1.053846 -25.615931 220 5 1.1 0.9;
+ 7775 1 151.5 7.9 0 5 0 1.054984 -28.678026 220 5 1.1 0.9;
+ 7776 2 0 0 0 0 0 1.072261 6.181044 380 5 1.3 0.7;
+ 7778 1 153 21.5 0 28.85 0 1.057591 -16.510132 380 5 1.1 0.9;
+ 7791 1 -0 0 0 1.33 0 1.03015 -12.988362 220 5 1.1 0.9;
+ 7797 1 -0 -0 0 2.09 0 1.051084 -24.096828 220 5 1.1 0.9;
+ 7808 2 0 0 0 0 0 1.054562 -0.188042 380 5 1.1 0.9;
+ 7809 1 169.5 27.7 0 3.04 0 1.024952 -11.538551 220 5 1.1 0.9;
+ 7824 1 9.21 3.4 0 2.63 0 1.047756 -6.282298 220 5 1.1 0.9;
+ 7831 1 -17.17 -7.1 0 57.019803 0 1.011199 -11.417611 380 5 1.1 0.9;
+ 7840 1 -19.28 29.9 0 1.6 0 1.049049 -2.414341 220 5 1.1 0.9;
+ 7842 2 0 0 0 0 0 1.001912 -12.534976 380 5 1.1 0.9;
+ 7847 1 0 -0 0 1.55 0 1.040499 -8.878125 220 5 1.1 0.9;
+ 7857 1 0 0 0 2.36 0 1.050458 0.170436 220 5 1.1 0.9;
+ 7862 1 0 0 0 9.74 0 1.040593 -21.115869 220 5 1.1 0.9;
+ 7865 1 84.99 19.6 0 4.32 0 1.074298 -26.36902 220 5 1.1 0.9;
+ 7873 1 -20.94 -6.16 0 11.99 0 1.021235 -15.229234 220 5 1.1 0.9;
+ 7881 1 -0 -0 0 7.99 0 1.055617 -14.956341 220 5 1.1 0.9;
+ 7883 1 47.55 17.8 0 0.32 0 1.050929 -28.78941 220 5 1.1 0.9;
+ 7885 1 142.4 20 0 2.42 0 1.037839 -21.110646 220 5 1.1 0.9;
+ 7886 1 162.5 42.7 0 12.79 0 1.018149 -19.303853 220 5 1.1 0.9;
+ 7892 1 36.94 11 0 0.52 0 1.053815 -11.294264 220 5 1.1 0.9;
+ 7895 1 338.7 52.5 0 11.36 0 1.059845 -19.561088 220 5 1.1 0.9;
+ 7903 1 0 -0 0 7.78 0 1.072768 -41.998744 220 5 1.1 0.9;
+ 7905 1 347.1 87.2 0 88.35 0 1.046655 -17.893306 380 5 1.1 0.9;
+ 7913 2 0 0 0 0 0 1.063764 -8.906151 380 5 1.1 0.9;
+ 7923 1 0 -0 0 0.97 0 1.038632 -22.138858 220 5 1.1 0.9;
+ 7937 1 56.06 17 0 2.4 0 1.040168 -7.402075 220 5 1.1 0.9;
+ 7943 1 38.44 2 0 0.56 0 1.047179 -16.175311 220 5 1.1 0.9;
+ 7945 1 17.92 5.8 0 0.84 0 1.031087 -5.74962 220 5 1.1 0.9;
+ 7955 1 111.6 8.9 0 16.19 0 1.068312 -23.349161 220 5 1.1 0.9;
+ 7961 1 50.56 8.1 0 8.02 0 1.034289 -8.616758 220 5 1.1 0.9;
+ 7967 1 0 -0 0 5.97 0 1.043007 -11.416934 220 5 1.1 0.9;
+ 7972 1 237.9 68.5 0 5.12 0 1.035175 -19.298443 220 5 1.1 0.9;
+ 7974 1 234 13.1 0 51.03 0 1.033995 -20.055775 220 5 1.1 0.9;
+ 7982 1 112 19.7 0 38.04 0 1.036111 -23.13213 220 5 1.1 0.9;
+ 7988 1 -3.55 -1.43 0 11.834121 0 1.0339 -2.136803 380 5 1.1 0.9;
+ 7989 1 0 0 0 0.27 0 1.052062 -3.729978 220 5 1.1 0.9;
+ 7994 1 11.91 3.3 0 6.84 0 1.015764 -16.263273 220 5 1.1 0.9;
+ 7998 2 0 0 0 0 0 1.048854 4.223749 380 5 1.1 0.9;
+ 8005 1 -0 -0 0 16.77 0 1.027697 -13.719399 220 5 1.1 0.9;
+ 8030 1 -0 0 0 122.13 0 1.034376 -4.451962 380 5 1.1 0.9;
+ 8035 1 -0 0 0 4.22 0 1.023645 -16.359288 220 5 1.1 0.9;
+ 8043 2 0 0 0 0 0 1.066913 -11.239517 220 5 1.1 0.9;
+ 8057 1 69.18 9.5 0 3.67 0 1.045952 -8.643584 220 5 1.1 0.9;
+ 8060 1 0 -0 0 9.54 0 1.05168 -13.395033 220 5 1.1 0.9;
+ 8104 1 127.2 40.8 0 0.2 0 1.070946 -25.178857 220 5 1.1 0.9;
+ 8107 1 68.18 16.1 0 3.35 0 1.034732 -23.363006 220 5 1.1 0.9;
+ 8109 2 0 0 0 0 0 1.067387 -21.117921 380 5 1.1 0.9;
+ 8112 1 87.9 29.3 0 1.21 0 1.031544 -3.541639 220 5 1.1 0.9;
+ 8128 1 -0 0 0 8.1 0 1.090736 -9.663123 380 5 1.1 0.9;
+ 8151 1 0 0 0 14.23 0 1.044491 -25.577335 220 5 1.1 0.9;
+ 8158 2 0 0 0 0 0 1.052602 -0.559615 220 5 1.1 0.9;
+ 8165 1 0 -0 0 2.42 0 1.061504 -3.473077 220 5 1.1 0.9;
+ 8180 1 291.6 47 0 2.38 0 1.075394 -30.774767 220 5 1.1 0.9;
+ 8189 1 0 -0 0 9.54 0 1.042203 -18.144075 220 5 1.1 0.9;
+ 8190 1 0 -0 0 0.32 0 1.048784 -10.298904 220 5 1.1 0.9;
+ 8191 1 0 0 0 11.38 0 1.051859 -15.264149 220 5 1.1 0.9;
+ 8195 1 -101.01 -129.29 0 37.176703 0 1.02377 -17.045599 380 5 1.1 0.9;
+ 8200 1 0 -0 0 39.58 0 1.021119 -6.153606 380 5 1.1 0.9;
+ 8209 1 83.39 16.5 0 16.43 0 1.033486 -20.136338 220 5 1.1 0.9;
+ 8214 1 58.97 11.1 0 1.05 0 1.04259 -11.470366 220 5 1.1 0.9;
+ 8222 2 0 0 0 0 0 1.02335 -10.438616 380 5 1.1 0.9;
+ 8225 2 0 0 0 0 0 1.071504 -11.705551 220 5 1.1 0.9;
+ 8250 1 196.1 32.1 0 3.86 0 1.04037 -25.998622 220 5 1.1 0.9;
+ 8255 1 39.04 13.1 0 3.22 0 1.021879 -13.796655 220 5 1.1 0.9;
+ 8265 1 40.44 20.5 0 0.85 0 1.066641 -23.859918 220 5 1.1 0.9;
+ 8267 2 0 0 0 0 0 1.043326 -9.93055 380 5 1.1 0.9;
+ 8291 1 0 -0 0 6.52 0 1.043396 -7.697439 220 5 1.1 0.9;
+ 8293 1 112.7 14.5 0 1.24 0 1.048233 -24.806368 220 5 1.1 0.9;
+ 8294 1 14.22 6.3 0 0.38 0 1.043617 -11.857424 220 5 1.1 0.9;
+ 8307 1 -0 0 0 0.14 0 1.051092 -3.882875 220 5 1.1 0.9;
+ 8310 1 -0 0 0 2.46 0 1.049352 -8.638203 220 5 1.1 0.9;
+ 8311 2 0 0 0 0 0 1.035451 -15.519296 220 5 1.1 0.9;
+ 8312 2 0 0 0 0 0 1.07814 -12.220054 380 5 1.1 0.9;
+ 8316 1 0 0 0 0.72 0 1.084023 -26.486866 220 5 1.1 0.9;
+ 8328 1 82.39 14.4 0 13.37 0 1.041343 -24.415623 220 5 1.1 0.9;
+ 8331 1 -0 -0 0 0.05 0 1.047611 -12.932386 220 5 1.1 0.9;
+ 8334 1 263.96 -98.64 0 27.848535 0 1.034142 -14.749149 380 5 1.1 0.9;
+ 8347 1 -2.09 -1.43 0 48.358243 0 0.988493 -18.64268 380 5 1.1 0.9;
+ 8361 1 126.54 29.1 0 12.55 0 1.073653 -26.422933 220 5 1.1 0.9;
+ 8367 1 77.99 19.3 0 3.04 0 1.034784 -6.699666 220 5 1.1 0.9;
+ 8369 1 -0 -0 0 1.23 0 1.02695 -9.179276 220 5 1.1 0.9;
+ 8373 1 216.3 -6.9 0 2.44 0 1.071546 -48.132392 220 5 1.1 0.9;
+ 8397 1 -0 0 0 4.05 0 1.042817 -25.347834 220 5 1.1 0.9;
+ 8405 1 40.75 12.5 0 2.61 0 1.036479 -12.357404 220 5 1.1 0.9;
+ 8406 1 0 0 0 14.38 0 1.050892 -25.13855 220 5 1.1 0.9;
+ 8411 1 39.64 9.6 0 1.8 0 1.042819 -25.804727 220 5 1.1 0.9;
+ 8439 1 380.8 62.8 0 7.11 0 0.998187 -23.461096 220 5 1.1 0.9;
+ 8448 1 286.1 89.3 0 8.89 0 1.018069 -20.595036 220 5 1.1 0.9;
+ 8458 2 0 0 0 0 0 1.042925 -9.400848 380 5 1.1 0.9;
+ 8466 1 0 -0 0 1.97 0 1.045302 -4.473537 220 5 1.1 0.9;
+ 8467 1 216.2 75.3 0 2.74 0 0.98622 -22.981008 220 5 1.1 0.9;
+ 8468 1 21.42 11.8 0 28.85 0 1.005238 -14.948026 380 5 1.1 0.9;
+ 8473 2 0 0 0 0 0 1.039202 -8.879096 220 5 1.1 0.9;
+ 8475 1 -0 0 0 8.35 0 1.072229 -47.841521 220 5 1.1 0.9;
+ 8477 1 0 0 0 2.46 0 1.068335 -10.11476 220 5 1.1 0.9;
+ 8478 1 -0 0 0 3.01 0 1.04799 -8.490097 220 5 1.1 0.9;
+ 8485 1 149 99.8 0 9.27 0 1.039726 -7.369105 220 5 1.1 0.9;
+ 8486 2 0 0 0 0 0 1.04752 -19.530978 380 5 1.1 0.9;
+ 8487 1 44.45 7.68 0 17.83 0 1.003338 -3.846694 380 5 1.1 0.9;
+ 8494 1 235.97 34.52 0 7.15 0 1.08964 -9.846898 380 5 1.1 0.9;
+ 8497 1 38.84 14.2 0 3.5 0 1.046629 -14.553599 220 5 1.1 0.9;
+ 8507 1 37.44 9.1 0 7.87 0 1.074417 -26.347125 220 5 1.1 0.9;
+ 8511 1 93.6 -43.5 0 33.51 0 1.04106 -24.505876 220 5 1.1 0.9;
+ 8515 2 0 0 0 0 0 1.053872 -12.378436 220 5 1.1 0.9;
+ 8522 2 0 0 0 0 0 1.019671 -15.723378 220 5 1.1 0.9;
+ 8535 1 72.68 24.3 0 3.12 0 1.036308 -21.925576 220 5 1.1 0.9;
+ 8542 1 87.7 26 0 47.58 0 1.044937 -21.028222 220 5 1.1 0.9;
+ 8546 1 5.01 1.8 0 0.77 0 1.038205 -11.643532 220 5 1.1 0.9;
+ 8560 1 -0 0 0 1.11 0 0.984498 -18.190495 380 5 1.1 0.9;
+ 8564 2 0 0 0 0 0 1.019727 -19.556828 220 5 1.1 0.9;
+ 8568 1 175.7 56.2 0 0.13 0 1.027945 -6.041782 220 5 1.1 0.9;
+ 8578 1 0 -0 0 4.55 0 1.049043 -21.931929 220 5 1.1 0.9;
+ 8592 1 -0 0 0 0.43 0 1.051916 -3.764146 220 5 1.1 0.9;
+ 8626 1 136 36.1 0 6.07 0 0.99463 -17.562106 220 5 1.1 0.9;
+ 8627 1 -0 0 0 4.26 0 1.048517 -26.395781 220 5 1.1 0.9;
+ 8628 1 277.1 37 0 21.03 0 1.042001 -23.598682 220 5 1.1 0.9;
+ 8636 1 31.43 10.6 0 1.61 0 1.041292 -21.579777 220 5 1.1 0.9;
+ 8651 1 162.49 45.11 0 5.38 0 1.024808 -17.313776 220 5 1.1 0.9;
+ 8653 1 44.55 7.5 0 0.6 0 1.036488 -16.021006 220 5 1.1 0.9;
+ 8656 1 5.51 1.3 0 0.09 0 1.031987 -8.436898 220 5 1.1 0.9;
+ 8669 1 74.98 10.5 0 12.96 0 1.050943 -15.2714 220 5 1.1 0.9;
+ 8670 2 0 0 0 0 0 1.049066 -6.522112 220 5 1.1 0.9;
+ 8672 1 -0 -0 0 28.515005 0 1.023418 -20.934804 380 5 1.1 0.9;
+ 8676 2 0 0 0 0 0 1.018762 -21.841814 220 5 1.1 0.9;
+ 8677 1 0 0 0 2.29 0 1.018085 -10.22697 220 5 1.1 0.9;
+ 8683 2 0 0 0 0 0 1.041975 -24.273671 220 5 1.1 0.9;
+ 8689 1 42.65 18.2 0 0 0 1.036224 -20.697926 220 5 1.1 0.9;
+ 8691 1 305.04 77.16 0 17.43 0 1.047013 -33.585967 220 5 1.1 0.9;
+ 8704 1 180.7 71.8 0 2.46 0 1.039389 -7.999499 220 5 1.1 0.9;
+ 8707 1 101.9 24.3 0 8.53 0 1.032359 -11.707737 220 5 1.1 0.9;
+ 8711 1 0 0 0 3.9 0 1.040912 -12.07314 220 5 1.1 0.9;
+ 8721 2 0 0 0 0 0 1.054052 -15.864679 380 5 1.1 0.9;
+ 8722 1 -0 0 0 2.13 0 1.072192 -25.045427 220 5 1.1 0.9;
+ 8732 1 66.27 19.3 0 12.94 0 1.038041 -21.15003 220 5 1.1 0.9;
+ 8743 1 11.61 7.6 0 6.21 0 1.035613 -34.477305 220 5 1.1 0.9;
+ 8748 1 279.7 4.6 0 3.77 0 1.067084 -49.622846 220 5 1.1 0.9;
+ 8763 1 -233.23 29.6 0 207.55 0 1.04005 2.599263 380 5 1.1 0.9;
+ 8765 1 -0 -0 0 11.69 0 1.051157 -15.257422 220 5 1.1 0.9;
+ 8787 1 22.83 8 0 3.71 0 1.066984 -16.98525 220 5 1.1 0.9;
+ 8788 1 143.8 46.45 0 3.26 0 1.046176 -5.977711 220 5 1.1 0.9;
+ 8791 1 -0 -0 0 0.36 0 1.057978 -22.356166 220 5 1.1 0.9;
+ 8795 2 0 0 0 0 0 1.054157 -0.136311 220 5 1.1 0.9;
+ 8804 1 22.02 4.4 0 4.83 0 1.049065 -9.481469 220 5 1.1 0.9;
+ 8807 2 0 0 0 0 0 1.05109 -3.882868 220 5 1.1 0.9;
+ 8808 1 203.6 19.81 0 15.46 0 1.060353 -25.817931 220 5 1.1 0.9;
+ 8809 1 101.2 -2.9 0 0.51 0 1.029974 -32.515321 220 5 1.1 0.9;
+ 8818 2 0 0 0 0 0 1.050791 0.636035 220 5 1.1 0.9;
+ 8825 1 406.04 95.5 0 35.34 0 1.014963 -2.776003 380 5 1.1 0.9;
+ 8829 1 91.6 27.1 0 10.95 0 1.044583 -21.076938 220 5 1.1 0.9;
+ 8834 1 -0 0 0 1.52 0 1.003582 -22.536497 220 5 1.1 0.9;
+ 8835 1 113.7 22.3 0 15.55 0 1.036698 -22.906459 220 5 1.1 0.9;
+ 8843 1 208.7 63 0 3.45 0 1.054844 -11.164607 220 5 1.1 0.9;
+ 8846 1 20.82 0 0 0.17 0 1.070172 7.811263 220 5 1.1 0.9;
+ 8853 1 410.3 91.6 0 13.25 0 1.052314 -36.519464 220 5 1.1 0.9;
+ 8854 1 69.18 35.1 0 12.59 0 1.027794 -44.429467 220 5 1.1 0.9;
+ 8860 1 57.16 19.7 0 22.17 0 1.020431 -10.190501 220 5 1.1 0.9;
+ 8864 1 63.31 -9.8 0 5.36 0 1.048228 -31.670524 220 5 1.1 0.9;
+ 8872 2 0 0 0 0 0 1.053844 -15.88923 380 5 1.1 0.9;
+ 8873 1 0 -0 0 1.87 0 1.071142 -27.284425 220 5 1.1 0.9;
+ 8874 1 285.2 61.4 0 26.04 0 1.046146 -20.00976 220 5 1.1 0.9;
+ 8877 1 -0 0 0 1.03 0 1.039567 -20.646198 220 5 1.1 0.9;
+ 8879 1 0 0 0 1.47 0 1.036915 -22.747121 220 5 1.1 0.9;
+ 8886 1 0 -0 0 -1.392036 0 0.983701 -3.785162 380 5 1.1 0.9;
+ 8887 1 0 0 0 102.70867 0 1.045962 1.729833 380 5 1.1 0.9;
+ 8893 1 278.3 33.6 0 25.9 0 1.05128 -15.163258 220 5 1.1 0.9;
+ 8900 1 3.1 1.6 0 0.09 0 1.047741 -23.703947 220 5 1.1 0.9;
+ 8903 2 0 0 0 0 0 1.020268 -11.421507 380 5 1.1 0.9;
+ 8906 1 91 21 0 11.23 0 1.036 -23.062052 220 5 1.1 0.9;
+ 8913 1 -0 0 0 1.13 0 1.040075 -20.555337 220 5 1.1 0.9;
+ 8930 1 139.4 21.2 0 6.21 0 0.991658 -18.577239 220 5 1.1 0.9;
+ 8931 1 -0.56 -0 0 108.21 0 1.090352 -9.661963 380 5 1.1 0.9;
+ 8947 1 3.7 0.2 0 0.05 0 1.03998 -11.496674 220 5 1.1 0.9;
+ 8950 2 0 0 0 0 0 1.047268 -14.839334 220 5 1.1 0.9;
+ 8961 2 0 0 0 0 0 1.035459 -14.187287 220 5 1.1 0.9;
+ 8975 1 0 -0 0 11.04 0 1.04225 -24.276259 220 5 1.1 0.9;
+ 8976 2 0 0 0 0 0 1.046972 -17.074322 220 5 1.1 0.9;
+ 8980 1 63.97 12.8 0 0.17 0 1.042994 -11.072487 220 5 1.1 0.9;
+ 8989 1 88.5 24.5 0 2.23 0 1.043398 -25.575347 220 5 1.1 0.9;
+ 8992 1 -0 -0 0 14.64 0 1.051114 -3.785395 220 5 1.1 0.9;
+ 8997 2 0 0 0 0 0 0.997131 -13.27089 380 5 1.1 0.9;
+ 8999 1 41.15 10.3 0 2.41 0 1.044391 -21.558302 220 5 1.1 0.9;
+ 9002 1 119.02 12.54 0 23.45 0 1.021009 -10.528192 220 5 1.1 0.9;
+ 9011 1 88.4 25.2 0 12.9 0 1.036275 -23.026084 220 5 1.1 0.9;
+ 9012 1 25.63 6.5 0 0.52 0 1.048758 1.093286 220 5 1.1 0.9;
+ 9014 1 70.78 19.6 0 8.1 0 1.051072 -6.681904 220 5 1.1 0.9;
+ 9018 1 55.46 16.9 0 1.92 0 1.022715 -6.602667 220 5 1.1 0.9;
+ 9019 1 91.4 18.1 0 4.89 0 1.040421 -24.677298 220 5 1.1 0.9;
+ 9021 1 152.18 21.63 0 1.91 0 1.035437 -6.308005 220 5 1.1 0.9;
+ 9033 1 76.88 16.4 0 6.61 0 1.049786 -26.382004 220 5 1.1 0.9;
+ 9045 1 60.57 18.9 0 1.46 0 1.039905 -24.629587 220 5 1.1 0.9;
+ 9051 1 0 -0 0 2.15 0 1.036594 0.577238 220 5 1.1 0.9;
+ 9059 1 0 -0 0 2 0 1.072487 -27.192131 220 5 1.1 0.9;
+ 9065 1 -0 -0 0 0.59 0 1.040021 2.414524 380 5 1.1 0.9;
+ 9066 1 23.26 3.01 0 9.29 0 1.019989 -20.806005 220 5 1.1 0.9;
+ 9067 2 0 0 0 0 0 1.040924 1.549232 220 5 1.1 0.9;
+ 9091 1 0 0 0 3.65 0 1.038554 -9.767436 220 5 1.1 0.9;
+ 9101 2 0 0 0 0 0 1.02885 -21.628013 380 5 1.1 0.9;
+ 9108 2 0 0 0 0 0 1.046626 -16.441009 220 5 1.1 0.9;
+ 9109 1 0 -0 0 0.31 0 1.036596 0.577218 220 5 1.1 0.9;
+ 9112 1 0 -0 0 19.71 0 1.047611 -12.93238 220 5 1.1 0.9;
+ 9119 1 -0 0 0 1.24 0 1.04289 -20.527494 220 5 1.1 0.9;
+ 9128 1 50.56 8.7 0 0.19 0 1.042244 -2.676445 220 5 1.1 0.9;
+ 9130 1 245.51 9.17 0 24.25 0 1.049965 -30.721639 220 5 1.1 0.9;
+ 9131 1 -0 -0 0 6.62 0 1.051124 -24.097314 220 5 1.1 0.9;
+ 9137 2 0 0 0 0 0 1.049768 -26.378636 220 5 1.1 0.9;
+ 9140 2 0 0 0 0 0 1.049624 -5.232971 220 5 1.1 0.9;
+ 9150 2 0 0 0 0 0 1.037969 -13.200551 380 5 1.1 0.9;
+ 9155 1 -0 -0 0 5.01 0 1.02382 -20.860292 220 5 1.1 0.9;
+ 9158 1 54.96 9.42 0 5.92 0 1.025798 -14.56483 220 5 1.1 0.9;
+ 9164 1 7.71 2.4 0 6.93 0 1.001887 -19.403088 220 5 1.1 0.9;
+ 9173 1 66.07 15.6 0 5.57 0 1.032906 -20.202148 220 5 1.1 0.9;
+ 9174 2 0 0 0 0 0 1.03623 -32.377948 380 5 1.1 0.9;
+ 9176 1 -0 0 0 1.28 0 1.047842 -12.93497 220 5 1.1 0.9;
+ 9180 2 0 0 0 0 0 1.061189 -8.603491 220 5 1.1 0.9;
+ 9181 1 2.43 1.35 0 0.1 0 1.032498 -9.466095 220 5 1.1 0.9;
+ 9185 1 66.97 18.6 0 18.5 0 1.051815 -6.62338 220 5 1.1 0.9;
+ 9189 1 62.57 -61 0 55.14 0 1.048019 -25.022568 220 5 1.1 0.9;
+ 9191 1 -0 -0 0 2.34 0 1.073685 -24.80852 220 5 1.1 0.9;
+ 9203 1 627.36 -73.13 0 27.185221 0 1.001613 -12.605605 380 5 1.1 0.9;
+ 9213 1 -0 -0 0 10.210952 0 1.023742 -4.653017 380 5 1.1 0.9;
+ 9217 1 -0 0 0 6.33 0 1.040155 -8.875709 220 5 1.1 0.9;
+ 9222 1 -5.15 -2.04 0 154.446402 0 1.053345 -16.073005 380 5 1.1 0.9;
+ 9231 1 242.08 59.98 0 5.6 0 1.029833 -19.150137 220 5 1.1 0.9;
+ 9241 1 0 -0 0 0.36 0 1.049081 -9.481609 220 5 1.1 0.9;
+% bus_i type Pd Qd Gs Bs area Vm Va base zone Vmax Vmin
+% FUBM BUSES
+ 10001 1 0 0 0 0 0 1 0 220 5 1.1 0.9;
+ 10002 1 0 0 0 0 0 1 0 220 5 1.1 0.9;
+ 10003 1 0 0 0 0 0 1 0 220 5 1.1 0.9;
+ 10004 1 0 0 0 0 0 1 0 220 5 1.1 0.9;
+ 10005 1 0 0 0 0 0 1 0 220 5 1.1 0.9;
+ ];
+
+%% generator data
+% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
+mpc.gen = [
+ 124 861.3 56.53 440.32 -172.59 1.081537 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 150 67.29 -7.99 77.09 -22.54 1.062805 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 221 -155.39 97.68 183.92 -65.3 0.984682 100 1 100 -207.18 0 0 0 0 0 0 0 0 0 0 0;
+ 338 83.7 2.5 55.54 -19.16 1.048249 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 352 1250.4 278.94 926.35 -297.68 1.055378 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 413 231 19.11 124.12 -49.84 1.05013 100 1 280 0 0 0 0 0 0 0 0 0 0 0 0;
+ 453 260.1 57.98 257.23 -74.4 1.018914 100 1 540 0 0 0 0 0 0 0 0 0 0 0 0;
+ 516 539.4 190.43 261.79 -106.67 1.075592 100 1 600 200 0 0 0 0 0 0 0 0 0 0 0;
+ 564 -51.67 -3.31 18.47 -19.35 1.069817 100 1 100 -68.89 0 0 0 0 0 0 0 0 0 0 0;
+ 583 -270 3.65 17.88 -7.03 1.045397 100 1 100 -360 0 0 0 0 0 0 0 0 0 0 0;
+ 615 38.2 -0.39 17.09 -7.79 1.063876 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0;
+ 616 379.2 37.76 217.9 -81.16 1.048713 100 1 480 160 0 0 0 0 0 0 0 0 0 0 0;
+ 639 -46.2 112.55 135.52 -38.9 1.051376 100 1 100 -61.6 0 0 0 0 0 0 0 0 0 0 0;
+ 682 37.4 8.53 38.77 -11.06 1.0691 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 749 198.88 -11.17 105.69 -43.84 1.057884 100 1 240 0 0 0 0 0 0 0 0 0 0 0 0;
+ 757 116.7 13.66 51.3 -23.41 1.017567 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 776 -111.4 3.36 18.16 -6.73 1.026368 100 1 100 -148.53 0 0 0 0 0 0 0 0 0 0 0;
+ 778 16.5 -0.67 12.37 -9.36 1.049411 100 1 33.58 0 0 0 0 0 0 0 0 0 0 0 0;
+ 795 58.4 7.75 36.75 -13.04 1.035522 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 803 -89.2 -1.52 74.03 -25.54 1.041369 100 1 100 -118.93 0 0 0 0 0 0 0 0 0 0 0;
+ 823 1274.2 289.74 926.68 -298.31 1.044097 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 851 59.56 50.82 96.64 -27.81 1.00025 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 858 855.6 147.86 440.67 -172.15 1.031745 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 891 1702.8 651.53 1097.41 -373.91 1.064525 100 1 2400 800 0 0 0 0 0 0 0 0 0 0 0;
+ 972 1221.2 393.14 934.73 -291.52 1.072621 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 1001 92.1 25.97 55.02 -19.81 1.074143 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1002 171 10.89 89.55 -35.15 1.041506 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1043 829.5 49 387.88 -163.4 1.028946 100 1 900 300 0 0 0 0 0 0 0 0 0 0 0;
+ 1083 91.8 9.85 54.91 -19.88 1.049472 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1093 837 83.03 550.69 -185.15 1.027056 100 1 1200 400 0 0 0 0 0 0 0 0 0 0 0;
+ 1100 58.2 5.6 36.8 -13.01 1.042801 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1102 -124.15 7.32 38.05 -11.59 1.049879 100 1 100 -165.54 0 0 0 0 0 0 0 0 0 0 0;
+ 1237 1504.8 364.78 906.61 -319.44 1.108028 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 1251 837 77.94 550.69 -185.15 1.027102 100 1 1200 400 0 0 0 0 0 0 0 0 0 0 0;
+ 1295 -124.1 4.52 36.92 -12.88 1.03682 100 1 100 -165.47 0 0 0 0 0 0 0 0 0 0 0;
+ 1341 67.2 29.74 57.03 -17.62 1.032899 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1354 -246.5 13.72 38.08 -11.73 1.041045 100 1 100 -328.67 0 0 0 0 0 0 0 0 0 0 0;
+ 1422 -101 2.33 18.09 -6.79 1.04353 100 1 100 -134.67 0 0 0 0 0 0 0 0 0 0 0;
+ 1436 49.4 2.95 37.72 -12.09 1.047684 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1478 62.6 7.49 36.4 -13.44 1.048068 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1604 50.6 13.86 37.66 -12.17 1.043862 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1642 50.4 11.76 37.74 -12.11 1.028554 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1680 1250.4 274.36 928.89 -296.1 1.04395 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 1708 860.8 121.94 439.37 -173.3 1.037938 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 1721 28.1 1.73 18.52 -6.39 1.062238 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1754 40 3.62 16.99 -7.92 1.04286 100 1 41.06 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1794 1250.4 253.94 926.35 -297.68 1.05295 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 1808 -0.6 -13.17 111.23 -38.16 1.046224 100 1 100 -0.8 0 0 0 0 0 0 0 0 0 0 0;
+ 1851 15.6 -1.26 11.76 -8.89 1.04762 100 1 31.92 0 0 0 0 0 0 0 0 0 0 0 0;
+ 1852 -241.8 10.63 58.16 -16.52 1.054325 100 1 100 -322.4 0 0 0 0 0 0 0 0 0 0 0;
+ 1888 573.68 42.43 396.02 -155.83 1.039377 100 1 912.78 312.78 0 0 0 0 0 0 0 0 0 0 0;
+ 1914 115.5 -45.22 160.36 -150.95 1.035636 100 1 472.16 39.35 0 0 0 0 0 0 0 0 0 0 0;
+ 1959 31 0.56 18.14 -6.75 1.064692 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2035 855.6 149.85 441.85 -171.27 1.03088 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 2050 836.2 -16.43 962.2 -263.65 1.009914 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 2085 176 31.77 88.39 -36.19 1.040351 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2177 -121.3 13.33 58.35 -16.26 1.07333 100 1 100 -161.73 0 0 0 0 0 0 0 0 0 0 0;
+ 2197 -53.29 -1.42 19.51 -14.74 1.035528 100 1 100 -71.05 0 0 0 0 0 0 0 0 0 0 0;
+ 2276 38.9 -22.64 41.67 -36.5 1.05324 100 1 119.3 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2291 110.5 13.69 95.69 -28.93 1.072528 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2359 78.2 7.2 34.35 -15.5 1.024884 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2421 -320.4 4.66 37.39 -12.45 1.047766 100 1 100 -427.2 0 0 0 0 0 0 0 0 0 0 0;
+ 2425 -100.5 5.31 54.3 -20.49 1.041186 100 1 100 -134 0 0 0 0 0 0 0 0 0 0 0;
+ 2426 -43.2 -30.65 105.34 -99.02 1.037687 100 1 100 -57.6 0 0 0 0 0 0 0 0 0 0 0;
+ 2446 1367 286.48 921.62 -304.73 1.06157 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 2468 46.8 5.15 38.02 -11.81 1.048132 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2481 31.8 11.5 39.12 -10.71 1.042777 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2489 286.5 -15.8 162.4 -61.79 1.049366 100 1 360 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2550 54.3 4.31 58.23 -16.49 1.049384 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2600 76.48 16.9 76.08 -23.59 1.038821 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2627 1367 302.84 921.52 -304.79 1.061488 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 2653 41.92 3.94 51.94 -22.8 1.036517 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2719 77.6 -15.35 70.15 -58.1 1.035384 100 1 196.72 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2786 1221.2 372.42 934.81 -291.47 1.073795 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 2797 -95.1 -11.62 88.33 -36.33 1.042226 100 1 100 -126.8 0 0 0 0 0 0 0 0 0 0 0;
+ 2799 66.8 -1.21 77.91 -21.66 1.05396 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2816 1250.4 270.9 926.26 -297.74 1.053944 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 2841 80.7 -3.29 55.98 -18.76 1.08248 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2842 31.6 5.75 18.19 -6.74 1.043712 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2872 4.5 0.33 3.31 -2.54 1.063841 100 1 9.05 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2878 8.95 -11.72 72.95 -68.71 1.057626 100 1 214.86 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2886 60.9 10.71 57.69 -17.02 1.055151 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2902 20.9 1.11 19.19 -5.72 1.059072 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2930 53.2 2.49 37.24 -12.54 1.047695 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2934 3.4 -0.16 2.51 -1.91 1.051149 100 1 6.83 0 0 0 0 0 0 0 0 0 0 0 0;
+ 2985 46.6 -69.84 184.46 -132.67 1.053607 100 1 493.35 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3018 162.5 -4.77 89.61 -34.82 1.041705 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3028 855.7 146.13 441.85 -171.27 1.030654 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 3114 38.6 4.12 17.33 -7.61 1.071964 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3133 85.54 0.39 113.97 -35.56 1.065372 100 1 240 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3134 -136.3 -11.71 70.25 -29.33 1.023117 100 1 100 -181.73 0 0 0 0 0 0 0 0 0 0 0;
+ 3183 98.7 -3.57 53.7 -20.98 1.055515 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3205 416.7 119.72 243.61 -88.46 1.041982 100 1 540 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3218 -107.4 4.44 36.79 -13 1.028507 100 1 100 -143.2 0 0 0 0 0 0 0 0 0 0 0;
+ 3240 -42.3 -25.61 62.23 -51.37 1.050305 100 1 100 -56.4 0 0 0 0 0 0 0 0 0 0 0;
+ 3306 861.3 143.67 439.2 -173.43 1.071978 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 3324 -26.48 12.72 38.13 -11.64 1.014126 100 1 100 -35.3 0 0 0 0 0 0 0 0 0 0 0;
+ 3346 56.8 11.49 37.1 -12.76 1.01594 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3353 19.07 5.42 38.2 -11.61 1.045739 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3364 44.5 -21.96 47.19 -41.44 1.0538 100 1 135.27 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3390 2.4 12.68 54.59 -20.19 1.039984 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3422 53.7 -3.24 58.19 -16.5 1.063657 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3436 521 217.43 550.97 -184.89 1.060777 100 1 1200 400 0 0 0 0 0 0 0 0 0 0 0;
+ 3492 -370.8 2.02 53.75 -21.08 1.04852 100 1 100 -494.4 0 0 0 0 0 0 0 0 0 0 0;
+ 3513 829.8 51 387.88 -163.4 1.028771 100 1 900 300 0 0 0 0 0 0 0 0 0 0 0;
+ 3565 15.88 2.27 38.83 -10.97 1.081614 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3580 539 189.12 261.7 -107.36 1.07602 100 1 600 0 0 0 0 0 0 0 0 0 0 0 0;
+ 3611 -125.4 3.51 54.59 -20.12 1.03905 100 1 100 -167.2 0 0 0 0 0 0 0 0 0 0 0;
+ 3656 -26.2 12.26 116.07 -33.32 1.070983 100 1 100 -34.93 0 0 0 0 0 0 0 0 0 0 0;
+ 3661 861.2 118.75 441.04 -172.05 1.059676 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 3698 -12.58 3.09 36.34 -13.47 1.041813 100 1 100 -16.78 0 0 0 0 0 0 0 0 0 0 0;
+ 3741 854.7 190.06 548.57 -187.16 1.031629 100 1 1200 400 0 0 0 0 0 0 0 0 0 0 0;
+ 3809 257 122.15 313.01 -116.73 1.084785 100 1 700 233.33 0 0 0 0 0 0 0 0 0 0 0;
+ 3825 837.3 54.8 388.17 -163.4 1.026994 100 1 900 300 0 0 0 0 0 0 0 0 0 0 0;
+ 3869 855.6 148.23 440.69 -172.14 1.031907 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 3876 -25.1 6.45 34.27 -15.52 1.044501 100 1 100 -33.47 0 0 0 0 0 0 0 0 0 0 0;
+ 3916 -21.27 11.22 38.02 -11.77 1.043758 100 1 100 -28.37 0 0 0 0 0 0 0 0 0 0 0;
+ 3951 -27.1 -74.05 126.16 -127.56 1.027439 100 1 100 -36.13 0 0 0 0 0 0 0 0 0 0 0;
+ 3971 -134.5 9.64 55.67 -19.09 1.063145 100 1 100 -179.33 0 0 0 0 0 0 0 0 0 0 0;
+ 4024 89.5 40.38 97.07 -27.44 1.040328 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4056 -76.9 3.73 38.05 -11.77 1.038526 100 1 100 -102.53 0 0 0 0 0 0 0 0 0 0 0;
+ 4084 366.1 46.44 264.94 -103.74 1.063234 100 1 600 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4118 41 5.09 38.37 -11.4 1.027195 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4125 59.6 16.3 36.89 -13 1.003502 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4128 67.5 24.27 57.03 -17.63 1.019761 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4231 2641.24 771.6 Inf -Inf 1.049182 100 1 4188.95 1333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 4331 60.2 6.92 36.73 -13.12 1.028646 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4395 -129.1 6.73 38.48 -11.33 1.039834 100 1 100 -172.13 0 0 0 0 0 0 0 0 0 0 0;
+ 4419 861.3 121.55 441.04 -172.05 1.059565 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 4480 861.3 143.79 439.2 -173.43 1.071852 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 4482 35.2 13.53 38.85 -10.95 1.049914 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4506 -171.8 12.84 37.86 -11.95 1.036047 100 1 100 -229.07 0 0 0 0 0 0 0 0 0 0 0;
+ 4566 -30.39 6.81 37.94 -11.87 1.073282 100 1 100 -40.51 0 0 0 0 0 0 0 0 0 0 0;
+ 4624 68 8.25 35.62 -14.19 1.042135 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4661 -78.9 2.19 19.14 -5.77 1.049813 100 1 100 -105.2 0 0 0 0 0 0 0 0 0 0 0;
+ 4701 93.2 -41.31 98.4 -86.29 1.043063 100 1 281.85 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4783 861.3 141.62 439.2 -173.43 1.071981 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 4816 -26.08 10.07 38.37 -11.44 1.067305 100 1 100 -34.77 0 0 0 0 0 0 0 0 0 0 0;
+ 4819 855.6 150.1 440.69 -172.14 1.031907 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 4823 10.3 1.59 4.44 -2.07 1.067114 100 1 10.46 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4850 88.8 11.86 76.52 -23.19 1.054975 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4880 -40.3 5.06 75.62 -23.96 1.034991 100 1 100 -53.73 0 0 0 0 0 0 0 0 0 0 0;
+ 4918 41.69 8.64 37.27 -12.57 1.057325 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 4952 -12.57 4.47 37.23 -12.61 1.045386 100 1 100 -16.77 0 0 0 0 0 0 0 0 0 0 0;
+ 5004 54.3 4.85 74.73 -70.41 1.0663 100 1 220.12 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5019 49.4 2.95 37.72 -12.09 1.047693 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5051 83.48 -1.38 74.55 -24.97 1.037373 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5067 542 142.39 258.91 -109.58 1.021924 100 1 600 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5110 -52.51 8.27 38.28 -11.5 1.032061 100 1 100 -70.01 0 0 0 0 0 0 0 0 0 0 0;
+ 5120 75.6 -5.04 56.35 -18.42 1.055539 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5144 1713.6 139.22 882.86 -343.24 1.035201 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 5237 106.8 10.9 75.02 -24.74 1.052719 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5278 119.4 -0.06 51.3 -23.49 1.042037 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5340 -159 11.05 36.37 -13.43 1.054941 100 1 100 -212 0 0 0 0 0 0 0 0 0 0 0;
+ 5365 19.59 1.13 18.14 -6.75 1.061754 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5379 1250.6 358.22 926.47 -297.63 1.107976 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 5395 -395.8 3.01 58.06 -16.66 1.048137 100 1 100 -527.73 0 0 0 0 0 0 0 0 0 0 0;
+ 5461 43.4 10.92 38.26 -11.55 1.06213 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5481 1368.6 146.68 920.31 -305.64 1.063711 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 5482 56.8 -22.21 101.32 -48.12 1.044486 100 1 249.06 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5486 861.3 119.59 441.04 -172.05 1.059636 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 5488 -96.4 14.63 37.49 -12.33 1.041881 100 1 100 -128.53 0 0 0 0 0 0 0 0 0 0 0;
+ 5490 3424.8 295.7 1765.36 -686.67 1.068845 100 1 4000 1333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 5533 173 14.6 88.87 -35.71 1.038212 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5546 21.5 1.97 19.16 -5.75 1.05378 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5564 57.6 11.81 36.8 -12.99 1.04123 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5658 229.8 77.84 103.18 -46.25 1.017689 100 1 240 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5664 128 14.87 72.71 -27.05 1.070507 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5709 837 75.6 550.69 -185.15 1.027078 100 1 1200 400 0 0 0 0 0 0 0 0 0 0 0;
+ 5781 1102.83 396.26 779.29 -324.79 1.0396 100 1 1800 600 0 0 0 0 0 0 0 0 0 0 0;
+ 5814 181.2 41.72 196.98 -77.17 1.044051 100 1 440 146.67 0 0 0 0 0 0 0 0 0 0 0;
+ 5856 305.7 19.99 214.13 -85 1.038417 100 1 480 160 0 0 0 0 0 0 0 0 0 0 0;
+ 5881 60 7.13 36.72 -13.13 1.065605 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 5940 -74.9 4.51 17.21 -7.73 1.030075 100 1 100 -99.87 0 0 0 0 0 0 0 0 0 0 0;
+ 5971 1221.2 370.23 934.54 -291.64 1.070056 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 5983 -102.5 3.55 37.27 -12.59 1.066029 100 1 100 -136.67 0 0 0 0 0 0 0 0 0 0 0;
+ 5994 -87.3 -16.58 60.51 -61.08 1.029184 100 1 100 -116.4 0 0 0 0 0 0 0 0 0 0 0;
+ 6036 820.2 300.86 390.4 -161.16 1.043738 100 1 900 300 0 0 0 0 0 0 0 0 0 0 0;
+ 6153 94.3 -78.07 249.65 -261.82 0.988112 100 1 769.94 32.08 0 0 0 0 0 0 0 0 0 0 0;
+ 6168 26.3 0.4 19.86 -14.93 1.040343 100 1 53.76 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6291 55.5 24.55 58.12 -16.6 1.040598 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6331 48.8 5.01 37.76 -12.05 1.052181 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6332 96 -9.58 96.56 -27.95 1.062214 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6351 22.08 14.99 38.29 -11.56 1.064446 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6368 -145.3 3 51.11 -23.46 1.043835 100 1 100 -193.73 0 0 0 0 0 0 0 0 0 0 0;
+ 6376 -27.8 -23.17 148.65 -50.73 1.046714 100 1 100 -37.07 0 0 0 0 0 0 0 0 0 0 0;
+ 6429 171 18.2 88.83 -35.69 1.039574 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6474 718.5 -12.86 438.72 -174.15 1.06557 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 6516 228.2 12.73 126.73 -47.83 1.052452 100 1 280 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6552 -204.2 5.93 37.58 -12.16 1.048796 100 1 100 -272.27 0 0 0 0 0 0 0 0 0 0 0;
+ 6734 382.7 -77.78 311.52 -132.09 1.061492 100 1 720 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6807 44.07 31.99 77.14 -22.46 1.006037 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6816 16.53 -8.62 77.35 -22.26 1.053803 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6820 15.9 -0.62 11.99 -9.06 1.049557 100 1 32.53 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6831 -57.5 4.01 35.62 -14.25 1.031347 100 1 100 -76.67 0 0 0 0 0 0 0 0 0 0 0;
+ 6845 102.9 17.09 53.24 -21.47 1.055216 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6852 -344.9 1.84 18.56 -6.34 1.031296 100 1 100 -459.87 0 0 0 0 0 0 0 0 0 0 0;
+ 6857 2463.6 391.48 1865.83 -585.95 1.021411 100 1 4000 1333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 6888 133 6.97 189.31 -59.87 1.039234 100 1 300 88.67 0 0 0 0 0 0 0 0 0 0 0;
+ 6947 227.5 5.93 126.09 -48.29 1.051367 100 1 280 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6969 39.8 -1.81 38.53 -11.27 1.059486 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 6982 -12.6 9.53 56.22 -18.44 1.036531 100 1 100 -16.8 0 0 0 0 0 0 0 0 0 0 0;
+ 7036 65.8 11.07 36.16 -13.72 1.041241 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 7049 55.5 16.47 58.18 -16.56 1.049669 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 7056 448.85 137.55 267.36 -100.98 1.006597 100 1 600 200 0 0 0 0 0 0 0 0 0 0 0;
+ 7115 65.87 13.66 95.06 -83.34 1.008722 100 1 272.28 0 0 0 0 0 0 0 0 0 0 0 0;
+ 7159 861.3 121.21 441.04 -172.05 1.059575 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 7183 1250.6 358.08 926.47 -297.63 1.107733 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 7209 7.3 0.36 3.12 -1.46 1.051113 100 1 7.35 0 0 0 0 0 0 0 0 0 0 0 0;
+ 7267 -39.7 22.41 89.84 -34.84 1.010817 100 1 100 -52.93 0 0 0 0 0 0 0 0 0 0 0;
+ 7282 2340.4 94.47 1862.29 -588.16 1.034538 100 1 4000 1333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 7327 59.06 19.56 76.11 -23.62 1.043172 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 7328 53 24.18 37.45 -12.39 0.999675 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 7466 -202.53 33.59 75.85 -77.06 1.057257 100 1 100 -270.04 0 0 0 0 0 0 0 0 0 0 0;
+ 7474 76.5 8.44 56.27 -18.41 1.027108 100 1 120 0 0 0 0 0 0 0 0 0 0 0 0;
+ 7495 75.8 67.52 214.23 -59.77 1.035256 100 1 200 50.53 0 0 0 0 0 0 0 0 0 0 0;
+ 7520 702.4 277.3 350.36 -140.73 1.037447 100 1 800 266.67 0 0 0 0 0 0 0 0 0 0 0;
+ 7522 508 235.59 371.11 -119.67 0.99994 100 1 800 266.67 0 0 0 0 0 0 0 0 0 0 0;
+ 7641 769.2 22.2 378.21 -162.35 1.051427 100 1 880 200 0 0 0 0 0 0 0 0 0 0 0;
+ 7697 228.2 12.72 126.73 -47.83 1.052424 100 1 280 0 0 0 0 0 0 0 0 0 0 0 0;
+ 7776 1221.2 354.58 934.73 -291.52 1.072261 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 7808 1250.4 279.8 926.35 -297.68 1.054562 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 7842 165 23.34 90.08 -34.56 1.001912 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 7913 1368.6 146.28 920.41 -305.58 1.063764 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 7998 811.8 175.43 391.57 -160.95 1.048854 100 1 900 300 0 0 0 0 0 0 0 0 0 0 0;
+ 8043 -27 4.11 75.67 -23.96 1.066913 100 1 100 -36 0 0 0 0 0 0 0 0 0 0 0;
+ 8109 992 864.28 Inf -Inf 1.067387 100 1 1041.6 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8158 153 -2.71 91.67 -33.01 1.052602 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8222 66.8 17.58 35.76 -14.05 1.02335 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8225 17 6.35 19.49 -5.42 1.071504 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8267 203.4 -3.04 106.84 -42.56 1.043326 100 1 240 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8311 -8.75 3.43 17.8 -7.13 1.035451 100 1 100 -11.66 0 0 0 0 0 0 0 0 0 0 0;
+ 8312 1702.2 433.08 1096.33 -374.64 1.07814 100 1 2400 800 0 0 0 0 0 0 0 0 0 0 0;
+ 8458 517.1 -58.18 474.42 -138.49 1.042925 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 8473 -135 -7.13 90.21 -34.45 1.039202 100 1 100 -180 0 0 0 0 0 0 0 0 0 0 0;
+ 8486 78.8 9.58 34.16 -15.67 1.04752 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8515 32.3 -18.17 93.03 -31.43 1.053872 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8522 -75.69 1.02 3.61 -1.69 1.019671 100 1 100 -100.92 0 0 0 0 0 0 0 0 0 0 0;
+ 8564 -65 20.7 51.91 -22.86 1.019727 100 1 100 -86.67 0 0 0 0 0 0 0 0 0 0 0;
+ 8670 -138.3 10.82 37.4 -12.46 1.049066 100 1 100 -184.4 0 0 0 0 0 0 0 0 0 0 0;
+ 8676 -259.1 12.69 34.92 -14.96 1.018762 100 1 100 -345.47 0 0 0 0 0 0 0 0 0 0 0;
+ 8683 -37.28 0.32 54.32 -20.39 1.041975 100 1 100 -49.7 0 0 0 0 0 0 0 0 0 0 0;
+ 8721 1232.6 152.55 932.68 -293.14 1.054052 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 8795 166.2 -6.14 111.7 -37.85 1.054157 100 1 240 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8807 -304 3.53 35.84 -14.07 1.05109 100 1 100 -405.33 0 0 0 0 0 0 0 0 0 0 0;
+ 8818 44.66 -2.57 76.87 -22.75 1.050791 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8872 1232.6 140.05 932.68 -293.14 1.053844 100 1 2000 666.67 0 0 0 0 0 0 0 0 0 0 0;
+ 8903 17 -1.08 28.99 -28.41 1.020268 100 1 86.73 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8950 -255.7 7.67 38.23 -11.61 1.047268 100 1 100 -340.94 0 0 0 0 0 0 0 0 0 0 0;
+ 8961 -61.8 -11.18 53.52 -50.38 1.035459 100 1 100 -82.4 0 0 0 0 0 0 0 0 0 0 0;
+ 8976 110 15.22 95.65 -28.95 1.046972 100 1 200 0 0 0 0 0 0 0 0 0 0 0 0;
+ 8997 78.2 -5.23 107.59 -101.48 0.997131 100 1 317.09 0 0 0 0 0 0 0 0 0 0 0 0;
+ 9067 369.6 48.34 198.07 -76.34 1.040924 100 1 440 146.67 0 0 0 0 0 0 0 0 0 0 0;
+ 9101 698.8 0.54 442.99 -169.92 1.02885 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 9108 -239.23 -1.6 18.65 -14.16 1.046626 100 1 100 -318.97 0 0 0 0 0 0 0 0 0 0 0;
+ 9137 42.7 18.81 335.96 -93.23 1.049768 100 1 100 28.47 0 0 0 0 0 0 0 0 0 0 0;
+ 9140 -37.2 28.17 73.19 -26.48 1.049624 100 1 100 -49.6 0 0 0 0 0 0 0 0 0 0 0;
+ 9150 860.8 117.32 439.38 -173.28 1.037969 100 1 1000 333.33 0 0 0 0 0 0 0 0 0 0 0;
+ 9174 -331.4 142.7 175 -49.16 1.03623 100 1 100 -441.87 0 0 0 0 0 0 0 0 0 0 0;
+ 9180 72 7.71 77.69 -21.97 1.061189 100 1 160 0 0 0 0 0 0 0 0 0 0 0 0;
+];
+
+%% branch data
+% fbus tbus r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP ----------------------
+mpc.branch = [
+ %Pegase System
+7351 5441 0.00018 0.000781 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4314 7571 0.002961 0.01669 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5803 3916 0.00056 0.00432 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6757 6036 0.0002 0.00246 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6757 6921 0.0003 0.00377 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5019 9112 0.00014 0.00057 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2930 9112 0.00013 0.000729 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1436 9112 0.00012 0.000581 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1851 9112 0.00011 0.00064 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8331 9112 0.00019 0.00056 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6220 8791 0.00062 0.004909 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9203 7842 7.00E-05 0.00076 0 887 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9203 8997 0.00066 0.00622 0 1611 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9203 2129 0.00054 0.00752 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9203 29 0.00105 0.00877 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+118 8903 8.00E-05 0.00091 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+118 4598 0.00056 0.00719 0 953 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2426 5533 0.000531 0.002039 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2426 4831 0.008659 0.03769 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2426 8961 0.003849 0.021099 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2426 8522 0.00688 0.035969 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2426 6888 0.006729 0.03713 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2426 3401 0.00111 0.006651 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2426 641 0.0023 0.008909 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2426 2600 0.000841 0.00313 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2426 5351 0.003521 0.017479 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3051 718 3.90E-05 0.00025 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3036 2327 0.000159 0.000729 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8651 7473 0.005281 0.032099 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8651 7473 0.005651 0.029419 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+903 3654 0.000271 0.00036 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8732 7050 0.00044 0.00143 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8732 3912 0.000159 0.00074 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2273 1973 0.00019 0.000591 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5131 2928 0.00019 0.00087 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6629 4918 0.002591 0.013659 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6629 7309 0.00305 0.01168 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+413 1102 0.000159 0.000599 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+413 1102 0.000159 0.00062 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3248 4918 0.00101 0.004229 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3248 4281 0.00319 0.018651 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3248 7309 0.000729 0.00337 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1146 1187 0.002961 0.012831 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1146 7945 0.000591 0.00339 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8900 2421 0.00024 0.001219 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6071 2972 0.006219 0.036341 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6071 6031 0.001841 0.01193 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3293 7264 0.001409 0.01113 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3293 283 0.00151 0.00768 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3293 3069 0.00599 0.03313 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3293 3390 0.001771 0.010151 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4689 4936 0.00074 0.00311 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4689 4936 0.000729 0.003159 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3218 7809 0.005271 0.01906 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3218 5455 0.00906 0.053151 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3218 1857 0.00405 0.0153 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6806 5410 0.00055 0.003961 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6806 5410 0.00055 0.003729 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6806 1609 0.00107 0.007789 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6806 1609 0.00112 0.00775 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6806 1609 0.001031 0.00775 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6806 2438 0.00062 0.003219 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6806 954 0.00068 0.002659 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9140 502 0.00193 0.012479 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9140 3013 0.001159 0.007229 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9140 2949 0.00137 0.008729 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9140 2949 0.001401 0.00855 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9140 2949 0.001331 0.008521 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7070 2208 0.00031 0.00081 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7070 8060 0.000341 0.00119 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7070 4484 0.00031 0.001281 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7070 4239 0.00094 0.0035 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8535 7047 7.00E-05 0.000651 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5477 3657 0.00019 0.00124 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5477 2928 0.000331 0.002539 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3145 2918 0.0016 0.02113 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7770 5317 0.000909 0.004711 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7770 5317 0.00088 0.004969 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3 8676 0.001841 0.0088 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3 8189 0.01013 0.04238 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 2938 0.00059 0.00802 0 723 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 2938 0.00054 0.0079 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 3918 0.00171 0.02128 0 986 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 3918 0.00174 0.02084 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 6581 0.00086 0.01433 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 6581 0.00087 0.01404 0 723 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 3830 0.00126 0.01447 0 1118 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 5648 0.00122 0.01509 0 1052 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 5648 0.00154 0.019 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4918 4907 0.00474 0.03564 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4918 5957 0.006 0.047849 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4918 5233 0.008039 0.03375 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6854 7309 2.10E-05 0.000211 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8311 3680 0.00045 0.002341 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2770 8804 0.000669 0.004281 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9241 8804 0.00068 0.00419 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3083 7124 0.000729 0.00431 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3083 7124 0.000591 0.004651 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3083 8873 0.00099 0.005081 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1566 7582 0.00212 0.013031 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1566 3541 0.002159 0.01275 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 3698 0.00025 0.00095 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 3698 0.000271 0.00089 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 2801 0.001961 0.012409 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 8328 0.00044 0.00207 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 8511 0.000469 0.00143 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 6570 0.001271 0.01406 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 6570 0.00124 0.013021 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 8975 0.000409 0.00239 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 216 0.00094 0.005 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 2961 0.000219 0.0007 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 6773 6.00E-05 0.00025 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8683 5278 5.00E-05 0.000229 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3768 2751 0.00019 0.000909 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2276 5546 0.001711 0.00782 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2276 6816 0.002651 0.01176 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7766 444 0.001409 0.010599 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7766 5334 0.001419 0.010219 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+839 3918 0.00013 0.00212 0 756 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+839 809 0.00026 0.00313 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4506 2286 0.0047 0.0318 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4506 6802 0.00136 0.00768 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4506 3520 0.005669 0.027789 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7273 6271 0.004409 0.033091 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7273 1435 0.01056 0.044469 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7273 7148 0.01963 0.07736 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7273 7437 0.01157 0.04694 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6104 871 0.000479 0.00255 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7580 871 0.000469 0.00236 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1188 1539 0.01237 0.067039 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1188 8515 0.0132 0.056229 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3971 4084 0.00026 0.001711 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3971 4084 0.000271 0.001669 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6845 5340 0.000211 0.000401 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8294 5814 0.00105 0.005159 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7115 6807 0.00212 0.00931 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+619 6791 0.000151 0.00068 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5418 4908 0.00019 0.00082 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5120 6816 0.003219 0.01405 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6692 9158 0.007271 0.033159 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6692 8035 0.006659 0.03132 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3445 2848 0.00057 0.00668 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3445 7056 0.00057 0.00758 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3445 7056 0.00039 0.00607 0 821 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3445 1642 0.00155 0.0179 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3445 4594 0.00036 0.00485 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6114 1692 0.000581 0.004229 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6114 8190 0.00056 0.00431 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6114 5836 0.003099 0.020531 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6114 3191 0.00118 0.016919 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6114 5300 0.00188 0.01407 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6114 4889 0.00545 0.04082 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7264 444 0.00214 0.01639 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7264 4747 0.002479 0.01549 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7982 9011 0.000159 0.001229 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7982 6675 0.00026 0.00162 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7982 6909 0.000159 0.00113 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7982 8835 0.000461 0.003219 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7982 4186 0.000159 0.001229 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1604 502 0.000229 0.00139 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2842 502 0.0002 0.00156 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1354 513 0.00145 0.00824 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1354 502 0.00069 0.005 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+891 3697 0.00036 0.00455 0 1809 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+891 3697 0.00036 0.00453 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8312 7541 0.00066 0.00997 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8312 7541 0.00064 0.01016 0 986 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6306 4826 9.90E-05 0.00044 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4826 4418 6.00E-05 0.000469 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4826 1605 3.90E-05 0.000341 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4826 6952 0.002531 0.01943 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4826 7124 0.00945 0.06418 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9128 217 0.000591 0.002831 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7014 217 0.00087 0.00387 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+720 5350 0.0015 0.01785 0 1183 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+720 5350 0.00147 0.0182 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1711 639 0.00151 0.0113 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1711 639 0.001479 0.011521 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1711 9130 0.00174 0.010341 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1711 9130 0.001659 0.01206 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8209 1998 0.00069 0.000479 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8209 7974 0.00044 0.00139 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1035 8180 0.002039 0.01601 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1035 7466 0.01349 0.05662 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1035 305 0.00082 0.00438 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1035 305 0.0008 0.004461 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1035 5106 0.001091 0.00888 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1035 5106 0.00111 0.007039 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2527 8466 0.000849 0.00537 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8669 8893 0.00061 0.00275 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6206 7691 0.00141 0.0188 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6206 6624 0.00121 0.01427 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3240 8158 0.001711 0.007159 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3240 8795 0.00545 0.02381 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3240 4143 0.000771 0.004331 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3240 2797 0.00414 0.03282 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3240 6331 0.00264 0.011521 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3240 6384 0.00261 0.011 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3240 7523 0.00239 0.00919 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3240 2889 0.000539 0.00226 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3240 6887 0.00325 0.017979 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1249 4541 0.00076 0.0071 0 1216 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+819 7523 0.000651 0.00343 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2304 4353 0.001219 0.00812 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2304 4816 0.00243 0.01439 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9174 6246 0.0006 0.00839 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9174 6246 0.00059 0.00856 0 1085 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9174 5658 0.00087 0.01328 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9174 5658 0.00073 0.01595 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2924 3645 0.00163 0.002039 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2924 3645 0.001659 0.002 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+59 5764 0.00339 0.019669 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+59 2360 0.00239 0.017281 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6510 9033 0.00032 0.00112 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6510 5918 0.0018 0.01401 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6510 5918 0.00212 0.012469 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1275 2850 0.00063 0.00411 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6426 4110 0.009729 0.03505 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6426 3558 0.01007 0.03056 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1758 2816 0.00042 0.00623 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1758 352 0.00036 0.00722 0 1743 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1758 6581 0.00053 0.0078 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1758 1923 0.00109 0.0173 0 723 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1758 5837 0.00071 0.01144 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1758 3830 0.00157 0.01884 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1758 3577 0.00032 0.00384 0 756 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8030 1794 0.00041 0.00649 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8030 7808 0.0004 0.00658 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8030 6581 0.00054 0.00763 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8030 1923 0.00107 0.01602 0 821 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8030 5837 0.0007 0.01165 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8030 5648 0.0016 0.01844 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8030 3577 0.00032 0.00376 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4615 171 0.00212 0.01207 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3137 2341 5.00E-05 0.00037 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6271 8787 0.00355 0.024651 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6252 9137 0.00675 0.04145 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5533 7133 0.00195 0.014341 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8361 4355 0.00018 0.00043 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8361 2928 0.00037 0.000969 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+609 1341 0.00257 0.017169 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+609 5419 0.00076 0.00399 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+609 5419 0.00075 0.00406 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+609 2079 0.003901 0.023961 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+609 772 0.00249 0.019211 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3654 2928 0.00025 0.001159 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 7282 0.00195 0.02924 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 2197 0.00152 0.01527 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 7640 0.00149 0.01558 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 1081 0.00253 0.0276 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 1081 0.00263 0.02648 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 2359 0.00077 0.0092 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 4196 0.00112 0.01705 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5856 8546 0.00226 0.01101 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5856 5987 0.004531 0.029039 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5856 8005 0.002081 0.030409 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5856 3925 0.0053 0.03257 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5856 3324 0.00513 0.041901 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5856 4748 0.001461 0.01056 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8265 4816 0.0005 0.002591 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6151 6313 0.00055 0.0033 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4005 6532 0.002289 0.01763 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4005 2177 0.0075 0.043531 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5723 2079 0.00138 0.019961 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5723 789 0.00126 0.018729 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2327 9189 0.00038 0.001331 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2327 3400 0.00019 0.001461 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+207 4747 0.002151 0.013401 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+207 7791 0.000789 0.005669 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3205 6735 3.00E-05 0.00042 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3205 666 0.00079 0.00899 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3205 666 0.0008 0.00879 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3205 4435 0.00334 0.03393 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3205 1644 0.00063 0.00789 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3205 3483 0.0006 0.00842 0 1216 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4683 7989 0.00011 0.00125 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4683 6516 0.00012 0.001091 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4683 7697 9.90E-05 0.00125 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4683 416 0.00294 0.02443 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4683 2847 0.00144 0.011151 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4683 2563 0.001831 0.010849 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4683 2563 0.001599 0.01055 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4683 2995 0.00144 0.019591 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5691 1001 0.0133 0.09551 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5691 4426 0.009591 0.073961 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5350 2721 0.0007 0.00671 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5350 2721 0.00072 0.00658 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2361 4936 0.001901 0.00964 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2361 5179 0.001711 0.01189 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2044 4748 0.00025 0.00187 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4197 5522 0.00043 0.002211 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5699 8670 0.000401 0.00243 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7809 5110 0.00336 0.017 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7222 4816 0.005521 0.031031 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4402 3817 9.90E-05 0.00026 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6857 2732 0.00045 0.00718 0 986 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6857 4550 0.00044 0.00665 0 821 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6857 4339 0.00103 0.01516 0 1183 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6857 7513 0.00101 0.01546 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5016 26 0.00045 0.00608 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5016 9213 0.0004 0.00501 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6112 9002 0.001729 0.01337 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6112 6231 0.00264 0.01489 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6112 883 0.002341 0.018961 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6112 5738 0.001841 0.01363 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8860 7700 0.001219 0.00949 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8860 9002 0.002271 0.01151 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8860 5990 0.010781 0.05775 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8860 6450 0.00251 0.013919 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8860 7726 0.00101 0.007331 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2489 4110 0.00061 0.003909 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3985 6376 0.004289 0.019331 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3985 4110 0.0008 0.004401 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3985 4829 0.008099 0.03519 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3985 7857 0.00063 0.004591 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2806 7857 0.000651 0.00456 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2489 9012 0.00114 0.00581 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2489 2231 0.001211 0.00538 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+658 3793 0.00418 0.030159 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+658 8497 0.00324 0.02413 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+658 8497 0.003169 0.024591 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3502 9002 0.000219 0.00088 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3502 9002 0.000289 0.00095 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6313 44 0.0035 0.022211 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6313 7582 0.00313 0.02256 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5944 8808 0.000831 0.00162 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3183 8515 0.002099 0.01068 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1005 8515 0.00224 0.00976 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8787 1448 0.00169 0.01231 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6636 9051 0.00011 0.00076 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9109 9051 0.00011 0.00068 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6961 6376 0.005479 0.021909 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6961 8818 0.003331 0.017039 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5077 4353 0.000479 0.001271 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7471 5241 0.00109 0.01629 0 723 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7471 8200 4.00E-05 0.00063 0 1710 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+549 6290 0.0053 0.024531 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+549 2291 0.004659 0.021919 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+549 3656 0.001659 0.01043 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5002 4144 0.006961 0.053539 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1888 5441 0.00036 0.00288 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1888 5441 0.00038 0.003 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5490 4970 0.00048 0.00643 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5490 4970 0.00051 0.0066 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5490 4970 0.00046 0.00729 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5490 5461 0.0006 0.00868 0 1710 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5490 7778 0.00068 0.01076 0 1842 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5490 6897 0.00066 0.01096 0 1809 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3075 4562 0.00101 0.005099 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+564 8475 0.003901 0.02437 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+564 2252 0.00276 0.016461 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+564 7903 0.00588 0.047081 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4331 1857 3.90E-05 0.000219 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2877 3674 0.00131 0.00538 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2854 1081 0.00679 0.04679 0 920 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2854 8267 0.00138 0.01466 0 986 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9112 9176 0.003531 0.01724 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9112 1422 0.01324 0.06936 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9112 8515 0.00363 0.01743 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9112 8515 0.00257 0.01662 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9112 5051 0.01399 0.056289 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9112 1051 0.00343 0.01751 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9112 1397 0.00301 0.015409 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9112 1584 0.00857 0.033091 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6168 6888 0.003341 0.01689 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7653 3019 3.90E-05 0.000219 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7341 7098 0.00087 0.00714 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4701 8267 0.00011 0.001 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1672 5365 0.000219 0.00101 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3880 5365 0.000219 0.001031 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6648 5365 0.000271 0.00101 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3609 5365 0.000271 0.000979 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2782 5365 0.000289 0.00107 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1844 5365 0.000289 0.00105 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4353 6053 0.001591 0.012289 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2166 5237 0.000271 0.001901 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2166 2886 0.00186 0.010711 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1043 3513 1.00E-05 0.0002 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4049 883 0.000169 0.000271 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4520 883 0.000169 0.00031 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1704 5814 0.00526 0.03787 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8107 1486 0.000229 0.000599 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5664 5522 0.00089 0.004091 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4482 8670 0.00093 0.004 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8795 7523 0.00289 0.013099 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2337 6430 0.002599 0.016479 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+455 7775 0.00369 0.02712 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+455 3857 0.0062 0.04864 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+455 333 0.008021 0.059031 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+455 6940 0.004979 0.0295 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8225 3656 0.001159 0.005281 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5413 7752 0.00361 0.01824 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5413 1940 0.001521 0.01075 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5413 4234 0.00868 0.041711 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2591 6828 0.01118 0.05986 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2591 7571 0.003229 0.02543 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2591 7571 0.00218 0.01869 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2591 7571 0.001901 0.021909 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2591 7994 0.00974 0.043969 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2591 7226 0.003461 0.01814 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2591 1554 0.00487 0.027669 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9011 1156 0.000651 0.003961 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8689 5502 0.00169 0.00887 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3085 8873 0.001711 0.01336 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1568 980 0.00031 0.000539 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3204 3331 0.0027 0.01157 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3557 639 0.000909 0.006901 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3557 4936 0.001729 0.01214 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+416 3492 0.00614 0.03106 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+416 7937 0.00418 0.02388 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3255 1262 0.00238 0.017771 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3255 1803 8.10E-05 0.00063 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7373 367 0.001599 0.01618 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4251 2132 0.00532 0.026961 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4251 2132 0.00361 0.02814 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4251 5567 0.002469 0.01025 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6376 1808 0.005229 0.02675 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6376 1808 0.00512 0.02726 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6376 7857 0.00355 0.01694 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9185 7289 0.00139 0.007659 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9185 3999 0.000169 0.000669 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8653 2303 0.00111 0.00712 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+908 6474 0.00031 0.001901 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7030 6474 0.000281 0.002091 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4205 6556 0.000281 0.001651 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7325 6556 0.000271 0.00169 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5857 3391 0.001521 0.00843 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5857 3760 0.000841 0.0062 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3707 8765 0.00019 0.00126 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+900 6619 0.000219 0.00143 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2918 8109 0.00121 0.01796 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2918 8109 0.0014 0.01512 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6532 2177 0.008409 0.063651 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6532 5317 0.00918 0.07344 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6532 608 0.004219 0.0345 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6532 608 0.0042 0.031651 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4494 8763 0.00121 0.01381 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4494 7056 0.00107 0.01326 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6828 5814 0.003401 0.02607 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3670 21 0.000289 0.00138 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5137 7702 0.001031 0.006039 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1334 7702 0.00105 0.005909 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8448 7624 0.001091 0.007901 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8448 1129 0.00332 0.024021 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8448 3070 0.00344 0.021419 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8448 306 0.00095 0.010419 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8448 306 0.00093 0.01062 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8448 7491 0.00474 0.025409 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4685 2089 0.000271 0.000841 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7485 6253 0.000271 0.00119 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7485 1562 0.000289 0.00076 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7776 1644 0.00031 0.00454 0 1842 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5971 3483 0.00032 0.0044 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2786 1644 0.00028 0.00494 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+972 3483 0.00028 0.00508 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8906 923 0.000531 0.00093 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8906 4914 0.0003 0.001031 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2656 9101 0.00139 0.02163 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2656 7164 0.00164 0.02321 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3519 9101 0.00136 0.02205 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3519 7164 0.0016 0.02367 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1775 9137 0.002091 0.01174 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1775 9137 0.001719 0.00961 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5641 1026 0.012341 0.076781 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5641 9137 0.00176 0.009419 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1096 2889 0.00031 0.00182 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7380 2732 0.00386 0.02348 0 1183 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7380 4787 0.00017 0.00104 0 1052 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3543 5308 0.00061 0.00808 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3543 3830 0.00059 0.0067 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2372 1027 0.00059 0.00748 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2372 5648 0.00061 0.0063 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+367 1172 0.001031 0.008789 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+367 9191 0.00051 0.006169 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+367 8722 0.0005 0.00619 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1833 3610 0.00049 0.00376 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1833 3610 0.000539 0.003229 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1833 3962 0.001031 0.00882 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1833 1838 0.000711 0.00463 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1833 2230 0.000711 0.004539 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5388 2467 0.00206 0.015341 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5388 2467 0.002021 0.01564 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6110 8853 0.00094 0.005781 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6110 1001 0.002219 0.016969 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7583 1808 0.00238 0.01187 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7583 2889 0.00707 0.03095 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+26 6624 0.00256 0.03401 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+26 2479 0.00203 0.02416 0 1052 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+26 4598 0.001 0.01459 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+26 4231 0.00103 0.00987 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+26 5144 0.00038 0.00483 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+26 5144 0.00041 0.00398 0 1216 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7691 2479 0.00167 0.01721 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7691 2129 0.00098 0.01487 0 887 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7691 9213 0.00042 0.00342 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7691 9213 0.00019 0.00248 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7691 4231 0.00105 0.00966 0 1809 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7691 3513 0.00043 0.00473 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7691 3513 0.00041 0.00397 0 1216 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1876 3906 0.00051 0.00514 0 1118 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+113 3906 0.00053 0.00503 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7752 3758 0.00455 0.022771 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7752 3758 0.00557 0.02055 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7752 3758 0.00339 0.02026 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4952 8976 0.00237 0.01068 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4952 8189 0.0037 0.019479 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6119 7886 0.01407 0.056849 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6119 4544 0.001669 0.015409 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6119 4544 0.001711 0.015091 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7905 3697 0.00172 0.01619 0 1578 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7905 7541 0.00029 0.00447 0 887 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7905 7541 0.00033 0.00387 0 1019 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7905 4141 0.00079 0.01154 0 887 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7905 4141 0.00077 0.01177 0 887 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7905 3022 0.00127 0.01498 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1768 163 0.00214 0.012599 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4245 2425 0.000159 0.00125 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3698 5297 0.000211 0.000669 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+750 8328 0.000341 0.001169 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+750 870 0.00024 0.001469 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+750 2961 0.00018 0.000669 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3499 7988 0.00033 0.00683 0 821 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3499 2197 0.00121 0.01211 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3499 7640 0.00123 0.01185 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3499 4231 0.00058 0.0097 0 1085 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3499 5144 0.00103 0.01292 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3499 3513 0.00116 0.01266 0 821 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7289 3999 0.0013 0.006841 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3018 1051 6.00E-05 0.000349 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2702 3435 0.000169 0.0007 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9131 2020 0.000169 0.000719 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6308 6684 0.000271 0.001031 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4831 3680 0.008271 0.036841 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5410 2751 0.002969 0.02299 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3082 4623 0.00124 0.01273 0 1118 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3082 4339 0.00106 0.00989 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3082 5288 7.00E-05 0.00029 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3082 5421 9.00E-05 0.00079 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3082 6475 0.00196 0.02049 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3082 8468 0.00158 0.01519 0 1183 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6224 2732 0.00172 0.01811 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6224 7513 0.00096 0.01121 0 1644 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6224 6475 0.00147 0.01707 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2174 4623 0.00129 0.0129 0 1216 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2174 4550 0.00179 0.01737 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2174 6475 0.00131 0.01935 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 9231 0.003901 0.01614 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 9231 0.002591 0.014771 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 9231 0.00224 0.0173 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 4054 0.00012 0.000849 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 3481 0.00394 0.03039 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 3602 0.00189 0.01 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 2794 0.00032 0.00257 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 2794 0.00038 0.00224 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 8467 0.00751 0.03955 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 1136 0.00086 0.006531 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2083 22 0.00087 0.006591 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8853 1001 0.003031 0.02276 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8853 4950 0.006331 0.03911 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8853 4410 0.00605 0.02986 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8853 6697 0.003919 0.01612 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8853 1159 0.002039 0.0108 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8853 7165 0.006289 0.026271 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2938 2848 0.00042 0.00547 0 756 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2938 2848 0.00043 0.00536 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2938 7522 0.00147 0.01373 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2938 7522 0.00131 0.01555 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2938 1642 0.00221 0.02217 0 1710 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2938 809 0.00224 0.0217 0 1710 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9189 6791 0.00095 0.003289 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9189 3400 0.000229 0.00082 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9189 7092 0.00068 0.00306 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9189 3718 0.00049 0.00256 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9189 3701 0.000531 0.0022 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9189 7507 0.00136 0.00956 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9189 7507 0.0012 0.010729 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9189 7507 0.00105 0.00861 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9189 2406 0.000591 0.006969 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2801 8511 0.00025 0.0008 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2801 216 0.00113 0.00632 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+453 2129 0.0003 0.00275 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8691 6952 0.00836 0.051659 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8691 6952 0.01338 0.073469 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8691 1183 0.0027 0.02089 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8691 4410 0.003419 0.02636 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8691 8743 0.009531 0.033711 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2446 8763 0.0004 0.00707 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2627 8763 0.00035 0.00701 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4951 6785 0.00194 0.01751 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4951 6785 0.00156 0.01936 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4623 964 0.00078 0.00941 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4623 964 0.00074 0.00969 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4623 8347 0.00042 0.00532 0 1578 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4623 8347 0.0004 0.00473 0 1743 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4623 8347 0.0006 0.00499 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1609 6552 0.00086 0.00638 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1609 6552 0.000969 0.00625 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1609 8999 0.002781 0.01725 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4368 4816 0.005031 0.028081 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5481 960 1.00E-05 0.00021 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7913 960 1.00E-05 0.00025 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+506 960 2.00E-05 0.00031 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2980 960 3.00E-05 0.0004 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4554 6382 0.000841 0.00474 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4554 6382 0.00082 0.00487 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6844 1595 0.00186 0.011979 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3672 5334 0.00056 0.003021 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6219 5334 0.00055 0.003081 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8997 6153 0.00114 0.01063 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1852 5935 0.003719 0.02295 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1852 5695 0.006669 0.04288 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2931 5799 0.00243 0.0198 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2931 7124 0.00845 0.04339 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2598 3674 0.00219 0.015169 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2598 2132 0.00357 0.0302 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2558 7571 0.005849 0.032419 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8834 1129 0.00406 0.01688 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7377 3324 0.00113 0.0065 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1265 4426 0.0068 0.04613 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1265 1965 0.00337 0.02011 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8060 7162 0.00011 0.0005 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6922 5482 0.003711 0.018521 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6922 1295 0.000271 0.00145 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8369 4710 0.00326 0.01824 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8961 7133 0.00118 0.00712 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8961 6888 0.00482 0.02232 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4185 7019 0.00013 0.000469 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4185 6253 0.000229 0.00075 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7895 3391 0.004591 0.035021 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7895 1448 0.005469 0.03924 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7895 1448 0.00536 0.0403 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7895 115 0.00424 0.033031 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 4306 2.00E-05 0.00024 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 1763 1.00E-05 0.00021 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 3697 0.00286 0.03653 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 3794 0.00117 0.01183 0 1644 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 3613 0.00103 0.01336 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 1502 0.00156 0.01969 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 6555 0.00449 0.05772 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 3608 0.00259 0.03469 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 4134 0.000219 0.00118 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 1979 6.00E-05 0.00095 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 516 6.00E-05 0.000651 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 3580 8.10E-05 0.000841 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 3809 0.00274 0.020831 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 5616 0.004781 0.027729 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 5616 0.002849 0.02093 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 6697 0.00513 0.03014 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 7165 0.00113 0.00651 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1001 892 0.00125 0.00707 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7438 5334 0.003349 0.01463 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7438 1526 0.00245 0.0122 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1301 6952 0.00587 0.036521 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1301 6952 0.00569 0.03774 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1301 6952 0.006031 0.03545 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1301 7883 0.000531 0.00301 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1301 6430 0.00076 0.006099 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+778 7209 0.008841 0.028919 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+778 1910 0.00169 0.007091 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+778 6820 0.001031 0.00361 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+778 3071 0.00813 0.030961 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5297 6267 0.00013 0.00068 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3657 3855 0.000211 0.000729 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3657 3855 0.000169 0.000669 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3657 2928 0.000669 0.00251 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3657 2928 0.000711 0.00238 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3657 1172 0.000229 0.00238 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3657 9191 0.0007 0.0065 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3657 8722 0.00061 0.006031 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6472 5362 0.000281 0.0018 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6472 3962 0.000211 0.002409 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1198 1343 0.00056 0.00773 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1198 29 0.0023 0.01581 0 1118 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7473 3680 0.005039 0.032151 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7473 96 0.00364 0.01713 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7473 1868 0.002169 0.012409 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+346 3184 0.00113 0.004719 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+346 6570 0.00113 0.004979 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3184 4728 0.00264 0.01174 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2654 7886 0.00494 0.03181 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2654 2132 0.003711 0.023961 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4144 8874 0.001409 0.01101 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4144 1625 0.001169 0.00593 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4144 1625 0.00118 0.00587 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4144 3786 0.00264 0.012469 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4144 3786 0.002349 0.01414 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3422 4100 0.00014 0.0007 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 4419 3.00E-05 0.00054 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 7159 3.00E-05 0.00055 0 1710 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 3661 4.00E-05 0.00058 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 5486 4.00E-05 0.00054 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 4231 0.00171 0.02197 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 4231 0.00164 0.02064 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 6921 0.00136 0.01756 0 1611 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 432 0.00097 0.00942 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 432 0.00086 0.01109 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6624 432 0.00085 0.0113 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3353 6887 0.000979 0.0058 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2479 2050 0.00052 0.00593 0 1809 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2479 2050 0.00046 0.00672 0 1809 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5482 8704 0.001151 0.00636 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5482 8704 0.001031 0.007211 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5482 4710 0.002341 0.02286 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5482 1295 0.002281 0.02518 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5482 1910 0.005479 0.02114 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5482 2985 0.011159 0.08856 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5482 5853 0.000669 0.00249 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5482 7824 0.00193 0.01643 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5482 3071 0.00024 0.0017 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4525 195 0.010159 0.065849 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9066 7367 0.00294 0.02131 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9066 9155 0.018841 0.07469 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9066 6357 0.015599 0.052169 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7886 3126 0.005831 0.03969 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7886 8564 0.00087 0.00661 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7886 5567 0.00637 0.024659 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6416 3069 0.0027 0.020419 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6416 3876 0.000409 0.00314 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6416 8804 0.001669 0.01301 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6416 8804 0.00164 0.01325 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7831 4550 0.00089 0.00556 0 1183 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7831 4125 0.00186 0.01809 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7831 3346 0.00381 0.02853 0 920 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5525 2377 0.012419 0.072151 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5525 1401 0.0042 0.02556 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5525 2850 0.010771 0.0493 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5525 2430 0.010159 0.04995 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5525 9164 0.013169 0.05113 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8511 1033 0.000469 0.001159 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8511 6178 0.000229 0.00105 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3400 980 0.000271 0.001271 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2101 4598 0.00099 0.01194 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2101 4541 0.00077 0.01184 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2101 5144 0.00034 0.00426 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3919 2129 0.00101 0.01168 0 1644 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3919 4541 0.00086 0.01046 0 1710 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3919 3513 0.00035 0.00417 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6675 1486 0.000159 0.00069 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4711 5836 0.000781 0.00488 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4711 575 0.000781 0.00511 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4711 8214 0.00064 0.003539 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4711 8214 0.00057 0.003781 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4711 3021 0.000531 0.00111 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4711 7967 0.000521 0.00113 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4711 5993 0.00176 0.00843 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4711 8804 0.002461 0.01975 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4513 6831 0.000591 0.00105 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2043 1422 0.00012 0.00064 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6714 1808 0.000581 0.004419 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6371 1808 0.000651 0.004331 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+513 2866 0.001289 0.008289 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4970 9222 0.00233 0.03502 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4970 9222 0.00238 0.03781 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4970 2072 0.00052 0.00605 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4970 5461 0.00023 0.00275 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4970 8109 0.00134 0.01343 0 1611 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4970 8109 0.00116 0.01552 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7955 707 0.004169 0.027919 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7955 4816 0.00063 0.008 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7955 1866 0.004841 0.028581 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7955 5488 0.007419 0.05787 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5093 2467 0.002719 0.020331 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2328 7178 0.000789 0.005 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9180 195 0.00238 0.013219 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9180 3133 0.003771 0.02701 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+292 4544 0.001271 0.00939 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9002 6737 0.000841 0.00131 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8439 3758 0.005711 0.043039 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8439 3758 0.00562 0.041901 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4974 2940 0.00356 0.019781 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4974 163 0.004841 0.03149 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+747 8507 0.00057 0.00107 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6909 4914 0.000539 0.00213 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+444 4747 0.0007 0.00425 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1459 6495 0.0012 0.009531 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1459 2751 0.00206 0.015901 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3601 4728 0.00063 0.00312 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1251 6475 3.00E-05 0.00041 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1093 6475 2.00E-05 0.00043 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5709 6475 3.00E-05 0.00039 0 1183 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3825 6475 3.00E-05 0.00038 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1415 3503 0.0008 0.004151 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4549 3503 0.000901 0.00381 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3072 639 0.000591 0.004341 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3072 639 0.000591 0.00405 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5007 4541 0.00218 0.0275 0 1052 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5007 8195 0.00184 0.01677 0 986 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+757 964 0.00058 0.00807 0 986 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+757 964 0.00056 0.00823 0 821 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+757 3906 0.00123 0.01146 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+757 3906 0.0011 0.01298 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+757 8347 0.00156 0.01585 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+757 2919 0.00226 0.02781 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3758 188 0.00614 0.02831 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3758 2242 0.00513 0.03401 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3903 4114 0.013219 0.0597 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5743 6990 0.012969 0.06087 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8626 8930 0.00437 0.032831 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8626 2467 0.005651 0.033229 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2161 5488 0.008969 0.03625 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2161 7772 0.012409 0.05645 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5003 6382 0.00038 0.002271 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6474 4084 0.00138 0.01089 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6474 4084 0.001539 0.012521 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6474 53 0.00205 0.014229 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6474 7259 0.00026 0.00164 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6474 2475 0.000289 0.00169 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5334 7577 0.003349 0.051211 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7961 2288 0.00038 0.001479 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1592 7098 0.00082 0.00625 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3187 2079 0.00275 0.015581 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6041 5926 0.000909 0.00739 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3697 8486 0.00082 0.01038 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3697 7530 0.00093 0.01017 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3697 1502 0.00137 0.01431 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3697 1552 0.00215 0.02021 0 1578 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6952 3793 0.01189 0.058841 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6738 2526 0.00104 0.01241 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6738 2526 0.00092 0.014 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6738 2365 0.00055 0.00845 0 1052 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6738 2365 0.00054 0.00861 0 887 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6738 3794 0.00105 0.01057 0 1710 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6738 3613 0.00089 0.01122 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6738 6901 0.00223 0.02584 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8180 5106 0.00101 0.007841 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8180 5106 0.001081 0.008099 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6240 7165 0.011081 0.068479 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9222 8721 2.00E-05 0.00033 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9222 8872 1.00E-05 0.00029 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9222 8672 0.00071 0.00892 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9222 7164 0.00136 0.01526 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5935 7772 0.005401 0.036021 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3134 3430 0.00437 0.033719 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3134 1051 0.005151 0.034919 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+283 800 0.00038 0.00139 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+283 1077 0.00037 0.0015 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+283 4747 0.00069 0.004461 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3391 5213 0.00688 0.040591 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3391 115 0.001341 0.008349 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3391 115 0.001229 0.009669 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4867 5753 0.00137 0.006039 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7539 6556 0.001919 0.01261 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7539 871 0.00163 0.0095 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8893 8874 0.00488 0.0497 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8893 4505 0.001289 0.0087 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8893 3436 0.00211 0.01524 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8893 3436 0.00206 0.015539 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8893 3436 0.00276 0.01631 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8893 6556 0.00305 0.019521 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8893 8765 0.000409 0.0023 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8893 6619 0.00036 0.00268 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8165 6734 0.00032 0.00049 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1078 6734 0.00013 0.000349 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7988 4231 0.0002 0.00327 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+804 2142 0.000919 0.00561 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+804 2142 0.00094 0.00549 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+804 7519 0.00175 0.01976 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+804 6744 0.001729 0.019331 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2286 6802 0.00406 0.02581 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2286 769 0.00526 0.025961 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3239 1081 0.00179 0.02098 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3239 5983 0.00162 0.02148 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3239 8267 0.00492 0.04991 0 953 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3239 960 0.00109 0.01361 0 986 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3239 960 0.00097 0.0153 0 789 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3239 3906 0.00322 0.03022 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1539 7361 0.032831 0.074151 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1539 6852 0.01411 0.058711 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1539 8515 0.02725 0.102979 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1539 3166 0.012229 0.04049 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1539 2676 0.01994 0.066719 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1539 3793 0.018591 0.07462 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1539 4529 0.008979 0.03251 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1539 4234 0.016531 0.086031 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8628 44 0.003591 0.02137 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8628 6630 0.00124 0.008 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8628 6630 0.001271 0.007831 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8628 1545 0.000469 0.00294 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8628 4215 0.000841 0.003289 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7163 1917 0.00219 0.016539 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7163 5519 0.002901 0.020901 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7647 225 0.0002 0.001211 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4864 1397 9.10E-05 0.000479 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7021 7119 0.005461 0.029469 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7021 3324 0.001979 0.011289 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1248 163 0.0023 0.01289 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9045 2457 0.000159 0.00037 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8874 3786 0.002789 0.01562 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5891 5574 0.002531 0.012331 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5891 7663 0.00357 0.023289 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5891 4889 0.00076 0.006039 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3997 1526 0.000469 0.00075 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+184 1526 0.00044 0.00069 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2972 2088 0.00561 0.035521 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8676 933 0.004539 0.03468 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8676 933 0.00175 0.0067 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8676 3643 0.007461 0.031419 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8704 6723 0.00224 0.012909 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7047 21 0.0003 0.000961 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7047 21 0.00032 0.001409 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7047 1551 0.002031 0.0157 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7047 4103 0.00038 0.00306 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7047 7862 0.00118 0.0083 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7047 5458 0.001229 0.00787 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5574 5666 0.00301 0.01538 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6742 5458 0.00063 0.00114 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5270 7862 0.00064 0.00111 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7775 3857 0.004919 0.03837 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6290 3436 0.001831 0.008349 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3430 401 0.00536 0.03188 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2967 8976 0.00038 0.001461 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2967 8976 0.000289 0.001521 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8976 2481 0.00305 0.016841 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8976 9108 0.001781 0.012729 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2056 7520 0.00041 0.00461 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2056 7520 0.0004 0.0047 0 920 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4084 5340 0.00213 0.01401 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4084 2319 0.001271 0.00887 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4084 2878 0.00462 0.02743 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2597 7422 0.001539 0.00776 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7183 8931 0.00025 0.00478 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5379 8931 0.00025 0.00487 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8128 8931 0.00025 0.00435 0 723 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6337 8931 0.00026 0.00426 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1237 8931 0.00025 0.00479 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4127 9173 0.000169 0.00076 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4127 7974 0.00039 0.00126 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2432 4816 0.011229 0.074659 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2432 1866 0.014521 0.058081 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2432 8809 0.00064 0.003919 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2432 5146 0.014789 0.07768 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2432 6940 0.00938 0.05355 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2432 1742 0.00124 0.004289 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5213 8627 0.00968 0.04388 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5213 174 0.008531 0.067151 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5213 7437 0.00731 0.04106 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7342 5940 0.004349 0.02555 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7342 7495 0.00599 0.03462 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8808 4816 0.002961 0.021591 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8808 4816 0.002901 0.02206 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8808 6053 0.002979 0.016969 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5764 4189 0.00312 0.020021 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8507 1973 0.000219 0.000909 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1394 1973 0.000219 0.00093 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2898 2128 0.000151 0.000289 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4942 8255 0.00563 0.043599 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4942 4748 0.000969 0.00612 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3486 3594 0.005021 0.020719 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3486 4679 0.00988 0.041039 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4656 4235 0.003159 0.02011 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4656 4235 0.003219 0.01969 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7129 5441 0.00049 0.00238 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7129 5441 0.000479 0.002419 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8250 5720 0.00264 0.019729 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8250 5720 0.002581 0.02011 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6831 6723 0.00037 0.002831 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6831 5686 0.00213 0.012789 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2377 805 0.018669 0.092281 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+907 9091 3.90E-05 0.000401 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4056 9091 6.00E-05 0.00044 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6837 2142 6.00E-05 0.0005 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5666 2641 0.001271 0.007031 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5666 7577 0.00055 0.003159 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5666 7577 0.00055 0.00338 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5666 7577 0.00105 0.004771 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5666 1629 0.003289 0.015039 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+726 687 0.00036 0.004349 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3526 687 0.00038 0.003669 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6382 2425 0.00118 0.00701 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6382 2425 0.001229 0.00686 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6382 5907 0.00301 0.0217 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6382 5907 0.003409 0.01924 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6382 5907 0.003409 0.01938 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7847 9217 0.002719 0.02131 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2981 1448 0.00295 0.01956 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5110 5686 0.001091 0.00831 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2968 5907 0.00111 0.008211 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5441 2155 0.002469 0.015271 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5441 8112 0.00212 0.01601 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5441 2535 0.00037 0.0028 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5441 7098 0.00162 0.01238 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5441 7098 0.001909 0.01162 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5441 7098 0.001909 0.010729 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5441 3737 0.00089 0.00526 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5441 5529 0.00087 0.00536 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5441 5753 0.001521 0.01176 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9019 6563 0.00014 0.000591 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1341 1101 0.003531 0.028781 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2797 8291 0.004599 0.03657 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2797 8367 0.00307 0.019159 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2797 1100 0.000581 0.004461 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2797 6887 0.00164 0.01161 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4939 6880 0.00057 0.003281 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7738 6982 0.020419 0.063669 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6565 3121 0.01424 0.04751 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8707 280 0.00157 0.008849 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8707 2510 0.01218 0.07524 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1625 766 0.00037 0.00151 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8411 6232 0.000219 0.000531 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3951 1397 0.002849 0.0137 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+964 7282 0.00116 0.01692 0 1183 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+964 7282 0.00133 0.01462 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+964 6475 0.00063 0.00821 0 887 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+964 6475 0.00064 0.00804 0 1183 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5658 5420 0.00126 0.01272 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5658 8267 0.00337 0.0494 0 1644 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5658 7328 0.0014 0.0214 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5658 7328 0.00137 0.02182 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5658 7164 0.00212 0.02063 0 1118 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5550 410 0.00186 0.01045 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5550 7579 0.00426 0.021771 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5550 7579 0.002659 0.020539 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5550 4189 0.00606 0.049919 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7282 4196 0.00109 0.01192 0 789 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1526 3916 0.013021 0.049219 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1526 4747 0.00236 0.01239 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1526 4747 0.0027 0.015169 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4541 3346 0.00285 0.03283 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4541 3346 0.00529 0.03969 0 920 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1343 3346 0.00254 0.03721 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3680 2719 0.000159 0.00069 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3680 2719 0.000229 0.000979 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3680 2719 0.00024 0.00082 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3680 795 0.000169 0.00075 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3680 4880 0.00368 0.01756 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3680 1868 0.002599 0.020659 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7464 5564 0.00018 0.00064 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7464 7036 0.000159 0.000771 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7464 5940 0.00357 0.01981 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7464 7495 0.006021 0.03205 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4850 2886 0.001781 0.01164 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4850 7049 0.002781 0.018831 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2510 6146 0.000349 0.00281 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+90 1860 0.00313 0.02444 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+90 1860 0.00368 0.02074 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2142 3276 9.10E-05 0.001539 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2142 3545 0.00251 0.01111 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2142 6842 0.003081 0.017961 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2142 6744 0.005341 0.030419 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2142 7635 9.90E-05 0.00126 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9091 1040 0.002169 0.017901 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2457 6178 0.00011 0.00038 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1422 1462 0.00212 0.00494 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1422 7772 0.018901 0.077349 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7881 5365 0.00957 0.0395 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7881 6982 0.02324 0.063469 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6926 3327 0.000531 0.004331 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1959 615 0.002581 0.006229 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6455 1262 0.00031 0.002211 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+803 6982 0.01087 0.06114 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+803 5918 0.011581 0.061099 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7624 3070 0.002099 0.016271 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+500 1547 0.00093 0.005461 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+500 5237 0.009591 0.037039 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+500 772 0.002591 0.017211 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+500 8950 0.00164 0.013651 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2754 2079 0.003219 0.014719 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2754 2229 0.00401 0.022229 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2754 7049 0.00126 0.010211 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4118 7873 0.009169 0.03993 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4118 3865 0.001349 0.006081 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1754 8486 0.00156 0.01931 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1754 7530 0.00152 0.01968 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1754 7778 0.00094 0.01433 0 1578 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1754 6897 0.00092 0.01461 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1754 960 0.00137 0.02012 0 1019 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1754 960 0.00134 0.02051 0 821 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3857 4491 0.00314 0.042151 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3857 6010 0.000651 0.00494 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3857 6940 0.003961 0.02426 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+858 1642 0.00013 0.0015 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3028 809 0.00013 0.00147 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4819 1642 0.00011 0.00172 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2035 809 0.00012 0.00166 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3869 1642 0.00012 0.00168 0 1809 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3741 809 0.00012 0.00172 0 1809 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+742 687 0.00093 0.005669 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2910 7098 0.00105 0.00506 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5688 6231 0.00113 0.006539 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5182 5455 0.00037 0.002919 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+707 5695 0.005169 0.03738 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3814 954 0.00125 0.006669 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2313 2438 0.001281 0.00661 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+195 2985 0.00226 0.0138 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2518 3513 0.00213 0.02677 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2518 3346 0.00154 0.01919 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4544 601 0.00687 0.04413 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4544 3241 0.0045 0.04725 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4544 7338 0.00138 0.00837 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3069 1538 0.000419 0.001901 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3069 1538 0.00043 0.00186 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6115 4729 0.003331 0.015099 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3344 6616 0.002099 0.01631 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3809 5616 0.001331 0.01082 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3809 6691 0.00199 0.00818 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3809 6691 0.00169 0.008831 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1326 892 0.001771 0.014281 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+601 616 0.003099 0.01844 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3496 1551 0.003409 0.01819 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4925 2230 0.00057 0.00369 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8057 5907 0.001081 0.00468 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5354 5907 0.00105 0.004771 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3674 616 0.001979 0.01549 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3674 7338 0.001469 0.015151 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5836 5083 0.000711 0.003969 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5836 7576 0.00051 0.00274 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5836 3191 0.000521 0.00306 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5836 3488 0.00188 0.011841 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5836 1578 0.002469 0.010539 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+575 5300 0.00045 0.00351 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3929 9173 0.00037 0.000659 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2089 3818 0.000401 0.0007 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2089 6232 0.00014 0.000531 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2089 1643 0.000289 0.0013 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2089 6253 7.00E-05 0.000289 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2089 6684 0.00051 0.002151 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2089 8151 0.00037 0.00157 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5067 449 0.00022 0.00277 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5067 449 0.00025 0.00271 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7641 3037 0.000271 0.002081 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7641 3037 0.00025 0.00231 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3191 2340 0.00095 0.00331 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3191 8711 0.00093 0.00336 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8104 8722 0.000341 0.002211 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2644 9191 0.00032 0.00232 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4128 8522 3.90E-05 0.000271 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+604 7522 0.00075 0.0101 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+604 4000 0.00118 0.01455 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2155 9021 0.0017 0.0098 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2155 9021 0.001521 0.01111 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2155 2042 0.000169 0.001401 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2155 687 0.002591 0.01725 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2155 3520 0.000169 0.001159 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2155 4729 0.00307 0.01339 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2641 4889 0.002591 0.013521 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9067 9051 0.000581 0.005031 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6969 5573 0.001419 0.00595 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+666 1494 0.00205 0.02664 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+666 2732 0.00295 0.03721 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+666 4550 0.00335 0.03648 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+666 1607 0.00022 0.00251 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+666 2093 0.00059 0.00651 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3565 2177 0.008539 0.041979 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3565 2841 0.001349 0.0052 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3611 7972 0.00245 0.013909 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3611 2481 0.001469 0.008419 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5420 7164 0.00084 0.00836 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7119 2078 0.002591 0.017789 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7119 7873 0.009651 0.05968 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7422 7519 0.00143 0.00799 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7422 6744 0.001969 0.014909 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1026 1860 0.01039 0.06406 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4765 3327 0.000719 0.005331 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6036 6921 0.00052 0.00565 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8670 7069 0.002409 0.019479 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8670 7069 0.00256 0.019151 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8670 2866 0.00656 0.02288 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4032 6450 0.0027 0.014901 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4032 5738 0.003591 0.01362 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7327 2481 0.002211 0.01188 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7327 8189 0.00068 0.00357 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7474 1584 0.000211 0.000969 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8947 3390 9.90E-05 0.000539 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1808 6384 0.00645 0.0263 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4624 6031 0.00063 0.001901 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1721 3558 0.000281 0.000669 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7694 3865 0.000219 0.00064 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9181 6723 0.00014 0.00105 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8373 8748 0.003219 0.020729 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8373 8475 0.00051 0.003151 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8373 8475 0.000409 0.00331 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5630 6639 0.002289 0.017479 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5630 1187 0.002831 0.01895 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5630 7274 0.006289 0.036521 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5630 8992 0.005651 0.032169 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5630 7266 0.00414 0.02262 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3492 6734 0.01095 0.05814 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3492 1015 0.009 0.0368 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3492 8310 0.000229 0.00181 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1980 6570 0.00119 0.00726 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9137 749 0.011771 0.051669 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7522 2183 0.00209 0.02279 0 1611 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7571 3916 0.002031 0.01443 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7571 6891 0.00145 0.008479 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2526 6199 0.00124 0.01433 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2526 6199 0.00127 0.01402 0 1776 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1483 3649 0.013039 0.052841 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2365 6199 0.00235 0.02739 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2365 6199 0.0024 0.02681 0 1118 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2365 4141 0.00135 0.02056 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2365 1311 0.00087 0.01124 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8316 174 0.0012 0.00818 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+174 6430 0.006961 0.05561 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5340 7892 0.00105 0.00763 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5340 561 0.000219 0.00182 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5340 8843 3.90E-05 0.0002 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5340 8843 4.50E-05 0.000195 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5340 4239 0.0035 0.022651 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3866 1860 0.004281 0.02319 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3866 5395 0.003729 0.014021 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7042 2177 0.00212 0.01582 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8672 7164 0.00056 0.00784 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1860 7772 0.004401 0.01813 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1860 7772 0.005021 0.02144 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4885 2928 0.00018 0.000219 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4157 2928 0.000151 0.000211 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4432 2928 0.000151 0.000211 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2072 5983 0.00282 0.02591 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3450 6552 0.00131 0.008539 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3956 7507 0.002159 0.015969 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5286 1838 0.00019 0.000281 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5571 2230 0.0002 0.000281 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2078 8005 0.00139 0.00774 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+639 6351 0.01101 0.06739 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+639 2749 0.00063 0.00463 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+639 9130 0.002341 0.009599 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+410 4189 0.00375 0.021659 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1494 5781 0.00056 0.00749 0 1183 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+583 6616 0.00118 0.00926 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+583 6031 0.002039 0.013081 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1746 7507 0.00155 0.010961 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3276 7635 3.90E-05 0.00036 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1105 196 0.00024 0.000409 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8522 7132 0.000341 0.001659 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8522 5351 0.005461 0.024919 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8763 7056 0.00158 0.02413 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8763 8825 0.00155 0.02458 0 756 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8763 6889 0.00021 0.00256 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8763 6889 0.00024 0.00243 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8763 8887 0.00144 0.02266 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8763 8887 0.0014 0.02098 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8763 8487 0.00086 0.01074 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8748 8475 0.003341 0.02611 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+217 6785 0.00387 0.02063 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+217 6785 0.00405 0.018271 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+217 1179 0.00101 0.00462 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+217 2575 0.00088 0.00389 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+217 7274 0.005081 0.039 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7972 8189 0.00257 0.0208 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7972 8189 0.00251 0.01926 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7972 1039 0.002531 0.01314 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7253 7840 0.00132 0.00869 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4395 8913 0.00082 0.004021 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4395 4852 0.00143 0.007479 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2795 1183 0.000659 0.005771 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2795 1183 0.000591 0.006539 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1305 6291 0.00589 0.025599 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1305 6982 0.00614 0.02343 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2732 1798 0.00155 0.01994 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2732 3346 0.00205 0.03218 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4550 3346 0.00233 0.03154 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4725 5738 0.002341 0.01982 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1083 8310 8.10E-05 0.000521 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1398 5567 9.90E-05 0.00069 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4281 4580 0.00276 0.016419 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7050 4908 0.00036 0.001229 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7050 3740 0.000229 0.000711 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6563 870 0.00013 0.00099 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8999 6495 0.001159 0.00689 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6888 5994 0.008531 0.03045 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5400 8005 0.000781 0.004531 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5400 8005 0.00075 0.00474 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5881 4031 0.002159 0.008349 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8195 8334 0.00162 0.01651 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+933 6357 0.01236 0.044211 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+933 6357 0.00825 0.03989 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+933 3775 0.02187 0.066961 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+933 3975 0.01212 0.06661 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3918 1642 0.00036 0.00534 0 789 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6802 1153 0.000229 0.00063 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6802 7599 0.000219 0.000581 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4025 3994 0.000281 0.00063 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1595 1414 0.005021 0.035659 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3114 3656 0.00174 0.007901 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5237 2229 0.003919 0.020581 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5237 9108 0.003341 0.016349 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5237 1478 0.003271 0.016669 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2799 8515 0.000151 0.000659 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6405 7873 0.00736 0.035659 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6405 3894 0.00944 0.042169 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4435 4734 0.00068 0.00652 0 756 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4435 3483 0.00188 0.02281 0 1282 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2079 7052 0.00168 0.00956 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2079 7052 0.001669 0.00981 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2079 772 0.002229 0.01599 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2079 772 0.00218 0.01631 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1081 6475 0.00238 0.02124 0 953 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1081 6475 0.00194 0.02023 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7361 3166 0.013831 0.05955 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7361 426 0.00876 0.04875 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2863 1857 0.0002 0.00099 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1364 2430 0.00105 0.00826 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2177 749 0.0172 0.06637 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3594 2850 0.00305 0.015781 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6555 3608 0.00208 0.02105 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8475 1965 0.00614 0.043729 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8475 5926 0.000229 0.001849 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5735 6053 0.00386 0.025789 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5735 2341 0.002031 0.012 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2629 7507 0.000591 0.004 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1137 2406 9.10E-05 0.00051 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7577 5814 0.00732 0.039969 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7577 3231 0.004581 0.02031 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7663 5814 0.00132 0.00537 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1183 1159 0.007521 0.0387 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6852 5051 0.005159 0.031281 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8307 8807 9.90E-05 0.001159 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6947 8807 9.90E-05 0.00113 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4505 4357 0.00019 0.000909 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7144 7791 0.00107 0.00413 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6889 2085 9.00E-05 0.00058 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6889 4024 9.00E-05 0.00059 0 1052 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6889 9065 8.00E-05 0.00053 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6889 661 8.00E-05 0.00052 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6612 8864 0.000271 0.00151 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8931 6199 0.00053 0.00585 0 1809 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8931 6199 0.00047 0.00663 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8931 6199 0.00046 0.00676 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8931 6199 0.00045 0.00689 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8931 8494 0.00028 0.00338 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8931 8494 0.0003 0.00319 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1643 4511 0.00025 0.00101 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+196 1973 0.000281 0.00119 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2902 5573 0.00018 0.00063 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4950 4410 0.00382 0.02868 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4950 333 0.00361 0.0235 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4950 6908 0.00538 0.03569 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3377 7726 6.00E-05 0.000409 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1027 3243 9.00E-05 0.00102 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1027 2458 0.0014 0.01649 0 1611 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1027 2919 0.00034 0.00427 0 1019 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5308 8560 0.0001 0.00109 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5308 6427 0.00137 0.01682 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5308 8347 0.00131 0.01262 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7148 5610 0.00262 0.019669 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7148 2421 0.00082 0.00526 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7148 2421 0.000841 0.005151 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7148 2421 0.000669 0.005081 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7148 6989 0.001919 0.012669 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+44 1545 0.002659 0.02 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+44 3541 0.003031 0.02343 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6231 4710 0.01176 0.059159 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6231 8367 0.002469 0.017531 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6231 2288 0.000669 0.005729 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8291 8473 0.000781 0.00876 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8291 5455 0.00062 0.00482 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8291 7635 0.001349 0.012599 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6842 8473 0.000979 0.0082 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6842 883 0.008091 0.028831 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6842 2288 0.000711 0.005969 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3969 7726 0.00145 0.00857 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1090 1129 0.00869 0.03768 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1090 3070 0.001719 0.00837 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8515 5365 0.01582 0.067349 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8515 5365 0.01457 0.06469 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8515 4529 0.021711 0.090539 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8515 3364 0.00019 0.000729 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+935 5383 0.001271 0.00638 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+920 6570 3.90E-05 0.0002 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6664 4426 0.000281 0.00236 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4339 2183 0.00019 0.00329 0 1644 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7513 4000 0.00035 0.00324 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6570 8542 0.00049 0.00349 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6570 8542 0.000469 0.00331 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6570 1662 0.00313 0.01324 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6570 9119 0.001031 0.006719 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6570 1151 0.00038 0.00401 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+502 3589 0.00037 0.002849 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8473 1040 0.00032 0.00256 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8473 145 0.00037 0.00118 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8473 4267 0.00068 0.001151 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4936 5179 0.00168 0.009841 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5317 8854 0.000599 0.002401 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9018 4 0.002169 0.00911 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9018 4829 0.002849 0.01282 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6253 5383 0.001229 0.01207 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6253 7507 0.001289 0.01089 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8887 1644 0.00093 0.01036 0 756 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8887 3483 0.00083 0.01174 0 723 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6639 7840 0.00118 0.009469 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6639 7840 0.001151 0.009651 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5461 8109 0.00101 0.01327 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6291 4189 0.00364 0.02486 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8405 4747 0.00056 0.00425 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8405 4580 0.00369 0.02681 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+338 7824 0.000531 0.00276 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2468 7824 0.000521 0.00281 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5257 7824 0.000419 0.00232 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2189 7824 0.000409 0.00237 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8458 8267 0.00014 0.00193 0 1414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2676 5987 0.003211 0.01481 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1187 5712 0.00381 0.01175 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1187 6521 0.003781 0.02676 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2360 8636 0.000919 0.005461 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2360 8829 0.000271 0.001211 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2360 4235 0.002229 0.017401 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2360 4235 0.00243 0.017659 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2360 4235 0.002531 0.01705 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8818 5099 0.012531 0.05451 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5781 4734 0.00087 0.01212 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5781 905 0.0006 0.00802 0 1611 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5781 8334 0.00072 0.00667 0 1743 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5781 2093 0.00234 0.02626 0 1315 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6772 6989 0.00038 0.002969 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7885 3912 0.00024 0.00045 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6730 3912 0.000229 0.000409 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4301 3912 0.000281 0.000401 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5362 5610 0.001211 0.005271 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5362 350 0.000281 0.00107 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5362 6763 0.00025 0.001091 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3855 1973 0.00019 0.00081 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3855 1973 0.00045 0.00136 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3481 554 0.003461 0.023289 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5460 8222 0.0013 0.01609 0 1743 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5460 8222 0.00128 0.0164 0 1611 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5460 2721 0.00089 0.01082 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5460 2721 0.00087 0.01102 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3786 8578 0.003349 0.02514 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+490 2653 0.0003 0.00061 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+148 7069 0.000289 0.001211 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7256 8743 0.01301 0.044091 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7256 1742 0.02162 0.065969 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8930 314 0.006461 0.05275 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6954 7974 0.0002 0.000271 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3325 7974 0.00018 0.00026 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5627 1742 0.00032 0.00188 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5610 6989 0.00105 0.006591 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+21 6163 0.00013 0.00055 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3749 5365 0.006151 0.04013 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3749 6982 0.007159 0.040591 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2291 3133 0.00874 0.048461 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2291 4738 0.004159 0.01606 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2291 3656 0.002919 0.01912 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+314 4300 0.00094 0.00394 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+314 5789 0.000901 0.00395 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+314 2467 0.003159 0.017789 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+314 2467 0.002419 0.018331 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+314 5256 0.00375 0.018281 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3200 2653 0.00025 0.001031 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4679 4852 0.00264 0.01238 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4679 4852 0.001289 0.00795 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4679 1151 0.00087 0.003081 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8568 5215 0.000401 0.00224 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+58 221 0.0003 0.00385 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6807 851 0.00126 0.008219 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+150 5099 0.01905 0.055729 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+150 3558 0.00201 0.00444 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7209 2934 0.00101 0.00324 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1465 4787 0.00105 0.00677 0 1118 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1465 3830 0.00039 0.00502 0 1052 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1465 5648 0.0004 0.00492 0 854 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1465 4000 0.00051 0.00617 0 1249 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7537 3485 0.0003 0.00314 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7537 3830 0.00051 0.00668 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7537 5648 0.0005 0.00678 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1262 2424 0.002909 0.017 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1262 1156 0.00245 0.011281 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1262 4914 0.0027 0.01532 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1262 4914 0.00105 0.011151 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1262 3834 0.00036 0.002669 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1262 556 0.0018 0.011169 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1262 3019 0.000711 0.007771 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1262 7923 0.00036 0.00257 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1551 4103 0.00201 0.01195 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1551 7862 0.001091 0.00731 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1551 5458 0.00105 0.007591 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1551 1838 0.00299 0.02256 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3070 2888 0.00036 0.00288 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4874 4504 0.00589 0.045599 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4874 3579 0.00157 0.0127 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4874 3579 0.00168 0.011969 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4874 7903 0.00289 0.021031 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6368 1102 0.00395 0.025211 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6368 9217 0.002771 0.021659 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6368 5653 0.002979 0.016901 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8478 5907 0.007419 0.034021 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5241 6921 0.00056 0.00813 0 789 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4 1813 0.00361 0.015211 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8950 7049 0.000409 0.003331 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6846 8788 0.004091 0.019599 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6846 6734 0.00294 0.012841 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4426 5616 0.020771 0.080479 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4426 1965 0.00662 0.0513 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4426 1767 0.00607 0.04581 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3037 1102 0.000669 0.0042 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3037 8485 0.001271 0.007419 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3037 5653 0.001599 0.012271 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5395 4661 0.009599 0.05024 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5395 520 0.00149 0.009219 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5395 6816 0.01488 0.06724 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5395 5918 0.003599 0.024031 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5395 5918 0.00519 0.024 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8636 1380 0.003461 0.013349 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3436 4239 0.00105 0.01236 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3436 4239 0.00199 0.012331 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3436 3656 0.00711 0.044711 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6203 7124 0.006729 0.02543 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9059 7124 0.005771 0.02999 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5994 96 0.0048 0.021771 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5049 306 0.00286 0.02212 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+718 8397 0.00351 0.02175 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+718 6982 0.008401 0.0448 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7202 8807 0.0018 0.01187 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7202 8807 0.001831 0.01163 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8592 2995 0.00075 0.00538 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6581 823 2.00E-05 0.00033 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6581 1680 1.00E-05 0.00034 0 1710 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6199 953 0.00023 0.00258 0 723 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6199 1817 0.00023 0.00252 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3231 1504 0.002031 0.008531 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3231 7226 0.005349 0.020789 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2928 7865 0.0002 0.00082 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3916 6891 0.002091 0.011219 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6053 171 0.00262 0.016979 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6053 171 0.002669 0.01663 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8829 3044 0.00025 0.00118 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1552 1194 0.00056 0.00715 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3912 3740 0.0007 0.00455 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3912 2695 0.000331 0.001711 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3912 2695 0.00011 0.000781 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3912 8877 0.00111 0.00664 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7520 8222 0.00066 0.00838 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7520 8222 0.00064 0.00854 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2421 3610 0.003091 0.017091 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2421 1414 0.00643 0.03687 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8879 3610 0.00275 0.01937 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8397 5918 0.00357 0.021289 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1914 6982 0.000289 0.002789 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7873 6638 0.002531 0.01345 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4562 7702 0.00162 0.012159 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4562 7702 0.00262 0.01168 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8835 1156 0.00099 0.006081 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8835 1233 0.000909 0.005979 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3390 408 0.00011 0.0008 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3390 7231 0.00011 0.00068 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3390 5993 0.00207 0.008341 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1910 2550 0.00019 0.001031 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3975 7353 0.014039 0.0667 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3126 7495 0.004961 0.03043 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2689 5753 0.00056 0.003531 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1201 4235 0.001461 0.00889 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7626 7076 6.00E-05 0.000419 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4823 4060 0.00139 0.005169 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4141 1311 0.00069 0.00825 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7124 4566 0.004969 0.030781 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7124 8873 0.00012 0.000969 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6684 5383 0.001091 0.010159 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8151 5383 0.000969 0.00887 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4357 6619 0.00099 0.006789 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8191 8765 0.001031 0.00586 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7466 5469 0.00401 0.03345 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3401 5351 9.10E-05 0.000349 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3760 225 0.00125 0.00745 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+53 4031 0.003711 0.024219 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8222 6921 0.00169 0.02156 0 1578 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8222 6921 0.00171 0.02114 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6556 4239 0.00088 0.00562 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6556 4239 0.0008 0.00618 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2940 7178 0.00161 0.01014 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3928 2563 0.00032 0.002031 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3928 6521 0.00011 0.000659 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1923 3830 0.00042 0.00505 0 986 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1923 5648 0.00043 0.00494 0 1151 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2815 4914 0.00038 0.000711 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2815 4914 0.00037 0.000659 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4125 1644 0.00248 0.03096 0 1743 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+163 3498 0.00375 0.019729 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+163 2430 0.00518 0.020021 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7943 9108 0.000771 0.003711 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7943 1478 0.00076 0.003789 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2308 3541 0.000781 0.00574 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3535 7582 0.00089 0.00562 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2019 8542 0.000331 0.001401 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5174 8542 0.000401 0.00137 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7945 5215 0.00051 0.003349 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2057 9130 0.000461 0.00168 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2057 9130 0.000469 0.00164 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4661 6816 0.006081 0.03114 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7519 776 0.005831 0.02218 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8989 3435 0.00013 0.000461 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7797 2020 0.00013 0.000461 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+871 4031 0.00262 0.020289 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+871 2878 0.00164 0.01194 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7353 9164 0.006479 0.02845 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7974 2012 0.00294 0.014419 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7974 2012 0.00238 0.01463 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7974 1750 0.002219 0.00993 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1401 2303 0.008651 0.04886 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4504 7903 0.00464 0.030979 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5837 449 0.00092 0.00889 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5837 449 0.00093 0.00869 0 1348 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5837 1817 0.0022 0.03485 0 1578 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5837 2458 0.00074 0.00941 0 1743 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5837 6427 0.00087 0.00884 0 1578 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5837 1730 0.00139 0.01662 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9217 594 0.002781 0.022979 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6351 5393 0.000521 0.00407 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6194 7702 0.008479 0.032841 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2503 7491 0.005669 0.02901 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4031 2872 0.001031 0.004099 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4031 8043 0.00301 0.018719 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1813 2866 0.00257 0.01713 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5365 5417 0.010461 0.03836 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5365 4100 0.001719 0.011531 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5365 1556 9.10E-05 0.00056 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3894 3865 0.00476 0.025289 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+128 1554 0.000219 0.00164 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+198 7994 0.002159 0.01163 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+198 1554 0.00295 0.01539 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2985 3133 0.007789 0.033039 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7316 3071 0.00026 0.0013 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6486 8992 0.00162 0.013229 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8485 594 0.007919 0.04194 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+682 8477 0.001229 0.00401 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5146 5488 0.008021 0.042831 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6638 776 0.007711 0.03006 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8788 789 0.00261 0.015469 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6332 1556 0.00139 0.00536 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6332 1556 0.001419 0.00525 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1883 7702 0.006289 0.032271 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1883 2132 0.011031 0.05625 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+171 2341 0.001841 0.01324 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6630 10 0.000599 0.00186 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4484 4239 0.00036 0.001591 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3044 4235 0.003849 0.027651 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+851 4454 0.00186 0.00874 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3485 2183 0.00025 0.00285 0 1480 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1156 7923 0.00207 0.008841 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1156 1233 6.00E-05 0.00039 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8913 4852 0.002159 0.008909 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4039 1233 0.000219 0.00039 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4914 2653 0.00011 0.000521 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4914 2653 0.00011 0.00049 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4914 556 0.000771 0.003789 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4914 3019 0.000229 0.002849 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7994 5256 0.00445 0.027599 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1709 3346 0.00218 0.02 0 1381 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1709 8468 0.00074 0.00865 0 1118 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7702 1234 0.002531 0.019419 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7702 8035 0.003 0.01631 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8677 3331 0.008461 0.025081 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8189 3643 0.00382 0.013669 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3133 8477 0.002581 0.01814 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6744 6101 0.00201 0.012219 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8542 4313 0.00087 0.001599 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+769 5233 0.00455 0.02394 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1965 5926 0.005651 0.041771 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9014 3999 0.00069 0.001271 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1917 8406 0.00068 0.00269 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1917 2021 0.00036 0.00261 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1917 8293 0.001669 0.012031 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4738 3656 0.009669 0.03513 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4738 8477 0.001099 0.00862 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7998 1644 0.0005 0.00711 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6734 1015 0.003919 0.017781 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6734 8992 0.00161 0.019781 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6734 789 0.0007 0.01256 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5004 5393 0.000409 0.0018 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1708 3906 2.00E-05 0.00043 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9150 3906 3.00E-05 0.0004 0 1710 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+280 9158 0.00968 0.056659 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8043 3656 0.003969 0.02925 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5712 8992 0.00219 0.01468 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5712 8466 0.000401 0.003159 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5712 6880 0.000531 0.003 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5215 7266 0.00136 0.00576 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8807 8992 0.000849 0.006289 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8807 8992 0.000841 0.006409 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8807 8992 0.00045 0.00506 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+218 2088 0.003669 0.02988 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+520 5918 0.002 0.01568 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2653 2128 0.00031 0.0008 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1216 5233 0.00043 0.00038 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8980 5993 0.00043 0.002229 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5212 5993 0.00049 0.00218 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3656 4060 0.00282 0.01844 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+883 3331 0.00462 0.014849 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5144 3346 0.00263 0.04076 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3498 2563 0.01062 0.056719 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1896 8200 0.0001 0.00105 0 657 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9130 8864 0.00239 0.017341 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3503 2510 0.001341 0.010581 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3503 6146 0.00101 0.007599 0 472 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+401 1584 0.00011 0.000289 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7328 6921 0.00146 0.01769 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7328 6921 0.0013 0.02004 0 1644 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6816 5573 0.007909 0.028349 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7396 8564 0.00012 0.00049 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7396 8564 0.00012 0.000479 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6921 432 0.00076 0.01018 0 1513 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6921 432 0.0009 0.00865 0 1677 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6921 432 0.00096 0.01294 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6921 432 0.0004 0.00756 0 1611 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6921 432 0.00039 0.00771 0 1447 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6921 8200 0.00163 0.02291 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2949 3121 0.00636 0.03855 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2949 3121 0.00639 0.03863 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+953 1730 0.00113 0.01362 0 690 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1767 892 0.00861 0.05318 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4674 4889 0.0012 0.004669 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4674 7076 0.00018 0.001091 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1234 8035 0.001401 0.00612 0 357 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+115 225 0.00068 0.00387 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5720 8578 0.0043 0.033591 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3579 5469 0.003039 0.01911 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3246 124 6.00E-05 0.00111 0 853 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8846 4783 5.00E-05 0.001091 0 853 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2393 3306 3.90E-05 0.00089 0 853 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1895 4480 3.90E-05 0.000901 0 853 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+678 4454 0.000169 0.00111 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1002 4852 0.000331 0.0027 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6429 2012 0.00026 0.00369 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4889 7076 0.000341 0.00274 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5341 7491 0.00038 0.00506 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2563 6521 0.00012 0.000831 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1111 594 0.003031 0.0123 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4747 7791 0.001521 0.00774 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3906 3022 0.00059 0.00552 0 1611 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3906 1194 0.00053 0.00625 0 1545 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5993 8804 0.00143 0.01076 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1798 8487 0.00056 0.00593 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2467 7178 0.00205 0.01461 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2132 2303 0.01068 0.054521 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8992 8466 0.00194 0.011039 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8992 6880 0.00131 0.010099 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8992 2995 0.001289 0.014229 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+805 3221 0.00455 0.027031 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+805 3327 0.00239 0.01414 0 510 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+805 8310 0.004039 0.029669 0 491 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+805 2088 0.001099 0.007771 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5383 2021 0.00082 0.00762 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5383 4114 0.000719 0.0033 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5383 5519 0.000599 0.00361 0 300 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5383 8293 0.000521 0.004039 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5383 3435 0.000901 0.0088 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7507 6990 0.000781 0.00306 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7507 2406 0.000419 0.00399 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7507 2020 0.000841 0.009841 0 281 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6478 6146 0.004021 0.03064 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4852 2695 0.0023 0.009031 0 338 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4852 2695 0.002081 0.009469 0 376 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4852 5502 0.00164 0.008831 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4852 8877 0.00094 0.00488 0 319 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4852 9119 0.000901 0.00551 0 453 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4852 1151 0.00051 0.005961 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2012 1750 0.00113 0.004349 0 433 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1478 6616 0.002081 0.013031 0 395 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+809 4594 0.00116 0.01438 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8656 4729 0.00013 0.001031 0 10000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4100 615 0.00036 0.002659 0 414 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4060 5393 0.000771 0.004539 0 529 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9203 2426 0.000695 0.049098 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9203 2426 0.000355 0.024893 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+118 2426 0.000365 0.024372 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3145 7770 0.000411 0.023652 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 4918 0.000386 0.025673 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7267 4918 0.000344 0.029336 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+839 4506 0.000653 0.052104 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+839 4506 0.000767 0.043531 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3445 6114 0.000323 0.028314 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3445 6114 0.000323 0.025999 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3445 7264 0.000365 0.025478 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+891 6306 0.00086 0.039291 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+720 1711 0.000355 0.026586 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+720 1711 0.000375 0.026313 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6206 3240 0.000344 0.023329 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6206 3240 0.000302 0.026375 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9174 2924 0.000788 0.04323 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9174 2924 0.000767 0.04407 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 5856 0.000767 0.043562 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 5856 0.000788 0.041281 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1355 5856 0.000892 0.040524 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3205 4683 0.000975 0.043562 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3205 4683 0.000757 0.042649 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5350 2361 0.000261 0.030762 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5350 2361 0.000261 0.030088 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5016 6112 0.000323 0.026447 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5016 8860 0.000323 0.026885 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7471 549 0.000323 0.02748 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7471 549 0.000292 0.028158 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+549 5002 0 0.009197 0 567 0 0 0 0.072386 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5490 3817 0.000736 0.044526 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2854 9112 0.00086 0.039488 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2918 6532 0.000365 0.024372 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2918 6532 0.000375 0.023986 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4494 7284 0.000386 0.025673 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2656 1775 0.000809 0.042318 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3519 5641 0.000705 0.042038 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3543 367 0.000334 0.028022 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3543 1833 0.000353 0.022403 0 591 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2372 367 0.000313 0.026354 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2372 367 0.000323 0.025478 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1876 7752 0.000344 0.024622 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+113 7752 0.000355 0.024038 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3499 7289 0.000881 0.038244 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3499 7289 0.000757 0.040959 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3082 2083 0.000354 0.028765 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6224 2083 0.000354 0.027114 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2174 2083 0.000695 0.04748 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4623 1609 0.000323 0.028314 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4623 1609 0.000323 0.026354 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4623 1609 0.000323 0.025696 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 1001 0.000355 0.027305 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 1001 0.000355 0.026666 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 1001 0.000923 0.037456 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5589 1001 0.000788 0.035217 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1198 7473 0.000323 0.026739 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1198 7473 0.000323 0.02749 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2479 5482 0.000313 0.027324 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2479 5482 0.000313 0.028074 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7831 5525 0.000601 0.024984 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7831 5525 0.000715 0.022797 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7831 5525 0.000344 0.024893 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4970 7955 0.000365 0.024163 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4970 7955 0.000344 0.02385 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5007 7367 0.000757 0.040182 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+757 3758 0.000323 0.028937 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3697 6952 0.000354 0.026958 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3697 6952 0.000778 0.045656 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3697 6952 0.000695 0.048932 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3697 6952 0.000302 0.025926 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6738 8180 0.000355 0.027328 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6738 8180 0.000365 0.027156 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9222 5935 0.000355 0.024299 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7988 804 0.000375 0.026313 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7988 804 0.000375 0.025605 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3239 1539 0.000334 0.026291 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3239 1539 0.000705 0.046735 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2056 4084 0.000313 0.026875 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2056 4084 0.000302 0.027376 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4598 5110 0.000664 0.044868 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2129 5110 0.000809 0.044526 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5658 5550 0.00086 0.034253 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5658 5550 0.000355 0.024372 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2848 1526 0.000365 0.023788 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4541 7464 0.000375 0.023204 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4541 7464 0.000302 0.026593 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1754 3857 0.000323 0.029256 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1754 3857 0.000334 0.029986 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1754 3857 0.000355 0.030979 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2518 4544 0.000302 0.025707 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2518 4544 0.000344 0.025405 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3069 6115 0.00012 0.008908 0 491 0 0 0 -0.072388 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5067 7641 0.000365 0.023715 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6036 8670 0.000365 0.023517 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6036 5522 0.000334 0.026812 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8486 8791 0.000695 0.047253 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7530 8791 0.000778 0.043759 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7522 7571 0.000313 0.030636 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7522 7571 0.000313 0.028286 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7522 7571 0.000344 0.028115 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2526 1483 0.000902 0.039425 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2365 8316 0.000355 0.024237 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8672 1860 0.000375 0.023986 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8672 1860 0.000375 0.023861 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1494 583 0.000819 0.04153 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1494 583 0.000809 0.042701 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1502 2795 0.000334 0.028022 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8195 933 0.000632 0.048237 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8195 933 0.000632 0.045159 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8195 933 0.000715 0.044039 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3918 6802 0.00074 0.044479 0 10000 0 0 0.986547 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3918 4025 0.00074 0.043811 0 10000 0 0 0.986547 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4435 2079 0.000375 0.02385 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4435 2079 0.000365 0.023267 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4435 2079 0.000323 0.026739 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1081 7361 0.000684 0.047025 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9101 2177 0.000313 0.02748 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6555 8475 0.000323 0.028554 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6555 8475 0.000302 0.026437 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7056 7577 0.000365 0.025551 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7056 7577 0.000344 0.024893 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7056 9051 0.000375 0.024508 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6889 6785 0.000778 0.041157 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6889 6785 0.000923 0.03702 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6889 6785 0.000302 0.026593 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1027 7148 0.000344 0.029667 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1027 44 0.000334 0.02748 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5308 7148 0.000323 0.030636 0 591 0 0 0.89674 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5308 44 0.000323 0.028526 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9213 6231 0.000344 0.025332 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9213 8291 0.000334 0.024674 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+9213 6842 0.000344 0.02457 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3608 6664 0.000365 0.023788 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4339 6570 0.000365 0.023601 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4339 6570 0.000344 0.02652 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7513 6570 0.000344 0.027272 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7513 6570 0.000334 0.027563 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8887 6639 0.000313 0.030636 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8887 6639 0.000313 0.028286 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5461 4816 0.000881 0.036803 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5461 4816 0.000902 0.036668 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5461 4816 0.000881 0.034014 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5460 3786 0.000365 0.026027 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5460 3786 0.000386 0.025673 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7256 4491 0.00012 0.011186 0 586 0 0 0 0.084507 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6153 58 0.00017 0.006789 0 1216 0 0 0 -0.086984 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+%CTT T_BUS r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP----------------------
+6153, 6807, 0.000664, 0.047107, 0, 10000, 0, 0, 0.982143, 0, 1, -360, 360, 0, 0, 0, 1.95, 0, 0, 0, 0, 0, 0, 1.22, 0.75, 0, 0, 1, 0, 0, -360, 360, 0, 0, 0, 0, 0; %CTT
+1465 1262 0.000313 0.028314 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1465 1262 0.000334 0.025707 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1465 1551 0.000344 0.025478 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7537 1551 0.000344 0.027236 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7537 1551 0.000375 0.026518 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6901 4874 0.000386 0.02646 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5241 4 0.000788 0.040317 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7520 561 0.000323 0.025863 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+749 4324 1.00E-05 0.022863 0 948 0 0 0 0.04898 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4141 7124 0.000334 0.030306 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4141 7124 0.000302 0.030636 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+%PST T_BUS r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP----------------------
+7466, 3649, 0.00011, 0.010476, 0, 472, 0, 0, 0, -0.06138, 1, -360, 360, -290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, -100, 100, 0, 0, 0, 0, 0; %PST
+8222 6556 0.000344 0.024841 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8222 6556 0.000365 0.025029 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8222 6556 0.000355 0.024101 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4125 163 0.000344 0.02385 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4125 163 0.000411 0.02313 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4125 163 0.000829 0.042764 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5837 9217 0.000705 0.04748 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5837 1448 0.000323 0.029986 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5837 1448 0.000302 0.029952 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8267 5365 0.000746 0.041064 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8267 5365 0.000881 0.042214 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2359 8005 0.00086 0.041209 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2359 8005 0.000912 0.038669 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8109 171 0.000375 0.026244 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8109 171 0.000375 0.025457 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3485 1156 0.000302 0.029096 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4734 2229 0.000302 0.029667 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1709 7702 0.000334 0.027563 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1709 7702 0.000323 0.028074 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+905 8189 0.000736 0.041064 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8334 8189 0.001234 0.040109 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8334 8189 0.000757 0.043209 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7998 6734 0.000323 0.026586 0 854 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4196 280 0.000788 0.040296 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4196 280 0.000912 0.040514 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6475 3503 0.000798 0.042183 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6475 3503 0.000778 0.043147 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7328 4235 0.000323 0.027793 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7328 4235 0.000302 0.027918 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7328 4235 0.000302 0.025926 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6921 2949 0.000344 0.024956 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+6921 2949 0.000355 0.024435 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3830 306 0.000386 0.026392 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+5648 306 0.000365 0.025525 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1730 115 0.000344 0.029986 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1730 115 0.000323 0.029838 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2721 5720 0.000323 0.02748 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2721 5720 0.000313 0.028001 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+432 3246 0.000179 0.012988 0 1151 0 0 0.990991 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+432 8846 0.000198 0.012724 0 1151 0 0 0.990991 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+432 2393 0.000207 0.012469 0 1151 0 0 0.990991 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+432 1895 0.000207 0.012206 0 1151 0 0 0.990991 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+432 3412 0.000217 0.012912 0 1151 0 0 0.990991 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+432 5586 0.000217 0.012627 0 1151 0 0 0.990991 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+432 3112 0.000198 0.014317 0 1151 0 0 0.990991 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+432 3112 0.000189 0.014592 0 1151 0 0 0.990991 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+432 7857 0.000354 0.02725 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+960 8497 0.000628 0.042428 0 10000 0 0 1.009174 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+960 8497 0.000726 0.044039 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3577 5907 0.000365 0.024893 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3577 5907 0.000438 0.02457 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3577 5907 0.000365 0.023986 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7164 5918 0.000375 0.023267 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+7164 5918 0.000323 0.026375 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1798 2467 0.000334 0.029735 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1798 2467 0.000313 0.030237 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3346 2132 0.000767 0.044049 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3346 2132 0.000302 0.026072 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3346 2132 0.00085 0.039892 0 10000 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+3483 8992 0.000344 0.024956 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8886 8992 0.000334 0.026666 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2093 805 0.000365 0.023788 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2093 805 0.000365 0.023465 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+221 1541 0.000334 0.026447 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8347 5383 0.000323 0.027042 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8347 5383 0.000313 0.02748 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8347 5383 0.000302 0.028314 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8347 7507 0.000323 0.025853 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8347 7507 0.000365 0.026197 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+8347 7507 0.000365 0.025165 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4000 4852 0.000355 0.024237 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4000 2012 0.000375 0.024247 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2183 4852 0.000365 0.023267 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2183 2012 0.000342 0.023139 0 591 0 0 0.982143 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1642 7098 0.000344 0.026666 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+1642 687 0.000334 0.027021 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+809 7098 0.000302 0.027615 0 591 0 0 0.979227 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+809 687 0.000313 0.026135 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4594 8804 0.000365 0.025905 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+4594 8804 0.000355 0.025238 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+2919 4215 0.000334 0.026814 0 591 0 0 0.93617 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+%Area 1-2 (Transformers for VSC DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP----------------------
+10001 2072 0.0003 0.0355 0 1000 1000 1000 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 1.05 1.22 0.75 1 0 1 -0.5 0.5 -360 360 0 0.001 0.0015 0.002 0; %vsc1 I
+10002 8195 0.0003 0.0355 0 1000 1000 1000 1 0 1 -360 360 50 0 0 0 0 0 0 0 1.01 1.07 1.22 0.75 4 0.02 1 -0.5 0.5 -100 100 0 0.001 0.0015 0.002 0.1; %vsc2 III
+10001 10002 0.0005 0 0 1000 1000 1000 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-2 (Transformers for VSC DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP----------------------
+10003 6246 0.00025 0.041 0 1000 1000 1000 1 0 1 -360 360 0 0 0 0 0 0 0 0 1.0 1.06 1.22 0.75 2 0.5 1 -0.5 0.5 -360 360 0 0.001 0.0015 0.002 0; %vsc3 II
+10004 7282 0.00025 0.041 0 1000 1000 1000 1 0 1 -360 360 -500 0 0 0 0 0 0 0 0 1.075 1.22 0.75 1 0.5 1 -0.5 0.5 -100 100 0 0.001 0.0015 0.002 0; %vsc4 I
+10005 352 0.00025 0.041 0 1000 1000 1000 1 0 1 -360 360 -450 0 0 0 0 0 0 0 0 0 1 1 1 0.5 1 -0.5 0.5 -100 100 0 0.001 0.0015 0.002 0; %vsc5 I
+10003 10004 0.0007 0 0 1000 1000 1000 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+10004 10005 0.0007 0 0 1000 1000 1000 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+10005 10003 0.0007 0 0 1000 1000 1000 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+];
+
+%%----- OPF Data -----%%
+%% generator cost data
+% 1 startup shutdown n x1 y1 ... xn yn
+% 2 startup shutdown n c(n-1) ... c0
+mpc.gencost = [
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+ 2 0 0 3 0 1 0;
+];
diff --git a/src/tests/data/grids/fubm_caseHVDC_qt.m b/src/tests/data/grids/fubm_caseHVDC_qt.m
new file mode 100644
index 000000000..9bc962e90
--- /dev/null
+++ b/src/tests/data/grids/fubm_caseHVDC_qt.m
@@ -0,0 +1,49 @@
+function mpc = fubm_caseHVDC_qt
+%%%%%%%%%%%%%%%%%%%%%%%%%% Case HVDC %%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% MATPOWER Case Format : Version 2
+mpc.version = '2';
+
+%%----- Power Flow Data -----%%
+%% system MVA base
+mpc.baseMVA = 100;
+
+%% bus data
+% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin
+mpc.bus = [
+ 001 3 0 0 0 0 1 1 0 135 1 1.1 0.9;
+ 002 1 3 0.3 0 0 1 1 0 135 1 1.1 0.9;
+ 003 1 0 0 0 0 3 1 0 200 1 1.1 0.9;
+ 004 1 0 0 0 0 3 1 0 200 1 1.1 0.9;
+ 005 1 1 0.5 0 0 2 1 0 135 1 1.1 0.9;
+ 006 2 0 0 0 0 2 1 0 135 1 1.1 0.9
+];
+
+%% generator data
+% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
+mpc.gen = [
+ 001 1 0 2 -2 1 100 1 2 0 0 0 0 0 0 0 0 0 0 0 0
+ 006 1 0 2 -2 1 100 1 5 0 0 0 0 0 0 0 0 0 0 0 0
+];
+
+%% branch data
+% fbus tbus r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET TAP_MAX TAP_MIN CONV BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP ----------------------
+mpc.branch = [
+ 001 002 0.001 0.10 0 100 100 100 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 002 005 0.0500 0.50 0 100 100 100 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 003 002 0.0001 0.15 0 100 100 100 1 0 1 -360 360 0 0 0 -0.3 0 0 0 0 0 0 1.2 0.8 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC1
+ 003 004 0.05 0 0 100 100 100 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 004 005 0.0001 0.15 0 100 100 100 0 0 1 -360 360 -0.5 0 0 0 0 0 0 0 1.1 0 1 1 2 0 1 -0.5 0.5 -50 50 0 0.0001 0.015 0.02 0; %VSC2
+ 006 005 0.001 0.10 0 100 100 100 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0
+];
+%%----- OPF Data -----%%
+%% generator cost data
+% 1 startup shutdown n x1 y1 ... xn yn
+% 2 startup shutdown n c(n-1) ... c0
+mpc.gencost = [
+2 0 0 3 0.02 1.0 1.0;
+2 0 0 3 0.01 2.0 1.0;
+2 0 0 3 0.01 0.0 0.0;
+2 0 0 3 0.01 0.0 0.0;
+];
+
diff --git a/src/tests/data/grids/fubm_caseHVDC_vt.m b/src/tests/data/grids/fubm_caseHVDC_vt.m
new file mode 100644
index 000000000..09b592683
--- /dev/null
+++ b/src/tests/data/grids/fubm_caseHVDC_vt.m
@@ -0,0 +1,49 @@
+function mpc = fubm_caseHVDC_vt
+%%%%%%%%%%%%%%%%%%%%%%%%%% Case HVDC %%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% MATPOWER Case Format : Version 2
+mpc.version = '2';
+
+%%----- Power Flow Data -----%%
+%% system MVA base
+mpc.baseMVA = 100;
+
+%% bus data
+% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin
+mpc.bus = [
+ 001 3 0 0 0 0 1 1 0 135 1 1.1 0.9;
+ 002 1 3 0.3 0 0 1 1 0 135 1 1.1 0.9;
+ 003 1 0 0 0 0 3 1 0 200 1 1.1 0.9;
+ 004 1 0 0 0 0 3 1 0 200 1 1.1 0.9;
+ 005 1 2 0.5 0 0 2 1 0 135 1 1.1 0.9;
+ 006 2 0 0 0 0 2 1 0 135 1 1.1 0.9
+];
+
+%% generator data
+% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
+mpc.gen = [
+ 001 1 0 2 -2 1.1 100 1 2 0 0 0 0 0 0 0 0 0 0 0 0
+ 006 1 0 2 -2 1.12 100 1 5 0 0 0 0 0 0 0 0 0 0 0 0
+];
+
+%% branch data
+% fbus tbus r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET TAP_MAX TAP_MIN CONV BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+mpc.branch = [
+ 001 002 0.001 0.10 0 100 100 100 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 002 005 1.0500 0.50 0 100 100 100 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 006 005 0.001 0.10 0 100 100 100 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 003 002 0.9 0.15 0 100 100 100 1 0 1 -360 360 0 0.0 0 0 0 0 0 0 0 1.096 2 0.1 1 0 1 -5 5 -360 360 0 0.0001 0.015 0.2 0; %VSC1
+ 004 005 0.9 0.35 0 100 100 100 0 0 1 -360 360 -0.35 0.0 0 0 0 0 0 0 1.104 0 2 0.1 2 0 1 -5 5 -50 50 0 0.0001 0.015 0.02 0; %VSC2
+ 003 004 2.05 0 0 100 100 100 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0; % DC line
+];
+%%----- OPF Data -----%%
+%% generator cost data
+% 1 startup shutdown n x1 y1 ... xn yn
+% 2 startup shutdown n c(n-1) ... c0
+mpc.gencost = [
+2 0 0 3 0.02 1.0 1.0;
+2 0 0 3 0.01 2.0 1.0;
+2 0 0 3 0.01 0.0 0.0;
+2 0 0 3 0.01 0.0 0.0;
+];
+
diff --git a/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt1.m b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt1.m
new file mode 100644
index 000000000..911652c5f
--- /dev/null
+++ b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt1.m
@@ -0,0 +1,179 @@
+function mpc = fubm_case_30_2MTDC_ctrls_vt1
+%%%%%%%%%%%%%%%%%%%%%%%% IEEE_30_VSC Test Case %%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% MATPOWER Case Format : Version 2
+mpc.version = '2';
+
+%%----- Power Flow Data -----%%
+%% system MVA base
+mpc.baseMVA = 100;
+
+%% area data
+% area refbus
+mpc.areas = [
+ 1 101; %area 1 IEEE 30 Bus System
+ 2 1; %area 2 DC GRID 1
+ 3 901; %area 3 Transformers for VSC
+ ];
+
+
+%% bus data
+% bus_i type Pd Qd Gs Bs area Vm Va base zone Vmax Vmin
+
+mpc.bus = [
+ %Area 1 (IEEE 30 Bus System)
+ 101 3 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 102 2 30 12.7 0 0 1 1 0 135 1 1.15 0.9;
+ 103 1 2.4 1.2 0 0 1 1 0 135 1 1.15 0.9;
+ 104 1 7.6 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 105 1 0 0 0 0.19 1 1 0 135 1 1.15 0.9;
+ 106 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 107 1 22.8 10.9 0 0 1 1 0 135 1 1.15 0.9;
+ 108 1 30 30 0 0 1 1 0 135 1 1.15 0.9;
+ 109 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 110 1 5.8 2 0 0 1 1 0 135 1 1.15 0.9;
+ 111 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 112 1 11.2 7.5 0 0 1 1 0 135 1 1.15 0.9;
+ 113 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 114 1 6.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 115 1 8.2 2.5 0 0 1 1 0 135 1 1.15 0.9;
+ 116 1 3.5 1.8 0 0 1 1 0 135 1 1.15 0.9;
+ 117 1 9 5.8 0 0 1 1 0 135 1 1.15 0.9;
+ 118 1 3.2 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 119 1 9.5 3.4 0 0 1 1 0 135 1 1.15 0.9;
+ 120 1 2.2 0.7 0 0 1 1 0 135 1 1.15 0.9;
+ 121 1 17.5 11.2 0 0 1 1 0 135 1 1.15 0.9;
+ 122 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 123 2 3.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 124 1 8.7 6.7 0 0.04 1 1 0 135 1 1.15 0.9;
+ 125 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 126 1 3.5 2.3 0 0 1 1 0 135 1 1.15 0.9;
+ 127 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 128 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 129 1 2.4 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 130 1 10.6 1.9 0 0 1 1 0 135 1 1.15 0.9;
+ %Area 2 (Transformers nodes for VSC DC GRID 1)
+ 901 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 902 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 903 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ %Area 3 (Transformers nodes for VSC DC GRID 1)
+ 904 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 905 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 906 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9
+ %Area 2 (DC GRID 1)
+ 1 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 2 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 3 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ %Area 3 (DC GRID 2)
+ 4 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 5 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 6 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 7 1 -15 0 0 0 3 1 0 200 1 1.15 0.9;
+ 8 1 -10 0 0 0 3 1 0 200 1 1.15 0.9;
+
+
+];
+%% generator data
+% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
+mpc.gen = [
+ %IEEE 57 Bus System
+ 101 23.54 0 150 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 102 60.97 0 60 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 122 21.59 0 62.5 -15 1 100 1 50 0 0 0 0 0 0 0 0 0 0 0 0;
+ 127 26.91 0 48.7 -15 1 100 1 55 0 0 0 0 0 0 0 0 0 0 0 0;
+ 123 19.2 0 40 -10 1 100 1 30 0 0 0 0 0 0 0 0 0 0 0 0;
+ 113 37 0 44.7 -15 1 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0
+ %WF Generator is added as a load in bus 7 and 8
+ ];
+%% branch data
+% fbus tbus r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET TAP_MAX TAP_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP ----------------------
+mpc.branch = [
+%Area 1 IEEE 57 Bus System
+ 101 102 0.02 0.06 0.03 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 101 103 0.05 0.19 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 104 0.06 0.17 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 103 104 0.01 0.04 0 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 105 0.05 0.2 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 106 0.06 0.18 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 106 0.01 0.04 0 90 90 90 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 107 0.05 0.12 0.01 70 70 70 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 107 0.03 0.08 0.01 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 108 0.01 0.04 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 109 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 110 0 0.56 0 32 32 32 1 0 1 -360 360 0 0 0 3.0 0 0 0 0 0 0 1.2 0.8 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 111 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 110 0 0.11 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 112 0 0.26 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 113 0 0.14 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 114 0.12 0.26 0 32 32 32 1 0 1 -360 360 3.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;
+ 112 115 0.07 0.13 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 116 0.09 0.2 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 114 115 0.22 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 116 117 0.08 0.19 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 118 0.11 0.22 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 118 119 0.06 0.13 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 119 120 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 120 0.09 0.21 0 32 32 32 1 0 1 -360 360 7.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;%PST1
+ 110 117 0.03 0.08 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 121 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 122 0.07 0.15 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 121 122 0.01 0.02 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 123 0.1 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 122 124 0.12 0.18 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 123 124 0.13 0.27 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 124 125 0.19 0.33 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 126 0.25 0.38 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 127 0.11 0.21 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 128 127 0 0.4 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 129 0.22 0.42 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 130 0.32 0.6 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 129 130 0.24 0.45 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 108 128 0.06 0.2 0.02 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 128 0.02 0.06 0.01 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-2 (Transformers for VSC DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 113 901 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 902 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 130 903 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-3 (Transformers for VSC DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 102 904 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 905 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 906 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 2 (VSC of DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 901 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 1.1 0 1 1 2 0 1 -0.5 0.5 -360 360 0.01 0.0001 0.15 2 0; %VSC1vdc
+ 002 902 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 5.37 0 0 -25 0 0 0 0 0 0 1.2 0.8 1 0 1 -0.5 0.5 -50.0 50 0.10 0.0001 0.15 2 0; %VSC2z
+ 003 903 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 -2.38 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -50.0 50 0.001 0.0001 0.15 2 0; %VSC3z
+%Area 3 (VSC of DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 904 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -360 360 0.01 0.0001 0.15 2 0; %VSC4z
+ 005 905 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 1.038 1.2 0.8 1 0 1 -0.5 0.5 -360 360 0.01 0.0001 0.15 2 0; %VSC5z
+ 006 906 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 15 0 0 0 0 0 0 0 1.05 0 1 1 2 0 1 -0.5 0.5 -50.0 50 0.01 0.0001 0.15 2 0; %VSC6vdc
+%Area 2 (DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 002 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 001 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 002 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 3 (DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 005 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 004 006 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 005 008 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 006 007 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+];
+%%----- OPF Data -----%%
+%% generator cost data
+% 1 startup shutdown n x1 y1 ... xn yn
+% 2 startup shutdown n c(n-1) ... c0
+mpc.gencost = [
+ %Pg cost
+ 2 0 0 3 0.02 2 0;
+ 2 0 0 3 0.0175 1.75 0;
+ 2 0 0 3 0.0625 1 0;
+ 2 0 0 3 0.00834 3.25 0;
+ 2 0 0 3 0.025 3 0;
+ 2 0 0 3 0.025 3 0;
+ %Qg cost
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+
+];
diff --git a/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt1_pf.m b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt1_pf.m
new file mode 100644
index 000000000..f4f370268
--- /dev/null
+++ b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt1_pf.m
@@ -0,0 +1,179 @@
+function mpc = fubm_case_30_2MTDC_ctrls_vt1_pf
+%%%%%%%%%%%%%%%%%%%%%%%% IEEE_30_VSC Test Case %%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% MATPOWER Case Format : Version 2
+mpc.version = '2';
+
+%%----- Power Flow Data -----%%
+%% system MVA base
+mpc.baseMVA = 100;
+
+%% area data
+% area refbus
+mpc.areas = [
+ 1 101; %area 1 IEEE 30 Bus System
+ 2 1; %area 2 DC GRID 1
+ 3 901; %area 3 Transformers for VSC
+ ];
+
+
+%% bus data
+% bus_i type Pd Qd Gs Bs area Vm Va base zone Vmax Vmin
+
+mpc.bus = [
+ %Area 1 (IEEE 30 Bus System)
+ 101 3 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 102 2 30 12.7 0 0 1 1 0 135 1 1.15 0.9;
+ 103 1 2.4 1.2 0 0 1 1 0 135 1 1.15 0.9;
+ 104 1 7.6 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 105 1 0 0 0 0.19 1 1 0 135 1 1.15 0.9;
+ 106 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 107 1 22.8 10.9 0 0 1 1 0 135 1 1.15 0.9;
+ 108 1 30 30 0 0 1 1 0 135 1 1.15 0.9;
+ 109 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 110 1 5.8 2 0 0 1 1 0 135 1 1.15 0.9;
+ 111 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 112 1 11.2 7.5 0 0 1 1 0 135 1 1.15 0.9;
+ 113 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 114 1 6.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 115 1 8.2 2.5 0 0 1 1 0 135 1 1.15 0.9;
+ 116 1 3.5 1.8 0 0 1 1 0 135 1 1.15 0.9;
+ 117 1 9 5.8 0 0 1 1 0 135 1 1.15 0.9;
+ 118 1 3.2 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 119 1 9.5 3.4 0 0 1 1 0 135 1 1.15 0.9;
+ 120 1 2.2 0.7 0 0 1 1 0 135 1 1.15 0.9;
+ 121 1 17.5 11.2 0 0 1 1 0 135 1 1.15 0.9;
+ 122 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 123 2 3.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 124 1 8.7 6.7 0 0.04 1 1 0 135 1 1.15 0.9;
+ 125 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 126 1 3.5 2.3 0 0 1 1 0 135 1 1.15 0.9;
+ 127 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 128 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 129 1 2.4 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 130 1 10.6 1.9 0 0 1 1 0 135 1 1.15 0.9;
+ %Area 2 (Transformers nodes for VSC DC GRID 1)
+ 901 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 902 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 903 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ %Area 3 (Transformers nodes for VSC DC GRID 1)
+ 904 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 905 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 906 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9
+ %Area 2 (DC GRID 1)
+ 1 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 2 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 3 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ %Area 3 (DC GRID 2)
+ 4 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 5 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 6 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 7 1 -15 0 0 0 3 1 0 200 1 1.15 0.9;
+ 8 1 -10 0 0 0 3 1 0 200 1 1.15 0.9;
+
+
+];
+%% generator data
+% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
+mpc.gen = [
+ %IEEE 57 Bus System
+ 101 23.54 0 150 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 102 60.97 0 60 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 122 21.59 0 62.5 -15 1 100 1 50 0 0 0 0 0 0 0 0 0 0 0 0;
+ 127 26.91 0 48.7 -15 1 100 1 55 0 0 0 0 0 0 0 0 0 0 0 0;
+ 123 19.2 0 40 -10 1 100 1 30 0 0 0 0 0 0 0 0 0 0 0 0;
+ 113 37 0 44.7 -15 1 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0
+ %WF Generator is added as a load in bus 7 and 8
+ ];
+%% branch data
+% fbus tbus r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET TAP_MAX TAP_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP ----------------------
+mpc.branch = [
+%Area 1 IEEE 57 Bus System
+ 101 102 0.02 0.06 0.03 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 101 103 0.05 0.19 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 104 0.06 0.17 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 103 104 0.01 0.04 0 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 105 0.05 0.2 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 106 0.06 0.18 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 106 0.01 0.04 0 90 90 90 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 107 0.05 0.12 0.01 70 70 70 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 107 0.03 0.08 0.01 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 108 0.01 0.04 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 109 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 110 0 0.56 0 32 32 32 1 0 1 -360 360 0 0 0 3.0 0 0 0 0 0 0 1.2 0.8 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 111 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 110 0 0.11 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 112 0 0.26 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 113 0 0.14 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 114 0.12 0.26 0 32 32 32 1 0 1 -360 360 3.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;
+ 112 115 0.07 0.13 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 116 0.09 0.2 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 114 115 0.22 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 116 117 0.08 0.19 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 118 0.11 0.22 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 118 119 0.06 0.13 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 119 120 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 120 0.09 0.21 0 32 32 32 1 0 1 -360 360 7.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;%PST1
+ 110 117 0.03 0.08 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 121 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 122 0.07 0.15 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 121 122 0.01 0.02 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 123 0.1 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 122 124 0.12 0.18 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 123 124 0.13 0.27 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 124 125 0.19 0.33 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 126 0.25 0.38 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 127 0.11 0.21 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 128 127 0 0.4 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 129 0.22 0.42 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 130 0.32 0.6 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 129 130 0.24 0.45 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 108 128 0.06 0.2 0.02 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 128 0.02 0.06 0.01 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-2 (Transformers for VSC DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 113 901 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 902 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 130 903 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-3 (Transformers for VSC DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 102 904 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 905 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 906 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 2 (VSC of DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 901 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 1.1 0 1 1 2 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC1vdc
+ 002 902 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 5.37 0 0 -25 0 0 0 0 0 0 1.2 0.8 1 0 1 -0.5 0.5 -50.0 50 0 0.0001 0.015 0.2 0; %VSC2z
+ 003 903 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 -2.38 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -50.0 50 0 0.0001 0.015 0.2 0; %VSC3z
+%Area 3 (VSC of DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 904 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC4z
+ 005 905 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 1.038 1.2 0.8 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC5z
+ 006 906 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 15 0 0 0 0 0 0 0 1.05 0 1 1 2 0 1 -0.5 0.5 -50.0 50 0 0.0001 0.015 0.2 0; %VSC6vdc
+%Area 2 (DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 002 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 001 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 002 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 3 (DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 005 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 004 006 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 005 008 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 006 007 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+];
+%%----- OPF Data -----%%
+%% generator cost data
+% 1 startup shutdown n x1 y1 ... xn yn
+% 2 startup shutdown n c(n-1) ... c0
+mpc.gencost = [
+ %Pg cost
+ 2 0 0 3 0.02 2 0;
+ 2 0 0 3 0.0175 1.75 0;
+ 2 0 0 3 0.0625 1 0;
+ 2 0 0 3 0.00834 3.25 0;
+ 2 0 0 3 0.025 3 0;
+ 2 0 0 3 0.025 3 0;
+ %Qg cost
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+
+];
diff --git a/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt2.m b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt2.m
new file mode 100644
index 000000000..ba9d54716
--- /dev/null
+++ b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt2.m
@@ -0,0 +1,179 @@
+function mpc = fubm_case_30_2MTDC_ctrls_vt2
+%%%%%%%%%%%%%%%%%%%%%%%% IEEE_30_VSC Test Case %%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% MATPOWER Case Format : Version 2
+mpc.version = '2';
+
+%%----- Power Flow Data -----%%
+%% system MVA base
+mpc.baseMVA = 100;
+
+%% area data
+% area refbus
+mpc.areas = [
+ 1 101; %area 1 IEEE 30 Bus System
+ 2 1; %area 2 DC GRID 1
+ 3 901; %area 3 Transformers for VSC
+ ];
+
+
+%% bus data
+% bus_i type Pd Qd Gs Bs area Vm Va base zone Vmax Vmin
+
+mpc.bus = [
+ %Area 1 (IEEE 30 Bus System)
+ 101 3 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 102 2 30 12.7 0 0 1 1 0 135 1 1.15 0.9;
+ 103 1 2.4 1.2 0 0 1 1 0 135 1 1.15 0.9;
+ 104 1 7.6 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 105 1 0 0 0 0.19 1 1 0 135 1 1.15 0.9;
+ 106 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 107 1 22.8 10.9 0 0 1 1 0 135 1 1.15 0.9;
+ 108 1 30 30 0 0 1 1 0 135 1 1.15 0.9;
+ 109 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 110 1 5.8 2 0 0 1 1 0 135 1 1.15 0.9;
+ 111 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 112 1 11.2 7.5 0 0 1 1 0 135 1 1.15 0.9;
+ 113 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 114 1 6.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 115 1 8.2 2.5 0 0 1 1 0 135 1 1.15 0.9;
+ 116 1 3.5 1.8 0 0 1 1 0 135 1 1.15 0.9;
+ 117 1 9 5.8 0 0 1 1 0 135 1 1.15 0.9;
+ 118 1 3.2 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 119 1 9.5 3.4 0 0 1 1 0 135 1 1.15 0.9;
+ 120 1 2.2 0.7 0 0 1 1 0 135 1 1.15 0.9;
+ 121 1 17.5 11.2 0 0 1 1 0 135 1 1.15 0.9;
+ 122 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 123 2 3.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 124 1 8.7 6.7 0 0.04 1 1 0 135 1 1.15 0.9;
+ 125 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 126 1 3.5 2.3 0 0 1 1 0 135 1 1.15 0.9;
+ 127 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 128 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 129 1 2.4 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 130 1 10.6 1.9 0 0 1 1 0 135 1 1.15 0.9;
+ %Area 2 (Transformers nodes for VSC DC GRID 1)
+ 901 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 902 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 903 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ %Area 3 (Transformers nodes for VSC DC GRID 1)
+ 904 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 905 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 906 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9
+ %Area 2 (DC GRID 1)
+ 1 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 2 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 3 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ %Area 3 (DC GRID 2)
+ 4 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 5 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 6 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 7 1 -15 0 0 0 3 1 0 200 1 1.15 0.9;
+ 8 1 -10 0 0 0 3 1 0 200 1 1.15 0.9;
+
+
+];
+%% generator data
+% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
+mpc.gen = [
+ %IEEE 57 Bus System
+ 101 23.54 0 150 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 102 60.97 0 60 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 122 21.59 0 62.5 -15 1 100 1 50 0 0 0 0 0 0 0 0 0 0 0 0;
+ 127 26.91 0 48.7 -15 1 100 1 55 0 0 0 0 0 0 0 0 0 0 0 0;
+ 123 19.2 0 40 -10 1 100 1 30 0 0 0 0 0 0 0 0 0 0 0 0;
+ 113 37 0 44.7 -15 1 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0
+ %WF Generator is added as a load in bus 7 and 8
+ ];
+%% branch data
+% fbus tbus r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP ----------------------
+mpc.branch = [
+%Area 1 IEEE 57 Bus System
+ 101 102 0.02 0.06 0.03 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 101 103 0.05 0.19 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 104 0.06 0.17 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 103 104 0.01 0.04 0 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 105 0.05 0.2 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 106 0.06 0.18 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 106 0.01 0.04 0 90 90 90 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 107 0.05 0.12 0.01 70 70 70 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 107 0.03 0.08 0.01 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 108 0.01 0.04 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 109 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 110 0 0.56 0 32 32 32 1 0 1 -360 360 0 0 0 3.0 0 0 0 0 0 0 1.2 0.8 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 111 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 110 0 0.11 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 112 0 0.26 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 113 0 0.14 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 114 0.12 0.26 0 32 32 32 1 0 1 -360 360 3.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;
+ 112 115 0.07 0.13 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 116 0.09 0.2 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 114 115 0.22 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 116 117 0.08 0.19 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 1.01 1.2 0.8 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 118 0.11 0.22 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 118 119 0.06 0.13 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 119 120 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 120 0.09 0.21 0 32 32 32 1 0 1 -360 360 7.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;%PST1
+ 110 117 0.03 0.08 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 121 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 122 0.07 0.15 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 121 122 0.01 0.02 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 123 0.1 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 122 124 0.12 0.18 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 123 124 0.13 0.27 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 124 125 0.19 0.33 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 126 0.25 0.38 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 127 0.11 0.21 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 128 127 0 0.4 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 129 0.22 0.42 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 130 0.32 0.6 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 129 130 0.24 0.45 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 108 128 0.06 0.2 0.02 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 128 0.02 0.06 0.01 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-2 (Transformers for VSC DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 113 901 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 902 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 130 903 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-3 (Transformers for VSC DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 102 904 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 905 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 906 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 2 (VSC of DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 901 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 1.1 0 1 1 2 0 1 -0.5 0.5 -360 360 0 0.0001 0.15 2 0; %VSC1vdc
+ 002 902 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 5.37 0 0 -25 0 0 0 0 0 0 1.2 0.8 1 0 1 -0.5 0.5 -50 50 0 0.0001 0.15 2 0; %VSC2z
+ 003 903 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 -2.38 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -50 50 0 0.0001 0.15 2 0; %VSC3z
+%Area 3 (VSC of DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 904 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.15 2 0; %VSC4z
+ 005 905 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 1.05 1.2 0.8 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.15 2 0; %VSC5z
+ 006 906 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 15 0 0 0 0 0 0 0 1.07 0 1 1 2 0 1 -0.5 0.5 -50 50 0 0.0001 0.15 2 0; %VSC6vdc
+%Area 2 (DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 002 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 001 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 002 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 3 (DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 005 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 004 006 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 005 008 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 006 007 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+];
+%%----- OPF Data -----%%
+%% generator cost data
+% 1 startup shutdown n x1 y1 ... xn yn
+% 2 startup shutdown n c(n-1) ... c0
+mpc.gencost = [
+ %Pg cost
+ 2 0 0 3 0.02 2 0;
+ 2 0 0 3 0.0175 1.75 0;
+ 2 0 0 3 0.0625 1 0;
+ 2 0 0 3 0.00834 3.25 0;
+ 2 0 0 3 0.025 3 0;
+ 2 0 0 3 0.025 3 0;
+ %Qg cost
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+
+];
diff --git a/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt2_pf.m b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt2_pf.m
new file mode 100644
index 000000000..6abee6ddd
--- /dev/null
+++ b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt2_pf.m
@@ -0,0 +1,179 @@
+function mpc = fubm_case_30_2MTDC_ctrls_vt2_pf
+%%%%%%%%%%%%%%%%%%%%%%%% IEEE_30_VSC Test Case %%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% MATPOWER Case Format : Version 2
+mpc.version = '2';
+
+%%----- Power Flow Data -----%%
+%% system MVA base
+mpc.baseMVA = 100;
+
+%% area data
+% area refbus
+mpc.areas = [
+ 1 101; %area 1 IEEE 30 Bus System
+ 2 1; %area 2 DC GRID 1
+ 3 901; %area 3 Transformers for VSC
+ ];
+
+
+%% bus data
+% bus_i type Pd Qd Gs Bs area Vm Va base zone Vmax Vmin
+
+mpc.bus = [
+ %Area 1 (IEEE 30 Bus System)
+ 101 3 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 102 2 30 12.7 0 0 1 1 0 135 1 1.15 0.9;
+ 103 1 2.4 1.2 0 0 1 1 0 135 1 1.15 0.9;
+ 104 1 7.6 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 105 1 0 0 0 0.19 1 1 0 135 1 1.15 0.9;
+ 106 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 107 1 22.8 10.9 0 0 1 1 0 135 1 1.15 0.9;
+ 108 1 30 30 0 0 1 1 0 135 1 1.15 0.9;
+ 109 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 110 1 5.8 2 0 0 1 1 0 135 1 1.15 0.9;
+ 111 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 112 1 11.2 7.5 0 0 1 1 0 135 1 1.15 0.9;
+ 113 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 114 1 6.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 115 1 8.2 2.5 0 0 1 1 0 135 1 1.15 0.9;
+ 116 1 3.5 1.8 0 0 1 1 0 135 1 1.15 0.9;
+ 117 1 9 5.8 0 0 1 1 0 135 1 1.15 0.9;
+ 118 1 3.2 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 119 1 9.5 3.4 0 0 1 1 0 135 1 1.15 0.9;
+ 120 1 2.2 0.7 0 0 1 1 0 135 1 1.15 0.9;
+ 121 1 17.5 11.2 0 0 1 1 0 135 1 1.15 0.9;
+ 122 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 123 2 3.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 124 1 8.7 6.7 0 0.04 1 1 0 135 1 1.15 0.9;
+ 125 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 126 1 3.5 2.3 0 0 1 1 0 135 1 1.15 0.9;
+ 127 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 128 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 129 1 2.4 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 130 1 10.6 1.9 0 0 1 1 0 135 1 1.15 0.9;
+ %Area 2 (Transformers nodes for VSC DC GRID 1)
+ 901 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 902 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 903 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ %Area 3 (Transformers nodes for VSC DC GRID 1)
+ 904 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 905 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 906 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9
+ %Area 2 (DC GRID 1)
+ 1 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 2 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 3 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ %Area 3 (DC GRID 2)
+ 4 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 5 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 6 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 7 1 -15 0 0 0 3 1 0 200 1 1.15 0.9;
+ 8 1 -10 0 0 0 3 1 0 200 1 1.15 0.9;
+
+
+];
+%% generator data
+% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
+mpc.gen = [
+ %IEEE 57 Bus System
+ 101 23.54 0 150 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 102 60.97 0 60 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 122 21.59 0 62.5 -15 1 100 1 50 0 0 0 0 0 0 0 0 0 0 0 0;
+ 127 26.91 0 48.7 -15 1 100 1 55 0 0 0 0 0 0 0 0 0 0 0 0;
+ 123 19.2 0 40 -10 1 100 1 30 0 0 0 0 0 0 0 0 0 0 0 0;
+ 113 37 0 44.7 -15 1 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0
+ %WF Generator is added as a load in bus 7 and 8
+ ];
+%% branch data
+% fbus tbus r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP ----------------------
+mpc.branch = [
+%Area 1 IEEE 57 Bus System
+ 101 102 0.02 0.06 0.03 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 101 103 0.05 0.19 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 104 0.06 0.17 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 103 104 0.01 0.04 0 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 105 0.05 0.2 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 106 0.06 0.18 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 106 0.01 0.04 0 90 90 90 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 107 0.05 0.12 0.01 70 70 70 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 107 0.03 0.08 0.01 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 108 0.01 0.04 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 109 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 110 0 0.56 0 32 32 32 1 0 1 -360 360 0 0 0 3.0 0 0 0 0 0 0 1.2 0.8 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 111 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 110 0 0.11 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 112 0 0.26 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 113 0 0.14 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 114 0.12 0.26 0 32 32 32 1 0 1 -360 360 3.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;
+ 112 115 0.07 0.13 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 116 0.09 0.2 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 114 115 0.22 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 116 117 0.08 0.19 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 1.01 1.2 0.8 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 118 0.11 0.22 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 118 119 0.06 0.13 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 119 120 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 120 0.09 0.21 0 32 32 32 1 0 1 -360 360 7.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;%PST1
+ 110 117 0.03 0.08 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 121 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 122 0.07 0.15 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 121 122 0.01 0.02 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 123 0.1 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 122 124 0.12 0.18 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 123 124 0.13 0.27 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 124 125 0.19 0.33 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 126 0.25 0.38 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 127 0.11 0.21 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 128 127 0 0.4 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 129 0.22 0.42 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 130 0.32 0.6 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 129 130 0.24 0.45 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 108 128 0.06 0.2 0.02 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 128 0.02 0.06 0.01 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-2 (Transformers for VSC DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 113 901 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 902 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 130 903 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-3 (Transformers for VSC DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 102 904 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 905 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 906 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 2 (VSC of DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 901 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 1.1 0 1 1 2 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC1vdc
+ 002 902 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 5.37 0 0 -25 0 0 0 0 0 0 1.2 0.8 1 0 1 -0.5 0.5 -50 50 0 0.0001 0.015 0.2 0; %VSC2z
+ 003 903 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 -2.38 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -50 50 0 0.0001 0.015 0.2 0; %VSC3z
+%Area 3 (VSC of DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 904 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC4z
+ 005 905 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 1.05 1.2 0.8 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC5z
+ 006 906 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 15 0 0 0 0 0 0 0 1.07 0 1 1 2 0 1 -0.5 0.5 -50 50 0 0.0001 0.015 0.2 0; %VSC6vdc
+%Area 2 (DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 002 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 001 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 002 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 3 (DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 005 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 004 006 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 005 008 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 006 007 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+];
+%%----- OPF Data -----%%
+%% generator cost data
+% 1 startup shutdown n x1 y1 ... xn yn
+% 2 startup shutdown n c(n-1) ... c0
+mpc.gencost = [
+ %Pg cost
+ 2 0 0 3 0.02 2 0;
+ 2 0 0 3 0.0175 1.75 0;
+ 2 0 0 3 0.0625 1 0;
+ 2 0 0 3 0.00834 3.25 0;
+ 2 0 0 3 0.025 3 0;
+ 2 0 0 3 0.025 3 0;
+ %Qg cost
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+
+];
diff --git a/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt2_pf_dp.m b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt2_pf_dp.m
new file mode 100644
index 000000000..cc69a2f2a
--- /dev/null
+++ b/src/tests/data/grids/fubm_case_30_2MTDC_ctrls_vt2_pf_dp.m
@@ -0,0 +1,201 @@
+function mpc = fubm_case_30_2MTDC_ctrls_vt2_pf_dp
+%%%%%%%%%%%%%%%%%%%%%%%% IEEE_30_VSC Test Case %%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% MATPOWER Case Format : Version 2
+mpc.version = '2';
+
+%%----- Power Flow Data -----%%
+%% system MVA base
+mpc.baseMVA = 100;
+
+%% area data
+% area refbus
+mpc.areas = [
+ 1 101; %area 1 IEEE 30 Bus System
+ 2 1; %area 2 DC GRID 1
+ 3 901; %area 3 Transformers for VSC
+ 4 909; %area 4 Statcom for VSC
+ 5 910; %area 5 Voltage Droop
+ ];
+
+
+%% bus data
+% bus_i type Pd Qd Gs Bs area Vm Va base zone Vmax Vmin
+
+mpc.bus = [
+ %Area 1 (IEEE 30 Bus System)
+ 101 3 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 102 2 30 12.7 0 0 1 1 0 135 1 1.15 0.9;
+ 103 1 2.4 1.2 0 0 1 1 0 135 1 1.15 0.9;
+ 104 1 7.6 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 105 1 0 0 0 0.19 1 1 0 135 1 1.15 0.9;
+ 106 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 107 1 22.8 10.9 0 0 1 1 0 135 1 1.15 0.9;
+ 108 1 30 30 0 0 1 1 0 135 1 1.15 0.9;
+ 109 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 110 1 5.8 2 0 0 1 1 0 135 1 1.15 0.9;
+ 111 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 112 1 11.2 7.5 0 0 1 1 0 135 1 1.15 0.9;
+ 113 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 114 1 6.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 115 1 8.2 2.5 0 0 1 1 0 135 1 1.15 0.9;
+ 116 1 3.5 1.8 0 0 1 1 0 135 1 1.15 0.9;
+ 117 1 9 5.8 0 0 1 1 0 135 1 1.15 0.9;
+ 118 1 3.2 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 119 1 9.5 3.4 0 0 1 1 0 135 1 1.15 0.9;
+ 120 1 2.2 0.7 0 0 1 1 0 135 1 1.15 0.9;
+ 121 1 17.5 11.2 0 0 1 1 0 135 1 1.15 0.9;
+ 122 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 123 2 3.2 1.6 0 0 1 1 0 135 1 1.15 0.9;
+ 124 1 8.7 6.7 0 0.04 1 1 0 135 1 1.15 0.9;
+ 125 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 126 1 3.5 2.3 0 0 1 1 0 135 1 1.15 0.9;
+ 127 2 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 128 1 0 0 0 0 1 1 0 135 1 1.15 0.9;
+ 129 1 2.4 0.9 0 0 1 1 0 135 1 1.15 0.9;
+ 130 1 10.6 1.9 0 0 1 1 0 135 1 1.15 0.9;
+ %Area 2 (Transformers nodes for VSC DC GRID 1)
+ 901 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 902 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ 903 1 0 0 0 0.0887 2 1 0 200 1 1.15 0.9;
+ %Area 3 (Transformers nodes for VSC DC GRID 2)
+ 904 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 905 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9;
+ 906 1 0 0 0 0.0887 3 1 0 200 1 1.15 0.9
+ %Area 2 (DC GRID 1)
+ 1 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 2 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ 3 1 0 0 0 0 2 1 0 200 1 1.15 0.9;
+ %Area 3 (DC GRID 2)
+ 4 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 5 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 6 1 0 0 0 0 3 1 0 200 1 1.15 0.9;
+ 7 1 -15 0 0 0 3 1 0 200 1 1.15 0.9;%Wind Farm Injection
+ 8 1 -10 0 0 0 3 1 0 200 1 1.15 0.9;%Wind Farm Injection
+ %Area 4 (Transformer nodes for STATCOMs)
+ 909 1 0 0 0 0 4 1 0 200 1 1.15 0.9;
+ %Area 4 (STATCOMs)
+ 9 1 0 0 0 0 4 1 0 200 1 1.15 0.9;%Fixed Node for STATCOM
+ %Area 5 (Transformer nodes for VSC DC GRID 3, DROOP)
+ 910 1 0 0 0 0 5 1 0 200 1 1.15 0.9;
+ 911 1 0 0 0 0 5 1 0 200 1 1.15 0.9;
+ %Area 4 (DC GRID 3, VSC DROOP)
+ 10 1 0 0 0 0 5 1 0 200 1 1.15 0.9;%Droop node
+ 11 1 0 0 0 0 5 1 0 200 1 1.15 0.9;
+];
+%% generator data
+% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
+mpc.gen = [
+ %IEEE 57 Bus System
+ 101 23.54 0 150 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 102 60.97 0 60 -20 1 100 1 80 0 0 0 0 0 0 0 0 0 0 0 0;
+ 122 21.59 0 62.5 -15 1 100 1 50 0 0 0 0 0 0 0 0 0 0 0 0;
+ 127 26.91 0 48.7 -15 1 100 1 55 0 0 0 0 0 0 0 0 0 0 0 0;
+ 123 19.2 0 40 -10 1 100 1 30 0 0 0 0 0 0 0 0 0 0 0 0;
+ 113 37 0 44.7 -15 1 100 1 40 0 0 0 0 0 0 0 0 0 0 0 0
+ %WF Generator is added as a load in bus 7 and 8
+ ];
+%% branch data
+% fbus tbus r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP ----------------------
+mpc.branch = [
+%Area 1 IEEE 57 Bus System
+ 101 102 0.02 0.06 0.03 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 101 103 0.05 0.19 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 104 0.06 0.17 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 103 104 0.01 0.04 0 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 105 0.05 0.2 0.02 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 106 0.06 0.18 0.02 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 106 0.01 0.04 0 90 90 90 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 107 0.05 0.12 0.01 70 70 70 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 107 0.03 0.08 0.01 130 130 130 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 108 0.01 0.04 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 109 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 110 0 0.56 0 32 32 32 1 0 1 -360 360 0 0 0 3.0 0 0 0 0 0 0 1.2 0.8 0 0 1 0 0 -360 360 0 0 0 0 0;%CTT1
+ 109 111 0 0.21 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 110 0 0.11 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 112 0 0.26 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 113 0 0.14 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 114 0.12 0.26 0 32 32 32 1 0 1 -360 360 3.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;%PST1
+ 112 115 0.07 0.13 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 116 0.09 0.2 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 114 115 0.22 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 116 117 0.08 0.19 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 1.01 1.2 0.8 0 0 1 0 0 -360 360 0 0 0 0 0;%CTT2
+ 115 118 0.11 0.22 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 118 119 0.06 0.13 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 119 120 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 120 0.09 0.21 0 32 32 32 1 0 1 -360 360 7.5 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -50.0 50.0 0 0 0 0 0;%PST2
+ 110 117 0.03 0.08 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 121 0.03 0.07 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 122 0.07 0.15 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 121 122 0.01 0.02 0 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 123 0.1 0.2 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 122 124 0.12 0.18 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 123 124 0.13 0.27 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 124 125 0.19 0.33 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 126 0.25 0.38 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 127 0.11 0.21 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 128 127 0 0.4 0 65 65 65 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 129 0.22 0.42 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 130 0.32 0.6 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 129 130 0.24 0.45 0 16 16 16 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 108 128 0.06 0.2 0.02 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 128 0.02 0.06 0.01 32 32 32 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-2 (Transformers for VSC DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 113 901 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 902 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 130 903 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-3 (Transformers for VSC DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 102 904 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 905 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 906 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 2 (VSC of DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 901 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 -3.5 0 0 0 0 0 0 0 1.1 0 1 1 4 0 1 -0.5 0.5 -50 50 0 0.0001 0.015 0.2 -0.1; %VSC1droop
+ 002 902 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 -25 0 0 0 0 0 0 1.2 0.8 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC2z
+ 003 903 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 -2.35 0 0 0 0 0 0 0 1.1 0 1 1 3 0 1 -0.5 0.5 -50 50 0 0.0001 0.015 0.2 -0.05; %VSC3droopZ
+%Area 3 (VSC of DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 904 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC4z
+ 005 905 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 1.05 1.2 0.8 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC5z
+ 006 906 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 15 0 0 0 0 0 0 0 1.07 0 1 1 2 0 1 -0.5 0.5 -50 50 0 0.0001 0.015 0.2 0; %VSC6vdc
+%Area 2 (DC GRID 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 001 002 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 001 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 002 003 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 3 (DC GRID 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 004 005 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 004 006 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 005 008 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 006 007 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 1-4 (Transformers for VSC STATCOM) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 124 909 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 4 (VSC of STATCOM) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 009 901 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 1.1 0 1 1 2 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC9vdc
+%Area 1-5 (Transformers for VSC DC GRID 3) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 123 910 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 108 911 0.0015 0.1121 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 5 (VSC of DC GRID 3) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 010 910 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 2 0 0 0 0 0 0 0 1.0 0 1 1 4 0 1 -0.5 0.5 -100 100 0 0.0001 0.015 0.2 -0.05; %VSC10droop
+ 011 911 0.0001 0.1643 0 100 100 100 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.015 0.2 0; %VSC11z
+%Area 5 (DC GRID 3) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 ----------------------
+ 010 011 0.05 0 0 200 200 200 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 -360 360 0 0 0 0 0;
+];
+%%----- OPF Data -----%%
+%% generator cost data
+% 1 startup shutdown n x1 y1 ... xn yn
+% 2 startup shutdown n c(n-1) ... c0
+mpc.gencost = [
+ %Pg cost
+ 2 0 0 3 0.02 2 0;
+ 2 0 0 3 0.0175 1.75 0;
+ 2 0 0 3 0.0625 1 0;
+ 2 0 0 3 0.00834 3.25 0;
+ 2 0 0 3 0.025 3 0;
+ 2 0 0 3 0.025 3 0;
+ %Qg cost
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+ 2 0 0 3 0.0000 0 0;
+
+];
diff --git a/src/tests/data/grids/fubm_case_57_14_2MTDC_ctrls.gridcal b/src/tests/data/grids/fubm_case_57_14_2MTDC_ctrls.gridcal
new file mode 100644
index 000000000..d7ad5f4f3
Binary files /dev/null and b/src/tests/data/grids/fubm_case_57_14_2MTDC_ctrls.gridcal differ
diff --git a/src/tests/data/grids/fubm_case_57_14_2MTDC_ctrls.m b/src/tests/data/grids/fubm_case_57_14_2MTDC_ctrls.m
new file mode 100644
index 000000000..9cd86d3a6
--- /dev/null
+++ b/src/tests/data/grids/fubm_case_57_14_2MTDC_ctrls.m
@@ -0,0 +1,292 @@
+function mpc = fubm_case_57_14_2MTDC_ctrls
+%%%%%%%%%%%%%%%%%%%%%%%%%% IEEE_57_14_VSC Test Case %%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% MATPOWER Case Format : Version 2
+mpc.version = '2';
+
+%%----- Power Flow Data -----%%
+%% system MVA base
+mpc.baseMVA = 100;
+
+%% area data
+% area refbus
+mpc.areas = [
+ 1 101; %area 1 IEEE 57 Bus System
+ 2 201; %area 2 IEEE 14 Bus System
+ 3 1; %DC area 1
+ 4 4; %DC area 2
+ ];
+
+%% bus data
+% bus_i type Pd Qd Gs Bs area Vm Va base zone Vmax Vmin
+
+mpc.bus = [
+ %Area 1 (IEEE 57 Bus System)
+ 101 3 55 17 0 0 1 1 0 0 1 1.06 0.94;
+ 102 2 3 88 0 0 1 1 0 0 1 1.06 0.94;
+ 103 2 41 21 0 0 1 1 0 0 1 1.06 0.94;
+ 104 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 105 1 13 4 0 0 1 1 0 0 1 1.06 0.94;
+ 106 2 75 2 0 0 1 1 0 0 1 1.06 0.94;
+ 107 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 108 2 150 22 0 0 1 1 0 0 1 1.06 0.94;
+ 109 2 121 26 0 0 1 1 0 0 1 1.06 0.94;
+ 110 1 5 2 0 0 1 1 0 0 1 1.06 0.94;
+ 111 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 112 2 377 24 0 0 1 1 0 0 1 1.06 0.94;
+ 113 1 18 2.3 0 0 1 1 0 0 1 1.06 0.94;
+ 114 1 10.5 5.3 0 0 1 1 0 0 1 1.06 0.94;
+ 115 1 22 5 0 0 1 1 0 0 1 1.06 0.94;
+ 116 1 43 3 0 0 1 1 0 0 1 1.06 0.94;
+ 117 1 42 8 0 0 1 1 0 0 1 1.06 0.94;
+ 118 1 27.2 9.8 0 10 1 1 0 0 1 1.06 0.94;
+ 119 1 3.3 0.6 0 0 1 1 0 0 1 1.06 0.94;
+ 120 1 2.3 1 0 0 1 1 0 0 1 1.06 0.94;
+ 121 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 122 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 123 1 6.3 2.1 0 0 1 1 0 0 1 1.06 0.94;
+ 124 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 125 1 6.3 3.2 0 5.9 1 1 0 0 1 1.06 0.94;
+ 126 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 127 1 9.3 0.5 0 0 1 1 0 0 1 1.06 0.94;
+ 128 1 4.6 2.3 0 0 1 1 0 0 1 1.06 0.94;
+ 129 1 17 2.6 0 0 1 1 0 0 1 1.06 0.94;
+ 130 1 3.6 1.8 0 0 1 1 0 0 1 1.06 0.94;
+ 131 1 5.8 2.9 0 0 1 1 0 0 1 1.06 0.94;
+ 132 1 1.6 0.8 0 0 1 1 0 0 1 1.06 0.94;
+ 133 1 3.8 1.9 0 0 1 1 0 0 1 1.06 0.94;
+ 134 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 135 1 6 3 0 0 1 1 0 0 1 1.06 0.94;
+ 136 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 137 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 138 1 14 7 0 0 1 1 0 0 1 1.06 0.94;
+ 139 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 140 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 141 1 6.3 3 0 0 1 1 0 0 1 1.06 0.94;
+ 142 1 7.1 4.4 0 0 1 1 0 0 1 1.06 0.94;
+ 143 1 2 1 0 0 1 1 0 0 1 1.06 0.94;
+ 144 1 12 1.8 0 0 1 1 0 0 1 1.06 0.94;
+ 145 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 146 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 147 1 29.7 11.6 0 0 1 1 0 0 1 1.06 0.94;
+ 148 1 0 0 0 0 1 1 0 0 1 1.06 0.94;
+ 149 1 18 8.5 0 0 1 1 0 0 1 1.06 0.94;
+ 150 1 21 10.5 0 0 1 1 0 0 1 1.06 0.94;
+ 151 1 18 5.3 0 0 1 1 0 0 1 1.06 0.94;
+ 152 1 4.9 2.2 0 0 1 1 0 0 1 1.06 0.94;
+ 153 1 20 10 0 6.3 1 1 0 0 1 1.06 0.94;
+ 154 1 4.1 1.4 0 0 1 1 0 0 1 1.06 0.94;
+ 155 1 6.8 3.4 0 0 1 1 0 0 1 1.06 0.94;
+ 156 1 7.6 2.2 0 0 1 1 0 0 1 1.06 0.94;
+ 157 1 6.7 2 0 0 1 1 0 0 1 1.06 0.94;
+ %Area 2 (IEEE 14 Bus System)
+ 201 2 0 0 0 0 2 1 0 0 1 1.06 0.94;
+ 202 2 21.7 12.7 0 0 2 1 0 0 1 1.06 0.94;
+ 203 2 94.2 19 0 0 2 1 0 0 1 1.06 0.94;
+ 204 1 47.8 -3.9 0 0 2 1 0 0 1 1.06 0.94;
+ 205 1 7.6 1.6 0 0 2 1 0 0 1 1.06 0.94;
+ 206 2 11.2 7.5 0 0 2 1 0 0 1 1.06 0.94;
+ 207 1 0 0 0 0 2 1 0 0 1 1.06 0.94;
+ 208 2 0 0 0 0 2 1 0 0 1 1.06 0.94;
+ 209 1 29.5 16.6 0 19 2 1 0 0 1 1.06 0.94;
+ 210 1 9 5.8 0 0 2 1 0 0 1 1.06 0.94;
+ 211 1 3.5 1.8 0 0 2 1 0 0 1 1.06 0.94;
+ 212 1 6.1 1.6 0 0 2 1 0 0 1 1.06 0.94;
+ 213 1 13.5 5.8 0 0 2 1 0 0 1 1.06 0.94;
+ 214 1 14.9 5 0 0 2 1 0 0 1 1.06 0.94;
+ %Area 3 (DC Area 1)
+ 1 1 0 0 0 0.0 3 1 0 100.0 1 1.06 0.94; %DC A3
+ 2 1 0 0 0 0.0 3 1 0 100.0 1 1.06 0.94; %DC A3
+ 3 1 0 0 0 0.0 3 1 0 100.0 1 1.06 0.94; %DC A3
+ %Area 4 (DC Area 2)
+ 4 1 0 0 0 0.0 4 1 0 200.0 1 1.06 0.94; %DC A4
+ 5 1 0 0 0 0.0 4 1 0 200.0 1 1.06 0.94; %DC A4
+ 6 1 0 0 0 0.0 4 1 0 200.0 1 1.06 0.94; %DC A4
+ 7 1 0 0 0 0.0 4 1 0 200.0 1 1.06 0.94; %DC A4
+ 8 1 0 0 0 0.0 4 1 0 200.0 1 1.06 0.94; %DC A4
+ 9 1 -20 0 0 0.0 4 1 0 200.0 1 1.06 0.94; %DC A4
+ 10 1 0 0 0 0.0 4 1 0 200.0 1 1.06 0.94; %DC A4
+];
+%% generator data
+% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
+mpc.gen = [
+ %IEEE 57 Bus System
+ 101 128.9 -16.1 200 -140 1.04 100 1 575.88 0 0 0 0 0 0 0 0 0 0 0 0;
+ 102 0 -0.8 50 -17 1.01 100 1 100 0 0 0 0 0 0 0 0 0 0 0 0;
+ 103 40 -1 60 -10 0.985 100 1 140 0 0 0 0 0 0 0 0 0 0 0 0;
+ 106 0 0.8 25 -8 0.98 100 1 100 0 0 0 0 0 0 0 0 0 0 0 0;
+ 108 450 62.1 200 -140 1.005 100 1 550 0 0 0 0 0 0 0 0 0 0 0 0;
+ 109 0 2.2 9 -3 0.98 100 1 100 0 0 0 0 0 0 0 0 0 0 0 0;
+ 112 310 128.5 155 -150 1.015 100 1 410 0 0 0 0 0 0 0 0 0 0 0 0;
+ %IEEE 14 Bus System
+ 201 232.4 -16.9 10 0 1.06 100 1 332.4 0 0 0 0 0 0 0 0 0 0 0 0;
+ 202 40 42.4 50 -40 1.045 100 1 140 0 0 0 0 0 0 0 0 0 0 0 0;
+ 203 0 23.4 40 0 1.01 100 1 100 0 0 0 0 0 0 0 0 0 0 0 0;
+ 206 0 12.2 24 -6 1.07 100 1 100 0 0 0 0 0 0 0 0 0 0 0 0;
+ 208 0 17.4 24 -6 1.09 100 1 100 0 0 0 0 0 0 0 0 0 0 0 0;
+ %PV Generator is added as a load in bus 9
+ ];
+%% branch data
+% fbus tbus r x b rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3 KDP ----------------------
+mpc.branch = [
+%Area 1 IEEE 57 Bus System
+ 101 102 0.0083 0.028 0.129 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 102 103 0.0298 0.085 0.0818 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 103 104 0.0112 0.0366 0.038 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 105 0.0625 0.132 0.0258 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 106 0.043 0.148 0.0348 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 107 0.02 0.102 0.0276 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 106 108 0.0339 0.173 0.047 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 108 109 0.0099 0.0505 0.0548 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 110 0.0369 0.1679 0.044 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 111 0.0258 0.0848 0.0218 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 112 0.0648 0.295 0.0772 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 113 0.0481 0.158 0.0406 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 113 114 0.0132 0.0434 0.011 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 113 115 0.0269 0.0869 0.023 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 101 115 0.0178 0.091 0.0988 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 101 116 0.0454 0.206 0.0546 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 101 117 0.0238 0.108 0.0286 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 103 115 0.0162 0.053 0.0544 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 118 0 0.555 0 000 0 0 0.97 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 104 118 0 0.43 0 000 0 0 0.978 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 105 106 0.0302 0.0641 0.0124 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 107 108 0.0139 0.0712 0.0194 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 112 0.0277 0.1262 0.0328 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 111 113 0.0223 0.0732 0.0188 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 113 0.0178 0.058 0.0604 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 116 0.018 0.0813 0.0216 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 112 117 0.0397 0.179 0.0476 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 114 115 0.0171 0.0547 0.0148 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 118 119 0.461 0.685 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 119 120 0.283 0.434 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 121 120 0 0.7767 0 000 0 0 1.043 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 121 122 0.0736 0.117 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 122 123 0.0099 0.0152 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 123 124 0.166 0.256 0.0084 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 124 125 0 1.182 0 000 0 0 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 124 125 0 1.23 0 000 0 0 1 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 124 126 0 0.0473 0 000 0 0 1.043 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 126 127 0.165 0.254 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 127 128 0.0618 0.0954 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 128 129 0.0418 0.0587 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 107 129 0 0.0648 0 000 0 0 0.967 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 125 130 0.135 0.202 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 130 131 0.326 0.497 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 131 132 0.507 0.755 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 132 133 0.0392 0.036 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 134 132 0 0.953 0 000 0 0 0.975 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 134 135 0.052 0.078 0.0032 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 135 136 0.043 0.0537 0.0016 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 136 137 0.029 0.0366 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 137 138 0.0651 0.1009 0.002 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 137 139 0.0239 0.0379 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 136 140 0.03 0.0466 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 122 138 0.0192 0.0295 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 111 141 0 0.749 0 000 0 0 0.955 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 141 142 0.207 0.352 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 141 143 0 0.412 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 138 144 0.0289 0.0585 0.002 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 115 145 0 0.1042 0 000 0 0 0.955 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 114 146 0 0.0735 0 000 0 0 0.9 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 146 147 0.023 0.068 0.0032 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 147 148 0.0182 0.0233 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 148 149 0.0834 0.129 0.0048 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 149 150 0.0801 0.128 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 150 151 0.1386 0.22 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 110 151 0 0.0712 0 000 0 0 0.93 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 113 149 0 0.191 0 000 0 0 0.895 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 129 152 0.1442 0.187 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 152 153 0.0762 0.0984 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 153 154 0.1878 0.232 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 154 155 0.1732 0.2265 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 111 143 0 0.153 0 000 0 0 0.958 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 144 145 0.0624 0.1242 0.004 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 140 156 0 1.195 0 000 0 0 0.958 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 156 141 0.553 0.549 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 156 142 0.2125 0.354 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 139 157 0 1.355 0 000 0 0 0.98 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 157 156 0.174 0.26 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 138 149 0.115 0.177 0.003 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 138 148 0.0312 0.0482 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 109 155 0 0.1205 0 000 0 0 0.94 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 2 IEEE 14 Bus System rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3
+ 201 202 0.01938 0.05917 0.0528 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 201 205 0.05403 0.22304 0.0492 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 202 203 0.04699 0.19797 0.0438 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 202 204 0.05811 0.17632 0.034 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 202 205 0.05695 0.17388 0.0346 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 203 204 0.06701 0.17103 0.0128 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 204 205 0.01335 0.04211 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 204 207 0 0.20912 0 000 0 0 0.978 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 204 209 0 0.55618 0 000 0 0 0.969 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 205 206 0 0.25202 0 000 0 0 0.932 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 206 211 0.09498 0.1989 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 206 212 0.12291 0.25581 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 206 213 0.06615 0.13027 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 207 208 0 0.17615 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 207 209 0 0.11001 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 209 210 0.03181 0.0845 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 209 214 0.12711 0.27038 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 210 211 0.08205 0.19207 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 212 213 0.22092 0.19988 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 213 214 0.17093 0.34802 0 000 0 0 0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+%Area 3 (DC Area 1) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A bEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3
+ % DC Grid
+ 1 2 0.010 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 2 3 0.010 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 3 1 0.020 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ % DC Converters rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3
+ 1 212 0.0510 0.033 0 000 500 500 1.0 0 1 -360 360 0 0 0 0 0 0 0 0 1.05 0 0 0 2 0 1 -0.5 0.5 -360 360 0 0.0001 0.005 0.05 0;%Conv1
+ 2 150 0.0765 0.050 0 000 500 500 1.0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.005 0.05 0;%Conv2
+ 3 151 0.0765 0.050 0 000 500 500 1.0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.005 0.05 0;%Conv3
+ % DC Transformers
+%Area 4 (DC Area 2) rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3
+ % DC Grid
+ 4 9 0.010 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 4 10 0.005 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 5 6 0.015 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 5 7 0.015 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 6 10 0.010 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 7 10 0.015 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ 8 9 0.015 0 0 000 500 500 0.0 0.0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 -360 360 0 0 0 0 0;
+ % DC Converters rateA rateB rateC ratio/ma angle status angmin angmax PF QF PT QT MU_SF MU_ST MU_ANGMIN MU_ANGMAX VF_SET VT_SET MA_MAX MA_MIN CONV_A BEQ K2 BEQ_MIN BEQ_MAX SH_MIN SH_MAX GSW ALPHA1 ALPHA2 ALPHA3
+ 4 101 0.0510 0.033 0 000 500 500 1.0 0 1 -360 360 0 0 0 0 0 0 0 0 1.01 0 0 0 2 0 1 -0.5 0.5 -360 360 0 0.0001 0.005 0.05 0;%Conv4
+ 5 202 0.0765 0.050 0 000 500 500 1.0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.005 0.05 0;%Conv5
+ 6 205 0.0765 0.050 0 000 500 500 1.0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.005 0.05 0;%Conv6
+ 7 115 0.0765 0.050 0 000 500 500 1.0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.005 0.05 0;%Conv7
+ 8 117 0.0765 0.050 0 000 500 500 1.0 0 1 -360 360 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 -0.5 0.5 -360 360 0 0.0001 0.005 0.05 0;%Conv8
+ % DC Transformers
+ ];
+%%----- OPF Data -----%%
+%% generator cost data
+% 1 startup shutdown n x1 y1 ... xn yn
+% 2 startup shutdown n c(n-1) ... c0
+mpc.gencost = [
+ %Pg cost
+ 2 0 0 3 0.077579519 20 0;
+ 2 0 0 3 0.01 40 0;
+ 2 0 0 3 0.25 20 0;
+ 2 0 0 3 0.01 40 0;
+ 2 0 0 3 0.0222222222 20 0;
+ 2 0 0 3 0.01 40 0;
+ 2 0 0 3 0.0322580645 20 0;
+ 2 0 0 3 0.0430292599 20 0;
+ 2 0 0 3 0.25 20 0;
+ 2 0 0 3 0.01 40 0;
+ 2 0 0 3 0.01 40 0;
+ 2 0 0 3 0.01 40 0;
+ %Qg cost
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+ 2 0 0 3 0.000 0 0;
+];
diff --git a/src/tests/demo_5_node.json b/src/tests/demo_5_node.json
deleted file mode 100644
index 45a0a1718..000000000
--- a/src/tests/demo_5_node.json
+++ /dev/null
@@ -1,601 +0,0 @@
-{
- "version": "3",
- "review": "1",
- "software": "GridCal",
- "units": {
- "Circuit": {
- "time": "Milliseconds since 1/1/1970 (Unix time in ms)"
- },
- "Substation": {},
- "Zone": {},
- "Area": {},
- "Country": {},
- "Bus": {
- "vnom": "kV",
- "vmin": "p.u.",
- "vmax": "p.u.",
- "rf": "p.u.",
- "xf": "p.u.",
- "x": "px",
- "y": "px",
- "h": "px",
- "w": "px",
- "lat": "degrees",
- "lon": "degrees",
- "alt": "m"
- },
- "Generator": {
- "p": "MW",
- "vset": "p.u.",
- "pf": "p.u.",
- "snom": "MVA",
- "enom": "MWh",
- "qmin": "MVAr",
- "qmax": "MVAr",
- "pmin": "MW",
- "pmax": "MW",
- "cost": "\u20ac/MWh"
- },
- "Load": {
- "g": "MVAr at V=1 p.u.",
- "b": "MVAr at V=1 p.u.",
- "ir": "MVAr at V=1 p.u.",
- "ii": "MVAr at V=1 p.u.",
- "p": "MW",
- "q": "MVAr"
- },
- "Line": {
- "rate": "MW",
- "r": "p.u.",
- "x": "p.u.",
- "b": "p.u.",
- "length": "km",
- "base_temperature": "\u00baC",
- "operational_temperature": "\u00baC",
- "alpha": "1/\u00baC"
- }
- },
- "devices": {
- "Circuit": {
- "id": "b3e45aaa1f5e48b3bb6c665b77fb35c4",
- "phases": "ps",
- "name": "",
- "sbase": 100,
- "fbase": 50.0,
- "model_version": 2,
- "user_name": "76284925432743:santi",
- "comments": ""
- },
- "Substation": [
- {
- "id": "67f02fc26dd94b3a9a772a8e75e87eb3",
- "name": "Default substation",
- "code": ""
- }
- ],
- "Zone": [
- {
- "id": "83b2fe03ca724539864f34a27845cf44",
- "name": "Default zone",
- "code": ""
- }
- ],
- "Area": [
- {
- "id": "01cb5c3368ec46418c0f6acbfe27b24d",
- "name": "Default area",
- "code": ""
- }
- ],
- "Country": [
- {
- "id": "81352837d37746d28a1c9a038ae2c50b",
- "name": "Default country",
- "code": ""
- }
- ],
- "Bus": [
- {
- "id": "acc828a87f8e4ac984949d569fffed03",
- "type": 2,
- "phases": "ps",
- "name": "Bus 1",
- "name_code": "",
- "active": true,
- "is_slack": false,
- "vnom": 20,
- "vmin": 0.9,
- "vmax": 1.1,
- "rf": 0.0,
- "xf": 0.0,
- "x": 0,
- "y": 0,
- "h": 0,
- "w": 0,
- "lat": 0.0,
- "lon": 0.0,
- "alt": 0.0,
- "country": "81352837d37746d28a1c9a038ae2c50b",
- "area": "01cb5c3368ec46418c0f6acbfe27b24d",
- "zone": "83b2fe03ca724539864f34a27845cf44",
- "substation": "67f02fc26dd94b3a9a772a8e75e87eb3"
- },
- {
- "id": "9e4e37442c3c483c843333069f3b4954",
- "type": 1,
- "phases": "ps",
- "name": "Bus 2",
- "name_code": "",
- "active": true,
- "is_slack": false,
- "vnom": 20,
- "vmin": 0.9,
- "vmax": 1.1,
- "rf": 0.0,
- "xf": 0.0,
- "x": 0,
- "y": 0,
- "h": 0,
- "w": 0,
- "lat": 0.0,
- "lon": 0.0,
- "alt": 0.0,
- "country": "81352837d37746d28a1c9a038ae2c50b",
- "area": "01cb5c3368ec46418c0f6acbfe27b24d",
- "zone": "83b2fe03ca724539864f34a27845cf44",
- "substation": "67f02fc26dd94b3a9a772a8e75e87eb3"
- },
- {
- "id": "cf08ffe7444c4a9a907b801647378232",
- "type": 1,
- "phases": "ps",
- "name": "Bus 3",
- "name_code": "",
- "active": true,
- "is_slack": false,
- "vnom": 20,
- "vmin": 0.9,
- "vmax": 1.1,
- "rf": 0.0,
- "xf": 0.0,
- "x": 0,
- "y": 0,
- "h": 0,
- "w": 0,
- "lat": 0.0,
- "lon": 0.0,
- "alt": 0.0,
- "country": "81352837d37746d28a1c9a038ae2c50b",
- "area": "01cb5c3368ec46418c0f6acbfe27b24d",
- "zone": "83b2fe03ca724539864f34a27845cf44",
- "substation": "67f02fc26dd94b3a9a772a8e75e87eb3"
- },
- {
- "id": "c3b4490daeb749cc87fd7e689e2222eb",
- "type": 1,
- "phases": "ps",
- "name": "Bus 4",
- "name_code": "",
- "active": true,
- "is_slack": false,
- "vnom": 20,
- "vmin": 0.9,
- "vmax": 1.1,
- "rf": 0.0,
- "xf": 0.0,
- "x": 0,
- "y": 0,
- "h": 0,
- "w": 0,
- "lat": 0.0,
- "lon": 0.0,
- "alt": 0.0,
- "country": "81352837d37746d28a1c9a038ae2c50b",
- "area": "01cb5c3368ec46418c0f6acbfe27b24d",
- "zone": "83b2fe03ca724539864f34a27845cf44",
- "substation": "67f02fc26dd94b3a9a772a8e75e87eb3"
- },
- {
- "id": "a3a5a2eb033b4a39bddf3517b202d1de",
- "type": 1,
- "phases": "ps",
- "name": "Bus 5",
- "name_code": "",
- "active": true,
- "is_slack": false,
- "vnom": 20,
- "vmin": 0.9,
- "vmax": 1.1,
- "rf": 0.0,
- "xf": 0.0,
- "x": 0,
- "y": 0,
- "h": 0,
- "w": 0,
- "lat": 0.0,
- "lon": 0.0,
- "alt": 0.0,
- "country": "81352837d37746d28a1c9a038ae2c50b",
- "area": "01cb5c3368ec46418c0f6acbfe27b24d",
- "zone": "83b2fe03ca724539864f34a27845cf44",
- "substation": "67f02fc26dd94b3a9a772a8e75e87eb3"
- }
- ],
- "Generator": [
- {
- "id": "5ab436a08c8c4fc9ba51bd6978678f44",
- "type": "generator",
- "phases": "ps",
- "name": "Slack Generator",
- "name_code": "",
- "bus": "acc828a87f8e4ac984949d569fffed03",
- "active": true,
- "is_controlled": true,
- "p": 0.0,
- "pf": 0.8,
- "vset": 1.0,
- "snom": 9999,
- "qmin": -9999,
- "qmax": 9999,
- "pmin": 0.0,
- "pmax": 9999.0,
- "cost": 1.0,
- "technology": ""
- }
- ],
- "Load": [
- {
- "id": "6ba4367a49ba4311bc6184e39bf42d7e",
- "type": "load",
- "phases": "ps",
- "name": "load 2",
- "name_code": "",
- "bus": "9e4e37442c3c483c843333069f3b4954",
- "active": true,
- "g": 0.0,
- "b": 0.0,
- "ir": 0.0,
- "ii": 0.0,
- "p": 40,
- "q": 20
- },
- {
- "id": "82b4572638dd4e1ea6a2013aa6ecff83",
- "type": "load",
- "phases": "ps",
- "name": "load 3",
- "name_code": "",
- "bus": "cf08ffe7444c4a9a907b801647378232",
- "active": true,
- "g": 0.0,
- "b": 0.0,
- "ir": 0.0,
- "ii": 0.0,
- "p": 25,
- "q": 15
- },
- {
- "id": "a29e8a8df53c44ff83d3aef9b87b2ece",
- "type": "load",
- "phases": "ps",
- "name": "load 4",
- "name_code": "",
- "bus": "c3b4490daeb749cc87fd7e689e2222eb",
- "active": true,
- "g": 0.0,
- "b": 0.0,
- "ir": 0.0,
- "ii": 0.0,
- "p": 40,
- "q": 20
- },
- {
- "id": "b4013adde08d4981a10ece058ec2c70e",
- "type": "load",
- "phases": "ps",
- "name": "load 5",
- "name_code": "",
- "bus": "a3a5a2eb033b4a39bddf3517b202d1de",
- "active": true,
- "g": 0.0,
- "b": 0.0,
- "ir": 0.0,
- "ii": 0.0,
- "p": 50,
- "q": 20
- }
- ],
- "Line": [
- {
- "id": "95ea0e38443e44f8b4111946abe504f0",
- "type": "line",
- "phases": "ps",
- "name": "line 1-2",
- "name_code": "",
- "bus_from": "acc828a87f8e4ac984949d569fffed03",
- "bus_to": "9e4e37442c3c483c843333069f3b4954",
- "active": true,
- "rate": 1.0,
- "contingency_factor1": 1.0,
- "contingency_factor2": 1.0,
- "contingency_factor3": 1.0,
- "r": 0.05,
- "x": 0.11,
- "b": 0.02,
- "length": 1,
- "base_temperature": 20,
- "operational_temperature": 20,
- "alpha": 0.0033,
- "locations": []
- },
- {
- "id": "f575b5b8fb9d487a93183ad06d33df88",
- "type": "line",
- "phases": "ps",
- "name": "line 1-3",
- "name_code": "",
- "bus_from": "acc828a87f8e4ac984949d569fffed03",
- "bus_to": "cf08ffe7444c4a9a907b801647378232",
- "active": true,
- "rate": 1.0,
- "contingency_factor1": 1.0,
- "contingency_factor2": 1.0,
- "contingency_factor3": 1.0,
- "r": 0.05,
- "x": 0.11,
- "b": 0.02,
- "length": 1,
- "base_temperature": 20,
- "operational_temperature": 20,
- "alpha": 0.0033,
- "locations": []
- },
- {
- "id": "b2ee3e910bc442fa91200672b47c35b6",
- "type": "line",
- "phases": "ps",
- "name": "line 1-5",
- "name_code": "",
- "bus_from": "acc828a87f8e4ac984949d569fffed03",
- "bus_to": "a3a5a2eb033b4a39bddf3517b202d1de",
- "active": true,
- "rate": 1.0,
- "contingency_factor1": 1.0,
- "contingency_factor2": 1.0,
- "contingency_factor3": 1.0,
- "r": 0.03,
- "x": 0.08,
- "b": 0.02,
- "length": 1,
- "base_temperature": 20,
- "operational_temperature": 20,
- "alpha": 0.0033,
- "locations": []
- },
- {
- "id": "d588b26ffc3c476081cb845b13e66240",
- "type": "line",
- "phases": "ps",
- "name": "line 2-3",
- "name_code": "",
- "bus_from": "9e4e37442c3c483c843333069f3b4954",
- "bus_to": "cf08ffe7444c4a9a907b801647378232",
- "active": true,
- "rate": 1.0,
- "contingency_factor1": 1.0,
- "contingency_factor2": 1.0,
- "contingency_factor3": 1.0,
- "r": 0.04,
- "x": 0.09,
- "b": 0.02,
- "length": 1,
- "base_temperature": 20,
- "operational_temperature": 20,
- "alpha": 0.0033,
- "locations": []
- },
- {
- "id": "6512cc1eb21d480d99f48998cea1f165",
- "type": "line",
- "phases": "ps",
- "name": "line 2-5",
- "name_code": "",
- "bus_from": "9e4e37442c3c483c843333069f3b4954",
- "bus_to": "a3a5a2eb033b4a39bddf3517b202d1de",
- "active": true,
- "rate": 1.0,
- "contingency_factor1": 1.0,
- "contingency_factor2": 1.0,
- "contingency_factor3": 1.0,
- "r": 0.04,
- "x": 0.09,
- "b": 0.02,
- "length": 1,
- "base_temperature": 20,
- "operational_temperature": 20,
- "alpha": 0.0033,
- "locations": []
- },
- {
- "id": "83c7bb64411c4fe282a15046c21343e8",
- "type": "line",
- "phases": "ps",
- "name": "line 3-4",
- "name_code": "",
- "bus_from": "cf08ffe7444c4a9a907b801647378232",
- "bus_to": "c3b4490daeb749cc87fd7e689e2222eb",
- "active": true,
- "rate": 1.0,
- "contingency_factor1": 1.0,
- "contingency_factor2": 1.0,
- "contingency_factor3": 1.0,
- "r": 0.06,
- "x": 0.13,
- "b": 0.03,
- "length": 1,
- "base_temperature": 20,
- "operational_temperature": 20,
- "alpha": 0.0033,
- "locations": []
- },
- {
- "id": "0e9dae1b651c41dd8cd596b107f58180",
- "type": "line",
- "phases": "ps",
- "name": "line 4-5",
- "name_code": "",
- "bus_from": "c3b4490daeb749cc87fd7e689e2222eb",
- "bus_to": "a3a5a2eb033b4a39bddf3517b202d1de",
- "active": true,
- "rate": 1.0,
- "contingency_factor1": 1.0,
- "contingency_factor2": 1.0,
- "contingency_factor3": 1.0,
- "r": 0.04,
- "x": 0.09,
- "b": 0.02,
- "length": 1,
- "base_temperature": 20,
- "operational_temperature": 20,
- "alpha": 0.0033,
- "locations": []
- }
- ]
- },
- "profiles": {
- "Circuit": {
- "time": []
- },
- "Substation": [
- {
- "id": "67f02fc26dd94b3a9a772a8e75e87eb3"
- }
- ],
- "Zone": [
- {
- "id": "83b2fe03ca724539864f34a27845cf44"
- }
- ],
- "Area": [
- {
- "id": "01cb5c3368ec46418c0f6acbfe27b24d"
- }
- ],
- "Country": [
- {
- "id": "81352837d37746d28a1c9a038ae2c50b"
- }
- ],
- "Bus": [
- {
- "id": "acc828a87f8e4ac984949d569fffed03",
- "active": []
- },
- {
- "id": "9e4e37442c3c483c843333069f3b4954",
- "active": []
- },
- {
- "id": "cf08ffe7444c4a9a907b801647378232",
- "active": []
- },
- {
- "id": "c3b4490daeb749cc87fd7e689e2222eb",
- "active": []
- },
- {
- "id": "a3a5a2eb033b4a39bddf3517b202d1de",
- "active": []
- }
- ],
- "Generator": [
- {
- "id": "5ab436a08c8c4fc9ba51bd6978678f44",
- "active": [],
- "p": [],
- "v": [],
- "pf": []
- }
- ],
- "Load": [
- {
- "id": "6ba4367a49ba4311bc6184e39bf42d7e",
- "active": [],
- "p": [],
- "q": [],
- "ir": [],
- "ii": [],
- "g": [],
- "b": []
- },
- {
- "id": "82b4572638dd4e1ea6a2013aa6ecff83",
- "active": [],
- "p": [],
- "q": [],
- "ir": [],
- "ii": [],
- "g": [],
- "b": []
- },
- {
- "id": "a29e8a8df53c44ff83d3aef9b87b2ece",
- "active": [],
- "p": [],
- "q": [],
- "ir": [],
- "ii": [],
- "g": [],
- "b": []
- },
- {
- "id": "b4013adde08d4981a10ece058ec2c70e",
- "active": [],
- "p": [],
- "q": [],
- "ir": [],
- "ii": [],
- "g": [],
- "b": []
- }
- ],
- "Line": [
- {
- "id": "95ea0e38443e44f8b4111946abe504f0",
- "active": [],
- "rate": []
- },
- {
- "id": "f575b5b8fb9d487a93183ad06d33df88",
- "active": [],
- "rate": []
- },
- {
- "id": "b2ee3e910bc442fa91200672b47c35b6",
- "active": [],
- "rate": []
- },
- {
- "id": "d588b26ffc3c476081cb845b13e66240",
- "active": [],
- "rate": []
- },
- {
- "id": "6512cc1eb21d480d99f48998cea1f165",
- "active": [],
- "rate": []
- },
- {
- "id": "83c7bb64411c4fe282a15046c21343e8",
- "active": [],
- "rate": []
- },
- {
- "id": "0e9dae1b651c41dd8cd596b107f58180",
- "active": [],
- "rate": []
- }
- ]
- },
- "results": {}
-}
\ No newline at end of file
diff --git a/src/tests/newton_equivalence_utils.py b/src/tests/newton_equivalence_utils.py
index 85b46ee10..2ebdaa621 100644
--- a/src/tests/newton_equivalence_utils.py
+++ b/src/tests/newton_equivalence_utils.py
@@ -5,12 +5,16 @@
import scipy.sparse as sp
from typing import List
from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobian
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobian
npa.findAndActivateLicense()
def convert_bus_types(arr: List["npa.BusType"]):
+ """
+ :param arr:
+ :return:
+ """
tpe = np.zeros(len(arr), dtype=int)
for i, val in enumerate(arr):
if val == npa.BusType.VD:
@@ -291,7 +295,7 @@ def compare_power_flow(grid_newton, grid_gc, tol=1e-6):
verbose=False,
tolerance=1e-6,
retry_with_other_methods=True,
- control_q=gce.ReactivePowerControlMode.NoControl,
+ control_q=False,
max_iter=15)
gc_power_flow = gce.PowerFlowDriver(grid_gc, gc_options)
gc_power_flow.run()
diff --git a/src/tests/print_power_flow_results.py b/src/tests/print_power_flow_results.py
deleted file mode 100644
index 9454d5486..000000000
--- a/src/tests/print_power_flow_results.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# GridCal
-# Copyright (C) 2022 Santiago PeƱate Vera
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-def print_power_flow_results(power_flow):
- print('\t|V|:', abs(power_flow.results.voltage))
- print('\t|Sf|:', abs(power_flow.results.Sf))
- print('\t|loading|:', abs(power_flow.results.loading) * 100)
- print('\terr:', power_flow.results.error)
- print('\tConv:', power_flow.results.converged)
diff --git a/src/tests/test_ac_opf.py b/src/tests/test_ac_opf.py
index ecf86cf29..f3556d896 100644
--- a/src/tests/test_ac_opf.py
+++ b/src/tests/test_ac_opf.py
@@ -19,7 +19,7 @@
import numpy as np
import GridCalEngine.api as gce
-from GridCalEngine.enumerations import TransformerControlType
+from GridCalEngine.enumerations import TapPhaseControl, TapModuleControl
from GridCalEngine.Simulations.OPF.NumericalMethods.ac_opf import ac_optimal_power_flow
from GridCalEngine.Simulations.OPF.NumericalMethods.ac_opf import NonlinearOPFResults
@@ -37,7 +37,7 @@ def case9() -> NonlinearOPFResults:
grid = gce.FileOpen(file_path).open()
nc = gce.compile_numerical_circuit_at(grid)
- pf_options = gce.PowerFlowOptions(control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(control_q=False)
opf_options = gce.OptimalPowerFlowOptions(ips_method=gce.SolverType.NR, ips_tolerance=1e-8)
return ac_optimal_power_flow(nc=nc, pf_options=pf_options, opf_options=opf_options)
@@ -59,7 +59,7 @@ def case14() -> tuple[NonlinearOPFResults, NonlinearOPFResults, NonlinearOPFResu
grid.lines[ll].monitor_loading = True
nc = gce.compile_numerical_circuit_at(grid)
- pf_options = gce.PowerFlowOptions(control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(control_q=False)
opf_options = gce.OptimalPowerFlowOptions(ips_method=gce.SolverType.NR, ips_tolerance=1e-8, ips_iterations=50,
acopf_mode=gce.AcOpfMode.ACOPFstd)
base_sol = ac_optimal_power_flow(nc=nc, pf_options=pf_options, opf_options=opf_options)
@@ -67,9 +67,13 @@ def case14() -> tuple[NonlinearOPFResults, NonlinearOPFResults, NonlinearOPFResu
opf_options.acopf_mode = gce.AcOpfMode.ACOPFslacks
slack_sol = ac_optimal_power_flow(nc=nc, pf_options=pf_options, opf_options=opf_options)
- grid.transformers2w[0].control_mode = TransformerControlType.PtQt
- grid.transformers2w[1].control_mode = TransformerControlType.Pf
- grid.transformers2w[2].control_mode = TransformerControlType.V
+ grid.transformers2w[0].tap_phase_control_mode = TapPhaseControl.Pt
+ grid.transformers2w[0].tap_module_control_mode = TapModuleControl.Qt
+
+ grid.transformers2w[1].tap_phase_control_mode = TapPhaseControl.Pf
+
+ grid.transformers2w[2].tap_module_control_mode = TapModuleControl.Vm
+ grid.transformers2w[2].regulation_bus = grid.transformers2w[2].bus_from
for ll in range(len(grid.lines)):
grid.lines[ll].monitor_loading = True
@@ -100,7 +104,7 @@ def case_pegase89() -> NonlinearOPFResults:
nc = gce.compile_numerical_circuit_at(grid)
# pf_options = gce.PowerFlowOptions(solver_type=gce.SolverType.NR, tolerance=1e-8)
# return ac_optimal_power_flow(nc=nc, pf_options=pf_options)
- pf_options = gce.PowerFlowOptions(control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(control_q=False)
opf_options = gce.OptimalPowerFlowOptions(ips_method=gce.SolverType.NR, ips_tolerance=1e-10,
acopf_mode=gce.AcOpfMode.ACOPFstd)
return ac_optimal_power_flow(nc=nc, pf_options=pf_options, opf_options=opf_options)
diff --git a/src/tests/admittance_matrix_test.py b/src/tests/test_admittance_matrix.py
similarity index 100%
rename from src/tests/admittance_matrix_test.py
rename to src/tests/test_admittance_matrix.py
diff --git a/src/tests/test_admittance_tap_derivatives.py b/src/tests/test_admittance_tap_derivatives.py
index 913834671..ab2c90175 100644
--- a/src/tests/test_admittance_tap_derivatives.py
+++ b/src/tests/test_admittance_tap_derivatives.py
@@ -18,19 +18,15 @@
import os
import numpy as np
import GridCalEngine.api as gce
-from GridCalEngine.enumerations import TransformerControlType
-from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
-from GridCalEngine.Simulations.OPF.NumericalMethods.ac_opf import ac_optimal_power_flow, NonlinearOPFResults
+from GridCalEngine.enumerations import TapPhaseControl, TapModuleControl
+from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at, NumericalCircuit
from trunk.acopf.acopf_admittance_tap_derivation import (compute_finitediff_admittances,
compute_finitediff_admittances_2dev,
compute_analytic_admittances,
compute_analytic_admittances_2dev)
-
-
-
-def case_3bus():
+def case_3bus() -> NumericalCircuit:
"""
:return:
@@ -55,12 +51,14 @@ def case_3bus():
grid.add_generator(b1, gce.Generator('G1', vset=1.00, Cost=1.0, Cost2=2.0))
grid.add_generator(b2, gce.Generator('G2', P=10, vset=0.995, Cost=1.0, Cost2=3.0))
- tr1 = gce.Transformer2W(b1, b2, 'Trafo1', control_mode=TransformerControlType.Pf,
+ tr1 = gce.Transformer2W(b1, b2, 'Trafo1', tap_phase_control_mode=TapPhaseControl.Pf,
tap_module=1.1, tap_phase=0.02, r=0.001, x=0.05)
grid.add_transformer2w(tr1)
- tr2 = gce.Transformer2W(b3, b1, 'Trafo1', control_mode=TransformerControlType.PtQt,
- tap_module=1.05, tap_phase=-0.02, r=0.001, x=0.05)
+ tr2 = gce.Transformer2W(b3, b1, 'Trafo1',
+ tap_phase_control_mode=TapPhaseControl.Pt, tap_phase=-0.02,
+ tap_module_control_mode=TapModuleControl.Qt, tap_module=1.05,
+ r=0.001, x=0.05)
grid.add_transformer2w(tr2)
nc = compile_numerical_circuit_at(circuit=grid)
@@ -68,7 +66,7 @@ def case_3bus():
return nc
-def case_5bus():
+def case_5bus() -> NumericalCircuit:
"""
Grid from Lynn Powel's book
"""
@@ -76,67 +74,68 @@ def case_5bus():
grid = gce.MultiCircuit()
# Add the buses and the generators and loads attached
- bus1 = gce.Bus('Bus 1', Vnom=20)
+ bus1 = gce.Bus(name='Bus 1', Vnom=20)
# bus1.is_slack = True # we may mark the bus a slack
grid.add_bus(bus1)
# add a generator to the bus 1
- gen1 = gce.Generator('Slack Generator', vset=1.05, Pmin=0, Pmax=1000,
+ gen1 = gce.Generator(name='Slack Generator', vset=1.05, Pmin=0, Pmax=1000,
Qmin=-1000, Qmax=1000, Cost=15, Cost2=0.0)
grid.add_generator(bus1, gen1)
# add bus 2 with a load attached
- bus2 = gce.Bus('Bus 2', Vnom=20)
+ bus2 = gce.Bus(name='Bus 2', Vnom=20)
grid.add_bus(bus2)
- grid.add_load(bus2, gce.Load('load 2', P=40, Q=20))
+ grid.add_load(bus2, gce.Load(name='load 2', P=40, Q=20))
# add bus 3 with a load attached
- bus3 = gce.Bus('Bus 3', Vnom=20)
+ bus3 = gce.Bus(name='Bus 3', Vnom=20)
grid.add_bus(bus3)
- grid.add_load(bus3, gce.Load('load 3', P=25, Q=15))
+ grid.add_load(bus3, gce.Load(name='load 3', P=25, Q=15))
# add bus 4 with a load attached
- bus4 = gce.Bus('Bus 4', Vnom=20)
+ bus4 = gce.Bus(name='Bus 4', Vnom=20)
grid.add_bus(bus4)
grid.add_load(bus4, gce.Load('load 4', P=40, Q=20))
# add bus 5 with a load attached
- bus5 = gce.Bus('Bus 5', Vnom=20)
+ bus5 = gce.Bus(name='Bus 5', Vnom=20)
grid.add_bus(bus5)
- grid.add_load(bus5, gce.Load('load 5', P=50, Q=20))
+ grid.add_load(bus5, gce.Load(name='load 5', P=50, Q=20))
# add Lines connecting the buses
- #grid.add_line(gce.Line(bus1, bus2, 'line 1-2', r=0.05, x=0.11, b=0.02, rate=1000))
- grid.add_line(gce.Line(bus1, bus3, 'line 1-3', r=0.05, x=0.11, b=0.02, rate=1000))
- grid.add_line(gce.Line(bus1, bus5, 'line 1-5', r=0.03, x=0.08, b=0.02, rate=1000))
+ # grid.add_line(gce.Line(bus1, bus2, 'line 1-2', r=0.05, x=0.11, b=0.02, rate=1000))
+ grid.add_line(gce.Line(bus1, bus3, name='line 1-3', r=0.05, x=0.11, b=0.02, rate=1000))
+ grid.add_line(gce.Line(bus1, bus5, name='line 1-5', r=0.03, x=0.08, b=0.02, rate=1000))
- tr1 = gce.Transformer2W(bus1, bus2, 'Trafo1', control_mode=TransformerControlType.fixed,
+ tr1 = gce.Transformer2W(bus1, bus2, name='Trafo1',
tap_module=1.1, tap_phase=0.02, r=0.05, x=0.11, b=0.02)
grid.add_transformer2w(tr1)
- tr2 = gce.Transformer2W(bus2, bus3, 'Trafo2', control_mode=TransformerControlType.fixed,
+ tr2 = gce.Transformer2W(bus2, bus3, name='Trafo2',
tap_module=0.98, tap_phase=-0.02, r=0.04, x=0.09, b=0.02)
grid.add_transformer2w(tr2)
- tr3 = gce.Transformer2W(bus2, bus5, 'Trafo3', control_mode=TransformerControlType.fixed,
+ tr3 = gce.Transformer2W(bus2, bus5, name='Trafo3',
tap_module=1.02, tap_phase=-0.04, r=0.04, x=0.09, b=0.02)
grid.add_transformer2w(tr3)
- tr4 = gce.Transformer2W(bus3, bus4, 'Trafo4', control_mode=TransformerControlType.Pf,
+ tr4 = gce.Transformer2W(bus3, bus4, name='Trafo4', tap_phase_control_mode=TapPhaseControl.Pf,
tap_module=1.05, tap_phase=0.04, r=0.06, x=0.13, b=0.03)
grid.add_transformer2w(tr4)
- tr5 = gce.Transformer2W(bus4, bus5, 'Trafo5', control_mode=TransformerControlType.fixed,
+ tr5 = gce.Transformer2W(bus4, bus5, name='Trafo5',
tap_module=0.97, tap_phase=-0.01, r=0.04, x=0.09, b=0.02)
grid.add_transformer2w(tr5)
- #grid.add_line(gce.Line(bus2, bus3, 'line 2-3', r=0.04, x=0.09, b=0.02, rate=1000))
- #grid.add_line(gce.Line(bus2, bus5, 'line 2-5', r=0.04, x=0.09, b=0.02, rate=1000))
- #grid.add_line(gce.Line(bus3, bus4, 'line 3-4', r=0.06, x=0.13, b=0.03, rate=1000))
- #grid.add_line(gce.Line(bus4, bus5, 'line 4-5', r=0.04, x=0.09, b=0.02, rate=1000))
+ # grid.add_line(gce.Line(bus2, bus3, 'line 2-3', r=0.04, x=0.09, b=0.02, rate=1000))
+ # grid.add_line(gce.Line(bus2, bus5, 'line 2-5', r=0.04, x=0.09, b=0.02, rate=1000))
+ # grid.add_line(gce.Line(bus3, bus4, 'line 3-4', r=0.06, x=0.13, b=0.03, rate=1000))
+ # grid.add_line(gce.Line(bus4, bus5, 'line 4-5', r=0.04, x=0.09, b=0.02, rate=1000))
nc = gce.compile_numerical_circuit_at(grid)
return nc
-def case9() -> NonlinearOPFResults:
+
+def case9() -> NumericalCircuit:
"""
Test case9 from matpower
:return:
@@ -153,7 +152,7 @@ def case9() -> NonlinearOPFResults:
return nc
-def case14() -> NonlinearOPFResults:
+def case14() -> NumericalCircuit:
"""
Test case14 from matpower
:return:
@@ -166,15 +165,14 @@ def case14() -> NonlinearOPFResults:
grid = gce.FileOpen(file_path).open()
for l in grid.get_transformers2w():
-
- l.control_mode = TransformerControlType.PtQt
+ l.set_tap_controls(TapPhaseControl.Pt, TapModuleControl.Qt)
nc = gce.compile_numerical_circuit_at(grid)
return nc
-def case_pegase89() -> NonlinearOPFResults:
+def case_pegase89() -> NumericalCircuit:
"""
Pegase89
"""
@@ -184,19 +182,18 @@ def case_pegase89() -> NonlinearOPFResults:
file_path = os.path.join('data', 'grids', 'case89pegase.m')
grid = gce.FileOpen(file_path).open()
- grid.get_transformers2w()[3].control_mode = TransformerControlType.PtQt
- grid.get_transformers2w()[7].control_mode = TransformerControlType.PtQt
- grid.get_transformers2w()[18].control_mode = TransformerControlType.V
- grid.get_transformers2w()[21].control_mode = TransformerControlType.PtQt
- grid.get_transformers2w()[36].control_mode = TransformerControlType.Pf
+ grid.get_transformers2w()[3].set_tap_controls(TapPhaseControl.Pt, TapModuleControl.Qt)
+ grid.get_transformers2w()[7].set_tap_controls(TapPhaseControl.Pt, TapModuleControl.Qt)
+ grid.get_transformers2w()[18].set_tap_controls(TapPhaseControl.fixed, TapModuleControl.Vm)
+ grid.get_transformers2w()[21].set_tap_controls(TapPhaseControl.Pt, TapModuleControl.Qt)
+ grid.get_transformers2w()[36].set_tap_controls(TapPhaseControl.Pf, TapModuleControl.fixed)
nc = gce.compile_numerical_circuit_at(grid)
return nc
-def test_case_3bus():
-
+def test_case_3bus() -> None:
nc = case_3bus()
A, B, C, D, E, F = compute_analytic_admittances(nc)
@@ -225,8 +222,7 @@ def test_case_3bus():
assert np.allclose(R.toarray(), R_.toarray(), atol=1e-1)
-def test_case_5bus():
-
+def test_case_5bus() -> None:
nc = case_5bus()
A, B, C, D, E, F = compute_analytic_admittances(nc)
@@ -255,8 +251,7 @@ def test_case_5bus():
assert np.allclose(R.toarray(), R_.toarray(), atol=1e-1)
-def test_pegase89():
-
+def test_pegase89() -> None:
nc = case_pegase89()
A, B, C, D, E, F = compute_analytic_admittances(nc)
@@ -285,8 +280,7 @@ def test_pegase89():
assert np.allclose(R.toarray(), R_.toarray(), atol=1e-1)
-def test_case14():
-
+def test_case14() -> None:
nc = case14()
A, B, C, D, E, F = compute_analytic_admittances(nc)
@@ -314,9 +308,3 @@ def test_case14():
assert np.allclose(Q.toarray(), Q_.toarray(), atol=1e-1)
assert np.allclose(R.toarray(), R_.toarray(), atol=1e-1)
# pass
-
-
-#def test_ieee14():
-
-
-#def test_pegase89():
diff --git a/src/tests/test_api_helm.py b/src/tests/test_api_helm.py
index 4217a4cdf..3924591fd 100644
--- a/src/tests/test_api_helm.py
+++ b/src/tests/test_api_helm.py
@@ -20,7 +20,6 @@
from GridCalEngine.IO.file_handler import FileOpen
from GridCalEngine.Simulations.PowerFlow.power_flow_options import SolverType
from GridCalEngine.Simulations.PowerFlow.power_flow_driver import PowerFlowOptions, PowerFlowDriver
-from tests.print_power_flow_results import print_power_flow_results
def test_api_helm():
@@ -39,8 +38,6 @@ def test_api_helm():
power_flow = PowerFlowDriver(grid, options)
power_flow.run()
- print_power_flow_results(power_flow)
-
if __name__ == '__main__':
test_api_helm()
diff --git a/src/tests/test_basic.py b/src/tests/test_basic.py
index d1450a6b6..4ca7d75ea 100644
--- a/src/tests/test_basic.py
+++ b/src/tests/test_basic.py
@@ -21,7 +21,7 @@
from GridCalEngine.Devices.Injections.static_generator import StaticGenerator
from GridCalEngine.Devices.Branches.transformer import TransformerType, Transformer2W
from GridCalEngine.Simulations.PowerFlow.power_flow_worker import PowerFlowOptions
-from GridCalEngine.Simulations.PowerFlow.power_flow_options import ReactivePowerControlMode, SolverType
+from GridCalEngine.Simulations.PowerFlow.power_flow_options import SolverType
from GridCalEngine.Simulations.PowerFlow.power_flow_driver import PowerFlowDriver
@@ -31,9 +31,9 @@ def complex_impedance(z, XR):
"""
z = float(abs(z))
XR = float(abs(XR))
- real = (z**2/(1+XR**2))**0.5
+ real = (z ** 2 / (1 + XR ** 2)) ** 0.5
try:
- imag = (z**2/(1+1/XR**2))**0.5
+ imag = (z ** 2 / (1 + 1 / XR ** 2)) ** 0.5
except ZeroDivisionError:
imag = 0.0
return complex(real, imag)
@@ -80,7 +80,7 @@ def test_basic():
# Create static generators (with fixed power factor)
M32 = StaticGenerator(name="M32",
P=4.2, # MW
- Q=0.0j) # MVAr
+ Q=0.0) # MVAr
M32.bus = B_LV_M32
grid.add_static_generator(B_LV_M32, M32)
@@ -142,7 +142,7 @@ def test_basic():
options = PowerFlowOptions(SolverType.NR,
verbose=True,
use_stored_guess=True,
- control_q=ReactivePowerControlMode.Direct,
+ control_q=True,
tolerance=1e-6,
max_iter=99)
@@ -169,7 +169,7 @@ def test_basic():
print(f" - {b}:")
print(f" R = {round(b.R, 4)} pu")
print(f" X = {round(b.X, 4)} pu")
- print(f" X/R = {round(b.X/b.R, 1)}")
+ print(f" X/R = {round(b.X / b.R, 1)}")
print(f" G = {round(b.G, 4)} pu")
print(f" B = {round(b.B, 4)} pu")
print()
@@ -181,7 +181,7 @@ def test_basic():
print("Losses:")
for i in range(len(branches)):
- print(f" - {branches[i]}: losses={1000*round(power_flow.results.losses[i], 3)} kVA")
+ print(f" - {branches[i]}: losses={1000 * round(power_flow.results.losses[i], 3)} kVA")
print()
equal = True
@@ -230,7 +230,7 @@ def test_gridcal_basic_pi():
# Create static generators (with fixed power factor)
M32 = StaticGenerator(name="M32",
P=4.2, # MW
- Q=0.0j) # MVAR
+ Q=0.0) # MVAR
M32.bus = B_LV_M32
grid.add_static_generator(B_LV_M32, M32)
@@ -242,7 +242,7 @@ def test_gridcal_basic_pi():
hv_nominal_voltage=100, # kV
lv_nominal_voltage=10, # kV
nominal_power=s,
- copper_losses=complex_impedance(z, xr).real*s*1000/Sbase,
+ copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase,
iron_losses=6.25, # kW
no_load_current=0.5, # %
short_circuit_voltage=z)
@@ -255,7 +255,7 @@ def test_gridcal_basic_pi():
hv_nominal_voltage=10, # kV
lv_nominal_voltage=0.6, # kV
nominal_power=s,
- copper_losses=complex_impedance(z, xr).real*s*1000/Sbase,
+ copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase,
iron_losses=6.25, # kW
no_load_current=0.5, # %
short_circuit_voltage=z)
@@ -292,14 +292,14 @@ def test_gridcal_basic_pi():
options = PowerFlowOptions(SolverType.NR,
verbose=True,
use_stored_guess=True,
- control_q=ReactivePowerControlMode.Direct,
+ control_q=True,
tolerance=1e-6,
max_iter=99)
power_flow = PowerFlowDriver(grid, options)
power_flow.run()
- approx_volt = [round(100*abs(v), 1) for v in power_flow.results.voltage]
+ approx_volt = [round(100 * abs(v), 1) for v in power_flow.results.voltage]
solution = [100.0, 99.5, 102.7, 102.8] # Expected solution from GridCal
etap_sol = [100.0, 99.6, 102.7, 102.9] # ETAP 16.1.0, for reference (ignores magnetizing branch)
@@ -320,7 +320,7 @@ def test_gridcal_basic_pi():
print(f" - {b}:")
print(f" R = {round(b.R, 4)} pu")
print(f" X = {round(b.X, 4)} pu")
- print(f" X/R = {round(b.X/b.R, 1)}")
+ print(f" X/R = {round(b.X / b.R, 1)}")
print(f" G = {round(b.G, 4)} pu")
print(f" B = {round(b.B, 4)} pu")
print()
@@ -332,7 +332,7 @@ def test_gridcal_basic_pi():
print("Losses:")
for i in range(len(branches)):
- print(f" - {branches[i]}: losses={1000*round(power_flow.results.losses[i], 3)} kVA")
+ print(f" - {branches[i]}: losses={1000 * round(power_flow.results.losses[i], 3)} kVA")
print()
equal = True
@@ -344,7 +344,6 @@ def test_gridcal_basic_pi():
if __name__ == '__main__':
-
test_basic()
test_gridcal_basic_pi()
diff --git a/src/tests/test_cgmes_ieeee.py b/src/tests/test_cgmes_ieeee.py
index 94dee8e04..009187741 100644
--- a/src/tests/test_cgmes_ieeee.py
+++ b/src/tests/test_cgmes_ieeee.py
@@ -141,7 +141,7 @@ def test_ieee_grids() -> None:
options = gce.PowerFlowOptions(gce.SolverType.NR,
verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
for grid_file, results_file in files:
diff --git a/src/tests/test_contingency.py b/src/tests/test_contingency.py
index b4dcc7f04..58922f2f2 100644
--- a/src/tests/test_contingency.py
+++ b/src/tests/test_contingency.py
@@ -29,12 +29,12 @@ def test_contingency() -> None:
pf_options = PowerFlowOptions(SolverType.NR,
verbose=False,
use_stored_guess=False,
- control_q=ReactivePowerControlMode.NoControl)
+ control_q=False)
- options = ContingencyAnalysisOptions(pf_options=pf_options,
+ options = ContingencyAnalysisOptions(pf_options=pf_options,
contingency_method=ContingencyMethod.PowerFlow)
-
- cont_analysis_driver = ContingencyAnalysisDriver(grid=main_circuit,
+
+ cont_analysis_driver = ContingencyAnalysisDriver(grid=main_circuit,
options=options,
linear_multiple_contingencies=None)
cont_analysis_driver.run()
@@ -59,7 +59,7 @@ def test_linear_contingency():
main_circuit = FileOpen(fname).open()
pf_options = PowerFlowOptions(SolverType.NR,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl)
+ control_q=False)
linear_analysis = LinearAnalysisDriver(grid=main_circuit)
linear_analysis.run()
@@ -73,6 +73,7 @@ def test_linear_contingency():
cont_analysis_driver.run()
print("")
+
# def test_lodf():
# fname = os.path.join('data', 'grids', 'IEEE14_contingency.gridcal')
# main_circuit = FileOpen(fname).open()
@@ -80,7 +81,7 @@ def test_linear_contingency():
# verbose=False,
# initialize_with_existing_solution=False,
# dispatch_storage=True,
-# control_q=ReactivePowerControlMode.NoControl,
+# control_q=False,
# control_p=False)
#
# linear_analysis = LinearAnalysisDriver(grid=main_circuit)
@@ -101,7 +102,7 @@ def test_linear_contingency():
# verbose=False,
# initialize_with_existing_solution=False,
# dispatch_storage=True,
-# control_q=ReactivePowerControlMode.NoControl,
+# control_q=False,
# control_p=False)
#
# branches = main_circuit.get_branches()
@@ -123,3 +124,6 @@ def test_linear_contingency():
# #res = linear_analysis.results.PTDF - ptdf_result
# #print(res)
# assert(np.isclose(linear_analysis.results.PTDF, ptdf_result).all())
+
+if __name__ == '__main__':
+ test_contingency()
diff --git a/src/tests/test_continuation_power_flow.py b/src/tests/test_continuation_power_flow.py
index f675eef4a..42f1dc75c 100644
--- a/src/tests/test_continuation_power_flow.py
+++ b/src/tests/test_continuation_power_flow.py
@@ -16,15 +16,13 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os
from GridCalEngine.api import *
-from tests.zip_file_mgmt import open_data_frame_from_zip
+from GridCalEngine.Utils.zip_file_mgmt import open_data_frame_from_zip
def test_cpf():
fname = os.path.join('data', 'grids', 'IEEE39_1W.gridcal')
main_circuit = FileOpen(fname).open()
- pf_options = PowerFlowOptions(SolverType.NR,
- verbose=0,
- control_q=ReactivePowerControlMode.NoControl)
+ pf_options = PowerFlowOptions(SolverType.NR, verbose=0, control_q=False)
Vmbase = open_data_frame_from_zip(file_name_zip=os.path.join('data', 'results', 'Results_IEEE39_1W.zip'),
file_name='Power flow Bus voltage module.csv').values[:, 0]
diff --git a/src/tests/deep_copy_test.py b/src/tests/test_deep_copy.py
similarity index 100%
rename from src/tests/deep_copy_test.py
rename to src/tests/test_deep_copy.py
diff --git a/src/tests/test_demo_5_node.py b/src/tests/test_demo_5_node.py
index 9d64b655a..b9688de61 100644
--- a/src/tests/test_demo_5_node.py
+++ b/src/tests/test_demo_5_node.py
@@ -17,7 +17,6 @@
import numpy as np
-from GridCalEngine.IO.file_handler import FileSave
from GridCalEngine.Devices.multi_circuit import MultiCircuit
from GridCalEngine.Devices import Bus
from GridCalEngine.Devices import Generator
@@ -25,11 +24,9 @@
from GridCalEngine.Devices import Line
from GridCalEngine.Simulations.PowerFlow.power_flow_options import SolverType
from GridCalEngine.Simulations.PowerFlow.power_flow_driver import PowerFlowOptions, PowerFlowDriver
-from tests.print_power_flow_results import print_power_flow_results
-from tests.conftest import ROOT_PATH
-def test_demo_5_node(root_path=ROOT_PATH):
+def test_demo_5_node():
grid = MultiCircuit()
@@ -73,11 +70,8 @@ def test_demo_5_node(root_path=ROOT_PATH):
power_flow = PowerFlowDriver(grid, options)
power_flow.run()
- print_power_flow_results(power_flow=power_flow)
v = np.array([1., 0.9553, 0.9548, 0.9334, 0.9534])
all_ok = np.isclose(np.abs(power_flow.results.voltage), v, atol=1e-3)
return all_ok
-if __name__ == '__main__':
- test_demo_5_node(root_path=ROOT_PATH)
diff --git a/src/tests/test_derivatives.py b/src/tests/test_derivatives.py
new file mode 100644
index 000000000..cd2b526e5
--- /dev/null
+++ b/src/tests/test_derivatives.py
@@ -0,0 +1,563 @@
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+import os
+import numpy as np
+from scipy.sparse import csc_matrix
+from GridCalEngine.Topology.admittance_matrices import compute_admittances
+import GridCalEngine.Simulations.Derivatives.csc_derivatives as cscdiff
+import GridCalEngine.Simulations.Derivatives.ac_jacobian as cscjac
+import GridCalEngine.Simulations.Derivatives.matpower_derivatives as mdiff
+from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import expand, polar_to_rect
+from GridCalEngine.Simulations.OPF.NumericalMethods.ac_opf_derivatives import compute_branch_power_derivatives
+from GridCalEngine.DataStructures.numerical_circuit import NumericalCircuit
+from GridCalEngine.Utils.Sparse.csc2 import mat_to_scipy, scipy_to_cxmat, CxCSC
+import GridCalEngine.api as gce
+
+
+def test_bus_derivatives():
+ """
+ Test the bus derivatives
+ :return:
+ """
+ Ybus = csc_matrix([[0.1 - 9.999j, - 0.1 + 9.999j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j],
+ [-0.1 + 9.999j, 1.9574 - 10.5489j, - 1.0852 + 0.1809j, 0. + 0.j, - 0.7763 + 0.3697j, 0. + 0.j],
+ [0. + 0.j, - 1.0852 + 0.1809j, 1.5797 - 0.2603j, - 0.4878 + 0.j, 0. + 0.j, 0. + 0.j],
+ [0. + 0.j, 0. + 0.j, - 0.4878 + 0.j, 1.4534 - 0.4252j, - 0.9807 + 0.3326j, 0. + 0.j],
+ [0. + 0.j, - 0.7763 + 0.3697j, 0. + 0.j, - 0.9477 + 0.4174j, 1.8415 - 10.744j, - 0.1 + 9.999j],
+ [0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, - 0.1 + 9.999j, 0.1 - 9.999j]])
+
+ Vm = np.array([1.1, 1.096, 1.0975, 1.104, 1.1261, 1.12])
+ Va = np.array([0., 0.0004, 0.0656, 0.0656, - 0.0269, - 0.0259])
+ V = polar_to_rect(Vm, Va)
+
+ Ybus_x = Ybus.data
+ Ybus_p = Ybus.indptr
+ Ybus_i = Ybus.indices
+ nbus = 6
+
+ dS_dVm_x, dS_dVa_x = cscdiff.dSbus_dV_numba_sparse_csc(Ybus_x, Ybus_p, Ybus_i, V, Vm)
+ dS_dVm1 = CxCSC(nbus, nbus, len(dS_dVm_x), False).set(Ybus_i, Ybus_p, dS_dVm_x).toarray()
+ dS_dVa1 = CxCSC(nbus, nbus, len(dS_dVa_x), False).set(Ybus_i, Ybus_p, dS_dVa_x).toarray()
+
+ dSbus_dVa, dSbus_dVm = mdiff.dSbus_dV_matpower(Ybus, V)
+ dS_dVa2 = scipy_to_cxmat(dSbus_dVa).toarray()
+ dS_dVm2 = scipy_to_cxmat(dSbus_dVm).toarray()
+
+ okVa = np.allclose(dS_dVa1, dS_dVa2)
+ okVm = np.allclose(dS_dVm1, dS_dVm2)
+ assert okVa
+ assert okVm
+
+ print()
+
+
+def check_dSf_dVm(dSf_dVm1, br_idx, bus_idx, nc: NumericalCircuit):
+ """
+
+ :param dSf_dVm1:
+ :param br_idx:
+ :param bus_idx:
+ :param nc:
+ :return:
+ """
+ dSf_dVm2 = cscdiff.dSf_dVm_csc(nbus=nc.nbus,
+ br_indices=br_idx,
+ bus_indices=bus_idx,
+ yff=nc.admittances_.yff,
+ yft=nc.admittances_.yft,
+ V=nc.Vbus,
+ F=nc.F, T=nc.T)
+
+ dSf_dVm3 = dSf_dVm1[np.ix_(br_idx, bus_idx)]
+
+ # print(f"dSf_dVm1 (matpower):\n {dSf_dVm1.real.toarray()}")
+ # print(f"dSf_dVm3 (matpower):\n {dSf_dVm3.real.toarray()}")
+ # print(f"dSf_dVm2 (new):\n {dSf_dVm2.real.toarray()}")
+
+ assert np.allclose(dSf_dVm3.toarray(), dSf_dVm2.toarray())
+
+
+def check_dSf_dVa(dSf_dVa1, br_idx, bus_idx, nc: NumericalCircuit):
+ """
+
+ :param dSf_dVa1:
+ :param br_idx:
+ :param bus_idx:
+ :param nc:
+ :return:
+ """
+ dSf_dVa2 = cscdiff.dSf_dVa_csc(nbus=nc.nbus,
+ br_indices=br_idx,
+ bus_indices=bus_idx,
+ yff=nc.admittances_.yff,
+ yft=nc.admittances_.yft,
+ V=nc.Vbus,
+ F=nc.F, T=nc.T)
+
+ dSf_dVa3 = dSf_dVa1[np.ix_(br_idx, bus_idx)]
+
+ # print(f"dSf_dVa1 (matpower):\n {dSf_dVa1.real.toarray()}")
+ # print(f"dSf_dVa3 (matpower):\n {dSf_dVa3.real.toarray()}")
+ # print(f"dSf_dVa2 (new):\n {dSf_dVa2.real.toarray()}")
+
+ assert np.allclose(dSf_dVa3.toarray(), dSf_dVa2.toarray())
+
+
+def check_dSt_dVm(dSt_dVm1, br_idx, bus_idx, nc: NumericalCircuit):
+ """
+
+ :param dSt_dVm1:
+ :param br_idx:
+ :param bus_idx:
+ :param nc:
+ :return:
+ """
+ dSt_dVm2 = cscdiff.dSt_dVm_csc(nbus=nc.nbus,
+ br_indices=br_idx,
+ bus_indices=bus_idx,
+ ytt=nc.admittances_.ytt,
+ ytf=nc.admittances_.ytf,
+ V=nc.Vbus,
+ F=nc.F, T=nc.T)
+
+ dSt_dVm3 = dSt_dVm1[np.ix_(br_idx, bus_idx)]
+
+ # print(f"dSf_dVm1 (matpower):\n {dSf_dVm1.real.toarray()}")
+ # print(f"dSf_dVm3 (matpower):\n {dSf_dVm3.real.toarray()}")
+ # print(f"dSf_dVm2 (new):\n {dSf_dVm2.real.toarray()}")
+
+ assert np.allclose(dSt_dVm3.toarray(), dSt_dVm2.toarray())
+
+
+def check_dSt_dVa(dSt_dVa1, br_idx, bus_idx, nc: NumericalCircuit):
+ """
+
+ :param dSt_dVa1:
+ :param br_idx:
+ :param bus_idx:
+ :param nc:
+ :return:
+ """
+ dSt_dVa2 = cscdiff.dSt_dVa_csc(nbus=nc.nbus,
+ br_indices=br_idx,
+ bus_indices=bus_idx,
+ ytf=nc.admittances_.ytf,
+ V=nc.Vbus,
+ F=nc.F, T=nc.T)
+
+ dSt_dVa3 = dSt_dVa1[np.ix_(br_idx, bus_idx)]
+
+ # print(f"dSt_dVa1 (matpower):\n {dSt_dVa1.real.toarray()}")
+ # print(f"dSt_dVa3 (matpower):\n {dSt_dVa3.real.toarray()}")
+ # print(f"dSt_dVa2 (new):\n {dSt_dVa2.real.toarray()}")
+
+ assert np.allclose(dSt_dVa3.toarray(), dSt_dVa2.toarray())
+
+
+def test_branch_derivatives() -> None:
+ """
+ Test the branch derivatives
+ :return:
+ """
+ fname = os.path.join("data", "grids", "RAW", "IEEE 14 bus.raw")
+ grid = gce.open_file(filename=fname)
+ nc = gce.compile_numerical_circuit_at(grid)
+
+ dSf_dVa1, dSf_dVm1, dSt_dVa1, dSt_dVm1 = mdiff.dSbr_dV_matpower(Yf=nc.Yf,
+ Yt=nc.Yt,
+ V=nc.Vbus,
+ F=nc.F,
+ T=nc.T,
+ Cf=nc.Cf,
+ Ct=nc.Ct)
+
+ test_data = [
+ {
+ "bus_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ "br_idx": np.array([10, 12, 14]),
+ },
+ {
+ "bus_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ "br_idx": np.array([2, 3, 4]),
+ },
+ {
+ "bus_idx": np.arange(nc.nbus),
+ "br_idx": np.arange(nc.nbr),
+ },
+ ]
+
+ for dta in test_data:
+ br_idx = dta["br_idx"]
+ bus_idx = dta["bus_idx"]
+ check_dSf_dVm(dSf_dVm1, br_idx, bus_idx, nc)
+ check_dSf_dVa(dSf_dVa1, br_idx, bus_idx, nc)
+ check_dSt_dVm(dSt_dVm1, br_idx, bus_idx, nc)
+ check_dSt_dVa(dSt_dVa1, br_idx, bus_idx, nc)
+
+
+def test_tau_derivatives() -> None:
+ """
+
+ :return:
+ """
+ # fname = os.path.join("data", "grids", "fubm_case_57_14_2MTDC_ctrls.gridcal")
+ fname = os.path.join("data", "grids", "RAW", "IEEE 14 bus.raw")
+ grid = gce.open_file(filename=fname)
+ nc = gce.compile_numerical_circuit_at(grid)
+
+ Ys = 1.0 / (nc.branch_data.R + 1j * nc.branch_data.X)
+
+ test_data = [
+ {
+ "bus_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ "br_idx": np.array([10, 12, 14]),
+ "sf_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ },
+ {
+ "bus_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ "br_idx": np.array([2, 3, 4]),
+ "sf_idx": np.array([2, 3, 4]),
+ },
+ {
+ "bus_idx": np.arange(nc.nbus),
+ "br_idx": np.arange(nc.nbr),
+ "sf_idx": np.arange(nc.nbr),
+ },
+ ]
+
+ for dta in test_data:
+ tau_idx = dta["br_idx"]
+ bus_idx = dta["bus_idx"]
+ sf_idx = dta["sf_idx"]
+
+ (dSbus_dm1, dSf_dm1, dSt_dm1,
+ dSbus_dtau1, dSf_dtau1, dSt_dtau1) = compute_branch_power_derivatives(all_tap_m=nc.branch_data.tap_module,
+ all_tap_tau=nc.branch_data.tap_angle,
+ V=nc.Vbus,
+ k_m=np.empty(0, dtype=int),
+ k_tau=tau_idx,
+ Cf=nc.Cf,
+ Ct=nc.Ct,
+ F=nc.F,
+ T=nc.T,
+ R=nc.branch_data.R,
+ X=nc.branch_data.X)
+
+ # dSbus_dtau1, dSf_dtau1, dSt_dtau1 = cscdiff.derivatives_tau_csc_numba(nbus=nc.nbus,
+ # nbr=nc.nbr,
+ # iPxsh=tau_idx,
+ # F=nc.F,
+ # T=nc.T,
+ # Ys=Ys,
+ # kconv=nc.branch_data.k,
+ # tap=nc.branch_data.tap,
+ # V=nc.Vbus)
+
+ # dSbus_dtau1, dSf_dtau1, dSt_dtau1 = mdiff.dS_dtau_matpower(V=nc.Vbus,
+ # Cf=nc.Cf,
+ # Ct=nc.Ct,
+ # R=nc.branch_data.R,
+ # X=nc.branch_data.X,
+ # k2=nc.branch_data.k,
+ # m=nc.branch_data.tap_module,
+ # tau=nc.branch_data.tap_angle)
+
+ # check_dSbus_dtau(dSbus_dtau1, br_idx, bus_idx, Ys, nc)
+
+ dSbus_dtau2 = cscdiff.dSbus_dtau_csc(nbus=nc.nbus,
+ bus_indices=bus_idx,
+ tau_indices=tau_idx,
+ F=nc.F,
+ T=nc.T,
+ Ys=Ys,
+ kconv=nc.branch_data.k,
+ tap=nc.branch_data.tap,
+ V=nc.Vbus)
+
+ dSbus_dtau3 = dSbus_dtau1[bus_idx, :]
+
+ # print(f"dSbus_dsh1 (matpower):\n {dSbus_dsh1.real.toarray()}")
+ # print(f"dSbus_dsh3 (matpower):\n {dSbus_dsh3.real.toarray()}")
+ # print(f"dSbus_dsh2 (new):\n {dSbus_dsh2.real.toarray()}")
+ ok1 = np.allclose(dSbus_dtau3.toarray(), dSbus_dtau2.toarray())
+ assert ok1
+
+ # check_dSf_dtau(dSf_dtau1, sf_idx, br_idx, Ys, nc)
+
+ dSf_dtau2 = cscdiff.dSf_dtau_csc(nbr=nc.nbr,
+ sf_indices=sf_idx,
+ tau_indices=tau_idx,
+ F=nc.F,
+ T=nc.T,
+ Ys=Ys,
+ kconv=nc.branch_data.k,
+ tap=nc.branch_data.tap,
+ V=nc.Vbus)
+
+ dSf_dtau3 = dSf_dtau1[sf_idx, :]
+
+ # print(f"dSf_dtau1 (matpower):\n {dSf_dtau1.real.toarray()}")
+ # print(f"dSf_dtau3 (matpower):\n {dSf_dtau3.real.toarray()}")
+ # print(f"dSf_dtau2 (new):\n {dSf_dtau2.real.toarray()}")
+ ok2 = np.allclose(dSf_dtau3.toarray(), dSf_dtau2.toarray())
+ assert ok2
+
+ # check_dSt_dtau(dSt_dtau1, sf_idx, br_idx, Ys, nc)
+
+ dSt_dtau2 = cscdiff.dSt_dtau_csc(nbr=nc.nbr,
+ st_indices=sf_idx,
+ tau_indices=tau_idx,
+ F=nc.F,
+ T=nc.T,
+ Ys=Ys,
+ kconv=nc.branch_data.k,
+ tap=nc.branch_data.tap,
+ V=nc.Vbus)
+
+ dSt_dtau3 = dSt_dtau1[sf_idx, :]
+
+ # print(f"dSt_dtau1 (matpower):\n {dSt_dtau1.real.toarray()}")
+ # print(f"dSt_dtau3 (matpower):\n {dSt_dtau3.real.toarray()}")
+ # print(f"dSt_dtau2 (new):\n {dSt_dtau2.real.toarray()}")
+ ok3 = np.allclose(dSt_dtau3.toarray(), dSt_dtau2.toarray())
+ assert ok3
+
+
+def test_m_derivatives() -> None:
+ """
+
+ :return:
+ """
+ # fname = os.path.join("data", "grids", "fubm_case_57_14_2MTDC_ctrls.gridcal")
+ fname = os.path.join("data", "grids", "RAW", "IEEE 14 bus.raw")
+ grid = gce.open_file(filename=fname)
+ nc = gce.compile_numerical_circuit_at(grid)
+
+ Ys = 1.0 / (nc.branch_data.R + 1j * nc.branch_data.X)
+
+ test_data = [
+ {
+ "bus_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ "br_idx": np.array([10, 12, 14]),
+ "sf_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ },
+ {
+ "bus_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ "br_idx": np.array([2, 3, 4]),
+ "sf_idx": np.array([2, 3, 4]),
+ },
+ {
+ "bus_idx": np.arange(nc.nbus),
+ "br_idx": np.arange(nc.nbr),
+ "sf_idx": np.arange(nc.nbr),
+ },
+ ]
+
+ for dta in test_data:
+ m_idx = dta["br_idx"]
+ bus_idx = dta["bus_idx"]
+ sf_idx = dta["sf_idx"]
+
+ dSbus_dm1, dSf_dm1, dSt_dm1 = cscdiff.derivatives_ma_csc_numba(nbus=nc.nbus,
+ nbr=nc.nbr,
+ iXxma=m_idx,
+ F=nc.F,
+ T=nc.T,
+ Ys=Ys,
+ kconv=nc.branch_data.k,
+ tap=nc.branch_data.tap,
+ tap_module=nc.branch_data.tap_module,
+ Bc=nc.branch_data.B,
+ Beq=nc.branch_data.Beq,
+ V=nc.Vbus)
+ dSbus_dm1, dSf_dm1, dSt_dm1 = mat_to_scipy(dSbus_dm1), mat_to_scipy(dSf_dm1), mat_to_scipy(dSt_dm1)
+
+ # (dSbus_dm1, dSf_dm1, dSt_dm1,
+ # dSbus_dtau1, dSf_dtau1, dSt_dtau1) = compute_branch_power_derivatives(all_tap_m=nc.branch_data.tap_module,
+ # all_tap_tau=nc.branch_data.tap_angle,
+ # V=nc.Vbus,
+ # k_m=m_idx,
+ # k_tau=np.empty(0, dtype=int),
+ # Cf=nc.Cf,
+ # Ct=nc.Ct,
+ # F=nc.F,
+ # T=nc.T,
+ # R=nc.branch_data.R,
+ # X=nc.branch_data.X)
+
+ # dSbus_dm1, dSf_dm1, dSt_dm1 = mdiff.dS_dm_matpower(V=nc.Vbus,
+ # Cf=nc.Cf,
+ # Ct=nc.Ct,
+ # R=nc.branch_data.R,
+ # X=nc.branch_data.X,
+ # B=nc.branch_data.B,
+ # Beq=nc.branch_data.Beq,
+ # k2=nc.branch_data.k,
+ # m=nc.branch_data.tap_module,
+ # tau=nc.branch_data.tap_angle)
+
+ dSbus_dm2 = cscdiff.dSbus_dm_csc(nbus=nc.nbus,
+ bus_indices=bus_idx,
+ m_indices=m_idx,
+ F=nc.F,
+ T=nc.T,
+ Ys=Ys,
+ Bc=nc.branch_data.B,
+ Beq=nc.branch_data.Beq,
+ kconv=nc.branch_data.k,
+ tap=nc.branch_data.tap,
+ tap_module=nc.branch_data.tap_module,
+ V=nc.Vbus)
+ dSbus_dm3 = dSbus_dm1[bus_idx, :]
+ assert np.allclose(dSbus_dm3.toarray(), dSbus_dm2.toarray())
+
+ dSf_dm2 = cscdiff.dSf_dm_csc(nbr=nc.nbr,
+ sf_indices=sf_idx,
+ m_indices=m_idx,
+ F=nc.F,
+ T=nc.T,
+ Ys=Ys,
+ Bc=nc.branch_data.B,
+ Beq=nc.branch_data.Beq,
+ kconv=nc.branch_data.k,
+ tap=nc.branch_data.tap,
+ tap_module=nc.branch_data.tap_module,
+ V=nc.Vbus)
+ dSf_dm3 = dSf_dm1[sf_idx, :]
+ assert np.allclose(dSf_dm3.toarray(), dSf_dm2.toarray())
+
+ dSt_dm2 = cscdiff.dSt_dm_csc(nbr=nc.nbr,
+ st_indices=sf_idx,
+ m_indices=m_idx,
+ F=nc.F,
+ T=nc.T,
+ Ys=Ys,
+ kconv=nc.branch_data.k,
+ tap=nc.branch_data.tap,
+ tap_module=nc.branch_data.tap_module,
+ V=nc.Vbus)
+ dSt_dm3 = dSt_dm1[sf_idx, :]
+
+ assert np.allclose(dSt_dm3.toarray(), dSt_dm2.toarray())
+
+
+def test_beq_derivatives() -> None:
+ """
+
+ :return:
+ """
+ # fname = os.path.join("data", "grids", "fubm_case_57_14_2MTDC_ctrls.gridcal")
+ fname = os.path.join("data", "grids", "RAW", "IEEE 14 bus.raw")
+ grid = gce.open_file(filename=fname)
+ nc = gce.compile_numerical_circuit_at(grid)
+
+ Ys = 1.0 / (nc.branch_data.R + 1j * nc.branch_data.X)
+
+ test_data = [
+ {
+ "bus_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ "br_idx": np.array([10, 12, 14]),
+ "sf_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ },
+ {
+ "bus_idx": np.array([1, 2, 3, 4, 5, 6, 7]),
+ "br_idx": np.array([2, 3, 4]),
+ "sf_idx": np.array([2, 3, 4]),
+ },
+ {
+ "bus_idx": np.arange(nc.nbus),
+ "br_idx": np.arange(nc.nbr),
+ "sf_idx": np.arange(nc.nbr),
+ },
+ ]
+
+ for dta in test_data:
+ m_idx = dta["br_idx"]
+ bus_idx = dta["bus_idx"]
+ sf_idx = dta["sf_idx"]
+
+ dSbus_dbeq1, dSf_dbeq1, dSt_dbeq1 = cscdiff.derivatives_Beq_csc_numba(nbus=nc.nbus,
+ nbr=nc.nbr,
+ iBeqx=m_idx,
+ F=nc.F,
+ kconv=nc.branch_data.k,
+ tap_module=nc.branch_data.tap_module,
+ V=nc.Vbus)
+ dSbus_dbeq1, dSf_dbeq1, dSt_dbeq1 = mat_to_scipy(dSbus_dbeq1), mat_to_scipy(dSf_dbeq1), mat_to_scipy(dSt_dbeq1)
+
+ # dSbus_dbeq1, dSf_dbeq1, dSt_dbeq1 = mdiff.dS_dbeq_matpower(V=nc.Vbus,
+ # Cf=nc.Cf,
+ # Ct=nc.Ct,
+ # k2=nc.branch_data.k,
+ # m=nc.branch_data.tap_module)
+
+ dSbus_dbeq2 = cscdiff.dSbus_dbeq_csc(nbus=nc.nbus,
+ bus_indices=bus_idx,
+ beq_indices=m_idx,
+ F=nc.F,
+ kconv=nc.branch_data.k,
+ tap_module=nc.branch_data.tap_module,
+ V=nc.Vbus)
+ dSbus_dbeq3 = dSbus_dbeq1[bus_idx, :]
+ assert np.allclose(dSbus_dbeq3.toarray(), dSbus_dbeq2.toarray())
+
+ dSf_dbeq2 = cscdiff.dSf_dbeq_csc(nbr=nc.nbr,
+ sf_indices=sf_idx,
+ beq_indices=m_idx,
+ F=nc.F,
+ kconv=nc.branch_data.k,
+ tap_module=nc.branch_data.tap_module,
+ V=nc.Vbus)
+ dSf_dbeq3 = dSf_dbeq1[sf_idx, :]
+ assert np.allclose(dSf_dbeq3.toarray(), dSf_dbeq2.toarray())
+
+ # dSt_dbeq is zero
+
+
+def test_jacobian():
+ fname = os.path.join("data", "grids", "RAW", "IEEE 14 bus.raw")
+ grid = gce.open_file(filename=fname)
+ nc = gce.compile_numerical_circuit_at(grid)
+
+ idx_dtheta = np.r_[nc.pv, nc.pq, nc.pqv, nc.p]
+ idx_dVm = np.r_[nc.pq, nc.p]
+ idx_dP = idx_dtheta
+ idx_dQ = np.r_[nc.pq, nc.pqv]
+
+ J1 = mdiff.Jacobian(nc.Ybus, nc.Vbus, idx_dP, idx_dQ, idx_dtheta, idx_dVm)
+
+ J3 = cscjac.AC_jacobian(nc.Ybus, nc.Vbus, idx_dtheta, idx_dVm)
+
+ J2 = cscjac.AC_jacobianVc(nc.Ybus, nc.Vbus, idx_dtheta, idx_dVm, idx_dQ)
+
+ ok1 = np.allclose(J1.toarray(), J2.toarray())
+ ok2 = np.allclose(J1.toarray(), J3.toarray())
+ ok = ok1 and ok2
+
+ if not ok:
+ print(f"J1:\n{J1.toarray()}\n")
+ print(f"J2:\n{J2.toarray()}\n")
+ print(f"ok {ok}")
+ assert ok
+
+
+if __name__ == '__main__':
+ # test_branch_derivatives()
+ test_tau_derivatives()
+ test_m_derivatives()
+ test_beq_derivatives()
+ # test_jacobian()
diff --git a/src/tests/test_generator_q_control.py b/src/tests/test_generator_q_control.py
index e333619ee..a9f28363e 100644
--- a/src/tests/test_generator_q_control.py
+++ b/src/tests/test_generator_q_control.py
@@ -2,7 +2,7 @@
from GridCalEngine.api import *
-def test_q_control_true():
+def test_q_control_true() -> None:
"""
Test that when the Q control is enabled the Q limits are respected
"""
@@ -12,7 +12,7 @@ def test_q_control_true():
for solver_type in [SolverType.NR, SolverType.IWAMOTO, SolverType.LM, SolverType.FASTDECOUPLED]:
options = PowerFlowOptions(solver_type,
- control_q=ReactivePowerControlMode.Direct,
+ control_q=True,
retry_with_other_methods=False)
power_flow = PowerFlowDriver(main_circuit, options)
@@ -39,10 +39,9 @@ def test_q_control_false():
main_circuit = FileOpen(fname).open()
for solver_type in [SolverType.NR, SolverType.IWAMOTO, SolverType.LM, SolverType.FASTDECOUPLED]:
-
options = PowerFlowOptions(solver_type,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
power_flow = PowerFlowDriver(main_circuit, options)
@@ -58,3 +57,7 @@ def test_q_control_false():
ok = l_ok.all() and r_ok.all()
assert not ok
+
+
+if __name__ == '__main__':
+ test_q_control_true()
diff --git a/src/tests/test_islands.py b/src/tests/test_islands.py
index 27192ed36..ff9ac4a90 100644
--- a/src/tests/test_islands.py
+++ b/src/tests/test_islands.py
@@ -20,7 +20,7 @@
from GridCalEngine.IO.file_handler import FileOpen
from GridCalEngine.Simulations.PowerFlow.power_flow_worker import PowerFlowOptions
-from GridCalEngine.Simulations.PowerFlow.power_flow_options import ReactivePowerControlMode, SolverType
+from GridCalEngine.Simulations.PowerFlow.power_flow_options import SolverType
from GridCalEngine.Simulations.PowerFlow.power_flow_driver import PowerFlowDriver
from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
from GridCalEngine.Topology.topology import find_islands
diff --git a/src/tests/test_latin_hypercube.py b/src/tests/test_latin_hypercube.py
index 87b1cfad9..dc11bc0e1 100644
--- a/src/tests/test_latin_hypercube.py
+++ b/src/tests/test_latin_hypercube.py
@@ -25,13 +25,9 @@ def test_lhs():
fname = os.path.join('data', 'grids', 'IEEE39_1W.gridcal')
print('Reading...')
main_circuit = FileOpen(fname).open()
- pf_options = PowerFlowOptions(SolverType.NR,
- verbose=False,
- control_q=ReactivePowerControlMode.NoControl)
+ pf_options = PowerFlowOptions(SolverType.NR, verbose=False, control_q=False)
print('Running LHC...')
- lhs_sim = StochasticPowerFlowDriver(main_circuit,
- pf_options,
- sampling_points=100)
+ lhs_sim = StochasticPowerFlowDriver(main_circuit, pf_options, sampling_points=100)
lhs_sim.run()
diff --git a/src/tests/test_monte_carlo.py b/src/tests/test_monte_carlo.py
index ec11eef4d..e6682ac23 100644
--- a/src/tests/test_monte_carlo.py
+++ b/src/tests/test_monte_carlo.py
@@ -25,18 +25,13 @@ def test_monte_carlo():
fname = os.path.join('data', 'grids', 'IEEE39_1W.gridcal')
print('Reading...')
main_circuit = FileOpen(fname).open()
- pf_options = PowerFlowOptions(SolverType.NR,
- verbose=0,
- control_q=ReactivePowerControlMode.NoControl)
+ pf_options = PowerFlowOptions(SolverType.NR, verbose=0, control_q=False)
####################################################################################################################
# Monte Carlo
####################################################################################################################
print('Running MC...')
- mc_sim = StochasticPowerFlowDriver(main_circuit,
- pf_options,
- mc_tol=1e-5,
- sampling_points=1000)
+ mc_sim = StochasticPowerFlowDriver(main_circuit, pf_options, mc_tol=1e-5, sampling_points=1000)
mc_sim.run()
diff --git a/src/tests/test_nodal_capacity.py b/src/tests/test_nodal_capacity.py
index 29d4b442e..02dcc8dc7 100644
--- a/src/tests/test_nodal_capacity.py
+++ b/src/tests/test_nodal_capacity.py
@@ -18,7 +18,9 @@ def test_linear_vs_nonlinear_ncap():
grid = gce.FileOpen(fname).open()
# Nonlinear OPF
- pf_options = gce.PowerFlowOptions(solver_type=gce.SolverType.NR, verbose=0)
+ pf_options = gce.PowerFlowOptions(solver_type=gce.SolverType.NR,
+ verbose=0,
+ control_q=False)
opf_options = gce.OptimalPowerFlowOptions(solver=gce.SolverType.NONLINEAR_OPF,
ips_tolerance=1e-8,
diff --git a/src/tests/test_opf_dispatches_controls.py b/src/tests/test_opf_dispatches_controls.py
index 6c5209ea7..cb4b919c1 100644
--- a/src/tests/test_opf_dispatches_controls.py
+++ b/src/tests/test_opf_dispatches_controls.py
@@ -16,7 +16,7 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os
from GridCalEngine.api import *
-from GridCalEngine.enumerations import HvdcControlType, TransformerControlType, TapAngleControl
+from GridCalEngine.enumerations import HvdcControlType, TapModuleControl, TapPhaseControl
def test_opf_hvdc():
@@ -26,7 +26,7 @@ def test_opf_hvdc():
power_flow_options = PowerFlowOptions(SolverType.NR,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
opf_options = OptimalPowerFlowOptions(verbose=0,
@@ -66,7 +66,7 @@ def test_opf_gen():
power_flow_options = PowerFlowOptions(SolverType.NR,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
opf_options = OptimalPowerFlowOptions(verbose=0,
@@ -108,7 +108,7 @@ def test_opf_line_monitoring():
power_flow_options = PowerFlowOptions(SolverType.NR,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
opf_options = OptimalPowerFlowOptions(verbose=0,
@@ -152,7 +152,7 @@ def test_opf_hvdc_controls():
power_flow_options = PowerFlowOptions(SolverType.NR,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
opf_options = OptimalPowerFlowOptions(verbose=0,
@@ -198,7 +198,7 @@ def test_opf_trafo_controls():
power_flow_options = PowerFlowOptions(SolverType.NR,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
opf_options = OptimalPowerFlowOptions(verbose=0,
@@ -208,22 +208,22 @@ def test_opf_trafo_controls():
generate_report=True)
# trafo fixed
- main_circuit.transformers2w[0].control_mode = TransformerControlType.fixed
+ main_circuit.transformers2w[0].tap_phase_control_mode = TapPhaseControl.fixed
opf = OptimalPowerFlowDriver(grid=main_circuit,
options=opf_options)
opf.run()
pf1 = opf.results.Sf[48]
# trafo controlling
- main_circuit.transformers2w[0].control_mode = TransformerControlType.Pf
- main_circuit.transformers2w[0].tap_angle_control_mode = TapAngleControl.Pf
+ main_circuit.transformers2w[0].tap_phase_control_mode = TapPhaseControl.Pf
+ main_circuit.transformers2w[0].tap_phase_control_mode = TapPhaseControl.Pf
opf = OptimalPowerFlowDriver(grid=main_circuit,
options=opf_options)
opf.run()
pf2 = opf.results.Sf[48]
# trafo back to fixed
- main_circuit.transformers2w[0].control_mode = TransformerControlType.fixed
+ main_circuit.transformers2w[0].tap_phase_control_mode = TapPhaseControl.fixed
opf = OptimalPowerFlowDriver(grid=main_circuit,
options=opf_options)
opf.run()
diff --git a/src/tests/test_opf_time_concatenation.py b/src/tests/test_opf_time_concatenation.py
index a1db914ab..c37764cf4 100644
--- a/src/tests/test_opf_time_concatenation.py
+++ b/src/tests/test_opf_time_concatenation.py
@@ -27,7 +27,7 @@ def test_opf_ts_batt():
power_flow_options = PowerFlowOptions(SolverType.NR,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
opf_options = OptimalPowerFlowOptions(verbose=0,
@@ -63,7 +63,7 @@ def test_opf_ts_hydro():
power_flow_options = PowerFlowOptions(SolverType.NR,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
opf_options = OptimalPowerFlowOptions(verbose=0,
diff --git a/src/tests/test_opf_time_series.py b/src/tests/test_opf_time_series.py
index cfa61775a..69489367b 100644
--- a/src/tests/test_opf_time_series.py
+++ b/src/tests/test_opf_time_series.py
@@ -27,7 +27,7 @@ def test_opf_ts():
power_flow_options = PowerFlowOptions(SolverType.NR,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
opf_options = OptimalPowerFlowOptions(verbose=0,
diff --git a/src/tests/test_power_flow.py b/src/tests/test_power_flow.py
index 430463d99..d317c9662 100644
--- a/src/tests/test_power_flow.py
+++ b/src/tests/test_power_flow.py
@@ -20,7 +20,7 @@
from GridCalEngine.IO.file_handler import FileOpen
from GridCalEngine.Simulations.PowerFlow.power_flow_worker import PowerFlowOptions
-from GridCalEngine.Simulations.PowerFlow.power_flow_options import ReactivePowerControlMode, SolverType
+from GridCalEngine.Simulations.PowerFlow.power_flow_options import SolverType
from GridCalEngine.Simulations.PowerFlow.power_flow_driver import PowerFlowDriver
from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
import GridCalEngine.api as gce
@@ -41,13 +41,14 @@ def test_ieee_grids():
('IEEE 118 Bus v2.raw', 'IEEE 118 Bus.sav.xlsx'),
]
- for solver_type in [SolverType.NR, SolverType.IWAMOTO, SolverType.LM, SolverType.FASTDECOUPLED]:
+ for solver_type in [SolverType.NR, SolverType.IWAMOTO, SolverType.LM,
+ SolverType.FASTDECOUPLED, SolverType.PowellDogLeg]:
print(solver_type)
options = PowerFlowOptions(solver_type,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
for f1, f2 in files:
@@ -93,7 +94,7 @@ def test_dc_pf_ieee14():
"""
options = PowerFlowOptions(SolverType.DC,
verbose=False,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
fname = os.path.join('data', 'grids', 'case14.m')
@@ -134,7 +135,7 @@ def test_dc_pf_ieee14_ps():
"""
options = PowerFlowOptions(SolverType.DC,
verbose=False,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
fname = os.path.join('data', 'grids', 'case14_ps.m')
@@ -196,10 +197,10 @@ def test_controllable_shunt() -> None:
"""
This tests that the controllable shunt is indeed controlling voltage at 1.02 at the third bus
"""
- options = PowerFlowOptions()
fname = os.path.join('data', 'grids', 'Controllable_shunt_example.gridcal')
main_circuit = FileOpen(fname).open()
+ options = PowerFlowOptions(control_q=False)
power_flow = PowerFlowDriver(main_circuit, options)
power_flow.run()
@@ -209,29 +210,260 @@ def test_controllable_shunt() -> None:
assert np.allclose(Vm_test, Vm, atol=1e-3)
-def test_voltage_remote_control_with_generation() -> None:
+def test_voltage_local_control_with_generation() -> None:
"""
-
- :return:
+ Check that a generator can perform remote voltage regulation
"""
fname = os.path.join('data', 'grids', 'RAW', 'IEEE 14 bus.raw')
grid = gce.open_file(fname)
- # control bus 6 with generator 4
- grid.generators[4].control_bus = grid.buses[6]
+ # control local bus with generator 4
+ gen = grid.generators[4]
+ gen.is_controlled = True
+ bus_dict = grid.get_bus_index_dict()
+ bus_i = bus_dict[gen.bus]
- for solver_type in [SolverType.NR, SolverType.IWAMOTO, SolverType.LM, SolverType.FASTDECOUPLED]:
+ # run power flow with the local voltage control enabled
+ for solver_type in [SolverType.NR, SolverType.IWAMOTO, SolverType.LM,
+ SolverType.FASTDECOUPLED, SolverType.PowellDogLeg]:
options = PowerFlowOptions(solver_type,
verbose=0,
- control_q=ReactivePowerControlMode.NoControl,
+ control_q=False,
retry_with_other_methods=False)
results = gce.power_flow(grid, options)
+ vm = np.abs(results.voltage)
+
+ assert results.converged
+ assert np.isclose(vm[bus_i], gen.Vset, atol=options.tolerance)
+
+ # run power flow with the local voltage control disabled
+ gen.is_controlled = False
+ for solver_type in [SolverType.NR, SolverType.IWAMOTO, SolverType.LM,
+ SolverType.FASTDECOUPLED, SolverType.PowellDogLeg]:
+ options = PowerFlowOptions(solver_type,
+ verbose=0,
+ control_q=False,
+ retry_with_other_methods=False)
+ results = gce.power_flow(grid, options)
vm = np.abs(results.voltage)
assert results.converged
- assert np.isclose(vm[6], grid.generators[4].Vset, atol=options.tolerance)
+ assert not np.isclose(vm[bus_i], gen.Vset, atol=options.tolerance)
- print(solver_type)
+
+def test_voltage_remote_control_with_generation() -> None:
+ """
+ Check that a generator can perform remote voltage regulation
+ """
+ fname = os.path.join('data', 'grids', 'RAW', 'IEEE 14 bus.raw')
+
+ grid = gce.open_file(fname)
+
+ # control bus 6 with generator 4
+ grid.generators[4].control_bus = grid.buses[6]
+
+ for control_remote_voltage in [True, False]:
+ for solver_type in [SolverType.NR, SolverType.IWAMOTO, SolverType.LM,
+ SolverType.FASTDECOUPLED, SolverType.PowellDogLeg]:
+
+ options = PowerFlowOptions(solver_type=solver_type,
+ verbose=0,
+ control_q=False,
+ retry_with_other_methods=False,
+ control_remote_voltage=control_remote_voltage)
+
+ results = gce.power_flow(grid, options)
+
+ vm = np.abs(results.voltage)
+
+ assert results.converged
+
+ # is the control voltage equal to the desired set point?
+ ok = np.isclose(vm[6], grid.generators[4].Vset, atol=options.tolerance)
+
+ if control_remote_voltage:
+ assert ok
+ else:
+ assert not ok
+
+
+def test_voltage_control_with_ltc() -> None:
+ """
+ Check that a transformer can regulate the voltage at a bus
+ """
+ fname = os.path.join('data', 'grids', '5Bus_LTC_FACTS_Fig4.7.gridcal')
+
+ grid = gce.open_file(fname)
+ bus_dict = grid.get_bus_index_dict()
+ ctrl_idx = bus_dict[grid.transformers2w[0].regulation_bus]
+
+ for control_taps_modules in [True, False]:
+ for solver_type in [SolverType.NR, SolverType.LM, SolverType.PowellDogLeg]:
+ options = PowerFlowOptions(solver_type,
+ verbose=0,
+ control_q=False,
+ retry_with_other_methods=False,
+ control_taps_modules=control_taps_modules,
+ control_taps_phase=False,
+ control_remote_voltage=False,
+ apply_temperature_correction=False)
+
+ results = gce.power_flow(grid, options)
+
+ vm = np.abs(results.voltage)
+
+ assert results.converged
+
+ # check that the bus voltage module is the the transformer voltage set point
+ ok = np.isclose(vm[ctrl_idx], grid.transformers2w[0].vset, atol=options.tolerance)
+
+ if control_taps_modules:
+ assert ok
+ else:
+ assert not ok
+
+
+def test_qf_control_with_ltc() -> None:
+ """
+ Check that a transformer can regulate the voltage at a bus
+ """
+ fname = os.path.join('data', 'grids', '5Bus_PST_FACTS_Fig4.10(Qf).gridcal')
+
+ grid = gce.open_file(fname)
+
+ for control_taps_modules in [True, False]:
+ for solver_type in [SolverType.NR, SolverType.LM, SolverType.PowellDogLeg]:
+ options = PowerFlowOptions(solver_type,
+ verbose=0,
+ control_q=False,
+ retry_with_other_methods=False,
+ control_taps_modules=control_taps_modules)
+
+ results = gce.power_flow(grid, options)
+
+ assert results.converged
+
+ # check that the bus voltage module is the the transformer voltage set point
+ ok = np.isclose(results.Sf[7].imag, grid.transformers2w[0].Qset, atol=options.tolerance)
+
+ if control_taps_modules:
+ assert ok
+ else:
+ assert not ok
+
+
+def test_qt_control_with_ltc() -> None:
+ """
+ Check that a transformer can regulate the voltage at a bus
+ """
+ fname = os.path.join('data', 'grids', '5Bus_PST_FACTS_Fig4.10(Qf).gridcal')
+
+ grid = gce.open_file(fname)
+ grid.transformers2w[0].tap_module_control_mode = gce.TapModuleControl.Qt
+
+ for control_taps_modules in [True, False]:
+ for solver_type in [SolverType.NR, SolverType.LM, SolverType.PowellDogLeg]:
+ options = PowerFlowOptions(solver_type,
+ verbose=0,
+ control_q=False,
+ retry_with_other_methods=False,
+ control_taps_modules=control_taps_modules)
+
+ results = gce.power_flow(grid, options)
+
+ assert results.converged
+
+ # check that the bus voltage module is the the transformer voltage set point
+ ok = np.isclose(results.St[7].imag, grid.transformers2w[0].Qset, atol=options.tolerance)
+
+ if control_taps_modules:
+ assert ok
+ else:
+ assert not ok
+
+
+def test_power_flow_control_with_pst_pf() -> None:
+ """
+ Check that a transformer can regulate the voltage at a bus
+ """
+ fname = os.path.join('data', 'grids', '5Bus_PST_FACTS_Fig4.10.gridcal')
+
+ grid = gce.open_file(fname)
+
+ for control_taps_phase in [True, False]:
+ for solver_type in [SolverType.NR, SolverType.LM, SolverType.PowellDogLeg]:
+ options = PowerFlowOptions(solver_type,
+ verbose=0,
+ control_q=False,
+ retry_with_other_methods=False,
+ control_taps_phase=control_taps_phase)
+
+ results = gce.power_flow(grid, options)
+
+ assert results.converged
+
+ # check that the bus voltage module is the the transformer voltage set point
+ ok = np.isclose(results.Sf[7].real, grid.transformers2w[0].Pset, atol=options.tolerance)
+
+ if control_taps_phase:
+ assert ok
+ else:
+ assert not ok
+
+
+def test_power_flow_control_with_pst_pt() -> None:
+ """
+ Check that a transformer can regulate the voltage at a bus
+ """
+ fname = os.path.join('data', 'grids', '5Bus_PST_FACTS_Fig4.10(Pt).gridcal')
+
+ grid = gce.open_file(fname)
+
+ for control_taps_phase in [True, False]:
+ for solver_type in [SolverType.NR, SolverType.LM, SolverType.PowellDogLeg]:
+ options = PowerFlowOptions(solver_type,
+ verbose=0,
+ control_q=False,
+ retry_with_other_methods=False,
+ control_taps_phase=control_taps_phase,
+ max_iter=80)
+
+ results = gce.power_flow(grid, options)
+
+ assert results.converged
+
+ # check that the bus voltage module is the the transformer voltage set point
+ ok = np.isclose(results.St[7].real, grid.transformers2w[0].Pset, atol=options.tolerance)
+
+ if control_taps_phase:
+ assert ok
+ else:
+ assert not ok
+
+
+def test_fubm() -> None:
+ """
+
+ :return:
+ """
+ fname = os.path.join('data', 'grids', 'fubm_caseHVDC_vt.m')
+ grid = gce.open_file(fname)
+
+ for solver_type in [SolverType.NR, SolverType.LM, SolverType.PowellDogLeg]:
+ opt = gce.PowerFlowOptions(solver_type=solver_type,
+ control_q=False,
+ retry_with_other_methods=False,
+ control_taps_modules=True,
+ control_taps_phase=True,
+ control_remote_voltage=True,
+ verbose=0)
+ driver = gce.PowerFlowDriver(grid=grid, options=opt)
+ driver.run()
+ results = driver.results
+ vm = np.abs(results.voltage)
+ expected_vm = np.array([1.1000, 1.0960, 1.0975, 1.1040, 1.1119, 1.1200])
+ ok = np.allclose(vm, expected_vm, rtol=1e-4)
+ assert ok
diff --git a/src/tests/profiles_test.py b/src/tests/test_profiles.py
similarity index 100%
rename from src/tests/profiles_test.py
rename to src/tests/test_profiles.py
diff --git a/src/tests/test_ptdf.py b/src/tests/test_ptdf.py
index e5d4de0d7..3ca4b16a9 100644
--- a/src/tests/test_ptdf.py
+++ b/src/tests/test_ptdf.py
@@ -219,7 +219,7 @@ def test_dcpowerflow():
pf_options = gce.PowerFlowOptions(gce.SolverType.DC,
verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl)
+ control_q=False)
options1 = gce.ContingencyAnalysisOptions(pf_options=pf_options, contingency_method=gce.ContingencyMethod.PowerFlow)
cont_analysis_driver1 = gce.ContingencyAnalysisDriver(grid=main_circuit, options=options1,
linear_multiple_contingencies=None)
@@ -420,9 +420,7 @@ def test_mlodf() -> None:
Sfmlodf = Sf0 + np.matmul(mlodf, Sf0red)
# Theoretical method
- pf_options = gce.PowerFlowOptions(gce.SolverType.NR,
- verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(gce.SolverType.NR, verbose=0, control_q=False)
options = gce.ContingencyAnalysisOptions(pf_options=pf_options, contingency_method=gce.ContingencyMethod.PTDF)
cont_analysis_driver = gce.ContingencyAnalysisDriver(grid=main_circuit, options=options,
@@ -446,9 +444,7 @@ def test_mlodf_sanpen():
main_circuit = gce.FileOpen(fname).open()
# DC power flow method
- pf_options = gce.PowerFlowOptions(gce.SolverType.DC,
- verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(gce.SolverType.DC, verbose=0, control_q=False)
options1 = gce.ContingencyAnalysisOptions(pf_options=pf_options, contingency_method=gce.ContingencyMethod.PowerFlow)
cont_analysis_driver1 = gce.ContingencyAnalysisDriver(grid=main_circuit, options=options1,
linear_multiple_contingencies=None)
@@ -490,9 +486,7 @@ def test_ptdf_generation_contingencies():
]:
main_circuit = gce.FileOpen(fname).open()
- pf_options = gce.PowerFlowOptions(gce.SolverType.DC,
- verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(gce.SolverType.DC, verbose=0, control_q=False)
# DC power flow method
options1 = gce.ContingencyAnalysisOptions(pf_options=pf_options, contingency_method=gce.ContingencyMethod.PowerFlow)
@@ -532,9 +526,7 @@ def test_lodf_single_contingencies():
main_circuit = gce.FileOpen(fname).open()
# DC power flow method
- pf_options = gce.PowerFlowOptions(gce.SolverType.DC,
- verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(gce.SolverType.DC, verbose=0, control_q=False)
options1 = gce.ContingencyAnalysisOptions(pf_options=pf_options,
contingency_method=gce.ContingencyMethod.PowerFlow)
@@ -585,14 +577,10 @@ def test_generation_contingencies_powerflow():
]:
main_circuit = gce.FileOpen(case['conti']).open()
- pf_options = gce.PowerFlowOptions(gce.SolverType.DC,
- verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(gce.SolverType.DC, verbose=0, control_q=False)
# DC power flow method with ContingencyAnalysisDriver
- pf_options = gce.PowerFlowOptions(gce.SolverType.DC,
- verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(gce.SolverType.DC, verbose=0, control_q=False)
options1 = gce.ContingencyAnalysisOptions(pf_options=pf_options, contingency_method=gce.ContingencyMethod.PowerFlow)
cont_analysis_driver1 = gce.ContingencyAnalysisDriver(grid=main_circuit, options=options1,
@@ -710,9 +698,7 @@ def test_ptdf_contingencies_powerflow():
linear_multi_contingency.compute(ptdf=linear_analysis.results.PTDF, lodf=linear_analysis.results.LODF)
# DC power flow method with ContingencyAnalysisDriver
- pf_options = gce.PowerFlowOptions(gce.SolverType.DC,
- verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(gce.SolverType.DC, verbose=0, control_q=False)
options1 = gce.ContingencyAnalysisOptions(pf_options=pf_options, contingency_method=gce.ContingencyMethod.PTDF)
cont_analysis_driver1 = gce.ContingencyAnalysisDriver(grid=main_circuit, options=options1,
@@ -743,9 +729,7 @@ def test_ptdf_contingencies_powerflow():
else:
# DC power flow method with ContingencyAnalysisDriver
- pf_options = gce.PowerFlowOptions(gce.SolverType.DC,
- verbose=0,
- control_q=gce.ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(gce.SolverType.DC, verbose=0, control_q=False)
options1 = gce.ContingencyAnalysisOptions(pf_options=pf_options, contingency_method=gce.ContingencyMethod.PowerFlow)
cont_analysis_driver1 = gce.ContingencyAnalysisDriver(grid=main_circuit, options=options1,
diff --git a/src/tests/test_short_circuit.py b/src/tests/test_short_circuit.py
index 6f8f50df8..5e84f5557 100644
--- a/src/tests/test_short_circuit.py
+++ b/src/tests/test_short_circuit.py
@@ -26,9 +26,7 @@ def test_short_circuit():
fname = os.path.join('data', 'grids', 'IEEE39_1W.gridcal')
print('Reading...')
main_circuit = FileOpen(fname).open()
- pf_options = PowerFlowOptions(solver_type=SolverType.NR,
- verbose=0,
- control_q=ReactivePowerControlMode.NoControl)
+ pf_options = PowerFlowOptions(solver_type=SolverType.NR, verbose=0, control_q=False)
####################################################################################################################
# PowerFlowDriver
####################################################################################################################
diff --git a/src/tests/test_sparse2.py b/src/tests/test_sparse2.py
index 5398351c3..53db312a3 100644
--- a/src/tests/test_sparse2.py
+++ b/src/tests/test_sparse2.py
@@ -14,13 +14,41 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from __future__ import annotations
from time import time
import numpy as np
import numba as nb
from scipy.sparse import csc_matrix, random, hstack, vstack
from scipy.sparse import rand
from scipy.sparse.linalg import spsolve as spsolve_scipy
-from GridCalEngine.Utils.Sparse.csc2 import (sp_slice, sp_slice_rows, csc_stack_2d_ff, scipy_to_mat, spsolve_csc, extend)
+from GridCalEngine.Utils.Sparse.csc2 import (sp_slice, sp_slice_rows, csc_stack_2d_ff, scipy_to_mat, spsolve_csc,
+ extend, CSC, csc_multiply_ff)
+
+
+def get_scipy_random_matrix(m: int | None = None, n: int | None = None) -> csc_matrix:
+ """
+
+ :param m: number or rows (if None, random)
+ :param n: number or cols (if None, random)
+ :return:
+ """
+ if m is None:
+ m = np.random.randint(1, 1000)
+
+ if n is None:
+ n = np.random.randint(1, 1000)
+
+ return rand(m, n, density=0.25, format="csc", random_state=42)
+
+
+def get_csc_random_matrix(m: int | None = None, n: int | None = None) -> CSC:
+ """
+
+ :param m: number or rows (if None, random)
+ :param n: number or cols (if None, random)
+ :return:
+ """
+ return scipy_to_mat(get_scipy_random_matrix(m, n))
def test_sp_slice():
@@ -103,8 +131,7 @@ def test_spsolve() -> None:
ok_a = not np.isnan(a).any()
try:
- b = spsolve_csc(scipy_to_mat(matrix), rhs)
- ok_b = True
+ b, ok_b = spsolve_csc(scipy_to_mat(matrix), rhs)
assert ok_a == ok_b
if ok_a and ok_b:
@@ -135,3 +162,24 @@ def test_extend():
B = extend(scipy_to_mat(matrix), last_col, last_row, val)
assert np.allclose(A.todense(), B.todense())
+
+
+# def test_mat_mat_mult():
+# for i in range(100):
+# m = np.random.randint(1, 1000)
+# n = np.random.randint(1, 1000)
+# o = np.random.randint(1, 1000)
+#
+# A1 = get_scipy_random_matrix(m, n)
+# B1 = get_scipy_random_matrix(n, o)
+# C1 = A1 @ B1
+#
+# A2 = get_csc_random_matrix(m, n)
+# B2 = get_csc_random_matrix(n, o)
+# C2 = A2 @ B2
+#
+# assert np.allclose(C1.toarray(), C2.toarray())
+#
+#
+# def test_mat_vec_mult():
+# pass
diff --git a/src/tests/test_time_series.py b/src/tests/test_time_series.py
index 4fd7f542e..5b3686277 100644
--- a/src/tests/test_time_series.py
+++ b/src/tests/test_time_series.py
@@ -17,7 +17,7 @@
import os
from GridCalEngine.api import *
-from tests.zip_file_mgmt import open_data_frame_from_zip
+from GridCalEngine.Utils.zip_file_mgmt import open_data_frame_from_zip
def test_time_series():
@@ -26,9 +26,7 @@ def test_time_series():
print('Reading...')
main_circuit = FileOpen(fname).open()
- pf_options = PowerFlowOptions(solver_type=SolverType.NR,
- verbose=0,
- control_q=ReactivePowerControlMode.NoControl)
+ pf_options = PowerFlowOptions(solver_type=SolverType.NR, verbose=0, control_q=False)
ts = PowerFlowTimeSeriesDriver(grid=main_circuit, options=pf_options, time_indices=np.arange(0, 96))
ts.run()
diff --git a/src/tests/test_transformer_controls.py b/src/tests/test_transformer_controls.py
index 2b1fd9308..f330cbabf 100644
--- a/src/tests/test_transformer_controls.py
+++ b/src/tests/test_transformer_controls.py
@@ -6,16 +6,15 @@ def test_v_control_true():
"""
Test that when the V control is enabled the voltage at the bus is the set point
"""
- options = PowerFlowOptions(SolverType.NR,
- control_q=ReactivePowerControlMode.Direct,
- retry_with_other_methods=False)
+ options = PowerFlowOptions(SolverType.NR, control_q=True, retry_with_other_methods=False)
fname = os.path.join('data', 'grids', 'IEEE57.gridcal')
main_circuit = FileOpen(fname).open()
tr = main_circuit.transformers2w[5]
- tr.control_mode = TransformerControlType.V
+ tr.tap_module_control_mode = TapModuleControl.Vm
+ tr.regulation_bus = tr.bus_to
tr.vset = 1.0
power_flow = PowerFlowDriver(main_circuit, options)
@@ -31,7 +30,7 @@ def test_v_control_false():
Test that when the V control is disabled the voltage at the bus is not the set point
"""
options = PowerFlowOptions(SolverType.NR,
- control_q=ReactivePowerControlMode.Direct,
+ control_q=True,
retry_with_other_methods=False)
fname = os.path.join('data', 'grids', 'IEEE57.gridcal')
@@ -39,7 +38,7 @@ def test_v_control_false():
tr = main_circuit.transformers2w[5]
- tr.control_mode = TransformerControlType.fixed
+ tr.tap_phase_control_mode = TapPhaseControl.fixed
tr.vset = 1.0
power_flow = PowerFlowDriver(main_circuit, options)
diff --git a/src/trunk/acdc_pf/fubm_caseHVDC_vt run matlab.txt b/src/trunk/acdc_pf/fubm_caseHVDC_vt run matlab.txt
new file mode 100644
index 000000000..84901b94a
--- /dev/null
+++ b/src/trunk/acdc_pf/fubm_caseHVDC_vt run matlab.txt
@@ -0,0 +1,411 @@
+FUBM Formulation
+Yff
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0811 - 0.1802i 0.9651 - 0.3753i 0.4878 + 0.0000i
+
+Yft
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0811 + 0.1802i -0.9651 + 0.3753i -0.4878 + 0.0000i
+
+Ytf
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0811 + 0.1802i -0.9651 + 0.3753i -0.4878 + 0.0000i
+
+Ytt
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0811 - 0.1802i 0.9651 - 0.3753i 0.4878 + 0.0000i
+
+--------------------------------------------------------------------------------------------------------------------------------
+Iter: 1
+--------------------------------------------------------------------------------------------------------------------------------
+
+J:
+ 12.6574 0 0 -0.1975 -0.4052 -1.1849 -0.8509 0 0 0 1.1849
+ 0 0.4144 0 0 -0.4144 -0.5385 -1.0655 -0.4144 0 0 0
+ 0 0 11.1989 0 -11.1989 0 -0.1120 0 0 0 0
+ -0.1975 0 0 0.1975 0 1.4144 0 0 0 0 -0.9773
+ -0.4052 -0.4144 -11.1989 0 12.0184 0 1.6546 0.4144 0 0 0
+ 1.1849 0.5385 0 -1.7234 0 0.1629 0 0 -1.0000 0 -0.1629
+ 0.8509 1.0655 0.1120 0 -2.0284 0 9.4696 -1.0655 0 0 0
+ 0 0.4144 0 0 -0.4144 0 -1.0655 -0.4144 0 0 0
+ 1.1849 0 0 -1.1849 0 0.1629 0 0 -1.0000 0 -0.1629
+ 0 -1.6041 0 0.5385 1.0655 0 -0.4144 1.0655 0 -1.2188 0
+ -2.1563 0 0 1.1849 0.8509 -0.1975 -0.4052 0 0 0 0.1975
+
+F:
+ 0.2250 0.1668 0.0034 -0.1545 -0.1669 -0.0173 -1.2694 0.1143 -0.0173 0.0431 0.0170
+
+dx:
+ 0.0004 0.0656 -0.0259 0.0656 -0.0269 0.0975 0.1261 0.0440 -0.0781 -0.0499 -0.0038
+
+Yff
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0919 - 0.2603i 0.9656 - 0.4252i 0.4878 + 0.0000i
+
+Yft
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0852 + 0.1809i -0.9477 + 0.4174i -0.4878 + 0.0000i
+
+Ytf
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0852 + 0.1809i -0.9807 + 0.3326i -0.4878 + 0.0000i
+
+Ytt
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0811 - 0.1802i 0.9651 - 0.3753i 0.4878 + 0.0000i
+
+Vm
+ 1.1000 1.0960 1.0975 1.1040 1.1261 1.1200
+
+Va
+ 0 0.0004 0.0656 0.0656 -0.0269 -0.0259
+
+tau
+ 0 0 0 0 0.0440 0
+
+beq
+ 0 0 0 -0.0781 -0.0499 0
+
+m
+ 0 0 0 0.9962 0 0
+
+Gsw
+ 0.0012 0.0002
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+Iter: 2
+--------------------------------------------------------------------------------------------------------------------------------
+
+J:
+ 12.6690 0 0 -0.1320 -0.4822 -1.1998 -0.8395 0 0 0 1.3218
+ 0 0.5242 0 0.0000 -0.5242 -0.5385 -1.0442 -0.5242 0 0 0
+ 0 0 12.6116 0 -12.6116 0 -0.1013 0 0 0 0
+ -0.3022 -0.0000 0 0.3022 0 1.7549 0 0 0.0000 0 -1.3410
+ -0.4300 -0.4079 -12.6114 0 13.4493 0 2.0789 0.4079 0 0 0
+ 1.2884 0.5910 0 -1.8795 0 0.2959 0 0 -1.2138 0 -0.3260
+ 0.9703 1.2211 0.1382 0 -2.3295 0 12.2556 -1.2211 0 0 0
+ 0 0.5242 0 0 -0.5242 0 -1.0442 -0.5242 0 0.0000 0
+ 1.2884 0 0 -1.2884 0 0.2959 0 0 -1.2138 0 -0.3260
+ 0 -1.7669 0 0.5910 1.1759 0.0000 -0.4655 1.1759 0 -1.2188 0
+ -2.3785 0 0 1.3168 0.9454 -0.1203 -0.4282 0 0 0 0.1325
+
+F:
+ 0.0028 0.0044 0.0013 0.0233 0.0258 0.0113 0.1811 0.0044 0.0113 -0.0059 0.0054
+
+dx:
+ -0.0046 0.0085 -0.0385 0.0085 -0.0383 -0.0000 -0.0138 0.0828 -0.0100 0.0352 0.0203
+
+Yff
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0475 - 0.2597i 0.9653 - 0.3901i 0.4878 + 0.0000i
+
+Yft
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0636 + 0.1773i -0.9100 + 0.4943i -0.4878 + 0.0000i
+
+Ytf
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0636 + 0.1773i -1.0049 + 0.2503i -0.4878 + 0.0000i
+
+Ytt
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0811 - 0.1802i 0.9651 - 0.3753i 0.4878 + 0.0000i
+
+Vm
+ 1.1000 1.0960 1.0975 1.1040 1.1123 1.1200
+
+Va
+ 0 -0.0043 0.0740 0.0740 -0.0651 -0.0644
+
+tau
+ 0 0 0 0 0.1268 0
+
+beq
+ 0 0 0 -0.0881 -0.0147 0
+
+m
+ 0 0 0 1.0165 0 0
+
+Gsw
+ 0.0017 0.0001
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+Iter:3
+--------------------------------------------------------------------------------------------------------------------------------
+
+J:
+ 12.6741 0 0 -0.1125 -0.5074 -1.1773 -0.8246 0 0 0 1.2711
+ 0 0.4756 0 -0.0000 -0.4756 -0.5385 -1.0603 -0.4756 0 0 0
+ 0 0 12.4565 0 -12.4565 0 -0.1037 0 0 0 0
+ -0.3127 0.0000 0 0.3127 0 1.6846 0 0 0 0 -1.2414
+ -0.3923 -0.4461 -12.4563 0 13.2947 0 2.0318 0.4461 0 0 0
+ 1.2587 0.5910 0 -1.8498 0 0.2851 0 0 -1.1658 0 -0.3079
+ 0.9721 1.1908 0.1337 0 -2.2966 0 11.9484 -1.1908 0 0 0
+ 0 0.4756 0 0 -0.4756 0 -1.0603 -0.4756 0 0.0000 0
+ 1.2587 0 0 -1.2587 0 0.2851 0 0 -1.1658 0 -0.3079
+ 0 -1.7704 0 0.5910 1.1794 -0.0000 -0.4276 1.1794 0 -1.2188 0
+ -2.3813 0 0 1.2921 0.9172 -0.1025 -0.4562 0 0 0 0.1107
+
+F:
+ -0.0001 0.0007 0.0000 -0.0005 0.0016 0.0001 0.0027 0.0007 0.0001 -0.0002 0.0004
+
+dx:
+ -0.0002 0.0028 -0.0053 0.0028 -0.0053 -0.0000 -0.0004 0.0105 -0.0033 0.0023 0.0004
+
+Yff
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0472 - 0.2626i 0.9652 - 0.3878i 0.4878 + 0.0000i
+
+Yft
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0631 + 0.1772i -0.9047 + 0.5038i -0.4878 + 0.0000i
+
+Ytf
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0631 + 0.1772i -1.0074 + 0.2398i -0.4878 + 0.0000i
+
+Ytt
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0811 - 0.1802i 0.9651 - 0.3753i 0.4878 + 0.0000i
+
+Vm
+ 1.1000 1.0960 1.0975 1.1040 1.1119 1.1200
+
+Va
+ 0 -0.0045 0.0768 0.0768 -0.0704 -0.0697
+
+tau
+ 0 0 0 0 0.1372 0
+
+beq
+ 0 0 0 -0.0914 -0.0124 0
+
+m
+ 0 0 0 1.0169 0 0
+
+Gsw
+ 0.0018 0.0001
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+Iter: 4
+--------------------------------------------------------------------------------------------------------------------------------
+J:
+ 12.6745 0 0 -0.1085 -0.5118 -1.1771 -0.8223 0 0 0 1.2705
+ 0 0.4726 0 -0.0000 -0.4726 -0.5385 -1.0613 -0.4726 0 0 0
+ 0 0 12.4521 0 -12.4521 0 -0.1038 0 0 0 0
+ -0.3164 0.0000 0 0.3164 0 1.6852 0 0 0 0 -1.2404
+ -0.3872 -0.4488 -12.4519 0 13.2879 0 2.0296 0.4488 0 0 0
+ 1.2573 0.5910 0 -1.8483 0 0.2883 0 0 -1.1649 0 -0.3111
+ 0.9737 1.1893 0.1336 0 -2.2966 0 11.9417 -1.1893 0 0 0
+ 0 0.4726 0 0 -0.4726 0 -1.0613 -0.4726 0 -0.0000 0
+ 1.2573 0 0 -1.2573 0 0.2883 0 0 -1.1649 0 -0.3111
+ 0 -1.7711 0 0.5910 1.1801 -0.0000 -0.4251 1.1801 0 -1.2188 0
+ -2.3813 0 0 1.2919 0.9144 -0.0989 -0.4603 0 0 0 0.1067
+
+F:
+ 1.0e-03 *
+
+ 0.0166 -0.1146 0.0000 0.6129 0.0163 0.0001 0.0072 -0.1146 0.0001 0.0003 0.0074
+
+dx:
+ 1.0e-03 *
+
+ -0.0392 -0.2630 0.2085 -0.2630 0.2085 0.0000 -0.0037 -0.7056 0.1249 -0.2251 0.4370
+
+Yff
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0464 - 0.2623i 0.9652 - 0.3880i 0.4878 + 0.0000i
+
+Yft
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0627 + 0.1771i -0.9051 + 0.5032i -0.4878 + 0.0000i
+
+Ytf
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0627 + 0.1771i -1.0072 + 0.2405i -0.4878 + 0.0000i
+
+Ytt
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0811 - 0.1802i 0.9651 - 0.3753i 0.4878 + 0.0000i
+
+Vm
+ 1.1000 1.0960 1.0975 1.1040 1.1119 1.1200
+
+Va
+ 0 -0.0046 0.0766 0.0766 -0.0702 -0.0695
+
+tau
+ 0 0 0 0 0.1365 0
+
+beq
+ 0 0 0 -0.0913 -0.0127 0
+
+m
+ 0 0 0 1.0173 0 0
+
+Gsw
+ 0.0018 0.0001
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+Iter: 5
+--------------------------------------------------------------------------------------------------------------------------------
+
+J:
+ 12.6745 0 0 -0.1087 -0.5116 -1.1766 -0.8225 0 0 0 1.2693
+ 0 0.4729 0 0.0000 -0.4729 -0.5385 -1.0612 -0.4729 0 0 0
+ 0 0 12.4520 0 -12.4520 0 -0.1038 0 0 0 0
+ -0.3159 -0.0000 0 0.3159 0 1.6839 0 0 0 0 -1.2382
+ -0.3875 -0.4485 -12.4518 0 13.2878 0 2.0295 0.4485 0 0 0
+ 1.2568 0.5910 0 -1.8478 0 0.2879 0 0 -1.1639 0 -0.3106
+ 0.9736 1.1894 0.1336 0 -2.2966 0 11.9417 -1.1894 0 0 0
+ 0 0.4729 0 0 -0.4729 0 -1.0612 -0.4729 0 -0.0000 0
+ 1.2568 0 0 -1.2568 0 0.2879 0 0 -1.1639 0 -0.3106
+ 0 -1.7710 0 0.5910 1.1799 0.0000 -0.4253 1.1799 0 -1.2188 0
+ -2.3813 0 0 1.2913 0.9145 -0.0991 -0.4601 0 0 0 0.1069
+
+F:
+ 1.0e-03 *
+
+ -0.0002 -0.0027 0.0000 0.1519 0.0001 0.0001 0.0000 -0.0027 0.0001 0.0000 0.0001
+
+dx:
+ 1.0e-03 *
+
+ -0.0123 -0.0285 -0.0059 -0.0285 -0.0059 -0.0000 -0.0000 -0.0283 -0.0140 -0.0054 0.1186
+
+Yff
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0462 - 0.2623i 0.9652 - 0.3880i 0.4878 + 0.0000i
+
+Yft
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0626 + 0.1771i -0.9051 + 0.5032i -0.4878 + 0.0000i
+
+Ytf
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0626 + 0.1771i -1.0072 + 0.2405i -0.4878 + 0.0000i
+
+Ytt
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0811 - 0.1802i 0.9651 - 0.3753i 0.4878 + 0.0000i
+
+Vm
+ 1.1000 1.0960 1.0975 1.1040 1.1119 1.1200
+
+Va
+ 0 -0.0046 0.0766 0.0766 -0.0702 -0.0695
+
+tau
+ 0 0 0 0 0.1365 0
+
+beq
+ 0 0 0 -0.0913 -0.0127 0
+
+m
+ 0 0 0 1.0174 0 0
+
+Gsw
+ 0.0018 0.0001
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+Iter: 6
+--------------------------------------------------------------------------------------------------------------------------------
+
+J:
+ 12.6745 0 0 -0.1087 -0.5116 -1.1765 -0.8225 0 0 0 1.2690
+ 0 0.4729 0 0.0000 -0.4729 -0.5385 -1.0612 -0.4729 0 0 0
+ 0 0 12.4520 0 -12.4520 0 -0.1038 0 0 0 0
+ -0.3159 -0.0000 0 0.3159 0 1.6835 0 0 0.0000 0 -1.2376
+ -0.3875 -0.4485 -12.4518 0 13.2878 0 2.0295 0.4485 0 0 0
+ 1.2566 0.5910 0 -1.8477 0 0.2878 0 0 -1.1636 0 -0.3105
+ 0.9736 1.1894 0.1336 0 -2.2966 0 11.9417 -1.1894 0 0 0
+ 0 0.4729 0 0 -0.4729 0 -1.0612 -0.4729 0 0.0000 0
+ 1.2566 0 0 -1.2566 0 0.2878 0 0 -1.1636 0 -0.3105
+ 0 -1.7710 0 0.5910 1.1799 0.0000 -0.4253 1.1799 0 -1.2188 0
+ -2.3813 0 0 1.2912 0.9145 -0.0991 -0.4601 0 0 0 0.1069
+
+F:
+ 1.0e-05 *
+
+ -0.0018 0.0217 0.0000 -0.7867 0.0000 0.0002 0.0000 0.0217 0.0002 0.0000 0.0002
+
+dx:
+ 1.0e-05 *
+
+ 0.0631 0.1600 0.0096 0.1600 0.0096 0.0000 0.0002 0.1960 0.0585 0.0440 -0.6109
+
+Yff
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0462 - 0.2623i 0.9652 - 0.3880i 0.4878 + 0.0000i
+
+Yft
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0626 + 0.1771i -0.9051 + 0.5032i -0.4878 + 0.0000i
+
+Ytf
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0626 + 0.1771i -1.0072 + 0.2405i -0.4878 + 0.0000i
+
+Ytt
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0811 - 0.1802i 0.9651 - 0.3753i 0.4878 + 0.0000i
+
+Vm
+ 1.1000 1.0960 1.0975 1.1040 1.1119 1.1200
+
+Va
+ 0 -0.0046 0.0766 0.0766 -0.0702 -0.0695
+
+tau
+ 0 0 0 0 0.1365 0
+
+beq
+ 0 0 0 -0.0913 -0.0127 0
+
+m
+ 0 0 0 1.0174 0 0
+
+Gsw
+ 0.0018 0.0001
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+Iter: 7
+--------------------------------------------------------------------------------------------------------------------------------
+
+J:
+ 12.6745 0 0 -0.1087 -0.5116 -1.1765 -0.8225 0 0 0 1.2691
+ 0 0.4729 0 0.0000 -0.4729 -0.5385 -1.0612 -0.4729 0 0 0
+ 0 0 12.4520 0 -12.4520 0 -0.1038 0 0 0 0
+ -0.3159 -0.0000 0 0.3159 0 1.6835 0 0 0 0 -1.2377
+ -0.3875 -0.4485 -12.4518 0 13.2878 0 2.0295 0.4485 0 0 0
+ 1.2567 0.5910 0 -1.8477 0 0.2878 0 0 -1.1636 0 -0.3105
+ 0.9736 1.1894 0.1336 0 -2.2966 0 11.9417 -1.1894 0 0 0
+ 0 0.4729 0 0 -0.4729 0 -1.0612 -0.4729 0 -0.0000 0
+ 1.2567 0 0 -1.2567 0 0.2878 0 0 -1.1636 0 -0.3105
+ 0 -1.7710 0 0.5910 1.1799 0.0000 -0.4253 1.1799 0 -1.2188 0
+ -2.3813 0 0 1.2912 0.9145 -0.0991 -0.4601 0 0 0 0.1069
+
+F:
+ 1.0e-07 *
+
+ -0.0005 0.0529 0.0000 0.8407 0.0000 0.0001 0.0000 0.0529 0.0001 0.0000 0.0001
+
+dx:
+ 1.0e-07 *
+
+ -0.0774 -0.0522 -0.2079 -0.0522 -0.2079 0.0000 0.0004 0.2666 -0.2101 0.1073 0.6857
+
+Yff
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0462 - 0.2623i 0.9652 - 0.3880i 0.4878 + 0.0000i
+
+Yft
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0626 + 0.1771i -0.9051 + 0.5032i -0.4878 + 0.0000i
+
+Ytf
+ -0.1000 + 9.9990i -0.7763 + 0.3697i -0.1000 + 9.9990i -1.0626 + 0.1771i -1.0072 + 0.2405i -0.4878 + 0.0000i
+
+Ytt
+ 0.1000 - 9.9990i 0.7763 - 0.3697i 0.1000 - 9.9990i 1.0811 - 0.1802i 0.9651 - 0.3753i 0.4878 + 0.0000i
+
+
+Vm
+ 1.1000 1.0960 1.0975 1.1040 1.1119 1.1200
+
+Va
+ 0 -0.0046 0.0766 0.0766 -0.0702 -0.0695
+
+tau
+ 0 0 0 0 0.1365 0
+
+beq
+ 0 0 0 -0.0913 -0.0127 0
+
+m
+ 0 0 0 1.0174 0 0
+
+Gsw
+ 0.0018 0.0001
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+END
+--------------------------------------------------------------------------------------------------------------------------------
+Newton's method power flow converged in 7 iterations.
diff --git a/src/trunk/acdc_pf/fubm_example.py b/src/trunk/acdc_pf/fubm_example.py
index e1eec9041..8b204b223 100644
--- a/src/trunk/acdc_pf/fubm_example.py
+++ b/src/trunk/acdc_pf/fubm_example.py
@@ -1,11 +1,20 @@
import GridCalEngine.api as gce
+import numpy as np
-fname = '/home/santi/Documentos/Git/GitHub/GridCal/Grids_and_profiles/grids/fubm_caseHVDC_vt.gridcal'
+# Set the printing precision to 4 decimal places
+np.set_printoptions(precision=4)
+
+fname = './../../tests/data/grids/fubm_caseHVDC_vt.m'
grid = gce.open_file(fname)
-results = gce.power_flow(grid)
+opt = gce.PowerFlowOptions(retry_with_other_methods=False, verbose=3, solver_type=gce.SolverType.NR)
+driver = gce.PowerFlowDriver(grid=grid, options=opt)
+driver.run()
+results = driver.results
print(results.get_bus_df())
print()
print(results.get_branch_df())
print("Error:", results.error)
+print("Vm:", np.abs(results.voltage))
+driver.logger.print()
diff --git a/src/trunk/acdc_pf/generalised_pf_run.py b/src/trunk/acdc_pf/generalised_pf_run.py
index 856887bbb..8f1c06f77 100644
--- a/src/trunk/acdc_pf/generalised_pf_run.py
+++ b/src/trunk/acdc_pf/generalised_pf_run.py
@@ -4,9 +4,9 @@
sys.path.append('C:/Users/raiya/Documents/8. eRoots/thesis/code/GridCal/src')
import GridCalEngine.api as gce
from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.generalised_power_flow import run_nonlinear_opf, \
- ac_optimal_power_flow
-from GridCalEngine.enumerations import TransformerControlType, AcOpfMode, ReactivePowerControlMode
+from generalised_power_flow import (run_nonlinear_opf,
+ ac_optimal_power_flow)
+from GridCalEngine.enumerations import TransformerControlType, AcOpfMode
def example_3bus_acopf():
@@ -472,7 +472,7 @@ def case14():
for ll in range(len(grid.lines)):
grid.lines[ll].monitor_loading = True
- pf_options = gce.PowerFlowOptions(solver_type=gce.SolverType.NR, control_q=ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(solver_type=gce.SolverType.NR, control_q=False)
opf_options = gce.OptimalPowerFlowOptions(solver=gce.SolverType.NONLINEAR_OPF, acopf_mode=AcOpfMode.ACOPFstd,
ips_tolerance=1e-6, ips_iterations=50, verbose=1)
res = run_nonlinear_opf(grid=grid, pf_options=pf_options, opf_options=opf_options, plot_error=True, pf_init=True)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/generalised_power_flow.py b/src/trunk/acdc_pf/generalised_power_flow.py
similarity index 99%
rename from src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/generalised_power_flow.py
rename to src/trunk/acdc_pf/generalised_power_flow.py
index 1143ffe2a..aa01c432e 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/generalised_power_flow.py
+++ b/src/trunk/acdc_pf/generalised_power_flow.py
@@ -24,7 +24,7 @@
from GridCalEngine.Simulations.PowerFlow.power_flow_worker import multi_island_pf_nc
from GridCalEngine.Simulations.PowerFlow.power_flow_options import PowerFlowOptions
from GridCalEngine.Simulations.OPF.opf_options import OptimalPowerFlowOptions
-from GridCalEngine.enumerations import ReactivePowerControlMode, AcOpfMode
+from GridCalEngine.enumerations import AcOpfMode
from typing import Union
from GridCalEngine.basic_structures import Vec, CxVec, IntVec, Logger
from GridCalEngine.Simulations.OPF.NumericalMethods.ac_opf_derivatives import (x2var, var2x, eval_f,
@@ -252,9 +252,9 @@ def compute_analytic_structures(x, mu, lmbda, compute_jac: bool, compute_hess: b
rates=rates, il=il, ig=ig, tanmax=tanmax, ctQ=ctQ, acopf_mode=acopf_mode)
fx, Gx, Hx, fxx, Gxx, Hxx = jacobians_and_hessians(x=x, c1=c1, c2=c2, c_s=c_s, c_v=c_v, Cg=Cg, Cf=Cf, Ct=Ct, Yf=Yf,
- Yt=Yt, Ybus=Ybus, Sbase=Sbase, il=il, ig=ig, slack=slack, pq=pq,
- pv=pv, tanmax=tanmax, alltapm=alltapm, alltapt=alltapt, fdc=fdc,
- tdc=tdc, k_m=k_m, k_tau=k_tau, mu=mu, lmbda=lmbda, R=R, X=X,
+ Yt=Yt, Ybus=Ybus, Sbase=Sbase, mon_br_idx=il, ig=ig, slack=slack, pq=pq,
+ pv=pv, tanmax=tanmax, alltapm=alltapm, alltapt=alltapt, F_hvdc=fdc,
+ T_hvdc=tdc, k_m=k_m, k_tau=k_tau, mu=mu, lmbda=lmbda, R=R, X=X,
F=from_idx, T=to_idx, ctQ=ctQ, acopf_mode=acopf_mode,
compute_jac=compute_jac, compute_hess=compute_hess)
@@ -577,7 +577,7 @@ def ac_optimal_power_flow(nc: NumericalCircuit,
# Number of inequalities: Line ratings, max and min angle of buses, voltage module range and
- if pf_options.control_Q == ReactivePowerControlMode.NoControl:
+ if not pf_options.control_Q:
NI = 2 * n_br_mon + 2 * npq + 4 * n_gen_disp + 2 * ntapm + 2 * ntapt + 2 * n_disp_hvdc + nsl # No Reactive constraint (power curve)
else:
NI = 2 * n_br_mon + 2 * npq + 5 * n_gen_disp + 2 * ntapm + 2 * ntapt + 2 * n_disp_hvdc + nsl
diff --git a/src/trunk/acopf/acopf_Q_disp.py b/src/trunk/acopf/acopf_Q_disp.py
index 71bc0a34c..a92e08d67 100644
--- a/src/trunk/acopf/acopf_Q_disp.py
+++ b/src/trunk/acopf/acopf_Q_disp.py
@@ -38,11 +38,11 @@ def modify_grid(grid):
def run_acopf(grid):
- pf_options = gce.PowerFlowOptions(control_q=gce.ReactivePowerControlMode.NoControl,
+ pf_options = gce.PowerFlowOptions(control_q=False,
ignore_single_node_islands=True,
max_iter=50,
max_outer_loop_iter=1000,
- q_steepness_factor=1.0,
+ trust_radius=1.0,
tolerance=1e-05)
opf_options = gce.OptimalPowerFlowOptions(ips_method=gce.SolverType.NR, ips_tolerance=1e-4,
diff --git a/src/trunk/acopf/acopf_admittance_tap_derivation.py b/src/trunk/acopf/acopf_admittance_tap_derivation.py
index 57a4a67b3..7ad27b8ac 100644
--- a/src/trunk/acopf/acopf_admittance_tap_derivation.py
+++ b/src/trunk/acopf/acopf_admittance_tap_derivation.py
@@ -1,12 +1,28 @@
-import os
+# GridCal
+# Copyright (C) 2015 - 2024 Santiago PeƱate Vera
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import GridCalEngine.api as gce
-from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
-from GridCalEngine.Simulations.OPF.NumericalMethods.ac_opf import run_nonlinear_opf, ac_optimal_power_flow
-from GridCalEngine.enumerations import TransformerControlType
-from scipy.sparse import csc_matrix as csc
+from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at, NumericalCircuit
+from GridCalEngine.Simulations.OPF.NumericalMethods.ac_opf import run_nonlinear_opf
+from GridCalEngine.Simulations.OPF.opf_options import OptimalPowerFlowOptions
+from GridCalEngine.enumerations import TapPhaseControl
from scipy import sparse as sp
import numpy as np
+
def example_3bus_acopf():
"""
@@ -32,11 +48,11 @@ def example_3bus_acopf():
grid.add_generator(b1, gce.Generator('G1', vset=1.00, Cost=1.0, Cost2=2.0))
grid.add_generator(b2, gce.Generator('G2', P=10, vset=0.995, Cost=1.0, Cost2=3.0))
- tr1 = gce.Transformer2W(b1, b2, 'Trafo1', control_mode=TransformerControlType.Pf,
+ tr1 = gce.Transformer2W(b1, b2, 'Trafo1', tap_phase_control_mode=TapPhaseControl.Pf,
tap_module=1.1, tap_phase=0.02, r=0.001, x=0.05)
grid.add_transformer2w(tr1)
- tr2 = gce.Transformer2W(b3, b1, 'Trafo1', control_mode=TransformerControlType.PtQt,
+ tr2 = gce.Transformer2W(b3, b1, 'Trafo1', tap_phase_control_mode=TapPhaseControl.Pf,
tap_module=1.05, tap_phase=-0.02, r=0.001, x=0.05)
grid.add_transformer2w(tr2)
@@ -56,12 +72,21 @@ def example_3bus_acopf():
# print('\n\n', grid.name)
# print('\tConv:\n', power_flow.results.get_bus_df())
# print('\tConv:\n', power_flow.results.get_branch_df())
+ opf_options = OptimalPowerFlowOptions()
pf_options = gce.PowerFlowOptions(solver_type=gce.SolverType.NR, verbose=3)
- run_nonlinear_opf(grid=grid, pf_options=pf_options, plot_error=True)
+ run_nonlinear_opf(grid=grid,
+ opf_options=opf_options,
+ pf_options=pf_options,
+ plot_error=True)
+
+def compute_analytic_admittances(nc: NumericalCircuit):
+ """
-def compute_analytic_admittances(nc):
+ :param nc:
+ :return:
+ """
k_m = nc.k_m
k_tau = nc.k_tau
k_mtau = nc.k_mtau
@@ -113,42 +138,51 @@ def compute_analytic_admittances(nc):
return dYbusdm, dYfdm, dYtdm, dYbusdt, dYfdt, dYtdt
-def compute_finitediff_admittances(nc, tol=1e-5):
+def compute_finitediff_admittances(nc: NumericalCircuit, tol=1e-5):
+ """
- k_m = nc.k_m
- k_tau = nc.k_tau
+ :param nc: NumericalCircuit
+ :param tol: tolerance
+ :return:
+ """
+ indices = nc.get_simulation_indices()
+ k_m = indices.k_m
+ k_tau = indices.k_tau
- Ybus0 = nc.Ybus
- Yf0 = nc.Yf
- Yt0 = nc.Yt
+ # base values
+ adm0 = nc.get_admittance_matrices()
+ # Modify tap modules
nc.branch_data.tap_module[k_m] += tol
- nc.reset_calculations()
-
- dYfdm = (nc.Yf - Yf0) / tol
- dYtdm = (nc.Yt - Yt0) / tol
- dYbusdm = (nc.Ybus - Ybus0) / tol
-
+ adm1 = nc.get_admittance_matrices()
nc.branch_data.tap_module[k_m] -= tol
- nc.branch_data.tap_angle[k_tau] += tol
- nc.reset_calculations()
-
- dYfdt = (nc.Yf - Yf0) / tol
- dYtdt = (nc.Yt - Yt0) / tol
- dYbusdt = (nc.Ybus - Ybus0) / tol
+ dYf_dm = (adm1.Yf - adm0.Yf) / tol
+ dYt_dm = (adm1.Yt - adm0.Yt) / tol
+ dY_dm = (adm1.Ybus - adm0.Ybus) / tol
+ # modify tap angles
+ nc.branch_data.tap_angle[k_tau] += tol
+ adm2 = nc.get_admittance_matrices()
nc.branch_data.tap_angle[k_tau] -= tol
- nc.reset_calculations()
- return dYbusdm, dYfdm, dYtdm, dYbusdt, dYfdt, dYtdt
+ dYf_dt = (adm2.Yf - adm0.Yf) / tol
+ dYt_dt = (adm2.Yt - adm0.Yt) / tol
+ dY_dt = (adm2.Ybus - adm0.Ybus) / tol
+ return dY_dm, dYf_dm, dYt_dm, dY_dt, dYf_dt, dYt_dt
-def compute_analytic_admittances_2dev(nc):
- k_m = nc.k_m
- k_tau = nc.k_tau
- k_mtau = nc.k_mtau
+def compute_analytic_admittances_2dev(nc: NumericalCircuit):
+ """
+
+ :param nc:
+ :return:
+ """
+ indices = nc.get_simulation_indices()
+ k_m = indices.k_m
+ k_tau = indices.k_tau
+ k_mtau = indices.k_mtau
tapm = nc.branch_data.tap_module
tapt = nc.branch_data.tap_angle
@@ -162,104 +196,109 @@ def compute_analytic_admittances_2dev(nc):
tau = tapt[k_m]
ylin = ys[k_m]
- dYffdmdm = np.zeros(len(tapm), dtype=complex)
- dYftdmdm = np.zeros(len(tapm), dtype=complex)
- dYtfdmdm = np.zeros(len(tapm), dtype=complex)
- dYttdmdm = np.zeros(len(tapm), dtype=complex)
+ # primitived
+ dyff_dmdm = np.zeros(nc.nbr, dtype=complex)
+ dyft_dmdm = np.zeros(nc.nbr, dtype=complex)
+ dytf_dmdm = np.zeros(nc.nbr, dtype=complex)
+ dytt_dmdm = np.zeros(nc.nbr, dtype=complex)
- dYffdmdm[k_m] = 6 * ylin / (mp * mp * mp * mp)
- dYftdmdm[k_m] = -2 * ylin / (mp * mp * mp * np.exp(-1.0j * tau))
- dYtfdmdm[k_m] = -2 * ylin / (mp * mp * mp * np.exp(1.0j * tau))
+ dyff_dmdm[k_m] = 6 * ylin / (mp * mp * mp * mp)
+ dyft_dmdm[k_m] = -2 * ylin / (mp * mp * mp * np.exp(-1.0j * tau))
+ dytf_dmdm[k_m] = -2 * ylin / (mp * mp * mp * np.exp(1.0j * tau))
- dYfdmdm = (sp.diags(dYffdmdm) * Cf + sp.diags(dYftdmdm) * Ct)
- dYtdmdm = (sp.diags(dYtfdmdm) * Cf + sp.diags(dYttdmdm) * Ct)
+ dYf_dmdm = (sp.diags(dyff_dmdm) * Cf + sp.diags(dyft_dmdm) * Ct)
+ dYt_dmdm = (sp.diags(dytf_dmdm) * Cf + sp.diags(dytt_dmdm) * Ct)
- dYbusdmdm = (Cf.T * dYfdmdm + Ct.T * dYtdmdm)
+ dY_dmdm = (Cf.T * dYf_dmdm + Ct.T * dYt_dmdm)
# Second partial derivative with respect to tap angle
mp = tapm[k_tau]
tau = tapt[k_tau]
ylin = ys[k_tau]
- dYffdtdt = np.zeros(len(tapm), dtype=complex)
- dYftdtdt = np.zeros(len(tapm), dtype=complex)
- dYtfdtdt = np.zeros(len(tapm), dtype=complex)
- dYttdtdt = np.zeros(len(tapm), dtype=complex)
+ # primitives
+ dyff_dtdt = np.zeros(nc.nbr, dtype=complex)
+ dyft_dtdt = np.zeros(nc.nbr, dtype=complex)
+ dytf_dtdt = np.zeros(nc.nbr, dtype=complex)
+ dytt_dtdt = np.zeros(nc.nbr, dtype=complex)
- dYftdtdt[k_tau] = ylin / (mp * np.exp(-1.0j * tau))
- dYtfdtdt[k_tau] = ylin / (mp * np.exp(1.0j * tau))
+ dyft_dtdt[k_tau] = ylin / (mp * np.exp(-1.0j * tau))
+ dytf_dtdt[k_tau] = ylin / (mp * np.exp(1.0j * tau))
- dYfdtdt = sp.diags(dYffdtdt) * Cf + sp.diags(dYftdtdt) * Ct
- dYtdtdt = sp.diags(dYtfdtdt) * Cf + sp.diags(dYttdtdt) * Ct
+ dYf_dtdt = sp.diags(dyff_dtdt) * Cf + sp.diags(dyft_dtdt) * Ct
+ dYt_dtdt = sp.diags(dytf_dtdt) * Cf + sp.diags(dytt_dtdt) * Ct
- dYbusdtdt = Cf.T * dYfdtdt + Ct.T * dYtdtdt
+ dY_dtdt = Cf.T * dYf_dtdt + Ct.T * dYt_dtdt
# Second partial derivative with respect to both tap module and angle
mp = tapm[k_mtau]
tau = tapt[k_mtau]
ylin = ys[k_mtau]
- dYffdmdt = np.zeros(len(tapm), dtype=complex)
- dYftdmdt = np.zeros(len(tapm), dtype=complex)
- dYtfdmdt = np.zeros(len(tapm), dtype=complex)
- dYttdmdt = np.zeros(len(tapm), dtype=complex)
+ # primitives
+ dyffdmdt = np.zeros(nc.nbr, dtype=complex)
+ dyft_dmdt = np.zeros(nc.nbr, dtype=complex)
+ dytf_dmdt = np.zeros(nc.nbr, dtype=complex)
+ dyttdmdt = np.zeros(nc.nbr, dtype=complex)
- dYftdmdt[k_mtau] = 1j * ylin / (mp * mp * np.exp(-1.0j * tau))
- dYtfdmdt[k_mtau] = -1j * ylin / (mp * mp * np.exp(1.0j * tau))
+ dyft_dmdt[k_mtau] = 1j * ylin / (mp * mp * np.exp(-1.0j * tau))
+ dytf_dmdt[k_mtau] = -1j * ylin / (mp * mp * np.exp(1.0j * tau))
- dYfdmdt = sp.diags(dYffdmdt) * Cf + sp.diags(dYftdmdt) * Ct
- dYtdmdt = sp.diags(dYtfdmdt) * Cf + sp.diags(dYttdmdt) * Ct
+ dYf_dmdt = sp.diags(dyffdmdt) * Cf + sp.diags(dyft_dmdt) * Ct
+ dYt_dmdt = sp.diags(dytf_dmdt) * Cf + sp.diags(dyttdmdt) * Ct
- dYbusdmdt = Cf.T * dYfdmdt + Ct.T * dYtdmdt
+ dY_dmdt = Cf.T * dYf_dmdt + Ct.T * dYt_dmdt
- dYfdtdm = dYfdmdt.copy()
- dYtdtdm = dYtdmdt.copy()
- dYbusdtdm = dYbusdmdt.copy()
+ dYf_dtdm = dYf_dmdt.copy()
+ dYt_dtdm = dYt_dmdt.copy()
+ dY_dtdm = dY_dmdt.copy()
- return (dYbusdmdm, dYfdmdm, dYtdmdm, dYbusdmdt, dYfdmdt, dYtdmdt,
- dYbusdtdm, dYfdtdm, dYtdtdm, dYbusdtdt, dYfdtdt, dYtdtdt)
+ return (dY_dmdm, dYf_dmdm, dYt_dmdm, dY_dmdt, dYf_dmdt, dYt_dmdt,
+ dY_dtdm, dYf_dtdm, dYt_dtdm, dY_dtdt, dYf_dtdt, dYt_dtdt)
-def compute_finitediff_admittances_2dev(nc, tol=1e-5):
+def compute_finitediff_admittances_2dev(nc: NumericalCircuit, tol=1e-5):
+ """
- k_m = nc.k_m
- k_tau = nc.k_tau
+ :param nc:
+ :param tol:
+ :return:
+ """
+ indices = nc.get_simulation_indices()
+ k_m = indices.k_m
+ k_tau = indices.k_tau
- dYb0dm, dYf0dm, dYt0dm, dYb0dt, dYf0dt, dYt0dt = compute_finitediff_admittances(nc)
+ # Refference
+ dY0_dm, dYf0_dm, dYt0_dm, dY0_dt, dYf0_dt, dYt0_dt = compute_finitediff_admittances(nc)
+ # Modify the tap module
nc.branch_data.tap_module[k_m] += tol
- nc.reset_calculations()
-
- dYbdm, dYfdm, dYtdm, dYbdt, dYfdt, dYtdt = compute_finitediff_admittances(nc)
-
- dYfdmdm = (dYfdm - dYf0dm) / tol
- dYtdmdm = (dYtdm - dYt0dm) / tol
- dYbusdmdm = (dYbdm - dYb0dm) / tol
-
- dYfdtdm = (dYfdt - dYf0dt) / tol
- dYtdtdm = (dYtdt - dYt0dt) / tol
- dYbusdtdm = (dYbdt - dYb0dt) / tol
-
+ dY_dm, dYf_dm, dYt_dm, dY_dt, dYf_dt, dYt_dt = compute_finitediff_admittances(nc)
nc.branch_data.tap_module[k_m] -= tol
- nc.branch_data.tap_angle[k_tau] += tol
- nc.reset_calculations()
+ dYf_dmdm = (dYf_dm - dYf0_dm) / tol
+ dYt_dmdm = (dYt_dm - dYt0_dm) / tol
+ dY_dmdm = (dY_dm - dY0_dm) / tol
- dYbdm, dYfdm, dYtdm, dYbdt, dYfdt, dYtdt = compute_finitediff_admittances(nc)
+ dYf_dtdm = (dYf_dt - dYf0_dt) / tol
+ dYt_dtdm = (dYt_dt - dYt0_dt) / tol
+ dY_dtdm = (dY_dt - dY0_dt) / tol
- dYfdmdt = (dYfdm - dYf0dm) / tol
- dYtdmdt = (dYtdm - dYt0dm) / tol
- dYbusdmdt = (dYbdm - dYb0dm) / tol
+ # Modify the tap angle
+ nc.branch_data.tap_angle[k_tau] += tol
+ dY_dm, dYf_dm, dYt_dm, dY_dt, dYf_dt, dYt_dt = compute_finitediff_admittances(nc)
+ nc.branch_data.tap_angle[k_tau] -= tol
- dYfdtdt = (dYfdt - dYf0dt) / tol
- dYtdtdt = (dYtdt - dYt0dt) / tol
- dYbusdtdt = (dYbdt - dYb0dt) / tol
+ dYf_dmdt = (dYf_dm - dYf0_dm) / tol
+ dYt_dmdt = (dYt_dm - dYt0_dm) / tol
+ dY_dmdt = (dY_dm - dY0_dm) / tol
- nc.branch_data.tap_angle[k_tau] -= tol
- nc.reset_calculations()
+ dYf_dtdt = (dYf_dt - dYf0_dt) / tol
+ dYt_dtdt = (dYt_dt - dYt0_dt) / tol
+ dY_dtdt = (dY_dt - dY0_dt) / tol
- return (dYbusdmdm, dYfdmdm, dYtdmdm, dYbusdmdt, dYfdmdt, dYtdmdt,
- dYbusdtdm, dYfdtdm, dYtdtdm, dYbusdtdt, dYfdtdt, dYtdtdt)
+ return (dY_dmdm, dYf_dmdm, dYt_dmdm, dY_dmdt, dYf_dmdt, dYt_dmdt,
+ dY_dtdm, dYf_dtdm, dYt_dtdm, dY_dtdt, dYf_dtdt, dYt_dtdt)
if __name__ == '__main__':
diff --git a/src/trunk/acopf/acopf_run.py b/src/trunk/acopf/acopf_run.py
index 724f4dfa7..807bb0b18 100644
--- a/src/trunk/acopf/acopf_run.py
+++ b/src/trunk/acopf/acopf_run.py
@@ -3,7 +3,7 @@
from GridCalEngine.DataStructures.numerical_circuit import compile_numerical_circuit_at
from GridCalEngine.Simulations.OPF.NumericalMethods.ac_opf import run_nonlinear_opf, ac_optimal_power_flow
from GridCalEngine.Simulations.OPF.linear_opf_ts import run_linear_opf_ts
-from GridCalEngine.enumerations import TransformerControlType, ReactivePowerControlMode
+from GridCalEngine.enumerations import TransformerControlType
from GridCalEngine.Simulations.NodalCapacity.nodal_capacity_ts_driver import NodalCapacityTimeSeriesDriver
from GridCalEngine.Simulations.NodalCapacity.nodal_capacity_options import NodalCapacityOptions
import numpy as np
@@ -303,7 +303,7 @@ def case14():
for ll in range(len(grid.lines)):
grid.lines[ll].monitor_loading = True
- pf_options = gce.PowerFlowOptions(solver_type=gce.SolverType.NR, control_q=ReactivePowerControlMode.NoControl)
+ pf_options = gce.PowerFlowOptions(solver_type=gce.SolverType.NR, control_q=False)
opf_options = gce.OptimalPowerFlowOptions(solver=gce.SolverType.NONLINEAR_OPF, acopf_mode=gce.AcOpfMode.ACOPFslacks,
ips_tolerance=1e-6, ips_iterations=50, verbose=1)
res = run_nonlinear_opf(grid=grid, pf_options=pf_options, opf_options=opf_options, plot_error=True, pf_init=True)
diff --git a/src/trunk/acopf/jacobian.py b/src/trunk/acopf/jacobian.py
index e917a0f48..df6ceb344 100644
--- a/src/trunk/acopf/jacobian.py
+++ b/src/trunk/acopf/jacobian.py
@@ -2,7 +2,7 @@
import scipy.sparse as sp
from math import sin, cos
import GridCalEngine.api as gc
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobian
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobian
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions import compute_power
diff --git a/src/trunk/code_generation/property_maker.py b/src/trunk/code_generation/property_maker.py
index 5f7bec2cd..26ae55842 100644
--- a/src/trunk/code_generation/property_maker.py
+++ b/src/trunk/code_generation/property_maker.py
@@ -1,9 +1,9 @@
lst = [
"k_pf_tau",
"k_qf_m",
- "k_zero_beq",
+ "k_qf_beq",
"k_vf_beq",
- "k_vt_m",
+ "k_v_m",
"k_qt_m",
"k_pf_dp",
"k_m",
diff --git a/src/tests/download_stats.py b/src/trunk/download_stats.py
similarity index 82%
rename from src/tests/download_stats.py
rename to src/trunk/download_stats.py
index e5e2b80b8..73106bd05 100644
--- a/src/tests/download_stats.py
+++ b/src/trunk/download_stats.py
@@ -29,7 +29,10 @@
locale.setlocale(locale.LC_ALL, '')
-class PyPIDownloadAggregator(object):
+class PyPIDownloadAggregator:
+ """
+ PyPIDownloadAggregator
+ """
def __init__(self, package_name, include_hidden=True):
self.package_name = package_name
@@ -76,26 +79,33 @@ def releases(self):
return result
+ def init_downloads(self):
+ """
+
+ :return:
+ """
+ for release in self.releases:
+ urls = self.proxy.release_urls(self.package_name, release)
+ self._downloads[release] = 0
+ for url in urls:
+ # upload times
+ uptime = url['upload_time']
+ if self.first_upload is None or uptime < self.first_upload:
+ self.first_upload = uptime
+ self.first_upload_rel = release
+
+ if self.last_upload is None or uptime > self.last_upload:
+ self.last_upload = uptime
+ self.last_upload_rel = release
+
+ self._downloads[release] += url['downloads']
+
@property
def downloads(self, force=False):
"""Calculate the total number of downloads for the package"""
if len(self._downloads) == 0 or force:
- for release in self.releases:
- urls = self.proxy.release_urls(self.package_name, release)
- self._downloads[release] = 0
- for url in urls:
- # upload times
- uptime = url['upload_time']
- if self.first_upload is None or uptime < self.first_upload:
- self.first_upload = uptime
- self.first_upload_rel = release
-
- if self.last_upload is None or uptime > self.last_upload:
- self.last_upload = uptime
- self.last_upload_rel = release
-
- self._downloads[release] += url['downloads']
+ self.init_downloads()
return self._downloads
@@ -114,7 +124,7 @@ def min(self):
def stats(self):
"""Prints a nicely formatted list of statistics about the package"""
- self.downloads # explicitly call, so we have first/last upload data
+ self.init_downloads()
fmt = locale.nl_langinfo(locale.D_T_FMT)
sep = lambda s: locale.format_string('%d', s, 3)
val = lambda dt: dt and dt.strftime(fmt) or '--'
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/levenberg_marquardt.py b/src/trunk/old_pf_implementations/levenberg_marquardt.py
similarity index 94%
rename from src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/levenberg_marquardt.py
rename to src/trunk/old_pf_implementations/levenberg_marquardt.py
index 1258f5806..ae5d41829 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/levenberg_marquardt.py
+++ b/src/trunk/old_pf_implementations/levenberg_marquardt.py
@@ -20,10 +20,9 @@
import numpy as np
import scipy.sparse as sp
from GridCalEngine.Utils.NumericalMethods.sparse_solve import get_sparse_type, get_linear_solver
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobianVc
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobianVc
import GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions as cf
from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
-from GridCalEngine.enumerations import ReactivePowerControlMode
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import control_q_inside_method
from GridCalEngine.basic_structures import Logger
import GridCalEngine.Utils.Sparse.csc2 as csc
@@ -35,8 +34,7 @@
def levenberg_marquardt_pf(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=50,
- control_q=ReactivePowerControlMode.NoControl,
- verbose=False, logger: Logger = None) -> NumericPowerFlowResults:
+ control_q=False, verbose=False, logger: Logger = None) -> NumericPowerFlowResults:
"""
Solves the power flow problem by the Levenberg-Marquardt power flow algorithm.
It is usually better than Newton-Raphson, but it takes an order of magnitude more time to converge.
@@ -190,7 +188,7 @@ def levenberg_marquardt_pf(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax,
# it is only worth checking Q limits with a low error
# since with higher errors, the Q values may be far from realistic
# finally, the Q control only makes sense if there are pv nodes
- if control_q != ReactivePowerControlMode.NoControl and normF < 1e-2 and (len(pv) + len(p)) > 0:
+ if control_q and normF < 1e-2 and (len(pv) + len(p)) > 0:
# check and adjust the reactive power
# this function passes pv buses to pq when the limits are violated,
@@ -227,7 +225,7 @@ def levenberg_marquardt_pf(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax,
elapsed = end - start
return NumericPowerFlowResults(V=V, converged=converged, norm_f=normF,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson.py b/src/trunk/old_pf_implementations/newton_raphson.py
similarity index 84%
rename from src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson.py
rename to src/trunk/old_pf_implementations/newton_raphson.py
index 7187bf7ee..664acfff1 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson.py
+++ b/src/trunk/old_pf_implementations/newton_raphson.py
@@ -19,10 +19,9 @@
import scipy
import numpy as np
from GridCalEngine.Utils.NumericalMethods.sparse_solve import get_sparse_type, get_linear_solver
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobian, AC_jacobianVc
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobianVc
import GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions as cf
from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
-from GridCalEngine.enumerations import ReactivePowerControlMode
from GridCalEngine.Simulations.PowerFlow.NumericalMethods.discrete_controls import control_q_inside_method
from GridCalEngine.basic_structures import Logger
from GridCalEngine.Utils.Sparse.csc2 import spsolve_csc
@@ -33,7 +32,7 @@
def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15, mu_0=1.0,
- acceleration_parameter=0.05, control_q=ReactivePowerControlMode.NoControl,
+ acceleration_parameter=0.05, control_q=False,
verbose=False, logger: Logger = None) -> NumericPowerFlowResults:
"""
Solves the power flow using a full Newton's method with backtracking correction.
@@ -73,17 +72,17 @@ def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
pv = pv_.copy()
pqv = pqv_.copy()
p = p_.copy()
- blck1_idx = np.r_[pv, pq, p, pqv]
- blck2_idx = np.r_[pq, p]
- blck3_idx = np.r_[pq, pqv]
- n_block1 = len(blck1_idx)
+ idx_dtheta = np.r_[pv, pq, p, pqv]
+ idx_dVm = np.r_[pq, p]
+ idx_dQ = np.r_[pq, pqv]
+ n_idx_dtheta = len(idx_dtheta)
- if n_block1 > 0:
+ if n_idx_dtheta > 0:
# evaluate F(x0)
Sbus = cf.compute_zip_power(S0, I0, Y0, Vm)
Scalc = cf.compute_power(Ybus, V)
- f = cf.compute_fx(Scalc, Sbus, blck1_idx, blck3_idx)
+ f = cf.compute_fx(Scalc, Sbus, idx_dtheta, idx_dQ)
norm_f = cf.compute_fx_error(f)
converged = norm_f < tol
@@ -97,20 +96,20 @@ def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
iteration += 1
# evaluate Jacobian
- J = AC_jacobianVc(Ybus, V, blck1_idx, blck2_idx, blck3_idx)
+ J = AC_jacobianVc(Ybus, V, idx_dtheta, idx_dVm, idx_dQ)
# compute update step
try:
# dx = linear_solver(J, f)
- dx = spsolve_csc(J, f)
+ dx, ok = spsolve_csc(J, f)
- if np.isnan(dx).any():
+ if not ok:
end = time.time()
elapsed = end - start
logger.add_error('NR Singular matrix @iter:'.format(iteration))
return NumericPowerFlowResults(V=V0, converged=converged, norm_f=norm_f,
- Scalc=S0, ma=None, theta=None, Beq=None,
+ Scalc=S0, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iteration, elapsed=elapsed)
except RuntimeError:
@@ -120,7 +119,7 @@ def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
logger.add_error('NR Singular matrix @iter:'.format(iteration))
return NumericPowerFlowResults(V=V0, converged=converged, norm_f=norm_f,
- Scalc=S0, ma=None, theta=None, Beq=None,
+ Scalc=S0, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iteration, elapsed=elapsed)
@@ -135,8 +134,8 @@ def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
logger.add_debug('Va:\n', Va)
# reassign the solution vector
- dVa[blck1_idx] = dx[:n_block1]
- dVm[blck2_idx] = dx[n_block1:]
+ dVa[idx_dtheta] = dx[:n_idx_dtheta]
+ dVm[idx_dVm] = dx[n_idx_dtheta:]
# set the values and correct with an adaptive mu if needed
mu = mu_0 # ideally 1.0
@@ -153,7 +152,7 @@ def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
# compute the mismatch function f(x_new)
Sbus = cf.compute_zip_power(S0, I0, Y0, Vm2)
Scalc = cf.compute_power(Ybus, V2)
- f = cf.compute_fx(Scalc, Sbus, blck1_idx, blck3_idx)
+ f = cf.compute_fx(Scalc, Sbus, idx_dtheta, idx_dQ)
norm_f_new = cf.compute_fx_error(f)
# change mu for the next iteration
@@ -184,7 +183,7 @@ def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
end = time.time()
elapsed = end - start
return NumericPowerFlowResults(V=V, converged=converged, norm_f=norm_f,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iteration, elapsed=elapsed)
@@ -192,7 +191,7 @@ def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
# it is only worth checking Q limits with a low error
# since with higher errors, the Q values may be far from realistic
# finally, the Q control only makes sense if there are pv nodes
- if control_q != ReactivePowerControlMode.NoControl and norm_f < 1e-2 and (len(pv) + len(p)) > 0:
+ if control_q and norm_f < 1e-2 and (len(pv) + len(p)) > 0:
# check and adjust the reactive power
# this function passes pv buses to pq when the limits are violated,
@@ -201,14 +200,14 @@ def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
if len(changed) > 0:
# adjust internal variables to the new pq|pv values
- blck1_idx = np.r_[pv, pq, p, pqv]
- blck2_idx = np.r_[pq, p]
- blck3_idx = np.r_[pq, pqv]
- n_block1 = len(blck1_idx)
+ idx_dtheta = np.r_[pv, pq, p, pqv]
+ idx_dVm = np.r_[pq, p]
+ idx_dQ = np.r_[pq, pqv]
+ n_idx_dtheta = len(idx_dtheta)
# recompute the error based on the new Scalc and S0
Sbus = cf.compute_zip_power(S0, I0, Y0, Vm)
- f = cf.compute_fx(Scalc, Sbus, blck1_idx, blck3_idx)
+ f = cf.compute_fx(Scalc, Sbus, idx_dtheta, idx_dQ)
norm_f = np.linalg.norm(f, np.inf)
# determine the convergence condition
@@ -223,6 +222,6 @@ def NR_LS(Ybus, S0, V0, I0, Y0, pv_, pq_, pqv_, p_, Qmin, Qmax, tol, max_it=15,
elapsed = end - start
return NumericPowerFlowResults(V=V, converged=converged, norm_f=norm_f,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iteration, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_decoupled.py b/src/trunk/old_pf_implementations/newton_raphson_decoupled.py
similarity index 98%
rename from src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_decoupled.py
rename to src/trunk/old_pf_implementations/newton_raphson_decoupled.py
index 5513bb408..8c5bad907 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_decoupled.py
+++ b/src/trunk/old_pf_implementations/newton_raphson_decoupled.py
@@ -196,7 +196,7 @@ def NRD_LS(Ybus, S0, V0, I0, Y0, pv, pq, tol, max_it=15,
# return NumericPowerFlowResults(V, converged, norm_f, Scalc, None, None, None, None, None, None, iter_, elapsed)
return NumericPowerFlowResults(V=V, converged=converged, norm_f=norm_f,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_, elapsed=elapsed)
diff --git a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_ode.py b/src/trunk/old_pf_implementations/newton_raphson_ode.py
similarity index 96%
rename from src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_ode.py
rename to src/trunk/old_pf_implementations/newton_raphson_ode.py
index 46a543b3f..06f4e7392 100644
--- a/src/GridCalEngine/Simulations/PowerFlow/NumericalMethods/newton_raphson_ode.py
+++ b/src/trunk/old_pf_implementations/newton_raphson_ode.py
@@ -20,7 +20,7 @@
import numpy as np
from GridCalEngine.Utils.NumericalMethods.sparse_solve import get_sparse_type, get_linear_solver
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobian
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobian
from GridCalEngine.Simulations.PowerFlow.power_flow_results import NumericPowerFlowResults
from GridCalEngine.Utils.Sparse.csc2 import spsolve_csc
@@ -86,7 +86,8 @@ def compute_fx(x, Ybus, S, I, pq, pv, pvpq, j1, j2, j3, j4, j5, j6, Va, Vm):
gx = AC_jacobian(Ybus, V, pvpq, pq)
# return the increment of x
- return spsolve_csc(gx, g)
+ dx, ok = spsolve_csc(gx, g)
+ return dx
def ContinuousNR(Ybus, Sbus, V0, Ibus, pv, pq, tol, max_it=15) -> NumericPowerFlowResults:
@@ -194,6 +195,6 @@ def ContinuousNR(Ybus, Sbus, V0, Ibus, pv, pq, tol, max_it=15) -> NumericPowerFl
# return NumericPowerFlowResults(V, converged, normF, Scalc, None, None, None, None, None, None, iter_, elapsed)
return NumericPowerFlowResults(V=V, converged=converged, norm_f=normF,
- Scalc=Scalc, ma=None, theta=None, Beq=None,
+ Scalc=Scalc, m=None, tau=None, Beq=None,
Ybus=None, Yf=None, Yt=None,
iterations=iter_, elapsed=elapsed)
diff --git a/src/trunk/pf/power_flow_research.py b/src/trunk/pf/power_flow_research.py
index 643710390..cb1f6b4ef 100644
--- a/src/trunk/pf/power_flow_research.py
+++ b/src/trunk/pf/power_flow_research.py
@@ -16,7 +16,6 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from typing import Tuple
import matplotlib.pyplot as plt
-import numpy as np
import sys
sys.path.append('C:/Users/raiya/Documents/8. eRoots/thesis/code/GridCal/src')
import GridCalEngine.api as gce
@@ -24,21 +23,14 @@
import numba as nb
from GridCalEngine.basic_structures import Vec, CscMat, CxVec, IntVec
import GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions as cf
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobian
-from GridCalEngine.Utils.NumericalMethods.common import ConvexFunctionResult, ConvexMethodResult
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobian
from GridCalEngine.Utils.NumericalMethods.newton_raphson import newton_raphson
-from GridCalEngine.Utils.NumericalMethods.powell import powell_dog_leg
-from GridCalEngine.Utils.NumericalMethods.levenberg_marquadt import levenberg_marquardt
from GridCalEngine.enumerations import SolverType
-from sympy import symbols, diff, exp, re, im
-import time
import numpy as np
-from typing import Callable, Any
from GridCalEngine.basic_structures import Vec
from GridCalEngine.Utils.NumericalMethods.common import (ConvexMethodResult, ConvexFunctionResult,
check_function_and_args)
from GridCalEngine.Utils.NumericalMethods.sparse_solve import get_linear_solver
-from GridCalEngine.basic_structures import Logger
from GridCalEngine.Devices.Branches import VSC, Transformer2W
from scipy.sparse import csc_matrix
from typing import Tuple, Union
@@ -3041,7 +3033,6 @@ def run_pf_ver2(grid: gce.MultiCircuit, pf_options: gce.PowerFlowOptions, debug
if __name__ == '__main__':
- import os
# grid_ = HelperFunctions.linn5bus_example() #converges true, and same as traditional powerflow
# grid_ = HelperFunctions.linn5bus_example2() #converges true
grid_ = HelperFunctions.ieee14_example() #converges true, and same as traditional powerflow
diff --git a/src/trunk/pf/power_flow_research_hvdc.py b/src/trunk/pf/power_flow_research_hvdc.py
index 67712fe39..68cb18f56 100644
--- a/src/trunk/pf/power_flow_research_hvdc.py
+++ b/src/trunk/pf/power_flow_research_hvdc.py
@@ -22,7 +22,7 @@
from GridCalEngine.basic_structures import Vec, CscMat, CxVec, IntVec
import GridCalEngine.Utils.NumericalMethods.autodiff as ad
import GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions as cf
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobian
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobian
from GridCalEngine.Utils.NumericalMethods.common import ConvexFunctionResult, ConvexMethodResult
from GridCalEngine.Utils.NumericalMethods.newton_raphson import newton_raphson
from GridCalEngine.Utils.NumericalMethods.powell import powell_dog_leg
diff --git a/src/trunk/pf/power_flow_research_sinj.py b/src/trunk/pf/power_flow_research_sinj.py
index f52068037..44e6f068a 100644
--- a/src/trunk/pf/power_flow_research_sinj.py
+++ b/src/trunk/pf/power_flow_research_sinj.py
@@ -23,7 +23,7 @@
from GridCalEngine.basic_structures import Vec, CscMat, CxVec, IntVec
import GridCalEngine.Simulations.PowerFlow.NumericalMethods.common_functions as cf
-from GridCalEngine.Simulations.PowerFlow.NumericalMethods.ac_jacobian import AC_jacobian
+from GridCalEngine.Simulations.Derivatives.ac_jacobian import AC_jacobian
from GridCalEngine.Utils.NumericalMethods.common import ConvexFunctionResult, ConvexMethodResult
from GridCalEngine.Utils.NumericalMethods.newton_raphson import newton_raphson
from GridCalEngine.Utils.NumericalMethods.powell import powell_dog_leg
diff --git a/src/trunk/qt_related/multi_select.py b/src/trunk/qt_related/multi_select.py
new file mode 100644
index 000000000..a2500c6de
--- /dev/null
+++ b/src/trunk/qt_related/multi_select.py
@@ -0,0 +1,34 @@
+from PySide6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsRectItem
+from PySide6.QtGui import QPen, QBrush, QColor, QPainter
+from PySide6.QtCore import Qt
+
+
+class MultiSelectScene(QGraphicsScene):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ # Add items with default flags to the scene
+ for i in range(5):
+ item = QGraphicsRectItem(i * 30, i * 30, 50, 50)
+ item.setFlags(QGraphicsRectItem.ItemIsSelectable | QGraphicsRectItem.ItemIsMovable)
+ item.setPen(QPen(Qt.black))
+ item.setBrush(QBrush(QColor(255, 0, 0, 127))) # Semi-transparent red
+ self.addItem(item)
+
+
+class MultiSelectView(QGraphicsView):
+ def __init__(self, scene, parent=None):
+ super().__init__(scene, parent)
+ self.setRenderHint(QPainter.Antialiasing)
+ self.setDragMode(QGraphicsView.DragMode.RubberBandDrag)
+
+
+if __name__ == "__main__":
+ app = QApplication([])
+
+ scene = MultiSelectScene()
+ view = MultiSelectView(scene)
+ view.setWindowTitle("QGraphicsScene Multi-Selection with Default Flags")
+ view.show()
+
+ app.exec()