Skip to content

guying

Guying

Guying is a class that allows to calculate the loads on the guying system of a support.

Parameters:

Name Type Description Default

balance_engine

BalanceEngine

balance engine instance

required
Source code in src/mechaphlowers/core/models/guying.py
145
146
147
148
149
150
151
152
def __init__(self, balance_engine: BalanceEngine):
    """Initialize Guying with a BalanceEngine instance.

    Args:
        balance_engine (BalanceEngine): balance engine instance
    """
    self.balance_engine = balance_engine
    self.bundle_number = balance_engine.section_array.bundle_number

compute

compute(
    index: int,
    with_pulley: bool,
    altitude: float,
    horizontal_distance: float,
    side: Literal['left', 'right'] = 'left',
    view: Literal['support', 'span'] = 'support',
) -> GuyingResults

Calculate guying system loads and forces.

Parameters:

Name Type Description Default

index

int

Index of the support (0 to number of supports - 1) or span (0 to number of supports - 2) depending on the view

required

with_pulley

bool

Whether the guying system uses a pulley. If True, support_index must be a suspension support (between 1 and number of supports - 2)

required

altitude

float

Guying cable attachment height (m)

required

horizontal_distance

float

Horizontal distance to guying attachment point (m)

required

side

Literal['left', 'right']

Side of the guying system ('left' or 'right') depending on the view. For 'support' view, it indicates the side of the support. For 'span' view, it indicates the selected support in the span (left or right support regarding the span)

'left'

view

Literal['support', 'span']

View of the guying system ('support' or 'span')

'support'

Returns:

Name Type Description
GuyingResults GuyingResults

Results containing guying_tension, vertical_force, angle

Raises:

Type Description
ValueError

If with_pulley is True and index is not a suspension support or if side is not 'left' or 'right'.

TypeError

If input types are incorrect.

