def _ensure_contingencies_monitored(options:Options, md:EgretModel, initial_ruc:bool = False) -> None: ''' Add contingency screening, if that option is enabled ''' if initial_ruc: _ensure_contingencies_monitored.contingency_dicts = {} for bn, b in md.elements('branch'): if not b.get('in_service', True): raise RuntimeError(f"Remove branches from service by setting the `planned_outage` attribute. " f"Branch {bn} has `in_service`:False") for bn, b in md.elements('bus'): if not b.get('in_service', True): raise RuntimeError(f"Buses cannot be removed from service in Prescient") if options.monitor_all_contingencies: key = [] for bn, b in md.elements('branch'): if 'planned_outage' in b: if isinstance(b['planned_outage'], dict): if any(b['planned_outage']['values']): key.append(b) elif b['planned_outage']: key.append(b) key = tuple(key) if key not in _ensure_contingencies_monitored.contingency_dicts: mapping_bus_to_idx = { k : i for i,k in enumerate(md.data['elements']['bus'].keys())} graph = construct_connection_graph(md.data['elements']['branch'], mapping_bus_to_idx) contingency_list = get_N_minus_1_branches(graph, md.data['elements']['branch'], mapping_bus_to_idx) contingency_dict = { cn : {'branch_contingency':cn} for cn in contingency_list} _ensure_contingencies_monitored.contingency_dicts[key] = contingency_dict md.data['elements']['contingency'] = _ensure_contingencies_monitored.contingency_dicts[key]
def populate_initial_state_data(self, options: Options, day: date, model: EgretModel) -> None: ''' Populate an existing model with initial state data for the requested day Sets T0 information from actuals: * initial_state_of_charge for each storage element * initial_status for each generator * initial_p_output for each generator Arguments --------- options: Option values day:date The day whose initial state will be saved in the model model: EgretModel The model whose values will be modifed ''' if day < self._first_day: day = self._first_day elif day > self._final_day: day = self._final_day actuals = self._get_actuals_by_date(day) for s, sdict in model.elements('storage'): soc = actuals.data['elements']['storage'][s][ 'initial_state_of_charge'] sdict['initial_state_of_charge'] = soc for g, gdict in model.elements('generator', generator_type='thermal'): source = actuals.data['elements']['generator'][g] gdict['initial_status'] = source['initial_status'] gdict['initial_p_output'] = source['initial_p_output']
def test_elements(): md = ModelData(dict(testdata)) for n, e in md.elements(element_type="generator"): assert n == 'G1' or n == 'G2' if n == 'G1': assert e["generator_type"] == 'thermal' if n == 'G2': assert e["generator_type"] == 'solar' buses = dict(md.elements(element_type='bus')) assert len(buses) == 4 assert 'B1' in buses assert 'B2' in buses assert 'B3' in buses assert 'B4' in buses assert buses['B1']['bus_type'] == 'PV' buses = dict(md.elements(element_type='bus', bus_type='PQ')) assert len(buses) == 2 assert 'B2' in buses assert 'B3' in buses buses = dict(md.elements(element_type='bus', bus_type=('PV', 'ref'))) assert len(buses) == 2 assert 'B1' in buses assert 'B4' in buses
def _copy_initial_state_into_model(options:Options, current_state:SimulationState, md:EgretModel): for g, g_dict in md.elements('generator', generator_type='thermal'): g_dict['initial_status'] = current_state.get_initial_generator_state(g) g_dict['initial_p_output'] = current_state.get_initial_power_generated(g) for s,s_dict in md.elements('storage'): s_dict['initial_state_of_charge'] = current_state.get_initial_state_of_charge(s)
def _populate_with_forecastable_data(self, options:Options, start_time:datetime, num_time_periods: int, time_period_length_minutes: int, model: EgretModel, identify_dat: Callable[[date], EgretModel] ) -> None: # For now, require the time period to always be 60 minutes assert(time_period_length_minutes == 60.0) step_delta = timedelta(minutes=time_period_length_minutes) # See if we have space to store all the requested data. # If not, only supply what we have space for if len(model.data['system']['time_keys']) < num_time_periods: num_time_periods = len(model.data['system']['time_keys']) # Collect a list of non-dispatchable generators renewables = list(model.elements('generator', generator_type='renewable')) start_hour = start_time.hour start_day = start_time.date() # Loop through each time step for step_index in range(0, num_time_periods): step_time = start_time + step_delta*step_index day = step_time.date() # 0-based hour, useable as index into forecast arrays hour = step_time.hour # For data starting at time 0, we collect tomorrow's data # from today's dat file if start_hour == 0 and day != start_day: day = start_day hour += 24 # If request is beyond the last day, just repeat the final day's values if day > self._final_day: day = self._final_day dat = identify_dat(day) # fill in renewables limits for gen, gdata in renewables: pmin = dat.data['elements']['generator'][gen]['p_min']['values'][hour] pmax = dat.data['elements']['generator'][gen]['p_max']['values'][hour] gdata['p_min']['values'][step_index] = pmin gdata['p_max']['values'][step_index] = pmax # Fill in load data for bus, bdata in model.elements('load'): load = dat.data['elements']['load'][bus]['p_load']['values'][hour] bdata['p_load']['values'][step_index] = load # Fill in reserve data reserve_req = dat.data['system']['reserve_requirement']['values'][hour] model.data['system']['reserve_requirement']['values'][step_index] = reserve_req
def _ensure_reserve_factor_honored(options:Options, md:EgretModel, time_periods:Iterable[int]) -> None: ''' Adjust reserve requirements to satisfy the reserve factor. For each time period in time_periods, ensure that the reserve requirement is no less than the total load for that time period multiplied by the reserve factor. If the reserve requirement for a time is too low it is raised, otherwise it is left alone. ''' if options.reserve_factor > 0: reserve_factor = options.reserve_factor reserve_reqs = md.data['system']['reserve_requirement']['values'] for t in time_periods: total_load = sum(bdata['p_load']['values'][t] for bus, bdata in md.elements('load')) min_reserve = reserve_factor*total_load if reserve_reqs[t] < min_reserve: reserve_reqs[t] = min_reserve