Source code for pybtls.bridge.bridge
"""
The methods and classes that are not defined in Python are defined in C++ py_main.cpp.
"""
from ..lib.BTLS import _Bridge
from .influence_line import InfluenceLine, InfluenceSurface
from ..output.output_config import OutputConfig
from collections import defaultdict
from typing import Union
from numpy import isclose
__all__ = ["Bridge"]
[docs]
class Bridge:
_Bridge_Index = 0
def __init__(self, length: float, no_lane: int):
"""
A Bridge instance in Python stores the data for creating a CBridge instance in C++.
Parameters
----------
length : float\n
Bridge length in m.
no_lane : int\n
Number of bridge lanes.
"""
Bridge._Bridge_Index += 1
self._bridge_index = Bridge._Bridge_Index
self._length = length
self._no_lane = no_lane
self._no_load_effect = 0
self._inf_file_dict = defaultdict(dict)
self._threshold_list = []
def __getstate__(self):
attribute_dict = {}
attribute_dict["bridge_index"] = self._bridge_index
attribute_dict["length"] = self._length
attribute_dict["no_lane"] = self._no_lane
attribute_dict["no_load_effect"] = self._no_load_effect
attribute_dict["inf_file_dict"] = self._inf_file_dict
attribute_dict["threshold_list"] = self._threshold_list
return attribute_dict
def __setstate__(self, attribute_dict):
self._bridge_index = attribute_dict["bridge_index"]
self._length = attribute_dict["length"]
self._no_lane = attribute_dict["no_lane"]
self._no_load_effect = attribute_dict["no_load_effect"]
self._inf_file_dict = attribute_dict["inf_file_dict"]
self._threshold_list = attribute_dict["threshold_list"]
[docs]
def add_load_effect(
self,
inf_line_surf: Union[InfluenceLine, list[InfluenceLine], InfluenceSurface],
inf_weight: list[float] = None,
threshold: float = 0.0,
) -> None:
"""
Add a load effect to the bridge.
Parameters
----------
inf_line_surf : Union[InfluenceLine,list[InfluenceLine],InfluenceSurface] \n
An InfluenceLine (same IL for all lanes); \n
An InfluenceLine list (one IL per lane); \n
An InfluenceSurface (for all lanes).
inf_weight : list[float], optional \n
Influence weight (0.0 to 1.0). \n
The default is 1.0 for all lanes.
threshold : float, optional \n
Threshold for POT analysis. \n
The default is 0.0.
Returns
-------
None.
"""
if isinstance(inf_line_surf, list):
if not all(
isinstance(inf_line, InfluenceLine) for inf_line in inf_line_surf
):
raise TypeError("All influence line should be InfluenceLine objects.")
if len(inf_line_surf) != self._no_lane:
raise ValueError(
"The number of influence lines should be equal to the number of lanes."
)
if not all([inf_line._data_assigned for inf_line in inf_line_surf]):
raise ValueError("All influence lines should have their data assigned.")
self._no_load_effect += 1
self._inf_file_dict[str(self._no_load_effect)]["inf_line"] = inf_line_surf
elif isinstance(inf_line_surf, (InfluenceLine, InfluenceSurface)):
if not inf_line_surf._data_assigned:
raise ValueError(
"The influence line or surface should have its data assigned."
)
self._no_load_effect += 1
self._inf_file_dict[str(self._no_load_effect)]["inf_line"] = [
inf_line_surf
] * self._no_lane
else:
raise TypeError(
"The influence line or surface must be InfluenceLine or InfluenceSurface object(s)."
)
if inf_weight is None:
self._inf_file_dict[str(self._no_load_effect)]["weight"] = [
1.0
] * self._no_lane
else:
if len(inf_weight) != self._no_lane:
raise ValueError(
"The length of inf_weight should be equal to the number of lanes."
)
self._inf_file_dict[str(self._no_load_effect)]["weight"] = inf_weight
self._threshold_list.append(threshold)
def _get_bridge(self, output_config: OutputConfig) -> _Bridge:
"""
Get the created C++ CBridge instance.
"""
bridge = _Bridge(output_config)
bridge.setIndex(self._bridge_index)
bridge.setLength(self._length)
bridge.setNoLoadEffects(self._no_load_effect)
bridge.initializeLanes(self._no_lane)
for load_case in list(self._inf_file_dict.keys()):
for i in range(self._no_lane):
temp_inf_file = self._inf_file_dict[load_case]["inf_line"][i]
temp_weight = self._inf_file_dict[load_case]["weight"][i]
if isinstance(temp_inf_file, InfluenceLine):
temp_IL = temp_inf_file._get_IL()
elif isinstance(temp_inf_file, InfluenceSurface):
temp_IL_file = InfluenceLine("surface")
temp_IL_file.set_IL(inf_surf=temp_inf_file)
temp_IL = temp_IL_file._get_IL()
temp_IL.setIndex(int(load_case))
if not isclose(
temp_IL.getLength(), self._length, atol=1e-2
): # centimeter level matching
raise RuntimeError(
f"Influence line or surface for lane {i+1} load case {load_case} is shorter or longer than the bridge."
)
brige_lane = bridge.getBridgeLane(
i
) # bridge_lane is a CBridgeLane& object from C++.
brige_lane.addLoadEffect(temp_IL, temp_weight)
bridge.setThresholds(self._threshold_list)
return bridge
@property
def no_lane(self) -> int:
return self._no_lane
@property
def length(self) -> float:
return self._length