Examples:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
>>> from mechaphlowers.core.models.balance.engine import BalanceEngine
>>> from mechaphlowers.core.models.guying import Guying
>>> balance_engine = BalanceEngine(...)  # Initialize with appropriate parameters
>>> guying_calculator = Guying(balance_engine)
>>> results = guying_calculator.compute(
...     index=2,
...     with_pulley=False,
...     altitude=30.0,
...     horizontal_distance=50.0,
...     side='left',
...     view='support',
... )
>>> print(results)
Guying Load: 1234.0 N
Vertical Load: 567.0 N
Longitudinal Load: 89.0 N
Guying Angle (degrees): 25.0 deg
Source code in src/mechaphlowers/core/models/guying.py
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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def compute(
    self,
    index: int,
    with_pulley: bool,
    altitude: float,
    horizontal_distance: float,
    side: Literal['left', 'right'] = 'left',
    view: Literal['support', 'span'] = 'support',
) -> GuyingResults:
    """Calculate guying system loads and forces.

    Args:
        index (int): Index of the support (0 to number of supports - 1) or span (0 to number of supports - 2) depending on the view
        with_pulley (bool): Whether the guying system uses a pulley. If True, support_index must be a suspension support (between 1 and number of supports - 2)
        altitude (float): Guying cable attachment height (m)
        horizontal_distance (float): Horizontal distance to guying attachment point (m)
        side (Literal['left', 'right']): Side of the guying system ('left' or 'right') depending on the view. For 'support' view, it indicates the side of the support. For 'span' view, it indicates the selected support in the span (left or right support regarding the span)
        view (Literal['support', 'span']): View of the guying system ('support' or 'span')

    Returns:
        GuyingResults: Results containing guying_tension, vertical_force, angle

    Raises:
        ValueError: If with_pulley is True and index is not a suspension support or if side is not 'left' or 'right'.
        TypeError: If input types are incorrect.

    Examples:
        >>> from mechaphlowers.core.models.balance.engine import BalanceEngine
        >>> from mechaphlowers.core.models.guying import Guying
        >>> balance_engine = BalanceEngine(...)  # Initialize with appropriate parameters
        >>> guying_calculator = Guying(balance_engine)
        >>> results = guying_calculator.compute(
        ...     index=2,
        ...     with_pulley=False,
        ...     altitude=30.0,
        ...     horizontal_distance=50.0,
        ...     side='left',
        ...     view='support',
        ... )
        >>> print(results)
        Guying Load: 1234.0 N
        Vertical Load: 567.0 N
        Longitudinal Load: 89.0 N
        Guying Angle (degrees): 25.0 deg
    """
    if not isinstance(index, int):
        raise TypeError("index must be int")
    if not isinstance(with_pulley, bool):
        raise TypeError("with_pulley must be bool")
    if not isinstance(view, str):
        raise TypeError("view must be str")
    if view not in ['support', 'span']:
        raise ValueError("view must be 'support' or 'span'")
    for name, value in {
        "guying_altitude": altitude,
        "guying_horizontal_distance": horizontal_distance,
    }.items():
        if not isinstance(value, Real):
            raise TypeError(f"{name} must be a real number")

    span_shape = self.balance_engine.support_number

    if view == 'span':
        logger.debug("Span view is selected for guying calculation.")
        warnings.warn(
            "Span view is selected for guying calculation.",
            ViewChoiceWarning,
        )
        index, side = span_to_support_view_guying(index, side)

    if with_pulley and (index == 0 or index >= span_shape - 1):
        raise ValueError(
            "With pulley, guying number must be between 1 and number of supports - 2"
        )

    if index < 0 or index >= span_shape:
        raise ValueError(f"index must be between 0 and {span_shape - 1}")

    if side == 'left':
        vhl_right = (
            self.balance_engine.balance_model.vhl_under_chain_right()
        )
        vhl_v = vhl_right.V.value('N')[index]
        vhl_h = vhl_right.H.value('N')[index]
        vhl_l = vhl_right.L.value('N')[index]

    elif side == 'right':
        vhl_left = self.balance_engine.balance_model.vhl_under_chain_left()
        vhl_v = vhl_left.V.value('N')[index]
        vhl_h = vhl_left.H.value('N')[index]
        vhl_l = vhl_left.L.value('N')[index]

    else:
        raise ValueError("side must be 'left' or 'right'")

    slope = self.balance_engine.span_model.slope(side)[index]
    span_tension = self.balance_engine.span_model.T_h()[index]

    if with_pulley:
        return self.static_calculate_guying_loads_with_pulley(
            vhl_v=vhl_v,
            attachment_altitude=self.balance_engine.balance_model.attachment_altitude_after_solve[
                index
            ],
            guying_altitude=altitude,
            guying_horizontal_distance=horizontal_distance,
            insulator_weight=self.balance_engine.section_array.data.insulator_weight.iloc[
                index
            ],
            cable_linear_weight=self.balance_engine.cable_array.data.linear_weight.iloc[
                0
            ],
            bundle_number=self.bundle_number,
            span_tension=span_tension,
            span_slope=slope,
        )
    else:
        return self.static_calculate_guying_loads(
            vhl_h=vhl_h,
            vhl_l=vhl_l,
            vhl_v=vhl_v,
            attachment_altitude=self.balance_engine.balance_model.attachment_altitude_after_solve[
                index
            ],
            guying_altitude=altitude,
            guying_horizontal_distance=horizontal_distance,
            insulator_weight=self.balance_engine.section_array.data.insulator_weight.iloc[
                index
            ],
            cable_linear_weight=self.balance_engine.cable_array.data.linear_weight.iloc[
                0
            ],
            bundle_number=self.bundle_number,
        )

static_calculate_guying_loads staticmethod

Calculate guying system loads and forces (direct guying without pulley).

Parameters:

Name Type Description Default

vhl_h

float

Horizontal load component (N)

required

vhl_l

float

