Skip to content

MESQUAL Membership Pairs Appender

BaseMembershipPairsAppender

Bases: ABC

Abstract base class for creating combination identifiers from paired energy system relationships.

In energy system modeling, many entities have directional relationships that require unique identification for analysis. This class provides a unified framework for creating combination identifiers from paired columns, particularly useful for:

  • Transmission lines connecting nodes (node_from/node_to combinations)
  • Regional trade flows (region_from/region_to pairs)
  • Pipeline connections (hub_from/hub_to relationships)
  • Market interconnections (market_from/market_to links)

The class supports three distinct combination strategies:

  1. Directional: Preserves relationship direction (A→B ≠ B→A)

    • Essential for analyzing flow directions, capacity constraints, and directional costs
  2. Sorted: Creates bidirectional identifiers (A→B = B→A becomes A-B)

    • Useful for identifying unique connections regardless of direction
  3. Opposite: Reverses relationship direction (A→B becomes B→A)

    • Enables reverse flow analysis and bidirectional modeling

This abstraction enables different implementation strategies (string concatenation, tuple creation, etc.) while maintaining consistent naming patterns across MESQUAL energy data models.

Parameters:

Name Type Description Default
from_identifier str

Suffix/prefix identifying source/origin columns. Defaults to '_from'.

'_from'
to_identifier str

Suffix/prefix identifying destination/target columns. Defaults to '_to'.

'_to'
combo_col_suffix str

Suffix for directional combination column names. Defaults to '_combo'.

'_combo'
combo_col_prefix str

Prefix for directional combination column names. Defaults to None.

None
sorted_combo_col_suffix str

Suffix for sorted combination column names. Defaults to '_combo_sorted'.

'_combo_sorted'
sorted_combo_col_prefix str

Prefix for sorted combination column names. Defaults to None.

None
opposite_combo_col_suffix str

Suffix for opposite combination column names. Defaults to '_combo_opposite'.

'_combo_opposite'
opposite_combo_col_prefix str

Prefix for opposite combination column names. Defaults to None.

None

Raises:

Type Description
ValueError

If neither suffix nor prefix is provided for any combination type.

Note

Either suffix or prefix must be specified for each combination type to ensure proper column naming conventions.

Examples:

>>> # For transmission line analysis
>>> appender = StringMembershipPairsAppender(separator=' → ')
>>> lines_df = appender.append_combo_columns(transmission_df)
>>> # Creates 'node_combo' column: 'NodeA → NodeB'

