def run(self): """ Run the monte carlo simulation @return: """ self.__cancel__ = False # compile # print('Compiling...', end='') numerical_circuit = self.grid.compile() calculation_inputs = numerical_circuit.compute( branch_tolerance_mode=self.options.branch_impedance_tolerance_mode) self.results = CascadingResults(self.cascade_type) # initialize the simulator if self.cascade_type is CascadeType.PowerFlow: model_simulator = PowerFlowMP(self.grid, self.options) elif self.cascade_type is CascadeType.LatinHypercube: model_simulator = LatinHypercubeSampling( self.grid, self.options, sampling_points=self.n_lhs_samples) else: model_simulator = PowerFlowMP(self.grid, self.options) self.progress_signal.emit(0.0) self.progress_text.emit('Running cascading failure...') n_grids = len(calculation_inputs) + self.max_additional_islands if n_grids > len(self.grid.buses): # safety check n_grids = len(self.grid.buses) - 1 # print('n grids: ', n_grids) it = 0 while len(calculation_inputs) <= n_grids and it <= n_grids: # For every circuit, run a power flow # for c in self.grid.circuits: model_simulator.run() # print(model_simulator.results.get_convergence_report()) # remove grid elements (branches) idx, criteria = self.remove_probability_based( numerical_circuit, model_simulator.results, max_val=1.0, min_prob=0.1) # store the removed indices and the results entry = CascadingReportElement(idx, model_simulator.results, criteria) self.results.events.append(entry) # recompile grid calculation_inputs = numerical_circuit.compute() it += 1 prog = max( len(calculation_inputs) / (n_grids + 1), it / (n_grids + 1)) self.progress_signal.emit(prog * 100.0) if self.__cancel__: break print('Grid split into ', len(calculation_inputs), ' islands after', it, ' steps') # send the finnish signal self.progress_signal.emit(0.0) self.progress_text.emit('Done!') self.done_signal.emit()
def test_gridcal_regulator(): """ GridCal test for the new implementation of transformer voltage regulators. """ test_name = "test_gridcal_regulator" grid = MultiCircuit(name=test_name) grid.Sbase = Sbase grid.time_profile = None grid.logger = list() # Create buses POI = Bus( name="POI", vnom=100, # kV is_slack=True) grid.add_bus(POI) B_C3 = Bus(name="B_C3", vnom=10) # kV grid.add_bus(B_C3) B_MV_M32 = Bus(name="B_MV_M32", vnom=10) # kV grid.add_bus(B_MV_M32) B_LV_M32 = Bus(name="B_LV_M32", vnom=0.6) # kV grid.add_bus(B_LV_M32) # Create voltage controlled generators (or slack, a.k.a. swing) UT = Generator(name="Utility") UT.bus = POI grid.add_generator(POI, UT) # Create static generators (with fixed power factor) M32 = StaticGenerator(name="M32", P=4.2, Q=0.0) # MVA (complex) M32.bus = B_LV_M32 grid.add_static_generator(B_LV_M32, M32) # Create transformer types s = 100 # MVA z = 8 # % xr = 40 SS = TransformerType( name="SS", hv_nominal_voltage=100, # kV lv_nominal_voltage=10, # kV nominal_power=s, # MVA copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase, # kW iron_losses=125, # kW no_load_current=0.5, # % short_circuit_voltage=z) # % grid.add_transformer_type(SS) s = 5 # MVA z = 6 # % xr = 20 PM = TransformerType( name="PM", hv_nominal_voltage=10, # kV lv_nominal_voltage=0.6, # kV nominal_power=s, # MVA copper_losses=complex_impedance(z, xr).real * s * 1000 / Sbase, # kW iron_losses=6.25, # kW no_load_current=0.5, # % short_circuit_voltage=z) # % grid.add_transformer_type(PM) # Create branches X_C3 = Branch(bus_from=POI, bus_to=B_C3, name="X_C3", branch_type=BranchType.Transformer, template=SS, bus_to_regulated=True, vset=1.05) X_C3.tap_changer = TapChanger(taps_up=16, taps_down=16, max_reg=1.1, min_reg=0.9) X_C3.tap_changer.set_tap(X_C3.tap_module) grid.add_branch(X_C3) C_M32 = Branch(bus_from=B_C3, bus_to=B_MV_M32, name="C_M32", r=7.84, x=1.74) grid.add_branch(C_M32) X_M32 = Branch(bus_from=B_MV_M32, bus_to=B_LV_M32, name="X_M32", branch_type=BranchType.Transformer, template=PM) grid.add_branch(X_M32) # Apply templates (device types) grid.apply_all_branch_types() print("Buses:") for i, b in enumerate(grid.buses): print(f" - bus[{i}]: {b}") print() options = PowerFlowOptions(SolverType.LM, verbose=True, initialize_with_existing_solution=True, multi_core=True, control_q=ReactivePowerControlMode.Direct, control_taps=TapsControlMode.Direct, tolerance=1e-6, max_iter=99) power_flow = PowerFlowMP(grid, options) power_flow.run() approx_volt = [round(100 * abs(v), 1) for v in power_flow.results.voltage] solution = [100.0, 105.2, 130.0, 130.1] # Expected solution from GridCal print() print(f"Test: {test_name}") print(f"Results: {approx_volt}") print(f"Solution: {solution}") print() print("Generators:") for g in grid.get_generators(): print(f" - Generator {g}: q_min={g.Qmin}pu, q_max={g.Qmax}pu") print() print("Branches:") for b in grid.branches: print( f" - {b}: R={round(b.R, 4)}pu, X={round(b.X, 4)}pu, X/R={round(b.X/b.R, 1)}, vset={b.vset}" ) print() print("Transformer types:") for t in grid.transformer_types: print( f" - {t}: Copper losses={int(t.Pcu)}kW, Iron losses={int(t.Pfe)}kW, SC voltage={t.Vsc}%" ) print() print("Losses:") for i in range(len(grid.branches)): print( f" - {grid.branches[i]}: losses={round(power_flow.results.losses[i], 3)} MVA" ) print() print(f"Voltage settings: {grid.numerical_circuit.vset}") equal = True for i in range(len(approx_volt)): if approx_volt[i] != solution[i]: equal = False assert equal