Ejemplo n.º 1
0
 def mv_vehicle_f(time: float, full_lanes: int):
     start = timer()
     vehicle = sample_vehicle(c), arrival(beta=lam, min_d=min_d)
     nonlocal count
     count += 1
     print_i(f"{count}{st(count)} sampled vehicles took {timer() - start}")
     return vehicle
Ejemplo n.º 2
0
def truck_1_loads(x: float):
    config = c()
    time = truck1.time_at(x=x, bridge=config.bridge)
    print_i(f"Time = {time:.4f}s")
    axle_loads = truck1.to_point_loads(time=time, bridge=config.bridge)
    for i in range(len(axle_loads)):
        print_i(
            f"Axle {i}: ({axle_loads[i][0].repr(config.bridge)}), "
            f" ({axle_loads[i][1].repr(config.bridge)})"
        )
Ejemplo n.º 3
0
def pairwise_cluster(c: Config, load: bool):
    """Cluster pairwise maps from healthy and damaged scenarios."""
    features_path = c.get_data_path("features", "pairwise-cluster", bridge=False)
    if not load:
        normal_traffic_array, _ = load_normal_traffic_array(c=c, mins=24)
        normal_traffic_array = normal_traffic_array[
            int(len(normal_traffic_array) / 24) :
        ]
        response_type = ResponseType.YTranslation
        grid_points = [
            Point(x=x, y=0, z=-9.65)
            for x, _ in itertools.product(
                np.linspace(c.bridge.x_min, c.bridge.x_max, 50),
                # np.linspace(c.bridge.x_min, c.bridge.x_max, 4),
                [1],
            )
        ]

        # Collect a list of features per scenarios scenario.
        features = []
        for damage_scenario in healthy_and_cracked_scenarios[1:]:
            damage_c = damage_scenario.use(c)
            responses = responses_to_traffic_array(
                c=damage_c,
                traffic_array=normal_traffic_array,
                response_type=response_type,
                bridge_scenario=damage_scenario,
                points=grid_points,
                sim_runner=OSRunner,
            ).T
            ks_values = []
            for p0_i, point0 in enumerate(grid_points):
                print_i(f"Point {p0_i + 1} / {len(grid_points)}", end="\r")
                ks_values.append([])
                for p1_i, point1 in enumerate(grid_points):
                    ks = ks_no_outliers(responses[p0_i], responses[p1_i])
                    ks_values[-1].append(ks)
            features.append((ks_values, damage_scenario.name))

        # Save features to disk.
        features = np.array(features)
        np.save(features_path, features)

    features = np.load(features_path)
    # Reduce each pairwise map to a sum per sensor.
    for f_i, (feature, feature_name) in enumerate(features):
        features[f_i] = ([sum(sensor) for sensor in feature], feature_name)
        features[f_i] = ([sum(sensor) for sensor in features[f_i]], feature_name)

    # Cluster each pairwise map.
    from sklearn.cluster import KMeans

    kmeans = KMeans(n_clusters=2)
    kmeans.fit(features)
Ejemplo n.º 4
0
def bridge_3d_nodes(deck_nodes: DeckNodes,
                    all_support_nodes: PierNodes) -> List[Node]:
    """All a bridge's nodes in a deterministic order."""
    all_nodes = list(itertools.chain.from_iterable(deck_nodes))
    for support_nodes in all_support_nodes:
        for wall_nodes in support_nodes:
            for y_nodes in wall_nodes:
                for node in y_nodes:
                    all_nodes.append(node)
    assert isinstance(all_nodes[0], Node)
    assert isinstance(all_nodes[-1], Node)
    print_i(f"Total bridge nodes: {len(all_nodes)}")
    return all_nodes
Ejemplo n.º 5
0
def parse_translation_responses_3d(
    results_dict,
    fem_params: SimParams,
    sim_ind: int,
    responses_path: str,
    response_type: ResponseType,
):
    """Parse translation fem from a 3D OpenSees simulation."""
    print(f"response_type = {response_type}")
    if response_type not in [RT.XTrans, RT.YTrans, RT.ZTrans]:
        raise ValueError("Must be translation response type")
    start = timer()
    translation_responses = opensees_to_numpy(responses_path)
    translation_responses *= -1
    print_i(
        f"OpenSees: Parsed {response_type.name()} fem in" + f" {timer() - start:.2f}s"
    )
    results_dict[sim_ind][response_type] = translation_responses
Ejemplo n.º 6
0
def os_runner(
        exe_path: Optional[str] = None) -> Callable[["Config"], OSRunner]:
    # Try using OpenSees on PATH.
    if exe_path is None:
        exe_path = spawn.find_executable("OpenSees")
        if exe_path is not None:
            print_i(f"Found Opensees at: {exe_path}")
    # Else try a few hardcoded possibilities e.g. for Singularity.
    try_exes = ["/opensees/bin/OpenSees"]
    if exe_path is None:
        for path in try_exes:
            if os.path.exists(path):
                print_i(f"Found Opensees at: {path}")
                exe_path = path
                break
    if exe_path is None:
        print_w("Could't find OpenSees executable")
    return lambda c: OSRunner(c=c, exe_path=exe_path)
Ejemplo n.º 7
0
def run_uls(
    c: Config,
    piers: bool,
    healthy: bool,
    cracked: bool,
    crack_x: Optional[int] = None,
    crack_length: Optional[int] = None,
):
    """Run all unit load simulations."""
    def crack_f():
        return transverse_crack(at_x=crack_x, length=crack_length)

    print_i(
        f"Running simulations with crack zone at x = {crack_x}, length = {crack_length}"
    )

    response_type = ResponseType.YTranslation
    if piers:
        # Pier settlement.
        list(
            PSResponses.load(c=c,
                             response_type=response_type,
                             fem_runner=OSRunner(c)))
    if healthy:
        c = healthy_damage_w_crack_nodes(crack_f=crack_f).use(c)[0]
        # Unit load simulations (healthy bridge).
        ULResponses.load_wheel_tracks(
            c=c,
            response_type=response_type,
            sim_runner=OSRunner(c),
            wheel_zs=c.bridge.wheel_track_zs(c),
            run_only=True,
        )
    elif cracked:
        # Unit load simulations (cracked bridge).
        c = crack_f().use(c)[0]
        ULResponses.load_wheel_tracks(
            c=c,
            response_type=response_type,
            sim_runner=OSRunner(c),
            wheel_zs=c.bridge.wheel_track_zs(c),
            run_only=True,
        )