>>> # For bidirectional connections
>>> lines_df = appender.append_sorted_combo_columns(transmission_df)
>>> # Creates 'node_combo_sorted' column: 'NodeA → NodeB' (alphabetical)
>>> lines_df = appender.append_opposite_combo_columns(transmission_df)
>>> # Creates 'node_combo_opposite' column: 'NodeB → NodeA' (alphabetical)
Source code in submodules/mesqual/mesqual/energy_data_handling/model_handling/membership_pairs_appender.py
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
class BaseMembershipPairsAppender(ABC):
    """Abstract base class for creating combination identifiers from paired energy system relationships.

    In energy system modeling, many entities have directional relationships that require
    unique identification for analysis. This class provides a unified framework for creating
    combination identifiers from paired columns, particularly useful for:

    - Transmission lines connecting nodes (node_from/node_to combinations)
    - Regional trade flows (region_from/region_to pairs)
    - Pipeline connections (hub_from/hub_to relationships)
    - Market interconnections (market_from/market_to links)

    The class supports three distinct combination strategies:

    1. **Directional**: Preserves relationship direction (A→B ≠ B→A)
        - Essential for analyzing flow directions, capacity constraints, and directional costs

    2. **Sorted**: Creates bidirectional identifiers (A→B = B→A becomes A-B)
        - Useful for identifying unique connections regardless of direction

    3. **Opposite**: Reverses relationship direction (A→B becomes B→A)
        - Enables reverse flow analysis and bidirectional modeling

    This abstraction enables different implementation strategies (string concatenation,
    tuple creation, etc.) while maintaining consistent naming patterns across MESQUAL
    energy data models.

    Args:
        from_identifier: Suffix/prefix identifying source/origin columns. Defaults to '_from'.
        to_identifier: Suffix/prefix identifying destination/target columns. Defaults to '_to'.
        combo_col_suffix: Suffix for directional combination column names. Defaults to '_combo'.
        combo_col_prefix: Prefix for directional combination column names. Defaults to None.
        sorted_combo_col_suffix: Suffix for sorted combination column names. Defaults to '_combo_sorted'.
        sorted_combo_col_prefix: Prefix for sorted combination column names. Defaults to None.
        opposite_combo_col_suffix: Suffix for opposite combination column names. Defaults to '_combo_opposite'.
        opposite_combo_col_prefix: Prefix for opposite combination column names. Defaults to None.

    Raises:
        ValueError: If neither suffix nor prefix is provided for any combination type.

    Note:
        Either suffix or prefix must be specified for each combination type to ensure
        proper column naming conventions.

    Examples:

        >>> # For transmission line analysis
        >>> appender = StringMembershipPairsAppender(separator=' → ')
        >>> lines_df = appender.append_combo_columns(transmission_df)
        >>> # Creates 'node_combo' column: 'NodeA → NodeB'

        >>> # For bidirectional connections
        >>> lines_df = appender.append_sorted_combo_columns(transmission_df)
        >>> # Creates 'node_combo_sorted' column: 'NodeA → NodeB' (alphabetical)
        >>> lines_df = appender.append_opposite_combo_columns(transmission_df)
        >>> # Creates 'node_combo_opposite' column: 'NodeB → NodeA' (alphabetical)
    """
    def __init__(
            self,
            from_identifier: str = '_from',
            to_identifier: str = '_to',
            combo_col_suffix: str = '_combo',
            combo_col_prefix: str = None,
            sorted_combo_col_suffix: str = '_combo_sorted',
            sorted_combo_col_prefix: str = None,
            opposite_combo_col_suffix: str = '_combo_opposite',
            opposite_combo_col_prefix: str = None,
    ):
        self._from_identifier = from_identifier
        self._to_identifier = to_identifier

        self._combo_col_suffix = combo_col_suffix or ''
        self._combo_col_prefix = combo_col_prefix or ''
        if not any([self._combo_col_suffix, self._combo_col_prefix]):
            raise ValueError("Must specify either suffix or prefix for combo columns")

        self._sorted_combo_col_suffix = sorted_combo_col_suffix or ''
        self._sorted_combo_col_prefix = sorted_combo_col_prefix or ''
        if not any([self._sorted_combo_col_suffix, self._sorted_combo_col_prefix]):
            raise ValueError("Must specify either suffix or prefix for sorted combo columns")

        self._opposite_combo_col_suffix = opposite_combo_col_suffix or ''
        self._opposite_combo_col_prefix = opposite_combo_col_prefix or ''
        if not any([self._opposite_combo_col_suffix, self._opposite_combo_col_prefix]):
            raise ValueError("Must specify either suffix or prefix for opposite combo columns")

        self._common_base_key_finder = CommonBaseKeyFinder(from_identifier, to_identifier)

    def append_combo_columns(
            self,
            df_with_from_to_columns: pd.DataFrame,
    ) -> pd.DataFrame:
        """Creates directional combination columns preserving relationship direction.

        Generates combination identifiers that maintain the original direction of
        relationships, essential for energy system analysis where flow direction,
        capacity constraints, and directional costs matter.

        This method automatically identifies all paired columns (those with matching
        base names plus from/to identifiers) and creates directional combinations
        using the configured naming strategy.

        Args:
            df_with_from_to_columns: DataFrame containing paired relationship columns
                                   (e.g., 'node_from'/'node_to', 'region_from'/'region_to')

        Returns:
            Enhanced DataFrame with directional combination columns added.
            Original data preserved, new columns follow configured naming pattern.

        Examples:
            Transmission line directional analysis:

            >>> # DataFrame with node connections
            >>> lines_df = pd.DataFrame({
            ...     'line_id': ['L1', 'L2', 'L3'],
            ...     'node_from': ['NodeA', 'NodeB', 'NodeC'],
            ...     'node_to': ['NodeB', 'NodeA', 'NodeA'],
            ...     'capacity_mw': [1000, 800, 600]
            ... })
            >>> 
            >>> appender = StringMembershipPairsAppender(separator=' → ')
            >>> result = appender.append_combo_columns(lines_df)
            >>> # Result includes 'node_combo': ['NodeA → NodeB', 'NodeB → NodeA', 'NodeC → NodeA']
        """
        return self._append_combo_columns(df_with_from_to_columns, 'directional')

    def append_sorted_combo_columns(
            self,
            df_with_from_to_columns: pd.DataFrame,
    ) -> pd.DataFrame:
        """Creates bidirectional combination columns with alphabetical ordering.

        Generates combination identifiers that treat relationships as bidirectional
        by sorting the paired values alphabetically. This is particularly useful for
        identifying unique connections regardless of direction, such as:

        - Transmission line corridors (same physical connection)
        - Regional trade partnerships (bidirectional trade agreements)
        - Pipeline systems (flow can be reversed)
        - Market coupling arrangements (mutual price influence)

        Args:
            df_with_from_to_columns: DataFrame containing paired relationship columns
                                   with potential bidirectional connections

        Returns:
            Enhanced DataFrame with sorted combination columns added.
            Bidirectional relationships receive identical identifiers.

        Examples:
            Bidirectional connection analysis:

            >>> # DataFrame with potentially bidirectional connections
            >>> connections_df = pd.DataFrame({
            ...     'connection_id': ['C1', 'C2', 'C3'],
            ...     'region_from': ['DE', 'FR', 'DE'],
            ...     'region_to': ['FR', 'DE', 'NL'],
            ...     'trade_capacity': [2000, 2000, 1500]
            ... })
            >>> 
            >>> appender = StringMembershipPairsAppender(separator='-')
            >>> result = appender.append_sorted_combo_columns(connections_df)
            >>> # Result includes 'region_combo_sorted': ['DE-FR', 'DE-FR', 'DE-NL']
            >>> # Note: 'DE→FR' and 'FR→DE' both become 'DE-FR'
        """
        return self._append_combo_columns(df_with_from_to_columns, 'sorted')

    def append_opposite_combo_columns(
            self,
            df_with_from_to_columns: pd.DataFrame,
    ) -> pd.DataFrame:
        """Creates reverse-direction combination columns for opposite flow analysis.

        Generates combination identifiers with reversed direction, enabling analysis
        of reverse flows, return paths, and bidirectional modeling scenarios. This
        is particularly valuable for:

        - Reverse power flows in transmission networks
        - Return commodity flows in pipeline systems
        - Opposite direction trade flows
        - Backup routing analysis

        The method swaps the from/to values before creating combinations, effectively
        creating the opposite directional identifier for each relationship.

        Args:
            df_with_from_to_columns: DataFrame containing directional relationships
                                   where reverse analysis is needed

        Returns:
            Enhanced DataFrame with opposite-direction combination columns added.
            Each relationship receives its reverse-direction identifier.

        Examples:
            Reverse flow analysis:

            >>> # DataFrame with primary flow directions
            >>> flows_df = pd.DataFrame({
            ...     'flow_id': ['F1', 'F2', 'F3'],
            ...     'hub_from': ['HubA', 'HubB', 'HubC'],
            ...     'hub_to': ['HubB', 'HubC', 'HubA'],
            ...     'primary_flow': [100, 150, 80]
            ... })
            >>> 
            >>> appender = StringMembershipPairsAppender(separator=' ← ')
            >>> result = appender.append_opposite_combo_columns(flows_df)
            >>> # Result includes 'hub_combo_opposite': ['HubB ← HubA', 'HubC ← HubB', 'HubA ← HubC']
            >>> # Useful for modeling reverse flow scenarios
        """
        return self._append_combo_columns(df_with_from_to_columns, 'opposite')

    def _append_combo_columns(
            self,
            df_with_from_to_columns: pd.DataFrame,
            which_combo: Literal['directional', 'sorted', 'opposite']
    ) -> pd.DataFrame:
        from_id = self._from_identifier
        to_id = self._to_identifier

        _col_names = df_with_from_to_columns.columns
        base_columns = self._common_base_key_finder.get_keys_for_which_all_association_tags_appear(_col_names)

        for base in base_columns:
            from_col = f'{base}{from_id}'
            to_col = f'{base}{to_id}'

            _from_values = df_with_from_to_columns[from_col]
            _to_values = df_with_from_to_columns[to_col]

            if which_combo == 'directional':
                new_col = f'{self._combo_col_prefix}{base}{self._combo_col_suffix}'
                new_values = self._combine_values(_from_values, _to_values)
            elif which_combo == 'sorted':
                new_col = f'{self._sorted_combo_col_prefix}{base}{self._sorted_combo_col_suffix}'
                new_values = self._combine_sorted_values(_from_values, _to_values)
            elif which_combo == 'opposite':
                new_col = f'{self._opposite_combo_col_prefix}{base}{self._opposite_combo_col_suffix}'
                new_values = self._combine_values(_to_values, _from_values)
            else:
                raise NotImplementedError

            df_with_from_to_columns = set_column(df_with_from_to_columns, new_col, new_values)

        return df_with_from_to_columns

    @abstractmethod
    def _combine_values(self, a: pd.Series, b: pd.Series) -> pd.Series:
        pass

    @abstractmethod
    def _combine_sorted_values(self, a: pd.Series, b: pd.Series) -> pd.Series:
        pass

