def get_node(self, x: float, y: float, z: float, deck: bool, comment: Optional[str] = None) -> Node: x, y, z = round_m(x), round_m(y), round_m(z) pos = (x, y, z) if pos not in self.nodes_by_pos: n_id = self.new_n_id() node = Node(n_id=n_id, x=x, y=y, z=z, deck=deck, comment=comment) self.nodes_by_id[n_id] = node self.nodes_by_pos[pos] = node self.nodes_by_pos_dict[x][y][z] = node return self.nodes_by_pos[pos]
def to_wheel_track_xs( self, c: "Config", wheel_x: float, wheel_track_xs: Optional[List[float]] = None ) -> Tuple[Tuple[float, float], Tuple[float, float]]: """X positions (and weighting) of unit loads for a x position. This implements wheel track bucketing! """ wheel_x = round_m(wheel_x) if wheel_track_xs is None: wheel_track_xs = c.bridge.wheel_track_xs(c) unit_load_x_ind = np.searchsorted(wheel_track_xs, wheel_x) unit_load_x = lambda: wheel_track_xs[unit_load_x_ind] if unit_load_x() > wheel_x: unit_load_x_ind -= 1 assert unit_load_x() <= wheel_x # If the unit load is an exact match just return it. if np.isclose(wheel_x, unit_load_x()): return ((wheel_x, 1), (0, 0)) # Otherwise, return a combination of two unit loads. In this case the # unit load's position is less than the wheel. unit_load_x_lo = unit_load_x() unit_load_x_hi = wheel_track_xs[unit_load_x_ind + 1] assert unit_load_x_hi > wheel_x dist_lo = abs(unit_load_x_lo - wheel_x) dist_hi = abs(unit_load_x_hi - wheel_x) dist = dist_lo + dist_hi return ((unit_load_x_lo, dist_hi / dist), (unit_load_x_hi, dist_lo / dist))
def __init__( self, n_id: int, x: float, y: float, z: float, deck: bool, pier: Optional[Support] = None, comment: Optional[str] = None, support: Optional[Support] = None, ): self.n_id = n_id self.x = round_m(x) self.y = round_m(y) self.z = round_m(z) self.pier = pier self.deck = deck self.comment = comment self.support = support
def id_str( c: Config, response_type: ResponseType, sim_runner: FEMRunner, wheel_zs: List[float], ): wheel_zs_str = [round_m(wheel_z) for wheel_z in wheel_zs] return ( f"il-{response_type.name()}-{sim_runner.name}-{c.il_unit_load_kn}" + f"-{c.il_num_loads}-z={wheel_zs_str}")
def _crack_deck(self, bridge: Bridge): """Adds cracked sections to the given bridge's deck.""" c_x_start, c_z_start, c_x_end, c_z_end = list( map(round_m, self.crack_area(bridge)) ) # print(f"crack x: (start, end) = ({c_x_start}, {c_x_end})") # print(f"crack z: (start, end) = ({c_z_start}, {c_z_end})") if callable(bridge.sections): raise NotImplementedError() # Find where the cracked area and current sections overlap. overlaps: List[Tuple[Section3D, float, float, float, float]] = [] for section in bridge.sections: s_x_start = round_m(bridge.x(section.start_x_frac)) s_z_start = round_m(bridge.z(section.start_z_frac)) s_x_end = round_m(bridge.x(section.end_x_frac)) s_z_end = round_m(bridge.z(section.end_z_frac)) # print() # print(f"section x: (start, end) = ({s_x_start}, {s_x_end})") # print(f"section z: (start, end) = ({s_z_start}, {s_z_end})") overlap_x_start = max(c_x_start, s_x_start) overlap_z_start = max(c_z_start, s_z_start) overlap_x_end = min(c_x_end, s_x_end) overlap_z_end = min(c_z_end, s_z_end) # print(f"overlap x (start, end) = ({overlap_x_start}, {overlap_x_end})") # print(f"overlap z (start, end) = ({overlap_z_start}, {overlap_z_end})") overlap_x = overlap_x_end - overlap_x_start overlap_z = overlap_z_end - overlap_z_start # print(f"overlap x = {overlap_x}") # print(f"overlap z = {overlap_z}") if overlap_x > 0 and overlap_z > 0: overlaps.append( ( section, overlap_x_start, overlap_z_start, overlap_x_end, overlap_z_end, ) ) # Create new cracked sections for each of these overlaps. cracked_sections, max_id = [], 1000000 for i, (section, x_start, z_start, x_end, z_end) in enumerate(overlaps): # print(f"x (start, end) = ({x_start}, {x_end})") # print(f"z (start, end) = ({z_start}, {z_end})") cracked_section = deepcopy(section) cracked_section.id = max_id + i + 1 y_x = cracked_section.youngs_x() cracked_section.youngs_x = lambda: 0.5 * y_x cracked_section.start_x_frac = bridge.x_frac(x_start) cracked_section.start_z_frac = bridge.z_frac(z_start) cracked_section.end_x_frac = bridge.x_frac(x_end) cracked_section.end_z_frac = bridge.z_frac(z_end) cracked_sections.append(cracked_section) bridge.sections = cracked_sections + bridge.sections
def wheel_track_xs(self, c: "Config"): """Unit load x positions for wheel tracks on this bridge.""" return round_m(np.linspace(c.bridge.x_min, c.bridge.x_max, c.il_num_loads))
def __init__(self, z0: float, z1: float, ltr: bool): self.z_min: float = round_m(min(z0, z1)) self.z_max: float = round_m(max(z0, z1)) self.ltr: bool = ltr self.width = round_m(self.z_max - self.z_min) self.z_center = round_m(self.z_min + (self.width / 2))
def z_min_max_bottom(self) -> Tuple[float, float]: """The min and max z positions for the bottom of this pier.""" half_bottom = self.width_bottom / 2 return round_m(self.z - half_bottom), round_m(self.z + half_bottom)
def z_min_max_top(self) -> Tuple[float, float]: """The min and max z positions for the top of this pier.""" half_top = self.width_top / 2 return round_m(self.z - half_top), round_m(self.z + half_top)
def y_min_max(self) -> Tuple[float, float]: """The min and max y positions for this pier.""" return round_m(-self.height), 0
def x_min_max_top(self) -> Tuple[float, float]: """The min and max x positions for the top of this pier.""" half_length = self.length / 2 return round_m(self.x - half_length), round_m(self.x + half_length)
def get_nodes_at_xy(self, x: float, y: float): x, y = round_m(x), round_m(y) return self.nodes_by_pos_dict[x][y].values()