def top_view_bridge( config: Config, abutments: bool = False, edges: bool = False, piers: bool = False, lanes: bool = False, lane_fill: bool = False, landscape: bool = True, compass: bool = False, ): """Plot the top view of a bridge's geometry. Args: bridge: the bridge top to plot. landscape: orient the plot in landscape (16 x 10) ? abutments: plot the bridge's abutments? edges: plot the longitudinal edges? piers: plot where the piers connect to the deck? lanes: plot lanes on the bridge? lane_fill: plot fill or only outline? compass: plot a compass rose? """ bridge = config.bridge if landscape: plt.landscape() plt.axis("equal") if edges: plt.hlines([bridge.z_min, bridge.z_max], 0, bridge.length) if abutments: plt.vlines([0, bridge.length], bridge.z_min, bridge.z_max) if piers: for pier in bridge.supports: z_min_top, z_max_top = pier.z_min_max_top() x_min, x_max = pier.x_min_max_top() plt.vlines([x_min, x_max], z_min_top, z_max_top) if lanes: for lane in bridge.lanes: plt.gca().add_patch( matplotlib.patches.Rectangle( (0, lane.z_min), bridge.length, lane.z_max - lane.z_min, facecolor="black" if lane_fill else "none", edgecolor="black", ) ) if compass: ax = plt.gca() # Reference to the original axis. dir_path = os.path.dirname(os.path.abspath(__file__)) compass_img = plt.imread(os.path.join(dir_path, "compass-rose.png")) c_len = max(bridge.width, bridge.length) * 0.2 ax_c = ax.inset_axes( [0, bridge.z_max + (c_len * 0.05), c_len, c_len], transform=ax.transData, ) ax_c.imshow(compass_img) ax_c.axis("off") plt.sca(ax) # Return control to the original axis. plt.xlabel("X position") plt.ylabel("Z position")
def wagen1_plot(c: Config): """Plot of wagen1 compared to given specification.""" plt.landscape() wheel_print = (0.31, 0.25) wheel_prints = [] for w_i in range(len(truck1.axle_distances) + 1): if w_i in [1, 2]: wheel_prints.append([wheel_print, wheel_print]) else: wheel_prints.append([wheel_print]) plt.subplot(1, 2, 1) xlim, ylim = topview_vehicle(truck1, wheel_prints=wheel_prints) plt.title("Truck 1 specification") plt.xlabel("Width (m)") plt.ylabel("Length (m)") plt.subplot(1, 2, 2) topview_vehicle(truck1, xlim=xlim, ylim=ylim) plt.title("Truck 1 in simulation") plt.xlabel("Width (m)") plt.ylabel("Length (m)") plt.savefig(c.get_image_path("vehicles", "wagen-1", bridge=False) + ".pdf") plt.close()
def make_boundary_plot(c: Config): """Top view of bridge with boundary conditions.""" plt.landscape() top_view_bridge(c.bridge, abutments=True, piers=True, compass=False) plt.vlines( [0, c.bridge.length], c.bridge.z_min, c.bridge.z_max, lw=5, color="orange", label=" Y = 1, Z = 1", ) for p_i, pier in enumerate(c.bridge.supports): z_min_top, z_max_top = pier.z_min_max_bottom() x_min, x_max = pier.x_min_max_top() x_center = x_min + ((x_max - x_min) / 2) plt.vlines( [x_center], z_min_top, z_max_top, lw=5, color="red" if (8 <= p_i <= 15) else "orange", label="X = 1, Y = 1, Z = 1" if p_i == 8 else None, ) legend_marker_size(plt.legend(), 50) plt.title("Bridge 705 boundary conditions of nodal supports") plt.tight_layout() plt.savefig(c.get_image_path("sensors", "boundary.pdf")) plt.close()
def temperature_effect_date(c: Config, month: str, vert: bool): temp = __init__.load(name=month) point = Point(x=51, y=0, z=-8.4) plt.landscape() def plot_hours(): if not vert: return label_set = False for dt in temp["datetime"]: if np.isclose(float(dt.hour + dt.minute), 0): label = None if not label_set: label = "Time at vertical line = 00:00" label_set = True plt.axvline(x=dt, linewidth=1, color="black", label=label) # Plot the temperature. plt.subplot(2, 1, 1) plot_hours() plt.scatter( temp["datetime"], temp["temp"], c=temp["missing"], cmap=mpl.cm.get_cmap("bwr"), s=1, ) plt.ylabel("Temperature (°C)") plt.xlabel("Date") plt.gcf().autofmt_xdate() plt.title(f"Temperature in {str(month[0]).upper()}{month[1:]}") plt.legend() # Plot the effect at a point. response_type = ResponseType.YTranslation plt.subplot(2, 1, 2) plot_hours() effect = __init__.effect( c=c, response_type=response_type, points=[point], temps=temp["temp"] )[0] plt.scatter( temp["datetime"], effect * 1000, c=temp["missing"], cmap=mpl.cm.get_cmap("bwr"), s=1, ) plt.ylabel(f"{response_type.name()} (mm)") plt.xlabel("Date") plt.gcf().autofmt_xdate() plt.title(f"{response_type.name()} to unit thermal loading in {month}") # Save. plt.tight_layout() plt.savefig(c.get_image_path("classify/temperature", f"{month}.png")) plt.savefig(c.get_image_path("classify/temperature", f"{month}.pdf")) plt.close()
def angles_3d( xs: List[float], ys: List[float], zs: List[float], angles: Optional[List[float]] = None, elev: Optional[float] = None, ): """Rotate a plot in 3D, yielding the axis and angle. TODO: Deprecate. Args: angles: Optional[List[float]], angles to plot at, if None use default angle. elev: Optional[float], elevation used if 'angles' is given. """ xs, ys, zs = np.array(xs), np.array(ys), np.array(zs) # Determine values for scaling axes. max_range = (np.array( [xs.max() - xs.min(), ys.max() - ys.min(), zs.max() - zs.min()]).max() / 2.0) mid_x = (xs.max() + xs.min()) * 0.5 mid_y = (ys.max() + ys.min()) * 0.5 mid_z = (zs.max() + zs.min()) * 0.5 # Ensure at least one angle in default case. if angles is None: angles = [None] # Plot for different angles. for ii in angles: plt.landscape() fig = plt.figure() # ax = fig.add_subplot(111, projection="3d", proj_type="ortho") ax = Axes3D(fig) ax.set_xlim(mid_x - max_range, mid_x + max_range) ax.set_ylim(mid_y - max_range, mid_y + max_range) ax.set_zlim(mid_z - max_range, mid_z + max_range) if ii is not None: ax.view_init(elev=elev, azim=ii) yield fig, ax, ii
def ax_3d( xs: List[float], ys: List[float], zs: List[float], ): """Return a new figure and 3D axis scaled to given data.""" xs, ys, zs = np.array(xs), np.array(ys), np.array(zs) max_range = (np.array( [xs.max() - xs.min(), ys.max() - ys.min(), zs.max() - zs.min()]).max() / 2.0) mid_x = (xs.max() + xs.min()) * 0.5 mid_y = (ys.max() + ys.min()) * 0.5 mid_z = (zs.max() + zs.min()) * 0.5 plt.landscape() fig = plt.figure() ax = fig.add_subplot(111, projection="3d", proj_type="ortho") ax.set_xlim(mid_x - max_range, mid_x + max_range) ax.set_ylim(mid_y - max_range, mid_y + max_range) ax.set_zlim(mid_z - max_range, mid_z + max_range) return fig, ax
def number_of_uls_plot(c: Config): """Plot error as a function of number of unit load simulations.""" if not c.shorten_paths: raise ValueError("This plot requires --shorten-paths true") response_type = ResponseType.YTranslation num_ulss = np.arange(100, 2000, 10) chosen_uls = 600 point = Point(x=c.bridge.x_max - (c.bridge.length / 2), y=0, z=-8.4) wagen1_time = truck1.time_at(x=point.x, bridge=c.bridge) print_i(f"Wagen 1 time at x = {point.x:.3f} is t = {wagen1_time:.3f}") # Determine the reference value. truck_loads = flatten( truck1.to_point_load_pw(time=wagen1_time, bridge=c.bridge), PointLoad) print_i(f"Truck loads = {truck_loads}") sim_responses = load_fem_responses( c=c, response_type=response_type, sim_runner=OSRunner(c), sim_params=SimParams(ploads=truck_loads, response_types=[response_type]), ) ref_value = sim_responses.at_deck(point, interp=True) * 1000 print_i(f"Reference value = {ref_value}") # Collect the data. total_load = [] num_loads = [] responses = [] for num_uls in num_ulss: c.il_num_loads = num_uls # Nested in here because it depends on the setting of 'il_num_loads'. truck_loads = flatten( truck1.to_wheel_track_loads(c=c, time=wagen1_time), PointLoad) num_loads.append(len(truck_loads)) total_load.append(sum(map(lambda l: l.kn, truck_loads))) sim_responses = load_fem_responses( c=c, response_type=response_type, sim_runner=OSRunner(c), sim_params=SimParams(ploads=truck_loads, response_types=[response_type]), ) responses.append(sim_responses.at_deck(point, interp=True) * 1000) # Plot the raw fem, then error on the second axis. plt.landscape() # plt.plot(num_ulss, fem) # plt.ylabel(f"{response_type.name().lower()} (mm)") plt.xlabel("ULS") error = np.abs(np.array(responses) - ref_value).flatten() * 100 # ax2 = plt.twinx() plt.plot(num_ulss, error) plt.ylabel("Error (%)") plt.title( f"Error in {response_type.name()} to Truck 1 as a function of ULS") # Plot the chosen number of ULS. chosen_error = np.interp([chosen_uls], num_ulss, error)[0] plt.axhline( chosen_error, label=f"At {chosen_uls} ULS, error = {np.around(chosen_error, 2)} %", color="black", ) plt.axhline(0, color="red", label="Response from direct simulation (no wheel tracks)") plt.legend() plt.tight_layout() plt.savefig(c.get_image_path("paramselection", "uls.pdf")) plt.close() # Additional verification plots. plt.plot(num_ulss, total_load) plt.savefig(c.get_image_path("paramselection", "uls-verify-total-load.pdf")) plt.close() plt.plot(num_ulss, num_loads) plt.savefig(c.get_image_path("paramselection", "uls-verify-num-loads.pdf")) plt.close()
def pairwise_sensors(c: Config, dist_measure=ks_no_outliers): """Compare distribution of pairs of sensors under HealthyScenario.""" normal_traffic_array, traffic_scenario = load_normal_traffic_array(c) response_type = ResponseType.YTranslation points = [ Point(x=x, y=0, z=z) for x, z in itertools.product( np.linspace(c.bridge.x_min, c.bridge.x_max, 50), np.linspace(c.bridge.z_min, c.bridge.z_max, 4), ) ] bridge_scenario = HealthyScenario() responses = responses_to_traffic_array( c=c, traffic_array=normal_traffic_array, response_type=response_type, bridge_scenario=bridge_scenario, points=points, sim_runner=OSRunner, ).T assert len(responses) == len(points) ks_values_healthy = [] for p0, point0 in enumerate(points): print_i(f"Point {p0 + 1} / {len(points)}") ks_values_healthy.append([]) for p1, point1 in enumerate(points): ks = dist_measure(responses[p0], responses[p1]) ks_values_healthy[-1].append(ks) plt.landscape() plt.imshow(ks_values_healthy) plt.savefig(c.get_image_path("joint-clustering", "healthy-bridge")) plt.close() bridge_scenario = each_pier_scenarios(c)[0] responses = responses_to_traffic_array( c=c, traffic_array=normal_traffic_array, response_type=response_type, bridge_scenario=bridge_scenario, points=points, sim_runner=OSRunner, ).T assert len(responses) == len(points) ks_values_damage = [] for p0, point0 in enumerate(points): print_i(f"Point {p0 + 1} / {len(points)}") ks_values_damage.append([]) for p1, point1 in enumerate(points): ks = dist_measure(responses[p0], responses[p1]) ks_values_damage[-1].append(ks) plt.imshow(ks_values_damage) plt.savefig(c.get_image_path("joint-clustering", "scenarios-bridge")) plt.close() ks_values_comp = [] for p0, point0 in enumerate(points): ks_values_comp.append([]) for p1, point1 in enumerate(points): comp = abs(ks_values_healthy[p0][p1] - ks_values_damage[p0][p1]) ks_values_comp[-1].append(comp) plt.landscape() plt.imshow(ks_values_comp) plt.savefig(c.get_image_path("joint-clustering", "scenarios-bridge-comp")) plt.close() responses = Responses.from_responses( response_type=response_type, responses=[(sum(ks_values_comp[p]), point) for p, point in enumerate(points)], ) top_view_bridge(c.bridge, abutments=True, piers=True) plot_contour_deck(c=c, responses=responses) plt.savefig(c.get_image_path("joint-clustering", "scenarios-bridge-comp-contour")) plt.close()
def plot_mmm_strain_convergence( c: Config, pier: int, df: pd.DataFrame, all_strains: Dict[float, Responses], title: str, without: Optional[Callable[[Point], bool]] = None, append: Optional[str] = None, ): """Plot convergence of given fem as model size grows.""" # A grid of points 1m apart, over which to calculate fem. grid = [ Point(x=x, y=0, z=z) for x, z in itertools.product( np.linspace(c.bridge.x_min, c.bridge.x_max, int(c.bridge.length)), np.linspace(c.bridge.z_min, c.bridge.z_max, int(c.bridge.width)), ) ] # If requested, remove some values from the fem. if without is not None: grid = [point for point in grid if not without(point)] for msl, strains in all_strains.items(): print(f"Removing points from strains with max_shell_len = {msl}") all_strains[msl] = strains.without(without) # Collect fem over all fem, and over the grid. Iterate by # decreasing max_shell_len. mins, maxes, means = [], [], [] gmins, gmaxes, gmeans = [], [], [] max_shell_lens = [] for msl, strains in sorted(all_strains.items(), key=lambda kv: -kv[0]): max_shell_lens.append(msl) print_i(f"Gathering strains with max_shell_len = {msl}", end="\r") grid_strains = np.array([strains.at_deck(point, interp=True) for point in grid]) gmins.append(scalar(np.min(grid_strains))) gmaxes.append(scalar(np.max(grid_strains))) gmeans.append(scalar(np.mean(grid_strains))) strains = np.array(list(strains.values())) mins.append(scalar(np.min(strains))) maxes.append(scalar(np.max(strains))) means.append(scalar(np.mean(strains))) print() # Normalize and plot the mins, maxes, and means. def normalize(ys): print(ys) return ys / np.mean(ys[-5:]) mins, maxes, means = normalize(mins), normalize(maxes), normalize(means) gmins, gmaxes, gmeans = normalize(gmins), normalize(gmaxes), normalize(gmeans) deck_nodes = [df.at[msl, "deck-nodes"] for msl in max_shell_lens] pier_nodes = [df.at[msl, "pier-nodes"] for msl in max_shell_lens] num_nodes = np.array(deck_nodes) + np.array(pier_nodes) print(f"MSLs = {max_shell_lens}") print(f"num_nodes = {num_nodes}") # Plot all lines, for debugging. plt.landscape() plt.plot(num_nodes, mins, label="mins") plt.plot(num_nodes, maxes, label="maxes") plt.plot(num_nodes, means, label="means") plt.plot(num_nodes, gmins, label="gmins") plt.plot(num_nodes, gmaxes, label="gmaxes") plt.plot(num_nodes, gmeans, label="gmeans") plt.grid(axis="y") plt.xlabel("Nodes in FEM") plt.ylabel("Strain") plt.title(title) plt.tight_layout() plt.legend() plt.savefig( c.get_image_path("convergence-pier-strain", f"mmm-{append}-all.pdf", acc=False) ) plt.close() # Only plot some lines, for the thesis. plt.landscape() plt.plot(num_nodes, gmins, label="Minimum") plt.plot(num_nodes, gmaxes, label="Maximum") plt.plot(num_nodes, gmeans, label="Mean") plt.grid(axis="y") plt.title(title) plt.xlabel("Nodes in FEM") plt.ylabel("Strain") plt.legend() plt.tight_layout() plt.savefig( c.get_image_path("convergence-pier-strain", f"mmm-{append}.pdf", acc=False) ) plt.close()