append_combo_columns

append_combo_columns(df_with_from_to_columns: DataFrame) -> DataFrame

Creates directional combination columns preserving relationship direction.

Generates combination identifiers that maintain the original direction of relationships, essential for energy system analysis where flow direction, capacity constraints, and directional costs matter.

This method automatically identifies all paired columns (those with matching base names plus from/to identifiers) and creates directional combinations using the configured naming strategy.

Parameters:

Name Type Description Default
df_with_from_to_columns DataFrame

DataFrame containing paired relationship columns (e.g., 'node_from'/'node_to', 'region_from'/'region_to')

required

Returns:

Type Description
DataFrame

Enhanced DataFrame with directional combination columns added.

DataFrame

Original data preserved, new columns follow configured naming pattern.

Examples:

Transmission line directional analysis:

>>> # DataFrame with node connections
>>> lines_df = pd.DataFrame({
...     'line_id': ['L1', 'L2', 'L3'],
...     'node_from': ['NodeA', 'NodeB', 'NodeC'],
...     'node_to': ['NodeB', 'NodeA', 'NodeA'],
...     'capacity_mw': [1000, 800, 600]
... })
>>> 
>>> appender = StringMembershipPairsAppender(separator=' → ')
>>> result = appender.append_combo_columns(lines_df)
>>> # Result includes 'node_combo': ['NodeA → NodeB', 'NodeB → NodeA', 'NodeC → NodeA']
Source code in submodules/mesqual/mesqual/energy_data_handling/model_handling/membership_pairs_appender.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
def append_combo_columns(
        self,
        df_with_from_to_columns: pd.DataFrame,
) -> pd.DataFrame:
    """Creates directional combination columns preserving relationship direction.

    Generates combination identifiers that maintain the original direction of
    relationships, essential for energy system analysis where flow direction,
    capacity constraints, and directional costs matter.

    This method automatically identifies all paired columns (those with matching
    base names plus from/to identifiers) and creates directional combinations
    using the configured naming strategy.

    Args:
        df_with_from_to_columns: DataFrame containing paired relationship columns
                               (e.g., 'node_from'/'node_to', 'region_from'/'region_to')

    Returns:
        Enhanced DataFrame with directional combination columns added.
        Original data preserved, new columns follow configured naming pattern.

    Examples:
        Transmission line directional analysis:

        >>> # DataFrame with node connections
        >>> lines_df = pd.DataFrame({
        ...     'line_id': ['L1', 'L2', 'L3'],
        ...     'node_from': ['NodeA', 'NodeB', 'NodeC'],
        ...     'node_to': ['NodeB', 'NodeA', 'NodeA'],
        ...     'capacity_mw': [1000, 800, 600]
        ... })
        >>> 
        >>> appender = StringMembershipPairsAppender(separator=' → ')
        >>> result = appender.append_combo_columns(lines_df)
        >>> # Result includes 'node_combo': ['NodeA → NodeB', 'NodeB → NodeA', 'NodeC → NodeA']
    """
    return self._append_combo_columns(df_with_from_to_columns, 'directional')

