def test_demo_5_node(root_path=ROOT_PATH): np.core.arrayprint.set_printoptions(precision=4) grid = MultiCircuit() # Add buses bus1 = Bus('Bus 1', vnom=20) grid.add_bus(bus1) gen1 = Generator('Slack Generator', voltage_module=1.0) grid.add_generator(bus1, gen1) bus2 = Bus('Bus 2', vnom=20) grid.add_bus(bus2) grid.add_load(bus2, Load('load 2', P=40, Q=20)) bus3 = Bus('Bus 3', vnom=20) grid.add_bus(bus3) grid.add_load(bus3, Load('load 3', P=25, Q=15)) bus4 = Bus('Bus 4', vnom=20) grid.add_bus(bus4) grid.add_load(bus4, Load('load 4', P=40, Q=20)) bus5 = Bus('Bus 5', vnom=20) grid.add_bus(bus5) grid.add_load(bus5, Load('load 5', P=50, Q=20)) # add branches (Lines in this case) grid.add_line(Line(bus1, bus2, 'line 1-2', r=0.05, x=0.11, b=0.02)) grid.add_line(Line(bus1, bus3, 'line 1-3', r=0.05, x=0.11, b=0.02)) grid.add_line(Line(bus1, bus5, 'line 1-5', r=0.03, x=0.08, b=0.02)) grid.add_line(Line(bus2, bus3, 'line 2-3', r=0.04, x=0.09, b=0.02)) grid.add_line(Line(bus2, bus5, 'line 2-5', r=0.04, x=0.09, b=0.02)) grid.add_line(Line(bus3, bus4, 'line 3-4', r=0.06, x=0.13, b=0.03)) grid.add_line(Line(bus4, bus5, 'line 4-5', r=0.04, x=0.09, b=0.02)) # grid.plot_graph() print('\n\n', grid.name) FileSave(grid, 'demo_5_node.json').save() options = PowerFlowOptions(SolverType.NR, verbose=False) 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
def parse_ac_line_segment(self, cim: CIMCircuit, circuit: MultiCircuit, busbar_dict): """ :param cim: :param circuit: :param busbar_dict: :return: """ if 'ACLineSegment' in cim.elements_by_type.keys(): for elm in cim.elements_by_type['ACLineSegment']: b1, b2 = elm.get_buses() B1, B2 = try_buses(b1, b2, busbar_dict) if B1 is not None and B2 is not None: R, X, G, B = elm.get_pu_values() rate = elm.get_rate() # create AcLineSegment (Line) line = gcdev.Line(idtag=elm.uuid, bus_from=B1, bus_to=B2, name=str(elm.name), r=R, x=X, b=B, rate=rate, active=True, mttf=0, mttr=0) circuit.add_line(line) else: self.logger.add_error('Bus not found', elm.rfid)
def parse_branches_data(circuit: MultiCircuit, data, bus_idx_dict, logger: Logger): """ Parse Matpower / FUBM Matpower branch data into GridCal :param circuit: MultiCircuit instance :param data: data dictionary :param bus_idx_dict: bus index -> object dictionary :return: Nothing """ # Branches table = data['branch'] n = len(table) if table.shape[1] == 37: # FUBM model logger.add_info('It is a FUBM model') if 'branch_names' in data.keys(): names = data['branch_names'] else: names = ['branch ' + str(i) for i in range(n)] for i in range(len(table)): f = circuit.buses[bus_idx_dict[int(table[i, matpower_branches.F_BUS])]] t = circuit.buses[bus_idx_dict[int(table[i, matpower_branches.T_BUS])]] if table.shape[1] == 37: # FUBM model # converter type (I, II, III) matpower_converter_mode = table[i, matpower_branches.CONV_A] if matpower_converter_mode > 0: # it is a converter # 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: if Vac_set == 0.0: control_mode = ConverterControlType.type_II_4 else: control_mode = ConverterControlType.type_II_5 elif matpower_converter_mode == 3: control_mode = ConverterControlType.type_III_6 elif matpower_converter_mode == 4: control_mode = ConverterControlType.type_III_7 else: control_mode = ConverterControlType.type_0_free rate = max(table[i, [ matpower_branches.RATE_A, matpower_branches. RATE_B, matpower_branches.RATE_C ]]) branch = VSC( bus_from=f, bus_to=t, name='VSC' + str(len(circuit.vsc_devices) + 1), active=bool(table[i, matpower_branches.BR_STATUS]), r1=table[i, matpower_branches.BR_R], x1=table[i, matpower_branches.BR_X], m=m, m_max=table[i, matpower_branches.MA_MAX], m_min=table[i, matpower_branches.MA_MIN], theta=table[i, matpower_branches.SHIFT], theta_max=np.deg2rad(table[i, matpower_branches.ANGMAX]), theta_min=np.deg2rad(table[i, matpower_branches.ANGMIN]), G0=table[i, matpower_branches.GSW], Beq=table[i, matpower_branches.BEQ], Beq_max=table[i, matpower_branches.BEQ_MAX], Beq_min=table[i, matpower_branches.BEQ_MIN], 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, alpha1=table[i, matpower_branches.ALPHA1], alpha2=table[i, matpower_branches.ALPHA2], alpha3=table[i, matpower_branches.ALPHA3]) circuit.add_vsc(branch) logger.add_info('Branch as converter', 'Branch {}'.format(str(i + 1))) else: 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: branch = Transformer2W( bus_from=f, bus_to=t, name=names[i], r=table[i, matpower_branches.BR_R], x=table[i, matpower_branches.BR_X], g=0, b=table[i, matpower_branches.BR_B], rate=table[i, matpower_branches.RATE_A], tap=table[i, matpower_branches.TAP], shift_angle=table[i, matpower_branches.SHIFT], active=bool(table[i, matpower_branches.BR_STATUS])) circuit.add_transformer2w(branch) logger.add_info('Branch as 2w transformer', 'Branch {}'.format(str(i + 1))) else: branch = Line(bus_from=f, bus_to=t, 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=table[i, matpower_branches.RATE_A], active=bool( table[i, matpower_branches.BR_STATUS])) circuit.add_line(branch) logger.add_info('Branch as line', 'Branch {}'.format(str(i + 1))) else: 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: branch = Transformer2W( bus_from=f, bus_to=t, name=names[i], r=table[i, matpower_branches.BR_R], x=table[i, matpower_branches.BR_X], g=0, b=table[i, matpower_branches.BR_B], rate=table[i, matpower_branches.RATE_A], tap=table[i, matpower_branches.TAP], shift_angle=table[i, matpower_branches.SHIFT], active=bool(table[i, matpower_branches.BR_STATUS])) circuit.add_transformer2w(branch) logger.add_info('Branch as 2w transformer', 'Branch {}'.format(str(i + 1))) else: branch = Line(bus_from=f, bus_to=t, 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=table[i, matpower_branches.RATE_A], active=bool(table[i, matpower_branches.BR_STATUS])) circuit.add_line(branch) logger.add_info('Branch as line', 'Branch {}'.format(str(i + 1))) # convert normal lines into DC-lines if needed for line in circuit.lines: if line.bus_to.is_dc and line.bus_from.is_dc: dc_line = DcLine(bus_from=line.bus_from, bus_to=line.bus_to, name=line.name, active=line.active, rate=line.rate, r=line.R, active_prof=line.active_prof, rate_prof=line.rate_prof) # add device to the circuit circuit.add_dc_line(dc_line) # delete the line from the circuit circuit.delete_line(line) logger.add_info('Converted to DC line', line.name)
def parse_json_data_v2(data: dict, logger: Logger): """ New Json parser :param data: :param logger: :return: """ devices = data['devices'] profiles = data['profiles'] if DeviceType.CircuitDevice.value in devices.keys(): dta = devices[DeviceType.CircuitDevice.value] circuit = MultiCircuit(name=str(dta['name']), Sbase=float(dta['sbase']), fbase=float(dta['fbase']), idtag=str(dta['id'])) jcircuit = devices["Circuit"] circuit.Sbase = jcircuit["sbase"] # Countries country_dict = dict() if 'Country' in devices.keys(): elms = devices["Country"] for jentry in elms: elm = Country(idtag=str(jentry['id']), code=str(jentry['code']), name=str(jentry['name'])) circuit.countries.append(elm) country_dict[elm.idtag] = elm else: elm = Country(idtag=None, code='Default', name='Default') circuit.countries.append(elm) # Areas areas_dict = dict() if 'Area' in devices.keys(): elms = devices["Area"] for jentry in elms: elm = Area(idtag=str(jentry['id']), code=str(jentry['code']), name=str(jentry['name'])) circuit.areas.append(elm) areas_dict[elm.idtag] = elm else: elm = Area(idtag=None, code='Default', name='Default') circuit.areas.append(elm) # Zones zones_dict = dict() if 'Zone' in devices.keys(): elms = devices["Zone"] for jentry in elms: elm = Zone(idtag=str(jentry['id']), code=str(jentry['code']), name=str(jentry['name'])) circuit.zones.append(elm) zones_dict[elm.idtag] = elm else: elm = Zone(idtag=None, code='Default', name='Default') circuit.zones.append(elm) # Substations substations_dict = dict() if 'Substation' in devices.keys(): elms = devices["Substation"] for jentry in elms: elm = Substation(idtag=str(jentry['id']), code=str(jentry['code']), name=str(jentry['name'])) circuit.substations.append(elm) substations_dict[elm.idtag] = elm else: elm = Substation(idtag=None, code='Default', name='Default') circuit.substations.append(elm) # buses bus_dict = dict() if 'Bus' in devices.keys(): buses = devices["Bus"] for jentry in buses: area_id = str(jentry['area']) if 'area' in jentry.keys() else '' zone_id = str(jentry['zone']) if 'zone' in jentry.keys() else '' substation_id = str(jentry['substation']) if 'substation' in jentry.keys() else '' country_id = str(jentry['country']) if 'country' in jentry.keys() else '' if area_id in areas_dict.keys(): area = areas_dict[area_id] else: area = circuit.areas[0] if zone_id in zones_dict.keys(): zone = zones_dict[zone_id] else: zone = circuit.zones[0] if substation_id in substations_dict.keys(): substation = substations_dict[substation_id] else: substation = circuit.substations[0] if country_id in country_dict.keys(): country = country_dict[country_id] else: country = circuit.countries[0] bus = Bus(name=str(jentry['name']), idtag=str(jentry['id']), vnom=float(jentry['vnom']), vmin=float(jentry['vmin']), vmax=float(jentry['vmax']), r_fault=float(jentry['rf']), x_fault=float(jentry['xf']), xpos=float(jentry['x']), ypos=float(jentry['y']), height=float(jentry['h']), width=float(jentry['w']), active=bool(jentry['active']), is_slack=bool(jentry['is_slack']), area=area, zone=zone, substation=substation, country=country, longitude=float(jentry['lon']), latitude=float(jentry['lat'])) bus_dict[jentry['id']] = bus circuit.add_bus(bus) if 'Generator' in devices.keys(): generators = devices["Generator"] for jentry in generators: gen = Generator(name=str(jentry['name']), idtag=str(jentry['id']), active_power=float(jentry['p']), power_factor=float(jentry['pf']), voltage_module=float(jentry['vset']), is_controlled=bool(jentry['is_controlled']), Qmin=float(jentry['qmin']), Qmax=float(jentry['qmax']), Snom=float(jentry['snom']), active=bool(jentry['active']), p_min=float(jentry['pmin']), p_max=float(jentry['pmax']), op_cost=float(jentry['cost']), ) gen.bus = bus_dict[jentry['bus']] circuit.add_generator(gen.bus, gen) if 'Battery' in devices.keys(): batteries = devices["Battery"] for jentry in batteries: gen = Battery(name=str(jentry['name']), idtag=str(jentry['id']), active_power=float(jentry['p']), power_factor=float(jentry['pf']), voltage_module=float(jentry['vset']), is_controlled=bool(jentry['is_controlled']), Qmin=float(jentry['qmin']), Qmax=float(jentry['qmax']), Snom=float(jentry['snom']), active=bool(jentry['active']), p_min=float(jentry['pmin']), p_max=float(jentry['pmax']), op_cost=float(jentry['cost']), ) gen.bus = bus_dict[jentry['bus']] circuit.add_battery(gen.bus, gen) if 'Load' in devices.keys(): loads = devices["Load"] for jentry in loads: elm = Load(name=str(jentry['name']), idtag=str(jentry['id']), P=float(jentry['p']), Q=float(jentry['q']), active=bool(jentry['active'])) elm.bus = bus_dict[jentry['bus']] circuit.add_load(elm.bus, elm) if "Shunt" in devices.keys(): shunts = devices["Shunt"] for jentry in shunts: elm = Shunt(name=str(jentry['name']), idtag=str(jentry['id']), G=float(jentry['g']), B=float(jentry['b']), active=bool(jentry['active'])) elm.bus = bus_dict[jentry['bus']] circuit.add_shunt(elm.bus, elm) if "Line" in devices.keys(): lines = devices["Line"] for entry in lines: elm = Line(bus_from=bus_dict[entry['bus_from']], bus_to=bus_dict[entry['bus_to']], name=str(entry['name']), idtag=str(entry['id']), r=float(entry['r']), x=float(entry['x']), b=float(entry['b']), rate=float(entry['rate']), active=entry['active'], length=float(entry['length']), ) circuit.add_line(elm) if "Transformer" in devices.keys() or "Transformer2w" in devices.keys(): if "Transformer" in devices.keys(): transformers = devices["Transformer"] elif "Transformer2w" in devices.keys(): transformers = devices["Transformer2w"] else: raise Exception('Transformer key not found') for entry in transformers: elm = Transformer2W(bus_from=bus_dict[entry['bus_from']], bus_to=bus_dict[entry['bus_to']], name=str(entry['name']), idtag=str(entry['id']), r=float(entry['r']), x=float(entry['x']), g=float(entry['g']), b=float(entry['b']), rate=float(entry['rate']), active=bool(entry['active']), tap=float(entry['tap_module']), shift_angle=float(entry['tap_angle']), ) circuit.add_transformer2w(elm) if "VSC" in devices.keys(): vsc = devices["VSC"] # TODO: call correct_buses_connection() if "HVDC Line" in devices.keys(): hvdc = devices["HVDC Line"] return circuit else: logger.add('The Json structure does not have a Circuit inside the devices!') return MultiCircuit()
def interpret_data_v1(circuit: MultiCircuit, data) -> MultiCircuit: """ Pass the loaded table-like data to the structures :param circuit: :param data: Data dictionary :return: """ circuit.clear() # time profile if 'master_time' in data.keys(): master_time_array = data['master_time'] else: master_time_array = None import GridCal.Engine.IO.matpower_bus_definitions as e # Buses table = data['bus'] n = table.shape[0] # load profiles if 'Lprof' in data.keys(): Pprof = data['Lprof'] Qprof = data['LprofQ'] are_load_prfiles = True print('There are load profiles') else: are_load_prfiles = False if 'bus_names' in data.keys(): names = data['bus_names'] else: names = ['bus ' + str(i+1) for i in range(n)] # Buses bus_idx_dict = dict() for i in range(n): # Create bus bus = Bus(name=names[i], vnom=table[i, e.BASE_KV], vmax=table[i, e.VMAX], vmin=table[i, e.VMIN]) # store the given bus index in relation to its real index in the table for later bus_idx_dict[table[i, e.BUS_I]] = i # determine if the bus is set as slack manually tpe = table[i, e.BUS_TYPE] if tpe == e.REF: bus.is_slack = True else: bus.is_slack = False # Add the load if table[i, e.PD] != 0 or table[i, e.QD] != 0: load = Load(P=table[i, e.PD], Q=table[i, e.QD]) load.bus = bus bus.loads.append(load) # Add the shunt if table[i, e.GS] != 0 or table[i, e.BS] != 0: shunt = Shunt(G=table[i, e.GS], B=table[i, e.BS]) shunt.bus = bus bus.shunts.append(shunt) # Add the bus to the circuit buses circuit.add_bus(bus) import GridCal.Engine.IO.matpower_gen_definitions as e # Generators table = data['gen'] n = len(table) # load profiles if 'Gprof' in data.keys(): Gprof = data['Gprof'] are_gen_prfiles = True print('There are gen profiles') else: are_gen_prfiles = False if 'gen_names' in data.keys(): names = data['gen_names'] else: names = ['gen ' + str(i) for i in range(n)] for i in range(len(table)): bus_idx = bus_idx_dict[int(table[i, e.GEN_BUS])] gen = Generator(name=names[i], active_power=table[i, e.PG], voltage_module=table[i, e.VG], Qmax=table[i, e.QMAX], Qmin=table[i, e.QMIN]) # Add the generator to the bus gen.bus = circuit.buses[bus_idx] circuit.buses[bus_idx].controlled_generators.append(gen) import GridCal.Engine.IO.matpower_branch_definitions as e # Branches table = data['branch'] n = len(table) if 'branch_names' in data.keys(): names = data['branch_names'] else: names = ['branch ' + str(i) for i in range(n)] for i in range(len(table)): f = circuit.buses[bus_idx_dict[int(table[i, e.F_BUS])]] t = circuit.buses[bus_idx_dict[int(table[i, e.T_BUS])]] if table.shape[1] == 37: # FUBM model matpower_mode = table[i, e.CONV_A] if matpower_mode > 0: # it is a converter # 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 Pset = table[i, e.PF] Vac_set = table[i, e.VT_SET] Vdc_set = table[i, e.VF_SET] Qset = table[i, e.QF] m = table[i, e.TAP] if table[i, e.TAP] > 0 else 1.0 if matpower_mode == 1: if Pset != 0.0: control_mode = ConverterControlType.type_1_pf elif Qset != 0.0: control_mode = ConverterControlType.type_1_qf elif Vac_set != 0.0: control_mode = ConverterControlType.type_1_vac else: control_mode = ConverterControlType.type_1_free elif matpower_mode == 2: if Pset == 0.0: control_mode = ConverterControlType.type_2_vdc else: control_mode = ConverterControlType.type_2_vdc_pf elif matpower_mode == 3: control_mode = ConverterControlType.type_3 elif matpower_mode == 4: control_mode = ConverterControlType.type_4 else: control_mode = ConverterControlType.type_1_free branch = VSC(bus_from=f, bus_to=t, name='VSC' + str(len(circuit.vsc_converters) + 1), active=bool(table[i, e.BR_STATUS]), r1=table[i, e.BR_R], x1=table[i, e.BR_X], m=m, m_max=table[i, e.MA_MAX], m_min=table[i, e.MA_MIN], theta=table[i, e.SHIFT], theta_max=np.deg2rad(table[i, e.ANGMAX]), theta_min=np.deg2rad(table[i, e.ANGMIN]), G0=table[i, e.GSW], Beq=table[i, e.BEQ], Beq_max=table[i, e.BEQ_MAX], Beq_min=table[i, e.BEQ_MIN], rate=table[i, e.RATE_A], kdp=table[i, e.KDP], control_mode=control_mode, Pset=Pset, Qset=Qset, Vac_set=Vac_set, Vdc_set=Vdc_set, alpha1=table[i, e.ALPHA1], alpha2=table[i, e.ALPHA2], alpha3=table[i, e.ALPHA3]) circuit.add_vsc(branch) else: if f.Vnom != t.Vnom or (table[i, e.TAP] != 1.0 and table[i, e.TAP] != 0) or table[i, e.SHIFT] != 0.0: branch = Transformer2W(bus_from=f, bus_to=t, name=names[i], r=table[i, e.BR_R], x=table[i, e.BR_X], g=0, b=table[i, e.BR_B], rate=table[i, e.RATE_A], tap=table[i, e.TAP], shift_angle=table[i, e.SHIFT], active=bool(table[i, e.BR_STATUS])) circuit.add_transformer2w(branch) else: branch = Line(bus_from=f, bus_to=t, name=names[i], r=table[i, e.BR_R], x=table[i, e.BR_X], b=table[i, e.BR_B], rate=table[i, e.RATE_A], active=bool(table[i, e.BR_STATUS])) circuit.add_line(branch) else: if f.Vnom != t.Vnom or (table[i, e.TAP] != 1.0 and table[i, e.TAP] != 0) or table[i, e.SHIFT] != 0.0: branch = Transformer2W(bus_from=f, bus_to=t, name=names[i], r=table[i, e.BR_R], x=table[i, e.BR_X], g=0, b=table[i, e.BR_B], rate=table[i, e.RATE_A], tap=table[i, e.TAP], shift_angle=table[i, e.SHIFT], active=bool(table[i, e.BR_STATUS])) circuit.add_transformer2w(branch) else: branch = Line(bus_from=f, bus_to=t, name=names[i], r=table[i, e.BR_R], x=table[i, e.BR_X], b=table[i, e.BR_B], rate=table[i, e.RATE_A], active=bool(table[i, e.BR_STATUS])) circuit.add_line(branch) # convert normal lines into DC-lines if needed for line in circuit.lines: if line.bus_to.is_dc and line.bus_from.is_dc: dc_line = DcLine(bus_from=line.bus_from, bus_to=line.bus_to, name=line.name, active=line.active, rate=line.rate, r=line.R, active_prof=line.active_prof, rate_prof=line.rate_prof) # add device to the circuit circuit.add_dc_line(dc_line) # delete the line from the circuit circuit.delete_line(line) # add the profiles if master_time_array is not None: circuit.format_profiles(master_time_array) return circuit
def test_tolerance_lf_higher(): test_name = "test_tolerance_lf_higher" grid = MultiCircuit(name=test_name) grid.Sbase = Sbase grid.time_profile = None grid.logger = Logger() # Create buses Bus0 = Bus(name="Bus0", vnom=25, is_slack=True) Bus1 = Bus(name="Bus1", vnom=25) grid.add_bus(Bus0) grid.add_bus(Bus1) # Create load grid.add_load(Bus1, Load(name="Load0", P=1.0, Q=0.4)) # Create slack bus grid.add_generator(Bus0, Generator(name="Utility")) # Create cable (r and x should be in pu) grid.add_line(Line(bus_from=Bus0, bus_to=Bus1, name="Cable1", r=0.01, x=0.05, tolerance=10)) # Run non-linear power flow options = PowerFlowOptions(verbose=True, branch_impedance_tolerance_mode=BranchImpedanceMode.Upper) power_flow = PowerFlowDriver(grid, options) power_flow.run() # Check solution approx_losses = round(1000 * power_flow.results.losses[0], 3) solution = complex(0.128, 0.58) # Expected solution from GridCal # Tested on ETAP 16.1.0 and pandapower print("\n=================================================================") print(f"Test: {test_name}") print("=================================================================\n") print(f"Results: {approx_losses}") print(f"Solution: {solution}") print() print("Buses:") for i, b in enumerate(grid.buses): print(f" - bus[{i}]: {b}") print() print("Branches:") branches = grid.get_branches() for b in branches: 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, 2)}") print() print("Voltages:") for i in range(len(grid.buses)): print( f" - {grid.buses[i]}: voltage={round(power_flow.results.voltage[i], 3)} pu" ) print() print("Losses:") for i in range(len(branches)): print( f" - {branches[i]}: losses={round(power_flow.results.losses[i], 3)} MVA" ) print() print("Loadings (power):") for i in range(len(branches)): print( f" - {branches[i]}: loading={round(power_flow.results.Sf[i], 3)} MVA" ) print() print("Loadings (current):") for i in range(len(branches)): print( f" - {branches[i]}: loading={round(power_flow.results.If[i], 3)} pu" ) print() assert approx_losses == solution
class GridGeneratorGUI(QDialog): def __init__( self, parent=None, ): """ :param parent: """ QDialog.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowTitle('Grid Generator') self.g = RpgAlgorithm() self.circuit = MultiCircuit() self.applied = False self.ui.applyButton.clicked.connect(self.apply) self.ui.previewButton.clicked.connect(self.preview) def msg(self, text, title="Warning"): """ Message box :param text: Text to display :param title: Name of the window """ msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText(text) # msg.setInformativeText("This is additional information") msg.setWindowTitle(title) # msg.setDetailedText("The details are as follows:") msg.setStandardButtons(QMessageBox.Ok) retval = msg.exec_() def fill_graph(self): """ # set desired parameters and perform algorithm :return: """ self.g = RpgAlgorithm() n = self.ui.nodes_spinBox.value() n0 = 10 r = self.ui.ratio_SpinBox.value() if n0 >= n: n0 = n - 1 self.g.set_params(n=n, n0=n0, r=r) self.g.initialise() self.g.grow() def preview(self): """ :return: """ self.fill_graph() G = nx.Graph(self.g.edges) pos = { i: (self.g.lat[i], self.g.lon[i]) for i in range(self.g.added_nodes) } self.ui.plotwidget.clear() nx.draw(G, ax=self.ui.plotwidget.get_axis(), pos=pos, with_labels=True, node_color='lightblue') self.ui.plotwidget.redraw() def apply(self): """ Create graph, then the circuit and close :return: Nothing """ self.fill_graph() self.circuit = MultiCircuit() explosion_factor = 10000.0 # number of nodes n = self.g.added_nodes # assign the load and generation buses genbus = self.ui.generation_nodes_SpinBox.value() loadbus = self.ui.load_nodes_SpinBox.value() if (genbus + loadbus) > 100: s = genbus + loadbus genbus /= s loadbus /= s gen_buses_num = int(np.floor(n * genbus / 100)) load_buses_num = int(np.floor(n * loadbus / 100)) rng = default_rng() numbers = rng.choice(n, size=gen_buses_num + load_buses_num, replace=False) gen_buses = numbers[:gen_buses_num] load_buses = numbers[gen_buses_num:] pmax = self.ui.power_SpinBox.value() # generate buses bus_dict = dict() for i in range(n): bus = Bus(name='Bus ' + str(i + 1), xpos=self.g.lat[i] * explosion_factor, ypos=-self.g.lon[i] * explosion_factor) bus_dict[i] = bus self.circuit.add_bus(bus) # generate loads factor = np.random.random(load_buses_num) factor /= factor.sum() pf = self.ui.power_factor_SpinBox.value() for k, i in enumerate(load_buses): bus = bus_dict[i] p = pmax * factor[k] q = p * pf load = Load(name='Load@bus' + str(i + 1), P=p, Q=q) self.circuit.add_load(bus, load) # generate generators factor = np.random.random(gen_buses_num) factor /= factor.sum() for k, i in enumerate(gen_buses): bus = bus_dict[i] gen = Generator(name='Generator@bus' + str(i + 1), active_power=pmax * factor[k]) self.circuit.add_generator(bus, gen) # generate lines r = self.ui.r_SpinBox.value() x = self.ui.x_SpinBox.value() b = self.ui.b_SpinBox.value() for f, t in self.g.edges: dx = (self.g.lat[f] - self.g.lat[t]) * explosion_factor dy = (self.g.lon[f] - self.g.lon[t]) * explosion_factor m = np.sqrt( dx * dx + dy * dy) / 10.0 # divided by 10 to have more meaningful values b1 = bus_dict[f] b2 = bus_dict[t] lne = Line(bus_from=b1, bus_to=b2, name='Line ' + str(f) + '-' + str(t), r=r * m, x=x * m, b=b * m, length=m) self.circuit.add_line(lne) # quit self.applied = True self.close()
def parse_json_data_v2(data: dict, logger: Logger): """ New Json parser :param data: :param logger: :return: """ devices = data['devices'] profiles = data['profiles'] if DeviceType.CircuitDevice.value in devices.keys(): dta = devices[DeviceType.CircuitDevice.value] circuit = MultiCircuit(name=str(dta['name']), Sbase=float(dta['sbase']), fbase=float(dta['fbase']), idtag=str(dta['id'])) jcircuit = devices["Circuit"] circuit.Sbase = jcircuit["sbase"] bus_dict = dict() if 'Bus' in devices.keys(): buses = devices["Bus"] for jentry in buses: bus = Bus(name=str(jentry['name']), idtag=str(jentry['id']), vnom=float(jentry['vnom']), vmin=float(jentry['vmin']), vmax=float(jentry['vmax']), r_fault=float(jentry['rf']), x_fault=float(jentry['xf']), xpos=float(jentry['x']), ypos=float(jentry['y']), height=float(jentry['h']), width=float(jentry['w']), active=bool(jentry['active']), is_slack=bool(jentry['is_slack']), # is_dc=jbus['id'], area=jentry['area'], zone=jentry['zone'], substation=jentry['substation'], # country=jbus['id'], longitude=float(jentry['lon']), latitude=float(jentry['lat']) ) bus_dict[jentry['id']] = bus circuit.add_bus(bus) if 'Generator' in devices.keys(): generators = devices["Generator"] for jentry in generators: gen = Generator(name=str(jentry['name']), idtag=str(jentry['id']), active_power=float(jentry['p']), power_factor=float(jentry['pf']), voltage_module=float(jentry['vset']), is_controlled=bool(jentry['is_controlled']), Qmin=float(jentry['qmin']), Qmax=float(jentry['qmax']), Snom=float(jentry['snom']), # power_prof=jgen['name'], # power_factor_prof=jgen['name'], # vset_prof=jgen['name'], # Cost_prof=jgen['name'], active=bool(jentry['active']), p_min=float(jentry['pmin']), p_max=float(jentry['pmax']), op_cost=float(jentry['cost']), # Sbase=jgen['name'], # enabled_dispatch=jgen['name'], # mttf=jgen['name'], # mttr=jgen['name'] ) gen.bus = bus_dict[jentry['bus']] circuit.add_generator(gen.bus, gen) if 'Battery' in devices.keys(): batteries = devices["Battery"] for jentry in batteries: gen = Battery(name=str(jentry['name']), idtag=str(jentry['id']), active_power=float(jentry['p']), power_factor=float(jentry['pf']), voltage_module=float(jentry['vset']), is_controlled=bool(jentry['is_controlled']), Qmin=float(jentry['qmin']), Qmax=float(jentry['qmax']), Snom=float(jentry['snom']), # power_prof=jgen['name'], # power_factor_prof=jgen['name'], # vset_prof=jgen['name'], # Cost_prof=jgen['name'], active=bool(jentry['active']), p_min=float(jentry['pmin']), p_max=float(jentry['pmax']), op_cost=float(jentry['cost']), # Sbase=jgen['name'], # enabled_dispatch=jgen['name'], # mttf=jgen['name'], # mttr=jgen['name'] ) gen.bus = bus_dict[jentry['bus']] circuit.add_battery(gen.bus, gen) if 'Load' in devices.keys(): loads = devices["Load"] for jentry in loads: elm = Load(name=str(jentry['name']), idtag=str(jentry['id']), # G: float = 0.0, # B: float = 0.0, # Ir: float = 0.0, # Ii: float = 0.0, P=float(jentry['p']), Q=float(jentry['q']), # cost=jentry['cost'], # G_prof: Any = None, # B_prof: Any = None, # Ir_prof: Any = None, # Ii_prof: Any = None, # P_prof: Any = None, # Q_prof: Any = None, active=bool(jentry['active'])) elm.bus = bus_dict[jentry['bus']] circuit.add_load(elm.bus, elm) if "Shunt" in devices.keys(): shunts = devices["Shunt"] for jentry in shunts: elm = Shunt(name=str(jentry['name']), idtag=str(jentry['id']), G=float(jentry['g']), B=float(jentry['b']), # G_prof: Any = None, # B_prof: Any = None, active=bool(jentry['active'])) elm.bus = bus_dict[jentry['bus']] circuit.add_shunt(elm.bus, elm) if "Line" in devices.keys(): lines = devices["Line"] for entry in lines: elm = Line(bus_from=bus_dict[entry['bus_from']], bus_to=bus_dict[entry['bus_to']], name=str(entry['name']), idtag=str(entry['id']), r=float(entry['r']), x=float(entry['x']), b=float(entry['b']), rate=float(entry['rate']), active=entry['active'], # tolerance: int = 0, # cost: float = 0.0, # mttf: int = 0, # mttr: int = 0, # r_fault: float = 0.0, # x_fault: float = 0.0, # fault_pos: float = 0.5, length=float(entry['length']), # temp_base: int = 20, # temp_oper: int = 20, # alpha: float = 0.00330, # template: LineTemplate = LineTemplate(), # rate_prof: Any = None, # Cost_prof: Any = None, # active_prof: Any = None, # temp_oper_prof: Any = None ) circuit.add_line(elm) if "Transformer" in devices.keys(): transformers = devices["Transformer"] for entry in transformers: elm = Transformer2W(bus_from=bus_dict[entry['bus_from']], bus_to=bus_dict[entry['bus_to']], name=str(entry['name']), idtag=str(entry['id']), r=float(entry['r']), x=float(entry['x']), g=float(entry['g']), b=float(entry['b']), rate=float(entry['rate']), active=bool(entry['active']), tap=float(entry['tap_module']), shift_angle=float(entry['tap_angle']), # tolerance: int = 0, # cost: float = 0.0, # mttf: int = 0, # mttr: int = 0, # r_fault: float = 0.0, # x_fault: float = 0.0, # fault_pos: float = 0.5, # temp_base: int = 20, # temp_oper: int = 20, # alpha: float = 0.00330, # template: LineTemplate = LineTemplate(), # rate_prof: Any = None, # Cost_prof: Any = None, # active_prof: Any = None, # temp_oper_prof: Any = None ) circuit.add_transformer2w(elm) if "VSC" in devices.keys(): vsc = devices["VSC"] if "HVDC Line" in devices.keys(): hvdc = devices["HVDC Line"] return circuit else: logger.add('The Json structure does not have a Circuit inside the devices!') return MultiCircuit()
def test_corr_line_losses(): test_name = "test_corr_line_losses" grid = MultiCircuit(name=test_name) grid.Sbase = Sbase grid.time_profile = None grid.logger = Logger() # Create buses Bus0 = Bus(name="Bus0", vnom=10, is_slack=True) Bus1 = Bus(name="Bus1", vnom=10) grid.add_bus(Bus0) grid.add_bus(Bus1) # Create load grid.add_load(Bus1, Load(name="Load0", P=1.0, Q=0.4)) # Create slack bus grid.add_generator(Bus0, Generator(name="Utility")) # Create cable cable = Line( bus_from=Bus0, bus_to=Bus1, name="Cable0", r=0.784, x=0.174, temp_base=20, # °C temp_oper=90, # °C alpha=0.00323) # Copper grid.add_line(cable) options = PowerFlowOptions(verbose=True, apply_temperature_correction=True) power_flow = PowerFlowDriver(grid, options) power_flow.run() # Check solution approx_losses = round(power_flow.results.losses[0], 3) solution = complex(0.011, 0.002) # Expected solution from GridCal # Tested on ETAP 16.1.0 print( "\n=================================================================") print(f"Test: {test_name}") print( "=================================================================\n") print(f"Results: {approx_losses}") print(f"Solution: {solution}") print() print("Buses:") for i, b in enumerate(grid.buses): print(f" - bus[{i}]: {b}") print() print("Branches:") for b in grid.lines: 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, 2)}") print() print("Voltages:") for i in range(len(grid.buses)): print( f" - {grid.buses[i]}: voltage={round(power_flow.results.voltage[i], 3)} pu" ) print() print("Losses:") for i in range(len(grid.lines)): print( f" - {grid.lines[i]}: losses={round(power_flow.results.losses[i], 3)} MVA" ) print() print("Loadings (power):") for i in range(len(grid.lines)): print( f" - {grid.lines[i]}: loading={round(power_flow.results.Sf[i], 3)} MVA" ) print() print("Loadings (current):") for i in range(len(grid.lines)): print( f" - {grid.lines[i]}: loading={round(power_flow.results.If[i], 3)} pu" ) print() assert approx_losses == solution
def interpret_data_v1(circuit: MultiCircuit, data) -> MultiCircuit: """ Pass the loaded table-like data to the structures :param circuit: :param data: Data dictionary :return: """ circuit.clear() # time profile if 'master_time' in data.keys(): master_time_array = data['master_time'] else: master_time_array = None import GridCal.Engine.IO.matpower_bus_definitions as e # Buses table = data['bus'] buses_dict = dict() n = len(table) # load profiles if 'Lprof' in data.keys(): Pprof = data['Lprof'] Qprof = data['LprofQ'] are_load_prfiles = True print('There are load profiles') else: are_load_prfiles = False if 'bus_names' in data.keys(): names = data['bus_names'] else: names = ['bus ' + str(i) for i in range(n)] # Buses bus_idx_dict = dict() for i in range(n): # Create bus bus = Bus(name=names[i], vnom=table[i, e.BASE_KV], vmax=table[i, e.VMAX], vmin=table[i, e.VMIN]) # store the given bus index in relation to its real index in the table for later bus_idx_dict[table[i, e.BUS_I]] = i # determine if the bus is set as slack manually tpe = table[i, e.BUS_TYPE] if tpe == e.REF: bus.is_slack = True else: bus.is_slack = False # Add the load if table[i, e.PD] != 0 or table[i, e.QD] != 0: load = Load(P=table[i, e.PD], Q=table[i, e.QD]) load.bus = bus bus.loads.append(load) # Add the shunt if table[i, e.GS] != 0 or table[i, e.BS] != 0: shunt = Shunt(G=table[i, e.GS], B=table[i, e.BS]) shunt.bus = bus bus.shunts.append(shunt) # Add the bus to the circuit buses circuit.add_bus(bus) import GridCal.Engine.IO.matpower_gen_definitions as e # Generators table = data['gen'] n = len(table) # load profiles if 'Gprof' in data.keys(): Gprof = data['Gprof'] are_gen_prfiles = True print('There are gen profiles') else: are_gen_prfiles = False if 'gen_names' in data.keys(): names = data['gen_names'] else: names = ['gen ' + str(i) for i in range(n)] for i in range(len(table)): bus_idx = bus_idx_dict[int(table[i, e.GEN_BUS])] gen = Generator(name=names[i], active_power=table[i, e.PG], voltage_module=table[i, e.VG], Qmax=table[i, e.QMAX], Qmin=table[i, e.QMIN]) # Add the generator to the bus gen.bus = circuit.buses[bus_idx] circuit.buses[bus_idx].controlled_generators.append(gen) import GridCal.Engine.IO.matpower_branch_definitions as e # Branches table = data['branch'] n = len(table) if 'branch_names' in data.keys(): names = data['branch_names'] else: names = ['branch ' + str(i) for i in range(n)] for i in range(len(table)): f = circuit.buses[bus_idx_dict[int(table[i, e.F_BUS])]] t = circuit.buses[bus_idx_dict[int(table[i, e.T_BUS])]] if f.Vnom != t.Vnom or table[i, e.TAP] != 1.0 or table[i, e.SHIFT] != 0.0: branch = Transformer2W(bus_from=f, bus_to=t, name=names[i], r=table[i, e.BR_R], x=table[i, e.BR_X], g=0, b=table[i, e.BR_B], rate=table[i, e.RATE_A], tap=table[i, e.TAP], shift_angle=table[i, e.SHIFT], active=bool(table[i, e.BR_STATUS])) circuit.add_transformer2w(branch) else: branch = Line(bus_from=f, bus_to=t, name=names[i], r=table[i, e.BR_R], x=table[i, e.BR_X], b=table[i, e.BR_B], rate=table[i, e.RATE_A], active=bool(table[i, e.BR_STATUS])) circuit.add_line(branch) # add the profiles if master_time_array is not None: circuit.format_profiles(master_time_array) print('Interpreted.') return circuit