Ejemplo n.º 8
0
def uls_contour_plot(c: Config, x_i: int, z_i: int,
                     response_type: ResponseType):
    wheel_xs = c.bridge.wheel_track_xs(c)
    wheel_x = wheel_xs[x_i]
    wheel_zs = c.bridge.wheel_track_zs(c)
    wheel_z = wheel_zs[z_i]
    print_i(f"Wheel (x, z) = ({wheel_x}, {wheel_z})")
    plt.landscape()
    plt.subplot(2, 1, 1)
    healthy = list(
        ILMatrix.load_wheel_track(
            c=c,
            response_type=response_type,
            fem_runner=OSRunner(c),
            load_z_frac=c.bridge.z_frac(wheel_z),
            run_only=False,
            indices=[x_i],
        ))[0].resize()
    top_view_bridge(bridge=c.bridge, compass=False, abutments=True, piers=True)
    plot_contour_deck(c=c, responses=healthy, sci_format=True, decimals=6)
    plt.title("Healthy")
    c = transverse_crack().use(c)[0]
    cracked = list(
        ILMatrix.load_wheel_track(
            c=c,
            response_type=response_type,
            fem_runner=OSRunner(c),
            load_z_frac=c.bridge.z_frac(wheel_z),
            run_only=False,
            indices=[x_i],
        ))[0].resize()
    plt.subplot(2, 1, 2)
    top_view_bridge(bridge=c.bridge, compass=False, abutments=True, piers=True)
    plot_contour_deck(c=c, responses=cracked, sci_format=True, decimals=6)
    plt.title("Cracked")
    plt.tight_layout()
    plt.savefig(
        c.get_image_path(
            "verification",
            safe_str(
                f"uls-contour-x-{wheel_x}-z-{wheel_z}-{response_type.name()}")
            + ".pdf",
        ))
Ejemplo n.º 9
0
def responses_to_loads_d(
        c: Config,
        response_type: ResponseType,
        points: List[Point],
        loads: List[List[PointLoad]],
        damage_scenario: Scenario = HealthyScenario(),
):
    """Responses to point-loads via direct simulation (not using superposition).
    """
    if not isinstance(damage_scenario, HealthyScenario):
        raise ValueError("Only HealthyDamage supported in direct simulation")
    expt_responses = load_expt_responses(
        c=c,
        expt_params=[SimParams(ploads=loads_) for loads_ in loads],
        response_type=response_type,
    )
    result = []
    for sim_responses in expt_responses:
        result.append(
            [sim_responses.at_deck(point, interp=True) for point in points])
        print_i("Interpolating fem in responses_from_load_d")
    return np.array(result)
Ejemplo n.º 10
0
 def ulm_partial(wheel_z):
     """Slice of unit load matrix for one wheel track."""
     wheel_track = ULResponses.load_wheel_track(
         c=c,
         response_type=response_type,
         fem_runner=sim_runner,
         load_z_frac=c.bridge.z_frac(wheel_z),
         run_only=False,
     )
     partial = np.empty((c.il_num_loads, len(points)))
     i = 0
     for sim_responses in wheel_track:
         for j, point in enumerate(points):
             partial[i][j] = sim_responses.at_deck(point, interp=False)
             if wheel_z < 0 and i == 302:
                 log(
                     c,
                     f"z = {wheel_z}, i = 302, partial[i][j] = {partial[i][j]}",
                 )
         i += 1
     assert i == c.il_num_loads
     print_i(f"Calculated unit load matrix for wheel track {wheel_z}")
     return partial
Ejemplo n.º 11
0
def run_ulm(c: Config, healthy: bool, cracked: bool, x_i: float, z_i: float):
    """Run all unit load simulations."""
    response_type = ResponseType.YTranslation
    wheel_xs = c.bridge.wheel_track_xs(c)
    wheel_x = wheel_xs[x_i]
    wheel_zs = c.bridge.wheel_track_zs(c)
    wheel_z = wheel_zs[z_i]
    print_i(f"Wheel (x, z) = ({wheel_x}, {wheel_z})")
    point = Point(x=wheel_x, y=0, z=wheel_z)
    if healthy:
        ULResponses.load_ulm(
            c=c,
            response_type=response_type,
            points=[point],
            sim_runner=OSRunner(c),
        )
    if cracked:
        c = transverse_crack().use(c)[0]
        ULResponses.load_ulm(
            c=c,
            response_type=response_type,
            points=[point],
            sim_runner=OSRunner(c),
        )
Ejemplo n.º 12
0
def plot_event(
    c: Config,
    event: Event,
    start_index: int,
    response_type: ResponseType,
    at: Point,
    overlap: Tuple[int, int],
    y_max: float,
    y_min: float,
):
    """Plot a single event with timing and overlap information."""
    time_series = event.get_time_series(noise=False)
    time_series_with_noise = event.get_time_series(noise=True)
    x_min = start_index * c.time_step
    x_max = (start_index + len(time_series)) * c.time_step
    overlap_height = y_max - y_min
    # Plot LHS overlap.
    if overlap[0]:
        overlap_width = (x_max - x_min) * (overlap[0] / len(time_series))
        plt.gca().add_patch(
            patches.Rectangle(
                xy=(x_min, y_min),
                width=overlap_width,
                height=overlap_height,
                alpha=0.1,
            ))
    # Plot RHS overlap.
    if overlap[1]:
        overlap_width = (x_max - x_min) * (overlap[1] / len(time_series))
        plt.gca().add_patch(
            patches.Rectangle(
                xy=(x_max - overlap_width, y_min),
                width=overlap_width,
                height=overlap_height,
                alpha=0.1,
            ))
    print_i(f"x_min = {x_min}")
    print_i(f"x_max = {x_max}")
    print_i(f"x.shape = {np.linspace(x_min, x_max, len(time_series)).shape}")
    x_axis = np.linspace(x_min, x_max, num=len(time_series))
    plt.plot(x_axis, time_series_with_noise, color="tab:orange")
    plt.plot(x_axis, time_series, color="tab:blue")
    plt.title(f"{response_type.name()} at {at.x:.2f}m")
    plt.xlabel("time (s)")
    plt.ylabel(f"{response_type.name().lower()} ({response_type.units()})")