Lateral/longitudinal load component (N)

required

vhl_v

float

Vertical load component (N)

required

attachment_altitude

float

Attachment altitude of chain (m)

required

guying_altitude

float

Guying cable attachment height (m)

required

guying_horizontal_distance

float

Horizontal distance to guying attachment point (m)

required

insulator_weight

float

Chain/insulator weight (N)

required

cable_linear_weight

float

Linear weight of conductor (N/m)

required

bundle_number

int

Bundle coefficient (dimensionless)

required

Returns:

Name Type Description
GuyingResults GuyingResults

Results containing guying_tension, vertical_force, longitudinal_force, and guying_angle_degrees

Source code in src/mechaphlowers/core/models/guying.py
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
361
362
363
364
365
366
367
368
369
@staticmethod
def static_calculate_guying_loads(
    vhl_h: float,
    vhl_l: float,
    vhl_v: float,
    attachment_altitude: float,
    guying_altitude: float,
    guying_horizontal_distance: float,
    insulator_weight: float,  # chain weight
    cable_linear_weight: float,  # linear weight of conductor
    bundle_number: int,  # bundle coefficient
) -> GuyingResults:
    """
    Calculate guying system loads and forces (direct guying without pulley).

    Args:
        vhl_h (float): Horizontal load component (N)
        vhl_l (float): Lateral/longitudinal load component (N)
        vhl_v (float): Vertical load component (N)
        attachment_altitude (float): Attachment altitude of chain (m)
        guying_altitude (float): Guying cable attachment height (m)
        guying_horizontal_distance (float): Horizontal distance to guying attachment point (m)
        insulator_weight (float): Chain/insulator weight (N)
        cable_linear_weight (float): Linear weight of conductor (N/m)
        bundle_number (int): Bundle coefficient (dimensionless)

    Returns:
        GuyingResults: Results containing guying_tension, vertical_force, longitudinal_force, and guying_angle_degrees
    """

    # Calculate resultant of H and L loads for guying system compensation
    result_h_l = np.sqrt(vhl_h**2 + vhl_l**2)

    # Calculate altitude difference between chain attachment and guying attachment
    delta_alt = attachment_altitude - guying_altitude

    # Calculate the load in the guying cable
    # (horizontal_distance = horizontal distance to guying point)
    guying_tension = (
        result_h_l
        / guying_horizontal_distance
        * np.sqrt(guying_horizontal_distance**2 + delta_alt**2)
    )

    # Calculate total vertical load under console
    # Total vertical load = base + chain weight + counter weight
    #                      + vertical component of guying load
    #                      + guying cable self-weight

    # counterweight already taken into account in vhl_v

    #  warning here, /10 means unit conversion from N to daN
    force_v = (
        vhl_v
        + insulator_weight
        + (result_h_l / guying_horizontal_distance) * delta_alt
        + np.sqrt(guying_horizontal_distance**2 + delta_alt**2)
        * cable_linear_weight
        * bundle_number
    )

    # Calculate angle of guying cable with horizontal (in degrees)
    if guying_tension != 0:
        guying_angle_rad = np.arccos(result_h_l / guying_tension)
        guying_angle_deg = np.degrees(guying_angle_rad)
    else:
        guying_angle_deg = 0.0

    # Longitudinal load (L) is zero
    force_l = 0.0

    return GuyingResults(
        **{
            "guying_tension": Q_(np.round(guying_tension, 0), "N"),
            "vertical_force": Q_(np.round(force_v, 0), "N"),
            "longitudinal_force": Q_(force_l, "N"),
            "guying_angle_degrees": Q_(
                np.round(guying_angle_deg, 1), "deg"
            ),
        }
    )

static_calculate_guying_loads_with_pulley staticmethod

Calculate guying system loads and forces with pulley.

This method calculates the tension in the bundle at the pulley point, which becomes the tension in the guying cable. It includes longitudinal load calculation which is specific to pulley configuration.