append_sorted_combo_columns

append_sorted_combo_columns(df_with_from_to_columns: DataFrame) -> DataFrame

Creates bidirectional combination columns with alphabetical ordering.

Generates combination identifiers that treat relationships as bidirectional by sorting the paired values alphabetically. This is particularly useful for identifying unique connections regardless of direction, such as:

  • Transmission line corridors (same physical connection)
  • Regional trade partnerships (bidirectional trade agreements)
  • Pipeline systems (flow can be reversed)
  • Market coupling arrangements (mutual price influence)

Parameters:

Name Type Description Default
df_with_from_to_columns DataFrame

DataFrame containing paired relationship columns with potential bidirectional connections

required

Returns:

Type Description
DataFrame

Enhanced DataFrame with sorted combination columns added.

DataFrame

Bidirectional relationships receive identical identifiers.

Examples:

Bidirectional connection analysis:

>>> # DataFrame with potentially bidirectional connections
>>> connections_df = pd.DataFrame({
...     'connection_id': ['C1', 'C2', 'C3'],
...     'region_from': ['DE', 'FR', 'DE'],
...     'region_to': ['FR', 'DE', 'NL'],
...     'trade_capacity': [2000, 2000, 1500]
... })
>>> 
>>> appender = StringMembershipPairsAppender(separator='-')
>>> result = appender.append_sorted_combo_columns(connections_df)
>>> # Result includes 'region_combo_sorted': ['DE-FR', 'DE-FR', 'DE-NL']
>>> # Note: 'DE→FR' and 'FR→DE' both become 'DE-FR'
Source code in submodules/mesqual/mesqual/energy_data_handling/model_handling/membership_pairs_appender.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
def append_sorted_combo_columns(
        self,
        df_with_from_to_columns: pd.DataFrame,
) -> pd.DataFrame:
    """Creates bidirectional combination columns with alphabetical ordering.

    Generates combination identifiers that treat relationships as bidirectional
    by sorting the paired values alphabetically. This is particularly useful for
    identifying unique connections regardless of direction, such as:

    - Transmission line corridors (same physical connection)
    - Regional trade partnerships (bidirectional trade agreements)
    - Pipeline systems (flow can be reversed)
    - Market coupling arrangements (mutual price influence)

    Args:
        df_with_from_to_columns: DataFrame containing paired relationship columns
                               with potential bidirectional connections

    Returns:
        Enhanced DataFrame with sorted combination columns added.
        Bidirectional relationships receive identical identifiers.

    Examples:
        Bidirectional connection analysis:

        >>> # DataFrame with potentially bidirectional connections
        >>> connections_df = pd.DataFrame({
        ...     'connection_id': ['C1', 'C2', 'C3'],
        ...     'region_from': ['DE', 'FR', 'DE'],
        ...     'region_to': ['FR', 'DE', 'NL'],
        ...     'trade_capacity': [2000, 2000, 1500]
        ... })
        >>> 
        >>> appender = StringMembershipPairsAppender(separator='-')
        >>> result = appender.append_sorted_combo_columns(connections_df)
        >>> # Result includes 'region_combo_sorted': ['DE-FR', 'DE-FR', 'DE-NL']
        >>> # Note: 'DE→FR' and 'FR→DE' both become 'DE-FR'
    """
    return self._append_combo_columns(df_with_from_to_columns, 'sorted')