Ejemplo n.º 13
0
def oneclass(c: Config):
    normal_traffic_array, traffic_scenario = load_normal_traffic_array(c)
    bridge_scenarios = [HealthyScenario()] + each_pier_scenarios(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 / 2, 20),
            np.linspace(c.bridge.z_min, c.bridge.z_max / 2, 3),
        )
    ]
    results = []

    for b, bridge_scenario in enumerate(bridge_scenarios):
        print_i(f"One class: bridge scenario {bridge_scenario.name}")
        responses = responses_to_traffic_array(
            c=c,
            traffic_array=normal_traffic_array,
            response_type=response_type,
            bridge_scenario=bridge_scenario,
            points=points,
            fem_runner=OSRunner(c),
        ).T
        print(len(normal_traffic_array))
        print(responses.shape)

        # Fit on the healthy scenario.
        if b == 0:
            assert len(responses) == len(points)
            clfs = []
            for r, rs in enumerate(responses):
                print_i(f"Training classifier {r} / {len(responses)}")
                clfs.append(OneClassSVM().fit(rs.reshape(-1, 1)))

        scenario_results = []
        for p, _ in enumerate(points):
            print_i(f"Predicting points {p} / {len(points)}")
            prediction = clfs[p].predict(responses[p].reshape(-1, 1))
            print(prediction)
            print(len(prediction[prediction < 0]))
            print(len(prediction[prediction > 0]))
Ejemplo n.º 14
0
def load(
    name: str, temp_quantile: Tuple[float, float] = (0.001, 0.999)
) -> pd.DataFrame:
    # If the file is already parsed, return it..
    name_path = os.path.join(project_dir(), "data/temperature", name + ".txt")
    saved_path = name_path + ".parsed"
    if os.path.exists(saved_path):
        df = pd.read_csv(saved_path, index_col=0, parse_dates=["datetime"])
        lq = df["temp"].quantile(temp_quantile[0])
        hq = df["temp"].quantile(temp_quantile[1])
        print(f"Temperature {temp_quantile} quantiles = {lq}, {hq}")
        df = df[(df["temp"] >= lq) & (df["temp"] <= hq)]
        return df
    # ..otherwise read and parse the data.
    with open(name_path) as f:
        temps = list(map(parse_line, f.readlines()))
    # Remove NANs.
    for line_ind, [dt, temp, solar] in enumerate(temps):
        if np.isnan(temp):
            print_i(f"NAN in {name} temperature")
            temps[line_ind][1] = temps[line_ind - 1][1]
        if np.isnan(solar):
            print_i(f"NAN in {name} solar radiation")
            temps[line_ind][2] = temps[line_ind - 1][2]
    # Pack it into a DataFrame.
    df = pd.DataFrame(temps, columns=["datetime", "temp", "solar"])
    # Convert to celcius.
    # df["temp"] = (df["temp"] - 32) * (5 / 9)
    # Remove duplicate times.
    len_before = len(df)
    df = df.drop_duplicates(subset=["datetime"], keep="first")
    len_after = len(df)
    print_i(
        f"Removed {len_before - len_after} duplicates, now {len_after} rows")
    # Sort.
    df = df.sort_values(by=["datetime"])
    # Save.
    df.to_csv(saved_path)
    return load(name=name)
Ejemplo n.º 15
0
def truck_1():
    vehicle.wagen1_plot(c())
    print_i(f"Truck 1 x positions: {_truck1_x_pos()}")
Ejemplo n.º 16
0
def wheel_tracks():
    config = c()
    print_i(f"Wheel tracks: {config.bridge.wheel_tracks(config)}")
Ejemplo n.º 17
0
    def traffic_sequence(
        self, bridge: Bridge, max_time: float, adjust: bool = True
    ) -> TrafficSequence:
        """Generate a 'TrafficSequence' under this traffic scenario.

        Returns a sequence of traffic events such that there is at least
        'max_time' of traffic from when the traffic sequence has warmed up.
        There is one additional event after 'max_time' is reached.

        Args:
            bridge: Bridge, bridge the vehicles drive on.
            max_time: float, simulation time after warm up, in seconds.

        """
        result: TrafficSequence = []
        time: float = 0

        # Per lane, a vehicles generator.
        mv_vehicle_gens = [
            self.mv_vehicles(bridge=bridge, lane=lane)
            for lane, _ in enumerate(bridge.lanes)
        ]

        # Per lane, next vehicles ready to drive onto the lane.
        next_vehicles: List[Vehicle] = [
            next(gen)(time=time, full_lanes=0) for gen in mv_vehicle_gens
        ]

        # All vehicles must start at x = 0, sanity check.
        if not all(v.init_x_frac == 0 for v in next_vehicles):
            raise ValueError("Initial vehicles not starting at x = 0")

        # Count the amount of full lanes traveled.
        first_vehicle: Vehicle = next_vehicles[0]
        full_lanes = lambda: first_vehicle.full_lanes(time=time, bridge=bridge)

        # Increase simulation by time taken to warm up.
        warmed_up_at = first_vehicle.time_left_bridge(bridge)
        print(f"Trafic warmed up at = {warmed_up_at}")
        max_time += warmed_up_at
        print(f"max_time = {max_time}")

        # Time vehicles will leave the bridge, in order.
        time_leave: List[Tuple[Vehicle, float]] = deque([])

        # Until maximum time is reached, see below..
        while True:
            # The next event's vehicles, time, and event type (enter/leave).
            vehicle, event_time, enter = None, np.inf, True

            # Find next enter/leave event.
            for v in next_vehicles:
                t = v.time_entering_bridge(bridge)
                if t < event_time:
                    vehicle, event_time = v, t
            assert enter == True
            # for v, t in time_leave:
            # Check if the next leave event is ready.
            if len(time_leave) > 0 and time_leave[0][1] < event_time:
                vehicle, event_time, enter = time_leave[0][0], time_leave[0][1], False

            # Add the enter/leave event to the sequence.
            result.append((vehicle, event_time, enter))
            time = event_time

            # Stop if maximum time is reached.
            if event_time > max_time:
                break
            print_i(f"Generating 'TrafficSequence', time = {time:.3f} s", end="\r")

            # Update vehicles entering/leaving the bridge.
            if enter:
                time_leave.append((vehicle, vehicle.time_left_bridge(bridge)))
                next_vehicles[vehicle.lane] = next(mv_vehicle_gens[vehicle.lane])(
                    time=time, full_lanes=full_lanes()
                )
            else:
                time_leave.popleft()

        print_i(
            f"Generated {time:.3f} - {warmed_up_at:.3f} = {time - warmed_up_at:.3f} s of 'TrafficSequence'"
        )
        return result
