diff --git a/code/steps/STEPS.depend b/code/steps/STEPS.depend index 131e5501..de155d67 100644 --- a/code/steps/STEPS.depend +++ b/code/steps/STEPS.depend @@ -455,7 +455,7 @@ "header/basic/sparse_matrix_define.h" -1584011626 d:\steps\code\steps\header\toolkit\dynamic_simulator\dynamic_simulator.h +1587544620 d:\steps\code\steps\header\toolkit\dynamic_simulator\dynamic_simulator.h "header/basic/power_mismatch_struct.h" "header/meter/meter.h" "header/network/network_matrix.h" @@ -2334,7 +2334,7 @@ "header/data_imexporter/psse_imexporter.h" "header/data_imexporter/bpa_imexporter.h" -1587542271 d:\steps\code\steps\header\apis\steps_api.h +1587544683 d:\steps\code\steps\header\apis\steps_api.h "header/basic/constants.h" @@ -2364,7 +2364,7 @@ "header/data_imexporter/bpa_imexporter.h" "header/data_imexporter/steps_imexporter.h" -1583938871 source:d:\steps\code\steps\source\apis\steps_api_dynamic_simulation.cpp +1587545465 source:d:\steps\code\steps\source\apis\steps_api_dynamic_simulation.cpp "header/apis/steps_api.h" "header/basic/utility.h" "header/toolkit/cct_searcher/cct_searcher.h" @@ -5717,7 +5717,7 @@ "header/toolkit/contingency_screener/contingency_screener.h" "header/STEPS.h" -1585493309 source:d:\steps\code\steps\source\toolkit\dynamic_simulator\dynamic_simulator.cpp +1587544632 source:d:\steps\code\steps\source\toolkit\dynamic_simulator\dynamic_simulator.cpp "header/toolkit/dynamic_simulator/dynamic_simulator.h" "header/basic/constants.h" "header/basic/utility.h" diff --git a/code/steps/header/apis/steps_api.h b/code/steps/header/apis/steps_api.h index 192443b5..27383d59 100644 --- a/code/steps/header/apis/steps_api.h +++ b/code/steps/header/apis/steps_api.h @@ -366,6 +366,7 @@ EXPORT_STEPS_DLL void api_start_dynamic_simulation(unsigned int toolkit_index=IN EXPORT_STEPS_DLL void api_stop_dynamic_simulation(unsigned int toolkit_index=INDEX_NOT_EXIST); EXPORT_STEPS_DLL void api_run_simulation_to_time(double t_end, unsigned int toolkit_index=INDEX_NOT_EXIST); EXPORT_STEPS_DLL void api_run_a_step(unsigned int toolkit_index=INDEX_NOT_EXIST); +EXPORT_STEPS_DLL bool api_get_system_angular_stable_flag(unsigned int toolkit_index=INDEX_NOT_EXIST); EXPORT_STEPS_DLL void api_set_bus_fault(unsigned int bus, char* fault_type, double fault_G, double fault_B, unsigned int toolkit_index=INDEX_NOT_EXIST); EXPORT_STEPS_DLL void api_clear_bus_fault(unsigned int bus, char* fault_type, unsigned int toolkit_index=INDEX_NOT_EXIST); diff --git a/code/steps/header/toolkit/dynamic_simulator/dynamic_simulator.h b/code/steps/header/toolkit/dynamic_simulator/dynamic_simulator.h index db20bb98..fac6a700 100644 --- a/code/steps/header/toolkit/dynamic_simulator/dynamic_simulator.h +++ b/code/steps/header/toolkit/dynamic_simulator/dynamic_simulator.h @@ -112,6 +112,7 @@ class DYNAMICS_SIMULATOR void update_bus_frequency_blocks_when_applying_event(); void update_equivalent_devices_buffer(); void update_equivalent_devices_output(); + bool get_system_angular_stable_flag() const; public: void enable_relay_action_flag(); private: @@ -290,6 +291,7 @@ class DYNAMICS_SIMULATOR bool flag_rotor_angle_stability_surveillance; double rotor_angle_stability_threshold_in_deg; vector< vector > generators_in_islands; + bool flag_rotor_angle_stable; string output_filename; ofstream csv_output_file, json_output_file, bin_output_file; diff --git a/code/steps/source/apis/steps_api_dynamic_simulation.cpp b/code/steps/source/apis/steps_api_dynamic_simulation.cpp index 157edffd..0d18ee06 100644 --- a/code/steps/source/apis/steps_api_dynamic_simulation.cpp +++ b/code/steps/source/apis/steps_api_dynamic_simulation.cpp @@ -462,6 +462,13 @@ void api_run_a_step(unsigned int toolkit_index) ds.run_a_step(); } +bool api_get_system_angular_stable_flag(unsigned int toolkit_index) +{ + STEPS& toolkit = get_toolkit(toolkit_index); + DYNAMICS_SIMULATOR& ds = toolkit.get_dynamic_simulator(); + return ds.get_system_angular_stable_flag(); +} + void api_set_bus_fault(unsigned int bus, char* fault_type, double fault_G, double fault_B, unsigned int toolkit_index) { STEPS& toolkit = get_toolkit(toolkit_index); diff --git a/code/steps/source/toolkit/dynamic_simulator/dynamic_simulator.cpp b/code/steps/source/toolkit/dynamic_simulator/dynamic_simulator.cpp index c118bc9e..14ed6839 100644 --- a/code/steps/source/toolkit/dynamic_simulator/dynamic_simulator.cpp +++ b/code/steps/source/toolkit/dynamic_simulator/dynamic_simulator.cpp @@ -67,6 +67,7 @@ void DYNAMICS_SIMULATOR::clear() set_rotor_angle_stability_surveillance_flag(false); set_rotor_angle_stability_threshold_in_deg(360.0); generators_in_islands.clear(); + flag_rotor_angle_stable = true; } void DYNAMICS_SIMULATOR::set_dynamic_simulation_time_step_in_s(double delt) @@ -1976,6 +1977,7 @@ void DYNAMICS_SIMULATOR::start() meter_values.resize(meters.size(), 0.0); TIME = -2.0*DELT; + flag_rotor_angle_stable = true; optimize_network_ordering(); @@ -2111,8 +2113,8 @@ void DYNAMICS_SIMULATOR::run_to(double time) run_a_step(); update_generators_in_islands(); - bool stable = is_system_angular_stable(); - if(stable==true) + flag_rotor_angle_stable = is_system_angular_stable(); + if(flag_rotor_angle_stable==true) ; else { @@ -2522,6 +2524,11 @@ void DYNAMICS_SIMULATOR::update_equivalent_devices_output() } } +bool DYNAMICS_SIMULATOR::get_system_angular_stable_flag() const +{ + return flag_rotor_angle_stable; +} + bool DYNAMICS_SIMULATOR::solve_network() { auto clock_start = steady_clock::now(); diff --git a/python/stepspy-current/README.md b/python/stepspy-current/README.md index 4aed900a..daa13966 100644 --- a/python/stepspy-current/README.md +++ b/python/stepspy-current/README.md @@ -23,6 +23,7 @@ STEPS is a simulation toolkit for powerflow and dynamic simulation of large-scal ## Realse Note +- 1.1.0. Apr. 22, 2020. Add new API: get_(lines/transformers/hvdcs)_between_lines(), set_(generator/wt_generator/pv_unit/energy_storage/load/hvdc)_power(), and is_system_angular_stable(). STEPS kernel version should be >=1.3. - 1.0.0. Apr. 22, 2020. Add new API: clear_meters() to clear all meters for dynamic simulation. STEPS kernel version should be >=1.2. - 0.13.0-alpha. Mar. 9, 2020. Add new APIs: change_bus_number() and change_bus_number_with_file(). get_areas(), get_zones(), and get_owners() are marked as deprecated. STEPS kernel version should be >=1.1.1. - 0.12.0. Feb. 8, 2020. Add new APIs: check_dynamic_least_time_constants(). Recover the save_powerflow_data() API of v0.9.0. diff --git a/python/stepspy-current/setup.py b/python/stepspy-current/setup.py index 8ba994c6..90e67b63 100644 --- a/python/stepspy-current/setup.py +++ b/python/stepspy-current/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="stepspy", - version="1.0.0", + version="1.1.0", author="Changgang Li", author_email="lichgang@sdu.edu.cn", description="Python module of Simulation Toolkit for Electrical Power Systems", @@ -15,7 +15,6 @@ packages=setuptools.find_packages(), classifiers=[ "Programming Language :: Python :: 3", - "Programming Language :: C++", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ], diff --git a/python/stepspy-current/stepspy/libsteps/pylibsteps.py b/python/stepspy-current/stepspy/libsteps/pylibsteps.py index 49e1bc9b..4519ae9b 100644 --- a/python/stepspy-current/stepspy/libsteps/pylibsteps.py +++ b/python/stepspy-current/stepspy/libsteps/pylibsteps.py @@ -651,6 +651,8 @@ def load_library(): libsteps.api_run_simulation_to_time.argtypes = (c_double, c_uint) libsteps.api_run_a_step.restype = None libsteps.api_run_a_step.argtypes = (c_uint, ) + libsteps.api_get_system_angular_stable_flag.restype = c_bool + libsteps.api_get_system_angular_stable_flag.argtypes = (c_uint, ) libsteps.api_set_bus_fault.restype = None libsteps.api_set_bus_fault.argtypes = (c_uint, c_char_p, c_double, c_double, c_uint) diff --git a/python/stepspy-current/stepspy/stepspy.py b/python/stepspy-current/stepspy/stepspy.py index 86f69654..efc46e03 100644 --- a/python/stepspy-current/stepspy/stepspy.py +++ b/python/stepspy-current/stepspy/stepspy.py @@ -1902,6 +1902,27 @@ def get_lines_at_bus(self, bus): lines.append((int(ibus), int(jbus), id)) STEPS_LIB.api_goto_next_device(device, self.toolkit_index) return tuple(lines) + + def get_lines_between_buses(self, ibus, jbus): + """ + Get all transmission lines between ibus and jbus. + Args: + (1) ibus: i-side bus number + (2) jbus: j-side bus number + Rets: + (1) Tuple of all transmission lines between given buses. Empty tuple if no transmission lines between given buses. + Example: + get_lines_between_buses(1,2) + """ + lines = self.get_lines_at_bus(ibus) + if len(lines)==0: + return lines + else: + lns = [] + for line in lines: + if jbus in line: + lns.append(line) + return tuple(lns) def get_all_transformers(self): """ @@ -1939,7 +1960,31 @@ def get_transformers_at_bus(self, bus): transformers.append((int(ibus), int(jbus), int(kbus), id)) STEPS_LIB.api_goto_next_device(device, self.toolkit_index) return tuple(transformers) - + + def get_transformers_between_buses(self, ibus, jbus, kbus=0): + """ + Get all transformers between ibus, jbus, and kbus. If kbus=0, two-winding transformers are returned. + Args: + (1) ibus: i-side bus number + (2) jbus: j-side bus number + (3) kbus: k-side bus number, 0 for two-winding transformers + Rets: + (1) Tuple of all transformers between given buses. Empty tuple if no transformers between given buses. + Example: + get_transformers_between_buses(1,2) + get_transformers_between_buses(1,2,0) + get_transformers_between_buses(1,2,3) + """ + transformers = self.get_transformers_at_bus(ibus) + if len(transformers)==0: + return transformers + else: + transes = [] + for trans in transformers: + if jbus in trans and kbus in trans: + transes.append(trans) + return tuple(transes) + def get_all_hvdcs(self): """ Get all HVDC links in the database. @@ -1975,6 +2020,27 @@ def get_hvdcs_at_bus(self, bus): STEPS_LIB.api_goto_next_device(device, self.toolkit_index) return tuple(hvdcs) + def get_hvdcs_between_buses(self, ibus, jbus): + """ + Get all HVDC links between ibus and jbus. + Args: + (1) ibus: i-side bus number + (2) jbus: j-side bus number + Rets: + (1) Tuple of all HVDC links between given buses. Empty tuple if no HVDC links between given buses. + Example: + get_hvdcs_between_buses(1,2) + """ + hvdcs = self.get_hvdcs_at_bus(ibus) + if len(hvdcs)==0: + return hvdcs + else: + dcs = [] + for dc in hvdcs: + if jbus in dc: + dcs.append(dc) + return tuple(dcs) + def get_generators_with_constraints(self, area=0, zone=0): """ Get all generators satisfying area and zone constraints. @@ -2696,7 +2762,63 @@ def set_energy_storage_data(self, energy_storage, par_type, par_name, value): """ global STEPS_LIB return self.__set_source_data(energy_storage, par_type, par_name, value) - + + def set_generator_power(self, generator, s): + """ + Set generator power. + Args: + (1) generator: Generator device id in format of (bus, ickt). + (2) s: Complex power generation in MVA. + Rets: N/A + Tips: N/A + Example: + set_generator_power((1,"#1"), 100+20j) + """ + self.set_generator_data(generator, "F", "PGEN_MW", s.real) + self.set_generator_data(generator, "F", "QGEN_MVAR", s.imag) + + def set_wt_generator_power(self, wt_generator, s): + """ + Set wt generator power. + Args: + (1) wt_generator: WT generator device id in format of (bus, ickt). + (2) s: Complex power generation in MVA. + Rets: N/A + Tips: N/A + Example: + set_wt_generator_power((1,"#1"), 100+20j) + """ + self.set_wt_generator_data(generator, "F", "PGEN_MW", s.real) + self.set_wt_generator_data(generator, "F", "QGEN_MVAR", s.imag) + + def set_pv_unit_power(self, pv_unit, s): + """ + Set pv unit power. + Args: + (1) pv_unit: PV unit device id in format of (bus, ickt). + (2) s: Complex power generation in MVA. + Rets: N/A + Tips: N/A + Example: + set_pv_unit_power((1,"#1"), 100+20j) + """ + self.set_pv_unit_data(generator, "F", "PGEN_MW", s.real) + self.set_pv_unit_data(generator, "F", "QGEN_MVAR", s.imag) + + def set_energy_storage_power(self, energy_storage, s): + """ + Set energy storage power. + Args: + (1) energy_storage: Energy storage device id in format of (bus, ickt). + (2) s: Complex power generation in MVA. + Rets: N/A + Tips: N/A + Example: + set_energy_storage_power((1,"#1"), 100+20j) + """ + self.set_energy_storage_data(energy_storage, "F", "PGEN_MW", s.real) + self.set_energy_storage_data(energy_storage, "F", "QGEN_MVAR", s.imag) + def set_load_data(self, load, par_type, par_name, value): """ Set load data. @@ -2729,6 +2851,31 @@ def set_load_data(self, load, par_type, par_name, value): return STEPS_LIB.api_set_load_string_data(bus, ickt, par_name, value, self.toolkit_index) return + def set_load_power(self, load, sp=None, si=None, sz=None): + """ + Set load power. + Args: + (1) load: Load device id in format of (bus, ickt). + (2) sp: Complex constant power load in MVA. + (3) si: Complex constant current load in MVA. + (4) sz: Complex constant impedance load in MVA. + Rets: N/A + Tips: + If the load component is None, the specific component is ignored. + Example: + set_load_power((1,"#1"), 100+20j) # set constant power part only + set_load_power((1,"#1"), sz = 60+10j) # set constant impedance part only + """ + if sp!=None: + self.set_load_data(load, "F", "PP0_MW",sp.real) + self.set_load_data(load, "F", "QP0_MVAR",sp.imag) + if si!=None: + self.set_load_data(load, "F", "PI0_MW",si.real) + self.set_load_data(load, "F", "QI0_MVAR",si.imag) + if sz!=None: + self.set_load_data(load, "F", "PZ0_MW",sz.real) + self.set_load_data(load, "F", "QZ0_MVAR",sz.imag) + def set_fixed_shunt_data(self, fixed_shunt, par_type, par_name, value): """ Set fixed shunt data. @@ -2893,7 +3040,19 @@ def set_hvdc_data(self, hvdc, par_type, side, par_name, value): value = self.__get_c_char_p_of_string(value) return STEPS_LIB.api_set_hvdc_string_data(ibus, jbus, ickt, side, par_name, value, self.toolkit_index) return - + def set_hvdc_power(self, hvdc, p): + """ + Set HVDC link power command. + Args: + (1) hvdc: HVDC link device id in format of (ibus, jbus, ickt). + (2) p: power command in MW. + Rets: N/A + Example: + set_hvdc_power((1,2,"DC1"), 2000) + """ + self.set_hvdc_data(hvdc, "F", "HVDC", "PDCN_MW", p) + return + def set_area_data(self, area, par_type, par_name, value): """ Set area data. @@ -4217,6 +4376,20 @@ def run_a_step(self): STEPS_LIB.api_run_a_step(self.toolkit_index) return + def is_system_angular_stable(self): + """ + Check if the system is angular stable or not. It is only VALID when system rotor angle stability surveillance flag is enabled. + If the surveillance flag is not enabled, True is always returned. + Args: N/A + Rets: + (1) flag: True if system is angular stable, and False if unstable. + Tips: + If the surveillance flag is enabled, False is returned if the maximum rotor angle difference in any island exceeds the threshold. + Other, True is returned. + """ + global STEPS_LIB + return STEPS_LIB.api_get_system_angular_stable_flag(self.toolkit_index) + def set_bus_fault(self, bus, fault_type, fault_shunt): """ Set bus fault.