append_opposite_combo_columns

append_opposite_combo_columns(df_with_from_to_columns: DataFrame) -> DataFrame

Creates reverse-direction combination columns for opposite flow analysis.

Generates combination identifiers with reversed direction, enabling analysis of reverse flows, return paths, and bidirectional modeling scenarios. This is particularly valuable for:

  • Reverse power flows in transmission networks
  • Return commodity flows in pipeline systems
  • Opposite direction trade flows
  • Backup routing analysis

The method swaps the from/to values before creating combinations, effectively creating the opposite directional identifier for each relationship.

Parameters:

Name Type Description Default
df_with_from_to_columns DataFrame

DataFrame containing directional relationships where reverse analysis is needed

required

Returns:

Type Description
DataFrame

Enhanced DataFrame with opposite-direction combination columns added.

DataFrame

Each relationship receives its reverse-direction identifier.

Examples:

Reverse flow analysis:

>>> # DataFrame with primary flow directions
>>> flows_df = pd.DataFrame({
...     'flow_id': ['F1', 'F2', 'F3'],
...     'hub_from': ['HubA', 'HubB', 'HubC'],
...     'hub_to': ['HubB', 'HubC', 'HubA'],
...     'primary_flow': [100, 150, 80]
... })
>>> 
>>> appender = StringMembershipPairsAppender(separator=' ← ')
>>> result = appender.append_opposite_combo_columns(flows_df)
>>> # Result includes 'hub_combo_opposite': ['HubB ← HubA', 'HubC ← HubB', 'HubA ← HubC']
>>> # Useful for modeling reverse flow scenarios
Source code in submodules/mesqual/mesqual/energy_data_handling/model_handling/membership_pairs_appender.py
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
def append_opposite_combo_columns(
        self,
        df_with_from_to_columns: pd.DataFrame,
) -> pd.DataFrame:
    """Creates reverse-direction combination columns for opposite flow analysis.

    Generates combination identifiers with reversed direction, enabling analysis
    of reverse flows, return paths, and bidirectional modeling scenarios. This
    is particularly valuable for:

    - Reverse power flows in transmission networks
    - Return commodity flows in pipeline systems
    - Opposite direction trade flows
    - Backup routing analysis

    The method swaps the from/to values before creating combinations, effectively
    creating the opposite directional identifier for each relationship.

    Args:
        df_with_from_to_columns: DataFrame containing directional relationships
                               where reverse analysis is needed

    Returns:
        Enhanced DataFrame with opposite-direction combination columns added.
        Each relationship receives its reverse-direction identifier.

    Examples:
        Reverse flow analysis:

        >>> # DataFrame with primary flow directions
        >>> flows_df = pd.DataFrame({
        ...     'flow_id': ['F1', 'F2', 'F3'],
        ...     'hub_from': ['HubA', 'HubB', 'HubC'],
        ...     'hub_to': ['HubB', 'HubC', 'HubA'],
        ...     'primary_flow': [100, 150, 80]
        ... })
        >>> 
        >>> appender = StringMembershipPairsAppender(separator=' ← ')
        >>> result = appender.append_opposite_combo_columns(flows_df)
        >>> # Result includes 'hub_combo_opposite': ['HubB ← HubA', 'HubC ← HubB', 'HubA ← HubC']
        >>> # Useful for modeling reverse flow scenarios
    """
    return self._append_combo_columns(df_with_from_to_columns, 'opposite')