Ejemplo n.º 18
0
def cluster_damage(c: Config, mins: float):
    # Create the traffic.
    traffic_scenario = normal_traffic(c=c, lam=5, min_d=2)
    traffic_sequence, traffic, traffic_array = load_traffic(
        c=c,
        traffic_scenario=traffic_scenario,
        max_time=mins * 60,
    )
    point = Point(x=21, y=0, z=-8.4)  # Point to investigate.
    # Collect vertical translation and strain for all scenarios scenarios.
    responses_y = []
    responses_s = []
    for damage_scenario in [
            healthy_damage,
            pier_disp_damage([(5, 0.5 / 1000)])
    ]:
        responses_y.append(
            responses_to_traffic_array(
                c=c,
                traffic_array=traffic_array,
                response_type=ResponseType.YTranslation,
                damage_scenario=damage_scenario,
                points=[point],
                sim_runner=OSRunner(c),
            ).T[0] * 1000)
        assert len(responses_y[-1]) == len(traffic_array)
        responses_s.append(
            responses_to_traffic_array(
                c=c,
                traffic_array=traffic_array,
                response_type=ResponseType.Strain,
                damage_scenario=damage_scenario,
                points=[point],
                sim_runner=OSRunner(c),
            ).T[0])
        assert len(responses_s[-1]) == len(traffic_array)
    # Calculate features per scenarios.
    damage_features = []
    damage_labels = []
    for damage_ind in range(len(responses_y)):
        y = responses_y[damage_ind]
        s = responses_s[damage_ind]
        for response_ind in range(len(y)):
            damage_features.append([y[response_ind], s[response_ind]])
            damage_labels.append(damage_ind)
    damage_features = np.array(damage_features)
    damage_labels = np.array(damage_labels)
    print_i(f"Dimensions of feature array = {damage_features.shape}")
    # Plot the reference data.
    plt.landscape()
    plt.scatter(damage_features[:, 0], damage_features[:, 1], c=damage_labels)
    plt.title("Reference")
    plt.tight_layout()
    plt.savefig(c.get_image_path("classify/cluster", "cluster-ref.pdf"))
    plt.close()
    # Plot the gaussian mixture results.
    gmm = mixture.GaussianMixture(n_components=2).fit(damage_features)
    labels = flip(l=gmm.predict(damage_features), ref=damage_labels)
    plt.landscape()
    plt.scatter(damage_features[:, 0], damage_features[:, 1], c=labels)
    plt.title("Gaussian mixture n = 2")
    plt.tight_layout()
    plt.savefig(c.get_image_path("classify/cluster", "cluster-model.pdf"))
    plt.close()
    # Plot and print the accuracy.
    # https://matplotlib.org/3.1.1/gallery/text_labels_and_annotations/custom_legends.html
    acc = abs(labels - damage_labels)
    total = defaultdict(lambda: 0)
    correct = defaultdict(lambda: 0)
    for ind, label in enumerate(damage_labels):
        total[label] += 1
        if acc[ind] == 0:
            correct[label] += 1
    for k, t in total.items():
        print_i(f"k = {k}: {correct[k]} / {t} = {correct[k] / t}")
    plt.scatter(damage_features[:, 0], damage_features[:, 1], c=acc)
    plt.tight_layout()
    plt.savefig(c.get_image_path("classify/cluster", "cluster-acc.pdf"))
    plt.close()
Ejemplo n.º 19
0
def to_traffic_array(
    c: Config,
    traffic_sequence: TrafficSequence,
    max_time: float,
    warm_up: bool = True,
    new: bool = True,
) -> Traffic:
    """Convert a 'TrafficSequence' to 'Traffic'.

    Args:
        c: Config, global configuration object.
        traffic_sequence: TrafficSequence, the sequence of traffic to convert
            into a 'TrafficArray'.
        max_time: float, maximum time of 'TrafficArray' to generate.
        warm_up: bool, if true then begin generating the 'TrafficArray' once the
            first vehicles has passed over the bridge (traffic has warmed up).
        new: bool, use the new "bucketing" method instead of the old method.

    """

    # NOTE: If you are going to try understand the code in this function then
    # start with looking at 'to_traffic', as that is almost a subset of this
    # code.

    print_i("Converting 'TrafficSequence' to 'TrafficArray'")
    time_step = c.sensor_hz
    print(
        f"array size = {int(max_time / time_step)}, {len(c.bridge.lanes) * 2 * c.il_num_loads}"
    )
    # Initial traffic array, to be filled in.
    result = np.zeros(
        (
            # '+ 1' to account for time t = 0.
            int(max_time / time_step) + 1,
            # 2 wheel tracks per lane.
            len(c.bridge.lanes) * 2 * c.il_num_loads,
        )
    )
    # Current traffic per lane.
    current = [deque([]) for _ in c.bridge.lanes]
    # Current time and timestep index.
    time, time_i = 0, 0
    # The next event and time the next event occurs.
    next_event_index = 0
    next_event_time = traffic_sequence[next_event_index][1]
    # Interpolate from x position to wheel track bucket.
    _interp = interp1d([c.bridge.x_min, c.bridge.x_max], [0, c.il_num_loads - 1])

    def interp(x):
        return int(np.around(_interp(x), 0))

    wheel_track_xs = c.bridge.wheel_track_xs(c)
    # Column index where each wheel track starts.
    j_indices = [
        (l * 2 * c.il_num_loads, ((l * 2) + 1) * c.il_num_loads)
        for l, _ in enumerate(current)
    ]

    # If it is requested that traffic warm up first, then until time
    # 'warmed_up_at' is reached, nothing will be added to the 'TrafficArray'.
    warmed_up_at = traffic_sequence[0][0].time_left_bridge(c.bridge)

    last_print_time, start_time = -np.inf, None
    while time_i < result.shape[0]:
        # Print an update when at least 1 second has passed.
        if time - last_print_time > 1:
            print_i(f"Generating 'TrafficArray', time = {time:.4f} s", end="\r")
            last_print_time = time

        # While events have occurred, update current traffic.
        while time > next_event_time or np.isclose(time, next_event_time):
            vehicle, _, enter = traffic_sequence[next_event_index]
            if enter:
                current[vehicle.lane].append(vehicle)
                print(
                    f"Vehicle entered {vehicle.lane} at t = {time:.3f}, sum = {len(current[vehicle.lane])}",
                    end="\r",
                )
            else:
                current[vehicle.lane].popleft()
                print(
                    f"Vehicle left {vehicle.lane} at t = {time:.3f}, sum = {len(current[vehicle.lane])}"
                )
            # Find the next event, if there is one.
            next_event_index += 1
            try:
                next_event_time = traffic_sequence[next_event_index][1]
            except IndexError:
                next_event_time = np.inf

        # Only add to the 'TrafficArray' if the traffic is not required to warm
        # up, or the traffic has already warmed up.
        if not warm_up or time > warmed_up_at or np.isclose(time, warmed_up_at):
            # TODO: This bottom part of the loop should be parallelized!
            if start_time is None:
                start_time = time
            # For each vehicles, find the lane it's on, and indices into the ULM.
            if new:
                for js, vehicles in zip(j_indices, current):
                    for vehicle in vehicles:
                        # Here the wheel track bucketing is implemented.
                        for axle_loads in vehicle.to_wheel_track_loads_(
                            c=c, time=time, wheel_track_xs=wheel_track_xs,
                        ):
                            # The x indices are equal per axle.
                            x_inds = [interp(x) for x, _ in axle_loads[0]]
                            for j, wheel_loads in zip(js, axle_loads):
                                for x_ind, (load_x, load_kn) in zip(
                                    x_inds, wheel_loads
                                ):
                                    result[time_i][j + x_ind] += load_kn
            # The old method.
            else:
                # For each lane.
                for (j0, j1), vehicles in zip(j_indices, current):
                    # For each vehicles.
                    for vehicle in vehicles:
                        xs = vehicle.xs_at(time=time, bridge=c.bridge)
                        kns = vehicle.kn_per_axle()
                        # assert len(xs) == len(kns)
                        # For each axle currently on the bridge.
                        for x, kn in zip(xs, kns):
                            if x >= c.bridge.x_min and x <= c.bridge.x_max:
                                x_ind = interp(x)
                                # For each wheel.
                                for j in [j0, j1]:
                                    # print(f"lane = {l}, w = {w}, x = {x}, x_interp = {x_interp(x)}, j = {j}, kn = {kn / 2}")
                                    result[time_i][j + x_ind] = kn / 2
            time_i += 1
        time += time_step

    print_i(
        f"Generated {time - start_time - time_step:.4f} s of 'TrafficArray' from 'TrafficSequence'"
    )
    return result
