def test_connect(trans_costs, capacity, gid, trans_table): """ Test connection to transmission lines and load centers """ tf = TF(trans_table, **trans_costs) avail_cap = tf[gid].get('avail_cap', None) if avail_cap is not None: if avail_cap > capacity: assert tf.connect(gid, capacity, apply=False)
def test_cost_calculation(i, trans_costs, distance, gid, trans_table): """ Test tranmission capital cost calculation """ tf = TF(trans_table, **trans_costs) true_cost = COSTS['{}-{}-{}'.format(i, distance, gid)] trans_cost = tf.cost(gid, distance) assert true_cost == trans_cost
def test_substation_connect(trans_table): """ Test connection to substation """ capacity = 350 gid = 68867 tf = TF(trans_table, **TRANS_COSTS_1, line_limited=False) assert tf.connect(gid, capacity, apply=False) tf = TF(trans_table, **TRANS_COSTS_1, line_limited=True) assert not tf.connect(gid, capacity, apply=False)
def _create_handler(trans_table, trans_costs=None): """ Create TransmissionFeatures handler from supply curve transmission mapping table. Update connection costs if given. Parameters ---------- trans_table : str | pandas.DataFrame Path to .csv or .json or DataFrame containing supply curve transmission mapping trans_costs : str | dict Transmission feature costs to use with TransmissionFeatures handler: line_tie_in_cost, line_cost, station_tie_in_cost, center_tie_in_cost, sink_tie_in_cost Returns ------- trans_features : TransmissionFeatures TransmissionFeatures or TransmissionCosts instance initilized with specified transmission costs """ if trans_costs is not None: kwargs = TF._parse_dictionary(trans_costs) else: kwargs = {} trans_features = TF(trans_table, **kwargs) return trans_features
def _feature_capacity(trans_table, trans_costs=None): """ Add the transmission connection feature capacity to the trans table. Parameters ---------- trans_table : pd.DataFrame Table mapping supply curve points to transmission features trans_costs : str | dict Transmission feature costs to use with TransmissionFeatures handler: line_tie_in_cost, line_cost, station_tie_in_cost, center_tie_in_cost, sink_tie_in_cost Returns ------- trans_table : pd.DataFrame Table mapping supply curve points to transmission features with 'avail_cap' column. """ avc = 0.1 if trans_costs is not None: if 'available_capacity' in trans_costs: avc = trans_costs['available_capacity'] feature_cap = TF.feature_capacity(trans_table, available_capacity=avc) dtype = trans_table['trans_line_gid'].dtype feature_cap['trans_line_gid'] = \ feature_cap['trans_line_gid'].astype(dtype) trans_table = trans_table.merge(feature_cap, on='trans_line_gid') return trans_table
def test_substation_load_spreading(i, trans_costs, trans_table): """ Test load spreading on connection to substation """ capacity = 350 gid = 68867 tf = TF(trans_table, **trans_costs) connect = tf.connect(gid, capacity, apply=True) assert connect line_gids = tf[gid]['lines'] missing = [gid for gid in line_gids if gid not in LINE_CAPS[i]] assert not any(missing), 'New gids not in baseline: {}'.format(missing) for line_id in line_gids: msg = 'Bad line cap: {}'.format(line_id) assert LINE_CAPS[i][line_id] == tf[line_id]['avail_cap'], msg
def fix_missing_dependencies(self, condf, linedf, scdf, simple=False): """Check for and find fix missing feature line dependencies. Parameters ---------- condf: pd.core.frame.DataFrame Data frame of supply curve point to transmission line connections. linedf: pd.core.frame.DataFrame Data frame of transmission line features. Returns ------- pd.core.frame.DataFrame The same data frame with added entries if missing line dependencies were found. """ # This requires an extra function def find_point(row, scdf): """Find the closest supply curve point to a line.""" # Find all distances to this line line = row["geometry"] scdists = [point.distance(line) for point in scdf["geometry"]] # Find the closest point from the distances dist_m = np.min(scdists) point_idx = np.where(scdists == dist_m)[0][0] point_row = scdf.iloc[point_idx] # These have different field names fields = { "sc_point_gid": "sc_point_gid", "sc_row_ind": "sc_point_row_id", "sc_col_ind": "sc_point_col_id" } # We need that points identifiers for key, field in fields.items(): row[field] = point_row[key] # Finally add in distance in miles row["dist_mi"] = dist_m / 1609.34 # We only need these fields keepers = [ 'ac_cap', 'cap_left', 'category', 'trans_gids', 'trans_line_gid', 'dist_mi', 'sc_point_gid', 'sc_point_row_id', 'sc_point_col_id' ] row = row[keepers] return row # Get missings dependencies - catching error from reV.handlers.transmission import TransmissionFeatures missing_dependencies = [] try: TransmissionFeatures(condf)._check_feature_dependencies() except RuntimeError as e: error = str(e) missing_str = error[error.index("dependencies:") + 14:] missing_dict = ast.literal_eval(missing_str) for gids in missing_dict.values(): for gid in gids: missing_dependencies.append(gid) # Find those features and reformat mdf = linedf[linedf["gid"].isin(missing_dependencies)] mdf = mdf.replace("null", np.nan) mdf = mdf.apply(find_point, scdf=scdf, axis=1) # Append these to the table condf = pd.concat([condf, mdf]) return condf
def _compute_lcot(trans_table, fcr, trans_costs=None, max_workers=None, connectable=True, line_limited=False): """ Compute levelized cost of transmission for all combinations of supply curve points and tranmission features in trans_table Parameters ---------- trans_table : pd.DataFrame Table mapping supply curve points to transmission features MUST contain supply curve point capacity fcr : float Fixed charge rate needed to compute LCOT trans_costs : str | dict Transmission feature costs to use with TransmissionFeatures handler: line_tie_in_cost, line_cost, station_tie_in_cost, center_tie_in_cost, sink_tie_in_cost max_workers : int | NoneType Number of workers to use to compute lcot, if > 1 run in parallel. None uses all available cpu's. connectable : bool Determine if connection is possible line_limited : bool Substation connection is limited by maximum capacity of the attached lines, legacy method Returns ------- lcot : list Levelized cost of transmission for all supply curve - tranmission feature connections cost : list Capital cost of tramsmission for all supply curve - transmission feature connections """ if 'capacity' not in trans_table: raise SupplyCurveInputError('Supply curve table must have ' 'supply curve point capacity ' 'to compute lcot') if trans_costs is not None: trans_costs = TF._parse_dictionary(trans_costs) else: trans_costs = {} if max_workers is None: max_workers = os.cpu_count() gid_mask = ~pd.isna(trans_table['sc_gid']) logger.info('Computing LCOT costs for all possible connections...') if max_workers > 1: groups = trans_table[gid_mask].groupby('sc_gid') loggers = [__name__, 'reV.handlers.transmission'] with SpawnProcessPool(max_workers=max_workers, loggers=loggers) as exe: futures = [] for sc_gid, sc_table in groups: if connectable: capacity = sc_table['capacity'].unique() if len(capacity) == 1: capacity = capacity[0] else: msg = ('Each supply curve point should only have ' 'a single capacity, but {} has {}' .format(sc_gid, capacity)) logger.error(msg) raise RuntimeError(msg) else: capacity = None futures.append(exe.submit(TC.feature_costs, sc_table, capacity=capacity, line_limited=line_limited, **trans_costs)) cost = [future.result() for future in futures] cost = np.hstack(cost) else: feature = TC(trans_table, line_limited=line_limited, **trans_costs) cost = [] for _, row in trans_table[gid_mask].iterrows(): if connectable: capacity = row['capacity'] else: capacity = None tm = row.get('transmission_multiplier', 1) cost.append(feature.cost(row['trans_line_gid'], row['dist_mi'], capacity=capacity, transmission_multiplier=tm)) cost = np.array(cost, dtype='float32') cf_mean_arr = trans_table.loc[gid_mask, 'mean_cf'].values lcot = (cost * fcr) / (cf_mean_arr * 8760) logger.info('LCOT cost calculation is complete.') return lcot, cost