StringMembershipPairsAppender

Bases: BaseMembershipPairsAppender

String-based implementation for creating combination identifiers from energy system relationships.

This concrete implementation creates human-readable string combinations from paired relationships using configurable separators. Particularly well-suited for:

  • Data visualization and reporting (readable connection labels)
  • User interface displays (network connection names)
  • Export formats requiring string identifiers
  • Debugging and data exploration

The class inherits all combination strategies from the base class while implementing string-specific combination logic with customizable separators for different use cases.

Parameters:

Name Type Description Default
separator str

String used to join paired values in combinations. Defaults to ' - '. Common patterns: ' → ' (directional), '-' (neutral), ' <-> ' (bidirectional)

' - '
**kwargs

All arguments from BaseMembershipPairsAppender for column naming configuration

required

Examples:

Energy system string combinations:

>>> # Transmission line connections with directional separator
>>> appender = StringMembershipPairsAppender(separator=' → ')
>>> lines_with_combos = appender.append_combo_columns(transmission_df)
>>> # Creates readable labels: 'NodeA → NodeB', 'NodeB → NodeC'
>>> # Regional trade connections with neutral separator
>>> trade_appender = StringMembershipPairsAppender(separator='-')
>>> trade_with_combos = trade_appender.append_sorted_combo_columns(trade_df)
>>> # Creates trade corridor labels: 'DE-FR', 'FR-NL'
Source code in submodules/mesqual/mesqual/energy_data_handling/model_handling/membership_pairs_appender.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
class StringMembershipPairsAppender(BaseMembershipPairsAppender):
    """String-based implementation for creating combination identifiers from energy system relationships.

    This concrete implementation creates human-readable string combinations from paired
    relationships using configurable separators. Particularly well-suited for:

    - Data visualization and reporting (readable connection labels)
    - User interface displays (network connection names)
    - Export formats requiring string identifiers
    - Debugging and data exploration

    The class inherits all combination strategies from the base class while implementing
    string-specific combination logic with customizable separators for different use cases.

    Args:
        separator: String used to join paired values in combinations. Defaults to ' - '.
                  Common patterns: ' → ' (directional), '-' (neutral), ' <-> ' (bidirectional)
        **kwargs: All arguments from BaseMembershipPairsAppender for column naming configuration

    Examples:
        Energy system string combinations:

        >>> # Transmission line connections with directional separator
        >>> appender = StringMembershipPairsAppender(separator=' → ')
        >>> lines_with_combos = appender.append_combo_columns(transmission_df)
        >>> # Creates readable labels: 'NodeA → NodeB', 'NodeB → NodeC'

        >>> # Regional trade connections with neutral separator
        >>> trade_appender = StringMembershipPairsAppender(separator='-')
        >>> trade_with_combos = trade_appender.append_sorted_combo_columns(trade_df)
        >>> # Creates trade corridor labels: 'DE-FR', 'FR-NL'
    """
    def __init__(
            self,
            from_identifier: str = '_from',
            to_identifier: str = '_to',
            combo_col_suffix: str = '_combo',
            combo_col_prefix: str = None,
            sorted_combo_col_suffix: str = '_combo_sorted',
            sorted_combo_col_prefix: str = None,
            opposite_combo_col_suffix: str = '_combo_opposite',
            opposite_combo_col_prefix: str = None,
            separator: str = ' - ',
    ):
        """Initialize the string-based membership pairs appender.

        Args:
            from_identifier: Suffix/prefix identifying source/origin columns. Defaults to '_from'.
            to_identifier: Suffix/prefix identifying destination/target columns. Defaults to '_to'.
            combo_col_suffix: Suffix for directional combination column names. Defaults to '_combo'.
            combo_col_prefix: Prefix for directional combination column names. Defaults to None.
            sorted_combo_col_suffix: Suffix for sorted combination column names. Defaults to '_combo_sorted'.
            sorted_combo_col_prefix: Prefix for sorted combination column names. Defaults to None.
            opposite_combo_col_suffix: Suffix for opposite combination column names. Defaults to '_combo_opposite'.
            opposite_combo_col_prefix: Prefix for opposite combination column names. Defaults to None.
            separator: String separator for joining paired values. Defaults to ' - '.
                      Use ' → ' for directional flows, '-' for neutral connections,
                      ' <-> ' for bidirectional relationships.
        """
        super().__init__(
            from_identifier=from_identifier,
            to_identifier=to_identifier,
            combo_col_suffix=combo_col_suffix,
            combo_col_prefix=combo_col_prefix,
            sorted_combo_col_suffix=sorted_combo_col_suffix,
            sorted_combo_col_prefix=sorted_combo_col_prefix,
            opposite_combo_col_suffix=opposite_combo_col_suffix,
            opposite_combo_col_prefix=opposite_combo_col_prefix,
        )
        self._separator = separator

    def _combine_values(self, a: pd.Series, b: pd.Series) -> pd.Series:
        """Combines two series into directional string combinations.

        Args:
            a: Source/origin values (from column)
            b: Destination/target values (to column)

        Returns:
            Series with string combinations preserving a→b direction
        """
        return a.astype(str) + self._separator + b.astype(str)

    def _combine_sorted_values(self, a: pd.Series, b: pd.Series) -> pd.Series:
        """Combines two series into bidirectional string combinations with alphabetical ordering.

        Args:
            a: First set of relationship values
            b: Second set of relationship values

        Returns:
            Series with alphabetically sorted string combinations (bidirectional)
        """
        return pd.DataFrame({
            'a': a.astype(str),
            'b': b.astype(str)
        }).apply(lambda x: self._separator.join(sorted([x['a'], x['b']])), axis=1)