Ejemplo n.º 20
0
def _savefig(s):
    print_i(f"Saving image to {s}")
    _og_savefig(s)
    if s.endswith(".pdf"):
        _og_savefig(s.replace(".pdf", ".png"))
Ejemplo n.º 21
0
def load_fem_responses(
    c: Config,
    sim_params: SimParams,
    response_type: ResponseType,
    run: bool = False,
    run_only: bool = False,
    index: Optional[Tuple[int, int]] = None,
) -> "FEMResponses":
    """Load responses of one sensor type from a FE simulation.

    This function is a layer over 'FEMRunner.run' and additionally handles
    saving/loading results to/from disk -- only running the simulation if
    necessary.

    Args:
        c: simulation configuration object.
        sim_params: simulation parameters.
        response_type: responses to load from disk and return.
        run: run the simulation even if results are already saved.
        run_only: don't bother returning results
        index: simulation progress (n/m) printed if given.

    NOTE: Note-to-self. This function is NOT to take a DamageScenario. The whole
    'fem' module of this package should be separate from that abstraction.

    """
    if response_type not in c.sim_runner.supported_response_types(c.bridge):
        raise ValueError(f"{response_type} not supported by FEMRunner")

    prog_str = "1/1: "
    if index is not None:
        prog_str = f"{index[0]}/{index[1]}: "
    print_prog = lambda s: print_i(prog_str + s, end="\r")

    path = _responses_path(
        sim_runner=c.sim_runner,
        sim_params=sim_params,
        response_type=response_type,
    )
    print_i(f"Loading responses from: {path}")

    # Run the FEM simulation, and/or clean build artefacts, if requested.
    if run or not os.path.exists(path):
        print_prog(f"Running simulation")
        c.sim_runner.run([sim_params])
    else:
        print_prog(f"Not running simulation")
    # If only running was requested then we are done.
    if run_only:
        return None

    start = timer()
    try:
        with open(path, "rb") as f:
            responses = dill.load(f)
    # Try again on Exception.
    except Exception as e:
        print_i(f"\n{str(e)}\nremoving and re-running sim. {index} at {path}")
        os.remove(path)
        return load_fem_responses(
            c=c,
            sim_params=sim_params,
            response_type=response_type,
            run=run,
            run_only=run_only,
            index=index,
        )

    print_prog(
        f"Loaded Responses in {timer() - start:.2f}s, ({response_type})")

    start = timer()
    sim_responses = SimResponses(
        c=c,
        sim_params=sim_params,
        sim_runner=c.sim_runner,
        response_type=response_type,
        responses=responses,
    )
    print_prog(
        f"Built FEMResponses in {timer() - start:.2f}s, ({response_type})")

    return sim_responses
Ejemplo n.º 22
0
    def __init__(
        self,
        bridge: Callable[[], "Bridge"],
        sim_runner: Callable[[], "FEMRunner"],
        vehicle_data_path: str,
        vehicle_pdf: List[Tuple[float, float]],
        vehicle_pdf_col: str,
        generated_data: str = "generated-data",
        shorten_paths: bool = False,
    ):
        """Simulation configuration object.

        Combines a Bridge and FEMRunner among other configuration.

        :param bridge: function that returns a bridge.
        :param sim_runner: simulation runner.
        :param vehicle_data_path: path of the vehicles CSV file.
        :param vehicle_pdf:
            percentage of vehicles below a maximum value for that column.

            Example: [(2.4, 0.5), (5.6, 94.5), (16, 5)]

            Here 5% of vehicles are 2.4m or less in length, 94.5% greater than
            2.4m and less than 5.6m, and the remaining 5% are less than 16m.
            This applies if 'vehicle_pdf_col' is "length".
        :param vehicle_pdf_col: column of vehicle_data to group by.
        :param generated_data: directory where to save generated files.
        :param shorten_paths: shorten simulation paths.
        """
        # Core.
        self._bridge = bridge
        self.bridge = self._bridge()
        self._sim_runner = sim_runner
        self.sim_runner = self._sim_runner(self)

        # OpenSees
        self.os_model_template_path: str = "model-template.tcl"
        self.os_3d_model_template_path: str = "model-template-3d.tcl"

        # Simulation performance.
        self.parallel = 1
        self.parallel_ulm = True
        self.shorten_paths = shorten_paths
        self.resp_matrices = dict()

        # Unit loads.
        self.il_num_loads: int = 600
        self.il_unit_load_kn: float = 1000
        self.pd_unit_disp: float = 1.0
        self.pd_unit_load_kn: int = 10
        self.unit_axial_delta_temp_c: int = 1
        self.unit_moment_delta_temp_c: int = 1
        self.cte = 12e-6

        # Responses & events.
        self.sensor_hz: float = 1 / 100
        self.event_time_s: float = 2  # Seconds.

        # Vehicles.
        self.perturb_stddev: float = 0.1
        self.axle_width: float = 2.5
        self.vehicle_pdf = vehicle_pdf
        self.vehicle_pdf_col = vehicle_pdf_col
        start = timer()
        self.vehicle_data_path = vehicle_data_path
        # Necessary to prevent a circular import.
        from bridge_sim.vehicles.sample import load_vehicle_data

        self.vehicle_data = load_vehicle_data(vehicle_data_path)
        print_i(
            f"Loaded vehicles data from {vehicle_data_path} in"
            + f" {timer() - start:.2f}s"
        )

        # Ensure vehicles probability density sums to 1.
        pdf_sum = sum(map(lambda f: f[1], self.vehicle_pdf))
        if int(pdf_sum) != 100:
            pre_pdf_sum = pdf_sum
            for i in range(len(self.vehicle_pdf)):
                self.vehicle_pdf[i] = (
                    self.vehicle_pdf[i][0],
                    self.vehicle_pdf[i][1] / pdf_sum,
                )
            pdf_sum = sum(map(lambda f: f[1], self.vehicle_pdf))
            print_w(f"Vehicle PDF sums to {pre_pdf_sum}, adjusted to sum to 1")

        # Root directories for generated data.
        self._root_generated_data_dir = generated_data
        self.root_generated_data_dir = lambda: _get_dir(self._root_generated_data_dir)
        if self._root_generated_data_dir[-1] in "/\\":
            raise ValueError("generated_data must not end in path separator")
        self.root_generated_images_dir = lambda: _get_dir(
            os.path.join(self.root_generated_data_dir() + "-images")
        )
