Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 24 additions & 23 deletions src/osdagbridge/core/bridge_types/plate_girder/designer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2967,31 +2967,32 @@ def _fmax_lc(lc_name, comp_i, comp_j):
except Exception:
pass

# (4) Fatigue stress/shear ranges — true range (max − min) across ALL SLS_FREQUENT_*
# combinations (IRC 22 Cl.604.5), matching the Vr_kN range pattern below.
# (4) Fatigue stress/shear ranges — IRC 22 Cl.604.5. Fatigue is driven by the
# LIVE (fatigue-vehicle) load ALONE — permanent loads are steady and don't
# cycle. The range is measured AT A GIVEN SECTION as the vehicle moves on/off:
# per-element (max − min, against the unloaded 0 state), worst section. These
# two values feed only the fatigue checks (8/9); other checks keep SLS_frequent.
stress_range_MPa = shear_range_MPa = 0.0
if _sls_frequent_lcs:
if all_live_lcs:
try:
ds = analysis_results.ds
mz_all = np.concatenate([
np.asarray(ds.forces.sel(Loadcase=_sls_frequent_lcs, Element=elements,
Component=c).values, dtype=float).flatten()
for c in ("Mz_i", "Mz_j")
])
mz_all = mz_all[~np.isnan(mz_all)]
if mz_all.size and Ze_comp_bot_mm3 > 0:
mz_range_Nm = max(float(mz_all.max()), 0.0) - min(float(mz_all.min()), 0.0)
# Composite section modulus — live-load stress acts on the composite section.
stress_range_MPa = mz_range_Nm * 1000.0 / Ze_comp_bot_mm3
vy_all = np.concatenate([
np.asarray(ds.forces.sel(Loadcase=_sls_frequent_lcs, Element=elements,
Component=c).values, dtype=float).flatten()
for c in ("Vy_i", "Vy_j")
])
vy_all = vy_all[~np.isnan(vy_all)]
if vy_all.size and Aw_mm2 > 0:
vy_range_N = max(float(vy_all.max()), 0.0) - min(float(vy_all.min()), 0.0)
shear_range_MPa = vy_range_N / Aw_mm2
f = analysis_results.ds.forces.sel(Loadcase=all_live_lcs, Element=elements)

def _sec_range(comp_i, comp_j):
"""Worst per-section (max − min) across live positions, incl. the 0 state."""
rng = 0.0
for c in (comp_i, comp_j):
da = f.sel(Component=c)
emax = da.max("Loadcase").clip(min=0) # vehicle on (or 0 if never +)
emin = da.min("Loadcase").clip(max=0) # vehicle off (0) or hogging
v = float((emax - emin).max())
if v == v: # skip NaN
rng = max(rng, v)
return rng

if Ze_comp_bot_mm3 > 0:
stress_range_MPa = _sec_range("Mz_i", "Mz_j") * 1000.0 / Ze_comp_bot_mm3
if Aw_mm2 > 0:
shear_range_MPa = _sec_range("Vy_i", "Vy_j") / Aw_mm2
except Exception:
pass

Expand Down
4 changes: 3 additions & 1 deletion src/osdagbridge/desktop/ui/docks/output_dock.py
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,9 @@ def refresh_loadcase_dropdowns(self):
# (which plots real dataset load cases).
if key == KEY_OUTPUT_DOCK_LOAD_COMBINATION:
combo.addItem("Design Envelope")
combo.setCurrentIndex(0) # first real load case is default
combo.setCurrentText("Design Envelope") # default for design dropdown
else:
combo.setCurrentIndex(0) # first real load case is default
combo.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLengthWithIcon)
combo.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)
combo.blockSignals(False)
Expand Down