Parameters:

Name Type Description Default

vhl_v

float

Vertical load component (N)

required

attachment_altitude

float

Attachment altitude of chain (m)

required

guying_altitude

float

Guying cable attachment height (m)

required

guying_horizontal_distance

float

Horizontal distance to guying attachment point (m)

required

insulator_weight

float

Chain/insulator weight (N)

required

cable_linear_weight

float

Linear weight of conductor (N/m)

required

bundle_number

int

Bundle coefficient (dimensionless)

required

span_tension

float

Horizontal tension in span (N)

required

span_slope

float

Span slope angle (radians)

required

Returns:

Name Type Description
GuyingResults GuyingResults

Results containing:

  • guying_tension: tension in guying cable (daN)
  • vertical_force: total vertical load under console (daN)
  • longitudinal_force: longitudinal load component (daN)
  • guying_angle_degrees: angle of guying cable with horizontal plane (degrees)
Source code in src/mechaphlowers/core/models/guying.py
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
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
@staticmethod
def static_calculate_guying_loads_with_pulley(
    vhl_v: float,
    attachment_altitude: float,
    guying_altitude: float,
    guying_horizontal_distance: float,
    insulator_weight: float,  # chain weight (pds_chaine)
    cable_linear_weight: float,  # linear weight of conductor (pds_lin)
    bundle_number: int,  # bundle coefficient (faisceau)
    span_tension: float,  # span horizontal tension (th)
    span_slope: float,  # span slope in radians (pente_g)
) -> GuyingResults:
    """
    Calculate guying system loads and forces with pulley.

    This method calculates the tension in the bundle at the pulley point,
    which becomes the tension in the guying cable. It includes longitudinal load
    calculation which is specific to pulley configuration.

    Args:
        vhl_v (float): Vertical load component (N)
        attachment_altitude (float): Attachment altitude of chain (m)
        guying_altitude (float): Guying cable attachment height (m)
        guying_horizontal_distance (float): Horizontal distance to guying attachment point (m)
        insulator_weight (float): Chain/insulator weight (N)
        cable_linear_weight (float): Linear weight of conductor (N/m)
        bundle_number (int): Bundle coefficient (dimensionless)
        span_tension (float): Horizontal tension in span (N)
        span_slope (float): Span slope angle (radians)

    Returns:
        GuyingResults: Results containing:
            <ul>
                <li>guying_tension: tension in guying cable (daN)</li>
                <li>vertical_force: total vertical load under console (daN)</li>
                <li>longitudinal_force: longitudinal load component (daN)</li>
                <li>guying_angle_degrees: angle of guying cable with horizontal plane (degrees)</li>
            </ul>
    """

    # ===== CALCULATION WITH PULLEY =====

    # Calculate tension in bundle at pulley point
    slope_rad = span_slope  # left slope (pente_g)

    # Tension in guying cable = span tension / cos(slope) * bundle factor
    guying_tension = span_tension / np.cos(slope_rad) * bundle_number

    # Calculate altitude difference between chain attachment and guying attachment
    delta_alt = attachment_altitude - guying_altitude

    # Calculate angle of guying cable with horizontal plane (in degrees)
    # Using arctan for angle calculation with pulley configuration
    guying_angle_rad = np.arctan(delta_alt / guying_horizontal_distance)
    guying_angle_deg = np.degrees(guying_angle_rad)

    # Calculate total vertical load under console

    # Add all vertical components:
    # - chain weight
    # - counter weight (already in vhl_v)
    # - vertical component of guying load (sin of angle * tension)
    # - self-weight of guying cable
    cable_length = np.sqrt(guying_horizontal_distance**2 + delta_alt**2)
    force_v = (
        vhl_v
        + insulator_weight
        + guying_tension * np.sin(guying_angle_rad)
        + cable_length * cable_linear_weight * bundle_number
    )

    # Calculate lateral load (L)
    # = bundle tension - horizontal component of guying load
    force_l = span_tension * bundle_number - guying_tension * np.cos(
        guying_angle_rad
    )

    return GuyingResults(
        **{
            "guying_tension": Q_(np.round(guying_tension, 0), "N"),
            "vertical_force": Q_(np.round(force_v, 0), "N"),
            "longitudinal_force": Q_(np.round(force_l, 0), "N"),
            "guying_angle_degrees": Q_(
                np.round(guying_angle_deg, 1), "deg"
            ),
        }
    )