Ejemplo n.º 23
0
def apply_effect(
    c: Config,
    points: List[Point],
    responses: List[List[float]],
    effect: List[List[float]],
    speed_up: int = 1,
    repeat_responses: bool = False,
) -> List[float]:
    """Time series of effect due to temperature at given points.

    Returns: a NumPy array of shape the same as given fem. The effect due
        to temperature is interpolated across the date range of the given
        fem, this is calculated under the assumption that temperature
        effect is given at one data point per minute and that the sensor
        fem are given at a rate of 'c.sensor_hz'.

    """
    raise ValueError("Deprecated")
    assert len(responses) == len(points)
    # Convert the temperature data into temperature effect at each point.
    # effect_ = effect(c=c, response_type=response_type, points=points, temps=temps)
    assert len(effect) == len(points)
    # A temperature sample is available per minute. Here we calculate the
    # number of fem between each pair of recorded temperatures and the
    # number of temperature samples required for the given fem.
    len_per_min = get_len_per_min(c=c, speed_up=speed_up)
    print_i(f"Length per minute = {len_per_min}, speed_up = {speed_up}")
    num_temps_req = math.ceil(len(responses[0]) / len_per_min) + 1
    if num_temps_req > len(effect[0]):
        raise ValueError(f"Not enough temperatures ({len(effect[0])}) for data"
                         f" (requires {num_temps_req})")
    # If additional temperature data is available, then use it if requested and
    # repeat the given fem. Here we calculate length, in terms of the
    # sample frequency, recall that temperature is sampled every minute.
    avail_len = (len(effect[0]) - 1) * len_per_min
    if repeat_responses and (avail_len > len(responses[0])):
        print_i(
            f"Increasing length of fem from {len(responses[0])} to {avail_len}"
        )
        num_temps_req = len(effect[0])
        new_responses = np.empty((len(responses), avail_len))
        for i in range(len(responses)):
            for j in range(math.ceil(avail_len / len(responses[0]))):
                start = j * len(responses[0])
                end = min(avail_len - 1, start + len(responses[0]))
                new_responses[i][start:end] = responses[i][:end - start]
        responses = new_responses
    # Fill in the fem array with the temperature effect.
    result = np.zeros((len(points), len(responses[0])))
    for i in range(len(points)):
        for j in range(num_temps_req - 1):
            start = j * len_per_min
            end = min(len(result[i]), start + len_per_min)
            print_d(D, f"start = {start}")
            print_d(D, f"end = {end}")
            print_d(D, f"end - start = {end - start}")
            # print_d(D, f"temp_start, temp_end = {temps[j]}, {temps[j + 1]}")
            print_d(
                D,
                f"effect_start, effect_end = {effect[i][j]}, {effect[i][j + 1]}"
            )
            result[i][start:end] = np.linspace(effect[i][j], effect[i][j + 1],
                                               end - start)
    if repeat_responses:
        return responses, result
    return result
Ejemplo n.º 24
0
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
Ejemplo n.º 25
0
def plot_events_from_traffic(
    c: Config,
    bridge: Bridge,
    bridge_scenario: DamageScenario,
    traffic_name: str,
    traffic: "Traffic",
    start_time: float,
    time_step: float,
    response_type: ResponseType,
    points: List[Point],
    fem_runner: FEMRunner,
    cols: int = 4,
    save: str = None,
):
    """Plot events from a traffic simulation on a bridge."""
    # Determine rows, cols and events per row.
    time_per_event = int(c.time_end / time_step)
    events = events_from_traffic(
        c=c,
        traffic=traffic,
        bridge_scenario=bridge_scenario,
        points=points,
        response_types=[response_type],
        fem_runner=fem_runner,
        start_time=start_time,
        time_step=time_step,
    )
    print(
        f"event time = {c.time_end}, time step = {time_step}, time per event = {time_per_event}"
    )
    print(f"num traffic = {len(traffic)}")
    print(f"num events = {len(events)}")
    for p, point in enumerate(points):
        events_ = events[p][0]  # Currently only one response type.

        # First determine rows and max/min response.
        rows = math.ceil(len(events_) / cols)
        y_min, y_max = np.inf, -np.inf
        for event in events_:
            y_min = min(y_min, np.min(event.get_time_series(noise=True)))
            y_max = max(y_max, np.max(event.get_time_series(noise=True)))
        y_min = min(y_min, -y_max)
        y_max = max(y_max, -y_min)
        assert isinstance(y_min, float)
        assert isinstance(y_max, float)
        y_min, y_max = np.min([y_min, -y_max]), np.max([y_max, -y_min])
        print_i(f"rows, cols = {rows}, {cols}")

        # Plot each event, including overlap.
        event_index = 0
        for row in range(rows):
            if event_index >= len(events_):
                break
            for col in range(cols):
                if event_index >= len(events_):
                    break
                event = events_[event_index]
                print_i(f"row, col = {row}, {col}")
                plt.subplot2grid((rows, cols), (row, col))
                end_overlap = event.overlap if event_index < len(
                    events_) - 1 else 0
                plot_event(
                    c=c,
                    event=event,
                    start_index=event.start_index,
                    response_type=response_type,
                    at=point,
                    overlap=(event.overlap, end_overlap),
                    y_min=y_min,
                    y_max=y_max,
                )
                event_index += 1
        if save:
            plt.savefig(f"{save}-at-{pstr(str(point))}")
            plt.close()