__init__

__init__(from_identifier: str = '_from', to_identifier: str = '_to', combo_col_suffix: str = '_combo', combo_col_prefix: str = None, sorted_combo_col_suffix: str = '_combo_sorted', sorted_combo_col_prefix: str = None, opposite_combo_col_suffix: str = '_combo_opposite', opposite_combo_col_prefix: str = None, separator: str = ' - ')

Initialize the string-based membership pairs appender.

Parameters:

Name Type Description Default
from_identifier str

Suffix/prefix identifying source/origin columns. Defaults to '_from'.

'_from'
to_identifier str

Suffix/prefix identifying destination/target columns. Defaults to '_to'.

'_to'
combo_col_suffix str

Suffix for directional combination column names. Defaults to '_combo'.

'_combo'
combo_col_prefix str

Prefix for directional combination column names. Defaults to None.

None
sorted_combo_col_suffix str

Suffix for sorted combination column names. Defaults to '_combo_sorted'.

'_combo_sorted'
sorted_combo_col_prefix str

Prefix for sorted combination column names. Defaults to None.

None
opposite_combo_col_suffix str

Suffix for opposite combination column names. Defaults to '_combo_opposite'.

'_combo_opposite'
opposite_combo_col_prefix str

Prefix for opposite combination column names. Defaults to None.

None
separator str

String separator for joining paired values. Defaults to ' - '. Use ' → ' for directional flows, '-' for neutral connections, ' <-> ' for bidirectional relationships.

' - '
Source code in submodules/mesqual/mesqual/energy_data_handling/model_handling/membership_pairs_appender.py
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
def __init__(
        self,
        from_identifier: str = '_from',
        to_identifier: str = '_to',
        combo_col_suffix: str = '_combo',
        combo_col_prefix: str = None,
        sorted_combo_col_suffix: str = '_combo_sorted',
        sorted_combo_col_prefix: str = None,
        opposite_combo_col_suffix: str = '_combo_opposite',
        opposite_combo_col_prefix: str = None,
        separator: str = ' - ',
):
    """Initialize the string-based membership pairs appender.

    Args:
        from_identifier: Suffix/prefix identifying source/origin columns. Defaults to '_from'.
        to_identifier: Suffix/prefix identifying destination/target columns. Defaults to '_to'.
        combo_col_suffix: Suffix for directional combination column names. Defaults to '_combo'.
        combo_col_prefix: Prefix for directional combination column names. Defaults to None.
        sorted_combo_col_suffix: Suffix for sorted combination column names. Defaults to '_combo_sorted'.
        sorted_combo_col_prefix: Prefix for sorted combination column names. Defaults to None.
        opposite_combo_col_suffix: Suffix for opposite combination column names. Defaults to '_combo_opposite'.
        opposite_combo_col_prefix: Prefix for opposite combination column names. Defaults to None.
        separator: String separator for joining paired values. Defaults to ' - '.
                  Use ' → ' for directional flows, '-' for neutral connections,
                  ' <-> ' for bidirectional relationships.
    """
    super().__init__(
        from_identifier=from_identifier,
        to_identifier=to_identifier,
        combo_col_suffix=combo_col_suffix,
        combo_col_prefix=combo_col_prefix,
        sorted_combo_col_suffix=sorted_combo_col_suffix,
        sorted_combo_col_prefix=sorted_combo_col_prefix,
        opposite_combo_col_suffix=opposite_combo_col_suffix,
        opposite_combo_col_prefix=opposite_combo_col_prefix,
    )
    self._separator = separator

