def plot_of_unit_loads(c: Config): """Make a contour plot of response at unit load position.""" fem_runner = OSRunner(c) response_type = ResponseType.YTranslation X, Z, R = [], [], [] for x in np.linspace(c.bridge.x_min, c.bridge.x_max, int(c.bridge.length)): X.append([]) Z.append([]) R.append([]) for z in np.linspace(c.bridge.z_min, c.bridge.z_max, int(c.bridge.width)): pload = PointLoad(x_frac=c.bridge.x_frac(x), z_frac=c.bridge.z_frac(z), kn=100) fem_params = SimParams(ploads=[pload], response_types=[response_type]) fem_responses = load_fem_responses( c=c, fem_params=fem_params, response_type=response_type, fem_runner=fem_runner, ) X[-1].append(x) Z[-1].append(z) R[-1].append(fem_responses._at(x=x, y=0, z=z)) cmap = get_cmap("bwr") plt.contourf(X, Z, R, levels=50, cmap=cmap) plt.show()
def cover_photo(c: Config, x: float, deformation_amp: float): """ TODO: SimParams takes any loads iterable, to be flattened. TODO: Wrap SimRunner into Config. TODO: Ignore response type in SimParams (fill in by load_sim_responses). """ response_type = ResponseType.YTranslation sim_responses = load_fem_responses( c=c, sim_runner=OSRunner(c), response_type=response_type, sim_params=SimParams( response_types=[response_type], ploads=list( chain.from_iterable( truck1.to_point_loads( bridge=c.bridge, time=truck1.time_at(x=x, bridge=c.bridge), ))), ), ) shells = contour_responses_3d(c=c, sim_responses=sim_responses) for cmap in [ parula_cmap, get_cmap("jet"), get_cmap("coolwarm"), get_cmap("viridis"), ]: contour_responses_3d( c=c, sim_responses=sim_responses, deformation_amp=deformation_amp, shells=shells, cmap=cmap, ) plt.axis("off") plt.grid(False) plt.savefig( c.get_image_path( "cover-photo", f"cover-photo-deform-{deformation_amp}" f"-cmap-{cmap.name}.pdf", )) plt.close()
def effect( c: Config, response_type: ResponseType, points: List[Point], temps_bt: Optional[Tuple[List[float], List[float]]] = None, len_per_hour: Optional[int] = None, temps: Optional[List[float]] = None, solar: Optional[List[float]] = None, d: bool = False, ret_temps_bt: bool = False, ) -> List[List[float]]: """Temperature effect at given points for a number of given temperatures. The result is of shape (number of points, number of temperatures). NOTE: The 'ThermalDamage' method 'to_strain' multiplies the results by E-6, which is called by this function. So take note that the strain values are already multiplied by E-6 (from microstrain to strain), and do not need to be resized. Args: c: Config, global configuration object. response_type: ResponseType, type of sensor response to temp. effect. points: List[Point], points at which to calculate temperature effect. temps_bt: A 2-tuple of arrays, the first array is for the temperatures at the bottom of the bridge, and the second array is for the temperatures at the top of the bridge. If this argument is given then 'temps', 'solar', 'len_per_hour' must not be given. len_per_hour: Optional[int], if given then temps and solar must also be given. The temperature fem are interpolated such that there are 'len_per_hour' fem for every hour of temperature data. It is assumed the temperature data is one data point per minute. temps: Optional[List[float]], first see 'len_per_hour'. Air temperature data given at one data point per minute. solar: Optional[List[float]], first see 'len_per_hour'. Solar irradiance data given at one data point per minute, same as 'temps'. """ if temps_bt is not None: if any(x is not None for x in [len_per_hour, temps, solar]): raise ValueError( "Must only pass 'temps_bt', or ('len_per_hour', 'temps' & 'solar')" ) original_c = c # Unit effect from uniform temperature loading. unit_uniform = ThermalScenario(axial_delta_temp=c.unit_axial_delta_temp_c) c, sim_params = unit_uniform.use(original_c) uniform_responses = load_fem_responses( c=c, sim_runner=OSRunner, response_type=response_type, sim_params=sim_params, ) # Unit effect from linear temperature loading. unit_linear = ThermalScenario(moment_delta_temp=c.unit_moment_delta_temp_c) c, sim_params = unit_linear.use(original_c) linear_responses = load_fem_responses( c=c, sim_runner=OSRunner, response_type=response_type, sim_params=sim_params, ) print_i("Loaded unit uniform and linear temperature fem") # Convert uniform fem to correct type (thermal post-processing). if response_type in [ ResponseType.Strain, ResponseType.StrainT, ResponseType.StrainZZB, ]: uniform_responses = unit_uniform.to_strain( c=c, sim_responses=uniform_responses) elif response_type == ResponseType.Stress: uniform_responses = unit_uniform.to_stress( c=c, sim_responses=uniform_responses) unit_uniforms = np.array(uniform_responses.at_decks(points)) print(f"Unit uniform temperature per point, shape = {unit_uniforms.shape}") # Convert linear fem to correct type (thermal post-processing). if response_type in [ ResponseType.Strain, ResponseType.StrainT, ResponseType.StrainZZB, ]: linear_responses = unit_linear.to_strain( c=c, sim_responses=linear_responses) elif response_type == ResponseType.Stress: linear_responses = unit_linear.to_stress( c=c, sim_responses=linear_responses) unit_linears = np.array(linear_responses.at_decks(points)) # Determine temperature gradient throughout the bridge. if temps_bt is None: temps_bottom, temps_top = temps_bottom_top(c=c, temps=temps, solar=solar, len_per_hour=len_per_hour) else: temps_bottom, temps_top = temps_bt temps_bottom, temps_top = np.array(temps_bottom), np.array(temps_top) temps_half = (temps_bottom + temps_top) / 2 temps_linear = temps_top - temps_bottom temps_uniform = temps_half - c.bridge.ref_temp_c # print(f"temps_bottom.shape = {temps_bottom.shape}") # print(f"temps_top.shape = {temps_top.shape}") # print(f"temps_half.shape = {temps_half.shape}") print_d(D, f"tb = {temps_bottom[:3]}") print_d(D, f"tt = {temps_top[:3]}") print_d(D, f"th = {temps_half[:3]}") print_d(D, f"temps linear = {temps_linear[:3]}") print_d(D, f"temps uniform = {temps_uniform[:3]}") # Combine uniform and linear fem. uniform_responses = np.array( [unit_uniform * temps_half for unit_uniform in unit_uniforms]) linear_responses = np.array( [unit_linear * temps_linear for unit_linear in unit_linears]) # print(f"uniform_responses.shape = {uniform_responses.shape}") # print(f"linear_responses.shape = {linear_responses.shape}") print_d(D, f"uniform fem = {uniform_responses[:3]}") print_d(D, f"linear fem = {linear_responses[:3]}") if d: return temps_uniform, temps_linear, uniform_responses + linear_responses if ret_temps_bt: return ((temps_bottom, temps_top), uniform_responses + linear_responses) return uniform_responses + linear_responses
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 comparison_plots_705(c: Config, run_only: bool, scatter: bool): """Make contour plots for all verification points on bridge 705.""" # from classify.scenario.bridge import transverse_crack # c = transverse_crack().use(c)[0] positions = [ # (52, -8.4, "a"), (34.95459, 26.24579 - 16.6, "a"), (51.25051, 16.6 - 16.6, "b"), (89.98269, 9.445789 - 16.6, "c"), (102.5037, 6.954211 - 16.6, "d"), # (34.95459, 29.22606 - 16.6, "a"), # (51.25051, 16.6 - 16.6, "b"), # (92.40638, 12.405 - 16.6, "c"), # (101.7649, 3.973938 - 16.6, "d"), ] diana_values = pd.read_csv("validation/diana-screenshots/min-max.csv") response_types = [ResponseType.YTranslation, ResponseType.Strain] # For each response type and loading position first create contour plots for # OpenSees. Then finally create subplots comparing to Diana. cmap = diana_cmap_r for load_x, load_z, label in positions: for response_type in response_types: # Setup the metadata. if response_type == ResponseType.YTranslation: rt_str = "displa" unit_str = "mm" elif response_type == ResponseType.Strain: rt_str = "strain" unit_str = "E-6" else: raise ValueError("Unsupported response type") row = diana_values[diana_values["name"] == f"{label}-{rt_str}"] dmin, dmax = float(row["dmin"]), float(row["dmax"]) omin, omax = float(row["omin"]), float(row["omax"]) amin, amax = max(dmin, omin), min(dmax, omax) levels = np.linspace(amin, amax, 16) # Create the OpenSees plot. loads = [ PointLoad( x_frac=c.bridge.x_frac(load_x), z_frac=c.bridge.z_frac(load_z), kn=100, ) ] fem_responses = load_fem_responses( c=c, response_type=response_type, sim_runner=OSRunner(c), sim_params=SimParams(ploads=loads, response_types=response_types), ) if run_only: continue title = ( f"{response_type.name()} from a {loads[0].kn} kN point load at" + f"\nx = {load_x:.3f}m, z = {load_z:.3f}m, with ") save = lambda prefix: c.get_image_path( "validation/diana-comp", safe_str(f"{prefix}{response_type.name()}") + ".pdf", ) top_view_bridge(c.bridge, piers=True, abutments=True) fem_responses = fem_responses.resize() sci_format = response_type == ResponseType.Strain plot_contour_deck( c=c, responses=fem_responses, ploads=loads, cmap=cmap, levels=levels, sci_format=sci_format, decimals=4, scatter=scatter, ) plt.title(title + "OpenSees") plt.tight_layout() plt.savefig(save(f"{label}-")) plt.close() # Finally create label/title the Diana plot. if label is not None: # First plot and clear, just to have the same colorbar. plot_contour_deck(c=c, responses=fem_responses, ploads=loads, cmap=cmap, levels=levels) plt.cla() # Then plot the bridge and top_view_bridge(c.bridge, piers=True, abutments=True) plt.imshow( mpimg.imread( f"validation/diana-screenshots/{label}-{rt_str}.png"), extent=( c.bridge.x_min, c.bridge.x_max, c.bridge.z_min, c.bridge.z_max, ), ) dmin_s = f"{dmin:.4e}" if sci_format else f"{dmin:.4f}" dmax_s = f"{dmax:.4e}" if sci_format else f"{dmax:.4f}" dabs_s = (f"{abs(dmin - dmax):.4e}" if sci_format else f"{abs(dmin - dmax):.4f}") for point, leg_label, color, alpha in [ ((load_x, load_z), f"{loads[0].kn} kN load", "r", 1), ((0, 0), f"min = {dmin_s} {fem_responses.units}", "r", 0), ((0, 0), f"max = {dmax_s} {fem_responses.units}", "r", 0), ((0, 0), f"|min-max| = {dabs_s} {fem_responses.units}", "r", 0), ]: plt.scatter( [point[0]], [point[1]], label=leg_label, marker="o", color=color, alpha=alpha, ) plt.legend() plt.title(title + "Diana") plt.xlabel("X position (m)") plt.ylabel("Z position (m)") plt.tight_layout() plt.savefig(save(f"{label}-diana-")) plt.close()
def piers_displaced(c: Config): """Contour plots of pier displacement for the given pier indices.""" pier_indices = [4, 5] response_types = [ResponseType.YTranslation, ResponseType.Strain] axis_values = pd.read_csv("validation/axis-screenshots/piers-min-max.csv") for r_i, response_type in enumerate(response_types): for p in pier_indices: # Run the simulation and collect fem. sim_responses = load_fem_responses( c=c, response_type=response_type, sim_runner=OSRunner(c), sim_params=SimParams(displacement_ctrl=PierSettlement( displacement=c.pd_unit_disp, pier=p), ), ) # In the case of stress we map from kn/m2 to kn/mm2 (E-6) and then # divide by 1000, so (E-9). assert c.pd_unit_disp == 1 if response_type == ResponseType.Strain: sim_responses.to_stress(c.bridge).map(lambda r: r * 1e-9) # Get min and max values for both Axis and OpenSees. rt_str = ("displa" if response_type == ResponseType.YTranslation else "stress") row = axis_values[axis_values["name"] == f"{p}-{rt_str}"] dmin, dmax = float(row["dmin"]), float(row["dmax"]) omin, omax = float(row["omin"]), float(row["omax"]) amin, amax = max(dmin, omin), min(dmax, omax) levels = np.linspace(amin, amax, 16) # Plot and save the image. If plotting strains use Axis values for # colour normalization. # norm = None from plot import axis_cmap_r cmap = axis_cmap_r top_view_bridge(c.bridge, abutments=True, piers=True) plot_contour_deck(c=c, cmap=cmap, responses=sim_responses, levels=levels) plt.tight_layout() plt.title( f"{sim_responses.response_type.name()} from 1mm pier settlement with OpenSees" ) plt.savefig( c.get_image_path( "validation/pier-displacement", safe_str(f"pier-{p}-{sim_responses.response_type.name()}") + ".pdf", )) plt.close() # First plot and clear, just to have the same colorbar. plot_contour_deck(c=c, responses=sim_responses, cmap=cmap, levels=levels) plt.cla() # Save the axis plots. axis_img = mpimg.imread( f"validation/axis-screenshots/{p}-{rt_str}.png") top_view_bridge(c.bridge, abutments=True) plt.imshow( axis_img, extent=( c.bridge.x_min, c.bridge.x_max, c.bridge.z_min, c.bridge.z_max, ), ) # Plot the load and min, max values. for point, leg_label, color in [ ((0, 0), f"min = {np.around(dmin, 3)} {sim_responses.units}", "r"), ((0, 0), f"max = {np.around(dmax, 3)} {sim_responses.units}", "r"), ( (0, 0), f"|min-max| = {np.around(abs(dmax - dmin), 3)} {sim_responses.units}", "r", ), ]: plt.scatter( [point[0]], [point[1]], label=leg_label, marker="o", color=color, alpha=0, ) if response_type == ResponseType.YTranslation: plt.legend() # Title and save. plt.title( f"{response_type.name()} from 1mm pier settlement with AxisVM") plt.xlabel("X position (m)") plt.ylabel("Z position (m)") plt.tight_layout() plt.savefig( c.get_image_path( "validation/pier-displacement", f"{p}-axis-{rt_str}.pdf", )) plt.close()
def point_load_response_plots(c: Config, x: float, z: float, kn: int = 1000, run: bool = False): """Response to a point load per scenarios scenario.""" response_types = [ResponseType.YTranslation, ResponseType.Strain] # scenarios = all_scenarios(c) damage_scenarios = [HealthyScenario(), transverse_crack()] # 10 x 10 grid of points on the bridge deck where to record fem. points = [ Point(x=x, y=0, z=z) for x, z in itertools.product( np.linspace(c.bridge.x_min, c.bridge.x_max, 30), np.linspace(c.bridge.z_min, c.bridge.z_max, 100), ) ] for response_type in response_types: all_responses = [] for damage_scenario in damage_scenarios: sim_params = SimParams( response_types=[response_type], ploads=[ PointLoad(x_frac=c.bridge.x_frac(x), z_frac=c.bridge.z_frac(z), kn=kn) ], ) use_c, sim_params = damage_scenario.use(c=c, sim_params=sim_params) all_responses.append( load_fem_responses( c=use_c, sim_params=sim_params, response_type=response_type, sim_runner=OSRunner(use_c), run=run, ).resize()) amin, amax = np.inf, -np.inf for sim_responses in all_responses: responses = np.array(list(sim_responses.values())) amin = min(amin, min(responses)) amax = max(amax, max(responses)) for d, damage_scenario in enumerate(damage_scenarios): top_view_bridge(c.bridge, abutments=True, piers=True) plot_contour_deck( c=c, responses=all_responses[d], levels=100, norm=colors.Normalize(vmin=amin, vmax=amax), decimals=10, ) plt.title(damage_scenario.name) plt.tight_layout() plt.savefig( c.get_image_path( "contour/point-load", safe_str( f"x-{x:.2f}-z-{z:.2f}-kn-{kn}-{response_type.name()}-{damage_scenario.name}" ) + ".pdf", )) plt.close()