Ejemplo n.º 26
0
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()
Ejemplo n.º 27
0
    def run(
        self,
        expt_params: List[SimParams],
        return_parsed: bool = False,
        return_converted: bool = False,
    ):
        """Run multiple simulations and save responses.

        TODO: Change ExptParams to SimParams.

        Args:
            expt_params: ExptParams, parameters for a number of simulations.
            return_parsed: bool, for testing, return parsed fem.
            return_converted: bool, for testing, return converted fem.

        """
        # Building.
        start = timer()
        expt_params = self._build(
            c=self.c,
            expt_params=expt_params,
            fem_runner=self,
        )
        print_i(f"FEMRunner: built {self.name} model file(s) in" +
                f" {timer() - start:.2f}s")

        # Running.
        for sim_ind, _ in enumerate(expt_params):
            start = timer()
            expt_params = self._run(self.c, expt_params, self, sim_ind)
            print_i(f"FEMRunner: ran {self.name}" +
                    f" {sim_ind + 1}/{len(expt_params)}" +
                    f" simulation in {timer() - start:.2f}s")

        # Parsing.
        start = timer()
        parsed_expt_responses = self._parse(self.c, expt_params, self)
        print_i(f"FEMRunner: parsed all fem in" + f" {timer() - start:.2f}s")
        if return_parsed:
            return parsed_expt_responses
        print(parsed_expt_responses[0].keys())

        # Converting.
        start = timer()
        converted_expt_responses = self._convert(
            c=self.c,
            expt_params=expt_params,
            parsed_expt_responses=parsed_expt_responses,
        )
        print_i(f"FEMRunner: converted all fem to [Response] in" +
                f" {timer() - start:.2f}s")
        if return_converted:
            return converted_expt_responses
        print(converted_expt_responses[0].keys())

        # Saving.
        for sim_ind in converted_expt_responses:
            print_d(D, f"sim_ind = {sim_ind}")
            for response_type, responses in converted_expt_responses[
                    sim_ind].items():
                print_d(D, f"response_type in converted = {response_type}")
                print(len(responses))
                fem_responses = SimResponses(
                    c=self.c,
                    sim_params=expt_params[sim_ind],
                    sim_runner=self,
                    response_type=response_type,
                    responses=responses,
                    build=False,
                )

                start = timer()
                fem_responses.save()
                print_i(
                    f"FEMRunner: saved simulation {sim_ind + 1} SimResponses" +
                    f" in ([Response]) in {timer() - start:.2f}s," +
                    f"({response_type})")