GuyingResults

GuyingResults(
    guying_tension: Quantity,
    vertical_force: Quantity,
    longitudinal_force: Quantity,
    guying_angle_degrees: Quantity,
)

Class to store guying loads results.

Parameters:

Name Type Description Default

guying_tension

Quantity

Tension in guying cable

required

vertical_force

Quantity

Total vertical force under console

required

longitudinal_force

Quantity

Longitudinal load component

required

guying_angle_degrees

Quantity

Angle of guying cable with horizontal plane

required

Raises:

Type Description
TypeError

If any of the inputs are not of type Quantity

Examples:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
>>> from pint import UnitRegistry
>>> ureg = UnitRegistry()
>>> guying_tension = 1000 * ureg.newton
>>> vertical_force = 500 * ureg.newton
>>> longitudinal_force = 200 * ureg.newton
>>> guying_angle_degrees = 30 * ureg.degree
>>> results = GuyingResults(
...     guying_tension, vertical_force, longitudinal_force, guying_angle_degrees
... )
>>> print(results)
Guying Load: 1000.0 newton
Vertical Load: 500.0 newton
Longitudinal Load: 200.0 newton
Guying Angle (degrees): 30.0 degree
Source code in src/mechaphlowers/core/models/guying.py
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
def __init__(
    self,
    guying_tension: Quantity,
    vertical_force: Quantity,
    longitudinal_force: Quantity,
    guying_angle_degrees: Quantity,
):
    """Initialize GuyingResults with calculated values.

    Args:
        guying_tension (Quantity): Tension in guying cable
        vertical_force (Quantity): Total vertical force under console
        longitudinal_force (Quantity): Longitudinal load component
        guying_angle_degrees (Quantity): Angle of guying cable with horizontal plane

    Raises:
        TypeError: If any of the inputs are not of type Quantity

    Examples:
        >>> from pint import UnitRegistry
        >>> ureg = UnitRegistry()
        >>> guying_tension = 1000 * ureg.newton
        >>> vertical_force = 500 * ureg.newton
        >>> longitudinal_force = 200 * ureg.newton
        >>> guying_angle_degrees = 30 * ureg.degree
        >>> results = GuyingResults(
        ...     guying_tension, vertical_force, longitudinal_force, guying_angle_degrees
        ... )
        >>> print(results)
        Guying Load: 1000.0 newton
        Vertical Load: 500.0 newton
        Longitudinal Load: 200.0 newton
        Guying Angle (degrees): 30.0 degree

    """
    for name, qty in {
        "guying_tension": guying_tension,
        "vertical_force": vertical_force,
        "longitudinal_force": longitudinal_force,
        "guying_angle_degrees": guying_angle_degrees,
    }.items():
        if not isinstance(qty, Quantity):
            raise TypeError(f"{name} must be a Quantity")
    self.guying_tension = guying_tension
    self.vertical_force = vertical_force
    self.longitudinal_force = longitudinal_force
    self.guying_angle_degrees = guying_angle_degrees

    self.output_unit_force = options.output_units.force
    self.output_unit_length = options.output_units.length

quantity_dict property

quantity_dict: dict[str, Quantity]

Return the values as a dictionary with appropriate units.

str_repr property

str_repr: str

Return a string representation of the results.

value_dict property

value_dict: dict[str, float]

Return the values as a dictionary with appropriate units.