TupleMembershipPairsAppender

Bases: BaseMembershipPairsAppender

Tuple-based implementation for creating combination identifiers from energy system relationships.

This concrete implementation creates tuple combinations from paired relationships, offering several advantages for programmatic use:

  • Memory efficiency (no string concatenation overhead)
  • Fast equality comparisons and set operations
  • Preservation of original data types
  • Direct use as dictionary keys or index values
  • Integration with pandas MultiIndex structures

Particularly valuable for:

  • High-performance energy system simulations
  • Large-scale network analysis
  • Optimization model formulations
  • Internal data processing pipelines

The tuple format maintains the exact relationship structure while enabling efficient programmatic manipulation of connection data.

Examples:

Energy system tuple combinations:

>>> # Transmission network with tuple identifiers
>>> appender = TupleMembershipPairsAppender()
>>> lines_with_tuples = appender.append_combo_columns(transmission_df)
>>> # Creates tuple identifiers: ('NodeA', 'NodeB'), ('NodeB', 'NodeC')
>>> # Bidirectional connections for optimization
>>> lines_bidirectional = appender.append_sorted_combo_columns(transmission_df)
>>> # Creates sorted tuples: ('NodeA', 'NodeB'), ('NodeB', 'NodeC')
>>> # Useful as keys in optimization constraints
Source code in submodules/mesqual/mesqual/energy_data_handling/model_handling/membership_pairs_appender.py
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
class TupleMembershipPairsAppender(BaseMembershipPairsAppender):
    """Tuple-based implementation for creating combination identifiers from energy system relationships.

    This concrete implementation creates tuple combinations from paired relationships,
    offering several advantages for programmatic use:

    - Memory efficiency (no string concatenation overhead)
    - Fast equality comparisons and set operations
    - Preservation of original data types
    - Direct use as dictionary keys or index values
    - Integration with pandas MultiIndex structures

    Particularly valuable for:

    - High-performance energy system simulations
    - Large-scale network analysis
    - Optimization model formulations
    - Internal data processing pipelines

    The tuple format maintains the exact relationship structure while enabling
    efficient programmatic manipulation of connection data.

    Examples:
        Energy system tuple combinations:

        >>> # Transmission network with tuple identifiers
        >>> appender = TupleMembershipPairsAppender()
        >>> lines_with_tuples = appender.append_combo_columns(transmission_df)
        >>> # Creates tuple identifiers: ('NodeA', 'NodeB'), ('NodeB', 'NodeC')

        >>> # Bidirectional connections for optimization
        >>> lines_bidirectional = appender.append_sorted_combo_columns(transmission_df)
        >>> # Creates sorted tuples: ('NodeA', 'NodeB'), ('NodeB', 'NodeC')
        >>> # Useful as keys in optimization constraints
    """
    def _combine_values(self, a: pd.Series, b: pd.Series) -> pd.Series:
        """Combines two series into directional tuple combinations.

        Args:
            a: Source/origin values (from column)
            b: Destination/target values (to column)

        Returns:
            Series with tuple combinations preserving (a, b) direction
        """
        return pd.Series([tuple(x) for x in zip(a, b)], index=a.index)

    def _combine_sorted_values(self, a: pd.Series, b: pd.Series) -> pd.Series:
        """Combines two series into bidirectional tuple combinations with alphabetical ordering.

        Args:
            a: First set of relationship values
            b: Second set of relationship values

        Returns:
            Series with alphabetically sorted tuple combinations (bidirectional)
        """
        return pd.Series([tuple(sorted([x, y])) for x, y in zip(a, b)], index=a.index)