Ejemplo n.º 28
0
def wagen_1_contour_plot(
    c: Config,
    x: int,
    crack_x: float,
    response_type: ResponseType,
    scatter: bool,
    run: bool,
    length: float,
    outline: bool,
    wheels: bool,
    temp: bool,
):
    original_c = c
    LOADS = False
    temp_bottom, temp_top = [17, 25]
    time = wagen1.time_at(x=x, bridge=c.bridge)

    def plot_wheels():
        if wheels:
            wagen1.plot_wheels(c=c,
                               time=time,
                               label="Truck 1 wheels",
                               zorder=100)

    center = c.bridge.x_max / 2
    min_x, max_x = center - 20, center + 20
    min_z, max_z = c.bridge.z_min, c.bridge.z_max

    def zoom_in():
        plt.ylim(min_z, max_z)
        plt.xlim(min_x, max_x)

    loads = wagen1.to_wheel_track_loads(c=c, time=time, flat=True)

    crack_f = lambda: transverse_crack(length=length, at_x=crack_x)
    c = healthy_damage_w_transverse_crack_nodes(crack_f).use(original_c)[0]
    deck_shells = get_bridge_shells(c.bridge)[0]
    healthy_responses = load_fem_responses(
        c=c,
        sim_params=SimParams(ploads=loads),
        response_type=response_type,
        sim_runner=OSRunner(c),
        run=run,
    ).at_shells(deck_shells)  # Convert fem to one per shell.
    if response_type in [ResponseType.Strain, ResponseType.StrainZZB]:
        # Resize by E-6 from microstrain to strain to match temperature units.
        healthy_responses = healthy_responses.resize()
    before_temp = healthy_responses.at_deck(Point(x=51, z=-8.4), interp=False)
    if temp:
        healthy_deck_points = healthy_responses.deck_points()  # Point of fem.
        temp_effect = temperature.effect(
            c=c,
            response_type=response_type,
            points=healthy_deck_points,
            temps_bt=([temp_bottom], [temp_top]),
        ).T[0]  # Temperature effect at existing response points.
        healthy_responses = healthy_responses.add(temp_effect,
                                                  healthy_deck_points)
    after_temp = healthy_responses.at_deck(Point(x=51, z=-8.4), interp=False)
    print_i(f"Healthy, before/after = {before_temp}, {after_temp}")
    if response_type in [ResponseType.Strain, ResponseType.StrainZZB]:
        healthy_responses = healthy_responses.map(lambda x: x * 1e6)
    else:
        healthy_responses = healthy_responses.resize()

    # Responses in cracked scenario.
    c = crack_f().use(original_c)[0]
    crack_responses = load_fem_responses(
        c=c,
        sim_params=SimParams(ploads=loads),
        response_type=response_type,
        sim_runner=OSRunner(c),
        run=run,
    ).at_shells(deck_shells)
    if response_type in [ResponseType.Strain, ResponseType.StrainZZB]:
        # Resize by E-6 from microstrain to strain to match temperature units.
        crack_responses = crack_responses.resize()
    before_temp = crack_responses.at_deck(Point(x=51, z=-8.4), interp=False)
    if temp:
        crack_deck_points = crack_responses.deck_points()  # Point of fem.
        temp_effect = temperature.effect(
            c=c,
            response_type=response_type,
            points=healthy_deck_points,
            temps_bt=([temp_bottom], [temp_top]),
        ).T[0]  # Temperature effect at existing response points.
        crack_responses = crack_responses.add(temp_effect, healthy_deck_points)
    after_temp = crack_responses.at_deck(Point(x=51, z=-8.4), interp=False)
    print_i(f"Crack, before/after = {before_temp}, {after_temp}")
    if response_type in [ResponseType.Strain, ResponseType.StrainZZB]:
        crack_responses = crack_responses.map(lambda x: x * 1e6)
    else:
        crack_responses = crack_responses.resize()

    # Limit to points in crack zone.
    without_cm = 35
    print(f"Avoid {without_cm} cm around crack zone")
    _without_crack_zone = crack_f().without(c.bridge, without_cm / 100)
    without_crack_zone = lambda p: not _without_crack_zone(p)
    if response_type in [ResponseType.Strain, ResponseType.StrainZZB]:
        healthy_responses = healthy_responses.without(without_crack_zone)
        crack_responses = crack_responses.without(without_crack_zone)

    # Norm calculation.
    vmin = min(healthy_responses.values())
    vmax = max(healthy_responses.values())
    vmin = min(vmin, min(crack_responses.values()))
    vmax = max(vmax, max(crack_responses.values()))
    norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
    print(f"Norm min/max = {vmin}, {vmax}")

    plt.portrait()
    plt.subplot(3, 1, 1)
    plot_contour_deck(
        c=c,
        responses=healthy_responses,
        ploads=loads if LOADS else [],
        scatter=scatter,
        norm=norm,
        decimals=2,
    )

    c_x_start, c_z_start, c_x_end, c_z_end = list(
        map(round_m,
            crack_f().crack_area(c.bridge)))

    def plot_outline(label="Crack zone"):
        if outline:
            plt.gca().add_patch(
                mpl.patches.Rectangle(
                    (c_x_start, c_z_start),
                    c_x_end - c_x_start,
                    c_z_end - c_z_start,
                    fill=not scatter,
                    edgecolor="black",
                    facecolor="white",
                    alpha=1,
                    label=label,
                ))

    top_view_bridge(bridge=c.bridge, compass=False, abutments=True, piers=True)
    plot_outline(label="Responses not considered")
    plot_wheels()
    zoom_in()

    def legend():
        plt.legend(
            loc="upper right",
            borderpad=0.2,
            labelspacing=0.2,
            borderaxespad=0,
            handletextpad=0.2,
            columnspacing=0.2,
        )

    legend()
    plt.title(f"Healthy bridge")
    plt.xlabel("")
    plt.tick_params(bottom=False, labelbottom=False)

    plt.subplot(3, 1, 2)
    plot_contour_deck(
        c=c,
        responses=crack_responses,
        ploads=loads if LOADS else [],
        scatter=scatter,
        norm=norm,
        decimals=2,
    )

    top_view_bridge(bridge=c.bridge, compass=False, abutments=True, piers=True)
    plot_outline()
    plot_wheels()
    zoom_in()

    legend()
    plt.title(f"Cracked bridge")
    plt.xlabel("")
    plt.tick_params(bottom=False, labelbottom=False)

    plt.subplot(3, 1, 3)
    responses = []
    for x in healthy_responses.deck_xs:
        for z in healthy_responses.zs[x][0]:
            responses.append((
                bridge_sim.sim.responses.responses[0][x][0][z] -
                crack_responses.at_deck(Point(x=x, z=z), interp=False),
                Point(x=x, z=z),
            ))
            # try:
            #     fem.append((
            #         healthy_responses.fem[0][x][0][z]
            #         - crack_responses.fem[0][x][0][z],
            #         Point(x=x, z=z)
            #     ))
            # except KeyError:
            #     pass
            #
    diff_responses = responses = Responses(
        response_type=response_type,
        responses=responses,
        units=healthy_responses.units,
    )
    plot_contour_deck(
        c=c,
        responses=diff_responses,
        ploads=loads if LOADS else [],
        cmap=mpl.cm.get_cmap("PiYG"),
        scatter=scatter,
        decimals=2,
    )

    print("********")
    print("********")
    print("********")
    grid_x, grid_z = 600, 200
    grid_points = list(
        filter(
            lambda p: not without_crack_zone(p),
            [
                Point(x=x, y=0, z=z)
                for x in np.linspace(c.bridge.x_min, c.bridge.x_max, grid_x)
                for z in np.linspace(c.bridge.z_min, c.bridge.z_max, grid_z)
            ],
        ))
    print(f"Amount grid points = {len(grid_points)}")
    grid_x_len = c.bridge.length / grid_x
    grid_z_len = c.bridge.width / grid_z
    grid_area = grid_x_len * grid_z_len
    print(f"Grid area = {grid_area}")
    print("Interpolating diff fem")
    interp_diff_responses = diff_responses.at_decks(grid_points)
    count_interp = len(interp_diff_responses)
    interp_diff_responses = interp_diff_responses[~np.
                                                  isnan(interp_diff_responses)]
    print(
        f"Removed {count_interp - len(interp_diff_responses)} of {count_interp} fem, remaining = {len(interp_diff_responses)}"
    )
    print("Finished interpolating diff fem")
    count_min, count_max = 0, 0
    d_min, d_max = min(diff_responses.values()), max(diff_responses.values())
    print(f"diff min, max = {d_min}, {d_max}")
    d_min08, d_max08 = d_min * 0.8, d_max * 0.8
    for interp_r in interp_diff_responses:
        if interp_r < d_min08:
            count_min += 1
        if interp_r > d_max08:
            count_max += 1
    print(f"Count = {count_min}, {count_max}")
    save_path = original_c.get_image_path(
        "verification",
        safe_str(
            f"truck1-contour-x-{x}{crack_x}{length}-{response_type.name()}-{temp}"
        ),
    )
    with open(save_path + ".txt", "w") as f:
        f.write(f"{count_min}, {count_max}\n")
        f.write(f"{count_min * grid_area}, {count_max * grid_area}")
    print(f"Wrote results to {save_path}.txt")

    top_view_bridge(bridge=c.bridge, compass=False, abutments=True, piers=True)
    plot_outline()
    plot_wheels()
    zoom_in()

    legend()
    temp_str = f"\nT_bot = {temp_bottom} °C, T_top = {temp_top} °C" if temp else ""
    plt.title(f"Difference of healthy & cracked bridge")
    rt_name = (f"Microstrain {response_type.ss_direction()}" if response_type
               in [ResponseType.Strain, ResponseType.StrainZZB
                   ] else response_type.name())

    plt.suptitle(f"{rt_name}: Truck 1 on healthy & cracked bridge{temp_str}")
    plt.tight_layout(rect=[0, 0.03, 1, 0.93 if temp else 0.95])
    plt.savefig(save_path + ".pdf")
Ejemplo n.º 29
0
def make_stats(c: Config):
    """Make all textual information for the thesis."""
    print_i("\n\n" + vehicle_density_stats(c) + "\n")
    print_i("\n\n" + vehicle_data_noise_stats(c) + "\n")
Ejemplo n.º 30
0
 def _plot_f(time_index):
     print_i(f"Animating time = {time_index * time_step:.3f}", end="\r")
     plot_f(time_index)